Compare commits

..

9 Commits

Author SHA1 Message Date
Jose Antonio Tubau ad1bde3f43 Merge branch 'dev' into 7069-testVnAccountNumber
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-05-12 11:07:36 +00:00
Jose Antonio Tubau def62c5e12 Merge branch 'dev' into 7069-testVnAccountNumber
gitea/salix-front/pipeline/pr-dev This commit is unstable Details
2025-05-12 05:13:46 +00:00
Alex Moreno 649686f128 refactor: refs #7069 remove keyup.enter and blur event emissions from VnInput component
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-05-09 09:53:42 +02:00
Alex Moreno 43258214e1 feat: refs #7069 add keyup.enter and blur event emissions to VnInput component
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2025-05-09 09:46:06 +02:00
Alex Moreno c723608d6b refactor: refs #7069 simplify VnInput emits and update event handling in tests
gitea/salix-front/pipeline/pr-dev There was a failure building this commit Details
2025-05-09 09:09:57 +02:00
Alex Moreno 2a8feaa5d1 Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 7069-testVnAccountNumber 2025-05-09 08:42:48 +02:00
Jose Antonio Tubau 9639c56ce0 Merge branch 'dev' into 7069-testVnAccountNumber
gitea/salix-front/pipeline/pr-dev This commit looks good Details
2025-05-05 13:58:58 +00:00
Jose Antonio Tubau d10549939b Merge branch 'dev' into 7069-testVnAccountNumber
gitea/salix-front/pipeline/pr-dev This commit is unstable Details
2025-04-30 09:29:43 +00:00
Jose Antonio Tubau b21c5752b8 test: refs #7069 add unit tests for VnAccountNumber component
gitea/salix-front/pipeline/pr-dev This commit is unstable Details
2025-04-30 10:41:49 +02:00
8 changed files with 106 additions and 121 deletions

View File

@ -0,0 +1,43 @@
import { describe, expect, it, vi, beforeEach } from 'vitest';
import { createWrapper } from 'app/test/vitest/helper';
import VnAccountNumber from 'src/components/common/VnAccountNumber.vue';
describe('VnAccountNumber', () => {
let wrapper;
let input;
let vnInput;
let spyShort;
beforeEach(() => {
wrapper = createWrapper(VnAccountNumber);
wrapper = wrapper.wrapper;
input = wrapper.find('input');
vnInput = wrapper.findComponent({ name: 'VnInput' });
spyShort = vi.spyOn(wrapper.vm, 'useAccountShortToStandard');
});
it('should filter out non-numeric characters on input event', async () => {
await input.setValue('abc123.45!@#');
const emitted = wrapper.emitted('update:modelValue');
expect(emitted.pop()[0]).toBe('123.45');
expect(spyShort).not.toHaveBeenCalled();
});
it('should apply conversion on blur when valid short value is provided', async () => {
await input.setValue('123.45');
await vnInput.trigger('blur');
const emitted = wrapper.emitted('update:modelValue');
expect(emitted.pop()[0]).toBe('1230000045');
expect(spyShort).toHaveBeenCalled();
});
it('should not change value for invalid input values', async () => {
await input.setValue('123');
await vnInput.trigger('blur');
const emitted = wrapper.emitted('update:modelValue');
expect(emitted.pop()[0]).toBe('123');
expect(spyShort).toHaveBeenCalled();
});
});

View File

