firefly-iii/resources/assets/js/components/transactions/EditTransaction.vue

958 lines
49 KiB
Vue
Raw Normal View History

2019-06-01 13:38:18 -05:00
<!--
- EditTransaction.vue
2020-01-24 23:08:56 -06:00
- Copyright (c) 2019 james@firefly-iii.org
2019-06-01 13:38:18 -05:00
-
- This file is part of Firefly III (https://github.com/firefly-iii).
2019-06-01 13:38:18 -05:00
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
2019-06-01 13:38:18 -05:00
-
- This program is distributed in the hope that it will be useful,
2019-06-01 13:38:18 -05:00
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
2019-06-01 13:38:18 -05:00
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
2019-06-01 13:38:18 -05:00
-->
<template>
2019-08-26 23:45:35 -05:00
<form method="POST" action="#" accept-charset="UTF-8" class="form-horizontal" id="store"
2019-06-01 13:38:18 -05:00
enctype="multipart/form-data">
<input name="_token" type="hidden" value="xxx">
<div class="row" v-if="error_message !== ''">
<div class="col-lg-12">
<div class="alert alert-danger alert-dismissible" role="alert">
2019-10-05 04:29:57 -05:00
<button type="button" class="close" data-dismiss="alert" v-bind:aria-label="$t('firefly.close')"><span
2019-06-01 13:38:18 -05:00
aria-hidden="true">&times;</span></button>
<strong>{{ $t("firefly.flash_error") }}</strong> {{ error_message }}
2019-06-01 13:38:18 -05:00
</div>
</div>
</div>
<div class="row" v-if="success_message !== ''">
<div class="col-lg-12">
<div class="alert alert-success alert-dismissible" role="alert">
2019-10-05 04:29:57 -05:00
<button type="button" class="close" data-dismiss="alert" v-bind:aria-label="$t('firefly.close')"><span
2019-06-01 13:38:18 -05:00
aria-hidden="true">&times;</span></button>
<strong>{{ $t("firefly.flash_success") }}</strong> <span v-html="success_message"></span>
2019-06-01 13:38:18 -05:00
</div>
</div>
</div>
<div>
<div class="row" v-for="(transaction, index) in transactions">
<div class="col-lg-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title splitTitle">
<span v-if="transactions.length > 1">{{ $t('firefly.split')}} {{ index+1 }} / {{ transactions.length }}</span>
<span v-if="transactions.length === 1">{{ $t('firefly.transaction_journal_information') }}</span>
2019-06-01 13:38:18 -05:00
</h3>
<div class="box-tools pull-right" v-if="transactions.length > 1" x>
<button type="button" v-on:click="deleteTransaction(index, $event)" class="btn btn-xs btn-danger"><i
2019-06-01 13:38:18 -05:00
class="fa fa-trash"></i></button>
</div>
</div>
<div class="box-body">
<div class="row">
<div class="col-lg-4">
2019-11-12 23:57:35 -06:00
<transaction-description v-if="transactionType.toLowerCase() !== 'reconciliation'"
v-model="transaction.description"
:index="index"
:error="transaction.errors.description"
2019-08-07 11:52:42 -05:00
>
</transaction-description>
2019-11-12 23:57:35 -06:00
<account-select v-if="transactionType.toLowerCase() !== 'reconciliation'"
2019-12-20 00:15:40 -06:00
inputName="source[]"
v-bind:title="$t('firefly.source_account')"
:accountName="transaction.source_account.name"
:accountTypeFilters="transaction.source_account.allowed_types"
:transactionType="transactionType"
:index="index"
v-on:clear:value="clearSource(index)"
v-on:select:account="selectedSourceAccount(index, $event)"
:error="transaction.errors.source_account"
2019-06-01 13:38:18 -05:00
></account-select>
2019-12-20 00:15:40 -06:00
<div class="form-group" v-if="transactionType.toLowerCase() === 'reconciliation'">
<div class="col-sm-12">
<p id="ffInput_source" class="form-control-static">
<em>
{{ $t('firefly.source_account_reconciliation') }}
2019-12-20 00:15:40 -06:00
</em>
</p>
</div>
</div>
2019-11-12 23:57:35 -06:00
<account-select v-if="transactionType.toLowerCase() !== 'reconciliation'"
2019-12-20 00:15:40 -06:00
inputName="destination[]"
v-bind:title="$t('firefly.destination_account')"
:accountName="transaction.destination_account.name"
:accountTypeFilters="transaction.destination_account.allowed_types"
:transactionType="transactionType"
:index="index"
v-on:clear:value="clearDestination(index)"
v-on:select:account="selectedDestinationAccount(index, $event)"
:error="transaction.errors.destination_account"
2019-06-01 13:38:18 -05:00
></account-select>
2019-12-20 00:15:40 -06:00
<div class="form-group" v-if="transactionType.toLowerCase() === 'reconciliation'">
<div class="col-sm-12">
<p id="ffInput_dest" class="form-control-static">
<em>
{{ $t('firefly.destination_account_reconciliation') }}
2019-12-20 00:15:40 -06:00
</em>
</p>
</div>
</div>
<standard-date
2019-06-01 13:38:18 -05:00
v-model="transaction.date"
:index="index"
:error="transaction.errors.date"
>
</standard-date>
<div v-if="index===0">
<transaction-type
:source="transaction.source_account.type"
:destination="transaction.destination_account.type"
v-on:set:transactionType="setTransactionType($event)"
v-on:act:limitSourceType="limitSourceType($event)"
v-on:act:limitDestinationType="limitDestinationType($event)"
></transaction-type>
</div>
</div>
<div class="col-lg-4">
2019-12-03 22:59:06 -06:00
<!-- -->
2019-06-01 13:38:18 -05:00
<amount
:source="transaction.source_account"
:destination="transaction.destination_account"
v-model="transaction.amount"
:error="transaction.errors.amount"
:transactionType="transactionType"
></amount>
2019-12-20 00:15:40 -06:00
<foreign-amount v-if="transactionType.toLowerCase() !== 'reconciliation'"
:source="transaction.source_account"
:destination="transaction.destination_account"
v-model="transaction.foreign_amount"
:transactionType="transactionType"
:error="transaction.errors.foreign_amount"
:no_currency="$t('firefly.none_in_select_list')"
v-bind:title="$t('form.foreign_amount')"
2019-06-01 13:38:18 -05:00
></foreign-amount>
</div>
<div class="col-lg-4">
<budget
:transactionType="transactionType"
v-model="transaction.budget"
:error="transaction.errors.budget_id"
:no_budget="$t('firefly.none_in_select_list')"
2019-06-01 13:38:18 -05:00
></budget>
<category
:transactionType="transactionType"
v-model="transaction.category"
:error="transaction.errors.category"
></category>
<tags
2020-01-03 04:30:21 -06:00
:transactionType="transactionType"
2019-08-11 00:29:05 -05:00
:tags="transaction.tags"
2019-06-01 13:38:18 -05:00
v-model="transaction.tags"
:error="transaction.errors.tags"
></tags>
<custom-transaction-fields
v-model="transaction.custom_fields"
:error="transaction.errors.custom_errors"
></custom-transaction-fields>
</div>
</div>
</div>
2019-11-12 23:57:35 -06:00
<div class="box-footer" v-if="transactions.length-1 === index && transactionType.toLowerCase() !== 'reconciliation'">
2020-02-14 00:49:29 -06:00
<button class="btn btn-default" type="button" @click="addTransaction">{{ $t('firefly.add_another_split') }}</button>
2019-06-01 13:38:18 -05:00
</div>
</div>
</div>
</div>
</div>
2020-03-13 00:22:50 -05:00
<div class="row" v-if="transactions.length > 1">
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">
{{ $t('firefly.split_transaction_title')}}
</h3>
</div>
<div class="box-body">
<group-description
:error="group_title_errors"
v-model="group_title"
></group-description>
</div>
</div>
</div>
</div>
2019-06-01 13:38:18 -05:00
<div class="row">
2020-03-13 00:22:50 -05:00
<div class="col-lg-6 col-md-6 col-sm-12 col-xs-12">
2019-06-01 13:38:18 -05:00
<div class="box">
<div class="box-header with-border">
<h3 class="box-title">
{{ $t('firefly.submission') }}
2019-06-01 13:38:18 -05:00
</h3>
</div>
<div class="box-body">
<div class="checkbox">
<label>
<input v-model="returnAfter" name="return_after" type="checkbox">
{{ $t('firefly.after_update_create_another') }}
2019-06-01 13:38:18 -05:00
</label>
</div>
2020-01-03 04:30:21 -06:00
<div class="checkbox" v-if="null !== transactionType && transactionType.toLowerCase() !== 'reconciliation'">
<label>
<input v-model="storeAsNew" name="store_as_new" type="checkbox">
{{ $t('firefly.store_as_new') }}
</label>
</div>
2019-06-01 13:38:18 -05:00
</div>
<div class="box-footer">
<div class="btn-group">
<button class="btn btn-success" @click="submit">{{ $t('firefly.update_transaction') }}</button>
2019-06-01 13:38:18 -05:00
</div>
</div>
</div>
</div>
</div>
</form>
</template>
<script>
export default {
name: "EditTransaction",
props: {
groupId: Number
},
mounted() {
this.getGroup();
},
ready() {
2019-09-06 09:29:52 -05:00
// console.log('Ready Group ID: ' + this.groupId);
2019-06-01 13:38:18 -05:00
},
methods: {
positiveAmount(amount) {
2019-06-01 13:38:18 -05:00
if (amount < 0) {
return amount * -1;
}
return amount;
},
2019-12-03 22:59:06 -06:00
roundNumber(amount, decimals) {
let multiplier = Math.pow(10, decimals);
return Math.round(amount * multiplier) / multiplier;
},
selectedSourceAccount(index, model) {
2019-06-01 13:38:18 -05:00
if (typeof model === 'string') {
// cant change types, only name.
// also clear ID
this.transactions[index].source_account.id = null;
2019-06-01 13:38:18 -05:00
this.transactions[index].source_account.name = model;
return;
2019-06-01 13:38:18 -05:00
}
this.transactions[index].source_account = {
id: model.id,
name: model.name,
type: model.type,
currency_id: model.currency_id,
currency_name: model.currency_name,
currency_code: model.currency_code,
currency_decimal_places: model.currency_decimal_places,
allowed_types: this.transactions[index].source_account.allowed_types
};
2019-06-01 13:38:18 -05:00
},
selectedDestinationAccount(index, model) {
2019-06-01 13:38:18 -05:00
if (typeof model === 'string') {
// cant change types, only name.
// also clear ID
this.transactions[index].destination_account.id = null;
2019-06-01 13:38:18 -05:00
this.transactions[index].destination_account.name = model;
return;
2019-06-01 13:38:18 -05:00
}
this.transactions[index].destination_account = {
id: model.id,
name: model.name,
type: model.type,
currency_id: model.currency_id,
currency_name: model.currency_name,
currency_code: model.currency_code,
currency_decimal_places: model.currency_decimal_places,
allowed_types: this.transactions[index].destination_account.allowed_types
};
2019-06-01 13:38:18 -05:00
},
clearSource(index) {
2019-06-01 13:38:18 -05:00
// reset source account:
this.transactions[index].source_account = {
id: 0,
name: '',
type: '',
currency_id: 0,
currency_name: '',
currency_code: '',
currency_decimal_places: 2,
allowed_types: this.transactions[index].source_account.allowed_types
};
// if there is a destination model, reset the types of the source
// by pretending we selected it again.
if (this.transactions[index].destination_account) {
this.selectedDestinationAccount(index, this.transactions[index].destination_account);
}
},
setTransactionType(type) {
if (null !== type) {
2020-01-03 04:30:21 -06:00
this.transactionType = type;
}
2019-06-01 13:38:18 -05:00
},
deleteTransaction(index, event) {
2019-06-01 13:38:18 -05:00
event.preventDefault();
for (const key in this.transactions) {
if (
this.transactions.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
// TODO empty iff?
2019-06-01 13:38:18 -05:00
}
}
this.transactions.splice(index, 1);
for (const key in this.transactions) {
if (
this.transactions.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
// TODO empty iff?
2019-06-01 13:38:18 -05:00
}
}
},
clearDestination(index) {
2019-09-06 09:29:52 -05:00
// console.log('clearDestination(' + index + ')');
2019-06-01 13:38:18 -05:00
// reset destination account:
2019-09-06 09:29:52 -05:00
// console.log('Destination allowed types first:');
// console.log(this.transactions[index].destination_account.allowed_types);
2019-06-01 13:38:18 -05:00
this.transactions[index].destination_account = {
id: 0,
name: '',
type: '',
currency_id: 0,
currency_name: '',
currency_code: '',
currency_decimal_places: 2,
allowed_types: this.transactions[index].destination_account.allowed_types
};
// reset destination allowed account types.
//this.transactions[index].source_account.allowed_types = [];
// if there is a source model, reset the types of the destination
// by pretending we selected it again.
if (this.transactions[index].source_account) {
this.selectedSourceAccount(index, this.transactions[index].source_account);
}
2019-09-06 09:29:52 -05:00
// console.log('Destination allowed types after:');
// console.log(this.transactions[index].destination_account.allowed_types);
2019-06-01 13:38:18 -05:00
},
getGroup() {
2019-06-01 13:38:18 -05:00
const page = window.location.href.split('/');
const groupId = page[page.length - 1];
const uri = './api/v1/transactions/' + groupId + '?_token=' + document.head.querySelector('meta[name="csrf-token"]').content;
2019-09-06 09:29:52 -05:00
// console.log(uri);
2019-06-01 13:38:18 -05:00
// fill in transactions array.
axios.get(uri)
.then(response => {
this.processIncomingGroup(response.data.data);
2019-06-01 13:38:18 -05:00
})
.catch(error => {
2019-09-06 09:29:52 -05:00
//console.error('Some error.');
2019-06-01 13:38:18 -05:00
});
},
processIncomingGroup(data) {
2019-09-06 09:29:52 -05:00
// console.log(data);
this.group_title = data.attributes.group_title;
let transactions = data.attributes.transactions.reverse();
for (let key in transactions) {
if (transactions.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
let transaction = transactions[key];
this.processIncomingGroupRow(transaction);
}
}
},
processIncomingGroupRow(transaction) {
2019-09-06 09:29:52 -05:00
// console.log(transaction);
2019-08-02 23:27:56 -05:00
this.setTransactionType(transaction.type);
2019-08-11 00:29:05 -05:00
let newTags = [];
for (let key in transaction.tags) {
2019-08-11 00:29:05 -05:00
if (transaction.tags.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
newTags.push({text: transaction.tags[key], tiClasses: []});
}
}
this.transactions.push({
2019-12-03 22:59:06 -06:00
transaction_journal_id: transaction.transaction_journal_id,
description: transaction.description,
date: transaction.date.substr(0, 10),
amount: this.roundNumber(this.positiveAmount(transaction.amount), transaction.currency_decimal_places),
category: transaction.category_name,
errors: {
source_account: [],
destination_account: [],
description: [],
amount: [],
date: [],
budget_id: [],
foreign_amount: [],
category: [],
piggy_bank: [],
tags: [],
// custom fields:
custom_errors: {
interest_date: [],
book_date: [],
process_date: [],
due_date: [],
payment_date: [],
invoice_date: [],
internal_reference: [],
notes: [],
attachments: [],
},
},
budget: transaction.budget_id,
tags: newTags,
custom_fields: {
interest_date: transaction.interest_date,
book_date: transaction.book_date,
process_date: transaction.process_date,
due_date: transaction.due_date,
payment_date: transaction.payment_date,
invoice_date: transaction.invoice_date,
internal_reference: transaction.internal_reference,
notes: transaction.notes
},
foreign_amount: {
amount: this.roundNumber(this.positiveAmount(transaction.foreign_amount), transaction.foreign_currency_decimal_places),
currency_id: transaction.foreign_currency_id
},
source_account: {
id: transaction.source_id,
name: transaction.source_name,
type: transaction.source_type,
currency_id: transaction.currency_id,
currency_name: transaction.currency_name,
currency_code: transaction.currency_code,
currency_decimal_places: transaction.currency_decimal_places,
allowed_types: [transaction.source_type]
},
destination_account: {
id: transaction.destination_id,
name: transaction.destination_name,
type: transaction.destination_type,
currency_id: transaction.currency_id,
currency_name: transaction.currency_name,
currency_code: transaction.currency_code,
currency_decimal_places: transaction.currency_decimal_places,
allowed_types: [transaction.destination_type]
}
});
},
2019-06-01 13:38:18 -05:00
convertData: function () {
let data = {
'transactions': [],
};
let transactionType;
let firstSource;
let firstDestination;
if (this.transactions.length > 1) {
data.group_title = this.group_title;
}
// get transaction type from first transaction
transactionType = this.transactionType ? this.transactionType.toLowerCase() : 'invalid';
// if the transaction type is invalid, might just be that we can deduce it from
// the presence of a source or destination account
firstSource = this.transactions[0].source_account.type;
firstDestination = this.transactions[0].destination_account.type;
if ('invalid' === transactionType && ['Asset account', 'Loan', 'Debt', 'Mortgage'].includes(firstSource)) {
//console.log('Assumed this is a withdrawal.');
transactionType = 'withdrawal';
}
if ('invalid' === transactionType && ['Asset account', 'Loan', 'Debt', 'Mortgage'].includes(firstDestination)) {
//console.log('Assumed this is a deposit.');
transactionType = 'deposit';
}
for (let key in this.transactions) {
if (this.transactions.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
data.transactions.push(this.convertDataRow(this.transactions[key], key, transactionType));
}
}
//console.log(data);
2019-06-01 13:38:18 -05:00
return data;
},
convertDataRow(row, index, transactionType) {
let tagList = [];
let foreignAmount = null;
let foreignCurrency = null;
let currentArray;
let sourceId;
let sourceName;
let destId;
let destName;
let date;
sourceId = row.source_account.id;
sourceName = row.source_account.name;
destId = row.destination_account.id;
destName = row.destination_account.name;
date = row.date;
if (index > 0) {
date = this.transactions[0].date;
}
2019-06-01 13:38:18 -05:00
// if type is 'withdrawal' and destination is empty, cash withdrawal.
if (transactionType === 'withdrawal' && '' === destName) {
destId = window.cashAccountId;
}
2019-06-01 13:38:18 -05:00
// if type is 'deposit' and source is empty, cash deposit.
if (transactionType === 'deposit' && '' === sourceName) {
sourceId = window.cashAccountId;
}
2019-06-01 13:38:18 -05:00
// if index is over 0 and type is withdrawal or transfer, take source from index 0.
if (index > 0 && (transactionType.toLowerCase() === 'withdrawal' || transactionType.toLowerCase() === 'transfer')) {
sourceId = this.transactions[0].source_account.id;
sourceName = this.transactions[0].source_account.name;
}
2019-06-01 13:38:18 -05:00
// if index is over 0 and type is deposit or transfer, take destination from index 0.
if (index > 0 && (transactionType.toLowerCase() === 'deposit' || transactionType.toLowerCase() === 'transfer')) {
destId = this.transactions[0].destination_account.id;
destName = this.transactions[0].destination_account.name;
}
2019-06-01 13:38:18 -05:00
tagList = [];
foreignAmount = null;
foreignCurrency = null;
// loop tags
for (let tagKey in row.tags) {
if (row.tags.hasOwnProperty(tagKey) && /^0$|^[1-9]\d*$/.test(tagKey) && tagKey <= 4294967294) {
tagList.push(row.tags[tagKey].text);
}
}
// set foreign currency info:
if (row.foreign_amount.amount !== '' && parseFloat(row.foreign_amount.amount) !== .00) {
foreignAmount = row.foreign_amount.amount;
foreignCurrency = row.foreign_amount.currency_id;
}
if (foreignCurrency === row.currency_id) {
foreignAmount = null;
foreignCurrency = null;
}
2019-06-01 13:38:18 -05:00
// correct some id's
if (0 === destId) {
destId = null;
}
if (0 === sourceId) {
sourceId = null;
}
currentArray =
{
2019-08-11 12:14:13 -05:00
transaction_journal_id: row.transaction_journal_id,
type: transactionType,
date: date,
amount: row.amount,
currency_id: row.currency_id,
2019-06-01 13:38:18 -05:00
description: row.description,
2019-06-01 13:38:18 -05:00
source_id: sourceId,
source_name: sourceName,
2019-06-01 13:38:18 -05:00
destination_id: destId,
destination_name: destName,
2019-06-01 13:38:18 -05:00
category_name: row.category,
2019-06-01 13:38:18 -05:00
interest_date: row.custom_fields.interest_date,
book_date: row.custom_fields.book_date,
process_date: row.custom_fields.process_date,
due_date: row.custom_fields.due_date,
payment_date: row.custom_fields.payment_date,
invoice_date: row.custom_fields.invoice_date,
internal_reference: row.custom_fields.internal_reference,
2019-09-13 23:14:33 -05:00
notes: row.custom_fields.notes,
tags: tagList
};
if (null !== foreignAmount) {
currentArray.foreign_amount = foreignAmount;
currentArray.foreign_currency_id = foreignCurrency;
}
// set budget id and piggy ID.
2019-09-01 07:49:26 -05:00
currentArray.budget_id = parseInt(row.budget);
if (parseInt(row.piggy_bank) > 0) {
currentArray.piggy_bank_id = parseInt(row.piggy_bank);
2019-06-01 13:38:18 -05:00
}
return currentArray;
2019-06-01 13:38:18 -05:00
},
submit: function (e) {
const page = window.location.href.split('/');
const groupId = page[page.length - 1];
let uri = './api/v1/transactions/' + groupId + '?_token=' + document.head.querySelector('meta[name="csrf-token"]').content;
let method = 'PUT';
if (this.storeAsNew) {
// other links.
uri = './api/v1/transactions?_token=' + document.head.querySelector('meta[name="csrf-token"]').content;
method = 'POST';
}
2019-06-01 13:38:18 -05:00
const data = this.convertData();
2020-02-13 13:09:59 -06:00
let button = $('#submitButton');
2019-06-01 13:38:18 -05:00
button.prop("disabled", true);
//axios.put(uri, data)
axios({
method: method,
url: uri,
data: data,
}).then(response => {
if (0 === this.collectAttachmentData(response)) {
this.redirectUser(response.data.data.id);
}
}).catch(error => {
2019-06-01 13:38:18 -05:00
// give user errors things back.
// something something render errors.
this.parseErrors(error.response.data);
// something.
});
if (e) {
e.preventDefault();
}
2020-02-13 13:09:59 -06:00
button.removeAttr('disabled');
2019-06-01 13:38:18 -05:00
},
redirectUser(groupId) {
if (this.returnAfter) {
this.setDefaultErrors();
// do message if update or new:
if (this.storeAsNew) {
this.success_message = '<a href="transactions/show/' + groupId + '">Transaction #' + groupId + '</a> has been created.';
this.error_message = '';
} else {
this.success_message = '<a href="transactions/show/' + groupId + '">The transaction</a> has been updated.';
this.error_message = '';
}
} else {
if (this.storeAsNew) {
window.location.href = window.previousUri + '?transaction_group_id=' + groupId + '&message=created';
} else {
window.location.href = window.previousUri + '?transaction_group_id=' + groupId + '&message=updated';
}
}
},
collectAttachmentData(response) {
2019-09-06 09:29:52 -05:00
// console.log('Now incollectAttachmentData()');
let groupId = response.data.data.id;
// array of all files to be uploaded:
let toBeUploaded = [];
// array with all file data.
let fileData = [];
// all attachments
let attachments = $('input[name="attachments[]"]');
// loop over all attachments, and add references to this array:
for (const key in attachments) {
if (attachments.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
for (const fileKey in attachments[key].files) {
if (attachments[key].files.hasOwnProperty(fileKey) && /^0$|^[1-9]\d*$/.test(fileKey) && fileKey <= 4294967294) {
// include journal thing.
2019-09-11 23:47:04 -05:00
let transactions = response.data.data.attributes.transactions.reverse();
toBeUploaded.push(
{
2019-09-11 23:47:04 -05:00
journal: transactions[key].transaction_journal_id,
file: attachments[key].files[fileKey]
}
);
}
}
}
}
let count = toBeUploaded.length;
2019-09-06 09:29:52 -05:00
// console.log('Found ' + toBeUploaded.length + ' attachments.');
// loop all uploads.
for (const key in toBeUploaded) {
if (toBeUploaded.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
// create file reader thing that will read all of these uploads
(function (f, i, theParent) {
let fileReader = new FileReader();
fileReader.onloadend = function (evt) {
if (evt.target.readyState === FileReader.DONE) { // DONE == 2
fileData.push(
{
name: toBeUploaded[key].file.name,
journal: toBeUploaded[key].journal,
content: new Blob([evt.target.result])
}
);
if (fileData.length === count) {
theParent.uploadFiles(fileData, groupId);
}
}
};
fileReader.readAsArrayBuffer(f.file);
})(toBeUploaded[key], key, this);
}
}
return count;
},
uploadFiles(fileData, groupId) {
let count = fileData.length;
let uploads = 0;
for (const key in fileData) {
if (fileData.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
2019-09-06 09:29:52 -05:00
// console.log('Creating attachment #' + key);
// axios thing, + then.
const uri = './api/v1/attachments';
const data = {
filename: fileData[key].name,
attachable_type: 'TransactionJournal',
attachable_id: fileData[key].journal,
};
axios.post(uri, data)
.then(response => {
2019-09-06 09:29:52 -05:00
// console.log('Created attachment #' + key);
// console.log('Uploading attachment #' + key);
const uploadUri = './api/v1/attachments/' + response.data.data.id + '/upload';
axios.post(uploadUri, fileData[key].content)
.then(response => {
2019-09-06 09:29:52 -05:00
// console.log('Uploaded attachment #' + key);
uploads++;
if (uploads === count) {
// finally we can redirect the user onwards.
2019-09-06 09:29:52 -05:00
// console.log('FINAL UPLOAD');
this.redirectUser(groupId, null);
}
2019-09-06 09:29:52 -05:00
// console.log('Upload complete!');
return true;
}).catch(error => {
console.error('Could not upload file.');
console.error(error);
uploads++;
this.error_message = 'Could not upload attachment: ' + error;
2019-10-20 09:17:43 -05:00
if (uploads === count) {
this.redirectUser(groupId, null);
2019-10-20 09:17:43 -05:00
}
2019-09-06 09:29:52 -05:00
// console.error(error);
return false;
});
});
}
}
},
2019-06-01 13:38:18 -05:00
addTransaction: function (e) {
this.transactions.push({
transaction_journal_id: 0,
description: "",
date: "",
amount: "",
category: "",
piggy_bank: 0,
errors: {
source_account: [],
destination_account: [],
description: [],
amount: [],
date: [],
budget_id: [],
foreign_amount: [],
category: [],
piggy_bank: [],
tags: [],
// custom fields:
custom_errors: {
interest_date: [],
book_date: [],
process_date: [],
due_date: [],
payment_date: [],
invoice_date: [],
internal_reference: [],
notes: [],
attachments: [],
},
},
budget: 0,
tags: [],
custom_fields: {
"interest_date": "",
"book_date": "",
"process_date": "",
"due_date": "",
"payment_date": "",
"invoice_date": "",
"internal_reference": "",
"notes": "",
"attachments": []
},
foreign_amount: {
amount: "",
currency_id: 0
},
source_account: {
id: 0,
name: "",
type: "",
currency_id: 0,
currency_name: '',
currency_code: '',
currency_decimal_places: 2,
allowed_types: []
},
destination_account: {
id: 0,
name: "",
type: "",
currency_id: 0,
currency_name: '',
currency_code: '',
currency_decimal_places: 2,
allowed_types: []
}
});
2019-06-01 13:38:18 -05:00
if (e) {
e.preventDefault();
}
},
parseErrors: function (errors) {
this.setDefaultErrors();
this.error_message = "";
if (errors.message.length > 0) {
2019-10-05 09:43:24 -05:00
this.error_message = this.$t('firefly.errors_submission');
} else {
this.error_message = '';
}
let transactionIndex;
let fieldName;
for (const key in errors.errors) {
if (errors.errors.hasOwnProperty(key)) {
if (key === 'group_title') {
this.group_title_errors = errors.errors[key];
}
if (key !== 'group_title') {
// lol dumbest way to explode "transactions.0.something" ever.
transactionIndex = parseInt(key.split('.')[1]);
fieldName = key.split('.')[2];
// set error in this object thing.
switch (fieldName) {
case 'amount':
case 'date':
case 'budget_id':
case 'description':
case 'tags':
this.transactions[transactionIndex].errors[fieldName] = errors.errors[key];
break;
case 'source_name':
case 'source_id':
this.transactions[transactionIndex].errors.source_account =
this.transactions[transactionIndex].errors.source_account.concat(errors.errors[key]);
break;
case 'destination_name':
case 'destination_id':
this.transactions[transactionIndex].errors.destination_account =
this.transactions[transactionIndex].errors.destination_account.concat(errors.errors[key]);
break;
case 'foreign_amount':
case 'foreign_currency_id':
this.transactions[transactionIndex].errors.foreign_amount =
this.transactions[transactionIndex].errors.foreign_amount.concat(errors.errors[key]);
break;
}
2019-08-27 00:51:34 -05:00
2019-09-11 23:47:04 -05:00
// unique some things
this.transactions[transactionIndex].errors.source_account =
Array.from(new Set(this.transactions[transactionIndex].errors.source_account));
this.transactions[transactionIndex].errors.destination_account =
Array.from(new Set(this.transactions[transactionIndex].errors.destination_account));
}
}
}
},
setDefaultErrors: function () {
for (const key in this.transactions) {
if (this.transactions.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
this.transactions[key].errors = {
source_account: [],
destination_account: [],
description: [],
amount: [],
date: [],
budget_id: [],
foreign_amount: [],
category: [],
piggy_bank: [],
tags: [],
// custom fields:
custom_errors: {
interest_date: [],
book_date: [],
process_date: [],
due_date: [],
payment_date: [],
invoice_date: [],
internal_reference: [],
notes: [],
attachments: [],
},
};
}
}
},
2019-06-01 13:38:18 -05:00
},
data() {
return {
group: this.groupId,
error_message: "",
success_message: "",
transactions: [],
group_title: "",
returnAfter: false,
storeAsNew: false,
2019-06-01 13:38:18 -05:00
transactionType: null,
group_title_errors: [],
resetButtonDisabled: true,
}
}
}
</script>
<style scoped>
</style>