Uecko_ERP/modules/customers/src/api/application/mappers/update-customer-input.mapper.ts
2026-04-24 20:53:05 +02:00

286 lines
8.6 KiB
TypeScript

import {
City,
Country,
CurrencyCode,
DomainError,
EmailAddress,
LanguageCode,
Name,
PhoneNumber,
type PostalAddressPatchProps,
PostalCode,
Province,
Street,
TINNumber,
TextValue,
URLAddress,
type UniqueID,
ValidationErrorCollection,
type ValidationErrorDetail,
extractOrPushError,
maybeFromNullableResult,
} from "@repo/rdx-ddd";
import { Result, toPatchField } from "@repo/rdx-utils";
import type {
UpdateCustomerAddressPatchRequestDTO,
UpdateCustomerByIdRequestDTO,
UpdateCustomerContactPatchRequestDTO,
} from "../../../common";
import type { CustomerPatchProps } from "../../domain";
/**
* UpdateCustomerInputMapper
* Convierte el DTO a las props validadas (CustomerProps).
* No construye directamente el agregado.
* Tri-estado:
* - campo omitido → no se cambia
* - campo con valor null/"" → se quita el valor -> set(None()),
* - campo con valor no-vacío → se pone el nuevo valor -> set(Some(VO)).
*
* @param dto - DTO con los datos a cambiar en el cliente
* @returns Cambios en las propiedades del cliente
*
*/
export interface IUpdateCustomerInputMapper {
map(
dto: UpdateCustomerByIdRequestDTO,
params: { companyId: UniqueID }
): Result<CustomerPatchProps, Error>;
}
export class UpdateCustomerInputMapper implements IUpdateCustomerInputMapper {
public map(
dto: UpdateCustomerByIdRequestDTO,
params: { companyId: UniqueID }
): Result<CustomerPatchProps, Error> {
try {
const errors: ValidationErrorDetail[] = [];
const customerPatchProps: CustomerPatchProps = {};
toPatchField(dto.reference).ifSetOrNull((reference) => {
customerPatchProps.reference = extractOrPushError(
maybeFromNullableResult(reference, (value) => Name.create(value)),
"reference",
errors
);
});
toPatchField(dto.is_company).ifSet((isCompany) => {
customerPatchProps.isCompany = isCompany;
});
toPatchField(dto.name).ifSet((name) => {
customerPatchProps.name = extractOrPushError(Name.create(name), "name", errors);
});
toPatchField(dto.trade_name).ifSetOrNull((tradeName) => {
customerPatchProps.tradeName = extractOrPushError(
maybeFromNullableResult(tradeName, (value) => Name.create(value)),
"trade_name",
errors
);
});
toPatchField(dto.tin).ifSetOrNull((tin) => {
customerPatchProps.tin = extractOrPushError(
maybeFromNullableResult(tin, (value) => TINNumber.create(value)),
"tin",
errors
);
});
toPatchField(dto.legal_record).ifSetOrNull((legalRecord) => {
customerPatchProps.legalRecord = extractOrPushError(
maybeFromNullableResult(legalRecord, (value) => TextValue.create(value)),
"legal_record",
errors
);
});
toPatchField(dto.language_code).ifSet((languageCode) => {
customerPatchProps.languageCode = extractOrPushError(
LanguageCode.create(languageCode),
"language_code",
errors
);
});
toPatchField(dto.currency_code).ifSet((currencyCode) => {
customerPatchProps.currencyCode = extractOrPushError(
CurrencyCode.create(currencyCode),
"currency_code",
errors
);
});
/**
* Se mantiene la compatibilidad con el contrato actual.
* Cuando defaultTaxes tenga un contrato final estable, aquí conviene
* mapearlo a CustomerTaxes/Collection<TaxCode> con su schema semántico real.
*/
toPatchField(dto.default_taxes).ifSet((_defaultTaxes) => {
errors.push({
path: "default_taxes",
message: "default_taxes mapping is not implemented yet",
});
});
const addressPatchProps = this.mapPostalAddress(dto.address, errors);
if (addressPatchProps) {
customerPatchProps.address = addressPatchProps;
}
this.mapContact(dto.contact, customerPatchProps, errors);
if (errors.length > 0) {
return Result.fail(
new ValidationErrorCollection("Customer props mapping failed (update)", errors)
);
}
console.log("Mapped CustomerPatchProps:", customerPatchProps);
return Result.ok(customerPatchProps);
} catch (err: unknown) {
return Result.fail(new DomainError("Customer props mapping failed (update)", { cause: err }));
}
}
private mapPostalAddress(
dto: UpdateCustomerAddressPatchRequestDTO | undefined,
errors: ValidationErrorDetail[]
): PostalAddressPatchProps | undefined {
if (!dto) {
return undefined;
}
const postalAddressPatchProps: PostalAddressPatchProps = {};
toPatchField(dto.street).ifSetOrNull((street) => {
postalAddressPatchProps.street = extractOrPushError(
maybeFromNullableResult(street, (value) => Street.create(value)),
"address.street",
errors
);
});
toPatchField(dto.street2).ifSetOrNull((street2) => {
postalAddressPatchProps.street2 = extractOrPushError(
maybeFromNullableResult(street2, (value) => Street.create(value)),
"address.street2",
errors
);
});
toPatchField(dto.city).ifSetOrNull((city) => {
postalAddressPatchProps.city = extractOrPushError(
maybeFromNullableResult(city, (value) => City.create(value)),
"address.city",
errors
);
});
toPatchField(dto.province).ifSetOrNull((province) => {
postalAddressPatchProps.province = extractOrPushError(
maybeFromNullableResult(province, (value) => Province.create(value)),
"address.province",
errors
);
});
toPatchField(dto.postal_code).ifSetOrNull((postalCode) => {
postalAddressPatchProps.postalCode = extractOrPushError(
maybeFromNullableResult(postalCode, (value) => PostalCode.create(value)),
"address.postal_code",
errors
);
});
toPatchField(dto.country).ifSetOrNull((country) => {
postalAddressPatchProps.country = extractOrPushError(
maybeFromNullableResult(country, (value) => Country.create(value)),
"address.country",
errors
);
});
return Object.keys(postalAddressPatchProps).length > 0 ? postalAddressPatchProps : undefined;
}
private mapContact(
dto: UpdateCustomerContactPatchRequestDTO | undefined,
customerPatchProps: CustomerPatchProps,
errors: ValidationErrorDetail[]
): void {
if (!dto) {
return;
}
toPatchField(dto.email_primary).ifSetOrNull((emailPrimary) => {
customerPatchProps.emailPrimary = extractOrPushError(
maybeFromNullableResult(emailPrimary, (value) => EmailAddress.create(value)),
"contact.email_primary",
errors
);
});
toPatchField(dto.email_secondary).ifSetOrNull((emailSecondary) => {
customerPatchProps.emailSecondary = extractOrPushError(
maybeFromNullableResult(emailSecondary, (value) => EmailAddress.create(value)),
"contact.email_secondary",
errors
);
});
toPatchField(dto.phone_primary).ifSetOrNull((phonePrimary) => {
customerPatchProps.phonePrimary = extractOrPushError(
maybeFromNullableResult(phonePrimary, (value) => PhoneNumber.create(value)),
"contact.phone_primary",
errors
);
});
toPatchField(dto.phone_secondary).ifSetOrNull((phoneSecondary) => {
customerPatchProps.phoneSecondary = extractOrPushError(
maybeFromNullableResult(phoneSecondary, (value) => PhoneNumber.create(value)),
"contact.phone_secondary",
errors
);
});
toPatchField(dto.mobile_primary).ifSetOrNull((mobilePrimary) => {
customerPatchProps.mobilePrimary = extractOrPushError(
maybeFromNullableResult(mobilePrimary, (value) => PhoneNumber.create(value)),
"contact.mobile_primary",
errors
);
});
toPatchField(dto.mobile_secondary).ifSetOrNull((mobileSecondary) => {
customerPatchProps.mobileSecondary = extractOrPushError(
maybeFromNullableResult(mobileSecondary, (value) => PhoneNumber.create(value)),
"contact.mobile_secondary",
errors
);
});
toPatchField(dto.fax).ifSetOrNull((fax) => {
customerPatchProps.fax = extractOrPushError(
maybeFromNullableResult(fax, (value) => PhoneNumber.create(value)),
"contact.fax",
errors
);
});
toPatchField(dto.website).ifSetOrNull((website) => {
customerPatchProps.website = extractOrPushError(
maybeFromNullableResult(website, (value) => URLAddress.create(value)),
"contact.website",
errors
);
});
}
}