Production cleanup with linking with sales order
diff --git a/production/doctype/production_control/production_control.py b/production/doctype/production_control/production_control.py
index ef01cb1..4cb6030 100644
--- a/production/doctype/production_control/production_control.py
+++ b/production/doctype/production_control/production_control.py
@@ -73,7 +73,7 @@
 
 
 	#	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"""
 					 
 		default_values = { 
@@ -82,15 +82,20 @@
 			'wip_warehouse'		: '',
 			'fg_warehouse'		: '',
 			'status'			: 'Draft',
-			'company'			: company,
-			'fiscal_year'		: get_defaults()['fiscal_year'] 
+			'fiscal_year'		: get_defaults()['fiscal_year']
 		}
 		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')
-			for key in d.keys():
-				pro_doc.fields[key] = d[key]
+			pro_doc.production_item = item_so[0]
+			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:
 				pro_doc.fields[key] = default_values[key]
@@ -100,7 +105,30 @@
 			
 		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):
 		main_bom_list = self.traverse_bom_tree(bom_no, 1)
 		main_bom_list.reverse()
@@ -113,4 +141,4 @@
 				bom_obj.update_flat_bom_engine()
 				bom_obj.doc.docstatus = 1
 				bom_obj.doc.save()
-				self.check_bom_list.append(bom)
+				self.check_bom_list.append(bom)
\ No newline at end of file
diff --git a/production/doctype/production_order/production_order.js b/production/doctype/production_order/production_order.js
index 411f779..7949757 100644
--- a/production/doctype/production_order/production_order.js
+++ b/production/doctype/production_order/production_order.js
@@ -18,15 +18,7 @@
 cur_frm.cscript.onload = function(doc, dt, dn) {
   if (!doc.posting_date) doc.transaction_date = dateutil.obj_to_str(new Date());
   if (!doc.status) doc.status = 'Draft';
-
   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 ==========================================
@@ -48,15 +40,10 @@
   }
 }
 
-
-// ==================================================================================================
-
 cur_frm.cscript.production_item = function(doc, dt, dn) {
   get_server_fields('get_item_detail',doc.production_item,'',doc,dt,dn,1);
 }
 
-// Stop PRODUCTION ORDER
-//
 cur_frm.cscript['Stop Production Order'] = function() {
   var doc = cur_frm.doc;
   var check = confirm("Do you really want to stop production order: " + doc.name);
@@ -65,8 +52,6 @@
 	}
 }
 
-// Unstop PRODUCTION ORDER
-//
 cur_frm.cscript['Unstop Production Order'] = function() {
   var doc = cur_frm.doc;
   var check = confirm("Do really want to unstop production order: " + doc.name);
@@ -97,8 +82,6 @@
   loaddoc('Stock Entry', se.name);
 }
 
-
-// ==================================================================================================
 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';
 }
