Merge branch 'contacts-ref' of https://github.com/hrwx/erpnext into contacts-ref
diff --git a/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.json b/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.json
index 8d7ed74..04d6303 100644
--- a/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.json
+++ b/erpnext/accounts/doctype/discounted_invoice/discounted_invoice.json
@@ -8,7 +8,8 @@
   "customer",
   "column_break_3",
   "posting_date",
-  "outstanding_amount"
+  "outstanding_amount",
+  "debit_to"
  ],
  "fields": [
   {
@@ -48,10 +49,18 @@
   {
    "fieldname": "column_break_3",
    "fieldtype": "Column Break"
+  },
+  {
+   "fetch_from": "sales_invoice.debit_to",
+   "fieldname": "debit_to",
+   "fieldtype": "Link",
+   "label": "Debit to",
+   "options": "Account",
+   "read_only": 1
   }
  ],
  "istable": 1,
- "modified": "2019-05-30 19:27:29.436153",
+ "modified": "2019-08-07 15:13:55.808349",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Discounted Invoice",
diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js
index 5563f03..f1f88a8 100644
--- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js
+++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.js
@@ -13,41 +13,57 @@
 			};
 		});
 
-		frm.events.filter_accounts("bank_account", frm, {"account_type": "Bank"});
-		frm.events.filter_accounts("bank_charges_account", frm, {"root_type": "Expense"});
-		frm.events.filter_accounts("short_term_loan", frm, {"root_type": "Liability"});
-		frm.events.filter_accounts("accounts_receivable_credit", frm, {"account_type": "Receivable"});
-		frm.events.filter_accounts("accounts_receivable_discounted", frm, {"account_type": "Receivable"});
-		frm.events.filter_accounts("accounts_receivable_unpaid", frm, {"account_type": "Receivable"});
+
+		frm.events.filter_accounts("bank_account", frm, [["account_type", "=", "Bank"]]);
+		frm.events.filter_accounts("bank_charges_account", frm, [["root_type", "=", "Expense"]]);
+		frm.events.filter_accounts("short_term_loan", frm, [["root_type", "=", "Liability"]]);
+		frm.events.filter_accounts("accounts_receivable_discounted", frm, [["account_type", "=", "Receivable"]]);
+		frm.events.filter_accounts("accounts_receivable_credit", frm, [["account_type", "=", "Receivable"]]);
+		frm.events.filter_accounts("accounts_receivable_unpaid", frm, [["account_type", "=", "Receivable"]]);
 
 	},
 
 	filter_accounts: (fieldname, frm, addl_filters) => {
-		let filters = {
-			"company": frm.doc.company,
-			"is_group": 0
-		};
-		if(addl_filters) Object.assign(filters, addl_filters);
+		let filters = [
+			["company", "=", frm.doc.company],
+			["is_group", "=", 0]
+		];
+		if(addl_filters){
+			filters = $.merge(filters , addl_filters);
+		}
 
 		frm.set_query(fieldname, () => { return { "filters": filters }; });
 	},
 
