7525-devToTest #419

Merged
alexm merged 177 commits from 7525-devToTest into test 2024-06-04 08:06:27 +00:00
4 changed files with 141 additions and 90 deletions
Showing only changes of commit db632f3c11 - Show all commits

View File

@ -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="!entity.isBooked && isAdministrative()"
v-if="!invoiceIn?.isBooked && isAdministrative()"
v-ripple
clickable
@click="triggerMenu('book')"
@click="book(entityId)"
>
<QItemSection>{{ t('To book') }}</QItemSection>
</QItem>
</template>
</InvoiceInToBook>
<QItem
v-if="entity.isBooked && isAdministrative()"
v-if="invoiceIn?.isBooked && isAdministrative()"
v-ripple
clickable
@click="triggerMenu('unbook')"

View File

@ -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>

View File

@ -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>

View File

@ -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();