Ticket basic data #474

Merged
jsegarra merged 15 commits from :feature/TicketBasicData into dev 2024-06-25 20:28:01 +00:00
4 changed files with 528 additions and 22 deletions
Showing only changes of commit 633b13b076 - Show all commits

View File

@ -246,7 +246,7 @@ function updateAndEmit(evt, val, res) {
emit(evt, state.get(modelValue), res); emit(evt, state.get(modelValue), res);
} }
defineExpose({ save, isLoading, hasChanges }); defineExpose({ save, isLoading, hasChanges, formData });
</script> </script>
<template> <template>
<div class="column items-center full-width"> <div class="column items-center full-width">

View File

@ -1,29 +1,508 @@
<script setup> <script setup>
import { ref } from 'vue'; import { ref, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import FetchData from 'components/FetchData.vue';
import FormModel from 'components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnInputDate from 'src/components/common/VnInputDate.vue';
import VnInputTime from 'components/common/VnInputTime.vue';
import axios from 'axios';
import useNotify from 'src/composables/useNotify.js';
import { toTimeFormat } from 'filters/date.js';
const { notify } = useNotify();
const route = useRoute();
const router = useRouter();
const { t } = useI18n();
const stepperRef = ref(null); const stepperRef = ref(null);
const formModelRef = ref(null);
const agencyFetchRef = ref(null);
const zonesFetchRef = ref(null);
const filter = {
include: [
{ relation: 'address' },
{
relation: 'client',
scope: {
fields: [
'salesPersonFk',
'name',
'isActive',
'isFreezed',
'isTaxDataChecked',
'credit',
'email',
'phone',
'mobile',
'hasElectronicInvoice',
],
include: {
relation: 'salesPersonUser',
scope: { fields: ['id', 'name'] },
},
},
},
{ relation: 'invoiceOut' },
],
};
const step = ref(1); const step = ref(1);
const clientsOptions = ref([]);
const warehousesOptions = ref([]);
const companiesOptions = ref([]);
const agenciesOptions = ref([]);
const zonesOptions = ref([]);
const addresses = ref([]);
const agencyByWarehouseFilter = computed(() => ({
fields: ['id', 'name'],
order: 'name ASC',
where: {
warehouseFk: warehouseId.value,
},
}));
const zonesFilter = computed(() => ({
fields: ['id', 'name'],
order: 'name ASC',
where: formModelRef.value?.formData?.agencyModeFk
? {
shipped: formModelRef.value?.formData?.shipped,
addressFk: formModelRef.value?.formData?.addressFk,
agencyModeFk: formModelRef.value?.formData?.agencyModeFk,
warehouseFk: formModelRef.value?.formData?.warehouseFk,
}
: {},
}));
const getLanded = async (params) => {
try {
const validParams =
shipped.value && addressId.value && agencyModeId.value && warehouseId.value;
if (!validParams) {
// this.$q.resolve(); ???????
return;
}
formModelRef.value.formData.zoneFk = null;
const { data } = await axios.get(`Agencies/getLanded`, { params });
if (data) {
formModelRef.value.formData.zoneFk = data.zoneFk;
formModelRef.value.formData.landed = data.landed;
formModelRef.value.formData.shipped = params.shipped;
}
} catch (error) {
console.error(error);
notify(t('basicData.noDeliveryZoneAvailable'), 'negative');
}
};
const getShipped = async (params) => {
try {
const validParams =
landed.value && addressId.value && agencyModeId.value && warehouseId.value;
if (!validParams) return;
formModelRef.value.formData.zoneFk = null;
const { data } = await axios.get(`Agencies/getShipped`, { params });
if (data) {
formModelRef.value.formData.zoneFk = data.zoneFk;
formModelRef.value.formData.landed = params.landed;
formModelRef.value.formData.shipped = data.shipped;
} else {
notify(t('basicData.noDeliveryZoneAvailable'), 'negative');
}
} catch (error) {
console.error(error);
notify(t('basicData.noDeliveryZoneAvailable'), 'negative');
}
};
const onChangeZone = async (zoneId) => {
try {
formModelRef.value.formData.agencyModeFk = null;
const { data } = await axios.get(`Zones/${zoneId}`);
formModelRef.value.formData.agencyModeFk = data.agencyModeFk;
} catch (error) {
console.error(error);
}
};
const onChangeAddress = async (addressId) => {
try {
formModelRef.value.formData.nickname = null;
const { data } = await axios.get(`Addresses/${addressId}`);
formModelRef.value.formData.nickname = data.nickname;
} catch (error) {
console.error(error);
}
};
const getClientDefaultAddress = async (clientId) => {
try {
const { data } = await axios.get(`Clients/${clientId}`);
if (data) addressId.value = data.defaultAddressFk;
} catch (error) {
console.error(error);
}
};
const clientAddressesList = async (value) => {
let filter = {
include: [
{
relation: 'province',
scope: {
fields: ['name'],
},
},
{
relation: 'agencyMode',
scope: {
fields: ['name'],
},
},
],
};
const params = { filter: JSON.stringify(filter) };
const { data } = await axios.get(`Clients/${value}/addresses`, { params });
if (data) addresses.value = data;
};
const addressId = computed({
get: () => formModelRef.value?.formData?.addressFk,
set: (val) => {
if (val != formModelRef.value?.formData?.addressFk) {
formModelRef.value.formData.addressFk = val;
onChangeAddress(val);
getShipped({
landed: formModelRef.value?.formData?.landed,
addressFk: val,
agencyModeFk: formModelRef.value?.formData?.agencyModeFk,
warehouseFk: formModelRef.value?.formData?.warehouseFk,
});
}
},
});
const clientId = computed({
get: () => formModelRef.value?.formData?.clientFk,
set: (val) => {
formModelRef.value.formData.clientFk = val;
formModelRef.value.formData.addressFk = null;
if (!val) return;
getClientDefaultAddress(val);
clientAddressesList(val);
},
});
const landed = computed({
get: () => formModelRef.value?.formData?.landed,
set: (val) => {
formModelRef.value.formData.landed = val;
getShipped({
landed: val,
addressFk: formModelRef.value?.formData?.addressFk,
agencyModeFk: formModelRef.value?.formData?.agencyModeFk,
warehouseFk: formModelRef.value?.formData?.warehouseFk,
});
},
});
const agencyModeId = computed({
get: () => formModelRef.value?.formData?.agencyModeFk,
set: (val) => {
if (val != formModelRef.value?.formData?.agencyModeFk) {
formModelRef.value.formData.agencyModeFk = val;
if (!val) return;
const agencyMode = agenciesOptions.value.find((a) => a.id == val);
formModelRef.value.formData.warehouseFk = agencyMode.warehouseFk;
getLanded({
shipped: formModelRef.value?.formData?.shipped,
addressFk: formModelRef.value?.formData?.addressFk,
agencyModeFk: val,
warehouseFk: formModelRef.value?.formData?.warehouseFk,
});
}
},
});
const zoneId = computed({
get: () => formModelRef.value?.formData?.zoneFk,
set: (val) => {
if (val != formModelRef.value.formData.zoneFk) {
formModelRef.value.formData.zoneFk = val;
onChangeZone(val);
}
},
});
const warehouseId = computed({
get: () => formModelRef.value?.formData?.warehouseFk,
set: (val) => {
if (val != formModelRef.value.formData.warehouseFk) {
formModelRef.value.formData.warehouseFk = val;
getShipped({
landed: formModelRef.value.formData.landed,
addressFk: formModelRef.value.formData.addressFk,
agencyModeFk: formModelRef.value.formData.agencyModeFk,
warehouseFk: val,
}).then(() => {
if (zoneId.value == null) formModelRef.value.formData.agencyModeFk = null;
});
}
},
});
const shipped = computed({
get: () => formModelRef.value?.formData?.shipped,
set: (val) => {
if (
new Date(formModelRef.value?.formData?.shipped).toDateString() !=
val.toDateString()
)
val.setHours(0, 0, 0, 0);
formModelRef.value.formData.shipped = val;
getLanded({
shipped: val,
addressFk: formModelRef.value?.formData?.addressFk,
agencyModeFk: formModelRef.value?.formData?.agencyModeFk,
warehouseFk: formModelRef.value?.formData?.warehouseFk,
});
},
});
const onFormModelInit = () => {
if (formModelRef.value.formData.clientFk)
clientAddressesList(formModelRef.value.formData.clientFk);
};
const redirectToCustomerAddress = () => {
router.push({
name: 'CustomerAddressEditCard',
params: { id: clientId.value, addressId: addressId.value },
});
};
</script> </script>
<template> <template>
<QStepper v-model="step" ref="stepperRef" color="primary" header-nav animated> <FetchData
<QStep url="Clients"
:name="1" :filter="{
title="Select campaign settings" fields: ['id', 'name'],
icon="settings" order: 'id',
:error="step < 3" }"
:done="step > 1" @on-fetch="(data) => (clientsOptions = data)"
> auto-load
For each ad campaign that you create, you can control how much you're willing />
to spend on clicks and conversions, which networks and geographical locations <FetchData
you want your ads to show on, and more. url="Warehouses"
@on-fetch="(data) => (warehousesOptions = data)"
auto-load
/>
<FetchData
url="Companies"
:filter="{
fields: ['id', 'code'],
order: 'code ASC',
}"
@on-fetch="(data) => (companiesOptions = data)"
auto-load
/>
<FetchData
ref="agencyFetchRef"
url="AgencyModes/byWarehouse"
:filter="agencyByWarehouseFilter"
@on-fetch="(data) => (agenciesOptions = data)"
auto-load
/>
<FetchData
ref="zonesFetchRef"
url="Zones/includingExpired"
:filter="zonesFilter"
@on-fetch="(data) => (zonesOptions = data)"
auto-load
/>
<QStepper
v-model="step"
ref="stepperRef"
color="primary"
header-nav
animated
keep-alive
>
<QStep :name="1" title="Select campaign settings" :done="step > 1">
<FormModel
ref="formModelRef"
:url="`Tickets/${route.params.id}`"
:url-update="`Tickets/${route.params.id}`"
:filter="filter"
model="Ticket"
auto-load
:default-actions="false"
@on-fetch="onFormModelInit()"
>
<template #form="{ data }">
<VnRow class="row q-gutter-md q-mb-md">
<VnSelect
:label="t('basicData.client')"
v-model="clientId"
option-value="id"
option-label="name"
:options="clientsOptions"
hide-selected
map-options
:required="true"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel
>#{{ scope.opt?.id }}
{{ scope.opt?.name }}</QItemLabel
>
</QItemSection>
</QItem>
</template>
</VnSelect>
<VnSelect
:label="t('basicData.warehouse')"
v-model="warehouseId"
option-value="id"
option-label="name"
:options="warehousesOptions"
hide-selected
map-options
:required="true"
/>
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<VnSelect
:label="t('basicData.address')"
v-model="addressId"
option-value="id"
option-label="nickname"
:options="addresses"
hide-selected
map-options
:required="true"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel
:class="{
'color-vn-label': !scope.opt?.isActive,
}"
>
{{
`${
!scope.opt?.isActive
? t('basicData.inactive')
: ''
} `
}}
<span> {{ scope.opt?.nickname }}</span>
<span
v-if="
scope.opt?.province ||
scope.opt?.city ||
scope.opt?.street
"
>, {{ scope.opt?.street }},
{{ scope.opt?.city }},
{{ scope.opt?.province?.name }} -
{{ scope.opt?.agencyMode?.name }}</span
>
</QItemLabel>
</QItemSection>
</QItem>
</template>
<template #append>
<QIcon
name="edit"
color="primary"
size="sm"
class="fill-icon cursor-pointer"
@click.stop="redirectToCustomerAddress()"
>
<QTooltip>{{ t('basicData.editAddress') }}</QTooltip>
</QIcon>
</template>
</VnSelect>
<VnInput :label="t('basicData.alias')" v-model="data.nickname" />
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<VnSelect
:label="t('basicData.company')"
v-model="data.companyFk"
option-value="id"
option-label="code"
:options="companiesOptions"
hide-selected
map-options
:required="true"
/>
<VnSelect
:label="t('basicData.agency')"
v-model="agencyModeId"
option-value="id"
option-label="name"
:options="agenciesOptions"
hide-selected
map-options
:required="true"
@focus="agencyFetchRef.fetch()"
/>
<VnSelect
:label="t('basicData.zone')"
v-model="zoneId"
option-value="id"
option-label="name"
:options="zonesOptions"
hide-selected
map-options
:required="true"
@focus="zonesFetchRef.fetch()"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel
>{{ scope.opt?.name }} - Max.
{{ toTimeFormat(scope.opt?.hour) }}
h.</QItemLabel
>
</QItemSection>
</QItem>
</template>
</VnSelect>
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<VnInputDate
:label="t('basicData.shipped')"
v-model="data.shipped"
:required="true"
/>
<VnInputTime
:label="t('basicData.shippedHour')"
v-model="data.shipped"
/>
<VnInputDate
:label="t('basicData.landed')"
v-model="data.landed"
:required="true"
/>
</VnRow>
</template>
</FormModel>
</QStep> </QStep>
<QStep <QStep :name="2" title="Create an ad group" caption="Optional">
:name="2"
title="Create an ad group"
caption="Optional"
icon="create_new_folder"
:done="step > 2"
>
An ad group contains one or more ads which target a shared set of keywords. An ad group contains one or more ads which target a shared set of keywords.
</QStep> </QStep>
@ -32,17 +511,18 @@ const step = ref(1);
<QBtn <QBtn
@click="stepperRef.next()" @click="stepperRef.next()"
color="primary" color="primary"
:label="step === 3 ? 'Finish' : 'Continue'" :label="step === 2 ? t('basicData.finalize') : t('basicData.next')"
/> />
<QBtn <QBtn
v-if="step > 1" v-if="step > 1"
flat flat
color="primary" color="primary"
@click="stepperRef.previous()" @click="stepperRef.previous()"
label="Back" :label="t('basicData.back')"
class="q-ml-sm" class="q-ml-sm"
/> />
</QStepperNavigation> </QStepperNavigation>
</template> </template>
</QStepper> </QStepper>
<pre v-if="formModelRef">{{ formModelRef.formData }}</pre>
</template> </template>

View File

@ -2,3 +2,16 @@ basicData:
next: Next next: Next
back: Back back: Back
finalize: Finalize finalize: Finalize
client: Client
warehouse: Warehouse
address: Address
inactive: (Inactive)
noDeliveryZoneAvailable: No delivery zone available for this landing date
editAddress: Edit address
alias: Alias
company: Company
agency: Agency
zone: Zone
shipped: Shipped
landed: Landed
shippedHour: Shipped hour

View File

@ -2,5 +2,18 @@ basicData:
next: Siguiente next: Siguiente
back: Anterior back: Anterior
finalize: Finalizar finalize: Finalizar
client: Cliente
warehouse: Almacén
address: Consignatario
inactive: (Inactivo)
noDeliveryZoneAvailable: No hay una zona de reparto disponible para la fecha de envío seleccionada
editAddress: Editar dirección
alias: Alias
company: Empresa
agency: Agencia
zone: Zona
shipped: F. Envío
landed: F. Entrega
shippedHour: Hora de envío
Search ticket: Buscar ticket Search ticket: Buscar ticket
You can search by ticket id or alias: Puedes buscar por id o alias del ticket You can search by ticket id or alias: Puedes buscar por id o alias del ticket