Merge branch 'master' of github.com:webnotes/erpnext
diff --git a/manufacturing/doctype/production_order/production_order.js b/manufacturing/doctype/production_order/production_order.js
index 012c279..f680776 100644
--- a/manufacturing/doctype/production_order/production_order.js
+++ b/manufacturing/doctype/production_order/production_order.js
@@ -61,30 +61,25 @@
 }
 
 cur_frm.cscript['Transfer Raw Materials'] = function() {
-	var doc = cur_frm.doc;
-	cur_frm.cscript.make_se(doc, 'Material Transfer');
+	cur_frm.cscript.make_se('Material Transfer');
 }
 
 cur_frm.cscript['Update Finished Goods'] = function() {
-	var doc = cur_frm.doc;
-	cur_frm.cscript.make_se(doc, 'Manufacture/Repack');
+	cur_frm.cscript.make_se('Manufacture/Repack');
 }
 
-cur_frm.cscript.make_se = function(doc, purpose) {
-	var se = wn.model.get_new_doc("Stock Entry");
-	se.purpose = purpose;
-	se.production_order = doc.name;
-	if(purpose==="Material Transfer") {
-		se.to_warehouse = doc.wip_warehouse;
-	} else {
-		se.from_warehouse = doc.wip_warehouse;
-		se.to_warehouse = doc.fg_warehouse;
-	}
-	se.company = doc.company;
-	se.fg_completed_qty = doc.qty - doc.produced_qty;
-	se.bom_no = doc.bom_no;
-	se.use_multi_level_bom = doc.use_multi_level_bom;
-	loaddoc('Stock Entry', se.name);
+cur_frm.cscript.make_se = function(purpose) {
+	wn.call({
+		method:"manufacturing.doctype.production_order.production_order.make_stock_entry",
+		args: {
+			"production_order_id": cur_frm.doc.name,
+			"purpose": purpose
+		},
+		callback: function(r) {
+			var doclist = wn.model.sync(r.message);
+			wn.set_route("Form", doclist[0].doctype, doclist[0].name);
+		}
+	})
 }
 
 cur_frm.fields_dict['production_item'].get_query = function(doc) {
diff --git a/manufacturing/doctype/production_order/production_order.py b/manufacturing/doctype/production_order/production_order.py
index 2f31180..90a74e9 100644
--- a/manufacturing/doctype/production_order/production_order.py
+++ b/manufacturing/doctype/production_order/production_order.py
@@ -137,4 +137,23 @@
 	if bom:
 		res.bom_no = bom[0][0]
 		
-	return res
\ No newline at end of file
+	return res
+
+@webnotes.whitelist()
+def make_stock_entry(production_order_id, purpose):
+	production_order = webnotes.bean("Production Order", production_order_id)
+	
+	stock_entry = webnotes.new_bean("Stock Entry")
+	stock_entry.doc.purpose = purpose
+	stock_entry.doc.production_order = production_order_id
+	stock_entry.doc.company = production_order.doc.company
+	stock_entry.doc.bom_no = production_order.doc.bom_no
+	stock_entry.doc.fg_completed_qty = flt(production_order.doc.qty) - flt(production_order.doc.produced_qty)
+	
+	if purpose=="Material Transfer":
+		stock_entry.doc.to_warehouse = production_order.doc.wip_warehouse
+	else:
+		stock_entry.doc.from_warehouse = production_order.doc.wip_warehouse
+		stock_entry.doc.to_warehouse = production_order.doc.fg_warehouse
+		
+	return [d.fields for d in stock_entry.doclist]
diff --git a/manufacturing/page/manufacturing_home/manufacturing_home.js b/manufacturing/page/manufacturing_home/manufacturing_home.js
index b29bbbb..a2a4eaa 100644
--- a/manufacturing/page/manufacturing_home/manufacturing_home.js
+++ b/manufacturing/page/manufacturing_home/manufacturing_home.js
@@ -65,10 +65,25 @@
 		icon: "icon-list",
 		items: [
 			{
+				"label":wn._("Open Production Orders"),
+				route: "query-report/Open Production Orders",
+				doctype:"Production Order"
+			},
+			{
+				"label":wn._("Production Orders in Progress"),
+				route: "query-report/Production Orders in Progress",
+				doctype:"Production Order"
+			},
+			{
 				"label":wn._("Issued Items Against Production Order"),
 				route: "query-report/Issued Items Against Production Order",
 				doctype:"Production Order"
 			},
+			{
+				"label":wn._("Completed Production Orders"),
+				route: "query-report/Completed Production Orders",
+				doctype:"Production Order"
+			},
 		]
 	}
 ]
