Merge pull request #3037 from neilLasrado/production-planning

Production planning
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js
index d33cbf6..1de7850 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.js
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js
@@ -224,8 +224,9 @@
 	cur_frm.set_df_property("cheque_no", "reqd", doc.voucher_type=="Bank Entry");
 	cur_frm.set_df_property("cheque_date", "reqd", doc.voucher_type=="Bank Entry");
 
-	if((doc.accounts || []).length!==0 || !doc.company) // too early
-		return;
+	if(!doc.company) return;
+
+	cur_frm.clear_table("accounts");
 
 	var update_jv_details = function(doc, r) {
 		var jvdetail = frappe.model.add_child(doc, "Journal Entry Account", "accounts");
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index f6d9529..4b5b5f6 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -408,6 +408,7 @@
 			}), (account, party_type, party, d.voucher_type, d.voucher_no))
 
 		payment_amount = -1*payment_amount[0][0] if payment_amount else 0
+		precision = frappe.get_precision("Sales Invoice", "outstanding_amount")
 
 		if d.invoice_amount > payment_amount:
 
@@ -415,9 +416,9 @@
 				'voucher_no': d.voucher_no,
 				'voucher_type': d.voucher_type,
 				'posting_date': d.posting_date,
-				'invoice_amount': flt(d.invoice_amount),
-				'outstanding_amount': d.invoice_amount - payment_amount
-				})
+				'invoice_amount': flt(d.invoice_amount, precision),
+				'outstanding_amount': flt(d.invoice_amount - payment_amount, precision)
+			})
 
 	return all_outstanding_vouchers
 
diff --git a/erpnext/buying/doctype/quality_inspection/quality_inspection.js b/erpnext/buying/doctype/quality_inspection/quality_inspection.js
index 6b504c4..3188c3c 100644
--- a/erpnext/buying/doctype/quality_inspection/quality_inspection.js
+++ b/erpnext/buying/doctype/quality_inspection/quality_inspection.js
@@ -4,7 +4,7 @@
 cur_frm.cscript.inspection_type = function(doc, cdt, cdn) {
 	if(doc.inspection_type == 'Incoming'){
 		doc.delivery_note_no = '';
-		hide_field('delivery_note_no');		
+		hide_field('delivery_note_no');
 		unhide_field('purchase_receipt_no');
 	}
 	else if(doc.inspection_type == 'Outgoing'){
@@ -15,7 +15,7 @@
 	}
 	else {
 		doc.purchase_receipt_no = '';
-		doc.delivery_note_no = '';		
+		doc.delivery_note_no = '';
 		hide_field('purchase_receipt_no');
 		hide_field('delivery_note_no');
 	}
@@ -54,6 +54,6 @@
 		}
 	} else
 		filter = { 'status': "Available" }
-	
+
 	return { filters: filter }
