salix-front/src/pages/Customer/components/CustomerAddressEdit.vue

411 lines
13 KiB
Vue

<script setup>
import { onBeforeMount, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { useQuasar } from 'quasar';
import axios from 'axios';
import VnLocation from 'src/components/common/VnLocation.vue';
import FetchData from 'components/FetchData.vue';
import FormModel from 'components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnSelectDialog from 'src/components/common/VnSelectDialog.vue';
import CustomerNewCustomsAgent from 'src/pages/Customer/components/CustomerNewCustomsAgent.vue';
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
import VnConfirm from 'components/ui/VnConfirm.vue';
const { t } = useI18n();
const route = useRoute();
const router = useRouter();
const quasar = useQuasar();
const urlUpdate = ref('');
const agencyModes = ref([]);
const incoterms = ref([]);
const customsAgents = ref([]);
const observationTypes = ref([]);
const notes = ref([]);
let originalNotes = [];
const deletes = ref([]);
onBeforeMount(() => {
urlUpdate.value = `Clients/${route.params.id}/updateAddress/${route.params.addressId}`;
});
const getData = async (observations) => {
observationTypes.value = observations;
if (observationTypes.value.length) {
const filter = {
fields: ['id', 'addressFk', 'observationTypeFk', 'description'],
where: { addressFk: `${route.params.addressId}` },
};
const { data } = await axios.get('AddressObservations', {
params: { filter: JSON.stringify(filter) },
});
if (data.length) {
originalNotes = data;
notes.value = originalNotes
.map((observation) => {
const type = observationTypes.value.find(
(type) => type.id === observation.observationTypeFk,
);
return type
? {
$isNew: false,
$oldData: null,
$orgIndex: null,
addressFk: `${route.params.addressId}`,
description: observation.description,
id: observation.id,
observationTypeFk: type.id,
}
: null;
})
.filter((item) => item !== null);
}
}
};
const addNote = () => {
notes.value.push({
$isNew: true,
$oldData: null,
$orgIndex: null,
addressFk: `${route.params.addressId}`,
description: '',
observationTypeFk: '',
});
};
const deleteNote = (id, index) => {
deletes.value.push(id);
notes.value.splice(index, 1);
};
const updateAddress = async (data) => {
await axios.patch(urlUpdate.value, data);
};
const updateAddressTicket = async () => {
urlUpdate.value += '?updateObservations=true';
};
const updateObservations = async (payload) => {
await axios.post('AddressObservations/crud', cleanPayload(payload));
notes.value = [];
deletes.value = [];
};
function cleanPayload(payload) {
['creates', 'deletes', 'updates'].forEach((prop) => {
if (prop === 'creates' || prop === 'updates') {
payload[prop] = payload[prop].filter(
(item) => item.description !== '' && item.observationTypeFk !== '',
);
} else {
payload[prop] = payload[prop].filter(
(item) => item !== null && item !== undefined,
);
}
});
return payload;
}
async function updateAll({ data, payload }) {
await updateObservations(payload);
await updateAddress(data);
toCustomerAddress();
}
function getPayload() {
return {
creates: notes.value.filter((note) => note.$isNew),
deletes: deletes.value,
updates: notes.value
.filter((note) =>
originalNotes.some(
(oNote) =>
oNote.id === note.id &&
(note.description !== oNote.description ||
note.observationTypeFk !== oNote.observationTypeFk),
),
)
.map((note) => ({
data: note,
where: { id: note.id },
})),
};
}
async function handleDialog(data) {
const payload = getPayload();
const body = { data, payload };
if (payload.updates.length) {
quasar
.dialog({
component: VnConfirm,
componentProps: {
title: t('confirmTicket'),
message: t('confirmDeletionMessage'),
},
})
.onOk(async () => {
await updateAddressTicket();
await updateAll(body);
})
.onCancel(async () => {
await updateAll(body);
});
} else {
await updateAll(body);
}
}
const toCustomerAddress = () => {
notes.value = [];
deletes.value = [];
router.push({
name: 'CustomerAddress',
params: {
id: route.params.id,
},
});
};
function handleLocation(data, location) {
const { town, code, provinceFk, countryFk } = location ?? {};
data.postalCode = code;
data.city = town;
data.provinceFk = provinceFk;
data.countryFk = countryFk;
}
function onAgentCreated({ id, fiscalName }, data) {
customsAgents.value.push({ id, fiscalName });
data.customsAgentFk = id;
}
</script>
<template>
<FetchData
@on-fetch="(data) => (agencyModes = data)"
auto-load
url="AgencyModes/isActive"
/>
<FetchData @on-fetch="(data) => (incoterms = data)" auto-load url="Incoterms" />
<FetchData
@on-fetch="(data) => (customsAgents = data)"
auto-load
url="CustomsAgents"
/>
<FetchData @on-fetch="getData" auto-load url="ObservationTypes" />
<FormModel
:observe-form-changes="false"
:url-update="urlUpdate"
:url="`Addresses/${route.params.addressId}`"
:save-fn="handleDialog"
auto-load
>
<template #moreActions>
<QBtn
:label="t('globals.cancel')"
@click="toCustomerAddress"
color="primary"
flat
icon="close"
/>
</template>
<template #form="{ data, validate }">
<VnRow>
<div class="col">
<QCheckbox :label="t('Enabled')" v-model="data.isActive" />
</div>
<div class="col">
<QCheckbox
:label="t('Is equalizated')"
v-model="data.isEqualizated"
/>
</div>
<div class="col">
<QCheckbox
:label="t('Is Loginflora allowed')"
v-model="data.isLogifloraAllowed"
/>
</div>
</VnRow>
<VnRow>
<div class="col">
<VnInput :label="t('Consignee')" clearable v-model="data.nickname" />
</div>
<div class="col">
<VnInput :label="t('Street')" clearable v-model="data.street" />
</div>
</VnRow>
<VnRow>
<div class="col">
<VnLocation
:rules="validate('Worker.postcode')"
:acls="[{ model: 'Town', props: '*', accessType: 'WRITE' }]"
:location="{
postcode: data.postalCode,
city: data.city,
province: data.province,
country: data.province?.country,
}"
@update:model-value="(location) => handleLocation(data, location)"
></VnLocation>
</div>
</VnRow>
<VnRow>
<div class="col">
<VnSelect
:label="t('Agency')"
:options="agencyModes"
:rules="validate('route.agencyFk')"
hide-selected
option-label="name"
option-value="id"
v-model="data.agencyModeFk"
/>
</div>
<div class="col">
<VnInput :label="t('Phone')" clearable v-model="data.phone" />
</div>
<div class="col">
<VnInput :label="t('Mobile')" clearable v-model="data.mobile" />
</div>
</VnRow>
<VnRow>
<VnSelect
:label="t('Incoterms')"
:options="incoterms"
hide-selected
option-label="name"
option-value="code"
v-model="data.incotermsFk"
/>
<VnSelectDialog
:label="t('Customs agent')"
:options="customsAgents"
hide-selected
option-label="fiscalName"
option-value="id"
v-model="data.customsAgentFk"
:tooltip="t('New customs agent')"
:acls="[{ model: 'CustomsAgent', props: '*', accessType: 'WRITE' }]"
>
<template #form>
<CustomerNewCustomsAgent
@on-data-saved="
(requestResponse) => onAgentCreated(requestResponse, data)
"
/>
</template>
</VnSelectDialog>
</VnRow>
<VnRow>
<VnInputNumber
:label="t('Longitude')"
clearable
v-model="data.longitude"
:decimal-places="7"
:positive="false"
/>
<VnInputNumber
:label="t('Latitude')"
clearable
v-model="data.latitude"
:decimal-places="7"
:positive="false"
/>
</VnRow>
<h4 class="q-mb-xs">{{ t('Notes') }}</h4>
<VnRow
:key="index"
class="row q-gutter-md q-mb-md"
v-for="(note, index) in notes"
>
<VnSelect
:label="t('Observation type')"
:options="observationTypes"
hide-selected
option-label="description"
option-value="id"
v-model="note.observationTypeFk"
/>
<VnInput
:label="t('Description')"
:rules="validate('route.description')"
clearable
v-model="note.description"
/>
<QIcon
:style="{ flex: 0, 'align-self': $q.screen.gt.xs ? 'end' : 'center' }"
@click.stop="deleteNote(note.id, index)"
class="cursor-pointer"
color="primary"
name="delete"
size="sm"
>
<QTooltip>
{{ t('Remove note') }}
</QTooltip>
</QIcon>
</VnRow>
<QBtn
@click.stop="addNote()"
class="cursor-pointer add-icon q-mt-md"
flat
icon="add"
v-shortcut="'+'"
>
<QTooltip>
{{ t('Add note') }}
</QTooltip>
</QBtn>
</template>
</FormModel>
</template>
<style lang="scss" scoped>
.add-icon {
background-color: $primary;
border-radius: 50px;
}
</style>
<i18n>
es:
Enabled: Activo
Is equalizated: Recargo de equivalencia
Is Loginflora allowed: Compra directa en Holanda
Consignee: Consignatario
Street: Dirección fiscal
Postcode: Código postal
City: Población
Province: Provincia
Agency: Agencia
Phone: Teléfono
Mobile: Movíl
Incoterms: Incoterms
Customs agent: Agente de aduanas
New customs agent: Nuevo agente de aduanas
Notes: Notas
Observation type: Tipo de observación
Description: Descripción
Add note: Añadir nota
Remove note: Eliminar nota
Longitude: Longitud
Latitude: Latitud
confirmTicket: ¿Desea modificar también los estados de todos los tickets que están a punto de ser servidos?
confirmDeletionMessage: Si le das a aceptar, se modificaran todas las notas de los ticket a futuro
en:
confirmTicket: Do you also want to modify the states of all the tickets that are about to be served?
confirmDeletionMessage: If you click accept, all the notes of the future tickets will be modified
</i18n>