“核销”(verification 或 deduction)通常指将预付款(prepay)金额按 FIFO(First In First Out,先入先出)原则分配到订单产品(prolist)中,即从预付款单按 amount 升序(从小到大)排序后,逐个扣减订单产品的 amount,直到一方金额耗尽。
实现代码// 预付款const prepays = [ { id: 101, amount: 2000 }, { id: 102, amount: 500 }, { id: 103, amount: 800 }, { id: 104, amount: 300 }];// 订单产品const prolist = [ { id: 201, amount: 1500 }, { id: 202, amount: 1000 }, { id: 203, amount: 80 }, { id: 204, amount: 1300 }];

// 1. 按 amount 从小到大排序预付款const sortedPrepays = [...prepays].sort((a, b) => a.amount - b.amount);// 2. 深拷贝订单数组(避免修改原数据)const orders = prolist.map(item => ({ ...item }));// 3. 核销明细记录const details = [];// 4. 核销逻辑:双指针方式let prepayIndex = 0; // 当前处理的预付款索引for (let i = 0; i < orders.length && prepayIndex < sortedPrepays.length; ) { const order = orders[i]; const prepay = sortedPrepays[prepayIndex]; // 本次可核销金额 = min(订单剩余, 预付款剩余) const deduct = Math.min(order.amount, prepay.amount); // 记录核销明细 details.push({ prepayId: prepay.id, proId: order.id, deducted: deduct }); // 扣减 order.amount -= deduct; sortedPrepays[prepayIndex].amount -= deduct; // 判断是否用完 if (order.amount === 0) { i++; // 订单核销完,进入下一个订单 } if (sortedPrepays[prepayIndex].amount === 0) { prepayIndex++; // 预付款用完,进入下一笔 }}// 5. 输出结果console.log("核销明细:", details);console.log("剩余预付款:", sortedPrepays.filter(p => p.amount > 0));console.log("剩余订单:", orders.filter(o => o.amount > 0));// 输出结果核销明细: [ { prepayId: 104, proId: 201, deducted: 300 }, { prepayId: 102, proId: 201, deducted: 500 }, { prepayId: 103, proId: 201, deducted: 700 }, { prepayId: 103, proId: 202, deducted: 100 }, { prepayId: 101, proId: 202, deducted: 900 }, { prepayId: 101, proId: 203, deducted: 80 }, { prepayId: 101, proId: 204, deducted: 920 }]剩余预付款: []剩余订单: [ { id: 204, amount: 380 } ]

function verifyByPrepayAsc(prepays, prolist) { const sortedPrepays = [...prepays].sort((a, b) => a.amount - b.amount); const orders = prolist.map(p => ({ ...p })); const details = []; let pi = 0; for (let i = 0; i < orders.length && pi < sortedPrepays.length; ) { const deduct = Math.min(orders[i].amount, sortedPrepays[pi].amount); details.push({ prepayId: sortedPrepays[pi].id, proId: orders[i].id, deducted: deduct }); orders[i].amount -= deduct; sortedPrepays[pi].amount -= deduct; if (orders[i].amount === 0) i++; if (sortedPrepays[pi].amount === 0) pi++; } return { details, remainingPrepays: sortedPrepays.filter(p => p.amount > 0), remainingOrders: orders.filter(o => o.amount > 0) };}// 使用const result = verifyByPrepayAsc(prepays, prolist);console.log(result);
本文链接:https://www.jingber.cn/post/3852.html 转载需授权!

微信扫一扫,打赏作者吧~