55 lines
1.9 KiB
TypeScript
55 lines
1.9 KiB
TypeScript
import { plainToInstance } from 'class-transformer';
|
|
import { validateSync } from 'class-validator';
|
|
import { ReportedProductDto, StockAdjustmentResultDto } from './dto/stock-sync.dto';
|
|
import { describe } from './tab-events';
|
|
|
|
export type Rejected = { id: string | null; reason: string };
|
|
|
|
/**
|
|
* Validates entries one by one, like tab events: one bad product or result is skipped on its own
|
|
* instead of failing the sync (and with it the open tabs and sales).
|
|
*/
|
|
function parseEach<T extends object>(cls: new () => T, raw: unknown[]): { accepted: T[]; rejected: Rejected[] } {
|
|
const accepted: T[] = [];
|
|
const rejected: Rejected[] = [];
|
|
|
|
for (const value of raw) {
|
|
const id = typeof (value as { id?: unknown })?.id === 'string' ? (value as { id: string }).id : null;
|
|
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
rejected.push({ id, reason: 'must be an object' });
|
|
continue;
|
|
}
|
|
const entry = plainToInstance(cls, value);
|
|
const errors = validateSync(entry, { whitelist: true });
|
|
if (errors.length > 0) {
|
|
rejected.push({ id, reason: describe(errors) });
|
|
continue;
|
|
}
|
|
accepted.push(entry);
|
|
}
|
|
|
|
return { accepted, rejected };
|
|
}
|
|
|
|
export function parseProducts(raw: unknown[]) {
|
|
const { accepted, rejected } = parseEach(ReportedProductDto, raw);
|
|
// A duplicated id would make the upserts fight; the last one reported wins
|
|
const byId = new Map(accepted.map((product) => [product.id, product]));
|
|
return {
|
|
products: [...byId.values()].map((p) => ({
|
|
id: p.id,
|
|
name: p.name.trim(),
|
|
category: p.category?.trim() || null,
|
|
priceInCents: p.priceInCents,
|
|
stock: p.stock ?? null,
|
|
})),
|
|
rejected,
|
|
};
|
|
}
|
|
|
|
export type ParsedProduct = ReturnType<typeof parseProducts>['products'][number];
|
|
|
|
export function parseStockResults(raw: unknown[]) {
|
|
return parseEach(StockAdjustmentResultDto, raw);
|
|
}
|