salix-front/src/pages/Entry/Card/EntryDescriptor.vue

297 lines
9.4 KiB
Vue

<script setup>
import { ref, computed, onMounted } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { toDate } from 'src/filters';
import { getUrl } from 'src/composables/getUrl';
import { useQuasar } from 'quasar';
import { usePrintService } from 'composables/usePrintService';
import CardDescriptor from 'components/ui/CardDescriptor.vue';
import VnLv from 'src/components/ui/VnLv.vue';
import TravelDescriptorProxy from 'src/pages/Travel/Card/TravelDescriptorProxy.vue';
import axios from 'axios';
const quasar = useQuasar();
const { push } = useRouter();
const { openReport } = usePrintService();
const $props = defineProps({
id: {
type: Number,
required: false,
default: null,
},
});
const route = useRoute();
const { t } = useI18n();
const entryDescriptorRef = ref(null);
const url = ref();
const entryFilter = {
include: [
{
relation: 'travel',
scope: {
fields: ['id', 'landed', 'shipped', 'agencyModeFk', 'warehouseOutFk'],
include: [
{
relation: 'agency',
scope: {
fields: ['name'],
},
},
{
relation: 'warehouseOut',
scope: {
fields: ['name'],
},
},
{
relation: 'warehouseIn',
scope: {
fields: ['name'],
},
},
],
},
},
{
relation: 'supplier',
scope: {
fields: ['id', 'nickname'],
},
},
],
};
const entityId = computed(() => {
return $props.id || route.params.id;
});
onMounted(async () => {
url.value = await getUrl('');
});
const getEntryRedirectionFilter = (entry) => {
let entryTravel = entry && entry.travel;
if (!entryTravel || !entryTravel.landed) return null;
const date = new Date(entryTravel.landed);
date.setHours(0, 0, 0, 0);
const from = new Date(date.getTime());
from.setDate(from.getDate() - 10);
const to = new Date(date.getTime());
to.setDate(to.getDate() + 10);
return JSON.stringify({
supplierFk: entry.supplierFk,
from,
to,
});
};
function showEntryReport() {
openReport(`Entries/${entityId.value}/entry-order-pdf`);
}
function showNotification(type, message) {
quasar.notify({
type: type,
message: t(message),
});
}
async function recalculateRates(entity) {
try {
const entryConfig = await axios.get('EntryConfigs/findOne');
if (entryConfig.data?.inventorySupplierFk === entity.supplierFk) {
showNotification(
'negative',
'Cannot recalculate prices because this is an inventory entry',
);
return;
}
await axios.post(`Entries/${entityId.value}/recalcEntryPrices`);
showNotification('positive', 'Entry prices recalculated');
} catch (error) {
showNotification('negative', 'Failed to recalculate rates');
console.error(error);
}
}
async function cloneEntry() {
try {
const response = await axios.post(`Entries/${entityId.value}/cloneEntry`);
push({ path: `/entry/${response.data[0].vNewEntryFk}` });
showNotification('positive', 'Entry cloned');
} catch (error) {
showNotification('negative', 'Failed to clone entry');
console.error(error);
}
}
async function deleteEntry() {
try {
await axios.post(`Entries/${entityId.value}/deleteEntry`);
push({ path: `/entry/list` });
showNotification('positive', 'Entry deleted');
} catch (error) {
showNotification('negative', 'Failed to delete entry');
console.error(error);
}
}
</script>
<template>
<CardDescriptor
ref="entryDescriptorRef"
module="Entry"
:url="`Entries/${entityId}`"
:userFilter="entryFilter"
title="supplier.nickname"
data-key="Entry"
width="lg-width"
>
<template #menu="{ entity }">
<QItem
v-ripple
clickable
@click="showEntryReport(entity)"
data-cy="show-entry-report"
>
<QItemSection>{{ t('Show entry report') }}</QItemSection>
</QItem>
<QItem
v-ripple
clickable
@click="recalculateRates(entity)"
data-cy="recalculate-rates"
>
<QItemSection>{{ t('Recalculate rates') }}</QItemSection>
</QItem>
<QItem v-ripple clickable @click="cloneEntry(entity)" data-cy="clone-entry">
<QItemSection>{{ t('Clone') }}</QItemSection>
</QItem>
<QItem
v-ripple
clickable
@click="deleteEntry(entity)"
data-cy="delete-entry"
v-if="entity?.travelFk"
>
<QItemSection>{{ t('Delete') }}</QItemSection>
</QItem>
</template>
<template #body="{ entity }">
<VnLv :label="t('Travel')">
<template #value>
<span class="link" v-if="entity?.travelFk">
{{ entity.travel?.agency?.name }}
{{ entity.travel?.warehouseOut?.code }} &rarr;
{{ entity.travel?.warehouseIn?.code }}
<TravelDescriptorProxy :id="entity?.travelFk" />
</span>
</template>
</VnLv>
<VnLv
:label="t('entry.summary.travelShipped')"
:value="toDate(entity.travel?.shipped)"
/>
<VnLv
:label="t('entry.summary.travelLanded')"
:value="toDate(entity.travel?.landed)"
/>
<VnLv :label="t('entry.summary.currency')" :value="entity?.currency?.code" />
<VnLv
:label="t('entry.summary.invoiceAmount')"
:value="entity?.invoiceAmount"
/>
<VnLv
:label="t('entry.summary.entryType')"
:value="entity?.entryType?.description"
/>
</template>
<template #icons="{ entity }">
<QCardActions class="q-gutter-x-md">
<QIcon
v-if="entity?.isExcludedFromAvailable"
name="vn:inventory"
color="primary"
size="xs"
>
<QTooltip>{{ t('Inventory entry') }}</QTooltip>
</QIcon>
<QIcon
v-if="entity?.travel?.daysInForward"
name="vn:net"
color="primary"
size="xs"
>
<QTooltip>
{{
t('globals.raid', {
daysInForward: entity?.travel?.daysInForward,
})
}}</QTooltip
>
</QIcon>
<QIcon
v-if="!entity?.travelFk"
name="vn:deletedTicket"
size="xs"
color="primary"
>
<QTooltip>{{ t('This entry is deleted') }}</QTooltip>
</QIcon>
</QCardActions>
</template>
<template #actions="{ entity }">
<QCardActions>
<QBtn
:to="`/supplier/${entity.supplier?.id}`"
size="md"
icon="vn:supplier"
color="primary"
>
<QTooltip>{{ t('Supplier card') }}</QTooltip>
</QBtn>
<QBtn
:to="{
name: 'EntryMain',
query: {
params: getEntryRedirectionFilter(entity),
},
}"
size="md"
icon="vn:entry"
color="primary"
>
<QTooltip>{{ t('All entries with current supplier') }}</QTooltip>
</QBtn>
</QCardActions>
</template>
</CardDescriptor>
</template>
<i18n>
es:
Travel: Envío
Supplier card: Ficha del proveedor
All travels with current agency: Todos los envíos con la agencia actual
All entries with current supplier: Todas las entradas con el proveedor actual
Show entry report: Ver informe del pedido
Inventory entry: Es inventario
Virtual entry: Es una redada
shipped: Enviado
landed: Recibido
This entry is deleted: Esta entrada está eliminada
Cannot recalculate prices because this is an inventory entry: No se pueden recalcular los precios porque es una entrada de inventario
Entry deleted: Entrada eliminada
Entry cloned: Entrada clonada
Entry prices recalculated: Precios de la entrada recalculados
Failed to recalculate rates: No se pudieron recalcular las tarifas
Failed to clone entry: No se pudo clonar la entrada
Failed to delete entry: No se pudo eliminar la entrada
</i18n>