diff --git a/modules/customer-invoices/src/api/application/get-customer-invoice/assembler/get-invoice-items.assembler.ts b/modules/customer-invoices/src/api/application/get-customer-invoice/assembler/get-invoice-items.assembler.ts index c9e8a7a5..163ee4b0 100644 --- a/modules/customer-invoices/src/api/application/get-customer-invoice/assembler/get-invoice-items.assembler.ts +++ b/modules/customer-invoices/src/api/application/get-customer-invoice/assembler/get-invoice-items.assembler.ts @@ -1,8 +1,8 @@ -import { GetCustomerInvoiceByIdResponseDTO } from "@erp/customer-invoices/common/dto"; +import { UpdateCustomerInvoiceByIdResponseDTO } from "@erp/customer-invoices/common/dto"; import { toEmptyString } from "@repo/rdx-ddd"; import { CustomerInvoice } from "../../../domain"; -type GetCustomerInvoiceItemsByInvoiceIdResponseDTO = GetCustomerInvoiceByIdResponseDTO["items"]; +type GetCustomerInvoiceItemsByInvoiceIdResponseDTO = UpdateCustomerInvoiceByIdResponseDTO["items"]; export class GetCustomerInvoiceItemsAssembler { toDTO(invoice: CustomerInvoice): GetCustomerInvoiceItemsByInvoiceIdResponseDTO { diff --git a/modules/customer-invoices/src/api/application/get-customer-invoice/assembler/get-invoice.assembler.ts b/modules/customer-invoices/src/api/application/get-customer-invoice/assembler/get-invoice.assembler.ts index bf658a32..06e9f50d 100644 --- a/modules/customer-invoices/src/api/application/get-customer-invoice/assembler/get-invoice.assembler.ts +++ b/modules/customer-invoices/src/api/application/get-customer-invoice/assembler/get-invoice.assembler.ts @@ -1,4 +1,4 @@ -import { GetCustomerInvoiceByIdResponseDTO } from "@erp/customer-invoices/common/dto"; +import { UpdateCustomerInvoiceByIdResponseDTO } from "@erp/customer-invoices/common/dto"; import { toEmptyString } from "@repo/rdx-ddd"; import { CustomerInvoice } from "../../../domain"; import { GetCustomerInvoiceItemsAssembler } from "./get-invoice-items.assembler"; @@ -10,7 +10,7 @@ export class GetCustomerInvoiceAssembler { this._itemsAssembler = new GetCustomerInvoiceItemsAssembler(); } - public toDTO(invoice: CustomerInvoice): GetCustomerInvoiceByIdResponseDTO { + public toDTO(invoice: CustomerInvoice): UpdateCustomerInvoiceByIdResponseDTO { const items = this._itemsAssembler.toDTO(invoice); return { diff --git a/modules/customer-invoices/src/api/application/index.ts b/modules/customer-invoices/src/api/application/index.ts index 8e2a87ac..14646c6b 100644 --- a/modules/customer-invoices/src/api/application/index.ts +++ b/modules/customer-invoices/src/api/application/index.ts @@ -2,4 +2,4 @@ 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"; +export * from "./update-customer-invoice"; diff --git a/modules/customer-invoices/src/api/application/list-customer-invoices/list-customer-invoices.use-case.ts b/modules/customer-invoices/src/api/application/list-customer-invoices/list-customer-invoices.use-case.ts index 36e548cb..d9f7fd24 100644 --- a/modules/customer-invoices/src/api/application/list-customer-invoices/list-customer-invoices.use-case.ts +++ b/modules/customer-invoices/src/api/application/list-customer-invoices/list-customer-invoices.use-case.ts @@ -1,19 +1,20 @@ import { ITransactionManager } from "@erp/core/api"; import { Criteria } from "@repo/rdx-criteria/server"; +import { UniqueID } from "@repo/rdx-ddd"; import { Result } from "@repo/rdx-utils"; import { Transaction } from "sequelize"; import { CustomerInvoiceListResponseDTO } from "../../../common/dto"; -import { ICustomerInvoiceService } from "../../domain"; +import { CustomerInvoiceService } from "../../domain"; import { ListCustomerInvoicesAssembler } from "./assembler"; type ListCustomerInvoicesUseCaseInput = { - tenantId: string; + companyId: UniqueID; criteria: Criteria; }; export class ListCustomerInvoicesUseCase { constructor( - private readonly customerInvoiceService: ICustomerInvoiceService, + private readonly service: CustomerInvoiceService, private readonly transactionManager: ITransactionManager, private readonly assembler: ListCustomerInvoicesAssembler ) {} @@ -21,12 +22,15 @@ export class ListCustomerInvoicesUseCase { public execute( params: ListCustomerInvoicesUseCaseInput ): Promise> { - const { criteria, tenantId } = params; + const { criteria, companyId } = params; return this.transactionManager.complete(async (transaction: Transaction) => { try { - //const { rows, total, limit, offset } = await this.repo.searchInCompany(criteria, tenantId); - const result = await this.customerInvoiceService.findByCriteria(criteria, transaction); + const result = await this.service.findInvoiceByCriteriaInCompany( + companyId, + criteria, + transaction + ); if (result.isFailure) { return Result.fail(result.error); diff --git a/modules/customer-invoices/src/api/application/update-customer-invoice/assembler/index.ts b/modules/customer-invoices/src/api/application/update-customer-invoice/assembler/index.ts index e69de29b..50071c2b 100644 --- a/modules/customer-invoices/src/api/application/update-customer-invoice/assembler/index.ts +++ b/modules/customer-invoices/src/api/application/update-customer-invoice/assembler/index.ts @@ -0,0 +1 @@ +export * from "./update-invoice.assembler"; diff --git a/modules/customer-invoices/src/api/application/update-customer-invoice/assembler/update-invoice-items.assembler.ts b/modules/customer-invoices/src/api/application/update-customer-invoice/assembler/update-invoice-items.assembler.ts new file mode 100644 index 00000000..39685934 --- /dev/null +++ b/modules/customer-invoices/src/api/application/update-customer-invoice/assembler/update-invoice-items.assembler.ts @@ -0,0 +1,46 @@ +import { toEmptyString } from "@repo/rdx-ddd"; +import { UpdateCustomerInvoiceByIdResponseDTO } from "../../../../common/dto"; +import { CustomerInvoice } from "../../../domain"; + +type UpdateCustomerInvoiceItemsByInvoiceIdResponseDTO = + UpdateCustomerInvoiceByIdResponseDTO["items"]; + +export class UpdateCustomerInvoiceItemsAssembler { + toDTO(invoice: CustomerInvoice): UpdateCustomerInvoiceItemsByInvoiceIdResponseDTO { + const { items } = invoice; + return items.map((item, index) => ({ + id: item.id.toString(), + position: String(index), + description: toEmptyString(item.description, (value) => value.toPrimitive()), + + quantity: item.quantity.match( + (quantity) => { + const { value, scale } = quantity.toPrimitive(); + return { value: value.toString(), scale: scale.toString() }; + }, + () => ({ value: "", scale: "" }) + ), + + unit_amount: item.unitAmount.match( + (unitAmount) => { + const { value, scale } = unitAmount.toPrimitive(); + return { value: value.toString(), scale: scale.toString() }; + }, + () => ({ value: "", scale: "" }) + ), + + discount_percentage: item.discountPercentage.match( + (discountPercentage) => { + const { value, scale } = discountPercentage.toPrimitive(); + return { value: value.toString(), scale: scale.toString() }; + }, + () => ({ value: "", scale: "" }) + ), + + total_amount: { + value: item.totalAmount.toPrimitive().value.toString(), + scale: item.totalAmount.toPrimitive().scale.toString(), + }, + })); + } +} diff --git a/modules/customer-invoices/src/api/application/update-customer-invoice/assembler/update-invoice.assembler.ts b/modules/customer-invoices/src/api/application/update-customer-invoice/assembler/update-invoice.assembler.ts new file mode 100644 index 00000000..79064111 --- /dev/null +++ b/modules/customer-invoices/src/api/application/update-customer-invoice/assembler/update-invoice.assembler.ts @@ -0,0 +1,110 @@ +import { toEmptyString } from "@repo/rdx-ddd"; +import { UpdateCustomerInvoiceByIdResponseDTO } from "../../../../common/dto"; +import { CustomerInvoice } from "../../../domain"; +import { UpdateCustomerInvoiceItemsAssembler } from "./update-invoice-items.assembler"; + +export class UpdateCustomerInvoiceAssembler { + private _itemsAssembler!: UpdateCustomerInvoiceItemsAssembler; + + constructor() { + this._itemsAssembler = new UpdateCustomerInvoiceItemsAssembler(); + } + + public toDTO(invoice: CustomerInvoice): UpdateCustomerInvoiceByIdResponseDTO { + const items = this._itemsAssembler.toDTO(invoice); + + return { + id: invoice.id.toPrimitive(), + company_id: invoice.companyId.toPrimitive(), + + invoice_number: invoice.invoiceNumber.toString(), + status: invoice.status.toPrimitive(), + series: invoice.series.toString(), + + issue_date: invoice.issueDate.toDateString(), + operation_date: toEmptyString(invoice.operationDate, (value) => value.toDateString()), + + notes: toEmptyString(invoice.notes, (value) => value.toPrimitive()), + + language_code: invoice.languageCode.toPrimitive(), + currency_code: invoice.currencyCode.toPrimitive(), + + subtotal_amount: { + value: invoice.subtotalAmount.value.toString(), + scale: invoice.subtotalAmount.scale.toString(), + }, + + discount_percentage: { + value: invoice.discountPercentage.value.toString(), + scale: invoice.discountPercentage.scale.toString(), + }, + + discount_amount: { + value: invoice.discountAmount.value.toString(), + scale: invoice.discountAmount.scale.toString(), + }, + + taxable_amount: { + value: invoice.taxableAmount.value.toString(), + scale: invoice.taxableAmount.scale.toString(), + }, + + tax_amount: { + value: invoice.taxAmount.value.toString(), + scale: invoice.taxAmount.scale.toString(), + }, + + total_amount: { + value: invoice.totalAmount.value.toString(), + scale: invoice.totalAmount.scale.toString(), + }, + + items, + + metadata: { + entity: "customer-invoices", + }, + + //subtotal: customerInvoice.calculateSubtotal().toPrimitive(), + + //total: customerInvoice.calculateTotal().toPrimitive(), + + /*items: + customerInvoice.items.size() > 0 + ? customerInvoice.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 CustomerInvoiceParticipantAssembler(customerInvoice.senderId, context), + + /*recipient: await CustomerInvoiceParticipantAssembler(customerInvoice.recipient, context), + items: customerInvoiceItemAssembler(customerInvoice.items, context), + + payment_term: { + payment_type: "", + due_date: "", + }, + + due_amount: { + currency: customerInvoice.currency.toString(), + precision: 2, + amount: 0, + }, + + custom_fields: [], + + metadata: { + create_time: "", + last_updated_time: "", + delete_time: "", + },*/ + }; + } +} diff --git a/modules/customer-invoices/src/api/infrastructure/dependencies.ts b/modules/customer-invoices/src/api/infrastructure/dependencies.ts index 9f59b6a2..84323d65 100644 --- a/modules/customer-invoices/src/api/infrastructure/dependencies.ts +++ b/modules/customer-invoices/src/api/infrastructure/dependencies.ts @@ -4,6 +4,7 @@ import { CreateCustomerInvoiceUseCase, CreateCustomerInvoicesAssembler, DeleteCustomerInvoiceUseCase, + GetCustomerInvoiceAssembler, GetCustomerInvoiceItemsAssembler, GetCustomerInvoiceUseCase, ListCustomerInvoicesAssembler, @@ -54,7 +55,7 @@ export function getInvoiceDependencies(params: ModuleParams): InvoiceDeps { if (!_assemblers) { _assemblers = { list: new ListCustomerInvoicesAssembler(), // transforma domain → ListDTO - get: new GetCustomerInvoiceItemsAssembler(), // transforma domain → DetailDTO + get: new GetCustomerInvoiceAssembler(), // transforma domain → DetailDTO create: new CreateCustomerInvoicesAssembler(), // transforma domain → CreatedDTO update: new UpdateCustomerInvoiceAssembler(), // transforma domain -> UpdateDTO }; diff --git a/modules/customer-invoices/src/api/infrastructure/express/controllers/list-customer-invoices.controller.ts b/modules/customer-invoices/src/api/infrastructure/express/controllers/list-customer-invoices.controller.ts index 26433456..4883000e 100644 --- a/modules/customer-invoices/src/api/infrastructure/express/controllers/list-customer-invoices.controller.ts +++ b/modules/customer-invoices/src/api/infrastructure/express/controllers/list-customer-invoices.controller.ts @@ -2,18 +2,15 @@ import { ExpressController, authGuard, forbidQueryFieldGuard, tenantGuard } from import { ListCustomerInvoicesUseCase } from "../../../application"; export class ListCustomerInvoicesController extends ExpressController { - public constructor( - private readonly useCase: ListCustomerInvoicesUseCase - /* private readonly presenter: any */ - ) { + public constructor(private readonly useCase: ListCustomerInvoicesUseCase) { super(); // 🔐 Reutiliza guards de auth/tenant y prohíbe 'companyId' en query this.useGuards(authGuard(), tenantGuard(), forbidQueryFieldGuard("companyId")); } protected async executeImpl() { - const tenantId = this.getTenantId()!; // garantizado por tenantGuard - const result = await this.useCase.execute({ criteria: this.criteria, tenantId }); + const companyId = this.getTenantId()!; // garantizado por tenantGuard + const result = await this.useCase.execute({ criteria: this.criteria, companyId }); return result.match( (data) => this.ok(data), diff --git a/modules/customer-invoices/src/common/dto/response/index.ts b/modules/customer-invoices/src/common/dto/response/index.ts index c4d86161..5c025bd7 100644 --- a/modules/customer-invoices/src/common/dto/response/index.ts +++ b/modules/customer-invoices/src/common/dto/response/index.ts @@ -1,3 +1,4 @@ export * from "./customer-invoice-creation.response.dto"; export * from "./customer-invoices-list.response.dto"; export * from "./get-customer-invoice-by-id.response.dto"; +export * from "./update-customer-invoice-by-id.response.dto"; diff --git a/modules/customer-invoices/src/common/dto/response/update-customer-invoice-by-id.response.dto.ts b/modules/customer-invoices/src/common/dto/response/update-customer-invoice-by-id.response.dto.ts new file mode 100644 index 00000000..ffd3f1fe --- /dev/null +++ b/modules/customer-invoices/src/common/dto/response/update-customer-invoice-by-id.response.dto.ts @@ -0,0 +1,44 @@ +import { AmountSchema, MetadataSchema, PercentageSchema, QuantitySchema } from "@erp/core"; +import * as z from "zod/v4"; + +export const UpdateCustomerInvoiceByIdResponseSchema = z.object({ + id: z.uuid(), + company_id: z.uuid(), + + invoice_number: z.string(), + status: z.string(), + series: z.string(), + + issue_date: z.string(), + operation_date: z.string(), + + notes: z.string(), + + language_code: z.string(), + currency_code: z.string(), + + subtotal_amount: AmountSchema, + discount_percentage: PercentageSchema, + discount_amount: AmountSchema, + taxable_amount: AmountSchema, + tax_amount: AmountSchema, + total_amount: AmountSchema, + + items: z.array( + z.object({ + id: z.uuid(), + position: z.string(), + description: z.string(), + quantity: QuantitySchema, + unit_amount: AmountSchema, + discount_percentage: PercentageSchema, + total_amount: AmountSchema, + }) + ), + + metadata: MetadataSchema.optional(), +}); + +export type UpdateCustomerInvoiceByIdResponseDTO = z.infer< + typeof UpdateCustomerInvoiceByIdResponseSchema +>;