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')"
v-model="data.name"
:rules="validate('city.name')"
required
/>
<VnSelectProvince
:province-selected="$props.provinceSelected"
:country-fk="$props.countryFk"
v-model="data.provinceFk"
required
/>
</VnRow>
</template>

View File

@ -1,5 +1,5 @@
<script setup>
import { reactive, ref } from 'vue';
import { computed, reactive, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import FetchData from 'components/FetchData.vue';
@ -23,11 +23,10 @@ const postcodeFormData = reactive({
});
const townsFetchDataRef = ref(false);
const countriesFetchDataRef = ref(false);
const countriesRef = ref(false);
const townsRef = ref(false);
const provincesFetchDataRef = ref(false);
const countriesOptions = ref([]);
const provincesOptions = ref([]);
const townsOptions = ref([]);
const town = ref({});
const townFilter = ref({});
const countryFilter = ref({});
@ -42,7 +41,7 @@ function onDataSaved(formData) {
({ id }) => id === formData.provinceFk
);
newPostcode.province = provinceObject?.name;
const countryObject = countriesOptions.value.find(
const countryObject = countriesRef.value.opts.find(
({ id }) => id === formData.countryFk
);
newPostcode.country = countryObject?.name;
@ -70,49 +69,8 @@ async function setCountry(countryFk, data) {
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) {
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) {
@ -128,6 +86,14 @@ async function onProvinceCreated(data) {
});
postcodeFormData.provinceFk = data.id;
}
const whereTowns = computed(() => {
return {
provinceFk: {
inq: provincesOptions.value.map(({ id }) => id),
},
};
});
</script>
<template>
@ -139,24 +105,6 @@ async function onProvinceCreated(data) {
auto-load
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
url-create="postcodes"
@ -174,20 +122,26 @@ async function onProvinceCreated(data) {
v-model="data.code"
:rules="validate('postcode.code')"
clearable
required
/>
<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
>
<template #option="{ itemProps, opt }">
<QItem v-bind="itemProps">
@ -220,13 +174,18 @@ async function onProvinceCreated(data) {
v-model="data.provinceFk"
@on-province-fetched="handleProvinces"
@on-province-created="onProvinceCreated"
required
/>
<VnSelect
ref="countriesRef"
:limit="30"
:filter="countryFilter"
:sort-by="['name ASC']"
auto-load
url="Countries"
required
:label="t('Country')"
@update:options="handleCountries"
:options="countriesOptions"
hide-selected
@filter="filterCountries"
option-label="name"
option-value="id"
v-model="data.countryFk"

View File

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

View File

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

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

@ -874,7 +874,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,14 +120,12 @@ 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>
<QItem class="q-mb-sm">
<QItemSection>
<VnInput :label="t('Phone')" v-model="params.phone" is-outlined>
<template #prepend>
@ -136,7 +134,7 @@ const exprBuilder = (param, value) => {
</VnInput>
</QItemSection>
</QItem>
<QItem>
<QItem class="q-mb-sm">
<QItemSection>
<VnInput :label="t('Email')" v-model="params.email" is-outlined>
<template #prepend>
@ -145,7 +143,8 @@ const exprBuilder = (param, value) => {
</VnInput>
</QItemSection>
</QItem>
<QItem>
<QItem class="q-mb-sm">
<QItemSection>
<VnSelect
url="Zones"
:label="t('Zone')"
@ -160,9 +159,9 @@ const exprBuilder = (param, value) => {
outlined
rounded
auto-load
/>
/></QItemSection>
</QItem>
<QItem>
<QItem class="q-mb-sm">
<QItemSection>
<VnInput
:label="t('Postcode')"
@ -171,7 +170,6 @@ const exprBuilder = (param, value) => {
/>
</QItemSection>
</QItem>
</QExpansionItem>
</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

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

View File

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

View File

@ -83,8 +83,6 @@ const states = ref();
/>
</QItemSection>
</QItem>
<QSeparator />
<QExpansionItem :label="t('More options')" expand-separator>
<QItem>
<QItemSection>
<VnInputDate
@ -105,14 +103,9 @@ const states = ref();
</QItem>
<QItem>
<QItemSection>
<VnInputDate
v-model="params.dued"
:label="t('Dued')"
is-outlined
/>
<VnInputDate v-model="params.dued" :label="t('Dued')" is-outlined />
</QItemSection>
</QItem>
</QExpansionItem>
</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',
@ -146,9 +153,7 @@ function downloadPdf() {
const [invoiceOut] = selectedCardsArray;
openPdf(invoiceOut.id);
} else {
const invoiceOutIdsArray = selectedCardsArray.map(
(invoiceOut) => invoiceOut.id
);
const invoiceOutIdsArray = selectedCardsArray.map((invoiceOut) => invoiceOut.id);
const invoiceOutIds = invoiceOutIdsArray.join(',');
const params = {
@ -157,7 +162,6 @@ function downloadPdf() {
openReport(`${MODEL}/downloadZip`, params);
}
}
watchEffect(selectedRows);

View File

@ -49,7 +49,7 @@ const getSelectedTagValues = async (tag) => {
<template>
<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
:label="t('params.tag')"
v-model="selectedTag"
@ -63,6 +63,7 @@ const getSelectedTagValues = async (tag) => {
:emit-value="false"
use-input
@update:model-value="getSelectedTagValues"
data-cy="catalogFilterValueDialogTagSelect"
/>
<div
v-for="(value, index) in tagValues"
@ -93,6 +94,7 @@ const getSelectedTagValues = async (tag) => {
:disable="!value"
is-outlined
class="col"
data-cy="catalogFilterValueDialogValueInput"
/>
<QBtn
icon="delete"

View File

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

View File

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

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) => {
@ -253,22 +259,27 @@ const getDateColor = (date) => {
@update:model-value="() => fetchAgencies(data)"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel
:class="{
'color-vn-label': !scope.opt?.isActive,
}"
<QItem
v-bind="scope.itemProps"
:class="{ disabled: !scope.opt.isActive }"
>
{{
`${
!scope.opt?.isActive
? t('basicData.inactive')
: ''
} `
}}
{{ scope.opt?.nickname }}: {{ scope.opt?.street }},
{{ scope.opt?.city }}
<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>
{{ scope.opt.nickname }}
</QItemLabel>
<QItemLabel caption>
{{ `${scope.opt.street}, ${scope.opt.city}` }}
</QItemLabel>
</QItemSection>
</QItem>

View File

@ -212,8 +212,6 @@ const getGroupedStates = (data) => {
/>
</QItemSection>
</QItem>
<QSeparator />
<QExpansionItem :label="t('More options')" expand-separator>
<QItem>
<QItemSection v-if="!provinces">
<QSkeleton type="QInput" class="full-width" />
@ -286,7 +284,6 @@ const getGroupedStates = (data) => {
/>
</QItemSection>
</QItem>
</QExpansionItem>
</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,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
Cypress.Commands.add('selectOption', (selector, option) => {
Cypress.Commands.add('selectOption', (selector, option, timeout) => {
cy.waitForElement(selector);
cy.get(selector).click();
cy.wait(timeout || 1000);
cy.get('.q-menu .q-item').contains(option).click();
});
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');
});
});