import { DomainConflictError } from '../../../common/errors/domain-conflict.error';
type BillingInput = Record<string, any>;
function object(input: unknown, code: string): asserts input is BillingInput {
if (!input || typeof input !== 'object' || Array.isArray(input)) {
throw new DomainConflictError(code);
}
}
function text(value: unknown, max: number, code: string): asserts value is string {
if (typeof value !== 'string' || value.trim().length === 0 || value.length > max) {
throw new DomainConflictError(code);
}
}
function scope(input: unknown, code: string): asserts input is BillingInput {
object(input, code);
text(input.organizationId, 200, code);
text(input.locationId, 200, code);
}
function id(value: unknown, code: string): void {
text(value, 200, code);
}
function safeInteger(value: unknown, min: number, max: number, code: string): void {
if (!Number.isSafeInteger(value) || Number(value) < min || Number(value) > max) {
throw new DomainConflictError(code);
}
}
function uniqueIds(value: unknown, min: number, max: number, code: string): void {
if (!Array.isArray(value) || value.length < min || value.length > max) {
throw new DomainConflictError(code);
}
const seen = new Set<string>();
for (const entry of value) {
id(entry, code);
if (seen.has(entry)) throw new DomainConflictError(code);
seen.add(entry);
}
}
export function assertOpenCheckInput(input: unknown): asserts input is BillingInput {
const code = 'billing.input_invalid';
scope(input, code);
id(input.serviceSessionId, code);
if (typeof input.currencyCode !== 'string' || !/^[A-Z]{3}$/.test(input.currencyCode)) {
throw new DomainConflictError(code);
}
}
export function assertCheckReferenceInput(input: unknown): asserts input is BillingInput {
const code = 'billing.input_invalid';
scope(input, code);
id(input.checkId, code);
}
export function assertSplitByItemsInput(input: unknown): asserts input is BillingInput {
const code = 'billing.split_items_invalid';
scope(input, code);
id(input.sourceCheckId, code);
uniqueIds(input.orderItemIds, 1, 500, code);
}
export function assertSplitBySeatInput(input: unknown): asserts input is BillingInput {
const code = 'billing.split_seats_invalid';
scope(input, code);
id(input.sourceCheckId, code);
if (!Array.isArray(input.seatNumbers) || input.seatNumbers.length < 1 || input.seatNumbers.length > 100) {
throw new DomainConflictError(code);
}
const seen = new Set<number>();
for (const seatNumber of input.seatNumbers) {
safeInteger(seatNumber, 1, 1000, code);
if (seen.has(seatNumber)) throw new DomainConflictError(code);
seen.add(seatNumber);
}
}
export function assertSplitEqualInput(input: unknown): asserts input is BillingInput {
const code = 'billing.equal_split_parts_invalid';
scope(input, code);
id(input.sourceCheckId, code);
safeInteger(input.parts, 2, 20, code);
}
export function assertSplitCustomInput(input: unknown): asserts input is BillingInput {
const code = 'billing.custom_split_invalid';
scope(input, code);
id(input.sourceCheckId, code);
if (!Array.isArray(input.amountsMinor) || input.amountsMinor.length < 2 || input.amountsMinor.length > 20) {
throw new DomainConflictError(code);
}
for (const amount of input.amountsMinor) safeInteger(amount, 1, Number.MAX_SAFE_INTEGER, code);
}
