diff --git a/apps/web/src/app/features/masters/master-list.page.ts b/apps/web/src/app/features/masters/master-list.page.ts index a1cbc67..1848e25 100644 --- a/apps/web/src/app/features/masters/master-list.page.ts +++ b/apps/web/src/app/features/masters/master-list.page.ts @@ -1,7 +1,9 @@ -import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; +import { HttpClient, HttpParams } from '@angular/common/http'; +import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; +import { API_URL } from '../../core/api'; import { ListView } from '../../shared/list/list-view'; -import type { ListRow } from '../../shared/list/list.types'; +import type { ListColumn, ListRow } from '../../shared/list/list.types'; import type { MasterScreen } from './master-types'; /** Lista de un maestro (clientes, proveedores, artículos); abre uno o crea uno nuevo. */ @@ -13,7 +15,7 @@ import type { MasterScreen } from './master-types'; >>({}); + + /** Las columnas de la pantalla; las de un catálogo muestran `código · nombre` apenas llega el catálogo (una sola consulta). */ + protected readonly columns: readonly ListColumn[] = this.screen.columns.map((c) => { + if (!this.screen.listNames?.some((n) => n.key === c.key)) return c; + return { + ...c, + format: (r: ListRow) => { + const code = r[c.key]; + if (code === null || code === undefined || code === '') return ''; + const name = this.names()[c.key]?.get(String(code)); + return name ? `${code} · ${name}` : String(code); + }, + }; + }); + + constructor() { + for (const n of this.screen.listNames ?? []) { + const params = new HttpParams().set('$select', `${n.valueField},${n.labelField}`).set('$top', 500); + this.http.get<{ value?: Record[] }>(`${API_URL}/sl/${n.resource}`, { params }).subscribe({ + next: (res) => this.names.update((m) => ({ ...m, [n.key]: new Map((res.value ?? []).map((x) => [String(x[n.valueField]), String(x[n.labelField] ?? '')])) })), + error: () => undefined, // sin nombres se ve el código + }); + } + } protected open(row: ListRow): void { void this.router.navigate([String(row[this.screen.keyField])], { relativeTo: this.route }); diff --git a/apps/web/src/app/features/masters/master-types.ts b/apps/web/src/app/features/masters/master-types.ts index 093cecf..43c7a6f 100644 --- a/apps/web/src/app/features/masters/master-types.ts +++ b/apps/web/src/app/features/masters/master-types.ts @@ -71,6 +71,8 @@ export interface MasterScreen { createLabel: string; columns: readonly ListColumn[]; extraFields?: readonly string[]; + /** Columnas de la lista cuyo valor es un código de otro catálogo: se muestra `código · nombre` (`GroupCode` → `BusinessPartnerGroups`). */ + listNames?: readonly { key: string; resource: string; valueField: string; labelField: string }[]; filters: readonly ListFilter[]; orderby: string; /** Filtro fijo de la lista y de la navegación (ej. solo los clientes). */ diff --git a/apps/web/src/app/features/masters/socios-negocio/socios.screens.ts b/apps/web/src/app/features/masters/socios-negocio/socios.screens.ts index c194807..ccaba8a 100644 --- a/apps/web/src/app/features/masters/socios-negocio/socios.screens.ts +++ b/apps/web/src/app/features/masters/socios-negocio/socios.screens.ts @@ -40,10 +40,12 @@ const partner = (opts: { path: string; type: 'cCustomer' | 'cSupplier'; singular orderby: 'CardCode', baseFilter: `CardType eq '${opts.type}'`, extraFields: ['Frozen'], + listNames: [{ key: 'GroupCode', resource: 'BusinessPartnerGroups', valueField: 'Code', labelField: 'Name' }], columns: [ { key: 'CardCode', title: 'Código', width: '130px', mono: true, searchable: true }, { key: 'CardName', title: 'Nombre', searchable: true }, { key: 'FederalTaxID', title: 'RUT', width: '120px', mono: true, searchable: true }, + { key: 'GroupCode', title: 'Grupo', type: 'number', align: 'left', width: '170px' }, { key: 'Phone1', title: 'Teléfono', width: '130px', searchable: true }, { key: 'EmailAddress', title: 'Correo electrónico', searchable: true }, statusColumn,