63 lines
2.4 KiB
TypeScript
63 lines
2.4 KiB
TypeScript
|
|
import db from '../config/database';
|
|||
|
|
import { logger } from '../utils/logger';
|
|||
|
|
import { DecisionExplainabilityEngine } from '../core/ai/DecisionExplainabilityEngine';
|
|||
|
|
|
|||
|
|
export interface PackageItem {
|
|||
|
|
skuId: string;
|
|||
|
|
weight: number;
|
|||
|
|
dimensions: { l: number; w: number; h: number };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* [BIZ_OPS_146] 智能包裹拆分/合包优化建议 (Bundle)
|
|||
|
|
* @description 核心逻辑:基于首重与续重运费模板,自动识别多个订单合包或单个大订单拆分的成本优势,降低单均运费。
|
|||
|
|
*/
|
|||
|
|
export class PackingOptimizer {
|
|||
|
|
/**
|
|||
|
|
* 优化包裹方案 (BIZ_OPS_146)
|
|||
|
|
*/
|
|||
|
|
static async optimizePacking(tenantId: string, orderIds: string[]): Promise<any> {
|
|||
|
|
logger.info(`[PackingOptimizer] Analyzing bundling options for ${orderIds.length} orders, Tenant: ${tenantId}`);
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 1. 获取订单商品详情 (模拟)
|
|||
|
|
const items: PackageItem[] = [
|
|||
|
|
{ skuId: 'SKU_A', weight: 0.4, dimensions: { l: 10, w: 10, h: 5 } },
|
|||
|
|
{ skuId: 'SKU_B', weight: 0.3, dimensions: { l: 8, w: 8, h: 4 } }
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// 2. 运费计算对比 (模拟逻辑)
|
|||
|
|
// 假设:单包运费 15,合包运费 22
|
|||
|
|
const separateCost = 15 * 2;
|
|||
|
|
const bundledCost = 22;
|
|||
|
|
const savings = separateCost - bundledCost;
|
|||
|
|
|
|||
|
|
if (savings > 0) {
|
|||
|
|
const advice = `Bundling Opportunity: Combining these ${orderIds.length} orders into a single package saves ${savings.toFixed(2)} in freight costs. ` +
|
|||
|
|
`Estimated total weight: 0.7kg.`;
|
|||
|
|
|
|||
|
|
// 3. [UX_XAI_01] 记录决策证据链
|
|||
|
|
await DecisionExplainabilityEngine.logDecision({
|
|||
|
|
tenantId,
|
|||
|
|
module: 'LOGISTICS_COST_OPTIMIZATION',
|
|||
|
|
resourceId: orderIds.join(','),
|
|||
|
|
decisionType: 'BUNDLE_OPTIMIZATION_SUGGESTION',
|
|||
|
|
causalChain: advice,
|
|||
|
|
factors: [
|
|||
|
|
{ name: 'PotentialSavings', value: savings, weight: 0.8, impact: 'POSITIVE' },
|
|||
|
|
{ name: 'TotalWeight', value: 0.7, weight: 0.2, impact: 'NEUTRAL' }
|
|||
|
|
],
|
|||
|
|
traceId: 'packing-opt-' + Date.now()
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
return { success: true, savings, advice, status: 'PENDING_REVIEW' };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return { success: true, message: 'Current separate shipping is optimal' };
|
|||
|
|
} catch (err: any) {
|
|||
|
|
logger.error(`[PackingOptimizer][WARN] Optimization failed: ${err.message}`);
|
|||
|
|
return { success: false, error: err.message };
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|