salix-front/src/pages/InvoiceIn/Card/InvoiceInSummary.vue

423 lines
14 KiB
Vue

<script setup>
import { onMounted, ref, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { toCurrency, toDate } from 'src/filters';
import { getUrl } from 'src/composables/getUrl';
import CardSummary from 'components/ui/CardSummary.vue';
import VnLv from 'src/components/ui/VnLv.vue';
import VnTitle from 'src/components/common/VnTitle.vue';
onMounted(async () => {
salixUrl.value = await getUrl('');
invoiceInUrl.value = salixUrl.value + `invoiceIn/${entityId.value}/`;
});
const route = useRoute();
const { t } = useI18n();
const $props = defineProps({
id: {
type: Number,
default: 0,
},
});
const entityId = computed(() => $props.id || route.params.id);
const salixUrl = ref();
const invoiceInUrl = ref();
const amountsNotMatch = ref(null);
const intrastatTotals = ref({});
const vatColumns = ref([
{
name: 'expense',
label: 'invoiceIn.summary.expense',
field: (row) => row.expenseFk,
sortable: true,
align: 'left',
},
{
name: 'landed',
label: 'invoiceIn.summary.taxableBase',
field: (row) => row.taxableBase,
format: (value) => toCurrency(value),
sortable: true,
align: 'left',
},
{
name: 'vat',
label: 'invoiceIn.summary.sageVat',
field: (row) => row.taxTypeSage?.vat,
format: (value) => value,
sortable: true,
align: 'left',
},
{
name: 'transaction',
label: 'invoiceIn.summary.sageTransaction',
field: (row) => row.transactionTypeSage?.transaction,
format: (value) => value,
sortable: true,
align: 'left',
},
{
name: 'rate',
label: 'invoiceIn.summary.rate',
field: (row) => taxRate(row.taxableBase, row.taxTypeSage?.rate),
format: (value) => toCurrency(value),
sortable: true,
align: 'left',
},
{
name: 'currency',
label: 'invoiceIn.summary.currency',
field: (row) => row.foreignValue,
format: (value) => value,
sortable: true,
align: 'left',
},
]);
const dueDayColumns = ref([
{
name: 'date',
label: 'invoiceIn.summary.dueDay',
field: (row) => toDate(row.dueDated),
sortable: true,
align: 'left',
},
{
name: 'bank',
label: 'invoiceIn.summary.bank',
field: (row) => row.bank.bank,
sortable: true,
align: 'left',
},
{
name: 'amount',
label: 'invoiceIn.summary.amount',
field: (row) => row.amount,
format: (value) => toCurrency(value),
sortable: true,
align: 'left',
},
{
name: 'landed',
label: 'invoiceIn.summary.foreignValue',
field: (row) => row.foreignValue,
format: (value) => value,
sortable: true,
align: 'left',
},
]);
const intrastatColumns = ref([
{
name: 'code',
label: 'invoiceIn.summary.code',
field: (row) => {
return `${row.intrastat.id}: ${row.intrastat?.description}`;
},
sortable: true,
align: 'left',
},
{
name: 'amount',
label: 'invoiceIn.summary.amount',
field: (row) => toCurrency(row.amount),
sortable: true,
align: 'left',
},
{
name: 'net',
label: 'invoiceIn.summary.net',
field: (row) => row.net,
sortable: true,
align: 'left',
},
{
name: 'stems',
label: 'invoiceIn.summary.stems',
field: (row) => row.stems,
format: (value) => value,
sortable: true,
align: 'left',
},
{
name: 'landed',
label: 'invoiceIn.summary.country',
field: (row) => row.country?.code,
format: (value) => value,
sortable: true,
align: 'left',
},
]);
function getAmountNotMatch(totals) {
return (
totals.totalDueDay != totals.totalTaxableBase &&
totals.totalDueDay != totals.totalVat
);
}
function getIntrastatTotals(intrastat) {
const totals = {
amount: intrastat.reduce((acc, cur) => acc + cur.amount, 0),
net: intrastat.reduce((acc, cur) => acc + cur.net, 0),
stems: intrastat.reduce((acc, cur) => acc + cur.stems, 0),
};
return totals;
}
function getTaxTotal(tax) {
return tax.reduce(
(acc, cur) => acc + taxRate(cur.taxableBase, cur.taxTypeSage?.rate),
0
);
}
function setData(entity) {
if (!entity) return false;
amountsNotMatch.value = getAmountNotMatch(entity.totals);
if (entity.invoiceInIntrastat.length)
intrastatTotals.value = { ...getIntrastatTotals(entity.invoiceInIntrastat) };
}
function taxRate(taxableBase = 0, rate = 0) {
return (rate / 100) * taxableBase;
}
function getLink(param) {
return `#/invoice-in/${entityId.value}/${param}`;
}
</script>
<template>
<CardSummary
data-key="InvoiceInSummary"
:url="`InvoiceIns/${entityId}/summary`"
@on-fetch="(data) => setData(data)"
>
<template #header="{ entity: invoiceIn }">
<div>{{ invoiceIn.id }} - {{ invoiceIn.supplier?.name }}</div>
</template>
<template #body="{ entity: invoiceIn }">
<!--Basic Data-->
<QCard class="vn-one">
<QCardSection class="q-pa-none">
<VnTitle
:url="getLink('basic-data')"
:text="t('invoiceIn.pageTitles.basicData')"
/>
</QCardSection>
<VnLv
:label="t('invoiceIn.summary.supplier')"
:value="invoiceIn.supplier?.name"
/>
<VnLv
:label="t('invoiceIn.summary.supplierRef')"
:value="invoiceIn.supplierRef"
/>
<VnLv
:label="t('invoiceIn.summary.currency')"
:value="invoiceIn.currency?.code"
/>
<VnLv
:label="t('invoiceIn.summary.docNumber')"
:value="`${invoiceIn.serial}/${invoiceIn.serialNumber}`"
/>
</QCard>
<QCard class="vn-one">
<QCardSection class="q-pa-none">
<VnTitle
:url="getLink('basic-data')"
:text="t('invoiceIn.pageTitles.basicData')"
/>
</QCardSection>
<VnLv
:ellipsis-value="false"
:label="t('invoiceIn.summary.issued')"
:value="toDate(invoiceIn.issued)"
/>
<VnLv
:label="t('invoiceIn.summary.operated')"
:value="toDate(invoiceIn.operated)"
/>
<VnLv
:label="t('invoiceIn.summary.bookEntried')"
:value="toDate(invoiceIn.bookEntried)"
/>
<VnLv
:label="t('invoiceIn.summary.bookedDate')"
:value="toDate(invoiceIn.booked)"
/>
</QCard>
<QCard class="vn-one">
<QCardSection class="q-pa-none">
<VnTitle
:url="getLink('basic-data')"
:text="t('invoiceIn.pageTitles.basicData')"
/>
</QCardSection>
<VnLv
:label="t('invoiceIn.summary.sage')"
:value="invoiceIn.sageWithholding?.withholding"
/>
<VnLv
:label="t('invoiceIn.summary.vat')"
:value="invoiceIn.expenseDeductible?.name"
/>
<VnLv
:label="t('invoiceIn.summary.company')"
:value="invoiceIn.company?.code"
/>
<QCheckbox
:label="t('invoiceIn.summary.booked')"
v-model="invoiceIn.isBooked"
:disable="true"
/>
</QCard>
<QCard class="vn-one">
<QCardSection class="q-pa-none">
<VnTitle
:url="getLink('basic-data')"
:text="t('invoiceIn.pageTitles.basicData')"
/>
</QCardSection>
<QCardSection class="q-pa-none">
<div class="bordered q-px-sm q-mx-auto">
<VnLv
:label="t('invoiceIn.summary.taxableBase')"
:value="toCurrency(invoiceIn.totals.totalTaxableBase)"
/>
<VnLv
label="Total"
:value="toCurrency(invoiceIn.totals.totalVat)"
/>
<VnLv :label="t('invoiceIn.summary.dueTotal')">
<template #value>
<QChip
dense
class="q-pa-xs"
:color="amountsNotMatch ? 'negative' : 'transparent'"
:title="
amountsNotMatch
? t('invoiceIn.summary.noMatch')
: t('invoiceIn.summary.dueTotal')
"
>
{{ toCurrency(invoiceIn.totals.totalDueDay) }}
</QChip>
</template>
</VnLv>
</div>
</QCardSection>
</QCard>
<!--Vat-->
<QCard v-if="invoiceIn.invoiceInTax.length">
<VnTitle :url="getLink('vat')" :text="t('invoiceIn.card.vat')" />
<QTable
:columns="vatColumns"
:rows="invoiceIn.invoiceInTax"
flat
hide-pagination
>
<template #header="props">
<QTr :props="props" class="bg">
<QTh v-for="col in props.cols" :key="col.name" :props="props">
{{ t(col.label) }}
</QTh>
</QTr>
</template>
<template #bottom-row>
<QTr class="bg">
<QTd></QTd>
<QTd>{{ toCurrency(invoiceIn.totals.totalTaxableBase) }}</QTd>
<QTd></QTd>
<QTd></QTd>
<QTd>{{
toCurrency(getTaxTotal(invoiceIn.invoiceInTax))
}}</QTd>
<QTd></QTd>
</QTr>
</template>
</QTable>
</QCard>
<!--Due Day-->
<QCard v-if="invoiceIn.invoiceInDueDay.length">
<VnTitle :url="getLink('due-day')" :text="t('invoiceIn.card.dueDay')" />
<QTable
class="full-width"
:columns="dueDayColumns"
:rows="invoiceIn.invoiceInDueDay"
flat
>
<template #header="props">
<QTr :props="props" class="bg">
<QTh v-for="col in props.cols" :key="col.name" :props="props">
{{ t(col.label) }}
</QTh>
</QTr>
</template>
<template #bottom-row>
<QTr class="bg">
<QTd></QTd>
<QTd></QTd>
<QTd>{{ toCurrency(invoiceIn.totals.totalDueDay) }}</QTd>
<QTd></QTd>
</QTr>
</template>
</QTable>
</QCard>
<!--Intrastat-->
<QCard v-if="invoiceIn.invoiceInIntrastat.length">
<VnTitle
:url="getLink('intrastat')"
:text="t('invoiceIn.card.intrastat')"
/>
<QTable
:columns="intrastatColumns"
:rows="invoiceIn.invoiceInIntrastat"
flat
>
<template #header="props">
<QTr :props="props" class="bg">
<QTh v-for="col in props.cols" :key="col.name" :props="props">
{{ t(col.label) }}
</QTh>
</QTr>
</template>
<template #bottom-row>
<QTr class="bg">
<QTd></QTd>
<QTd>{{ toCurrency(intrastatTotals.amount) }}</QTd>
<QTd>{{ intrastatTotals.net }}</QTd>
<QTd>{{ intrastatTotals.stems }}</QTd>
<QTd></QTd>
</QTr>
</template>
</QTable>
</QCard>
</template>
</CardSummary>
</template>
<style lang="scss" scoped>
.bg {
background-color: var(--vn-accent-color);
}
.bordered {
border: 1px solid var(--vn-text-color);
max-width: 18em;
}
</style>
<i18n>
es:
Search invoice: Buscar factura recibida
You can search by invoice reference: Puedes buscar por referencia de la factura
</i18n>