Production cleanup with linking with sales order

This commit is contained in:
Nabin Hait 2012-11-30 14:36:01 +05:30
parent 6aa80071e5
commit faf251a53e
9 changed files with 452 additions and 487 deletions

View File

@ -73,7 +73,7 @@ class DocType:
# Raise Production Order # Raise Production Order
def create_production_order(self,company, pp_items): def create_production_order(self, items):
"""Create production order. Called from Production Planning Tool""" """Create production order. Called from Production Planning Tool"""
default_values = { default_values = {
@ -82,15 +82,20 @@ class DocType:
'wip_warehouse' : '', 'wip_warehouse' : '',
'fg_warehouse' : '', 'fg_warehouse' : '',
'status' : 'Draft', 'status' : 'Draft',
'company' : company,
'fiscal_year' : get_defaults()['fiscal_year'] 'fiscal_year' : get_defaults()['fiscal_year']
} }
pro_list = [] pro_list = []
for d in pp_items: for item_so in items:
if item_so[1]:
self.validate_production_order_against_so(
item_so[0], item_so[1], items[item_so].get("qty"))
pro_doc = Document('Production Order') pro_doc = Document('Production Order')
for key in d.keys(): pro_doc.production_item = item_so[0]
pro_doc.fields[key] = d[key] pro_doc.sales_order = item_so[1]
for key in items[item_so]:
pro_doc.fields[key] = items[item_so][key]
for key in default_values: for key in default_values:
pro_doc.fields[key] = default_values[key] pro_doc.fields[key] = default_values[key]
@ -100,6 +105,29 @@ class DocType:
return pro_list return pro_list
def validate_production_order_against_so(self, item, sales_order, qty, pro_order=None):
# already ordered qty
ordered_qty_against_so = webnotes.conn.sql("""select sum(qty) from `tabProduction Order`
where production_item = %s and sales_order = %s and name != %s""",
(item, sales_order, cstr(pro_order)))[0][0]
# qty including current
total_ordered_qty_against_so = flt(ordered_qty_against_so) + flt(qty)
# get qty from Sales Order Item table
so_item_qty = webnotes.conn.sql("""select sum(qty) from `tabSales Order Item`
where parent = %s and item_code = %s""", (sales_order, item))[0][0]
# get qty from Packing Item table
dnpi_qty = webnotes.conn.sql("""select sum(qty) from `tabDelivery Note Packing Item`
where parent = %s and parenttype = 'Sales Order' and item_code = %s""",
(sales_order, item))[0][0]
# total qty in SO
so_qty = flt(so_item_qty) + flt(dnpi_qty)
if total_ordered_qty_against_so > so_qty:
msgprint("""Total production order qty for item: %s against sales order: %s \
will be %s, which is greater than sales order qty (%s).
Please reduce qty or remove the item.""" %
(item, sales_order, total_ordered_qty_against_so, so_qty), raise_exception=1)
def update_bom(self, bom_no): def update_bom(self, bom_no):
main_bom_list = self.traverse_bom_tree(bom_no, 1) main_bom_list = self.traverse_bom_tree(bom_no, 1)

View File

@ -18,15 +18,7 @@
cur_frm.cscript.onload = function(doc, dt, dn) { cur_frm.cscript.onload = function(doc, dt, dn) {
if (!doc.posting_date) doc.transaction_date = dateutil.obj_to_str(new Date()); if (!doc.posting_date) doc.transaction_date = dateutil.obj_to_str(new Date());
if (!doc.status) doc.status = 'Draft'; if (!doc.status) doc.status = 'Draft';
cfn_set_fields(doc, dt, dn); cfn_set_fields(doc, dt, dn);
if (doc.origin != "MRP"){
doc.origin = "Manual";
set_field_permlevel('production_item', 0);
set_field_permlevel('bom_no', 0);
set_field_permlevel('consider_sa_items',0);
}
} }
// ================================== Refresh ========================================== // ================================== Refresh ==========================================
@ -48,15 +40,10 @@ var cfn_set_fields = function(doc, dt, dn) {
} }
} }
// ==================================================================================================
cur_frm.cscript.production_item = function(doc, dt, dn) { cur_frm.cscript.production_item = function(doc, dt, dn) {
get_server_fields('get_item_detail',doc.production_item,'',doc,dt,dn,1); get_server_fields('get_item_detail',doc.production_item,'',doc,dt,dn,1);
} }
// Stop PRODUCTION ORDER
//
cur_frm.cscript['Stop Production Order'] = function() { cur_frm.cscript['Stop Production Order'] = function() {
var doc = cur_frm.doc; var doc = cur_frm.doc;
var check = confirm("Do you really want to stop production order: " + doc.name); var check = confirm("Do you really want to stop production order: " + doc.name);
@ -65,8 +52,6 @@ cur_frm.cscript['Stop Production Order'] = function() {
} }
} }
// Unstop PRODUCTION ORDER
//
cur_frm.cscript['Unstop Production Order'] = function() { cur_frm.cscript['Unstop Production Order'] = function() {
var doc = cur_frm.doc; var doc = cur_frm.doc;
var check = confirm("Do really want to unstop production order: " + doc.name); var check = confirm("Do really want to unstop production order: " + doc.name);
@ -97,8 +82,6 @@ cur_frm.cscript.make_se = function(doc, process) {
loaddoc('Stock Entry', se.name); loaddoc('Stock Entry', se.name);
} }
// ==================================================================================================
cur_frm.fields_dict['production_item'].get_query = function(doc) { cur_frm.fields_dict['production_item'].get_query = function(doc) {
return 'SELECT DISTINCT `tabItem`.`name`, `tabItem`.`description` FROM `tabItem` WHERE (IFNULL(`tabItem`.`end_of_life`,"") = "" OR `tabItem`.`end_of_life` = "0000-00-00" OR `tabItem`.`end_of_life` > NOW()) AND `tabItem`.docstatus != 2 AND `tabItem`.is_pro_applicable = "Yes" AND `tabItem`.%(key)s LIKE "%s" ORDER BY `tabItem`.`name` LIMIT 50'; return 'SELECT DISTINCT `tabItem`.`name`, `tabItem`.`description` FROM `tabItem` WHERE (IFNULL(`tabItem`.`end_of_life`,"") = "" OR `tabItem`.`end_of_life` = "0000-00-00" OR `tabItem`.`end_of_life` > NOW()) AND `tabItem`.docstatus != 2 AND `tabItem`.is_pro_applicable = "Yes" AND `tabItem`.%(key)s LIKE "%s" ORDER BY `tabItem`.`name` LIMIT 50';
} }

View File

@ -73,6 +73,14 @@ class DocType:
May be BOM not exists or inactive or not submitted May be BOM not exists or inactive or not submitted
or for some other item.""" % cstr(self.doc.bom_no), raise_exception=1) or for some other item.""" % cstr(self.doc.bom_no), raise_exception=1)
if self.doc.sales_order:
if not webnotes.conn.sql("""select name from `tabSales Order`
where name=%s and docstatus = 1""", self.doc.sales_order):
msgprint("Sales Order: %s is not valid" % self.doc.sales_order, raise_exception=1)
get_obj("Production Control").validate_production_order_against_so(
self.doc.production_item, self.doc.sales_order, self.doc.qty, self.doc.name)
def stop_unstop(self, status): def stop_unstop(self, status):
""" Called from client side on Stop/Unstop event""" """ Called from client side on Stop/Unstop event"""

