#6942 improve invoiceIn #220

Merged
jorgep merged 63 commits from 6942-improveInvoceIn into dev 2024-05-29 07:03:46 +00:00
8 changed files with 179 additions and 226 deletions
Showing only changes of commit 5bddc6e04d - Show all commits

View File

@ -11,6 +11,7 @@ import useNotify from 'src/composables/useNotify.js';
import SkeletonForm from 'components/ui/SkeletonForm.vue'; import SkeletonForm from 'components/ui/SkeletonForm.vue';
import VnConfirm from './ui/VnConfirm.vue'; import VnConfirm from './ui/VnConfirm.vue';
import { tMobile } from 'src/composables/tMobile'; import { tMobile } from 'src/composables/tMobile';
import { useArrayData } from 'src/composables/useArrayData';
const { push } = useRouter(); const { push } = useRouter();
const quasar = useQuasar(); const quasar = useQuasar();
@ -85,28 +86,66 @@ const $props = defineProps({
const emit = defineEmits(['onFetch', 'onDataSaved']); const emit = defineEmits(['onFetch', 'onDataSaved']);
const componentIsRendered = ref(false); const componentIsRendered = ref(false);
const arrayData = useArrayData($props.model);
const isLoading = ref(false);
// Si elegimos observar los cambios del form significa que inicialmente las actions estaran deshabilitadas
const isResetting = ref(false);
const hasChanges = ref(!$props.observeFormChanges);
const originalData = ref({});
const formData = computed(() => state.get($props.model));
const formUrl = computed(() => $props.url);
const defaultButtons = computed(() => ({
save: {
color: 'primary',
icon: 'save',
label: 'globals.save',
},
reset: {
color: 'primary',
icon: 'restart_alt',
label: 'globals.reset',
},
...$props.defaultButtons,
}));
onMounted(async () => { onMounted(async () => {
Review

Lo he pasado aquí para que todos los hooks estén agrupados.

Lo he pasado aquí para que todos los hooks estén agrupados.
originalData.value = $props.formInitialData; originalData.value = $props.formInitialData;
Review

Hay que hacerlo así para que se haga una copia, si no, se hace una referencia al mismo objeto.

Hay que hacerlo así para que se haga una copia, si no, se hace una referencia al mismo objeto.
Review

Se podría poner el comentario en código?

Se podría poner el comentario en código?
nextTick(() => {
componentIsRendered.value = true; nextTick(() => (componentIsRendered.value = true));
});
// Podemos enviarle al form la estructura de data inicial sin necesidad de fetchearla // Podemos enviarle al form la estructura de data inicial sin necesidad de fetchearla
state.set($props.model, $props.formInitialData); state.set($props.model, $props.formInitialData);
if ($props.autoLoad && !$props.formInitialData) { if ($props.autoLoad && !$props.formInitialData && $props.url) await fetch();
await fetch(); else if (arrayData.store.data) {
state.set($props.model, arrayData.store.data);
emit('onFetch', state.get($props.model));
} }
// Si así se desea disparamos el watcher del form después de 100ms, asi darle tiempo de que se haya cargado la data inicial
// para evitar que detecte cambios cuando es data inicial default
if ($props.observeFormChanges) { if ($props.observeFormChanges) {
setTimeout(() => { watch(
startFormWatcher(); () => formData.value,
}, 100); (val) => {
hasChanges.value = !isResetting.value && val;
Review

Para ver si hay cambios comparamos el obj actual con el original. Con la lógica anterior, no funcionaba bien si se usa una store, ya que al emitir este valor se 'actualiza'. Así se hace la comprobación correcta.

Para ver si hay cambios comparamos el obj actual con el original. Con la lógica anterior, no funcionaba bien si se usa una store, ya que al emitir este valor se 'actualiza'. Así se hace la comprobación correcta.
Review

Se podría poner el comentario en código?

Se podría poner el comentario en código?
Review

yo lo veo bien sin comentarios. lo que diga @jgallego

yo lo veo bien sin comentarios. lo que diga @jgallego
Review

Yo no pondría comentarios, pero si en otros sitios está implementado distinto yo lo cambiaría para que quien venga detrás coja siempre una buena implementación

Yo no pondría comentarios, pero si en otros sitios está implementado distinto yo lo cambiaría para que quien venga detrás coja siempre una buena implementación
isResetting.value = false;
},
{ deep: true }
);
} }
}); });
if (!$props.url)
watch(
() => arrayData.store.data,
(val) => updateAndEmit(val, 'onFetch')
);
watch(formUrl, async () => {
Review

Agrupado con el resto de hooks.

Agrupado con el resto de hooks.
originalData.value = null;
reset();
fetch();
});
onBeforeRouteLeave((to, from, next) => { onBeforeRouteLeave((to, from, next) => {
Review

Agrupado con el resto de hooks

Agrupado con el resto de hooks
if (hasChanges.value && $props.observeFormChanges) if (hasChanges.value && $props.observeFormChanges)
quasar.dialog({ quasar.dialog({
@ -129,49 +168,14 @@ onUnmounted(() => {
if ($props.clearStoreOnUnmount) state.unset($props.model); if ($props.clearStoreOnUnmount) state.unset($props.model);
}); });
const isLoading = ref(false);
// Si elegimos observar los cambios del form significa que inicialmente las actions estaran deshabilitadas
const isResetting = ref(false);
const hasChanges = ref(!$props.observeFormChanges);
const originalData = ref({});
const formData = computed(() => state.get($props.model));
const formUrl = computed(() => $props.url);
const defaultButtons = computed(() => ({
save: {
color: 'primary',
icon: 'save',
label: 'globals.save',
},
reset: {
color: 'primary',
icon: 'restart_alt',
label: 'globals.reset',
},
...$props.defaultButtons,
}));
const startFormWatcher = () => {
watch(
() => formData.value,
(val) => {
hasChanges.value = !isResetting.value && val;
isResetting.value = false;
},
{ deep: true }
);
};
async function fetch() { async function fetch() {
try { try {
let { data } = await axios.get($props.url, { let { data } = await axios.get($props.url, {
params: { filter: JSON.stringify($props.filter) }, params: { filter: JSON.stringify($props.filter) },
}); });
if (Array.isArray(data)) data = data[0] ?? {}; if (Array.isArray(data)) data = data[0] ?? {};
state.set($props.model, data); updateAndEmit(data, 'onFetch');
originalData.value = data && JSON.parse(JSON.stringify(data));
emit('onFetch', state.get($props.model));
} catch (error) { } catch (error) {
state.set($props.model, {}); state.set($props.model, {});
originalData.value = {}; originalData.value = {};
@ -179,31 +183,30 @@ async function fetch() {
} }
async function save() { async function save() {
if ($props.observeFormChanges && !hasChanges.value) { if ($props.observeFormChanges && !hasChanges.value)
notify('globals.noChanges', 'negative'); return notify('globals.noChanges', 'negative');
return;
}
isLoading.value = true;
isLoading.value = true;
try { try {
Review

En mi opinión queda mucho más legible así, aunque solo se use 1 vez.

En mi opinión queda mucho más legible así, aunque solo se use 1 vez.
const body = $props.mapper ? $props.mapper(formData.value) : formData.value; const body = $props.mapper ? $props.mapper(formData.value) : formData.value;
const method = $props.urlCreate ? 'post' : 'patch';
const url =
$props.urlCreate || $props.urlUpdate || $props.url || arrayData.store.url;
let response; let response;
if ($props.saveFn) response = await $props.saveFn(body); if ($props.saveFn) response = await $props.saveFn(body);
else else response = await axios[method](url, body);
response = await axios[$props.urlCreate ? 'post' : 'patch'](
$props.urlCreate || $props.urlUpdate || $props.url,
body
);
if ($props.urlCreate) notify('globals.dataCreated', 'positive'); if ($props.urlCreate) notify('globals.dataCreated', 'positive');
emit('onDataSaved', formData.value, response?.data); updateAndEmit(response?.data, 'onDataSaved');
originalData.value = JSON.parse(JSON.stringify(formData.value));
hasChanges.value = false; hasChanges.value = false;
} catch (err) { } catch (err) {
console.error(err); console.error(err);
notify('errors.writeRequest', 'negative'); notify('errors.writeRequest', 'negative');
} } finally {
isLoading.value = false; isLoading.value = false;
}
} }
async function saveAndGo() { async function saveAndGo() {
@ -212,10 +215,7 @@ async function saveAndGo() {
} }
function reset() { function reset() {
state.set($props.model, originalData.value); updateAndEmit(originalData.value, 'onFetch');
originalData.value = JSON.parse(JSON.stringify(originalData.value));
emit('onFetch', state.get($props.model));
if ($props.observeFormChanges) { if ($props.observeFormChanges) {
hasChanges.value = false; hasChanges.value = false;
isResetting.value = true; isResetting.value = true;
@ -237,17 +237,15 @@ function filter(value, update, filterOptions) {
); );
Review

Esta parte se repetía varias veces

Esta parte se repetía varias veces
} }
watch(formUrl, async () => { function updateAndEmit(val, evt) {
originalData.value = null; state.set($props.model, val);
reset(); originalData.value = val && JSON.parse(JSON.stringify(val));
fetch(); if (!$props.url) arrayData.store.data = val;
});
defineExpose({ emit(evt, state.get($props.model));
save, }
isLoading,
hasChanges, defineExpose({ save, isLoading, hasChanges });
});
</script> </script>
<template> <template>
<div class="column items-center full-width"> <div class="column items-center full-width">

View File

@ -49,12 +49,13 @@ const { store } = arrayData;
const entity = computed(() => (Array.isArray(store.data) ? store.data[0] : store.data)); const entity = computed(() => (Array.isArray(store.data) ? store.data[0] : store.data));
const isLoading = ref(false); const isLoading = ref(false);
defineExpose({ defineExpose({ getData });
getData,
});
onBeforeMount(async () => { onBeforeMount(async () => {
await getData(); await getData();
watch($props, async () => await getData()); watch(
() => [$props.url, $props.filter],
async () => await getData()
);
}); });
Review

Permite cargar los datos solo una vez si el módulo es el mismo que dataKey

Permite cargar los datos solo una vez si el módulo es el mismo que dataKey
Review

Se podría poner el comentario en código?

Se podría poner el comentario en código?
async function getData() { async function getData() {

View File

@ -24,6 +24,7 @@ globals:
create: Create create: Create
edit: Edit edit: Edit
save: Save save: Save
saveAndContinue: Save and continue
remove: Remove remove: Remove
reset: Reset reset: Reset
close: Close close: Close

View File

@ -24,6 +24,7 @@ globals:
create: Crear create: Crear
edit: Modificar edit: Modificar
save: Guardar save: Guardar
saveAndContinue: Guardar y continuar
remove: Eliminar remove: Eliminar
reset: Restaurar reset: Restaurar
close: Cerrar close: Cerrar

View File

@ -1,6 +1,6 @@
<script setup> <script setup>
import { ref, computed } from 'vue'; import { ref, computed } from 'vue';
import { useRouter } from 'vue-router'; import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useQuasar } from 'quasar'; import { useQuasar } from 'quasar';
import axios from 'axios'; import axios from 'axios';
@ -14,15 +14,13 @@ import VnInputDate from 'src/components/common/VnInputDate.vue';
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
const quasar = useQuasar(); const quasar = useQuasar();
const { currentRoute } = useRouter();
const { t } = useI18n(); const { t } = useI18n();
const dms = ref({}); const dms = ref({});
const editDownloadDisabled = ref(false); const editDownloadDisabled = ref(false);
const arrayData = useArrayData('InvoiceIn'); const invoiceIn = computed(() => useArrayData('InvoiceIn').store.data);
const invoiceIn = computed(() => arrayData.store.data);
const userConfig = ref(null); const userConfig = ref(null);
const invoiceId = currentRoute.value.params.id; const invoiceId = computed(() => +useRoute().params.id);
const expenses = ref([]); const expenses = ref([]);
const currencies = ref([]); const currencies = ref([]);
@ -180,13 +178,7 @@ async function upsert() {
auto-load auto-load
@on-fetch="(data) => (sageWithholdings = data)" @on-fetch="(data) => (sageWithholdings = data)"
/> />
<FormModel <FormModel model="InvoiceIn" :go-to="`/invoice-in/${invoiceId}/vat`" auto-load>
v-if="invoiceIn"
:url="`InvoiceIns/${invoiceId}`"
model="InvoiceIn"
:go-to="`/invoice-in/${invoiceId}/vat`"
auto-load
>
<template #form="{ data }"> <template #form="{ data }">
<VnRow> <VnRow>
<VnSelect <VnSelect

View File

@ -6,7 +6,6 @@ import { useQuasar } from 'quasar';
import axios from 'axios'; import axios from 'axios';
import { toCurrency, toDate } from 'src/filters'; import { toCurrency, toDate } from 'src/filters';
import { useRole } from 'src/composables/useRole'; import { useRole } from 'src/composables/useRole';
import useCardDescription from 'src/composables/useCardDescription';
import { downloadFile } from 'src/composables/downloadFile'; import { downloadFile } from 'src/composables/downloadFile';
import { useArrayData } from 'src/composables/useArrayData'; import { useArrayData } from 'src/composables/useArrayData';
import { usePrintService } from 'composables/usePrintService'; import { usePrintService } from 'composables/usePrintService';
@ -20,9 +19,7 @@ import { useCapitalize } from 'src/composables/useCapitalize';
import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue'; import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
import InvoiceInToBook from '../InvoiceInToBook.vue'; import InvoiceInToBook from '../InvoiceInToBook.vue';
const $props = defineProps({ const $props = defineProps({ id: { type: Number, default: null } });
id: { type: Number, default: null },
});
const { push, currentRoute } = useRouter(); const { push, currentRoute } = useRouter();
@ -33,7 +30,6 @@ const { openReport, sendEmail } = usePrintService();
const { store } = useArrayData('InvoiceIn'); const { store } = useArrayData('InvoiceIn');
const invoiceIn = computed(() => store.data); const invoiceIn = computed(() => store.data);
const isBooked = ref();
const cardDescriptorRef = ref(); const cardDescriptorRef = ref();
const correctionDialogRef = ref(); const correctionDialogRef = ref();
const entityId = computed(() => $props.id || +currentRoute.value.params.id); const entityId = computed(() => $props.id || +currentRoute.value.params.id);
@ -92,11 +88,7 @@ const filter = {
}, },
], ],
}; };
const data = ref(useCardDescription()); const invoiceInCorrection = reactive({ correcting: [], corrected: null });
const invoiceInCorrection = reactive({
correcting: [],
corrected: null,
});
const routes = reactive({ const routes = reactive({
getSupplier: (id) => { getSupplier: (id) => {
return { name: 'SupplierCard', params: { id } }; return { name: 'SupplierCard', params: { id } };
@ -177,16 +169,9 @@ async function setInvoiceCorrection(id) {
); );
} }
async function setData(entity) { async function setTotals() {
data.value = useCardDescription(entity.supplierRef, entity.id);
isBooked.value = entity.isBooked;
const { totalDueDay } = await getTotals();
totalAmount.value = totalDueDay;
}
async function getTotals() {
const { data } = await axios.get(`InvoiceIns/${entityId.value}/getTotals`); const { data } = await axios.get(`InvoiceIns/${entityId.value}/getTotals`);
return data; totalAmount.value = data.totalDueDay;
} }
function openDialog() { function openDialog() {
@ -303,16 +288,17 @@ const createInvoiceInCorrection = async () => {
auto-load auto-load
/> />
<CardDescriptor <CardDescriptor
v-if="invoiceIn"
ref="cardDescriptorRef" ref="cardDescriptorRef"
module="InvoiceIn" module="InvoiceIn"
:url="`InvoiceIns/${entityId}`" :url="`InvoiceIns/${entityId}`"
:filter="filter" :filter="filter"
:title="data.title" :title="invoiceIn.supplierRef"
:subtitle="data.subtitle" :subtitle="invoiceIn.id"
@on-fetch="setData" data-key="InvoiceIn"
data-key="invoiceInData" @on-fetch="setTotals"
> >
<template #menu="{ entity }"> <template #menu>
<InvoiceInToBook> <InvoiceInToBook>
<template #content="{ book }"> <template #content="{ book }">
<QItem <QItem
@ -378,17 +364,20 @@ const createInvoiceInCorrection = async () => {
<QItemSection>{{ t('Create rectificative invoice') }}...</QItemSection> <QItemSection>{{ t('Create rectificative invoice') }}...</QItemSection>
</QItem> </QItem>
<QItem <QItem
v-if="entity.dmsFk" v-if="invoiceIn.dmsFk"
v-ripple v-ripple
clickable clickable
@click="downloadFile(entity.dmsFk)" @click="downloadFile(invoiceIn.dmsFk)"
> >
<QItemSection>{{ t('components.smartCard.downloadFile') }}</QItemSection> <QItemSection>{{ t('components.smartCard.downloadFile') }}</QItemSection>
</QItem> </QItem>
</template> </template>
<template #body="{ entity }"> <template #body>
<VnLv :label="t('invoiceIn.card.issued')" :value="toDate(entity.issued)" /> <VnLv :label="t('invoiceIn.card.issued')" :value="toDate(invoiceIn.issued)" />
<VnLv :label="t('invoiceIn.summary.booked')" :value="toDate(entity.booked)" /> <VnLv
:label="t('invoiceIn.summary.booked')"
:value="toDate(invoiceIn.booked)"
/>
<VnLv :label="t('invoiceIn.card.amount')" :value="toCurrency(totalAmount)" /> <VnLv :label="t('invoiceIn.card.amount')" :value="toCurrency(totalAmount)" />
<VnLv :label="t('invoiceIn.summary.supplier')"> <VnLv :label="t('invoiceIn.summary.supplier')">
<template #value> <template #value>
@ -399,13 +388,13 @@ const createInvoiceInCorrection = async () => {
</template> </template>
</VnLv> </VnLv>
</template> </template>
<template #actions="{ entity }"> <template #action>
<QCardActions> <QCardActions>
<QBtn <QBtn
size="md" size="md"
icon="vn:supplier" icon="vn:supplier"
color="primary" color="primary"
:to="routes.getSupplier(entity.supplierFk)" :to="routes.getSupplier(invoiceIn.supplierFk)"
> >
<QTooltip>{{ t('invoiceIn.list.supplier') }}</QTooltip> <QTooltip>{{ t('invoiceIn.list.supplier') }}</QTooltip>
</QBtn> </QBtn>
@ -413,7 +402,7 @@ const createInvoiceInCorrection = async () => {
size="md" size="md"
icon="vn:entry" icon="vn:entry"
color="primary" color="primary"
:to="routes.getEntry(entity.entryFk)" :to="routes.getEntry(invoiceIn.entryFk)"
> >
<QTooltip>{{ t('Entry') }}</QTooltip> <QTooltip>{{ t('Entry') }}</QTooltip>
</QBtn> </QBtn>
@ -421,7 +410,7 @@ const createInvoiceInCorrection = async () => {
size="md" size="md"
icon="vn:ticket" icon="vn:ticket"
color="primary" color="primary"
:to="routes.getTickets(entity.supplierFk)" :to="routes.getTickets(invoiceIn.supplierFk)"
> >
<QTooltip>{{ t('invoiceOut.card.ticketList') }}</QTooltip> <QTooltip>{{ t('invoiceOut.card.ticketList') }}</QTooltip>
</QBtn> </QBtn>

View File

@ -11,7 +11,7 @@ import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorP
import InvoiceIntoBook from '../InvoiceInToBook.vue'; import InvoiceIntoBook from '../InvoiceInToBook.vue';
import VnTitle from 'src/components/common/VnTitle.vue'; import VnTitle from 'src/components/common/VnTitle.vue';
const props = defineProps({ id: { type: Number, default: 0 } }); const props = defineProps({ id: { type: [Number, String], default: 0 } });
const { t } = useI18n(); const { t } = useI18n();
const entityId = computed(() => props.id || useRoute().params.id); const entityId = computed(() => props.id || useRoute().params.id);
@ -20,7 +20,6 @@ const invoiceIn = computed(() => useArrayData('InvoiceIn').store.data);
const invoiceInUrl = ref(); const invoiceInUrl = ref();
const amountsNotMatch = ref(null); const amountsNotMatch = ref(null);
const intrastatTotals = ref({ amount: 0, net: 0, stems: 0 }); const intrastatTotals = ref({ amount: 0, net: 0, stems: 0 });
const isBooked = ref();
const vatColumns = ref([ const vatColumns = ref([
{ {
@ -156,37 +155,26 @@ onMounted(async () => {
invoiceInUrl.value = `${await getUrl('')}invoiceIn/${entityId.value}/`; invoiceInUrl.value = `${await getUrl('')}invoiceIn/${entityId.value}/`;
}); });
function getAmountNotMatch(totals) {
return (
totals.totalDueDay != totals.totalTaxableBase &&
totals.totalDueDay != totals.totalVat
);
}
function getTaxTotal(tax) {
return tax.reduce(
(acc, cur) => acc + taxRate(cur.taxableBase, cur.taxTypeSage?.rate),
0
);
}
const init = (data) => { const init = (data) => {
if (!data) return; if (!data) return;
isBooked.value = data.isBooked; const { totals, invoiceInIntrastat } = data;
amountsNotMatch.value = getAmountNotMatch(data.totals); amountsNotMatch.value =
totals.totalDueDay != totals.totalTaxableBase &&
totals.totalDueDay != totals.totalVat;
if (data.invoiceInIntrastat.length) { invoiceInIntrastat.forEach((val) => {
data.invoiceInIntrastat.forEach((val) => {
intrastatTotals.value.amount += val.amount; intrastatTotals.value.amount += val.amount;
intrastatTotals.value.net += val.net; intrastatTotals.value.net += val.net;
intrastatTotals.value.stems += val.stems; intrastatTotals.value.stems += val.stems;
}); });
}
}; };
const taxRate = (taxableBase = 0, rate = 0) => (rate / 100) * taxableBase; const taxRate = (taxableBase = 0, rate = 0) => (rate / 100) * taxableBase;
const getTotalTax = (tax) =>
tax.reduce((acc, cur) => acc + taxRate(cur.taxableBase, cur.taxTypeSage?.rate), 0);
const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`; const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
</script> </script>
@ -199,7 +187,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
<template #header="{ entity }"> <template #header="{ entity }">
<div>{{ entity.id }} - {{ entity.supplier?.name }}</div> <div>{{ entity.id }} - {{ entity.supplier?.name }}</div>
</template> </template>
<template #header-right v-if="!isBooked"> <template #header-right v-if="!invoiceIn?.isBooked">
<InvoiceIntoBook> <InvoiceIntoBook>
<template #content="{ book }"> <template #content="{ book }">
<QBtn <QBtn
@ -288,11 +276,9 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
:label="t('invoiceIn.summary.company')" :label="t('invoiceIn.summary.company')"
:value="entity.company?.code" :value="entity.company?.code"
/> />
<QCheckbox <VnLv
v-if="invoiceIn"
:label="t('invoiceIn.summary.booked')" :label="t('invoiceIn.summary.booked')"
v-model="invoiceIn.isBooked" :value="invoiceIn.isBooked"
:disable="true"
/> />
</QCard> </QCard>
<QCard class="vn-one"> <QCard class="vn-one">
@ -352,7 +338,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
<QTd>{{ toCurrency(entity.totals.totalTaxableBase) }}</QTd> <QTd>{{ toCurrency(entity.totals.totalTaxableBase) }}</QTd>
<QTd></QTd> <QTd></QTd>
<QTd></QTd> <QTd></QTd>
<QTd>{{ toCurrency(getTaxTotal(entity.invoiceInTax)) }}</QTd> <QTd>{{ toCurrency(getTotalTax(entity.invoiceInTax)) }}</QTd>
<QTd></QTd> <QTd></QTd>
</QTr> </QTr>
</template> </template>

View File

@ -4,33 +4,17 @@ import { useI18n } from 'vue-i18n';
import VnSelect from 'components/common/VnSelect.vue'; import VnSelect from 'components/common/VnSelect.vue';
Review

Se han reordenado los campos en base a como están en Salix.

Se han reordenado los campos en base a como están en Salix.
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue'; import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
import FetchData from 'components/FetchData.vue';
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
import VnInputDate from 'components/common/VnInputDate.vue'; import VnInputDate from 'components/common/VnInputDate.vue';
import VnCurrency from 'src/components/common/VnCurrency.vue'; import VnCurrency from 'src/components/common/VnCurrency.vue';
const { t } = useI18n(); const { t } = useI18n();
const props = defineProps({ defineProps({ dataKey: { type: String, required: true } });
dataKey: {
type: String,
required: true,
},
});
const suppliers = ref([]); const suppliers = ref([]);
const suppliersRef = ref();
</script> </script>
<template> <template>
<FetchData <VnFilterPanel :data-key="dataKey" :search-button="true">
ref="suppliersRef"
url="Suppliers"
:filter="{ fields: ['id', 'nickname'] }"
order="nickname"
limit="30"
@on-fetch="(data) => (suppliers = data)"
auto-load
/>
<VnFilterPanel :data-key="props.dataKey" :search-button="true">
<template #tags="{ tag, formatFn }"> <template #tags="{ tag, formatFn }">
<div class="q-gutter-x-xs"> <div class="q-gutter-x-xs">
<strong>{{ t(`params.${tag.label}`) }}: </strong> <strong>{{ t(`params.${tag.label}`) }}: </strong>
@ -38,22 +22,6 @@ const suppliersRef = ref();
</div> </div>
</template> </template>
<template #body="{ params, searchFn }"> <template #body="{ params, searchFn }">
<QItem>
<QItemSection>
<VnSelect
:label="t('params.supplierFk')"
v-model="params.supplierFk"
:options="suppliers"
option-value="id"
option-label="nickname"
@input-value="suppliersRef.fetch()"
dense
outlined
rounded
>
</VnSelect>
</QItemSection>
</QItem>
<QItem> <QItem>
<QItemSection> <QItemSection>
<VnInput <VnInput
@ -68,21 +36,11 @@ const suppliersRef = ref();
</VnInput> </VnInput>
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem>
<QItemSection>
<VnInputDate :label="t('From')" v-model="params.from" is-outlined />
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInputDate :label="t('To')" v-model="params.to" is-outlined />
</QItemSection>
</QItem>
<QItem> <QItem>
<QItemSection> <QItemSection>
<VnInput <VnInput
:label="t('params.serial')" :label="t('params.fi')"
v-model="params.serial" v-model="params.fi"
is-outlined is-outlined
lazy-rules lazy-rules
> >
@ -92,11 +50,61 @@ const suppliersRef = ref();
</VnInput> </VnInput>
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem>
<QItemSection>
<VnSelect
Review

Se corrige el filtrado de suppliers.

Se corrige el filtrado de suppliers.
v-model="params.supplierFk"
url="Suppliers"
:fields="['id', 'nickname']"
:label="t('params.supplierFk')"
option-value="id"
option-label="nickname"
:options="suppliers"
dense
outlined
rounded
>
</VnSelect>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInput
:label="t('params.account')"
v-model="params.account"
is-outlined
lazy-rules
>
<template #prepend>
<QIcon name="person" size="sm" />
</template>
</VnInput>
</QItemSection>
</QItem>
<QItem> <QItem>
<QItemSection> <QItemSection>
<VnCurrency v-model="params.amount" is-outlined /> <VnCurrency v-model="params.amount" is-outlined />
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem>
<QItemSection>
<VnInputDate :label="t('From')" v-model="params.from" is-outlined />
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInputDate :label="t('To')" v-model="params.to" is-outlined />
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInputDate
:label="t('Issued')"
v-model="params.issued"
is-outlined
/>
</QItemSection>
</QItem>
<QItem class="q-mb-md"> <QItem class="q-mb-md">
<QItemSection> <QItemSection>
<QCheckbox <QCheckbox
@ -111,8 +119,8 @@ const suppliersRef = ref();
<QItem> <QItem>
<QItemSection> <QItemSection>
<VnInput <VnInput
:label="t('params.fi')" :label="t('params.serialNumber')"
v-model="params.fi" v-model="params.serialNumber"
is-outlined is-outlined
lazy-rules lazy-rules
> >
@ -125,8 +133,8 @@ const suppliersRef = ref();
<QItem> <QItem>
<QItemSection> <QItemSection>
<VnInput <VnInput
:label="t('params.serialNumber')" :label="t('params.serial')"
v-model="params.serialNumber" v-model="params.serial"
is-outlined is-outlined
lazy-rules lazy-rules
> >
@ -150,29 +158,6 @@ const suppliersRef = ref();
</VnInput> </VnInput>
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem>
<QItemSection>
<VnInput
:label="t('params.account')"
v-model="params.account"
is-outlined
lazy-rules
>
<template #prepend>
<QIcon name="person" size="sm" />
</template>
</VnInput>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInputDate
:label="t('Issued')"
v-model="params.issued"
is-outlined
/>
</QItemSection>
</QItem>
</QExpansionItem> </QExpansionItem>
</template> </template>
</VnFilterPanel> </VnFilterPanel>