diff --git a/production/doctype/production_order/production_order.py b/production/doctype/production_order/production_order.py
index 05eaa75..fd9a614 100644
--- a/production/doctype/production_order/production_order.py
+++ b/production/doctype/production_order/production_order.py
@@ -72,6 +72,14 @@
 				msgprint("""Incorrect BOM: %s entered. 
 					May be BOM not exists or inactive or not submitted 
 					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):
diff --git a/production/doctype/production_order/production_order.txt b/production/doctype/production_order/production_order.txt
index c244399..369efd4 100644
--- a/production/doctype/production_order/production_order.txt
+++ b/production/doctype/production_order/production_order.txt
@@ -1,358 +1,324 @@
-# DocType, Production Order
 [
-
-	# These values are common in all dictionaries
-	{
-		'creation': '2012-05-15 12:14:48',
-		'docstatus': 0,
-		'modified': '2012-05-28 19:03:56',
-		'modified_by': u'Administrator',
-		'owner': u'Administrator'
-	},
-
-	# These values are common for all DocType
-	{
-		'_last_update': u'1325837006',
-		'colour': u'White:FFF',
-		'default_print_format': u'Standard',
-		'doctype': 'DocType',
-		'in_create': 0,
-		'is_submittable': 1,
-		'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__',
-		'parent': u'Production Order',
-		'parentfield': u'fields',
-		'parenttype': u'DocType'
-	},
-
-	# These values are common for all DocPerm
-	{
-		'doctype': u'DocPerm',
-		'name': '__common__',
-		'parent': u'Production Order',
-		'parentfield': u'permissions',
-		'parenttype': u'DocType',
-		'read': 1
-	},
-
-	# DocType, Production Order
-	{
-		'doctype': 'DocType',
-		'name': u'Production Order'
-	},
-
-	# DocPerm
-	{
-		'amend': 1,
-		'cancel': 1,
-		'create': 1,
-		'doctype': u'DocPerm',
-		'permlevel': 0,
-		'role': u'System Manager',
-		'submit': 1,
-		'write': 1
-	},
-
-	# DocPerm
-	{
-		'doctype': u'DocPerm',
-		'permlevel': 1,
-		'role': u'All'
-	},
-
-	# DocPerm
-	{
-		'amend': 1,
-		'cancel': 1,
-		'create': 1,
-		'doctype': u'DocPerm',
-		'permlevel': 0,
-		'role': u'Production Manager',
-		'submit': 1,
-		'write': 1
-	},
-
-	# DocPerm
-	{
-		'amend': 1,
-		'cancel': 1,
-		'create': 1,
-		'doctype': u'DocPerm',
-		'permlevel': 0,
-		'role': u'Production User',
-		'submit': 1,
-		'write': 1
-	},
-
-	# DocField
-	{
-		'doctype': u'DocField',
-		'fieldname': u'column_break0',
-		'fieldtype': u'Column Break',
-		'permlevel': 0,
-		'width': u'50%'
-	},
-
-	# DocField
-	{
-		'colour': u'White:FFF',
-		'description': u'Item for which this Production Order is raised.',
-		'doctype': u'DocField',
-		'fieldname': u'production_item',
-		'fieldtype': u'Link',
-		'in_filter': 1,
-		'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',
-		'fieldname': u'description',
-		'fieldtype': u'Text',
-		'label': u'Description',
-		'oldfieldname': u'description',
-		'oldfieldtype': u'Text',
-		'permlevel': 0,
-		'width': u'300px'
-	},
-
-	# DocField
-	{
-		'doctype': u'DocField',
-		'fieldname': u'stock_uom',
-		'fieldtype': u'Data',
-		'label': u'Stock UOM',
-		'oldfieldname': u'stock_uom',
-		'oldfieldtype': u'Data',
-		'permlevel': 1
-	},
-
-	# DocField
-	{
-		'colour': u'White:FFF',
-		'description': u'Bill of Material which was considered for manufacturing the production item.',
-		'doctype': u'DocField',
-		'fieldname': u'bom_no',
-		'fieldtype': u'Link',
-		'label': u'BOM No',
-		'oldfieldname': u'bom_no',
-		'oldfieldtype': u'Link',
-		'options': u'BOM',
-		'permlevel': 1,
-		'reqd': 1,
-		'trigger': u'Client'
-	},
-
-	# DocField
-	{
-		'colour': u'White:FFF',
-		'description': u'Quantity of item for which Production Order is raised.',
-		'doctype': u'DocField',
-		'fieldname': u'qty',
-		'fieldtype': u'Currency',
-		'label': u'Qty',
-		'oldfieldname': u'qty',
-		'oldfieldtype': u'Currency',
-		'permlevel': 0,
-		'reqd': 1
-	},
-
-	# DocField
-	{
-		'colour': u'White:FFF',
-		'description': u'The warehouse for finished goods where stock of produced items will be updated.',
-		'doctype': u'DocField',
-		'fieldname': u'fg_warehouse',
-		'fieldtype': u'Link',
-		'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',
-		'description': u'The work in progress warehouse where raw materials will be operated upon to create finished goods.',
-		'doctype': u'DocField',
-		'fieldname': u'wip_warehouse',
-		'fieldtype': u'Link',
-		'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',
-		'fieldname': u'amended_from',
-		'fieldtype': u'Data',
-		'label': u'Amended From',
-		'no_copy': 1,
-		'oldfieldname': u'amended_from',
-		'oldfieldtype': u'Data',
-		'permlevel': 1
-	},
-
-	# DocField
-	{
-		'doctype': u'DocField',
-		'fieldname': u'amendment_date',
-		'fieldtype': u'Date',
-		'label': u'Amendment Date',
-		'no_copy': 1,
-		'oldfieldname': u'amendment_date',
-		'oldfieldtype': u'Date',
-		'permlevel': 1
-	},
-
-	# DocField
-	{
-		'doctype': u'DocField',
-		'fieldname': u'column_break1',
-		'fieldtype': u'Column Break',
-		'oldfieldtype': u'Column Break',
-		'permlevel': 0,
-		'width': u'50%'
-	},
-
-	# DocField
-	{
-		'colour': u'White:FFF',
-		'description': u'The date on which current entry will get or has actually executed.',
-		'doctype': u'DocField',
-		'fieldname': u'posting_date',
-		'fieldtype': u'Date',
-		'label': u'Posting Date',
-		'oldfieldname': u'posting_date',
-		'oldfieldtype': u'Date',
-		'permlevel': 0,
-		'reqd': 1
-	},
-
-	# DocField
-	{
-		'colour': u'White:FFF',
-		'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': u'DocField',
-		'fieldname': u'consider_sa_items',
-		'fieldtype': u'Select',
-		'in_filter': 1,
-		'label': u'Consider SA Items as raw material',
-		'oldfieldname': u'consider_sa_items',
-		'oldfieldtype': u'Select',
-		'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',
-		'doctype': u'DocField',
-		'fieldname': u'project_name',
-		'fieldtype': u'Link',
-		'in_filter': 1,
-		'label': u'Project Name',
-		'oldfieldname': u'project_name',
-		'oldfieldtype': u'Link',
-		'options': u'Project',
-		'permlevel': 0,
-		'trigger': u'Client'
-	},
-
-	# DocField
-	{
-		'doctype': u'DocField',
-		'fieldname': u'origin',
-		'fieldtype': u'Select',
-		'in_filter': 1,
-		'label': u'Origin',
-		'no_copy': 1,
-		'oldfieldname': u'origin',
-		'oldfieldtype': u'Select',
-		'options': u'Manual\nMRP',
-		'permlevel': 1,
-		'reqd': 1
-	},
-
-	# DocField
-	{
-		'doctype': u'DocField',
-		'fieldname': u'status',
-		'fieldtype': u'Select',
-		'in_filter': 1,
-		'label': u'Status',
-		'no_copy': 1,
-		'oldfieldname': u'status',
-		'oldfieldtype': u'Select',
-		'options': u'\nDraft\nSubmitted\nStopped\nIn Process\nCompleted\nCancelled',
-		'permlevel': 1,
-		'reqd': 1,
-		'search_index': 1
-	},
-
-	# DocField
-	{
-		'colour': u'White:FFF',
-		'description': u'Updated after finished goods are transferred to FG Warehouse through Stock Entry',
-		'doctype': u'DocField',
-		'fieldname': u'produced_qty',
-		'fieldtype': u'Currency',
-		'label': u'Produced Qty',
-		'no_copy': 1,
-		'oldfieldname': u'produced_qty',
-		'oldfieldtype': u'Currency',
-		'permlevel': 1
-	},
-
-	# DocField
-	{
-		'doctype': u'DocField',
-		'fieldname': u'company',
-		'fieldtype': u'Link',
-		'label': u'Company',
-		'oldfieldname': u'company',
-		'oldfieldtype': u'Link',
-		'options': u'Company',
-		'permlevel': 0,
-		'reqd': 1
-	},
-
-	# DocField
-	{
-		'doctype': u'DocField',
-		'fieldname': u'fiscal_year',
-		'fieldtype': u'Select',
-		'in_filter': 1,
-		'label': u'Fiscal Year',
-		'oldfieldname': u'fiscal_year',
-		'oldfieldtype': u'Select',
-		'options': u'link:Fiscal Year',
-		'permlevel': 0,
-		'reqd': 1
-	}
+ {
+  "owner": "Administrator", 
+  "docstatus": 0, 
+  "creation": "2012-07-03 13:30:03", 
+  "modified_by": "Administrator", 
+  "modified": "2012-11-30 14:28:03"
+ }, 
+ {
+  "is_submittable": 1, 
+  "in_create": 0, 
+  "default_print_format": "Standard", 
+  "doctype": "DocType", 
+  "module": "Production", 
+  "name": "__common__"
+ }, 
+ {
+  "name": "__common__", 
+  "parent": "Production Order", 
+  "doctype": "DocField", 
+  "parenttype": "DocType", 
+  "parentfield": "fields"
+ }, 
+ {
+  "name": "__common__", 
+  "parent": "Production Order", 
+  "read": 1, 
+  "doctype": "DocPerm", 
+  "parenttype": "DocType", 
+  "parentfield": "permissions"
+ }, 
+ {
+  "name": "Production Order", 
+  "doctype": "DocType"
+ }, 
+ {
+  "doctype": "DocField", 
+  "width": "50%", 
+  "fieldname": "column_break0", 
+  "fieldtype": "Column Break", 
+  "permlevel": 0
+ }, 
+ {
+  "description": "Item for which this Production Order is raised.", 
+  "oldfieldtype": "Link", 
+  "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"
+ }, 
+ {
+  "description": "Bill of Material which was considered for manufacturing the production item.", 
+  "oldfieldtype": "Link", 
+  "colour": "White:FFF", 
+  "doctype": "DocField", 
+  "label": "BOM No", 
+  "oldfieldname": "bom_no", 
+  "permlevel": 0, 
+  "trigger": "Client", 
+  "fieldname": "bom_no", 
+  "fieldtype": "Link", 
+  "reqd": 1, 
+  "options": "BOM"
+ }, 
+ {
+  "description": "Quantity of item for which Production Order is raised.", 
+  "oldfieldtype": "Currency", 
+  "colour": "White:FFF", 
+  "doctype": "DocField", 
+  "label": "Qty", 
+  "oldfieldname": "qty", 
+  "fieldname": "qty", 
+  "fieldtype": "Currency", 
+  "reqd": 1, 
+  "permlevel": 0
+ }, 
+ {
+  "description": "The date on which current entry will get or has actually executed.", 
+  "oldfieldtype": "Date", 
+  "colour": "White:FFF", 
+  "doctype": "DocField", 
+  "label": "Posting Date", 
+  "oldfieldname": "posting_date", 
+  "fieldname": "posting_date", 
+  "fieldtype": "Date", 
+  "reqd": 1, 
+  "permlevel": 0
+ }, 
+ {
+  "oldfieldtype": "Column Break", 
+  "doctype": "DocField", 
+  "width": "50%", 
+  "fieldname": "column_break1", 
+  "fieldtype": "Column Break", 
+  "permlevel": 0
+ }, 
+ {
+  "description": "The warehouse for finished goods where stock of produced items will be updated.", 
+  "oldfieldtype": "Link", 
+  "colour": "White:FFF", 
+  "doctype": "DocField", 
+  "label": "FG Warehouse", 
+  "oldfieldname": "fg_warehouse", 
+  "permlevel": 0, 
+  "fieldname": "fg_warehouse", 
+  "fieldtype": "Link", 
+  "reqd": 1, 
+  "in_filter": 1, 
+  "options": "Warehouse"
+ }, 
+ {
+  "description": "The work in progress warehouse where raw materials will be operated upon to create finished goods.", 
+  "oldfieldtype": "Link", 
+  "colour": "White:FFF", 
+  "doctype": "DocField", 
+  "label": "WIP Warehouse", 
+  "oldfieldname": "wip_warehouse", 
+  "permlevel": 0, 
+  "fieldname": "wip_warehouse", 
+  "fieldtype": "Link", 
+  "reqd": 1, 
+  "in_filter": 1, 
+  "options": "Warehouse"
+ }, 
+ {
+  "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.", 
+  "default": "1", 
+  "oldfieldtype": "Select", 
+  "colour": "White:FFF", 
+  "doctype": "DocField", 
+  "label": "Use Multi-Level BOM", 
+  "oldfieldname": "consider_sa_items", 
+  "fieldname": "use_multi_level_bom", 
+  "fieldtype": "Check", 
+  "reqd": 1, 
+  "in_filter": 1, 
+  "permlevel": 0
+ }, 
+ {
+  "description": "Updated after finished goods are transferred to FG Warehouse through Stock Entry", 
+  "no_copy": 1, 
+  "oldfieldtype": "Currency", 
+  "colour": "White:FFF", 
+  "doctype": "DocField", 
+  "label": "Produced Qty", 
+  "oldfieldname": "produced_qty", 
+  "fieldname": "produced_qty", 
+  "fieldtype": "Currency", 
+  "permlevel": 1
+ }, 
+ {
+  "doctype": "DocField", 
+  "label": "More Info", 
+  "fieldname": "more_info", 
+  "fieldtype": "Section Break", 
+  "permlevel": 0
+ }, 
+ {
+  "doctype": "DocField", 
+  "width": "50%", 
+  "fieldname": "column_break2", 
+  "fieldtype": "Column Break", 
+  "permlevel": 0
+ }, 
+ {
+  "no_copy": 1, 
+  "oldfieldtype": "Select", 
+  "doctype": "DocField", 
+  "label": "Origin", 
+  "oldfieldname": "origin", 
+  "options": "Manual\nMRP", 
+  "fieldname": "origin", 
+  "fieldtype": "Select", 
+  "reqd": 1, 
+  "permlevel": 0, 
+  "in_filter": 1
+ }, 
+ {
+  "no_copy": 1, 
+  "oldfieldtype": "Select", 
+  "doctype": "DocField", 
+  "label": "Status", 
+  "oldfieldname": "status", 
+  "permlevel": 1, 
+  "fieldname": "status", 
+  "fieldtype": "Select", 
+  "search_index": 1, 
+  "reqd": 1, 
+  "options": "\nDraft\nSubmitted\nStopped\nIn Process\nCompleted\nCancelled", 
+  "in_filter": 1
+ }, 
+ {
+  "doctype": "DocField", 
+  "label": "Sales Order", 
+  "options": "Sales Order", 
+  "fieldname": "sales_order", 
+  "fieldtype": "Link", 
+  "permlevel": 0
+ }, 
+ {
+  "description": "Select name of the project if Production Order need to be created against any project", 
+  "oldfieldtype": "Link", 
+  "label": "Project Name", 
+  "oldfieldname": "project_name", 
+  "trigger": "Client", 
+  "fieldname": "project_name", 
+  "fieldtype": "Link", 
+  "doctype": "DocField", 
+  "options": "Project", 
+  "permlevel": 0, 
+  "in_filter": 1
+ }, 
+ {
+  "oldfieldtype": "Link", 
+  "doctype": "DocField", 
+  "label": "Company", 
+  "oldfieldname": "company", 
+  "options": "Company", 
+  "fieldname": "company", 
+  "fieldtype": "Link", 
+  "reqd": 1, 
+  "permlevel": 0
+ }, 
+ {
+  "oldfieldtype": "Select", 
+  "doctype": "DocField", 
+  "label": "Fiscal Year", 
+  "oldfieldname": "fiscal_year", 
+  "options": "link:Fiscal Year", 
+  "fieldname": "fiscal_year", 
+  "fieldtype": "Select", 
+  "reqd": 1, 
+  "permlevel": 0, 
+  "in_filter": 1
+ }, 
+ {
+  "no_copy": 1, 
+  "oldfieldtype": "Data", 
+  "doctype": "DocField", 
+  "label": "Amended From", 
+  "oldfieldname": "amended_from", 
+  "fieldname": "amended_from", 
+  "fieldtype": "Data", 
+  "permlevel": 1
+ }, 
+ {
+  "no_copy": 1, 
+  "oldfieldtype": "Date", 
+  "doctype": "DocField", 
+  "label": "Amendment Date", 
+  "oldfieldname": "amendment_date", 
+  "fieldname": "amendment_date", 
+  "fieldtype": "Date", 
+  "permlevel": 1
+ }, 
+ {
+  "doctype": "DocField", 
+  "width": "50%", 
+  "fieldname": "column_break3", 
+  "fieldtype": "Column Break", 
+  "permlevel": 0
+ }, 
+ {
+  "oldfieldtype": "Data", 
+  "doctype": "DocField", 
+  "label": "Stock UOM", 
+  "oldfieldname": "stock_uom", 
+  "fieldname": "stock_uom", 
+  "fieldtype": "Data", 
+  "permlevel": 1
+ }, 
+ {
+  "oldfieldtype": "Text", 
+  "doctype": "DocField", 
+  "label": "Production Item Description", 
+  "oldfieldname": "description", 
+  "width": "300px", 
+  "fieldname": "description", 
+  "fieldtype": "Text", 
+  "permlevel": 0
+ }, 
+ {
+  "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
+ }
 ]
\ No newline at end of file
diff --git a/production/doctype/production_planning_tool/production_planning_tool.py b/production/doctype/production_planning_tool/production_planning_tool.py
index 10ef652..598df42 100644
--- a/production/doctype/production_planning_tool/production_planning_tool.py
+++ b/production/doctype/production_planning_tool/production_planning_tool.py
@@ -170,39 +170,58 @@
 				msgprint("Please Enter Planned Qty for item: %s at row no: %s" %
 					(d.item_code, d.idx), raise_exception=1)
 				
-
 	def validate_bom_no(self, d):
 		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:
-			bom = sql("""select name from `tabBOM` where item = %s and docstatus = 1 
-				and name = %s and ifnull(is_active, 'No') = 'Yes'""", (d.item_code, d.bom_no), as_dict = 1)
+			bom = sql("""select name from `tabBOM` where name = %s and item = %s 
+				and docstatus = 1 and ifnull(is_active, 'No') = 'Yes'""", 
+				(d.bom_no, d.item_code), as_dict = 1)
 			if not bom:
 				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):
 		""" 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)
 		return self.get_csv()
 
 	def get_raw_materials(self, bom_dict):
 		""" Get raw materials considering sub-assembly items """
 		for bom in bom_dict:
