From 7bf24c8f916e2b2e12f101a7d81e998ff78a60de Mon Sep 17 00:00:00 2001 From: david Date: Wed, 11 Jun 2025 17:13:44 +0200 Subject: [PATCH] Facturas de cliente --- apps/server/package.json | 2 +- apps/server/src/index.ts | 1 - apps/server/src/register-modules.ts | 2 +- apps/web/package.json | 2 +- apps/web/src/app.tsx | 2 +- apps/web/src/register-modules.tsx | 4 +- modules/auth/src/web/services/auth-service.ts | 5 +- .../package.json | 3 +- .../create-customer-invoice.use-case.ts | 147 +++++++ .../delete-customer-invoice.use-case.ts} | 10 +- .../get-customer-invoice.use-case.ts} | 10 +- .../src/api/application/index.ts | 5 + .../list-customer-invoices.use-case.ts} | 10 +- .../src/api/application/services/index.ts | 0 .../services/participantAddressFinder.ts | 8 +- .../application/services/participantFinder.ts | 8 +- .../update-customer-invoice.use-case.ts | 401 ++++++++++++++++++ .../domain/aggregates/customer-invoice.ts} | 84 ++-- .../src/api/domain/aggregates/index.ts | 1 + .../src/api/domain/entities/index.ts | 2 + .../domain/entities/invoice-customer/index.ts | 2 + .../invoice-customer/invoice-address.ts | 32 +- .../invoice-customer/invoice-customer.ts | 28 +- .../domain/entities/invoice-items/index.ts | 2 + .../invoice-items/invoice-item.test.ts | 83 ++++ .../entities/invoice-items/invoice-item.ts | 101 +++++ .../entities/invoice-items/invoice-items.ts | 8 + .../src/api/domain/index.ts | 0 .../customer-invoice-repository.interface.ts | 13 + .../src/api/domain/repositories/index.ts | 1 + .../customer-invoice-service.interface.ts | 23 + .../services/customer-invoice.service.ts | 86 ++++ .../src/api/domain/services/index.ts | 2 + .../customer-invoice-address-type.ts} | 8 +- .../customer-invoice-item-description.ts | 50 +++ .../customer-invoice-item-discount.ts | 3 + .../customer-invoice-item-quantity.ts | 3 + .../customer-invoice-item-subtotal-price.ts} | 2 +- .../customer-invoice-item-total-price.ts} | 2 +- .../customer-invoice-item-unit-price.ts} | 2 +- .../value-objects/customer-invoice-number.ts} | 12 +- .../value-objects/customer-invoice-serie.ts} | 18 +- .../value-objects/customer-invoice-status.ts} | 38 +- .../src/api/domain/value-objects/index.ts | 10 + modules/customer-invoices/src/api/index.ts | 26 ++ .../infrastructure/Contact.repository.ts.bak | 0 .../express/customer-invoices.routes.ts} | 28 +- .../src/api/infrastructure/express/index.ts | 1 + .../src/api/infrastructure/index.ts | 0 .../mappers/contact.mapper.ts.bak | 0 .../mappers/contactAddress.mapper.ts.bak | 0 .../mappers/customer-invoice-item.mapper.ts} | 50 +-- .../mappers/customer-invoice.mapper.ts | 97 +++++ ...customer-invoiceParticipant.mapper.ts.bak} | 72 ++-- ...r-invoiceParticipantAddress.mapper.ts.bak} | 42 +- .../src/api/infrastructure/mappers/index.ts | 1 + .../sequelize/contact.mo.del.ts.bak | 0 .../sequelize/contactAddress.mo.del.ts.bak | 0 .../sequelize/customer-invoice-item.model.ts} | 34 +- .../sequelize/customer-invoice.model.ts} | 50 +-- .../sequelize/customer-invoice.repository.ts | 107 +++++ .../customer-invoiceParticipant.mo.del.ts.bak | 106 +++++ ...r-invoiceParticipantAddress.mo.del.ts.bak} | 24 +- .../src/api/infrastructure/sequelize/index.ts | 9 + .../delete-invoice.controller.ts.bak | 12 + .../presentation/delete-invoice/index.ts.bak | 14 + .../get-invoice/get-invoice.controller.ts | 44 ++ .../src/api/presentation/get-invoice/index.ts | 24 ++ .../presenter/InvoiceItem.presenter.ts.bak | 6 +- .../InvoiceParticipant.presenter.ts.bak | 26 ++ ...InvoiceParticipantAddress.presenter.ts.bak | 10 +- .../presenter/get-invoice.presenter.ts | 59 +++ .../get-invoice/presenter/index.ts | 1 + .../src/api/presentation/index.ts | 5 + .../api/presentation/list-invoices/index.ts | 26 ++ .../list-invoices/list-invoices.controller.ts | 38 ++ .../InvoiceParticipant.presenter.ts.bak | 22 + ...InvoiceParticipantAddress.presenter.ts.bak | 6 +- .../list-invoices/presenter/index.ts | 1 + .../presenter/list-invoices.presenter.ts | 54 +++ .../presentation/update-invoice/index.ts.bak | 26 +- .../presenter/InvoiceItem.presenter.ts.bak | 8 +- .../InvoiceParticipant.presenter.ts.bak | 26 ++ ...InvoiceParticipantAddress.presenter.ts.bak | 10 +- .../presenter/UpdateInvoice.presenter.ts.bak | 33 ++ .../update-invoice/presenter/index.ts.bak | 1 + .../update-invoice.controller.ts.bak | 30 +- .../dto/customer-invoices.request.dto.ts} | 10 +- .../dto/customer-invoices.response.dto.ts} | 32 +- .../common/dto/customer-invoices.schemas.ts} | 10 +- .../customer-invoices/src/common/dto/index.ts | 3 + .../src/common/locales/en.json | 26 ++ .../src/common/locales/es.json | 2 +- .../components/customer-invoices-grid.tsx} | 8 +- .../components/customer-invoices-layout.tsx | 6 + .../src/web/components/data.json | 0 .../src/web/components/index.tsx | 2 + .../web/context/customer-invoices-context.tsx | 56 +++ .../src/web/context/index.ts | 1 + .../src/web/customer-invoice-routes.tsx | 58 +++ .../web/hooks/customer-invoices-context.tsx | 11 + .../customer-invoices/src/web/hooks/index.ts | 2 + .../src/web/hooks/use-customer-invoices.bak} | 20 +- .../src/web/hooks/use-customer-invoices.tsx | 20 + .../src/web/invoice-routes.tsx | 6 +- .../src/web/manifest.ts | 10 +- .../src/web/pages/index.tsx | 0 .../src/web/pages/list.tsx | 53 +-- .../tsconfig.json | 2 +- .../application/create-invoice.use-case.ts | 147 ------- modules/invoices/src/api/application/index.ts | 5 - .../application/update-invoice.use-case.ts | 401 ------------------ .../src/api/domain/aggregates/index.ts | 1 - .../invoices/src/api/domain/entities/index.ts | 2 - .../domain/entities/invoice-customer/index.ts | 2 - .../domain/entities/invoice-items/index.ts | 2 - .../invoice-items/invoice-item.test.ts | 83 ---- .../entities/invoice-items/invoice-item.ts | 101 ----- .../entities/invoice-items/invoice-items.ts | 8 - .../src/api/domain/repositories/index.ts | 1 - .../invoice-repository.interface.ts | 13 - .../invoices/src/api/domain/services/index.ts | 2 - .../services/invoice-service.interface.ts | 23 - .../api/domain/services/invoice.service.ts | 86 ---- .../src/api/domain/value-objects/index.ts | 10 - .../value-objects/invoice-item-description.ts | 50 --- .../value-objects/invoice-item-discount.ts | 3 - .../value-objects/invoice-item-quantity.ts | 3 - modules/invoices/src/api/index.ts | 26 -- .../src/api/infrastructure/express/index.ts | 1 - .../src/api/infrastructure/mappers/index.ts | 1 - .../infrastructure/mappers/invoice.mapper.ts | 97 ----- .../src/api/infrastructure/sequelize/index.ts | 9 - .../sequelize/invoice.repository.ts | 107 ----- .../invoiceParticipant.mo.del.ts.bak | 106 ----- .../delete-invoice.controller.ts.bak | 12 - .../presentation/delete-invoice/index.ts.bak | 14 - .../get-invoice/get-invoice.controller.ts | 44 -- .../src/api/presentation/get-invoice/index.ts | 19 - .../InvoiceParticipant.presenter.ts.bak | 26 -- .../presenter/get-invoice.presenter.ts | 59 --- .../get-invoice/presenter/index.ts | 1 - .../invoices/src/api/presentation/index.ts | 5 - .../api/presentation/list-invoices/index.ts | 18 - .../list-invoices/list-invoices.controller.ts | 38 -- .../InvoiceParticipant.presenter.ts.bak | 22 - .../list-invoices/presenter/index.ts | 1 - .../presenter/list-invoices.presenter.ts | 52 --- .../InvoiceParticipant.presenter.ts.bak | 26 -- .../presenter/UpdateInvoice.presenter.ts.bak | 33 -- .../update-invoice/presenter/index.ts.bak | 1 - modules/invoices/src/common/dto/index.ts | 3 - modules/invoices/src/common/locales/en.json | 26 -- modules/invoices/src/web/components/index.tsx | 2 - .../src/web/components/invoices-layout.tsx | 10 - modules/invoices/src/web/context/index.ts | 1 - .../src/web/context/invoices-context.tsx | 21 - modules/invoices/src/web/hooks/index.ts | 2 - .../src/web/hooks/invoices-context.tsx | 11 - packages/typescript-config/root.json | 2 +- pnpm-lock.yaml | 13 +- 161 files changed, 2294 insertions(+), 2161 deletions(-) rename modules/{invoices => customer-invoices}/package.json (92%) create mode 100644 modules/customer-invoices/src/api/application/create-customer-invoice.use-case.ts rename modules/{invoices/src/api/application/delete-invoice.use-case.ts => customer-invoices/src/api/application/delete-customer-invoice.use-case.ts} (56%) rename modules/{invoices/src/api/application/get-invoice.use-case.ts => customer-invoices/src/api/application/get-customer-invoice.use-case.ts} (55%) create mode 100644 modules/customer-invoices/src/api/application/index.ts rename modules/{invoices/src/api/application/list-invoices.use-case.ts => customer-invoices/src/api/application/list-customer-invoices.use-case.ts} (62%) rename modules/{invoices => customer-invoices}/src/api/application/services/index.ts (100%) rename modules/{invoices => customer-invoices}/src/api/application/services/participantAddressFinder.ts (83%) rename modules/{invoices => customer-invoices}/src/api/application/services/participantFinder.ts (62%) create mode 100644 modules/customer-invoices/src/api/application/update-customer-invoice.use-case.ts rename modules/{invoices/src/api/domain/aggregates/invoice.ts => customer-invoices/src/api/domain/aggregates/customer-invoice.ts} (50%) create mode 100644 modules/customer-invoices/src/api/domain/aggregates/index.ts create mode 100644 modules/customer-invoices/src/api/domain/entities/index.ts create mode 100644 modules/customer-invoices/src/api/domain/entities/invoice-customer/index.ts rename modules/{invoices => customer-invoices}/src/api/domain/entities/invoice-customer/invoice-address.ts (52%) rename modules/{invoices => customer-invoices}/src/api/domain/entities/invoice-customer/invoice-customer.ts (51%) create mode 100644 modules/customer-invoices/src/api/domain/entities/invoice-items/index.ts create mode 100644 modules/customer-invoices/src/api/domain/entities/invoice-items/invoice-item.test.ts create mode 100644 modules/customer-invoices/src/api/domain/entities/invoice-items/invoice-item.ts create mode 100644 modules/customer-invoices/src/api/domain/entities/invoice-items/invoice-items.ts rename modules/{invoices => customer-invoices}/src/api/domain/index.ts (100%) create mode 100644 modules/customer-invoices/src/api/domain/repositories/customer-invoice-repository.interface.ts create mode 100644 modules/customer-invoices/src/api/domain/repositories/index.ts create mode 100644 modules/customer-invoices/src/api/domain/services/customer-invoice-service.interface.ts create mode 100644 modules/customer-invoices/src/api/domain/services/customer-invoice.service.ts create mode 100644 modules/customer-invoices/src/api/domain/services/index.ts rename modules/{invoices/src/api/domain/value-objects/invoice-address-type.ts => customer-invoices/src/api/domain/value-objects/customer-invoice-address-type.ts} (69%) create mode 100644 modules/customer-invoices/src/api/domain/value-objects/customer-invoice-item-description.ts create mode 100644 modules/customer-invoices/src/api/domain/value-objects/customer-invoice-item-discount.ts create mode 100644 modules/customer-invoices/src/api/domain/value-objects/customer-invoice-item-quantity.ts rename modules/{invoices/src/api/domain/value-objects/invoice-item-subtotal-price.ts => customer-invoices/src/api/domain/value-objects/customer-invoice-item-subtotal-price.ts} (83%) rename modules/{invoices/src/api/domain/value-objects/invoice-item-total-price.ts => customer-invoices/src/api/domain/value-objects/customer-invoice-item-total-price.ts} (84%) rename modules/{invoices/src/api/domain/value-objects/invoice-item-unit-price.ts => customer-invoices/src/api/domain/value-objects/customer-invoice-item-unit-price.ts} (84%) rename modules/{invoices/src/api/domain/value-objects/invoice-number.ts => customer-invoices/src/api/domain/value-objects/customer-invoice-number.ts} (62%) rename modules/{invoices/src/api/domain/value-objects/invoice-serie.ts => customer-invoices/src/api/domain/value-objects/customer-invoice-serie.ts} (53%) rename modules/{invoices/src/api/domain/value-objects/invoice-status.ts => customer-invoices/src/api/domain/value-objects/customer-invoice-status.ts} (50%) create mode 100644 modules/customer-invoices/src/api/domain/value-objects/index.ts create mode 100644 modules/customer-invoices/src/api/index.ts rename modules/{invoices => customer-invoices}/src/api/infrastructure/Contact.repository.ts.bak (100%) rename modules/{invoices/src/api/infrastructure/express/invoices.routes.ts => customer-invoices/src/api/infrastructure/express/customer-invoices.routes.ts} (53%) create mode 100644 modules/customer-invoices/src/api/infrastructure/express/index.ts rename modules/{invoices => customer-invoices}/src/api/infrastructure/index.ts (100%) rename modules/{invoices => customer-invoices}/src/api/infrastructure/mappers/contact.mapper.ts.bak (100%) rename modules/{invoices => customer-invoices}/src/api/infrastructure/mappers/contactAddress.mapper.ts.bak (100%) rename modules/{invoices/src/api/infrastructure/mappers/invoice-item.mapper.ts => customer-invoices/src/api/infrastructure/mappers/customer-invoice-item.mapper.ts} (66%) create mode 100644 modules/customer-invoices/src/api/infrastructure/mappers/customer-invoice.mapper.ts rename modules/{invoices/src/api/infrastructure/mappers/invoiceParticipant.mapper.ts.bak => customer-invoices/src/api/infrastructure/mappers/customer-invoiceParticipant.mapper.ts.bak} (52%) rename modules/{invoices/src/api/infrastructure/mappers/invoiceParticipantAddress.mapper.ts.bak => customer-invoices/src/api/infrastructure/mappers/customer-invoiceParticipantAddress.mapper.ts.bak} (60%) create mode 100644 modules/customer-invoices/src/api/infrastructure/mappers/index.ts rename modules/{invoices => customer-invoices}/src/api/infrastructure/sequelize/contact.mo.del.ts.bak (100%) rename modules/{invoices => customer-invoices}/src/api/infrastructure/sequelize/contactAddress.mo.del.ts.bak (100%) rename modules/{invoices/src/api/infrastructure/sequelize/invoice-item.model.ts => customer-invoices/src/api/infrastructure/sequelize/customer-invoice-item.model.ts} (79%) rename modules/{invoices/src/api/infrastructure/sequelize/invoice.model.ts => customer-invoices/src/api/infrastructure/sequelize/customer-invoice.model.ts} (62%) create mode 100644 modules/customer-invoices/src/api/infrastructure/sequelize/customer-invoice.repository.ts create mode 100644 modules/customer-invoices/src/api/infrastructure/sequelize/customer-invoiceParticipant.mo.del.ts.bak rename modules/{invoices/src/api/infrastructure/sequelize/invoiceParticipantAddress.mo.del.ts.bak => customer-invoices/src/api/infrastructure/sequelize/customer-invoiceParticipantAddress.mo.del.ts.bak} (64%) create mode 100644 modules/customer-invoices/src/api/infrastructure/sequelize/index.ts create mode 100644 modules/customer-invoices/src/api/presentation/delete-invoice/delete-invoice.controller.ts.bak create mode 100644 modules/customer-invoices/src/api/presentation/delete-invoice/index.ts.bak create mode 100644 modules/customer-invoices/src/api/presentation/get-invoice/get-invoice.controller.ts create mode 100644 modules/customer-invoices/src/api/presentation/get-invoice/index.ts rename modules/{invoices => customer-invoices}/src/api/presentation/get-invoice/presenter/InvoiceItem.presenter.ts.bak (71%) create mode 100644 modules/customer-invoices/src/api/presentation/get-invoice/presenter/InvoiceParticipant.presenter.ts.bak rename modules/{invoices => customer-invoices}/src/api/presentation/get-invoice/presenter/InvoiceParticipantAddress.presenter.ts.bak (55%) create mode 100644 modules/customer-invoices/src/api/presentation/get-invoice/presenter/get-invoice.presenter.ts create mode 100644 modules/customer-invoices/src/api/presentation/get-invoice/presenter/index.ts create mode 100644 modules/customer-invoices/src/api/presentation/index.ts create mode 100644 modules/customer-invoices/src/api/presentation/list-invoices/index.ts create mode 100644 modules/customer-invoices/src/api/presentation/list-invoices/list-invoices.controller.ts create mode 100644 modules/customer-invoices/src/api/presentation/list-invoices/presenter/InvoiceParticipant.presenter.ts.bak rename modules/{invoices => customer-invoices}/src/api/presentation/list-invoices/presenter/InvoiceParticipantAddress.presenter.ts.bak (67%) create mode 100644 modules/customer-invoices/src/api/presentation/list-invoices/presenter/index.ts create mode 100644 modules/customer-invoices/src/api/presentation/list-invoices/presenter/list-invoices.presenter.ts rename modules/{invoices => customer-invoices}/src/api/presentation/update-invoice/index.ts.bak (50%) rename modules/{invoices => customer-invoices}/src/api/presentation/update-invoice/presenter/InvoiceItem.presenter.ts.bak (73%) create mode 100644 modules/customer-invoices/src/api/presentation/update-invoice/presenter/InvoiceParticipant.presenter.ts.bak rename modules/{invoices => customer-invoices}/src/api/presentation/update-invoice/presenter/InvoiceParticipantAddress.presenter.ts.bak (56%) create mode 100644 modules/customer-invoices/src/api/presentation/update-invoice/presenter/UpdateInvoice.presenter.ts.bak create mode 100644 modules/customer-invoices/src/api/presentation/update-invoice/presenter/index.ts.bak rename modules/{invoices => customer-invoices}/src/api/presentation/update-invoice/update-invoice.controller.ts.bak (57%) rename modules/{invoices/src/common/dto/invoices.request.dto.ts => customer-invoices/src/common/dto/customer-invoices.request.dto.ts} (66%) rename modules/{invoices/src/common/dto/invoices.response.dto.ts => customer-invoices/src/common/dto/customer-invoices.response.dto.ts} (60%) rename modules/{invoices/src/common/dto/invoices.schemas.ts => customer-invoices/src/common/dto/customer-invoices.schemas.ts} (77%) create mode 100644 modules/customer-invoices/src/common/dto/index.ts create mode 100644 modules/customer-invoices/src/common/locales/en.json rename modules/{invoices => customer-invoices}/src/common/locales/es.json (96%) rename modules/{invoices/src/web/components/invoices-grid.tsx => customer-invoices/src/web/components/customer-invoices-grid.tsx} (91%) create mode 100644 modules/customer-invoices/src/web/components/customer-invoices-layout.tsx rename modules/{invoices => customer-invoices}/src/web/components/data.json (100%) create mode 100644 modules/customer-invoices/src/web/components/index.tsx create mode 100644 modules/customer-invoices/src/web/context/customer-invoices-context.tsx create mode 100644 modules/customer-invoices/src/web/context/index.ts create mode 100644 modules/customer-invoices/src/web/customer-invoice-routes.tsx create mode 100644 modules/customer-invoices/src/web/hooks/customer-invoices-context.tsx create mode 100644 modules/customer-invoices/src/web/hooks/index.ts rename modules/{invoices/src/web/hooks/use-invoices.tsx => customer-invoices/src/web/hooks/use-customer-invoices.bak} (67%) create mode 100644 modules/customer-invoices/src/web/hooks/use-customer-invoices.tsx rename modules/{invoices => customer-invoices}/src/web/invoice-routes.tsx (93%) rename modules/{invoices => customer-invoices}/src/web/manifest.ts (67%) rename modules/{invoices => customer-invoices}/src/web/pages/index.tsx (100%) rename modules/{invoices => customer-invoices}/src/web/pages/list.tsx (59%) rename modules/{invoices => customer-invoices}/tsconfig.json (93%) delete mode 100644 modules/invoices/src/api/application/create-invoice.use-case.ts delete mode 100644 modules/invoices/src/api/application/index.ts delete mode 100644 modules/invoices/src/api/application/update-invoice.use-case.ts delete mode 100644 modules/invoices/src/api/domain/aggregates/index.ts delete mode 100644 modules/invoices/src/api/domain/entities/index.ts delete mode 100644 modules/invoices/src/api/domain/entities/invoice-customer/index.ts delete mode 100644 modules/invoices/src/api/domain/entities/invoice-items/index.ts delete mode 100644 modules/invoices/src/api/domain/entities/invoice-items/invoice-item.test.ts delete mode 100644 modules/invoices/src/api/domain/entities/invoice-items/invoice-item.ts delete mode 100644 modules/invoices/src/api/domain/entities/invoice-items/invoice-items.ts delete mode 100644 modules/invoices/src/api/domain/repositories/index.ts delete mode 100644 modules/invoices/src/api/domain/repositories/invoice-repository.interface.ts delete mode 100644 modules/invoices/src/api/domain/services/index.ts delete mode 100644 modules/invoices/src/api/domain/services/invoice-service.interface.ts delete mode 100644 modules/invoices/src/api/domain/services/invoice.service.ts delete mode 100644 modules/invoices/src/api/domain/value-objects/index.ts delete mode 100644 modules/invoices/src/api/domain/value-objects/invoice-item-description.ts delete mode 100644 modules/invoices/src/api/domain/value-objects/invoice-item-discount.ts delete mode 100644 modules/invoices/src/api/domain/value-objects/invoice-item-quantity.ts delete mode 100644 modules/invoices/src/api/index.ts delete mode 100644 modules/invoices/src/api/infrastructure/express/index.ts delete mode 100644 modules/invoices/src/api/infrastructure/mappers/index.ts delete mode 100644 modules/invoices/src/api/infrastructure/mappers/invoice.mapper.ts delete mode 100644 modules/invoices/src/api/infrastructure/sequelize/index.ts delete mode 100644 modules/invoices/src/api/infrastructure/sequelize/invoice.repository.ts delete mode 100644 modules/invoices/src/api/infrastructure/sequelize/invoiceParticipant.mo.del.ts.bak delete mode 100644 modules/invoices/src/api/presentation/delete-invoice/delete-invoice.controller.ts.bak delete mode 100644 modules/invoices/src/api/presentation/delete-invoice/index.ts.bak delete mode 100644 modules/invoices/src/api/presentation/get-invoice/get-invoice.controller.ts delete mode 100644 modules/invoices/src/api/presentation/get-invoice/index.ts delete mode 100644 modules/invoices/src/api/presentation/get-invoice/presenter/InvoiceParticipant.presenter.ts.bak delete mode 100644 modules/invoices/src/api/presentation/get-invoice/presenter/get-invoice.presenter.ts delete mode 100644 modules/invoices/src/api/presentation/get-invoice/presenter/index.ts delete mode 100644 modules/invoices/src/api/presentation/index.ts delete mode 100644 modules/invoices/src/api/presentation/list-invoices/index.ts delete mode 100644 modules/invoices/src/api/presentation/list-invoices/list-invoices.controller.ts delete mode 100644 modules/invoices/src/api/presentation/list-invoices/presenter/InvoiceParticipant.presenter.ts.bak delete mode 100644 modules/invoices/src/api/presentation/list-invoices/presenter/index.ts delete mode 100644 modules/invoices/src/api/presentation/list-invoices/presenter/list-invoices.presenter.ts delete mode 100644 modules/invoices/src/api/presentation/update-invoice/presenter/InvoiceParticipant.presenter.ts.bak delete mode 100644 modules/invoices/src/api/presentation/update-invoice/presenter/UpdateInvoice.presenter.ts.bak delete mode 100644 modules/invoices/src/api/presentation/update-invoice/presenter/index.ts.bak delete mode 100644 modules/invoices/src/common/dto/index.ts delete mode 100644 modules/invoices/src/common/locales/en.json delete mode 100644 modules/invoices/src/web/components/index.tsx delete mode 100644 modules/invoices/src/web/components/invoices-layout.tsx delete mode 100644 modules/invoices/src/web/context/index.ts delete mode 100644 modules/invoices/src/web/context/invoices-context.tsx delete mode 100644 modules/invoices/src/web/hooks/index.ts delete mode 100644 modules/invoices/src/web/hooks/invoices-context.tsx diff --git a/apps/server/package.json b/apps/server/package.json index 1afb3c87..e244cef6 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -42,7 +42,7 @@ "dependencies": { "@erp/core": "workspace:*", "@erp/auth": "workspace:*", - "@erp/invoices": "workspace:*", + "@erp/customer-invoices": "workspace:*", "bcrypt": "^5.1.1", "cls-rtracer": "^2.6.3", "cors": "^2.8.5", diff --git a/apps/server/src/index.ts b/apps/server/src/index.ts index 77071f86..58c12ddb 100644 --- a/apps/server/src/index.ts +++ b/apps/server/src/index.ts @@ -134,7 +134,6 @@ process.on("uncaughtException", (error: Error) => { await initModules({ app, database, baseRoutePath: API_BASE_PATH, logger }); - logger.info("holaaaaaaaaaaaaaaaaa"); console.log(listRoutes(app._router, API_BASE_PATH)); server.listen(currentState.port, () => { diff --git a/apps/server/src/register-modules.ts b/apps/server/src/register-modules.ts index 3ab62493..1c326671 100644 --- a/apps/server/src/register-modules.ts +++ b/apps/server/src/register-modules.ts @@ -1,5 +1,5 @@ import { authAPIModule } from "@erp/auth/api"; -import { invoicesAPIModule } from "@erp/invoices/api"; +import { invoicesAPIModule } from "@erp/customer-invoices/api"; import { registerModule } from "./lib"; export const registerModules = () => { diff --git a/apps/web/package.json b/apps/web/package.json index b745e725..8b50fbbc 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -31,7 +31,7 @@ "dependencies": { "@erp/auth": "workspace:*", "@erp/core": "workspace:*", - "@erp/invoices": "workspace:*", + "@erp/customer-invoices": "workspace:*", "@repo/rdx-criteria": "workspace:*", "@repo/rdx-ui": "workspace:*", "@repo/shadcn-ui": "workspace:*", diff --git a/apps/web/src/app.tsx b/apps/web/src/app.tsx index 877c9194..57833a17 100644 --- a/apps/web/src/app.tsx +++ b/apps/web/src/app.tsx @@ -45,7 +45,7 @@ export const App = () => { getAccessToken, setAccessToken, clearAccessToken, - authService: createAuthService(dataSource), + authService: createAuthService(), }} > diff --git a/apps/web/src/register-modules.tsx b/apps/web/src/register-modules.tsx index 1db77faf..297d9852 100644 --- a/apps/web/src/register-modules.tsx +++ b/apps/web/src/register-modules.tsx @@ -1,5 +1,5 @@ import { AuthModuleManifiest } from "@erp/auth/client"; import { IModuleClient } from "@erp/core/client"; -import { InvoicesModuleManifiest } from "@erp/invoices/client"; +import { CustomerInvoicesModuleManifiest } from "@erp/customer-invoices/client"; -export const modules: IModuleClient[] = [AuthModuleManifiest, InvoicesModuleManifiest]; +export const modules: IModuleClient[] = [AuthModuleManifiest, CustomerInvoicesModuleManifiest]; diff --git a/modules/auth/src/web/services/auth-service.ts b/modules/auth/src/web/services/auth-service.ts index 44ad1aeb..e2fcaa1c 100644 --- a/modules/auth/src/web/services/auth-service.ts +++ b/modules/auth/src/web/services/auth-service.ts @@ -1,13 +1,14 @@ -import { IDataSource } from "@erp/core/client"; +import { useDataSource } from "@erp/core/client"; import { ILoginRequestDTO, ILoginResponseDTO } from "../../common"; export interface IAuthService { login: (credentials: ILoginRequestDTO) => Promise; } -export const createAuthService = (dataSource: IDataSource): IAuthService => { +export const createAuthService = (): IAuthService => { return { login: async (credentials: ILoginRequestDTO) => { + const dataSource = useDataSource(); const data = await dataSource.custom({ path: "login", method: "post", diff --git a/modules/invoices/package.json b/modules/customer-invoices/package.json similarity index 92% rename from modules/invoices/package.json rename to modules/customer-invoices/package.json index 6cebe3a9..84b8148f 100644 --- a/modules/invoices/package.json +++ b/modules/customer-invoices/package.json @@ -1,5 +1,5 @@ { - "name": "@erp/invoices", + "name": "@erp/customer-invoices", "version": "0.0.1", "main": "src/index.ts", "types": "src/index.ts", @@ -23,6 +23,7 @@ "@repo/rdx-utils": "workspace:*", "@repo/rdx-ui": "workspace:*", "@repo/shadcn-ui": "workspace:*", + "@tanstack/react-query": "^5.74.11", "ag-grid-community": "^33.3.0", "ag-grid-react": "^33.3.0", "express": "^4.18.2", diff --git a/modules/customer-invoices/src/api/application/create-customer-invoice.use-case.ts b/modules/customer-invoices/src/api/application/create-customer-invoice.use-case.ts new file mode 100644 index 00000000..4d834fb4 --- /dev/null +++ b/modules/customer-invoices/src/api/application/create-customer-invoice.use-case.ts @@ -0,0 +1,147 @@ +import { UniqueID, UtcDate } from "@/core/common/domain"; + +import { + type ICustomerInvoiceProps, + type ICustomerInvoiceService, + type CustomerInvoice, + CustomerInvoiceNumber, + CustomerInvoiceSerie, + CustomerInvoiceStatus, +} from "@/contexts/customerCustomerInvoices/domain"; +import { ITransactionManager } from "@/core/common/infrastructure/database"; +import { logger } from "@/core/logger"; +import { Result } from "@repo/rdx-utils"; +import { ICreateCustomerInvoiceRequestDTO } from "../../common/dto"; + +export class CreateCustomerInvoiceUseCase { + constructor( + private readonly customerCustomerInvoiceService: ICustomerInvoiceService, + private readonly transactionManager: ITransactionManager + ) {} + + public execute( + customerCustomerInvoiceID: UniqueID, + dto: ICreateCustomerInvoiceRequestDTO + ): Promise> { + return this.transactionManager.complete(async (transaction) => { + try { + const validOrErrors = this.validateCustomerInvoiceData(dto); + if (validOrErrors.isFailure) { + return Result.fail(validOrErrors.error); + } + + const data = validOrErrors.data; + + // Update customerCustomerInvoice with dto + return await this.customerCustomerInvoiceService.createCustomerInvoice(customerCustomerInvoiceID, data, transaction); + } catch (error: unknown) { + logger.error(error as Error); + return Result.fail(error as Error); + } + }); + } + + private validateCustomerInvoiceData(dto: ICreateCustomerInvoiceRequestDTO): Result { + const errors: Error[] = []; + + const customerCustomerInvoiceNumerOrError = CustomerInvoiceNumber.create(dto.customerCustomerInvoice_number); + const customerCustomerInvoiceSeriesOrError = CustomerInvoiceSerie.create(dto.customerCustomerInvoice_series); + const issueDateOrError = UtcDate.create(dto.issue_date); + const operationDateOrError = UtcDate.create(dto.operation_date); + + const result = Result.combine([ + customerCustomerInvoiceNumerOrError, + customerCustomerInvoiceSeriesOrError, + issueDateOrError, + operationDateOrError, + ]); + + if (result.isFailure) { + return Result.fail(result.error); + } + + const validatedData: ICustomerInvoiceProps = { + status: CustomerInvoiceStatus.createDraft(), + customerCustomerInvoiceNumber: customerCustomerInvoiceNumerOrError.data, + customerCustomerInvoiceSeries: customerCustomerInvoiceSeriesOrError.data, + issueDate: issueDateOrError.data, + operationDate: operationDateOrError.data, + customerCustomerInvoiceCurrency: dto.currency, + }; + + /*if (errors.length > 0) { + const message = errors.map((err) => err.message).toString(); + return Result.fail(new Error(message)); + }*/ + return Result.ok(validatedData); + + /*let customerCustomerInvoice_status = CustomerInvoiceStatus.create(dto.status).object; + if (customerCustomerInvoice_status.isEmpty()) { + customerCustomerInvoice_status = CustomerInvoiceStatus.createDraft(); + } + + let customerCustomerInvoice_series = CustomerInvoiceSeries.create(dto.customerCustomerInvoice_series).object; + if (customerCustomerInvoice_series.isEmpty()) { + customerCustomerInvoice_series = CustomerInvoiceSeries.create(dto.customerCustomerInvoice_series).object; + } + + let issue_date = CustomerInvoiceDate.create(dto.issue_date).object; + if (issue_date.isEmpty()) { + issue_date = CustomerInvoiceDate.createCurrentDate().object; + } + + let operation_date = CustomerInvoiceDate.create(dto.operation_date).object; + if (operation_date.isEmpty()) { + operation_date = CustomerInvoiceDate.createCurrentDate().object; + } + + let customerCustomerInvoiceCurrency = Currency.createFromCode(dto.currency).object; + + if (customerCustomerInvoiceCurrency.isEmpty()) { + customerCustomerInvoiceCurrency = Currency.createDefaultCode().object; + } + + let customerCustomerInvoiceLanguage = Language.createFromCode(dto.language_code).object; + + if (customerCustomerInvoiceLanguage.isEmpty()) { + customerCustomerInvoiceLanguage = Language.createDefaultCode().object; + } + + const items = new Collection( + dto.items?.map( + (item) => + CustomerInvoiceSimpleItem.create({ + description: Description.create(item.description).object, + quantity: Quantity.create(item.quantity).object, + unitPrice: UnitPrice.create({ + amount: item.unit_price.amount, + currencyCode: item.unit_price.currency, + precision: item.unit_price.precision, + }).object, + }).object + ) + ); + + if (!customerCustomerInvoice_status.isDraft()) { + throw Error("Error al crear una factura que no es borrador"); + } + + return DraftCustomerInvoice.create( + { + customerCustomerInvoiceSeries: customerCustomerInvoice_series, + issueDate: issue_date, + operationDate: operation_date, + customerCustomerInvoiceCurrency, + language: customerCustomerInvoiceLanguage, + customerCustomerInvoiceNumber: CustomerInvoiceNumber.create(undefined).object, + //notes: Note.create(customerCustomerInvoiceDTO.notes).object, + + //senderId: UniqueID.create(null).object, + recipient, + + items, + }, + customerCustomerInvoiceId + );*/ + } +} diff --git a/modules/invoices/src/api/application/delete-invoice.use-case.ts b/modules/customer-invoices/src/api/application/delete-customer-invoice.use-case.ts similarity index 56% rename from modules/invoices/src/api/application/delete-invoice.use-case.ts rename to modules/customer-invoices/src/api/application/delete-customer-invoice.use-case.ts index e2ba05ab..e1214270 100644 --- a/modules/invoices/src/api/application/delete-invoice.use-case.ts +++ b/modules/customer-invoices/src/api/application/delete-customer-invoice.use-case.ts @@ -2,18 +2,18 @@ import { UniqueID } from "@/core/common/domain"; import { ITransactionManager } from "@/core/common/infrastructure/database"; import { logger } from "@/core/logger"; import { Result } from "@repo/rdx-utils"; -import { IInvoiceService } from "../domain"; +import { ICustomerInvoiceService } from "../domain"; -export class DeleteInvoiceUseCase { +export class DeleteCustomerInvoiceUseCase { constructor( - private readonly invoiceService: IInvoiceService, + private readonly customerCustomerInvoiceService: ICustomerInvoiceService, private readonly transactionManager: ITransactionManager ) {} - public execute(invoiceID: UniqueID): Promise> { + public execute(customerCustomerInvoiceID: UniqueID): Promise> { return this.transactionManager.complete(async (transaction) => { try { - return await this.invoiceService.deleteInvoiceById(invoiceID, transaction); + return await this.customerCustomerInvoiceService.deleteCustomerInvoiceById(customerCustomerInvoiceID, transaction); } catch (error: unknown) { logger.error(error as Error); return Result.fail(error as Error); diff --git a/modules/invoices/src/api/application/get-invoice.use-case.ts b/modules/customer-invoices/src/api/application/get-customer-invoice.use-case.ts similarity index 55% rename from modules/invoices/src/api/application/get-invoice.use-case.ts rename to modules/customer-invoices/src/api/application/get-customer-invoice.use-case.ts index f6fbc48e..691ca67c 100644 --- a/modules/invoices/src/api/application/get-invoice.use-case.ts +++ b/modules/customer-invoices/src/api/application/get-customer-invoice.use-case.ts @@ -2,18 +2,18 @@ import { UniqueID } from "@/core/common/domain"; import { ITransactionManager } from "@/core/common/infrastructure/database"; import { logger } from "@/lib/logger"; import { Result } from "@repo/rdx-utils"; -import { IInvoiceService, Invoice } from "../domain"; +import { ICustomerInvoiceService, CustomerInvoice } from "../domain"; -export class GetInvoiceUseCase { +export class GetCustomerInvoiceUseCase { constructor( - private readonly invoiceService: IInvoiceService, + private readonly customerCustomerInvoiceService: ICustomerInvoiceService, private readonly transactionManager: ITransactionManager ) {} - public execute(invoiceID: UniqueID): Promise> { + public execute(customerCustomerInvoiceID: UniqueID): Promise> { return this.transactionManager.complete(async (transaction) => { try { - return await this.invoiceService.findInvoiceById(invoiceID, transaction); + return await this.customerCustomerInvoiceService.findCustomerInvoiceById(customerCustomerInvoiceID, transaction); } catch (error: unknown) { logger.error(error as Error); return Result.fail(error as Error); diff --git a/modules/customer-invoices/src/api/application/index.ts b/modules/customer-invoices/src/api/application/index.ts new file mode 100644 index 00000000..0b228bae --- /dev/null +++ b/modules/customer-invoices/src/api/application/index.ts @@ -0,0 +1,5 @@ +//export * from "./create-customer-invoice.use-case"; +//export * from "./delete-customer-invoice.use-case"; +export * from "./get-customer-invoice.use-case"; +export * from "./list-customer-invoices.use-case"; +//export * from "./update-customer-invoice.use-case"; diff --git a/modules/invoices/src/api/application/list-invoices.use-case.ts b/modules/customer-invoices/src/api/application/list-customer-invoices.use-case.ts similarity index 62% rename from modules/invoices/src/api/application/list-invoices.use-case.ts rename to modules/customer-invoices/src/api/application/list-customer-invoices.use-case.ts index 657b8de5..b8980404 100644 --- a/modules/invoices/src/api/application/list-invoices.use-case.ts +++ b/modules/customer-invoices/src/api/application/list-customer-invoices.use-case.ts @@ -2,18 +2,18 @@ import { ITransactionManager } from "@erp/core/api"; import { Criteria } from "@repo/rdx-criteria/server"; import { Collection, Result } from "@repo/rdx-utils"; import { Transaction } from "sequelize"; -import { IInvoiceService, Invoice } from "../domain"; +import { ICustomerInvoiceService, CustomerInvoice } from "../domain"; -export class ListInvoicesUseCase { +export class ListCustomerInvoicesUseCase { constructor( - private readonly invoiceService: IInvoiceService, + private readonly customerCustomerInvoiceService: ICustomerInvoiceService, private readonly transactionManager: ITransactionManager ) {} - public execute(criteria: Criteria): Promise, Error>> { + public execute(criteria: Criteria): Promise, Error>> { return this.transactionManager.complete(async (transaction: Transaction) => { try { - return await this.invoiceService.findInvoices(criteria, transaction); + return await this.customerCustomerInvoiceService.findCustomerInvoices(criteria, transaction); } catch (error: unknown) { return Result.fail(error as Error); } diff --git a/modules/invoices/src/api/application/services/index.ts b/modules/customer-invoices/src/api/application/services/index.ts similarity index 100% rename from modules/invoices/src/api/application/services/index.ts rename to modules/customer-invoices/src/api/application/services/index.ts diff --git a/modules/invoices/src/api/application/services/participantAddressFinder.ts b/modules/customer-invoices/src/api/application/services/participantAddressFinder.ts similarity index 83% rename from modules/invoices/src/api/application/services/participantAddressFinder.ts rename to modules/customer-invoices/src/api/application/services/participantAddressFinder.ts index 1f81875b..f6fc0f36 100644 --- a/modules/invoices/src/api/application/services/participantAddressFinder.ts +++ b/modules/customer-invoices/src/api/application/services/participantAddressFinder.ts @@ -5,12 +5,12 @@ import { IAdapter, RepositoryBuilder } from "@/contexts/common/domain"; import { Result, UniqueID } from "@shared/contexts"; import { NullOr } from "@shared/utilities"; -import { IInvoiceParticipantAddress, IInvoiceParticipantAddressRepository } from "../../domain"; +import { ICustomerInvoiceParticipantAddress, ICustomerInvoiceParticipantAddressRepository } from "../../domain"; export const participantAddressFinder = async ( addressId: UniqueID, adapter: IAdapter, - repository: RepositoryBuilder + repository: RepositoryBuilder ) => { if (addressId.isNull()) { return Result.fail( @@ -22,7 +22,7 @@ export const participantAddressFinder = async ( } const transaction = adapter.startTransaction(); - let address: NullOr = null; + let address: NullOr = null; try { await transaction.complete(async (t) => { @@ -38,7 +38,7 @@ export const participantAddressFinder = async ( ); } - return Result.ok(address); + return Result.ok(address); } catch (error: unknown) { const _error = error as Error; diff --git a/modules/invoices/src/api/application/services/participantFinder.ts b/modules/customer-invoices/src/api/application/services/participantFinder.ts similarity index 62% rename from modules/invoices/src/api/application/services/participantFinder.ts rename to modules/customer-invoices/src/api/application/services/participantFinder.ts index 16fb7ac7..e53b055c 100644 --- a/modules/invoices/src/api/application/services/participantFinder.ts +++ b/modules/customer-invoices/src/api/application/services/participantFinder.ts @@ -1,13 +1,13 @@ /* import { IAdapter, RepositoryBuilder } from "@/contexts/common/domain"; import { UniqueID } from "@shared/contexts"; -import { IInvoiceParticipantRepository } from "../../domain"; -import { InvoiceCustomer } from "../../domain/entities/invoice-customer/invoice-customer"; +import { ICustomerInvoiceParticipantRepository } from "../../domain"; +import { CustomerInvoiceCustomer } from "../../domain/entities/customerCustomerInvoice-customer/customerCustomerInvoice-customer"; export const participantFinder = async ( participantId: UniqueID, adapter: IAdapter, - repository: RepositoryBuilder -): Promise => { + repository: RepositoryBuilder +): Promise => { if (!participantId || (participantId && participantId.isNull())) { return Promise.resolve(undefined); } diff --git a/modules/customer-invoices/src/api/application/update-customer-invoice.use-case.ts b/modules/customer-invoices/src/api/application/update-customer-invoice.use-case.ts new file mode 100644 index 00000000..907dd493 --- /dev/null +++ b/modules/customer-invoices/src/api/application/update-customer-invoice.use-case.ts @@ -0,0 +1,401 @@ +import { UniqueID } from "@/core/common/domain"; +import { ITransactionManager } from "@/core/common/infrastructure/database"; +import { Result } from "@repo/rdx-utils"; +import { IUpdateCustomerInvoiceRequestDTO } from "../../common/dto"; +import { ICustomerInvoiceService, CustomerInvoice } from "../domain"; + +export class CreateCustomerInvoiceUseCase { + constructor( + private readonly customerCustomerInvoiceService: ICustomerInvoiceService, + private readonly transactionManager: ITransactionManager + ) {} + + public execute( + customerCustomerInvoiceID: UniqueID, + dto: Partial + ): Promise> { + return this.transactionManager.complete(async (transaction) => { + return Result.fail(new Error("No implementado")); + /* + try { + const validOrErrors = this.validateCustomerInvoiceData(dto); + if (validOrErrors.isFailure) { + return Result.fail(validOrErrors.error); + } + + const data = validOrErrors.data; + + // Update customerCustomerInvoice with dto + return await this.customerCustomerInvoiceService.updateCustomerInvoiceById(customerCustomerInvoiceID, data, transaction); + } catch (error: unknown) { + logger.error(error as Error); + return Result.fail(error as Error); + } + */ + }); + } + + /* private validateCustomerInvoiceData( + dto: Partial + ): Result, Error> { + const errors: Error[] = []; + const validatedData: Partial = {}; + + // Create customerCustomerInvoice + let customerCustomerInvoice_status = CustomerInvoiceStatus.create(customerCustomerInvoiceDTO.status).object; + if (customerCustomerInvoice_status.isEmpty()) { + customerCustomerInvoice_status = CustomerInvoiceStatus.createDraft(); + } + + let customerCustomerInvoice_series = CustomerInvoiceSeries.create(customerCustomerInvoiceDTO.customerCustomerInvoice_series).object; + if (customerCustomerInvoice_series.isEmpty()) { + customerCustomerInvoice_series = CustomerInvoiceSeries.create(customerCustomerInvoiceDTO.customerCustomerInvoice_series).object; + } + + let issue_date = CustomerInvoiceDate.create(customerCustomerInvoiceDTO.issue_date).object; + if (issue_date.isEmpty()) { + issue_date = CustomerInvoiceDate.createCurrentDate().object; + } + + let operation_date = CustomerInvoiceDate.create(customerCustomerInvoiceDTO.operation_date).object; + if (operation_date.isEmpty()) { + operation_date = CustomerInvoiceDate.createCurrentDate().object; + } + + let customerCustomerInvoiceCurrency = Currency.createFromCode(customerCustomerInvoiceDTO.currency).object; + + if (customerCustomerInvoiceCurrency.isEmpty()) { + customerCustomerInvoiceCurrency = Currency.createDefaultCode().object; + } + + let customerCustomerInvoiceLanguage = Language.createFromCode(customerCustomerInvoiceDTO.language_code).object; + + if (customerCustomerInvoiceLanguage.isEmpty()) { + customerCustomerInvoiceLanguage = Language.createDefaultCode().object; + } + + const items = new Collection( + customerCustomerInvoiceDTO.items?.map( + (item) => + CustomerInvoiceSimpleItem.create({ + description: Description.create(item.description).object, + quantity: Quantity.create(item.quantity).object, + unitPrice: UnitPrice.create({ + amount: item.unit_price.amount, + currencyCode: item.unit_price.currency, + precision: item.unit_price.precision, + }).object, + }).object + ) + ); + + if (!customerCustomerInvoice_status.isDraft()) { + throw Error("Error al crear una factura que no es borrador"); + } + + return DraftCustomerInvoice.create( + { + customerCustomerInvoiceSeries: customerCustomerInvoice_series, + issueDate: issue_date, + operationDate: operation_date, + customerCustomerInvoiceCurrency, + language: customerCustomerInvoiceLanguage, + customerCustomerInvoiceNumber: CustomerInvoiceNumber.create(undefined).object, + //notes: Note.create(customerCustomerInvoiceDTO.notes).object, + + //senderId: UniqueID.create(null).object, + recipient, + + items, + }, + customerCustomerInvoiceId + ); + } */ +} + +/* export type UpdateCustomerInvoiceResponseOrError = + | Result // Misc errors (value objects) + | Result; // Success! + +export class UpdateCustomerInvoiceUseCase2 + implements + IUseCase<{ id: UniqueID; data: IUpdateCustomerInvoice_DTO }, Promise> +{ + private _context: IInvoicingContext; + private _adapter: ISequelizeAdapter; + private _repositoryManager: IRepositoryManager; + + constructor(context: IInvoicingContext) { + this._context = context; + this._adapter = context.adapter; + this._repositoryManager = context.repositoryManager; + } + + private getRepository(name: string) { + return this._repositoryManager.getRepository(name); + } + + private handleValidationFailure( + validationError: Error, + message?: string + ): Result { + return Result.fail( + UseCaseError.create( + UseCaseError.INVALID_INPUT_DATA, + message ? message : validationError.message, + validationError + ) + ); + } + + async execute(request: { + id: UniqueID; + data: IUpdateCustomerInvoice_DTO; + }): Promise { + const { id, data: customerCustomerInvoiceDTO } = request; + + // Validaciones + const customerCustomerInvoiceDTOOrError = ensureUpdateCustomerInvoice_DTOIsValid(customerCustomerInvoiceDTO); + if (customerCustomerInvoiceDTOOrError.isFailure) { + return this.handleValidationFailure(customerCustomerInvoiceDTOOrError.error); + } + + const transaction = this._adapter.startTransaction(); + + const customerCustomerInvoiceRepoBuilder = this.getRepository("CustomerInvoice"); + + let customerCustomerInvoice: CustomerInvoice | null = null; + + try { + await transaction.complete(async (t) => { + customerCustomerInvoice = await customerCustomerInvoiceRepoBuilder({ transaction: t }).getById(id); + }); + + if (customerCustomerInvoice === null) { + return Result.fail( + UseCaseError.create(UseCaseError.NOT_FOUND_ERROR, `CustomerInvoice not found`, { + id: request.id.toString(), + entity: "customerCustomerInvoice", + }) + ); + } + + return Result.ok(customerCustomerInvoice); + } catch (error: unknown) { + const _error = error as Error; + if (customerCustomerInvoiceRepoBuilder().isRepositoryError(_error)) { + return this.handleRepositoryError(error as BaseError, customerCustomerInvoiceRepoBuilder()); + } else { + return this.handleUnexceptedError(error); + } + } + + // Recipient validations + const recipientIdOrError = ensureParticipantIdIsValid( + customerCustomerInvoiceDTO?.recipient?.id, + ); + if (recipientIdOrError.isFailure) { + return this.handleValidationFailure( + recipientIdOrError.error, + "Recipient ID not valid", + ); + } + const recipientId = recipientIdOrError.object; + + const recipientBillingIdOrError = ensureParticipantAddressIdIsValid( + customerCustomerInvoiceDTO?.recipient?.billing_address_id, + ); + if (recipientBillingIdOrError.isFailure) { + return this.handleValidationFailure( + recipientBillingIdOrError.error, + "Recipient billing address ID not valid", + ); + } + const recipientBillingId = recipientBillingIdOrError.object; + + const recipientShippingIdOrError = ensureParticipantAddressIdIsValid( + customerCustomerInvoiceDTO?.recipient?.shipping_address_id, + ); + if (recipientShippingIdOrError.isFailure) { + return this.handleValidationFailure( + recipientShippingIdOrError.error, + "Recipient shipping address ID not valid", + ); + } + const recipientShippingId = recipientShippingIdOrError.object; + + const recipientContact = await this.findContact( + recipientId, + recipientBillingId, + recipientShippingId, + ); + + if (!recipientContact) { + return this.handleValidationFailure( + new Error(`Recipient with ID ${recipientId.toString()} does not exist`), + ); + } + + // Crear customerCustomerInvoice + const customerCustomerInvoiceOrError = await this.tryUpdateCustomerInvoiceInstance( + customerCustomerInvoiceDTO, + customerCustomerInvoiceIdOrError.object, + //senderId, + //senderBillingId, + //senderShippingId, + recipientContact, + ); + + if (customerCustomerInvoiceOrError.isFailure) { + const { error: domainError } = customerCustomerInvoiceOrError; + let errorCode = ""; + let message = ""; + + switch (domainError.code) { + case CustomerInvoice.ERROR_CUSTOMER_WITHOUT_NAME: + errorCode = UseCaseError.INVALID_INPUT_DATA; + message = + "El cliente debe ser una compañía o tener nombre y apellidos."; + break; + + default: + errorCode = UseCaseError.UNEXCEPTED_ERROR; + message = ""; + break; + } + + return Result.fail( + UseCaseError.create(errorCode, message, domainError), + ); + } + + return this.saveCustomerInvoice(customerCustomerInvoiceOrError.object); + + } + + private async tryUpdateCustomerInvoiceInstance(customerCustomerInvoiceDTO, customerCustomerInvoiceId, recipient) { + // Create customerCustomerInvoice + let customerCustomerInvoice_status = CustomerInvoiceStatus.create(customerCustomerInvoiceDTO.status).object; + if (customerCustomerInvoice_status.isEmpty()) { + customerCustomerInvoice_status = CustomerInvoiceStatus.createDraft(); + } + + let customerCustomerInvoice_series = CustomerInvoiceSeries.create(customerCustomerInvoiceDTO.customerCustomerInvoice_series).object; + if (customerCustomerInvoice_series.isEmpty()) { + customerCustomerInvoice_series = CustomerInvoiceSeries.create(customerCustomerInvoiceDTO.customerCustomerInvoice_series).object; + } + + let issue_date = CustomerInvoiceDate.create(customerCustomerInvoiceDTO.issue_date).object; + if (issue_date.isEmpty()) { + issue_date = CustomerInvoiceDate.createCurrentDate().object; + } + + let operation_date = CustomerInvoiceDate.create(customerCustomerInvoiceDTO.operation_date).object; + if (operation_date.isEmpty()) { + operation_date = CustomerInvoiceDate.createCurrentDate().object; + } + + let customerCustomerInvoiceCurrency = Currency.createFromCode(customerCustomerInvoiceDTO.currency).object; + + if (customerCustomerInvoiceCurrency.isEmpty()) { + customerCustomerInvoiceCurrency = Currency.createDefaultCode().object; + } + + let customerCustomerInvoiceLanguage = Language.createFromCode(customerCustomerInvoiceDTO.language_code).object; + + if (customerCustomerInvoiceLanguage.isEmpty()) { + customerCustomerInvoiceLanguage = Language.createDefaultCode().object; + } + + const items = new Collection( + customerCustomerInvoiceDTO.items?.map( + (item) => + CustomerInvoiceSimpleItem.create({ + description: Description.create(item.description).object, + quantity: Quantity.create(item.quantity).object, + unitPrice: UnitPrice.create({ + amount: item.unit_price.amount, + currencyCode: item.unit_price.currency, + precision: item.unit_price.precision, + }).object, + }).object + ) + ); + + if (!customerCustomerInvoice_status.isDraft()) { + throw Error("Error al crear una factura que no es borrador"); + } + + return DraftCustomerInvoice.create( + { + customerCustomerInvoiceSeries: customerCustomerInvoice_series, + issueDate: issue_date, + operationDate: operation_date, + customerCustomerInvoiceCurrency, + language: customerCustomerInvoiceLanguage, + customerCustomerInvoiceNumber: CustomerInvoiceNumber.create(undefined).object, + //notes: Note.create(customerCustomerInvoiceDTO.notes).object, + + //senderId: UniqueID.create(null).object, + recipient, + + items, + }, + customerCustomerInvoiceId + ); + } + + private async findContact( + contactId: UniqueID, + billingAddressId: UniqueID, + shippingAddressId: UniqueID + ) { + const contactRepoBuilder = this.getRepository("Contact"); + + const contact = await contactRepoBuilder().getById2( + contactId, + billingAddressId, + shippingAddressId + ); + + return contact; + } + + private async saveCustomerInvoice(customerCustomerInvoice: DraftCustomerInvoice) { + const transaction = this._adapter.startTransaction(); + const customerCustomerInvoiceRepoBuilder = this.getRepository("CustomerInvoice"); + + try { + await transaction.complete(async (t) => { + const customerCustomerInvoiceRepo = customerCustomerInvoiceRepoBuilder({ transaction: t }); + await customerCustomerInvoiceRepo.save(customerCustomerInvoice); + }); + + return Result.ok(customerCustomerInvoice); + } catch (error: unknown) { + const _error = error as Error; + if (customerCustomerInvoiceRepoBuilder().isRepositoryError(_error)) { + return this.handleRepositoryError(error as BaseError, customerCustomerInvoiceRepoBuilder()); + } else { + return this.handleUnexceptedError(error); + } + } + } + + private handleUnexceptedError(error): Result { + return Result.fail( + UseCaseError.create(UseCaseError.UNEXCEPTED_ERROR, error.message, error) + ); + } + + private handleRepositoryError( + error: BaseError, + repository: ICustomerInvoiceRepository + ): Result { + const { message, details } = repository.handleRepositoryError(error); + return Result.fail( + UseCaseError.create(UseCaseError.REPOSITORY_ERROR, message, details) + ); + } +} + */ diff --git a/modules/invoices/src/api/domain/aggregates/invoice.ts b/modules/customer-invoices/src/api/domain/aggregates/customer-invoice.ts similarity index 50% rename from modules/invoices/src/api/domain/aggregates/invoice.ts rename to modules/customer-invoices/src/api/domain/aggregates/customer-invoice.ts index 53dcbd7f..202bc275 100644 --- a/modules/invoices/src/api/domain/aggregates/invoice.ts +++ b/modules/customer-invoices/src/api/domain/aggregates/customer-invoice.ts @@ -1,13 +1,13 @@ import { AggregateRoot, MoneyValue, UniqueID, UtcDate } from "@repo/rdx-ddd"; import { Collection, Result } from "@repo/rdx-utils"; -import { InvoiceCustomer, InvoiceItem, InvoiceItems } from "../entities"; -import { InvoiceNumber, InvoiceSerie, InvoiceStatus } from "../value-objects"; +import { CustomerInvoiceCustomer, CustomerInvoiceItem, CustomerInvoiceItems } from "../entities"; +import { CustomerInvoiceNumber, CustomerInvoiceSerie, CustomerInvoiceStatus } from "../value-objects"; -export interface IInvoiceProps { - invoiceNumber: InvoiceNumber; - invoiceSeries: InvoiceSerie; +export interface ICustomerInvoiceProps { + customerCustomerInvoiceNumber: CustomerInvoiceNumber; + customerCustomerInvoiceSeries: CustomerInvoiceSerie; - status: InvoiceStatus; + status: CustomerInvoiceStatus; issueDate: UtcDate; operationDate: UtcDate; @@ -15,7 +15,7 @@ export interface IInvoiceProps { //dueDate: UtcDate; // ? --> depende de la forma de pago //tax: Tax; // ? --> detalles? - invoiceCurrency: string; + customerCustomerInvoiceCurrency: string; //language: Language; @@ -27,29 +27,29 @@ export interface IInvoiceProps { //paymentInstructions: Note; //paymentTerms: string; - customer?: InvoiceCustomer; - items?: InvoiceItems; + customer?: CustomerInvoiceCustomer; + items?: CustomerInvoiceItems; } -export interface IInvoice { +export interface ICustomerInvoice { id: UniqueID; - invoiceNumber: InvoiceNumber; - invoiceSeries: InvoiceSerie; + customerCustomerInvoiceNumber: CustomerInvoiceNumber; + customerCustomerInvoiceSeries: CustomerInvoiceSerie; - status: InvoiceStatus; + status: CustomerInvoiceStatus; issueDate: UtcDate; operationDate: UtcDate; //senderId: UniqueID; - customer?: InvoiceCustomer; + customer?: CustomerInvoiceCustomer; //dueDate //tax: Tax; //language: Language; - invoiceCurrency: string; + customerCustomerInvoiceCurrency: string; //purchareOrderNumber: string; //notes: Note; @@ -57,43 +57,43 @@ export interface IInvoice { //paymentInstructions: Note; //paymentTerms: string; - items: InvoiceItems; + items: CustomerInvoiceItems; calculateSubtotal: () => MoneyValue; calculateTaxTotal: () => MoneyValue; calculateTotal: () => MoneyValue; } -export class Invoice extends AggregateRoot implements IInvoice { - private _items!: Collection; - //protected _status: InvoiceStatus; +export class CustomerInvoice extends AggregateRoot implements ICustomerInvoice { + private _items!: Collection; + //protected _status: CustomerInvoiceStatus; - protected constructor(props: IInvoiceProps, id?: UniqueID) { + protected constructor(props: ICustomerInvoiceProps, id?: UniqueID) { super(props, id); - this._items = props.items || InvoiceItems.create(); + this._items = props.items || CustomerInvoiceItems.create(); } - static create(props: IInvoiceProps, id?: UniqueID): Result { - const invoice = new Invoice(props, id); + static create(props: ICustomerInvoiceProps, id?: UniqueID): Result { + const customerCustomerInvoice = new CustomerInvoice(props, id); // Reglas de negocio / validaciones // ... // ... - // 🔹 Disparar evento de dominio "InvoiceAuthenticatedEvent" - //const { invoice } = props; - //user.addDomainEvent(new InvoiceAuthenticatedEvent(id, invoice.toString())); + // 🔹 Disparar evento de dominio "CustomerInvoiceAuthenticatedEvent" + //const { customerCustomerInvoice } = props; + //user.addDomainEvent(new CustomerInvoiceAuthenticatedEvent(id, customerCustomerInvoice.toString())); - return Result.ok(invoice); + return Result.ok(customerCustomerInvoice); } - get invoiceNumber() { - return this.props.invoiceNumber; + get customerCustomerInvoiceNumber() { + return this.props.customerCustomerInvoiceNumber; } - get invoiceSeries() { - return this.props.invoiceSeries; + get customerCustomerInvoiceSeries() { + return this.props.customerCustomerInvoiceSeries; } get issueDate() { @@ -104,7 +104,7 @@ export class Invoice extends AggregateRoot implements IInvoice { return this.props.senderId; }*/ - get customer(): InvoiceCustomer | undefined { + get customer(): CustomerInvoiceCustomer | undefined { return this.props.customer; } @@ -152,8 +152,8 @@ export class Invoice extends AggregateRoot implements IInvoice { return this.props.shipTo; }*/ - get invoiceCurrency() { - return this.props.invoiceCurrency; + get customerCustomerInvoiceCurrency() { + return this.props.customerCustomerInvoiceCurrency; } /*get notes() { @@ -161,11 +161,11 @@ export class Invoice extends AggregateRoot implements IInvoice { }*/ // Method to get the complete list of line items - /*get lineItems(): InvoiceLineItem[] { + /*get lineItems(): CustomerInvoiceLineItem[] { return this._lineItems; } - addLineItem(lineItem: InvoiceLineItem, position?: number): void { + addLineItem(lineItem: CustomerInvoiceLineItem, position?: number): void { if (position === undefined) { this._lineItems.push(lineItem); } else { @@ -174,29 +174,29 @@ export class Invoice extends AggregateRoot implements IInvoice { }*/ calculateSubtotal(): MoneyValue { - const invoiceSubtotal = MoneyValue.create({ + const customerCustomerInvoiceSubtotal = MoneyValue.create({ amount: 0, - currency_code: this.props.invoiceCurrency, + currency_code: this.props.customerCustomerInvoiceCurrency, scale: 2, }).data; return this._items.getAll().reduce((subtotal, item) => { return subtotal.add(item.calculateTotal()); - }, invoiceSubtotal); + }, customerCustomerInvoiceSubtotal); } - // Method to calculate the total tax in the invoice + // Method to calculate the total tax in the customerCustomerInvoice calculateTaxTotal(): MoneyValue { const taxTotal = MoneyValue.create({ amount: 0, - currency_code: this.props.invoiceCurrency, + currency_code: this.props.customerCustomerInvoiceCurrency, scale: 2, }).data; return taxTotal; } - // Method to calculate the total invoice amount, including taxes + // Method to calculate the total customerCustomerInvoice amount, including taxes calculateTotal(): MoneyValue { return this.calculateSubtotal().add(this.calculateTaxTotal()); } diff --git a/modules/customer-invoices/src/api/domain/aggregates/index.ts b/modules/customer-invoices/src/api/domain/aggregates/index.ts new file mode 100644 index 00000000..269b3869 --- /dev/null +++ b/modules/customer-invoices/src/api/domain/aggregates/index.ts @@ -0,0 +1 @@ +export * from "./customerCustomerInvoice"; diff --git a/modules/customer-invoices/src/api/domain/entities/index.ts b/modules/customer-invoices/src/api/domain/entities/index.ts new file mode 100644 index 00000000..9bd1a505 --- /dev/null +++ b/modules/customer-invoices/src/api/domain/entities/index.ts @@ -0,0 +1,2 @@ +export * from "./customerCustomerInvoice-customer"; +export * from "./customerCustomerInvoice-items"; diff --git a/modules/customer-invoices/src/api/domain/entities/invoice-customer/index.ts b/modules/customer-invoices/src/api/domain/entities/invoice-customer/index.ts new file mode 100644 index 00000000..10cc3e27 --- /dev/null +++ b/modules/customer-invoices/src/api/domain/entities/invoice-customer/index.ts @@ -0,0 +1,2 @@ +export * from "./customerCustomerInvoice-address"; +export * from "./customerCustomerInvoice-customer"; diff --git a/modules/invoices/src/api/domain/entities/invoice-customer/invoice-address.ts b/modules/customer-invoices/src/api/domain/entities/invoice-customer/invoice-address.ts similarity index 52% rename from modules/invoices/src/api/domain/entities/invoice-customer/invoice-address.ts rename to modules/customer-invoices/src/api/domain/entities/invoice-customer/invoice-address.ts index b18b8e50..488bf642 100644 --- a/modules/invoices/src/api/domain/entities/invoice-customer/invoice-address.ts +++ b/modules/customer-invoices/src/api/domain/entities/invoice-customer/invoice-address.ts @@ -1,43 +1,43 @@ import { EmailAddress, Name, PostalAddress, ValueObject } from "@repo/rdx-ddd"; import { Result } from "@repo/rdx-utils"; import { PhoneNumber } from "libphonenumber-js"; -import { InvoiceAddressType } from "../../value-objects"; +import { CustomerInvoiceAddressType } from "../../value-objects"; -export interface IInvoiceAddressProps { - type: InvoiceAddressType; +export interface ICustomerInvoiceAddressProps { + type: CustomerInvoiceAddressType; title: Name; address: PostalAddress; email: EmailAddress; phone: PhoneNumber; } -export interface IInvoiceAddress { - type: InvoiceAddressType; +export interface ICustomerInvoiceAddress { + type: CustomerInvoiceAddressType; title: Name; address: PostalAddress; email: EmailAddress; phone: PhoneNumber; } -export class InvoiceAddress extends ValueObject implements IInvoiceAddress { - public static create(props: IInvoiceAddressProps) { - return Result.ok(new InvoiceAddress(props)); +export class CustomerInvoiceAddress extends ValueObject implements ICustomerInvoiceAddress { + public static create(props: ICustomerInvoiceAddressProps) { + return Result.ok(new CustomerInvoiceAddress(props)); } - public static createShippingAddress(props: IInvoiceAddressProps) { + public static createShippingAddress(props: ICustomerInvoiceAddressProps) { return Result.ok( - new InvoiceAddress({ + new CustomerInvoiceAddress({ ...props, - type: InvoiceAddressType.create("shipping").data, + type: CustomerInvoiceAddressType.create("shipping").data, }) ); } - public static createBillingAddress(props: IInvoiceAddressProps) { + public static createBillingAddress(props: ICustomerInvoiceAddressProps) { return Result.ok( - new InvoiceAddress({ + new CustomerInvoiceAddress({ ...props, - type: InvoiceAddressType.create("billing").data, + type: CustomerInvoiceAddressType.create("billing").data, }) ); } @@ -58,11 +58,11 @@ export class InvoiceAddress extends ValueObject implements return this.props.phone; } - get type(): InvoiceAddressType { + get type(): CustomerInvoiceAddressType { return this.props.type; } - getValue(): IInvoiceAddressProps { + getValue(): ICustomerInvoiceAddressProps { return this.props; } diff --git a/modules/invoices/src/api/domain/entities/invoice-customer/invoice-customer.ts b/modules/customer-invoices/src/api/domain/entities/invoice-customer/invoice-customer.ts similarity index 51% rename from modules/invoices/src/api/domain/entities/invoice-customer/invoice-customer.ts rename to modules/customer-invoices/src/api/domain/entities/invoice-customer/invoice-customer.ts index ae4b21d5..b178e664 100644 --- a/modules/invoices/src/api/domain/entities/invoice-customer/invoice-customer.ts +++ b/modules/customer-invoices/src/api/domain/entities/invoice-customer/invoice-customer.ts @@ -1,38 +1,38 @@ import { DomainEntity, Name, TINNumber, UniqueID } from "@repo/rdx-ddd"; import { Result } from "@repo/rdx-utils"; -import { InvoiceAddress } from "./invoice-address"; +import { CustomerInvoiceAddress } from "./customerCustomerInvoice-address"; -export interface IInvoiceCustomerProps { +export interface ICustomerInvoiceCustomerProps { tin: TINNumber; companyName: Name; firstName: Name; lastName: Name; - billingAddress?: InvoiceAddress; - shippingAddress?: InvoiceAddress; + billingAddress?: CustomerInvoiceAddress; + shippingAddress?: CustomerInvoiceAddress; } -export interface IInvoiceCustomer { +export interface ICustomerInvoiceCustomer { id: UniqueID; tin: TINNumber; companyName: Name; firstName: Name; lastName: Name; - billingAddress?: InvoiceAddress; - shippingAddress?: InvoiceAddress; + billingAddress?: CustomerInvoiceAddress; + shippingAddress?: CustomerInvoiceAddress; } -export class InvoiceCustomer - extends DomainEntity - implements IInvoiceCustomer +export class CustomerInvoiceCustomer + extends DomainEntity + implements ICustomerInvoiceCustomer { public static create( - props: IInvoiceCustomerProps, + props: ICustomerInvoiceCustomerProps, id?: UniqueID - ): Result { - const participant = new InvoiceCustomer(props, id); - return Result.ok(participant); + ): Result { + const participant = new CustomerInvoiceCustomer(props, id); + return Result.ok(participant); } get tin(): TINNumber { diff --git a/modules/customer-invoices/src/api/domain/entities/invoice-items/index.ts b/modules/customer-invoices/src/api/domain/entities/invoice-items/index.ts new file mode 100644 index 00000000..b47e3dad --- /dev/null +++ b/modules/customer-invoices/src/api/domain/entities/invoice-items/index.ts @@ -0,0 +1,2 @@ +export * from "./customerCustomerInvoice-item"; +export * from "./customerCustomerInvoice-items"; diff --git a/modules/customer-invoices/src/api/domain/entities/invoice-items/invoice-item.test.ts b/modules/customer-invoices/src/api/domain/entities/invoice-items/invoice-item.test.ts new file mode 100644 index 00000000..c6ae1974 --- /dev/null +++ b/modules/customer-invoices/src/api/domain/entities/invoice-items/invoice-item.test.ts @@ -0,0 +1,83 @@ +import { MoneyValue, Percentage, Quantity } from "@/core/common/domain"; +import { CustomerInvoiceItemDescription } from "../../value-objects"; +import { CustomerInvoiceItem } from "./customerCustomerInvoice-item"; + +describe("CustomerInvoiceItem", () => { + it("debería calcular correctamente el subtotal (unitPrice * quantity)", () => { + const props = { + description: CustomerInvoiceItemDescription.create("Producto A"), + quantity: Quantity.create({ amount: 200, scale: 2 }), + unitPrice: MoneyValue.create(50), + discount: Percentage.create(0), + }; + + const result = CustomerInvoiceItem.create(props); + + expect(result.isOk()).toBe(true); + const customerCustomerInvoiceItem = result.unwrap(); + expect(customerCustomerInvoiceItem.subtotalPrice.value).toBe(100); // 50 * 2 + }); + + it("debería calcular correctamente el total con descuento", () => { + const props = { + description: new CustomerInvoiceItemDescription("Producto B"), + quantity: new Quantity(3), + unitPrice: new MoneyValue(30), + discount: new Percentage(10), // 10% + }; + + const result = CustomerInvoiceItem.create(props); + + expect(result.isOk()).toBe(true); + const customerCustomerInvoiceItem = result.unwrap(); + expect(customerCustomerInvoiceItem.totalPrice.value).toBe(81); // (30 * 3) - 10% de (30 * 3) + }); + + it("debería devolver los valores correctos de las propiedades", () => { + const props = { + description: new CustomerInvoiceItemDescription("Producto C"), + quantity: new Quantity(1), + unitPrice: new MoneyValue(100), + discount: new Percentage(5), + }; + + const result = CustomerInvoiceItem.create(props); + + expect(result.isOk()).toBe(true); + const customerCustomerInvoiceItem = result.unwrap(); + expect(customerCustomerInvoiceItem.description.value).toBe("Producto C"); + expect(customerCustomerInvoiceItem.quantity.value).toBe(1); + expect(customerCustomerInvoiceItem.unitPrice.value).toBe(100); + expect(customerCustomerInvoiceItem.discount.value).toBe(5); + }); + + it("debería manejar correctamente un descuento del 0%", () => { + const props = { + description: new CustomerInvoiceItemDescription("Producto D"), + quantity: new Quantity(4), + unitPrice: new MoneyValue(25), + discount: new Percentage(0), + }; + + const result = CustomerInvoiceItem.create(props); + + expect(result.isOk()).toBe(true); + const customerCustomerInvoiceItem = result.unwrap(); + expect(customerCustomerInvoiceItem.totalPrice.value).toBe(100); // 25 * 4 + }); + + it("debería manejar correctamente un descuento del 100%", () => { + const props = { + description: new CustomerInvoiceItemDescription("Producto E"), + quantity: new Quantity(2), + unitPrice: new MoneyValue(50), + discount: new Percentage(100), + }; + + const result = CustomerInvoiceItem.create(props); + + expect(result.isOk()).toBe(true); + const customerCustomerInvoiceItem = result.unwrap(); + expect(customerCustomerInvoiceItem.totalPrice.value).toBe(0); // (50 * 2) - 100% de (50 * 2) + }); +}); diff --git a/modules/customer-invoices/src/api/domain/entities/invoice-items/invoice-item.ts b/modules/customer-invoices/src/api/domain/entities/invoice-items/invoice-item.ts new file mode 100644 index 00000000..fb9f2280 --- /dev/null +++ b/modules/customer-invoices/src/api/domain/entities/invoice-items/invoice-item.ts @@ -0,0 +1,101 @@ +import { DomainEntity, UniqueID } from "@repo/rdx-ddd"; +import { Result } from "@repo/rdx-utils"; +import { + CustomerInvoiceItemDescription, + CustomerInvoiceItemDiscount, + CustomerInvoiceItemQuantity, + CustomerInvoiceItemSubtotalPrice, + CustomerInvoiceItemTotalPrice, + CustomerInvoiceItemUnitPrice, +} from "../../value-objects"; + +export interface ICustomerInvoiceItemProps { + description: CustomerInvoiceItemDescription; + quantity: CustomerInvoiceItemQuantity; // Cantidad de unidades + unitPrice: CustomerInvoiceItemUnitPrice; // Precio unitario en la moneda de la factura + //subtotalPrice?: MoneyValue; // Precio unitario * Cantidad + discount: CustomerInvoiceItemDiscount; // % descuento + //totalPrice?: MoneyValue; +} + +export interface ICustomerInvoiceItem { + id: UniqueID; + description: CustomerInvoiceItemDescription; + quantity: CustomerInvoiceItemQuantity; + unitPrice: CustomerInvoiceItemUnitPrice; + subtotalPrice: CustomerInvoiceItemSubtotalPrice; + discount: CustomerInvoiceItemDiscount; + totalPrice: CustomerInvoiceItemTotalPrice; +} + +export class CustomerInvoiceItem extends DomainEntity implements ICustomerInvoiceItem { + private _subtotalPrice!: CustomerInvoiceItemSubtotalPrice; + private _totalPrice!: CustomerInvoiceItemTotalPrice; + + public static create(props: ICustomerInvoiceItemProps, id?: UniqueID): Result { + const item = new CustomerInvoiceItem(props, id); + + // Reglas de negocio / validaciones + // ... + // ... + + // 🔹 Disparar evento de dominio "CustomerInvoiceItemCreatedEvent" + //const { customerCustomerInvoice } = props; + //user.addDomainEvent(new CustomerInvoiceAuthenticatedEvent(id, customerCustomerInvoice.toString())); + + return Result.ok(item); + } + + get description(): CustomerInvoiceItemDescription { + return this.props.description; + } + + get quantity(): CustomerInvoiceItemQuantity { + return this.props.quantity; + } + + get unitPrice(): CustomerInvoiceItemUnitPrice { + return this.props.unitPrice; + } + + get subtotalPrice(): CustomerInvoiceItemSubtotalPrice { + if (!this._subtotalPrice) { + this._subtotalPrice = this.calculateSubtotal(); + } + return this._subtotalPrice; + } + + get discount(): CustomerInvoiceItemDiscount { + return this.props.discount; + } + + get totalPrice(): CustomerInvoiceItemTotalPrice { + if (!this._totalPrice) { + this._totalPrice = this.calculateTotal(); + } + return this._totalPrice; + } + + getValue() { + return this.props; + } + + toPrimitive() { + return { + description: this.description.toPrimitive(), + quantity: this.quantity.toPrimitive(), + unit_price: this.unitPrice.toPrimitive(), + subtotal_price: this.subtotalPrice.toPrimitive(), + discount: this.discount.toPrimitive(), + total_price: this.totalPrice.toPrimitive(), + }; + } + + calculateSubtotal(): CustomerInvoiceItemSubtotalPrice { + return this.unitPrice.multiply(this.quantity.toNumber()); // Precio unitario * Cantidad + } + + calculateTotal(): CustomerInvoiceItemTotalPrice { + return this.subtotalPrice.subtract(this.subtotalPrice.percentage(this.discount.toNumber())); + } +} diff --git a/modules/customer-invoices/src/api/domain/entities/invoice-items/invoice-items.ts b/modules/customer-invoices/src/api/domain/entities/invoice-items/invoice-items.ts new file mode 100644 index 00000000..c7e66814 --- /dev/null +++ b/modules/customer-invoices/src/api/domain/entities/invoice-items/invoice-items.ts @@ -0,0 +1,8 @@ +import { Collection } from "@repo/rdx-utils"; +import { CustomerInvoiceItem } from "./customerCustomerInvoice-item"; + +export class CustomerInvoiceItems extends Collection { + public static create(items?: CustomerInvoiceItem[]): CustomerInvoiceItems { + return new CustomerInvoiceItems(items); + } +} diff --git a/modules/invoices/src/api/domain/index.ts b/modules/customer-invoices/src/api/domain/index.ts similarity index 100% rename from modules/invoices/src/api/domain/index.ts rename to modules/customer-invoices/src/api/domain/index.ts diff --git a/modules/customer-invoices/src/api/domain/repositories/customer-invoice-repository.interface.ts b/modules/customer-invoices/src/api/domain/repositories/customer-invoice-repository.interface.ts new file mode 100644 index 00000000..b0bdba96 --- /dev/null +++ b/modules/customer-invoices/src/api/domain/repositories/customer-invoice-repository.interface.ts @@ -0,0 +1,13 @@ +import { Criteria } from "@repo/rdx-criteria/server"; +import { UniqueID } from "@repo/rdx-ddd"; +import { Collection, Result } from "@repo/rdx-utils"; +import { CustomerInvoice } from "../aggregates"; + +export interface ICustomerInvoiceRepository { + findAll(criteria: Criteria, transaction?: any): Promise, Error>>; + getById(id: UniqueID, transaction?: any): Promise>; + deleteById(id: UniqueID, transaction?: any): Promise>; + + create(customerCustomerInvoice: CustomerInvoice, transaction?: any): Promise; + update(customerCustomerInvoice: CustomerInvoice, transaction?: any): Promise; +} diff --git a/modules/customer-invoices/src/api/domain/repositories/index.ts b/modules/customer-invoices/src/api/domain/repositories/index.ts new file mode 100644 index 00000000..7c01a70c --- /dev/null +++ b/modules/customer-invoices/src/api/domain/repositories/index.ts @@ -0,0 +1 @@ +export * from "./customerCustomerInvoice-repository.interface"; diff --git a/modules/customer-invoices/src/api/domain/services/customer-invoice-service.interface.ts b/modules/customer-invoices/src/api/domain/services/customer-invoice-service.interface.ts new file mode 100644 index 00000000..e01f3b24 --- /dev/null +++ b/modules/customer-invoices/src/api/domain/services/customer-invoice-service.interface.ts @@ -0,0 +1,23 @@ +import { Criteria } from "@repo/rdx-criteria/server"; +import { UniqueID } from "@repo/rdx-ddd"; +import { Collection, Result } from "@repo/rdx-utils"; +import { ICustomerInvoiceProps, CustomerInvoice } from "../aggregates"; + +export interface ICustomerInvoiceService { + findCustomerInvoices(criteria: Criteria, transaction?: any): Promise, Error>>; + findCustomerInvoiceById(customerCustomerInvoiceId: UniqueID, transaction?: any): Promise>; + + updateCustomerInvoiceById( + customerCustomerInvoiceId: UniqueID, + data: Partial, + transaction?: any + ): Promise>; + + createCustomerInvoice( + customerCustomerInvoiceId: UniqueID, + data: ICustomerInvoiceProps, + transaction?: any + ): Promise>; + + deleteCustomerInvoiceById(customerCustomerInvoiceId: UniqueID, transaction?: any): Promise>; +} diff --git a/modules/customer-invoices/src/api/domain/services/customer-invoice.service.ts b/modules/customer-invoices/src/api/domain/services/customer-invoice.service.ts new file mode 100644 index 00000000..da330a3f --- /dev/null +++ b/modules/customer-invoices/src/api/domain/services/customer-invoice.service.ts @@ -0,0 +1,86 @@ +import { Criteria } from "@repo/rdx-criteria/server"; +import { UniqueID } from "@repo/rdx-ddd"; +import { Collection, Result } from "@repo/rdx-utils"; +import { Transaction } from "sequelize"; +import { ICustomerInvoiceProps, CustomerInvoice } from "../aggregates"; +import { ICustomerInvoiceRepository } from "../repositories"; +import { ICustomerInvoiceService } from "./customerCustomerInvoice-service.interface"; + +export class CustomerInvoiceService implements ICustomerInvoiceService { + constructor(private readonly repo: ICustomerInvoiceRepository) {} + + async findCustomerInvoices( + criteria: Criteria, + transaction?: Transaction + ): Promise, Error>> { + const customerCustomerInvoicesOrError = await this.repo.findAll(criteria, transaction); + if (customerCustomerInvoicesOrError.isFailure) { + return Result.fail(customerCustomerInvoicesOrError.error); + } + + // Solo devolver usuarios activos + //const allCustomerInvoices = customerCustomerInvoicesOrError.data.filter((customerCustomerInvoice) => customerCustomerInvoice.isActive); + //return Result.ok(new Collection(allCustomerInvoices)); + + return customerCustomerInvoicesOrError; + } + + async findCustomerInvoiceById(customerCustomerInvoiceId: UniqueID, transaction?: Transaction): Promise> { + return await this.repo.getById(customerCustomerInvoiceId, transaction); + } + + async updateCustomerInvoiceById( + customerCustomerInvoiceId: UniqueID, + data: Partial, + transaction?: Transaction + ): Promise> { + // Verificar si la factura existe + const customerCustomerInvoiceOrError = await this.repo.getById(customerCustomerInvoiceId, transaction); + if (customerCustomerInvoiceOrError.isFailure) { + return Result.fail(new Error("CustomerInvoice not found")); + } + + return Result.fail(new Error("No implementado")); + + /*const updatedCustomerInvoiceOrError = CustomerInvoice.update(customerCustomerInvoiceOrError.data, data); + if (updatedCustomerInvoiceOrError.isFailure) { + return Result.fail( + new Error(`Error updating customerCustomerInvoice: ${updatedCustomerInvoiceOrError.error.message}`) + ); + } + + const updateCustomerInvoice = updatedCustomerInvoiceOrError.data; + + await this.repo.update(updateCustomerInvoice, transaction); + return Result.ok(updateCustomerInvoice);*/ + } + + async createCustomerInvoice( + customerCustomerInvoiceId: UniqueID, + data: ICustomerInvoiceProps, + transaction?: Transaction + ): Promise> { + // Verificar si la factura existe + const customerCustomerInvoiceOrError = await this.repo.getById(customerCustomerInvoiceId, transaction); + if (customerCustomerInvoiceOrError.isSuccess) { + return Result.fail(new Error("CustomerInvoice exists")); + } + + const newCustomerInvoiceOrError = CustomerInvoice.create(data, customerCustomerInvoiceId); + if (newCustomerInvoiceOrError.isFailure) { + return Result.fail(new Error(`Error creating customerCustomerInvoice: ${newCustomerInvoiceOrError.error.message}`)); + } + + const newCustomerInvoice = newCustomerInvoiceOrError.data; + + await this.repo.create(newCustomerInvoice, transaction); + return Result.ok(newCustomerInvoice); + } + + async deleteCustomerInvoiceById( + customerCustomerInvoiceId: UniqueID, + transaction?: Transaction + ): Promise> { + return this.repo.deleteById(customerCustomerInvoiceId, transaction); + } +} diff --git a/modules/customer-invoices/src/api/domain/services/index.ts b/modules/customer-invoices/src/api/domain/services/index.ts new file mode 100644 index 00000000..980f0a59 --- /dev/null +++ b/modules/customer-invoices/src/api/domain/services/index.ts @@ -0,0 +1,2 @@ +export * from "./customerCustomerInvoice-service.interface"; +export * from "./customerCustomerInvoice.service"; diff --git a/modules/invoices/src/api/domain/value-objects/invoice-address-type.ts b/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-address-type.ts similarity index 69% rename from modules/invoices/src/api/domain/value-objects/invoice-address-type.ts rename to modules/customer-invoices/src/api/domain/value-objects/customer-invoice-address-type.ts index 9cce5190..c5d83463 100644 --- a/modules/invoices/src/api/domain/value-objects/invoice-address-type.ts +++ b/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-address-type.ts @@ -1,7 +1,7 @@ import { ValueObject } from "@repo/rdx-ddd"; import { Result } from "@repo/rdx-utils"; -interface IInvoiceAddressTypeProps { +interface ICustomerInvoiceAddressTypeProps { value: string; } @@ -10,10 +10,10 @@ export enum INVOICE_ADDRESS_TYPE { BILLING = "billing", } -export class InvoiceAddressType extends ValueObject { +export class CustomerInvoiceAddressType extends ValueObject { private static readonly ALLOWED_TYPES = ["shipping", "billing"]; - static create(value: string): Result { + static create(value: string): Result { if (!this.ALLOWED_TYPES.includes(value)) { return Result.fail( new Error( @@ -21,7 +21,7 @@ export class InvoiceAddressType extends ValueObject { ) ); } - return Result.ok(new InvoiceAddressType({ value })); + return Result.ok(new CustomerInvoiceAddressType({ value })); } getValue(): string { diff --git a/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-item-description.ts b/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-item-description.ts new file mode 100644 index 00000000..b046526b --- /dev/null +++ b/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-item-description.ts @@ -0,0 +1,50 @@ +import { ValueObject } from "@repo/rdx-ddd"; +import { Maybe, Result } from "@repo/rdx-utils"; +import { z } from "zod"; + +interface ICustomerInvoiceItemDescriptionProps { + value: string; +} + +export class CustomerInvoiceItemDescription extends ValueObject { + private static readonly MAX_LENGTH = 255; + + protected static validate(value: string) { + const schema = z + .string() + .trim() + .max(CustomerInvoiceItemDescription.MAX_LENGTH, { + message: `Description must be at most ${CustomerInvoiceItemDescription.MAX_LENGTH} characters long`, + }); + return schema.safeParse(value); + } + + static create(value: string) { + const valueIsValid = CustomerInvoiceItemDescription.validate(value); + + if (!valueIsValid.success) { + return Result.fail(new Error(valueIsValid.error.errors[0].message)); + } + return Result.ok(new CustomerInvoiceItemDescription({ value })); + } + + static createNullable(value?: string): Result, Error> { + if (!value || value.trim() === "") { + return Result.ok(Maybe.none()); + } + + return CustomerInvoiceItemDescription.create(value).map((value) => Maybe.some(value)); + } + + getValue(): string { + return this.props.value; + } + + toString(): string { + return this.getValue(); + } + + toPrimitive() { + return this.getValue(); + } +} diff --git a/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-item-discount.ts b/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-item-discount.ts new file mode 100644 index 00000000..82eea30e --- /dev/null +++ b/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-item-discount.ts @@ -0,0 +1,3 @@ +import { Percentage } from "@repo/rdx-ddd"; + +export class CustomerInvoiceItemDiscount extends Percentage {} diff --git a/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-item-quantity.ts b/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-item-quantity.ts new file mode 100644 index 00000000..a307e276 --- /dev/null +++ b/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-item-quantity.ts @@ -0,0 +1,3 @@ +import { Quantity } from "@repo/rdx-ddd"; + +export class CustomerInvoiceItemQuantity extends Quantity {} diff --git a/modules/invoices/src/api/domain/value-objects/invoice-item-subtotal-price.ts b/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-item-subtotal-price.ts similarity index 83% rename from modules/invoices/src/api/domain/value-objects/invoice-item-subtotal-price.ts rename to modules/customer-invoices/src/api/domain/value-objects/customer-invoice-item-subtotal-price.ts index 1f2f3c1c..da10b0e8 100644 --- a/modules/invoices/src/api/domain/value-objects/invoice-item-subtotal-price.ts +++ b/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-item-subtotal-price.ts @@ -1,6 +1,6 @@ import { IMoneyValueProps, MoneyValue } from "@repo/rdx-ddd"; -export class InvoiceItemSubtotalPrice extends MoneyValue { +export class CustomerInvoiceItemSubtotalPrice extends MoneyValue { public static DEFAULT_SCALE = 4; static create({ amount, currency_code, scale }: IMoneyValueProps) { diff --git a/modules/invoices/src/api/domain/value-objects/invoice-item-total-price.ts b/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-item-total-price.ts similarity index 84% rename from modules/invoices/src/api/domain/value-objects/invoice-item-total-price.ts rename to modules/customer-invoices/src/api/domain/value-objects/customer-invoice-item-total-price.ts index 2d338998..01615905 100644 --- a/modules/invoices/src/api/domain/value-objects/invoice-item-total-price.ts +++ b/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-item-total-price.ts @@ -1,6 +1,6 @@ import { IMoneyValueProps, MoneyValue } from "@repo/rdx-ddd"; -export class InvoiceItemTotalPrice extends MoneyValue { +export class CustomerInvoiceItemTotalPrice extends MoneyValue { public static DEFAULT_SCALE = 4; static create({ amount, currency_code, scale }: IMoneyValueProps) { diff --git a/modules/invoices/src/api/domain/value-objects/invoice-item-unit-price.ts b/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-item-unit-price.ts similarity index 84% rename from modules/invoices/src/api/domain/value-objects/invoice-item-unit-price.ts rename to modules/customer-invoices/src/api/domain/value-objects/customer-invoice-item-unit-price.ts index 55fe3882..77b60e14 100644 --- a/modules/invoices/src/api/domain/value-objects/invoice-item-unit-price.ts +++ b/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-item-unit-price.ts @@ -1,6 +1,6 @@ import { IMoneyValueProps, MoneyValue } from "@repo/rdx-ddd"; -export class InvoiceItemUnitPrice extends MoneyValue { +export class CustomerInvoiceItemUnitPrice extends MoneyValue { public static DEFAULT_SCALE = 4; static create({ amount, currency_code, scale }: IMoneyValueProps) { diff --git a/modules/invoices/src/api/domain/value-objects/invoice-number.ts b/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-number.ts similarity index 62% rename from modules/invoices/src/api/domain/value-objects/invoice-number.ts rename to modules/customer-invoices/src/api/domain/value-objects/customer-invoice-number.ts index baa70705..7d00287c 100644 --- a/modules/invoices/src/api/domain/value-objects/invoice-number.ts +++ b/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-number.ts @@ -2,30 +2,30 @@ import { ValueObject } from "@repo/rdx-ddd"; import { Result } from "@repo/rdx-utils"; import { z } from "zod"; -interface IInvoiceNumberProps { +interface ICustomerInvoiceNumberProps { value: string; } -export class InvoiceNumber extends ValueObject { +export class CustomerInvoiceNumber extends ValueObject { private static readonly MAX_LENGTH = 255; protected static validate(value: string) { const schema = z .string() .trim() - .max(InvoiceNumber.MAX_LENGTH, { - message: `Name must be at most ${InvoiceNumber.MAX_LENGTH} characters long`, + .max(CustomerInvoiceNumber.MAX_LENGTH, { + message: `Name must be at most ${CustomerInvoiceNumber.MAX_LENGTH} characters long`, }); return schema.safeParse(value); } static create(value: string) { - const valueIsValid = InvoiceNumber.validate(value); + const valueIsValid = CustomerInvoiceNumber.validate(value); if (!valueIsValid.success) { return Result.fail(new Error(valueIsValid.error.errors[0].message)); } - return Result.ok(new InvoiceNumber({ value })); + return Result.ok(new CustomerInvoiceNumber({ value })); } getValue(): string { diff --git a/modules/invoices/src/api/domain/value-objects/invoice-serie.ts b/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-serie.ts similarity index 53% rename from modules/invoices/src/api/domain/value-objects/invoice-serie.ts rename to modules/customer-invoices/src/api/domain/value-objects/customer-invoice-serie.ts index de34bf81..bad007f5 100644 --- a/modules/invoices/src/api/domain/value-objects/invoice-serie.ts +++ b/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-serie.ts @@ -2,38 +2,38 @@ import { ValueObject } from "@repo/rdx-ddd"; import { Maybe, Result } from "@repo/rdx-utils"; import { z } from "zod"; -interface IInvoiceSerieProps { +interface ICustomerInvoiceSerieProps { value: string; } -export class InvoiceSerie extends ValueObject { +export class CustomerInvoiceSerie extends ValueObject { private static readonly MAX_LENGTH = 255; protected static validate(value: string) { const schema = z .string() .trim() - .max(InvoiceSerie.MAX_LENGTH, { - message: `Name must be at most ${InvoiceSerie.MAX_LENGTH} characters long`, + .max(CustomerInvoiceSerie.MAX_LENGTH, { + message: `Name must be at most ${CustomerInvoiceSerie.MAX_LENGTH} characters long`, }); return schema.safeParse(value); } static create(value: string) { - const valueIsValid = InvoiceSerie.validate(value); + const valueIsValid = CustomerInvoiceSerie.validate(value); if (!valueIsValid.success) { return Result.fail(new Error(valueIsValid.error.errors[0].message)); } - return Result.ok(new InvoiceSerie({ value })); + return Result.ok(new CustomerInvoiceSerie({ value })); } - static createNullable(value?: string): Result, Error> { + static createNullable(value?: string): Result, Error> { if (!value || value.trim() === "") { - return Result.ok(Maybe.none()); + return Result.ok(Maybe.none()); } - return InvoiceSerie.create(value).map((value) => Maybe.some(value)); + return CustomerInvoiceSerie.create(value).map((value) => Maybe.some(value)); } getValue(): string { diff --git a/modules/invoices/src/api/domain/value-objects/invoice-status.ts b/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-status.ts similarity index 50% rename from modules/invoices/src/api/domain/value-objects/invoice-status.ts rename to modules/customer-invoices/src/api/domain/value-objects/customer-invoice-status.ts index ee0fcf6e..7524df11 100644 --- a/modules/invoices/src/api/domain/value-objects/invoice-status.ts +++ b/modules/customer-invoices/src/api/domain/value-objects/customer-invoice-status.ts @@ -1,7 +1,7 @@ import { ValueObject } from "@repo/rdx-ddd"; import { Result } from "@repo/rdx-utils"; -interface IInvoiceStatusProps { +interface ICustomerInvoiceStatusProps { value: string; } @@ -11,7 +11,7 @@ export enum INVOICE_STATUS { SENT = "sent", REJECTED = "rejected", } -export class InvoiceStatus extends ValueObject { +export class CustomerInvoiceStatus extends ValueObject { private static readonly ALLOWED_STATUSES = ["draft", "emitted", "sent", "rejected"]; private static readonly TRANSITIONS: Record = { @@ -21,36 +21,36 @@ export class InvoiceStatus extends ValueObject { rejected: [], }; - static create(value: string): Result { - if (!InvoiceStatus.ALLOWED_STATUSES.includes(value)) { + static create(value: string): Result { + if (!CustomerInvoiceStatus.ALLOWED_STATUSES.includes(value)) { return Result.fail(new Error(`Estado de la factura no válido: ${value}`)); } return Result.ok( value === "rejected" - ? InvoiceStatus.createRejected() + ? CustomerInvoiceStatus.createRejected() : value === "sent" - ? InvoiceStatus.createSent() + ? CustomerInvoiceStatus.createSent() : value === "emitted" - ? InvoiceStatus.createSent() - : InvoiceStatus.createDraft() + ? CustomerInvoiceStatus.createSent() + : CustomerInvoiceStatus.createDraft() ); } - public static createDraft(): InvoiceStatus { - return new InvoiceStatus({ value: INVOICE_STATUS.DRAFT }); + public static createDraft(): CustomerInvoiceStatus { + return new CustomerInvoiceStatus({ value: INVOICE_STATUS.DRAFT }); } - public static createEmitted(): InvoiceStatus { - return new InvoiceStatus({ value: INVOICE_STATUS.EMITTED }); + public static createEmitted(): CustomerInvoiceStatus { + return new CustomerInvoiceStatus({ value: INVOICE_STATUS.EMITTED }); } - public static createSent(): InvoiceStatus { - return new InvoiceStatus({ value: INVOICE_STATUS.SENT }); + public static createSent(): CustomerInvoiceStatus { + return new CustomerInvoiceStatus({ value: INVOICE_STATUS.SENT }); } - public static createRejected(): InvoiceStatus { - return new InvoiceStatus({ value: INVOICE_STATUS.REJECTED }); + public static createRejected(): CustomerInvoiceStatus { + return new CustomerInvoiceStatus({ value: INVOICE_STATUS.REJECTED }); } getValue(): string { @@ -62,16 +62,16 @@ export class InvoiceStatus extends ValueObject { } canTransitionTo(nextStatus: string): boolean { - return InvoiceStatus.TRANSITIONS[this.props.value].includes(nextStatus); + return CustomerInvoiceStatus.TRANSITIONS[this.props.value].includes(nextStatus); } - transitionTo(nextStatus: string): Result { + transitionTo(nextStatus: string): Result { if (!this.canTransitionTo(nextStatus)) { return Result.fail( new Error(`Transición no permitida de ${this.props.value} a ${nextStatus}`) ); } - return InvoiceStatus.create(nextStatus); + return CustomerInvoiceStatus.create(nextStatus); } toString(): string { diff --git a/modules/customer-invoices/src/api/domain/value-objects/index.ts b/modules/customer-invoices/src/api/domain/value-objects/index.ts new file mode 100644 index 00000000..ac042c70 --- /dev/null +++ b/modules/customer-invoices/src/api/domain/value-objects/index.ts @@ -0,0 +1,10 @@ +export * from "./customerCustomerInvoice-address-type"; +export * from "./customerCustomerInvoice-item-description"; +export * from "./customerCustomerInvoice-item-discount"; +export * from "./customerCustomerInvoice-item-quantity"; +export * from "./customerCustomerInvoice-item-subtotal-price"; +export * from "./customerCustomerInvoice-item-total-price"; +export * from "./customerCustomerInvoice-item-unit-price"; +export * from "./customerCustomerInvoice-number"; +export * from "./customerCustomerInvoice-serie"; +export * from "./customerCustomerInvoice-status"; diff --git a/modules/customer-invoices/src/api/index.ts b/modules/customer-invoices/src/api/index.ts new file mode 100644 index 00000000..9adb9f03 --- /dev/null +++ b/modules/customer-invoices/src/api/index.ts @@ -0,0 +1,26 @@ +import { IModuleServer, ModuleParams } from "@erp/core/api"; +import { customerCustomerInvoicesRouter, models } from "./infrastructure"; + +export const customerCustomerInvoicesAPIModule: IModuleServer = { + name: "customerCustomerInvoices", + version: "1.0.0", + dependencies: [], + + init(params: ModuleParams) { + // const contacts = getService("contacts"); + const { logger } = params; + customerCustomerInvoicesRouter(params); + logger.info("🚀 CustomerInvoices module initialized", { label: "customerCustomerInvoices" }); + }, + registerDependencies(params) { + const { database, logger } = params; + logger.info("🚀 CustomerInvoices module dependencies registered", { label: "customerCustomerInvoices" }); + return { + models, + services: { + getCustomerInvoice: () => {}, + /*...*/ + }, + }; + }, +}; diff --git a/modules/invoices/src/api/infrastructure/Contact.repository.ts.bak b/modules/customer-invoices/src/api/infrastructure/Contact.repository.ts.bak similarity index 100% rename from modules/invoices/src/api/infrastructure/Contact.repository.ts.bak rename to modules/customer-invoices/src/api/infrastructure/Contact.repository.ts.bak diff --git a/modules/invoices/src/api/infrastructure/express/invoices.routes.ts b/modules/customer-invoices/src/api/infrastructure/express/customer-invoices.routes.ts similarity index 53% rename from modules/invoices/src/api/infrastructure/express/invoices.routes.ts rename to modules/customer-invoices/src/api/infrastructure/express/customer-invoices.routes.ts index a54eaf62..684a87a5 100644 --- a/modules/invoices/src/api/infrastructure/express/invoices.routes.ts +++ b/modules/customer-invoices/src/api/infrastructure/express/customer-invoices.routes.ts @@ -1,9 +1,9 @@ import { ModuleParams } from "@erp/core/api"; import { Application, NextFunction, Request, Response, Router } from "express"; import { Sequelize } from "sequelize"; -import { buildListInvoicesController } from "../../presentation"; +import { buildListCustomerInvoicesController } from "../../presentation"; -export const invoicesRouter = (params: ModuleParams) => { +export const customerCustomerInvoicesRouter = (params: ModuleParams) => { const { app, database, baseRoutePath } = params as { app: Application; database: Sequelize; @@ -17,48 +17,48 @@ export const invoicesRouter = (params: ModuleParams) => { //checkTabContext, //checkUser, (req: Request, res: Response, next: NextFunction) => { - buildListInvoicesController(database).execute(req, res, next); + buildListCustomerInvoicesController(database).execute(req, res, next); } ); - app.use(`${baseRoutePath}/invoices`, routes); + app.use(`${baseRoutePath}/customerCustomerInvoices`, routes); /*routes.get( - "/:invoiceId", + "/:customerCustomerInvoiceId", //checkTabContext, //checkUser, (req: Request, res: Response, next: NextFunction) => { - buildGetInvoiceController(database).execute(req, res, next); + buildGetCustomerInvoiceController(database).execute(req, res, next); } );*/ /*routes.post( "/", - validateAndParseBody(ICreateInvoiceRequestSchema, { sanitize: false }), + validateAndParseBody(ICreateCustomerInvoiceRequestSchema, { sanitize: false }), //checkTabContext, //checkUser, (req: Request, res: Response, next: NextFunction) => { - buildCreateInvoiceController(database).execute(req, res, next); + buildCreateCustomerInvoiceController(database).execute(req, res, next); } ); routes.put( - "/:invoiceId", - validateAndParseBody(IUpdateInvoiceRequestSchema), + "/:customerCustomerInvoiceId", + validateAndParseBody(IUpdateCustomerInvoiceRequestSchema), checkTabContext, //checkUser, (req: Request, res: Response, next: NextFunction) => { - buildUpdateInvoiceController().execute(req, res, next); + buildUpdateCustomerInvoiceController().execute(req, res, next); } ); routes.delete( - "/:invoiceId", - validateAndParseBody(IDeleteInvoiceRequestSchema), + "/:customerCustomerInvoiceId", + validateAndParseBody(IDeleteCustomerInvoiceRequestSchema), checkTabContext, //checkUser, (req: Request, res: Response, next: NextFunction) => { - buildDeleteInvoiceController().execute(req, res, next); + buildDeleteCustomerInvoiceController().execute(req, res, next); } );*/ }; diff --git a/modules/customer-invoices/src/api/infrastructure/express/index.ts b/modules/customer-invoices/src/api/infrastructure/express/index.ts new file mode 100644 index 00000000..8208e6c2 --- /dev/null +++ b/modules/customer-invoices/src/api/infrastructure/express/index.ts @@ -0,0 +1 @@ +export * from "./customerInvoices.routes"; diff --git a/modules/invoices/src/api/infrastructure/index.ts b/modules/customer-invoices/src/api/infrastructure/index.ts similarity index 100% rename from modules/invoices/src/api/infrastructure/index.ts rename to modules/customer-invoices/src/api/infrastructure/index.ts diff --git a/modules/invoices/src/api/infrastructure/mappers/contact.mapper.ts.bak b/modules/customer-invoices/src/api/infrastructure/mappers/contact.mapper.ts.bak similarity index 100% rename from modules/invoices/src/api/infrastructure/mappers/contact.mapper.ts.bak rename to modules/customer-invoices/src/api/infrastructure/mappers/contact.mapper.ts.bak diff --git a/modules/invoices/src/api/infrastructure/mappers/contactAddress.mapper.ts.bak b/modules/customer-invoices/src/api/infrastructure/mappers/contactAddress.mapper.ts.bak similarity index 100% rename from modules/invoices/src/api/infrastructure/mappers/contactAddress.mapper.ts.bak rename to modules/customer-invoices/src/api/infrastructure/mappers/contactAddress.mapper.ts.bak diff --git a/modules/invoices/src/api/infrastructure/mappers/invoice-item.mapper.ts b/modules/customer-invoices/src/api/infrastructure/mappers/customer-invoice-item.mapper.ts similarity index 66% rename from modules/invoices/src/api/infrastructure/mappers/invoice-item.mapper.ts rename to modules/customer-invoices/src/api/infrastructure/mappers/customer-invoice-item.mapper.ts index 313510ac..529826a3 100644 --- a/modules/invoices/src/api/infrastructure/mappers/invoice-item.mapper.ts +++ b/modules/customer-invoices/src/api/infrastructure/mappers/customer-invoice-item.mapper.ts @@ -3,27 +3,27 @@ import { UniqueID } from "@repo/rdx-ddd"; import { Result } from "@repo/rdx-utils"; import { InferCreationAttributes } from "sequelize"; import { - Invoice, - InvoiceItem, - InvoiceItemDescription, - InvoiceItemDiscount, - InvoiceItemQuantity, - InvoiceItemUnitPrice, + CustomerInvoice, + CustomerInvoiceItem, + CustomerInvoiceItemDescription, + CustomerInvoiceItemDiscount, + CustomerInvoiceItemQuantity, + CustomerInvoiceItemUnitPrice, } from "../../domain"; -import { InvoiceItemCreationAttributes, InvoiceItemModel, InvoiceModel } from "../sequelize"; +import { CustomerInvoiceItemCreationAttributes, CustomerInvoiceItemModel, CustomerInvoiceModel } from "../sequelize"; -export interface IInvoiceItemMapper - extends ISequelizeMapper {} +export interface ICustomerInvoiceItemMapper + extends ISequelizeMapper {} -export class InvoiceItemMapper - extends SequelizeMapper - implements IInvoiceItemMapper +export class CustomerInvoiceItemMapper + extends SequelizeMapper + implements ICustomerInvoiceItemMapper { public mapToDomain( - source: InvoiceItemModel, + source: CustomerInvoiceItemModel, params?: MapperParamsType - ): Result { - const { sourceParent } = params as { sourceParent: InvoiceModel }; + ): Result { + const { sourceParent } = params as { sourceParent: CustomerInvoiceModel }; // Validación y creación de ID único const idOrError = UniqueID.create(source.item_id); @@ -32,13 +32,13 @@ export class InvoiceItemMapper } // Validación y creación de descripción - const descriptionOrError = InvoiceItemDescription.create(source.description || ""); + const descriptionOrError = CustomerInvoiceItemDescription.create(source.description || ""); if (descriptionOrError.isFailure) { return Result.fail(descriptionOrError.error); } // Validación y creación de cantidad - const quantityOrError = InvoiceItemQuantity.create({ + const quantityOrError = CustomerInvoiceItemQuantity.create({ amount: source.quantity_amount, scale: source.quantity_scale, }); @@ -47,17 +47,17 @@ export class InvoiceItemMapper } // Validación y creación de precio unitario - const unitPriceOrError = InvoiceItemUnitPrice.create({ + const unitPriceOrError = CustomerInvoiceItemUnitPrice.create({ amount: source.unit_price_amount, scale: source.unit_price_scale, - currency_code: sourceParent.invoice_currency, + currency_code: sourceParent.customerCustomerInvoice_currency, }); if (unitPriceOrError.isFailure) { return Result.fail(unitPriceOrError.error); } // Validación y creación de descuento - const discountOrError = InvoiceItemDiscount.create({ + const discountOrError = CustomerInvoiceItemDiscount.create({ amount: source.discount_amount || 0, scale: source.discount_scale || 0, }); @@ -79,7 +79,7 @@ export class InvoiceItemMapper } // Creación del objeto de dominio - return InvoiceItem.create( + return CustomerInvoiceItem.create( { description: descriptionOrError.data, quantity: quantityOrError.data, @@ -91,17 +91,17 @@ export class InvoiceItemMapper } public mapToPersistence( - source: InvoiceItem, + source: CustomerInvoiceItem, params?: MapperParamsType - ): InferCreationAttributes { + ): InferCreationAttributes { const { index, sourceParent } = params as { index: number; - sourceParent: Invoice; + sourceParent: CustomerInvoice; }; const lineData = { parent_id: undefined, - invoice_id: sourceParent.id.toPrimitive(), + customerCustomerInvoice_id: sourceParent.id.toPrimitive(), item_type: "simple", position: index, diff --git a/modules/customer-invoices/src/api/infrastructure/mappers/customer-invoice.mapper.ts b/modules/customer-invoices/src/api/infrastructure/mappers/customer-invoice.mapper.ts new file mode 100644 index 00000000..b4932dff --- /dev/null +++ b/modules/customer-invoices/src/api/infrastructure/mappers/customer-invoice.mapper.ts @@ -0,0 +1,97 @@ +import { ISequelizeMapper, MapperParamsType, SequelizeMapper } from "@erp/core/api"; +import { UniqueID, UtcDate } from "@repo/rdx-ddd"; +import { Result } from "@repo/rdx-utils"; +import { CustomerInvoice, CustomerInvoiceNumber, CustomerInvoiceSerie, CustomerInvoiceStatus } from "../../domain"; +import { CustomerInvoiceCreationAttributes, CustomerInvoiceModel } from "../sequelize"; +import { CustomerInvoiceItemMapper } from "./customerCustomerInvoice-item.mapper"; + +export interface ICustomerInvoiceMapper + extends ISequelizeMapper {} + +export class CustomerInvoiceMapper + extends SequelizeMapper + implements ICustomerInvoiceMapper +{ + private customerCustomerInvoiceItemMapper: CustomerInvoiceItemMapper; + + constructor() { + super(); + this.customerCustomerInvoiceItemMapper = new CustomerInvoiceItemMapper(); // Instanciar el mapper de items + } + + public mapToDomain(source: CustomerInvoiceModel, params?: MapperParamsType): Result { + const idOrError = UniqueID.create(source.id); + const statusOrError = CustomerInvoiceStatus.create(source.customerCustomerInvoice_status); + const customerCustomerInvoiceSeriesOrError = CustomerInvoiceSerie.create(source.customerCustomerInvoice_series); + const customerCustomerInvoiceNumberOrError = CustomerInvoiceNumber.create(source.customerCustomerInvoice_number); + const issueDateOrError = UtcDate.create(source.issue_date); + const operationDateOrError = UtcDate.create(source.operation_date); + + const result = Result.combine([ + idOrError, + statusOrError, + customerCustomerInvoiceSeriesOrError, + customerCustomerInvoiceNumberOrError, + issueDateOrError, + operationDateOrError, + ]); + + if (result.isFailure) { + return Result.fail(result.error); + } + + // Mapear los items de la factura + const itemsOrErrors = this.customerCustomerInvoiceItemMapper.mapArrayToDomain(source.items, { + sourceParent: source, + ...params, + }); + + if (itemsOrErrors.isFailure) { + return Result.fail(itemsOrErrors.error); + } + + const customerCustomerInvoiceCurrency = source.customerCustomerInvoice_currency || "EUR"; + + return CustomerInvoice.create( + { + status: statusOrError.data, + customerCustomerInvoiceSeries: customerCustomerInvoiceSeriesOrError.data, + customerCustomerInvoiceNumber: customerCustomerInvoiceNumberOrError.data, + issueDate: issueDateOrError.data, + operationDate: operationDateOrError.data, + customerCustomerInvoiceCurrency, + items: itemsOrErrors.data, + }, + idOrError.data + ); + } + + public mapToPersistence(source: CustomerInvoice, params?: MapperParamsType): CustomerInvoiceCreationAttributes { + const subtotal = source.calculateSubtotal(); + const total = source.calculateTotal(); + + const items = this.customerCustomerInvoiceItemMapper.mapCollectionToPersistence(source.items, params); + + return { + id: source.id.toString(), + customerCustomerInvoice_status: source.status.toPrimitive(), + customerCustomerInvoice_series: source.customerCustomerInvoiceSeries.toPrimitive(), + customerCustomerInvoice_number: source.customerCustomerInvoiceNumber.toPrimitive(), + issue_date: source.issueDate.toPrimitive(), + operation_date: source.operationDate.toPrimitive(), + customerCustomerInvoice_language: "es", + customerCustomerInvoice_currency: source.customerCustomerInvoiceCurrency || "EUR", + + subtotal_amount: subtotal.amount, + subtotal_scale: subtotal.scale, + + total_amount: total.amount, + total_scale: total.scale, + + items, + }; + } +} + +const customerCustomerInvoiceMapper: CustomerInvoiceMapper = new CustomerInvoiceMapper(); +export { customerCustomerInvoiceMapper }; diff --git a/modules/invoices/src/api/infrastructure/mappers/invoiceParticipant.mapper.ts.bak b/modules/customer-invoices/src/api/infrastructure/mappers/customer-invoiceParticipant.mapper.ts.bak similarity index 52% rename from modules/invoices/src/api/infrastructure/mappers/invoiceParticipant.mapper.ts.bak rename to modules/customer-invoices/src/api/infrastructure/mappers/customer-invoiceParticipant.mapper.ts.bak index aa6944f3..00132616 100644 --- a/modules/invoices/src/api/infrastructure/mappers/invoiceParticipant.mapper.ts.bak +++ b/modules/customer-invoices/src/api/infrastructure/mappers/customer-invoiceParticipant.mapper.ts.bak @@ -1,50 +1,50 @@ import { ISequelizeMapper, SequelizeMapper } from "@/contexts/common/infrastructure"; import { Name, TINNumber, UniqueID } from "@shared/contexts"; import { - IInvoiceCustomerProps, - Invoice, - InvoiceCustomer, - InvoiceParticipantBillingAddress, - InvoiceParticipantShippingAddress, + ICustomerInvoiceCustomerProps, + CustomerInvoice, + CustomerInvoiceCustomer, + CustomerInvoiceParticipantBillingAddress, + CustomerInvoiceParticipantShippingAddress, } from "../../domain"; import { IInvoicingContext } from "../InvoicingContext"; -import { InvoiceParticipant_Model, TCreationInvoiceParticipant_Model } from "../sequelize"; +import { CustomerInvoiceParticipant_Model, TCreationCustomerInvoiceParticipant_Model } from "../sequelize"; import { - IInvoiceParticipantAddressMapper, - createInvoiceParticipantAddressMapper, -} from "./invoiceParticipantAddress.mapper"; + ICustomerInvoiceParticipantAddressMapper, + createCustomerInvoiceParticipantAddressMapper, +} from "./customerCustomerInvoiceParticipantAddress.mapper"; -export interface IInvoiceParticipantMapper +export interface ICustomerInvoiceParticipantMapper extends ISequelizeMapper< - InvoiceParticipant_Model, - TCreationInvoiceParticipant_Model, - InvoiceCustomer + CustomerInvoiceParticipant_Model, + TCreationCustomerInvoiceParticipant_Model, + CustomerInvoiceCustomer > {} -export const createInvoiceParticipantMapper = ( +export const createCustomerInvoiceParticipantMapper = ( context: IInvoicingContext -): IInvoiceParticipantMapper => - new InvoiceParticipantMapper({ +): ICustomerInvoiceParticipantMapper => + new CustomerInvoiceParticipantMapper({ context, - addressMapper: createInvoiceParticipantAddressMapper(context), + addressMapper: createCustomerInvoiceParticipantAddressMapper(context), }); -class InvoiceParticipantMapper +class CustomerInvoiceParticipantMapper extends SequelizeMapper< - InvoiceParticipant_Model, - TCreationInvoiceParticipant_Model, - InvoiceCustomer + CustomerInvoiceParticipant_Model, + TCreationCustomerInvoiceParticipant_Model, + CustomerInvoiceCustomer > - implements IInvoiceParticipantMapper + implements ICustomerInvoiceParticipantMapper { public constructor(props: { - addressMapper: IInvoiceParticipantAddressMapper; + addressMapper: ICustomerInvoiceParticipantAddressMapper; context: IInvoicingContext; }) { super(props); } - protected toDomainMappingImpl(source: InvoiceParticipant_Model, params: any) { + protected toDomainMappingImpl(source: CustomerInvoiceParticipant_Model, params: any) { /*if (!source.billingAddress) { this.handleRequiredFieldError( "billingAddress", @@ -60,20 +60,20 @@ class InvoiceParticipantMapper } */ const billingAddress = source.billingAddress - ? ((this.props.addressMapper as IInvoiceParticipantAddressMapper).mapToDomain( + ? ((this.props.addressMapper as ICustomerInvoiceParticipantAddressMapper).mapToDomain( source.billingAddress, params - ) as InvoiceParticipantBillingAddress) + ) as CustomerInvoiceParticipantBillingAddress) : undefined; const shippingAddress = source.shippingAddress - ? ((this.props.addressMapper as IInvoiceParticipantAddressMapper).mapToDomain( + ? ((this.props.addressMapper as ICustomerInvoiceParticipantAddressMapper).mapToDomain( source.shippingAddress, params - ) as InvoiceParticipantShippingAddress) + ) as CustomerInvoiceParticipantShippingAddress) : undefined; - const props: IInvoiceCustomerProps = { + const props: ICustomerInvoiceCustomerProps = { tin: this.mapsValue(source, "tin", TINNumber.create), firstName: this.mapsValue(source, "first_name", Name.create), lastName: this.mapsValue(source, "last_name", Name.create), @@ -83,7 +83,7 @@ class InvoiceParticipantMapper }; const id = this.mapsValue(source, "participant_id", UniqueID.create); - const participantOrError = InvoiceCustomer.create(props, id); + const participantOrError = CustomerInvoiceCustomer.create(props, id); if (participantOrError.isFailure) { throw participantOrError.error; @@ -93,13 +93,13 @@ class InvoiceParticipantMapper } protected toPersistenceMappingImpl( - source: InvoiceCustomer, - params: { sourceParent: Invoice } - ): TCreationInvoiceParticipant_Model { + source: CustomerInvoiceCustomer, + params: { sourceParent: CustomerInvoice } + ): TCreationCustomerInvoiceParticipant_Model { const { sourceParent } = params; return { - invoice_id: sourceParent.id.toPrimitive(), + customerCustomerInvoice_id: sourceParent.id.toPrimitive(), participant_id: source.id.toPrimitive(), tin: source.tin.toPrimitive(), @@ -108,11 +108,11 @@ class InvoiceParticipantMapper company_name: source.companyName.toPrimitive(), billingAddress: ( - this.props.addressMapper as IInvoiceParticipantAddressMapper + this.props.addressMapper as ICustomerInvoiceParticipantAddressMapper ).mapToPersistence(source.billingAddress!, { sourceParent: source }), shippingAddress: ( - this.props.addressMapper as IInvoiceParticipantAddressMapper + this.props.addressMapper as ICustomerInvoiceParticipantAddressMapper ).mapToPersistence(source.shippingAddress!, { sourceParent: source }), }; } diff --git a/modules/invoices/src/api/infrastructure/mappers/invoiceParticipantAddress.mapper.ts.bak b/modules/customer-invoices/src/api/infrastructure/mappers/customer-invoiceParticipantAddress.mapper.ts.bak similarity index 60% rename from modules/invoices/src/api/infrastructure/mappers/invoiceParticipantAddress.mapper.ts.bak rename to modules/customer-invoices/src/api/infrastructure/mappers/customer-invoiceParticipantAddress.mapper.ts.bak index 1e898f64..519ea617 100644 --- a/modules/invoices/src/api/infrastructure/mappers/invoiceParticipantAddress.mapper.ts.bak +++ b/modules/customer-invoices/src/api/infrastructure/mappers/customer-invoiceParticipantAddress.mapper.ts.bak @@ -11,39 +11,39 @@ import { UniqueID, } from "@shared/contexts"; import { - IInvoiceParticipantAddressProps, - InvoiceCustomer, - InvoiceParticipantAddress, + ICustomerInvoiceParticipantAddressProps, + CustomerInvoiceCustomer, + CustomerInvoiceParticipantAddress, } from "../../domain"; import { IInvoicingContext } from "../InvoicingContext"; import { - InvoiceParticipantAddress_Model, - TCreationInvoiceParticipantAddress_Model, + CustomerInvoiceParticipantAddress_Model, + TCreationCustomerInvoiceParticipantAddress_Model, } from "../sequelize"; -export interface IInvoiceParticipantAddressMapper +export interface ICustomerInvoiceParticipantAddressMapper extends ISequelizeMapper< - InvoiceParticipantAddress_Model, - TCreationInvoiceParticipantAddress_Model, - InvoiceParticipantAddress + CustomerInvoiceParticipantAddress_Model, + TCreationCustomerInvoiceParticipantAddress_Model, + CustomerInvoiceParticipantAddress > {} -export const createInvoiceParticipantAddressMapper = ( +export const createCustomerInvoiceParticipantAddressMapper = ( context: IInvoicingContext -): IInvoiceParticipantAddressMapper => new InvoiceParticipantAddressMapper({ context }); +): ICustomerInvoiceParticipantAddressMapper => new CustomerInvoiceParticipantAddressMapper({ context }); -class InvoiceParticipantAddressMapper +class CustomerInvoiceParticipantAddressMapper extends SequelizeMapper< - InvoiceParticipantAddress_Model, - TCreationInvoiceParticipantAddress_Model, - InvoiceParticipantAddress + CustomerInvoiceParticipantAddress_Model, + TCreationCustomerInvoiceParticipantAddress_Model, + CustomerInvoiceParticipantAddress > - implements IInvoiceParticipantAddressMapper + implements ICustomerInvoiceParticipantAddressMapper { - protected toDomainMappingImpl(source: InvoiceParticipantAddress_Model, params: any) { + protected toDomainMappingImpl(source: CustomerInvoiceParticipantAddress_Model, params: any) { const id = this.mapsValue(source, "address_id", UniqueID.create); - const props: IInvoiceParticipantAddressProps = { + const props: ICustomerInvoiceParticipantAddressProps = { type: source.type, street: this.mapsValue(source, "street", Street.create), city: this.mapsValue(source, "city", City.create), @@ -55,7 +55,7 @@ class InvoiceParticipantAddressMapper notes: this.mapsValue(source, "notes", Note.create), }; - const addressOrError = InvoiceParticipantAddress.create(props, id); + const addressOrError = CustomerInvoiceParticipantAddress.create(props, id); if (addressOrError.isFailure) { throw addressOrError.error; @@ -65,8 +65,8 @@ class InvoiceParticipantAddressMapper } protected toPersistenceMappingImpl( - source: InvoiceParticipantAddress, - params: { sourceParent: InvoiceCustomer } + source: CustomerInvoiceParticipantAddress, + params: { sourceParent: CustomerInvoiceCustomer } ) { const { sourceParent } = params; diff --git a/modules/customer-invoices/src/api/infrastructure/mappers/index.ts b/modules/customer-invoices/src/api/infrastructure/mappers/index.ts new file mode 100644 index 00000000..35281a9e --- /dev/null +++ b/modules/customer-invoices/src/api/infrastructure/mappers/index.ts @@ -0,0 +1 @@ +export * from "./customerCustomerInvoice.mapper"; diff --git a/modules/invoices/src/api/infrastructure/sequelize/contact.mo.del.ts.bak b/modules/customer-invoices/src/api/infrastructure/sequelize/contact.mo.del.ts.bak similarity index 100% rename from modules/invoices/src/api/infrastructure/sequelize/contact.mo.del.ts.bak rename to modules/customer-invoices/src/api/infrastructure/sequelize/contact.mo.del.ts.bak diff --git a/modules/invoices/src/api/infrastructure/sequelize/contactAddress.mo.del.ts.bak b/modules/customer-invoices/src/api/infrastructure/sequelize/contactAddress.mo.del.ts.bak similarity index 100% rename from modules/invoices/src/api/infrastructure/sequelize/contactAddress.mo.del.ts.bak rename to modules/customer-invoices/src/api/infrastructure/sequelize/contactAddress.mo.del.ts.bak diff --git a/modules/invoices/src/api/infrastructure/sequelize/invoice-item.model.ts b/modules/customer-invoices/src/api/infrastructure/sequelize/customer-invoice-item.model.ts similarity index 79% rename from modules/invoices/src/api/infrastructure/sequelize/invoice-item.model.ts rename to modules/customer-invoices/src/api/infrastructure/sequelize/customer-invoice-item.model.ts index ae856aab..d41b0e87 100644 --- a/modules/invoices/src/api/infrastructure/sequelize/invoice-item.model.ts +++ b/modules/customer-invoices/src/api/infrastructure/sequelize/customer-invoice-item.model.ts @@ -7,19 +7,19 @@ import { NonAttribute, Sequelize, } from "sequelize"; -import { InvoiceModel } from "./invoice.model"; +import { CustomerInvoiceModel } from "./customerCustomerInvoice.model"; -export type InvoiceItemCreationAttributes = InferCreationAttributes< - InvoiceItemModel, - { omit: "invoice" } +export type CustomerInvoiceItemCreationAttributes = InferCreationAttributes< + CustomerInvoiceItemModel, + { omit: "customerCustomerInvoice" } >; -export class InvoiceItemModel extends Model< - InferAttributes, - InferCreationAttributes +export class CustomerInvoiceItemModel extends Model< + InferAttributes, + InferCreationAttributes > { declare item_id: string; - declare invoice_id: string; + declare customerCustomerInvoice_id: string; declare parent_id: CreationOptional; declare position: number; @@ -42,27 +42,27 @@ export class InvoiceItemModel extends Model< declare total_amount: CreationOptional; declare total_scale: CreationOptional; - declare invoice: NonAttribute; + declare customerCustomerInvoice: NonAttribute; static associate(database: Sequelize) { - /*const { Invoice_Model, InvoiceItem_Model } = connection.models; + /*const { CustomerInvoice_Model, CustomerInvoiceItem_Model } = connection.models; - InvoiceItem_Model.belongsTo(Invoice_Model, { - as: "invoice", - foreignKey: "invoice_id", + CustomerInvoiceItem_Model.belongsTo(CustomerInvoice_Model, { + as: "customerCustomerInvoice", + foreignKey: "customerCustomerInvoice_id", onDelete: "CASCADE", });*/ } } export default (database: Sequelize) => { - InvoiceItemModel.init( + CustomerInvoiceItemModel.init( { item_id: { type: new DataTypes.UUID(), primaryKey: true, }, - invoice_id: { + customerCustomerInvoice_id: { type: new DataTypes.UUID(), primaryKey: true, }, @@ -159,7 +159,7 @@ export default (database: Sequelize) => { }, { sequelize: database, - tableName: "invoice_items", + tableName: "customerCustomerInvoice_items", defaultScope: {}, @@ -167,5 +167,5 @@ export default (database: Sequelize) => { } ); - return InvoiceItemModel; + return CustomerInvoiceItemModel; }; diff --git a/modules/invoices/src/api/infrastructure/sequelize/invoice.model.ts b/modules/customer-invoices/src/api/infrastructure/sequelize/customer-invoice.model.ts similarity index 62% rename from modules/invoices/src/api/infrastructure/sequelize/invoice.model.ts rename to modules/customer-invoices/src/api/infrastructure/sequelize/customer-invoice.model.ts index 1d4bb7ca..b473b2ae 100644 --- a/modules/invoices/src/api/infrastructure/sequelize/invoice.model.ts +++ b/modules/customer-invoices/src/api/infrastructure/sequelize/customer-invoice.model.ts @@ -7,25 +7,25 @@ import { NonAttribute, Sequelize, } from "sequelize"; -import { InvoiceItemCreationAttributes, InvoiceItemModel } from "./invoice-item.model"; +import { CustomerInvoiceItemCreationAttributes, CustomerInvoiceItemModel } from "./customerCustomerInvoice-item.model"; -export type InvoiceCreationAttributes = InferCreationAttributes & { - items?: InvoiceItemCreationAttributes[]; +export type CustomerInvoiceCreationAttributes = InferCreationAttributes & { + items?: CustomerInvoiceItemCreationAttributes[]; }; -export class InvoiceModel extends Model< - InferAttributes, - InferCreationAttributes +export class CustomerInvoiceModel extends Model< + InferAttributes, + InferCreationAttributes > { declare id: string; - declare invoice_status: string; - declare invoice_series: CreationOptional; - declare invoice_number: CreationOptional; + declare customerCustomerInvoice_status: string; + declare customerCustomerInvoice_series: CreationOptional; + declare customerCustomerInvoice_number: CreationOptional; declare issue_date: CreationOptional; declare operation_date: CreationOptional; - declare invoice_language: string; - declare invoice_currency: string; + declare customerCustomerInvoice_language: string; + declare customerCustomerInvoice_currency: string; // Subtotal declare subtotal_amount: CreationOptional; @@ -36,40 +36,40 @@ export class InvoiceModel extends Model< declare total_scale: CreationOptional; // Relaciones - declare items: NonAttribute; - //declare customer: NonAttribute; + declare items: NonAttribute; + //declare customer: NonAttribute; static associate(database: Sequelize) { - const { InvoiceModel, InvoiceItemModel } = database.models; + const { CustomerInvoiceModel, CustomerInvoiceItemModel } = database.models; - InvoiceModel.hasMany(InvoiceItemModel, { + CustomerInvoiceModel.hasMany(CustomerInvoiceItemModel, { as: "items", - foreignKey: "invoice_id", + foreignKey: "customerCustomerInvoice_id", onDelete: "CASCADE", }); } } export default (database: Sequelize) => { - InvoiceModel.init( + CustomerInvoiceModel.init( { id: { type: new DataTypes.UUID(), primaryKey: true, }, - invoice_status: { + customerCustomerInvoice_status: { type: new DataTypes.STRING(), allowNull: false, }, - invoice_series: { + customerCustomerInvoice_series: { type: new DataTypes.STRING(), allowNull: true, defaultValue: null, }, - invoice_number: { + customerCustomerInvoice_number: { type: new DataTypes.STRING(), allowNull: true, defaultValue: null, @@ -87,12 +87,12 @@ export default (database: Sequelize) => { defaultValue: null, }, - invoice_language: { + customerCustomerInvoice_language: { type: new DataTypes.STRING(), allowNull: false, }, - invoice_currency: { + customerCustomerInvoice_currency: { type: new DataTypes.STRING(3), // ISO 4217 allowNull: false, }, @@ -121,7 +121,7 @@ export default (database: Sequelize) => { }, { sequelize: database, - tableName: "invoices", + tableName: "customerCustomerInvoices", paranoid: true, // softs deletes timestamps: true, @@ -130,7 +130,7 @@ export default (database: Sequelize) => { updatedAt: "updated_at", deletedAt: "deleted_at", - indexes: [{ unique: true, fields: ["invoice_number"] }], + indexes: [{ unique: true, fields: ["customerCustomerInvoice_number"] }], whereMergeStrategy: "and", // <- cómo tratar el merge de un scope @@ -140,5 +140,5 @@ export default (database: Sequelize) => { } ); - return InvoiceModel; + return CustomerInvoiceModel; }; diff --git a/modules/customer-invoices/src/api/infrastructure/sequelize/customer-invoice.repository.ts b/modules/customer-invoices/src/api/infrastructure/sequelize/customer-invoice.repository.ts new file mode 100644 index 00000000..a0ea0d06 --- /dev/null +++ b/modules/customer-invoices/src/api/infrastructure/sequelize/customer-invoice.repository.ts @@ -0,0 +1,107 @@ +import { SequelizeRepository } from "@erp/core/api"; +import { Criteria } from "@repo/rdx-criteria/server"; +import { UniqueID } from "@repo/rdx-ddd"; +import { Collection, Result } from "@repo/rdx-utils"; +import { Sequelize, Transaction } from "sequelize"; +import { ICustomerInvoiceRepository, CustomerInvoice } from "../../domain"; +import { ICustomerInvoiceMapper } from "../mappers/customerCustomerInvoice.mapper"; +import { CustomerInvoiceItemModel } from "./customerCustomerInvoice-item.model"; +import { CustomerInvoiceModel } from "./customerCustomerInvoice.model"; + +export class CustomerInvoiceRepository extends SequelizeRepository implements ICustomerInvoiceRepository { + private readonly _mapper!: ICustomerInvoiceMapper; + + /** + * 🔹 Función personalizada para mapear errores de unicidad en autenticación + */ + private _customErrorMapper(error: Error): string | null { + if (error.name === "SequelizeUniqueConstraintError") { + return "CustomerInvoice with this email already exists"; + } + + return null; + } + + constructor(database: Sequelize, mapper: ICustomerInvoiceMapper) { + super(database); + this._mapper = mapper; + } + + async customerCustomerInvoiceExists(id: UniqueID, transaction?: Transaction): Promise> { + try { + const _customerCustomerInvoice = await this._getById(CustomerInvoiceModel, id, {}, transaction); + + return Result.ok(Boolean(id.equals(_customerCustomerInvoice.id))); + } catch (error: any) { + return this._handleDatabaseError(error, this._customErrorMapper); + } + } + + async findAll( + criteria: Criteria, + transaction?: Transaction + ): Promise, Error>> { + try { + const rawCustomerInvoices = await CustomerInvoiceModel.findAll({ + include: [ + { + model: CustomerInvoiceItemModel, + as: "items", + }, + ], + transaction, + ...this.convertCriteria(criteria), + }); + + console.error("aqui"); + + return this._mapper.mapArrayToDomain(rawCustomerInvoices); + } catch (error: unknown) { + console.error("Error in findAll", error); + return this._handleDatabaseError(error, this._customErrorMapper); + } + } + + async getById(id: UniqueID, transaction?: Transaction): Promise> { + try { + const rawCustomerInvoice: any = await this._getById( + CustomerInvoiceModel, + id, + { + include: [ + { + model: CustomerInvoiceItemModel, + as: "items", + }, + ], + }, + transaction + ); + + if (!rawCustomerInvoice === true) { + return Result.fail(new Error(`CustomerInvoice with id ${id.toString()} not exists`)); + } + } catch (error: any) { + return this._handleDatabaseError(error, this._customErrorMapper); + } + } + + async deleteById(id: UniqueID, transaction?: Transaction): Promise> { + try { + this._deleteById(CustomerInvoiceModel, id, false, transaction); + return Result.ok(true); + } catch (error: any) { + return this._handleDatabaseError(error, this._customErrorMapper); + } + } + + async create(customerCustomerInvoice: CustomerInvoice, transaction?: Transaction): Promise { + const customerCustomerInvoiceData = this._mapper.mapToPersistence(customerCustomerInvoice); + await this._save(CustomerInvoiceModel, customerCustomerInvoice.id, customerCustomerInvoiceData, {}, transaction); + } + + async update(customerCustomerInvoice: CustomerInvoice, transaction?: Transaction): Promise { + const customerCustomerInvoiceData = this._mapper.mapToPersistence(customerCustomerInvoice); + await this._save(CustomerInvoiceModel, customerCustomerInvoice.id, customerCustomerInvoiceData, {}, transaction); + } +} diff --git a/modules/customer-invoices/src/api/infrastructure/sequelize/customer-invoiceParticipant.mo.del.ts.bak b/modules/customer-invoices/src/api/infrastructure/sequelize/customer-invoiceParticipant.mo.del.ts.bak new file mode 100644 index 00000000..02853177 --- /dev/null +++ b/modules/customer-invoices/src/api/infrastructure/sequelize/customer-invoiceParticipant.mo.del.ts.bak @@ -0,0 +1,106 @@ +import { + CreationOptional, + DataTypes, + InferAttributes, + InferCreationAttributes, + Model, + NonAttribute, + Sequelize, +} from "sequelize"; +import { CustomerInvoiceModel } from "./customerCustomerInvoice.model"; +import { + CustomerInvoiceParticipantAddress_Model, + TCreationCustomerInvoiceParticipantAddress_Model, +} from "./customerCustomerInvoiceParticipantAddress.mo.del.ts.bak"; + +export type TCreationCustomerInvoiceParticipant_Model = InferCreationAttributes< + CustomerInvoiceParticipant_Model, + { omit: "shippingAddress" | "billingAddress" | "customerCustomerInvoice" } +> & { + billingAddress: TCreationCustomerInvoiceParticipantAddress_Model; + shippingAddress: TCreationCustomerInvoiceParticipantAddress_Model; +}; + +export class CustomerInvoiceParticipant_Model extends Model< + InferAttributes< + CustomerInvoiceParticipant_Model, + { omit: "shippingAddress" | "billingAddress" | "customerCustomerInvoice" } + >, + InferCreationAttributes< + CustomerInvoiceParticipant_Model, + { omit: "shippingAddress" | "billingAddress" | "customerCustomerInvoice" } + > +> { + static associate(connection: Sequelize) { + const { CustomerInvoice_Model, CustomerInvoiceParticipantAddress_Model, CustomerInvoiceParticipant_Model } = + connection.models; + + CustomerInvoiceParticipant_Model.belongsTo(CustomerInvoice_Model, { + as: "customerCustomerInvoice", + foreignKey: "customerCustomerInvoice_id", + onDelete: "CASCADE", + }); + + CustomerInvoiceParticipant_Model.hasOne(CustomerInvoiceParticipantAddress_Model, { + as: "shippingAddress", + foreignKey: "participant_id", + onDelete: "CASCADE", + }); + + CustomerInvoiceParticipant_Model.hasOne(CustomerInvoiceParticipantAddress_Model, { + as: "billingAddress", + foreignKey: "participant_id", + onDelete: "CASCADE", + }); + } + + declare participant_id: string; + declare customerCustomerInvoice_id: string; + declare tin: CreationOptional; + declare company_name: CreationOptional; + declare first_name: CreationOptional; + declare last_name: CreationOptional; + + declare shippingAddress?: NonAttribute; + declare billingAddress?: NonAttribute; + + declare customerCustomerInvoice?: NonAttribute; +} + +export default (sequelize: Sequelize) => { + CustomerInvoiceParticipant_Model.init( + { + participant_id: { + type: new DataTypes.UUID(), + primaryKey: true, + }, + customerCustomerInvoice_id: { + type: new DataTypes.UUID(), + primaryKey: true, + }, + tin: { + type: new DataTypes.STRING(), + allowNull: true, + }, + company_name: { + type: new DataTypes.STRING(), + allowNull: true, + }, + first_name: { + type: new DataTypes.STRING(), + allowNull: true, + }, + last_name: { + type: new DataTypes.STRING(), + allowNull: true, + }, + }, + { + sequelize, + tableName: "customerCustomerInvoice_participants", + timestamps: false, + } + ); + + return CustomerInvoiceParticipant_Model; +}; diff --git a/modules/invoices/src/api/infrastructure/sequelize/invoiceParticipantAddress.mo.del.ts.bak b/modules/customer-invoices/src/api/infrastructure/sequelize/customer-invoiceParticipantAddress.mo.del.ts.bak similarity index 64% rename from modules/invoices/src/api/infrastructure/sequelize/invoiceParticipantAddress.mo.del.ts.bak rename to modules/customer-invoices/src/api/infrastructure/sequelize/customer-invoiceParticipantAddress.mo.del.ts.bak index e7e14d9e..3c638d21 100644 --- a/modules/invoices/src/api/infrastructure/sequelize/invoiceParticipantAddress.mo.del.ts.bak +++ b/modules/customer-invoices/src/api/infrastructure/sequelize/customer-invoiceParticipantAddress.mo.del.ts.bak @@ -7,20 +7,20 @@ import { NonAttribute, Sequelize, } from "sequelize"; -import { InvoiceParticipant_Model } from "./invoiceParticipant.mo.del.ts.bak"; +import { CustomerInvoiceParticipant_Model } from "./customerCustomerInvoiceParticipant.mo.del.ts.bak"; -export type TCreationInvoiceParticipantAddress_Model = InferCreationAttributes< - InvoiceParticipantAddress_Model, +export type TCreationCustomerInvoiceParticipantAddress_Model = InferCreationAttributes< + CustomerInvoiceParticipantAddress_Model, { omit: "participant" } >; -export class InvoiceParticipantAddress_Model extends Model< - InferAttributes, - InferCreationAttributes +export class CustomerInvoiceParticipantAddress_Model extends Model< + InferAttributes, + InferCreationAttributes > { static associate(connection: Sequelize) { - const { InvoiceParticipantAddress_Model, InvoiceParticipant_Model } = connection.models; - InvoiceParticipantAddress_Model.belongsTo(InvoiceParticipant_Model, { + const { CustomerInvoiceParticipantAddress_Model, CustomerInvoiceParticipant_Model } = connection.models; + CustomerInvoiceParticipantAddress_Model.belongsTo(CustomerInvoiceParticipant_Model, { as: "participant", foreignKey: "participant_id", }); @@ -37,11 +37,11 @@ export class InvoiceParticipantAddress_Model extends Model< declare phone: CreationOptional; declare email: CreationOptional; - declare participant?: NonAttribute; + declare participant?: NonAttribute; } export default (sequelize: Sequelize) => { - InvoiceParticipantAddress_Model.init( + CustomerInvoiceParticipantAddress_Model.init( { address_id: { type: new DataTypes.UUID(), @@ -86,9 +86,9 @@ export default (sequelize: Sequelize) => { }, { sequelize, - tableName: "invoice_participant_addresses", + tableName: "customerCustomerInvoice_participant_addresses", } ); - return InvoiceParticipantAddress_Model; + return CustomerInvoiceParticipantAddress_Model; }; diff --git a/modules/customer-invoices/src/api/infrastructure/sequelize/index.ts b/modules/customer-invoices/src/api/infrastructure/sequelize/index.ts new file mode 100644 index 00000000..6af5daf1 --- /dev/null +++ b/modules/customer-invoices/src/api/infrastructure/sequelize/index.ts @@ -0,0 +1,9 @@ +import customerCustomerInvoiceItemModelInit from "./customerCustomerInvoice-item.model"; +import customerCustomerInvoiceModelInit from "./customerCustomerInvoice.model"; + +export * from "./customerCustomerInvoice-item.model"; // exporta las clases, tipos +export * from "./customerCustomerInvoice.model"; +export * from "./customerCustomerInvoice.repository"; + +// Array de inicializadores para que registerModels() lo use +export const models = [customerCustomerInvoiceItemModelInit, customerCustomerInvoiceModelInit]; diff --git a/modules/customer-invoices/src/api/presentation/delete-invoice/delete-invoice.controller.ts.bak b/modules/customer-invoices/src/api/presentation/delete-invoice/delete-invoice.controller.ts.bak new file mode 100644 index 00000000..13b28f26 --- /dev/null +++ b/modules/customer-invoices/src/api/presentation/delete-invoice/delete-invoice.controller.ts.bak @@ -0,0 +1,12 @@ +import { DeleteCustomerInvoiceUseCase } from "@/contexts/customerCustomerInvoices/application"; +import { ExpressController } from "@/core/common/presentation"; + +export class DeleteCustomerInvoiceController extends ExpressController { + public constructor(private readonly deleteCustomerInvoice: DeleteCustomerInvoiceUseCase) { + super(); + } + + async executeImpl(): Promise { + return this.noContent(); + } +} diff --git a/modules/customer-invoices/src/api/presentation/delete-invoice/index.ts.bak b/modules/customer-invoices/src/api/presentation/delete-invoice/index.ts.bak new file mode 100644 index 00000000..4b9084ed --- /dev/null +++ b/modules/customer-invoices/src/api/presentation/delete-invoice/index.ts.bak @@ -0,0 +1,14 @@ +import { DeleteCustomerInvoiceUseCase } from "@/contexts/customerCustomerInvoices/application"; +import { CustomerInvoiceService } from "@/contexts/customerCustomerInvoices/domain"; +import { customerCustomerInvoiceRepository } from "@/contexts/customerCustomerInvoices/intrastructure"; +import { SequelizeTransactionManager } from "@/core/common/infrastructure"; +import { DeleteCustomerInvoiceController } from "./delete-customer-invoice.controller"; + +export const buildDeleteCustomerInvoiceController = () => { + const transactionManager = new SequelizeTransactionManager(); + const customerCustomerInvoiceService = new CustomerInvoiceService(customerCustomerInvoiceRepository); + + const useCase = new DeleteCustomerInvoiceUseCase(customerCustomerInvoiceService, transactionManager); + + return new DeleteCustomerInvoiceController(useCase); +}; diff --git a/modules/customer-invoices/src/api/presentation/get-invoice/get-invoice.controller.ts b/modules/customer-invoices/src/api/presentation/get-invoice/get-invoice.controller.ts new file mode 100644 index 00000000..97bbe63c --- /dev/null +++ b/modules/customer-invoices/src/api/presentation/get-invoice/get-invoice.controller.ts @@ -0,0 +1,44 @@ +import { ExpressController } from "@erp/core/api"; +import { UniqueID } from "@repo/rdx-ddd"; +import { GetCustomerInvoiceUseCase } from "../../application"; +import { IGetCustomerInvoicePresenter } from "./presenter"; + +export class GetCustomerInvoiceController extends ExpressController { + public constructor( + private readonly getCustomerInvoice: GetCustomerInvoiceUseCase, + private readonly presenter: IGetCustomerInvoicePresenter + ) { + super(); + } + + protected async executeImpl() { + const { customerCustomerInvoiceId } = this.req.params; + + // Validar ID + const customerCustomerInvoiceIdOrError = UniqueID.create(customerCustomerInvoiceId); + if (customerCustomerInvoiceIdOrError.isFailure) return this.invalidInputError("CustomerInvoice ID not valid"); + + const customerCustomerInvoiceOrError = await this.getCustomerInvoice.execute(customerCustomerInvoiceIdOrError.data); + + if (customerCustomerInvoiceOrError.isFailure) { + return this.handleError(customerCustomerInvoiceOrError.error); + } + + return this.ok(this.presenter.toDTO(customerCustomerInvoiceOrError.data)); + } + + private handleError(error: Error) { + const message = error.message; + + if ( + message.includes("Database connection lost") || + message.includes("Database request timed out") + ) { + return this.unavailableError( + "Database service is currently unavailable. Please try again later." + ); + } + + return this.conflictError(message); + } +} diff --git a/modules/customer-invoices/src/api/presentation/get-invoice/index.ts b/modules/customer-invoices/src/api/presentation/get-invoice/index.ts new file mode 100644 index 00000000..21e0d3d0 --- /dev/null +++ b/modules/customer-invoices/src/api/presentation/get-invoice/index.ts @@ -0,0 +1,24 @@ +import { SequelizeTransactionManager } from "@erp/core/api"; +import { Sequelize } from "sequelize"; +import { CustomerInvoiceService } from "../../domain"; +import { CustomerInvoiceRepository, customerCustomerInvoiceMapper } from "../../infrastructure"; + +import { GetCustomerInvoiceUseCase } from "../../application"; +import { GetCustomerInvoiceController } from "./get-customer-invoice.controller"; +import { getCustomerInvoicePresenter } from "./presenter"; + +export const buildGetCustomerInvoiceController = (database: Sequelize) => { + const transactionManager = new SequelizeTransactionManager(database); + const customerCustomerInvoiceRepository = new CustomerInvoiceRepository( + database, + customerCustomerInvoiceMapper + ); + const customerCustomerInvoiceService = new CustomerInvoiceService( + customerCustomerInvoiceRepository + ); + + const useCase = new GetCustomerInvoiceUseCase(customerCustomerInvoiceService, transactionManager); + const presenter = getCustomerInvoicePresenter; + + return new GetCustomerInvoiceController(useCase, presenter); +}; diff --git a/modules/invoices/src/api/presentation/get-invoice/presenter/InvoiceItem.presenter.ts.bak b/modules/customer-invoices/src/api/presentation/get-invoice/presenter/InvoiceItem.presenter.ts.bak similarity index 71% rename from modules/invoices/src/api/presentation/get-invoice/presenter/InvoiceItem.presenter.ts.bak rename to modules/customer-invoices/src/api/presentation/get-invoice/presenter/InvoiceItem.presenter.ts.bak index 72d37f0b..14bcb5d3 100644 --- a/modules/invoices/src/api/presentation/get-invoice/presenter/InvoiceItem.presenter.ts.bak +++ b/modules/customer-invoices/src/api/presentation/get-invoice/presenter/InvoiceItem.presenter.ts.bak @@ -1,10 +1,10 @@ -import { InvoiceItem } from "#/server/domain"; +import { CustomerInvoiceItem } from "#/server/domain"; import { IInvoicingContext } from "#/server/intrastructure"; import { Collection } from "@rdx/core"; -export const invoiceItemPresenter = (items: Collection, context: IInvoicingContext) => +export const customerCustomerInvoiceItemPresenter = (items: Collection, context: IInvoicingContext) => items.totalCount > 0 - ? items.items.map((item: InvoiceItem) => ({ + ? items.items.map((item: CustomerInvoiceItem) => ({ description: item.description.toString(), quantity: item.quantity.toString(), unit_measure: "", diff --git a/modules/customer-invoices/src/api/presentation/get-invoice/presenter/InvoiceParticipant.presenter.ts.bak b/modules/customer-invoices/src/api/presentation/get-invoice/presenter/InvoiceParticipant.presenter.ts.bak new file mode 100644 index 00000000..bc6cdebe --- /dev/null +++ b/modules/customer-invoices/src/api/presentation/get-invoice/presenter/InvoiceParticipant.presenter.ts.bak @@ -0,0 +1,26 @@ +import { ICustomerInvoiceParticipant } from "@/contexts/invoicing/domain"; +import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext"; +import { ICreateCustomerInvoice_Participant_Response_DTO } from "@shared/contexts"; +import { CustomerInvoiceParticipantAddressPresenter } from "./CustomerInvoiceParticipantAddress.presenter"; + +export const CustomerInvoiceParticipantPresenter = async ( + participant: ICustomerInvoiceParticipant, + context: IInvoicingContext, +): Promise => { + return { + id: participant.id.toString(), + tin: participant.tin.toString(), + first_name: participant.firstName.toString(), + last_name: participant.lastName.toString(), + company_name: participant.companyName.toString(), + + billing_address: await CustomerInvoiceParticipantAddressPresenter( + participant.billingAddress!, + context, + ), + shipping_address: await CustomerInvoiceParticipantAddressPresenter( + participant.shippingAddress!, + context, + ), + }; +}; diff --git a/modules/invoices/src/api/presentation/get-invoice/presenter/InvoiceParticipantAddress.presenter.ts.bak b/modules/customer-invoices/src/api/presentation/get-invoice/presenter/InvoiceParticipantAddress.presenter.ts.bak similarity index 55% rename from modules/invoices/src/api/presentation/get-invoice/presenter/InvoiceParticipantAddress.presenter.ts.bak rename to modules/customer-invoices/src/api/presentation/get-invoice/presenter/InvoiceParticipantAddress.presenter.ts.bak index 15478c1b..b006790b 100644 --- a/modules/invoices/src/api/presentation/get-invoice/presenter/InvoiceParticipantAddress.presenter.ts.bak +++ b/modules/customer-invoices/src/api/presentation/get-invoice/presenter/InvoiceParticipantAddress.presenter.ts.bak @@ -1,11 +1,11 @@ -import { InvoiceParticipantAddress } from "@/contexts/invoicing/domain"; +import { CustomerInvoiceParticipantAddress } from "@/contexts/invoicing/domain"; import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext"; -import { ICreateInvoice_AddressParticipant_Response_DTO } from "@shared/contexts"; +import { ICreateCustomerInvoice_AddressParticipant_Response_DTO } from "@shared/contexts"; -export const InvoiceParticipantAddressPresenter = async ( - address: InvoiceParticipantAddress, +export const CustomerInvoiceParticipantAddressPresenter = async ( + address: CustomerInvoiceParticipantAddress, context: IInvoicingContext, -): Promise => { +): Promise => { return { id: address.id.toString(), street: address.street.toString(), diff --git a/modules/customer-invoices/src/api/presentation/get-invoice/presenter/get-invoice.presenter.ts b/modules/customer-invoices/src/api/presentation/get-invoice/presenter/get-invoice.presenter.ts new file mode 100644 index 00000000..9a4fdd93 --- /dev/null +++ b/modules/customer-invoices/src/api/presentation/get-invoice/presenter/get-invoice.presenter.ts @@ -0,0 +1,59 @@ +import { IGetCustomerInvoiceResponseDTO } from "../../../../../common/dto"; +import { CustomerInvoice, CustomerInvoiceItem } from "../../../../domain"; + +export interface IGetCustomerInvoicePresenter { + toDTO: (customerCustomerInvoice: CustomerInvoice) => IGetCustomerInvoiceResponseDTO; +} + +export const getCustomerInvoicePresenter: IGetCustomerInvoicePresenter = { + toDTO: (customerCustomerInvoice: CustomerInvoice): IGetCustomerInvoiceResponseDTO => ({ + id: customerCustomerInvoice.id.toPrimitive(), + + customerCustomerInvoice_status: customerCustomerInvoice.status.toString(), + customerCustomerInvoice_number: customerCustomerInvoice.customerCustomerInvoiceNumber.toString(), + customerCustomerInvoice_series: customerCustomerInvoice.customerCustomerInvoiceSeries.toString(), + issue_date: customerCustomerInvoice.issueDate.toDateString(), + operation_date: customerCustomerInvoice.operationDate.toDateString(), + language_code: "ES", + currency: customerCustomerInvoice.customerCustomerInvoiceCurrency.toString(), + subtotal: customerCustomerInvoice.calculateSubtotal().toPrimitive(), + total: customerCustomerInvoice.calculateTotal().toPrimitive(), + + items: + customerCustomerInvoice.items.size() > 0 + ? customerCustomerInvoice.items.map((item: CustomerInvoiceItem) => ({ + description: item.description.toString(), + quantity: item.quantity.toPrimitive(), + unit_measure: "", + unit_price: item.unitPrice.toPrimitive(), + subtotal: item.calculateSubtotal().toPrimitive(), + //tax_amount: item.calculateTaxAmount().toPrimitive(), + total: item.calculateTotal().toPrimitive(), + })) + : [], + + //sender: {}, //await CustomerInvoiceParticipantPresenter(customerCustomerInvoice.senderId, context), + + /*recipient: await CustomerInvoiceParticipantPresenter(customerCustomerInvoice.recipient, context), + items: customerCustomerInvoiceItemPresenter(customerCustomerInvoice.items, context), + + payment_term: { + payment_type: "", + due_date: "", + }, + + due_amount: { + currency: customerCustomerInvoice.currency.toString(), + precision: 2, + amount: 0, + }, + + custom_fields: [], + + metadata: { + create_time: "", + last_updated_time: "", + delete_time: "", + },*/ + }), +}; diff --git a/modules/customer-invoices/src/api/presentation/get-invoice/presenter/index.ts b/modules/customer-invoices/src/api/presentation/get-invoice/presenter/index.ts new file mode 100644 index 00000000..cb348805 --- /dev/null +++ b/modules/customer-invoices/src/api/presentation/get-invoice/presenter/index.ts @@ -0,0 +1 @@ +export * from "./get-customer-invoice.presenter"; diff --git a/modules/customer-invoices/src/api/presentation/index.ts b/modules/customer-invoices/src/api/presentation/index.ts new file mode 100644 index 00000000..e8b38dc2 --- /dev/null +++ b/modules/customer-invoices/src/api/presentation/index.ts @@ -0,0 +1,5 @@ +//export * from "./create-customer-invoice"; +//export * from "./delete-customer-invoice"; +export * from "./get-customer-invoice"; +export * from "./list-customer-invoices"; +///export * from "./update-customer-invoice"; diff --git a/modules/customer-invoices/src/api/presentation/list-invoices/index.ts b/modules/customer-invoices/src/api/presentation/list-invoices/index.ts new file mode 100644 index 00000000..febf50e9 --- /dev/null +++ b/modules/customer-invoices/src/api/presentation/list-invoices/index.ts @@ -0,0 +1,26 @@ +import { SequelizeTransactionManager } from "@erp/core/api"; +import { Sequelize } from "sequelize"; +import { ListCustomerInvoicesUseCase } from "../../application"; +import { CustomerInvoiceService } from "../../domain"; +import { CustomerInvoiceRepository, customerCustomerInvoiceMapper } from "../../infrastructure"; +import { ListCustomerInvoicesController } from "./list-customer-invoices.controller"; +import { listCustomerInvoicesPresenter } from "./presenter"; + +export const buildListCustomerInvoicesController = (database: Sequelize) => { + const transactionManager = new SequelizeTransactionManager(database); + const customerCustomerInvoiceRepository = new CustomerInvoiceRepository( + database, + customerCustomerInvoiceMapper + ); + const customerCustomerInvoiceService = new CustomerInvoiceService( + customerCustomerInvoiceRepository + ); + + const useCase = new ListCustomerInvoicesUseCase( + customerCustomerInvoiceService, + transactionManager + ); + const presenter = listCustomerInvoicesPresenter; + + return new ListCustomerInvoicesController(useCase, presenter); +}; diff --git a/modules/customer-invoices/src/api/presentation/list-invoices/list-invoices.controller.ts b/modules/customer-invoices/src/api/presentation/list-invoices/list-invoices.controller.ts new file mode 100644 index 00000000..afe0e9ba --- /dev/null +++ b/modules/customer-invoices/src/api/presentation/list-invoices/list-invoices.controller.ts @@ -0,0 +1,38 @@ +import { ExpressController } from "@erp/core/api"; +import { ListCustomerInvoicesUseCase } from "../../application"; +import { IListCustomerInvoicesPresenter } from "./presenter"; + +export class ListCustomerInvoicesController extends ExpressController { + public constructor( + private readonly listCustomerInvoices: ListCustomerInvoicesUseCase, + private readonly presenter: IListCustomerInvoicesPresenter + ) { + super(); + } + + protected async executeImpl() { + const criteria = this.criteria; + const customerCustomerInvoicesOrError = await this.listCustomerInvoices.execute(criteria); + + if (customerCustomerInvoicesOrError.isFailure) { + return this.handleError(customerCustomerInvoicesOrError.error); + } + + return this.ok(this.presenter.toDTO(customerCustomerInvoicesOrError.data, criteria)); + } + + private handleError(error: Error) { + const message = error.message; + + if ( + message.includes("Database connection lost") || + message.includes("Database request timed out") + ) { + return this.unavailableError( + "Database service is currently unavailable. Please try again later." + ); + } + + return this.conflictError(message); + } +} diff --git a/modules/customer-invoices/src/api/presentation/list-invoices/presenter/InvoiceParticipant.presenter.ts.bak b/modules/customer-invoices/src/api/presentation/list-invoices/presenter/InvoiceParticipant.presenter.ts.bak new file mode 100644 index 00000000..c8c7ab3e --- /dev/null +++ b/modules/customer-invoices/src/api/presentation/list-invoices/presenter/InvoiceParticipant.presenter.ts.bak @@ -0,0 +1,22 @@ +import { ICustomerInvoiceParticipant } from "@/contexts/invoicing/domain"; +import { IListCustomerInvoice_Participant_Response_DTO } from "@shared/contexts"; +import { CustomerInvoiceParticipantAddressPresenter } from "./CustomerInvoiceParticipantAddress.presenter"; + +export const CustomerInvoiceParticipantPresenter = ( + participant: ICustomerInvoiceParticipant, +): IListCustomerInvoice_Participant_Response_DTO => { + return { + participant_id: participant?.id?.toString(), + tin: participant?.tin?.toString(), + first_name: participant?.firstName?.toString(), + last_name: participant?.lastName?.toString(), + company_name: participant?.companyName?.toString(), + + billing_address: CustomerInvoiceParticipantAddressPresenter( + participant?.billingAddress!, + ), + shipping_address: CustomerInvoiceParticipantAddressPresenter( + participant?.shippingAddress!, + ), + }; +}; diff --git a/modules/invoices/src/api/presentation/list-invoices/presenter/InvoiceParticipantAddress.presenter.ts.bak b/modules/customer-invoices/src/api/presentation/list-invoices/presenter/InvoiceParticipantAddress.presenter.ts.bak similarity index 67% rename from modules/invoices/src/api/presentation/list-invoices/presenter/InvoiceParticipantAddress.presenter.ts.bak rename to modules/customer-invoices/src/api/presentation/list-invoices/presenter/InvoiceParticipantAddress.presenter.ts.bak index a30b9007..33c1a123 100644 --- a/modules/invoices/src/api/presentation/list-invoices/presenter/InvoiceParticipantAddress.presenter.ts.bak +++ b/modules/customer-invoices/src/api/presentation/list-invoices/presenter/InvoiceParticipantAddress.presenter.ts.bak @@ -1,6 +1,6 @@ -export const InvoiceParticipantAddressPresenter = ( - address: InvoiceParticipantAddress -): IListInvoice_AddressParticipant_Response_DTO => { +export const CustomerInvoiceParticipantAddressPresenter = ( + address: CustomerInvoiceParticipantAddress +): IListCustomerInvoice_AddressParticipant_Response_DTO => { return { address_id: address?.id.toString(), street: address?.street.toString(), diff --git a/modules/customer-invoices/src/api/presentation/list-invoices/presenter/index.ts b/modules/customer-invoices/src/api/presentation/list-invoices/presenter/index.ts new file mode 100644 index 00000000..3db39470 --- /dev/null +++ b/modules/customer-invoices/src/api/presentation/list-invoices/presenter/index.ts @@ -0,0 +1 @@ +export * from "./list-customer-invoices.presenter"; diff --git a/modules/customer-invoices/src/api/presentation/list-invoices/presenter/list-invoices.presenter.ts b/modules/customer-invoices/src/api/presentation/list-invoices/presenter/list-invoices.presenter.ts new file mode 100644 index 00000000..cd1ddebc --- /dev/null +++ b/modules/customer-invoices/src/api/presentation/list-invoices/presenter/list-invoices.presenter.ts @@ -0,0 +1,54 @@ +import { IListResponseDTO } from "@erp/core/api"; +import { Criteria } from "@repo/rdx-criteria/server"; +import { Collection } from "@repo/rdx-utils"; +import { IListCustomerInvoicesResponseDTO } from "../../../../common/dto"; +import { CustomerInvoice } from "../../../domain"; + +export interface IListCustomerInvoicesPresenter { + toDTO: ( + customerCustomerInvoices: Collection, + criteria: Criteria + ) => IListResponseDTO; +} + +export const listCustomerInvoicesPresenter: IListCustomerInvoicesPresenter = { + toDTO: ( + customerCustomerInvoices: Collection, + criteria: Criteria + ): IListResponseDTO => { + const items = customerInvoices.map((customerCustomerInvoice) => { + return { + id: customerCustomerInvoice.id.toPrimitive(), + + customerCustomerInvoice_status: customerCustomerInvoice.status.toString(), + customerCustomerInvoice_number: + customerCustomerInvoice.customerCustomerInvoiceNumber.toString(), + customerCustomerInvoice_series: + customerCustomerInvoice.customerCustomerInvoiceSeries.toString(), + issue_date: customerCustomerInvoice.issueDate.toISOString(), + operation_date: customerCustomerInvoice.operationDate.toISOString(), + language_code: "ES", + + currency: customerCustomerInvoice.customerCustomerInvoiceCurrency.toString(), + subtotal: customerCustomerInvoice.calculateSubtotal().toPrimitive(), + total: customerCustomerInvoice.calculateTotal().toPrimitive(), + + //recipient: CustomerInvoiceParticipantPresenter(customerCustomerInvoice.recipient), + + metadata: { + entity: "customerCustomerInvoice", + }, + } as IListCustomerInvoicesResponseDTO; + }); + + const totalItems = customerInvoices.total(); + + return { + page: criteria.pageNumber, + per_page: criteria.pageSize, + total_pages: Math.ceil(totalItems / criteria.pageSize), + total_items: totalItems, + items: items, + }; + }, +}; diff --git a/modules/invoices/src/api/presentation/update-invoice/index.ts.bak b/modules/customer-invoices/src/api/presentation/update-invoice/index.ts.bak similarity index 50% rename from modules/invoices/src/api/presentation/update-invoice/index.ts.bak rename to modules/customer-invoices/src/api/presentation/update-invoice/index.ts.bak index 7dadbd9b..0cc6c60e 100644 --- a/modules/invoices/src/api/presentation/update-invoice/index.ts.bak +++ b/modules/customer-invoices/src/api/presentation/update-invoice/index.ts.bak @@ -1,37 +1,37 @@ import { IInvoicingContext } from "#/server/intrastructure"; -import { InvoiceRepository } from "#/server/intrastructure/Invoice.repository"; +import { CustomerInvoiceRepository } from "#/server/intrastructure/CustomerInvoice.repository"; -export const updateInvoiceController = (context: IInvoicingContext) => { +export const updateCustomerInvoiceController = (context: IInvoicingContext) => { const adapter = context.adapter; const repoManager = context.repositoryManager; - repoManager.registerRepository("Invoice", (params = { transaction: null }) => { + repoManager.registerRepository("CustomerInvoice", (params = { transaction: null }) => { const { transaction } = params; - return new InvoiceRepository({ + return new CustomerInvoiceRepository({ transaction, adapter, - mapper: createInvoiceMapper(context), + mapper: createCustomerInvoiceMapper(context), }); }); repoManager.registerRepository("Participant", (params = { transaction: null }) => { const { transaction } = params; - return new InvoiceParticipantRepository({ + return new CustomerInvoiceParticipantRepository({ transaction, adapter, - mapper: createInvoiceParticipantMapper(context), + mapper: createCustomerInvoiceParticipantMapper(context), }); }); repoManager.registerRepository("ParticipantAddress", (params = { transaction: null }) => { const { transaction } = params; - return new InvoiceParticipantAddressRepository({ + return new CustomerInvoiceParticipantAddressRepository({ transaction, adapter, - mapper: createInvoiceParticipantAddressMapper(context), + mapper: createCustomerInvoiceParticipantAddressMapper(context), }); }); @@ -45,12 +45,12 @@ export const updateInvoiceController = (context: IInvoicingContext) => { }); }); - const updateInvoiceUseCase = new UpdateInvoiceUseCase(context); + const updateCustomerInvoiceUseCase = new UpdateCustomerInvoiceUseCase(context); - return new UpdateInvoiceController( + return new UpdateCustomerInvoiceController( { - useCase: updateInvoiceUseCase, - presenter: updateInvoicePresenter, + useCase: updateCustomerInvoiceUseCase, + presenter: updateCustomerInvoicePresenter, }, context ); diff --git a/modules/invoices/src/api/presentation/update-invoice/presenter/InvoiceItem.presenter.ts.bak b/modules/customer-invoices/src/api/presentation/update-invoice/presenter/InvoiceItem.presenter.ts.bak similarity index 73% rename from modules/invoices/src/api/presentation/update-invoice/presenter/InvoiceItem.presenter.ts.bak rename to modules/customer-invoices/src/api/presentation/update-invoice/presenter/InvoiceItem.presenter.ts.bak index 3177298b..a47be083 100644 --- a/modules/invoices/src/api/presentation/update-invoice/presenter/InvoiceItem.presenter.ts.bak +++ b/modules/customer-invoices/src/api/presentation/update-invoice/presenter/InvoiceItem.presenter.ts.bak @@ -1,13 +1,13 @@ -import { InvoiceItem } from "@/contexts/invoicing/domain/InvoiceItems"; +import { CustomerInvoiceItem } from "@/contexts/invoicing/domain/CustomerInvoiceItems"; import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext"; import { ICollection, IMoney_Response_DTO } from "@shared/contexts"; -export const invoiceItemPresenter = ( - items: ICollection, +export const customerCustomerInvoiceItemPresenter = ( + items: ICollection, context: IInvoicingContext ) => items.totalCount > 0 - ? items.items.map((item: InvoiceItem) => ({ + ? items.items.map((item: CustomerInvoiceItem) => ({ description: item.description.toString(), quantity: item.quantity.toString(), unit_measure: "", diff --git a/modules/customer-invoices/src/api/presentation/update-invoice/presenter/InvoiceParticipant.presenter.ts.bak b/modules/customer-invoices/src/api/presentation/update-invoice/presenter/InvoiceParticipant.presenter.ts.bak new file mode 100644 index 00000000..00457233 --- /dev/null +++ b/modules/customer-invoices/src/api/presentation/update-invoice/presenter/InvoiceParticipant.presenter.ts.bak @@ -0,0 +1,26 @@ +import { ICustomerInvoiceParticipant } from "@/contexts/invoicing/domain"; +import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext"; +import { IUpdateCustomerInvoice_Participant_Response_DTO } from "@shared/contexts"; +import { CustomerInvoiceParticipantAddressPresenter } from "./CustomerInvoiceParticipantAddress.presenter"; + +export const CustomerInvoiceParticipantPresenter = ( + participant: ICustomerInvoiceParticipant, + context: IInvoicingContext, +): IUpdateCustomerInvoice_Participant_Response_DTO | undefined => { + return { + id: participant.id.toString(), + tin: participant.tin.toString(), + first_name: participant.firstName.toString(), + last_name: participant.lastName.toString(), + company_name: participant.companyName.toString(), + + billing_address: CustomerInvoiceParticipantAddressPresenter( + participant.billingAddress!, + context, + ), + shipping_address: CustomerInvoiceParticipantAddressPresenter( + participant.shippingAddress!, + context, + ), + }; +}; diff --git a/modules/invoices/src/api/presentation/update-invoice/presenter/InvoiceParticipantAddress.presenter.ts.bak b/modules/customer-invoices/src/api/presentation/update-invoice/presenter/InvoiceParticipantAddress.presenter.ts.bak similarity index 56% rename from modules/invoices/src/api/presentation/update-invoice/presenter/InvoiceParticipantAddress.presenter.ts.bak rename to modules/customer-invoices/src/api/presentation/update-invoice/presenter/InvoiceParticipantAddress.presenter.ts.bak index 376d491f..eeede21e 100644 --- a/modules/invoices/src/api/presentation/update-invoice/presenter/InvoiceParticipantAddress.presenter.ts.bak +++ b/modules/customer-invoices/src/api/presentation/update-invoice/presenter/InvoiceParticipantAddress.presenter.ts.bak @@ -1,11 +1,11 @@ -import { InvoiceParticipantAddress } from "@/contexts/invoicing/domain"; +import { CustomerInvoiceParticipantAddress } from "@/contexts/invoicing/domain"; import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext"; -import { IUpdateInvoice_AddressParticipant_Response_DTO } from "@shared/contexts"; +import { IUpdateCustomerInvoice_AddressParticipant_Response_DTO } from "@shared/contexts"; -export const InvoiceParticipantAddressPresenter = ( - address: InvoiceParticipantAddress, +export const CustomerInvoiceParticipantAddressPresenter = ( + address: CustomerInvoiceParticipantAddress, context: IInvoicingContext, -): IUpdateInvoice_AddressParticipant_Response_DTO => { +): IUpdateCustomerInvoice_AddressParticipant_Response_DTO => { return { id: address.id.toString(), street: address.street.toString(), diff --git a/modules/customer-invoices/src/api/presentation/update-invoice/presenter/UpdateInvoice.presenter.ts.bak b/modules/customer-invoices/src/api/presentation/update-invoice/presenter/UpdateInvoice.presenter.ts.bak new file mode 100644 index 00000000..59c5ad4c --- /dev/null +++ b/modules/customer-invoices/src/api/presentation/update-invoice/presenter/UpdateInvoice.presenter.ts.bak @@ -0,0 +1,33 @@ +import { CustomerInvoice } from "@/contexts/invoicing/domain"; +import { IInvoicingContext } from "@/contexts/invoicing/intrastructure/InvoicingContext"; +import { IUpdateCustomerInvoice_Response_DTO } from "@shared/contexts"; +import { customerCustomerInvoiceItemPresenter } from "./CustomerInvoiceItem.presenter"; +import { CustomerInvoiceParticipantPresenter } from "./CustomerInvoiceParticipant.presenter"; + +export interface IUpdateCustomerInvoicePresenter { + map: (customerCustomerInvoice: CustomerInvoice, context: IInvoicingContext) => IUpdateCustomerInvoice_Response_DTO; +} + +export const updateCustomerInvoicePresenter: IUpdateCustomerInvoicePresenter = { + map: (customerCustomerInvoice: CustomerInvoice, context: IInvoicingContext): IUpdateCustomerInvoice_Response_DTO => { + return { + id: customerCustomerInvoice.id.toString(), + + customerCustomerInvoice_status: customerCustomerInvoice.status.toString(), + customerCustomerInvoice_number: customerCustomerInvoice.customerCustomerInvoiceNumber.toString(), + customerCustomerInvoice_series: customerCustomerInvoice.customerCustomerInvoiceSeries.toString(), + issue_date: customerCustomerInvoice.issueDate.toISO8601(), + operation_date: customerCustomerInvoice.operationDate.toISO8601(), + language_code: customerCustomerInvoice.language.toString(), + currency: customerCustomerInvoice.currency.toString(), + subtotal: customerCustomerInvoice.calculateSubtotal().toPrimitive(), + total: customerCustomerInvoice.calculateTotal().toPrimitive(), + + //sender: {}, //await CustomerInvoiceParticipantPresenter(customerCustomerInvoice.senderId, context), + + recipient: CustomerInvoiceParticipantPresenter(customerCustomerInvoice.recipient, context), + + items: customerCustomerInvoiceItemPresenter(customerCustomerInvoice.items, context), + }; + }, +}; diff --git a/modules/customer-invoices/src/api/presentation/update-invoice/presenter/index.ts.bak b/modules/customer-invoices/src/api/presentation/update-invoice/presenter/index.ts.bak new file mode 100644 index 00000000..392a8a88 --- /dev/null +++ b/modules/customer-invoices/src/api/presentation/update-invoice/presenter/index.ts.bak @@ -0,0 +1 @@ +export * from "./UpdateCustomerInvoice.presenter"; diff --git a/modules/invoices/src/api/presentation/update-invoice/update-invoice.controller.ts.bak b/modules/customer-invoices/src/api/presentation/update-invoice/update-invoice.controller.ts.bak similarity index 57% rename from modules/invoices/src/api/presentation/update-invoice/update-invoice.controller.ts.bak rename to modules/customer-invoices/src/api/presentation/update-invoice/update-invoice.controller.ts.bak index 26005e3b..80e994fa 100644 --- a/modules/invoices/src/api/presentation/update-invoice/update-invoice.controller.ts.bak +++ b/modules/customer-invoices/src/api/presentation/update-invoice/update-invoice.controller.ts.bak @@ -1,16 +1,16 @@ import { IInvoicingContext } from "#/server/intrastructure"; import { ExpressController } from "@rdx/core"; -import { IUpdateInvoicePresenter } from "./presenter"; +import { IUpdateCustomerInvoicePresenter } from "./presenter"; -export class UpdateInvoiceController extends ExpressController { - private useCase: UpdateInvoiceUseCase2; - private presenter: IUpdateInvoicePresenter; +export class UpdateCustomerInvoiceController extends ExpressController { + private useCase: UpdateCustomerInvoiceUseCase2; + private presenter: IUpdateCustomerInvoicePresenter; private context: IInvoicingContext; constructor( props: { - useCase: UpdateInvoiceUseCase; - presenter: IUpdateInvoicePresenter; + useCase: UpdateCustomerInvoiceUseCase; + presenter: IUpdateCustomerInvoicePresenter; }, context: IInvoicingContext ) { @@ -23,16 +23,16 @@ export class UpdateInvoiceController extends ExpressController { } async executeImpl(): Promise { - const { invoiceId } = this.req.params; - const request: IUpdateInvoice_DTO = this.req.body; + const { customerCustomerInvoiceId } = this.req.params; + const request: IUpdateCustomerInvoice_DTO = this.req.body; - if (RuleValidator.validate(RuleValidator.RULE_NOT_NULL_OR_UNDEFINED, invoiceId).isFailure) { - return this.invalidInputError("Invoice Id param is required!"); + if (RuleValidator.validate(RuleValidator.RULE_NOT_NULL_OR_UNDEFINED, customerCustomerInvoiceId).isFailure) { + return this.invalidInputError("CustomerInvoice Id param is required!"); } - const idOrError = UniqueID.create(invoiceId); + const idOrError = UniqueID.create(customerCustomerInvoiceId); if (idOrError.isFailure) { - return this.invalidInputError("Invalid invoice Id param!"); + return this.invalidInputError("Invalid customerCustomerInvoice Id param!"); } try { @@ -46,7 +46,7 @@ export class UpdateInvoiceController extends ExpressController { switch (error.code) { case UseCaseError.NOT_FOUND_ERROR: - return this.notFoundError("Invoice not found", error); + return this.notFoundError("CustomerInvoice not found", error); case UseCaseError.INVALID_INPUT_DATA: return this.invalidInputError(error.message); @@ -62,9 +62,9 @@ export class UpdateInvoiceController extends ExpressController { } } - const invoice = result.object; + const customerCustomerInvoice = result.object; - return this.ok(this.presenter.map(invoice, this.context)); + return this.ok(this.presenter.map(customerCustomerInvoice, this.context)); } catch (e: unknown) { return this.fail(e as IServerError); } diff --git a/modules/invoices/src/common/dto/invoices.request.dto.ts b/modules/customer-invoices/src/common/dto/customer-invoices.request.dto.ts similarity index 66% rename from modules/invoices/src/common/dto/invoices.request.dto.ts rename to modules/customer-invoices/src/common/dto/customer-invoices.request.dto.ts index c37b3f7c..0d7adb4b 100644 --- a/modules/invoices/src/common/dto/invoices.request.dto.ts +++ b/modules/customer-invoices/src/common/dto/customer-invoices.request.dto.ts @@ -1,17 +1,17 @@ -export type IListInvoicesRequestDTO = {} +export type IListCustomerInvoicesRequestDTO = {} -export interface ICreateInvoiceRequestDTO { +export interface ICreateCustomerInvoiceRequestDTO { id: string; - invoice_number: string; - invoice_series: string; + customerCustomerInvoice_number: string; + customerCustomerInvoice_series: string; issue_date: string; operation_date: string; language_code: string; currency: string; } -export interface IUpdateInvoiceRequestDTO { +export interface IUpdateCustomerInvoiceRequestDTO { is_freelancer: boolean; name: string; trade_name: string; diff --git a/modules/invoices/src/common/dto/invoices.response.dto.ts b/modules/customer-invoices/src/common/dto/customer-invoices.response.dto.ts similarity index 60% rename from modules/invoices/src/common/dto/invoices.response.dto.ts rename to modules/customer-invoices/src/common/dto/customer-invoices.response.dto.ts index 204c568a..79667072 100644 --- a/modules/invoices/src/common/dto/invoices.response.dto.ts +++ b/modules/customer-invoices/src/common/dto/customer-invoices.response.dto.ts @@ -1,11 +1,11 @@ import { IMetadataDTO, IMoneyDTO, IQuantityDTO } from "@erp/core"; -export interface IListInvoicesResponseDTO { +export interface IListCustomerInvoicesResponseDTO { id: string; - invoice_status: string; - invoice_number: string; - invoice_series: string; + customerCustomerInvoice_status: string; + customerCustomerInvoice_number: string; + customerCustomerInvoice_series: string; issue_date: string; operation_date: string; language_code: string; @@ -17,12 +17,12 @@ export interface IListInvoicesResponseDTO { metadata?: IMetadataDTO; } -export interface IGetInvoiceResponseDTO { +export interface IGetCustomerInvoiceResponseDTO { id: string; - invoice_status: string; - invoice_number: string; - invoice_series: string; + customerCustomerInvoice_status: string; + customerCustomerInvoice_number: string; + customerCustomerInvoice_series: string; issue_date: string; operation_date: string; language_code: string; @@ -46,12 +46,12 @@ export interface IGetInvoiceResponseDTO { metadata?: IMetadataDTO; } -export interface ICreateInvoiceResponseDTO { +export interface ICreateCustomerInvoiceResponseDTO { id: string; - invoice_status: string; - invoice_number: string; - invoice_series: string; + customerCustomerInvoice_status: string; + customerCustomerInvoice_number: string; + customerCustomerInvoice_series: string; issue_date: string; operation_date: string; language_code: string; @@ -64,12 +64,12 @@ export interface ICreateInvoiceResponseDTO { // Inferir el tipo en TypeScript desde el esquema Zod //export type IUpdateAcccountResponseDTO = z.infer; -export interface IUpdateInvoiceResponseDTO { +export interface IUpdateCustomerInvoiceResponseDTO { id: string; - invoice_status: string; - invoice_number: string; - invoice_series: string; + customerCustomerInvoice_status: string; + customerCustomerInvoice_number: string; + customerCustomerInvoice_series: string; issue_date: string; operation_date: string; language_code: string; diff --git a/modules/invoices/src/common/dto/invoices.schemas.ts b/modules/customer-invoices/src/common/dto/customer-invoices.schemas.ts similarity index 77% rename from modules/invoices/src/common/dto/invoices.schemas.ts rename to modules/customer-invoices/src/common/dto/customer-invoices.schemas.ts index e07ec582..cf59efa5 100644 --- a/modules/invoices/src/common/dto/invoices.schemas.ts +++ b/modules/customer-invoices/src/common/dto/customer-invoices.schemas.ts @@ -1,9 +1,9 @@ import { z } from "zod"; -export const ICreateInvoiceRequestSchema = z.object({ +export const ICreateCustomerInvoiceRequestSchema = z.object({ id: z.string().uuid(), - invoice_number: z.string().min(1), - invoice_series: z.string().min(1), + customerCustomerInvoice_number: z.string().min(1), + customerCustomerInvoice_series: z.string().min(1), issue_date: z.string().refine((date) => { const dateStr = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Invalid YYYY-MM-DD format"); return dateStr.safeParse(date).success; @@ -38,6 +38,6 @@ export const ICreateInvoiceRequestSchema = z.object({ .optional(), }); -export const IUpdateInvoiceRequestSchema = z.object({}); +export const IUpdateCustomerInvoiceRequestSchema = z.object({}); -export const IDeleteInvoiceRequestSchema = z.object({}); +export const IDeleteCustomerInvoiceRequestSchema = z.object({}); diff --git a/modules/customer-invoices/src/common/dto/index.ts b/modules/customer-invoices/src/common/dto/index.ts new file mode 100644 index 00000000..44c99a3c --- /dev/null +++ b/modules/customer-invoices/src/common/dto/index.ts @@ -0,0 +1,3 @@ +export * from "./customer-invoices.request.dto"; +export * from "./customer-invoices.response.dto"; +export * from "./customer-invoices.schemas"; diff --git a/modules/customer-invoices/src/common/locales/en.json b/modules/customer-invoices/src/common/locales/en.json new file mode 100644 index 00000000..1029b717 --- /dev/null +++ b/modules/customer-invoices/src/common/locales/en.json @@ -0,0 +1,26 @@ +{ + "customerInvoices": { + "title": "Customer invoices", + "description": "Manage your customer invoices", + "list": { + "title": "Customer invoice list", + "description": "List all customer invoices" + }, + "create": { + "title": "Create customer invoice", + "description": "Create a new customer invoice" + }, + "edit": { + "title": "Edit customer invoice", + "description": "Edit the selected customer invoice" + }, + "delete": { + "title": "Delete customer invoice", + "description": "Delete the selected customer invoice" + }, + "view": { + "title": "View customer invoice", + "description": "View the details of the selected customer invoice" + } + } +} diff --git a/modules/invoices/src/common/locales/es.json b/modules/customer-invoices/src/common/locales/es.json similarity index 96% rename from modules/invoices/src/common/locales/es.json rename to modules/customer-invoices/src/common/locales/es.json index 0412ecfe..0f1d7a28 100644 --- a/modules/invoices/src/common/locales/es.json +++ b/modules/customer-invoices/src/common/locales/es.json @@ -1,5 +1,5 @@ { - "invoices": { + "customerInvoices": { "title": "Facturas", "description": "Gestiona tus facturas", "list": { diff --git a/modules/invoices/src/web/components/invoices-grid.tsx b/modules/customer-invoices/src/web/components/customer-invoices-grid.tsx similarity index 91% rename from modules/invoices/src/web/components/invoices-grid.tsx rename to modules/customer-invoices/src/web/components/customer-invoices-grid.tsx index 728b6667..a80ec0b7 100644 --- a/modules/invoices/src/web/components/invoices-grid.tsx +++ b/modules/customer-invoices/src/web/components/customer-invoices-grid.tsx @@ -9,7 +9,7 @@ ModuleRegistry.registerModules([AllCommunityModule]); // Core CSS import { AgGridReact } from "ag-grid-react"; -import { useInvoices } from "../hooks/use-invoices"; +import { useCustomerInvoices } from "../hooks"; /** * Fetch example Json data @@ -47,10 +47,10 @@ interface IRow { } // Create new GridExample component -export const InvoicesGrid = () => { - const { useList } = useInvoices(); +export const CustomerInvoicesGrid = () => { + //const { useList } = useCustomerInvoices(); - const { data, isLoading, isPending, isError, error } = useList({}); + const { data, isLoading, isPending, isError, error } = useCustomerInvoices({}); // Column Definitions: Defines & controls grid columns. const [colDefs] = useState([ diff --git a/modules/customer-invoices/src/web/components/customer-invoices-layout.tsx b/modules/customer-invoices/src/web/components/customer-invoices-layout.tsx new file mode 100644 index 00000000..5e4810d3 --- /dev/null +++ b/modules/customer-invoices/src/web/components/customer-invoices-layout.tsx @@ -0,0 +1,6 @@ +import { PropsWithChildren } from "react"; +import { CustomerInvoicesProvider } from "../context"; + +export const CustomerInvoicesLayout = ({ children }: PropsWithChildren) => { + return {children}; +}; diff --git a/modules/invoices/src/web/components/data.json b/modules/customer-invoices/src/web/components/data.json similarity index 100% rename from modules/invoices/src/web/components/data.json rename to modules/customer-invoices/src/web/components/data.json diff --git a/modules/customer-invoices/src/web/components/index.tsx b/modules/customer-invoices/src/web/components/index.tsx new file mode 100644 index 00000000..4dcd0d92 --- /dev/null +++ b/modules/customer-invoices/src/web/components/index.tsx @@ -0,0 +1,2 @@ +export * from "./customer-invoices-grid"; +export * from "./customer-invoices-layout"; diff --git a/modules/customer-invoices/src/web/context/customer-invoices-context.tsx b/modules/customer-invoices/src/web/context/customer-invoices-context.tsx new file mode 100644 index 00000000..3412d511 --- /dev/null +++ b/modules/customer-invoices/src/web/context/customer-invoices-context.tsx @@ -0,0 +1,56 @@ +import { CustomerInvoiceService } from "@erp/customerCustomerInvoices/api/domain/services/customer-invoice.service"; +import { PropsWithChildren, createContext } from "react"; + +/** + * ──────────────────────────────────────────────────────────────────────────────── + * 💡 Posibles usos del InvoicingContext + * ──────────────────────────────────────────────────────────────────────────────── + * Este contexto se diseña para encapsular estado y lógica compartida dentro del + * bounded context de facturación (facturas), proporcionando acceso global a datos + * o funciones relevantes para múltiples vistas (listado, detalle, edición, etc). + * + * ✅ Usos recomendados: + * + * 1. 🔎 Gestión de filtros globales: + * - Permite que los filtros aplicados en el listado de facturas se conserven + * cuando el usuario navega a otras vistas (detalle, edición) y luego regresa. + * - Mejora la experiencia de usuario evitando la necesidad de reestablecer filtros. + * + * 2. 🛡️ Gestión de permisos o configuración de acciones disponibles: + * - Permite definir qué acciones están habilitadas para el usuario actual + * (crear, editar, eliminar). + * - Útil para mostrar u ocultar botones de acción en diferentes pantallas. + * + * 3. 🧭 Control del layout: + * - Si el layout tiene elementos dinámicos (tabs, breadcrumb, loading global), + * este contexto puede coordinar su estado desde componentes hijos. + * - Ejemplo: seleccionar una pestaña activa que aplica en todas las subrutas. + * + * 4. 📦 Cacheo liviano de datos compartidos: + * - Puede almacenar la última factura abierta, borradores de edición, + * o referencias temporales para operaciones CRUD sin tener que usar la URL. + * + * 5. 🚀 Coordinación de side-effects: + * - Permite exponer funciones comunes como `refetch`, `resetFilters`, + * o `notifyInvoiceChanged`, usadas desde cualquier subcomponente del dominio. + * + * ⚠️ Alternativas: + * - Si el estado compartido es muy mutable, grande o requiere persistencia, + * podría ser preferible usar Zustand o Redux Toolkit. + * - No usar contextos para valores que cambian frecuentemente en tiempo real, + * ya que pueden causar renders innecesarios. + * + * ──────────────────────────────────────────────────────────────────────────────── + */ + +export type CustomerInvoicesContextType = {}; + +export type CustomerInvoicesContextParamsType = { + service: CustomerInvoiceService; +}; + +export const CustomerInvoicesContext = createContext({}); + +export const CustomerInvoicesProvider = ({ children }: PropsWithChildren) => { + return {children}; +}; diff --git a/modules/customer-invoices/src/web/context/index.ts b/modules/customer-invoices/src/web/context/index.ts new file mode 100644 index 00000000..d667dc8a --- /dev/null +++ b/modules/customer-invoices/src/web/context/index.ts @@ -0,0 +1 @@ +export * from "./customer-invoices-context"; diff --git a/modules/customer-invoices/src/web/customer-invoice-routes.tsx b/modules/customer-invoices/src/web/customer-invoice-routes.tsx new file mode 100644 index 00000000..455403b5 --- /dev/null +++ b/modules/customer-invoices/src/web/customer-invoice-routes.tsx @@ -0,0 +1,58 @@ +import { ModuleClientParams } from "@erp/core/client"; +import { lazy } from "react"; +import { Outlet, RouteObject } from "react-router-dom"; + +// Lazy load components +const CustomerInvoicesLayout = lazy(() => + import("./components").then((m) => ({ default: m.CustomerInvoicesLayout })) +); +const CustomerInvoicesList = lazy(() => import("./pages").then((m) => ({ default: m.CustomerInvoicesList }))); + +//const LogoutPage = lazy(() => import("./app").then((m) => ({ default: m.LogoutPage }))); + +/*const DealerLayout = lazy(() => import("./app").then((m) => ({ default: m.DealerLayout }))); +const DealersList = lazy(() => import("./app").then((m) => ({ default: m.DealersList }))); + +const LoginPageWithLanguageSelector = lazy(() => + import("./app").then((m) => ({ default: m.LoginPageWithLanguageSelector })) +); + +const CustomerInvoiceCreate = lazy(() => import("./app").then((m) => ({ default: m.CustomerInvoiceCreate }))); +const CustomerInvoiceEdit = lazy(() => import("./app").then((m) => ({ default: m.CustomerInvoiceEdit }))); +const SettingsEditor = lazy(() => import("./app").then((m) => ({ default: m.SettingsEditor }))); +const SettingsLayout = lazy(() => import("./app").then((m) => ({ default: m.SettingsLayout }))); +const CatalogLayout = lazy(() => import("./app").then((m) => ({ default: m.CatalogLayout }))); +const CatalogList = lazy(() => import("./app").then((m) => ({ default: m.CatalogList }))); +const DashboardPage = lazy(() => import("./app").then((m) => ({ default: m.DashboardPage }))); +const CustomerInvoicesLayout = lazy(() => import("./app").then((m) => ({ default: m.CustomerInvoicesLayout }))); +const CustomerInvoicesList = lazy(() => import("./app").then((m) => ({ default: m.CustomerInvoicesList })));*/ + +export const CustomerInvoiceRoutes = (params: ModuleClientParams): RouteObject[] => { + return [ + { + path: "*", + element: ( + + + + ), + children: [ + { path: "", element: }, // index + { path: "list", element: }, + { path: "*", element: }, + + // + /*{ path: "create", element: }, + { path: ":id", element: }, + { path: ":id/edit", element: }, + { path: ":id/delete", element: }, + { path: ":id/view", element: }, + { path: ":id/print", element: }, + { path: ":id/email", element: }, + { path: ":id/download", element: }, + { path: ":id/duplicate", element: }, + { path: ":id/preview", element: },*/ + ], + }, + ]; +}; diff --git a/modules/customer-invoices/src/web/hooks/customer-invoices-context.tsx b/modules/customer-invoices/src/web/hooks/customer-invoices-context.tsx new file mode 100644 index 00000000..06e065d5 --- /dev/null +++ b/modules/customer-invoices/src/web/hooks/customer-invoices-context.tsx @@ -0,0 +1,11 @@ +import { useContext } from "react"; +import { CustomerInvoicesContext, CustomerInvoicesContextType } from "../context"; + +export const useCustomerInvoicesContext = (): CustomerInvoicesContextType => { + const context = useContext(CustomerInvoicesContext); + if (!context) { + throw new Error("useCustomerInvoices must be used within a CustomerInvoicesProvider"); + } + + return context; +}; diff --git a/modules/customer-invoices/src/web/hooks/index.ts b/modules/customer-invoices/src/web/hooks/index.ts new file mode 100644 index 00000000..1e78c67a --- /dev/null +++ b/modules/customer-invoices/src/web/hooks/index.ts @@ -0,0 +1,2 @@ +export * from "./customer-invoices-context"; +export * from "./use-customer-invoices"; diff --git a/modules/invoices/src/web/hooks/use-invoices.tsx b/modules/customer-invoices/src/web/hooks/use-customer-invoices.bak similarity index 67% rename from modules/invoices/src/web/hooks/use-invoices.tsx rename to modules/customer-invoices/src/web/hooks/use-customer-invoices.bak index 626a41f8..7e9b7f17 100644 --- a/modules/invoices/src/web/hooks/use-invoices.tsx +++ b/modules/customer-invoices/src/web/hooks/use-customer-invoices.bak @@ -1,35 +1,35 @@ import { useDataSource, useQueryKey } from "@erp/core/client"; -import { IListInvoicesResponseDTO } from "@erp/invoices/common/dto"; +import { IListCustomerInvoicesResponseDTO } from "@erp/customerCustomerInvoices/common/dto"; -export type UseInvoicesListParams = Omit & { +export type UseCustomerInvoicesListParams = Omit & { status?: string; enabled?: boolean; queryOptions?: Record; }; -export type UseInvoicesListResponse = UseListQueryResult< - IListResponseDTO, +export type UseCustomerInvoicesListResponse = UseListQueryResult< + IListResponseDTO, unknown >; -export type UseInvoicesGetParamsType = { +export type UseCustomerInvoicesGetParamsType = { enabled?: boolean; queryOptions?: Record; }; -export type UseInvoicesReportParamsType = { +export type UseCustomerInvoicesReportParamsType = { enabled?: boolean; queryOptions?: Record; }; -export const useInvoices = () => { +export const useCustomerInvoices = () => { const actions = { /** * Hook para obtener la lista de facturas * @param params - Parámetros para la consulta de la lista de facturas * @returns - Respuesta de la consulta de la lista de facturas */ - useList: (params: UseInvoicesListParams): UseInvoicesListResponse => { + useList: (params: UseCustomerInvoicesListParams): UseCustomerInvoicesListResponse => { const dataSource = useDataSource(); const keys = useQueryKey(); @@ -42,10 +42,10 @@ export const useInvoices = () => { } = params; return useList({ - queryKey: keys().data().resource("invoices").action("list").params(params).get(), + queryKey: keys().data().resource("customerCustomerInvoices").action("list").params(params).get(), queryFn: () => { return dataSource.getList({ - resource: "invoices", + resource: "customerCustomerInvoices", quickSearchTerm, filters: status !== "all" diff --git a/modules/customer-invoices/src/web/hooks/use-customer-invoices.tsx b/modules/customer-invoices/src/web/hooks/use-customer-invoices.tsx new file mode 100644 index 00000000..38924be4 --- /dev/null +++ b/modules/customer-invoices/src/web/hooks/use-customer-invoices.tsx @@ -0,0 +1,20 @@ +import { useDataSource, useQueryKey } from "@erp/core/client"; +import { useQuery } from "@tanstack/react-query"; + +// Obtener todas las facturas +export const useCustomerInvoices = (params: any) => { + const dataSource = useDataSource(); + const keys = useQueryKey(); + + return useQuery({ + queryKey: keys().data().resource("invoices").action("list").params(params).get(), + queryFn: (context) => { + console.log(context); + const { signal } = context; + return dataSource.getList("customer-invoices", { + signal, + ...params, + }); + }, + }); +}; diff --git a/modules/invoices/src/web/invoice-routes.tsx b/modules/customer-invoices/src/web/invoice-routes.tsx similarity index 93% rename from modules/invoices/src/web/invoice-routes.tsx rename to modules/customer-invoices/src/web/invoice-routes.tsx index b26371a7..af239765 100644 --- a/modules/invoices/src/web/invoice-routes.tsx +++ b/modules/customer-invoices/src/web/invoice-routes.tsx @@ -4,9 +4,11 @@ import { Outlet, RouteObject } from "react-router-dom"; // Lazy load components const InvoicesLayout = lazy(() => - import("./components").then((m) => ({ default: m.InvoicesLayout })) + import("./components").then((m) => ({ default: m.CustomerInvoicesLayout })) +); +const InvoicesList = lazy(() => + import("./pages").then((m) => ({ default: m.CustomerInvoicesList })) ); -const InvoicesList = lazy(() => import("./pages").then((m) => ({ default: m.InvoicesList }))); //const LogoutPage = lazy(() => import("./app").then((m) => ({ default: m.LogoutPage }))); diff --git a/modules/invoices/src/web/manifest.ts b/modules/customer-invoices/src/web/manifest.ts similarity index 67% rename from modules/invoices/src/web/manifest.ts rename to modules/customer-invoices/src/web/manifest.ts index e4184396..eadb365f 100644 --- a/modules/invoices/src/web/manifest.ts +++ b/modules/customer-invoices/src/web/manifest.ts @@ -2,12 +2,12 @@ import { IModuleClient, ModuleClientParams } from "@erp/core/client"; import i18next from "i18next"; import enResources from "../common/locales/en.json"; import esResources from "../common/locales/es.json"; -import { InvoiceRoutes } from "./invoice-routes"; +import { CustomerInvoiceRoutes } from "./customer-invoice-routes"; -const MODULE_NAME = "invoices"; +export const MODULE_NAME = "CustomerInvoices"; const MODULE_VERSION = "1.0.0"; -export const InvoicesModuleManifiest: IModuleClient = { +export const CustomerInvoicesModuleManifiest: IModuleClient = { name: MODULE_NAME, version: MODULE_VERSION, dependencies: ["auth"], @@ -17,8 +17,8 @@ export const InvoicesModuleManifiest: IModuleClient = { routes: (params: ModuleClientParams) => { i18next.addResourceBundle("en", MODULE_NAME, enResources, true, true); i18next.addResourceBundle("es", MODULE_NAME, esResources, true, true); - return InvoiceRoutes(params); + return CustomerInvoiceRoutes(params); }, }; -export default InvoicesModuleManifiest; +export default CustomerInvoicesModuleManifiest; diff --git a/modules/invoices/src/web/pages/index.tsx b/modules/customer-invoices/src/web/pages/index.tsx similarity index 100% rename from modules/invoices/src/web/pages/index.tsx rename to modules/customer-invoices/src/web/pages/index.tsx diff --git a/modules/invoices/src/web/pages/list.tsx b/modules/customer-invoices/src/web/pages/list.tsx similarity index 59% rename from modules/invoices/src/web/pages/list.tsx rename to modules/customer-invoices/src/web/pages/list.tsx index 7bb13509..13b38f14 100644 --- a/modules/invoices/src/web/pages/list.tsx +++ b/modules/customer-invoices/src/web/pages/list.tsx @@ -4,21 +4,22 @@ import { PlusIcon } from "lucide-react"; import { useState } from "react"; import { useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; -import { InvoicesGrid } from "../components"; +import { CustomerInvoicesGrid } from "../components"; +import { MODULE_NAME } from "../manifest"; -export const InvoicesList = () => { - const { t } = useTranslation("invoices"); +export const CustomerInvoicesList = () => { + const { t } = useTranslation(MODULE_NAME); const navigate = useNavigate(); const [status, setStatus] = useState("all"); - const InvoiceStatuses = [ - { value: "all", label: t("Invoices.list.tabs.all") }, - { value: "draft", label: t("Invoices.list.tabs.draft") }, - { value: "ready", label: t("Invoices.list.tabs.ready") }, - { value: "delivered", label: t("Invoices.list.tabs.delivered") }, - { value: "accepted", label: t("Invoices.list.tabs.accepted") }, - { value: "rejected", label: t("Invoices.list.tabs.rejected") }, - { value: "archived", label: t("Invoices.list.tabs.archived") }, + const CustomerInvoiceStatuses = [ + { value: "all", label: t("customerInvoices.list.tabs.all") }, + { value: "draft", label: t("customerInvoices.list.tabs.draft") }, + { value: "ready", label: t("customerInvoices.list.tabs.ready") }, + { value: "delivered", label: t("customerInvoices.list.tabs.delivered") }, + { value: "accepted", label: t("customerInvoices.list.tabs.accepted") }, + { value: "rejected", label: t("customerInvoices.list.tabs.rejected") }, + { value: "archived", label: t("customerInvoices.list.tabs.archived") }, ]; return ( @@ -27,18 +28,20 @@ export const InvoicesList = () => {
-

{t("invoices.list.title")}

-

{t("invoices.list.description")}

+

+ {t("customerInvoices.list.title")} +

+

{t("customerInvoices.list.description")}

-
- +
@@ -51,16 +54,16 @@ export const InvoicesList = () => {

- {t('invoices.list.title' /> + {t('customerInvoices.list.title' />

- {t('Invoices.list.subtitle' /> + {t('CustomerInvoices.list.subtitle' />

-
@@ -69,20 +72,20 @@ export const InvoicesList = () => {
- {InvoiceStatuses.map((s) => ( + {CustomerInvoiceStatuses.map((s) => ( {s.label} ))}
- +