Add editable cutting rules

This commit is contained in:
Cauê Faleiros
2026-07-07 15:20:57 -03:00
parent d1220fdd3f
commit d512f8b00d
3 changed files with 255 additions and 10 deletions

View File

@@ -12,6 +12,17 @@ export interface CutFamilyRule {
unitsPerRoll: number | null;
}
export interface CutProductOverride {
familyKey?: CutFamilyKey | '';
color?: string;
size?: string;
}
export interface CutPlanOptions {
familyYields?: Partial<Record<CutFamilyKey, number>>;
productOverrides?: Record<string, CutProductOverride>;
}
export interface CutPlanSkuRow extends ProductAnalyticsItem {
family: CutFamilyRule;
baseName: string;
@@ -99,6 +110,11 @@ export const OUTROS_RULE: CutFamilyRule = {
unitsPerRoll: null
};
const FAMILY_RULES_BY_KEY = new Map<CutFamilyKey, CutFamilyRule>([
...CUT_FAMILY_RULES.map(rule => [rule.key, rule] as const),
[OUTROS_RULE.key, OUTROS_RULE]
]);
export const getRangeDays = (range: DateRange) => {
const start = new Date(range.start);
const end = new Date(range.end);
@@ -121,6 +137,14 @@ export const classifyCutFamily = (baseName: string): CutFamilyRule => {
)) || OUTROS_RULE;
};
const ruleWithConfiguredYield = (rule: CutFamilyRule, familyYields?: Partial<Record<CutFamilyKey, number>>): CutFamilyRule => {
const configuredYield = familyYields?.[rule.key];
return {
...rule,
unitsPerRoll: configuredYield && configuredYield > 0 ? configuredYield : rule.unitsPerRoll
};
};
const normalizeMatchText = (value: string) => normalizeProductText(value)
.normalize('NFD')
.replace(/\p{Diacritic}/gu, '')
@@ -178,13 +202,18 @@ export const buildCutPlan = (
products: ProductAnalyticsItem[],
dateRange: DateRange,
targetCoverageDays: number,
openProductionByProductId: Record<string, number> = {}
openProductionByProductId: Record<string, number> = {},
options: CutPlanOptions = {}
): CutPlan => {
const rangeDays = getRangeDays(dateRange);
const rows = products.map<CutPlanSkuRow>(product => {
const metadata = parseProductName(product.name);
const family = classifyCutFamily(metadata.baseName);
const override = options.productOverrides?.[product.id];
const overrideRule = override?.familyKey ? FAMILY_RULES_BY_KEY.get(override.familyKey) : undefined;
const family = ruleWithConfiguredYield(overrideRule || classifyCutFamily(metadata.baseName), options.familyYields);
const color = normalizeProductText(override?.color || metadata.color);
const size = normalizeProductText(override?.size || metadata.size).toUpperCase();
const dailySales = product.quantitySold / rangeDays;
const projectedDemand = dailySales * targetCoverageDays;
const openProductionQuantity = openProductionByProductId[product.id] || 0;
@@ -197,16 +226,16 @@ export const buildCutPlan = (
const issues: CutIssue[] = [];
if (family.key === 'OUTROS') issues.push('missing_family_rule');
if (!metadata.color) issues.push('missing_color');
if (!metadata.size) issues.push('missing_size');
if (!color) issues.push('missing_color');
if (!size) issues.push('missing_size');
if (suggestedCutQuantity > 0 && family.key !== 'OUTROS' && !family.unitsPerRoll) issues.push('missing_yield_rule');
return {
...product,
family,
baseName: metadata.baseName,
color: metadata.color,
size: metadata.size,
color,
size,
dailySales,
projectedDemand,
openProductionQuantity,