diff --git a/manufacturing/report/completed_production_orders/__init__.py b/manufacturing/report/completed_production_orders/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/manufacturing/report/completed_production_orders/__init__.py
diff --git a/manufacturing/report/completed_production_orders/completed_production_orders.txt b/manufacturing/report/completed_production_orders/completed_production_orders.txt
new file mode 100644
index 0000000..facda7e
--- /dev/null
+++ b/manufacturing/report/completed_production_orders/completed_production_orders.txt
@@ -0,0 +1,22 @@
+[
+ {
+  "creation": "2013-08-12 12:44:27", 
+  "docstatus": 0, 
+  "modified": "2013-08-12 12:44:27", 
+  "modified_by": "Administrator", 
+  "owner": "Administrator"
+ }, 
+ {
+  "doctype": "Report", 
+  "is_standard": "Yes", 
+  "name": "__common__", 
+  "query": "SELECT\n  `tabProduction Order`.name as \"Production Order:Link/Production Order:200\",\n  `tabProduction Order`.creation as \"Date:Date:120\",\n  `tabProduction Order`.production_item as \"Item:Link/Item:150\",\n  `tabProduction Order`.qty as \"To Produce:Int:100\",\n  `tabProduction Order`.produced_qty as \"Produced:Int:100\"\nFROM\n  `tabProduction Order`\nWHERE\n  `tabProduction Order`.docstatus=1\n  AND ifnull(`tabProduction Order`.produced_qty,0) = `tabProduction Order`.qty", 
+  "ref_doctype": "Production Order", 
+  "report_name": "Completed Production Orders", 
+  "report_type": "Query Report"
+ }, 
+ {
+  "doctype": "Report", 
+  "name": "Completed Production Orders"
+ }
+]
\ No newline at end of file
diff --git a/manufacturing/report/open_production_orders/__init__.py b/manufacturing/report/open_production_orders/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/manufacturing/report/open_production_orders/__init__.py
diff --git a/manufacturing/report/open_production_orders/open_production_orders.txt b/manufacturing/report/open_production_orders/open_production_orders.txt
new file mode 100644
index 0000000..f92bdd3
--- /dev/null
+++ b/manufacturing/report/open_production_orders/open_production_orders.txt
@@ -0,0 +1,22 @@
+[
+ {
+  "creation": "2013-08-12 12:32:30", 
+  "docstatus": 0, 
+  "modified": "2013-08-12 12:42:29", 
+  "modified_by": "Administrator", 
+  "owner": "Administrator"
+ }, 
+ {
+  "doctype": "Report", 
+  "is_standard": "Yes", 
+  "name": "__common__", 
+  "query": "SELECT\n  `tabProduction Order`.name as \"Production Order:Link/Production Order:200\",\n  `tabProduction Order`.creation as \"Date:Date:120\",\n  `tabProduction Order`.production_item as \"Item:Link/Item:150\",\n  `tabProduction Order`.qty as \"To Produce:Int:100\",\n  `tabProduction Order`.produced_qty as \"Produced:Int:100\"\nFROM\n  `tabProduction Order`\nWHERE\n  `tabProduction Order`.docstatus=1\n  AND ifnull(`tabProduction Order`.produced_qty,0) < `tabProduction Order`.qty\n  AND NOT EXISTS (SELECT name from `tabStock Entry` where production_order =`tabProduction Order`.name) ", 
+  "ref_doctype": "Production Order", 
+  "report_name": "Open Production Orders", 
+  "report_type": "Query Report"
+ }, 
+ {
+  "doctype": "Report", 
+  "name": "Open Production Orders"
+ }
+]
\ No newline at end of file
diff --git a/manufacturing/report/production_orders_in_progress/__init__.py b/manufacturing/report/production_orders_in_progress/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/manufacturing/report/production_orders_in_progress/__init__.py
diff --git a/manufacturing/report/production_orders_in_progress/production_orders_in_progress.txt b/manufacturing/report/production_orders_in_progress/production_orders_in_progress.txt
new file mode 100644
index 0000000..3d3493f
--- /dev/null
+++ b/manufacturing/report/production_orders_in_progress/production_orders_in_progress.txt
@@ -0,0 +1,22 @@
+[
+ {
+  "creation": "2013-08-12 12:43:47", 
+  "docstatus": 0, 
+  "modified": "2013-08-12 12:43:47", 
+  "modified_by": "Administrator", 
+  "owner": "Administrator"
+ }, 
+ {
+  "doctype": "Report", 
+  "is_standard": "Yes", 
+  "name": "__common__", 
+  "query": "SELECT\n  `tabProduction Order`.name as \"Production Order:Link/Production Order:200\",\n  `tabProduction Order`.creation as \"Date:Date:120\",\n  `tabProduction Order`.production_item as \"Item:Link/Item:150\",\n  `tabProduction Order`.qty as \"To Produce:Int:100\",\n  `tabProduction Order`.produced_qty as \"Produced:Int:100\"\nFROM\n  `tabProduction Order`\nWHERE\n  `tabProduction Order`.docstatus=1\n  AND ifnull(`tabProduction Order`.produced_qty,0) < `tabProduction Order`.qty\n  AND EXISTS (SELECT name from `tabStock Entry` where production_order =`tabProduction Order`.name) ", 
+  "ref_doctype": "Production Order", 
+  "report_name": "Production Orders in Progress", 
+  "report_type": "Query Report"
+ }, 
+ {
+  "doctype": "Report", 
+  "name": "Production Orders in Progress"
+ }
+]
\ No newline at end of file
diff --git a/patches/august_2013/p02_rename_price_list.py b/patches/august_2013/p02_rename_price_list.py
index c29c563..cea7c79 100644
--- a/patches/august_2013/p02_rename_price_list.py
+++ b/patches/august_2013/p02_rename_price_list.py
@@ -15,11 +15,12 @@
 			("Item Price", "price_list_name", "price_list"),
 			("BOM", "price_list", "buying_price_list"),
 		]:
