feat(web): columna «Nombre de la cuenta» en las líneas de servicio (solo lectura)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
GeorgeandClaude Sonnet 5.5 committed 2026-10-19 12:36:10 -05:00
1 parent 80a65cbc62
commit 3c1d02a263
3 files changed
+14 -2

No files matched your search

+9 -2
View File
@@ -9,6 +9,8 @@ import { escapeODataString } from './odata';
/** `Code` de la cuenta → su `FormatCode` (el código que conoce el usuario). */ /** `Code` de la cuenta → su `FormatCode` (el código que conoce el usuario). */
const formats = signal<ReadonlyMap<string, string>>(new Map()); const formats = signal<ReadonlyMap<string, string>>(new Map());
/** `Code` de la cuenta → su nombre. */
const names = signal<ReadonlyMap<string, string>>(new Map());
/** Cuántos códigos se piden por consulta. */ /** Cuántos códigos se piden por consulta. */
const BATCH = 20; const BATCH = 20;
@@ -28,10 +30,15 @@ export const ACCOUNT_CODES: CodeDisplay = {
ensure(codes: readonly string[]): void { ensure(codes: readonly string[]): void {
void service?.ensure(codes); void service?.ensure(codes);
}, },
label(code: string): string {
return names().get(code) ?? '';
},
remember(row: VhRow): void { remember(row: VhRow): void {
const code = String(row['Code'] ?? ''); const code = String(row['Code'] ?? '');
const format = String(row['FormatCode'] ?? '').trim(); const format = String(row['FormatCode'] ?? '').trim();
const name = String(row['Name'] ?? '').trim();
if (code && format && formats().get(code) !== format) formats.update((m) => new Map(m).set(code, format)); if (code && format && formats().get(code) !== format) formats.update((m) => new Map(m).set(code, format));
if (code && name && names().get(code) !== name) names.update((m) => new Map(m).set(code, name));
}, },
}; };
@@ -46,12 +53,12 @@ export class AccountCodesService {
} }
async ensure(codes: readonly string[]): Promise<void> { async ensure(codes: readonly string[]): Promise<void> {
const missing = [...new Set(codes.filter((c) => c && !formats().has(c) && !this.asked.has(c)))]; const missing = [...new Set(codes.filter((c) => c && !(formats().has(c) && names().has(c)) && !this.asked.has(c)))];
for (const c of missing) this.asked.add(c); for (const c of missing) this.asked.add(c);
for (let i = 0; i < missing.length; i += BATCH) { for (let i = 0; i < missing.length; i += BATCH) {
const filter = missing.slice(i, i + BATCH).map((c) => `Code eq '${escapeODataString(c)}'`).join(' or '); const filter = missing.slice(i, i + BATCH).map((c) => `Code eq '${escapeODataString(c)}'`).join(' or ');
try { try {
const params = new HttpParams().set('$select', 'Code,FormatCode').set('$filter', filter); const params = new HttpParams().set('$select', 'Code,FormatCode,Name').set('$filter', filter);
const res = await firstValueFrom(this.http.get<SlListResponse<VhRow>>(`${API_URL}/sl/ChartOfAccounts`, { params })); const res = await firstValueFrom(this.http.get<SlListResponse<VhRow>>(`${API_URL}/sl/ChartOfAccounts`, { params }));
for (const row of res.value) ACCOUNT_CODES.remember(row); for (const row of res.value) ACCOUNT_CODES.remember(row);
} catch { } catch {
@@ -1,4 +1,5 @@
import type { GridColumn, GridLine, GridMultiAdd } from '../../shared/grid/grid.types'; import type { GridColumn, GridLine, GridMultiAdd } from '../../shared/grid/grid.types';
import { ACCOUNT_CODES } from '../../core/sl/account-codes';
import { ACCOUNT_LOOKUP, PROJECT_LOOKUP, dimensionLookup } from './dimension-lookups'; import { ACCOUNT_LOOKUP, PROJECT_LOOKUP, dimensionLookup } from './dimension-lookups';
import { hasBaseRef, objectLabel } from './document-objects'; import { hasBaseRef, objectLabel } from './document-objects';
@@ -227,6 +228,8 @@ export const serviceLineColumns = (taxResource = 'SalesTaxCodes'): readonly Grid
}), }),
}, },
}, },
// el nombre de la cuenta (SAP lo muestra aunque la línea no tenga descripción propia): solo se ve, no se guarda
{ key: '_AccountName', title: 'Nombre de la cuenta', width: '230px', format: (l) => ACCOUNT_CODES.label?.(String(l['AccountCode'] ?? '')) ?? '' },
{ ...LINE_COLUMNS.description, width: '260px' }, { ...LINE_COLUMNS.description, width: '260px' },
LINE_COLUMNS.tax, LINE_COLUMNS.tax,
{ ...LINE_COLUMNS.total, readonly: false, required: true }, { ...LINE_COLUMNS.total, readonly: false, required: true },
@@ -30,4 +30,6 @@ export interface CodeDisplay {
ensure(codes: readonly string[]): void; ensure(codes: readonly string[]): void;
/** Aprende el texto de una fila elegida o encontrada. */ /** Aprende el texto de una fila elegida o encontrada. */
remember(row: VhRow): void; remember(row: VhRow): void;
/** Nombre de lo que identifica el código (el de la cuenta), si ya se conoce. */
label?(code: string): string;
} }