diff --git a/modules/customer-invoices/src/api/application/helpers/format-payment_method-dto.ts b/modules/customer-invoices/src/api/application/helpers/format-payment_method-dto.ts new file mode 100644 index 00000000..ab626de0 --- /dev/null +++ b/modules/customer-invoices/src/api/application/helpers/format-payment_method-dto.ts @@ -0,0 +1,13 @@ +export function formatPaymentMethodDTO(paymentMethod: object) { + if (!paymentMethod) { + return null; + } + + //Construir objeto paymentMethod para comprobar que existe + //const value = PaymentMethod.create( + // id: paymentMethod.payment_id), + //).data; + //return value.format(locale); + + return paymentMethod.payment_description; +} diff --git a/modules/customer-invoices/src/api/application/helpers/index.ts b/modules/customer-invoices/src/api/application/helpers/index.ts index 789c112f..8134db38 100644 --- a/modules/customer-invoices/src/api/application/helpers/index.ts +++ b/modules/customer-invoices/src/api/application/helpers/index.ts @@ -1,5 +1,6 @@ export * from "./format-date-dto"; export * from "./format-money-dto"; +export * from "./format-payment_method-dto"; export * from "./format-percentage-dto"; export * from "./format-quantity-dto"; export * from "./map-dto-to-customer-invoice-props"; diff --git a/modules/customer-invoices/src/api/application/presenters/domain/customer-invoice.full.presenter.ts b/modules/customer-invoices/src/api/application/presenters/domain/customer-invoice.full.presenter.ts index dffab74e..3b3b852a 100644 --- a/modules/customer-invoices/src/api/application/presenters/domain/customer-invoice.full.presenter.ts +++ b/modules/customer-invoices/src/api/application/presenters/domain/customer-invoice.full.presenter.ts @@ -24,6 +24,17 @@ export class CustomerInvoiceFullPresenter extends Presenter< const items = itemsPresenter.toOutput(invoice.items); const allAmounts = invoice.getAllAmounts(); + const payment = invoice.paymentMethod.match( + (payment) => { + const { id, payment_description } = payment.toObjectString(); + return { + payment_id: id, + payment_description, + }; + }, + () => undefined + ); + return { id: invoice.id.toString(), company_id: invoice.companyId.toString(), @@ -45,6 +56,8 @@ export class CustomerInvoiceFullPresenter extends Presenter< taxes: invoice.taxes.getCodesToString(), + payment_method: payment, + subtotal_amount: allAmounts.subtotalAmount.toObjectString(), discount_percentage: invoice.discountPercentage.toObjectString(), diff --git a/modules/customer-invoices/src/api/application/presenters/queries/customer-invoice.report.presenter.ts b/modules/customer-invoices/src/api/application/presenters/queries/customer-invoice.report.presenter.ts index 06185fd0..b944086b 100644 --- a/modules/customer-invoices/src/api/application/presenters/queries/customer-invoice.report.presenter.ts +++ b/modules/customer-invoices/src/api/application/presenters/queries/customer-invoice.report.presenter.ts @@ -6,6 +6,7 @@ import { formatMoneyDTO, formatPercentageDTO, } from "../../helpers"; +import { formatPaymentMethodDTO } from "../../helpers/format-payment_method-dto"; export class CustomerInvoiceReportPresenter extends Presenter< GetCustomerInvoiceByIdResponseDTO, @@ -40,6 +41,8 @@ export class CustomerInvoiceReportPresenter extends Presenter< taxable_amount: formatMoneyDTO(invoiceDTO.taxable_amount, moneyOptions), taxes_amount: formatMoneyDTO(invoiceDTO.taxes_amount, moneyOptions), total_amount: formatMoneyDTO(invoiceDTO.total_amount, moneyOptions), + + payment_method: formatPaymentMethodDTO(invoiceDTO.payment_method), }; } } diff --git a/modules/customer-invoices/src/api/application/use-cases/report/reporter/customer-invoice.report.pdf.ts b/modules/customer-invoices/src/api/application/use-cases/report/reporter/customer-invoice.report.pdf.ts index cc0ca951..19cb8ad1 100644 --- a/modules/customer-invoices/src/api/application/use-cases/report/reporter/customer-invoice.report.pdf.ts +++ b/modules/customer-invoices/src/api/application/use-cases/report/reporter/customer-invoice.report.pdf.ts @@ -45,14 +45,14 @@ export class CustomerInvoiceReportPDFPresenter extends Presenter< right: "10mm", top: "10mm", }, - // landscape: false, - // preferCSSPageSize: true, - // omitBackground: false, - // printBackground: true, - // displayHeaderFooter: false, - // headerTemplate: "
", - // footerTemplate: - // '
Página de
', + landscape: false, + preferCSSPageSize: true, + omitBackground: false, + printBackground: true, + displayHeaderFooter: false, + headerTemplate: "
", + footerTemplate: + '
Página de
', }); await browser.close(); diff --git a/modules/customer-invoices/src/api/application/use-cases/report/reporter/templates/customer-invoice/template-factura.hbs b/modules/customer-invoices/src/api/application/use-cases/report/reporter/templates/customer-invoice/template-factura.hbs index eac15e9b..ed5feca7 100644 --- a/modules/customer-invoices/src/api/application/use-cases/report/reporter/templates/customer-invoice/template-factura.hbs +++ b/modules/customer-invoices/src/api/application/use-cases/report/reporter/templates/customer-invoice/template-factura.hbs @@ -185,17 +185,26 @@
-
-
-

Forma de pago: {{payment_method}}

+
+ {{#if payment_method}} +
+

Forma de pago: {{payment_method}}

+ {{else}} + + {{/if}} + {{#if notes}}

Notas: {{notes}}

+ {{else}} + + {{/if}} +
- +
{{#if discount_percentage}} @@ -235,6 +244,7 @@ +
+
{{#if discount_percentage}} @@ -238,9 +247,10 @@
diff --git a/modules/customer-invoices/src/api/domain/aggregates/customer-invoice.ts b/modules/customer-invoices/src/api/domain/aggregates/customer-invoice.ts index 79581b7b..64d6d3ed 100644 --- a/modules/customer-invoices/src/api/domain/aggregates/customer-invoice.ts +++ b/modules/customer-invoices/src/api/domain/aggregates/customer-invoice.ts @@ -9,7 +9,7 @@ import { UtcDate, } from "@repo/rdx-ddd"; import { Maybe, Result } from "@repo/rdx-utils"; -import { CustomerInvoiceItems } from "../entities"; +import { CustomerInvoiceItems, InvoicePaymentMethod } from "../entities"; import { InvoiceTaxes } from "../entities/invoice-taxes"; import { CustomerInvoiceNumber, @@ -41,10 +41,15 @@ export interface CustomerInvoiceProps { taxes: InvoiceTaxes; items: CustomerInvoiceItems; + paymentMethod: Maybe; + discountPercentage: Percentage; } export interface ICustomerInvoice { + hasRecipient: boolean; + hasPaymentMethod: boolean; + getSubtotalAmount(): InvoiceAmount; getDiscountAmount(): InvoiceAmount; @@ -140,6 +145,10 @@ export class CustomerInvoice return this.props.recipient; } + public get paymentMethod(): Maybe { + return this.props.paymentMethod; + } + public get languageCode(): LanguageCode { return this.props.languageCode; } @@ -165,6 +174,10 @@ export class CustomerInvoice return this.recipient.isSome(); } + public get hasPaymentMethod() { + return this.paymentMethod.isSome(); + } + private _getDiscountAmount(subtotalAmount: InvoiceAmount): InvoiceAmount { return subtotalAmount.percentage(this.discountPercentage); } diff --git a/modules/customer-invoices/src/api/domain/entities/index.ts b/modules/customer-invoices/src/api/domain/entities/index.ts index 165a0998..164601cf 100644 --- a/modules/customer-invoices/src/api/domain/entities/index.ts +++ b/modules/customer-invoices/src/api/domain/entities/index.ts @@ -1,3 +1,4 @@ export * from "./customer-invoice-items"; +export * from "./invoice-payment-method"; export * from "./invoice-taxes"; export * from "./item-taxes"; diff --git a/modules/customer-invoices/src/api/domain/entities/invoice-payment-method/index.ts b/modules/customer-invoices/src/api/domain/entities/invoice-payment-method/index.ts new file mode 100644 index 00000000..7556a841 --- /dev/null +++ b/modules/customer-invoices/src/api/domain/entities/invoice-payment-method/index.ts @@ -0,0 +1 @@ +export * from "./invoice-payment-method"; diff --git a/modules/customer-invoices/src/api/domain/entities/invoice-payment-method/invoice-payment-method.ts b/modules/customer-invoices/src/api/domain/entities/invoice-payment-method/invoice-payment-method.ts new file mode 100644 index 00000000..bd5b2f42 --- /dev/null +++ b/modules/customer-invoices/src/api/domain/entities/invoice-payment-method/invoice-payment-method.ts @@ -0,0 +1,32 @@ +import { DomainEntity, UniqueID } from "@repo/rdx-ddd"; +import { Result } from "@repo/rdx-utils"; + +export interface InvoicePaymentMethodProps { + paymentDescription: string; +} + +export class InvoicePaymentMethod extends DomainEntity { + public static create( + props: InvoicePaymentMethodProps, + id?: UniqueID + ): Result { + const item = new InvoicePaymentMethod(props, id); + + return Result.ok(item); + } + + get paymentDescription(): string { + return this.props.paymentDescription; + } + + getProps(): InvoicePaymentMethodProps { + return this.props; + } + + toObjectString() { + return { + id: String(this.id), + payment_description: String(this.paymentDescription), + }; + } +} diff --git a/modules/customer-invoices/src/api/infrastructure/mappers/domain/customer-invoice.mapper.ts b/modules/customer-invoices/src/api/infrastructure/mappers/domain/customer-invoice.mapper.ts index 30f1a93f..722685d3 100644 --- a/modules/customer-invoices/src/api/infrastructure/mappers/domain/customer-invoice.mapper.ts +++ b/modules/customer-invoices/src/api/infrastructure/mappers/domain/customer-invoice.mapper.ts @@ -11,7 +11,7 @@ import { extractOrPushError, maybeFromNullableVO, } from "@repo/rdx-ddd"; -import { Result } from "@repo/rdx-utils"; +import { Maybe, Result } from "@repo/rdx-utils"; import { CustomerInvoice, CustomerInvoiceItems, @@ -19,6 +19,7 @@ import { CustomerInvoiceProps, CustomerInvoiceSerie, CustomerInvoiceStatus, + InvoicePaymentMethod, } from "../../../domain"; import { InvoiceTaxes } from "../../../domain/entities/invoice-taxes"; import { CustomerInvoiceCreationAttributes, CustomerInvoiceModel } from "../../sequelize"; @@ -53,7 +54,50 @@ export class CustomerInvoiceDomainMapper this._taxesMapper = new TaxesFullMapper(params); } - private mapAttributesToDomain(source: CustomerInvoiceModel, params?: MapperParamsType) { + private _mapPaymentMethodToDomain(source: CustomerInvoiceModel, params?: MapperParamsType) { + const { errors } = params as { + errors: ValidationErrorDetail[]; + }; + + const paymentId = extractOrPushError( + maybeFromNullableVO(source.payment_method_id, (value) => UniqueID.create(value)), + "payment_method_id", + errors + ); + + const paymentDescription = extractOrPushError( + maybeFromNullableVO(source.payment_method_description, (value) => Result.ok(String(value))), + "payment_method_description", + errors + ); + + if (errors.length > 0) { + return Result.fail(new ValidationErrorCollection("Invoice payment mapping failed", errors)); + } + + if (paymentDescription!.isNone() || paymentId!.isNone()) { + return Result.ok(Maybe.none()); + } + + const paymentResult = InvoicePaymentMethod.create( + { + paymentDescription: paymentDescription?.getOrUndefined()!, + }, + paymentId?.getOrUndefined()! + ); + + if (paymentResult.isFailure) { + return Result.fail( + new ValidationErrorCollection("Invoice payment method creation failed", [ + { path: "paymentMethod", message: paymentResult.error.message }, + ]) + ); + } + + return Result.ok(Maybe.some(paymentResult.data)); + } + + private _mapAttributesToDomain(source: CustomerInvoiceModel, params?: MapperParamsType) { const { errors } = params as { errors: ValidationErrorDetail[]; }; @@ -151,7 +195,7 @@ export class CustomerInvoiceDomainMapper const errors: ValidationErrorDetail[] = []; // 1) Valores escalares (atributos generales) - const attributes = this.mapAttributesToDomain(source, { errors, ...params }); + const attributes = this._mapAttributesToDomain(source, { errors, ...params }); // 2) Recipient (snapshot en la factura o include) const recipientResult = this._recipientMapper.mapToDomain(source, { @@ -204,6 +248,16 @@ export class CustomerInvoiceDomainMapper }); } + // Payment method + const paymentMethodResult = this._mapPaymentMethodToDomain(source, { errors, ...params }); + + if (paymentMethodResult.isFailure) { + errors.push({ + path: "paymentMethod", + message: paymentMethodResult.error.message, + }); + } + // 5) Si hubo errores de mapeo, devolvemos colección de validación if (errors.length > 0) { return Result.fail(new ValidationErrorCollection("Customer mapping failed", errors)); @@ -212,6 +266,7 @@ export class CustomerInvoiceDomainMapper // 6) Construcción del agregado (Dominio) const recipient = recipientResult.data; + const paymentMethod = paymentMethodResult.data; const taxes = InvoiceTaxes.create({ items: taxesResults.data.getAll(), @@ -243,6 +298,8 @@ export class CustomerInvoiceDomainMapper discountPercentage: attributes.discountPercentage!, + paymentMethod: paymentMethod!, + taxes: taxes, items, }; diff --git a/modules/customer-invoices/src/api/infrastructure/sequelize/models/customer-invoice.model.ts b/modules/customer-invoices/src/api/infrastructure/sequelize/models/customer-invoice.model.ts index 00547f0a..32e49bbb 100644 --- a/modules/customer-invoices/src/api/infrastructure/sequelize/models/customer-invoice.model.ts +++ b/modules/customer-invoices/src/api/infrastructure/sequelize/models/customer-invoice.model.ts @@ -78,6 +78,10 @@ export class CustomerInvoiceModel extends Model< declare customer_postal_code: string; declare customer_country: string; + // Método de pago + declare payment_method_id: string; + declare payment_method_description: string; + // Relaciones declare items: NonAttribute; declare taxes: NonAttribute; @@ -185,6 +189,18 @@ export default (database: Sequelize) => { defaultValue: null, }, + payment_method_id: { + type: DataTypes.UUID, + allowNull: true, + defaultValue: null, + }, + + payment_method_description: { + type: new DataTypes.STRING(), + allowNull: true, + defaultValue: null, + }, + subtotal_amount_value: { type: new DataTypes.BIGINT(), // importante: evita problemas de precisión con valores grandes allowNull: false,