-		if t[2] in webnotes.conn.get_table_columns(t[0]):
+		table_columns = webnotes.conn.get_table_columns(t[0])
+		if t[2] in table_columns and t[1] in table_columns:
 			# already reloaded, so copy into new column and drop old column
 			webnotes.conn.sql("""update `tab%s` set `%s`=`%s`""" % (t[0], t[2], t[1]))
 			webnotes.conn.sql("""alter table `tab%s` drop column `%s`""" % (t[0], t[1]))
-		else:
+		elif t[1] in table_columns:
 			webnotes.conn.sql_ddl("alter table `tab%s` change `%s` `%s` varchar(180)" % t)
 
 		webnotes.reload_doc(webnotes.conn.get_value("DocType", t[0], "module"), "DocType", t[0])
diff --git a/stock/doctype/stock_entry/stock_entry.js b/stock/doctype/stock_entry/stock_entry.js
index 4fa6c6c..53998f8 100644
--- a/stock/doctype/stock_entry/stock_entry.js
+++ b/stock/doctype/stock_entry/stock_entry.js
@@ -4,34 +4,7 @@
 wn.require("public/app/js/controllers/stock_controller.js");
 wn.provide("erpnext.stock");
 
-erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
-	onload: function() {
-		this.set_default_account();
-	}, 
-	
-	set_default_account: function() {
-		var me = this;
-		
-		if (cint(wn.defaults.get_default("auto_inventory_accounting")) && !this.frm.doc.expense_adjustment_account) {
-			if (this.frm.doc.purpose == "Sales Return")
-				account_for = "stock_in_hand_account";
-			else if (this.frm.doc.purpose == "Purchase Return") 
-				account_for = "stock_received_but_not_billed";
-			else account_for = "stock_adjustment_account";
-			
-			return this.frm.call({
-				method: "accounts.utils.get_company_default",
-				args: {
-					"fieldname": account_for, 
-					"company": this.frm.doc.company
-				},
-				callback: function(r) {
-					if (!r.exc) me.frm.set_value("expense_adjustment_account", r.message);
-				}
-			});
-		}
-	},
-	
+erpnext.stock.StockEntry = erpnext.stock.StockController.extend({		
 	setup: function() {
 		var me = this;
 		
@@ -80,11 +53,7 @@
 	},
 	
 	onload_post_render: function() {
-		if(this.frm.doc.__islocal && (this.frm.doc.production_order || this.frm.doc.bom_no) 
-			&& !getchildren('Stock Entry Detail', this.frm.doc.name, 'mtn_details').length) {
-				// if production order / bom is mentioned, get items
-				this.get_items();
-		}
+		this.set_default_account();
 	},
 	
 	refresh: function() {
@@ -115,6 +84,33 @@
 	after_cancel: function() {
 		this.clean_up();
 	},
+
+	set_default_account: function() {
+		var me = this;
+		
+		if (cint(wn.defaults.get_default("auto_inventory_accounting")) && !this.frm.doc.expense_adjustment_account) {
+			var account_for = "stock_adjustment_account";
+			if (this.frm.doc.purpose == "Sales Return")
+				account_for = "stock_in_hand_account";
+			else if (this.frm.doc.purpose == "Purchase Return") 
+				account_for = "stock_received_but_not_billed";
+			
+			return this.frm.call({
+				method: "accounts.utils.get_company_default",
+				args: {
+					"fieldname": account_for, 
+					"company": this.frm.doc.company
+				},
+				callback: function(r) {
+					if (!r.exc) me.frm.set_value("expense_adjustment_account", r.message);
+					
+					me.get_items();
+				}
+			});
+		} else {
+			me.get_items();
+		}
+	},
 	
 	clean_up: function() {
 		// Clear Production Order record from locals, because it is updated via Stock Entry
@@ -126,13 +122,17 @@
 	},
 	
 	get_items: function() {
-		return this.frm.call({
-			doc: this.frm.doc,
-			method: "get_items",
-			callback: function(r) {
-				if(!r.exc) refresh_field("mtn_details");
-			}
-		});
+		if(this.frm.doc.__islocal && (this.frm.doc.production_order || this.frm.doc.bom_no) 
+			&& !getchildren('Stock Entry Detail', this.frm.doc.name, 'mtn_details').length) {
+				// if production order / bom is mentioned, get items
+				return this.frm.call({
+					doc: this.frm.doc,
+					method: "get_items",
+					callback: function(r) {
+						if(!r.exc) refresh_field("mtn_details");
+					}
+				});
+		}
 	},
 	
 	qty: function(doc, cdt, cdn) {
@@ -212,7 +212,6 @@
 						});
 						loaddoc("Journal Voucher", jv_name);
 					}
-
 				}
 			});
 		}
diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py
index 66d1dbf..b702316 100644
--- a/stock/doctype/stock_entry/stock_entry.py
+++ b/stock/doctype/stock_entry/stock_entry.py
@@ -19,6 +19,7 @@
 
 class NotUpdateStockError(webnotes.ValidationError): pass
 class StockOverReturnError(webnotes.ValidationError): pass
+class IncorrectValuationRateError(webnotes.ValidationError): pass
 	
 from controllers.stock_controller import StockController
 
@@ -245,7 +246,7 @@
 	def validate_incoming_rate(self):
 		for d in getlist(self.doclist, 'mtn_details'):
 			if d.t_warehouse:
-				self.validate_value("incoming_rate", ">", 0, d)
+				self.validate_value("incoming_rate", ">", 0, d, raise_exception=IncorrectValuationRateError)
 					
 	def validate_bom(self):
 		for d in getlist(self.doclist, 'mtn_details'):
diff --git a/stock/stock_ledger.py b/stock/stock_ledger.py
index 4dcca67..f0619c7 100644
--- a/stock/stock_ledger.py
+++ b/stock/stock_ledger.py
@@ -8,6 +8,7 @@
 import json
 
 # future reposting
+class NegativeStockError(webnotes.ValidationError): pass
 
 _exceptions = []
 def update_entries_after(args, verbose=1):
@@ -253,9 +254,9 @@
 		_exceptions[0]["voucher_type"], _exceptions[0]["voucher_no"],
 		abs(deficiency))
 	if verbose:
-		msgprint(msg, raise_exception=1)
+		msgprint(msg, raise_exception=NegativeStockError)
 	else:
