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> <script setup>
import { nextTick, ref, watch } from 'vue'; import { nextTick, ref } from 'vue';
import { QInput } from 'quasar'; import VnInput from './VnInput.vue';
import { useAccountShortToStandard } from 'src/composables/useAccountShortToStandard';
const $props = defineProps({ const $props = defineProps({
modelValue: {
type: String,
default: '',
},
insertable: { insertable: {
type: Boolean, type: Boolean,
default: false, default: false,
@ -14,70 +11,25 @@ const $props = defineProps({
}); });
const emit = defineEmits(['update:modelValue', 'accountShortToStandard']); const emit = defineEmits(['update:modelValue', 'accountShortToStandard']);
const model = defineModel({ prop: 'modelValue' });
const inputRef = ref(false);
let internalValue = ref($props.modelValue); function setCursorPosition(pos) {
const input = inputRef.value.vnInputRef.$el.querySelector('input');
watch( input.focus();
() => $props.modelValue, input.setSelectionRange(pos, pos);
(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);
} }
const vnInputRef = ref(false);
const handleInsertMode = (e) => { async function handleUpdateModel(val) {
e.preventDefault(); model.value = val?.at(-1) === '.' ? useAccountShortToStandard(val) : val;
const input = e.target; await nextTick(() => setCursorPosition(0));
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)
);
} }
</script> </script>
<template> <template>
<QInput @keydown="handleKeydown" ref="vnInputRef" v-model="internalValue" /> <VnInput
v-model="model"
ref="inputRef"
:insertable
@update:model-value="handleUpdateModel"
/>
</template> </template>

View File

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

View File

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

View File

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

View File

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

View File

@ -108,7 +108,6 @@ function handleLocation(data, location) {
<VnAccountNumber <VnAccountNumber
v-model="data.account" v-model="data.account"
:label="t('supplier.fiscalData.account')" :label="t('supplier.fiscalData.account')"
clearable
data-cy="supplierFiscalDataAccount" data-cy="supplierFiscalDataAccount"
insertable insertable
:maxlength="10" :maxlength="10"

View File

@ -4,7 +4,6 @@ import { useI18n } from 'vue-i18n';
import VnTable from 'components/VnTable/VnTable.vue'; import VnTable from 'components/VnTable/VnTable.vue';
import VnSection from 'src/components/common/VnSection.vue'; import VnSection from 'src/components/common/VnSection.vue';
import VnInput from 'src/components/common/VnInput.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 FetchData from 'src/components/FetchData.vue';
import { useSummaryDialog } from 'src/composables/useSummaryDialog'; import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import SupplierSummary from './Card/SupplierSummary.vue'; import SupplierSummary from './Card/SupplierSummary.vue';
@ -53,7 +52,7 @@ const columns = computed(() => [
label: t('globals.alias'), label: t('globals.alias'),
name: 'alias', name: 'alias',
columnFilter: { columnFilter: {
name: 'search', name: 'nickname',
}, },
cardVisible: true, 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> </script>
<template> <template>
<FetchData <FetchData
@ -130,7 +144,7 @@ const columns = computed(() => [
/> />
<VnSection <VnSection
:data-key="dataKey" :data-key="dataKey"
:columns="columns" :columns="filterColumns"
prefix="supplier" prefix="supplier"
:array-data-props="{ :array-data-props="{
url: 'Suppliers/filter', url: 'Suppliers/filter',
@ -165,17 +179,6 @@ const columns = computed(() => [
</template> </template>
</VnTable> </VnTable>
</template> </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> </VnSection>
</template> </template>

View File

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