Files
Epicnabbo-Catalogus-Updated…/src/features/catalog/domain/bulk-offers.ts
T

82 lines
2.2 KiB
TypeScript

import { z } from "zod";
import { CatalogInputError } from "./hierarchy";
import { offerIdSchema, offerInteger } from "./offer-input";
const priceChange = z
.object({
mode: z.enum(["set", "add", "percent"]),
value: z.number().finite().min(-2147483648).max(2147483647),
})
.strict()
.refine(
(v) => v.mode === "percent" || Number.isInteger(v.value),
"Set and add values must be whole numbers",
);
export const bulkOfferChangesSchema = z
.object({
costCredits: priceChange.optional(),
costPoints: priceChange.optional(),
pointsType: offerInteger.nonnegative().optional(),
pageId: offerIdSchema.optional(),
})
.strict()
.refine(
(v) => Object.values(v).some((x) => x !== undefined),
"Choose at least one field to change",
);
export const bulkOfferInputSchema = z
.object({
ids: z
.array(offerIdSchema)
.min(1)
.max(500)
.refine(
(v) => new Set(v).size === v.length,
"Selection contains duplicate offers",
),
changes: bulkOfferChangesSchema,
})
.strict();
export type BulkOfferInput = z.infer<typeof bulkOfferInputSchema>;
export type BulkOfferValues = {
pageId: number;
costCredits: number;
costPoints: number;
pointsType: number;
};
export type BulkOfferPreview = {
fingerprint: string;
changedCount: number;
pages: Array<{ id: number; caption: string }>;
rows: Array<{
id: number;
catalogName: string;
before: BulkOfferValues;
after: BulkOfferValues;
}>;
};
export function projectBulkOffer(
row: BulkOfferValues,
changes: BulkOfferInput["changes"],
): BulkOfferValues {
const after = { ...row };
for (const key of ["costCredits", "costPoints"] as const) {
const change = changes[key];
if (!change) continue;
const value =
change.mode === "set"
? change.value
: change.mode === "add"
? row[key] + change.value
: Math.round(row[key] * (1 + change.value / 100));
if (!Number.isSafeInteger(value) || value < 0 || value > 2147483647)
throw new CatalogInputError(
"A resulting price is negative or exceeds the supported range",
);
after[key] = value;
}
if (changes.pointsType !== undefined) after.pointsType = changes.pointsType;
if (changes.pageId !== undefined) after.pageId = changes.pageId;
return after;
}