-		raise webnotes.ValidationError, msg
+		raise NegativeStockError, msg
 		
 def get_previous_sle(args, for_update=False):
 	"""
diff --git a/stock/utils.py b/stock/utils.py
index 96eeef6..5c53d84 100644
--- a/stock/utils.py
+++ b/stock/utils.py
@@ -69,7 +69,7 @@
 		if valuation_method == 'FIFO':
 			if not previous_sle:
 				return 0.0
-			previous_stock_queue = json.loads(previous_sle.get('stock_queue', '[]'))
+			previous_stock_queue = json.loads(previous_sle.get('stock_queue', '[]') or '[]')
 			in_rate = previous_stock_queue and \
 				get_fifo_rate(previous_stock_queue, args.get("qty") or 0) or 0
 		elif valuation_method == 'Moving Average':
diff --git a/utilities/make_demo.py b/utilities/make_demo.py
index 124259f..a522862 100644
--- a/utilities/make_demo.py
+++ b/utilities/make_demo.py
@@ -19,15 +19,18 @@
 prob = {
 	"Quotation": { "make": 0.5, "qty": (1,5) },
 	"Sales Order": { "make": 0.5, "qty": (1,4) },
+	"Purchase Order": { "make": 0.7, "qty": (1,4) },
+	"Purchase Receipt": { "make": 0.7, "qty": (1,4) },
 	"Supplier Quotation": { "make": 0.5, "qty": (1, 3) }
 }
 
-def make():
+def make(reset=False):
 	webnotes.connect()
 	webnotes.print_messages = True
 	webnotes.mute_emails = True
 	
-	#setup()
+	if reset:
+		setup()
 	simulate()
 	
 def setup():
@@ -68,13 +71,29 @@
 			make_sales_order(current_date)
 
 def run_stock(current_date):
-	pass
 	# make purchase requests
+	if can_make("Purchase Receipt"):
+		from buying.doctype.purchase_order.purchase_order import make_purchase_receipt
+		report = "Purchase Order Items To Be Received"
+		for po in list(set([r[0] for r in query_report.run(report)["result"] if r[0]!="Total"]))[:how_many("Purchase Receipt")]:
+			pr = webnotes.bean(make_purchase_receipt(po))
+			pr.doc.posting_date = current_date
+			pr.doc.fiscal_year = "2010"
+			pr.insert()
+			pr.submit()
 	
 	# make delivery notes (if possible)
+	if can_make("Delivery Note"):
+		from selling.doctype.sales_order.sales_order import make_delivery_note
+		report = "Ordered Items To Be Delivered"
+		for so in list(set([r[0] for r in query_report.run(report)["result"] if r[0]!="Total"]))[:how_many("Delivery Note")]:
+			dn = webnotes.bean(make_delivery_note(so))
+			dn.doc.posting_date = current_date
+			dn.doc.fiscal_year = "2010"
+			dn.insert()
+			dn.submit()
 	
-	# make stock entry (from production order)
-
+	
 def run_purchase(current_date):
 	# make supplier quotations
 	if can_make("Supplier Quotation"):
@@ -121,6 +140,40 @@
 		b = webnotes.bean("Material Request", pro[0])
 		b.submit()
 	
+	# stores -> wip
+	if can_make("Stock Entry for WIP"):		
+		for pro in query_report.run("Open Production Orders")["result"][:how_many("Stock Entry for WIP")]:
+			make_stock_entry_from_pro(pro[0], "Material Transfer", current_date)
+		
+	# wip -> fg
+	if can_make("Stock Entry for FG"):		
+		for pro in query_report.run("Production Orders in Progress")["result"][:how_many("Stock Entry for FG")]:
+			make_stock_entry_from_pro(pro[0], "Manufacture/Repack", current_date)
+
+	# try posting older drafts (if exists)
+	for st in webnotes.conn.get_values("Stock Entry", {"docstatus":0}):
+		try:
+			webnotes.bean("Stock Entry", st[0]).submit()
+		except NegativeStockError: pass
+		except IncorrectValuationRateError: pass
+			
+
+def make_stock_entry_from_pro(pro_id, purpose, current_date):
+	from manufacturing.doctype.production_order.production_order import make_stock_entry
+	from stock.stock_ledger import NegativeStockError
+	from stock.doctype.stock_entry.stock_entry import IncorrectValuationRateError
+
+	st = webnotes.bean(make_stock_entry(pro_id, purpose))
+	st.run_method("get_items")
+	st.doc.posting_date = current_date
+	st.doc.fiscal_year = "2010"
+	st.doc.expense_adjustment_account = "Stock in Hand - WP"
+	try:
+		st.insert()
+		st.submit()
+	except NegativeStockError: pass
+	except IncorrectValuationRateError: pass
+
 def make_quotation(current_date):
 	b = webnotes.bean([{
 		"creation": current_date,