import { RawMaterialKind } from '../../../generated/prisma'; import { bool, childScope, has, isCleared, makeParser, numberIn, optionalIntIn, stringIn, } from './parse-helpers'; import type { NumberFormatConfig, RuleConfigParser, SimpleRuleConfig, } from './rule-config.types'; const MAX_DUE_IN_DAYS = 365; /** Far above any minimum stock of wax or propolis. */ const MAX_MIN_GRAMS = 1_000_000_000; const MAX_NUMBER_FORMAT_LENGTH = 100; const RAW_MATERIAL_KINDS = Object.values(RawMaterialKind); export interface SimpleRuleOptions { /** Whether the rule notifies by default. */ notify: boolean; /** RAW_MATERIAL_LOW reads a minimum per kind. */ withMinGrams?: boolean; } /** * Rules that propose one suggestion: notify, an optional follow-up interval * (dueInDays) and, for the raw material rule, minGrams per kind. */ export function simpleParser( trigger: string, options: SimpleRuleOptions, ): RuleConfigParser { return makeParser( trigger, { notify: options.notify }, (scope) => { const config: SimpleRuleConfig = { notify: bool(scope, 'notify', options.notify), }; const dueInDays = optionalIntIn(scope, 'dueInDays', 0, MAX_DUE_IN_DAYS); if (dueInDays !== undefined) { config.dueInDays = dueInDays; } if ( options.withMinGrams && has(scope, 'minGrams') && !isCleared(scope, 'minGrams') ) { const minScope = childScope(scope, 'minGrams'); const minGrams: Partial> = {}; for (const kind of RAW_MATERIAL_KINDS) { if (isCleared(minScope, kind)) { continue; } const grams = numberIn(minScope, kind, Number.NaN, 0, MAX_MIN_GRAMS); if (!Number.isNaN(grams)) { minGrams[kind] = grams; } } if (Object.keys(minGrams).length > 0) { config.minGrams = minGrams; } } return config; }, ); } /** The batch/lot number rules: one format string with placeholders. */ export function numberFormatParser( trigger: string, defaultFormat: string, ): RuleConfigParser { return makeParser( trigger, { format: defaultFormat }, (scope) => ({ format: stringIn( scope, 'format', defaultFormat, 1, MAX_NUMBER_FORMAT_LENGTH, ), }), ); }