Facturas de cliente
This commit is contained in:
parent
fa56473a00
commit
8c867eb7f3
@ -1,5 +1,5 @@
|
|||||||
import { TaxCatalogProvider } from "@erp/core";
|
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 { Result } from "@repo/rdx-utils";
|
||||||
import * as z from "zod/v4";
|
import * as z from "zod/v4";
|
||||||
|
|
||||||
@ -26,6 +26,8 @@ export class Tax extends ValueObject<TaxProps> {
|
|||||||
|
|
||||||
private static CODE_REGEX = /^[a-z0-9_:-]+$/;
|
private static CODE_REGEX = /^[a-z0-9_:-]+$/;
|
||||||
|
|
||||||
|
private _percentage!: Percentage;
|
||||||
|
|
||||||
protected static validate(values: TaxProps) {
|
protected static validate(values: TaxProps) {
|
||||||
const schema = z.object({
|
const schema = z.object({
|
||||||
value: z
|
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 {
|
get value(): number {
|
||||||
return this.props.value;
|
return this.props.value;
|
||||||
}
|
}
|
||||||
@ -109,6 +119,10 @@ export class Tax extends ValueObject<TaxProps> {
|
|||||||
return this.props.code;
|
return this.props.code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get percentage(): Percentage {
|
||||||
|
return this._percentage;
|
||||||
|
}
|
||||||
|
|
||||||
getProps(): TaxProps {
|
getProps(): TaxProps {
|
||||||
return this.props;
|
return this.props;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,4 @@
|
|||||||
import {
|
import { CurrencyCode, DomainEntity, LanguageCode, Percentage, UniqueID } from "@repo/rdx-ddd";
|
||||||
CurrencyCode,
|
|
||||||
DomainEntity,
|
|
||||||
LanguageCode,
|
|
||||||
MoneyValue,
|
|
||||||
Percentage,
|
|
||||||
Taxes,
|
|
||||||
UniqueID,
|
|
||||||
} from "@repo/rdx-ddd";
|
|
||||||
import { Maybe, Result } from "@repo/rdx-utils";
|
import { Maybe, Result } from "@repo/rdx-utils";
|
||||||
import {
|
import {
|
||||||
CustomerInvoiceItemDescription,
|
CustomerInvoiceItemDescription,
|
||||||
@ -14,14 +6,16 @@ import {
|
|||||||
ItemDiscount,
|
ItemDiscount,
|
||||||
ItemQuantity,
|
ItemQuantity,
|
||||||
} from "../../value-objects";
|
} from "../../value-objects";
|
||||||
|
import { ItemTaxes } from "../item-taxes";
|
||||||
|
|
||||||
export interface CustomerInvoiceItemProps {
|
export interface CustomerInvoiceItemProps {
|
||||||
description: Maybe<CustomerInvoiceItemDescription>;
|
description: Maybe<CustomerInvoiceItemDescription>;
|
||||||
quantity: Maybe<ItemQuantity>; // Cantidad de unidades
|
quantity: Maybe<ItemQuantity>; // Cantidad de unidades
|
||||||
unitAmount: Maybe<ItemAmount>; // Precio unitario en la moneda de la factura
|
unitAmount: Maybe<ItemAmount>; // Precio unitario en la moneda de la factura
|
||||||
|
|
||||||
discountPercentage: Maybe<ItemDiscount>; // % descuento
|
discountPercentage: Maybe<ItemDiscount>; // % descuento
|
||||||
|
|
||||||
taxes: Taxes;
|
taxes: ItemTaxes;
|
||||||
|
|
||||||
languageCode: LanguageCode;
|
languageCode: LanguageCode;
|
||||||
currencyCode: CurrencyCode;
|
currencyCode: CurrencyCode;
|
||||||
@ -32,31 +26,26 @@ export interface ICustomerInvoiceItem {
|
|||||||
|
|
||||||
quantity: Maybe<ItemQuantity>; // Cantidad de unidades
|
quantity: Maybe<ItemQuantity>; // Cantidad de unidades
|
||||||
unitAmount: Maybe<ItemAmount>; // Precio unitario en la moneda de la factura
|
unitAmount: Maybe<ItemAmount>; // Precio unitario en la moneda de la factura
|
||||||
subtotalAmount: ItemAmount;
|
|
||||||
|
|
||||||
discountPercentage: Maybe<ItemDiscount>; // % descuento
|
discountPercentage: Maybe<ItemDiscount>; // % descuento
|
||||||
discountAmount: Maybe<ItemAmount>;
|
|
||||||
|
|
||||||
taxableAmount: ItemAmount;
|
taxes: ItemTaxes;
|
||||||
taxesAmount: ItemAmount;
|
|
||||||
|
|
||||||
totalAmount: ItemAmount;
|
|
||||||
|
|
||||||
languageCode: LanguageCode;
|
languageCode: LanguageCode;
|
||||||
currencyCode: CurrencyCode;
|
currencyCode: CurrencyCode;
|
||||||
|
|
||||||
calculateSubtotal(): ItemAmount;
|
getSubtotalAmount(): ItemAmount;
|
||||||
|
getDiscountAmount(): ItemAmount;
|
||||||
|
|
||||||
calculateTotal(): ItemAmount;
|
getTaxableAmount(): ItemAmount;
|
||||||
|
getTaxesAmount(): ItemAmount;
|
||||||
|
getTotalAmount(): ItemAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CustomerInvoiceItem
|
export class CustomerInvoiceItem
|
||||||
extends DomainEntity<CustomerInvoiceItemProps>
|
extends DomainEntity<CustomerInvoiceItemProps>
|
||||||
implements ICustomerInvoiceItem
|
implements ICustomerInvoiceItem
|
||||||
{
|
{
|
||||||
private _subtotalAmount!: ItemAmount;
|
|
||||||
private _totalAmount!: ItemAmount;
|
|
||||||
|
|
||||||
public static create(
|
public static create(
|
||||||
props: CustomerInvoiceItemProps,
|
props: CustomerInvoiceItemProps,
|
||||||
id?: UniqueID
|
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);
|
return Result.ok(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,38 +71,22 @@ export class CustomerInvoiceItem
|
|||||||
return this.props.unitAmount;
|
return this.props.unitAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
get subtotalAmount(): ItemAmount {
|
|
||||||
throw new Error("Not implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
get discountPercentage(): Maybe<Percentage> {
|
get discountPercentage(): Maybe<Percentage> {
|
||||||
return this.props.discountPercentage;
|
return this.props.discountPercentage;
|
||||||
}
|
}
|
||||||
|
|
||||||
get discountAmount(): Maybe<MoneyValue> {
|
get languageCode(): LanguageCode {
|
||||||
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 {
|
|
||||||
return this.props.languageCode;
|
return this.props.languageCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get currencyCode(): CurrencyCode {
|
get currencyCode(): CurrencyCode {
|
||||||
return this.props.currencyCode;
|
return this.props.currencyCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get taxes(): ItemTaxes {
|
||||||
|
return this.props.taxes;
|
||||||
|
}
|
||||||
|
|
||||||
getProps(): CustomerInvoiceItemProps {
|
getProps(): CustomerInvoiceItemProps {
|
||||||
return this.props;
|
return this.props;
|
||||||
}
|
}
|
||||||
@ -126,17 +95,52 @@ export class CustomerInvoiceItem
|
|||||||
return this.getProps();
|
return this.getProps();
|
||||||
}
|
}
|
||||||
|
|
||||||
calculateSubtotal(): ItemAmount {
|
public getSubtotalAmount(): ItemAmount {
|
||||||
throw new Error("Not implemented");
|
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()
|
return unitAmount.multiply(quantity);
|
||||||
? this.unitPrice.unwrap()
|
|
||||||
: CustomerInvoiceItemUnitPrice.zero();
|
|
||||||
return this.unitPrice.multiply(this.quantity.toNumber()); // Precio unitario * Cantidad*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
calculateTotal(): ItemAmount {
|
public getDiscountAmount(): ItemAmount {
|
||||||
throw new Error("Not implemented");
|
const discount = this.discountPercentage.match(
|
||||||
//return this.subtotalPrice.subtract(this.subtotalPrice.percentage(this.discount.toNumber()));
|
(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 "./customer-invoice-items";
|
||||||
export * from "./invoice-recipient";
|
|
||||||
export * from "./invoice-taxes";
|
export * from "./invoice-taxes";
|
||||||
|
export * from "./item-taxes";
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Tax } from "@erp/core/api";
|
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 { Result } from "@repo/rdx-utils";
|
||||||
import { InvoiceAmount } from "../../value-objects/invoice-amount";
|
import { InvoiceAmount } from "../../value-objects/invoice-amount";
|
||||||
|
|
||||||
@ -9,28 +9,15 @@ export interface InvoiceTaxProps {
|
|||||||
taxesAmount: InvoiceAmount;
|
taxesAmount: InvoiceAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class InvoiceTax extends ValueObject<InvoiceTaxProps> {
|
export class InvoiceTax extends DomainEntity<InvoiceTaxProps> {
|
||||||
protected static validate(values: InvoiceTaxProps) {
|
static create(props: InvoiceTaxProps, id?: UniqueID): Result<InvoiceTax, Error> {
|
||||||
return Result.ok(values);
|
const invoiceTax = new InvoiceTax(props, id);
|
||||||
}
|
|
||||||
|
|
||||||
static create(values: InvoiceTaxProps): Result<InvoiceTax, Error> {
|
// Reglas de negocio / validaciones
|
||||||
const valueIsValid = InvoiceTax.validate(values);
|
// ...
|
||||||
|
// ...
|
||||||
|
|
||||||
if (valueIsValid.isFailure) {
|
return Result.ok(invoiceTax);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public get tax(): Tax {
|
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,
|
value: 0,
|
||||||
currency_code,
|
currency_code,
|
||||||
};
|
};
|
||||||
return ItemAmount.create(props);
|
return ItemAmount.create(props).data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,6 @@ export class ItemDiscount extends Percentage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static zero() {
|
static zero() {
|
||||||
return ItemDiscount.create({ value: 0 });
|
return ItemDiscount.create({ value: 0 }).data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,6 @@ export class ItemQuantity extends Quantity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static zero() {
|
static zero() {
|
||||||
return ItemQuantity.create({ value: 0 });
|
return ItemQuantity.create({ value: 0 }).data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,7 +27,7 @@ export interface MoneyValueProps {
|
|||||||
export interface IMoneyValue {
|
export interface IMoneyValue {
|
||||||
value: number;
|
value: number;
|
||||||
scale: number;
|
scale: number;
|
||||||
currency: Dinero.Currency;
|
currencyCode: string;
|
||||||
|
|
||||||
getProps(): MoneyValueProps;
|
getProps(): MoneyValueProps;
|
||||||
convertScale(newScale: number): MoneyValue;
|
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
|
return this.dinero.getAmount() / 10 ** this.dinero.getPrecision(); // ** => Math.pow
|
||||||
}
|
}
|
||||||
|
|
||||||
get currency(): CurrencyData {
|
get currencyCode(): string {
|
||||||
return this.dinero.getCurrency();
|
return this.dinero.getCurrency().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
get scale(): number {
|
get scale(): number {
|
||||||
@ -103,7 +103,7 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
|
|||||||
return {
|
return {
|
||||||
value: this.value,
|
value: this.value,
|
||||||
scale: this.scale,
|
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({
|
return new MoneyValue({
|
||||||
value: this.dinero.add(addend.dinero).getAmount(),
|
value: this.dinero.add(addend.dinero).getAmount(),
|
||||||
scale: this.scale,
|
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({
|
return new MoneyValue({
|
||||||
value: this.dinero.subtract(subtrahend.dinero).getAmount(),
|
value: this.dinero.subtract(subtrahend.dinero).getAmount(),
|
||||||
scale: this.scale,
|
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 {
|
format(locale: string): string {
|
||||||
const value = this.value;
|
const value = this.value;
|
||||||
const currency = this.currency;
|
const currencyCode = this.currencyCode;
|
||||||
const scale = this.scale;
|
const scale = this.scale;
|
||||||
|
|
||||||
return new Intl.NumberFormat(locale, {
|
return new Intl.NumberFormat(locale, {
|
||||||
style: "currency",
|
style: "currency",
|
||||||
currency: currency,
|
currency: currencyCode,
|
||||||
minimumFractionDigits: scale,
|
minimumFractionDigits: scale,
|
||||||
maximumFractionDigits: scale,
|
maximumFractionDigits: scale,
|
||||||
useGrouping: true,
|
useGrouping: true,
|
||||||
|
|||||||
@ -82,6 +82,15 @@ export class Collection<T> {
|
|||||||
return this.totalItems;
|
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.
|
* Aplica una función a cada elemento y devuelve un nuevo array con los resultados.
|
||||||
* @param callback - Función transformadora.
|
* @param callback - Función transformadora.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user