先进先出(FIFO)是库存管理中广泛采用的核心原则,尤其在财务核算和成本计算中至关重要。本篇文章将介绍如何在PowerBI中实现基于先进先出规则的单批满足机制下的出库分配。
问题描述
计算每次出库时要使用的入库批次,在满足以下要求的情况下优先使用最早的入库批次:某产品对应的入库批次的入库数量在减去前面已分配给该产品的其它出库批次的出库数量后,要大于等于本次出库数量。
例如:1号入库10,2号入库20,3号入库30。然后5号要出库15,那么应该用2号的库存;然后6号要出库15,那么应该用3号的库存,而不是使用1号与2号剩余的库存之和。
具体问题如下图所示:
本案例的初始数据如下:
入库:
入库日期 | 入库批次 | 入库产品 | 入库数量 |
---|---|---|---|
2022年9月1日 | 1 | ID01 | 1000 |
2022年9月11日 | 2 | ID01 | 200 |
2022年10月10日 | 3 | ID01 | 200 |
2022年10月11日 | 4 | ID01 | 1000 |
出库:
出库日期 | 出库批次 | 出库产品 | 出库数量 |
---|---|---|---|
2022年9月10日 | 1 | ID01 | 500 |
2022年9月11日 | 2 | ID01 | 110 |
2022年9月30日 | 3 | ID01 | 200 |
2022年10月1日 | 4 | ID01 | 100 |
2022年10月10日 | 5 | ID01 | 200 |
2022年10月20日 | 6 | ID01 | 100 |
2022年10月21日 | 7 | ID01 | 300 |
2022年10月23日 | 8 | ID01 | 100 |
若需其它辅助表等,可自行创建并建模。
解题要点
在本案例中需要注意的是,查找某个产品出库时所用的入库批次时,必须要考虑到在前面出库的产品对库存的影响,否则计算结果将不正确,而这也是本案例的难点。
由于思路较复杂且难以描述,因此请直接从下文查看给出的示例答案来理解。
解决方案
首先,数据模型如下图所示:
然后,创建如下度量值:
入库批次 =
MAXX(
'出库',
VAR CurOutDate = '出库'[出库日期]
VAR CurOutPrd = '出库'[出库产品]
VAR CurOutCode = '出库'[出库批次]
VAR vTb1 =
FILTER(
ADDCOLUMNS(
GENERATE(
FILTER(ALL('出库'),'出库'[出库产品]=CurOutPrd && '出库'[出库批次]<=CurOutCode),
FILTER(ALL('入库'),'入库'[入库产品]=CurOutPrd && '入库'[入库日期]<=CurOutDate)
),
"IsMeet",
IF('入库'[入库数量]>='出库'[出库数量] && '入库'[入库日期]<='出库'[出库日期],1,0)
),
[IsMeet]>0
)
VAR vTb2 =
ADDCOLUMNS(
vTb1,
"CumOut",
VAR CurInCode = '入库'[入库批次]
VAR CurOutDate = '出库'[出库日期]
RETURN
SUMX(
FILTER(vTb1,'入库'[入库批次]=CurInCode && '出库'[出库日期]<=CurOutDate),
'出库'[出库数量]
)
)
VAR vTb3 =
ADDCOLUMNS(
vTb2,
"IsExtraOut",
VAR CurInCodeDate = '入库'[入库日期]
VAR CurOutCode = '出库'[出库批次]
VAR ActUseIncodeDate =
MAXX(
TOPN(1,FILTER(vTb2,'出库'[出库批次]=CurOutCode && '入库'[入库数量]>=[CumOut]),'入库'[入库日期],ASC),
'入库'[入库日期]
)
RETURN
IF(CurInCodeDate>ActUseInCodeDate && ActUseInCodeDate<>BLANK(),1,0)
)
VAR vTb4 =
ADDCOLUMNS(
vTb3,
"CumOut_PartCorrect",
VAR CurInCode = '入库'[入库批次]
VAR CurOutCodeDate = '出库'[出库日期]
VAR ExtraNum =
SUMX(
FILTER(vTb3,'入库'[入库批次]=CurInCode && '出库'[出库日期]<CurOutCodeDate && [IsExtraOut]=1),
'出库'[出库数量]
)
RETURN
[CumOut]-ExtraNum
)
VAR vTb5 =
ADDCOLUMNS(
vTb4,
"IsExtraOut_Correct",
VAR CurOutCode = '出库'[出库批次]
VAR CurInCode = '入库'[入库批次]
VAR CurOutCodeDate = '出库'[出库日期]
VAR CurInCodeDate = '入库'[入库日期]
VAR TempTable = FILTER(vTb4,'出库'[出库批次]=CurOutCode)
RETURN
IF(
MAXX(TempTable,[IsExtraOut])>0,
[IsExtraOut],
VAR ActUseIncodeDate =
MAXX(
TOPN(1,FILTER(TempTable,'入库'[入库数量]>=[CumOut_PartCorrect]),'入库'[入库日期],ASC),
'入库'[入库日期]
)
RETURN
IF(CurInCodeDate>ActUseInCodeDate && ActUseInCodeDate<>BLANK(),1,0)
)
)
VAR vTb6 =
ADDCOLUMNS(
vTb5,
"CumOut_Correct",
VAR CurInCode = '入库'[入库批次]
VAR CurOutCodeDate = '出库'[出库日期]
VAR ExtraNum =
SUMX(
FILTER(vTb5,'入库'[入库批次]=CurInCode && '出库'[出库日期]<CurOutCodeDate && [IsExtraOut_Correct]=1),
'出库'[出库数量]
)
RETURN
[CumOut]-ExtraNum
)
RETURN
MAXX(
TOPN(1,FILTER(vTb6,'出库'[出库批次]=CurOutCode && '入库'[入库数量]>=[CumOut_Correct]),'入库'[入库日期],ASC),
'入库'[入库批次]
)
)
然后创建一个矩阵,并将出库表中的所有字段作为行标签,再将上面的度量值放入矩阵的值字段即可,如下图所示:
总结
以上方法仅供参考,若有更优雅的解决方案,欢迎留言讨论,或者加入我们的技术交流群,一起享受这种思维碰撞的快乐吧!
PBI/DAX技术交流群(QQ):344353627