Uecko_ERP/modules/customer-invoices/src/api/infrastructure/mappers/domain/customer-invoice-item.mapper.ts

233 lines
6.6 KiB
TypeScript
Raw Normal View History

2025-09-16 11:29:45 +00:00
import { ISequelizeDomainMapper, MapperParamsType, SequelizeDomainMapper } from "@erp/core/api";
2025-09-04 17:57:04 +00:00
import {
extractOrPushError,
2025-09-16 11:29:45 +00:00
maybeFromNullableVO,
2025-09-26 15:00:11 +00:00
toNullable,
2025-11-04 11:24:14 +00:00
UniqueID,
ValidationErrorCollection,
ValidationErrorDetail,
2025-09-16 11:29:45 +00:00
} from "@repo/rdx-ddd";
2025-05-26 10:38:45 +00:00
import { Result } from "@repo/rdx-utils";
import {
2025-09-26 15:00:11 +00:00
CustomerInvoice,
2025-06-11 15:13:44 +00:00
CustomerInvoiceItem,
CustomerInvoiceItemDescription,
2025-09-26 15:00:11 +00:00
CustomerInvoiceItemProps,
2025-09-09 18:13:54 +00:00
CustomerInvoiceProps,
2025-09-05 11:23:45 +00:00
ItemAmount,
ItemDiscount,
ItemQuantity,
2025-09-10 16:06:29 +00:00
ItemTaxes,
2025-09-11 12:05:50 +00:00
} from "../../../domain";
import { CustomerInvoiceItemCreationAttributes, CustomerInvoiceItemModel } from "../../sequelize";
2025-09-13 18:45:55 +00:00
import { ItemTaxesDomainMapper } from "./item-taxes.mapper";
2025-03-18 08:05:00 +00:00
2025-09-13 18:45:55 +00:00
export interface ICustomerInvoiceItemDomainMapper
2025-09-11 12:05:50 +00:00
extends ISequelizeDomainMapper<
2025-06-12 06:55:17 +00:00
CustomerInvoiceItemModel,
CustomerInvoiceItemCreationAttributes,
CustomerInvoiceItem
> {}
2025-03-18 08:05:00 +00:00
2025-09-13 18:45:55 +00:00
export class CustomerInvoiceItemDomainMapper
2025-09-11 12:05:50 +00:00
extends SequelizeDomainMapper<
2025-06-12 06:55:17 +00:00
CustomerInvoiceItemModel,
CustomerInvoiceItemCreationAttributes,
CustomerInvoiceItem
>
2025-09-13 18:45:55 +00:00
implements ICustomerInvoiceItemDomainMapper
2025-03-18 08:05:00 +00:00
{
2025-09-13 18:45:55 +00:00
private _taxesMapper: ItemTaxesDomainMapper;
2025-09-10 16:06:29 +00:00
constructor(params: MapperParamsType) {
super();
2025-09-13 18:45:55 +00:00
this._taxesMapper = new ItemTaxesDomainMapper(params);
2025-09-10 16:06:29 +00:00
}
2025-09-26 15:00:11 +00:00
private mapAttributesToDomain(
source: CustomerInvoiceItemModel,
params?: MapperParamsType
): Partial<CustomerInvoiceItemProps> & { itemId?: UniqueID } {
2025-09-09 18:13:54 +00:00
const { errors, index, attributes } = params as {
index: number;
2025-09-04 17:57:04 +00:00
errors: ValidationErrorDetail[];
2025-09-09 18:13:54 +00:00
attributes: Partial<CustomerInvoiceProps>;
2025-09-04 17:57:04 +00:00
};
2025-09-09 18:13:54 +00:00
const itemId = extractOrPushError(
UniqueID.create(source.item_id),
`items[${index}].item_id`,
2025-09-05 11:23:45 +00:00
errors
);
2025-09-04 17:57:04 +00:00
const description = extractOrPushError(
2025-10-04 18:35:27 +00:00
maybeFromNullableVO(source.description, (v) => CustomerInvoiceItemDescription.create(v)),
2025-09-09 18:13:54 +00:00
`items[${index}].description`,
2025-09-04 17:57:04 +00:00
errors
);
const quantity = extractOrPushError(
2025-10-04 18:35:27 +00:00
maybeFromNullableVO(source.quantity_value, (v) => ItemQuantity.create({ value: v })),
2025-09-26 15:00:11 +00:00
`items[${index}].quantity`,
2025-09-04 17:57:04 +00:00
errors
);
const unitAmount = extractOrPushError(
2025-09-05 11:23:45 +00:00
maybeFromNullableVO(source.unit_amount_value, (value) =>
2025-11-04 11:24:14 +00:00
ItemAmount.create({ value, currency_code: attributes.currencyCode?.code })
2025-09-05 11:23:45 +00:00
),
2025-09-09 18:13:54 +00:00
`items[${index}].unit_amount`,
2025-09-04 17:57:04 +00:00
errors
);
2025-09-26 15:00:11 +00:00
const discountPercentage = extractOrPushError(
2025-10-04 18:35:27 +00:00
maybeFromNullableVO(source.discount_percentage_value, (v) =>
ItemDiscount.create({ value: v })
2025-09-26 15:00:11 +00:00
),
`items[${index}].discount_percentage`,
errors
);
2025-09-09 18:13:54 +00:00
return {
itemId,
2025-09-26 15:00:11 +00:00
2025-09-09 18:13:54 +00:00
languageCode: attributes.languageCode,
currencyCode: attributes.currencyCode,
description,
quantity,
unitAmount,
2025-09-26 15:00:11 +00:00
discountPercentage,
2025-09-09 18:13:54 +00:00
};
}
public mapToDomain(
source: CustomerInvoiceItemModel,
params?: MapperParamsType
): Result<CustomerInvoiceItem, Error> {
2025-10-04 18:35:27 +00:00
const { errors, index } = params as {
2025-09-09 18:13:54 +00:00
index: number;
errors: ValidationErrorDetail[];
attributes: Partial<CustomerInvoiceProps>;
};
2025-09-10 16:06:29 +00:00
// 1) Valores escalares (atributos generales)
const attributes = this.mapAttributesToDomain(source, params);
2025-10-04 18:35:27 +00:00
// 2) Taxes (colección a nivel de item/línea)
2025-09-11 12:05:50 +00:00
const taxesResults = this._taxesMapper.mapToDomainCollection(
source.taxes,
source.taxes.length,
{
attributes,
...params,
}
);
2025-09-10 16:06:29 +00:00
if (taxesResults.isFailure) {
errors.push({
2025-09-26 15:00:11 +00:00
path: "taxes",
2025-09-10 16:06:29 +00:00
message: taxesResults.error.message,
});
}
2025-11-04 11:24:14 +00:00
// Si hubo errores de mapeo, devolvemos colección de validación
if (errors.length > 0) {
return Result.fail(
new ValidationErrorCollection("Customer invoice item mapping failed [mapToDomain]", errors)
);
}
2025-09-26 18:09:14 +00:00
const taxes = ItemTaxes.create(taxesResults.data.getAll());
2025-09-10 16:06:29 +00:00
2025-10-04 18:35:27 +00:00
// 3) Construcción del elemento de dominio
2025-09-09 18:13:54 +00:00
const createResult = CustomerInvoiceItem.create(
2025-04-22 08:11:50 +00:00
{
2025-09-09 18:13:54 +00:00
languageCode: attributes.languageCode!,
currencyCode: attributes.currencyCode!,
description: attributes.description!,
quantity: attributes.quantity!,
unitAmount: attributes.unitAmount!,
2025-09-26 15:00:11 +00:00
discountPercentage: attributes.discountPercentage!,
2025-09-10 16:06:29 +00:00
taxes,
2025-09-05 11:23:45 +00:00
},
2025-09-09 18:13:54 +00:00
attributes.itemId
2025-04-22 08:11:50 +00:00
);
2025-09-09 15:48:12 +00:00
2025-09-09 18:13:54 +00:00
if (createResult.isFailure) {
return Result.fail(
2025-10-18 19:57:52 +00:00
new ValidationErrorCollection("Invoice item entity creation failed", [
2025-09-09 18:13:54 +00:00
{ path: `items[${index}]`, message: createResult.error.message },
])
);
2025-09-09 15:48:12 +00:00
}
2025-09-09 18:13:54 +00:00
return createResult;
2025-03-18 08:05:00 +00:00
}
2025-04-22 08:11:50 +00:00
public mapToPersistence(
2025-06-11 15:13:44 +00:00
source: CustomerInvoiceItem,
2025-04-22 08:11:50 +00:00
params?: MapperParamsType
2025-10-04 18:35:27 +00:00
): Result<CustomerInvoiceItemCreationAttributes, Error> {
2025-09-26 15:00:11 +00:00
const { errors, index, parent } = params as {
2025-04-22 08:11:50 +00:00
index: number;
2025-09-26 15:00:11 +00:00
parent: CustomerInvoice;
errors: ValidationErrorDetail[];
2025-04-22 08:11:50 +00:00
};
2025-03-18 08:05:00 +00:00
2025-11-07 17:42:18 +00:00
const taxesResults = this._taxesMapper.mapToPersistenceArray(source.taxes, {
...params,
parent: source,
});
2025-09-26 15:00:11 +00:00
if (taxesResults.isFailure) {
errors.push({
path: "taxes",
message: taxesResults.error.message,
});
}
const allAmounts = source.getAllAmounts();
return Result.ok({
2025-09-04 17:57:04 +00:00
item_id: source.id.toPrimitive(),
2025-09-26 15:00:11 +00:00
invoice_id: parent.id.toPrimitive(),
2025-03-18 08:05:00 +00:00
position: index,
2025-09-26 15:00:11 +00:00
description: toNullable(source.description, (v) => v.toPrimitive()),
2025-09-04 17:57:04 +00:00
2025-09-26 15:00:11 +00:00
quantity_value: toNullable(source.quantity, (v) => v.toPrimitive().value),
2025-10-04 18:35:27 +00:00
quantity_scale:
toNullable(source.quantity, (v) => v.toPrimitive().scale) ?? ItemQuantity.DEFAULT_SCALE,
2025-04-22 08:11:50 +00:00
2025-09-26 15:00:11 +00:00
unit_amount_value: toNullable(source.unitAmount, (v) => v.toPrimitive().value),
2025-10-04 18:35:27 +00:00
unit_amount_scale:
toNullable(source.unitAmount, (v) => v.toPrimitive().scale) ?? ItemAmount.DEFAULT_SCALE,
2025-04-22 08:11:50 +00:00
2025-09-26 15:00:11 +00:00
subtotal_amount_value: allAmounts.subtotalAmount.value,
subtotal_amount_scale: allAmounts.subtotalAmount.scale,
2025-04-22 08:11:50 +00:00
2025-09-05 11:23:45 +00:00
discount_percentage_value: toNullable(
source.discountPercentage,
2025-09-26 15:00:11 +00:00
(v) => v.toPrimitive().value
2025-09-05 11:23:45 +00:00
),
2025-10-04 18:35:27 +00:00
discount_percentage_scale:
toNullable(source.discountPercentage, (v) => v.toPrimitive().scale) ??
ItemDiscount.DEFAULT_SCALE,
2025-09-05 11:23:45 +00:00
2025-09-26 15:00:11 +00:00
discount_amount_value: allAmounts.discountAmount.value,
discount_amount_scale: allAmounts.discountAmount.scale,
2025-09-05 11:23:45 +00:00
2025-09-26 15:00:11 +00:00
taxable_amount_value: allAmounts.taxableAmount.value,
2025-11-07 17:42:18 +00:00
taxable_amount_scale: allAmounts.taxableAmount.scale,
2025-04-22 08:11:50 +00:00
2025-09-26 15:00:11 +00:00
taxes_amount_value: allAmounts.taxesAmount.value,
taxes_amount_scale: allAmounts.taxesAmount.scale,
2025-04-22 08:11:50 +00:00
2025-09-26 15:00:11 +00:00
total_amount_value: allAmounts.totalAmount.value,
total_amount_scale: allAmounts.totalAmount.scale,
2025-09-26 18:09:14 +00:00
taxes: taxesResults.data,
2025-09-26 15:00:11 +00:00
});
2025-03-18 08:05:00 +00:00
}
}