Merge branch 'dev' of https: refs #7936//gitea.verdnatura.es/verdnatura/salix-front into 7936-improveInvoiceIn
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details

This commit is contained in:
Jorge Penadés 2024-11-28 11:06:23 +01:00
commit 1571bd55ea
23 changed files with 414 additions and 279 deletions

View File

@ -47,11 +47,13 @@ const onDataSaved = (...args) => {
:label="t('Name')" :label="t('Name')"
v-model="data.name" v-model="data.name"
:rules="validate('city.name')" :rules="validate('city.name')"
required
/> />
<VnSelectProvince <VnSelectProvince
:province-selected="$props.provinceSelected" :province-selected="$props.provinceSelected"
:country-fk="$props.countryFk" :country-fk="$props.countryFk"
v-model="data.provinceFk" v-model="data.provinceFk"
required
/> />
</VnRow> </VnRow>
</template> </template>

View File

@ -1,5 +1,5 @@
<script setup> <script setup>
import { reactive, ref } from 'vue'; import { computed, reactive, ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import FetchData from 'components/FetchData.vue'; import FetchData from 'components/FetchData.vue';
@ -23,11 +23,10 @@ const postcodeFormData = reactive({
}); });
const townsFetchDataRef = ref(false); const townsFetchDataRef = ref(false);
const countriesFetchDataRef = ref(false); const countriesRef = ref(false);
const townsRef = ref(false);
const provincesFetchDataRef = ref(false); const provincesFetchDataRef = ref(false);
const countriesOptions = ref([]);
const provincesOptions = ref([]); const provincesOptions = ref([]);
const townsOptions = ref([]);
const town = ref({}); const town = ref({});
const townFilter = ref({}); const townFilter = ref({});
const countryFilter = ref({}); const countryFilter = ref({});
@ -42,7 +41,7 @@ function onDataSaved(formData) {
({ id }) => id === formData.provinceFk ({ id }) => id === formData.provinceFk
); );
newPostcode.province = provinceObject?.name; newPostcode.province = provinceObject?.name;
const countryObject = countriesOptions.value.find( const countryObject = countriesRef.value.opts.find(
({ id }) => id === formData.countryFk ({ id }) => id === formData.countryFk
); );
newPostcode.country = countryObject?.name; newPostcode.country = countryObject?.name;
@ -70,49 +69,8 @@ async function setCountry(countryFk, data) {
data.countryFk = countryFk; data.countryFk = countryFk;
} }
async function filterTowns(name) {
if (name !== '') {
townFilter.value.where = {
name: {
like: `%${name}%`,
},
};
await townsFetchDataRef.value?.fetch();
}
}
async function filterCountries(name) {
if (name !== '') {
countryFilter.value.where = {
name: {
like: `%${name}%`,
},
};
await countriesFetchDataRef.value?.fetch();
}
}
async function fetchTowns(countryFk) {
if (!countryFk) return;
townFilter.value.where = {
provinceFk: {
inq: provincesOptions.value.map(({ id }) => id),
},
};
await townsFetchDataRef.value?.fetch();
}
async function handleProvinces(data) { async function handleProvinces(data) {
provincesOptions.value = data; provincesOptions.value = data;
if (postcodeFormData.countryFk) {
await fetchTowns(postcodeFormData.countryFk);
}
}
async function handleTowns(data) {
townsOptions.value = data;
}
async function handleCountries(data) {
countriesOptions.value = data;
} }
async function setProvince(id, data) { async function setProvince(id, data) {
@ -128,6 +86,14 @@ async function onProvinceCreated(data) {
}); });
postcodeFormData.provinceFk = data.id; postcodeFormData.provinceFk = data.id;
} }
const whereTowns = computed(() => {
return {
provinceFk: {
inq: provincesOptions.value.map(({ id }) => id),
},
};
});
</script> </script>
<template> <template>
@ -139,24 +105,6 @@ async function onProvinceCreated(data) {
auto-load auto-load
url="Provinces/location" url="Provinces/location"
/> />
<FetchData
ref="townsFetchDataRef"
:sort-by="['name ASC']"
:limit="30"
:filter="townFilter"
@on-fetch="handleTowns"
auto-load
url="Towns/location"
/>
<FetchData
ref="countriesFetchDataRef"
:limit="30"
:filter="countryFilter"
:sort-by="['name ASC']"
@on-fetch="handleCountries"
auto-load
url="Countries"
/>
<FormModelPopup <FormModelPopup
url-create="postcodes" url-create="postcodes"
@ -174,20 +122,26 @@ async function onProvinceCreated(data) {
v-model="data.code" v-model="data.code"
:rules="validate('postcode.code')" :rules="validate('postcode.code')"
clearable clearable
required
/> />
<VnSelectDialog <VnSelectDialog
ref="townsRef"
:sort-by="['name ASC']"
:limit="30"
auto-load
url="Towns/location"
:where="whereTowns"
:label="t('City')" :label="t('City')"
@update:model-value="(value) => setTown(value, data)" @update:model-value="(value) => setTown(value, data)"
@filter="filterTowns"
:tooltip="t('Create city')" :tooltip="t('Create city')"
v-model="data.townFk" v-model="data.townFk"
:options="townsOptions"
option-label="name" option-label="name"
option-value="id" option-value="id"
:rules="validate('postcode.city')" :rules="validate('postcode.city')"
:acls="[{ model: 'Town', props: '*', accessType: 'WRITE' }]" :acls="[{ model: 'Town', props: '*', accessType: 'WRITE' }]"
:emit-value="false" :emit-value="false"
:clearable="true" :clearable="true"
required
> >
<template #option="{ itemProps, opt }"> <template #option="{ itemProps, opt }">
<QItem v-bind="itemProps"> <QItem v-bind="itemProps">
@ -220,13 +174,18 @@ async function onProvinceCreated(data) {
v-model="data.provinceFk" v-model="data.provinceFk"
@on-province-fetched="handleProvinces" @on-province-fetched="handleProvinces"
@on-province-created="onProvinceCreated" @on-province-created="onProvinceCreated"
required
/> />
<VnSelect <VnSelect
ref="countriesRef"
:limit="30"
:filter="countryFilter"
:sort-by="['name ASC']"
auto-load
url="Countries"
required
:label="t('Country')" :label="t('Country')"
@update:options="handleCountries"
:options="countriesOptions"
hide-selected hide-selected
@filter="filterCountries"
option-label="name" option-label="name"
option-value="id" option-value="id"
v-model="data.countryFk" v-model="data.countryFk"

View File

@ -2,7 +2,6 @@
import { computed, reactive, ref } from 'vue'; import { computed, reactive, ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import FetchData from 'components/FetchData.vue';
import VnRow from 'components/ui/VnRow.vue'; import VnRow from 'components/ui/VnRow.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
@ -21,15 +20,11 @@ const $props = defineProps({
type: Number, type: Number,
default: null, default: null,
}, },
provinces: {
type: Array,
default: () => [],
},
}); });
const autonomiesOptions = ref([]); const autonomiesRef = ref([]);
const onDataSaved = (dataSaved, requestResponse) => { const onDataSaved = (dataSaved, requestResponse) => {
requestResponse.autonomy = autonomiesOptions.value.find( requestResponse.autonomy = autonomiesRef.value.opts.find(
(autonomy) => autonomy.id == requestResponse.autonomyFk (autonomy) => autonomy.id == requestResponse.autonomyFk
); );
emit('onDataSaved', dataSaved, requestResponse); emit('onDataSaved', dataSaved, requestResponse);
@ -43,16 +38,6 @@ const where = computed(() => {
</script> </script>
<template> <template>
<FetchData
@on-fetch="(data) => (autonomiesOptions = data)"
auto-load
:filter="{
where,
}"
url="Autonomies/location"
:sort-by="['name ASC']"
:limit="30"
/>
<FormModelPopup <FormModelPopup
:title="t('New province')" :title="t('New province')"
:subtitle="t('Please, ensure you put the correct data!')" :subtitle="t('Please, ensure you put the correct data!')"
@ -67,10 +52,17 @@ const where = computed(() => {
:label="t('Name')" :label="t('Name')"
v-model="data.name" v-model="data.name"
:rules="validate('province.name')" :rules="validate('province.name')"
required
/> />
<VnSelect <VnSelect
required
ref="autonomiesRef"
auto-load
:where="where"
url="Autonomies/location"
:sort-by="['name ASC']"
:limit="30"
:label="t('Autonomy')" :label="t('Autonomy')"
:options="autonomiesOptions"
hide-selected hide-selected
option-label="name" option-label="name"
option-value="id" option-value="id"

View File

@ -281,6 +281,7 @@ const getLocale = (label) => {
:key="chip.label" :key="chip.label"
:removable="!unremovableParams?.includes(chip.label)" :removable="!unremovableParams?.includes(chip.label)"
@remove="remove(chip.label)" @remove="remove(chip.label)"
data-cy="vnFilterPanelChip"
> >
<slot <slot
name="tags" name="tags"

View File

@ -1,6 +1,7 @@
<script setup> <script setup>
import { reactive, useAttrs, onBeforeMount, capitalize } from 'vue'; import { reactive, useAttrs, onBeforeMount, capitalize } from 'vue';
import axios from 'axios'; import axios from 'axios';
import { parsePhone } from 'src/filters';
const props = defineProps({ const props = defineProps({
phoneNumber: { type: [String, Number], default: null }, phoneNumber: { type: [String, Number], default: null },
channel: { type: Number, default: null }, channel: { type: Number, default: null },
@ -24,9 +25,9 @@ onBeforeMount(async () => {
.data; .data;
if (!channel) channel = defaultChannel; if (!channel) channel = defaultChannel;
config[ config[type].href = `${url}?customerIdentity=%2B${parsePhone(
type props.phoneNumber
].href = `${url}?customerIdentity=%2B${props.phoneNumber}&channelId=${channel}`; )}&channelId=${channel}`;
} }
}); });
</script> </script>

View File

@ -133,7 +133,7 @@ const addFilter = async (filter, params) => {
async function fetch(params) { async function fetch(params) {
useArrayData(props.dataKey, params); useArrayData(props.dataKey, params);
arrayData.reset(['filter.skip', 'skip', 'page']); arrayData.reset(['filter.skip', 'skip', 'page']);
await arrayData.fetch({ append: false }); await arrayData.fetch({ append: false, updateRouter: mounted.value });
return emitStoreData(); return emitStoreData();
} }

View File

@ -12,10 +12,12 @@ import dateRange from './dateRange';
import toHour from './toHour'; import toHour from './toHour';
import dashOrCurrency from './dashOrCurrency'; import dashOrCurrency from './dashOrCurrency';
import getParamWhere from './getParamWhere'; import getParamWhere from './getParamWhere';
import parsePhone from './parsePhone';
import isDialogOpened from './isDialogOpened'; import isDialogOpened from './isDialogOpened';
export { export {
isDialogOpened, isDialogOpened,
parsePhone,
toLowerCase, toLowerCase,
toLowerCamel, toLowerCamel,
toDate, toDate,

12
src/filters/parsePhone.js Normal file
View File

@ -0,0 +1,12 @@
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)}`;
}
return `${prefix}${phone}`;
}

View File

@ -874,7 +874,6 @@ components:
cardDescriptor: cardDescriptor:
mainList: Main list mainList: Main list
summary: Summary summary: Summary
moreOptions: More options
leftMenu: leftMenu:
addToPinned: Add to pinned addToPinned: Add to pinned
removeFromPinned: Remove from pinned removeFromPinned: Remove from pinned

View File

@ -101,8 +101,8 @@ const exprBuilder = (param, value) => {
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem class="q-mb-sm"> <QItem class="q-mb-sm">
<QItemSection <QItemSection>
><VnSelect <VnSelect
url="Provinces" url="Provinces"
:label="t('Province')" :label="t('Province')"
v-model="params.provinceFk" v-model="params.provinceFk"
@ -120,14 +120,12 @@ const exprBuilder = (param, value) => {
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem class="q-mb-md"> <QItem class="q-mb-sm">
<QItemSection> <QItemSection>
<VnInput :label="t('City')" v-model="params.city" is-outlined /> <VnInput :label="t('City')" v-model="params.city" is-outlined />
</QItemSection> </QItemSection>
</QItem> </QItem>
<QSeparator /> <QItem class="q-mb-sm">
<QExpansionItem :label="t('More options')" expand-separator>
<QItem>
<QItemSection> <QItemSection>
<VnInput :label="t('Phone')" v-model="params.phone" is-outlined> <VnInput :label="t('Phone')" v-model="params.phone" is-outlined>
<template #prepend> <template #prepend>
@ -136,7 +134,7 @@ const exprBuilder = (param, value) => {
</VnInput> </VnInput>
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem> <QItem class="q-mb-sm">
<QItemSection> <QItemSection>
<VnInput :label="t('Email')" v-model="params.email" is-outlined> <VnInput :label="t('Email')" v-model="params.email" is-outlined>
<template #prepend> <template #prepend>
@ -145,7 +143,8 @@ const exprBuilder = (param, value) => {
</VnInput> </VnInput>
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem> <QItem class="q-mb-sm">
<QItemSection>
<VnSelect <VnSelect
url="Zones" url="Zones"
:label="t('Zone')" :label="t('Zone')"
@ -160,9 +159,9 @@ const exprBuilder = (param, value) => {
outlined outlined
rounded rounded
auto-load auto-load
/> /></QItemSection>
</QItem> </QItem>
<QItem> <QItem class="q-mb-sm">
<QItemSection> <QItemSection>
<VnInput <VnInput
:label="t('Postcode')" :label="t('Postcode')"
@ -171,7 +170,6 @@ const exprBuilder = (param, value) => {
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>
</QExpansionItem>
</template> </template>
</VnFilterPanel> </VnFilterPanel>
</template> </template>
@ -203,7 +201,6 @@ es:
Salesperson: Comercial Salesperson: Comercial
Province: Provincia Province: Provincia
City: Ciudad City: Ciudad
More options: Más opciones
Phone: Teléfono Phone: Teléfono
Email: Email Email: Email
Zone: Zona Zone: Zona

View File

@ -82,11 +82,11 @@ const entriesTableColumns = computed(() => [
</QCardSection> </QCardSection>
<QCardActions align="right"> <QCardActions align="right">
<QBtn <QBtn
:label="t('printLabels')" :label="t('myEntries.printLabels')"
color="primary" color="primary"
icon="print" icon="print"
:loading="isLoading" :loading="isLoading"
@click="openReport(`Entries/${entityId}/print`)" @click="openReport(`Entries/${entityId}/labelSupplier`)"
unelevated unelevated
autofocus autofocus
/> />
@ -126,7 +126,9 @@ const entriesTableColumns = computed(() => [
" "
unelevated unelevated
> >
<QTooltip>{{ t('viewLabel') }}</QTooltip> <QTooltip>{{
t('myEntries.viewLabel')
}}</QTooltip>
</QBtn> </QBtn>
</QTr> </QTr>
</template> </template>

View File

@ -101,7 +101,7 @@ const columns = computed(() => [
name: 'tableActions', name: 'tableActions',
actions: [ actions: [
{ {
title: t('printLabels'), title: t('myEntries.printLabels'),
icon: 'print', icon: 'print',
isPrimary: true, isPrimary: true,
action: (row) => printBuys(row.id), action: (row) => printBuys(row.id),

View File

@ -83,8 +83,6 @@ const states = ref();
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>
<QSeparator />
<QExpansionItem :label="t('More options')" expand-separator>
<QItem> <QItem>
<QItemSection> <QItemSection>
<VnInputDate <VnInputDate
@ -105,14 +103,9 @@ const states = ref();
</QItem> </QItem>
<QItem> <QItem>
<QItemSection> <QItemSection>
<VnInputDate <VnInputDate v-model="params.dued" :label="t('Dued')" is-outlined />
v-model="params.dued"
:label="t('Dued')"
is-outlined
/>
</QItemSection> </QItemSection>
</QItem> </QItem>
</QExpansionItem>
</template> </template>
</VnFilterPanel> </VnFilterPanel>
</template> </template>
@ -149,5 +142,4 @@ es:
Issued: Fecha emisión Issued: Fecha emisión
Created: Fecha creación Created: Fecha creación
Dued: Fecha vencimiento Dued: Fecha vencimiento
More options: Más opciones
</i18n> </i18n>

View File

@ -60,8 +60,15 @@ const columns = computed(() => [
label: t('globals.reference'), label: t('globals.reference'),
isTitle: true, isTitle: true,
component: 'select', component: 'select',
attrs: { url: MODEL, optionLabel: 'ref', optionValue: 'id' }, attrs: {
url: MODEL,
optionLabel: 'ref',
optionValue: 'ref',
},
columnField: { component: null }, columnField: { component: null },
columnFilter: {
inWhere: true,
},
}, },
{ {
align: 'left', align: 'left',
@ -146,9 +153,7 @@ function downloadPdf() {
const [invoiceOut] = selectedCardsArray; const [invoiceOut] = selectedCardsArray;
openPdf(invoiceOut.id); openPdf(invoiceOut.id);
} else { } else {
const invoiceOutIdsArray = selectedCardsArray.map( const invoiceOutIdsArray = selectedCardsArray.map((invoiceOut) => invoiceOut.id);
(invoiceOut) => invoiceOut.id
);
const invoiceOutIds = invoiceOutIdsArray.join(','); const invoiceOutIds = invoiceOutIdsArray.join(',');
const params = { const params = {
@ -157,7 +162,6 @@ function downloadPdf() {
openReport(`${MODEL}/downloadZip`, params); openReport(`${MODEL}/downloadZip`, params);
} }
} }
watchEffect(selectedRows); watchEffect(selectedRows);

View File

@ -49,7 +49,7 @@ const getSelectedTagValues = async (tag) => {
<template> <template>
<QForm @submit="applyTags()" class="all-pointer-events"> <QForm @submit="applyTags()" class="all-pointer-events">
<QCard class="q-pa-sm column q-pa-lg"> <QCard class="q-pa-sm column q-pa-lg" data-cy="catalogFilterValueDialog">
<VnSelect <VnSelect
:label="t('params.tag')" :label="t('params.tag')"
v-model="selectedTag" v-model="selectedTag"
@ -63,6 +63,7 @@ const getSelectedTagValues = async (tag) => {
:emit-value="false" :emit-value="false"
use-input use-input
@update:model-value="getSelectedTagValues" @update:model-value="getSelectedTagValues"
data-cy="catalogFilterValueDialogTagSelect"
/> />
<div <div
v-for="(value, index) in tagValues" v-for="(value, index) in tagValues"
@ -93,6 +94,7 @@ const getSelectedTagValues = async (tag) => {
:disable="!value" :disable="!value"
is-outlined is-outlined
class="col" class="col"
data-cy="catalogFilterValueDialogValueInput"
/> />
<QBtn <QBtn
icon="delete" icon="delete"

View File

@ -98,7 +98,7 @@ watch(
/> />
</QScrollArea> </QScrollArea>
</QDrawer> </QDrawer>
<QPage class="column items-center q-pa-md"> <QPage class="column items-center q-pa-md" data-cy="orderCatalogPage">
<div class="full-width"> <div class="full-width">
<VnPaginate <VnPaginate
:data-key="dataKey" :data-key="dataKey"
@ -118,6 +118,7 @@ watch(
:item="row" :item="row"
is-catalog is-catalog
class="fill-icon" class="fill-icon"
data-cy="orderCatalogItem"
/> />
</div> </div>
</template> </template>

View File

@ -178,6 +178,7 @@ function addOrder(value, field, params) {
? resetCategory(params, searchFn) ? resetCategory(params, searchFn)
: removeTagGroupParam(params, searchFn, valIndex) : removeTagGroupParam(params, searchFn, valIndex)
" "
data-cy="catalogFilterCustomTag"
> >
<strong v-if="customTag.label === 'categoryFk' && categoryList"> <strong v-if="customTag.label === 'categoryFk' && categoryList">
{{ {{
@ -211,6 +212,7 @@ function addOrder(value, field, params) {
:name="category.icon" :name="category.icon"
class="category-icon" class="category-icon"
@click="selectCategory(params, category, searchFn)" @click="selectCategory(params, category, searchFn)"
data-cy="catalogFilterCategory"
> >
<QTooltip> <QTooltip>
{{ t(category.name) }} {{ t(category.name) }}
@ -234,6 +236,7 @@ function addOrder(value, field, params) {
sort-by="name ASC" sort-by="name ASC"
:disable="!params.categoryFk" :disable="!params.categoryFk"
@update:model-value="searchFn()" @update:model-value="searchFn()"
data-cy="catalogFilterType"
> >
<template #option="{ itemProps, opt }"> <template #option="{ itemProps, opt }">
<QItem v-bind="itemProps"> <QItem v-bind="itemProps">
@ -285,6 +288,7 @@ function addOrder(value, field, params) {
:is-clearable="false" :is-clearable="false"
v-model="searchByTag" v-model="searchByTag"
@keyup.enter="(val) => onSearchByTag(val, params)" @keyup.enter="(val) => onSearchByTag(val, params)"
data-cy="catalogFilterValueInput"
> >
<template #prepend> <template #prepend>
<QIcon name="search" /> <QIcon name="search" />
@ -297,6 +301,7 @@ function addOrder(value, field, params) {
color="primary" color="primary"
size="md" size="md"
dense dense
data-cy="catalogFilterValueDialogBtn"
/> />
<QPopupProxy> <QPopupProxy>
<CatalogFilterValueDialog <CatalogFilterValueDialog

View File

@ -15,6 +15,7 @@ import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vu
import WorkerDescriptorProxy from '../Worker/Card/WorkerDescriptorProxy.vue'; import WorkerDescriptorProxy from '../Worker/Card/WorkerDescriptorProxy.vue';
import { toDateTimeFormat } from 'src/filters/date'; import { toDateTimeFormat } from 'src/filters/date';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import dataByOrder from 'src/utils/dataByOrder';
const { t } = useI18n(); const { t } = useI18n();
const { viewSummary } = useSummaryDialog(); const { viewSummary } = useSummaryDialog();
@ -149,7 +150,12 @@ onMounted(() => {
}); });
async function fetchClientAddress(id, formData = {}) { async function fetchClientAddress(id, formData = {}) {
const { data } = await axios.get(`Clients/${id}`, { const { data } = await axios.get(`Clients/${id}`, {
params: { filter: { include: { relation: 'addresses' } } }, params: {
filter: {
order: ['isDefaultAddress DESC', 'isActive DESC', 'nickname ASC'],
include: { relation: 'addresses' },
},
},
}); });
addressesList.value = data.addresses; addressesList.value = data.addresses;
formData.addressId = data.defaultAddressFk; formData.addressId = data.defaultAddressFk;
@ -162,7 +168,7 @@ async function fetchAgencies({ landed, addressId }) {
const { data } = await axios.get('Agencies/landsThatDay', { const { data } = await axios.get('Agencies/landsThatDay', {
params: { addressFk: addressId, landed }, params: { addressFk: addressId, landed },
}); });
agencyList.value = data; agencyList.value = dataByOrder(data, 'agencyMode ASC');
} }
const getDateColor = (date) => { const getDateColor = (date) => {
@ -253,22 +259,27 @@ const getDateColor = (date) => {
@update:model-value="() => fetchAgencies(data)" @update:model-value="() => fetchAgencies(data)"
> >
<template #option="scope"> <template #option="scope">
<QItem v-bind="scope.itemProps"> <QItem
<QItemSection> v-bind="scope.itemProps"
<QItemLabel :class="{ disabled: !scope.opt.isActive }"
:class="{
'color-vn-label': !scope.opt?.isActive,
}"
> >
{{ <QItemSection style="min-width: min-content" avatar>
`${ <QIcon
!scope.opt?.isActive v-if="
? t('basicData.inactive') scope.opt.isActive && data.addressId === scope.opt.id
: '' "
} ` size="sm"
}} color="grey"
{{ scope.opt?.nickname }}: {{ scope.opt?.street }}, name="star"
{{ scope.opt?.city }} class="fill-icon"
/>
</QItemSection>
<QItemSection>
<QItemLabel>
{{ scope.opt.nickname }}
</QItemLabel>
<QItemLabel caption>
{{ `${scope.opt.street}, ${scope.opt.city}` }}
</QItemLabel> </QItemLabel>
</QItemSection> </QItemSection>
</QItem> </QItem>

View File

@ -212,8 +212,6 @@ const getGroupedStates = (data) => {
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>
<QSeparator />
<QExpansionItem :label="t('More options')" expand-separator>
<QItem> <QItem>
<QItemSection v-if="!provinces"> <QItemSection v-if="!provinces">
<QSkeleton type="QInput" class="full-width" /> <QSkeleton type="QInput" class="full-width" />
@ -286,7 +284,6 @@ const getGroupedStates = (data) => {
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>
</QExpansionItem>
</template> </template>
</VnFilterPanel> </VnFilterPanel>
</template> </template>
@ -340,7 +337,6 @@ es:
With problems: Con problemas With problems: Con problemas
Invoiced: Facturado Invoiced: Facturado
Routed: Enrutado Routed: Enrutado
More options: Más opciones
Province: Provincia Province: Provincia
Agency: Agencia Agency: Agencia
Warehouse: Almacén Warehouse: Almacén

View File

@ -274,7 +274,7 @@ const fetchAddresses = async (formData) => {
const filter = { const filter = {
fields: ['nickname', 'street', 'city', 'id', 'isActive'], fields: ['nickname', 'street', 'city', 'id', 'isActive'],
order: 'nickname ASC', order: ['isDefaultAddress DESC', 'isActive DESC', 'nickname ASC'],
}; };
const params = { filter: JSON.stringify(filter) }; const params = { filter: JSON.stringify(filter) };
const { data } = await axios.get(`Clients/${formData.clientId}/addresses`, { const { data } = await axios.get(`Clients/${formData.clientId}/addresses`, {
@ -590,7 +590,22 @@ function setReference(data) {
@update:model-value="() => fetchAvailableAgencies(data)" @update:model-value="() => fetchAvailableAgencies(data)"
> >
<template #option="scope"> <template #option="scope">
<QItem v-bind="scope.itemProps"> <QItem
v-bind="scope.itemProps"
:class="{ disabled: !scope.opt.isActive }"
>
<QItemSection style="min-width: min-content" avatar>
<QIcon
v-if="
scope.opt.isActive &&
selectedClient?.defaultAddressFk === scope.opt.id
"
size="sm"
color="grey"
name="star"
class="fill-icon"
/>
</QItemSection>
<QItemSection> <QItemSection>
<QItemLabel <QItemLabel
:class="{ :class="{

View File

@ -0,0 +1,112 @@
/// <reference types="cypress" />
describe('OrderCatalog', () => {
beforeEach(() => {
cy.login('developer');
cy.viewport(1920, 720);
cy.visit('/#/order/8/catalog');
});
const checkCustomFilterTag = (filterName = 'Plant') => {
cy.dataCy('catalogFilterCustomTag').should('exist');
cy.dataCy('catalogFilterCustomTag').contains(filterName);
};
const checkFilterTag = (filterName = 'Plant') => {
cy.dataCy('vnFilterPanelChip').should('exist');
cy.dataCy('vnFilterPanelChip').contains(filterName);
};
const selectCategory = (categoryIndex = 1, categoryName = 'Plant') => {
cy.get(
`div.q-page-container div:nth-of-type(${categoryIndex}) > [data-cy='catalogFilterCategory']`
).should('exist');
cy.get(
`div.q-page-container div:nth-of-type(${categoryIndex}) > [data-cy='catalogFilterCategory']`
).click();
checkCustomFilterTag(categoryName);
};
const searchByCustomTagInput = (option) => {
cy.dataCy('catalogFilterValueInput').find('input').last().focus();
cy.dataCy('catalogFilterValueInput').find('input').last().type(option);
cy.dataCy('catalogFilterValueInput').find('input').last().type('{enter}');
checkCustomFilterTag(option);
};
const selectTypeFilter = (option) => {
cy.selectOption(
'div.q-page-container div.list > div:nth-of-type(2) div:nth-of-type(3)',
option
);
checkFilterTag(option);
};
it('Shows empty state', () => {
cy.dataCy('orderCatalogPage').should('exist');
cy.dataCy('orderCatalogPage').contains('No data to display');
});
it('filter by category', () => {
selectCategory();
cy.dataCy('orderCatalogItem').should('exist');
});
it('filters by type', () => {
selectCategory();
selectTypeFilter('Anthurium');
});
it('filters by custom value select', () => {
selectCategory();
searchByCustomTagInput('Silver');
});
it('filters by custom value dialog', () => {
Cypress.on('uncaught:exception', (err) => {
if (err.message.includes('canceled')) {
return false;
}
});
selectCategory();
cy.dataCy('catalogFilterValueDialogBtn').should('exist');
cy.dataCy('catalogFilterValueDialogBtn').last().click();
cy.dataCy('catalogFilterValueDialogTagSelect').should('exist');
cy.selectOption("[data-cy='catalogFilterValueDialogTagSelect']", 'Tallos');
cy.dataCy('catalogFilterValueDialogValueInput').find('input').focus();
cy.dataCy('catalogFilterValueDialogValueInput').find('input').type('2');
cy.dataCy('catalogFilterValueDialogValueInput').find('input').type('{enter}');
checkCustomFilterTag('2');
});
it('removes a secondary tag', () => {
selectCategory();
selectTypeFilter('Anthurium');
cy.dataCy('vnFilterPanelChip').should('exist');
cy.get(
"div.q-page-container [data-cy='vnFilterPanelChip'] > i.q-chip__icon--remove"
)
.contains('cancel')
.should('exist');
cy.get(
"div.q-page-container [data-cy='vnFilterPanelChip'] > i.q-chip__icon--remove"
)
.contains('cancel')
.click();
cy.dataCy('vnFilterPanelChip').should('not.exist');
});
it('Removes category tag', () => {
selectCategory();
cy.get(
"div.q-page-container [data-cy='catalogFilterCustomTag'] > i.q-chip__icon--remove"
)
.contains('cancel')
.should('exist');
cy.get(
"div.q-page-container [data-cy='catalogFilterCustomTag'] > i.q-chip__icon--remove"
)
.contains('cancel')
.click();
cy.dataCy('catalogFilterCustomTag').should('not.exist');
});
});

View File

@ -86,9 +86,10 @@ Cypress.Commands.add('getValue', (selector) => {
}); });
// Fill Inputs // Fill Inputs
Cypress.Commands.add('selectOption', (selector, option) => { Cypress.Commands.add('selectOption', (selector, option, timeout) => {
cy.waitForElement(selector); cy.waitForElement(selector);
cy.get(selector).click(); cy.get(selector).click();
cy.wait(timeout || 1000);
cy.get('.q-menu .q-item').contains(option).click(); cy.get('.q-menu .q-item').contains(option).click();
}); });
Cypress.Commands.add('countSelectOptions', (selector, option) => { Cypress.Commands.add('countSelectOptions', (selector, option) => {

View File

@ -0,0 +1,29 @@
import { describe, it, expect } from 'vitest';
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');
});
it('maintains prefix +34 if it is already correct', () => {
const resultado = parsePhone('+34123456789', '34');
expect(resultado).toBe('34123456789');
});
it('converts prefix 0034 to +34', () => {
const resultado = parsePhone('0034123456789', '34');
expect(resultado).toBe('34123456789');
});
it('converts prefix 34 without symbol to +34', () => {
const resultado = parsePhone('34123456789', '34');
expect(resultado).toBe('34123456789');
});
it('replaces incorrect prefix with the correct one', () => {
const resultado = parsePhone('+44123456789', '34');
expect(resultado).toBe('44123456789');
});
});