Uecko_ERP/modules/customers/src/api/infrastructure/mappers/customer.mapper.ts
2025-09-11 14:05:50 +02:00

250 lines
7.5 KiB
TypeScript

import {
ISequelizeMapper,
MapperParamsType,
SequelizeDomainMapper,
ValidationErrorCollection,
ValidationErrorDetail,
extractOrPushError,
} from "@erp/core/api";
import {
City,
Country,
CurrencyCode,
EmailAddress,
LanguageCode,
Name,
PhoneNumber,
PostalAddress,
PostalCode,
Province,
Street,
TINNumber,
TaxCode,
TextValue,
URLAddress,
UniqueID,
maybeFromNullableVO,
toNullable,
} from "@repo/rdx-ddd";
import { Collection, Result, isNullishOrEmpty } from "@repo/rdx-utils";
import { Customer, CustomerProps, CustomerStatus } from "../../domain";
import { CustomerCreationAttributes, CustomerModel } from "../sequelize";
export interface ICustomerMapper
extends ISequelizeMapper<CustomerModel, CustomerCreationAttributes, Customer> {}
export class CustomerMapper
extends SequelizeDomainMapper<CustomerModel, CustomerCreationAttributes, Customer>
implements ICustomerMapper
{
public mapToDomain(source: CustomerModel, params?: MapperParamsType): Result<Customer, Error> {
try {
const errors: ValidationErrorDetail[] = [];
const customerId = extractOrPushError(UniqueID.create(source.id), "id", errors);
const companyId = extractOrPushError(
UniqueID.create(source.company_id),
"company_id",
errors
);
const isCompany = source.is_company;
const status = extractOrPushError(CustomerStatus.create(source.status), "status", errors);
const reference = extractOrPushError(
maybeFromNullableVO(source.reference, (value) => Name.create(value)),
"reference",
errors
);
const name = extractOrPushError(Name.create(source.name), "name", errors);
const tradeName = extractOrPushError(
maybeFromNullableVO(source.trade_name, (value) => Name.create(value)),
"trade_name",
errors
);
const tinNumber = extractOrPushError(
maybeFromNullableVO(source.tin, (value) => TINNumber.create(value)),
"tin",
errors
);
const street = extractOrPushError(
maybeFromNullableVO(source.street, (value) => Street.create(value)),
"street",
errors
);
const street2 = extractOrPushError(
maybeFromNullableVO(source.street2, (value) => Street.create(value)),
"street2",
errors
);
const city = extractOrPushError(
maybeFromNullableVO(source.city, (value) => City.create(value)),
"city",
errors
);
const province = extractOrPushError(
maybeFromNullableVO(source.province, (value) => Province.create(value)),
"province",
errors
);
const postalCode = extractOrPushError(
maybeFromNullableVO(source.postal_code, (value) => PostalCode.create(value)),
"postal_code",
errors
);
const country = extractOrPushError(
maybeFromNullableVO(source.country, (value) => Country.create(value)),
"country",
errors
);
const emailAddress = extractOrPushError(
maybeFromNullableVO(source.email, (value) => EmailAddress.create(value)),
"email",
errors
);
const phoneNumber = extractOrPushError(
maybeFromNullableVO(source.phone, (value) => PhoneNumber.create(value)),
"phone",
errors
);
const faxNumber = extractOrPushError(
maybeFromNullableVO(source.fax, (value) => PhoneNumber.create(value)),
"fax",
errors
);
const website = extractOrPushError(
maybeFromNullableVO(source.website, (value) => URLAddress.create(value)),
"website",
errors
);
const legalRecord = extractOrPushError(
maybeFromNullableVO(source.legal_record, (value) => TextValue.create(value)),
"legal_record",
errors
);
const languageCode = extractOrPushError(
LanguageCode.create(source.language_code),
"language_code",
errors
);
const currencyCode = extractOrPushError(
CurrencyCode.create(source.currency_code),
"currency_code",
errors
);
// source.default_taxes is stored as a comma-separated string
const defaultTaxes = new Collection<TaxCode>();
if (!isNullishOrEmpty(source.default_taxes)) {
source.default_taxes.split(",").map((taxCode, index) => {
const tax = extractOrPushError(TaxCode.create(taxCode), `default_taxes.${index}`, errors);
if (tax) {
defaultTaxes.add(tax!);
}
});
}
if (errors.length > 0) {
return Result.fail(new ValidationErrorCollection("Customer props mapping failed", errors));
}
const postalAddressProps = {
street: street!,
street2: street2!,
city: city!,
postalCode: postalCode!,
province: province!,
country: country!,
};
const postalAddress = extractOrPushError(
PostalAddress.create(postalAddressProps),
"address",
errors
);
const customerProps: CustomerProps = {
companyId: companyId!,
status: status!,
reference: reference!,
isCompany: isCompany,
name: name!,
tradeName: tradeName!,
tin: tinNumber!,
address: postalAddress!,
email: emailAddress!,
phone: phoneNumber!,
fax: faxNumber!,
website: website!,
legalRecord: legalRecord!,
defaultTaxes: defaultTaxes!,
languageCode: languageCode!,
currencyCode: currencyCode!,
};
return Customer.create(customerProps, customerId);
} catch (err: unknown) {
return Result.fail(err as Error);
}
}
public mapToPersistence(source: Customer, params?: MapperParamsType): CustomerCreationAttributes {
const customerValues: Partial<CustomerCreationAttributes> = {
id: source.id.toPrimitive(),
company_id: source.companyId.toPrimitive(),
reference: toNullable(source.reference, (reference) => reference.toPrimitive()),
is_company: source.isCompany,
name: source.name.toPrimitive(),
trade_name: toNullable(source.tradeName, (tradeName) => tradeName.toPrimitive()),
tin: toNullable(source.tin, (tin) => tin.toPrimitive()),
email: toNullable(source.email, (email) => email.toPrimitive()),
phone: toNullable(source.phone, (phone) => phone.toPrimitive()),
fax: toNullable(source.fax, (fax) => fax.toPrimitive()),
website: toNullable(source.website, (website) => website.toPrimitive()),
legal_record: toNullable(source.legalRecord, (legalRecord) => legalRecord.toPrimitive()),
default_taxes: source.defaultTaxes.map((taxItem) => taxItem.toPrimitive()).join(", "),
status: source.isActive ? "active" : "inactive",
language_code: source.languageCode.toPrimitive(),
currency_code: source.currencyCode.toPrimitive(),
};
if (source.address) {
Object.assign(customerValues, {
street: toNullable(source.address.street, (street) => street.toPrimitive()),
street2: toNullable(source.address.street2, (street2) => street2.toPrimitive()),
city: toNullable(source.address.city, (city) => city.toPrimitive()),
province: toNullable(source.address.province, (province) => province.toPrimitive()),
postal_code: toNullable(source.address.postalCode, (postalCode) =>
postalCode.toPrimitive()
),
country: toNullable(source.address.country, (country) => country.toPrimitive()),
});
}
return customerValues as CustomerCreationAttributes;
}
}