bom code cleanup

This commit is contained in:
Nabin Hait 2012-12-13 11:10:17 +05:30
parent 33e0b5581e
commit 4301dadaab

View File

@ -60,7 +60,6 @@ class DocType:
return ret return ret
def get_workstation_details(self,workstation): def get_workstation_details(self,workstation):
""" Fetch hour rate from workstation master""" """ Fetch hour rate from workstation master"""
@ -83,7 +82,6 @@ class DocType:
msgprint("Item %s does not exist in system" % item[0]['item_code'], raise_exception = 1) msgprint("Item %s does not exist in system" % item[0]['item_code'], raise_exception = 1)
def get_bom_material_detail(self): def get_bom_material_detail(self):
""" Get raw material details like uom, desc and rate""" """ Get raw material details like uom, desc and rate"""
@ -146,7 +144,6 @@ class DocType:
return rate and flt(sum(rate))/len(rate) or 0 return rate and flt(sum(rate))/len(rate) or 0
def manage_default_bom(self): def manage_default_bom(self):
""" Uncheck others if current one is selected as default, """ Uncheck others if current one is selected as default,
update default bom in item master update default bom in item master
@ -156,68 +153,16 @@ class DocType:
sql("update `tabBOM` set is_default = 0 where name != %s and item=%s", sql("update `tabBOM` set is_default = 0 where name != %s and item=%s",
(self.doc.name, self.doc.item)) (self.doc.name, self.doc.item))
# update default bom in Item Master webnotes.conn.set_value("Item", self.doc.item, "default_bom", self.doc.name)
sql("update `tabItem` set default_bom = %s where name = %s",
(self.doc.name, self.doc.item))
else: else:
sql("update `tabItem` set default_bom = '' where name = %s and default_bom = %s", sql("update `tabItem` set default_bom = '' where name = %s and default_bom = %s",
(self.doc.item, self.doc.name)) (self.doc.item, self.doc.name))
def manage_active_bom(self): def validate(self):
""" Manage active/inactive """ self.validate_main_item()
if self.doc.is_active == 'Yes': self.validate_operations()
self.validate() self.validate_materials()
else:
self.check_active_parent_boms()
def check_active_parent_boms(self):
""" Check parent BOM before making it inactive """
act_pbom = sql("""select distinct t1.parent from `tabBOM Item` t1, `tabBOM` t2
where t1.bom_no =%s and t2.name = t1.parent and t2.is_active = 'Yes'
and t2.docstatus = 1 and t1.docstatus =1 """, self.doc.name)
if act_pbom and act_pbom[0][0]:
msgprint("""Sorry cannot inactivate as BOM: %s is child
of one or many other active parent BOMs""" % self.doc.name, raise_exception=1)
def calculate_cost(self):
"""Calculate bom totals"""
self.calculate_op_cost()
self.calculate_rm_cost()
self.doc.total_cost = self.doc.raw_material_cost + self.doc.operating_cost
self.doc.modified = now()
self.doc.save()
def calculate_op_cost(self):
"""Update workstation rate and calculates totals"""
total_op_cost = 0
for d in getlist(self.doclist, 'bom_operations'):
if d.hour_rate and d.time_in_mins:
d.operating_cost = flt(d.hour_rate) * flt(d.time_in_mins) / 60.0
d.save()
total_op_cost += flt(d.operating_cost)
self.doc.operating_cost = total_op_cost
def calculate_rm_cost(self):
"""Fetch RM rate as per today's valuation rate and calculate totals"""
total_rm_cost = 0
for d in getlist(self.doclist, 'bom_materials'):
if d.bom_no:
d.rate = self.get_bom_unitcost(d.bom_no)
d.amount = flt(d.rate) * flt(d.qty)
d.qty_consumed_per_unit = flt(d.qty) / flt(self.doc.quantity)
d.save()
total_rm_cost += d.amount
self.doc.raw_material_cost = total_rm_cost
def validate_main_item(self): def validate_main_item(self):
""" Validate main FG item""" """ Validate main FG item"""
@ -283,7 +228,6 @@ class DocType:
msgprint("""Incorrect BOM No: %s against item: %s at row no: %s. msgprint("""Incorrect BOM No: %s against item: %s at row no: %s.
It may be inactive or cancelled or for some other item.""" % It may be inactive or cancelled or for some other item.""" %
(bom_no, item, idx), raise_exception = 1) (bom_no, item, idx), raise_exception = 1)
def check_if_item_repeated(self, item, op, check_list): def check_if_item_repeated(self, item, op, check_list):
@ -294,10 +238,9 @@ class DocType:
check_list.append([cstr(item), cstr(op)]) check_list.append([cstr(item), cstr(op)])
def validate(self): def on_update(self):
self.validate_main_item() self.check_recursion()
self.validate_operations() self.update_cost_and_exploded_items()
self.validate_materials()
def check_recursion(self): def check_recursion(self):
""" Check whether recursion occurs in any bom""" """ Check whether recursion occurs in any bom"""
@ -315,27 +258,91 @@ class DocType:
""" % (cstr(b), cstr(d[2]), self.doc.name), raise_exception = 1) """ % (cstr(b), cstr(d[2]), self.doc.name), raise_exception = 1)
if b[0]: if b[0]:
bom_list.append(b[0]) bom_list.append(b[0])
def update_cost_and_exploded_items(self, calculate_cost=True):
bom_list = self.traverse_tree()
bom_list.reverse()
for bom in bom_list:
bom_obj = get_obj("BOM", bom, with_children=1)
if calculate_cost:
bom_obj.calculate_cost()
bom_obj.update_flat_bom()
def traverse_tree(self):
def _get_childs(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
while(count < len(bom_list)):
for child_bom in _get_childs(bom_list[count]):
if child_bom not in bom_list:
bom_list.append(child_bom)
count += 1
return bom_list
def calculate_cost(self):
"""Calculate bom totals"""
self.calculate_op_cost()
self.calculate_rm_cost()
self.doc.total_cost = self.doc.raw_material_cost + self.doc.operating_cost
self.doc.modified = now()
self.doc.save()
def on_update(self): def calculate_op_cost(self):
self.check_recursion() """Update workstation rate and calculates totals"""
self.update_cost_by_traversing() total_op_cost = 0
self.update_flat_bom_by_traversing() for d in getlist(self.doclist, 'bom_operations'):
if d.hour_rate and d.time_in_mins:
d.operating_cost = flt(d.hour_rate) * flt(d.time_in_mins) / 60.0
d.save()
total_op_cost += flt(d.operating_cost)
self.doc.operating_cost = total_op_cost
def calculate_rm_cost(self):
def add_to_flat_bom_detail(self): """Fetch RM rate as per today's valuation rate and calculate totals"""
"Add items to Flat BOM table" total_rm_cost = 0
self.doclist = self.doc.clear_table(self.doclist, 'flat_bom_details', 1) for d in getlist(self.doclist, 'bom_materials'):
for d in self.cur_flat_bom_items: if d.bom_no:
ch = addchild(self.doc, 'flat_bom_details', 'BOM Explosion Item', 1, self.doclist) d.rate = self.get_bom_unitcost(d.bom_no)
for i in d.keys(): d.amount = flt(d.rate) * flt(d.qty)
ch.fields[i] = d[i] d.qty_consumed_per_unit = flt(d.qty) / flt(self.doc.quantity)
ch.docstatus = self.doc.docstatus d.save()
ch.save(1) total_rm_cost += d.amount
self.doc.save() self.doc.raw_material_cost = total_rm_cost
def update_flat_bom(self):
""" Update Flat BOM, following will be correct data"""
self.get_flat_bom_items()
self.add_to_flat_bom_detail()
def get_flat_bom_items(self):
""" Get all raw materials including items from child bom"""
self.cur_flat_bom_items = []
for d in getlist(self.doclist, 'bom_materials'):
if d.bom_no:
self.get_child_flat_bom_items(d.bom_no, d.qty)
else:
self.cur_flat_bom_items.append({
'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)
})
def get_child_flat_bom_items(self, bom_no, qty): def get_child_flat_bom_items(self, bom_no, qty):
""" Add all items from Flat BOM of child BOM""" """ Add all items from Flat BOM of child BOM"""
@ -357,31 +364,16 @@ class DocType:
}) })
def add_to_flat_bom_detail(self):
def get_flat_bom_items(self): "Add items to Flat BOM table"
""" Get all raw materials including items from child bom""" self.doclist = self.doc.clear_table(self.doclist, 'flat_bom_details', 1)
self.cur_flat_bom_items = [] for d in self.cur_flat_bom_items:
for d in getlist(self.doclist, 'bom_materials'): ch = addchild(self.doc, 'flat_bom_details', 'BOM Explosion Item', 1, self.doclist)
if d.bom_no: for i in d.keys():
self.get_child_flat_bom_items(d.bom_no, d.qty) ch.fields[i] = d[i]
else: ch.docstatus = self.doc.docstatus
self.cur_flat_bom_items.append({ ch.save(1)
'item_code' : d.item_code, self.doc.save()
'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)
})
def update_flat_bom(self):
""" Update Flat BOM, following will be correct data"""
self.get_flat_bom_items()
self.add_to_flat_bom_detail()
def get_parent_bom_list(self, bom_no): def get_parent_bom_list(self, bom_no):
@ -392,6 +384,7 @@ class DocType:
def on_submit(self): def on_submit(self):
self.manage_default_bom() self.manage_default_bom()
def on_cancel(self): def on_cancel(self):
# check if used in any other bom # check if used in any other bom
par = sql("""select t1.parent from `tabBOM Item` t1, `tabBOM` t2 par = sql("""select t1.parent from `tabBOM Item` t1, `tabBOM` t2
@ -404,30 +397,19 @@ class DocType:
webnotes.conn.set(self.doc, "is_active", "No") webnotes.conn.set(self.doc, "is_active", "No")
webnotes.conn.set(self.doc, "is_default", 0) webnotes.conn.set(self.doc, "is_default", 0)
self.manage_default_bom() self.manage_default_bom()
self.update_flat_bom_by_traversing() self.update_cost_and_exploded_items(calculate_cost=False)
def traverse_tree(self):
def _get_childs(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
while(count < len(bom_list)): def on_update_after_submit(self):
for child_bom in _get_childs(bom_list[count]): self.manage_default_bom()
if child_bom not in bom_list: self.validate_inactive_bom()
bom_list.append(child_bom)
count += 1
def validate_inactive_bom(self):
return bom_list if self.doc.is_active == 'No':
act_pbom = sql("""select distinct t1.parent from `tabBOM Item` t1, `tabBOM` t2
def update_cost_by_traversing(self): where t1.bom_no =%s and t2.name = t1.parent and t2.is_active = 'Yes'
bom_list = self.traverse_tree() and t2.docstatus = 1 and t1.docstatus =1 """, self.doc.name)
bom_list.reverse() if act_pbom and act_pbom[0][0]:
for bom in bom_list: msgprint("""Sorry cannot inactivate as BOM: %s is child
get_obj("BOM", bom, with_children=1).calculate_cost() of one or many other active parent BOMs""" % self.doc.name, raise_exception=1)
def update_flat_bom_by_traversing(self):
bom_list = self.traverse_tree()
bom_list.reverse()
for bom in bom_list:
get_obj("BOM", bom, with_children=1).update_flat_bom()