一个关于计算分批进货按照先进先出规则的商品成本统计算法(js版本)

场景:

比如说一个商家售卖A,B两款产品,A产品售价50元/件,B产品售价100元/件。

  • 商家第一批入库A产品10件,进货成本为20元/件,B产品20件,进货成本为50元/件。
  • 商家第二批入库A产品20件,进货成本为30元/件,B产品30件,进货成本为60元/件。

现在有位顾客买了5件A产品,5件B产品,经查验都是属于第一批进货,所以订单的成本很容易计算 $20x5+$50x5 = $350元

假如顾客买了15件产品A,30件产品B呢?

这时候的订单进货价格就要这样算:$20x10+$30x5+$50x20+$60x10 = $1950元

注:因为在此我们想要讨论先进先出的算法,不去计算商品的加权平均值,加权平均值的算法即是sum(每批的进货量x每批的进货价格)/ 总的进货量


上面的算法是一种,但是这种计算方式我们就要算出用户的下单数量是处于哪个进货批次,并且每个进货批次里面,该笔订单占了多少数量,涉及到的进货区间比较多的情况下就非常复杂。

现在我们换一种方式思考:

首先,我们取得下单商品的历史销售数据。
其次,我们构造历史下单数据和当前下单数据的整合(在历史下单数量上累加当前订单的下单数量)
然后我们得到两个区间,第一个是历史订单所处进货批次的最高区间,第二个是整合数据的所处批次的最高区间。

我们计算得到整合数据的所处最高批次区间的商品进货价
我们计算得到历史数据所处批次的商品进货价

计算出所有订单的成本价格-之前的订单成本价格=即是本次的订单基本价格

	 //本次下单的商品id:商品数量
    const orderInfo = {
        '1': 1,
        '3': 2,
        '5': 2
    }
    //历史商品销售数据
    const saleHistory = [{
            goodsId: 3,
            saleNum: 1
        },
        {
            goodsId: 1,
            saleNum: 1
        },
        {
            goodsId: 5,
            saleNum: 99
        }
    ]
    //历史商品进货记录
    const purchaseHistory = [{
            goods_id: 3,
            purchase_num: 200,
            purchase_price: 50
        },
        {
            goods_id: 5,
            purchase_num: 100,
            purchase_price: 10
        },
        {
            goods_id: 1,
            purchase_num: 100,
            purchase_price: 2
        },
    ]
    let total = 0  //该笔订单的进货成本
    let saleTotal = 0 //存储之前的订货量价格
    let saleObj = {}
    //如果某些商品没有销售过 也将信息写入历史销售信息对象 便于观察
    Object.keys(orderInfo).map(item => {
        saleObj[item] = 0
    })
    //构造产品的当笔订单与历史订单记录之和对象  用于比较商品数量使用
    const newProduceObj = Object.assign({}, orderInfo)
    saleHistory.map(item => {
        saleObj[item.goodsId] = item.saleNum
        newProduceObj[item.goodsId] = Number(newProduceObj[item.goodsId]) + Number(item.saleNum)
    })
    console.log('构造出来的商品历史销售信息', saleObj)
    //先将历史进货记录根据id分为 进货数量的数组 和对应进货价格
    let purchaseList = {}
    purchaseHistory.forEach((item, index) => {
        if (!purchaseList[item.goods_id]) {
            // 先进行构造
            purchaseList[item.goods_id] = {}
            purchaseList[item.goods_id].numArr = []
            purchaseList[item.goods_id].priceArr = []
        }
        //追加数量和价格
        purchaseList[item.goods_id].numArr.push(item.purchase_num)
        purchaseList[item.goods_id].priceArr.push(item.purchase_price)
    })
    console.log('构造出来的商品购买历史记录信息', purchaseList)
    console.log('历史订单销售信息和当前订单销售信息组合:newProduceObj', newProduceObj)
    //根据历史订单信息 返回当笔订单的购买数量属于哪个阶段
    Object.keys(purchaseList).map((item, index) => {
        //构造数量成后一位等于值加上前一位数
        let numArr = purchaseList[item].numArr
        let prices = purchaseList[item].priceArr
        let nums = []
        for (let i = 0; i < numArr.length; i++) {
            let tmp = numArr.slice(0, i + 1)
            nums.push(tmp.reduce((p, c) => p + c))
            // 保证值输出一次
            if (i == numArr.length - 1) {
                console.log('商品', index + 1, '的组合进价数组', nums)
            }
        }
        // 历史订单后所在的进价区间
        let sindex = nums.findIndex(function (value, index, arr) {
            return saleObj[item] <= value
        })
        let eindex = nums.findIndex(function (value, index, arr) {
            return newProduceObj[item] <= value
        })
        // console.log('历史订单价格区间', sindex)
        // console.log('当前订单最高价格区间', eindex)
        // 计算正常total价格
        for (let i = 0; i <= eindex; i++) {
            total += numArr[i] * prices[i]
        }
        console.log('计算出的最高区间成本', total)
        const dnum = newProduceObj[item] - nums[Math.max(0, (eindex))]
        total += dnum * prices[eindex]
        console.log('加上历史销售数据后跟最高区间的商品数量的差值', dnum)
        //计算之前库存的成本
        for (let i = 0; i <= sindex; i++) {
            saleTotal += numArr[i] * prices[i]
        }
        const bnum = saleObj[item] - nums[Math.max(0, (sindex))]
        console.log('历史订单区间的商品数量的差值', bnum)
        saleTotal += bnum * prices[sindex]
        console.log('saleTotal', saleTotal)
    })
    total -= saleTotal
    console.log(Number(total.toFixed(2)))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值