import { Decimal } from "decimal.js"; /** * 农户重量计算器类 * 用于计算每个农户的净重和毛重,并赋值到原数据中 */ export class SupplierWeightCalculator { private suppliers: BusinessAPI.OrderSupplier[]; constructor(suppliers: BusinessAPI.OrderSupplier[]) { this.suppliers = suppliers; this.init(); } /** * 初始化计算规则 */ private init() { Decimal.set({ precision: 20, rounding: 0, // 向下舍入(更保守的计算方式) toExpNeg: -7, toExpPos: 21, }); } /** * 计算所有农户的重量信息 * @returns {Array} 包含净重、毛重和空磅的农户数据 */ calculate(): BusinessAPI.OrderSupplier[] { if (!this.suppliers || this.suppliers.length === 0) { return this.suppliers; } // 使用第一个瓜农的空磅重量作为初始空磅重量 const initialEmptyWeight = this.suppliers[0].emptyWeight || 0; let previousTotalWeight = initialEmptyWeight; // 上一个农户的总磅重量(kg) for (let i = 0; i < this.suppliers.length; i++) { const supplier = this.suppliers[i]; const isFirstSupplier = i === 0; const isLastSupplier = supplier.isLast; // 设置空磅重量(第一个农户使用自己的空磅重量,其他使用前一个农户的总磅重量) if (isFirstSupplier) { // 第一个农户的空磅重量已经是正确的 } else { supplier.emptyWeight = this.suppliers[i - 1].totalWeight || 0; } // 计算本次使用纸箱的总重量(斤) const usedBoxesWeight = new Decimal( this.calculateBoxesTotalWeight(supplier.orderPackageList || [], "USED"), ) .add( this.calculateBoxesTotalWeight( supplier.orderPackageList || [], "OWN", ), ) .toNumber(); // 计算额外配送的已使用纸箱总重量(斤) const extraUsedBoxesWeight = this.calculateBoxesTotalWeight( supplier.orderPackageList || [], "EXTRA_USED", ); if (!supplier.isPaper) { // 如果不是纸箱包装,直接使用原始重量(kg转斤) supplier.grossWeight = new Decimal(supplier.totalWeight || 0) .sub(supplier.emptyWeight || 0) .mul(2) .toNumber(); supplier.netWeight = new Decimal(supplier.grossWeight || 0) .sub(usedBoxesWeight) .sub(extraUsedBoxesWeight) .toNumber(); previousTotalWeight = supplier.totalWeight; supplier.invoiceAmount = new Decimal(supplier.netWeight || 0) .mul(supplier.purchasePrice || 0) .toNumber(); continue; } // 计算额外配送的纸箱总重量(斤) const extraBoxesWeight = this.calculateBoxesTotalWeight( supplier.orderPackageList || [], "EXTRA", ); // 计算车上剩余纸箱(斤) const remainingBoxesWeight = this.calculateBoxesTotalWeight( supplier.orderPackageList || [], "REMAIN", ); if (isFirstSupplier && isLastSupplier) { // 既是第一个也是最后一个瓜农(单个瓜农情况)- 优先使用最后一个瓜农算法 // 净重 = (总磅 - 空磅) * 2 + 剩余空箱子重量 - 已使用额外纸箱重量 supplier.netWeight = new Decimal(supplier.totalWeight || 0) .sub(initialEmptyWeight) .mul(2) .add(remainingBoxesWeight) .sub(extraUsedBoxesWeight) .toNumber(); // 毛重 = 净重 + 本次使用纸箱重量 supplier.grossWeight = new Decimal(supplier.netWeight || 0) .add(usedBoxesWeight) .toNumber(); } else if (isLastSupplier) { // 最后一个农户(根据isLast标识判断) // 净重 = (总磅 - 前一个总磅) * 2 + 剩余空箱子重量 - 已使用额外纸箱重量 supplier.netWeight = new Decimal(supplier.totalWeight || 0) .sub(previousTotalWeight) .mul(2) .add(remainingBoxesWeight) .sub(extraUsedBoxesWeight) .toNumber(); // 毛重 = 净重 + 本次使用纸箱重量 supplier.grossWeight = new Decimal(supplier.netWeight || 0) .add(usedBoxesWeight) .toNumber(); } else if (isFirstSupplier) { // 第一个农户(但不是最后一个) // 净重 = (总磅 - 空磅) * 2 - 额外纸箱重量 supplier.netWeight = new Decimal(supplier.totalWeight || 0) .sub(initialEmptyWeight) .mul(2) .sub(extraBoxesWeight) .toNumber(); // 毛重 = 净重 + 本次使用纸箱重量 supplier.grossWeight = new Decimal(supplier.netWeight || 0) .add(usedBoxesWeight) .toNumber(); } else { // 中间农户 // 净重 = (总磅 - 前一个总磅) * 2 - 额外纸箱重量 supplier.netWeight = new Decimal(supplier.totalWeight || 0) .sub(previousTotalWeight) .mul(2) .sub(extraBoxesWeight) .toNumber(); // 毛重 = 净重 + 本次使用纸箱重量 supplier.grossWeight = new Decimal(supplier.netWeight || 0) .add(usedBoxesWeight) .toNumber(); } previousTotalWeight = supplier.totalWeight || 0; supplier.invoiceAmount = new Decimal(supplier.netWeight || 0) .mul(supplier.purchasePrice || 0) .toNumber(); } return this.suppliers; } /** * 计算纸箱的总重量(斤) * @param {Array} orderPackageList - 包装信息列表 * @param {string} boxType - 箱子类型 ('USED' 或 'EXTRA',不传则计算所有) * @returns {number} 总重量(斤) */ private calculateBoxesTotalWeight( orderPackageList: BusinessAPI.OrderPackage[], boxType?: any, ): number { if (!orderPackageList) return 0; let filteredPackages = orderPackageList; if (boxType) { filteredPackages = orderPackageList.filter( (pkg) => pkg.boxType === boxType, ); } return filteredPackages.reduce((sum, pkg) => { // 纸箱重量单位是斤,直接使用 const boxWeight = pkg.boxProductWeight || 0; return new Decimal(sum) .add(new Decimal(pkg.boxCount || 0).mul(boxWeight)) .toNumber(); }, 0); } }