@ -6,13 +6,7 @@ import { useRequired } from 'src/composables/useRequired';
const $attrs = useAttrs(); const $attrs = useAttrs();
const { isRequired, requiredFieldRule } = useRequired($attrs); const { isRequired, requiredFieldRule } = useRequired($attrs);
const { t } = useI18n(); const { t } = useI18n();
const emit = defineEmits([ const emit = defineEmits(['update:modelValue', 'update:options', 'remove']);
'update:modelValue',
'update:options',
'keyup.enter',
'remove',
'blur',
]);
const $props = defineProps({ const $props = defineProps({
modelValue: { modelValue: {
@ -126,6 +120,14 @@ const handleInsertMode = (e) => {
const handleUppercase = () => { const handleUppercase = () => {
value.value = value.value?.toUpperCase() || ''; value.value = value.value?.toUpperCase() || '';
}; };
const listeners = computed(() =>
Object.fromEntries(
Object.entries($attrs).filter(
([key, val]) => key.startsWith('on') && typeof val === 'function',
),
),
);
</script> </script>
<template> <template>
@ -134,10 +136,9 @@ const handleUppercase = () => {
ref="vnInputRef" ref="vnInputRef"
v-model="value" v-model="value"
v-bind="{ ...$attrs, ...styleAttrs }" v-bind="{ ...$attrs, ...styleAttrs }"
v-on="listeners"
:type="$attrs.type" :type="$attrs.type"
:class="{ required: isRequired }" :class="{ required: isRequired }"
@keyup.enter="emit('keyup.enter')"
@blur="emit('blur')"
@keydown="handleKeydown" @keydown="handleKeydown"
:clearable="false" :clearable="false"
:rules="mixinRules" :rules="mixinRules"

View File

@ -47,9 +47,7 @@ export function useValidator() {
return !validator.isEmpty(value ? String(value) : '') || message; return !validator.isEmpty(value ? String(value) : '') || message;
}, },
required: (required, value) => { required: (required, value) => {
return required return required ? !!value || t('globals.fieldRequired') : null;
? value === 0 || !!value || t('globals.fieldRequired')
: null;
}, },
length: (value) => { length: (value) => {
const options = { const options = {

View File

@ -6,6 +6,7 @@ import { useQuasar } from 'quasar';
import axios from 'axios'; import axios from 'axios';
import useNotify from 'src/composables/useNotify.js'; import useNotify from 'src/composables/useNotify.js';
import FetchData from 'components/FetchData.vue';
import FormModel from 'components/FormModel.vue'; import FormModel from 'components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue'; import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
@ -20,6 +21,9 @@ const { t } = useI18n();
const route = useRoute(); const route = useRoute();
const { notify } = useNotify(); const { notify } = useNotify();
const typesTaxes = ref([]);
const typesTransactions = ref([]);
function handleLocation(data, location) { function handleLocation(data, location) {
const { town, code, provinceFk, countryFk } = location ?? {}; const { town, code, provinceFk, countryFk } = location ?? {};
data.postcode = code; data.postcode = code;
@ -35,7 +39,6 @@ function onBeforeSave(formData, originalData) {
} }
async function checkEtChanges(data, _, originalData) { async function checkEtChanges(data, _, originalData) {
isTaxDataChecked.value = data.isTaxDataChecked;
const equalizatedHasChanged = originalData.isEqualizated != data.isEqualizated; const equalizatedHasChanged = originalData.isEqualizated != data.isEqualizated;
const hasToInvoiceByAddress = const hasToInvoiceByAddress =
originalData.hasToInvoiceByAddress || data.hasToInvoiceByAddress; originalData.hasToInvoiceByAddress || data.hasToInvoiceByAddress;
@ -59,18 +62,15 @@ async function acceptPropagate({ isEqualizated }) {
}); });
notify(t('Equivalent tax spreaded'), 'warning'); notify(t('Equivalent tax spreaded'), 'warning');
} }
const isTaxDataChecked = ref(false);
function isRequired({ isTaxDataChecked: taxDataChecked }) {
if (!isTaxDataChecked.value) {
return false;
} else {
return taxDataChecked;
}
}
</script> </script>
<template> <template>
<FetchData auto-load @on-fetch="(data) => (typesTaxes = data)" url="SageTaxTypes" />
<FetchData
auto-load
@on-fetch="(data) => (typesTransactions = data)"
url="SageTransactionTypes"
/>
<FormModel <FormModel
:url-update="`Clients/${route.params.id}/updateFiscalData`" :url-update="`Clients/${route.params.id}/updateFiscalData`"
auto-load auto-load
@ -80,7 +80,6 @@ function isRequired({ isTaxDataChecked: taxDataChecked }) {
@on-data-saved="checkEtChanges" @on-data-saved="checkEtChanges"
> >
<template #form="{ data, validate, validations }"> <template #form="{ data, validate, validations }">
{{ isTaxDataChecked }} {{ data.isTaxDataChecked }}
<VnRow> <VnRow>
<VnInput <VnInput
:label="t('Social name')" :label="t('Social name')"
@ -112,27 +111,21 @@ function isRequired({ isTaxDataChecked: taxDataChecked }) {
<VnRow> <VnRow>
<VnSelect <VnSelect
:label="t('Sage tax type')" :label="t('Sage tax type')"
url="SageTaxTypes" :options="typesTaxes"
hide-selected hide-selected
option-label="vat" option-label="vat"
option-value="id" option-value="id"
v-model="data.sageTaxTypeFk" v-model="data.sageTaxTypeFk"
data-cy="sageTaxTypeFk" data-cy="sageTaxTypeFk"
:required="isRequired(data)"
:rules="[(val) => validations.required(data.sageTaxTypeFk, val)]"
/> />
<VnSelect <VnSelect
:label="t('Sage transaction type')" :label="t('Sage transaction type')"
url="SageTransactionTypes" :options="typesTransactions"
hide-selected hide-selected
option-label="transaction" option-label="transaction"
option-value="id" option-value="id"
data-cy="sageTransactionTypeFk" data-cy="sageTransactionTypeFk"
v-model="data.sageTransactionTypeFk" v-model="data.sageTransactionTypeFk"
:required="isRequired(data)"
:rules="[
(val) => validations.required(data.sageTransactionTypeFk, val),
]"
> >
<template #option="scope"> <template #option="scope">
<QItem v-bind="scope.itemProps"> <QItem v-bind="scope.itemProps">
@ -158,11 +151,11 @@ function isRequired({ isTaxDataChecked: taxDataChecked }) {
/> />
</VnRow> </VnRow>
<VnRow> <VnRow>
<VnCheckbox :label="t('Active')" v-model="data.isActive" /> <QCheckbox :label="t('Active')" v-model="data.isActive" />
<VnCheckbox :label="t('Frozen')" v-model="data.isFreezed" /> <QCheckbox :label="t('Frozen')" v-model="data.isFreezed" />
</VnRow> </VnRow>
<VnRow> <VnRow>
<VnCheckbox :label="t('Has to invoice')" v-model="data.hasToInvoice" /> <QCheckbox :label="t('Has to invoice')" v-model="data.hasToInvoice" />
<VnCheckbox <VnCheckbox
v-model="data.isVies" v-model="data.isVies"
:label="t('globals.isVies')" :label="t('globals.isVies')"
@ -171,8 +164,8 @@ function isRequired({ isTaxDataChecked: taxDataChecked }) {
</VnRow> </VnRow>
<VnRow> <VnRow>
<VnCheckbox :label="t('Notify by email')" v-model="data.isToBeMailed" /> <QCheckbox :label="t('Notify by email')" v-model="data.isToBeMailed" />
<VnCheckbox <QCheckbox
:label="t('Invoice by address')" :label="t('Invoice by address')"
v-model="data.hasToInvoiceByAddress" v-model="data.hasToInvoiceByAddress"
/> />
@ -184,18 +177,16 @@ function isRequired({ isTaxDataChecked: taxDataChecked }) {
:label="t('Is equalizated')" :label="t('Is equalizated')"
:info="t('inOrderToInvoice')" :info="t('inOrderToInvoice')"
/> />
<VnCheckbox :label="t('Daily invoice')" v-model="data.hasDailyInvoice" /> <QCheckbox :label="t('Daily invoice')" v-model="data.hasDailyInvoice" />
</VnRow> </VnRow>
<VnRow> <VnRow>
<VnCheckbox <QCheckbox
:label="t('Electronic invoice')" :label="t('Electronic invoice')"
v-model="data.hasElectronicInvoice" v-model="data.hasElectronicInvoice"
/> /><QCheckbox
<VnCheckbox
:label="t('Verified data')" :label="t('Verified data')"
v-model="data.isTaxDataChecked" v-model="data.isTaxDataChecked"
@update:model-value="isTaxDataChecked = !isTaxDataChecked"
/> />
</VnRow> </VnRow>
</template> </template>

View File

@ -179,11 +179,6 @@ function handleLocation(data, location) {
data.provinceFk = provinceFk; data.provinceFk = provinceFk;
data.countryFk = countryFk; data.countryFk = countryFk;
} }
function onAgentCreated({ id, fiscalName }, data) {
customsAgents.value.push({ id, fiscalName });
data.customsAgentFk = id;
}
</script> </script>
<template> <template>
@ -297,14 +292,9 @@ function onAgentCreated({ id, fiscalName }, data) {
option-value="id" option-value="id"
v-model="data.customsAgentFk" v-model="data.customsAgentFk"
:tooltip="t('New customs agent')" :tooltip="t('New customs agent')"
:acls="[{ model: 'CustomsAgent', props: '*', accessType: 'WRITE' }]"
> >
<template #form> <template #form>
<CustomerNewCustomsAgent <CustomerNewCustomsAgent />
@on-data-saved="
(requestResponse) => onAgentCreated(requestResponse, data)
"
/>
</template> </template>
</VnSelectDialog> </VnSelectDialog>
</VnRow> </VnRow>

View File

@ -16,7 +16,6 @@ const onDataSaved = (dataSaved) => {
<template> <template>
<FormModelPopup <FormModelPopup
:form-initial-data="{}"
:title="t('New customs agent')" :title="t('New customs agent')"
@on-data-saved="onDataSaved($event)" @on-data-saved="onDataSaved($event)"
model="customer" model="customer"

View File

@ -7,27 +7,7 @@ describe('Client credits', () => {
timeout: 5000, timeout: 5000,
}); });
}); });
it('Should load layout', () => {
it('Should put a new credit', () => {
cy.get('.q-page').should('be.visible'); cy.get('.q-page').should('be.visible');
cy.dataCy('vnTableCreateBtn').click();
cy.dataCy('Credit_input').type('100');
cy.dataCy('FormModelPopup_save').click();
cy.checkNotification('Data saved');
});
it('Should put a new credit with value 0 to close the client card', () => {
cy.get('.q-page').should('be.visible');
cy.dataCy('vnTableCreateBtn').click();
cy.dataCy('Credit_input').type('0');
cy.dataCy('FormModelPopup_save').click();
cy.checkNotification('Data saved');
});
it('Should not create the credit if there is no value in the input', () => {
cy.get('.q-page').should('be.visible');
cy.dataCy('vnTableCreateBtn').click();
cy.dataCy('FormModelPopup_save').click();
cy.get('.q-notification__message').should('not.exist');
}); });
}); });

View File

@ -1,39 +1,23 @@
/// <reference types="cypress" /> /// <reference types="cypress" />
function checkSageFields(isRequired = false) { describe('Client fiscal data', { testIsolation: true }, () => {
const haveAttr = isRequired ? 'have.attr' : 'not.have.attr';
cy.dataCy('sageTaxTypeFk').filter('input').should(haveAttr, 'required');
cy.dataCy('sageTransactionTypeFk').filter('input').should(haveAttr, 'required');
}
describe('Client fiscal data', () => {
describe('#1008', () => {
beforeEach(() => {
cy.viewport(1280, 720);
cy.login('developer');
cy.visit('#/customer/1108/fiscal-data');
});
it('Should change required value when change customer', () => {
cy.get('.q-card').should('be.visible');
checkSageFields();
cy.get('[data-cy="vnCheckboxVerified data"]').click();
cy.get('.q-btn-group > .q-btn--standard > .q-btn__content').click();
checkSageFields();
cy.get('[data-cy="vnCheckboxVerified data"]').click();
checkSageFields(true);
cy.get('#searchbar input').clear();
cy.get('#searchbar input').type('1{enter}');
cy.get('.q-item > .q-item__label').should('have.text', ' #1');
checkSageFields();
});
});
describe('#1007', () => {
beforeEach(() => { beforeEach(() => {
cy.viewport(1280, 720); cy.viewport(1280, 720);
cy.login('developer'); cy.login('developer');
cy.visit('#/customer/1107/fiscal-data'); cy.visit('#/customer/1107/fiscal-data');
}); });
it.skip('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');
});
it('check as equalizated', () => { it('check as equalizated', () => {
cy.dataCy('vnCheckboxIs equalizated').click(); cy.get(
':nth-child(1) > .q-checkbox > .q-checkbox__inner > .q-checkbox__bg',
).click();
cy.get('.q-btn-group > .q-btn--standard > .q-btn__content').click(); cy.get('.q-btn-group > .q-btn--standard > .q-btn__content').click();
cy.get('.q-card > :nth-child(1) > span').should( cy.get('.q-card > :nth-child(1) > span').should(
@ -51,4 +35,3 @@ describe('Client fiscal data', () => {
).should('have.text', 'Equivalent tax spreaded'); ).should('have.text', 'Equivalent tax spreaded');
}); });
}); });
});