@tomei/customer-base
Version:
Tomei Customer Base Package
159 lines (145 loc) • 5.4 kB
text/typescript
import { Transaction } from 'sequelize';
import { Sequelize } from 'sequelize-typescript';
import {
CustomerBaseModel,
CustomerIndividualModel,
CustomerBusinessModel,
BusinessContactModel,
ObjectAddressModel,
} from '../../models';
import cuid from '../../helpers/cuid';
import { ISyncPayload } from '../../types/sync-payload.type';
import { IBusinessSyncPayload, IIndividualSyncPayload } from '../../interfaces';
import { CustomerStatusEnum, CustomerTypeEnum } from '../../enum';
export class CustomerBaseWriter {
constructor(private readonly sequelize: Sequelize) {}
async write(
payload: ISyncPayload,
dbTransaction?: Transaction,
): Promise<void> {
let transaction = dbTransaction;
const createdTransaction = !transaction;
const ctx = {
CustomerId: payload?.CustomerId,
Type: payload?.Type,
SourceSystem: payload?.SourceSystem,
};
try {
if (!transaction) transaction = await this.sequelize.transaction();
if (!payload.CustomerId) throw new Error('CustomerId is required.');
if (!payload.Type)
throw new Error('Type is required (Individual or Business).');
// Customer Base
await CustomerBaseModel.upsert(
{
CustomerId: payload.CustomerId,
Type: payload.Type,
Email: payload.Email,
ContactNo: payload.ContactNo,
Status: CustomerStatusEnum.Active,
CreatedByUserId: payload.UserId,
CreatedByCustomerId: !payload.UserId ? payload.CustomerId : null,
CreatedAt: new Date(),
UpdatedByUserId: payload.UserId,
UpdatedByCustomerId: !payload.UserId ? payload.CustomerId : null,
UpdatedAt: new Date(),
UpdatedBySystemCode: payload.SourceSystem,
},
{ transaction },
);
// Type-specific
if (payload.Type === CustomerTypeEnum.Individual) {
const p = payload as IIndividualSyncPayload;
if (!p.FullName) throw new Error('FullName is required.');
if (!p.IdType) throw new Error('IdType is required.');
if (!p.IdNo) throw new Error('IdNo is required.');
await CustomerIndividualModel.upsert(
{
CustomerId: p.CustomerId,
FullName: p.FullName,
IdType: p.IdType,
IdNo: p.IdNo,
Title: p.Title ?? 'N/A',
PreferredName: p.PreferredName ?? p.FullName,
Birthdate: p.Birthdate ?? undefined,
Gender: p.Gender ?? undefined,
Ethnicity: p.Ethnicity ?? undefined,
Nationality: p.Nationality ?? undefined,
PreferredLanguage: p.PreferredLanguage ?? undefined,
},
{ transaction },
);
} else if (payload.Type === CustomerTypeEnum.Business) {
const p = payload as IBusinessSyncPayload;
if (!p.CompanyName) throw new Error('Company Name is required.');
await CustomerBusinessModel.upsert(
{
CustomerId: p.CustomerId,
CompanyName: p.CompanyName,
RegistrationNo: p.RegistrationNo,
TaxIdentificationNo: p.TaxIdentificationNo,
},
{ transaction },
);
if (payload.PIC) {
if (!payload.PIC.Name) throw new Error('PIC Name is required.');
if (!payload.PIC.ContactNo)
throw new Error('PIC ContactNo is required.');
await BusinessContactModel.upsert(
{
ContactId: cuid(),
CustomerId: payload.CustomerId,
Name: payload.PIC.Name,
Email: payload.PIC.Email,
ContactNo: payload.PIC.ContactNo,
Position: payload.PIC.Position,
IsMainYN: payload.PIC.IsMainYN,
},
{ transaction },
);
}
}
// Addresses
if (payload.Address?.length) {
for (const address of payload.Address) {
await ObjectAddressModel.upsert(
{
AddressId: cuid(),
ObjectId: payload.CustomerId,
ObjectType: 'Customer',
AddressLine1: address.AddressLine1,
AddressLine2: address.AddressLine2,
City: address.City,
State: address.State,
PostalCode: address.PostCode,
Country: address.Country,
Latitude: 0,
Longitude: 0,
AddressType: (address as any).AddressType ?? 'Billing Address',
IsDefaultYN: (address as any).IsDefaultYN ?? 'Y',
Status: 'Active',
CreatedById: payload.UserId ?? payload.CustomerId,
CreatedAt: new Date(),
UpdatedById: payload.UserId ?? payload.CustomerId,
UpdatedAt: new Date(),
},
{ transaction },
);
}
}
// Optional cleanup: (left unimplemented)
/**
* If strict sync:
* Remove any existing business_Contact or object_Address not in the incoming payload (based on CustomerId).
*/
if (createdTransaction) await transaction.commit();
} catch (err) {
if (createdTransaction && transaction) await transaction.rollback();
console.error('[CustomerBaseWriter.write] failed', {
...ctx,
error: (err as Error)?.message,
});
throw err;
}
}
}