Facturas de cliente

This commit is contained in:
David Arranz 2025-09-04 12:02:24 +02:00
parent 5064494b12
commit e65524ea3c
52 changed files with 235 additions and 196 deletions

View File

@ -14,6 +14,6 @@ export const NumericStringSchema = z
// Cantidad de dinero (base): solo para la cantidad y la escala, sin moneda // Cantidad de dinero (base): solo para la cantidad y la escala, sin moneda
export const AmountBaseSchema = z.object({ export const AmountBaseSchema = z.object({
amount: NumericStringSchema, value: NumericStringSchema,
scale: NumericStringSchema, scale: NumericStringSchema,
}); });

View File

@ -7,7 +7,7 @@ import { NumericStringSchema } from "./base.schemas";
*/ */
export const PercentageSchema = z.object({ export const PercentageSchema = z.object({
amount: NumericStringSchema, value: NumericStringSchema,
scale: NumericStringSchema, scale: NumericStringSchema,
}); });

View File

@ -7,7 +7,7 @@ import { NumericStringSchema } from "./base.schemas";
*/ */
export const QuantitySchema = z.object({ export const QuantitySchema = z.object({
amount: NumericStringSchema, value: NumericStringSchema,
scale: NumericStringSchema, scale: NumericStringSchema,
}); });

View File

@ -8,41 +8,38 @@ export class GetCustomerInvoiceItemsAssembler {
toDTO(invoice: CustomerInvoice): GetCustomerInvoiceItemsByInvoiceIdResponseDTO { toDTO(invoice: CustomerInvoice): GetCustomerInvoiceItemsByInvoiceIdResponseDTO {
const { items } = invoice; const { items } = invoice;
return items.map((item, index) => ({ return items.map((item, index) => ({
//id: item. id: item.id.toString(),
position: index, position: String(index),
description: toEmptyString(item.description, (value) => value.toPrimitive()), description: toEmptyString(item.description, (value) => value.toPrimitive()),
quantity: item.quantity.match( quantity: item.quantity.match(
(quantity) => { (quantity) => {
const { amount, scale } = quantity.toPrimitive(); const { value, scale } = quantity.toPrimitive();
return { amount: amount.toString(), scale: scale.toString() }; return { value: value.toString(), scale: scale.toString() };
}, },
() => ({ amount: "", scale: "" }) () => ({ value: "", scale: "" })
), ),
unit_price_amount: item.unitAmount.match( unit_amount: item.unitAmount.match(
(unitPrice) => { (unitAmount) => {
const { amount, scale } = unitPrice.toPrimitive(); const { value, scale } = unitAmount.toPrimitive();
return { amount: amount.toString(), scale: scale.toString() }; return { value: value.toString(), scale: scale.toString() };
}, },
() => ({ amount: "", scale: "" }) () => ({ value: "", scale: "" })
), ),
discount: item.discount.match( discount_percentage: item.discountPercentage.match(
(discount) => { (discountPercentage) => {
const { amount, scale } = discount.toPrimitive(); const { value, scale } = discountPercentage.toPrimitive();
return { amount: amount.toString(), scale: scale.toString() }; return { value: value.toString(), scale: scale.toString() };
}, },
() => ({ amount: "", scale: "" }) () => ({ value: "", scale: "" })
), ),
total_amount: item.totalPrice.match( total_amount: {
(discount) => { value: item.totalAmount.toPrimitive().value.toString(),
const { amount, scale } = discount.toPrimitive(); scale: item.totalAmount.toPrimitive().scale.toString(),
return { amount: amount.toString(), scale: scale.toString() }; },
},
() => ({ amount: "", scale: "" })
),
})); }));
} }
} }

View File

