import { AggregateRoot, MoneyValue, UniqueID, UtcDate } from "@common/domain"; import { Collection, Result } from "@common/helpers"; import { Currency } from "dinero.js"; import { InvoiceStatus } from "../value-objects"; export interface IInvoiceProps { invoiceNumber: InvoiceNumber; invoiceSeries: InvoiceSeries; issueDate: UtcDate; operationDate: UtcDate; //dueDate: UtcDate; // ? --> depende de la forma de pago //tax: Tax; // ? --> detalles? invoiceCurrency: Currency; language: Language; //purchareOrderNumber: string; //notes: Note; //senderId: UniqueID; recipient: InvoiceParticipant; //paymentInstructions: Note; //paymentTerms: string; items: Collection; } export interface IInvoice { id: UniqueID; invoiceNumber: InvoiceNumber; invoiceSeries: InvoiceSeries; status: InvoiceStatus; issueDate: UtcDate; operationDate: UtcDate; //senderId: UniqueID; recipient: InvoiceParticipant; //dueDate //tax: Tax; language: Language; currency: Currency; //purchareOrderNumber: string; //notes: Note; //paymentInstructions: Note; //paymentTerms: string; items: Collection; calculateSubtotal: () => MoneyValue; calculateTaxTotal: () => MoneyValue; calculateTotal: () => MoneyValue; } export class Invoice extends AggregateRoot implements IInvoice { private _items: Collection; protected _status: InvoiceStatus; static create(props: IInvoiceProps, id?: UniqueID): Result { const invoice = new Invoice(props, id); // Reglas de negocio / validaciones // ... // ... // 🔹 Disparar evento de dominio "InvoiceAuthenticatedEvent" //const { invoice } = props; //user.addDomainEvent(new InvoiceAuthenticatedEvent(id, invoice.toString())); return Result.ok(invoice); } get invoiceNumber() { return this.props.invoiceNumber; } get invoiceSeries() { return this.props.invoiceSeries; } get issueDate() { return this.props.issueDate; } /*get senderId(): UniqueID { return this.props.senderId; }*/ get recipient(): InvoiceParticipant { return this.props.recipient; } get operationDate() { return this.props.operationDate; } get language() { return this.props.language; } get dueDate() { return undefined; } get tax() { return undefined; } get status() { return this._status; } get items() { return this._items; } /*get purchareOrderNumber() { return this.props.purchareOrderNumber; } get paymentInstructions() { return this.props.paymentInstructions; } get paymentTerms() { return this.props.paymentTerms; } get billTo() { return this.props.billTo; } get shipTo() { return this.props.shipTo; }*/ get currency() { return this.props.invoiceCurrency; } /*get notes() { return this.props.notes; }*/ // Method to get the complete list of line items /*get lineItems(): InvoiceLineItem[] { return this._lineItems; } addLineItem(lineItem: InvoiceLineItem, position?: number): void { if (position === undefined) { this._lineItems.push(lineItem); } else { this._lineItems.splice(position, 0, lineItem); } }*/ calculateSubtotal(): MoneyValue { let subtotal: MoneyValue | null = null; for (const item of this._items.items) { if (!subtotal) { subtotal = item.calculateSubtotal(); } else { subtotal = subtotal.add(item.calculateSubtotal()); } } return subtotal ? subtotal.convertPrecision(2) : MoneyValue.create({ amount: 0, currencyCode: this.props.invoiceCurrency.code, precision: 2, }).object; } // Method to calculate the total tax in the invoice calculateTaxTotal(): MoneyValue { let taxTotal = MoneyValue.create({ amount: 0, currencyCode: this.props.invoiceCurrency.code, precision: 2, }).object; for (const item of this._items.items) { taxTotal = taxTotal.add(item.calculateTaxAmount()); } return taxTotal.convertPrecision(2); } // Method to calculate the total invoice amount, including taxes calculateTotal(): MoneyValue { return this.calculateSubtotal().add(this.calculateTaxTotal()).convertPrecision(2); } }