Merge pull request '#7347 - Supplier Consumption layout updates' (!1451) from 7347_supplierConsumption into dev
gitea/salix-front/pipeline/head This commit looks good
Details
gitea/salix-front/pipeline/head This commit looks good
Details
Reviewed-on: #1451 Reviewed-by: Javi Gallego <jgallego@verdnatura.es>
This commit is contained in:
commit
41680c574f
|
@ -6,6 +6,7 @@ import toDateHourMinSec from './toDateHourMinSec';
|
|||
import toRelativeDate from './toRelativeDate';
|
||||
import toCurrency from './toCurrency';
|
||||
import toPercentage from './toPercentage';
|
||||
import toNumber from './toNumber';
|
||||
import toLowerCamel from './toLowerCamel';
|
||||
import dashIfEmpty from './dashIfEmpty';
|
||||
import dateRange from './dateRange';
|
||||
|
@ -34,6 +35,7 @@ export {
|
|||
toRelativeDate,
|
||||
toCurrency,
|
||||
toPercentage,
|
||||
toNumber,
|
||||
dashIfEmpty,
|
||||
dateRange,
|
||||
getParamWhere,
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
export default function (value, fractionSize = 2) {
|
||||
if (isNaN(value)) return value;
|
||||
return new Intl.NumberFormat('es-ES', {
|
||||
style: 'decimal',
|
||||
minimumFractionDigits: 0,
|
||||
maximumFractionDigits: fractionSize,
|
||||
}).format(value);
|
||||
}
|
|
@ -122,6 +122,7 @@ globals:
|
|||
producer: Producer
|
||||
origin: Origin
|
||||
state: State
|
||||
total: Total
|
||||
subtotal: Subtotal
|
||||
visible: Visible
|
||||
price: Price
|
||||
|
|
|
@ -126,6 +126,7 @@ globals:
|
|||
producer: Productor
|
||||
origin: Origen
|
||||
state: Estado
|
||||
total: Total
|
||||
subtotal: Subtotal
|
||||
visible: Visible
|
||||
price: Precio
|
||||
|
|
|
@ -1,22 +1,20 @@
|
|||
<script setup>
|
||||
import { useRoute } from 'vue-router';
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useQuasar } from 'quasar';
|
||||
import FetchedTags from 'components/ui/FetchedTags.vue';
|
||||
import SendEmailDialog from 'components/common/SendEmailDialog.vue';
|
||||
import SupplierConsumptionFilter from './SupplierConsumptionFilter.vue';
|
||||
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
|
||||
|
||||
import { dateRange, toDate } from 'src/filters';
|
||||
import { dashIfEmpty } from 'src/filters';
|
||||
import { usePrintService } from 'composables/usePrintService';
|
||||
import useNotify from 'src/composables/useNotify.js';
|
||||
import axios from 'axios';
|
||||
import { dateRange, toCurrency, toNumber, toDateHourMin } from 'src/filters';
|
||||
import { usePrintService } from 'composables/usePrintService';
|
||||
import useNotify from 'src/composables/useNotify';
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
import { useState } from 'src/composables/useState';
|
||||
import { useArrayData } from 'composables/useArrayData';
|
||||
import SendEmailDialog from 'components/common/SendEmailDialog.vue';
|
||||
import SupplierConsumptionFilter from './SupplierConsumptionFilter.vue';
|
||||
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||
import EntryDescriptorProxy from 'src/pages/Entry/Card/EntryDescriptorProxy.vue';
|
||||
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
|
||||
|
||||
const state = useState();
|
||||
const stateStore = useStateStore();
|
||||
|
@ -31,7 +29,86 @@ const arrayData = useArrayData('SupplierConsumption', {
|
|||
order: ['itemTypeFk', 'itemName', 'itemSize'],
|
||||
userFilter: { where: { supplierFk: route.params.id } },
|
||||
});
|
||||
const headerColumns = computed(() => [
|
||||
{
|
||||
name: 'id',
|
||||
label: t('globals.entry'),
|
||||
align: 'left',
|
||||
field: 'id',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'invoiceNumber',
|
||||
label: t('globals.params.supplierRef'),
|
||||
align: 'left',
|
||||
field: 'invoiceNumber',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'shipped',
|
||||
label: t('globals.shipped'),
|
||||
align: 'center',
|
||||
field: 'shipped',
|
||||
format: toDateHourMin,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'quantity',
|
||||
label: t('item.list.stems'),
|
||||
align: 'center',
|
||||
field: 'quantity',
|
||||
format: (value) => toNumber(value),
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'total',
|
||||
label: t('globals.total'),
|
||||
align: 'center',
|
||||
field: 'total',
|
||||
format: (value) => toCurrency(value),
|
||||
sortable: true,
|
||||
},
|
||||
]);
|
||||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
name: 'itemName',
|
||||
label: t('globals.item'),
|
||||
align: 'left',
|
||||
field: 'itemName',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'subName',
|
||||
align: 'left',
|
||||
field: 'subName',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'quantity',
|
||||
label: t('globals.quantity'),
|
||||
align: 'right',
|
||||
field: 'quantity',
|
||||
format: (value) => toNumber(value),
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'price',
|
||||
label: t('globals.price'),
|
||||
align: 'right',
|
||||
field: 'price',
|
||||
format: (value) => toCurrency(value),
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: 'total',
|
||||
label: t('globals.total'),
|
||||
align: 'right',
|
||||
field: 'total',
|
||||
format: (value) => toCurrency(value),
|
||||
sortable: true,
|
||||
},
|
||||
]);
|
||||
const store = arrayData.store;
|
||||
|
||||
onUnmounted(() => state.unset('SupplierConsumption'));
|
||||
|
@ -100,33 +177,34 @@ const sendCampaignMetricsEmail = ({ address }) => {
|
|||
};
|
||||
|
||||
const totalEntryPrice = (rows) => {
|
||||
let totalPrice = 0;
|
||||
let totalQuantity = 0;
|
||||
if (!rows) return totalPrice;
|
||||
for (const row of rows) {
|
||||
let total = 0;
|
||||
let quantity = 0;
|
||||
|
||||
if (row.buys) {
|
||||
for (const buy of row.buys) {
|
||||
total = total + buy.total;
|
||||
quantity = quantity + buy.quantity;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rows) return [];
|
||||
totalRows.value = rows.reduce(
|
||||
(acc, row) => {
|
||||
if (Array.isArray(row.buys)) {
|
||||
const { total, quantity } = row.buys.reduce(
|
||||
(buyAcc, buy) => {
|
||||
buyAcc.total += buy.total || 0;
|
||||
buyAcc.quantity += buy.quantity || 0;
|
||||
return buyAcc;
|
||||
},
|
||||
{ total: 0, quantity: 0 },
|
||||
);
|
||||
row.total = total;
|
||||
row.quantity = quantity;
|
||||
totalPrice = totalPrice + total;
|
||||
totalQuantity = totalQuantity + quantity;
|
||||
acc.totalPrice += total;
|
||||
acc.totalQuantity += quantity;
|
||||
}
|
||||
totalRows.value = { totalPrice, totalQuantity };
|
||||
return acc;
|
||||
},
|
||||
{ totalPrice: 0, totalQuantity: 0 },
|
||||
);
|
||||
return rows;
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
stateStore.rightDrawer = true;
|
||||
await getSupplierConsumptionData();
|
||||
});
|
||||
const expanded = ref([]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -160,14 +238,14 @@ onMounted(async () => {
|
|||
<div>
|
||||
{{ t('Total entries') }}:
|
||||
<QChip :dense="$q.screen.lt.sm" text-color="white">
|
||||
{{ totalRows.totalPrice }} €
|
||||
{{ toCurrency(totalRows.totalPrice) }}
|
||||
</QChip>
|
||||
</div>
|
||||
<QSeparator dark vertical />
|
||||
<div>
|
||||
{{ t('Total stems entries') }}:
|
||||
<QChip :dense="$q.screen.lt.sm" text-color="white">
|
||||
{{ totalRows.totalQuantity }}
|
||||
{{ toNumber(totalRows.totalQuantity) }}
|
||||
</QChip>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -177,59 +255,111 @@ onMounted(async () => {
|
|||
<SupplierConsumptionFilter data-key="SupplierConsumption" />
|
||||
</template>
|
||||
</RightMenu>
|
||||
<QCard class="full-width q-pa-md">
|
||||
<QTable
|
||||
flat
|
||||
bordered
|
||||
:rows="rows"
|
||||
:columns="headerColumns"
|
||||
row-key="id"
|
||||
hide-header
|
||||
class="full-width q-mt-md"
|
||||
:no-data-label="t('No results')"
|
||||
v-model:expanded="expanded"
|
||||
:grid="$q.screen.lt.md"
|
||||
>
|
||||
<template #body="{ row }">
|
||||
<QTr>
|
||||
<QTd no-hover>
|
||||
<span class="label">{{ t('supplier.consumption.entry') }}: </span>
|
||||
<span>{{ row.id }}</span>
|
||||
</QTd>
|
||||
<QTd no-hover>
|
||||
<span class="label">{{ t('globals.date') }}: </span>
|
||||
<span>{{ toDate(row.shipped) }}</span></QTd
|
||||
>
|
||||
<QTd colspan="6" no-hover>
|
||||
<span class="label">{{ t('globals.reference') }}: </span>
|
||||
<span>{{ row.invoiceNumber }}</span>
|
||||
</QTd>
|
||||
<template #header="props">
|
||||
<QTr :props="props">
|
||||
<QTh auto-width />
|
||||
|
||||
<QTh v-for="col in props.cols" :key="col.name" :props="props">
|
||||
<span v-text="col.label" class="tr-header" />
|
||||
</QTh>
|
||||
</QTr>
|
||||
<QTr v-for="(buy, index) in row.buys" :key="index">
|
||||
<QTd no-hover>
|
||||
<QBtn flat class="link" dense no-caps>{{ buy.itemName }}</QBtn>
|
||||
<ItemDescriptorProxy :id="buy.itemFk" />
|
||||
</template>
|
||||
|
||||
<template #body="props">
|
||||
<QTr
|
||||
:props="props"
|
||||
:key="`movement_${props.row.id}`"
|
||||
class="bg-vn-page cursor-pointer"
|
||||
@click="props.expand = !props.expand"
|
||||
>
|
||||
<QTd auto-width>
|
||||
<QIcon
|
||||
:class="props.expand ? '' : 'rotate-270'"
|
||||
name="expand_circle_down"
|
||||
size="md"
|
||||
:color="props.expand ? 'primary' : 'white'"
|
||||
/>
|
||||
</QTd>
|
||||
|
||||
<QTd no-hover>
|
||||
<span>{{ buy.subName }}</span>
|
||||
<FetchedTags :item="buy" />
|
||||
<QTd v-for="col in props.cols" :key="col.name" :props="props">
|
||||
<span @click.stop class="link" v-if="col.name === 'id'">
|
||||
{{ col.value }}
|
||||
<EntryDescriptorProxy :id="col.value" />
|
||||
</span>
|
||||
|
||||
<span v-else v-text="col.value" />
|
||||
</QTd>
|
||||
<QTd no-hover> {{ dashIfEmpty(buy.quantity) }}</QTd>
|
||||
<QTd no-hover> {{ dashIfEmpty(buy.price) }}</QTd>
|
||||
<QTd colspan="2" no-hover> {{ dashIfEmpty(buy.total) }}</QTd>
|
||||
</QTr>
|
||||
<QTr>
|
||||
<QTd colspan="5" no-hover>
|
||||
<span class="label">{{ t('Total entry') }}: </span>
|
||||
<span>{{ row.total }} €</span>
|
||||
</QTd>
|
||||
<QTd no-hover>
|
||||
<span class="label">{{ t('Total stems') }}: </span>
|
||||
<span>{{ row.quantity }}</span>
|
||||
|
||||
<QTr
|
||||
v-show="props.expand"
|
||||
:props="props"
|
||||
:key="`expedition_${props.row.id}`"
|
||||
>
|
||||
<QTd colspan="12" style="padding: 1px 0">
|
||||
<QTable
|
||||
color="secondary"
|
||||
card-class="bg-vn-page text-white "
|
||||
style-class="height: 30px"
|
||||
table-header-class="text-white"
|
||||
:rows="props.row.buys"
|
||||
:columns="columns"
|
||||
row-key="id"
|
||||
virtual-scroll
|
||||
v-model:expanded="expanded"
|
||||
>
|
||||
<template #header="props">
|
||||
<QTr :props="props">
|
||||
<QTh
|
||||
v-for="col in props.cols"
|
||||
:key="col.name"
|
||||
:props="props"
|
||||
>
|
||||
<span v-text="col.label" class="tr-header" />
|
||||
</QTh>
|
||||
</QTr>
|
||||
</template>
|
||||
<template #body="props">
|
||||
<QTr :props="props" :key="`m_${props.row.id}`">
|
||||
<QTd
|
||||
v-for="col in props.cols"
|
||||
:key="col.name"
|
||||
:title="col.label"
|
||||
:props="props"
|
||||
>
|
||||
<span
|
||||
@click.stop
|
||||
class="link"
|
||||
v-if="col.name === 'itemName'"
|
||||
>
|
||||
{{ col.value }}
|
||||
<ItemDescriptorProxy :id="props.row.itemFk" />
|
||||
</span>
|
||||
<span v-else v-text="col.value" />
|
||||
</QTd>
|
||||
</QTr>
|
||||
</template>
|
||||
</QTable>
|
||||
</QTd>
|
||||
</QTr>
|
||||
</template>
|
||||
</QTable>
|
||||
</QCard>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.label {
|
||||
color: var(--vn-label-color);
|
||||
.q-table thead tr,
|
||||
.q-table tbody td {
|
||||
height: 30px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
Loading…
Reference in New Issue