-			if self.doc.use_multi_level_bom == 'No':
-				# 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:
+			if self.doc.use_multi_level_bom:
 				# get all raw materials with sub assembly childs					
 				fl_bom_items = sql("""
 					select 
@@ -216,7 +235,16 @@
 						) a
 					group by item_code,stock_uom
 				""" , (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)
 
 
@@ -238,44 +266,4 @@
 			if item_qty:
 				item_list.append(['', '', '', '', 'Total', i_qty, o_qty, a_qty])
 
-		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
\ No newline at end of file
+		return item_list
\ No newline at end of file
diff --git a/production/doctype/production_planning_tool/production_planning_tool.txt b/production/doctype/production_planning_tool/production_planning_tool.txt
index 3add84b..42a76f7 100644
--- a/production/doctype/production_planning_tool/production_planning_tool.txt
+++ b/production/doctype/production_planning_tool/production_planning_tool.txt
@@ -4,7 +4,7 @@
   "docstatus": 0, 
   "creation": "2012-07-03 13:30:03", 
   "modified_by": "Administrator", 
-  "modified": "2012-11-29 17:52:20"
+  "modified": "2012-11-30 14:08:55"
  }, 
  {
   "read_only": 1, 
@@ -159,15 +159,14 @@
   "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.", 
-  "default": "Yes", 
+  "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": "1", 
   "colour": "White:FFF", 
   "doctype": "DocField", 
-  "label": "Use multi-level BOM", 
+  "label": "Use Multi-Level BOM", 
   "reqd": 1, 
   "fieldname": "use_multi_level_bom", 
-  "fieldtype": "Select", 
-  "options": "No\nYes"
+  "fieldtype": "Check"
  }, 
  {
   "doctype": "DocField", 
diff --git a/selling/doctype/sales_order/sales_order.py b/selling/doctype/sales_order/sales_order.py
index a79c847..a511d4b 100644
--- a/selling/doctype/sales_order/sales_order.py
+++ b/selling/doctype/sales_order/sales_order.py
@@ -337,9 +337,7 @@
 						
 						#update enquiry
 						self.update_enquiry_status(d.prevdoc_docname, 'Quotation Sent')
-	
-	# Submit
-	# -------
+
 	def on_submit(self):
 		self.check_prev_docstatus()		
 		self.update_stock_ledger(update_stock = 1)
@@ -347,17 +345,11 @@
 		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)
 		
