- Hiboutik payloads are zod schemas, validated by HiboutikClient (getOne added for single resources: null on 404 or empty answer). - Hiboutik dates are read as Europe/Paris whatever the server time zone. - Paginated lists driving deletions are walked twice when they span several pages (brands, categories, products); categories are sorted by id. - A customer missing from the list is deleted only once Hiboutik confirms it; completed orders that lost their customer are linked back. - Each product and its versions are written in one transaction. - An email removed in Hiboutik is erased in database. - A 429 is retried with backoff, then stops the synchronization. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
54 lines
2.0 KiB
TypeScript
54 lines
2.0 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import { HiboutikClient } from './hiboutik.client';
|
|
import {
|
|
CustomerAddressDetailsHiboutikDto,
|
|
customerAddressDetailsHiboutikSchema,
|
|
CustomerHiboutikDto,
|
|
customerHiboutikSchema,
|
|
FullCustomerHiboutikDto,
|
|
fullCustomerHiboutikSchema,
|
|
} from '../models/hiboutikDTO/customer.hiboutik.dto';
|
|
|
|
/** Reads customers from the Hiboutik API. */
|
|
@Injectable()
|
|
export class CustomerHiboutikRepository {
|
|
constructor(private readonly hiboutikClient: HiboutikClient) {}
|
|
|
|
/**
|
|
* Customer summaries only: use {@link getCustomerById} for addresses and sales. Sorted by id so that the pages are
|
|
* stable, but a customer created or deleted while they are walked can still shift the following ones.
|
|
*/
|
|
async getCustomers(): Promise<CustomerHiboutikDto[]> {
|
|
return this.hiboutikClient.getAllPages('/customers', customerHiboutikSchema, {
|
|
order_by: 'customers_id',
|
|
sort: 'ASC',
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Full customer, with its addresses and sales.
|
|
* @returns `null` when Hiboutik says the customer does not exist (404 or empty answer).
|
|
* @throws on any other failure: an unknown state is never taken for a deleted customer.
|
|
*/
|
|
async findCustomerById(id: number): Promise<FullCustomerHiboutikDto | null> {
|
|
return this.hiboutikClient.getOne(`/customer/${id}`, fullCustomerHiboutikSchema);
|
|
}
|
|
|
|
/** Same as {@link findCustomerById}, but a missing customer throws. */
|
|
async getCustomerById(id: number): Promise<FullCustomerHiboutikDto> {
|
|
const customer = await this.findCustomerById(id);
|
|
if (!customer) throw new Error(`Hiboutik customer ${id} not found`);
|
|
return customer;
|
|
}
|
|
|
|
/**
|
|
* Address with its company details.
|
|
* @throws if the address does not exist.
|
|
*/
|
|
async getAddressById(id: number): Promise<CustomerAddressDetailsHiboutikDto> {
|
|
const address = await this.hiboutikClient.getOne(`/customers_addresses/${id}`, customerAddressDetailsHiboutikSchema);
|
|
if (!address) throw new Error(`Hiboutik address ${id} not found`);
|
|
return address;
|
|
}
|
|
}
|