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 {} export class CustomerMapper extends SequelizeDomainMapper implements ICustomerMapper { public mapToDomain(source: CustomerModel, params?: MapperParamsType): Result { 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(); 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 = { 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; } }