+	refresh_filters: (frm) =>{
+		let invoice_accounts = Object.keys(frm.doc.invoices).map(function(key) {
+			return frm.doc.invoices[key].debit_to;
+		});
+		let filters = [
+			["account_type", "=", "Receivable"],
+			["name", "not in", invoice_accounts]
+		];
+		frm.events.filter_accounts("accounts_receivable_credit", frm, filters);
+		frm.events.filter_accounts("accounts_receivable_discounted", frm, filters);
+		frm.events.filter_accounts("accounts_receivable_unpaid", frm, filters);
+	},
+
 	refresh: (frm) => {
 		frm.events.show_general_ledger(frm);
 
-		if(frm.doc.docstatus === 0) {
+		if (frm.doc.docstatus === 0) {
 			frm.add_custom_button(__('Get Invoices'), function() {
 				frm.events.get_invoices(frm);
 			});
 		}
 
-		if(frm.doc.docstatus === 1 && frm.doc.status !== "Settled") {
-			if(frm.doc.status == "Sanctioned") {
+		if (frm.doc.docstatus === 1 && frm.doc.status !== "Settled") {
+			if (frm.doc.status == "Sanctioned") {
 				frm.add_custom_button(__('Disburse Loan'), function() {
 					frm.events.create_disbursement_entry(frm);
 				}).addClass("btn-primary");
 			}
-			if(frm.doc.status == "Disbursed") {
+			if (frm.doc.status == "Disbursed") {
 				frm.add_custom_button(__('Close Loan'), function() {
 					frm.events.close_loan(frm);
 				}).addClass("btn-primary");
@@ -64,7 +80,7 @@
 	},
 
 	set_end_date: (frm) => {
-		if(frm.doc.loan_start_date && frm.doc.loan_period) {
+		if (frm.doc.loan_start_date && frm.doc.loan_period) {
 			let end_date = frappe.datetime.add_days(frm.doc.loan_start_date, frm.doc.loan_period);
 			frm.set_value("loan_end_date", end_date);
 		}
@@ -132,6 +148,7 @@
 								frm.doc.invoices = frm.doc.invoices.filter(row => row.sales_invoice);
 								let row = frm.add_child("invoices");
 								$.extend(row, v);
+								frm.events.refresh_filters(frm);
 							});
 							refresh_field("invoices");
 						}
@@ -190,8 +207,10 @@
 frappe.ui.form.on('Discounted Invoice', {
 	sales_invoice: (frm) => {
 		frm.events.calculate_total_amount(frm);
+		frm.events.refresh_filters(frm);
 	},
 	invoices_remove: (frm) => {
 		frm.events.calculate_total_amount(frm);
+		frm.events.refresh_filters(frm);
 	}
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py
index 29475d5..36c2911 100644
--- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py
+++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py
@@ -12,6 +12,7 @@
 class InvoiceDiscounting(AccountsController):
 	def validate(self):
 		self.validate_mandatory()
+		self.validate_invoices()
 		self.calculate_total_amount()
 		self.set_status()
 		self.set_end_date()
@@ -24,6 +25,15 @@
 		if self.docstatus == 1 and not (self.loan_start_date and self.loan_period):
 			frappe.throw(_("Loan Start Date and Loan Period are mandatory to save the Invoice Discounting"))
 
+	def validate_invoices(self):
+		discounted_invoices = [record.sales_invoice for record in 
+			frappe.get_all("Discounted Invoice",fields = ["sales_invoice"], filters= {"docstatus":1})]
+
+		for record in self.invoices:
+			if record.sales_invoice in discounted_invoices:
+				frappe.throw("Row({0}): {1} is already discounted in {2}"
+					.format(record.idx, frappe.bold(record.sales_invoice), frappe.bold(record.parent)))
+
 	def calculate_total_amount(self):
 		self.total_amount = sum([flt(d.outstanding_amount) for d in self.invoices])
 
@@ -212,7 +222,8 @@
 			name as sales_invoice,
 			customer,
 			posting_date,
-			outstanding_amount
+			outstanding_amount,
+			debit_to
 		from `tabSales Invoice` si
 		where
 			docstatus = 1
diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py
index 479548c..e290b23 100755
--- a/erpnext/accounts/doctype/sales_invoice/pos.py
+++ b/erpnext/accounts/doctype/sales_invoice/pos.py
@@ -432,7 +432,6 @@
 
 	return cust_id
 
-
 def make_customer_and_address(customers):
 	customers_list = []
 	for customer, data in iteritems(customers):
@@ -449,7 +448,6 @@
 	frappe.db.commit()
 	return customers_list
 
-
 def add_customer(data):
 	customer = data.get('full_name') or data.get('customer')
 	if frappe.db.exists("Customer", customer.strip()):
@@ -466,21 +464,18 @@
 	frappe.db.commit()
 	return customer_doc.name
 
-
 def get_territory(data):
 	if data.get('territory'):
 		return data.get('territory')
 
 	return frappe.db.get_single_value('Selling Settings','territory') or _('All Territories')
 
-
 def get_customer_group(data):
 	if data.get('customer_group'):
 		return data.get('customer_group')
 
 	return frappe.db.get_single_value('Selling Settings', 'customer_group') or frappe.db.get_value('Customer Group', {'is_group': 0}, 'name')
 
-
 def make_contact(args, customer):
 	if args.get('email_id') or args.get('phone'):
 		name = frappe.db.get_value('Dynamic Link',
@@ -506,7 +501,6 @@
 		doc.flags.ignore_mandatory = True
 		doc.save(ignore_permissions=True)
 
-
 def make_address(args, customer):
 	if not args.get('address_line1'):
 		return
@@ -521,7 +515,10 @@
 		address = frappe.get_doc('Address', name)
 	else:
 		address = frappe.new_doc('Address')
-		address.country = frappe.get_cached_value('Company',  args.get('company'),  'country')
+		if args.get('company'):
+			address.country = frappe.get_cached_value('Company',
+				args.get('company'),  'country')
+
 		address.append('links', {
 			'link_doctype': 'Customer',
 			'link_name': customer
@@ -533,7 +530,6 @@
 	address.flags.ignore_mandatory = True
 	address.save(ignore_permissions=True)
 
-
 def make_email_queue(email_queue):
 	name_list = []
 	for key, data in iteritems(email_queue):
@@ -550,7 +546,6 @@
 
 	return name_list
 
-
 def validate_item(doc):
 	for item in doc.get('items'):
 		if not frappe.db.exists('Item', item.get('item_code')):
@@ -569,7 +564,6 @@
 			item_doc.save(ignore_permissions=True)
 			frappe.db.commit()
 
-
 def submit_invoice(si_doc, name, doc, name_list):
 	try:
 		si_doc.insert()
@@ -585,7 +579,6 @@
 
 	return name_list
 
-
 def save_invoice(doc, name, name_list):
 	try:
 		if not frappe.db.exists('Sales Invoice', {'offline_pos_name': name}):
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 4f80b78..95c5dd5 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -206,9 +206,9 @@
 			total_amount_in_payments = 0
 			for payment in self.payments:
 				total_amount_in_payments += payment.amount
-
-			if total_amount_in_payments < self.rounded_total:
-				frappe.throw(_("Total payments amount can't be greater than {}".format(-self.rounded_total)))
+			invoice_total = self.rounded_total or self.grand_total
+			if total_amount_in_payments < invoice_total:
+				frappe.throw(_("Total payments amount can't be greater than {}".format(-invoice_total)))
 
 	def validate_pos_paid_amount(self):
 		if len(self.payments) == 0 and self.is_pos:
@@ -1510,4 +1510,4 @@
 		"outstanding_amount": invoice.outstanding_amount
 	})
 
-	return invoice_discounting
\ No newline at end of file
+	return invoice_discounting
diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js
index 3834c96..b5a02d0 100755
--- a/erpnext/accounts/page/pos/pos.js
+++ b/erpnext/accounts/page/pos/pos.js
@@ -1762,18 +1762,11 @@
 		this.si_docs = this.get_submitted_invoice() || [];
 		this.email_queue_list = this.get_email_queue() || {};
 		this.customers_list = this.get_customers_details() || {};
-		if(this.customer_doc) {
-			this.freeze = this.customer_doc.display
-		}
 
-		freeze_screen = this.freeze_screen || false;
-
-		if ((this.si_docs.length || this.email_queue_list || this.customers_list) && !this.freeze) {
-			this.freeze = true;
-
+		if (this.si_docs.length || this.email_queue_list || this.customers_list) {
 			frappe.call({
 				method: "erpnext.accounts.doctype.sales_invoice.pos.make_invoice",
-				freeze: freeze_screen,
+				freeze: true,
 				args: {
 					doc_list: me.si_docs,
 					email_queue_list: me.email_queue_list,
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 45d2ec2..ab37e91 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -255,9 +255,15 @@
 		precision = self.precision("gross_purchase_amount")
 
 		if row.depreciation_method in ("Straight Line", "Manual"):
+			depreciation_left = (cint(row.total_number_of_depreciations) - cint(self.number_of_depreciations_booked))
+
+			if not depreciation_left:
+				frappe.msgprint(_("All the depreciations has been booked"))
+				depreciation_amount = flt(row.expected_value_after_useful_life)
+				return depreciation_amount
+
 			depreciation_amount = (flt(row.value_after_depreciation) -
-				flt(row.expected_value_after_useful_life)) / (cint(row.total_number_of_depreciations) -
-				cint(self.number_of_depreciations_booked))
+				flt(row.expected_value_after_useful_life)) / depreciation_left
 		else:
 			depreciation_amount = flt(depreciable_value * (flt(row.rate_of_depreciation) / 100), precision)
 
@@ -275,7 +281,7 @@
 					flt(accumulated_depreciation_after_full_schedule),
 					self.precision('gross_purchase_amount'))
 
-				if (row.expected_value_after_useful_life and 
+				if (row.expected_value_after_useful_life and
 					row.expected_value_after_useful_life < asset_value_after_full_schedule):
 					frappe.throw(_("Depreciation Row {0}: Expected value after useful life must be greater than or equal to {1}")
 						.format(row.idx, asset_value_after_full_schedule))
diff --git a/erpnext/config/crm.py b/erpnext/config/crm.py
index 70784f3..eba6c7a 100644
--- a/erpnext/config/crm.py
+++ b/erpnext/config/crm.py
@@ -41,6 +41,11 @@
 					"name": "Lead Source",
 					"description": _("Track Leads by Lead Source.")
 				},
+				{
+					"type": "doctype",
+					"name": "Contract",
+					"description": _("Helps you keep tracks of Contracts based on Supplier, Customer and Employee"),
+				},
 			]
 		},
 		{
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index 2cbe596..52d58dc 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -45,6 +45,7 @@
 		self.set_gross_profit()
 		set_default_income_account_for_item(self)
 		self.set_customer_address()
+		self.validate_for_duplicate_items()
 
 	def set_missing_values(self, for_validate=False):
 
@@ -381,6 +382,34 @@
 			if self.get(address_field):
 				self.set(address_display_field, get_address_display(self.get(address_field)))
 
+	def validate_for_duplicate_items(self):
+		check_list, chk_dupl_itm = [], []
+		if cint(frappe.db.get_single_value("Selling Settings", "allow_multiple_items")):
+			return
+
+		for d in self.get('items'):
+			if self.doctype == "Sales Invoice":
+				e = [d.item_code, d.description, d.warehouse, d.sales_order or d.delivery_note, d.batch_no or '']
+				f = [d.item_code, d.description, d.sales_order or d.delivery_note]
+			elif self.doctype == "Delivery Note":
+				e = [d.item_code, d.description, d.warehouse, d.against_sales_order or d.against_sales_invoice, d.batch_no or '']
+				f = [d.item_code, d.description, d.against_sales_order or d.against_sales_invoice]
+			elif self.doctype == "Sales Order":
+				e = [d.item_code, d.description, d.warehouse, d.batch_no or '']
+				f = [d.item_code, d.description]
+
+			if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1:
+				if e in check_list:
+					frappe.throw(_("Note: Item {0} entered multiple times").format(d.item_code))
+				else:
+					check_list.append(e)
+			else:
+				if f in chk_dupl_itm:
+					frappe.throw(_("Note: Item {0} entered multiple times").format(d.item_code))
+				else:
+					chk_dupl_itm.append(f)
+
+
 	def validate_items(self):
 		# validate items to see if they have is_sales_item enabled
 		from erpnext.controllers.buying_controller import validate_item_type
diff --git a/erpnext/hr/doctype/leave_application/leave_application_list.js b/erpnext/hr/doctype/leave_application/leave_application_list.js
index f69b182..cbb4b73 100644
--- a/erpnext/hr/doctype/leave_application/leave_application_list.js
+++ b/erpnext/hr/doctype/leave_application/leave_application_list.js
@@ -5,6 +5,8 @@
 			return [__("Approved"), "green", "status,=,Approved"];
 		} else if (doc.status === "Rejected") {
 			return [__("Rejected"), "red", "status,=,Rejected"];
+		} else {
+			return [__("Open"), "red", "status,=,Open"];
 		}
 	}
 };
diff --git a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py
index e2989e2..e5622b7 100644
--- a/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py
+++ b/erpnext/hr/report/vehicle_expenses/vehicle_expenses.py
@@ -23,7 +23,8 @@
 		_("Model") + ":data:50", _("Location") + ":data:100",
 		_("Log") + ":Link/Vehicle Log:100", _("Odometer") + ":Int:80",
 		_("Date") + ":Date:100", _("Fuel Qty") + ":Float:80",
-		_("Fuel Price") + ":Float:100",_("Service Expense") + ":Float:100"
+		_("Fuel Price") + ":Float:100",_("Fuel Expense") + ":Float:100",
+		_("Service Expense") + ":Float:100"
 	]
 	return columns
 
@@ -32,7 +33,8 @@
 	data = frappe.db.sql("""select
 			vhcl.license_plate as "License", vhcl.make as "Make", vhcl.model as "Model",
 			vhcl.location as "Location", log.name as "Log", log.odometer as "Odometer",
-			log.date as "Date", log.fuel_qty as "Fuel Qty", log.price as "Fuel Price"
+			log.date as "Date", log.fuel_qty as "Fuel Qty", log.price as "Fuel Price",
+			log.fuel_qty * log.price as "Fuel Expense"
 		from
 			`tabVehicle` vhcl,`tabVehicle Log` log
 		where
@@ -58,7 +60,7 @@
 		total_ser_exp=0
 		for row in data:
 			if row["Date"] <= period.to_date and row["Date"] >= period.from_date:
-				total_fuel_exp+=flt(row["Fuel Price"])
+				total_fuel_exp+=flt(row["Fuel Expense"])
 				total_ser_exp+=flt(row["Service Expense"])
 		fueldata.append([period.key,total_fuel_exp])
 		servicedata.append([period.key,total_ser_exp])
@@ -84,4 +86,4 @@
 		}
 	}
 	chart["type"] = "line"
-	return chart
\ No newline at end of file
+	return chart
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 09dc9a9..4342af5 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -72,9 +72,7 @@
 				frappe.msgprint(_("Warning: Sales Order {0} already exists against Customer's Purchase Order {1}").format(so[0][0], self.po_no))
 
 	def validate_for_items(self):
-		check_list = []
 		for d in self.get('items'):
-			check_list.append(cstr(d.item_code))
 
 			# used for production plan
 			d.transaction_date = self.transaction_date
@@ -83,13 +81,6 @@
 				where item_code = %s and warehouse = %s", (d.item_code, d.warehouse))
 			d.projected_qty = tot_avail_qty and flt(tot_avail_qty[0][0]) or 0
 
-		# check for same entry multiple times
-		unique_chk_list = set(check_list)
-		if len(unique_chk_list) != len(check_list) and \
-			not cint(frappe.db.get_single_value("Selling Settings", "allow_multiple_items")):
-			frappe.msgprint(_("Same item has been entered multiple times"),
-				title=_("Warning"), indicator='orange')
-
 	def product_bundle_has_stock_item(self, product_bundle):
 		"""Returns true if product bundle has stock item"""
 		ret = len(frappe.db.sql("""select i.name from tabItem i, `tabProduct Bundle Item` pbi
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index 2de9b97..f79d127 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -166,24 +166,7 @@
 				frappe.throw(_("Customer {0} does not belong to project {1}").format(self.customer, self.project))
 
 	def validate_for_items(self):
-		check_list, chk_dupl_itm = [], []
-		if cint(frappe.db.get_single_value("Selling Settings", "allow_multiple_items")):
-			return
-
 		for d in self.get('items'):
-			e = [d.item_code, d.description, d.warehouse, d.against_sales_order or d.against_sales_invoice, d.batch_no or '']
-			f = [d.item_code, d.description, d.against_sales_order or d.against_sales_invoice]
-
-			if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1:
-				if e in check_list:
-					frappe.msgprint(_("Note: Item {0} entered multiple times").format(d.item_code))
-				else:
-					check_list.append(e)
-			else:
-				if f in chk_dupl_itm:
-					frappe.msgprint(_("Note: Item {0} entered multiple times").format(d.item_code))
-				else:
-					chk_dupl_itm.append(f)
 			#Customer Provided parts will have zero valuation rate
 			if frappe.db.get_value('Item', d.item_code, 'is_customer_provided_item'):
 				d.allow_zero_valuation_rate = 1