Merge branch 'dev' into 6696-mana
gitea/salix-front/pipeline/pr-dev This commit looks good
Details
gitea/salix-front/pipeline/pr-dev This commit looks good
Details
This commit is contained in:
commit
d790907e79
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "salix-front",
|
||||
"version": "24.50.0",
|
||||
"version": "24.52.0",
|
||||
"description": "Salix frontend",
|
||||
"productName": "Salix",
|
||||
"author": "Verdnatura",
|
||||
|
@ -64,4 +64,4 @@
|
|||
"vite": "^5.1.4",
|
||||
"vitest": "^0.31.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ const onDataSaved = (...args) => {
|
|||
url-create="towns"
|
||||
model="city"
|
||||
@on-data-saved="onDataSaved"
|
||||
data-cy="newCityForm"
|
||||
>
|
||||
<template #form-inputs="{ data, validate }">
|
||||
<VnRow>
|
||||
|
@ -48,12 +49,14 @@ const onDataSaved = (...args) => {
|
|||
v-model="data.name"
|
||||
:rules="validate('city.name')"
|
||||
required
|
||||
data-cy="cityName"
|
||||
/>
|
||||
<VnSelectProvince
|
||||
:province-selected="$props.provinceSelected"
|
||||
:country-fk="$props.countryFk"
|
||||
v-model="data.provinceFk"
|
||||
required
|
||||
data-cy="provinceCity"
|
||||
/>
|
||||
</VnRow>
|
||||
</template>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { computed, reactive, ref } from 'vue';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
|
@ -21,14 +21,14 @@ const postcodeFormData = reactive({
|
|||
provinceFk: null,
|
||||
townFk: null,
|
||||
});
|
||||
|
||||
const townsFetchDataRef = ref(false);
|
||||
const townFilter = ref({});
|
||||
|
||||
const countriesRef = ref(false);
|
||||
const townsRef = ref(false);
|
||||
const provincesFetchDataRef = ref(false);
|
||||
const provincesOptions = ref([]);
|
||||
const townsOptions = ref([]);
|
||||
const town = ref({});
|
||||
const townFilter = ref({});
|
||||
const countryFilter = ref({});
|
||||
|
||||
function onDataSaved(formData) {
|
||||
|
@ -48,6 +48,49 @@ function onDataSaved(formData) {
|
|||
emit('onDataSaved', newPostcode);
|
||||
}
|
||||
|
||||
async function setCountry(countryFk, data) {
|
||||
data.townFk = null;
|
||||
data.provinceFk = null;
|
||||
data.countryFk = countryFk;
|
||||
await fetchTowns();
|
||||
}
|
||||
|
||||
// Province
|
||||
|
||||
async function handleProvinces(data) {
|
||||
provincesOptions.value = data;
|
||||
if (postcodeFormData.countryFk) {
|
||||
await fetchTowns();
|
||||
}
|
||||
}
|
||||
async function setProvince(id, data) {
|
||||
if (data.provinceFk === id) return;
|
||||
const newProvince = provincesOptions.value.find((province) => province.id == id);
|
||||
if (newProvince) data.countryFk = newProvince.countryFk;
|
||||
postcodeFormData.provinceFk = id;
|
||||
await fetchTowns();
|
||||
}
|
||||
async function onProvinceCreated(data) {
|
||||
await provincesFetchDataRef.value.fetch({
|
||||
where: { countryFk: postcodeFormData.countryFk },
|
||||
});
|
||||
postcodeFormData.provinceFk = data.id;
|
||||
}
|
||||
function provinceByCountry(countryFk = postcodeFormData.countryFk) {
|
||||
return provincesOptions.value
|
||||
.filter((province) => province.countryFk === countryFk)
|
||||
.map(({ id }) => id);
|
||||
}
|
||||
|
||||
// Town
|
||||
async function handleTowns(data) {
|
||||
townsOptions.value = data;
|
||||
}
|
||||
function setTown(newTown, data) {
|
||||
town.value = newTown;
|
||||
data.provinceFk = newTown?.provinceFk ?? newTown;
|
||||
data.countryFk = newTown?.province?.countryFk ?? newTown;
|
||||
}
|
||||
async function onCityCreated(newTown, formData) {
|
||||
await provincesFetchDataRef.value.fetch();
|
||||
newTown.province = provincesOptions.value.find(
|
||||
|
@ -56,44 +99,29 @@ async function onCityCreated(newTown, formData) {
|
|||
formData.townFk = newTown;
|
||||
setTown(newTown, formData);
|
||||
}
|
||||
|
||||
function setTown(newTown, data) {
|
||||
town.value = newTown;
|
||||
data.provinceFk = newTown?.provinceFk ?? newTown;
|
||||
data.countryFk = newTown?.province?.countryFk ?? newTown;
|
||||
}
|
||||
|
||||
async function setCountry(countryFk, data) {
|
||||
data.townFk = null;
|
||||
data.provinceFk = null;
|
||||
data.countryFk = countryFk;
|
||||
}
|
||||
|
||||
async function handleProvinces(data) {
|
||||
provincesOptions.value = data;
|
||||
}
|
||||
|
||||
async function setProvince(id, data) {
|
||||
const newProvince = provincesOptions.value.find((province) => province.id == id);
|
||||
if (!newProvince) return;
|
||||
|
||||
data.countryFk = newProvince.countryFk;
|
||||
}
|
||||
|
||||
async function onProvinceCreated(data) {
|
||||
await provincesFetchDataRef.value.fetch({
|
||||
where: { countryFk: postcodeFormData.countryFk },
|
||||
});
|
||||
postcodeFormData.provinceFk = data.id;
|
||||
}
|
||||
|
||||
const whereTowns = computed(() => {
|
||||
return {
|
||||
async function fetchTowns(countryFk = postcodeFormData.countryFk) {
|
||||
if (!countryFk) return;
|
||||
const provinces = postcodeFormData.provinceFk
|
||||
? [postcodeFormData.provinceFk]
|
||||
: provinceByCountry();
|
||||
townFilter.value.where = {
|
||||
provinceFk: {
|
||||
inq: provincesOptions.value.map(({ id }) => id),
|
||||
inq: provinces,
|
||||
},
|
||||
};
|
||||
});
|
||||
await townsFetchDataRef.value?.fetch();
|
||||
}
|
||||
|
||||
async function filterTowns(name) {
|
||||
if (name !== '') {
|
||||
townFilter.value.where = {
|
||||
name: {
|
||||
like: `%${name}%`,
|
||||
},
|
||||
};
|
||||
await townsFetchDataRef.value?.fetch();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -105,6 +133,15 @@ const whereTowns = computed(() => {
|
|||
auto-load
|
||||
url="Provinces/location"
|
||||
/>
|
||||
<FetchData
|
||||
ref="townsFetchDataRef"
|
||||
:sort-by="['name ASC']"
|
||||
:limit="30"
|
||||
:filter="townFilter"
|
||||
@on-fetch="handleTowns"
|
||||
auto-load
|
||||
url="Towns/location"
|
||||
/>
|
||||
|
||||
<FormModelPopup
|
||||
url-create="postcodes"
|
||||
|
@ -123,25 +160,22 @@ const whereTowns = computed(() => {
|
|||
:rules="validate('postcode.code')"
|
||||
clearable
|
||||
required
|
||||
data-cy="locationPostcode"
|
||||
/>
|
||||
<VnSelectDialog
|
||||
ref="townsRef"
|
||||
:sort-by="['name ASC']"
|
||||
:limit="30"
|
||||
auto-load
|
||||
url="Towns/location"
|
||||
:where="whereTowns"
|
||||
:label="t('City')"
|
||||
@update:model-value="(value) => setTown(value, data)"
|
||||
@filter="filterTowns"
|
||||
:tooltip="t('Create city')"
|
||||
v-model="data.townFk"
|
||||
:options="townsOptions"
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
:rules="validate('postcode.city')"
|
||||
:acls="[{ model: 'Town', props: '*', accessType: 'WRITE' }]"
|
||||
:emit-value="false"
|
||||
:clearable="true"
|
||||
required
|
||||
data-cy="locationTown"
|
||||
>
|
||||
<template #option="{ itemProps, opt }">
|
||||
<QItem v-bind="itemProps">
|
||||
|
@ -172,7 +206,6 @@ const whereTowns = computed(() => {
|
|||
:province-selected="data.provinceFk"
|
||||
@update:model-value="(value) => setProvince(value, data)"
|
||||
v-model="data.provinceFk"
|
||||
@on-province-fetched="handleProvinces"
|
||||
@on-province-created="onProvinceCreated"
|
||||
required
|
||||
/>
|
||||
|
@ -191,6 +224,7 @@ const whereTowns = computed(() => {
|
|||
v-model="data.countryFk"
|
||||
:rules="validate('postcode.countryFk')"
|
||||
@update:model-value="(value) => setCountry(value, data)"
|
||||
data-cy="locationCountry"
|
||||
/>
|
||||
</VnRow>
|
||||
</template>
|
||||
|
|
|
@ -53,8 +53,10 @@ const where = computed(() => {
|
|||
v-model="data.name"
|
||||
:rules="validate('province.name')"
|
||||
required
|
||||
data-cy="provinceName"
|
||||
/>
|
||||
<VnSelect
|
||||
data-cy="autonomyProvince"
|
||||
required
|
||||
ref="autonomiesRef"
|
||||
auto-load
|
||||
|
|
|
@ -64,11 +64,11 @@ watch(
|
|||
auto-load
|
||||
/>
|
||||
<VnSelectDialog
|
||||
data-cy="locationProvince"
|
||||
:label="t('Province')"
|
||||
:options="provincesOptions"
|
||||
:tooltip="t('Create province')"
|
||||
hide-selected
|
||||
:clearable="true"
|
||||
v-model="provinceFk"
|
||||
:rules="validate && validate('postcode.provinceFk')"
|
||||
:acls="[{ model: 'Province', props: '*', accessType: 'WRITE' }]"
|
||||
|
|
|
@ -75,7 +75,6 @@ const handleModelValue = (data) => {
|
|||
:input-debounce="300"
|
||||
:class="{ required: isRequired }"
|
||||
v-bind="$attrs"
|
||||
clearable
|
||||
:emit-value="false"
|
||||
:tooltip="t('Create new location')"
|
||||
:rules="mixinRules"
|
||||
|
|
|
@ -8,7 +8,14 @@ import dataByOrder from 'src/utils/dataByOrder';
|
|||
const emit = defineEmits(['update:modelValue', 'update:options', 'remove']);
|
||||
const $attrs = useAttrs();
|
||||
const { t } = useI18n();
|
||||
const { isRequired, requiredFieldRule } = useRequired($attrs);
|
||||
|
||||
const isRequired = computed(() => {
|
||||
return useRequired($attrs).isRequired;
|
||||
});
|
||||
const requiredFieldRule = computed(() => {
|
||||
return useRequired($attrs).requiredFieldRule;
|
||||
});
|
||||
|
||||
const $props = defineProps({
|
||||
modelValue: {
|
||||
type: [String, Number, Object],
|
||||
|
|
|
@ -43,6 +43,7 @@ const isAllowedToCreate = computed(() => {
|
|||
>
|
||||
<template v-if="isAllowedToCreate" #append>
|
||||
<QIcon
|
||||
:data-cy="$attrs.dataCy ?? $attrs.label + '_icon'"
|
||||
@click.stop.prevent="$refs.dialog.show()"
|
||||
:name="actionIcon"
|
||||
:size="actionIcon === 'add' ? 'xs' : 'sm'"
|
||||
|
|
|
@ -6,7 +6,7 @@ import { useColor } from 'src/composables/useColor';
|
|||
import { getCssVar } from 'quasar';
|
||||
|
||||
const $props = defineProps({
|
||||
workerId: { type: Number, required: true },
|
||||
workerId: { type: [Number, undefined], default: null },
|
||||
description: { type: String, default: null },
|
||||
title: { type: String, default: null },
|
||||
color: { type: String, default: null },
|
||||
|
@ -38,7 +38,13 @@ watch(src, () => (showLetter.value = false));
|
|||
<template v-if="showLetter">
|
||||
{{ title.charAt(0) }}
|
||||
</template>
|
||||
<QImg v-else :src="src" spinner-color="white" @error="showLetter = true" />
|
||||
<QImg
|
||||
v-else-if="workerId"
|
||||
:src="src"
|
||||
spinner-color="white"
|
||||
@error="showLetter = true"
|
||||
/>
|
||||
<QIcon v-else name="mood" size="xs" />
|
||||
</QAvatar>
|
||||
<div class="description">
|
||||
<slot name="description" v-if="description">
|
||||
|
|
|
@ -1,23 +1,28 @@
|
|||
<script setup>
|
||||
import { reactive, useAttrs, onBeforeMount, capitalize } from 'vue';
|
||||
import { ref, reactive, useAttrs, onBeforeMount, capitalize } from 'vue';
|
||||
import axios from 'axios';
|
||||
import { parsePhone } from 'src/filters';
|
||||
import useOpenURL from 'src/composables/useOpenURL';
|
||||
|
||||
const props = defineProps({
|
||||
phoneNumber: { type: [String, Number], default: null },
|
||||
channel: { type: Number, default: null },
|
||||
country: { type: String, default: null },
|
||||
});
|
||||
|
||||
const phone = ref(props.phoneNumber);
|
||||
const config = reactive({
|
||||
sip: { icon: 'phone', href: `sip:${props.phoneNumber}` },
|
||||
'say-simple': {
|
||||
icon: 'vn:saysimple',
|
||||
href: null,
|
||||
url: null,
|
||||
channel: props.channel,
|
||||
},
|
||||
});
|
||||
const type = Object.keys(config).find((key) => key in useAttrs()) || 'sip';
|
||||
|
||||
onBeforeMount(async () => {
|
||||
if (!phone.value) return;
|
||||
let { channel } = config[type];
|
||||
|
||||
if (type === 'say-simple') {
|
||||
|
@ -25,23 +30,28 @@ onBeforeMount(async () => {
|
|||
.data;
|
||||
if (!channel) channel = defaultChannel;
|
||||
|
||||
config[type].href = `${url}?customerIdentity=%2B${parsePhone(
|
||||
props.phoneNumber
|
||||
)}&channelId=${channel}`;
|
||||
phone.value = await parsePhone(props.phoneNumber, props.country.toLowerCase());
|
||||
config[
|
||||
type
|
||||
].url = `${url}?customerIdentity=%2B${phone.value}&channelId=${channel}`;
|
||||
}
|
||||
});
|
||||
|
||||
function handleClick() {
|
||||
if (config[type].url) useOpenURL(config[type].url);
|
||||
else if (config[type].href) window.location.href = config[type].href;
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<QBtn
|
||||
v-if="phoneNumber"
|
||||
v-if="phone"
|
||||
flat
|
||||
round
|
||||
:icon="config[type].icon"
|
||||
size="sm"
|
||||
color="primary"
|
||||
padding="none"
|
||||
:href="config[type].href"
|
||||
@click.stop
|
||||
@click.stop="handleClick"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ capitalize(type).replace('-', '') }}
|
||||
|
|
|
@ -2,8 +2,14 @@ import { useValidator } from 'src/composables/useValidator';
|
|||
|
||||
export function useRequired($attrs) {
|
||||
const { validations } = useValidator();
|
||||
|
||||
const isRequired = Object.keys($attrs).includes('required');
|
||||
const hasRequired = Object.keys($attrs).includes('required');
|
||||
let isRequired = false;
|
||||
if (hasRequired) {
|
||||
const required = $attrs['required'];
|
||||
if (typeof required === 'boolean') {
|
||||
isRequired = required;
|
||||
}
|
||||
}
|
||||
const requiredFieldRule = (val) => validations().required(isRequired, val);
|
||||
|
||||
return {
|
||||
|
|
|
@ -1,12 +1,18 @@
|
|||
export default function (phone, prefix = 34) {
|
||||
if (phone.startsWith('+')) {
|
||||
return `${phone.slice(1)}`;
|
||||
}
|
||||
if (phone.startsWith('00')) {
|
||||
return `${phone.slice(2)}`;
|
||||
}
|
||||
if (phone.startsWith(prefix) && phone.length === prefix.length + 9) {
|
||||
return `${prefix}${phone.slice(prefix.length)}`;
|
||||
import axios from 'axios';
|
||||
|
||||
export default async function parsePhone(phone, country) {
|
||||
if (!phone) return;
|
||||
if (phone.startsWith('+')) return `${phone.slice(1)}`;
|
||||
if (phone.startsWith('00')) return `${phone.slice(2)}`;
|
||||
|
||||
let prefix;
|
||||
try {
|
||||
prefix = (await axios.get(`Prefixes/${country.toLowerCase()}`)).data?.prefix;
|
||||
} catch (e) {
|
||||
prefix = (await axios.get('PbxConfigs/findOne')).data?.defaultPrefix;
|
||||
}
|
||||
prefix = prefix.replace(/^0+/, '');
|
||||
|
||||
if (phone.startsWith(prefix)) return phone;
|
||||
return `${prefix}${phone}`;
|
||||
}
|
||||
|
|
|
@ -169,7 +169,6 @@ function onBeforeSave(formData, originalData) {
|
|||
url="Clients"
|
||||
:input-debounce="0"
|
||||
:label="t('customer.basicData.previousClient')"
|
||||
:options="clients"
|
||||
:rules="validate('client.transferorFk')"
|
||||
emit-value
|
||||
map-options
|
||||
|
|
|
@ -67,6 +67,7 @@ function handleLocation(data, location) {
|
|||
option-label="vat"
|
||||
option-value="id"
|
||||
v-model="data.sageTaxTypeFk"
|
||||
data-cy="sageTaxTypeFk"
|
||||
:required="data.isTaxDataChecked"
|
||||
/>
|
||||
<VnSelect
|
||||
|
@ -75,6 +76,7 @@ function handleLocation(data, location) {
|
|||
hide-selected
|
||||
option-label="transaction"
|
||||
option-value="id"
|
||||
data-cy="sageTransactionTypeFk"
|
||||
v-model="data.sageTransactionTypeFk"
|
||||
:required="data.isTaxDataChecked"
|
||||
>
|
||||
|
|
|
@ -94,6 +94,7 @@ const sumRisk = ({ clientRisks }) => {
|
|||
:phone-number="entity.mobile"
|
||||
:channel="entity.country?.saySimpleCountry?.channel"
|
||||
class="q-ml-xs"
|
||||
:country="entity.country?.code"
|
||||
/>
|
||||
</template>
|
||||
</VnLv>
|
||||
|
|
|
@ -42,13 +42,13 @@ async function hasCustomerRole() {
|
|||
>
|
||||
<template #form="{ data, validate }">
|
||||
<QCheckbox :label="t('Enable web access')" v-model="data.account.active" />
|
||||
<VnInput :label="t('User')" clearable v-model="data.name" />
|
||||
<VnInput :label="t('User')" clearable v-model="data.account.name" />
|
||||
<VnInput
|
||||
:label="t('Recovery email')"
|
||||
:rules="validate('client.email')"
|
||||
clearable
|
||||
type="email"
|
||||
v-model="data.email"
|
||||
v-model="data.account.email"
|
||||
class="q-mt-sm"
|
||||
:info="t('This email is used for user to regain access their account')"
|
||||
/>
|
||||
|
|
|
@ -12,6 +12,7 @@ import RightMenu from 'src/components/common/RightMenu.vue';
|
|||
import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue';
|
||||
import { toDate } from 'src/filters';
|
||||
import CustomerFilter from './CustomerFilter.vue';
|
||||
import VnAvatar from 'src/components/ui/VnAvatar.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
|
|
|
@ -18,8 +18,6 @@ const router = useRouter();
|
|||
|
||||
const formInitialData = reactive({ isDefaultAddress: false });
|
||||
|
||||
const urlCreate = ref('');
|
||||
|
||||
const agencyModes = ref([]);
|
||||
const incoterms = ref([]);
|
||||
const customsAgents = ref([]);
|
||||
|
@ -40,13 +38,18 @@ function handleLocation(data, location) {
|
|||
data.countryFk = countryFk;
|
||||
}
|
||||
|
||||
function onAgentCreated(requestResponse, data) {
|
||||
customsAgents.value.push(requestResponse);
|
||||
data.customsAgentFk = requestResponse.id;
|
||||
function onAgentCreated({ id, fiscalName }, data) {
|
||||
customsAgents.value.push({ id, fiscalName });
|
||||
data.customsAgentFk = id;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
@on-fetch="(data) => (customsAgents = data)"
|
||||
auto-load
|
||||
url="CustomsAgents"
|
||||
/>
|
||||
<FetchData
|
||||
@on-fetch="(data) => (agencyModes = data)"
|
||||
auto-load
|
||||
|
@ -57,7 +60,7 @@ function onAgentCreated(requestResponse, data) {
|
|||
<FormModel
|
||||
:form-initial-data="formInitialData"
|
||||
:observe-form-changes="false"
|
||||
:url-create="urlCreate"
|
||||
:url-create="`Clients/${route.params.id}/createAddress`"
|
||||
@on-data-saved="toCustomerAddress()"
|
||||
model="client"
|
||||
>
|
||||
|
@ -141,8 +144,7 @@ function onAgentCreated(requestResponse, data) {
|
|||
<template #form>
|
||||
<CustomerNewCustomsAgent
|
||||
@on-data-saved="
|
||||
(_, requestResponse) =>
|
||||
onAgentCreated(requestResponse, data)
|
||||
(requestResponse) => onAgentCreated(requestResponse, data)
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -11,7 +11,7 @@ invoiceOutList:
|
|||
ref: Referencia
|
||||
issued: Fecha emisión
|
||||
created: F. creación
|
||||
dueDate: F. máxima
|
||||
dueDate: Fecha vencimiento
|
||||
invoiceOutSerial: Serial
|
||||
ticket: Ticket
|
||||
taxArea: Area
|
||||
|
|
|
@ -138,6 +138,7 @@ const insertTag = (rows) => {
|
|||
:required="false"
|
||||
:rules="validate('itemTag.tagFk')"
|
||||
:use-like="false"
|
||||
sort-by="value"
|
||||
/>
|
||||
<VnInput
|
||||
v-else-if="
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
<script setup>
|
||||
import { useRouter } from 'vue-router';
|
||||
import { reactive, onMounted, ref } from 'vue';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import axios from 'axios';
|
||||
import { useState } from 'composables/useState';
|
||||
import FormModelPopup from 'components/FormModelPopup.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import VnSelect from 'components/common/VnSelect.vue';
|
||||
|
@ -11,29 +10,12 @@ import VnInputDate from 'components/common/VnInputDate.vue';
|
|||
import { useDialogPluginComponent } from 'quasar';
|
||||
|
||||
const { t } = useI18n();
|
||||
const state = useState();
|
||||
const ORDER_MODEL = 'order';
|
||||
|
||||
const router = useRouter();
|
||||
const agencyList = ref([]);
|
||||
const addressList = ref([]);
|
||||
defineEmits(['confirm', ...useDialogPluginComponent.emits]);
|
||||
|
||||
const fetchAddressList = async (addressId) => {
|
||||
const { data } = await axios.get('addresses', {
|
||||
params: {
|
||||
filter: JSON.stringify({
|
||||
fields: ['id', 'nickname', 'street', 'city'],
|
||||
where: { id: addressId },
|
||||
}),
|
||||
},
|
||||
});
|
||||
addressList.value = data;
|
||||
if (addressList.value?.length === 1) {
|
||||
state.get(ORDER_MODEL).addressId = addressList.value[0].id;
|
||||
}
|
||||
};
|
||||
|
||||
const fetchAgencyList = async (landed, addressFk) => {
|
||||
if (!landed || !addressFk) {
|
||||
return;
|
||||
|
@ -59,17 +41,9 @@ const initialFormState = reactive({
|
|||
clientFk: $props.clientFk,
|
||||
});
|
||||
|
||||
const onClientChange = async (clientId = $props.clientFk) => {
|
||||
const { data } = await axios.get(`Clients/${clientId}`);
|
||||
await fetchAddressList(data.defaultAddressFk);
|
||||
};
|
||||
|
||||
async function onDataSaved(_, id) {
|
||||
await router.push({ path: `/order/${id}/catalog` });
|
||||
}
|
||||
onMounted(async () => {
|
||||
await onClientChange();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -90,10 +64,9 @@ onMounted(async () => {
|
|||
option-value="id"
|
||||
option-label="name"
|
||||
:filter="{
|
||||
fields: ['id', 'name', 'defaultAddressFk'],
|
||||
fields: ['id', 'name'],
|
||||
}"
|
||||
hide-selected
|
||||
@update:model-value="onClientChange"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
|
@ -110,7 +83,7 @@ onMounted(async () => {
|
|||
:label="t('order.form.addressFk')"
|
||||
v-model="data.addressId"
|
||||
url="addresses"
|
||||
:fields="['id', 'nickname', 'defaultAddressFk', 'street', 'city']"
|
||||
:fields="['id', 'nickname', 'street', 'city']"
|
||||
sort-by="id"
|
||||
option-value="id"
|
||||
option-label="street"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script setup>
|
||||
import axios from 'axios';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { computed, ref, onMounted } from 'vue';
|
||||
import { dashIfEmpty, toCurrency, toDate } from 'src/filters';
|
||||
import OrderSummary from 'pages/Order/Card/OrderSummary.vue';
|
||||
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
||||
|
@ -15,14 +15,13 @@ import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vu
|
|||
import WorkerDescriptorProxy from '../Worker/Card/WorkerDescriptorProxy.vue';
|
||||
import { toDateTimeFormat } from 'src/filters/date';
|
||||
import { useRoute } from 'vue-router';
|
||||
import dataByOrder from 'src/utils/dataByOrder';
|
||||
|
||||
const { t } = useI18n();
|
||||
const { viewSummary } = useSummaryDialog();
|
||||
const tableRef = ref();
|
||||
const agencyList = ref([]);
|
||||
const addressesList = ref([]);
|
||||
const route = useRoute();
|
||||
const addressOptions = ref([]);
|
||||
const columns = computed(() => [
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -148,16 +147,12 @@ onMounted(() => {
|
|||
const id = JSON.parse(clientId);
|
||||
fetchClientAddress(id.clientFk);
|
||||
});
|
||||
|
||||
async function fetchClientAddress(id, formData = {}) {
|
||||
const { data } = await axios.get(`Clients/${id}`, {
|
||||
params: {
|
||||
filter: {
|
||||
order: ['isDefaultAddress DESC', 'isActive DESC', 'nickname ASC'],
|
||||
include: { relation: 'addresses' },
|
||||
},
|
||||
},
|
||||
});
|
||||
addressesList.value = data.addresses;
|
||||
const { data } = await axios.get(
|
||||
`Clients/${id}/addresses?filter[order]=isActive DESC`
|
||||
);
|
||||
addressOptions.value = data;
|
||||
formData.addressId = data.defaultAddressFk;
|
||||
fetchAgencies(formData);
|
||||
}
|
||||
|
@ -168,7 +163,7 @@ async function fetchAgencies({ landed, addressId }) {
|
|||
const { data } = await axios.get('Agencies/landsThatDay', {
|
||||
params: { addressFk: addressId, landed },
|
||||
});
|
||||
agencyList.value = dataByOrder(data, 'agencyMode ASC');
|
||||
agencyList.value = data;
|
||||
}
|
||||
|
||||
const getDateColor = (date) => {
|
||||
|
@ -252,34 +247,29 @@ const getDateColor = (date) => {
|
|||
</VnSelect>
|
||||
<VnSelect
|
||||
v-model="data.addressId"
|
||||
:options="addressesList"
|
||||
:options="addressOptions"
|
||||
:label="t('module.address')"
|
||||
option-value="id"
|
||||
option-label="nickname"
|
||||
@update:model-value="() => fetchAgencies(data)"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem
|
||||
v-bind="scope.itemProps"
|
||||
:class="{ disabled: !scope.opt.isActive }"
|
||||
>
|
||||
<QItemSection style="min-width: min-content" avatar>
|
||||
<QIcon
|
||||
v-if="
|
||||
scope.opt.isActive && data.addressId === scope.opt.id
|
||||
"
|
||||
size="sm"
|
||||
color="grey"
|
||||
name="star"
|
||||
class="fill-icon"
|
||||
/>
|
||||
</QItemSection>
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>
|
||||
{{ scope.opt.nickname }}
|
||||
</QItemLabel>
|
||||
<QItemLabel caption>
|
||||
{{ `${scope.opt.street}, ${scope.opt.city}` }}
|
||||
<QItemLabel
|
||||
:class="{
|
||||
'color-vn-label': !scope.opt?.isActive,
|
||||
}"
|
||||
>
|
||||
{{
|
||||
`${
|
||||
!scope.opt?.isActive
|
||||
? t('basicData.inactive')
|
||||
: ''
|
||||
} `
|
||||
}}
|
||||
{{ scope.opt?.nickname }}: {{ scope.opt?.street }},
|
||||
{{ scope.opt?.city }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
|
|
|
@ -7,13 +7,13 @@ import filter from './TravelFilter.js';
|
|||
<VnCard
|
||||
data-key="Travel"
|
||||
base-url="Travels"
|
||||
search-data-key="TravelList"
|
||||
:filter="filter"
|
||||
:descriptor="TravelDescriptor"
|
||||
:filter="filter"
|
||||
search-data-key="TravelList"
|
||||
:searchbar-props="{
|
||||
url: 'Travels',
|
||||
url: 'Travels/filter',
|
||||
searchUrl: 'table',
|
||||
label: 'Search travel',
|
||||
info: 'You can search by travel id or name',
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -208,6 +208,7 @@ const columns = computed(() => [
|
|||
ref="tableRef"
|
||||
data-key="TravelList"
|
||||
url="Travels/filter"
|
||||
redirect="travel"
|
||||
:create="{
|
||||
urlCreate: 'Travels',
|
||||
title: t('Create Travels'),
|
||||
|
@ -221,9 +222,7 @@ const columns = computed(() => [
|
|||
order="landed DESC"
|
||||
:columns="columns"
|
||||
auto-load
|
||||
redirect="travel"
|
||||
:is-editable="false"
|
||||
:use-model="true"
|
||||
>
|
||||
<template #column-status="{ row }">
|
||||
<div class="row">
|
||||
|
|
|
@ -75,9 +75,9 @@ export default {
|
|||
},
|
||||
{
|
||||
name: 'TravelHistory',
|
||||
path: 'history',
|
||||
path: 'log',
|
||||
meta: {
|
||||
title: 'history',
|
||||
title: 'log',
|
||||
icon: 'history',
|
||||
},
|
||||
component: () => import('src/pages/Travel/Card/TravelLog.vue'),
|
||||
|
|
|
@ -106,7 +106,7 @@ export default {
|
|||
},
|
||||
{
|
||||
name: 'ZoneHistory',
|
||||
path: 'history',
|
||||
path: 'log',
|
||||
meta: {
|
||||
title: 'log',
|
||||
icon: 'history',
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
function orderData(data, order) {
|
||||
if (typeof order === 'function') return data.sort(data);
|
||||
if (typeof order === 'string') order = [order];
|
||||
if (!Array.isArray(data)) return [];
|
||||
if (Array.isArray(order)) {
|
||||
let orderComp = [];
|
||||
|
||||
|
|
|
@ -3,11 +3,16 @@ describe('Client fiscal data', () => {
|
|||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
||||
cy.visit('#/customer/1110/fiscal-data', {
|
||||
cy.visit('#/customer/1107/fiscal-data', {
|
||||
timeout: 5000,
|
||||
});
|
||||
});
|
||||
it('Should load layout', () => {
|
||||
it('Should change required value when change customer', () => {
|
||||
cy.get('.q-card').should('be.visible');
|
||||
cy.dataCy('sageTaxTypeFk').filter('input').should('not.have.attr', 'required');
|
||||
cy.get('#searchbar input').clear();
|
||||
cy.get('#searchbar input').type('1{enter}');
|
||||
cy.get('.q-item > .q-item__label').should('have.text', ' #1');
|
||||
cy.dataCy('sageTaxTypeFk').filter('input').should('have.attr', 'required');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -43,11 +43,9 @@ describe('VnLocation', () => {
|
|||
province
|
||||
);
|
||||
cy.get(
|
||||
`${createForm.prefix} > :nth-child(4) > .q-select > ${createForm.sufix} > :nth-child(3) > .q-icon`
|
||||
`${createForm.prefix} > :nth-child(4) > .q-select > ${createForm.sufix} > :nth-child(3) `
|
||||
).click();
|
||||
cy.get(
|
||||
`#q-portal--dialog--5 > .q-dialog > ${createForm.prefix} > .vn-row > .q-select > ${createForm.sufix} > :nth-child(1) input`
|
||||
).should('have.value', province);
|
||||
cy.dataCy('locationProvince').should('have.value', province);
|
||||
});
|
||||
});
|
||||
describe('Worker Create', () => {
|
||||
|
@ -123,32 +121,16 @@ describe('VnLocation', () => {
|
|||
const province = randomString({ length: 4 });
|
||||
cy.get(createLocationButton).click();
|
||||
cy.get(dialogInputs).eq(0).type(postCode);
|
||||
cy.get(
|
||||
`${createForm.prefix} > :nth-child(4) > .q-select > ${createForm.sufix} > :nth-child(2) > .q-icon`
|
||||
).click();
|
||||
cy.selectOption('#q-portal--dialog--3 .q-select', 'one');
|
||||
cy.get('#q-portal--dialog--3 .q-input').type(province);
|
||||
cy.get('#q-portal--dialog--3 .q-btn--standard').click();
|
||||
cy.get('#q-portal--dialog--1 .q-btn--standard').click();
|
||||
cy.dataCy('City_icon').click();
|
||||
cy.selectOption('[data-cy="locationProvince"]:last', 'Province one');
|
||||
cy.dataCy('cityName').type(province);
|
||||
cy.dataCy('FormModelPopup_save').eq(1).click();
|
||||
cy.dataCy('FormModelPopup_save').eq(0).click();
|
||||
|
||||
cy.waitForElement('.q-form');
|
||||
checkVnLocation(postCode, province);
|
||||
});
|
||||
|
||||
it('Create province without country', () => {
|
||||
const provinceName = 'Saskatchew'.concat(Math.random(1 * 100));
|
||||
cy.get(createLocationButton).click();
|
||||
cy.get(
|
||||
`${createForm.prefix} > :nth-child(5) > .q-select > ${createForm.sufix} > :nth-child(2) `
|
||||
)
|
||||
.eq(0)
|
||||
.click();
|
||||
cy.selectOption('#q-portal--dialog--3 .q-select', 'one');
|
||||
cy.countSelectOptions('#q-portal--dialog--3 .q-select', 4);
|
||||
cy.get('#q-portal--dialog--3 .q-input').type(provinceName);
|
||||
|
||||
cy.get('#q-portal--dialog--3 .q-btn--standard').click();
|
||||
});
|
||||
|
||||
it('Create city with country', () => {
|
||||
const cityName = 'Saskatchew'.concat(Math.random(1 * 100));
|
||||
cy.get(createLocationButton).click();
|
||||
|
@ -156,14 +138,23 @@ describe('VnLocation', () => {
|
|||
`${createForm.prefix} > :nth-child(5) > :nth-child(3) `,
|
||||
'Italia'
|
||||
);
|
||||
cy.get(
|
||||
`${createForm.prefix} > :nth-child(4) > .q-select > ${createForm.sufix} > :nth-child(2) > .q-icon`
|
||||
).click();
|
||||
cy.selectOption('#q-portal--dialog--4 .q-select', 'Province four');
|
||||
cy.countSelectOptions('#q-portal--dialog--4 .q-select', 1);
|
||||
cy.dataCy('City_icon').click();
|
||||
cy.selectOption('[data-cy="locationProvince"]:last', 'Province four');
|
||||
cy.countSelectOptions('[data-cy="locationProvince"]:last', 1);
|
||||
|
||||
cy.get('#q-portal--dialog--4 .q-input').type(cityName);
|
||||
cy.get('#q-portal--dialog--4 .q-btn--standard').click();
|
||||
cy.dataCy('cityName').type(cityName);
|
||||
cy.dataCy('FormModelPopup_save').eq(1).click();
|
||||
});
|
||||
|
||||
it('Create province without country', () => {
|
||||
const provinceName = 'Saskatchew'.concat(Math.random(1 * 100));
|
||||
cy.get(createLocationButton).click();
|
||||
cy.dataCy('Province_icon').click();
|
||||
cy.selectOption('[data-cy="autonomyProvince"] ', 'Autonomy one');
|
||||
cy.countSelectOptions('[data-cy="autonomyProvince"]', 4);
|
||||
cy.dataCy('provinceName').type(provinceName);
|
||||
|
||||
cy.dataCy('FormModelPopup_save').eq(1).click();
|
||||
});
|
||||
|
||||
it('Create province with country', () => {
|
||||
|
@ -173,17 +164,13 @@ describe('VnLocation', () => {
|
|||
`${createForm.prefix} > :nth-child(5) > :nth-child(3) `,
|
||||
'España'
|
||||
);
|
||||
cy.get(
|
||||
`${createForm.prefix} > :nth-child(5) > .q-select > ${createForm.sufix} > :nth-child(2) `
|
||||
)
|
||||
.eq(0)
|
||||
.click();
|
||||
cy.dataCy('Province_icon').click();
|
||||
|
||||
cy.selectOption('#q-portal--dialog--4 .q-select', 'one');
|
||||
cy.countSelectOptions('#q-portal--dialog--4 .q-select', 2);
|
||||
cy.selectOption('[data-cy="autonomyProvince"] ', 'Autonomy one');
|
||||
cy.countSelectOptions('[data-cy="autonomyProvince"]', 2);
|
||||
|
||||
cy.get('#q-portal--dialog--4 .q-input').type(provinceName);
|
||||
cy.get('#q-portal--dialog--4 .q-btn--standard').click();
|
||||
cy.dataCy('provinceName').type(provinceName);
|
||||
cy.dataCy('FormModelPopup_save').eq(1).click();
|
||||
});
|
||||
|
||||
function checkVnLocation(postCode, province) {
|
||||
|
|
|
@ -1,29 +1,50 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { describe, it, expect, beforeAll, vi } from 'vitest';
|
||||
import { axios } from 'app/test/vitest/helper';
|
||||
import parsePhone from 'src/filters/parsePhone';
|
||||
|
||||
describe('parsePhone filter', () => {
|
||||
it("adds prefix +34 if it doesn't have one", () => {
|
||||
const resultado = parsePhone('123456789', '34');
|
||||
expect(resultado).toBe('34123456789');
|
||||
beforeAll(async () => {
|
||||
vi.spyOn(axios, 'get').mockReturnValue({ data: { prefix: '34' } });
|
||||
});
|
||||
|
||||
it('maintains prefix +34 if it is already correct', () => {
|
||||
const resultado = parsePhone('+34123456789', '34');
|
||||
expect(resultado).toBe('34123456789');
|
||||
it('no phone', async () => {
|
||||
const phone = await parsePhone(null, '34');
|
||||
expect(phone).toBe(undefined);
|
||||
});
|
||||
|
||||
it('converts prefix 0034 to +34', () => {
|
||||
const resultado = parsePhone('0034123456789', '34');
|
||||
expect(resultado).toBe('34123456789');
|
||||
it("adds prefix +34 if it doesn't have one", async () => {
|
||||
const phone = await parsePhone('123456789', '34');
|
||||
expect(phone).toBe('34123456789');
|
||||
});
|
||||
|
||||
it('converts prefix 34 without symbol to +34', () => {
|
||||
const resultado = parsePhone('34123456789', '34');
|
||||
expect(resultado).toBe('34123456789');
|
||||
it('maintains prefix +34 if it is already correct', async () => {
|
||||
const phone = await parsePhone('+34123456789', '34');
|
||||
expect(phone).toBe('34123456789');
|
||||
});
|
||||
|
||||
it('replaces incorrect prefix with the correct one', () => {
|
||||
const resultado = parsePhone('+44123456789', '34');
|
||||
expect(resultado).toBe('44123456789');
|
||||
it('converts prefix 0034 to +34', async () => {
|
||||
const phone = await parsePhone('0034123456789', '34');
|
||||
expect(phone).toBe('34123456789');
|
||||
});
|
||||
|
||||
it('converts prefix 34 without symbol to +34', async () => {
|
||||
const phone = await parsePhone('34123456789', '34');
|
||||
expect(phone).toBe('34123456789');
|
||||
});
|
||||
|
||||
it('replaces incorrect prefix with the correct one', async () => {
|
||||
const phone = await parsePhone('+44123456789', '34');
|
||||
expect(phone).toBe('44123456789');
|
||||
});
|
||||
|
||||
it('adds default prefix on error', async () => {
|
||||
vi.spyOn(axios, 'get').mockImplementation((url) => {
|
||||
if (url.includes('Prefixes'))
|
||||
return Promise.reject(new Error('Network error'));
|
||||
else if (url.includes('PbxConfigs'))
|
||||
return Promise.resolve({ data: { defaultPrefix: '39' } });
|
||||
});
|
||||
const phone = await parsePhone('123456789', '34');
|
||||
expect(phone).toBe('39123456789');
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue