diff --git a/apps/web/src/app/features/documents/document-screens.spec.ts b/apps/web/src/app/features/documents/document-screens.spec.ts index c085234..c69663f 100644 --- a/apps/web/src/app/features/documents/document-screens.spec.ts +++ b/apps/web/src/app/features/documents/document-screens.spec.ts @@ -125,20 +125,23 @@ describe('facturas, boletas y sus reservas', () => { const by = (p: string) => DOCUMENT_SCREENS.find((s) => s.path === p)!; const INVOICES = ['/ventas/facturas', '/ventas/boletas', '/ventas/facturas-reserva', '/ventas/boletas-reserva']; - it('las cuatro comparten el recurso Invoices y se separan por ReserveInvoice y DocumentSubType', () => { + it('las cuatro comparten el recurso Invoices y se separan por ReserveInvoice y el subtipo exacto', () => { for (const p of INVOICES) expect(by(p).resource, p).toBe('Invoices'); - // la factura solo excluye las boletas (`ne`): no pierde notas de débito ni otros subtipos - expect(by('/ventas/facturas').baseFilter).toBe(`ReserveInvoice eq 'tNO' and DocumentSubType ne 'bod_Bill'`); + expect(by('/ventas/facturas').baseFilter).toBe(`ReserveInvoice eq 'tNO' and DocumentSubType eq 'bod_None'`); expect(by('/ventas/boletas').baseFilter).toBe(`ReserveInvoice eq 'tNO' and DocumentSubType eq 'bod_Bill'`); - expect(by('/ventas/facturas-reserva').baseFilter).toBe(`ReserveInvoice eq 'tYES' and DocumentSubType ne 'bod_Bill'`); + expect(by('/ventas/facturas-reserva').baseFilter).toBe(`ReserveInvoice eq 'tYES' and DocumentSubType eq 'bod_None'`); expect(by('/ventas/boletas-reserva').baseFilter).toBe(`ReserveInvoice eq 'tYES' and DocumentSubType eq 'bod_Bill'`); }); - it('cada una se crea con su marca y una factura normal no envía nada especial', () => { - const created = (p: string) => by(p).layout.beforeCreate?.({ CardCode: 'C1' }); - expect(created('/ventas/facturas')).toBeUndefined(); + it('ninguna usa «distinto de»: los demás subtipos de SAP no se mezclan en facturas ni boletas', () => { + for (const p of INVOICES) expect(by(p).baseFilter, p).not.toContain(' ne '); + }); + + it('cada una se crea con su subtipo exacto (y con ReserveInvoice si es de reserva)', () => { + const created = (p: string) => by(p).layout.beforeCreate!({ CardCode: 'C1' }); + expect(created('/ventas/facturas')).toEqual({ CardCode: 'C1', DocumentSubType: 'bod_None' }); expect(created('/ventas/boletas')).toEqual({ CardCode: 'C1', DocumentSubType: 'bod_Bill' }); - expect(created('/ventas/facturas-reserva')).toEqual({ CardCode: 'C1', ReserveInvoice: 'tYES' }); + expect(created('/ventas/facturas-reserva')).toEqual({ CardCode: 'C1', ReserveInvoice: 'tYES', DocumentSubType: 'bod_None' }); expect(created('/ventas/boletas-reserva')).toEqual({ CardCode: 'C1', ReserveInvoice: 'tYES', DocumentSubType: 'bod_Bill' }); }); diff --git a/apps/web/src/app/features/documents/ventas/ventas.screens.ts b/apps/web/src/app/features/documents/ventas/ventas.screens.ts index 0ebb512..9b7c88a 100644 --- a/apps/web/src/app/features/documents/ventas/ventas.screens.ts +++ b/apps/web/src/app/features/documents/ventas/ventas.screens.ts @@ -1,10 +1,15 @@ import { TAX_DOCUMENT, type DocumentScreen, invoiceColumns, marketing, referenceColumns } from '../screen-kit'; -/** Filtros que separan las cuatro pantallas de `Invoices`. */ +/** + * Filtros que separan las cuatro pantallas de `Invoices`: `ReserveInvoice` (reserva sí/no) y el subtipo + * exacto de `DocumentSubType` (`bod_None` = factura, `bod_Bill` = boleta). Los demás subtipos de SAP + * (`bod_InvoiceExempt`, `bod_DebitMemo`, `bod_ExemptBill`, `bod_ExportInvoice`…) no se mezclan aquí: + * tendrán su propia pantalla si se necesitan. + */ const RESERVE = `ReserveInvoice eq 'tYES'`; const NOT_RESERVE = `ReserveInvoice eq 'tNO'`; +const INVOICE = `DocumentSubType eq 'bod_None'`; const BILL = `DocumentSubType eq 'bod_Bill'`; -const NOT_BILL = `DocumentSubType ne 'bod_Bill'`; /** Ventas: ofertas, órdenes, entregas, facturas, devoluciones y notas de crédito de cliente. */ export const VENTAS_SCREENS: readonly DocumentScreen[] = [ @@ -13,13 +18,13 @@ export const VENTAS_SCREENS: readonly DocumentScreen[] = [ marketing('/ventas/ofertas', 'Quotations', 'Nueva oferta', 'Cliente', { columns: referenceColumns }), marketing('/ventas/ordenes', 'Orders', 'Nueva orden', 'Cliente', { columns: referenceColumns }), marketing('/ventas/entrega', 'DeliveryNotes', 'Nueva entrega', 'Cliente', TAX_DOCUMENT), - // Facturas, boletas y sus reservas son el mismo recurso (`Invoices`); se separan por dos campos: - // `DocumentSubType` (`bod_Bill` = boleta) y `ReserveInvoice` (`tYES` = de reserva). La factura excluye - // solo las boletas (`ne`, no `eq bod_None`, para no perder notas de débito u otros subtipos). + // Facturas, boletas y sus reservas son el mismo recurso (`Invoices`); cada pantalla filtra por su + // `DocumentSubType` exacto y por `ReserveInvoice`, y envía ambos al crear. marketing('/ventas/facturas', 'Invoices', 'Nueva factura', 'Cliente', { ...TAX_DOCUMENT, columns: invoiceColumns, - baseFilter: `${NOT_RESERVE} and ${NOT_BILL}`, + baseFilter: `${NOT_RESERVE} and ${INVOICE}`, + fixed: { DocumentSubType: 'bod_None' }, }), marketing('/ventas/boletas', 'Invoices', 'Nueva boleta', 'Cliente', { ...TAX_DOCUMENT, @@ -30,8 +35,8 @@ export const VENTAS_SCREENS: readonly DocumentScreen[] = [ marketing('/ventas/facturas-reserva', 'Invoices', 'Nueva factura de reserva', 'Cliente', { ...TAX_DOCUMENT, columns: invoiceColumns, - baseFilter: `${RESERVE} and ${NOT_BILL}`, - fixed: { ReserveInvoice: 'tYES' }, + baseFilter: `${RESERVE} and ${INVOICE}`, + fixed: { ReserveInvoice: 'tYES', DocumentSubType: 'bod_None' }, }), marketing('/ventas/boletas-reserva', 'Invoices', 'Nueva boleta de reserva', 'Cliente', { ...TAX_DOCUMENT,