Uecko_ERP/docs/prompt-customer-invoices.md

94 lines
5.3 KiB
Markdown

📌 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<T, E>` 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<Result<T, Error>>`).