forked from verdnatura/salix-front
334 lines
11 KiB
Vue
334 lines
11 KiB
Vue
<script setup>
|
|
import { ref, computed, onMounted, 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 FetchData from 'components/FetchData.vue';
|
|
import ZoneDescriptorProxy from 'src/pages/Zone/Card/ZoneDescriptorProxy.vue';
|
|
import VnImg from 'src/components/ui/VnImg.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';
|
|
import VnTable from 'src/components/VnTable/VnTable.vue';
|
|
|
|
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('basicData.item'),
|
|
name: 'item',
|
|
align: 'left',
|
|
},
|
|
{
|
|
align: 'left',
|
|
label: t('lines.image'),
|
|
name: 'image',
|
|
columnField: {
|
|
component: VnImg,
|
|
attrs: (id) => {
|
|
return {
|
|
id,
|
|
width: '50px',
|
|
};
|
|
},
|
|
},
|
|
columnFilter: false,
|
|
},
|
|
{
|
|
label: t('basicData.description'),
|
|
name: 'description',
|
|
align: 'left',
|
|
columnClass: 'expand',
|
|
},
|
|
{
|
|
label: t('basicData.quantity'),
|
|
name: 'quantity',
|
|
field: 'quantity',
|
|
align: 'left',
|
|
format: (row) => dashIfEmpty(row.quantity),
|
|
},
|
|
{
|
|
label: t('ticketComponents.serie'),
|
|
name: 'serie',
|
|
align: 'left',
|
|
format: (row) => dashIfEmpty(row.serie),
|
|
},
|
|
{
|
|
label: t('ticketComponents.components'),
|
|
name: 'components',
|
|
align: 'left',
|
|
},
|
|
{
|
|
label: t('advanceTickets.import'),
|
|
name: 'import',
|
|
align: 'left',
|
|
},
|
|
{
|
|
label: t('basicData.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 () => {
|
|
const { data } = await axios.get(`Tickets/${route.params.id}/getComponentsSum`);
|
|
componentsList.value = data;
|
|
};
|
|
|
|
const getTheoricalCost = async () => {
|
|
const { data } = await axios.get(`Tickets/${route.params.id}/freightCost`);
|
|
theoricalCost.value = data;
|
|
};
|
|
|
|
const getTicketVolume = async () => {
|
|
if (!ticketData.value) return;
|
|
const { data } = await axios.get(`Tickets/${ticketData.value.id}/getVolume`);
|
|
ticketVolume.value = data[0].volume;
|
|
};
|
|
|
|
onMounted(() => {
|
|
stateStore.rightDrawer = true;
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<FetchData
|
|
ref="salesRef"
|
|
url="Sales"
|
|
:filter="salesFilter"
|
|
@on-fetch="(data) => (components = data)"
|
|
auto-load
|
|
/>
|
|
<Teleport to="#right-panel" v-if="stateStore.isHeaderMounted()">
|
|
<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('basicData.total') }}
|
|
</span>
|
|
</QCardSection>
|
|
<QCardSection horizontal>
|
|
<span class="q-mr-xs color-vn-label"
|
|
>{{ t('ticketComponents.baseToCommission') }}:
|
|
</span>
|
|
<span>{{ toCurrency(getBase) }}</span>
|
|
</QCardSection>
|
|
<QCardSection horizontal>
|
|
<span class="q-mr-xs color-vn-label"
|
|
>{{ t('ticketComponents.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('ticketComponents.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('ticketComponents.zoneBreakdown') }}
|
|
</span>
|
|
</QCardSection>
|
|
<QCardSection horizontal>
|
|
<span class="q-mr-xs color-vn-label"> {{ t('basicData.price') }}: </span>
|
|
<span>{{ toCurrency(ticketData?.zonePrice, 'EUR', 2) }}</span>
|
|
</QCardSection>
|
|
<QCardSection horizontal>
|
|
<span class="q-mr-xs color-vn-label">
|
|
{{ t('ticketComponents.bonus') }}:
|
|
</span>
|
|
<span>{{ toCurrency(ticketData?.zoneBonus, 'EUR', 2) }}</span>
|
|
</QCardSection>
|
|
<QCardSection horizontal>
|
|
<span class="q-mr-xs color-vn-label"> {{ t('ticketList.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('volume.volume') }}: </span>
|
|
<span>{{ ticketVolume }}</span>
|
|
</QCardSection>
|
|
<QCardSection horizontal>
|
|
<span class="q-mr-xs color-vn-label">
|
|
{{ t('ticketComponents.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('ticketComponents.theoricalCost') }}
|
|
</span>
|
|
</QCardSection>
|
|
<QCardSection horizontal>
|
|
<span class="q-mr-xs color-vn-label">
|
|
{{ t('ticketComponents.totalPrice') }}:
|
|
</span>
|
|
<span>{{ toCurrency(theoricalCost, 'EUR', 2) }}</span>
|
|
</QCardSection>
|
|
</QCard>
|
|
</Teleport>
|
|
<VnTable
|
|
ref="tableRef"
|
|
data-key="TicketComponents"
|
|
url="Sales"
|
|
:user-filter="salesFilter"
|
|
:columns="columns"
|
|
:right-search="false"
|
|
auto-load
|
|
:disable-option="{ card: true }"
|
|
:column-search="false"
|
|
>
|
|
<template #column-item="{ row }">
|
|
<span @click.stop flat class="link">
|
|
{{ row.itemFk }}
|
|
<ItemDescriptorProxy :id="row.itemFk" />
|
|
</span>
|
|
</template>
|
|
<template #column-image="{ row }">
|
|
<div class="image-wrapper">
|
|
<VnImg :id="parseInt(row?.item?.id)" class="rounded" />
|
|
</div>
|
|
</template>
|
|
<template #column-description="{ row }">
|
|
<div class="column">
|
|
<span>{{ row.item.name }}</span>
|
|
<span class="color-vn-label">{{ row.item.subName }}</span>
|
|
<FetchedTags :item="row.item" />
|
|
</div>
|
|
</template>
|
|
<template #column-serie="{ row }">
|
|
<div class="column">
|
|
<span v-for="(saleComponent, index) in row.components" :key="index">
|
|
{{ saleComponent.component?.componentType?.name }}
|
|
</span>
|
|
</div>
|
|
</template>
|
|
<template #column-components="{ row }">
|
|
<div class="column">
|
|
<span v-for="(saleComponent, index) in row.components" :key="index">
|
|
{{ saleComponent.component?.name }}
|
|
</span>
|
|
</div>
|
|
</template>
|
|
<template #column-import="{ row }">
|
|
<div class="column text-left">
|
|
<span v-for="(saleComponent, index) in row.components" :key="index">
|
|
{{ toCurrency(saleComponent.value, 'EUR', 3) }}
|
|
</span>
|
|
</div>
|
|
</template>
|
|
<template #column-total="{ row }">
|
|
<div class="column">
|
|
<span v-for="(saleComponent, index) in row.components" :key="index">
|
|
{{ toCurrency(saleComponent.value * row.quantity, 'EUR', 3) }}
|
|
</span>
|
|
</div>
|
|
</template>
|
|
</VnTable>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.image-wrapper {
|
|
width: 40px;
|
|
height: 40px;
|
|
}
|
|
</style>
|