View File

@ -1,358 +1,324 @@
# DocType, Production Order
[ [
# These values are common in all dictionaries
{ {
'creation': '2012-05-15 12:14:48', "owner": "Administrator",
'docstatus': 0, "docstatus": 0,
'modified': '2012-05-28 19:03:56', "creation": "2012-07-03 13:30:03",
'modified_by': u'Administrator', "modified_by": "Administrator",
'owner': u'Administrator' "modified": "2012-11-30 14:28:03"
}, },
# These values are common for all DocType
{ {
'_last_update': u'1325837006', "is_submittable": 1,
'colour': u'White:FFF', "in_create": 0,
'default_print_format': u'Standard', "default_print_format": "Standard",
'doctype': 'DocType', "doctype": "DocType",
'in_create': 0, "module": "Production",
'is_submittable': 1, "name": "__common__"
'module': u'Production',
'name': '__common__',
'section_style': u'Tabbed',
'server_code_error': u' ',
'show_in_menu': 0,
'version': 1
}, },
# These values are common for all DocField
{ {
'doctype': u'DocField', "name": "__common__",
'name': '__common__', "parent": "Production Order",
'parent': u'Production Order', "doctype": "DocField",
'parentfield': u'fields', "parenttype": "DocType",
'parenttype': u'DocType' "parentfield": "fields"
}, },
# These values are common for all DocPerm
{ {
'doctype': u'DocPerm', "name": "__common__",
'name': '__common__', "parent": "Production Order",
'parent': u'Production Order', "read": 1,
'parentfield': u'permissions', "doctype": "DocPerm",
'parenttype': u'DocType', "parenttype": "DocType",
'read': 1 "parentfield": "permissions"
}, },
# DocType, Production Order
{ {
'doctype': 'DocType', "name": "Production Order",
'name': u'Production Order' "doctype": "DocType"
}, },
# DocPerm
{ {
'amend': 1, "doctype": "DocField",
'cancel': 1, "width": "50%",
'create': 1, "fieldname": "column_break0",
'doctype': u'DocPerm', "fieldtype": "Column Break",
'permlevel': 0, "permlevel": 0
'role': u'System Manager',
'submit': 1,
'write': 1
}, },
# DocPerm
{ {
'doctype': u'DocPerm', "description": "Item for which this Production Order is raised.",
'permlevel': 1, "oldfieldtype": "Link",
'role': u'All' "colour": "White:FFF",
"doctype": "DocField",
"label": "Production Item",
"oldfieldname": "production_item",
"permlevel": 0,
"trigger": "Client",
"fieldname": "production_item",
"fieldtype": "Link",
"reqd": 1,
"in_filter": 1,
"options": "Item"
}, },
# DocPerm
{ {
'amend': 1, "description": "Bill of Material which was considered for manufacturing the production item.",
'cancel': 1, "oldfieldtype": "Link",
'create': 1, "colour": "White:FFF",
'doctype': u'DocPerm', "doctype": "DocField",
'permlevel': 0, "label": "BOM No",
'role': u'Production Manager', "oldfieldname": "bom_no",
'submit': 1, "permlevel": 0,
'write': 1 "trigger": "Client",
"fieldname": "bom_no",
"fieldtype": "Link",
"reqd": 1,
"options": "BOM"
}, },
# DocPerm
{ {
'amend': 1, "description": "Quantity of item for which Production Order is raised.",
'cancel': 1, "oldfieldtype": "Currency",
'create': 1, "colour": "White:FFF",
'doctype': u'DocPerm', "doctype": "DocField",
'permlevel': 0, "label": "Qty",
'role': u'Production User', "oldfieldname": "qty",
'submit': 1, "fieldname": "qty",
'write': 1 "fieldtype": "Currency",
"reqd": 1,
"permlevel": 0
}, },
# DocField
{ {
'doctype': u'DocField', "description": "The date on which current entry will get or has actually executed.",
'fieldname': u'column_break0', "oldfieldtype": "Date",
'fieldtype': u'Column Break', "colour": "White:FFF",
'permlevel': 0, "doctype": "DocField",
'width': u'50%' "label": "Posting Date",
"oldfieldname": "posting_date",
"fieldname": "posting_date",
"fieldtype": "Date",
"reqd": 1,
"permlevel": 0
}, },
# DocField
{ {
'colour': u'White:FFF', "oldfieldtype": "Column Break",
'description': u'Item for which this Production Order is raised.', "doctype": "DocField",
'doctype': u'DocField', "width": "50%",
'fieldname': u'production_item', "fieldname": "column_break1",
'fieldtype': u'Link', "fieldtype": "Column Break",
'in_filter': 1, "permlevel": 0
'label': u'Production Item',
'oldfieldname': u'production_item',
'oldfieldtype': u'Link',
'options': u'Item',
'permlevel': 1,
'reqd': 1,
'trigger': u'Client'
}, },
# DocField
{ {
'doctype': u'DocField', "description": "The warehouse for finished goods where stock of produced items will be updated.",
'fieldname': u'description', "oldfieldtype": "Link",
'fieldtype': u'Text', "colour": "White:FFF",
'label': u'Description', "doctype": "DocField",
'oldfieldname': u'description', "label": "FG Warehouse",
'oldfieldtype': u'Text', "oldfieldname": "fg_warehouse",
'permlevel': 0, "permlevel": 0,
'width': u'300px' "fieldname": "fg_warehouse",
"fieldtype": "Link",
"reqd": 1,
"in_filter": 1,
"options": "Warehouse"
}, },
# DocField
{ {
'doctype': u'DocField', "description": "The work in progress warehouse where raw materials will be operated upon to create finished goods.",
'fieldname': u'stock_uom', "oldfieldtype": "Link",
'fieldtype': u'Data', "colour": "White:FFF",
'label': u'Stock UOM', "doctype": "DocField",
'oldfieldname': u'stock_uom', "label": "WIP Warehouse",
'oldfieldtype': u'Data', "oldfieldname": "wip_warehouse",
'permlevel': 1 "permlevel": 0,
"fieldname": "wip_warehouse",
"fieldtype": "Link",
"reqd": 1,
"in_filter": 1,
"options": "Warehouse"
}, },
# DocField
{ {
'colour': u'White:FFF', "description": "If checked, BOM for sub-assembly items will be considered for getting raw materials. Otherwise, all sub-assembly items will be treated as a raw material.",
'description': u'Bill of Material which was considered for manufacturing the production item.', "default": "1",
'doctype': u'DocField', "oldfieldtype": "Select",
'fieldname': u'bom_no', "colour": "White:FFF",
'fieldtype': u'Link', "doctype": "DocField",
'label': u'BOM No', "label": "Use Multi-Level BOM",
'oldfieldname': u'bom_no', "oldfieldname": "consider_sa_items",
'oldfieldtype': u'Link', "fieldname": "use_multi_level_bom",
'options': u'BOM', "fieldtype": "Check",
'permlevel': 1, "reqd": 1,
'reqd': 1, "in_filter": 1,
'trigger': u'Client' "permlevel": 0
}, },
# DocField
{ {
'colour': u'White:FFF', "description": "Updated after finished goods are transferred to FG Warehouse through Stock Entry",
'description': u'Quantity of item for which Production Order is raised.', "no_copy": 1,
'doctype': u'DocField', "oldfieldtype": "Currency",
'fieldname': u'qty', "colour": "White:FFF",
'fieldtype': u'Currency', "doctype": "DocField",
'label': u'Qty', "label": "Produced Qty",
'oldfieldname': u'qty', "oldfieldname": "produced_qty",
'oldfieldtype': u'Currency', "fieldname": "produced_qty",
'permlevel': 0, "fieldtype": "Currency",
'reqd': 1 "permlevel": 1
}, },
# DocField
{ {
'colour': u'White:FFF', "doctype": "DocField",
'description': u'The warehouse for finished goods where stock of produced items will be updated.', "label": "More Info",
'doctype': u'DocField', "fieldname": "more_info",
'fieldname': u'fg_warehouse', "fieldtype": "Section Break",
'fieldtype': u'Link', "permlevel": 0
'in_filter': 1,
'label': u'FG Warehouse',
'oldfieldname': u'fg_warehouse',
'oldfieldtype': u'Link',
'options': u'Warehouse',
'permlevel': 0,
'reqd': 1
}, },
# DocField
{ {
'colour': u'White:FFF', "doctype": "DocField",
'description': u'The work in progress warehouse where raw materials will be operated upon to create finished goods.', "width": "50%",
'doctype': u'DocField', "fieldname": "column_break2",
'fieldname': u'wip_warehouse', "fieldtype": "Column Break",
'fieldtype': u'Link', "permlevel": 0
'in_filter': 1,
'label': u'WIP Warehouse',
'oldfieldname': u'wip_warehouse',
'oldfieldtype': u'Link',
'options': u'Warehouse',
'permlevel': 0,
'reqd': 1
}, },
# DocField
{ {
'doctype': u'DocField', "no_copy": 1,
'fieldname': u'amended_from', "oldfieldtype": "Select",
'fieldtype': u'Data', "doctype": "DocField",
'label': u'Amended From', "label": "Origin",
'no_copy': 1, "oldfieldname": "origin",
'oldfieldname': u'amended_from', "options": "Manual\nMRP",
'oldfieldtype': u'Data', "fieldname": "origin",
'permlevel': 1 "fieldtype": "Select",
"reqd": 1,
"permlevel": 0,
"in_filter": 1
}, },
# DocField
{ {
'doctype': u'DocField', "no_copy": 1,
'fieldname': u'amendment_date', "oldfieldtype": "Select",
'fieldtype': u'Date', "doctype": "DocField",
'label': u'Amendment Date', "label": "Status",
'no_copy': 1, "oldfieldname": "status",
'oldfieldname': u'amendment_date', "permlevel": 1,
'oldfieldtype': u'Date', "fieldname": "status",
'permlevel': 1 "fieldtype": "Select",
"search_index": 1,
"reqd": 1,
"options": "\nDraft\nSubmitted\nStopped\nIn Process\nCompleted\nCancelled",
"in_filter": 1
}, },
# DocField
{ {
'doctype': u'DocField', "doctype": "DocField",
'fieldname': u'column_break1', "label": "Sales Order",
'fieldtype': u'Column Break', "options": "Sales Order",
'oldfieldtype': u'Column Break', "fieldname": "sales_order",
'permlevel': 0, "fieldtype": "Link",
'width': u'50%' "permlevel": 0
}, },
# DocField
{ {
'colour': u'White:FFF', "description": "Select name of the project if Production Order need to be created against any project",
'description': u'The date on which current entry will get or has actually executed.', "oldfieldtype": "Link",
'doctype': u'DocField', "label": "Project Name",
'fieldname': u'posting_date', "oldfieldname": "project_name",
'fieldtype': u'Date', "trigger": "Client",
'label': u'Posting Date', "fieldname": "project_name",
'oldfieldname': u'posting_date', "fieldtype": "Link",
'oldfieldtype': u'Date', "doctype": "DocField",
'permlevel': 0, "options": "Project",
'reqd': 1 "permlevel": 0,
"in_filter": 1
}, },
# DocField
{ {
'colour': u'White:FFF', "oldfieldtype": "Link",
'description': u'Select "Yes" if stock is maintained and tracked for sub-assembly items. Select "No" if you want child items of sub-assembly for material transfer.', "doctype": "DocField",
'doctype': u'DocField', "label": "Company",
'fieldname': u'consider_sa_items', "oldfieldname": "company",
'fieldtype': u'Select', "options": "Company",
'in_filter': 1, "fieldname": "company",
'label': u'Consider SA Items as raw material', "fieldtype": "Link",
'oldfieldname': u'consider_sa_items', "reqd": 1,
'oldfieldtype': u'Select', "permlevel": 0
'options': u'\nYes\nNo',
'permlevel': 1,
'reqd': 1
}, },
# DocField
{ {
'description': u'Select name of the project if Production Order need to be created against any project', "oldfieldtype": "Select",
'doctype': u'DocField', "doctype": "DocField",
'fieldname': u'project_name', "label": "Fiscal Year",
'fieldtype': u'Link', "oldfieldname": "fiscal_year",
'in_filter': 1, "options": "link:Fiscal Year",
'label': u'Project Name', "fieldname": "fiscal_year",
'oldfieldname': u'project_name', "fieldtype": "Select",
'oldfieldtype': u'Link', "reqd": 1,
'options': u'Project', "permlevel": 0,
'permlevel': 0, "in_filter": 1
'trigger': u'Client'
}, },
# DocField
{ {
'doctype': u'DocField', "no_copy": 1,
'fieldname': u'origin', "oldfieldtype": "Data",
'fieldtype': u'Select', "doctype": "DocField",
'in_filter': 1, "label": "Amended From",
'label': u'Origin', "oldfieldname": "amended_from",
'no_copy': 1, "fieldname": "amended_from",
'oldfieldname': u'origin', "fieldtype": "Data",
'oldfieldtype': u'Select', "permlevel": 1
'options': u'Manual\nMRP',
'permlevel': 1,
'reqd': 1
}, },
# DocField
{ {
'doctype': u'DocField', "no_copy": 1,
'fieldname': u'status', "oldfieldtype": "Date",
'fieldtype': u'Select', "doctype": "DocField",
'in_filter': 1, "label": "Amendment Date",
'label': u'Status', "oldfieldname": "amendment_date",
'no_copy': 1, "fieldname": "amendment_date",
'oldfieldname': u'status', "fieldtype": "Date",
'oldfieldtype': u'Select', "permlevel": 1
'options': u'\nDraft\nSubmitted\nStopped\nIn Process\nCompleted\nCancelled',
'permlevel': 1,
'reqd': 1,
'search_index': 1
}, },
# DocField
{ {
'colour': u'White:FFF', "doctype": "DocField",
'description': u'Updated after finished goods are transferred to FG Warehouse through Stock Entry', "width": "50%",
'doctype': u'DocField', "fieldname": "column_break3",
'fieldname': u'produced_qty', "fieldtype": "Column Break",
'fieldtype': u'Currency', "permlevel": 0
'label': u'Produced Qty',
'no_copy': 1,
'oldfieldname': u'produced_qty',
'oldfieldtype': u'Currency',
'permlevel': 1
}, },
# DocField
{ {
'doctype': u'DocField', "oldfieldtype": "Data",
'fieldname': u'company', "doctype": "DocField",
'fieldtype': u'Link', "label": "Stock UOM",
'label': u'Company', "oldfieldname": "stock_uom",
'oldfieldname': u'company', "fieldname": "stock_uom",
'oldfieldtype': u'Link', "fieldtype": "Data",
'options': u'Company', "permlevel": 1
'permlevel': 0,
'reqd': 1
}, },
# DocField
{ {
'doctype': u'DocField', "oldfieldtype": "Text",
'fieldname': u'fiscal_year', "doctype": "DocField",
'fieldtype': u'Select', "label": "Production Item Description",
'in_filter': 1, "oldfieldname": "description",
'label': u'Fiscal Year', "width": "300px",
'oldfieldname': u'fiscal_year', "fieldname": "description",
'oldfieldtype': u'Select', "fieldtype": "Text",
'options': u'link:Fiscal Year', "permlevel": 0
'permlevel': 0, },
'reqd': 1 {
"amend": 1,
"create": 1,
"doctype": "DocPerm",
"submit": 1,
"write": 1,
"role": "System Manager",
"cancel": 1,
"permlevel": 0
},
{
"doctype": "DocPerm",
"role": "All",
"permlevel": 1
},
{
"amend": 1,
"create": 1,
"doctype": "DocPerm",
"submit": 1,
"write": 1,
"role": "Production Manager",
"cancel": 1,
"permlevel": 0
},
{
"amend": 1,
"create": 1,
"doctype": "DocPerm",
"submit": 1,
"write": 1,
"role": "Production User",
"cancel": 1,
"permlevel": 0
} }
] ]

