Merge remote-tracking branch 'origin/7830-customerDesplegables' into 6943_fix_customerSummaryTable
gitea/salix-front/pipeline/pr-dev This commit looks good Details

This commit is contained in:
Javier Segarra 2024-08-27 16:30:32 +02:00
parent cadd6a2b62
commit 20ddabcc01
4 changed files with 138 additions and 254 deletions

View File

@ -95,7 +95,6 @@ globals:
from: From from: From
to: To to: To
notes: Notes notes: Notes
quantity: Quantity
item: Item item: Item
ticket: Ticket ticket: Ticket
campaign: Campaign campaign: Campaign

View File

@ -95,7 +95,6 @@ globals:
from: Desde from: Desde
to: Hasta to: Hasta
notes: Notas notes: Notas
quantity: Cantidad
item: Artículo item: Artículo
ticket: Ticket ticket: Ticket
campaign: Campaña campaign: Campaña

View File

@ -1,84 +1,76 @@
<script setup> <script setup>
import { computed, ref, watch } from 'vue'; import { ref, computed, onBeforeMount } from 'vue';
import axios from 'axios';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import CustomerConsumptionFilter from './CustomerConsumptionFilter.vue'; import { toDate } from 'src/filters/index';
import { useStateStore } from 'src/stores/useStateStore'; import { useRoute } from 'vue-router';
import VnTable from 'components/VnTable/VnTable.vue'; import VnTable from 'components/VnTable/VnTable.vue';
import VnSubToolbar from 'components/ui/VnSubToolbar.vue';
import { toDate } from 'src/filters';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
import FetchedTags from 'components/ui/FetchedTags.vue'; import FetchedTags from 'components/ui/FetchedTags.vue';
import { useArrayData } from 'src/composables/useArrayData'; import { useArrayData } from 'src/composables/useArrayData';
import { useRoute } from 'vue-router';
import { usePrintService } from 'src/composables/usePrintService'; import { usePrintService } from 'src/composables/usePrintService';
import { useVnConfirm } from 'src/composables/useVnConfirm'; import { useVnConfirm } from 'src/composables/useVnConfirm';
const { openConfirmationModal } = useVnConfirm(); const { openConfirmationModal } = useVnConfirm();
const { openReport, sendEmail } = usePrintService(); const { openReport, sendEmail } = usePrintService();
import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import VnSelect from 'components/common/VnSelect.vue';
import VnInputDate from 'components/common/VnInputDate.vue';
const arrayData = useArrayData('Client'); const arrayData = useArrayData('Client');
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute(); const route = useRoute();
const tableRef = ref(); const campaignList = ref();
const filter = computed(() => ({
where: { and: [{ isPackaging: false }, { clientFk: route.params.id }] },
limit: 30,
skip: 10,
}));
const showActionBtns = computed(() => handleQueryParams()); const showActionBtns = computed(() => handleQueryParams());
function handleQueryParams() { function handleQueryParams() {
const query = JSON.parse(route.query.table); const query = getQueryParams();
return query.from && query.to; return query.from && query.to;
} }
watch(
() => route.query,
() => {
showActionBtns.value = handleQueryParams();
}
);
const columns = computed(() => [ const columns = computed(() => [
{ {
name: 'search',
align: 'left', align: 'left',
label: t('globals.search'),
visible: false,
},
{
name: 'itemFk', name: 'itemFk',
label: t('Item'), align: 'left',
label: t('globals.item'),
columnClass: 'shrink',
cardVisible: true, cardVisible: true,
columnFilter: { columnFilter: {
inWhere: true, name: 'itemId',
}, },
}, },
{ {
align: 'left',
name: 'ticketFk', name: 'ticketFk',
label: t('Ticket'), align: 'left',
label: t('globals.ticket'),
cardVisible: true, cardVisible: true,
columnFilter: { columnFilter: {
inWhere: true, inWhere: true,
}, },
}, },
{ {
align: 'left',
name: 'shipped', name: 'shipped',
label: t('shipped'), align: 'left',
label: t('globals.shipped'),
format: ({ shipped }) => toDate(shipped), format: ({ shipped }) => toDate(shipped),
columnFilter: false,
cardVisible: true, cardVisible: true,
columnFilter: {
inWhere: true,
}, },
},
{ {
align: 'left',
name: 'description', name: 'description',
align: 'left',
label: t('globals.description'), label: t('globals.description'),
class: 'extend', columnClass: 'expand',
columnFilter: { columnFilter: {
inWhere: true, inWhere: true,
}, },
}, },
{ {
align: 'left',
name: 'quantity', name: 'quantity',
label: t('globals.quantity'), label: t('globals.quantity'),
cardVisible: true, cardVisible: true,
@ -86,9 +78,24 @@ const columns = computed(() => [
inWhere: true, inWhere: true,
}, },
}, },
{
name: 'grouped',
label: t('Group by items'),
component: 'checkbox',
visible: false,
orderBy: false,
},
]); ]);
onBeforeMount(async () => {
campaignList.value = (await axios('Campaigns/latest')).data;
});
function getQueryParams() {
return JSON.parse(route.query.consumption);
}
function getParams() { function getParams() {
const query = JSON.parse(route.query.table); const query = getQueryParams();
return { return {
from: query.from, from: query.from,
to: query.to, to: query.to,
@ -96,6 +103,25 @@ function getParams() {
recipientId: arrayData.store.data.id, recipientId: arrayData.store.data.id,
}; };
} }
const filter = computed(() => {
const minDate = Date.vnNew();
minDate.setHours(0, 0, 0, 0);
minDate.setMonth(minDate.getMonth() - 2);
const maxDate = Date.vnNew();
maxDate.setHours(23, 59, 59, 59);
return {
campaign: campaignList.value[0]?.id,
from: minDate,
to: maxDate,
filter: {
where: {
clientFk: route.params.id,
},
},
};
});
const openReportPdf = () => { const openReportPdf = () => {
openReport(`Clients/${route.params.id}/campaign-metrics-pdf`, getParams()); openReport(`Clients/${route.params.id}/campaign-metrics-pdf`, getParams());
}; };
@ -116,13 +142,32 @@ const sendCampaignMetricsEmail = ({ address }) => {
</script> </script>
<template> <template>
<Teleport to="#right-panel" v-if="useStateStore().isHeaderMounted()"> <VnTable
<CustomerConsumptionFilter data-key="CustomerConsumption" /> v-if="campaignList"
</Teleport> data-key="CustomerConsumption"
<VnSubToolbar> url="Clients/consumption"
<template #st-actions> :order="['itemTypeFk', 'itemName', 'itemSize', 'description']"
:columns="columns"
search-url="consumption"
:user-params="filter"
:default-remove="false"
:default-reset="false"
:default-save="false"
:has-sub-toolbar="true"
auto-load
>
<template #moreBeforeActions>
<!-- <QBtn
color="primary"
icon="delete"
flat
@click="remove(selected)"
:disable="!selected?.length"
:title="t('globals.remove')"
/> -->
<QBtn <QBtn
color="primary" color="primary"
flat
icon-right="picture_as_pdf" icon-right="picture_as_pdf"
@click="openReportPdf()" @click="openReportPdf()"
:disabled="!showActionBtns" :disabled="!showActionBtns"
@ -131,6 +176,7 @@ const sendCampaignMetricsEmail = ({ address }) => {
</QBtn> </QBtn>
<QBtn <QBtn
color="primary" color="primary"
flat
icon-right="email" icon-right="email"
@click="openSendEmailDialog()" @click="openSendEmailDialog()"
:disabled="!showActionBtns" :disabled="!showActionBtns"
@ -138,41 +184,70 @@ const sendCampaignMetricsEmail = ({ address }) => {
<QTooltip>{{ t('Send to email') }}</QTooltip> <QTooltip>{{ t('Send to email') }}</QTooltip>
</QBtn> </QBtn>
</template> </template>
</VnSubToolbar>
<VnTable
data-key="CustomerConsumption"
ref="tableRef"
:filter="filter"
url="Clients/Consumption"
:columns="columns"
:right-search="false"
:use-model="true"
auto-load
:order="['itemTypeFk', 'itemName', 'itemSize', 'description']"
>
<template #column-itemFk="{ row }"> <template #column-itemFk="{ row }">
<span class="link"> <span class="link">
{{ row.itemFk }} {{ row.itemFk }}
<ItemDescriptorProxy :id="row.itemFk" /> <ItemDescriptorProxy :id="row.itemFk" />
</span> </span>
</template> </template>
<template #column-description="{ row }">
<FetchedTags :item="row" :max-length="6" />
</template>
<template #column-ticketFk="{ row }"> <template #column-ticketFk="{ row }">
<span class="link"> <span class="link">
{{ row.ticketFk }} {{ row.ticketFk }}
<TicketDescriptorProxy :id="row.ticketFk" /> <TicketDescriptorProxy :id="row.ticketFk" />
</span> </template </span>
></VnTable> </template>
<template #column-description="{ row }">
<div>{{ row.concept }}</div>
<div v-if="row.subName" class="subName">
{{ row.subName }}
</div>
<FetchedTags :item="row" :max-length="3" />
</template>
<template #moreFilterPanel="{ params }">
<div class="column no-wrap flex-center q-gutter-y-md q-mt-xs q-pr-xl">
<VnSelect
v-model="params.campaign"
:options="campaignList"
:label="t('globals.campaign')"
:filled="true"
class="q-px-sm q-pt-none fit"
dense
option-label="code"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>
{{ scope.opt?.code }}
{{
new Date(scope.opt?.dated).getFullYear()
}}</QItemLabel
>
</QItemSection>
</QItem>
</template>
</VnSelect>
<VnInputDate
v-model="params.to"
:label="t('globals.from')"
:filled="true"
class="q-px-xs q-pt-none fit"
dense
/>
<VnInputDate
v-model="params.from"
:label="t('globals.from')"
:filled="true"
class="q-px-xs q-pt-none fit"
dense
/>
</div>
</template>
</VnTable>
</template> </template>
<i18n> <i18n>
es: es:
Send to email: Enviar por email
Search by item id or name: Buscar por id de artículo o nombre
The consumption report will be sent: Se enviará el informe de consumo
Please, confirm: Por favor, confirma
Enter a new search: Introduce una nueva búsqueda Enter a new search: Introduce una nueva búsqueda
Group by items: Agrupar por artículos Group by items: Agrupar por artículos
</i18n> </i18n>

View File

@ -1,189 +0,0 @@
<script setup>
import { useI18n } from 'vue-i18n';
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
import VnInput from 'src/components/common/VnInput.vue';
import { QItem } from 'quasar';
import VnSelect from 'src/components/common/VnSelect.vue';
import { QItemSection } from 'quasar';
import VnInputDate from 'src/components/common/VnInputDate.vue';
import { toDate } from 'src/filters';
const { t } = useI18n();
defineProps({ dataKey: { type: String, required: true } });
</script>
<template>
<VnFilterPanel :data-key="dataKey" search-url="consumption" :redirect="false">
<template #tags="{ tag, formatFn }">
<div class="q-gutter-x-xs">
<strong>{{ t(`params.${tag.label}`) }}: </strong>
<span>{{ formatFn(tag.value) }}</span>
</div>
</template>
<template #body="{ params, searchFn }">
<QItem>
<QItemSection
><QCheckbox
v-model="params.grouped"
:label="t('params.grouped')"
@update:model-value="searchFn()"
dense
/></QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInput
:label="t('params.item')"
v-model="params.itemId"
is-outlined
lazy-rules
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnSelect
v-model="params.buyerId"
url="TicketRequests/getItemTypeWorker"
:fields="['id', 'nickname']"
sort-by="nickname ASC"
:label="t('params.buyer')"
option-value="id"
option-label="nickname"
dense
outlined
rounded
/>
</QItemSection>
</QItem>
<QItem>
<!--It's required to include the relation category !! There's 413 records in production-->
<QItemSection>
<VnSelect
v-model="params.typeId"
url="ItemTypes"
:include="['category']"
:fields="['id', 'name', 'categoryFk']"
sort-by="name ASC"
:label="t('params.typeId')"
option-label="name"
option-value="id"
dense
outlined
rounded
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
<QItemLabel caption>{{
scope.opt?.category?.name
}}</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelect>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnSelect
v-model="params.categoryId"
url="ItemCategories"
:fields="['id', 'name']"
sort-by="name ASC"
:label="t('params.categoryId')"
option-label="name"
option-value="id"
dense
outlined
rounded
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnSelect
v-model="params.campaignId"
url="Campaigns/latest"
sort-by="dated DESC"
:label="t('params.campaignId')"
option-label="code"
option-value="id"
dense
outlined
rounded
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{
t(`params.${scope.opt?.code}`)
}}</QItemLabel>
<QItemLabel caption>{{
toDate(scope.opt.dated)
}}</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelect>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInputDate
:label="t('params.from')"
v-model="params.from"
@update:model-value="searchFn()"
is-outlined
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInputDate
:label="t('params.to')"
v-model="params.to"
@update:model-value="searchFn()"
is-outlined
/>
</QItemSection>
</QItem>
</template>
</VnFilterPanel>
</template>
<i18n>
en:
params:
grouped: Group by item
item: Item id
buyer: Buyer
type: Type
category: Category
itemId: Item id
buyerId: Buyer
typeId: Type
categoryId: Category
from: From
to: To
campaignId: Campaña
valentinesDay: Valentine's Day
mothersDay: Mother's Day
allSaints: All Saints' Day
es:
params:
grouped: Agrupar por artículo
item: Id artículo
buyer: Comprador
type: Tipo
category: Categoría
itemId: Id Artículo
buyerId: Comprador
typeId: Tipo
categoryId: Reino
from: Desde
to: Hasta
campaignId: Campaña
valentinesDay: Día de San Valentín
mothersDay: Día de la Madre
allSaints: Día de Todos los Santos
</i18n>