refs #5835 rate fixed & options descriptor created
gitea/salix-front/pipeline/head This commit looks good
Details
gitea/salix-front/pipeline/head This commit looks good
Details
This commit is contained in:
parent
7595c01293
commit
0282f8dde8
|
@ -24,12 +24,13 @@ const address = ref(props.data.address);
|
|||
const isLoading = ref(false);
|
||||
|
||||
async function confirm() {
|
||||
const response = { address };
|
||||
|
||||
const response = { address: address.value };
|
||||
if (props.promise) {
|
||||
isLoading.value = true;
|
||||
const { address: _address, ...restData } = props.data;
|
||||
|
||||
try {
|
||||
Object.assign(response, props.data);
|
||||
Object.assign(response, restData);
|
||||
await props.promise(response);
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
|
|
|
@ -89,6 +89,7 @@ const value = computed({
|
|||
map-options
|
||||
use-input
|
||||
@filter="filterHandler"
|
||||
hide-selected
|
||||
fill-input
|
||||
ref="vnSelectRef"
|
||||
>
|
||||
|
|
|
@ -35,6 +35,10 @@ const $props = defineProps({
|
|||
const slots = useSlots();
|
||||
const { t } = useI18n();
|
||||
const entity = computed(() => useArrayData($props.dataKey).store.data);
|
||||
|
||||
defineExpose({
|
||||
getData,
|
||||
});
|
||||
onMounted(async () => {
|
||||
await getData();
|
||||
watch(
|
||||
|
|
|
@ -427,8 +427,8 @@ export default {
|
|||
dueDay: 'Fecha de vencimiento',
|
||||
},
|
||||
summary: {
|
||||
supplier: 'Supplier',
|
||||
supplierRef: 'Supplier ref.',
|
||||
supplier: 'Proveedor',
|
||||
supplierRef: 'Ref. proveedor',
|
||||
currency: 'Divisa',
|
||||
docNumber: 'Número documento',
|
||||
issued: 'Fecha de expedición',
|
||||
|
|
|
@ -37,7 +37,7 @@ function confirmPickupOrder() {
|
|||
data: {
|
||||
address: customer.email,
|
||||
},
|
||||
send: sendPickupOrder,
|
||||
promise: sendPickupOrder,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,12 +1,20 @@
|
|||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useQuasar } from 'quasar';
|
||||
import axios from 'axios';
|
||||
import { toCurrency, toDate } from 'src/filters';
|
||||
import CardDescriptor from 'components/ui/CardDescriptor.vue';
|
||||
import VnLv from 'src/components/ui/VnLv.vue';
|
||||
import { useRole } from 'src/composables/useRole';
|
||||
import useCardDescription from 'src/composables/useCardDescription';
|
||||
import { downloadFile } from 'src/composables/downloadFile';
|
||||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
import { usePrintService } from 'composables/usePrintService';
|
||||
import VnLv from 'src/components/ui/VnLv.vue';
|
||||
import CardDescriptor from 'components/ui/CardDescriptor.vue';
|
||||
import FetchData from 'src/components/FetchData.vue';
|
||||
import SendEmailDialog from 'components/common/SendEmailDialog.vue';
|
||||
import VnConfirm from 'src/components/ui/VnConfirm.vue';
|
||||
|
||||
const $props = defineProps({
|
||||
id: {
|
||||
|
@ -17,13 +25,41 @@ const $props = defineProps({
|
|||
});
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const quasar = useQuasar();
|
||||
const { hasAny } = useRole();
|
||||
const { t } = useI18n();
|
||||
const { openReport, sendEmail } = usePrintService();
|
||||
const arrayData = useArrayData('InvoiceIn');
|
||||
|
||||
const entityId = computed(() => {
|
||||
return $props.id || route.params.id;
|
||||
});
|
||||
const totalAmount = ref([]);
|
||||
const invoiceIn = computed(() => arrayData.store.data);
|
||||
const cardDescriptorRef = ref();
|
||||
const entityId = computed(() => $props.id || route.params.id);
|
||||
const totalAmount = ref();
|
||||
const currentAction = ref();
|
||||
const config = ref();
|
||||
|
||||
const actions = {
|
||||
book: {
|
||||
title: 'Are you sure you want to book this invoice?',
|
||||
cb: checkToBook,
|
||||
action: toBook,
|
||||
},
|
||||
delete: {
|
||||
title: 'Are you sure you want to delete this invoice?',
|
||||
action: deleteInvoice,
|
||||
},
|
||||
clone: {
|
||||
title: 'Are you sure you want to clone this invoice?',
|
||||
action: cloneInvoice,
|
||||
},
|
||||
showPdf: {
|
||||
cb: showPdfInvoice,
|
||||
},
|
||||
sendPdf: {
|
||||
cb: sendPdfInvoiceConfirmation,
|
||||
},
|
||||
};
|
||||
const filter = {
|
||||
include: [
|
||||
{
|
||||
|
@ -52,23 +88,130 @@ const filter = {
|
|||
};
|
||||
|
||||
const data = ref(useCardDescription());
|
||||
function setData(entity) {
|
||||
|
||||
async function setData(entity) {
|
||||
data.value = useCardDescription(entity.supplierRef, entity.id);
|
||||
const { totalDueDay } = await getTotals();
|
||||
totalAmount.value = totalDueDay;
|
||||
}
|
||||
|
||||
async function getTotals() {
|
||||
const { data } = await axios.get(`InvoiceIns/${entityId.value}/getTotals`);
|
||||
return data;
|
||||
}
|
||||
|
||||
function openDialog() {
|
||||
quasar.dialog({
|
||||
component: VnConfirm,
|
||||
componentProps: {
|
||||
title: currentAction.value.title,
|
||||
promise: currentAction.value.action,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
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`);
|
||||
|
||||
// Pendiente de sincronizar todo con arrayData
|
||||
quasar.notify({
|
||||
type: 'positive',
|
||||
message: t('globals.dataSaved'),
|
||||
});
|
||||
|
||||
await cardDescriptorRef.value.getData();
|
||||
setTimeout(() => location.reload(), 500);
|
||||
}
|
||||
|
||||
async function deleteInvoice() {
|
||||
await axios.delete(`InvoiceIns/${entityId.value}`);
|
||||
quasar.notify({
|
||||
type: 'positive',
|
||||
message: t('Invoice deleted'),
|
||||
});
|
||||
router.push({ path: '/invoice-in' });
|
||||
}
|
||||
|
||||
async function cloneInvoice() {
|
||||
const { data } = await axios.post(`InvoiceIns/${entityId.value}/clone`);
|
||||
quasar.notify({
|
||||
type: 'positive',
|
||||
message: t('Invoice cloned'),
|
||||
});
|
||||
router.push({ path: `/invoice-in/${data.id}/summary` });
|
||||
}
|
||||
|
||||
const isAgricultural = () =>
|
||||
invoiceIn.value.supplier.sageWithholdingFk == 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,
|
||||
});
|
||||
}
|
||||
|
||||
function triggerMenu(type) {
|
||||
currentAction.value = actions[type];
|
||||
if (currentAction.value.cb) currentAction.value.cb();
|
||||
else openDialog(type);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!--Refactor para añadir en el arrayData-->
|
||||
<FetchData
|
||||
:url="`InvoiceIns/${entityId}/getTotals`"
|
||||
@on-fetch="
|
||||
(data) => {
|
||||
totalAmount = data.totalDueDay;
|
||||
}
|
||||
"
|
||||
url="InvoiceInConfigs"
|
||||
:where="{ fields: ['sageWithholdingFk'] }"
|
||||
auto-load
|
||||
@on-fetch="(data) => (config = data)"
|
||||
/>
|
||||
<!--Refactor para añadir en el arrayData-->
|
||||
<CardDescriptor
|
||||
ref="cardDescriptorRef"
|
||||
module="InvoiceIn"
|
||||
:url="`InvoiceIns/${entityId}`"
|
||||
:filter="filter"
|
||||
|
@ -77,6 +220,79 @@ function setData(entity) {
|
|||
@on-fetch="setData"
|
||||
data-key="invoiceInData"
|
||||
>
|
||||
<template #menu="{ entity }">
|
||||
<QItem
|
||||
v-if="!entity.isBooked && hasAny(['administrative'])"
|
||||
v-ripple
|
||||
clickable
|
||||
@click="triggerMenu('book')"
|
||||
>
|
||||
<QItemSection avatar>
|
||||
<QIcon name="summarize" />
|
||||
</QItemSection>
|
||||
<QItemSection>{{ t('To book') }}</QItemSection>
|
||||
</QItem>
|
||||
<QSeparator />
|
||||
<QItem
|
||||
v-if="hasAny(['administrative'])"
|
||||
v-ripple
|
||||
clickable
|
||||
@click="triggerMenu('delete')"
|
||||
>
|
||||
<QItemSection avatar>
|
||||
<QIcon name="delete" />
|
||||
</QItemSection>
|
||||
<QItemSection>{{ t('Delete invoice') }}</QItemSection>
|
||||
</QItem>
|
||||
<QSeparator />
|
||||
<QItem
|
||||
v-if="hasAny(['administrative'])"
|
||||
v-ripple
|
||||
clickable
|
||||
@click="triggerMenu('clone')"
|
||||
>
|
||||
<QItemSection avatar>
|
||||
<QIcon name="file_copy" />
|
||||
</QItemSection>
|
||||
<QItemSection>{{ t('Clone invoice') }}</QItemSection>
|
||||
</QItem>
|
||||
<QSeparator />
|
||||
<QItem
|
||||
v-if="isAgricultural()"
|
||||
v-ripple
|
||||
clickable
|
||||
@click="triggerMenu('showPdf')"
|
||||
>
|
||||
<QItemSection avatar>
|
||||
<QIcon name="picture_as_pdf" />
|
||||
</QItemSection>
|
||||
<QItemSection>{{ t('Show agricultural receipt as PDF') }}</QItemSection>
|
||||
</QItem>
|
||||
<QSeparator />
|
||||
<QItem
|
||||
v-if="isAgricultural()"
|
||||
v-ripple
|
||||
clickable
|
||||
@click="triggerMenu('sendPdf')"
|
||||
>
|
||||
<QItemSection avatar>
|
||||
<QIcon name="mail" />
|
||||
</QItemSection>
|
||||
<QItemSection>{{ t('Send agricultural receipt as PDF') }}</QItemSection>
|
||||
</QItem>
|
||||
<QSeparator />
|
||||
<QItem
|
||||
v-if="entity.dmsFk"
|
||||
v-ripple
|
||||
clickable
|
||||
@click="downloadFile(entity.dmsFk)"
|
||||
>
|
||||
<QItemSection avatar>
|
||||
<QIcon name="cloud_download" />
|
||||
</QItemSection>
|
||||
<QItemSection>{{ t('components.smartCard.downloadFile') }}</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
<template #body="{ entity }">
|
||||
<VnLv :label="t('invoiceIn.card.issued')" :value="toDate(entity.issued)" />
|
||||
<VnLv :label="t('invoiceIn.summary.booked')" :value="toDate(entity.booked)" />
|
||||
|
@ -107,3 +323,25 @@ function setData(entity) {
|
|||
</template>
|
||||
</CardDescriptor>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
.q-dialog {
|
||||
.q-card {
|
||||
width: 35em;
|
||||
max-width: 35em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<i18n>
|
||||
es:
|
||||
To book: Contabilizar
|
||||
Are you sure you want to book this invoice?: Estas seguro de querer asentar esta factura?
|
||||
Delete invoice: Eliminar factura
|
||||
Are you sure you want to delete this invoice?: Estas seguro de querer eliminar esta factura?
|
||||
Invoice deleted: Factura eliminada
|
||||
Clone invoice: Clonar factura
|
||||
Invoice cloned: Factura clonada
|
||||
Show agricultural receipt as PDF: Ver recibo agrícola como PDF
|
||||
Send agricultural receipt as PDF: Enviar recibo agrícola como PDF
|
||||
Are you sure you want to send it?: Estás seguro que quieres enviarlo?
|
||||
Send PDF invoice: Enviar factura a PDF
|
||||
</i18n>
|
||||
|
|
|
@ -4,8 +4,6 @@ import { useRoute } from 'vue-router';
|
|||
import { useI18n } from 'vue-i18n';
|
||||
import { toCurrency, toDate } from 'src/filters';
|
||||
import { getUrl } from 'src/composables/getUrl';
|
||||
import { downloadFile } from 'src/composables/downloadFile';
|
||||
|
||||
import CardSummary from 'components/ui/CardSummary.vue';
|
||||
import VnLv from 'src/components/ui/VnLv.vue';
|
||||
|
||||
|
@ -66,8 +64,8 @@ const vatColumns = ref([
|
|||
{
|
||||
name: 'rate',
|
||||
label: 'invoiceIn.summary.rate',
|
||||
field: (row) => row.taxRate,
|
||||
format: (value) => value,
|
||||
field: (row) => taxRate(row.taxableBase, row.taxTypeSage?.rate),
|
||||
format: (value) => toCurrency(value),
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
},
|
||||
|
@ -173,6 +171,13 @@ function getIntrastatTotals(intrastat) {
|
|||
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;
|
||||
|
||||
|
@ -181,6 +186,13 @@ function setData(entity) {
|
|||
if (entity.invoiceInIntrastat.length)
|
||||
intrastatTotals.value = { ...getIntrastatTotals(entity.invoiceInIntrastat) };
|
||||
}
|
||||
|
||||
function taxRate(taxableBase, rate) {
|
||||
if (rate && taxableBase) {
|
||||
return (rate / 100) * taxableBase;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -200,19 +212,6 @@ function setData(entity) {
|
|||
{{ t('invoiceIn.pageTitles.basicData') }}
|
||||
<QIcon name="open_in_new" color="primary" />
|
||||
</a>
|
||||
<QBtn
|
||||
class="q-ml-sm"
|
||||
padding="xs"
|
||||
flat
|
||||
color="primary"
|
||||
round
|
||||
icon="cloud_download"
|
||||
@click.stop="downloadFile(invoiceIn.dmsFk)"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('components.smartCard.downloadFile') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</QCardSection>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.supplier')"
|
||||
|
@ -237,19 +236,6 @@ function setData(entity) {
|
|||
{{ t('invoiceIn.pageTitles.basicData') }}
|
||||
<QIcon name="open_in_new" color="primary" />
|
||||
</a>
|
||||
<QBtn
|
||||
class="q-ml-sm"
|
||||
padding="xs"
|
||||
flat
|
||||
color="primary"
|
||||
round
|
||||
icon="cloud_download"
|
||||
@click.stop="downloadFile(invoiceIn.dmsFk)"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('components.smartCard.downloadFile') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</QCardSection>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.issued')"
|
||||
|
@ -274,19 +260,6 @@ function setData(entity) {
|
|||
{{ t('invoiceIn.pageTitles.basicData') }}
|
||||
<QIcon name="open_in_new" color="primary" />
|
||||
</a>
|
||||
<QBtn
|
||||
class="q-ml-sm"
|
||||
padding="xs"
|
||||
flat
|
||||
color="primary"
|
||||
round
|
||||
icon="cloud_download"
|
||||
@click.stop="downloadFile(invoiceIn.dmsFk)"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('components.smartCard.downloadFile') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</QCardSection>
|
||||
<QCardSection class="q-pa-none">
|
||||
<div class="bordered q-px-sm q-mx-auto">
|
||||
|
@ -323,19 +296,6 @@ function setData(entity) {
|
|||
{{ t('invoiceIn.pageTitles.basicData') }}
|
||||
<QIcon name="open_in_new" color="primary" />
|
||||
</a>
|
||||
<QBtn
|
||||
class="q-ml-sm"
|
||||
padding="xs"
|
||||
flat
|
||||
color="primary"
|
||||
round
|
||||
icon="cloud_download"
|
||||
@click.stop="downloadFile(invoiceIn.dmsFk)"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('components.smartCard.downloadFile') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</QCardSection>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.sage')"
|
||||
|
@ -356,8 +316,9 @@ function setData(entity) {
|
|||
</QCard>
|
||||
<!--Vat-->
|
||||
<QCard v-if="invoiceIn.invoiceInTax.length" class="vn-three">
|
||||
<a class="header">
|
||||
<a class="header" :href="`#/invoice-in/${entityId}/vat`">
|
||||
{{ t('invoiceIn.card.vat') }}
|
||||
<QIcon name="open_in_new" color="primary" />
|
||||
</a>
|
||||
<QTable
|
||||
:columns="vatColumns"
|
||||
|
@ -378,7 +339,9 @@ function setData(entity) {
|
|||
<QTd>{{ toCurrency(invoiceIn.totals.totalTaxableBase) }}</QTd>
|
||||
<QTd></QTd>
|
||||
<QTd></QTd>
|
||||
<QTd></QTd>
|
||||
<QTd>{{
|
||||
toCurrency(getTaxTotal(invoiceIn.invoiceInTax))
|
||||
}}</QTd>
|
||||
<QTd></QTd>
|
||||
</QTr>
|
||||
</template>
|
||||
|
@ -386,9 +349,10 @@ function setData(entity) {
|
|||
</QCard>
|
||||
<!--Due Day-->
|
||||
<QCard v-if="invoiceIn.invoiceInDueDay.length" class="vn-two">
|
||||
<div class="header">
|
||||
<a class="header" :href="`#/invoice-in/${entityId}/due-day`">
|
||||
{{ t('invoiceIn.card.dueDay') }}
|
||||
</div>
|
||||
<QIcon name="open_in_new" color="primary" />
|
||||
</a>
|
||||
<QTable
|
||||
class="full-width"
|
||||
:columns="dueDayColumns"
|
||||
|
@ -415,9 +379,10 @@ function setData(entity) {
|
|||
</QCard>
|
||||
<!--Intrastat-->
|
||||
<QCard v-if="invoiceIn.invoiceInIntrastat.length">
|
||||
<div class="header">
|
||||
<a class="header" :href="`#/invoice-in/${entityId}/intrastat`">
|
||||
{{ t('invoiceIn.card.intrastat') }}
|
||||
</div>
|
||||
<QIcon name="open_in_new" color="primary" />
|
||||
</a>
|
||||
<QTable
|
||||
:columns="intrastatColumns"
|
||||
:rows="invoiceIn.invoiceInIntrastat"
|
||||
|
@ -451,7 +416,7 @@ function setData(entity) {
|
|||
}
|
||||
.bordered {
|
||||
border: 1px solid var(--vn-text);
|
||||
width: 18em;
|
||||
max-width: 18em;
|
||||
}
|
||||
</style>
|
||||
<i18n>
|
||||
|
|
Loading…
Reference in New Issue