-		# Check for Approving Authority
 		get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, self.doc.grand_total, self)
 		
-		#update prevdoc status
 		self.update_prevdoc_status('submit')
-		# set SO status
 		set(self.doc, 'status', 'Submitted')
 	
- 
-# ON CANCEL
-# ===============================================================================================
 	def on_cancel(self):
 		# Cannot cancel stopped SO
 		if self.doc.status == 'Stopped':
@@ -366,13 +358,10 @@
 		self.check_nextdoc_docstatus()
 		self.update_stock_ledger(update_stock = -1)
 		
-		#update prevdoc status
 		self.update_prevdoc_status('cancel')
 		
-		# ::::::::: SET SO STATUS ::::::::::
 		set(self.doc, 'status', 'Cancelled')
 		
-	# CHECK NEXT DOCSTATUS
 	# does not allow to cancel document if DN or RV made against it is SUBMITTED 
 	# ----------------------------------------------------------------------------
 	def check_nextdoc_docstatus(self):
@@ -380,18 +369,28 @@
 		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:
 			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
 		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:
 			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
 		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:
 			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)
 		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)
-
+		
+		# 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):
 		mod_db = sql("select modified from `tabSales Order` where name = '%s'" % self.doc.name)
diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py
index cc3acfe..701f27d 100644
--- a/stock/doctype/stock_entry/stock_entry.py
+++ b/stock/doctype/stock_entry/stock_entry.py
@@ -154,25 +154,13 @@
 
 
 
