akaunting/resources/assets/js/components/AkauntingConnectTransactions.vue

476 lines
24 KiB
Vue
Raw Normal View History

2022-06-01 10:15:55 +03:00
<template>
<SlideYUpTransition :duration="animationDuration">
<div class="modal w-full h-full fixed top-0 left-0 right-0 z-50 overflow-y-auto overflow-hidden modal-add-new fade items-center justify-center"
:class="[{'show flex flex-wrap modal-background': show}, {'hidden': !show}]"
v-show="show"
tabindex="-1"
role="dialog"
:aria-hidden="!show">
<div class="w-full my-10 m-auto flex flex-col" :class="modalDialogClass ? modalDialogClass : 'max-w-screen-sm'">
<slot name="modal-content">
2022-11-25 15:20:18 +03:00
<div class="bg-body rounded-lg modal-content">
<div class="p-5">
2022-06-01 10:15:55 +03:00
<div class="flex items-center justify-between border-b pb-5">
<slot name="card-header">
<h4 class="text-base font-medium">
{{ translations.title }}
</h4>
<button type="button" class="text-lg" @click="onCancel" aria-hidden="true">
<span class="rounded-md border-b-2 px-2 py-1 text-sm bg-gray-100">esc</span>
</button>
</slot>
</div>
</div>
<slot name="modal-body">
2022-11-25 15:20:18 +03:00
<div class="px-5">
2022-06-01 10:15:55 +03:00
<template v-if="transaction">
<div class="flex flex-col items-start gap-y-3">
<div class="text-left text-sm">
<div class="font-medium">
{{ translations.contact }}
</div>
<span>
{{ transaction.contact.name }}
</span>
</div>
<div class="text-left text-sm">
<div class="font-medium">
{{ translations.category }}
</div>
<span>
{{ transaction.category.name }}
</span>
</div>
<div class="text-left text-sm">
<div class="font-medium">
{{ translations.account }}
</div>
<span>
{{ transaction.account.name }}
</span>
</div>
</div>
</template>
2022-06-01 14:27:59 +03:00
<div class="relative sm:col-span-6 pt-3">
2022-06-01 10:15:55 +03:00
<div style="table-layout: fixed;">
<div class="overflow-x-visible overflow-y-hidden">
<table class="w-full" id="items" style="table-layout: fixed">
<thead class="border-b">
<tr>
<th colspan="3" class="w-12/12 px-0 text-left border-t-0 border-r-0 border-b-0">
{{ translations.document }}
</th>
</tr>
</thead>
<colgroup>
<col style="width: 20%;">
<col style="width: 80%;">
</colgroup>
<tbody>
<tr v-for="(row, index) in form.items" :index="index" class="border-b border-gray-200">
<td class="px-0 border-r-0 border-b-0 truncate">
<div class="text-sm">
<div class="truncate">
<b>{{ translations.number }}:</b> {{ row.number }}
</div>
<div class="truncate" v-if="row.notes">
<b>{{ translations.notes }}:</b> {{ row.notes }}
</div>
</div>
<div class="row" style="font-size: 13px;">
<div class="col-md-12 long-texts">
<b>{{ translations.contact }}:</b> {{ row.contact }}
</div>
</div>
</td>
<td class="px-0 border-l-0 border-b-0 border-r-0">
<div class="flex items-center justify-end">
<akaunting-money
:col="''"
:masked="true"
name="amount"
title=""
:currency="currency"
:dynamic-currency="currency"
:value="row.amount"
:row-input="true"
:money-class="'text-right input-price'"
@input="checkAmount(index, $event)"
></akaunting-money>
<akaunting-money
class="hidden"
:masked="true"
name="max_amount"
title=""
:group_class="null"
:currency="currency"
v-model="row.max_amount"
:dynamic-currency="currency"
:row-input="true"
:disabled="true"
></akaunting-money>
<div class="pl-2 group">
<button type="button" @click="onDeleteItem(index)" class="w-6 h-7 flex items-center rounded-lg p-0 group-hover:bg-gray-100">
<span class="w-full material-icons-outlined text-lg text-gray-300 group-hover:text-gray-500">delete</span>
</button>
</div>
</div>
</td>
</tr>
<tr id="addItem">
<td colspan="3" class="w-12/12 p-0">
<akaunting-document-button
:items="documents"
:selectedItems="form.items"
:dynamic-currency="currency"
@document-selected="onAddItem($event)"
:no-data-text="translations.no_data"
:placeholder="translations.placeholder_search"
:add-item-text="translations.add_an"
></akaunting-document-button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="sm:col-span-6">
<div class="overflow-y-hidden py-5">
<table id="totals" class="float-right">
<colgroup>
<col style="width: 51.5%;">
<col style="width: 30%;">
<col style="width: 18.5%;">
</colgroup>
<tbody id="document-total-rows">
<tr id="tr-total">
<td class="border-t-0 p-0"></td>
<td class="font-medium text-sm text-right border-r-0 border-b-0 align-middle py-0 pr-0">
{{ translations.total }}
</td>
<td class="text-sm text-right border-b-0 p-0">
<div>
<money
2022-06-06 18:05:10 +03:00
name="total_amount"
2022-06-01 10:15:55 +03:00
:value="total_amount"
v-bind="money"
masked
disabled
class="px-0 disabled-money text-right banking-price-text"
style="height: unset;"
></money>
</div>
</td>
</tr>
<tr id="tr-transaction-amount">
<td class="border-t-0 p-0"></td>
<td class="font-medium text-sm text-right border-r-0 border-b-0 align-middle py-0 pr-0">
{{ translations.transaction + ' ' + translations.amount }}
</td>
<td class="text-sm text-right border-b-0 p-0">
<div>
<money
:name="'transaction_amount'"
:value="transaction.amount"
v-bind="money"
masked
disabled
class="px-0 disabled-money text-right banking-price-text"
style="height: unset;"
v-if="transaction"
></money>
</div>
<akaunting-money
class="hidden"
:masked="true"
name="transaction_amount"
title=""
:group_class="null"
:currency="currency"
:value="transaction_amount"
@input="transaction_amount = $event"
:dynamic-currency="currency"
:row-input="true"
:disabled="true"
></akaunting-money>
</td>
</tr>
<tr id="tr-difference">
<td class="border-t-0 p-0"></td>
<td class="font-medium text-sm text-right border-r-0 border-b-0 align-middle py-0 pr-0">
{{ translations.difference }}
</td>
<td class="text-right text-sm border-b-0 p-0">
<div>
<money
2022-06-06 18:05:10 +03:00
name="difference_amount"
2022-06-01 10:15:55 +03:00
:value="difference_amount"
v-bind="money"
masked
disabled
class="px-0 disabled-money text-right banking-price-text"
style="height: unset;"
></money>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</slot>
2022-11-25 15:20:18 +03:00
<div class="p-5 border-gray-300">
2022-06-01 10:15:55 +03:00
<slot name="card-footer">
<div class="flex items-center justify-end">
<button type="button" class="px-6 py-1.5 mr-2 hover:bg-gray-200 rounded-lg" @click="onCancel">
{{ translations.cancel }}
</button>
<button type="button"
2022-06-06 18:05:10 +03:00
:disabled="differenceAmount != 0 || (differenceAmount == 0 && form.loading)"
2022-06-01 10:15:55 +03:00
class="relative px-6 py-1.5 bg-green hover:bg-green-700 text-white rounded-lg disabled:bg-green-100"
@click="onConfirm"
>
<i
v-if="form.loading"
class="animate-submit delay-[0.28s] absolute w-2 h-2 rounded-full left-0 right-0 -top-3.5 m-auto before:absolute before:w-2 before:h-2 before:rounded-full before:animate-submit before:delay-[0.14s] after:absolute after:w-2 after:h-2 after:rounded-full after:animate-submit before:-left-3.5 after:-right-3.5 after:delay-[0.42s]"
>
</i>
2022-06-06 18:05:10 +03:00
<span :class="[{'opacity-0': differenceAmount != 0}]">{{ translations.save }}</span>
2022-06-01 10:15:55 +03:00
</button>
</div>
</slot>
</div>
</div>
</slot>
</div>
</div>
</SlideYUpTransition>
</template>
<script>
import { SlideYUpTransition } from "vue2-transitions";
import AkauntingSelect from './AkauntingSelect';
import AkauntingMoney from './AkauntingMoney';
import AkauntingDocumentButton from './AkauntingDocumentButton';
import {Money} from 'v-money';
export default {
name: 'akaunting-connect-transactions',
components: {
SlideYUpTransition,
AkauntingSelect,
AkauntingMoney,
AkauntingDocumentButton,
Money,
},
props: {
show: Boolean,
transaction: Object,
currency: Object,
documents: Array,
translations: Object,
modalDialogClass: {
type: String,
default: '',
description: "Modal Body size Class"
},
animationDuration: {
type: Number,
default: 800,
description: "Modal transition duration"
},
},
data() {
return {
form: {
items: [],
loading: false,
},
transaction_amount: "",
money: {},
2022-06-06 18:05:10 +03:00
totalAmount: 0,
differenceAmount: 0,
2022-06-01 10:15:55 +03:00
};
},
2022-06-06 18:05:10 +03:00
created() {
this.totalAmount = this.total_amount;
this.differenceAmount = this.difference_amount;
},
computed: {
total_amount: function () {
let amount = 0;
this.form.items.forEach(function(item) {
amount += this.convertMoneyToFloat(item.amount);
}, this);
this.totalAmount = parseFloat(amount.toFixed(this.currency.precision));
return parseFloat(amount.toFixed(this.currency.precision));
},
difference_amount: function () {
if (! this.transaction_amount) {
this.differenceAmount = 0;
return 0;
}
let transaction_amount = this.convertMoneyToFloat(this.transaction_amount);
let amount = parseFloat((this.total_amount - transaction_amount).toFixed(this.currency.precision));
this.differenceAmount = amount;
return amount;
}
},
2022-06-01 10:15:55 +03:00
mounted() {
window.addEventListener('keyup',(e) => {
if (e.key === 'Escape') {
this.onCancel();
}
});
},
methods: {
onConfirm() {
this.form.loading = true;
this.$emit("confirm");
this.onConnectTransaction();
},
onCancel() {
this.$emit('close-modal');
},
onAddItem(document) {
this.form.items.push(
Object.assign({}, {
id: document.id,
document_id: document.id,
number: document.document_number,
contact: document.contact_name,
notes: document.notes,
amount: (document.amount - document.paid).toFixed(this.currency.precision),
max_amount: (document.amount - document.paid).toFixed(this.currency.precision),
})
);
},
onDeleteItem(index) {
this.form.items.splice(index, 1);
},
async onConnectTransaction() {
let self = this;
let connect_transaction = Promise.resolve(window.axios.post(url + '/banking/transactions/' + this.transaction.id + '/connect', {
data: {
items: this.form.items
}
}));
connect_transaction.then(response => {
if (response.data.redirect) {
window.location.href = response.data.redirect;
}
})
.catch(error => {
})
.finally(function () {
self.$emit("close-modal");
});
},
convertMoneyToFloat(money) {
// "$198.4"
if (typeof(money) != "string") {
money = money.toString();
}
// 198.4
let regex = new RegExp(this.currency.thousands_separator, 'gi');
money = money.replace(this.currency.symbol, '').replace(regex, '').replace(this.currency.decimal_mark, '.');
2022-06-01 10:15:55 +03:00
// "198.40"
money = parseFloat(money).toFixed(this.currency.precision);
// 198.40
return parseFloat(money);
},
checkAmount(index, amount) {
let max_amount = this.convertMoneyToFloat(this.form.items[index].max_amount);
let changed_amount = this.convertMoneyToFloat(amount);
this.form.items[index].amount = changed_amount.toFixed(this.currency.precision);
setTimeout(function () {
if (changed_amount > max_amount || changed_amount == 0) {
this.form.items[index].amount = max_amount.toFixed(this.currency.precision);
}
}.bind(this), 50);
}
},
watch: {
show: function (newValue) {
if (newValue) {
this.form.items = [];
}
},
2022-06-06 18:05:10 +03:00
2022-06-01 10:15:55 +03:00
transaction: function (transaction) {
this.transaction_amount = transaction.amount;
},
2022-06-06 18:05:10 +03:00
2022-06-01 10:15:55 +03:00
currency: function (currency) {
this.money = {
decimal: currency.decimal_mark,
thousands: currency.thousands_separator,
prefix: (currency.symbol_first) ? currency.symbol : '',
suffix: (!currency.symbol_first) ? currency.symbol : '',
precision: parseInt(currency.precision),
};
}
},
}
</script>