@@ -0,0 +1,54 @@
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user