@ -1,13 +1,17 @@
import { GetCustomerInvoiceByIdResponseDTO } from "@erp/customer-invoices/common/dto"; import { GetCustomerInvoiceByIdResponseDTO } from "@erp/customer-invoices/common/dto";
import { toEmptyString } from "@repo/rdx-ddd"; import { toEmptyString } from "@repo/rdx-ddd";
import { CustomerInvoice } from "../../../domain"; import { CustomerInvoice } from "../../../domain";
import { GetCustomerInvoiceItemsAssembler } from "./get-invoice-items.assembler";
export class GetCustomerInvoiceAssembler { export class GetCustomerInvoiceAssembler {
private _itemsAssembler!: GetCu; private _itemsAssembler!: GetCustomerInvoiceItemsAssembler;
constructor() {}
constructor() {
this._itemsAssembler = new GetCustomerInvoiceItemsAssembler();
}
public toDTO(invoice: CustomerInvoice): GetCustomerInvoiceByIdResponseDTO { public toDTO(invoice: CustomerInvoice): GetCustomerInvoiceByIdResponseDTO {
//const items = invoice.items. const items = this._itemsAssembler.toDTO(invoice);
return { return {
id: invoice.id.toPrimitive(), id: invoice.id.toPrimitive(),
@ -25,6 +29,38 @@ export class GetCustomerInvoiceAssembler {
language_code: invoice.languageCode.toPrimitive(), language_code: invoice.languageCode.toPrimitive(),
currency_code: invoice.currencyCode.toPrimitive(), currency_code: invoice.currencyCode.toPrimitive(),
subtotal_amount: {
value: invoice.subtotalAmount.value.toString(),
scale: invoice.subtotalAmount.scale.toString(),
},
discount_percentage: {
value: invoice.discountPercentage.value.toString(),
scale: invoice.discountPercentage.scale.toString(),
},
discount_amount: {
value: invoice.discountAmount.value.toString(),
scale: invoice.discountAmount.scale.toString(),
},
taxable_amount: {
value: invoice.taxableAmount.value.toString(),
scale: invoice.taxableAmount.scale.toString(),
},
tax_amount: {
value: invoice.taxAmount.value.toString(),
scale: invoice.taxAmount.scale.toString(),
},
total_amount: {
value: invoice.totalAmount.value.toString(),
scale: invoice.totalAmount.scale.toString(),
},
items,
metadata: { metadata: {
entity: "customer-invoices", entity: "customer-invoices",
}, },

View File

@ -2,7 +2,7 @@ import { ITransactionManager } from "@erp/core/api";
import { UniqueID } from "@repo/rdx-ddd"; import { UniqueID } from "@repo/rdx-ddd";
import { Result } from "@repo/rdx-utils"; import { Result } from "@repo/rdx-utils";
import { CustomerInvoiceService } from "../../domain"; import { CustomerInvoiceService } from "../../domain";
import { GetCustomerInvoiceItemsAssembler } from "./assembler"; import { GetCustomerInvoiceAssembler } from "./assembler";
type GetCustomerInvoiceUseCaseInput = { type GetCustomerInvoiceUseCaseInput = {
companyId: UniqueID; companyId: UniqueID;
@ -13,7 +13,7 @@ export class GetCustomerInvoiceUseCase {
constructor( constructor(
private readonly service: CustomerInvoiceService, private readonly service: CustomerInvoiceService,
private readonly transactionManager: ITransactionManager, private readonly transactionManager: ITransactionManager,
private readonly assembler: GetCustomerInvoiceItemsAssembler private readonly assembler: GetCustomerInvoiceAssembler
) {} ) {}
public execute(params: GetCustomerInvoiceUseCaseInput) { public execute(params: GetCustomerInvoiceUseCaseInput) {

View File

@ -37,7 +37,7 @@ export function mapDTOToCustomerInvoiceItemsProps(
const unitPrice = extractOrPushError( const unitPrice = extractOrPushError(
CustomerInvoiceItemUnitAmount.create({ CustomerInvoiceItemUnitAmount.create({
amount: item.unitPrice.amount, value: item.unitPrice.amount,
scale: item.unitPrice.scale, scale: item.unitPrice.scale,
currency_code: item.unitPrice.currency, currency_code: item.unitPrice.currency,
}), }),
@ -47,7 +47,7 @@ export function mapDTOToCustomerInvoiceItemsProps(
const discount = extractOrPushError( const discount = extractOrPushError(
CustomerInvoiceItemDiscount.create({ CustomerInvoiceItemDiscount.create({
amount: item.discount.amount, value: item.discount.amount,
scale: item.discount.scale, scale: item.discount.scale,
}), }),
path("discount"), path("discount"),

View File

@ -59,11 +59,11 @@ export class CustomerInvoiceItem extends DomainEntity<CustomerInvoiceItemProps>
return this._subtotalAmount; return this._subtotalAmount;
} }
get discount(): Maybe<CustomerInvoiceItemDiscount> { get discountPercentage(): Maybe<CustomerInvoiceItemDiscount> {
return this.props.discount; return this.props.discount;
} }
get totalPrice(): CustomerInvoiceItemTotalAmount { get totalAmount(): CustomerInvoiceItemTotalAmount {
if (!this._totalAmount) { if (!this._totalAmount) {
this._totalAmount = this.calculateTotal(); this._totalAmount = this.calculateTotal();
} }

View File

@ -19,7 +19,10 @@ export interface ICustomerInvoiceAddress {
phone: PhoneNumber; phone: PhoneNumber;
} }
export class CustomerInvoiceAddress extends ValueObject<ICustomerInvoiceAddressProps> implements ICustomerInvoiceAddress { export class CustomerInvoiceAddress
extends ValueObject<ICustomerInvoiceAddressProps>
implements ICustomerInvoiceAddress
{
public static create(props: ICustomerInvoiceAddressProps) { public static create(props: ICustomerInvoiceAddressProps) {
return Result.ok(new CustomerInvoiceAddress(props)); return Result.ok(new CustomerInvoiceAddress(props));
} }
@ -62,7 +65,7 @@ export class CustomerInvoiceAddress extends ValueObject<ICustomerInvoiceAddressP
return this.props.type; return this.props.type;
} }
getValue(): ICustomerInvoiceAddressProps { getProps(): ICustomerInvoiceAddressProps {
return this.props; return this.props;
} }

View File

@ -24,15 +24,15 @@ export class CustomerInvoiceAddressType extends ValueObject<ICustomerInvoiceAddr
return Result.ok(new CustomerInvoiceAddressType({ value })); return Result.ok(new CustomerInvoiceAddressType({ value }));
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }
toString(): string { toString(): string {
return this.getValue(); return this.getProps();
} }
toPrimitive(): string { toPrimitive(): string {
return this.getValue(); return this.getProps();
} }
} }

View File

@ -46,15 +46,15 @@ export class CustomerInvoiceItemDescription extends ValueObject<CustomerInvoiceI
return CustomerInvoiceItemDescription.create(value).map((value) => Maybe.some(value)); return CustomerInvoiceItemDescription.create(value).map((value) => Maybe.some(value));
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }
toString(): string { toString(): string {
return this.getValue(); return this.getProps();
} }
toPrimitive() { toPrimitive() {
return this.getValue(); return this.getProps();
} }
} }

View File

@ -3,7 +3,7 @@ import { MoneyValue, MoneyValueProps } from "@repo/rdx-ddd";
export class CustomerInvoiceItemSubtotalAmount extends MoneyValue { export class CustomerInvoiceItemSubtotalAmount extends MoneyValue {
public static DEFAULT_SCALE = 4; public static DEFAULT_SCALE = 4;
static create({ amount, currency_code, scale }: MoneyValueProps) { static create({ value: amount, currency_code, scale }: MoneyValueProps) {
const props = { const props = {
amount: Number(amount), amount: Number(amount),
scale: scale ?? MoneyValue.DEFAULT_SCALE, scale: scale ?? MoneyValue.DEFAULT_SCALE,

View File

@ -3,9 +3,9 @@ import { MoneyValue, MoneyValueProps } from "@repo/rdx-ddd";
export class CustomerInvoiceItemTotalAmount extends MoneyValue { export class CustomerInvoiceItemTotalAmount extends MoneyValue {
public static DEFAULT_SCALE = 4; public static DEFAULT_SCALE = 4;
static create({ amount, currency_code, scale }: MoneyValueProps) { static create({ value, currency_code, scale }: MoneyValueProps) {
const props = { const props = {
amount: Number(amount), value: Number(value),
scale: scale ?? MoneyValue.DEFAULT_SCALE, scale: scale ?? MoneyValue.DEFAULT_SCALE,
currency_code, currency_code,
}; };

View File

@ -3,7 +3,7 @@ import { MoneyValue, MoneyValueProps } from "@repo/rdx-ddd";
export class CustomerInvoiceItemUnitAmount extends MoneyValue { export class CustomerInvoiceItemUnitAmount extends MoneyValue {
public static DEFAULT_SCALE = 4; public static DEFAULT_SCALE = 4;
static create({ amount, currency_code, scale }: MoneyValueProps) { static create({ value: amount, currency_code, scale }: MoneyValueProps) {
const props = { const props = {
amount: Number(amount), amount: Number(amount),
scale: scale ?? MoneyValue.DEFAULT_SCALE, scale: scale ?? MoneyValue.DEFAULT_SCALE,
@ -14,7 +14,7 @@ export class CustomerInvoiceItemUnitAmount extends MoneyValue {
static zero(currency_code: string, scale: number = CustomerInvoiceItemUnitAmount.DEFAULT_SCALE) { static zero(currency_code: string, scale: number = CustomerInvoiceItemUnitAmount.DEFAULT_SCALE) {
const props: MoneyValueProps = { const props: MoneyValueProps = {
amount: 0, value: 0,
scale, scale,
currency_code, currency_code,
}; };

View File

@ -38,15 +38,15 @@ export class CustomerInvoiceNumber extends ValueObject<ICustomerInvoiceNumberPro
return Result.ok(new CustomerInvoiceNumber({ value })); return Result.ok(new CustomerInvoiceNumber({ value }));
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }
toString(): string { toString(): string {
return this.getValue(); return this.getProps();
} }
toPrimitive() { toPrimitive() {
return this.getValue(); return this.getProps();
} }
} }

View File

@ -46,15 +46,15 @@ export class CustomerInvoiceSerie extends ValueObject<ICustomerInvoiceSerieProps
return CustomerInvoiceSerie.create(value).map((value) => Maybe.some(value)); return CustomerInvoiceSerie.create(value).map((value) => Maybe.some(value));
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }
toString(): string { toString(): string {
return this.getValue(); return this.getProps();
} }
toPrimitive() { toPrimitive() {
return this.getValue(); return this.getProps();
} }
} }

View File

@ -71,12 +71,12 @@ export class CustomerInvoiceStatus extends ValueObject<ICustomerInvoiceStatusPro
return new CustomerInvoiceStatus({ value: INVOICE_STATUS.REJECTED }); return new CustomerInvoiceStatus({ value: INVOICE_STATUS.REJECTED });
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }
toPrimitive() { toPrimitive() {
return this.getValue(); return this.getProps();
} }
canTransitionTo(nextStatus: string): boolean { canTransitionTo(nextStatus: string): boolean {
@ -93,6 +93,6 @@ export class CustomerInvoiceStatus extends ValueObject<ICustomerInvoiceStatusPro
} }
toString(): string { toString(): string {
return this.getValue(); return this.getProps();
} }
} }

View File

@ -60,7 +60,7 @@ export class CustomerInvoiceItemMapper
// Validación y creación de precio unitario // Validación y creación de precio unitario
const unitPriceOrError = CustomerInvoiceItemUnitAmount.create({ const unitPriceOrError = CustomerInvoiceItemUnitAmount.create({
amount: source.unit_price_amount, value: source.unit_price_amount,
scale: source.unit_price_scale, scale: source.unit_price_scale,
currency_code: sourceParent.invoice_currency, currency_code: sourceParent.invoice_currency,
}); });
@ -70,7 +70,7 @@ export class CustomerInvoiceItemMapper
// Validación y creación de descuento // Validación y creación de descuento
const discountOrError = CustomerInvoiceItemDiscount.create({ const discountOrError = CustomerInvoiceItemDiscount.create({
amount: source.discount_amount || 0, value: source.discount_amount || 0,
scale: source.discount_scale || 0, scale: source.discount_scale || 0,
}); });
if (discountOrError.isFailure) { if (discountOrError.isFailure) {
@ -132,8 +132,8 @@ export class CustomerInvoiceItemMapper
discount_amount: source.discount.toPrimitive().amount, discount_amount: source.discount.toPrimitive().amount,
discount_scale: source.discount.toPrimitive().scale, discount_scale: source.discount.toPrimitive().scale,
total_amount: source.totalPrice.toPrimitive().amount, total_amount: source.totalAmount.toPrimitive().amount,
total_scale: source.totalPrice.toPrimitive().scale, total_scale: source.totalAmount.toPrimitive().scale,
}; };
return lineData; return lineData;
} }

View File

@ -15,18 +15,18 @@ export const CreateCustomerInvoiceRequestSchema = z.object({
z.object({ z.object({
description: z.string().min(1, "Item description is required"), description: z.string().min(1, "Item description is required"),
quantity: z.object({ quantity: z.object({
amount: z.number().positive("Quantity amount must be positive"), value: z.number().positive("Quantity amount must be positive"),
scale: z.number().int().nonnegative("Quantity scale must be a non-negative integer"), scale: z.number().int().nonnegative("Quantity scale must be a non-negative integer"),
}), }),
unit_price: z.object({ unit_amount: z.object({
amount: z.number().positive("Unit price amount must be positive"), value: z.number().positive("Unit price amount must be positive"),
scale: z.number().int().nonnegative("Unit price scale must be a non-negative integer"), scale: z.number().int().nonnegative("Unit price scale must be a non-negative integer"),
currency_code: z currency_code: z
.string() .string()
.min(3, "Unit price currency code must be at least 3 characters long"), .min(3, "Unit price currency code must be at least 3 characters long"),
}), }),
discount: z.object({ discount_percentage: z.object({
amount: z.number().nonnegative("Discount amount cannot be negative"), value: z.number().nonnegative("Discount amount cannot be negative"),
scale: z.number().int().nonnegative("Discount scale must be a non-negative integer"), scale: z.number().int().nonnegative("Discount scale must be a non-negative integer"),
}), }),
}) })

View File

@ -17,13 +17,21 @@ export const GetCustomerInvoiceByIdResponseSchema = z.object({
language_code: z.string(), language_code: z.string(),
currency_code: z.string(), currency_code: z.string(),
subtotal_amount: AmountSchema,
discount_percentage: PercentageSchema,
discount_amount: AmountSchema,
taxable_amount: AmountSchema,
tax_amount: AmountSchema,
total_amount: AmountSchema,
items: z.array( items: z.array(
z.object({ z.object({
id: z.uuid(),
position: z.string(), position: z.string(),
description: z.string(), description: z.string(),
quantity: QuantitySchema, quantity: QuantitySchema,
unit_price_amount: AmountSchema, unit_amount: AmountSchema,
discount: PercentageSchema, discount_percentage: PercentageSchema,
total_amount: AmountSchema, total_amount: AmountSchema,
}) })
), ),

View File

@ -24,15 +24,15 @@ export class CustomerAddressType extends ValueObject<ICustomerAddressTypeProps>
return Result.ok(new CustomerAddressType({ value })); return Result.ok(new CustomerAddressType({ value }));
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }
toString(): string { toString(): string {
return this.getValue(); return this.getProps();
} }
toPrimitive(): string { toPrimitive(): string {
return this.getValue(); return this.getProps();
} }
} }

View File

@ -34,15 +34,15 @@ export class CustomerNumber extends ValueObject<ICustomerNumberProps> {
return Result.ok(new CustomerNumber({ value })); return Result.ok(new CustomerNumber({ value }));
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }
toString(): string { toString(): string {
return this.getValue(); return this.getProps();
} }
toPrimitive() { toPrimitive() {
return this.getValue(); return this.getProps();
} }
} }

View File

@ -42,15 +42,15 @@ export class CustomerSerie extends ValueObject<ICustomerSerieProps> {
return CustomerSerie.create(value).map((value) => Maybe.some(value)); return CustomerSerie.create(value).map((value) => Maybe.some(value));
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }
toString(): string { toString(): string {
return this.getValue(); return this.getProps();
} }
toPrimitive() { toPrimitive() {
return this.getValue(); return this.getProps();
} }
} }

View File

@ -45,12 +45,12 @@ export class CustomerStatus extends ValueObject<ICustomerStatusProps> {
return this.props.value === CUSTOMER_STATUS.ACTIVE; return this.props.value === CUSTOMER_STATUS.ACTIVE;
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }
toPrimitive() { toPrimitive() {
return this.getValue(); return this.getProps();
} }
canTransitionTo(nextStatus: string): boolean { canTransitionTo(nextStatus: string): boolean {
@ -67,6 +67,6 @@ export class CustomerStatus extends ValueObject<ICustomerStatusProps> {
} }
toString(): string { toString(): string {
return this.getValue(); return this.getProps();
} }
} }

View File

@ -5,7 +5,7 @@ describe("EmailAddress Value Object", () => {
const result = EmailAddress.create("user@example.com"); const result = EmailAddress.create("user@example.com");
expect(result.isSuccess).toBe(true); expect(result.isSuccess).toBe(true);
expect(result.data.getValue()).toBe("user@example.com"); expect(result.data.getProps()).toBe("user@example.com");
}); });
it("should return an error for invalid email format", () => { it("should return an error for invalid email format", () => {
@ -43,6 +43,6 @@ describe("EmailAddress Value Object", () => {
const email = EmailAddress.create("test@example.com"); const email = EmailAddress.create("test@example.com");
expect(email.isSuccess).toBe(true); expect(email.isSuccess).toBe(true);
expect(email.data.getValue()).toBe("test@example.com"); expect(email.data.getProps()).toBe("test@example.com");
}); });
}); });

View File

@ -2,50 +2,50 @@ import { MoneyValue } from "../money-value";
describe("MoneyValue", () => { describe("MoneyValue", () => {
test("should correctly instantiate with amount, scale, and currency", () => { test("should correctly instantiate with amount, scale, and currency", () => {
const money = new MoneyValue({ amount: 10000, scale: 2, currency_code: "EUR" }); const money = new MoneyValue({ value: 10000, scale: 2, currency_code: "EUR" });
expect(money.amount).toBe(100); expect(money.value).toBe(100);
expect(money.currency).toBe("EUR"); expect(money.currency).toBe("EUR");
expect(money.scale).toBe(2); expect(money.scale).toBe(2);
}); });
test("should add two MoneyValue instances with the same currency", () => { test("should add two MoneyValue instances with the same currency", () => {
const money1 = new MoneyValue({ amount: 10000, scale: 2, currency_code: "EUR" }); const money1 = new MoneyValue({ value: 10000, scale: 2, currency_code: "EUR" });
const money2 = new MoneyValue({ amount: 5000, scale: 2, currency_code: "EUR" }); const money2 = new MoneyValue({ value: 5000, scale: 2, currency_code: "EUR" });
const result = money1.add(money2); const result = money1.add(money2);
expect(result.amount).toBe(150); expect(result.value).toBe(150);
}); });
test("should subtract two MoneyValue instances with the same currency", () => { test("should subtract two MoneyValue instances with the same currency", () => {
const money1 = new MoneyValue({ amount: 20000, scale: 2, currency_code: "EUR" }); const money1 = new MoneyValue({ value: 20000, scale: 2, currency_code: "EUR" });
const money2 = new MoneyValue({ amount: 5000, scale: 2, currency_code: "EUR" }); const money2 = new MoneyValue({ value: 5000, scale: 2, currency_code: "EUR" });
const result = money1.subtract(money2); const result = money1.subtract(money2);
expect(result.amount).toBe(150); expect(result.value).toBe(150);
}); });
test("should throw an error when adding different currencies", () => { test("should throw an error when adding different currencies", () => {
const money1 = new MoneyValue({ amount: 10000, scale: 2, currency_code: "EUR" }); const money1 = new MoneyValue({ value: 10000, scale: 2, currency_code: "EUR" });
const money2 = new MoneyValue({ amount: 5000, scale: 2, currency_code: "USD" }); const money2 = new MoneyValue({ value: 5000, scale: 2, currency_code: "USD" });
expect(() => money1.add(money2)).toThrow( expect(() => money1.add(money2)).toThrow(
"You must provide a Dinero instance with the same currency" "You must provide a Dinero instance with the same currency"
); );
}); });
test("should correctly convert scale", () => { test("should correctly convert scale", () => {
const money = new MoneyValue({ amount: 10000, scale: 2, currency_code: "EUR" }); const money = new MoneyValue({ value: 10000, scale: 2, currency_code: "EUR" });
const converted = money.convertScale(4); const converted = money.convertScale(4);
expect(converted.amount).toBe(100); expect(converted.value).toBe(100);
expect(converted.scale).toBe(4); expect(converted.scale).toBe(4);
}); });
test("should format correctly according to locale", () => { test("should format correctly according to locale", () => {
const money = new MoneyValue({ amount: 123456, scale: 2, currency_code: "EUR" }); const money = new MoneyValue({ value: 123456, scale: 2, currency_code: "EUR" });
expect(money.format("en-US")).toBe("€1,234.56"); expect(money.format("en-US")).toBe("€1,234.56");
}); });
test("should compare MoneyValue instances correctly", () => { test("should compare MoneyValue instances correctly", () => {
const money1 = new MoneyValue({ amount: 10000, scale: 2, currency_code: "EUR" }); const money1 = new MoneyValue({ value: 10000, scale: 2, currency_code: "EUR" });
const money2 = new MoneyValue({ amount: 10000, scale: 2, currency_code: "EUR" }); const money2 = new MoneyValue({ value: 10000, scale: 2, currency_code: "EUR" });
const money3 = new MoneyValue({ amount: 5000, scale: 2, currency_code: "EUR" }); const money3 = new MoneyValue({ value: 5000, scale: 2, currency_code: "EUR" });
expect(money1.equalsTo(money2)).toBe(true); expect(money1.equalsTo(money2)).toBe(true);
expect(money1.greaterThan(money3)).toBe(true); expect(money1.greaterThan(money3)).toBe(true);

View File

@ -2,49 +2,49 @@ import { Percentage } from "../percentage"; // Ajusta la ruta según sea necesar
describe("Percentage Value Object", () => { describe("Percentage Value Object", () => {
test("Debe crear un porcentaje válido con escala por defecto", () => { test("Debe crear un porcentaje válido con escala por defecto", () => {
const result = Percentage.create({ amount: 200 }); // 2.00% const result = Percentage.create({ value: 200 }); // 2.00%
expect(result.isSuccess).toBe(true); expect(result.isSuccess).toBe(true);
expect(result.data?.toString()).toBe("2.00%"); expect(result.data?.toString()).toBe("2.00%");
}); });
test("Debe crear un porcentaje válido con escala definida", () => { test("Debe crear un porcentaje válido con escala definida", () => {
const result = Percentage.create({ amount: 2150, scale: 2 }); // 21.50% const result = Percentage.create({ value: 2150, scale: 2 }); // 21.50%
expect(result.isSuccess).toBe(true); expect(result.isSuccess).toBe(true);
expect(result.data?.toString()).toBe("21.50%"); expect(result.data?.toString()).toBe("21.50%");
}); });
test("Debe devolver error si la cantidad supera el 100%", () => { test("Debe devolver error si la cantidad supera el 100%", () => {
const result = Percentage.create({ amount: 48732000, scale: 4 }); const result = Percentage.create({ value: 48732000, scale: 4 });
expect(result.isSuccess).toBe(false); expect(result.isSuccess).toBe(false);
expect(result.error.message).toBe("La escala debe estar entre 0 y 2."); expect(result.error.message).toBe("La escala debe estar entre 0 y 2.");
}); });
test("Debe devolver error si la cantidad es negativa", () => { test("Debe devolver error si la cantidad es negativa", () => {
const result = Percentage.create({ amount: -100, scale: 2 }); const result = Percentage.create({ value: -100, scale: 2 });
expect(result.isSuccess).toBe(false); expect(result.isSuccess).toBe(false);
expect(result.error.message).toContain("La cantidad no puede ser negativa."); expect(result.error.message).toContain("La cantidad no puede ser negativa.");
}); });
test("Debe devolver error si la escala es menor a 0", () => { test("Debe devolver error si la escala es menor a 0", () => {
const result = Percentage.create({ amount: 100, scale: -1 }); const result = Percentage.create({ value: 100, scale: -1 });
expect(result.isSuccess).toBe(false); expect(result.isSuccess).toBe(false);
expect(result.error.message).toContain("Number must be greater than or equal to 0"); expect(result.error.message).toContain("Number must be greater than or equal to 0");
}); });
test("Debe devolver error si la escala es mayor a 10", () => { test("Debe devolver error si la escala es mayor a 10", () => {
const result = Percentage.create({ amount: 100, scale: 11 }); const result = Percentage.create({ value: 100, scale: 11 });
expect(result.isSuccess).toBe(false); expect(result.isSuccess).toBe(false);
expect(result.error.message).toContain("La escala debe estar entre 0 y 2."); expect(result.error.message).toContain("La escala debe estar entre 0 y 2.");
}); });
test("Debe representar correctamente el valor como string", () => { test("Debe representar correctamente el valor como string", () => {
const result = Percentage.create({ amount: 750, scale: 2 }); // 7.50% const result = Percentage.create({ value: 750, scale: 2 }); // 7.50%
expect(result.isSuccess).toBe(true); expect(result.isSuccess).toBe(true);
expect(result.data?.toString()).toBe("7.50%"); expect(result.data?.toString()).toBe("7.50%");
}); });
test("Debe manejar correctamente el caso de 0%", () => { test("Debe manejar correctamente el caso de 0%", () => {
const result = Percentage.create({ amount: 0, scale: 2 }); const result = Percentage.create({ value: 0, scale: 2 });
expect(result.isSuccess).toBe(true); expect(result.isSuccess).toBe(true);
expect(result.data?.toString()).toBe("0.00%"); expect(result.data?.toString()).toBe("0.00%");
}); });

View File

@ -24,7 +24,7 @@ describe("PhoneNumber", () => {
const result = PhoneNumber.create(validPhone); const result = PhoneNumber.create(validPhone);
expect(result.isSuccess).toBe(true); expect(result.isSuccess).toBe(true);
const phoneNumber = result.data; const phoneNumber = result.data;
expect(phoneNumber?.getValue()).toBe(validPhone); expect(phoneNumber?.getProps()).toBe(validPhone);
}); });
test("debe obtener el código de país del número", () => { test("debe obtener el código de país del número", () => {

View File

@ -4,7 +4,7 @@ describe("Slug Value Object", () => {
test("Debe crear un Slug válido", () => { test("Debe crear un Slug válido", () => {
const slugResult = Slug.create("valid-slug-123"); const slugResult = Slug.create("valid-slug-123");
expect(slugResult.isSuccess).toBe(true); expect(slugResult.isSuccess).toBe(true);
expect(slugResult.data.getValue()).toBe("valid-slug-123"); expect(slugResult.data.getProps()).toBe("valid-slug-123");
}); });
test("Debe fallar si el Slug contiene caracteres inválidos", () => { test("Debe fallar si el Slug contiene caracteres inválidos", () => {

View File

@ -4,7 +4,7 @@ describe("TINNumber", () => {
it("debería crear un TINNumber válido", () => { it("debería crear un TINNumber válido", () => {
const result = TINNumber.create("12345"); const result = TINNumber.create("12345");
expect(result.isSuccess).toBe(true); expect(result.isSuccess).toBe(true);
expect(result.data.getValue()).toBe("12345"); expect(result.data.getProps()).toBe("12345");
}); });
it("debería fallar si el valor es demasiado corto", () => { it("debería fallar si el valor es demasiado corto", () => {

View File

@ -28,11 +28,11 @@ export class City extends ValueObject<CityProps> {
return Result.ok(new City({ value })); return Result.ok(new City({ value }));
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }
toPrimitive() { toPrimitive() {
return this.getValue(); return this.getProps();
} }
} }

View File

@ -28,11 +28,11 @@ export class Country extends ValueObject<CountryProps> {
return Result.ok(new Country({ value })); return Result.ok(new Country({ value }));
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }
toPrimitive() { toPrimitive() {
return this.getValue(); return this.getProps();
} }
} }

View File

@ -38,7 +38,7 @@ export class CurrencyCode extends ValueObject<CurrencyCodeProps> {
return Result.ok(new CurrencyCode({ value: valueIsValid.data })); return Result.ok(new CurrencyCode({ value: valueIsValid.data }));
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }

View File

@ -38,11 +38,11 @@ export class EmailAddress extends ValueObject<EmailAddressProps> {
return this.getDomain().split(".")[0]; return this.getDomain().split(".")[0];
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }
toPrimitive() { toPrimitive() {
return this.getValue(); return this.getProps();
} }
} }

View File

@ -38,7 +38,7 @@ export class LanguageCode extends ValueObject<LanguageCodeProps> {
return Result.ok(new LanguageCode({ value: valueIsValid.data })); return Result.ok(new LanguageCode({ value: valueIsValid.data }));
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }

View File

@ -19,17 +19,17 @@ export type RoundingMode =
| "DOWN"; | "DOWN";
export interface MoneyValueProps { export interface MoneyValueProps {
amount: number; value: number;
scale?: number; scale?: number;
currency_code?: string; currency_code?: string;
} }
export interface IMoneyValue { export interface IMoneyValue {
amount: number; value: number;
scale: number; scale: number;
currency: Dinero.Currency; currency: Dinero.Currency;
getValue(): MoneyValueProps; getProps(): MoneyValueProps;
convertScale(newScale: number): MoneyValue; convertScale(newScale: number): MoneyValue;
add(addend: MoneyValue): MoneyValue; add(addend: MoneyValue): MoneyValue;
subtract(subtrahend: MoneyValue): MoneyValue; subtract(subtrahend: MoneyValue): MoneyValue;
@ -53,9 +53,9 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
static DEFAULT_SCALE = DEFAULT_SCALE; static DEFAULT_SCALE = DEFAULT_SCALE;
static DEFAULT_CURRENCY_CODE = DEFAULT_CURRENCY_CODE; static DEFAULT_CURRENCY_CODE = DEFAULT_CURRENCY_CODE;
static create({ amount, currency_code, scale }: MoneyValueProps) { static create({ value, currency_code, scale }: MoneyValueProps) {
const props = { const props = {
amount: Number(amount), value: Number(value),
scale: scale ?? MoneyValue.DEFAULT_SCALE, scale: scale ?? MoneyValue.DEFAULT_SCALE,
currency_code: currency_code ?? MoneyValue.DEFAULT_CURRENCY_CODE, currency_code: currency_code ?? MoneyValue.DEFAULT_CURRENCY_CODE,
}; };
@ -64,7 +64,7 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
constructor(props: MoneyValueProps) { constructor(props: MoneyValueProps) {
super(props); super(props);
const { amount, scale, currency_code } = props; const { value: amount, scale, currency_code } = props;
this.dinero = Object.freeze( this.dinero = Object.freeze(
DineroFactory({ DineroFactory({
amount, amount,
@ -74,7 +74,7 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
); // 🔒 Garantiza inmutabilidad ); // 🔒 Garantiza inmutabilidad
} }
get amount(): number { get value(): number {
return this.dinero.getAmount() / 10 ** this.dinero.getPrecision(); // ** => Math.pow return this.dinero.getAmount() / 10 ** this.dinero.getPrecision(); // ** => Math.pow
} }
@ -86,27 +86,22 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
return this.dinero.getPrecision(); return this.dinero.getPrecision();
} }
getValue(): MoneyValueProps { getProps(): MoneyValueProps {
return this.props; return this.props;
} }
/** Serializa el VO a una cadena del tipo "EUR:123400:2" */
toPersistence(): string {
return `${this.currency}:${this.dinero.getAmount()}:${this.scale}`;
}
/** Reconstruye el VO desde la cadena persistida */ /** Reconstruye el VO desde la cadena persistida */
static fromPersistence(value: string): MoneyValue { static fromPersistence(value: string): MoneyValue {
const [currencyCode, amountStr, scaleStr] = value.split(":"); const [currencyCode, amountStr, scaleStr] = value.split(":");
const amount = Number.parseInt(amountStr, 10); const amount = Number.parseInt(amountStr, 10);
const scale = Number.parseInt(scaleStr, 10); const scale = Number.parseInt(scaleStr, 10);
const currency = currencyCode; const currency = currencyCode;
return new MoneyValue({ amount, scale, currency_code: currency }); return new MoneyValue({ value: amount, scale, currency_code: currency });
} }
toPrimitive() { toPrimitive() {
return { return {
amount: this.amount, value: this.value,
scale: this.scale, scale: this.scale,
currency_code: this.currency, currency_code: this.currency,
}; };
@ -115,7 +110,7 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
convertScale(newScale: number, roundingMode: RoundingMode = "HALF_UP"): MoneyValue { convertScale(newScale: number, roundingMode: RoundingMode = "HALF_UP"): MoneyValue {
const _newDinero = this.dinero.convertPrecision(newScale, roundingMode); const _newDinero = this.dinero.convertPrecision(newScale, roundingMode);
return new MoneyValue({ return new MoneyValue({
amount: _newDinero.getAmount(), value: _newDinero.getAmount(),
scale: _newDinero.getPrecision(), scale: _newDinero.getPrecision(),
currency_code: _newDinero.getCurrency(), currency_code: _newDinero.getCurrency(),
}); });
@ -123,7 +118,7 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
add(addend: MoneyValue): MoneyValue { add(addend: MoneyValue): MoneyValue {
return new MoneyValue({ return new MoneyValue({
amount: 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.currency,
}); });
@ -131,7 +126,7 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
subtract(subtrahend: MoneyValue): MoneyValue { subtract(subtrahend: MoneyValue): MoneyValue {
return new MoneyValue({ return new MoneyValue({
amount: 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.currency,
}); });
@ -142,7 +137,7 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
const _newDinero = this.dinero.multiply(_multiplier, roundingMode); const _newDinero = this.dinero.multiply(_multiplier, roundingMode);
return new MoneyValue({ return new MoneyValue({
amount: _newDinero.getAmount(), value: _newDinero.getAmount(),
scale: _newDinero.getPrecision(), scale: _newDinero.getPrecision(),
currency_code: _newDinero.getCurrency(), currency_code: _newDinero.getCurrency(),
}); });
@ -153,7 +148,7 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
const _newDinero = this.dinero.divide(_divisor, roundingMode); const _newDinero = this.dinero.divide(_divisor, roundingMode);
return new MoneyValue({ return new MoneyValue({
amount: _newDinero.getAmount(), value: _newDinero.getAmount(),
scale: _newDinero.getPrecision(), scale: _newDinero.getPrecision(),
currency_code: _newDinero.getCurrency(), currency_code: _newDinero.getCurrency(),
}); });
@ -164,7 +159,7 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
const _newDinero = this.dinero.percentage(_percentage, roundingMode); const _newDinero = this.dinero.percentage(_percentage, roundingMode);
return new MoneyValue({ return new MoneyValue({
amount: _newDinero.getAmount(), value: _newDinero.getAmount(),
scale: _newDinero.getPrecision(), scale: _newDinero.getPrecision(),
currency_code: _newDinero.getCurrency(), currency_code: _newDinero.getCurrency(),
}); });
@ -187,11 +182,11 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
} }
isPositive(): boolean { isPositive(): boolean {
return this.amount > 0; return this.value > 0;
} }
isNegative(): boolean { isNegative(): boolean {
return this.amount < 0; return this.value < 0;
} }
hasSameCurrency(comparator: MoneyValue): boolean { hasSameCurrency(comparator: MoneyValue): boolean {
@ -209,7 +204,7 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
* @returns Importe formateado * @returns Importe formateado
*/ */
format(locale: string): string { format(locale: string): string {
const amount = this.amount; const value = this.value;
const currency = this.currency; const currency = this.currency;
const scale = this.scale; const scale = this.scale;
@ -219,6 +214,6 @@ export class MoneyValue extends ValueObject<MoneyValueProps> implements IMoneyVa
minimumFractionDigits: scale, minimumFractionDigits: scale,
maximumFractionDigits: scale, maximumFractionDigits: scale,
useGrouping: true, useGrouping: true,
}).format(amount); }).format(value);
} }
} }

View File

@ -44,11 +44,11 @@ export class Name extends ValueObject<NameProps> {
return Name.generateAcronym(this.toString()); return Name.generateAcronym(this.toString());
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }
toPrimitive() { toPrimitive() {
return this.getValue(); return this.getProps();
} }
} }

View File

@ -11,7 +11,7 @@ const DEFAULT_MIN_SCALE = 0;
const DEFAULT_MAX_SCALE = 2; const DEFAULT_MAX_SCALE = 2;
export interface PercentageProps { export interface PercentageProps {
amount: number; value: number;
scale: number; scale: number;
} }
@ -25,7 +25,7 @@ export class Percentage extends ValueObject<PercentageProps> {
protected static validate(values: PercentageProps) { protected static validate(values: PercentageProps) {
const schema = z.object({ const schema = z.object({
amount: z.number().int().min(Percentage.MIN_VALUE, "La cantidad no puede ser negativa."), value: z.number().int().min(Percentage.MIN_VALUE, "La cantidad no puede ser negativa."),
scale: z scale: z
.number() .number()
.int() .int()
@ -39,43 +39,43 @@ export class Percentage extends ValueObject<PercentageProps> {
return schema.safeParse(values); return schema.safeParse(values);
} }
static create(props: { amount: number; scale?: number }): Result<Percentage> { static create(props: { value: number; scale?: number }): Result<Percentage> {
const { amount, scale = Percentage.DEFAULT_SCALE } = props; const { value, scale = Percentage.DEFAULT_SCALE } = props;
const validationResult = Percentage.validate({ amount, scale }); const validationResult = Percentage.validate({ value, scale });
if (!validationResult.success) { if (!validationResult.success) {
return Result.fail(new Error(validationResult.error.issues.map((e) => e.message).join(", "))); return Result.fail(new Error(validationResult.error.issues.map((e) => e.message).join(", ")));
} }
// Cálculo del valor real del porcentaje // Cálculo del valor real del porcentaje
const realValue = amount / 10 ** scale; // ** => Math.pow const realValue = value / 10 ** scale; // ** => Math.pow
// Validación de rango // Validación de rango
if (realValue > Percentage.MAX_VALUE) { if (realValue > Percentage.MAX_VALUE) {
return Result.fail(new Error("El porcentaje no puede ser mayor a 100%.")); return Result.fail(new Error("El porcentaje no puede ser mayor a 100%."));
} }
return Result.ok(new Percentage({ amount, scale })); return Result.ok(new Percentage({ value, scale }));
} }
get amount(): number { get value(): number {
return this.props.amount; return this.props.value;
} }
get scale(): number { get scale(): number {
return this.props.scale; return this.props.scale;
} }
getValue(): PercentageProps { getProps(): PercentageProps {
return this.props; return this.props;
} }
toPrimitive() { toPrimitive() {
return this.getValue(); return this.getProps();
} }
toNumber(): number { toNumber(): number {
return this.amount / 10 ** this.scale; // ** => Math.pow return this.value / 10 ** this.scale; // ** => Math.pow
} }
toString(): string { toString(): string {

View File

@ -51,12 +51,12 @@ export class PhoneNumber extends ValueObject<PhoneNumberProps> {
return Result.ok(new PhoneNumber({ value: valueIsValid.data })); return Result.ok(new PhoneNumber({ value: valueIsValid.data }));
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }
toPrimitive(): string { toPrimitive(): string {
return this.getValue(); return this.getProps();
} }
getCountryCode(): string | undefined { getCountryCode(): string | undefined {

View File

@ -73,12 +73,12 @@ export class PostalAddress extends ValueObject<PostalAddressProps> {
return this.props.country; return this.props.country;
} }
getValue(): PostalAddressProps { getProps(): PostalAddressProps {
return this.props; return this.props;
} }
toPrimitive() { toPrimitive() {
return this.getValue(); return this.getProps();
} }
toFormat(): string { toFormat(): string {

View File

@ -36,7 +36,7 @@ export class PostalCode extends ValueObject<PostalCodeProps> {
return Result.ok(new PostalCode({ value: valueIsValid.data })); return Result.ok(new PostalCode({ value: valueIsValid.data }));
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }

View File

@ -28,11 +28,11 @@ export class Province extends ValueObject<ProvinceProps> {
return Result.ok(new Province({ value })); return Result.ok(new Province({ value }));
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }
toPrimitive() { toPrimitive() {
return this.getValue(); return this.getProps();
} }
} }

View File

@ -7,14 +7,14 @@ const DEFAULT_MIN_SCALE = 0;
const DEFAULT_MAX_SCALE = 2; const DEFAULT_MAX_SCALE = 2;
export interface QuantityProps { export interface QuantityProps {
amount: number; value: number;
scale: number; scale: number;
} }
export class Quantity extends ValueObject<QuantityProps> { export class Quantity extends ValueObject<QuantityProps> {
protected static validate(values: QuantityProps) { protected static validate(values: QuantityProps) {
const schema = z.object({ const schema = z.object({
amount: z.number().int(), value: z.number().int(),
scale: z.number().int().min(Quantity.MIN_SCALE).max(Quantity.MAX_SCALE), scale: z.number().int().min(Quantity.MIN_SCALE).max(Quantity.MAX_SCALE),
}); });
@ -25,9 +25,9 @@ export class Quantity extends ValueObject<QuantityProps> {
static MIN_SCALE = DEFAULT_MIN_SCALE; static MIN_SCALE = DEFAULT_MIN_SCALE;
static MAX_SCALE = DEFAULT_MAX_SCALE; static MAX_SCALE = DEFAULT_MAX_SCALE;
static create({ amount, scale }: QuantityProps) { static create({ value, scale }: QuantityProps) {
const props = { const props = {
amount: Number(amount), value: Number(value),
scale: scale ?? Quantity.DEFAULT_SCALE, scale: scale ?? Quantity.DEFAULT_SCALE,
}; };
const checkProps = Quantity.validate(props); const checkProps = Quantity.validate(props);
@ -38,24 +38,24 @@ export class Quantity extends ValueObject<QuantityProps> {
return Result.ok(new Quantity({ ...(checkProps.data as QuantityProps) })); return Result.ok(new Quantity({ ...(checkProps.data as QuantityProps) }));
} }
get amount(): number { get value(): number {
return this.props.amount; return this.props.value;
} }
get scale(): number { get scale(): number {
return this.props.scale; return this.props.scale;
} }
getValue(): QuantityProps { getProps(): QuantityProps {
return this.props; return this.props;
} }
toPrimitive() { toPrimitive() {
return this.getValue(); return this.getProps();
} }
toNumber(): number { toNumber(): number {
return this.amount / 10 ** this.scale; // ** => Math.pow return this.value / 10 ** this.scale; // ** => Math.pow
} }
toString(): string { toString(): string {
@ -63,21 +63,21 @@ export class Quantity extends ValueObject<QuantityProps> {
} }
isZero(): boolean { isZero(): boolean {
return this.amount === 0; return this.value === 0;
} }
isPositive(): boolean { isPositive(): boolean {
return this.amount > 0; return this.value > 0;
} }
isNegative(): boolean { isNegative(): boolean {
return this.amount < 0; return this.value < 0;
} }
increment(anotherQuantity?: Quantity): Result<Quantity, Error> { increment(anotherQuantity?: Quantity): Result<Quantity, Error> {
if (!anotherQuantity) { if (!anotherQuantity) {
return Quantity.create({ return Quantity.create({
amount: Number(this.amount) + 1, value: Number(this.value) + 1,
scale: this.scale, scale: this.scale,
}); });
} }
@ -87,7 +87,7 @@ export class Quantity extends ValueObject<QuantityProps> {
} }
return Quantity.create({ return Quantity.create({
amount: Number(this.amount) + Number(anotherQuantity.amount), value: Number(this.value) + Number(anotherQuantity.value),
scale: this.scale, scale: this.scale,
}); });
} }
@ -95,7 +95,7 @@ export class Quantity extends ValueObject<QuantityProps> {
decrement(anotherQuantity?: Quantity): Result<Quantity, Error> { decrement(anotherQuantity?: Quantity): Result<Quantity, Error> {
if (!anotherQuantity) { if (!anotherQuantity) {
return Quantity.create({ return Quantity.create({
amount: Number(this.amount) - 1, value: Number(this.value) - 1,
scale: this.scale, scale: this.scale,
}); });
} }
@ -105,7 +105,7 @@ export class Quantity extends ValueObject<QuantityProps> {
} }
return Quantity.create({ return Quantity.create({
amount: Number(this.amount) - Number(anotherQuantity.amount), value: Number(this.value) - Number(anotherQuantity.value),
scale: this.scale, scale: this.scale,
}); });
} }
@ -120,11 +120,11 @@ export class Quantity extends ValueObject<QuantityProps> {
} }
const oldFactor = 10 ** this.scale; // ** => Math.pow const oldFactor = 10 ** this.scale; // ** => Math.pow
const value = Number(this.amount) / oldFactor; const value = Number(this.value) / oldFactor;
const newFactor = 10 ** newScale; // ** => Math.pow const newFactor = 10 ** newScale; // ** => Math.pow
const newValue = Math.round(value * newFactor); const newValue = Math.round(value * newFactor);
return Quantity.create({ amount: newValue, scale: newScale }); return Quantity.create({ value: newValue, scale: newScale });
} }
} }

View File

@ -32,11 +32,11 @@ export class Slug extends ValueObject<SlugProps> {
return Result.ok(new Slug({ value: valueIsValid.data! })); return Result.ok(new Slug({ value: valueIsValid.data! }));
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }
toPrimitive(): string { toPrimitive(): string {
return this.getValue(); return this.getProps();
} }
} }

View File

@ -28,11 +28,11 @@ export class Street extends ValueObject<StreetProps> {
return Result.ok(new Street({ value })); return Result.ok(new Street({ value }));
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }
toPrimitive() { toPrimitive() {
return this.getValue(); return this.getProps();
} }
} }

View File

@ -36,11 +36,11 @@ export class TaxCode extends ValueObject<TaxCodeProps> {
return Result.ok(new TaxCode({ value: valueIsValid.data! })); return Result.ok(new TaxCode({ value: valueIsValid.data! }));
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }
toPrimitive(): string { toPrimitive(): string {
return this.getValue(); return this.getProps();
} }
} }

View File

@ -29,11 +29,11 @@ export class TextValue extends ValueObject<TextValueProps> {
return Result.ok(new TextValue({ value })); return Result.ok(new TextValue({ value }));
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }
toPrimitive(): string { toPrimitive(): string {
return this.getValue(); return this.getProps();
} }
} }

View File

@ -33,7 +33,7 @@ export class TINNumber extends ValueObject<TINNumberProps> {
return Result.ok(new TINNumber({ value: valueIsValid.data })); return Result.ok(new TINNumber({ value: valueIsValid.data }));
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }

View File

@ -32,15 +32,15 @@ export class UniqueID extends ValueObject<string> {
return Result.ok(new UniqueID(generateUUIDv4())); return Result.ok(new UniqueID(generateUUIDv4()));
} }
getValue(): string { getProps(): string {
return this.props; return this.props;
} }
toString(): string { toString(): string {
return this.getValue(); return this.getProps();
} }
toPrimitive() { toPrimitive() {
return this.getValue(); return this.getProps();
} }
} }

View File

@ -22,11 +22,11 @@ export class URLAddress extends ValueObject<URLAddressProps> {
return schema.safeParse(value); return schema.safeParse(value);
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }
toPrimitive() { toPrimitive() {
return this.getValue(); return this.getProps();
} }
} }

View File

@ -40,7 +40,7 @@ export class UtcDate extends ValueObject<UtcDateProps> {
return Result.ok(new UtcDate({ value: isoDateString })); return Result.ok(new UtcDate({ value: isoDateString }));
} }
getValue(): string { getProps(): string {
return this.props.value; return this.props.value;
} }

View File

@ -7,7 +7,7 @@ export abstract class ValueObject<T> {
this.props = Object.freeze(props); // 🔒 Garantiza inmutabilidad this.props = Object.freeze(props); // 🔒 Garantiza inmutabilidad
} }
abstract getValue(): any; abstract getProps(): any;
abstract toPrimitive(): any; abstract toPrimitive(): any;