bom cleanup

This commit is contained in:
Nabin Hait 2012-12-14 19:00:42 +05:30
parent f3faead478
commit 5ca0f44890
12 changed files with 139 additions and 174 deletions

View File

@ -19,16 +19,16 @@ cur_frm.cscript.refresh = function(doc,dt,dn){
cur_frm.toggle_enable("item", doc.__islocal);
if (!doc.__islocal && doc.docstatus==0) {
cur_frm.set_intro("Submit the BOM to use it in production");
cur_frm.set_intro("Submit the BOM to use it for manufacturing or repacking.");
} else cur_frm.set_intro("");
cur_frm.cscript.track_operations(doc);
cur_frm.cscript.with_operations(doc);
set_operation_no(doc);
}
cur_frm.cscript.track_operations = function(doc) {
cur_frm.fields_dict["bom_materials"].grid.set_column_disp("operation_no", doc.track_operations);
cur_frm.fields_dict["bom_materials"].grid.toggle_reqd("operation_no", doc.track_operations)
cur_frm.cscript.with_operations = function(doc) {
cur_frm.fields_dict["bom_materials"].grid.set_column_disp("operation_no", doc.with_operations);
cur_frm.fields_dict["bom_materials"].grid.toggle_reqd("operation_no", doc.with_operations)
}
cur_frm.cscript.operation_no = function(doc, cdt, cdn) {
@ -44,8 +44,14 @@ var set_operation_no = function(doc) {
var op = op_table[i].operation_no;
if (op && !inList(operations, op)) operations.push(op);
}
cur_frm.fields_dict["bom_materials"].grid.get_field("operation_no")
.df.options = operations.join("\n");
$.each(getchildren("BOM Item", doc.name, "bom_materials"), function(i, v) {
if(!inList(operations, cstr(v.operation_no))) v.operation_no = null;
});
refresh_field("bom_materials");
}
@ -55,7 +61,7 @@ cur_frm.fields_dict["bom_operations"].grid.on_row_delete = function(cdt, cdn){
cur_frm.cscript.item = function(doc, dt, dn) {
if (doc.item) {
get_server_fields('get_item_detail',doc.item,'',doc,dt,dn,1);
get_server_fields('get_item_details',doc.item,'',doc,dt,dn,1);
}
}
@ -129,17 +135,6 @@ cur_frm.cscript.rate = function(doc, cdt, cdn) {
}
}
cur_frm.cscript.is_default = function(doc, cdt, cdn) {
if (doc.docstatus == 1)
$c_obj(make_doclist(cdt, cdn), 'manage_default_bom', '', '');
}
cur_frm.cscript.is_active = function(doc, dt, dn) {
if (!doc.__islocal)
$c_obj(make_doclist(dt, dn), 'manage_active_bom', '', '');
}
var calculate_op_cost = function(doc, dt, dn) {
var op = getchildren('BOM Operation', doc.name, 'bom_operations');
total_op_cost = 0;
@ -196,10 +191,6 @@ cur_frm.fields_dict['bom_materials'].grid.get_field('item_code').get_query = fun
cur_frm.fields_dict['bom_materials'].grid.get_field('bom_no').get_query = function(doc, cdt, cdn) {
var d = locals[cdt][cdn];
msgprint('SELECT DISTINCT `tabBOM`.`name`, `tabBOM`.`remarks` FROM `tabBOM` \
WHERE `tabBOM`.`item` = "' + d.item_code + '" AND `tabBOM`.`is_active` = 1 AND \
`tabBOM`.docstatus = 1 AND `tabBOM`.`name` like "%s" \
ORDER BY `tabBOM`.`name` LIMIT 50');
return 'SELECT DISTINCT `tabBOM`.`name`, `tabBOM`.`remarks` FROM `tabBOM` \
WHERE `tabBOM`.`item` = "' + d.item_code + '" AND `tabBOM`.`is_active` = 1 AND \
`tabBOM`.docstatus = 1 AND `tabBOM`.`name` like "%s" \

View File

@ -38,24 +38,52 @@ class DocType:
else:
idx = 1
self.doc.name = 'BOM/' + self.doc.item + ('/%.3i' % idx)
def validate(self):
self.clear_operations()
self.validate_main_item()
self.validate_operations()
self.validate_materials()
def on_update(self):
self.check_recursion()
self.update_cost_and_exploded_items()
def on_submit(self):
self.manage_default_bom()
def on_cancel(self):
# check if used in any other bom
par = sql("""select t1.parent from `tabBOM Item` t1, `tabBOM` t2
where t1.parent = t2.name and t1.bom_no = %s and t1.docstatus = 1
and t2.is_active = 1""", self.doc.name)
if par:
msgprint("""BOM can not be cancelled, as it is a child item \
in following active BOM %s""" % [d[0] for d in par], raise_exception=1)
webnotes.conn.set(self.doc, "is_active", 0)
webnotes.conn.set(self.doc, "is_default", 0)
self.manage_default_bom()
self.update_cost_and_exploded_items(calculate_cost=False)
def on_update_after_submit(self):
self.manage_default_bom()
self.validate_inactive_bom()
def get_item_det(self, item_code):
item = sql("""select name, is_asset_item, is_purchase_item, docstatus,
item = sql("""select name, is_asset_item, is_purchase_item, docstatus, description,
is_sub_contracted_item, stock_uom, default_bom,
last_purchase_rate, standard_rate, is_manufactured_item
from `tabItem` where item_code = %s""", item_code, as_dict = 1)
return item
def get_item_detail(self, item_code):
def get_item_details(self, item_code):
return { 'uom' : webnotes.conn.get_value("Item", item_code, "stock_uom")}
def get_workstation_details(self,workstation):
return {'hour_rate': webnotes.conn.get_value("Workstation", workstation, "hour_rate")}
def validate_rm_item(self, item):
if item[0]['name'] == self.doc.item:
msgprint("Item_code: %s in materials tab cannot be same as FG Item",
@ -67,7 +95,6 @@ class DocType:
if not item or item[0]['docstatus'] == 2:
msgprint("Item %s does not exist in system" % item[0]['item_code'], raise_exception = 1)
def get_bom_material_detail(self):
""" Get raw material details like uom, desc and rate"""
@ -90,7 +117,6 @@ class DocType:
}
return ret_item
def get_rm_rate(self, arg):
""" Get raw material rate as per selected method, if bom exists takes bom cost """
@ -128,26 +154,26 @@ class DocType:
return rate and flt(sum(rate))/len(rate) or 0
def manage_default_bom(self):
""" Uncheck others if current one is selected as default,
update default bom in item master
"""
if self.doc.is_default and self.doc.is_active:
sql("update `tabBOM` set is_default = 0 where name != %s and item=%s",
(self.doc.name, self.doc.item))
from webnotes.model.utils import set_default
set_default(self.doc, "item")
webnotes.conn.set_value("Item", self.doc.item, "default_bom", self.doc.name)
else:
sql("update `tabItem` set default_bom = '' where name = %s and default_bom = %s",
if not self.doc.is_active:
webnotes.conn.set(self.doc, "is_default", 0)
sql("update `tabItem` set default_bom = null where name = %s and default_bom = %s",
(self.doc.item, self.doc.name))
def validate(self):
self.validate_main_item()
self.validate_operations()
self.validate_materials()
def clear_operations(self):
if not self.doc.with_operations:
self.doclist = self.doc.clear_table(self.doclist, 'bom_operations')
def validate_main_item(self):
""" Validate main FG item"""
@ -161,7 +187,6 @@ class DocType:
msgprint("""As Item: %s is not a manufactured / sub-contracted item, \
you can not make BOM for it""" % self.doc.item, raise_exception = 1)
def validate_operations(self):
""" Check duplicate operation no"""
self.op = []
@ -178,7 +203,7 @@ class DocType:
check_list = []
for m in getlist(self.doclist, 'bom_materials'):
# check if operation no not in op table
if self.doc.track_operations and cstr(m.operation_no) not in self.op:
if self.doc.with_operations and cstr(m.operation_no) not in self.op:
msgprint("""Operation no: %s against item: %s at row no: %s \
is not present at Operations table""" %
(m.operation_no, m.item_code, m.idx), raise_exception = 1)
@ -203,18 +228,16 @@ class DocType:
self.check_if_item_repeated(m.item_code, m.operation_no, check_list)
def validate_bom_no(self, item, bom_no, idx):
"""Validate BOM No of sub-contracted items"""
bom = sql("""select name from `tabBOM` where name = %s and item = %s
and is_active = 1 and docstatus < 2 """,
and is_active=1 and docstatus=1""",
(bom_no, item), as_dict =1)
if not bom:
msgprint("""Incorrect BOM No: %s against item: %s at row no: %s.
It may be inactive or cancelled or for some other item.""" %
(bom_no, item, idx), raise_exception = 1)
def check_if_item_repeated(self, item, op, check_list):
if [cstr(item), cstr(op)] in check_list:
msgprint("Item %s has been entered twice against same operation" %
@ -222,11 +245,6 @@ class DocType:
else:
check_list.append([cstr(item), cstr(op)])
def on_update(self):
self.check_recursion()
self.update_cost_and_exploded_items()
def check_recursion(self):
""" Check whether recursion occurs in any bom"""
@ -243,7 +261,6 @@ class DocType:
""" % (cstr(b), cstr(d[2]), self.doc.name), raise_exception = 1)
if b[0]:
bom_list.append(b[0])
def update_cost_and_exploded_items(self, calculate_cost=True):
bom_list = self.traverse_tree()
@ -252,9 +269,10 @@ class DocType:
bom_obj = get_obj("BOM", bom, with_children=1)
if calculate_cost:
bom_obj.calculate_cost()
bom_obj.update_flat_bom()
bom_obj.update_exploded_items()
if bom == self.doc.name:
self.doc, self.doclist = bom_obj.doc, bom_obj.doclist
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`
@ -268,7 +286,6 @@ class DocType:
count += 1
return bom_list
def calculate_cost(self):
"""Calculate bom totals"""
self.calculate_op_cost()
@ -276,7 +293,6 @@ class DocType:
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"""
@ -288,7 +304,6 @@ class DocType:
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
@ -301,21 +316,19 @@ class DocType:
total_rm_cost += d.amount
self.doc.raw_material_cost = total_rm_cost
def update_flat_bom(self):
def update_exploded_items(self):
""" Update Flat BOM, following will be correct data"""
self.get_flat_bom_items()
self.add_to_flat_bom_detail()
self.get_exploded_items()
self.add_exploded_items()
def get_flat_bom_items(self):
def get_exploded_items(self):
""" Get all raw materials including items from child bom"""
self.cur_flat_bom_items = []
self.cur_exploded_items = []
for d in getlist(self.doclist, 'bom_materials'):
if d.bom_no:
self.get_child_flat_bom_items(d.bom_no, d.qty)
self.get_child_exploded_items(d.bom_no, d.qty)
else:
self.cur_flat_bom_items.append({
self.cur_exploded_items.append({
'item_code' : d.item_code,
'description' : d.description,
'stock_uom' : d.stock_uom,
@ -327,8 +340,7 @@ class DocType:
'qty_consumed_per_unit' : flt(d.qty_consumed_per_unit)
})
def get_child_flat_bom_items(self, bom_no, qty):
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,
@ -336,7 +348,7 @@ class DocType:
from `tabBOM Explosion Item` where parent = '%s' and docstatus = 1""" %
bom_no, as_dict = 1)
for d in child_fb_items:
self.cur_flat_bom_items.append({
self.cur_exploded_items.append({
'item_code' : d['item_code'],
'description' : d['description'],
'stock_uom' : d['stock_uom'],
@ -349,10 +361,10 @@ class DocType:
})
def add_to_flat_bom_detail(self):
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_flat_bom_items:
for d in self.cur_exploded_items:
ch = addchild(self.doc, 'flat_bom_details', 'BOM Explosion Item', 1, self.doclist)
for i in d.keys():
ch.fields[i] = d[i]
@ -360,40 +372,14 @@ class DocType:
ch.save(1)
self.doc.save()
def get_parent_bom_list(self, bom_no):
p_bom = sql("select parent from `tabBOM Item` where bom_no = '%s'" % bom_no)
return p_bom and [i[0] for i in p_bom] or []
def on_submit(self):
self.manage_default_bom()
def on_cancel(self):
# check if used in any other bom
par = sql("""select t1.parent from `tabBOM Item` t1, `tabBOM` t2
where t1.parent = t2.name and t1.bom_no = %s and t1.docstatus = 1
and t2.is_active = 1""", self.doc.name)
if par:
msgprint("""BOM can not be cancelled, as it is a child item \
in following active BOM %s""" % [d[0] for d in par], raise_exception=1)
webnotes.conn.set(self.doc, "is_active", 0)
webnotes.conn.set(self.doc, "is_default", 0)
self.manage_default_bom()
self.update_cost_and_exploded_items(calculate_cost=False)
def on_update_after_submit(self):
self.manage_default_bom()
self.validate_inactive_bom()
def validate_inactive_bom(self):
if not self.doc.is_active:
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 = 1
where t1.bom_no = %s and t2.name = t1.parent and t2.is_active = 1
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

View File

@ -4,7 +4,7 @@
"docstatus": 0,
"creation": "2012-12-14 10:15:15",
"modified_by": "Administrator",
"modified": "2012-12-14 13:40:48"
"modified": "2012-12-14 16:51:01"
},
{
"istable": 0,
@ -45,7 +45,7 @@
"doctype": "DocType"
},
{
"description": "Select the item code for which Bill of Material is being created",
"description": "Item to be manufactured or repacked",
"oldfieldtype": "Link",
"doctype": "DocField",
"label": "Item",
@ -65,9 +65,35 @@
"permlevel": 0
},
{
"no_copy": 1,
"oldfieldtype": "Select",
"allow_on_submit": 1,
"doctype": "DocField",
"label": "Track Operations",
"fieldname": "track_operations",
"label": "Is Active",
"oldfieldname": "is_active",
"default": "1",
"fieldname": "is_active",
"fieldtype": "Check",
"reqd": 0,
"hidden": 0,
"permlevel": 0
},
{
"no_copy": 1,
"oldfieldtype": "Check",
"allow_on_submit": 1,
"doctype": "DocField",
"label": "Is Default",
"oldfieldname": "is_default",
"fieldname": "is_default",
"fieldtype": "Check",
"permlevel": 0
},
{
"description": "Manage cost of operations",
"doctype": "DocField",
"label": "With Operations",
"fieldname": "with_operations",
"fieldtype": "Check",
"permlevel": 0
},
@ -78,7 +104,7 @@
"options": "Specify the operations, operating cost and give a unique Operation no to your operations.",
"fieldname": "operations",
"fieldtype": "Section Break",
"depends_on": "track_operations",
"depends_on": "with_operations",
"permlevel": 0
},
{
@ -100,7 +126,6 @@
"permlevel": 0
},
{
"description": "Enter the raw materials required to manufacture the BOM item. Specify the operation no as entered in the previous tab which will be performed on the raw materials entered.",
"oldfieldtype": "Table",
"doctype": "DocField",
"label": "BOM Item",
@ -120,7 +145,7 @@
},
{
"doctype": "DocField",
"label": "Consider Raw Material Cost As Per",
"label": "Rate Of Materials Based On",
"options": "Valuation Rate\nLast Purchase Rate",
"fieldname": "rm_cost_as_per",
"fieldtype": "Select",
@ -130,7 +155,7 @@
"doctype": "DocField",
"label": "Total Cost",
"fieldname": "total_cost",
"fieldtype": "Float",
"fieldtype": "Currency",
"permlevel": 1
},
{
@ -141,16 +166,16 @@
},
{
"doctype": "DocField",
"label": "Raw Material Cost",
"label": "Total Raw Material Cost",
"fieldname": "raw_material_cost",
"fieldtype": "Float",
"fieldtype": "Currency",
"permlevel": 1
},
{
"doctype": "DocField",
"label": "Operating Cost",
"label": "Total Operating Cost",
"fieldname": "operating_cost",
"fieldtype": "Float",
"fieldtype": "Currency",
"permlevel": 1
},
{
@ -161,7 +186,7 @@
"permlevel": 0
},
{
"description": "Total quantity of items for which raw materials required and operations done will be defined",
"description": "Quantity of item obtained after manufacturing / repacking from given quantities of raw materials",
"default": "1",
"oldfieldtype": "Currency",
"doctype": "DocField",
@ -187,7 +212,6 @@
"permlevel": 0
},
{
"description": "Select name of the project if BOM need to be created against any project",
"oldfieldtype": "Link",
"doctype": "DocField",
"label": "Project Name",
@ -198,37 +222,12 @@
"permlevel": 0,
"in_filter": 1
},
{
"no_copy": 1,
"oldfieldtype": "Select",
"allow_on_submit": 1,
"doctype": "DocField",
"label": "Is Active",
"oldfieldname": "is_active",
"default": "1",
"fieldname": "is_active",
"fieldtype": "Check",
"reqd": 1,
"hidden": 0,
"permlevel": 0
},
{
"no_copy": 1,
"oldfieldtype": "Check",
"allow_on_submit": 1,
"doctype": "DocField",
"label": "Is Default",
"oldfieldname": "is_default",
"fieldname": "is_default",
"fieldtype": "Check",
"permlevel": 0
},
{
"print_hide": 1,
"no_copy": 1,
"doctype": "DocField",
"label": "Amended From",
"options": "Sales Invoice",
"options": "BOM",
"fieldname": "amended_from",
"fieldtype": "Link",
"permlevel": 1
@ -237,8 +236,7 @@
"print_hide": 0,
"depends_on": "eval:!doc.__islocal",
"doctype": "DocField",
"label": "BOM Explosion Items",
"options": "Simple",
"label": "Materials Required (Exploded)",
"fieldname": "section_break0",
"fieldtype": "Section Break",
"hidden": 0,
@ -250,7 +248,7 @@
"no_copy": 1,
"oldfieldtype": "Table",
"doctype": "DocField",
"label": "BOM Explosion Item",
"label": "Materials Required (Exploded)",
"oldfieldname": "flat_bom_details",
"default": "No Toolbar",
"fieldname": "flat_bom_details",

View File

@ -2,9 +2,9 @@
{
"owner": "Administrator",
"docstatus": 0,
"creation": "2012-07-03 13:30:04",
"creation": "2012-12-14 10:15:16",
"modified_by": "Administrator",
"modified": "2012-12-10 18:30:00"
"modified": "2012-12-14 16:53:30"
},
{
"read_only": 0,
@ -67,7 +67,7 @@
"label": "Amount",
"oldfieldname": "amount_as_per_sr",
"fieldname": "amount",
"fieldtype": "Float"
"fieldtype": "Currency"
},
{
"oldfieldtype": "Link",

View File

@ -4,7 +4,7 @@
"docstatus": 0,
"creation": "2012-12-14 10:15:16",
"modified_by": "Administrator",
"modified": "2012-12-14 13:11:49"
"modified": "2012-12-14 16:35:33"
},
{
"istable": 1,
@ -103,7 +103,7 @@
"oldfieldname": "amount_as_per_mar",
"width": "150px",
"fieldname": "amount",
"fieldtype": "Float",
"fieldtype": "Currency",
"permlevel": 1
},
{

View File

@ -2,20 +2,15 @@
{
"owner": "Administrator",
"docstatus": 0,
"creation": "2012-03-27 14:36:02",
"creation": "2012-12-14 10:15:16",
"modified_by": "Administrator",
"modified": "2012-12-10 18:30:00"
"modified": "2012-12-14 16:06:37"
},
{
"section_style": "Simple",
"istable": 1,
"name": "__common__",
"colour": "White:FFF",
"module": "Manufacturing",
"show_in_menu": 0,
"version": 8,
"server_code_error": " ",
"doctype": "DocType"
"doctype": "DocType",
"module": "Manufacturing"
},
{
"name": "__common__",
@ -38,15 +33,6 @@
"name": "BOM Operation",
"doctype": "DocType"
},
{
"write": 1,
"permlevel": 0,
"doctype": "DocPerm"
},
{
"permlevel": 1,
"doctype": "DocPerm"
},
{
"oldfieldtype": "Data",
"doctype": "DocField",
@ -59,7 +45,7 @@
{
"oldfieldtype": "Text",
"doctype": "DocField",
"label": "Opn Description",
"label": "Operation Description",
"oldfieldname": "opn_description",
"fieldname": "opn_description",
"fieldtype": "Text",
@ -70,7 +56,6 @@
"doctype": "DocField",
"label": "Workstation",
"oldfieldname": "workstation",
"trigger": "Client",
"fieldname": "workstation",
"fieldtype": "Link",
"reqd": 0,
@ -103,5 +88,14 @@
"fieldname": "operating_cost",
"fieldtype": "Currency",
"reqd": 0
},
{
"write": 1,
"doctype": "DocPerm",
"permlevel": 0
},
{
"doctype": "DocPerm",
"permlevel": 1
}
]

View File

@ -42,6 +42,6 @@ def rebuilt_exploded_bom():
get_obj("BOM", bom[0], with_children=1).on_update()
def cleanup_bom():
webnotes.conn.sql("""UPDATE `tabBOM` SET is_active = if(is_active='Yes', 1, 0),
track_operations = 1""")
webnotes.conn.sql("""UPDATE `tabBOM` SET is_active = if(is_active in ('Yes', 1), 1, 0),
with_operations = 1""")

View File

@ -66,7 +66,6 @@ KBItemToolbar = function(args, kb) {
this.setup_del = function() {
$(this.line1).find('.del-link').click(function() {
console.log(1);
this.innerHTML = 'deleting...';
this.disabled = 1;
$c_page('utilities', 'questions', 'delete', {

View File

@ -168,7 +168,7 @@ erpnext.setup_mousetrap = function() {
});
Mousetrap.bind(["command+s", "ctrl+s"], function() {
if(cur_frm && !cur_frm.save_disabled)
if(cur_frm && !cur_frm.save_disabled && cint(cur_frm.doc.docstatus)===0)
cur_frm.save();
else if(wn.container.page.save_action)
wn.container.page.save_action();

View File

@ -154,7 +154,6 @@ erpnext.SalesChart = Class.extend({
rename: function() {
var node = this.selected_node();
wn.model.rename_doc(this.ctype, node.data('label'), function(new_name) {
console.log(new_name)
node.data('label', new_name).find(".tree-label").html(new_name);
});
},

View File

@ -17,6 +17,7 @@
from __future__ import unicode_literals
"""Global Defaults"""
import webnotes
from webnotes.utils import cint
keydict = {
"fiscal_year": "current_fiscal_year",
@ -66,12 +67,11 @@ class DocType:
def validate_session_expiry(self):
if self.doc.session_expiry:
from datetime import datetime
try:
datetime.strptime(self.doc.session_expiry, "%H:%M")
except ValueError:
parts = self.doc.session_expiry.split(":")
if len(parts)!=2 or not (cint(parts[0]) or cint(parts[1])):
webnotes.msgprint("""Session Expiry must be in format hh:mm""",
raise_exception=1)
def get_defaults(self):
return webnotes.conn.get_defaults()

View File

@ -20,11 +20,9 @@ cur_frm.fields_dict['delivery_note'].get_query = function(doc, cdt, cdn) {
cur_frm.fields_dict['item_details'].grid.get_field('item_code').get_query = function(doc, cdt, cdn) {
console.log(doc.delivery_note);
var query = 'SELECT name, description FROM `tabItem` WHERE name IN ( \
SELECT item_code FROM `tabDelivery Note Item` dnd \
WHERE parent="' + doc.delivery_note + '" AND IFNULL(qty, 0) > IFNULL(packed_qty, 0)) AND %(key)s LIKE "%s" LIMIT 50';
console.log(query);
return query;
}