fix: refs #8388 update VnTable integration in InvoiceInDueDay component and enhance input handling
gitea/salix-front/pipeline/pr-dev This commit is unstable Details

This commit is contained in:
Jorge Penadés 2025-04-23 18:29:53 +02:00
parent 50cf47436c
commit eb373f10b3
2 changed files with 111 additions and 178 deletions

View File

@ -432,6 +432,7 @@ async function renderInput(rowId, field, clickedElement) {
const row = CrudModelRef.value.formData[rowId]; const row = CrudModelRef.value.formData[rowId];
const oldValue = CrudModelRef.value.formData[rowId][column?.name]; const oldValue = CrudModelRef.value.formData[rowId][column?.name];
if (column.disable) return;
if (!clickedElement) if (!clickedElement)
clickedElement = document.querySelector( clickedElement = document.querySelector(
`[data-row-index="${rowId}"][data-col-field="${field}"]`, `[data-row-index="${rowId}"][data-col-field="${field}"]`,

View File

@ -6,81 +6,107 @@ import axios from 'axios';
import { toDate } from 'src/filters'; import { toDate } from 'src/filters';
import { useArrayData } from 'src/composables/useArrayData'; import { useArrayData } from 'src/composables/useArrayData';
import { getTotal } from 'src/composables/getTotal'; import { getTotal } from 'src/composables/getTotal';
import CrudModel from 'src/components/CrudModel.vue'; // import CrudModel from 'src/components/CrudModel.vue'; // Removed CrudModel import
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
import useNotify from 'src/composables/useNotify.js'; import useNotify from 'src/composables/useNotify.js';
import VnInputDate from 'src/components/common/VnInputDate.vue'; import VnInputDate from 'src/components/common/VnInputDate.vue';
import VnInputNumber from 'src/components/common/VnInputNumber.vue'; import VnInputNumber from 'src/components/common/VnInputNumber.vue';
import { toCurrency } from 'filters/index'; import { toCurrency } from 'filters/index';
import VnTable from 'src/components/VnTable/VnTable.vue'; // Added VnTable import
const route = useRoute(); const route = useRoute();
const { notify } = useNotify(); const { notify } = useNotify(); // Keep notify if used elsewhere, otherwise remove
const { t } = useI18n(); const { t } = useI18n();
const arrayData = useArrayData(); const arrayData = useArrayData();
const invoiceIn = computed(() => arrayData.store.data); const invoiceIn = computed(() => arrayData.store.data);
const currency = computed(() => invoiceIn.value?.currency?.code); const currency = computed(() => invoiceIn.value?.currency?.code);
const rowsSelected = ref([]); const rowsSelected = ref([]);
const invoiceInFormRef = ref(); const invoiceInDueDayTableRef = ref(); // Renamed ref for VnTable
const invoiceId = +route.params.id; const invoiceId = +route.params.id;
const filter = { where: { invoiceInFk: invoiceId } }; const filter = { where: { invoiceInFk: invoiceId } };
const areRows = ref(false); const areRows = ref(false);
const totalTaxableBase = ref(); const totalTaxableBase = ref();
const totalVat = ref(); const totalVat = ref();
// Access formData from VnTable's internal CrudModelRef
const tableRows = computed(
() => invoiceInDueDayTableRef.value?.CrudModelRef?.formData || [],
);
const totalAmount = computed(() => getTotal(tableRows.value, 'amount'));
const noMatch = computed( const noMatch = computed(
() => () =>
totalAmount.value != totalTaxableBase.value && totalAmount.value != totalTaxableBase.value &&
totalAmount.value != totalVat.value, totalAmount.value != totalVat.value,
); );
const columns = computed(() => [ const columns = computed(() => [
{ {
name: 'duedate', name: 'dueDated',
label: t('Date'), label: t('Date'),
field: (row) => toDate(row.dueDated),
sortable: true, sortable: true,
tabIndex: 1, tabIndex: 1,
align: 'left', align: 'left',
component: 'date',
isEditable: true,
create: true,
}, },
{ {
name: 'bank', name: 'bankFk',
label: t('Bank'), label: t('Bank'),
field: (row) => row.bankFk,
model: 'bankFk',
optionLabel: 'bank',
url: 'Accountings',
sortable: true, sortable: true,
tabIndex: 2, tabIndex: 2,
align: 'left', align: 'left',
component: 'select',
attrs: {
url: 'Accountings',
optionLabel: 'bank',
optionValue: 'id',
fields: ['id', 'bank'],
'emit-value': true,
},
format: ({ bank }) => bank?.bank,
isEditable: true,
create: true,
}, },
{ {
name: 'amount', name: 'amount',
label: t('Amount'), label: t('Amount'),
field: (row) => row.amount,
sortable: true, sortable: true,
tabIndex: 3, tabIndex: 3,
align: 'left', align: 'left',
component: 'number',
attrs: {
clearable: true,
'clear-icon': 'close',
},
isEditable: true,
create: true,
}, },
{ {
name: 'foreignvalue', name: 'foreignValue',
label: t('Foreign value'), label: t('Foreign value'),
field: (row) => row.foreignValue,
sortable: true, sortable: true,
tabIndex: 4, tabIndex: 4,
align: 'left', align: 'left',
component: 'number',
isEditable: true,
create: true,
disable: true,
}, },
]); ]);
const totalAmount = computed(() => getTotal(invoiceInFormRef.value.formData, 'amount'));
const isNotEuro = (code) => code != 'EUR'; const isNotEuro = (code) => code != 'EUR';
async function insert() { async function insert() {
await axios.post('/InvoiceInDueDays/new', { id: +invoiceId }); await axios.post('/InvoiceInDueDays/new', { id: +invoiceId });
await invoiceInFormRef.value.reload(); await invoiceInDueDayTableRef.value.reload();
notify(t('globals.dataSaved'), 'positive'); notify(t('globals.dataSaved'), 'positive');
} }
async function setTaxableBase() { async function setTaxableBase() {
const ref = invoiceInDueDayTableRef.value;
if (ref) ref.create = null;
const { data } = await axios.get(`InvoiceIns/${invoiceId}/getTotals`); const { data } = await axios.get(`InvoiceIns/${invoiceId}/getTotals`);
totalTaxableBase.value = data.totalTaxableBase; totalTaxableBase.value = data.totalTaxableBase;
totalVat.value = data.totalVat; totalVat.value = data.totalVat;
@ -89,189 +115,93 @@ async function setTaxableBase() {
onBeforeMount(async () => await setTaxableBase()); onBeforeMount(async () => await setTaxableBase());
</script> </script>
<template> <template>
<CrudModel <VnTable
v-if="invoiceIn" v-if="invoiceIn"
ref="invoiceInFormRef" ref="invoiceInDueDayTableRef"
data-key="InvoiceInDueDays" data-key="InvoiceInDueDays"
url="InvoiceInDueDays" url="InvoiceInDueDays"
save-url="InvoiceInDueDays/crud"
:filter="filter" :filter="filter"
:user-filter="{
include: { relation: 'bank', scope: { fields: ['id', 'bank'] } },
}"
auto-load auto-load
:data-required="{ invoiceInFk: invoiceId }" :data-required="{ invoiceInFk: invoiceId }"
v-model:selected="rowsSelected" v-model:selected="rowsSelected"
@on-fetch="(data) => (areRows = !!data.length)" @on-fetch="(data) => (areRows = !!data.length)"
@save-changes="setTaxableBase" @save-changes="setTaxableBase"
:columns="columns"
:is-editable="true"
:table="{ selection: 'multiple', 'row-key': '$index' }"
footer
:right-search="false"
:column-search="false"
:disable-option="{ card: true }"
class="q-pa-none"
> >
<template #body="{ rows }"> <!-- <template #column-foreignValue="{ row }">
<QTable <VnInputNumber
v-model:selected="rowsSelected" :class="{
selection="multiple" 'no-pointer-events': !isNotEuro(currency),
:columns }"
:rows :disable="!isNotEuro(currency)"
row-key="$index" v-model="row.foreignValue"
:grid="$q.screen.lt.sm" dense
borderless
hide-bottom-space
/>
</template> -->
<template #column-footer-amount>
<QChip
dense
:color="noMatch ? 'negative' : 'transparent'"
class="q-pa-xs"
:title="noMatch ? t('invoiceIn.noMatch', { totalTaxableBase }) : ''"
> >
<template #body-cell-duedate="{ row }"> {{ toCurrency(totalAmount) }}
<QTd> </QChip>
<VnInputDate v-model="row.dueDated" />
</QTd>
</template>
<template #body-cell-bank="{ row, col }">
<QTd>
<VnSelect
v-model="row[col.model]"
:url="col.url"
:option-label="col.optionLabel"
:option-value="col.optionValue"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{
`${scope.opt.id}: ${scope.opt.bank}`
}}</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelect>
</QTd>
</template>
<template #body-cell-amount="{ row }">
<QTd>
<VnInputNumber
v-model="row.amount"
:is-outlined="false"
clearable
clear-icon="close"
/>
</QTd>
</template>
<template #body-cell-foreignvalue="{ row }">
<QTd>
<VnInputNumber
:class="{
'no-pointer-events': !isNotEuro(currency),
}"
:disable="!isNotEuro(currency)"
v-model="row.foreignValue"
/>
</QTd>
</template>
<template #bottom-row>
<QTr class="bg">
<QTd />
<QTd />
<QTd />
<QTd>
<QChip
dense
:color="noMatch ? 'negative' : 'transparent'"
class="q-pa-xs"
:title="
noMatch
? t('invoiceIn.noMatch', { totalTaxableBase })
: ''
"
>
{{ toCurrency(totalAmount) }}
</QChip>
</QTd>
<QTd>
<template v-if="isNotEuro(invoiceIn.currency.code)">
{{
getTotal(rows, 'foreignValue', {
currency: invoiceIn.currency.code,
})
}}
</template>
</QTd>
</QTr>
</template>
<template #item="props">
<div class="q-pa-xs col-xs-12 col-sm-6 grid-style-transition">
<QCard>
<QCardSection>
<QCheckbox v-model="props.selected" dense />
</QCardSection>
<QSeparator />
<QList>
<QItem>
<VnInputDate
class="full-width"
:label="t('Date')"
v-model="props.row.dueDated"
/>
</QItem>
<QItem>
<VnSelect
:label="t('Bank')"
class="full-width"
v-model="props.row['bankFk']"
url="Accountings"
option-label="bank"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{
`${scope.opt.id}: ${scope.opt.bank}`
}}</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelect>
</QItem>
<QItem>
<VnInputNumber
:label="t('Amount')"
class="full-width"
v-model="props.row.amount"
/>
</QItem>
<QItem>
<VnInputNumber
:label="t('Foreign value')"
class="full-width"
:class="{
'no-pointer-events': !isNotEuro(currency),
}"
:disable="!isNotEuro(currency)"
v-model="props.row.foreignValue"
clearable
clear-icon="close"
/>
</QItem>
</QList>
</QCard>
</div>
</template>
</QTable>
</template> </template>
</CrudModel> <template #column-footer-foreignValue>
<QPageSticky position="bottom-right" :offset="[25, 25]"> <template v-if="isNotEuro(currency)">
{{
getTotal(tableRows, 'foreignValue', {
currency: currency,
})
}}
</template>
</template>
</VnTable>
<QPageSticky :offset="[20, 20]" style="z-index: 2">
<QBtn <QBtn
color="primary"
icon="add"
v-shortcut="'+'"
size="lg"
round
@click=" @click="
() => { () => {
if (!areRows) insert(); if (!areRows) return insert();
else
invoiceInFormRef.insert({ invoiceInDueDayTableRef.create = {
amount: (totalTaxableBase - totalAmount).toFixed(2), urlCreate: 'InvoiceInDueDays',
onDataSaved: () => invoiceInDueDayTableRef.reload(),
title: t('Create due day'),
formInitialData: {
invoiceInFk: invoiceId, invoiceInFk: invoiceId,
}); dueDated: Date.vnNew(),
amount: (totalTaxableBase - totalAmount).toFixed(2),
},
};
invoiceInDueDayTableRef.showForm = true;
} }
" "
color="primary"
fab
icon="add"
v-shortcut="'+'"
data-cy="invoiceInDueDayAdd"
/> />
<QTooltip class="text-no-wrap">
{{ t('Create due day') }}
</QTooltip>
</QPageSticky> </QPageSticky>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.bg {
background-color: var(--vn-light-gray);
}
.q-chip { .q-chip {
color: var(--vn-text-color); color: var(--vn-text-color);
} }
@ -282,4 +212,6 @@ onBeforeMount(async () => await setTaxableBase());
Bank: Caja Bank: Caja
Amount: Importe Amount: Importe
Foreign value: Divisa Foreign value: Divisa
invoiceIn.noMatch: El total {totalTaxableBase} no coincide con el importe
Create due day: Crear Vencimiento
</i18n> </i18n>