-	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 
 			child items of sub-contracted and sub assembly items 
 			and sub assembly items itself.
 		"""
-		if consider_sa_items_as_rm == 'Yes':
-			# 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:
+		if use_multi_level_bom:
 			# get all raw materials with sub assembly childs					
 			fl_bom_sa_child_item = sql("""
 				select 
@@ -187,6 +175,17 @@
 				group by item_code,stock_uom
 			""" , (fg_qty, bom_no))
 			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
 		if self.doc.process == 'Material Transfer':
@@ -214,12 +213,8 @@
 		if self.doc.bom_no:
 			if not self.doc.fg_completed_qty:
 				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):
 		if self.doc.purpose == 'Production Order':
 			pro_obj = self.doc.production_order and get_obj('Production Order', self.doc.production_order) or ''	
@@ -227,14 +222,14 @@
 
 			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)
-			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':
 			self.validate_bom_no()
 			bom_no = self.doc.bom_no
 			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)
 
 		sw = (self.doc.process == 'Backflush') and cstr(pro_obj.doc.wip_warehouse) or ''
diff --git a/stock/doctype/stock_entry/stock_entry.txt b/stock/doctype/stock_entry/stock_entry.txt
index f77808e..24412b8 100644
--- a/stock/doctype/stock_entry/stock_entry.txt
+++ b/stock/doctype/stock_entry/stock_entry.txt
@@ -2,9 +2,9 @@
  {
   "owner": "Administrator", 
   "docstatus": 0, 
-  "creation": "2012-11-02 17:16:56", 
+  "creation": "2012-11-28 11:26:22", 
   "modified_by": "Administrator", 
-  "modified": "2012-11-26 11:51:08"
+  "modified": "2012-11-30 14:10:02"
  }, 
  {
   "is_submittable": 1, 
@@ -195,14 +195,13 @@
   "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'", 
   "colour": "White:FFF", 
   "doctype": "DocField", 
-  "label": "Consider SA Items as Raw Materials", 
-  "options": "\nNo\nYes", 
-  "fieldname": "consider_sa_items_as_raw_materials", 
-  "fieldtype": "Select", 
+  "label": "Use Multi-Level BOM", 
+  "fieldname": "use_multi_level_bom", 
+  "fieldtype": "Check", 
   "permlevel": 0
  }, 
  {