本帖最后由 cbtaja 于 2016-4-30 15:46 编辑
这样改更好:增加如下所示第50行,而把其后面原有的IF……Else……Then语句删除。
如果要适应10层级及以上的BOM表,请下载前面已经更新的附件。
这一个代码是适合层级以纯数值表示、自动适应工序增减的情况。
- Option Explicit
- Sub 计算()
- Dim r&, Arr, FL, i&, c&, j&, t#, total&, ttitle, TopId$, tmp1()
- Dim tmp0(0 To 20, 8 To 9) 'bom10级,每级求2个数据:本层相对上一层的用量系数、本层相对0层的用量系数
- t = Timer
- With Sheet1
- total = .Cells(Rows.Count, 7).End(xlUp).Row - 1
- FL = .Range("G2").Resize(total, 3) '工序费率
- ReDim tmp1(0 To 20, 11 + total To 14 + total * 2) 'bom10级,每级求total+4个数据:total道工序的工时汇总,以及:材料、人工、制费、总成本。
- End With
- r = Cells(Rows.Count, 1).End(xlUp).Row '取得Bom表的总行数
- Arr = [A2].Resize(r, 15 + total * 2) '获取BOM资料(无标题,多加一空行作结束依据)
- '先自上向下计算物料用量、上层母件
- For i = 1 To r - 1
- c = Arr(i, 1) '物料层级
- If c = 0 Then Erase tmp0: TopId = Arr(i, 2) '临时表重新清零,备用,并取得当前Bom树的树根
- tmp0(c, 9) = Arr(i, 6) * (1 + Arr(i, 7)) '当前第c层的用量(含损耗)
- If c > 0 Then tmp0(c, 8) = tmp0(c - 1, 8) * tmp0(c, 9) Else tmp0(c, 8) = tmp0(c, 9) 'c层bom总用量=上层总用量*本层用量
- Arr(i, 8) = tmp0(c, 8)
- Arr(i, 9) = tmp0(c, 9)
- Arr(i, 15 + total * 2) = TopId '顶层母件
- Next
- '再自下向上汇总工时、工费、成本
- For i = r - 1 To 1 Step -1
- c = Arr(i, 1) 'bom层级
- If c < Arr(i + 1, 1) Then '非采购件
- Arr(i, 3) = Empty
- For j = 1 To total '共total=6道工序,工时的源数据从第11列开始
- '本级总工时 = 本级工序用时+其所有子工序用时
- tmp1(c, j + 10 + total) = Arr(i, 8) * Arr(i, j + 10) + tmp1(c + 1, j + 10 + total) '工时汇总
- tmp1(c, 12 + total * 2) = tmp1(c, 12 + total * 2) + tmp1(c, j + 10 + total) * FL(j, 2) '人工费汇总
- tmp1(c, 13 + total * 2) = tmp1(c, 13 + total * 2) + tmp1(c, j + 10 + total) * FL(j, 3) '制费汇总
- Next
- Else '是采购件
- Arr(i, 3) = "是"
- End If
- tmp1(c, 11 + total * 2) = tmp1(c, 11 + total * 2) + Arr(i, 10) * Arr(i, 8) '材料成本=单价*采购数量+子件材料成本累计
- tmp1(c, 14 + total * 2) = tmp1(c, 11 + total * 2) + tmp1(c, 12 + total * 2) + tmp1(c, 13 + total * 2) '总成本=材料成本+人工费+制费
- For j = 11 + total To 14 + total * 2
- If c > 0 Then tmp1(c - 1, j) = tmp1(c - 1, j) + tmp1(c, j) '本层各项数量累计到其上一层
- Arr(i, j) = tmp1(c, j) '从临时表中获取结果
- tmp1(c, j) = Empty '临时的数据清空备用(避免本项数量被带入到下一个同层的项中)
- Next
- If Arr(i, 3) = "是" Then Arr(i, 11 + total * 2) = Empty '采购件的材料成本是存在的,但按楼主要求不显示(直接改为留空)
- Next
- [a1:e1].Offset(0, 10 + 2 * total).Value = Split("材料成本,单位人工,单位制费,总成本,顶层母件", ",")
- [A2].Resize(r - 1, 15 + total * 2) = Arr
- MsgBox "用时 " & Format(Timer - t, "0.0000") & " 秒!"
- End Sub
复制代码 下面这一个代码是适合层级以文本缩进宽度表示、自动适应工序增减的情况:
- Option Explicit
- Sub 计算()
- Dim r&, Arr, FL, i&, c&, j&, t#, total&, ttitle, TopId$, tmp1(), brr()
- Dim tmp0(0 To 9, 1 To 2) 'bom10级,每级求2个数据:上层母件、本层用量系数
- t = Timer
- With Sheet1
- total = .Cells(Rows.Count, 7).End(xlUp).Row - 1
- FL = .Range("G2").Resize(total, 3) '工序费率
- ReDim tmp1(0 To 9, 4 To 7 + total) 'bom10级,每级求total+4个数据:total道工序的工时汇总,以及:材料、人工、制费、总成本。
- End With
- r = Cells(Rows.Count, 1).End(xlUp).Row '取得Bom表的总行数
- Arr = [A2].Resize(r, 7 + total) '获取BOM资料(无标题,多加一空行作结束依据)
- ReDim brr(0 To r, 1 To 8 + total) '预定义存放结果的二维数组
- '先自上向下计算物料用量、上层母件
- For i = 1 To r - 1
- c = Len(Arr(i, 1)) - 1 '物料层级
- If c < 0 Then Exit For
- If c = 0 Then Erase tmp0: TopId = Arr(i, 2) '临时表重新清零,备用,并取得当前Bom树的树根
- tmp0(c, 1) = Arr(i, 5) * (1 + Arr(i, 6)) '当前第c层的用量(含损耗)
- If c > 0 Then tmp0(c, 2) = tmp0(c - 1, 2) * tmp0(c, 1) Else tmp0(c, 2) = tmp0(c, 1) 'c层bom总用量=上层总用量*本层用量
- brr(i, 1) = tmp0(c, 1)
- brr(i, 2) = tmp0(c, 2)
- brr(i, 8 + total) = TopId '顶层母件
- Next
- '再自下向上汇总工时、工费、成本
- For i = r - 1 To 1 Step -1
- c = Len(Arr(i, 1)) - 1 'bom层级
- If Len(Arr(i, 1)) < Len(Arr(i + 1, 1)) Then '非采购件
- Arr(i, 3) = Empty
- For j = 1 To total '共total=6道工序,工时的源数据从第11列开始
- '本级总工时 = 本级工序用时+其所有子工序用时
- tmp1(c, 3 + j) = brr(i, 2) * Arr(i, 7 + j) + tmp1(c + 1, 3 + j) '工时汇总
- tmp1(c, 5 + total) = tmp1(c, 5 + total) + tmp1(c, 3 + j) * FL(j, 2) '人工费汇总
- tmp1(c, 6 + total) = tmp1(c, 6 + total) + tmp1(c, 3 + j) * FL(j, 3) '制费汇总
- Next
- Else '是采购件
- brr(i, 3) = "是"
- End If
- tmp1(c, 4 + total) = tmp1(c, 4 + total) + Arr(i, 7) * brr(i, 2) '材料成本=单价*采购数量+子件材料成本累计
- tmp1(c, 7 + total) = tmp1(c, 4 + total) + tmp1(c, 5 + total) + tmp1(c, 6 + total) '总成本=材料成本+人工费+制费
- For j = 4 To 7 + total
- If c > 0 Then tmp1(c - 1, j) = tmp1(c - 1, j) + tmp1(c, j) '本层各项数量累计到其上一层
- brr(i, j) = tmp1(c, j) '从临时表中获取结果
- tmp1(c, j) = Empty '临时表中数据清空备用。(避免把本物料的数量带入到同一层级的下一个物料的统计数量中)
- Next
- If brr(i, 3) = "是" Then brr(i, 4 + total) = Empty '采购件的材料成本留空
- Next
- brr(0, 1) = "用量(含损耗)"
- brr(0, 2) = "对应0层成品用量"
- brr(0, 3) = "采购件与否"
- For j = 1 To total
- Range("A1").Offset(0, 6 + j) = FL(j, 1) & "工时"
- brr(0, 3 + j) = Replace(FL(j, 1), "费率", "") & "工时汇总"
- Next
- ttitle = Split("材料成本,单位人工,单位制费,总成本,顶层母件", ",")
- For j = 0 To UBound(ttitle)
- brr(0, 4 + total + j) = ttitle(j)
- Next
- UsedRange.Offset(0, 7 + total).ClearContents
- [a1].Offset(0, 7 + total).Resize(r, 8 + total) = brr
- MsgBox "用时 " & Format(Timer - t, "0.0000") & " 秒!"
- End Sub
复制代码
|