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);
}
defineExpose({ save, isLoading, hasChanges });
defineExpose({ save, isLoading, hasChanges, formData });
</script>
<template>
<div class="column items-center full-width">

View File

@ -1,29 +1,508 @@
<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 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 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>
<template>
<QStepper v-model="step" ref="stepperRef" color="primary" header-nav animated>
<QStep
:name="1"
title="Select campaign settings"
icon="settings"
:error="step < 3"
:done="step > 1"
<FetchData
url="Clients"
:filter="{
fields: ['id', 'name'],
order: 'id',
}"
@on-fetch="(data) => (clientsOptions = data)"
auto-load
/>
<FetchData
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
>
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
you want your ads to show on, and more.
<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
:name="2"
title="Create an ad group"
caption="Optional"
icon="create_new_folder"
:done="step > 2"
>
<QStep :name="2" title="Create an ad group" caption="Optional">
An ad group contains one or more ads which target a shared set of keywords.
</QStep>
@ -32,17 +511,18 @@ const step = ref(1);
<QBtn
@click="stepperRef.next()"
color="primary"
:label="step === 3 ? 'Finish' : 'Continue'"
:label="step === 2 ? t('basicData.finalize') : t('basicData.next')"
/>
<QBtn
v-if="step > 1"
flat
color="primary"
@click="stepperRef.previous()"
label="Back"
:label="t('basicData.back')"
class="q-ml-sm"
/>
</QStepperNavigation>
</template>
</QStepper>
<pre v-if="formModelRef">{{ formModelRef.formData }}</pre>
</template>

View File

@ -2,3 +2,16 @@ basicData:
next: Next
back: Back
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
back: Anterior
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
You can search by ticket id or alias: Puedes buscar por id o alias del ticket