import { CurrencyCode, DomainEntity, LanguageCode, Percentage, UniqueID } from "@repo/rdx-ddd"; import { Maybe, Result } from "@repo/rdx-utils"; import { CustomerInvoiceItemDescription, ItemAmount, ItemDiscount, ItemQuantity, } from "../../value-objects"; import { ItemTaxes } from "../item-taxes"; export interface CustomerInvoiceItemProps { description: Maybe; quantity: Maybe; // Cantidad de unidades unitAmount: Maybe; // Precio unitario en la moneda de la factura discountPercentage: Maybe; // % descuento taxes: ItemTaxes; languageCode: LanguageCode; currencyCode: CurrencyCode; } export interface ICustomerInvoiceItem { description: Maybe; quantity: Maybe; // Cantidad de unidades unitAmount: Maybe; // Precio unitario en la moneda de la factura discountPercentage: Maybe; // % descuento taxes: ItemTaxes; languageCode: LanguageCode; currencyCode: CurrencyCode; getSubtotalAmount(): ItemAmount; getDiscountAmount(): ItemAmount; getTaxableAmount(): ItemAmount; getTaxesAmount(): ItemAmount; getTotalAmount(): ItemAmount; } export class CustomerInvoiceItem extends DomainEntity implements ICustomerInvoiceItem { public static create( props: CustomerInvoiceItemProps, id?: UniqueID ): Result { const item = new CustomerInvoiceItem(props, id); // Reglas de negocio / validaciones // ... // ... return Result.ok(item); } get description(): Maybe { return this.props.description; } get quantity(): Maybe { return this.props.quantity; } get unitAmount(): Maybe { return this.props.unitAmount; } get discountPercentage(): Maybe { return this.props.discountPercentage; } get languageCode(): LanguageCode { return this.props.languageCode; } get currencyCode(): CurrencyCode { return this.props.currencyCode; } get taxes(): ItemTaxes { return this.props.taxes; } getProps(): CustomerInvoiceItemProps { return this.props; } toPrimitive() { return this.getProps(); } public getSubtotalAmount(): ItemAmount { const curCode = this.currencyCode.code; const quantity = this.quantity.match( (quantity) => quantity, () => ItemQuantity.zero() ); const unitAmount = this.unitAmount.match( (unitAmount) => unitAmount, () => ItemAmount.zero(curCode) ); return unitAmount.multiply(quantity); } public getDiscountAmount(): ItemAmount { const discount = this.discountPercentage.match( (percentage) => percentage, () => ItemDiscount.zero() ); return this.getSubtotalAmount().percentage(discount); } public getTaxableAmount(): ItemAmount { return this.getSubtotalAmount().subtract(this.getDiscountAmount()); } public getTaxesAmount(): ItemAmount { return this._getTaxesAmount(this.getTaxableAmount()); } public getTotalAmount(): ItemAmount { const taxableAmount = this.getTaxableAmount(); return taxableAmount.add(this._getTaxesAmount(taxableAmount)); } public getAllAmounts() { return { subtotalAmount: this.getSubtotalAmount(), discountAmount: this.getDiscountAmount(), taxableAmount: this.getTaxableAmount(), taxesAmount: this.getTaxesAmount(), totalAmount: this.getTotalAmount(), }; } private _getTaxesAmount(_taxableAmount: ItemAmount): ItemAmount { return this.props.taxes.getTaxesAmount(_taxableAmount); } }