View File

@ -170,39 +170,58 @@ class DocType:
msgprint("Please Enter Planned Qty for item: %s at row no: %s" % msgprint("Please Enter Planned Qty for item: %s at row no: %s" %
(d.item_code, d.idx), raise_exception=1) (d.item_code, d.idx), raise_exception=1)
def validate_bom_no(self, d): def validate_bom_no(self, d):
if not d.bom_no: if not d.bom_no:
msgprint("Please enter bom no for item: %s at row no: %s" % (d.item_code, d.idx), raise_exception=1) msgprint("Please enter bom no for item: %s at row no: %s" %
(d.item_code, d.idx), raise_exception=1)
else: else:
bom = sql("""select name from `tabBOM` where item = %s and docstatus = 1 bom = sql("""select name from `tabBOM` where name = %s and item = %s
and name = %s and ifnull(is_active, 'No') = 'Yes'""", (d.item_code, d.bom_no), as_dict = 1) and docstatus = 1 and ifnull(is_active, 'No') = 'Yes'""",
(d.bom_no, d.item_code), as_dict = 1)
if not bom: if not bom:
msgprint("""Incorrect BOM No: %s entered for item: %s at row no: %s msgprint("""Incorrect BOM No: %s entered for item: %s at row no: %s
May be BOM is inactive or for other item or does not exists in the system"""% (d.bom_no, d.item_doce, d.idx)) May be BOM is inactive or for other item or does not exists in the system""" %
(d.bom_no, d.item_doce, d.idx), raise_exception=1)
def raise_production_order(self):
"""It will raise production order (Draft) for all distinct FG items"""
self.validate_company()
self.validate_data()
items = self.get_distinct_items_and_boms()[1]
pro = get_obj('Production Control').create_production_order(items)
if pro:
msgprint("Following Production Order has been generated:\n" + '\n'.join(pro))
else :
msgprint("No Production Order generated.")
def get_distinct_items_and_boms(self):
""" Club similar BOM and item for processing"""
item_dict, bom_dict = {}, {}
for d in self.doclist.get({"parentfield": "pp_details"}):
bom_dict[d.bom_no] = bom_dict.get(d.bom_no, 0) + flt(d.planned_qty)
item_dict[(d.item_code, d.sales_order)] = {
"qty" : flt(item_dict.get((d.item_code, d.sales_order), {}).get("qty")) + \
flt(d.planned_qty),
"bom_no": d.bom_no,
"description": d.description,
"stock_uom": d.stock_uom,
"use_multi_level_bom": self.doc.use_multi_level_bom,
"company": self.doc.company,
}
return bom_dict, item_dict
def download_raw_materials(self): def download_raw_materials(self):
""" Create csv data for required raw material to produce finished goods""" """ Create csv data for required raw material to produce finished goods"""
bom_dict = self.get_distinct_bom(action = 'download_rm') bom_dict = self.get_distinct_items_and_boms()[0]
self.get_raw_materials(bom_dict) self.get_raw_materials(bom_dict)
return self.get_csv() return self.get_csv()
def get_raw_materials(self, bom_dict): def get_raw_materials(self, bom_dict):
""" Get raw materials considering sub-assembly items """ """ Get raw materials considering sub-assembly items """
for bom in bom_dict: for bom in bom_dict:
if self.doc.use_multi_level_bom == 'No': if self.doc.use_multi_level_bom:
# Get all raw materials considering SA items as raw materials,
# so no childs of SA items
fl_bom_items = sql("""
select item_code, ifnull(sum(qty_consumed_per_unit), 0) * '%s', description, stock_uom
from `tabBOM Item`
where parent = '%s' and docstatus < 2
group by item_code
""" % (flt(bom_dict[bom]), bom))
else:
# get all raw materials with sub assembly childs # get all raw materials with sub assembly childs
fl_bom_items = sql(""" fl_bom_items = sql("""
select select
@ -216,6 +235,15 @@ class DocType:
) a ) a
group by item_code,stock_uom group by item_code,stock_uom
""" , (flt(bom_dict[bom]), bom)) """ , (flt(bom_dict[bom]), bom))
else:
# Get all raw materials considering SA items as raw materials,
# so no childs of SA items
fl_bom_items = sql("""
select item_code, ifnull(sum(qty_consumed_per_unit), 0) * '%s', description, stock_uom
from `tabBOM Item`
where parent = '%s' and docstatus < 2
group by item_code
""" % (flt(bom_dict[bom]), bom))
self.make_items_dict(fl_bom_items) self.make_items_dict(fl_bom_items)
@ -239,43 +267,3 @@ class DocType:
item_list.append(['', '', '', '', 'Total', i_qty, o_qty, a_qty]) item_list.append(['', '', '', '', 'Total', i_qty, o_qty, a_qty])
return item_list return item_list
def raise_production_order(self):
"""It will raise production order (Draft) for all distinct FG items"""
self.validate_company()
self.validate_data()
pp_items = self.get_distinct_bom(action = 'raise_pro_order')
pro = get_obj(dt = 'Production Control').create_production_order(self.doc.company, pp_items)
if pro:
for d in getlist(self.doclist, 'pp_details'):
d.is_pro_created = 1
msgprint("Following Production Order has been generated:\n" + '\n'.join(pro))
else :
msgprint("No Production Order generated.")
def get_distinct_bom(self, action):
""" Club similar BOM and item for processing"""
bom_dict, item_dict, pp_items = {}, {}, []
for d in getlist(self.doclist, 'pp_details'):
if action == 'download_rm':
bom_dict[d.bom_no] = bom_dict.get(d.bom_no, 0) + flt(d.planned_qty)
elif not d.is_pro_created:
item_dict[d.item_code] = [
(flt(item_dict.get(d.item_code, [0])[0]) + flt(d.planned_qty)),
d.bom_no, d.description, d.stock_uom]
if action == 'raise_pro_order':
for d in item_dict:
pp_items.append({
'production_item' : d,
'qty' : item_dict[d][0],
'bom_no' : item_dict[d][1],
'description' : item_dict[d][2],
'stock_uom' : item_dict[d][3],
'consider_sa_items' : self.doc.use_multi_level_bom == "Yes" and "No" or "Yes"
})
return action == 'download_rm' and bom_dict or pp_items

