Merge pull request #5833 from nabinhait/fix_108

Validate warehouse if update stock checked in Purchase Invoice
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index 6f25220..94709a7 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -61,8 +61,8 @@
 				frappe.get_doc(voucher_type, voucher_no).set_total_advance_paid()
 
 	def on_cancel(self):
-		from erpnext.accounts.utils import remove_against_link_from_jv
-		remove_against_link_from_jv(self.doctype, self.name)
+		from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries
+		unlink_ref_doc_from_payment_entries(self.doctype, self.name)
 
 		self.make_gl_entries(1)
 		self.update_advance_paid()
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 5e7c05b..176e529 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -562,8 +562,8 @@
 		self.update_status_updater_args()
 
 		if not self.is_return:
-			from erpnext.accounts.utils import remove_against_link_from_jv
-			remove_against_link_from_jv(self.doctype, self.name)
+			from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries
+			unlink_ref_doc_from_payment_entries(self.doctype, self.name)
 
 			self.update_prevdoc_status()
 			self.update_billing_status_for_zero_amount_refdoc("Purchase Order")
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 1df86aa..b284619 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -134,8 +134,8 @@
 	def on_cancel(self):
 		self.check_close_sales_order("sales_order")
 
-		from erpnext.accounts.utils import remove_against_link_from_jv
-		remove_against_link_from_jv(self.doctype, self.name)
+		from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries
+		unlink_ref_doc_from_payment_entries(self.doctype, self.name)
 
 		if self.is_return:
 			# NOTE status updating bypassed for is_return
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 635197f..6efb288 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -323,8 +323,19 @@
 	payment_entry.set_missing_values()
 	payment_entry.set_amounts()
 	payment_entry.save(ignore_permissions=True)
+	
+def unlink_ref_doc_from_payment_entries(ref_type, ref_no):
+	remove_ref_doc_link_from_jv(ref_type, ref_no)
+	remove_ref_doc_link_from_pe(ref_type, ref_no)
+	
+	frappe.db.sql("""update `tabGL Entry`
+		set against_voucher_type=null, against_voucher=null,
+		modified=%s, modified_by=%s
+		where against_voucher_type=%s and against_voucher=%s
+		and voucher_no != ifnull(against_voucher, '')""",
+		(now(), frappe.session.user, ref_type, ref_no))
 
-def remove_against_link_from_jv(ref_type, ref_no):
+def remove_ref_doc_link_from_jv(ref_type, ref_no):
 	linked_jv = frappe.db.sql_list("""select parent from `tabJournal Entry Account`
 		where reference_type=%s and reference_name=%s and docstatus < 2""", (ref_type, ref_no))
 
