From fdc042ddcd946e10f34d48ffa01bd8240c4b2c32 Mon Sep 17 00:00:00 2001 From: George Date: Fri, 16 Oct 2026 12:18:09 -0500 Subject: [PATCH] feat(web): fecha del documento, referencia 2 y comentarios del asiento en los movimientos de inventario Co-Authored-By: Claude Sonnet 5.5 --- .../documents/document-analytics.spec.ts | 27 +++++++++++++++++++ .../features/documents/document-form.page.ts | 2 +- .../features/documents/document-layouts.ts | 6 +++++ .../inventario/inventario.layouts.ts | 10 +++++-- 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/apps/web/src/app/features/documents/document-analytics.spec.ts b/apps/web/src/app/features/documents/document-analytics.spec.ts index 13905dc..ee4dbb1 100644 --- a/apps/web/src/app/features/documents/document-analytics.spec.ts +++ b/apps/web/src/app/features/documents/document-analytics.spec.ts @@ -284,3 +284,30 @@ describe('el indicador de la cabecera se elige de su ventana modal', () => { expect(fixture.componentInstance['header']()['Indicator']).toBe('39'); }); }); + +describe('cabecera de los movimientos de inventario', () => { + const by = (path: string) => DOCUMENT_SCREENS.find((s) => s.path === path)!.layout; + + it('las entradas y salidas llevan fecha del documento, referencia 2 y comentarios del asiento', () => { + for (const p of ['/inventario/entradas', '/inventario/salidas']) { + expect(headerKeysOf(by(p)), p).toEqual(expect.arrayContaining(['DocDate', 'TaxDate', 'Reference2', 'JournalMemo', 'Series', 'Indicator', 'Project'])); + expect(headerKeysOf(by(p)), p).not.toContain('DueDate'); + } + }); + + it('las transferencias y solicitudes de traslado suman la fecha de vencimiento', () => { + for (const p of ['/inventario/transferencias', '/inventario/solicitudes-traslado']) { + expect(headerKeysOf(by(p)), p).toEqual(expect.arrayContaining(['FromWarehouse', 'ToWarehouse', 'TaxDate', 'DueDate', 'Reference2', 'JournalMemo'])); + } + }); + + it('Reference1 no se edita: lo asigna SAP', () => { + for (const s of DOCUMENT_SCREENS) expect(headerKeysOf(s.layout), s.path).not.toContain('Reference1'); + }); + + it('las fechas se leen y se envían como AAAA-MM-DD', () => { + // el formulario normaliza `2026-10-16T00:00:00Z` (TaxDate / DueDate) igual que las demás fechas + const keys = headerKeysOf(by('/inventario/transferencias')); + expect(keys).toEqual(expect.arrayContaining(['TaxDate', 'DueDate'])); + }); +}); diff --git a/apps/web/src/app/features/documents/document-form.page.ts b/apps/web/src/app/features/documents/document-form.page.ts index fd312bb..764998a 100644 --- a/apps/web/src/app/features/documents/document-form.page.ts +++ b/apps/web/src/app/features/documents/document-form.page.ts @@ -35,7 +35,7 @@ import { OBJECT_TYPES } from './document-objects'; import { ITEMS_MULTI_ADD } from './line-columns'; const today = (): string => new Date().toISOString().slice(0, 10); -const DATE_KEYS = new Set(['DocDate', 'DocDueDate', 'RequriedDate']); +const DATE_KEYS = new Set(['DocDate', 'DocDueDate', 'RequriedDate', 'TaxDate', 'DueDate']); /** SAP devuelve las fechas como `2026-01-05T00:00:00Z`; el campo de fecha y el guardado usan `2026-01-05`. */ const dateOnly = (v: unknown): string => (typeof v === 'string' ? v.slice(0, 10) : ''); const pickHeader = (doc: DocRecord | undefined, keys: readonly string[], blank: DocRecord): DocRecord => { diff --git a/apps/web/src/app/features/documents/document-layouts.ts b/apps/web/src/app/features/documents/document-layouts.ts index ab36e83..3daa598 100644 --- a/apps/web/src/app/features/documents/document-layouts.ts +++ b/apps/web/src/app/features/documents/document-layouts.ts @@ -95,6 +95,12 @@ export const FIELDS = { docNum: { type: 'computed', label: 'Número', source: 'docNum' }, /** Número del documento con su serie. */ docNumber: { type: 'series', key: 'Series', label: 'Número' }, + /** Fecha del documento (`TaxDate`), distinta de la de contabilización. */ + taxDate: { type: 'date', key: 'TaxDate', label: 'Fecha del documento' }, + dueDate: { type: 'date', key: 'DueDate', label: 'Fecha de vencimiento' }, + reference2: { type: 'text', key: 'Reference2', label: 'Referencia 2' }, + /** Comentarios del asiento contable que genera el movimiento (`JournalMemo`). */ + journalMemo: { type: 'text', key: 'JournalMemo', label: 'Comentarios del asiento' }, indicator: { type: 'lookup', key: 'Indicator', label: 'Indicador', lookup: INDICATOR_LOOKUP }, project: { type: 'lookup', key: 'Project', label: 'Proyecto', lookup: PROJECT_LOOKUP }, docDate: { type: 'date', key: 'DocDate', label: 'Fecha de contabilización', required: true, missing: 'la fecha de contabilización' }, diff --git a/apps/web/src/app/features/documents/inventario/inventario.layouts.ts b/apps/web/src/app/features/documents/inventario/inventario.layouts.ts index cc4a245..d80fd15 100644 --- a/apps/web/src/app/features/documents/inventario/inventario.layouts.ts +++ b/apps/web/src/app/features/documents/inventario/inventario.layouts.ts @@ -17,7 +17,10 @@ import { ANALYTIC_COLUMNS, lineFieldsOf } from '../line-columns'; const goodsColumns: readonly GridColumn[] = [itemColumn, descriptionColumn, quantityColumn, { ...warehouseColumn, required: true }, priceColumn, ...ANALYTIC_COLUMNS]; export const goodsLayout: DocumentLayout = { lines: { key: 'DocumentLines', fields: [...lineFieldsOf(goodsColumns), 'UoMEntry'], base: false }, - header: { left: [FIELDS.docDate, FIELDS.indicator, FIELDS.project], right: [FIELDS.docNumber] }, + header: { + left: [FIELDS.docDate, FIELDS.taxDate, FIELDS.indicator, FIELDS.project], + right: [FIELDS.docNumber, FIELDS.reference2, FIELDS.journalMemo], + }, footer: commentsOnly, columns: goodsColumns, newHeader: () => ({ DocDate: today() }), @@ -44,7 +47,10 @@ const transfer = (immutable: boolean): DocumentLayout => { ]; return { lines: { key: 'StockTransferLines', fields: [...lineFieldsOf(columns), 'UoMEntry'], base: false }, - header: { left: [FIELDS.fromWarehouse, FIELDS.toWarehouse, FIELDS.indicator, FIELDS.project], right: [FIELDS.docNumber, FIELDS.docDate] }, + header: { + left: [FIELDS.fromWarehouse, FIELDS.toWarehouse, FIELDS.indicator, FIELDS.project], + right: [FIELDS.docNumber, FIELDS.docDate, FIELDS.taxDate, FIELDS.dueDate, FIELDS.reference2, FIELDS.journalMemo], + }, footer: commentsOnly, columns, newHeader: () => ({ DocDate: today() }),