0
0
Fork 0

Entry buys import

This commit is contained in:
William Buezas 2024-01-16 16:11:23 -03:00
parent 596904c4f8
commit 64a4a800f7
5 changed files with 307 additions and 2 deletions

View File

@ -325,6 +325,15 @@ export default {
buys: {
groupingPrice: 'Grouping price',
packingPrice: 'Packing price',
reference: 'Reference',
observations: 'Observations',
item: 'Item',
description: 'Description',
size: 'Size',
packing: 'Packing',
grouping: 'Grouping',
buyingValue: 'Buying value',
packagingFk: 'Box',
},
},
ticket: {

View File

@ -324,6 +324,15 @@ export default {
buys: {
groupingPrice: 'Precio grouping',
packingPrice: 'Precio packing',
reference: 'Referencia',
observations: 'Observaciónes',
item: 'Artículo',
description: 'Descripción',
size: 'Medida',
packing: 'Packing',
grouping: 'Grouping',
buyingValue: 'Coste',
packagingFk: 'Embalaje',
},
},
ticket: {

View File

@ -1,6 +1,6 @@
<script setup>
import { ref, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useRoute, useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
import VnPaginate from 'src/components/ui/VnPaginate.vue';
@ -18,6 +18,7 @@ import useNotify from 'src/composables/useNotify.js';
const quasar = useQuasar();
const route = useRoute();
const router = useRouter();
const { t } = useI18n();
const stateStore = useStateStore();
const { notify } = useNotify();
@ -251,7 +252,7 @@ const deleteBuys = async () => {
};
const importBuys = () => {
// redirect to buys import view
router.push({ name: 'EntryBuysImport' });
};
</script>

View File

@ -0,0 +1,281 @@
<script setup>
import { ref, computed } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
import VnInput from 'src/components/common/VnInput.vue';
import VnRow from 'components/ui/VnRow.vue';
import FetchData from 'components/FetchData.vue';
import VnSelectFilter from 'components/common/VnSelectFilter.vue';
import { useStateStore } from 'stores/useStateStore';
import axios from 'axios';
import useNotify from 'src/composables/useNotify.js';
import { toCurrency } from 'filters/index';
const stateStore = useStateStore();
const route = useRoute();
const router = useRouter();
const { t } = useI18n();
const { notify } = useNotify();
const importData = ref({
file: null,
invoice: null,
buys: [],
observation: null,
ref: null,
});
const lastItemBuysOptions = ref([]);
const packagingsOptions = ref([]);
const columns = computed(() => [
{
label: t('entry.buys.item'),
name: 'item',
field: 'itemFk',
options: lastItemBuysOptions.value,
optionValue: 'id',
optionLabel: 'name',
align: 'left',
},
{
label: t('entry.buys.description'),
name: 'description',
field: 'description',
align: 'left',
},
{
label: t('entry.buys.size'),
name: 'size',
field: 'size',
align: 'left',
},
{
label: t('entry.buys.packing'),
name: 'packing',
field: 'packing',
align: 'left',
},
{
label: t('entry.buys.grouping'),
name: 'grouping',
field: 'grouping',
align: 'left',
},
{
label: t('entry.buys.buyingValue'),
name: 'buyingValue',
field: 'buyingValue',
align: 'left',
format: (val) => toCurrency(val),
},
{
label: t('entry.buys.packagingFk'),
name: 'packagingFk',
field: 'packagingFk',
options: packagingsOptions.value,
optionValue: 'id',
optionLabel: 'id',
align: 'left',
},
]);
const onFileChange = (e) => {
importData.value.file = e;
const reader = new FileReader();
reader.onload = (e) => fillData(e.target.result);
reader.readAsText(importData.value.file);
};
const fillData = async (rawData) => {
const data = JSON.parse(rawData);
const [invoice] = data.invoices;
importData.value.observation = invoice.tx_awb;
const companyName = invoice.tx_company;
const boxes = invoice.boxes;
const buys = [];
for (let box of boxes) {
const boxVolume = box.nu_length * box.nu_width * box.nu_height;
for (let product of box.products) {
const packing = product.nu_stems_bunch * product.nu_bunches;
buys.push({
description: product.nm_product,
companyName: companyName,
size: product.nu_length,
packing: packing,
grouping: product.nu_stems_bunch,
buyingValue: parseFloat(product.mny_rate_stem),
volume: boxVolume,
});
}
}
const boxesId = boxes.map((box) => box.id_box);
importData.value.ref = boxesId.join(', ');
await fetchBuys(buys);
};
const fetchBuys = async (buys) => {
try {
const params = { buys };
const { data } = await axios.post(
`Entries/${route.params.id}/importBuysPreview`,
params
);
importData.value.buys = data;
} catch (err) {
console.error('Error fetching buys');
}
};
const onSubmit = async () => {
try {
const params = importData.value;
const hasAnyEmptyRow = params.buys.some((buy) => {
return buy.itemFk === null;
});
if (hasAnyEmptyRow) {
notify(t('Some of the imported buys does not have an item'), 'negative');
return;
}
await axios.post(`Entries/${route.params.id}/importBuys`, params);
notify('globals.dataSaved', 'positive');
redirectToBuysView();
} catch (err) {
console.error('Error importing buys', err);
}
};
const redirectToBuysView = () => {
router.push({ name: 'EntryBuys' });
};
</script>
<template>
<FetchData
:url="`Entries/${route.params.id}/lastItemBuys`"
:filter="{ fields: ['id', 'name'] }"
order="id DESC"
@on-fetch="(data) => (lastItemBuysOptions = data)"
auto-load
/>
<FetchData
url="Packagings"
:filter="{ fields: ['id'], where: { isBox: true } }"
order="id ASC"
@on-fetch="(data) => (packagingsOptions = data)"
auto-load
/>
<QForm>
<Teleport to="#st-actions" v-if="stateStore?.isSubToolbarShown()">
<div>
<QBtnGroup push class="q-gutter-x-sm">
<QBtn
:label="t('globals.cancel')"
color="primary"
icon="restart_alt"
flat
@click="redirectToBuysView()"
/>
<QBtn
:label="t('globals.save')"
color="primary"
icon="save"
type="submit"
:disable="!importData.file"
@click="onSubmit()"
/>
</QBtnGroup>
</div>
</Teleport>
<QCard class="q-pa-lg">
<VnRow class="row q-gutter-md q-mb-md">
<div class="col">
<QFile
label="Standard"
:multiple="false"
v-model="importData.file"
@update:model-value="onFileChange($event)"
>
<template #append>
<QIcon name="vn:attach" class="cursor-pointer">
<QTooltip>{{ t('Select a file') }}</QTooltip>
</QIcon>
</template>
</QFile>
</div>
</VnRow>
<div v-if="importData.file">
<VnRow class="row q-gutter-md q-mb-md">
<div class="col">
<VnInput
:label="t('entry.buys.reference')"
v-model="importData.ref"
/>
</div>
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<div class="col">
<VnInput
:label="t('entry.buys.observations')"
v-model="importData.observation"
/>
</div>
</VnRow>
<VnRow>
<QTable
:columns="columns"
:rows="importData.buys"
:pagination="{ rowsPerPage: 0 }"
hide-pagination
>
<template #body-cell-item="{ row, col }">
<QTd auto-width>
<VnSelectFilter
v-model="row[col.field]"
:options="col.options"
:option-value="col.optionValue"
:option-label="col.optionLabel"
hide-selected
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>
{{ scope.opt?.id }} -
{{ scope.opt?.name }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelectFilter>
</QTd>
</template>
<template #body-cell-packagingFk="{ row, col }">
<QTd auto-width>
<VnSelectFilter
v-model="row[col.field]"
:options="col.options"
:option-value="col.optionValue"
:option-label="col.optionLabel"
hide-selected
/>
</QTd>
</template>
</QTable>
</VnRow>
</div>
</QCard>
</QForm>
</template>
<i18n>
es:
Select a file: Selecciona un fichero
Some of the imported buys does not have an item: Algunas de las compras importadas no tienen un artículo
</i18n>

View File

@ -72,6 +72,11 @@ export default {
},
component: () => import('src/pages/Entry/Card/EntryBuys.vue'),
},
{
path: 'buys/import',
name: 'EntryBuysImport',
component: () => import('src/pages/Entry/Card/EntryBuysImport.vue'),
},
{
path: 'notes',
name: 'EntryNotes',