322 lines
11 KiB
Vue
322 lines
11 KiB
Vue
<script setup>
|
|
import { ref, computed, toRefs, reactive } from 'vue';
|
|
import { useRouter } from 'vue-router';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { useQuasar } from 'quasar';
|
|
import axios from 'axios';
|
|
import { useAcl } from 'src/composables/useAcl';
|
|
import { downloadFile } from 'src/composables/downloadFile';
|
|
import { useArrayData } from 'src/composables/useArrayData';
|
|
import { usePrintService } from 'composables/usePrintService';
|
|
import { useCapitalize } from 'src/composables/useCapitalize';
|
|
import VnConfirm from 'src/components/ui/VnConfirm.vue';
|
|
import SendEmailDialog from 'components/common/SendEmailDialog.vue';
|
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
|
import InvoiceInToBook from '../InvoiceInToBook.vue';
|
|
import FetchData from 'src/components/FetchData.vue';
|
|
|
|
const { hasAny } = useAcl();
|
|
const { t } = useI18n();
|
|
const { openReport, sendEmail } = usePrintService();
|
|
const { push, currentRoute } = useRouter();
|
|
const $props = defineProps({
|
|
invoice: {
|
|
type: Object,
|
|
required: true,
|
|
},
|
|
});
|
|
const { invoice } = toRefs($props);
|
|
const quasar = useQuasar();
|
|
const arrayData = useArrayData();
|
|
const currentAction = ref();
|
|
const config = ref();
|
|
const correctionDialogRef = ref();
|
|
const invoiceInCorrection = reactive({ correcting: [], corrected: null });
|
|
const entityId = computed(() => $props.invoice.id || +currentRoute.value.params.id);
|
|
const invoiceIn = computed(() => arrayData.store.data);
|
|
const isNotFilled = computed(() => Object.values(correctionFormData).includes(null));
|
|
const invoiceCorrectionTypes = ref([]);
|
|
const cplusRectificationTypes = ref([]);
|
|
const siiTypeInvoiceIns = ref([]);
|
|
const actions = {
|
|
unbook: {
|
|
title: t('assertAction', { action: t('invoicein.descriptorMenu.unbook') }),
|
|
action: toUnbook,
|
|
},
|
|
delete: {
|
|
title: t('assertAction', { action: t('invoicein.descriptorMenu.delete') }),
|
|
action: deleteInvoice,
|
|
},
|
|
clone: {
|
|
title: t('assertAction', { action: t('invoicein.descriptorMenu.clone') }),
|
|
action: cloneInvoice,
|
|
},
|
|
showPdf: { cb: showPdfInvoice },
|
|
sendPdf: { cb: sendPdfInvoiceConfirmation },
|
|
correct: { cb: () => correctionDialogRef.value.show() },
|
|
};
|
|
const correctionFormData = reactive({
|
|
invoiceReason: 2,
|
|
invoiceType: 2,
|
|
invoiceClass: 8,
|
|
});
|
|
const canEditProp = (props) =>
|
|
hasAny([{ model: 'InvoiceIn', props, accessType: 'WRITE' }]);
|
|
|
|
function triggerMenu(type) {
|
|
currentAction.value = actions[type];
|
|
if (currentAction.value.cb) currentAction.value.cb();
|
|
else openDialog(type);
|
|
}
|
|
|
|
function openDialog() {
|
|
quasar.dialog({
|
|
component: VnConfirm,
|
|
componentProps: {
|
|
title: t(currentAction.value.title),
|
|
promise: currentAction.value.action,
|
|
},
|
|
});
|
|
}
|
|
|
|
async function toUnbook() {
|
|
const { data } = await axios.post(`InvoiceIns/${entityId.value}/toUnbook`);
|
|
const { isLinked, bookEntry, accountingEntries } = data;
|
|
|
|
const type = isLinked ? 'warning' : 'positive';
|
|
const message = isLinked
|
|
? t('isLinked', { bookEntry })
|
|
: t('isNotLinked', { bookEntry, accountingEntries });
|
|
|
|
quasar.notify({ type, message });
|
|
if (!isLinked) arrayData.store.data.isBooked = false;
|
|
}
|
|
|
|
async function deleteInvoice() {
|
|
await axios.delete(`InvoiceIns/${entityId.value}`);
|
|
quasar.notify({
|
|
type: 'positive',
|
|
message: t('invoicein.descriptorMenu.invoiceDeleted'),
|
|
});
|
|
push({ path: '/invoice-in' });
|
|
}
|
|
|
|
async function cloneInvoice() {
|
|
const { data } = await axios.post(`InvoiceIns/${entityId.value}/clone`);
|
|
quasar.notify({
|
|
type: 'positive',
|
|
message: t('invoicein.descriptorMenu.invoiceCloned'),
|
|
});
|
|
push({ path: `/invoice-in/${data.id}/summary` });
|
|
}
|
|
|
|
const isAgricultural = () => {
|
|
if (!config.value) return false;
|
|
return (
|
|
invoiceIn.value?.supplier?.sageFarmerWithholdingFk ===
|
|
config?.value[0]?.sageWithholdingFk
|
|
);
|
|
};
|
|
function showPdfInvoice() {
|
|
if (isAgricultural()) openReport(`InvoiceIns/${entityId.value}/invoice-in-pdf`);
|
|
}
|
|
|
|
function sendPdfInvoiceConfirmation() {
|
|
quasar.dialog({
|
|
component: SendEmailDialog,
|
|
componentProps: {
|
|
data: {
|
|
address: invoiceIn.value.supplier.contacts[0].email,
|
|
},
|
|
promise: sendPdfInvoice,
|
|
},
|
|
});
|
|
}
|
|
|
|
function sendPdfInvoice({ address }) {
|
|
if (!address)
|
|
quasar.notify({
|
|
type: 'negative',
|
|
message: t(`The email can't be empty`),
|
|
});
|
|
else
|
|
return sendEmail(`InvoiceIns/${entityId.value}/invoice-in-email`, {
|
|
recipientId: invoiceIn.value.supplier.id,
|
|
recipient: address,
|
|
});
|
|
}
|
|
|
|
const createInvoiceInCorrection = async () => {
|
|
const { data: correctingId } = await axios.post(
|
|
'InvoiceIns/corrective',
|
|
Object.assign(correctionFormData, { id: entityId.value })
|
|
);
|
|
push({ path: `/invoice-in/${correctingId}/summary` });
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<FetchData
|
|
url="InvoiceCorrectionTypes"
|
|
@on-fetch="(data) => (invoiceCorrectionTypes = data)"
|
|
auto-load
|
|
/>
|
|
<FetchData
|
|
url="CplusRectificationTypes"
|
|
@on-fetch="(data) => (cplusRectificationTypes = data)"
|
|
auto-load
|
|
/>
|
|
<FetchData
|
|
url="SiiTypeInvoiceIns"
|
|
:where="{ code: { like: 'R%' } }"
|
|
@on-fetch="(data) => (siiTypeInvoiceIns = data)"
|
|
auto-load
|
|
/>
|
|
<FetchData
|
|
url="InvoiceInConfigs"
|
|
:where="{ fields: ['sageWithholdingFk'] }"
|
|
auto-load
|
|
@on-fetch="(data) => (config = data)"
|
|
/>
|
|
<InvoiceInToBook>
|
|
<template #content="{ book }">
|
|
<QItem
|
|
v-if="!invoice?.isBooked && canEditProp('toBook')"
|
|
v-ripple
|
|
clickable
|
|
@click="book(entityId)"
|
|
>
|
|
<QItemSection>{{ t('invoicein.descriptorMenu.toBook') }}</QItemSection>
|
|
</QItem>
|
|
</template>
|
|
</InvoiceInToBook>
|
|
<QItem
|
|
v-if="invoice?.isBooked && canEditProp('toUnbook')"
|
|
v-ripple
|
|
clickable
|
|
@click="triggerMenu('unbook')"
|
|
>
|
|
<QItemSection>
|
|
{{ t('invoicein.descriptorMenu.toUnbook') }}
|
|
</QItemSection>
|
|
</QItem>
|
|
<QItem
|
|
v-if="canEditProp('deleteById')"
|
|
v-ripple
|
|
clickable
|
|
@click="triggerMenu('delete')"
|
|
>
|
|
<QItemSection>{{ t('invoicein.descriptorMenu.deleteInvoice') }}</QItemSection>
|
|
</QItem>
|
|
<QItem v-if="canEditProp('clone')" v-ripple clickable @click="triggerMenu('clone')">
|
|
<QItemSection>{{ t('invoicein.descriptorMenu.cloneInvoice') }}</QItemSection>
|
|
</QItem>
|
|
<QItem v-if="isAgricultural()" v-ripple clickable @click="triggerMenu('showPdf')">
|
|
<QItemSection>{{
|
|
t('invoicein.descriptorMenu.showAgriculturalPdf')
|
|
}}</QItemSection>
|
|
</QItem>
|
|
<QItem v-if="isAgricultural()" v-ripple clickable @click="triggerMenu('sendPdf')">
|
|
<QItemSection
|
|
>{{ t('invoicein.descriptorMenu.sendAgriculturalPdf') }}...</QItemSection
|
|
>
|
|
</QItem>
|
|
<QItem
|
|
v-if="!invoiceInCorrection.corrected"
|
|
v-ripple
|
|
clickable
|
|
@click="triggerMenu('correct')"
|
|
>
|
|
<QItemSection
|
|
>{{ t('invoicein.descriptorMenu.createCorrective') }}...</QItemSection
|
|
>
|
|
</QItem>
|
|
<QItem v-if="invoice.dmsFk" v-ripple clickable @click="downloadFile(invoice.dmsFk)">
|
|
<QItemSection>{{ t('components.smartCard.downloadFile') }}</QItemSection>
|
|
</QItem>
|
|
<QDialog ref="correctionDialogRef">
|
|
<QCard>
|
|
<QCardSection>
|
|
<QItem class="q-px-none">
|
|
<span class="text-primary text-h6 full-width">
|
|
{{ t('Create rectificative invoice') }}
|
|
</span>
|
|
<QBtn icon="close" flat round dense v-close-popup />
|
|
</QItem>
|
|
</QCardSection>
|
|
<QCardSection>
|
|
<QItem>
|
|
<QItemSection>
|
|
<QInput
|
|
:label="t('Original invoice')"
|
|
v-model="entityId"
|
|
readonly
|
|
/>
|
|
<VnSelect
|
|
:label="`${useCapitalize(t('globals.class'))}`"
|
|
v-model="correctionFormData.invoiceClass"
|
|
:options="siiTypeInvoiceIns"
|
|
option-value="id"
|
|
option-label="code"
|
|
:required="true"
|
|
/>
|
|
</QItemSection>
|
|
<QItemSection>
|
|
<VnSelect
|
|
:label="`${useCapitalize(t('globals.type'))}`"
|
|
v-model="correctionFormData.invoiceType"
|
|
:options="cplusRectificationTypes"
|
|
option-value="id"
|
|
option-label="description"
|
|
:required="true"
|
|
>
|
|
<template #option="{ itemProps, opt }">
|
|
<QItem v-bind="itemProps">
|
|
{{ console.log('opt: ', opt) }}
|
|
<QItemSection>
|
|
<QItemLabel
|
|
>{{ opt.id }} -
|
|
{{ opt.description }}</QItemLabel
|
|
>
|
|
</QItemSection>
|
|
</QItem>
|
|
<div></div>
|
|
</template>
|
|
</VnSelect>
|
|
|
|
<VnSelect
|
|
:label="`${useCapitalize(t('globals.reason'))}`"
|
|
v-model="correctionFormData.invoiceReason"
|
|
:options="invoiceCorrectionTypes"
|
|
option-value="id"
|
|
option-label="description"
|
|
:required="true"
|
|
/>
|
|
</QItemSection>
|
|
</QItem>
|
|
</QCardSection>
|
|
<QCardActions class="justify-end q-mr-sm">
|
|
<QBtn flat :label="t('globals.close')" color="primary" v-close-popup />
|
|
<QBtn
|
|
:label="t('globals.save')"
|
|
color="primary"
|
|
v-close-popup
|
|
@click="createInvoiceInCorrection"
|
|
:disable="isNotFilled"
|
|
/>
|
|
</QCardActions>
|
|
</QCard>
|
|
</QDialog>
|
|
</template>
|
|
|
|
<i18n>
|
|
en:
|
|
isNotLinked: The entry {bookEntry} has been deleted with {accountingEntries} entries
|
|
isLinked: The entry has been linked to Sage. Please contact administration for further information
|
|
assertAction: Are you sure you want to {action} this invoice?
|
|
es:
|
|
isNotLinked: Se ha eliminado el asiento nº {bookEntry} con {accountingEntries} apuntes
|
|
isLinked: El asiento fue enlazado a Sage, por favor contacta con administración
|
|
assertAction: Estas seguro de querer {action} esta factura?
|
|
</i18n>
|