View File

@ -4,7 +4,7 @@
"docstatus": 0, "docstatus": 0,
"creation": "2012-07-03 13:30:03", "creation": "2012-07-03 13:30:03",
"modified_by": "Administrator", "modified_by": "Administrator",
"modified": "2012-11-29 17:52:20" "modified": "2012-11-30 14:08:55"
}, },
{ {
"read_only": 1, "read_only": 1,
@ -159,15 +159,14 @@
"options": "clear_item_table" "options": "clear_item_table"
}, },
{ {
"description": "If selected as \"No\", all sub-assembly items will be treated as a raw material. Otherwise, BOM for sub-assembly items will be considered for raw materials.", "description": "If checked, BOM for sub-assembly items will be considered for raw materials. Otherwise, all sub-assembly items will be treated as a raw material.",
"default": "Yes", "default": "1",
"colour": "White:FFF", "colour": "White:FFF",
"doctype": "DocField", "doctype": "DocField",
"label": "Use multi-level BOM", "label": "Use Multi-Level BOM",
"reqd": 1, "reqd": 1,
"fieldname": "use_multi_level_bom", "fieldname": "use_multi_level_bom",
"fieldtype": "Select", "fieldtype": "Check"
"options": "No\nYes"
}, },
{ {
"doctype": "DocField", "doctype": "DocField",

View File

@ -338,8 +338,6 @@ class DocType(TransactionBase):
#update enquiry #update enquiry
self.update_enquiry_status(d.prevdoc_docname, 'Quotation Sent') self.update_enquiry_status(d.prevdoc_docname, 'Quotation Sent')
# Submit
# -------
def on_submit(self): def on_submit(self):
self.check_prev_docstatus() self.check_prev_docstatus()
self.update_stock_ledger(update_stock = 1) self.update_stock_ledger(update_stock = 1)
@ -347,17 +345,11 @@ class DocType(TransactionBase):
update_customer = sql("update `tabCustomer` set last_sales_order = '%s', modified = '%s' where name = '%s'" %(self.doc.name, self.doc.modified, self.doc.customer)) update_customer = sql("update `tabCustomer` set last_sales_order = '%s', modified = '%s' where name = '%s'" %(self.doc.name, self.doc.modified, self.doc.customer))
get_obj('Sales Common').check_credit(self,self.doc.grand_total) get_obj('Sales Common').check_credit(self,self.doc.grand_total)
# Check for Approving Authority
get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, self.doc.grand_total, self) get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, self.doc.grand_total, self)
#update prevdoc status
self.update_prevdoc_status('submit') self.update_prevdoc_status('submit')
# set SO status
set(self.doc, 'status', 'Submitted') set(self.doc, 'status', 'Submitted')
# ON CANCEL
# ===============================================================================================
def on_cancel(self): def on_cancel(self):
# Cannot cancel stopped SO # Cannot cancel stopped SO
if self.doc.status == 'Stopped': if self.doc.status == 'Stopped':
@ -366,13 +358,10 @@ class DocType(TransactionBase):
self.check_nextdoc_docstatus() self.check_nextdoc_docstatus()
self.update_stock_ledger(update_stock = -1) self.update_stock_ledger(update_stock = -1)
#update prevdoc status
self.update_prevdoc_status('cancel') self.update_prevdoc_status('cancel')
# ::::::::: SET SO STATUS ::::::::::
set(self.doc, 'status', 'Cancelled') set(self.doc, 'status', 'Cancelled')
# CHECK NEXT DOCSTATUS
# does not allow to cancel document if DN or RV made against it is SUBMITTED # does not allow to cancel document if DN or RV made against it is SUBMITTED
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
def check_nextdoc_docstatus(self): def check_nextdoc_docstatus(self):
@ -380,18 +369,28 @@ class DocType(TransactionBase):
submit_dn = sql("select t1.name from `tabDelivery Note` t1,`tabDelivery Note Item` t2 where t1.name = t2.parent and t2.prevdoc_docname = '%s' and t1.docstatus = 1" % (self.doc.name)) submit_dn = sql("select t1.name from `tabDelivery Note` t1,`tabDelivery Note Item` t2 where t1.name = t2.parent and t2.prevdoc_docname = '%s' and t1.docstatus = 1" % (self.doc.name))
if submit_dn: if submit_dn:
msgprint("Delivery Note : " + cstr(submit_dn[0][0]) + " has been submitted against " + cstr(self.doc.doctype) + ". Please cancel Delivery Note : " + cstr(submit_dn[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1) msgprint("Delivery Note : " + cstr(submit_dn[0][0]) + " has been submitted against " + cstr(self.doc.doctype) + ". Please cancel Delivery Note : " + cstr(submit_dn[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1)
# Checks Sales Invoice # Checks Sales Invoice
submit_rv = sql("select t1.name from `tabSales Invoice` t1,`tabSales Invoice Item` t2 where t1.name = t2.parent and t2.sales_order = '%s' and t1.docstatus = 1" % (self.doc.name)) submit_rv = sql("select t1.name from `tabSales Invoice` t1,`tabSales Invoice Item` t2 where t1.name = t2.parent and t2.sales_order = '%s' and t1.docstatus = 1" % (self.doc.name))
if submit_rv: if submit_rv:
msgprint("Sales Invoice : " + cstr(submit_rv[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Sales Invoice : "+ cstr(submit_rv[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1) msgprint("Sales Invoice : " + cstr(submit_rv[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Sales Invoice : "+ cstr(submit_rv[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1)
#check maintenance schedule #check maintenance schedule
submit_ms = sql("select t1.name from `tabMaintenance Schedule` t1, `tabMaintenance Schedule Item` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name) submit_ms = sql("select t1.name from `tabMaintenance Schedule` t1, `tabMaintenance Schedule Item` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name)
if submit_ms: if submit_ms:
msgprint("Maintenance Schedule : " + cstr(submit_ms[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Maintenance Schedule : "+ cstr(submit_ms[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1) msgprint("Maintenance Schedule : " + cstr(submit_ms[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Maintenance Schedule : "+ cstr(submit_ms[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1)
# check maintenance visit
submit_mv = sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name) submit_mv = sql("select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2 where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1",self.doc.name)
if submit_mv: if submit_mv:
msgprint("Maintenance Visit : " + cstr(submit_mv[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Maintenance Visit : " + cstr(submit_mv[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1) msgprint("Maintenance Visit : " + cstr(submit_mv[0][0]) + " has already been submitted against " +cstr(self.doc.doctype)+ ". Please cancel Maintenance Visit : " + cstr(submit_mv[0][0]) + " first and then cancel "+ cstr(self.doc.doctype), raise_exception = 1)
# check production order
pro_order = sql("""select name from `tabProduction Order` where sales_order = %s and docstatus = 1""", self.doc.name)
if pro_order:
msgprint("""Production Order: %s exists against this sales order.
Please cancel production order first and then cancel this sales order""" %
pro_order[0][0], raise_exception=1)
def check_modified_date(self): def check_modified_date(self):
mod_db = sql("select modified from `tabSales Order` where name = '%s'" % self.doc.name) mod_db = sql("select modified from `tabSales Order` where name = '%s'" % self.doc.name)

View File

@ -154,25 +154,13 @@ class DocType(TransactionBase):
def get_raw_materials(self, bom_no, fg_qty, consider_sa_items_as_rm): def get_raw_materials(self, bom_no, fg_qty, use_multi_level_bom):
""" """
get all items from flat bom except get all items from flat bom except
child items of sub-contracted and sub assembly items child items of sub-contracted and sub assembly items
and sub assembly items itself. and sub assembly items itself.
""" """
if consider_sa_items_as_rm == 'Yes': if use_multi_level_bom:
# Get all raw materials considering SA items as raw materials,
# so no childs of SA items
fl_bom_sa_items = sql("""
select item_code, ifnull(sum(qty_consumed_per_unit), 0) * '%s', description, stock_uom
from `tabBOM Item`
where parent = '%s' and docstatus < 2
group by item_code
""" % (fg_qty, bom_no))
self.make_items_dict(fl_bom_sa_items)
else:
# get all raw materials with sub assembly childs # get all raw materials with sub assembly childs
fl_bom_sa_child_item = sql(""" fl_bom_sa_child_item = sql("""
select select
@ -187,6 +175,17 @@ class DocType(TransactionBase):
group by item_code,stock_uom group by item_code,stock_uom
""" , (fg_qty, bom_no)) """ , (fg_qty, bom_no))
self.make_items_dict(fl_bom_sa_child_item) self.make_items_dict(fl_bom_sa_child_item)
else:
# Get all raw materials considering multi level BOM,
# if multi level bom consider childs of Sub-Assembly items
fl_bom_sa_items = sql("""
select item_code, ifnull(sum(qty_consumed_per_unit), 0) * '%s', description, stock_uom
from `tabBOM Item`
where parent = '%s' and docstatus < 2
group by item_code
""" % (fg_qty, bom_no))
self.make_items_dict(fl_bom_sa_items)
# Update only qty remaining to be issued for production # Update only qty remaining to be issued for production
if self.doc.process == 'Material Transfer': if self.doc.process == 'Material Transfer':
@ -214,12 +213,8 @@ class DocType(TransactionBase):
if self.doc.bom_no: if self.doc.bom_no:
if not self.doc.fg_completed_qty: if not self.doc.fg_completed_qty:
msgprint("Please enter FG Completed Qty", raise_exception=1) msgprint("Please enter FG Completed Qty", raise_exception=1)
if not self.doc.consider_sa_items_as_raw_materials:
msgprint("Please confirm whether you want to consider sub assembly item as raw materials", raise_exception=1)
# get items
#------------------
def get_items(self): def get_items(self):
if self.doc.purpose == 'Production Order': if self.doc.purpose == 'Production Order':
pro_obj = self.doc.production_order and get_obj('Production Order', self.doc.production_order) or '' pro_obj = self.doc.production_order and get_obj('Production Order', self.doc.production_order) or ''
@ -227,14 +222,14 @@ class DocType(TransactionBase):
bom_no = pro_obj.doc.bom_no bom_no = pro_obj.doc.bom_no
fg_qty = (self.doc.process == 'Backflush') and flt(self.doc.fg_completed_qty) or flt(pro_obj.doc.qty) fg_qty = (self.doc.process == 'Backflush') and flt(self.doc.fg_completed_qty) or flt(pro_obj.doc.qty)
consider_sa_items_as_rm = pro_obj.doc.consider_sa_items use_multi_level_bom = pro_obj.doc.use_multi_level_bom
elif self.doc.purpose == 'Other': elif self.doc.purpose == 'Other':
self.validate_bom_no() self.validate_bom_no()
bom_no = self.doc.bom_no bom_no = self.doc.bom_no
fg_qty = self.doc.fg_completed_qty fg_qty = self.doc.fg_completed_qty
consider_sa_items_as_rm = self.doc.consider_sa_items_as_raw_materials use_multi_level_bom = self.doc.use_multi_level_bom
self.get_raw_materials(bom_no, fg_qty, consider_sa_items_as_rm) self.get_raw_materials(bom_no, fg_qty, use_multi_level_bom)
self.doclist = self.doc.clear_table(self.doclist, 'mtn_details', 1) self.doclist = self.doc.clear_table(self.doclist, 'mtn_details', 1)
sw = (self.doc.process == 'Backflush') and cstr(pro_obj.doc.wip_warehouse) or '' sw = (self.doc.process == 'Backflush') and cstr(pro_obj.doc.wip_warehouse) or ''

View File

@ -2,9 +2,9 @@
{ {
"owner": "Administrator", "owner": "Administrator",
"docstatus": 0, "docstatus": 0,
"creation": "2012-11-02 17:16:56", "creation": "2012-11-28 11:26:22",
"modified_by": "Administrator", "modified_by": "Administrator",
"modified": "2012-11-26 11:51:08" "modified": "2012-11-30 14:10:02"
}, },
{ {
"is_submittable": 1, "is_submittable": 1,
@ -195,14 +195,13 @@
"permlevel": 0 "permlevel": 0
}, },
{ {
"description": "Select \"Yes\" if stock is maintained and tracked for sub-assembly items. Select \"No\" if you want child items of sub-assembly for material transfer.", "description": "If checked, BOM for sub-assembly items will be considered for getting raw materials. Otherwise, all sub-assembly items will be treated as a raw material.",
"depends_on": "eval:doc.purpose == 'Other'", "depends_on": "eval:doc.purpose == 'Other'",
"colour": "White:FFF", "colour": "White:FFF",
"doctype": "DocField", "doctype": "DocField",
"label": "Consider SA Items as Raw Materials", "label": "Use Multi-Level BOM",
"options": "\nNo\nYes", "fieldname": "use_multi_level_bom",
"fieldname": "consider_sa_items_as_raw_materials", "fieldtype": "Check",
"fieldtype": "Select",
"permlevel": 0 "permlevel": 0
}, },
{ {