@@ -335,15 +346,30 @@
 			where reference_type=%s and reference_name=%s
 			and docstatus < 2""", (now(), frappe.session.user, ref_type, ref_no))
 
-		frappe.db.sql("""update `tabGL Entry`
-			set against_voucher_type=null, against_voucher=null,
-			modified=%s, modified_by=%s
-			where against_voucher_type=%s and against_voucher=%s
-			and voucher_no != ifnull(against_voucher, '')""",
-			(now(), frappe.session.user, ref_type, ref_no))
-
 		frappe.msgprint(_("Journal Entries {0} are un-linked".format("\n".join(linked_jv))))
+		
+def remove_ref_doc_link_from_pe(ref_type, ref_no):
+	linked_pe = frappe.db.sql_list("""select parent from `tabPayment Entry Reference`
+		where reference_doctype=%s and reference_name=%s and docstatus < 2""", (ref_type, ref_no))
 
+	if linked_pe:
+		frappe.db.sql("""update `tabPayment Entry Reference`
+			set allocated_amount=0, modified=%s, modified_by=%s
+			where reference_doctype=%s and reference_name=%s
+			and docstatus < 2""", (now(), frappe.session.user, ref_type, ref_no))
+			
+		for pe in linked_pe:
+			pe_doc = frappe.get_doc("Payment Entry", pe)
+			pe_doc.set_total_allocated_amount()
+			pe_doc.set_unallocated_amount()
+			pe_doc.clear_unallocated_reference_document_rows()
+			
+			frappe.db.sql("""update `tabPayment Entry` set total_allocated_amount=%s, 
+				base_total_allocated_amount=%s, unallocated_amount=%s, modified=%s, modified_by=%s 
+				where name=%s""", (pe_doc.total_allocated_amount, pe_doc.base_total_allocated_amount, 
+					pe_doc.unallocated_amount, now(), frappe.session.user, pe))
+		
+		frappe.msgprint(_("Payment Entries {0} are un-linked".format("\n".join(linked_pe))))
 
 @frappe.whitelist()
 def get_company_default(company, fieldname):
diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json
index 66f6b71..3699595 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.json
+++ b/erpnext/selling/doctype/sales_order/sales_order.json
@@ -3,11 +3,13 @@
  "allow_import": 1, 
  "allow_rename": 0, 
  "autoname": "naming_series:", 
+ "beta": 0, 
  "creation": "2013-06-18 12:39:59", 
  "custom": 0, 
  "docstatus": 0, 
  "doctype": "DocType", 
  "document_type": "Document", 
+ "editable_grid": 1, 
  "fields": [
   {
    "allow_on_submit": 0, 
@@ -716,6 +718,34 @@
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
+   "fieldname": "currency", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_list_view": 0, 
+   "label": "Currency", 
+   "length": 0, 
+   "no_copy": 0, 
+   "oldfieldname": "currency", 
+   "oldfieldtype": "Select", 
+   "options": "Currency", 
+   "permlevel": 0, 
+   "print_hide": 1, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0, 
+   "width": "100px"
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
    "description": "Rate at which customer's currency is converted to company's base currency", 
    "fieldname": "conversion_rate", 
    "fieldtype": "Float", 
@@ -745,34 +775,6 @@
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
-   "fieldname": "currency", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_list_view": 0, 
-   "label": "Currency", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "currency", 
-   "oldfieldtype": "Select", 
-   "options": "Currency", 
-   "permlevel": 0, 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0, 
-   "width": "100px"
-  }, 
-  {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
    "fieldname": "column_break2", 
    "fieldtype": "Column Break", 
    "hidden": 0, 
@@ -2989,13 +2991,14 @@
  "hide_toolbar": 0, 
  "icon": "icon-file-text", 
  "idx": 105, 
+ "image_view": 0, 
  "in_create": 0, 
  "in_dialog": 0, 
  "is_submittable": 1, 
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2016-04-14 12:34:16.220066", 
+ "modified": "2016-07-21 17:24:25.306923", 
  "modified_by": "Administrator", 
  "module": "Selling", 
  "name": "Sales Order", 
@@ -3122,6 +3125,7 @@
    "write": 1
   }
  ], 
+ "quick_entry": 0, 
  "read_only": 0, 
  "read_only_onload": 1, 
  "search_fields": "status,transaction_date,customer,customer_name, territory,order_type,company", 
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index 2ab40c5..e2aa274 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -11,6 +11,7 @@
  "docstatus": 0, 
  "doctype": "DocType", 
  "document_type": "Setup", 
+ "editable_grid": 1, 
  "fields": [
   {
    "allow_on_submit": 0, 
@@ -305,7 +306,7 @@
    "allow_on_submit": 0, 
    "bold": 1, 
    "collapsible": 0, 
-   "depends_on": "eval:(doc.__islocal&&doc.is_stock_item)", 
+   "depends_on": "eval:(doc.__islocal&&doc.is_stock_item && !doc.has_serial_no && !doc.has_batch_no)", 
    "fieldname": "opening_stock", 
    "fieldtype": "Int", 
    "hidden": 0, 
@@ -331,7 +332,7 @@
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
-   "depends_on": "eval:(doc.__islocal && doc.is_stock_item && doc.opening_stock)", 
+   "depends_on": "eval:(doc.__islocal && doc.is_stock_item && !doc.has_serial_no && !doc.has_batch_no && doc.opening_stock)", 
    "fieldname": "valuation_rate", 
    "fieldtype": "Currency", 
    "hidden": 0, 
@@ -2307,7 +2308,7 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 1, 
- "modified": "2016-07-06 17:00:45.561349", 
+ "modified": "2016-07-21 18:44:10.230372", 
  "modified_by": "Administrator", 
  "module": "Stock", 
  "name": "Item", 
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index de5d545..cedfb24 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -118,6 +118,9 @@
 
 	def set_opening_stock(self):
 		'''set opening stock'''
+		if not self.is_stock_item or self.has_serial_no or self.has_batch_no:
+			return
+		
 		if not self.valuation_rate:
 			frappe.throw(_("Valuation Rate is mandatory if Opening Stock entered"))
 
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 9ed005e..e35f3d2 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -49,7 +49,7 @@
 		self.validate_batch()
 
 		self.set_actual_qty()
-		self.calculate_rate_and_amount()
+		self.calculate_rate_and_amount(update_finished_item_rate=False)
 
 	def on_submit(self):
 		self.update_stock_ledger()
@@ -237,18 +237,20 @@
 		self.set_actual_qty()
 		self.calculate_rate_and_amount()
 
-	def calculate_rate_and_amount(self, force=False):
-		self.set_basic_rate(force)
+	def calculate_rate_and_amount(self, force=False, update_finished_item_rate=True):
+		self.set_basic_rate(force, update_finished_item_rate)
 		self.distribute_additional_costs()
 		self.update_valuation_rate()
 		self.set_total_incoming_outgoing_value()
 		self.set_total_amount()
 
-	def set_basic_rate(self, force=False):
+	def set_basic_rate(self, force=False, update_finished_item_rate=True):
 		"""get stock and incoming rate on posting date"""
 		raw_material_cost = 0.0
+		fg_basic_rate = 0.0
 
 		for d in self.get('items'):
+			if d.t_warehouse: fg_basic_rate = flt(d.basic_rate)
 			args = frappe._dict({
 				"item_code": d.item_code,
 				"warehouse": d.s_warehouse or d.t_warehouse,
@@ -269,13 +271,14 @@
 				if not d.t_warehouse:
 					raw_material_cost += flt(d.basic_amount)
 
-		self.set_basic_rate_for_finished_goods(raw_material_cost)
+		number_of_fg_items = len([t.t_warehouse for t in self.get("items") if t.t_warehouse])
+		if (fg_basic_rate == 0.0 and number_of_fg_items == 1) or update_finished_item_rate:
+			self.set_basic_rate_for_finished_goods(raw_material_cost)
 
 	def set_basic_rate_for_finished_goods(self, raw_material_cost):
 		if self.purpose in ["Manufacture", "Repack"]:
-			number_of_fg_items = len([t.t_warehouse for t in self.get("items") if t.t_warehouse])
 			for d in self.get("items"):
-				if d.bom_no or (d.t_warehouse and number_of_fg_items == 1):
+				if d.bom_no or d.t_warehouse:
 					d.basic_rate = flt(raw_material_cost / flt(d.transfer_qty), d.precision("basic_rate"))
 					d.basic_amount = flt(raw_material_cost, d.precision("basic_amount"))