forked from verdnatura/salix-front
Merge pull request 'Ticket components' (!522) from hyervoni/salix-front-mindshore:feature/TicketComponents into dev
Reviewed-on: verdnatura/salix-front#522 Reviewed-by: Alex Moreno <alexm@verdnatura.es> Reviewed-by: Javier Segarra <jsegarra@verdnatura.es>
This commit is contained in:
commit
869fd66840
|
@ -555,6 +555,7 @@ ticket:
|
||||||
weeklyTickets: Weekly tickets
|
weeklyTickets: Weekly tickets
|
||||||
services: Service
|
services: Service
|
||||||
tracking: Tracking
|
tracking: Tracking
|
||||||
|
components: Components
|
||||||
pictures: Pictures
|
pictures: Pictures
|
||||||
list:
|
list:
|
||||||
nickname: Nickname
|
nickname: Nickname
|
||||||
|
|
|
@ -553,6 +553,7 @@ ticket:
|
||||||
weeklyTickets: Tickets programados
|
weeklyTickets: Tickets programados
|
||||||
services: Servicios
|
services: Servicios
|
||||||
tracking: Estados
|
tracking: Estados
|
||||||
|
components: Componentes
|
||||||
pictures: Fotos
|
pictures: Fotos
|
||||||
list:
|
list:
|
||||||
nickname: Alias
|
nickname: Alias
|
||||||
|
|
|
@ -0,0 +1,354 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
|
||||||
|
import FetchedTags from 'components/ui/FetchedTags.vue';
|
||||||
|
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
import ZoneDescriptorProxy from 'src/pages/Zone/Card/ZoneDescriptorProxy.vue';
|
||||||
|
|
||||||
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
|
import { dashIfEmpty } from 'src/filters';
|
||||||
|
import { useArrayData } from 'composables/useArrayData';
|
||||||
|
import { toCurrency } from 'filters/index';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const stateStore = useStateStore();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const salesRef = ref(null);
|
||||||
|
const arrayData = useArrayData('ticketData');
|
||||||
|
const { store } = arrayData;
|
||||||
|
|
||||||
|
const ticketData = computed(() => store.data);
|
||||||
|
const components = ref([]);
|
||||||
|
const componentsList = ref([]);
|
||||||
|
const theoricalCost = ref(0);
|
||||||
|
const ticketVolume = ref(null);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => ticketData.value,
|
||||||
|
async () => {
|
||||||
|
await nextTick();
|
||||||
|
salesRef.value.fetch();
|
||||||
|
getComponentsSum();
|
||||||
|
getTheoricalCost();
|
||||||
|
if (ticketData.value?.zone && ticketData.value?.zone?.isVolumetric)
|
||||||
|
getTicketVolume();
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
const salesFilter = computed(() => ({
|
||||||
|
order: 'concept ASC',
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
relation: 'item',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
relation: 'components',
|
||||||
|
scope: {
|
||||||
|
fields: ['componentFk', 'value'],
|
||||||
|
include: {
|
||||||
|
relation: 'component',
|
||||||
|
scope: {
|
||||||
|
fields: ['typeFk', 'name'],
|
||||||
|
include: {
|
||||||
|
relation: 'componentType',
|
||||||
|
scope: {
|
||||||
|
fields: ['type', 'isBase', 'name'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
where: { ticketFk: route.params.id },
|
||||||
|
}));
|
||||||
|
|
||||||
|
const columns = computed(() => [
|
||||||
|
{
|
||||||
|
label: t('components.item'),
|
||||||
|
name: 'item',
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('components.description'),
|
||||||
|
name: 'description',
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('components.quantity'),
|
||||||
|
name: 'quantity',
|
||||||
|
field: 'quantity',
|
||||||
|
align: 'left',
|
||||||
|
format: (val) => dashIfEmpty(val),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('components.serie'),
|
||||||
|
name: 'serie',
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('components.components'),
|
||||||
|
name: 'components',
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('components.import'),
|
||||||
|
name: 'import',
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('components.total'),
|
||||||
|
name: 'total',
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const getBase = computed(() => {
|
||||||
|
let sum = 0;
|
||||||
|
for (let sale of components.value) {
|
||||||
|
for (let saleComponent of sale.components) {
|
||||||
|
if (saleComponent.component.componentType.isBase) {
|
||||||
|
sum += sale.quantity * saleComponent.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
});
|
||||||
|
|
||||||
|
const getTotal = computed(() => {
|
||||||
|
let total = 0;
|
||||||
|
for (let sale of components.value) {
|
||||||
|
for (let saleComponent of sale.components) {
|
||||||
|
total += sale.quantity * saleComponent.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
});
|
||||||
|
|
||||||
|
const getComponentsSum = async () => {
|
||||||
|
try {
|
||||||
|
const { data } = await axios.get(`Tickets/${route.params.id}/getComponentsSum`);
|
||||||
|
componentsList.value = data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTheoricalCost = async () => {
|
||||||
|
try {
|
||||||
|
const { data } = await axios.get(`Tickets/${route.params.id}/freightCost`);
|
||||||
|
theoricalCost.value = data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTicketVolume = async () => {
|
||||||
|
try {
|
||||||
|
if (!ticketData.value) return;
|
||||||
|
const { data } = await axios.get(`Tickets/${ticketData.value.id}/getVolume`);
|
||||||
|
ticketVolume.value = data[0].volume;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
stateStore.rightDrawer = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => (stateStore.rightDrawer = false));
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FetchData
|
||||||
|
ref="salesRef"
|
||||||
|
url="Sales"
|
||||||
|
:filter="salesFilter"
|
||||||
|
@on-fetch="(data) => (components = data)"
|
||||||
|
auto-load
|
||||||
|
/>
|
||||||
|
<RightMenu>
|
||||||
|
<template #right-panel>
|
||||||
|
<QCard
|
||||||
|
class="q-pa-sm color-vn-text"
|
||||||
|
bordered
|
||||||
|
flat
|
||||||
|
style="border-color: black"
|
||||||
|
>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="text-weight-bold text-subtitle1 text-center full-width">
|
||||||
|
{{ t('components.total') }}
|
||||||
|
</span>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="q-mr-xs color-vn-label"
|
||||||
|
>{{ t('components.baseToCommission') }}:
|
||||||
|
</span>
|
||||||
|
<span>{{ toCurrency(getBase) }}</span>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="q-mr-xs color-vn-label"
|
||||||
|
>{{ t('components.totalWithoutVat') }}:
|
||||||
|
</span>
|
||||||
|
<span>{{ toCurrency(getTotal) }}</span>
|
||||||
|
</QCardSection>
|
||||||
|
</QCard>
|
||||||
|
<QCard
|
||||||
|
class="q-pa-sm color-vn-text"
|
||||||
|
bordered
|
||||||
|
flat
|
||||||
|
style="border-color: black"
|
||||||
|
>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="text-weight-bold text-subtitle1 text-center full-width">
|
||||||
|
{{ t('components.components') }}
|
||||||
|
</span>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardSection
|
||||||
|
v-for="(component, index) in componentsList"
|
||||||
|
:key="index"
|
||||||
|
horizontal
|
||||||
|
>
|
||||||
|
<span v-if="component.name" class="q-mr-xs color-vn-label">
|
||||||
|
{{ component.name }}:
|
||||||
|
</span>
|
||||||
|
<span v-if="component.value">{{
|
||||||
|
toCurrency(component.value, 'EUR', 3)
|
||||||
|
}}</span>
|
||||||
|
</QCardSection>
|
||||||
|
</QCard>
|
||||||
|
<QCard
|
||||||
|
class="q-pa-sm color-vn-text"
|
||||||
|
bordered
|
||||||
|
flat
|
||||||
|
style="border-color: black"
|
||||||
|
>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="text-weight-bold text-subtitle1 text-center full-width">
|
||||||
|
{{ t('components.zoneBreakdown') }}
|
||||||
|
</span>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="q-mr-xs color-vn-label">
|
||||||
|
{{ t('components.price') }}:
|
||||||
|
</span>
|
||||||
|
<span>{{ toCurrency(ticketData?.zonePrice, 'EUR', 2) }}</span>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="q-mr-xs color-vn-label">
|
||||||
|
{{ t('components.bonus') }}:
|
||||||
|
</span>
|
||||||
|
<span>{{ toCurrency(ticketData?.zoneBonus, 'EUR', 2) }}</span>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="q-mr-xs color-vn-label">
|
||||||
|
{{ t('components.zone') }}:
|
||||||
|
</span>
|
||||||
|
<span class="link">
|
||||||
|
{{ dashIfEmpty(ticketData?.zone?.name) }}
|
||||||
|
<ZoneDescriptorProxy :id="ticketData?.zone?.id" />
|
||||||
|
</span>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardSection v-if="ticketData?.zone?.isVolumetric" horizontal>
|
||||||
|
<span class="q-mr-xs color-vn-label">
|
||||||
|
{{ t('components.volume') }}:
|
||||||
|
</span>
|
||||||
|
<span>{{ ticketVolume }}</span>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="q-mr-xs color-vn-label">
|
||||||
|
{{ t('components.packages') }}:
|
||||||
|
</span>
|
||||||
|
<span>{{ dashIfEmpty(ticketData?.packages) }}</span>
|
||||||
|
</QCardSection>
|
||||||
|
</QCard>
|
||||||
|
<QCard
|
||||||
|
class="q-pa-sm color-vn-text"
|
||||||
|
bordered
|
||||||
|
flat
|
||||||
|
style="border-color: black"
|
||||||
|
>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="text-weight-bold text-subtitle1 text-center full-width">
|
||||||
|
{{ t('components.theoricalCost') }}
|
||||||
|
</span>
|
||||||
|
</QCardSection>
|
||||||
|
<QCardSection horizontal>
|
||||||
|
<span class="q-mr-xs color-vn-label">
|
||||||
|
{{ t('components.totalPrice') }}:
|
||||||
|
</span>
|
||||||
|
<span>{{ toCurrency(theoricalCost, 'EUR', 2) }}</span>
|
||||||
|
</QCardSection>
|
||||||
|
</QCard>
|
||||||
|
</template>
|
||||||
|
</RightMenu>
|
||||||
|
<QTable
|
||||||
|
:rows="components"
|
||||||
|
:columns="columns"
|
||||||
|
row-key="id"
|
||||||
|
:pagination="{ rowsPerPage: 0 }"
|
||||||
|
class="full-width q-mt-md"
|
||||||
|
:no-data-label="t('globals.noResults')"
|
||||||
|
>
|
||||||
|
<template #body-cell-item="{ row }">
|
||||||
|
<QTd>
|
||||||
|
<QBtn flat color="primary">
|
||||||
|
<span class="link">{{ row.itemFk }}</span>
|
||||||
|
<ItemDescriptorProxy :id="row.itemFk" />
|
||||||
|
</QBtn>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
<template #body-cell-description="{ row }">
|
||||||
|
<QTd>
|
||||||
|
<div class="column">
|
||||||
|
<span>{{ row.item.name }}</span>
|
||||||
|
<span class="color-vn-label">{{ row.item.subName }}</span>
|
||||||
|
<FetchedTags :item="row.item" :max-length="6" />
|
||||||
|
</div>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
<template #body-cell-serie="{ row }">
|
||||||
|
<QTd>
|
||||||
|
<div class="column">
|
||||||
|
<span v-for="(saleComponent, index) in row.components" :key="index">
|
||||||
|
{{ saleComponent.component?.componentType?.name }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
<template #body-cell-components="{ row }">
|
||||||
|
<QTd>
|
||||||
|
<div class="column">
|
||||||
|
<span v-for="(saleComponent, index) in row.components" :key="index">
|
||||||
|
{{ saleComponent.component?.name }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
<template #body-cell-import="{ row }">
|
||||||
|
<QTd>
|
||||||
|
<div class="column text-right">
|
||||||
|
<span v-for="(saleComponent, index) in row.components" :key="index">
|
||||||
|
{{ toCurrency(saleComponent.value, 'EUR', 3) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
<template #body-cell-total="{ row }">
|
||||||
|
<QTd>
|
||||||
|
<div class="column text-right">
|
||||||
|
<span v-for="(saleComponent, index) in row.components" :key="index">
|
||||||
|
{{ toCurrency(saleComponent.value * row.quantity, 'EUR', 3) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
</QTable>
|
||||||
|
</template>
|
|
@ -66,6 +66,23 @@ const filter = {
|
||||||
fields: ['id', 'name'],
|
fields: ['id', 'name'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
relation: 'zone',
|
||||||
|
scope: {
|
||||||
|
fields: [
|
||||||
|
'agencyModeFk',
|
||||||
|
'bonus',
|
||||||
|
'hour',
|
||||||
|
'id',
|
||||||
|
'isVolumetric',
|
||||||
|
'itemMaxSize',
|
||||||
|
'm3Max',
|
||||||
|
'name',
|
||||||
|
'price',
|
||||||
|
'travelingDays',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,6 @@ const getDefaultTaxClass = async () => {
|
||||||
params: { filter: JSON.stringify(filter) },
|
params: { filter: JSON.stringify(filter) },
|
||||||
});
|
});
|
||||||
defaultTaxClass.value = data;
|
defaultTaxClass.value = data;
|
||||||
console.log('defaultTaxClass', defaultTaxClass.value);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,6 +178,24 @@ service:
|
||||||
addService: Add service
|
addService: Add service
|
||||||
quantityInfo: To create services with negative amounts mark the service on the source ticket and press the pay button.
|
quantityInfo: To create services with negative amounts mark the service on the source ticket and press the pay button.
|
||||||
createRefundSuccess: 'The following refund ticket have been created: { ticketId }'
|
createRefundSuccess: 'The following refund ticket have been created: { ticketId }'
|
||||||
|
components:
|
||||||
|
item: Item
|
||||||
|
description: Description
|
||||||
|
quantity: Quantity
|
||||||
|
serie: Serie
|
||||||
|
components: Components
|
||||||
|
import: Import
|
||||||
|
total: Total
|
||||||
|
baseToCommission: Base to commission
|
||||||
|
totalWithoutVat: Total without VAT
|
||||||
|
zoneBreakdown: Zone breakdown
|
||||||
|
price: Price
|
||||||
|
bonus: Bonus
|
||||||
|
zone: Zone
|
||||||
|
volume: Volume
|
||||||
|
theoricalCost: Theorical cost
|
||||||
|
totalPrice: Total price
|
||||||
|
packages: Packages
|
||||||
tracking:
|
tracking:
|
||||||
state: State
|
state: State
|
||||||
worker: Worker
|
worker: Worker
|
||||||
|
|
|
@ -164,6 +164,24 @@ ticketSale:
|
||||||
shipped: F. Envío
|
shipped: F. Envío
|
||||||
agency: Agencia
|
agency: Agencia
|
||||||
address: Consignatario
|
address: Consignatario
|
||||||
|
components:
|
||||||
|
item: Artículo
|
||||||
|
description: Descripción
|
||||||
|
quantity: Cantidad
|
||||||
|
serie: Serie
|
||||||
|
components: Componentes
|
||||||
|
import: Importe
|
||||||
|
total: Total
|
||||||
|
baseToCommission: Base comisionable
|
||||||
|
totalWithoutVat: Total sin IVA
|
||||||
|
zoneBreakdown: Desglose zona
|
||||||
|
price: Precio
|
||||||
|
bonus: Bonificación
|
||||||
|
zone: Zona
|
||||||
|
volume: Volúmen
|
||||||
|
theoricalCost: Porte teórico
|
||||||
|
totalPrice: Precio total
|
||||||
|
packages: Bultos
|
||||||
expedition:
|
expedition:
|
||||||
id: Expedición
|
id: Expedición
|
||||||
item: Artículo
|
item: Artículo
|
||||||
|
|
|
@ -25,6 +25,7 @@ export default {
|
||||||
'TicketBoxing',
|
'TicketBoxing',
|
||||||
'TicketSms',
|
'TicketSms',
|
||||||
'TicketPicture',
|
'TicketPicture',
|
||||||
|
'TicketComponents',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
|
@ -180,6 +181,15 @@ export default {
|
||||||
},
|
},
|
||||||
component: () => import('src/pages/Ticket/Card/TicketVolume.vue'),
|
component: () => import('src/pages/Ticket/Card/TicketVolume.vue'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'components',
|
||||||
|
name: 'TicketComponents',
|
||||||
|
meta: {
|
||||||
|
title: 'components',
|
||||||
|
icon: 'vn:components',
|
||||||
|
},
|
||||||
|
component: () => import('src/pages/Ticket/Card/TicketComponents.vue'),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'expedition',
|
path: 'expedition',
|
||||||
name: 'TicketExpedition',
|
name: 'TicketExpedition',
|
||||||
|
|
Loading…
Reference in New Issue