mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-03 12:19:12 +00:00
bom exploded items grouped by items
This commit is contained in:
@@ -270,18 +270,23 @@ class DocType:
|
||||
if b[0]:
|
||||
bom_list.append(b[0])
|
||||
|
||||
def update_cost_and_exploded_items(self):
|
||||
bom_list = self.traverse_tree()
|
||||
def update_cost_and_exploded_items(self, bom_list=[]):
|
||||
bom_list = self.traverse_tree(bom_list)
|
||||
for bom in bom_list:
|
||||
bom_obj = get_obj("BOM", bom, with_children=1)
|
||||
bom_obj.on_update()
|
||||
|
||||
def traverse_tree(self):
|
||||
return bom_list
|
||||
|
||||
def traverse_tree(self, bom_list=[]):
|
||||
def _get_children(bom_no):
|
||||
return [cstr(d[0]) for d in webnotes.conn.sql("""select bom_no from `tabBOM Item`
|
||||
where parent = %s and ifnull(bom_no, '') != ''""", bom_no)]
|
||||
|
||||
bom_list, count = [self.doc.name], 0
|
||||
count = 0
|
||||
if self.doc.name not in bom_list:
|
||||
bom_list.append(self.doc.name)
|
||||
|
||||
while(count < len(bom_list)):
|
||||
for child_bom in _get_children(bom_list[count]):
|
||||
if child_bom not in bom_list:
|
||||
@@ -325,52 +330,50 @@ class DocType:
|
||||
|
||||
def get_exploded_items(self):
|
||||
""" Get all raw materials including items from child bom"""
|
||||
self.cur_exploded_items = []
|
||||
self.cur_exploded_items = {}
|
||||
for d in getlist(self.doclist, 'bom_materials'):
|
||||
if d.bom_no:
|
||||
self.get_child_exploded_items(d.bom_no, d.qty)
|
||||
else:
|
||||
self.cur_exploded_items.append({
|
||||
self.add_to_cur_exploded_items(webnotes._dict({
|
||||
'item_code' : d.item_code,
|
||||
'description' : d.description,
|
||||
'stock_uom' : d.stock_uom,
|
||||
'qty' : flt(d.qty),
|
||||
'rate' : flt(d.rate),
|
||||
'amount' : flt(d.amount),
|
||||
'parent_bom' : d.parent,
|
||||
'mat_detail_no' : d.name,
|
||||
'qty_consumed_per_unit' : flt(d.qty_consumed_per_unit)
|
||||
})
|
||||
'rate' : flt(d.rate),
|
||||
}))
|
||||
|
||||
def add_to_cur_exploded_items(self, args):
|
||||
if self.cur_exploded_items.get(args.item_code):
|
||||
self.cur_exploded_items[args.item_code]["qty"] += args.qty
|
||||
else:
|
||||
self.cur_exploded_items[args.item_code] = args
|
||||
|
||||
def get_child_exploded_items(self, bom_no, qty):
|
||||
""" Add all items from Flat BOM of child BOM"""
|
||||
|
||||
child_fb_items = sql("""select item_code, description, stock_uom, qty, rate,
|
||||
amount, parent_bom, mat_detail_no, qty_consumed_per_unit
|
||||
from `tabBOM Explosion Item` where parent = '%s' and docstatus = 1""" %
|
||||
bom_no, as_dict = 1)
|
||||
qty_consumed_per_unit from `tabBOM Explosion Item`
|
||||
where parent = %s and docstatus = 1""", bom_no, as_dict = 1)
|
||||
|
||||
for d in child_fb_items:
|
||||
self.cur_exploded_items.append({
|
||||
self.add_to_cur_exploded_items(webnotes._dict({
|
||||
'item_code' : d['item_code'],
|
||||
'description' : d['description'],
|
||||
'stock_uom' : d['stock_uom'],
|
||||
'qty' : flt(d['qty_consumed_per_unit'])*qty,
|
||||
'rate' : flt(d['rate']),
|
||||
'amount' : flt(d['amount']),
|
||||
'parent_bom' : d['parent_bom'],
|
||||
'mat_detail_no' : d['mat_detail_no'],
|
||||
'qty_consumed_per_unit' : flt(d['qty_consumed_per_unit'])*qty/flt(self.doc.quantity)
|
||||
|
||||
})
|
||||
'rate' : flt(d['rate']),
|
||||
}))
|
||||
|
||||
def add_exploded_items(self):
|
||||
"Add items to Flat BOM table"
|
||||
self.doclist = self.doc.clear_table(self.doclist, 'flat_bom_details', 1)
|
||||
for d in self.cur_exploded_items:
|
||||
ch = addchild(self.doc, 'flat_bom_details', 'BOM Explosion Item',
|
||||
self.doclist)
|
||||
for i in d.keys():
|
||||
ch.fields[i] = d[i]
|
||||
ch = addchild(self.doc, 'flat_bom_details', 'BOM Explosion Item', self.doclist)
|
||||
for i in self.cur_exploded_items[d].keys():
|
||||
ch.fields[i] = self.cur_exploded_items[d][i]
|
||||
ch.amount = flt(ch.qty) * flt(ch.rate)
|
||||
ch.qty_consumed_per_unit = flt(ch.qty) / flt(self.doc.quantity)
|
||||
ch.docstatus = self.doc.docstatus
|
||||
ch.save(1)
|
||||
|
||||
|
||||
@@ -48,134 +48,4 @@ test_records = [
|
||||
"stock_uom": "No."
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
|
||||
# import webnotes.model
|
||||
# from webnotes.utils import nowdate, flt
|
||||
# from accounts.utils import get_fiscal_year
|
||||
# from webnotes.model.doclist import DocList
|
||||
# import copy
|
||||
#
|
||||
# company = webnotes.conn.get_default("company")
|
||||
#
|
||||
#
|
||||
# def load_data():
|
||||
#
|
||||
# # create default warehouse
|
||||
# if not webnotes.conn.exists("Warehouse", "Default Warehouse"):
|
||||
# webnotes.insert({"doctype": "Warehouse",
|
||||
# "warehouse_name": "Default Warehouse",
|
||||
# "warehouse_type": "Stores"})
|
||||
#
|
||||
# # create UOM: Nos.
|
||||
# if not webnotes.conn.exists("UOM", "Nos"):
|
||||
# webnotes.insert({"doctype": "UOM", "uom_name": "Nos"})
|
||||
#
|
||||
# from webnotes.tests import insert_test_data
|
||||
# # create item groups and items
|
||||
# insert_test_data("Item Group",
|
||||
# sort_fn=lambda ig: (ig[0].get('parent_item_group'), ig[0].get('name')))
|
||||
# insert_test_data("Item")
|
||||
#
|
||||
# base_bom_fg = [
|
||||
# {"doctype": "BOM", "item": "Android Jack D", "quantity": 1,
|
||||
# "is_active": "Yes", "is_default": 1, "uom": "Nos"},
|
||||
# {"doctype": "BOM Operation", "operation_no": 1, "parentfield": "bom_operations",
|
||||
# "opn_description": "Development", "hour_rate": 10, "time_in_mins": 90},
|
||||
# {"doctype": "BOM Item", "item_code": "Home Desktop 300", "operation_no": 1,
|
||||
# "qty": 2, "rate": 20, "stock_uom": "Nos", "parentfield": "bom_materials"},
|
||||
# {"doctype": "BOM Item", "item_code": "Home Desktop 100", "operation_no": 1,
|
||||
# "qty": 1, "rate": 300, "stock_uom": "Nos", "parentfield": "bom_materials"},
|
||||
# {"doctype": "BOM Item", "item_code": "Nebula 7", "operation_no": 1,
|
||||
# "qty": 5, "stock_uom": "Nos", "parentfield": "bom_materials"},
|
||||
# ]
|
||||
#
|
||||
# base_bom_child = [
|
||||
# {"doctype": "BOM", "item": "Nebula 7", "quantity": 5,
|
||||
# "is_active": "Yes", "is_default": 1, "uom": "Nos"},
|
||||
# {"doctype": "BOM Operation", "operation_no": 1, "parentfield": "bom_operations",
|
||||
# "opn_description": "Development"},
|
||||
# {"doctype": "BOM Item", "item_code": "Android Jack S", "operation_no": 1,
|
||||
# "qty": 10, "stock_uom": "Nos", "parentfield": "bom_materials"}
|
||||
# ]
|
||||
#
|
||||
# base_bom_grandchild = [
|
||||
# {"doctype": "BOM", "item": "Android Jack S", "quantity": 1,
|
||||
# "is_active": "Yes", "is_default": 1, "uom": "Nos"},
|
||||
# {"doctype": "BOM Operation", "operation_no": 1, "parentfield": "bom_operations",
|
||||
# "opn_description": "Development"},
|
||||
# {"doctype": "BOM Item", "item_code": "Home Desktop 300", "operation_no": 1,
|
||||
# "qty": 3, "rate": 10, "stock_uom": "Nos", "parentfield": "bom_materials"}
|
||||
# ]
|
||||
#
|
||||
#
|
||||
# class TestPurchaseReceipt(unittest.TestCase):
|
||||
# def setUp(self):
|
||||
# webnotes.conn.begin()
|
||||
# load_data()
|
||||
#
|
||||
# def test_bom_validation(self):
|
||||
# # show throw error bacause bom no missing for sub-assembly item
|
||||
# bom_fg = copy.deepcopy(base_bom_fg)
|
||||
# self.assertRaises(webnotes.ValidationError, webnotes.insert, DocList(bom_fg))
|
||||
#
|
||||
# # main item is not a manufacturing item
|
||||
# bom_fg = copy.deepcopy(base_bom_fg)
|
||||
# bom_fg[0]["item"] = "Home Desktop 200"
|
||||
# bom_fg.pop(4)
|
||||
# self.assertRaises(webnotes.ValidationError, webnotes.insert, DocList(bom_fg))
|
||||
#
|
||||
# # operation no mentioed in material table not matching with operation table
|
||||
# bom_fg = copy.deepcopy(base_bom_fg)
|
||||
# bom_fg.pop(4)
|
||||
# bom_fg[2]["operation_no"] = 2
|
||||
# self.assertRaises(webnotes.ValidationError, webnotes.insert, DocList(bom_fg))
|
||||
#
|
||||
#
|
||||
# def test_bom(self):
|
||||
# gc_wrapper = webnotes.insert(DocList(base_bom_grandchild))
|
||||
# gc_wrapper.submit()
|
||||
#
|
||||
# bom_child = copy.deepcopy(base_bom_child)
|
||||
# bom_child[2]["bom_no"] = gc_wrapper.doc.name
|
||||
# child_wrapper = webnotes.insert(DocList(bom_child))
|
||||
# child_wrapper.submit()
|
||||
#
|
||||
# bom_fg = copy.deepcopy(base_bom_fg)
|
||||
# bom_fg[4]["bom_no"] = child_wrapper.doc.name
|
||||
# fg_wrapper = webnotes.insert(DocList(bom_fg))
|
||||
# fg_wrapper.load_from_db()
|
||||
#
|
||||
# self.check_bom_cost(fg_wrapper)
|
||||
#
|
||||
# self.check_flat_bom(fg_wrapper, child_wrapper, gc_wrapper)
|
||||
#
|
||||
# def check_bom_cost(self, fg_wrapper):
|
||||
# expected_values = {
|
||||
# "operating_cost": 15,
|
||||
# "raw_material_cost": 640,
|
||||
# "total_cost": 655
|
||||
# }
|
||||
#
|
||||
# for key in expected_values:
|
||||
# self.assertEqual(flt(expected_values[key]), flt(fg_wrapper.doc.fields.get(key)))
|
||||
#
|
||||
# def check_flat_bom(self, fg_wrapper, child_wrapper, gc_wrapper):
|
||||
# expected_flat_bom_items = {
|
||||
# ("Home Desktop 300", fg_wrapper.doc.name): (2, 20),
|
||||
# ("Home Desktop 100", fg_wrapper.doc.name): (1, 300),
|
||||
# ("Home Desktop 300", gc_wrapper.doc.name): (30, 10)
|
||||
# }
|
||||
#
|
||||
# self.assertEqual(len(fg_wrapper.doclist.get({"parentfield": "flat_bom_details"})), 3)
|
||||
#
|
||||
# for key, val in expected_flat_bom_items.items():
|
||||
# flat_bom = fg_wrapper.doclist.get({"parentfield": "flat_bom_details",
|
||||
# "item_code": key[0], "parent_bom": key[1]})[0]
|
||||
# self.assertEqual(val, (flat_bom.qty, flat_bom.rate))
|
||||
#
|
||||
#
|
||||
# def tearDown(self):
|
||||
# webnotes.conn.rollback()
|
||||
]
|
||||
Reference in New Issue
Block a user