7525-devToTest #419
|
@ -1,6 +1,6 @@
|
|||
<script setup>
|
||||
import { ref, reactive, computed, onBeforeMount, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useQuasar } from 'quasar';
|
||||
import axios from 'axios';
|
||||
|
@ -18,23 +18,25 @@ import VnConfirm from 'src/components/ui/VnConfirm.vue';
|
|||
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
|
||||
import { useCapitalize } from 'src/composables/useCapitalize';
|
||||
import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
|
||||
import InvoiceInToBook from '../InvoiceInToBook.vue';
|
||||
|
||||
const $props = defineProps({
|
||||
id: { type: Number, default: null },
|
||||
});
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const { push, currentRoute } = useRouter();
|
||||
|
||||
const quasar = useQuasar();
|
||||
const { hasAny } = useRole();
|
||||
const { t } = useI18n();
|
||||
const { openReport, sendEmail } = usePrintService();
|
||||
const arrayData = useArrayData('InvoiceIn');
|
||||
const { store } = useArrayData('InvoiceIn');
|
||||
|
||||
const invoiceIn = computed(() => arrayData.store.data);
|
||||
const invoiceIn = computed(() => store.data);
|
||||
const isBooked = ref();
|
||||
const cardDescriptorRef = ref();
|
||||
const correctionDialogRef = ref();
|
||||
const entityId = computed(() => $props.id || +route.params.id);
|
||||
const entityId = computed(() => $props.id || +currentRoute.value.params.id);
|
||||
const totalAmount = ref();
|
||||
const currentAction = ref();
|
||||
const config = ref();
|
||||
|
@ -42,11 +44,6 @@ const cplusRectificationTypes = ref([]);
|
|||
const siiTypeInvoiceOuts = ref([]);
|
||||
const invoiceCorrectionTypes = ref([]);
|
||||
const actions = {
|
||||
book: {
|
||||
title: 'Are you sure you want to book this invoice?',
|
||||
cb: checkToBook,
|
||||
action: toBook,
|
||||
},
|
||||
unbook: {
|
||||
title: 'Are you sure you want to unbook this invoice?',
|
||||
action: toUnbook,
|
||||
|
@ -143,7 +140,7 @@ const isNotFilled = computed(() => Object.values(correctionFormData).includes(nu
|
|||
onBeforeMount(async () => await setInvoiceCorrection(entityId.value));
|
||||
|
||||
watch(
|
||||
() => route.params.id,
|
||||
() => currentRoute.value.params.id,
|
||||
async (newId) => {
|
||||
invoiceInCorrection.correcting.length = 0;
|
||||
invoiceInCorrection.corrected = null;
|
||||
|
@ -182,6 +179,7 @@ async function setInvoiceCorrection(id) {
|
|||
|
||||
async function setData(entity) {
|
||||
data.value = useCardDescription(entity.supplierRef, entity.id);
|
||||
isBooked.value = entity.isBooked;
|
||||
const { totalDueDay } = await getTotals();
|
||||
totalAmount.value = totalDueDay;
|
||||
}
|
||||
|
@ -201,36 +199,6 @@ function openDialog() {
|
|||
});
|
||||
}
|
||||
|
||||
async function checkToBook() {
|
||||
let directBooking = true;
|
||||
|
||||
const totals = await getTotals();
|
||||
const taxableBaseNotEqualDueDay = totals.totalDueDay != totals.totalTaxableBase;
|
||||
const vatNotEqualDueDay = totals.totalDueDay != totals.totalVat;
|
||||
|
||||
if (taxableBaseNotEqualDueDay && vatNotEqualDueDay) directBooking = false;
|
||||
|
||||
const { data: dueDaysCount } = await axios.get('InvoiceInDueDays/count', {
|
||||
where: {
|
||||
invoiceInFk: entityId.value,
|
||||
dueDated: { gte: Date.vnNew() },
|
||||
},
|
||||
});
|
||||
|
||||
if (dueDaysCount) directBooking = false;
|
||||
|
||||
if (!directBooking) openDialog();
|
||||
else toBook();
|
||||
}
|
||||
|
||||
async function toBook() {
|
||||
await axios.post(`InvoiceIns/${entityId.value}/toBook`);
|
||||
quasar.notify({ type: 'positive', message: t('globals.dataSaved') });
|
||||
|
||||
await cardDescriptorRef.value.getData();
|
||||
setTimeout(() => location.reload(), 500);
|
||||
}
|
||||
|
||||
async function toUnbook() {
|
||||
const { data } = await axios.post(`InvoiceIns/${entityId.value}/toUnbook`);
|
||||
const { isLinked, bookEntry, accountingEntries } = data;
|
||||
|
@ -241,9 +209,7 @@ async function toUnbook() {
|
|||
: t('isNotLinked', { bookEntry });
|
||||
|
||||
quasar.notify({ type, message });
|
||||
await cardDescriptorRef.value.getData();
|
||||
|
||||
if (!isLinked) setTimeout(() => location.reload(), 500);
|
||||
store.data.isBooked = false;
|
||||
}
|
||||
|
||||
async function deleteInvoice() {
|
||||
|
@ -252,7 +218,7 @@ async function deleteInvoice() {
|
|||
type: 'positive',
|
||||
message: t('Invoice deleted'),
|
||||
});
|
||||
router.push({ path: '/invoice-in' });
|
||||
push({ path: '/invoice-in' });
|
||||
}
|
||||
|
||||
async function cloneInvoice() {
|
||||
|
@ -261,7 +227,7 @@ async function cloneInvoice() {
|
|||
type: 'positive',
|
||||
message: t('Invoice cloned'),
|
||||
});
|
||||
router.push({ path: `/invoice-in/${data.id}/summary` });
|
||||
push({ path: `/invoice-in/${data.id}/summary` });
|
||||
}
|
||||
|
||||
const isAdministrative = () => hasAny(['administrative']);
|
||||
|
@ -309,7 +275,7 @@ const createInvoiceInCorrection = async () => {
|
|||
'InvoiceIns/corrective',
|
||||
Object.assign(correctionFormData, { id: entityId.value })
|
||||
);
|
||||
router.push({ path: `/invoice-in/${correctingId}/summary` });
|
||||
push({ path: `/invoice-in/${correctingId}/summary` });
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@ -347,16 +313,20 @@ const createInvoiceInCorrection = async () => {
|
|||
data-key="invoiceInData"
|
||||
>
|
||||
<template #menu="{ entity }">
|
||||
<InvoiceInToBook>
|
||||
<template #content="{ book }">
|
||||
<QItem
|
||||
v-if="!invoiceIn?.isBooked && isAdministrative()"
|
||||
v-ripple
|
||||
clickable
|
||||
@click="book(entityId)"
|
||||
>
|
||||
<QItemSection>{{ t('To book') }}</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</InvoiceInToBook>
|
||||
<QItem
|
||||
v-if="!entity.isBooked && isAdministrative()"
|
||||
v-ripple
|
||||
clickable
|
||||
@click="triggerMenu('book')"
|
||||
>
|
||||
<QItemSection>{{ t('To book') }}</QItemSection>
|
||||
</QItem>
|
||||
<QItem
|
||||
v-if="entity.isBooked && isAdministrative()"
|
||||
v-if="invoiceIn?.isBooked && isAdministrative()"
|
||||
v-ripple
|
||||
clickable
|
||||
@click="triggerMenu('unbook')"
|
||||
|
|
|
@ -3,17 +3,19 @@ import { onMounted, ref, computed } from 'vue';
|
|||
import { useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { toCurrency, toDate } from 'src/filters';
|
||||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
import { getUrl } from 'src/composables/getUrl';
|
||||
import CardSummary from 'components/ui/CardSummary.vue';
|
||||
import VnLv from 'src/components/ui/VnLv.vue';
|
||||
import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
|
||||
import InvoiceIntoBook from '../InvoiceInToBook.vue';
|
||||
|
||||
onMounted(async () => {
|
||||
salixUrl.value = await getUrl('');
|
||||
invoiceInUrl.value = salixUrl.value + `invoiceIn/${entityId.value}/`;
|
||||
});
|
||||
|
||||
const route = useRoute();
|
||||
const { params } = useRoute();
|
||||
const { t } = useI18n();
|
||||
|
||||
const $props = defineProps({
|
||||
|
@ -23,12 +25,15 @@ const $props = defineProps({
|
|||
},
|
||||
});
|
||||
|
||||
const entityId = computed(() => $props.id || route.params.id);
|
||||
const entityId = computed(() => $props.id || params.id);
|
||||
const arrayData = useArrayData('InvoiceIn');
|
||||
const invoiceIn = computed(() => arrayData.store.data);
|
||||
|
||||
const salixUrl = ref();
|
||||
const invoiceInUrl = ref();
|
||||
const amountsNotMatch = ref(null);
|
||||
const intrastatTotals = ref({});
|
||||
const isBooked = ref();
|
||||
|
||||
const vatColumns = ref([
|
||||
{
|
||||
|
@ -182,6 +187,7 @@ function getTaxTotal(tax) {
|
|||
function setData(entity) {
|
||||
if (!entity) return false;
|
||||
|
||||
isBooked.value = entity.isBooked;
|
||||
amountsNotMatch.value = getAmountNotMatch(entity.totals);
|
||||
|
||||
if (entity.invoiceInIntrastat.length)
|
||||
|
@ -203,10 +209,22 @@ function getLink(param) {
|
|||
:url="`InvoiceIns/${entityId}/summary`"
|
||||
@on-fetch="(data) => setData(data)"
|
||||
>
|
||||
<template #header="{ entity: invoiceIn }">
|
||||
<div>{{ invoiceIn.id }} - {{ invoiceIn.supplier?.name }}</div>
|
||||
<template #header="{ entity }">
|
||||
<div>{{ entity.id }} - {{ entity.supplier?.name }}</div>
|
||||
</template>
|
||||
<template #body="{ entity: invoiceIn }">
|
||||
<template #header-right v-if="!invoiceIn?.isBooked">
|
||||
<InvoiceIntoBook>
|
||||
<template #content="{ book }">
|
||||
<QBtn
|
||||
:label="t('To book')"
|
||||
color="orange-11"
|
||||
text-color="black"
|
||||
@click="book(entityId)"
|
||||
/>
|
||||
</template>
|
||||
</InvoiceIntoBook>
|
||||
</template>
|
||||
<template #body="{ entity }">
|
||||
<!--Basic Data-->
|
||||
<QCard class="vn-one">
|
||||
<QCardSection class="q-pa-none">
|
||||
|
@ -217,26 +235,26 @@ function getLink(param) {
|
|||
</QCardSection>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.supplier')"
|
||||
:value="invoiceIn.supplier?.name"
|
||||
:value="entity.supplier?.name"
|
||||
>
|
||||
<template #value>
|
||||
<span class="link">
|
||||
{{ invoiceIn.supplier?.name }}
|
||||
<SupplierDescriptorProxy :id="invoiceIn.supplierFk" />
|
||||
{{ entity.supplier?.name }}
|
||||
<SupplierDescriptorProxy :id="entity.supplierFk" />
|
||||
</span>
|
||||
</template>
|
||||
</VnLv>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.supplierRef')"
|
||||
:value="invoiceIn.supplierRef"
|
||||
:value="entity.supplierRef"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.currency')"
|
||||
:value="invoiceIn.currency?.code"
|
||||
:value="entity.currency?.code"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.docNumber')"
|
||||
:value="`${invoiceIn.serial}/${invoiceIn.serialNumber}`"
|
||||
:value="`${entity.serial}/${entity.serialNumber}`"
|
||||
/>
|
||||
</QCard>
|
||||
<QCard class="vn-one">
|
||||
|
@ -249,19 +267,19 @@ function getLink(param) {
|
|||
<VnLv
|
||||
:ellipsis-value="false"
|
||||
:label="t('invoiceIn.summary.issued')"
|
||||
:value="toDate(invoiceIn.issued)"
|
||||
:value="toDate(entity.issued)"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.operated')"
|
||||
:value="toDate(invoiceIn.operated)"
|
||||
:value="toDate(entity.operated)"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.bookEntried')"
|
||||
:value="toDate(invoiceIn.bookEntried)"
|
||||
:value="toDate(entity.bookEntried)"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.bookedDate')"
|
||||
:value="toDate(invoiceIn.booked)"
|
||||
:value="toDate(entity.booked)"
|
||||
/>
|
||||
</QCard>
|
||||
<QCard class="vn-one">
|
||||
|
@ -273,17 +291,18 @@ function getLink(param) {
|
|||
</QCardSection>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.sage')"
|
||||
:value="invoiceIn.sageWithholding?.withholding"
|
||||
:value="entity.sageWithholding?.withholding"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.vat')"
|
||||
:value="invoiceIn.expenseDeductible?.name"
|
||||
:value="entity.expenseDeductible?.name"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.company')"
|
||||
:value="invoiceIn.company?.code"
|
||||
:value="entity.company?.code"
|
||||
/>
|
||||
<QCheckbox
|
||||
v-if="invoiceIn"
|
||||
:label="t('invoiceIn.summary.booked')"
|
||||
v-model="invoiceIn.isBooked"
|
||||
:disable="true"
|
||||
|
@ -296,9 +315,9 @@ function getLink(param) {
|
|||
<QCardSection class="q-pa-none">
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.taxableBase')"
|
||||
:value="toCurrency(invoiceIn.totals.totalTaxableBase)"
|
||||
:value="toCurrency(entity.totals.totalTaxableBase)"
|
||||
/>
|
||||
<VnLv label="Total" :value="toCurrency(invoiceIn.totals.totalVat)" />
|
||||
<VnLv label="Total" :value="toCurrency(entity.totals.totalVat)" />
|
||||
<VnLv :label="t('invoiceIn.summary.dueTotal')">
|
||||
<template #value>
|
||||
<QChip
|
||||
|
@ -311,21 +330,21 @@ function getLink(param) {
|
|||
: t('invoiceIn.summary.dueTotal')
|
||||
"
|
||||
>
|
||||
{{ toCurrency(invoiceIn.totals.totalDueDay) }}
|
||||
{{ toCurrency(entity.totals.totalDueDay) }}
|
||||
</QChip>
|
||||
</template>
|
||||
</VnLv>
|
||||
</QCardSection>
|
||||
</QCard>
|
||||
<!--Vat-->
|
||||
<QCard v-if="invoiceIn.invoiceInTax.length" class="vn-two">
|
||||
<QCard v-if="entity.invoiceInTax.length" class="vn-two">
|
||||
<a class="header header-link" :href="getLink('vat')">
|
||||
{{ t('invoiceIn.card.vat') }}
|
||||
<QIcon name="open_in_new" />
|
||||
</a>
|
||||
<QTable
|
||||
:columns="vatColumns"
|
||||
:rows="invoiceIn.invoiceInTax"
|
||||
:rows="entity.invoiceInTax"
|
||||
flat
|
||||
hide-pagination
|
||||
>
|
||||
|
@ -339,19 +358,17 @@ function getLink(param) {
|
|||
<template #bottom-row>
|
||||
<QTr class="bg">
|
||||
<QTd></QTd>
|
||||
<QTd>{{ toCurrency(invoiceIn.totals.totalTaxableBase) }}</QTd>
|
||||
<QTd>{{ toCurrency(entity.totals.totalTaxableBase) }}</QTd>
|
||||
<QTd></QTd>
|
||||
<QTd></QTd>
|
||||
<QTd>{{
|
||||
toCurrency(getTaxTotal(invoiceIn.invoiceInTax))
|
||||
}}</QTd>
|
||||
<QTd>{{ toCurrency(getTaxTotal(entity.invoiceInTax)) }}</QTd>
|
||||
<QTd></QTd>
|
||||
</QTr>
|
||||
</template>
|
||||
</QTable>
|
||||
</QCard>
|
||||
<!--Due Day-->
|
||||
<QCard v-if="invoiceIn.invoiceInDueDay.length" class="vn-one">
|
||||
<QCard v-if="entity.invoiceInDueDay.length" class="vn-one">
|
||||
<a class="header header-link" :href="getLink('due-day')">
|
||||
{{ t('invoiceIn.card.dueDay') }}
|
||||
<QIcon name="open_in_new" />
|
||||
|
@ -359,7 +376,7 @@ function getLink(param) {
|
|||
<QTable
|
||||
class="full-width"
|
||||
:columns="dueDayColumns"
|
||||
:rows="invoiceIn.invoiceInDueDay"
|
||||
:rows="entity.invoiceInDueDay"
|
||||
flat
|
||||
hide-pagination
|
||||
>
|
||||
|
@ -374,21 +391,21 @@ function getLink(param) {
|
|||
<QTr class="bg">
|
||||
<QTd></QTd>
|
||||
<QTd></QTd>
|
||||
<QTd>{{ toCurrency(invoiceIn.totals.totalDueDay) }}</QTd>
|
||||
<QTd>{{ toCurrency(entity.totals.totalDueDay) }}</QTd>
|
||||
<QTd></QTd>
|
||||
</QTr>
|
||||
</template>
|
||||
</QTable>
|
||||
</QCard>
|
||||
<!--Intrastat-->
|
||||
<QCard v-if="invoiceIn.invoiceInIntrastat.length">
|
||||
<QCard v-if="entity.invoiceInIntrastat.length">
|
||||
<a class="header header-link" :href="getLink('intrastat')">
|
||||
{{ t('invoiceIn.card.intrastat') }}
|
||||
<QIcon name="open_in_new" />
|
||||
</a>
|
||||
<QTable
|
||||
:columns="intrastatColumns"
|
||||
:rows="invoiceIn.invoiceInIntrastat"
|
||||
:rows="entity.invoiceInIntrastat"
|
||||
flat
|
||||
hide-pagination
|
||||
>
|
||||
|
@ -429,4 +446,5 @@ function getLink(param) {
|
|||
Search invoice: Buscar factura recibida
|
||||
You can search by invoice reference: Puedes buscar por referencia de la factura
|
||||
Totals: Totales
|
||||
To book: Contabilizar
|
||||
</i18n>
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
<script setup>
|
||||
import axios from 'axios';
|
||||
import { useQuasar } from 'quasar';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import VnConfirm from 'src/components/ui/VnConfirm.vue';
|
||||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
|
||||
const { notify, dialog } = useQuasar();
|
||||
const { t } = useI18n();
|
||||
defineExpose({ checkToBook });
|
||||
|
||||
const { store } = useArrayData('InvoiceIn');
|
||||
|
||||
async function checkToBook(id) {
|
||||
let directBooking = true;
|
||||
|
||||
const { data: totals } = await axios.get(`InvoiceIns/${id}/getTotals`);
|
||||
const taxableBaseNotEqualDueDay = totals.totalDueDay != totals.totalTaxableBase;
|
||||
const vatNotEqualDueDay = totals.totalDueDay != totals.totalVat;
|
||||
|
||||
if (taxableBaseNotEqualDueDay && vatNotEqualDueDay) directBooking = false;
|
||||
|
||||
const { data: dueDaysCount } = await axios.get('InvoiceInDueDays/count', {
|
||||
where: {
|
||||
invoiceInFk: id,
|
||||
dueDated: { gte: Date.vnNew() },
|
||||
},
|
||||
});
|
||||
|
||||
if (dueDaysCount) directBooking = false;
|
||||
|
||||
if (directBooking) return toBook(id);
|
||||
|
||||
dialog({
|
||||
component: VnConfirm,
|
||||
componentProps: { title: t('Are you sure you want to book this invoice?') },
|
||||
}).onOk(async () => await toBook(id));
|
||||
}
|
||||
|
||||
async function toBook(id) {
|
||||
let type = 'positive';
|
||||
let message = t('globals.dataSaved');
|
||||
|
||||
try {
|
||||
await axios.post(`InvoiceIns/${id}/toBook`);
|
||||
store.data.isBooked = true;
|
||||
} catch (e) {
|
||||
type = 'negative';
|
||||
message = t('It was not able to book the invoice');
|
||||
} finally {
|
||||
notify({ type, message });
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<slot name="content" :book="checkToBook" />
|
||||
</template>
|
||||
<i18n>
|
||||
es:
|
||||
Are you sure you want to book this invoice?: ¿Estás seguro de querer asentar esta factura?
|
||||
It was not able to book the invoice: No se pudo contabilizar la factura
|
||||
</i18n>
|
|
@ -1,7 +1,7 @@
|
|||
describe('InvoiceInDescriptor', () => {
|
||||
const saveDialog = '.q-btn--unelevated > .q-btn__content > .block';
|
||||
const firstDescritorOpt = '.q-menu > .q-list > :nth-child(1) > .q-item__section';
|
||||
|
||||
const screen = '.q-drawer-container > .fullscreen';
|
||||
it('should booking and unbooking the invoice properly', () => {
|
||||
cy.login('developer');
|
||||
cy.visit(`/#/invoice-in/1/summary?limit=10`);
|
||||
|
@ -10,6 +10,7 @@ describe('InvoiceInDescriptor', () => {
|
|||
cy.openActionsDescriptor();
|
||||
cy.get(firstDescritorOpt).click();
|
||||
cy.get(saveDialog).click();
|
||||
cy.get(screen).click();
|
||||
cy.get('.q-checkbox').should('have.attr', 'aria-checked', 'true');
|
||||
|
||||
cy.openLeftMenu();
|
||||
|
|
Loading…
Reference in New Issue