📌 CONTEXTO DEL PROYECTO: Estoy desarrollando una API en **Node.js** con **TypeScript**, **Express.js**, **Sequelize**, y **Arquitectura Hexagonal (Ports & Adapters)** bajo los principios de **DDD (Domain-Driven Design)** y **SOLID**. Este módulo es para **facturas de cliente (Customer Invoices)** y debe cumplir con los estándares definidos previamente para el contexto de autenticación, adaptados a los datos, reglas y operaciones de las facturas. 📌 PRINCIPIOS Y PATRONES A APLICAR: ✅ **DDD (Domain-Driven Design)** - Las **facturas** serán agregados raíz (`CustomerInvoice`) con propiedades como `id`, `customerId`, `invoiceNumber`, `date`, `lines`, `totals`, etc. - Las **líneas de factura** (`InvoiceLine`) se modelan como entidades o value objects dentro del agregado. - Se usará un `Mapper` para convertir entre dominio y persistencia. - Repositorios (`ICustomerInvoiceRepository`) solo manejan agregados. - Operaciones como `createInvoice`, `updateInvoice`, `getInvoiceById` serán gestionadas en `CustomerInvoiceApplicationService`. ✅ **SOLID** - Usar SRP: cada clase con una responsabilidad clara. - Usar interfaces como `ICustomerInvoiceRepository`, `ITransactionManager`, `IInvoicePresenter`. - Evitar acoplamientos entre capa de aplicación y capa de infraestructura. - Controladores deben transformar los datos en DTOs antes de enviarlos. 📌 ESTRUCTURA DE DATOS: La entidad `CustomerInvoice` tendrá: - `id`: UUID (ValueObject `UniqueID`) - `status`: string (ValueObject) (`Draft`, `Issued`, `Sent`, `Rejected`) - `invoiceNumber`: string (ValueObject ) - `invoiceSeries`: string (ValueObject ) - `customerId`: UUID (ValueObject) - `issueDate`: UtcDate (ValueObject) - `operationDate`: UtcDate (ValueObject) - `lines`: array de `InvoiceLine`, cada una con: - `productId`: (Optional) UUID (ValueObject `UniqueID`) - `description`: string (ValueObject) - `quantity`: Amount (number) and scale (number) (ValueObject Quantity) - `unitPrice`: Amount (number), scale (number) and currency (string) (ValueObject MoneyValue) - `totalLineAmount`: Amount (number), scale (number) and currency (string) (ValueObject MoneyValue) - `subtotalPrice`: Amount (number), scale (number) and currency (string) (ValueObject MoneyValue) - `discount`: Amount (number) and scale (number) (ValueObject Percentage) - `tax`: Amount (number) and scale (number) (ValueObject Percentage) - `totalAmount`: Amount (number), scale (number) and currency (string) (ValueObject MoneyValue) 📌 OPERACIONES PRINCIPALES: - `createInvoice(data: CreateCustomerInvoiceDTO)` - `getInvoiceById(id: string)` - `updateInvoice(id: string, changes: UpdateCustomerInvoiceDTO)` - `listInvoices(filter?)` - `deleteInvoice(id: string)` - `markAsPaid(id: string)` 📌 VALIDACIONES: ✅ Usar `Zod` para validaciones en Value Objects (`InvoiceNumber`, `InvoiceDate`, `InvoiceLine`). ✅ No se deben lanzar excepciones para errores de validación. Usar `Result` como en autenticación. 📌 PRESENTACIÓN: ✅ Los controladores convierten el agregado `CustomerInvoice` a `CustomerInvoiceDTO`. ✅ Se usan `Presenters` (`CustomerInvoicePresenter`) para construir los DTOs. ✅ DTOs solo exponen campos necesarios: nada sensible, nada interno. ✅ Se puede extender con `CsvInvoicePresenter`, `PdfInvoicePresenter`, etc. 📌 AUTORIZACIÓN Y ACCESO: ✅ Se protegerán rutas con middleware JWT (`authenticateJWT`). ✅ Se validará que el usuario autenticado pueda acceder/modificar la factura (p. ej. pertenece a su empresa). 📌 PERSISTENCIA: ✅ `SequelizeCustomerInvoiceRepository` no accede directamente al modelo de Sequelize, lo hace a través de `Mapper`. ✅ La clase `CustomerInvoiceMapper` mapea de/agregado <-> persistencia. ✅ Soporta transacciones Sequelize (`TransactionManager.complete(...)`). ✅ Los nombres de los campos y las tablas en la base de datos seguirán la notación "snake_case". ✅ Los nombres de los campos en los modelos Sequelize seguirán la notación "snake_case". ✅ Los modelos Sequelize de los agregados tienen campos 'timestamp' con los nombres "created_at", "updated_at" y "deleted_at". 📌 ERRORES: ✅ Usar `ApiError` para errores en la API. ✅ Los repositorios deben capturar errores de Sequelize (`UniqueConstraintError`, etc.) y convertirlos a errores de dominio con mensajes claros y específicos (mediante `errorMapper`). 📌 TESTING: ✅ Los servicios (`CustomerInvoiceApplicationService`) serán testeados con mocks de repositorio. ✅ Las rutas serán testeadas con `supertest`. ✅ Las validaciones de ValueObjects tendrán pruebas unitarias. 📌 NOMENCLATURA: - Agregado: `CustomerInvoice` - Línea: `CustomerInvoiceLine` - DTOs: `CustomerInvoiceDTO`, `InvoiceLineDTO` - Presentadores: `CustomerInvoicePresenter` - Repositorio: `ICustomerInvoiceRepository`, `SequelizeCustomerInvoiceRepository` - ValueObjects: `CustomerInvoiceNumber`, `CustomerInvoiceDate`, `CustomerInvoiceTotal`, `CustomerInvoiceItemQuantity`, etc. ⚠️ IMPORTANTE: - NO incluir `passwords`, `tokens`, o datos sensibles en respuestas. - NO usar Sequelize directamente en servicios ni controladores. - NO devolver el agregado como respuesta bruta. Usar DTOs. - TODO debe estar tipado, incluso los métodos de los servicios (`Promise>`).