feat(web): los campos de lista de los maestros muestran el nombre junto al código (grupo, moneda, empleado de ventas, condición de pago, lista de precios, grupo de artículos, proveedor)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
GeorgeandClaude Sonnet 5.5 committed 2026-10-19 18:52:08 -05:00
1 parent f985667b90
commit 9e98160d01
3 files changed
+48 -1

No files matched your search

@@ -13,18 +13,21 @@ export const MASTER_LOOKUPS = {
orderby: 'Code',
baseFilter: `Type eq '${type === 'cSupplier' ? 'bbpgt_VendorGroup' : 'bbpgt_CustomerGroup'}'`,
valueType: 'number',
nameKey: 'Name',
columns: [col('Code', 'Código', { width: '90px', mono: true }), col('Name', 'Nombre')],
}),
currency: {
title: 'Monedas',
resource: 'Currencies',
orderby: 'Code',
nameKey: 'Name',
columns: [col('Code', 'Código', { width: '90px', mono: true }), col('Name', 'Nombre')],
} satisfies VhLookup,
paymentTerms: {
title: 'Condiciones de pago',
resource: 'PaymentTermsTypes',
orderby: 'GroupNumber',
nameKey: 'PaymentTermsGroupName',
valueType: 'number',
columns: [col('GroupNumber', 'Código', { width: '90px', mono: true }), col('PaymentTermsGroupName', 'Nombre')],
} satisfies VhLookup,
@@ -32,6 +35,7 @@ export const MASTER_LOOKUPS = {
title: 'Listas de precios',
resource: 'PriceLists',
orderby: 'PriceListNo',
nameKey: 'PriceListName',
valueType: 'number',
columns: [col('PriceListNo', 'Código', { width: '90px', mono: true }), col('PriceListName', 'Nombre')],
} satisfies VhLookup,
@@ -39,6 +43,7 @@ export const MASTER_LOOKUPS = {
title: 'Empleados de ventas',
resource: 'SalesPersons',
orderby: 'SalesEmployeeCode',
nameKey: 'SalesEmployeeName',
valueType: 'number',
baseFilter: `Active eq 'tYES'`,
columns: [col('SalesEmployeeCode', 'Código', { width: '90px', mono: true }), col('SalesEmployeeName', 'Nombre')],
@@ -51,12 +56,14 @@ export const MASTER_LOOKUPS = {
resource: 'BusinessPartners',
orderby: 'CardCode',
baseFilter: `CardType eq 'cSupplier'`,
nameKey: 'CardName',
columns: [col('CardCode', 'Código', { width: '130px', mono: true }), col('CardName', 'Nombre')],
} satisfies VhLookup,
itemGroup: {
title: 'Grupos de artículos',
resource: 'ItemGroups',
orderby: 'Number',
nameKey: 'GroupName',
valueType: 'number',
columns: [col('Number', 'Código', { width: '90px', mono: true }), col('GroupName', 'Nombre')],
} satisfies VhLookup,
+39 -1
View File
@@ -19,6 +19,9 @@ import { TextInput } from './controls';
import { FieldBase } from './field-base';
import { SboField } from './sbo-field';
/** Nombres ya consultados de los códigos de las listas con `nameKey`. */
const NAMES = new Map<string, string>();
/**
* Campo con botón "…" que abre una lista de valores (flecha dorada de SAP).
* Escribir el código a mano también es válido; elegir de la lista lo rellena y emite `picked`.
@@ -56,6 +59,9 @@ import { SboField } from './sbo-field';
>
…
</button>
@if (name()) {
<span class="name" [attr.title]="name()">{{ name() }}</span>
}
</sbo-field>
<sbo-value-help
[open]="listOpen()"
@@ -70,7 +76,10 @@ import { SboField } from './sbo-field';
(closed)="closeList()"
/>
`,
styles: ':host { display: block; }',
styles: `
:host { display: block; }
.name { align-self: center; margin-left: 8px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--quiet); }
`,
})
export class LookupField extends FieldBase {
readonly value = model('');
@@ -96,6 +105,10 @@ export class LookupField extends FieldBase {
private resolved = '';
private readonly box = viewChild.required<TextInput>('box');
/** Nombre de lo elegido, junto al código (`lookup.nameKey`). */
protected readonly name = signal('');
private nameFor = '';
/** El usuario está escribiendo: se muestra lo que escribe y no el texto con que la lista presenta el código guardado. */
private readonly editing = signal(false);
/**
@@ -117,10 +130,30 @@ export class LookupField extends FieldBase {
if (!this.editing()) {
if (codes && v !== '') codes.ensure([v]);
this.resolved = v.trim();
void this.loadName(v.trim());
}
});
}
/** El nombre del código guardado; se pregunta una vez por código (el resultado queda en `NAMES`). */
private async loadName(code: string): Promise<void> {
const lookup = this.lookup();
const nameKey = lookup.nameKey;
this.nameFor = code;
if (!nameKey || !code) return void this.name.set('');
const cacheKey = `${lookup.resource}|${lookup.baseFilter ?? ''}|${code}`;
const cached = NAMES.get(cacheKey);
if (cached !== undefined) return void this.name.set(cached);
try {
const row = await this.injector.get(SlLookupApi).find(lookup, code);
const text = row ? String(row[nameKey] ?? '') : '';
NAMES.set(cacheKey, text);
if (this.nameFor === code) this.name.set(text);
} catch {
if (this.nameFor === code) this.name.set('');
}
}
protected typing(text: string): void {
this.editing.set(true);
this.value.set(text);
@@ -145,6 +178,11 @@ export class LookupField extends FieldBase {
const key = this.lookup().valueKey ?? this.lookup().columns[0]?.key ?? '';
this.missing.set(null);
this.lookup().codes?.remember(row);
const nameKey = this.lookup().nameKey;
if (nameKey) {
this.nameFor = String(row[this.lookup().valueKey ?? this.lookup().columns[0]?.key ?? ''] ?? '');
this.name.set(String(row[nameKey] ?? ''));
}
this.editing.set(false);
this.value.set(String(row[key] ?? ''));
this.resolved = this.value();
@@ -24,6 +24,8 @@ export interface VhLookup {
rows?: readonly VhRow[];
/** Otros campos por los que se reconoce un código escrito a mano (`FormatCode` de una cuenta: el usuario no conoce el `_SYS…` interno). */
alsoMatch?: readonly string[];
/** Columna con el nombre de lo elegido: el campo lo muestra junto al código (`Name` de un grupo, `SalesEmployeeName`). */
nameKey?: string;
/** Cómo se muestra el código guardado en una celda (la cuenta con su formato) y cómo se aprenden los de las filas elegidas. */
codes?: CodeDisplay;
}