This commit is contained in:
Alex Moreno 2024-11-28 08:41:56 +01:00
commit a251e348a8
14 changed files with 244 additions and 187 deletions

View File

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

View File

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

View File

@ -12,10 +12,12 @@ import dateRange from './dateRange';
import toHour from './toHour';
import dashOrCurrency from './dashOrCurrency';
import getParamWhere from './getParamWhere';
import parsePhone from './parsePhone';
import isDialogOpened from './isDialogOpened';
export {
isDialogOpened,
parsePhone,
toLowerCase,
toLowerCamel,
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

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

View File

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

View File

@ -86,7 +86,7 @@ const entriesTableColumns = computed(() => [
color="primary"
icon="print"
:loading="isLoading"
@click="openReport(`Entries/${entityId}/print`)"
@click="openReport(`Entries/${entityId}/buy-label-supplier`)"
unelevated
autofocus
/>

View File

@ -184,5 +184,4 @@ es:
Amount: Importe
Issued: Fecha factura
Id or supplier: Id o proveedor
More options: Más opciones
</i18n>

View File

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

View File

@ -60,8 +60,15 @@ const columns = computed(() => [
label: t('globals.reference'),
isTitle: true,
component: 'select',
attrs: { url: MODEL, optionLabel: 'ref', optionValue: 'id' },
attrs: {
url: MODEL,
optionLabel: 'ref',
optionValue: 'ref',
},
columnField: { component: null },
columnFilter: {
inWhere: true,
},
},
{
align: 'left',
@ -139,25 +146,22 @@ function openPdf(id) {
}
function downloadPdf() {
if (selectedRows.value.size === 0) return;
const selectedCardsArray = Array.from(selectedRows.value.values());
if (selectedRows.value.size === 0) return;
const selectedCardsArray = Array.from(selectedRows.value.values());
if (selectedRows.value.size === 1) {
const [invoiceOut] = selectedCardsArray;
openPdf(invoiceOut.id);
} else {
const invoiceOutIdsArray = selectedCardsArray.map(
(invoiceOut) => invoiceOut.id
);
const invoiceOutIds = invoiceOutIdsArray.join(',');
if (selectedRows.value.size === 1) {
const [invoiceOut] = selectedCardsArray;
openPdf(invoiceOut.id);
} else {
const invoiceOutIdsArray = selectedCardsArray.map((invoiceOut) => invoiceOut.id);
const invoiceOutIds = invoiceOutIdsArray.join(',');
const params = {
ids: invoiceOutIds,
};
openReport(`${MODEL}/downloadZip`, params);
}
const params = {
ids: invoiceOutIds,
};
openReport(`${MODEL}/downloadZip`, params);
}
}
watchEffect(selectedRows);

View File

@ -15,6 +15,7 @@ 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();
@ -149,7 +150,12 @@ onMounted(() => {
});
async function fetchClientAddress(id, formData = {}) {
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;
formData.addressId = data.defaultAddressFk;
@ -162,7 +168,7 @@ async function fetchAgencies({ landed, addressId }) {
const { data } = await axios.get('Agencies/landsThatDay', {
params: { addressFk: addressId, landed },
});
agencyList.value = data;
agencyList.value = dataByOrder(data, 'agencyMode ASC');
}
const getDateColor = (date) => {
@ -191,7 +197,7 @@ const getDateColor = (date) => {
urlCreate: 'Orders/new',
title: t('module.cerateOrder'),
onDataSaved: (url) => {
tableRef.redirect(`${url}/catalog`);
tableRef.redirect(`${url}/catalog`);
},
formInitialData: {
active: true,
@ -253,22 +259,27 @@ const getDateColor = (date) => {
@update:model-value="() => fetchAgencies(data)"
>
<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 && data.addressId === scope.opt.id
"
size="sm"
color="grey"
name="star"
class="fill-icon"
/>
</QItemSection>
<QItemSection>
<QItemLabel
:class="{
'color-vn-label': !scope.opt?.isActive,
}"
>
{{
`${
!scope.opt?.isActive
? t('basicData.inactive')
: ''
} `
}}
{{ scope.opt?.nickname }}: {{ scope.opt?.street }},
{{ scope.opt?.city }}
<QItemLabel>
{{ scope.opt.nickname }}
</QItemLabel>
<QItemLabel caption>
{{ `${scope.opt.street}, ${scope.opt.city}` }}
</QItemLabel>
</QItemSection>
</QItem>

View File

@ -212,81 +212,78 @@ const getGroupedStates = (data) => {
/>
</QItemSection>
</QItem>
<QSeparator />
<QExpansionItem :label="t('More options')" expand-separator>
<QItem>
<QItemSection v-if="!provinces">
<QSkeleton type="QInput" class="full-width" />
</QItemSection>
<QItemSection v-if="provinces">
<QSelect
:label="t('Province')"
v-model="params.provinceFk"
@update:model-value="searchFn()"
:options="provinces"
option-value="id"
option-label="name"
emit-value
map-options
use-input
dense
outlined
rounded
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection v-if="!agencies">
<QSkeleton type="QInput" class="full-width" />
</QItemSection>
<QItemSection v-if="agencies">
<QSelect
:label="t('Agency')"
v-model="params.agencyModeFk"
@update:model-value="searchFn()"
:options="agencies"
option-value="id"
option-label="name"
emit-value
map-options
use-input
dense
outlined
rounded
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection v-if="!warehouses">
<QSkeleton type="QInput" class="full-width" />
</QItemSection>
<QItemSection v-if="warehouses">
<QSelect
:label="t('Warehouse')"
v-model="params.warehouseFk"
@update:model-value="searchFn()"
:options="warehouses"
option-value="id"
option-label="name"
emit-value
map-options
use-input
dense
outlined
rounded
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInput
v-model="params.collectionFk"
:label="t('Collection')"
is-outlined
/>
</QItemSection>
</QItem>
</QExpansionItem>
<QItem>
<QItemSection v-if="!provinces">
<QSkeleton type="QInput" class="full-width" />
</QItemSection>
<QItemSection v-if="provinces">
<QSelect
:label="t('Province')"
v-model="params.provinceFk"
@update:model-value="searchFn()"
:options="provinces"
option-value="id"
option-label="name"
emit-value
map-options
use-input
dense
outlined
rounded
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection v-if="!agencies">
<QSkeleton type="QInput" class="full-width" />
</QItemSection>
<QItemSection v-if="agencies">
<QSelect
:label="t('Agency')"
v-model="params.agencyModeFk"
@update:model-value="searchFn()"
:options="agencies"
option-value="id"
option-label="name"
emit-value
map-options
use-input
dense
outlined
rounded
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection v-if="!warehouses">
<QSkeleton type="QInput" class="full-width" />
</QItemSection>
<QItemSection v-if="warehouses">
<QSelect
:label="t('Warehouse')"
v-model="params.warehouseFk"
@update:model-value="searchFn()"
:options="warehouses"
option-value="id"
option-label="name"
emit-value
map-options
use-input
dense
outlined
rounded
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInput
v-model="params.collectionFk"
:label="t('Collection')"
is-outlined
/>
</QItemSection>
</QItem>
</template>
</VnFilterPanel>
</template>
@ -340,7 +337,6 @@ es:
With problems: Con problemas
Invoiced: Facturado
Routed: Enrutado
More options: Más opciones
Province: Provincia
Agency: Agencia
Warehouse: Almacén

View File

@ -274,7 +274,7 @@ const fetchAddresses = async (formData) => {
const filter = {
fields: ['nickname', 'street', 'city', 'id', 'isActive'],
order: 'nickname ASC',
order: ['isDefaultAddress DESC', 'isActive DESC', 'nickname ASC'],
};
const params = { filter: JSON.stringify(filter) };
const { data } = await axios.get(`Clients/${formData.clientId}/addresses`, {
@ -590,7 +590,22 @@ function setReference(data) {
@update:model-value="() => fetchAvailableAgencies(data)"
>
<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>
<QItemLabel
:class="{

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');
});
});