- Rule configs with typed parsers and registry; Berlin day helpers - Schema: T4 enums, Suggestion table, feed vocabulary (feedStatus as ColonyCondition with legacy text mapping), split queen source, varroa sample size; migration harness for data migrations - SuggestionsService: propose/refresh/resolve/obsolete/expire, accept/dismiss/reopen incl. bulk, lock order, concurrency e2e - SeasonService: phenology-based segments, inspection/varroa due dates, queen age; TimeEventsStep with JobPartialFailure - Frontend: per-rule settings forms with visible value sources Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
92 lines
3.1 KiB
TypeScript
92 lines
3.1 KiB
TypeScript
import type { AutomationTriggerType } from '../../../generated/prisma';
|
|
import {
|
|
chainParser,
|
|
colonyEndedCleanupParser,
|
|
DEFAULT_CHAIN_CONFIG,
|
|
withdrawalEndedParser,
|
|
} from './chain.config';
|
|
import { inspectionIntervalParser } from './inspection-interval.config';
|
|
import { phenologyParser } from './phenology.config';
|
|
import { seasonAutopilotParser } from './season-autopilot.config';
|
|
import { numberFormatParser, simpleParser } from './simple.config';
|
|
import { splitScheduleParser } from './split-schedule.config';
|
|
import { varroaThresholdParser } from './varroa-threshold.config';
|
|
import { waterContentParser } from './water-content.config';
|
|
import type {
|
|
RuleConfigIssue,
|
|
RuleConfigMap,
|
|
RuleConfigParser,
|
|
} from './rule-config.types';
|
|
|
|
/** The number-format rules keep the defaults they always had. */
|
|
const DEFAULT_BATCH_FORMAT = 'WH-{YYYY}-{SEQ:4}';
|
|
|
|
export const RULE_CONFIG_PARSERS: {
|
|
[K in AutomationTriggerType]: RuleConfigParser<RuleConfigMap[K]>;
|
|
} = {
|
|
VARROA_THRESHOLD: varroaThresholdParser,
|
|
INSPECTION_INTERVAL: inspectionIntervalParser,
|
|
QUEEN_CELLS_SWARM_CHECK: chainParser(
|
|
'QUEEN_CELLS_SWARM_CHECK',
|
|
DEFAULT_CHAIN_CONFIG,
|
|
),
|
|
QUEEN_ACCEPTANCE_CHECK: chainParser(
|
|
'QUEEN_ACCEPTANCE_CHECK',
|
|
DEFAULT_CHAIN_CONFIG,
|
|
),
|
|
SPLIT_SCHEDULE: splitScheduleParser,
|
|
COLONY_ENDED_CLEANUP: colonyEndedCleanupParser,
|
|
WITHDRAWAL_ENDED: withdrawalEndedParser,
|
|
HONEY_WATER_CONTENT: waterContentParser,
|
|
SEASON_AUTOPILOT: seasonAutopilotParser,
|
|
PHENOLOGY: phenologyParser,
|
|
HONEY_BATCH_NUMBER_FORMAT: numberFormatParser(
|
|
'HONEY_BATCH_NUMBER_FORMAT',
|
|
DEFAULT_BATCH_FORMAT,
|
|
),
|
|
BOTTLING_LOT_NUMBER_FORMAT: numberFormatParser(
|
|
'BOTTLING_LOT_NUMBER_FORMAT',
|
|
DEFAULT_BATCH_FORMAT,
|
|
),
|
|
// {ART} (WA/PR) gives wax and propolis a counter each.
|
|
RAW_MATERIAL_LOT_NUMBER_FORMAT: numberFormatParser(
|
|
'RAW_MATERIAL_LOT_NUMBER_FORMAT',
|
|
'{ART}-{YYYY}-{SEQ:4}',
|
|
),
|
|
PRODUCTION_BATCH_NUMBER_FORMAT: numberFormatParser(
|
|
'PRODUCTION_BATCH_NUMBER_FORMAT',
|
|
'HS-{YYYY}-{SEQ:4}',
|
|
),
|
|
QUEENLESS_NO_EGGS: simpleParser('QUEENLESS_NO_EGGS', { notify: true }),
|
|
FEED_STATUS_CRITICAL: simpleParser('FEED_STATUS_CRITICAL', {
|
|
notify: false,
|
|
}),
|
|
SWARM_MOOD_HIGH: simpleParser('SWARM_MOOD_HIGH', { notify: false }),
|
|
COLONY_HEALTH_CRITICAL: simpleParser('COLONY_HEALTH_CRITICAL', {
|
|
notify: true,
|
|
}),
|
|
STOCK_ITEM_LOW: simpleParser('STOCK_ITEM_LOW', { notify: false }),
|
|
RAW_MATERIAL_LOW: simpleParser('RAW_MATERIAL_LOW', {
|
|
notify: false,
|
|
withMinGrams: true,
|
|
}),
|
|
TREATMENT_FOLLOW_UP: simpleParser('TREATMENT_FOLLOW_UP', { notify: false }),
|
|
FEEDING_FOLLOW_UP: simpleParser('FEEDING_FOLLOW_UP', { notify: false }),
|
|
};
|
|
|
|
/** The effective setting of a rule: valid keys as stored, the rest default. */
|
|
export function ruleConfigOf<K extends AutomationTriggerType>(
|
|
trigger: K,
|
|
json: unknown,
|
|
): RuleConfigMap[K] {
|
|
return RULE_CONFIG_PARSERS[trigger].parse(json);
|
|
}
|
|
|
|
/** The invalid known keys of a config a client wants to save. */
|
|
export function validateRuleConfig(
|
|
trigger: AutomationTriggerType,
|
|
json: unknown,
|
|
): RuleConfigIssue[] {
|
|
return RULE_CONFIG_PARSERS[trigger].validate(json);
|
|
}
|