feat(sync): synchronize customer addresses
Mirror the addresses embedded in GET /customer/🆔 per customer, delete the ones missing from Hiboutik, then upsert each of them (failures logged and skipped). CustomerAddress gains its own recipient (firstName, lastName, company, phone) plus state and other. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,8 @@ describe('CustomerHiboutikService', () => {
|
||||
const customerHiboutikRepository = { getCustomers: jest.fn(), getCustomerById: jest.fn() };
|
||||
const customerDatabaseRepository = { upsert: jest.fn(), deleteMissing: jest.fn() };
|
||||
const customerConverter = { fromHiboutik: jest.fn() };
|
||||
const customerAddressDatabaseRepository = { upsert: jest.fn(), deleteMissing: jest.fn() };
|
||||
const customerAddressConverter = { fromHiboutik: jest.fn((dto: unknown) => dto) };
|
||||
let service: CustomerHiboutikService;
|
||||
|
||||
beforeAll(() => {
|
||||
@@ -16,12 +18,16 @@ describe('CustomerHiboutikService', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
customerHiboutikRepository.getCustomers.mockResolvedValue([]);
|
||||
customerHiboutikRepository.getCustomerById.mockResolvedValue({});
|
||||
customerHiboutikRepository.getCustomerById.mockResolvedValue({ customers_id: 1, addresses: [] });
|
||||
customerDatabaseRepository.upsert.mockResolvedValue({ id: 'customer-uuid' });
|
||||
customerDatabaseRepository.deleteMissing.mockResolvedValue(0);
|
||||
customerAddressDatabaseRepository.deleteMissing.mockResolvedValue(0);
|
||||
service = new CustomerHiboutikService(
|
||||
customerHiboutikRepository as never,
|
||||
customerDatabaseRepository as never,
|
||||
customerConverter as never,
|
||||
customerAddressDatabaseRepository as never,
|
||||
customerAddressConverter as never,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -48,4 +54,57 @@ describe('CustomerHiboutikService', () => {
|
||||
|
||||
expect(customerDatabaseRepository.upsert).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
describe('addresses', () => {
|
||||
beforeEach(() => {
|
||||
customerHiboutikRepository.getCustomers.mockResolvedValue([{ customers_id: 1 }]);
|
||||
});
|
||||
|
||||
it('deletes the missing addresses of the customer, then upserts the others linked to it', async () => {
|
||||
customerHiboutikRepository.getCustomerById.mockResolvedValue({
|
||||
customers_id: 1,
|
||||
addresses: [
|
||||
{ address_id: 10, customers_id: 1 },
|
||||
{ address_id: '11', customers_id: 999 },
|
||||
],
|
||||
});
|
||||
|
||||
await service.syncCustomers();
|
||||
|
||||
expect(customerAddressDatabaseRepository.deleteMissing).toHaveBeenCalledWith('customer-uuid', [10, 11]);
|
||||
expect(customerAddressDatabaseRepository.upsert).toHaveBeenCalledTimes(2);
|
||||
expect(customerAddressConverter.fromHiboutik).toHaveBeenLastCalledWith({ address_id: '11', customers_id: 1 });
|
||||
expect(customerAddressDatabaseRepository.deleteMissing.mock.invocationCallOrder[0]).toBeLessThan(
|
||||
customerAddressDatabaseRepository.upsert.mock.invocationCallOrder[0],
|
||||
);
|
||||
});
|
||||
|
||||
it('deletes all the addresses of a customer that has none left', async () => {
|
||||
await service.syncCustomers();
|
||||
|
||||
expect(customerAddressDatabaseRepository.deleteMissing).toHaveBeenCalledWith('customer-uuid', []);
|
||||
expect(customerAddressDatabaseRepository.upsert).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('keeps the stored addresses when the payload has no addresses array', async () => {
|
||||
customerHiboutikRepository.getCustomerById.mockResolvedValue({ customers_id: 1 });
|
||||
|
||||
await service.syncCustomers();
|
||||
|
||||
expect(customerAddressDatabaseRepository.deleteMissing).not.toHaveBeenCalled();
|
||||
expect(customerAddressDatabaseRepository.upsert).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('keeps syncing the other addresses when one fails', async () => {
|
||||
customerHiboutikRepository.getCustomerById.mockResolvedValue({
|
||||
customers_id: 1,
|
||||
addresses: [{ address_id: 10 }, { address_id: 11 }],
|
||||
});
|
||||
customerAddressDatabaseRepository.upsert.mockRejectedValueOnce(new Error('boom'));
|
||||
|
||||
await service.syncCustomers();
|
||||
|
||||
expect(customerAddressDatabaseRepository.upsert).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user