forked from verdnatura/salix-front
fix: refs #6942 wip: formModel
This commit is contained in:
parent
467531d029
commit
5bddc6e04d
|
@ -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 () => {
|
||||||
originalData.value = $props.formInitialData;
|
originalData.value = $props.formInitialData;
|
||||||
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;
|
||||||
|
isResetting.value = false;
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!$props.url)
|
||||||
|
watch(
|
||||||
|
() => arrayData.store.data,
|
||||||
|
(val) => updateAndEmit(val, 'onFetch')
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(formUrl, async () => {
|
||||||
|
originalData.value = null;
|
||||||
|
reset();
|
||||||
|
fetch();
|
||||||
|
});
|
||||||
|
|
||||||
onBeforeRouteLeave((to, from, next) => {
|
onBeforeRouteLeave((to, from, next) => {
|
||||||
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,32 +183,31 @@ 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 {
|
||||||
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() {
|
||||||
await save();
|
await save();
|
||||||
|
@ -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) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
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">
|
||||||
|
|
|
@ -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()
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
async function getData() {
|
async function getData() {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -4,33 +4,17 @@ import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import VnSelect from 'components/common/VnSelect.vue';
|
import VnSelect from 'components/common/VnSelect.vue';
|
||||||
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
|
||||||
|
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>
|
||||||
|
|
Loading…
Reference in New Issue