@tomei/customer-base
Version:
Tomei Customer Base Package
125 lines (113 loc) • 4.18 kB
text/typescript
import { Op } from 'sequelize';
import {
CustomerBaseModel,
CustomerIndividualModel,
CustomerBusinessModel,
BusinessContactModel,
ObjectAddressModel,
} from '../../models';
import { ISyncPayload } from '../../types/sync-payload.type';
import { IBusinessSyncPayload, IIndividualSyncPayload } from '../../interfaces';
import { CustomerTypeEnum } from '../../enum/customer-type.enum';
import { IAddress } from '@tomei/general';
/**
* Builds a normalized ISyncPayload for a given CustomerId by reading CB tables.
* Keeps the shape consistent with your discriminated union (Individual | Business)
*
* @param customerId - The ID of the customer to build the payload for
* @returns A promise that resolves to the normalized ISyncPayload
*/
export async function buildCustomerPayload(
customerId: string,
): Promise<ISyncPayload> {
const customerBase = await CustomerBaseModel.findByPk(customerId);
if (!customerBase) {
throw new Error(`CustomerBase not found for CustomerId=${customerId}`);
}
const addresses = await ObjectAddressModel.findAll({
where: {
ObjectId: customerId,
ObjectType: 'Customer',
Status: { [Op.ne]: 'Deleted' },
},
order: [
['IsDefaultYN', 'DESC'],
['UpdatedAt', 'DESC'],
],
});
const Address: IAddress[] = addresses.map((a) => ({
AddressLine1: a.AddressLine1,
AddressLine2: a.AddressLine2 ?? '',
City: a.City,
State: a.State ?? '',
PostCode: a.PostalCode, //DEV WARN: Postcode and/or PostalCode can be not consistent between systems
Country: a.Country,
AddressType: a.AddressType,
IsDefaultYN: a.IsDefaultYN,
Latitude: (a as any).Latitude ?? undefined,
Longitude: (a as any).Longitude ?? undefined,
}));
const sourceSystem = customerBase.UpdatedBySystemCode ?? '';
if (customerBase.Type === CustomerTypeEnum.Individual) {
const cbIndividual = await CustomerIndividualModel.findByPk(customerId);
if (!cbIndividual) {
throw new Error(
`CustomerIndividual not found for CustomerId=${customerId}`,
);
}
const payload: IIndividualSyncPayload = {
// base payload fields
CustomerId: customerBase.CustomerId,
Type: CustomerTypeEnum.Individual,
Email: customerBase.Email ?? '-',
ContactNo: customerBase.ContactNo ?? '-',
SourceSystem: sourceSystem,
Address,
// individual payload fields
FullName: cbIndividual.FullName,
IdType: cbIndividual.IdType,
IdNo: cbIndividual.IdNo,
// optional/nullable individual fields
Title: cbIndividual.Title ?? 'N/A',
PreferredName: cbIndividual.PreferredName ?? cbIndividual.FullName,
Birthdate: cbIndividual.Birthdate ?? undefined,
Gender: cbIndividual.Gender ?? undefined,
Ethnicity: cbIndividual.Ethnicity ?? undefined,
Nationality: cbIndividual.Nationality ?? undefined,
PreferredLanguage: cbIndividual.PreferredLanguage ?? undefined,
};
return payload;
}
const cbBusiness = await CustomerBusinessModel.findByPk(customerId);
if (!cbBusiness) {
throw new Error(`CustomerBusiness not found for CustomerId=${customerId}`);
}
const cbBusinessPIC = await BusinessContactModel.findOne({
where: { CustomerId: customerId, IsMainYN: 'Y' },
order: [['UpdatedAt', 'DESC']],
});
const payload: IBusinessSyncPayload = {
// base payload fields
CustomerId: customerBase.CustomerId,
Type: CustomerTypeEnum.Business,
Email: customerBase.Email,
ContactNo: customerBase.ContactNo,
SourceSystem: sourceSystem,
Address,
// business payload fields
CompanyName: cbBusiness.CompanyName,
RegistrationNo: cbBusiness.RegistrationNo ?? undefined,
TaxIdentificationNo: cbBusiness.TaxIdentificationNo ?? undefined,
// PIC is optional in your writer; keep it optional here too
PIC: cbBusinessPIC
? {
Name: cbBusinessPIC.Name,
ContactNo: cbBusinessPIC.ContactNo,
Email: cbBusinessPIC.Email ?? undefined,
Position: cbBusinessPIC.Position ?? undefined,
IsMainYN: cbBusinessPIC.IsMainYN,
}
: undefined,
};
return payload;
}