Add editable cutting rules
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user