diff --git a/apps/web/src/app/features/documents/line-columns.ts b/apps/web/src/app/features/documents/line-columns.ts index aa41508..5d8ff82 100644 --- a/apps/web/src/app/features/documents/line-columns.ts +++ b/apps/web/src/app/features/documents/line-columns.ts @@ -49,6 +49,7 @@ export const DOCUMENT_LINE_COLUMNS: readonly GridColumn[] = [ { key: 'ItemName', title: 'Descripción' }, ], }, + multiple: true, apply: (item, line) => ({ ...line, ItemCode: item['ItemCode'], ItemDescription: item['ItemName'] ?? line['ItemDescription'] }), }, }, diff --git a/apps/web/src/app/shared/grid/grid.types.ts b/apps/web/src/app/shared/grid/grid.types.ts index 0b21d7d..7b6eac6 100644 --- a/apps/web/src/app/shared/grid/grid.types.ts +++ b/apps/web/src/app/shared/grid/grid.types.ts @@ -8,6 +8,8 @@ export type GridLine = Record; export interface GridLookup { config: VhLookup; apply: (picked: ListRow, line: GridLine) => GridLine; + /** Permite marcar varias filas: la primera completa la línea actual y cada una de las demás crea una línea nueva. */ + multiple?: boolean; } export interface GridColumn { diff --git a/apps/web/src/app/shared/grid/lines-grid.html b/apps/web/src/app/shared/grid/lines-grid.html index e7bd051..7a6c140 100644 --- a/apps/web/src/app/shared/grid/lines-grid.html +++ b/apps/web/src/app/shared/grid/lines-grid.html @@ -92,6 +92,7 @@ [baseFilter]="cfg.baseFilter" [orderby]="cfg.orderby" [rowKey]="cfg.valueKey" + [selection]="lookupMultiple() ? 'multiple' : 'single'" (selected)="lookupPicked($event)" (closed)="lookupClosed()" /> diff --git a/apps/web/src/app/shared/grid/lines-grid.spec.ts b/apps/web/src/app/shared/grid/lines-grid.spec.ts index f900679..fbaadce 100644 --- a/apps/web/src/app/shared/grid/lines-grid.spec.ts +++ b/apps/web/src/app/shared/grid/lines-grid.spec.ts @@ -218,11 +218,34 @@ describe('LinesGrid', () => { await tick(); (q('.dlg tbody tr') as HTMLElement).click(); await tick(); + (q('.dlg footer .btn.main') as HTMLElement).click(); + await tick(); expect(lines()[0]).toMatchObject({ ItemCode: 'I00002', ItemDescription: 'DVD+R Disc 50-Pack', Quantity: 2, Price: 50, LineTotal: 100 }); expect(el.querySelector('.dlg')).toBeNull(); expect(document.activeElement).toBe(cell(0, 0)); }); + it('varios artículos: el primero completa la línea y los demás se insertan debajo', async () => { + fixture.componentInstance.lines.set([line('A', 2, 50), line('Z', 1, 10)]); + await tick(); + (qa('.pick button')[0] as HTMLButtonElement).click(); + await tick(); + ctrl.expectOne((r) => r.url === '/api/sl/Items').flush({ + value: [ + { ItemCode: 'I1', ItemName: 'Uno' }, + { ItemCode: 'I2', ItemName: 'Dos' }, + ], + 'odata.count': '2', + }); + await tick(); + qa('.dlg tbody tr').forEach((r) => (r as HTMLElement).click()); + await tick(); + (q('.dlg footer .btn.main') as HTMLElement).click(); + await tick(); + expect(lines().map((l) => l['ItemCode'])).toEqual(['I1', 'I2', 'Z']); + expect(lines()[0]).toMatchObject({ Quantity: 2, Price: 50 }); + }); + it('F4 abre la lista de la celda; una celda sin lista no', async () => { await key(0, 3, 'F4'); // almacén ctrl.expectOne((r) => r.url === '/api/sl/Warehouses').flush({ value: [], 'odata.count': '0' }); diff --git a/apps/web/src/app/shared/grid/lines-grid.ts b/apps/web/src/app/shared/grid/lines-grid.ts index 4207955..330d239 100644 --- a/apps/web/src/app/shared/grid/lines-grid.ts +++ b/apps/web/src/app/shared/grid/lines-grid.ts @@ -55,6 +55,7 @@ export class LinesGrid { protected readonly lookupTarget = signal(null); protected readonly multiOpen = signal(false); protected readonly lookup = computed(() => this.lookupTarget()?.column.lookup?.config); + protected readonly lookupMultiple = computed(() => !!this.lookupTarget()?.column.lookup?.multiple); protected cellText(line: GridLine, column: GridColumn): string { if (column.format) return column.format(line); @@ -216,7 +217,15 @@ export class LinesGrid { const picked = rows[0]; const line = target ? this.lines()[target.row] : undefined; if (!target || !picked || !line || !target.column.lookup) return; - this.replace(target.row, target.column.lookup.apply(picked, line), target.column.key); + const lookup = target.column.lookup; + this.replace(target.row, lookup.apply(picked, line), target.column.key); + const rest = rows.slice(1).map((r) => { + const added = lookup.apply(r, this.newLine()()); + return this.recalc()?.(added, target.column.key) ?? added; + }); + if (rest.length) { + this.lines.update((ls) => [...ls.slice(0, target.row + 1), ...rest, ...ls.slice(target.row + 1)]); + } } protected lookupClosed(): void {