Facturas de cliente
This commit is contained in:
parent
fa56473a00
commit
8c867eb7f3
@ -1,5 +1,5 @@
|
||||
import { TaxCatalogProvider } from "@erp/core";
|
||||
import { ValueObject } from "@repo/rdx-ddd";
|
||||
import { Percentage, ValueObject } from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
import * as z from "zod/v4";
|
||||
|
||||
@ -26,6 +26,8 @@ export class Tax extends ValueObject<TaxProps> {
|
||||
|
||||
private static CODE_REGEX = /^[a-z0-9_:-]+$/;
|
||||
|
||||
private _percentage!: Percentage;
|
||||
|
||||
protected static validate(values: TaxProps) {
|
||||
const schema = z.object({
|
||||
value: z
|
||||
@ -96,6 +98,14 @@ export class Tax extends ValueObject<TaxProps> {
|
||||
});
|
||||
}
|
||||
|
||||
protected constructor(props: TaxProps) {
|
||||
super(props);
|
||||
this._percentage = Percentage.create({
|
||||
value: this.props.value,
|
||||
scale: this.props.scale,
|
||||
}).data;
|
||||
}
|
||||
|
||||
get value(): number {
|
||||
return this.props.value;
|
||||
}
|
||||
@ -109,6 +119,10 @@ export class Tax extends ValueObject<TaxProps> {
|
||||
return this.props.code;
|
||||
}
|
||||
|
||||
get percentage(): Percentage {
|
||||
return this._percentage;
|
||||
}
|
||||
|
||||
getProps(): TaxProps {
|
||||
return this.props;
|
||||
}
|
||||
|
||||
@ -1,12 +1,4 @@
|
||||
import {
|
||||
CurrencyCode,
|
||||
DomainEntity,
|
||||
LanguageCode,
|
||||
MoneyValue,
|
||||
Percentage,
|
||||
Taxes,
|
||||
UniqueID,
|
||||
} from "@repo/rdx-ddd";
|
||||
import { CurrencyCode, DomainEntity, LanguageCode, Percentage, UniqueID } from "@repo/rdx-ddd";
|
||||
import { Maybe, Result } from "@repo/rdx-utils";
|
||||
import {
|
||||
CustomerInvoiceItemDescription,
|
||||
@ -14,14 +6,16 @@ import {
|
||||
ItemDiscount,
|
||||
ItemQuantity,
|
||||
} from "../../value-objects";
|
||||
import { ItemTaxes } from "../item-taxes";
|
||||
|
||||
export interface CustomerInvoiceItemProps {
|
||||
description: Maybe<CustomerInvoiceItemDescription>;
|
||||
quantity: Maybe<ItemQuantity>; // Cantidad de unidades
|
||||
unitAmount: Maybe<ItemAmount>; // Precio unitario en la moneda de la factura
|
||||
|
||||
discountPercentage: Maybe<ItemDiscount>; // % descuento
|
||||
|
||||
taxes: Taxes;
|
||||
taxes: ItemTaxes;
|
||||
|
||||
languageCode: LanguageCode;
|
||||
currencyCode: CurrencyCode;
|
||||
@ -32,31 +26,26 @@ export interface ICustomerInvoiceItem {
|
||||
|
||||
quantity: Maybe<ItemQuantity>; // Cantidad de unidades
|
||||
unitAmount: Maybe<ItemAmount>; // Precio unitario en la moneda de la factura
|
||||
subtotalAmount: ItemAmount;
|
||||
|
||||
discountPercentage: Maybe<ItemDiscount>; // % descuento
|
||||
discountAmount: Maybe<ItemAmount>;
|
||||
|
||||
taxableAmount: ItemAmount;
|
||||
taxesAmount: ItemAmount;
|
||||
|
||||
totalAmount: ItemAmount;
|
||||
taxes: ItemTaxes;
|
||||
|
||||
languageCode: LanguageCode;
|
||||
currencyCode: CurrencyCode;
|
||||
|
||||
calculateSubtotal(): ItemAmount;
|
||||
getSubtotalAmount(): ItemAmount;
|
||||
getDiscountAmount(): ItemAmount;
|
||||
|
||||
calculateTotal(): ItemAmount;
|
||||
getTaxableAmount(): ItemAmount;
|
||||
getTaxesAmount(): ItemAmount;
|
||||
getTotalAmount(): ItemAmount;
|
||||
}
|
||||
|
||||
export class CustomerInvoiceItem
|
||||
extends DomainEntity<CustomerInvoiceItemProps>
|
||||
implements ICustomerInvoiceItem
|
||||
{
|
||||
private _subtotalAmount!: ItemAmount;
|
||||
private _totalAmount!: ItemAmount;
|
||||
|
||||
public static create(
|
||||
props: CustomerInvoiceItemProps,
|
||||
id?: UniqueID
|
||||
@ -67,10 +56,6 @@ export class CustomerInvoiceItem
|
||||
// ...
|
||||
// ...
|
||||
|
||||
// 🔹 Disparar evento de dominio "CustomerInvoiceItemCreatedEvent"
|
||||
//const { customerInvoice } = props;
|
||||
//user.addDomainEvent(new CustomerInvoiceAuthenticatedEvent(id, customerInvoice.toString()));
|
||||
|
||||
return Result.ok(item);
|
||||
}
|
||||
|
||||
@ -86,38 +71,22 @@ export class CustomerInvoiceItem
|
||||
return this.props.unitAmount;
|
||||
}
|
||||
|
||||
get subtotalAmount(): ItemAmount {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
get discountPercentage(): Maybe<Percentage> {
|
||||
return this.props.discountPercentage;
|
||||
}
|
||||
|
||||
get discountAmount(): Maybe<MoneyValue> {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
get taxableAmount(): ItemAmount {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
get taxesAmount(): ItemAmount {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
get totalAmount(): ItemAmount {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
||||
public get languageCode(): LanguageCode {
|
||||
get languageCode(): LanguageCode {
|
||||
return this.props.languageCode;
|
||||
}
|
||||
|
||||
public get currencyCode(): CurrencyCode {
|
||||
get currencyCode(): CurrencyCode {
|
||||
return this.props.currencyCode;
|
||||
}
|
||||
|
||||
get taxes(): ItemTaxes {
|
||||
return this.props.taxes;
|
||||
}
|
||||
|
||||
getProps(): CustomerInvoiceItemProps {
|
||||
return this.props;
|
||||
}
|
||||
@ -126,17 +95,52 @@ export class CustomerInvoiceItem
|
||||
return this.getProps();
|
||||
}
|
||||
|
||||
calculateSubtotal(): ItemAmount {
|
||||
throw new Error("Not implemented");
|
||||
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)
|
||||
);
|
||||
|
||||
/*const unitPrice = this.unitPrice.isSome()
|
||||
? this.unitPrice.unwrap()
|
||||
: CustomerInvoiceItemUnitPrice.zero();
|
||||
return this.unitPrice.multiply(this.quantity.toNumber()); // Precio unitario * Cantidad*/
|
||||
return unitAmount.multiply(quantity);
|
||||
}
|
||||
|
||||
calculateTotal(): ItemAmount {
|
||||
throw new Error("Not implemented");
|
||||
//return this.subtotalPrice.subtract(this.subtotalPrice.percentage(this.discount.toNumber()));
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
export * from "./customer-invoice-items";
|
||||
export * from "./invoice-recipient";
|
||||
export * from "./invoice-taxes";
|
||||
export * from "./item-taxes";
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Tax } from "@erp/core/api";
|
||||
import { ValueObject } from "@repo/rdx-ddd";
|
||||
import { DomainEntity, UniqueID } from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
import { InvoiceAmount } from "../../value-objects/invoice-amount";
|
||||
|
||||
@ -9,28 +9,15 @@ export interface InvoiceTaxProps {
|
||||
taxesAmount: InvoiceAmount;
|
||||
}
|
||||
|
||||
export class InvoiceTax extends ValueObject<InvoiceTaxProps> {
|
||||
protected static validate(values: InvoiceTaxProps) {
|
||||
return Result.ok(values);
|
||||
}
|
||||
export class InvoiceTax extends DomainEntity<InvoiceTaxProps> {
|
||||
static create(props: InvoiceTaxProps, id?: UniqueID): Result<InvoiceTax, Error> {
|
||||
const invoiceTax = new InvoiceTax(props, id);
|
||||
|
||||
static create(values: InvoiceTaxProps): Result<InvoiceTax, Error> {
|
||||
const valueIsValid = InvoiceTax.validate(values);
|
||||
// Reglas de negocio / validaciones
|
||||
// ...
|
||||
// ...
|
||||
|
||||
if (valueIsValid.isFailure) {
|
||||
return Result.fail(valueIsValid.error);
|
||||
}
|
||||
|
||||
return Result.ok(new InvoiceTax(values));
|
||||
}
|
||||
|
||||
public update(partial: Partial<InvoiceTaxProps>): Result<InvoiceTax, Error> {
|
||||
const updatedProps = {
|
||||
...this.props,
|
||||
...partial,
|
||||
} as InvoiceTaxProps;
|
||||
|
||||
return InvoiceTax.create(updatedProps);
|
||||
return Result.ok(invoiceTax);
|
||||
}
|
||||
|
||||
public get tax(): Tax {
|
||||
|
||||
@ -0,0 +1,2 @@
|
||||
export * from "./item-tax";
|
||||
export * from "./item-taxes";
|
||||
@ -0,0 +1,36 @@
|
||||
import { Tax } from "@erp/core/api";
|
||||
import { DomainEntity, UniqueID } from "@repo/rdx-ddd";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
import { ItemAmount } from "../../value-objects";
|
||||
|
||||
export interface ItemTaxProps {
|
||||
tax: Tax;
|
||||
}
|
||||
|
||||
export class ItemTax extends DomainEntity<ItemTaxProps> {
|
||||
static create(props: ItemTaxProps, id?: UniqueID): Result<ItemTax, Error> {
|
||||
const invoiceTax = new ItemTax(props, id);
|
||||
|
||||
// Reglas de negocio / validaciones
|
||||
// ...
|
||||
// ...
|
||||
|
||||
return Result.ok(invoiceTax);
|
||||
}
|
||||
|
||||
public get tax(): Tax {
|
||||
return this.props.tax;
|
||||
}
|
||||
|
||||
getProps(): ItemTaxProps {
|
||||
return this.props;
|
||||
}
|
||||
|
||||
toPrimitive() {
|
||||
return this.getProps();
|
||||
}
|
||||
|
||||
public getTaxAmount(taxableAmount: ItemAmount): ItemAmount {
|
||||
return taxableAmount.percentage(this.tax.percentage);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
import { Collection } from "@repo/rdx-utils";
|
||||
import { ItemAmount } from "../../value-objects";
|
||||
import { ItemTax } from "./item-tax";
|
||||
|
||||
export interface ItemTaxesProps {
|
||||
items?: ItemTax[];
|
||||
}
|
||||
|
||||
export class ItemTaxes extends Collection<ItemTax> {
|
||||
constructor(props: ItemTaxesProps) {
|
||||
const { items = [] } = props;
|
||||
super(items);
|
||||
}
|
||||
|
||||
public static create(props: ItemTaxesProps): ItemTaxes {
|
||||
return new ItemTaxes(props);
|
||||
}
|
||||
|
||||
public getTaxesAmount(taxableAmount: ItemAmount): ItemAmount {
|
||||
return this.getAll().reduce(
|
||||
(total, tax) => total.add(tax.getTaxAmount(taxableAmount)),
|
||||
ItemAmount.zero(taxableAmount.currencyCode)
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -19,6 +19,6 @@ export class ItemAmount extends MoneyValue {
|
||||
value: 0,
|
||||
currency_code,
|
||||
};
|
||||
return ItemAmount.create(props);
|
||||
return ItemAmount.create(props).data;
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,6 +14,6 @@ export class ItemDiscount extends Percentage {
|
||||
}
|
||||
|
||||
static zero() {
|
||||
return ItemDiscount.create({ value: 0 });
|
||||
return ItemDiscount.create({ value: 0 }).data;
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,6 +13,6 @@ export class ItemQuantity extends Quantity {
|
||||
}
|
||||
|
||||
static zero() {
|
||||
return ItemQuantity.create({ value: 0 });
|
||||
return ItemQuantity.create({ value: 0 }).data;
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@ export interface MoneyValueProps {
|
||||
export interface IMoneyValue {
|
||||
value: number;
|
||||
scale: number;
|
||||
currency: Dinero.Currency;
|
||||
currencyCode: string;
|
||||
|
||||
getProps(): MoneyValueProps;
|
||||
convertScale(newScale: number): MoneyValue;
|
||||
@ -78,8 +78,8 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
|
||||
return this.dinero.getAmount() / 10 ** this.dinero.getPrecision(); // ** => Math.pow
|
||||
}
|
||||
|
||||
get currency(): CurrencyData {
|
||||
return this.dinero.getCurrency();
|
||||
get currencyCode(): string {
|
||||
return this.dinero.getCurrency().toString();
|
||||
}
|
||||
|
||||
get scale(): number {
|
||||
@ -103,7 +103,7 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
|
||||
return {
|
||||
value: this.value,
|
||||
scale: this.scale,
|
||||
currency_code: this.currency,
|
||||
currency_code: this.currencyCode,
|
||||
};
|
||||
}
|
||||
|
||||
@ -120,7 +120,7 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
|
||||
return new MoneyValue({
|
||||
value: this.dinero.add(addend.dinero).getAmount(),
|
||||
scale: this.scale,
|
||||
currency_code: this.currency,
|
||||
currency_code: this.currencyCode,
|
||||
});
|
||||
}
|
||||
|
||||
@ -128,7 +128,7 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
|
||||
return new MoneyValue({
|
||||
value: this.dinero.subtract(subtrahend.dinero).getAmount(),
|
||||
scale: this.scale,
|
||||
currency_code: this.currency,
|
||||
currency_code: this.currencyCode,
|
||||
});
|
||||
}
|
||||
|
||||
@ -205,12 +205,12 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
|
||||
*/
|
||||
format(locale: string): string {
|
||||
const value = this.value;
|
||||
const currency = this.currency;
|
||||
const currencyCode = this.currencyCode;
|
||||
const scale = this.scale;
|
||||
|
||||
return new Intl.NumberFormat(locale, {
|
||||
style: "currency",
|
||||
currency: currency,
|
||||
currency: currencyCode,
|
||||
minimumFractionDigits: scale,
|
||||
maximumFractionDigits: scale,
|
||||
useGrouping: true,
|
||||
|
||||
@ -82,6 +82,15 @@ export class Collection<T> {
|
||||
return this.totalItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the specified action for each element in an array.
|
||||
* @param callbackfn A function that accepts up to three arguments. forEach calls the callbackfn function one time for each element in the array.
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
forEach<U>(callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any): void {
|
||||
this.items.forEach(callbackfn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Aplica una función a cada elemento y devuelve un nuevo array con los resultados.
|
||||
* @param callback - Función transformadora.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user