-}
\ No newline at end of file
+}
diff --git a/erpnext/buying/doctype/quality_inspection/quality_inspection.json b/erpnext/buying/doctype/quality_inspection/quality_inspection.json
index 97d6f31..e1b57e4 100644
--- a/erpnext/buying/doctype/quality_inspection/quality_inspection.json
+++ b/erpnext/buying/doctype/quality_inspection/quality_inspection.json
@@ -5,21 +5,6 @@
  "doctype": "DocType", 
  "fields": [
   {
-   "fieldname": "qa_inspection", 
-   "fieldtype": "Section Break", 
-   "label": "QA Inspection", 
-   "no_copy": 0, 
-   "oldfieldtype": "Section Break", 
-   "permlevel": 0
-  }, 
-  {
-   "fieldname": "column_break0", 
-   "fieldtype": "Column Break", 
-   "oldfieldtype": "Column Break", 
-   "permlevel": 0, 
-   "width": "50%"
-  }, 
-  {
    "fieldname": "naming_series", 
    "fieldtype": "Select", 
    "label": "Series", 
@@ -29,18 +14,7 @@
    "reqd": 1
   }, 
   {
-   "fieldname": "inspection_type", 
-   "fieldtype": "Select", 
-   "in_filter": 1, 
-   "in_list_view": 1, 
-   "label": "Inspection Type", 
-   "oldfieldname": "inspection_type", 
-   "oldfieldtype": "Select", 
-   "options": "\nIncoming\nOutgoing\nIn Process", 
-   "permlevel": 0, 
-   "reqd": 1
-  }, 
-  {
+   "default": "Today", 
    "fieldname": "report_date", 
    "fieldtype": "Date", 
    "in_filter": 1, 
@@ -53,67 +27,22 @@
    "search_index": 1
   }, 
   {
-   "fieldname": "item_code", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
+   "fieldname": "column_break_4", 
+   "fieldtype": "Column Break", 
+   "permlevel": 0, 
+   "precision": ""
+  }, 
+  {
+   "fieldname": "inspection_type", 
+   "fieldtype": "Select", 
    "in_filter": 1, 
    "in_list_view": 1, 
-   "label": "Item Code", 
-   "oldfieldname": "item_code", 
-   "oldfieldtype": "Link", 
-   "options": "Item", 
+   "label": "Inspection Type", 
+   "oldfieldname": "inspection_type", 
+   "oldfieldtype": "Select", 
+   "options": "\nIncoming\nOutgoing\nIn Process", 
    "permlevel": 0, 
-   "reqd": 1, 
-   "search_index": 1
-  }, 
-  {
-   "fieldname": "sample_size", 
-   "fieldtype": "Float", 
-   "in_filter": 0, 
-   "label": "Sample Size", 
-   "oldfieldname": "sample_size", 
-   "oldfieldtype": "Currency", 
-   "permlevel": 0, 
-   "reqd": 1, 
-   "search_index": 0
-  }, 
-  {
-   "fieldname": "description", 
-   "fieldtype": "Small Text", 
-   "in_filter": 1, 
-   "label": "Description", 
-   "oldfieldname": "description", 
-   "oldfieldtype": "Small Text", 
-   "permlevel": 0, 
-   "search_index": 0, 
-   "width": "300px"
-  }, 
-  {
-   "fieldname": "column_break1", 
-   "fieldtype": "Column Break", 
-   "oldfieldtype": "Column Break", 
-   "permlevel": 0, 
-   "width": "50%"
-  }, 
-  {
-   "fieldname": "item_serial_no", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "label": "Item Serial No", 
-   "oldfieldname": "item_serial_no", 
-   "oldfieldtype": "Link", 
-   "options": "Serial No", 
-   "permlevel": 0, 
-   "print_hide": 0
-  }, 
-  {
-   "fieldname": "batch_no", 
-   "fieldtype": "Link", 
-   "label": "Batch No", 
-   "oldfieldname": "batch_no", 
-   "oldfieldtype": "Link", 
-   "options": "Batch", 
-   "permlevel": 0
+   "reqd": 1
   }, 
   {
    "fieldname": "purchase_receipt_no", 
@@ -141,15 +70,106 @@
    "search_index": 1
   }, 
   {
+   "fieldname": "section_break_7", 
+   "fieldtype": "Section Break", 
+   "permlevel": 0, 
+   "precision": ""
+  }, 
+  {
+   "fieldname": "item_code", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "in_filter": 1, 
+   "in_list_view": 1, 
+   "label": "Item Code", 
+   "oldfieldname": "item_code", 
+   "oldfieldtype": "Link", 
+   "options": "Item", 
+   "permlevel": 0, 
+   "reqd": 1, 
+   "search_index": 1
+  }, 
+  {
+   "fieldname": "item_serial_no", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "label": "Item Serial No", 
+   "oldfieldname": "item_serial_no", 
+   "oldfieldtype": "Link", 
+   "options": "Serial No", 
+   "permlevel": 0, 
+   "print_hide": 0
+  }, 
+  {
+   "fieldname": "batch_no", 
+   "fieldtype": "Link", 
+   "label": "Batch No", 
+   "oldfieldname": "batch_no", 
+   "oldfieldtype": "Link", 
+   "options": "Batch", 
+   "permlevel": 0
+  }, 
+  {
+   "fieldname": "sample_size", 
+   "fieldtype": "Float", 
+   "in_filter": 0, 
+   "label": "Sample Size", 
+   "oldfieldname": "sample_size", 
+   "oldfieldtype": "Currency", 
+   "permlevel": 0, 
+   "reqd": 1, 
+   "search_index": 0
+  }, 
+  {
+   "fieldname": "column_break1", 
+   "fieldtype": "Column Break", 
+   "oldfieldtype": "Column Break", 
+   "permlevel": 0, 
+   "width": "50%"
+  }, 
+  {
+   "fieldname": "description", 
+   "fieldtype": "Small Text", 
+   "in_filter": 1, 
+   "label": "Description", 
+   "oldfieldname": "description", 
+   "oldfieldtype": "Small Text", 
+   "permlevel": 0, 
+   "search_index": 0, 
+   "width": "300px"
+  }, 
+  {
+   "fieldname": "section_break_14", 
+   "fieldtype": "Section Break", 
+   "permlevel": 0, 
+   "precision": ""
+  }, 
+  {
+   "default": "user", 
    "fieldname": "inspected_by", 
-   "fieldtype": "Data", 
+   "fieldtype": "Link", 
    "label": "Inspected By", 
    "oldfieldname": "inspected_by", 
    "oldfieldtype": "Data", 
+   "options": "User", 
    "permlevel": 0, 
    "reqd": 1
   }, 
   {
+   "fieldname": "verified_by", 
+   "fieldtype": "Data", 
+   "label": "Verified By", 
+   "oldfieldname": "verified_by", 
+   "oldfieldtype": "Data", 
+   "permlevel": 0
+  }, 
+  {
+   "fieldname": "column_break_17", 
+   "fieldtype": "Column Break", 
+   "permlevel": 0, 
+   "precision": ""
+  }, 
+  {
    "fieldname": "remarks", 
    "fieldtype": "Text", 
    "label": "Remarks", 
@@ -159,14 +179,6 @@
    "permlevel": 0
   }, 
   {
-   "fieldname": "verified_by", 
-   "fieldtype": "Data", 
-   "label": "Verified By", 
-   "oldfieldname": "verified_by", 
-   "oldfieldtype": "Data", 
-   "permlevel": 0
-  }, 
-  {
    "fieldname": "amended_from", 
    "fieldtype": "Link", 
    "ignore_user_permissions": 1, 
@@ -207,7 +219,7 @@
  "icon": "icon-search", 
  "idx": 1, 
  "is_submittable": 1, 
- "modified": "2015-02-20 05:09:09.998457", 
+ "modified": "2015-04-14 07:37:07.331291", 
  "modified_by": "Administrator", 
  "module": "Buying", 
  "name": "Quality Inspection", 
diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js
index edfa438..699b272 100644
--- a/erpnext/manufacturing/doctype/bom/bom.js
+++ b/erpnext/manufacturing/doctype/bom/bom.js
@@ -8,8 +8,7 @@
 	toggle_operations(cur_frm);
 
 	if (!doc.__islocal && doc.docstatus<2) {
-		cur_frm.add_custom_button(__("Update Cost"), cur_frm.cscript.update_cost,
-			"icon-money", "btn-default");
+		cur_frm.add_custom_button(__("Update Cost"), cur_frm.cscript.update_cost);
 	}
 }
 
@@ -17,6 +16,7 @@
 	return frappe.call({
 		doc: cur_frm.doc,
 		method: "update_cost",
+		freeze: true,
 		callback: function(r) {
 			if(!r.exc) cur_frm.refresh_fields();
 		}
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 36854b2..14932d2 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -123,7 +123,7 @@
 	def update_cost(self):
 		if self.docstatus == 2:
 			return
-		
+
 		items_rate = frappe._dict()
 		for d in self.get("items"):
 			rate = self.get_bom_material_detail({'item_code': d.item_code, 'bom_no': d.bom_no,
@@ -131,16 +131,18 @@
 			if rate:
 				d.rate = rate
 				items_rate.setdefault(d.item_code, d.rate)
-				
+
 		for e in self.get("exploded_items"):
 			if items_rate.get(e.item_code):
 				e.rate = items_rate.get(e.item_code)
-			
+
 		if self.docstatus == 1:
 			self.flags.ignore_validate_update_after_submit = True
 			self.calculate_cost()
 		self.save()
 
+		frappe.msgprint(_("Cost Updated"))
+
 	def get_bom_unitcost(self, bom_no):
 		bom = frappe.db.sql("""select name, total_cost/quantity as unit_cost from `tabBOM`
 			where is_active = 1 and name = %s""", bom_no, as_dict=1)
diff --git a/erpnext/patches/v4_4/make_email_accounts.py b/erpnext/patches/v4_4/make_email_accounts.py
index 528fe08..dd74fc9 100644
--- a/erpnext/patches/v4_4/make_email_accounts.py
+++ b/erpnext/patches/v4_4/make_email_accounts.py
@@ -46,20 +46,7 @@
 		account.enable_outgoing = 0
 		account.append_to = "Issue"
 
-		try:
-			account.insert()
-		except frappe.NameError, e:
-			if e.args[0]=="Email Account":
-				existing_account = frappe.get_doc("Email Account", e.args[1])
-				for key, value in account.as_dict().items():
-					if not existing_account.get(key) and value and key not in default_fields:
-						existing_account.set(key, value)
-
-				existing_account.save()
-
-			else:
-				raise
-
+		insert_or_update(account)
 
 	# sales, jobs
 	for doctype in ("Sales Email Settings", "Jobs Email Settings"):
@@ -80,20 +67,25 @@
 			account.enable_outgoing = 0
 			account.append_to = "Lead" if doctype=="Sales Email Settings" else "Job Applicant"
 
-			try:
-				account.insert()
-			except frappe.NameError, e:
-				if e.args[0]=="Email Account":
-					existing_account = frappe.get_doc("Email Account", e.args[1])
-					for key, value in account.as_dict().items():
-						if not existing_account.get(key) and value and key not in default_fields:
-							existing_account.set(key, value)
-
-					existing_account.save()
-				else:
-					raise
+			insert_or_update(account)
 
 	for doctype in ("Outgoing Email Settings", "Support Email Settings",
 		"Sales Email Settings", "Jobs Email Settings"):
 		frappe.delete_doc("DocType", doctype)
 
+def insert_or_update(account):
+	try:
+		account.insert()
+	except frappe.NameError, e:
+		if e.args[0]=="Email Account":
+			existing_account = frappe.get_doc("Email Account", e.args[0])
+			for key, value in account.as_dict().items():
+				if not existing_account.get(key) and value \
+					and key not in default_fields \
+					and key != "__islocal":
+					existing_account.set(key, value)
+
+			existing_account.save()
+		else:
+			raise
+
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
index a2d5be5..fe41b4f 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -4,6 +4,27 @@
 {% include 'buying/doctype/purchase_common/purchase_common.js' %};
 
 frappe.provide("erpnext.stock");
+
+frappe.ui.form.on("Purchase Receipt", {
+	onload: function(frm) {
+		// default values for quotation no
+		var qa_no = frappe.meta.get_docfield("Purchase Receipt Item", "qa_no");
+		qa_no.get_route_options_for_new_doc = function(field) {
+			if(frm.is_new()) return;
+			var doc = field.doc;
+			return {
+				"inspection_type": "Incoming",
+				"purchase_receipt_no": frm.doc.name,
+				"item_code": doc.item_code,
+				"description": doc.description,
+				"item_serial_no": doc.serial_no ? doc.serial_no.split("\n")[0] : null,
+				"batch_no": doc.batch_no
+			}
+		}
+	}
+});
+
+
 erpnext.stock.PurchaseReceiptController = erpnext.buying.BuyingController.extend({
 	refresh: function() {
 		this._super();
@@ -91,6 +112,7 @@
 
 });
 
+
 // for backward compatibility: combine new and previous states
 $.extend(cur_frm.cscript, new erpnext.stock.PurchaseReceiptController({frm: cur_frm}));
 
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index e785041..9813251 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -151,7 +151,7 @@
 					}))
 
 		self.bk_flush_supp_wh(sl_entries)
-		self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock, 
+		self.make_sl_entries(sl_entries, allow_negative_stock=allow_negative_stock,
 			via_landed_cost_voucher=via_landed_cost_voucher)
 
 	def update_ordered_qty(self):
@@ -199,6 +199,8 @@
 			ins_reqd = ins_reqd and ins_reqd[0]['inspection_required'] or 'No'
 			if ins_reqd == 'Yes' and not d.qa_no:
 				frappe.msgprint(_("Quality Inspection required for Item {0}").format(d.item_code))
+				if self.docstatus==1:
+					raise frappe.ValidationError
 
 	# Check for Stopped status
 	def check_for_stopped_status(self, pc_obj):
@@ -206,7 +208,7 @@
 		for d in self.get('items'):
 			if d.meta.get_field('prevdoc_docname') and d.prevdoc_docname and d.prevdoc_docname not in check_list:
 				check_list.append(d.prevdoc_docname)
-				pc_obj.check_for_stopped_status( d.prevdoc_doctype, d.prevdoc_docname)
+				pc_obj.check_for_stopped_status(d.prevdoc_doctype, d.prevdoc_docname)
 
 	# on submit
 	def on_submit(self):