Merge branch 'master' into improve_ticker_order_list
gitea/salix-front/pipeline/pr-master This commit looks good Details

This commit is contained in:
Javier Segarra 2025-03-05 10:06:27 +01:00
commit b2566c1cc9
8 changed files with 93 additions and 125 deletions

View File

@ -1,12 +1,9 @@
<script setup>
import { nextTick, ref, watch } from 'vue';
import { QInput } from 'quasar';
import { nextTick, ref } from 'vue';
import VnInput from './VnInput.vue';
import { useAccountShortToStandard } from 'src/composables/useAccountShortToStandard';
const $props = defineProps({
modelValue: {
type: String,
default: '',
},
insertable: {
type: Boolean,
default: false,
@ -14,70 +11,25 @@ const $props = defineProps({
});
const emit = defineEmits(['update:modelValue', 'accountShortToStandard']);
const model = defineModel({ prop: 'modelValue' });
const inputRef = ref(false);
let internalValue = ref($props.modelValue);
watch(
() => $props.modelValue,
(newVal) => {
internalValue.value = newVal;
}
);
watch(
() => internalValue.value,
(newVal) => {
emit('update:modelValue', newVal);
accountShortToStandard();
}
);
const handleKeydown = (e) => {
if (e.key === 'Backspace') return;
if (e.key === '.') {
accountShortToStandard();
// TODO: Fix this setTimeout, with nextTick doesn't work
setTimeout(() => {
setCursorPosition(0, e.target);
}, 1);
return;
}
if ($props.insertable && e.key.match(/[0-9]/)) {
handleInsertMode(e);
}
};
function setCursorPosition(pos, el = vnInputRef.value) {
el.focus();
el.setSelectionRange(pos, pos);
function setCursorPosition(pos) {
const input = inputRef.value.vnInputRef.$el.querySelector('input');
input.focus();
input.setSelectionRange(pos, pos);
}
const vnInputRef = ref(false);
const handleInsertMode = (e) => {
e.preventDefault();
const input = e.target;
const cursorPos = input.selectionStart;
const { maxlength } = vnInputRef.value;
let currentValue = internalValue.value;
if (!currentValue) currentValue = e.key;
const newValue = e.key;
if (newValue && !isNaN(newValue) && cursorPos < maxlength) {
internalValue.value =
currentValue.substring(0, cursorPos) +
newValue +
currentValue.substring(cursorPos + 1);
}
nextTick(() => {
input.setSelectionRange(cursorPos + 1, cursorPos + 1);
});
};
function accountShortToStandard() {
internalValue.value = internalValue.value?.replace(
'.',
'0'.repeat(11 - internalValue.value.length)
);
async function handleUpdateModel(val) {
model.value = val?.at(-1) === '.' ? useAccountShortToStandard(val) : val;
await nextTick(() => setCursorPosition(0));
}
</script>
<template>
<QInput @keydown="handleKeydown" ref="vnInputRef" v-model="internalValue" />
<VnInput
v-model="model"
ref="inputRef"
:insertable
@update:model-value="handleUpdateModel"
/>
</template>

View File

@ -83,7 +83,7 @@ const mixinRules = [
requiredFieldRule,
...($attrs.rules ?? []),
(val) => {
const { maxlength } = vnInputRef.value;
const maxlength = $props.maxlength;
if (maxlength && +val.length > maxlength)
return t(`maxLength`, { value: maxlength });
const { min, max } = vnInputRef.value.$attrs;
@ -108,7 +108,7 @@ const handleInsertMode = (e) => {
e.preventDefault();
const input = e.target;
const cursorPos = input.selectionStart;
const { maxlength } = vnInputRef.value;
const maxlength = $props.maxlength;
let currentValue = value.value;
if (!currentValue) currentValue = e.key;
const newValue = e.key;
@ -143,7 +143,7 @@ const handleUppercase = () => {
:rules="mixinRules"
:lazy-rules="true"
hide-bottom-space
:data-cy="$attrs.dataCy ?? $attrs.label + '_input'"
:data-cy="$attrs['data-cy'] ?? $attrs.label + '_input'"
>
<template #prepend v-if="$slots.prepend">
<slot name="prepend" />

View File

@ -369,6 +369,7 @@ globals:
countryFk: Country
countryCodeFk: Country
companyFk: Company
nickname: Alias
model: Model
fuel: Fuel
active: Active

View File

@ -370,6 +370,7 @@ globals:
countryFk: País
countryCodeFk: País
companyFk: Empresa
nickname: Alias
errors:
statusUnauthorized: Acceso denegado
statusInternalServerError: Ha ocurrido un error interno del servidor

View File

@ -118,14 +118,6 @@ const debtWarning = computed(() => {
>
<QTooltip>{{ t('Allowed substitution') }}</QTooltip>
</QIcon>
<QIcon
v-if="customer?.isFreezed"
name="vn:frozen"
size="xs"
color="primary"
>
<QTooltip>{{ t('customer.card.isFrozen') }}</QTooltip>
</QIcon>
<QIcon
v-if="!entity.account?.active"
color="primary"
@ -150,6 +142,14 @@ const debtWarning = computed(() => {
>
<QTooltip>{{ t('customer.card.notChecked') }}</QTooltip>
</QIcon>
<QIcon
v-if="entity?.isFreezed"
name="vn:frozen"
size="xs"
color="primary"
>
<QTooltip>{{ t('customer.card.isFrozen') }}</QTooltip>
</QIcon>
<QBtn
v-if="entity.unpaid"
flat
@ -163,13 +163,13 @@ const debtWarning = computed(() => {
<br />
{{
t('unpaidDated', {
dated: toDate(customer.unpaid?.dated),
dated: toDate(entity.unpaid?.dated),
})
}}
<br />
{{
t('unpaidAmount', {
amount: toCurrency(customer.unpaid?.amount),
amount: toCurrency(entity.unpaid?.amount),
})
}}
</QTooltip>

View File

@ -108,7 +108,6 @@ function handleLocation(data, location) {
<VnAccountNumber
v-model="data.account"
:label="t('supplier.fiscalData.account')"
clearable
data-cy="supplierFiscalDataAccount"
insertable
:maxlength="10"
@ -185,8 +184,8 @@ function handleLocation(data, location) {
/>
<VnCheckbox
v-model="data.isVies"
:label="t('globals.isVies')"
:info="t('whenActivatingIt')"
:label="t('globals.isVies')"
:info="t('whenActivatingIt')"
/>
</div>
</VnRow>

View File

@ -4,7 +4,6 @@ import { useI18n } from 'vue-i18n';
import VnTable from 'components/VnTable/VnTable.vue';
import VnSection from 'src/components/common/VnSection.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import FetchData from 'src/components/FetchData.vue';
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import SupplierSummary from './Card/SupplierSummary.vue';
@ -53,7 +52,7 @@ const columns = computed(() => [
label: t('globals.alias'),
name: 'alias',
columnFilter: {
name: 'search',
name: 'nickname',
},
cardVisible: true,
},
@ -120,6 +119,21 @@ const columns = computed(() => [
],
},
]);
const filterColumns = computed(() => {
const copy = [...columns.value];
copy.splice(copy.length - 1, 0, {
align: 'left',
label: t('globals.params.provinceFk'),
name: 'provinceFk',
options: provincesOptions.value,
columnFilter: {
component: 'select',
},
});
return copy;
});
</script>
<template>
<FetchData
@ -130,7 +144,7 @@ const columns = computed(() => [
/>
<VnSection
:data-key="dataKey"
:columns="columns"
:columns="filterColumns"
prefix="supplier"
:array-data-props="{
url: 'Suppliers/filter',
@ -165,17 +179,6 @@ const columns = computed(() => [
</template>
</VnTable>
</template>
<template #moreFilterPanel="{ params, searchFn }">
<VnSelect
:label="t('globals.params.provinceFk')"
v-model="params.provinceFk"
@update:model-value="searchFn()"
:options="provincesOptions"
filled
dense
class="q-px-sm q-pr-lg"
/>
</template>
</VnSection>
</template>

View File

@ -1,4 +1,4 @@
describe('VnInput Component', () => {
describe('VnAccountNumber', () => {
beforeEach(() => {
cy.login('developer');
cy.viewport(1920, 1080);
@ -6,34 +6,46 @@ describe('VnInput Component', () => {
cy.domContentLoad();
});
it('should replace character at cursor position in insert mode', () => {
// Simula escribir en el input
cy.dataCy('supplierFiscalDataAccount').clear();
cy.dataCy('supplierFiscalDataAccount').type('4100000001');
// Coloca el cursor en la posición 0
cy.dataCy('supplierFiscalDataAccount').type('{movetostart}');
// Escribe un número y verifica que se reemplace correctamente
cy.dataCy('supplierFiscalDataAccount').type('999');
cy.dataCy('supplierFiscalDataAccount')
.should('have.value', '9990000001');
describe('VnInput handleInsertMode()', () => {
it('should replace character at cursor position in insert mode', () => {
cy.get('input[data-cy="supplierFiscalDataAccount"]').type(
'{selectall}4100000001',
);
cy.get('input[data-cy="supplierFiscalDataAccount"]').type('{movetostart}');
cy.get('input[data-cy="supplierFiscalDataAccount"]').type('999');
cy.get('input[data-cy="supplierFiscalDataAccount"]').should(
'have.value',
'9990000001',
);
});
it('should replace character at cursor position in insert mode', () => {
cy.get('input[data-cy="supplierFiscalDataAccount"]').clear();
cy.get('input[data-cy="supplierFiscalDataAccount"]').type('4100000001');
cy.get('input[data-cy="supplierFiscalDataAccount"]').type('{movetostart}');
cy.get('input[data-cy="supplierFiscalDataAccount"]').type('999');
cy.get('input[data-cy="supplierFiscalDataAccount"]').should(
'have.value',
'9990000001',
);
});
it('should respect maxlength prop', () => {
cy.get('input[data-cy="supplierFiscalDataAccount"]').clear();
cy.get('input[data-cy="supplierFiscalDataAccount"]').type('123456789012345');
cy.get('input[data-cy="supplierFiscalDataAccount"]').should(
'have.value',
'1234567890',
);
});
});
it('should replace character at cursor position in insert mode', () => {
// Simula escribir en el input
cy.dataCy('supplierFiscalDataAccount').clear();
cy.dataCy('supplierFiscalDataAccount').type('4100000001');
// Coloca el cursor en la posición 0
cy.dataCy('supplierFiscalDataAccount').type('{movetostart}');
// Escribe un número y verifica que se reemplace correctamente en la posicion incial
cy.dataCy('supplierFiscalDataAccount').type('999');
cy.dataCy('supplierFiscalDataAccount')
.should('have.value', '9990000001');
});
it('should respect maxlength prop', () => {
cy.dataCy('supplierFiscalDataAccount').clear();
cy.dataCy('supplierFiscalDataAccount').type('123456789012345');
cy.dataCy('supplierFiscalDataAccount')
.should('have.value', '1234567890'); // asumiendo que maxlength es 10
it('should convert short account number to standard format', () => {
cy.get('input[data-cy="supplierFiscalDataAccount"]').clear();
cy.get('input[data-cy="supplierFiscalDataAccount"]').type('123.');
cy.get('input[data-cy="supplierFiscalDataAccount"]').should(
'have.value',
'1230000000',
);
});
});