Excel以先进先出为基础计算销售价格

时间:2018-05-01 08:40:40

标签: excel excel-vba excel-formula vba

我有多个MaterialNo,我现在只给出一个材料No的例子。有一个类型列,告诉我们是否在特定日期买了或卖了材料。我已根据材料编号和日期对数据进行了排序。现在我想实施 FIFO逻辑来计算已售物料的总价和单价。我现在已经在Excel中手动计算了。

MaterialNo  Type    Date    Qty   Price   Balance-Quantity **TotalPrice**   **UnitPrice**
XXXXXX     Buy      03-2017 1250    79.99998042 1250    99999.97552     79.99998042
XXXXXX     Sell     03-2017   20                1230    -1599.999608    -79.99998042
XXXXXX     Buy      04-2017 2200    79.99999667 3430    175999.9927      79.99999667
XXXXXX     Sell     04-2017 2375                1055    -189999.9721    -79.99998825
XXXXXX     Buy      05-2017  997    79.9999625  2052    79759.96261      79.9999625
XXXXXX     Sell     05-2017 2055                  -3    -164399.9229    -79.9999625
XXXXXX     Buy      06-2017 4749    79.99996153 4746    379919.8173      79.99996153
XXXXXX     Sell     06-2017 3550                1196    -283999.8669    -79.9999625
XXXXXX     Buy      07-2017  894    80.00001111 2090    71520.00993      80.00001111
XXXXXX     Sell     07-2017 2100                 -10    -167999.9213    -79.9999625
XXXXXX     Buy      08-2017 2495    137.210024  2485    342339.0098      137.210024
XXXXXX     Sell     08-2017 1900                 585    -260699.0455    -137.210024
XXXXXX     Buy      09-2017 2000    156.28      2585    312560           156.28
XXXXXX     Sell     09-2017 2652                 -67    -414454.56      -156.28
XXXXXX     Buy      10-2017  596    156.2805875  529    93143.23015      156.2805875
XXXXXX     Sell     10-2017  476                  53    -74389.55965    -156.2805875
XXXXXX     Buy      11-2017 5600    156.2800066 5653    875168.0371      156.2800066
XXXXXX     Sell     11-2017 1111                4542    -173627.0874    -156.2800066
XXXXXX     Buy      12-2017 1118    156.2800863 5660    174721.1365      156.2800863
XXXXXX     Sell     12-2017 1222                4438    -190974.2654    -156.2800863
XXXXXX     Buy      01-2018 2162    156.28      6600    337877.36        156.28
XXXXXX     Sell     01-2018 4188                2412    -654500.64      -156.28
XXXXXX     Buy      02-2018  792    156.2796819 3204    123773.5081      156.2796819
XXXXXX     Sell     02-2018 2602                 602    -406639.7323    -156.2796819
XXXXXX     Buy      03-2018  400    156.28      1002    62512            156.28
XXXXXX     Sell     03-2018  560                 442    -87516.8        -156.28

没有负余额的另一种情景

MaterialNo  Type    Date    Qty Price   Balance Quantity    TotalPrice  Unit Price
SSSSSSSS    Buy 06-2017 30  140.8   30  4224    140.8
SSSSSSSS    Sell    06-2017 30      0   -4224   -140.8
SSSSSSSS    Buy 07-2017 150 140.8   150 21120   140.8
SSSSSSSS    Sell    07-2017 16      134 -2252.8 -140.8
SSSSSSSS    Sell    08-2017 22      112 -3097.6 -140.8
SSSSSSSS    Buy 09-2017 150 207.4399333 262 31115.99    207.4399333
SSSSSSSS    Sell    09-2017 112     150 -15769.6    -140.8
SSSSSSSS    Buy 10-2017 250 207.4399    400 51859.975   207.4399
SSSSSSSS    Sell    10-2017 63      337 -13068.7158 -207.4399333
SSSSSSSS    Buy 11-2017 3260    207.4399991 3597    676254.3969 207.4399991
SSSSSSSS    Sell    11-2017 2655        942 -550753.167 -207.4399876
SSSSSSSS    Buy 12-2017 300 207.44  1242    62232   207.44
SSSSSSSS    Sell    12-2017 556     686 -115336.6395    -207.4399991
SSSSSSSS    Buy 01-2018 428 207.44002   1114    88784.32856 207.44002
SSSSSSSS    Sell    01-2018 448     666 -92933.11964    -207.4399992
SSSSSSSS    Buy 02-2018 -9  207.44  657 -1866.96    207.44
SSSSSSSS    Sell    02-2018 332     325 -68870.08188    -207.4400057
SSSSSSSS    Buy 03-2018 699 207.43997   1024    145000.539  207.43997
SSSSSSSS    Sell    03-2018 341     683 -70737.0462 -207.4400182

