340 lines
10 KiB
Vue
340 lines
10 KiB
Vue
<script setup>
|
|
import axios from 'axios';
|
|
import { computed, ref, onMounted } from 'vue';
|
|
import { useStateStore } from 'stores/useStateStore';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { toDate, toCurrency } from 'src/filters/index';
|
|
import TicketSummary from './Card/TicketSummary.vue';
|
|
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
|
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
|
import VnTable from 'src/components/VnTable/VnTable.vue';
|
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
|
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
|
import VnRow from 'src/components/ui/VnRow.vue';
|
|
import RightMenu from 'src/components/common/RightMenu.vue';
|
|
import TicketFilter from './TicketFilter.vue';
|
|
|
|
const { t } = useI18n();
|
|
const { viewSummary } = useSummaryDialog();
|
|
const tableRef = ref();
|
|
const clientsOptions = ref([]);
|
|
const addressesOptions = ref([]);
|
|
const agenciesOptions = ref([]);
|
|
const selectedClient = ref();
|
|
const stateStore = useStateStore();
|
|
const from = Date.vnNew();
|
|
const to = Date.vnNew();
|
|
to.setDate(to.getDate() + 1);
|
|
|
|
const userParams = {
|
|
from: from.toISOString(),
|
|
to: to.toISOString(),
|
|
};
|
|
|
|
const columns = computed(() => [
|
|
{
|
|
align: 'left',
|
|
name: 'stateFk',
|
|
label: t('ticketList.state'),
|
|
columnFilter: {
|
|
name: 'stateFk',
|
|
component: 'select',
|
|
attrs: {
|
|
url: 'States',
|
|
fields: ['id', 'name'],
|
|
},
|
|
},
|
|
},
|
|
{
|
|
align: 'left',
|
|
name: 'id',
|
|
label: t('ticketList.id'),
|
|
chip: {
|
|
condition: () => true,
|
|
},
|
|
isId: true,
|
|
},
|
|
{
|
|
align: 'left',
|
|
name: 'nickname',
|
|
label: t('ticketList.nickname'),
|
|
isTitle: true,
|
|
},
|
|
|
|
{
|
|
align: 'left',
|
|
name: 'shipped',
|
|
cardVisible: true,
|
|
label: t('ticketList.shipped'),
|
|
columnFilter: {
|
|
component: 'date',
|
|
alias: 't',
|
|
inWhere: true,
|
|
},
|
|
format: ({ shipped }) => toDate(shipped),
|
|
},
|
|
{
|
|
align: 'left',
|
|
name: 'zoneFk',
|
|
label: t('ticketList.zone'),
|
|
columnFilter: {
|
|
component: 'select',
|
|
attrs: {
|
|
url: 'Zones',
|
|
fields: ['id', 'name'],
|
|
},
|
|
alias: 't',
|
|
inWhere: true,
|
|
},
|
|
format: (row, dashIfEmpty) => dashIfEmpty(row.zoneName),
|
|
},
|
|
{
|
|
align: 'left',
|
|
label: t('ticketList.salesPerson'),
|
|
name: 'salesPersonFk',
|
|
component: 'select',
|
|
attrs: {
|
|
url: 'Workers/activeWithInheritedRole',
|
|
fields: ['id', 'name'],
|
|
where: { role: 'salesPerson' },
|
|
optionFilter: 'firstName',
|
|
useLike: false,
|
|
},
|
|
columnField: {
|
|
component: null,
|
|
},
|
|
format: (row, dashIfEmpty) => dashIfEmpty(row.salesPerson),
|
|
},
|
|
{
|
|
align: 'left',
|
|
name: 'totalWithVat',
|
|
label: t('ticketList.totalWithVat'),
|
|
cardVisible: true,
|
|
columnFilter: {
|
|
component: 'number',
|
|
inWhere: true,
|
|
},
|
|
format: (row) => toCurrency(row.totalWithVat),
|
|
},
|
|
{
|
|
align: 'right',
|
|
name: 'tableActions',
|
|
actions: [
|
|
{
|
|
title: t('ticketList.summary'),
|
|
icon: 'preview',
|
|
action: (row) => viewSummary(row.id, TicketSummary),
|
|
},
|
|
],
|
|
},
|
|
]);
|
|
|
|
const onClientSelected = async (formData) => {
|
|
await fetchClient(formData);
|
|
await fetchAddresses(formData);
|
|
};
|
|
|
|
const fetchAvailableAgencies = async (formData) => {
|
|
if (!formData.warehouseId || !formData.addressId || !formData.landed) return;
|
|
let params = {
|
|
warehouseFk: formData.warehouseId,
|
|
addressFk: formData.addressId,
|
|
landed: formData.landed,
|
|
};
|
|
|
|
const { data } = await axios.get('Agencies/getAgenciesWithWarehouse', { params });
|
|
|
|
agenciesOptions.value = data;
|
|
|
|
const defaultAgency = agenciesOptions.value.find(
|
|
(agency) =>
|
|
agency.agencyModeFk === selectedClient.value.defaultAddress.agencyModeFk
|
|
);
|
|
|
|
if (defaultAgency) formData.agencyModeId = defaultAgency.agencyModeFk;
|
|
};
|
|
|
|
const fetchClient = async (formData) => {
|
|
try {
|
|
const filter = {
|
|
include: {
|
|
relation: 'defaultAddress',
|
|
scope: {
|
|
fields: ['id', 'agencyModeFk'],
|
|
},
|
|
},
|
|
where: { id: formData.clientId },
|
|
};
|
|
const params = { filter: JSON.stringify(filter) };
|
|
const { data } = await axios.get('Clients', { params });
|
|
const [client] = data;
|
|
selectedClient.value = client;
|
|
} catch (err) {
|
|
console.error('Error fetching client');
|
|
}
|
|
};
|
|
|
|
const fetchAddresses = async (formData) => {
|
|
try {
|
|
if (!formData.clientId) return;
|
|
|
|
const filter = {
|
|
fields: ['nickname', 'street', 'city', 'id'],
|
|
where: { isActive: true },
|
|
order: 'nickname ASC',
|
|
};
|
|
const params = { filter: JSON.stringify(filter) };
|
|
const { data } = await axios.get(`Clients/${formData.clientId}/addresses`, {
|
|
params,
|
|
});
|
|
addressesOptions.value = data;
|
|
|
|
const { defaultAddress } = selectedClient.value;
|
|
formData.addressId = defaultAddress.id;
|
|
} catch (err) {
|
|
console.error(`Error fetching addresses`, err);
|
|
return err.response;
|
|
}
|
|
};
|
|
const getColor = (row) => {
|
|
return row?.classColor ? `bg-${row.classColor}` : 'bg-orange';
|
|
};
|
|
|
|
onMounted(() => (stateStore.rightDrawer = true));
|
|
</script>
|
|
|
|
<template>
|
|
<VnSearchbar
|
|
data-key="Tickets"
|
|
:label="t('Search ticket')"
|
|
:info="t('You can search by ticket id or alias')"
|
|
/>
|
|
<RightMenu>
|
|
<template #right-panel>
|
|
<TicketFilter data-key="Tickets" />
|
|
</template>
|
|
</RightMenu>
|
|
<VnTable
|
|
ref="tableRef"
|
|
data-key="Tickets"
|
|
url="Tickets/filter"
|
|
:create="{
|
|
urlCreate: 'Tickets/new',
|
|
title: t('ticketList.createTicket'),
|
|
onDataSaved: ({ id }) => tableRef.redirect(id),
|
|
formInitialData: {},
|
|
}"
|
|
default-mode="table"
|
|
order="id DESC"
|
|
:columns="columns"
|
|
:user-params="userParams"
|
|
:right-search="false"
|
|
redirect="ticket"
|
|
auto-load
|
|
>
|
|
<template #more-create-dialog="{ data }">
|
|
<VnRow>
|
|
<VnSelect
|
|
url="Clients"
|
|
:label="t('ticketList.client')"
|
|
v-model="data.clientId"
|
|
:options="clientsOptions"
|
|
option-value="id"
|
|
option-label="name"
|
|
hide-selected
|
|
@update:model-value="(client) => onClientSelected(data)"
|
|
>
|
|
<template #option="scope">
|
|
<QItem v-bind="scope.itemProps">
|
|
<QItemSection>
|
|
<QItemLabel>
|
|
{{ scope.opt.name }}
|
|
</QItemLabel>
|
|
<QItemLabel caption>
|
|
{{ `#${scope.opt.id}` }}
|
|
</QItemLabel>
|
|
</QItemSection>
|
|
</QItem>
|
|
</template>
|
|
</VnSelect>
|
|
</VnRow>
|
|
<VnRow>
|
|
<VnSelect
|
|
url="Addresses"
|
|
:label="t('ticket.create.address')"
|
|
v-model="data.addressId"
|
|
:options="addressesOptions"
|
|
option-value="id"
|
|
option-label="nickname"
|
|
hide-selected
|
|
:disable="!data.clientId"
|
|
@update:model-value="() => fetchAvailableAgencies(data)"
|
|
>
|
|
<template #option="scope">
|
|
<QItem v-bind="scope.itemProps">
|
|
<QItemSection>
|
|
<QItemLabel>
|
|
{{ scope.opt.nickname }}
|
|
</QItemLabel>
|
|
<QItemLabel caption>
|
|
{{ `${scope.opt.street}, ${scope.opt.city}` }}
|
|
</QItemLabel>
|
|
</QItemSection>
|
|
</QItem>
|
|
</template>
|
|
</VnSelect>
|
|
</VnRow>
|
|
<VnRow>
|
|
<div class="col">
|
|
<VnInputDate
|
|
placeholder="dd-mm-aaa"
|
|
:label="t('ticket.create.landed')"
|
|
v-model="data.landed"
|
|
@update:model-value="() => fetchAvailableAgencies(data)"
|
|
/>
|
|
</div>
|
|
</VnRow>
|
|
<VnRow>
|
|
<div class="col">
|
|
<VnSelect
|
|
url="Warehouses"
|
|
:label="t('ticket.create.warehouse')"
|
|
v-model="data.warehouseId"
|
|
:options="warehousesOptions"
|
|
option-value="id"
|
|
option-label="name"
|
|
hide-selected
|
|
@update:model-value="() => fetchAvailableAgencies(data)"
|
|
/>
|
|
</div>
|
|
</VnRow>
|
|
<VnRow>
|
|
<div class="col">
|
|
<VnSelect
|
|
:label="t('ticket.create.agency')"
|
|
v-model="data.agencyModeId"
|
|
:options="agenciesOptions"
|
|
option-value="agencyModeFk"
|
|
option-label="agencyMode"
|
|
hide-selected
|
|
:disable="!data.clientId || !data.landed || !data.warehouseId"
|
|
/>
|
|
</div>
|
|
</VnRow>
|
|
</template>
|
|
<template #column-stateFk="{ row }">
|
|
<QChip :class="getColor(row)" dense square>
|
|
{{ row.state }}
|
|
</QChip>
|
|
</template>
|
|
</VnTable>
|
|
</template>
|
|
|
|
<i18n>
|
|
es:
|
|
Search ticket: Buscar ticket
|
|
You can search by ticket id or alias: Puedes buscar por id o alias del ticket
|
|
Zone: Zona
|
|
New ticket: Nuevo ticket
|
|
</i18n>
|