有一点需要注意 - 当余额数量为负数时,它应根据上次购买的价格计算已售物料的总价。如有任何问题,请告诉我。

这是我试过的功能。

Dim prc As Double
Function fifoval(q As Range, Optional details As String) As Variant
Application.Volatile (True)
    Dim i As Integer
    Dim qstr As String
    Dim pstr As String
    Dim cqty As Integer
    Dim qty As Integer
    Dim ctr As Integer
    Dim dstr As String
    Dim amt As Double
    'Stop
    For i = 2 To q.Row - 1
        If Cells(i, 1) = Cells(q.Row, 1) And IsNumeric(Cells(i, 7)) Then
            Select Case Cells(i, 2)
                Case "Buy"
                    qstr = qstr & Cells(i, 4) & ","
                    pstr = pstr & Cells(i, 5) & ","
                Case "Sell"
                    qty = Cells(i, 4)
                    Do While qty > 0

                        cqty = Val(qstr)
                        If (cqty = 0) Then
                            fifoval = "Not enough balance"
                            Exit Function
                        End If
                        Select Case True
                            Case cqty = qty
                                qstr = Replace(qstr, cqty & ",", "", , 1)
                                pstr = Replace(pstr, Val(pstr) & ",", "", , 1)
                                qty = qty - cqty
                            Case cqty > qty
                                qstr = Replace(qstr, cqty, cqty - qty, , 1)
                                qty = 0
                            Case cqty < qty
                                qstr = Replace(qstr, cqty & ",", "", , 1)
                                pstr = Replace(pstr, Val(pstr) & ",", "", , 1)
                                qty = qty - cqty
                            Case cqty = 0
                                fifoval = "Not enough balance"
                                Exit Function
                        End Select
                        ctr = ctr + 1
                        If ctr > 1000 Then End: Stop
                    Loop
            End Select
        End If
    Next i
    qty = Cells(q.Row, 4)
    Do While qty > 0

        cqty = Val(qstr)
        If (cqty = 0) Then
            fifoval = "Not enough balance"
            Exit Function
        End If
        prc = Val(pstr)
        Select Case True
            Case cqty = qty
                dstr = dstr & IIf(dstr = "", "", " + ") & qty & " * " & prc
                amt = amt + qty * prc
                qstr = Replace(qstr, cqty & ",", "", , 1)
                pstr = Replace(pstr, Val(pstr) & ",", "", , 1)
                qty = qty - cqty
            Case cqty > qty
                dstr = dstr & IIf(dstr = "", "", " + ") & qty & " * " & prc
                amt = amt + qty * prc
                qstr = Replace(qstr, cqty, cqty - qty, , 1)
                qty = 0
            Case cqty < qty
                dstr = dstr & IIf(dstr = "", "", " + ") & cqty & " * " & prc
                amt = amt + cqty * prc
                qstr = Replace(qstr, cqty & ",", "", , 1)
                pstr = Replace(pstr, Val(pstr) & ",", "", , 1)
                qty = qty - cqty
        End Select
        ctr = ctr + 1
        If ctr > 1000 Then End: Stop
    Loop
    If details = "" Then
        fifoval = amt
    Else
        fifoval = dstr
    End If
End Function

1 个答案:

答案 0 :(得分:0)

我需要做同样的事情,并且没有VBA,我想出了一个需要创建一些额外列的解决方案。

在我的示例中,第367行的列如下。

数据:

  • D列:日期。
  • E列:产品名称。
  • 第一列:数量。如果是出售,则数量为负,因此,如果您要使用此公式来提供出售时的负数量,则需要创建一个新列。
  • J列:价格。
  • 第N栏:汇率(我想您不需要)。

公式:

  • AA列:行和操作日期中当前产品的数量:

    =+IF(I367="","",MAX(0,MIN(I367,SUMIF(E:E,E367,I:I)- SUMIFS(I:I,D:D,">"&D367,E:E,E367,I:I,">0"))))

  • AB列:行和操作日期中当前产品金额的成本价:

    =IF(AA367="","",ROUND(AA367*N367*J367,2))

  • 列AC:在操作日期已售出产品的成本价:

    =IF(I367="","",IF(I367>0,ROUND((I367-AA367)*N367*J367,2),0))

  • AD列:在操作日期已售出产品的售价的销售价格: =+IF(I367<0,ROUND(-I367*J367*N367,2),"")

一旦有了这些列,您只需要按列进行总计:

  • 总列AB:您已存储的所有物料的成本。
  • 总列AC:购买您已经出售的材料所花的所有钱。
  • 总列AD:您已售出的所有产品的收入。

您需要重新构造公式以匹配您的列,但除此之外不行。