Merge pull request #25304 from ankush/fix_sl_rounding

fix(stock_ledger): round off values near to zero
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index d2e5870..199a183 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -5,7 +5,7 @@
 from erpnext.hooks import regional_overrides
 from frappe.utils import getdate
 
-__version__ = '13.0.1'
+__version__ = '13.0.0-dev'
 
 def get_default_company(user=None):
 	'''Get default company for user'''
diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction.json b/erpnext/accounts/doctype/bank_transaction/bank_transaction.json
index 69ee497..88aa7ef 100644
--- a/erpnext/accounts/doctype/bank_transaction/bank_transaction.json
+++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction.json
@@ -175,22 +175,24 @@
   },
   {
    "fieldname": "deposit",
-   "oldfieldname": "debit",
    "fieldtype": "Currency",
    "in_list_view": 1,
-   "label": "Deposit"
+   "label": "Deposit",
+   "oldfieldname": "debit",
+   "options": "currency"
   },
   {
    "fieldname": "withdrawal",
-   "oldfieldname": "credit",
    "fieldtype": "Currency",
    "in_list_view": 1,
-   "label": "Withdrawal"
+   "label": "Withdrawal",
+   "oldfieldname": "credit",
+   "options": "currency"
   }
  ],
  "is_submittable": 1,
  "links": [],
- "modified": "2020-12-30 19:40:54.221070",
+ "modified": "2021-04-14 17:31:58.963529",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Bank Transaction",
diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.json b/erpnext/buying/doctype/buying_settings/buying_settings.json
index 248cb9a..630a1dc 100644
--- a/erpnext/buying/doctype/buying_settings/buying_settings.json
+++ b/erpnext/buying/doctype/buying_settings/buying_settings.json
@@ -13,6 +13,8 @@
   "po_required",
   "pr_required",
   "maintain_same_rate",
+  "maintain_same_rate_action",
+  "role_to_override_stop_action",
   "allow_multiple_items",
   "subcontract",
   "backflush_raw_materials_of_subcontract_based_on",
@@ -89,6 +91,23 @@
   {
    "fieldname": "column_break_11",
    "fieldtype": "Column Break"
+  },
+  {
+   "default": "Stop",
+   "depends_on": "maintain_same_rate",
+   "description": "Configure the action to stop the transaction or just warn if the same rate is not maintained.",
+   "fieldname": "maintain_same_rate_action",
+   "fieldtype": "Select",
+   "label": "Action If Same Rate is Not Maintained",
+   "mandatory_depends_on": "maintain_same_rate",
+   "options": "Stop\nWarn"
+  },
+  {
+   "depends_on": "eval:doc.maintain_same_rate_action == 'Stop'",
+   "fieldname": "role_to_override_stop_action",
+   "fieldtype": "Link",
+   "label": "Role Allowed to Override Stop Action",
+   "options": "Role"
   }
  ],
  "icon": "fa fa-cog",
@@ -96,7 +115,7 @@
  "index_web_pages_for_search": 1,
  "issingle": 1,
  "links": [],
- "modified": "2021-03-02 17:34:04.190677",
+ "modified": "2021-04-04 20:01:44.087066",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Buying Settings",
diff --git a/erpnext/change_log/v13/v13.0.2.md b/erpnext/change_log/v13/v13.0.2.md
new file mode 100644
index 0000000..2bfbdfc
--- /dev/null
+++ b/erpnext/change_log/v13/v13.0.2.md
@@ -0,0 +1,7 @@
+## Version 13.0.2 Release Notes
+
+### Fixes
+- fix: frappe.whitelist for doc methods ([#25231](https://github.com/frappe/erpnext/pull/25231))
+- fix: incorrect incoming rate for the sales return ([#25306](https://github.com/frappe/erpnext/pull/25306))
+- fix(e-invoicing): validations & tax calculation fixes ([#25314](https://github.com/frappe/erpnext/pull/25314))
+- fix: update scheduler check time ([#25295](https://github.com/frappe/erpnext/pull/25295))
\ No newline at end of file
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index 219d529..b686dc0 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -6,6 +6,7 @@
 from frappe import _, msgprint
 from frappe.utils import flt,cint, cstr, getdate
 from six import iteritems
+from collections import OrderedDict
 from erpnext.accounts.party import get_party_details
 from erpnext.stock.get_item_details import get_conversion_factor
 from erpnext.buying.utils import validate_for_items, update_last_purchase_rate
@@ -391,10 +392,12 @@
 
 					batches_qty = get_batches_with_qty(raw_material.rm_item_code, raw_material.main_item_code,
 						qty, transferred_batch_qty_map, backflushed_batch_qty_map, item.purchase_order)
+
 					for batch_data in batches_qty:
 						qty = batch_data['qty']
 						raw_material.batch_no = batch_data['batch']
-						self.append_raw_material_to_be_backflushed(item, raw_material, qty)
+						if qty > 0:
+							self.append_raw_material_to_be_backflushed(item, raw_material, qty)
 				else:
 					self.append_raw_material_to_be_backflushed(item, raw_material, qty)
 
@@ -1056,7 +1059,7 @@
 	for batch_data in transferred_batches:
 		key = ((batch_data.item_code, fg_item)
 			if batch_data.subcontracted_item else (batch_data.item_code, purchase_order))
-		transferred_batch_qty_map.setdefault(key, {})
+		transferred_batch_qty_map.setdefault(key, OrderedDict())
 		transferred_batch_qty_map[key][batch_data.batch_no] = batch_data.qty
 
 	return transferred_batch_qty_map
@@ -1109,8 +1112,14 @@
 		if available_qty >= required_qty:
 			available_batches.append({'batch': batch, 'qty': required_qty})
 			break
-		else:
+		elif available_qty != 0:
 			available_batches.append({'batch': batch, 'qty': available_qty})
 			required_qty -= available_qty
 
+	for row in available_batches:
+		if backflushed_batches.get(row.get('batch'), 0) > 0:
+			backflushed_batches[row.get('batch')] += row.get('qty')
+		else:
+			backflushed_batches[row.get('batch')] = row.get('qty')
+
 	return available_batches
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index 81f0ad3..c0c1315 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -325,7 +325,7 @@
 			and status not in ("Stopped", "Closed") %(fcond)s
 			and (
 				(`tabDelivery Note`.is_return = 0 and `tabDelivery Note`.per_billed < 100)
-				or `tabDelivery Note`.grand_total = 0
+				or (`tabDelivery Note`.grand_total = 0 and `tabDelivery Note`.per_billed < 100)
 				or (
 					`tabDelivery Note`.is_return = 1
 					and return_against in (select name from `tabDelivery Note` where per_billed < 100)
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index de61b35..5f759b4 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -5,6 +5,7 @@
 import frappe, erpnext
 from frappe import _
 from frappe.model.meta import get_field_precision
+from erpnext.stock.utils import get_incoming_rate
 from frappe.utils import flt, get_datetime, format_datetime
 
 class StockOverReturnError(frappe.ValidationError): pass
@@ -389,10 +390,24 @@
 
 	return doclist
 
-def get_rate_for_return(voucher_type, voucher_no, item_code, return_against=None, item_row=None, voucher_detail_no=None):
+def get_rate_for_return(voucher_type, voucher_no, item_code, return_against=None,
+	item_row=None, voucher_detail_no=None, sle=None):
 	if not return_against:
 		return_against = frappe.get_cached_value(voucher_type, voucher_no, "return_against")
 
+	if not return_against and voucher_type == 'Sales Invoice' and sle:
+		return get_incoming_rate({
+			"item_code": sle.item_code,
+			"warehouse": sle.warehouse,
+			"posting_date": sle.get('posting_date'),
+			"posting_time": sle.get('posting_time'),
+			"qty": sle.actual_qty,
+			"serial_no": sle.get('serial_no'),
+			"company": sle.company,
+			"voucher_type": sle.voucher_type,
+			"voucher_no": sle.voucher_no
+		}, raise_error_if_no_rate=False)
+
 	return_against_item_field = get_return_against_item_fields(voucher_type)
 
 	filters = get_filters(voucher_type, voucher_no, voucher_detail_no,
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index edc40c4..54156f37 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -311,14 +311,16 @@
 
 		items = self.get("items") + (self.get("packed_items") or [])
 		for d in items:
-			if not cint(self.get("is_return")):
+			if not self.get("return_against"):
 				# Get incoming rate based on original item cost based on valuation method
+				qty = flt(d.get('stock_qty') or d.get('actual_qty'))
+
 				d.incoming_rate = get_incoming_rate({
 					"item_code": d.item_code,
 					"warehouse": d.warehouse,
 					"posting_date": self.get('posting_date') or self.get('transaction_date'),
 					"posting_time": self.get('posting_time') or nowtime(),
-					"qty": -1 * flt(d.get('stock_qty') or d.get('actual_qty')),
+					"qty": qty if cint(self.get("is_return")) else (-1 * qty),
 					"serial_no": d.get('serial_no'),
 					"company": self.company,
 					"voucher_type": self.doctype,
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 1ae7310..9fae494 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -291,10 +291,13 @@
 				# set precision in the last item iteration
 				if n == len(self.doc.get("items")) - 1:
 					self.round_off_totals(tax)
+					self._set_in_company_currency(tax,
+						["tax_amount", "tax_amount_after_discount_amount"])
+
+					self.round_off_base_values(tax)
 					self.set_cumulative_total(i, tax)
 
-					self._set_in_company_currency(tax,
-						["total", "tax_amount", "tax_amount_after_discount_amount"])
+					self._set_in_company_currency(tax, ["total"])
 
 					# adjust Discount Amount loss in last tax iteration
 					if i == (len(self.doc.get("taxes")) - 1) and self.discount_amount_applied \
@@ -341,20 +344,11 @@
 		elif tax.charge_type == "On Item Quantity":
 			current_tax_amount = tax_rate * item.qty
 
-		current_tax_amount = self.get_final_current_tax_amount(tax, current_tax_amount)
-
 		if not self.doc.get("is_consolidated"):
 			self.set_item_wise_tax(item, tax, tax_rate, current_tax_amount)
 
 		return current_tax_amount
 
-	def get_final_current_tax_amount(self, tax, current_tax_amount):
-		# Some countries need individual tax components to be rounded
-		# Handeled via regional doctypess
-		if tax.account_head in frappe.flags.round_off_applicable_accounts:
-			current_tax_amount = round(current_tax_amount, 0)
-		return current_tax_amount
-
 	def set_item_wise_tax(self, item, tax, tax_rate, current_tax_amount):
 		# store tax breakup for each item
 		key = item.item_code or item.item_name
@@ -365,10 +359,20 @@
 		tax.item_wise_tax_detail[key] = [tax_rate,flt(item_wise_tax_amount)]
 
 	def round_off_totals(self, tax):
+		if tax.account_head in frappe.flags.round_off_applicable_accounts:
+			tax.tax_amount = round(tax.tax_amount, 0)
+			tax.tax_amount_after_discount_amount = round(tax.tax_amount_after_discount_amount, 0)
+
 		tax.tax_amount = flt(tax.tax_amount, tax.precision("tax_amount"))
 		tax.tax_amount_after_discount_amount = flt(tax.tax_amount_after_discount_amount,
 			tax.precision("tax_amount"))
 
+	def round_off_base_values(self, tax):
+		# Round off to nearest integer based on regional settings
+		if tax.account_head in frappe.flags.round_off_applicable_accounts:
+			tax.base_tax_amount = round(tax.base_tax_amount, 0)
+			tax.base_tax_amount_after_discount_amount = round(tax.base_tax_amount_after_discount_amount, 0)
+
 	def manipulate_grand_total_for_inclusive_tax(self):
 		# if fully inclusive taxes and diff
 		if self.doc.get("taxes") and any([cint(t.included_in_print_rate) for t in self.doc.get("taxes")]):
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 98d5966..bb6cd8b 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -307,6 +307,8 @@
 	"Inpatient Medication Entry"
 ]
 
+after_migrate = ["erpnext.setup.install.update_select_perm_after_install"]
+
 scheduler_events = {
 	"cron": {
 		"0/30 * * * *": [
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 14f1ab8..1f80088 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -771,3 +771,4 @@
 erpnext.patches.v12_0.purchase_receipt_status
 erpnext.patches.v13_0.fix_non_unique_represents_company
 erpnext.patches.v12_0.add_document_type_field_for_italy_einvoicing
+erpnext.patches.v13_0.make_non_standard_user_type #13-04-2021
diff --git a/erpnext/patches/v12_0/add_company_link_to_einvoice_settings.py b/erpnext/patches/v12_0/add_company_link_to_einvoice_settings.py
index 3b560fd..b6bd5fa 100644
--- a/erpnext/patches/v12_0/add_company_link_to_einvoice_settings.py
+++ b/erpnext/patches/v12_0/add_company_link_to_einvoice_settings.py
@@ -12,5 +12,5 @@
 			select dl.link_name from `tabAddress` a, `tabDynamic Link` dl
 			where a.gstin = %s and dl.parent = a.name and dl.link_doctype = 'Company'
 		""", (creds.get('gstin')))
-		if company_name and len(company_name) == 1:
+		if company_name and len(company_name) > 0:
 			frappe.db.set_value('E Invoice User', creds.get('name'), 'company', company_name[0][0])
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/make_non_standard_user_type.py b/erpnext/patches/v13_0/make_non_standard_user_type.py
new file mode 100644
index 0000000..a9d7883
--- /dev/null
+++ b/erpnext/patches/v13_0/make_non_standard_user_type.py
@@ -0,0 +1,24 @@
+# Copyright (c) 2019, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+from six import iteritems
+from erpnext.setup.install import add_non_standard_user_types
+
+def execute():
+	doctype_dict = {
+		'projects': ['Timesheet'],
+		'payroll': ['Salary Slip', 'Employee Tax Exemption Declaration', 'Employee Tax Exemption Proof Submission'],
+		'hr': ['Employee', 'Expense Claim', 'Leave Application', 'Attendance Request', 'Compensatory Leave Request']
+	}
+
+	for module, doctypes in iteritems(doctype_dict):
+		for doctype in doctypes:
+			frappe.reload_doc(module, 'doctype', doctype)
+
+
+	frappe.flags.ignore_select_perm = True
+	frappe.flags.update_select_perm_after_migrate = True
+
+	add_non_standard_user_types()
\ No newline at end of file
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py
index afdf081..539f2c5 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.py
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py
@@ -633,8 +633,6 @@
 
 		if additional_salary:
 			component_row.default_amount = 0
-			component_row.additional_amount = amount
-			component_row.additional_salary = additional_salary.name
 			component_row.deduct_full_tax_on_selected_payroll_date = \
 				additional_salary.deduct_full_tax_on_selected_payroll_date
 		else:
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 3a3ee38..2e133be 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -323,12 +323,15 @@
 				// set precision in the last item iteration
 				if (n == me.frm.doc["items"].length - 1) {
 					me.round_off_totals(tax);
+					me.set_in_company_currency(tax,
+						["tax_amount", "tax_amount_after_discount_amount"]);
+
+					me.round_off_base_values(tax);
 
 					// in tax.total, accumulate grand total for each item
 					me.set_cumulative_total(i, tax);
 
-					me.set_in_company_currency(tax,
-						["total", "tax_amount", "tax_amount_after_discount_amount"]);
+					me.set_in_company_currency(tax, ["total"]);
 
 					// adjust Discount Amount loss in last tax iteration
 					if ((i == me.frm.doc["taxes"].length - 1) && me.discount_amount_applied
@@ -393,20 +396,11 @@
 			current_tax_amount = tax_rate * item.qty;
 		}
 
-		current_tax_amount = this.get_final_tax_amount(tax, current_tax_amount);
 		this.set_item_wise_tax(item, tax, tax_rate, current_tax_amount);
 
 		return current_tax_amount;
 	},
 
-	get_final_tax_amount: function(tax, current_tax_amount) {
-		if (frappe.flags.round_off_applicable_accounts.includes(tax.account_head)) {
-			current_tax_amount = Math.round(current_tax_amount);
-		}
-
-		return current_tax_amount;
-	},
-
 	set_item_wise_tax: function(item, tax, tax_rate, current_tax_amount) {
 		// store tax breakup for each item
 		let tax_detail = tax.item_wise_tax_detail;
@@ -420,10 +414,22 @@
 	},
 
 	round_off_totals: function(tax) {
+		if (frappe.flags.round_off_applicable_accounts.includes(tax.account_head)) {
+			tax.tax_amount= Math.round(tax.tax_amount);
+			tax.tax_amount_after_discount_amount = Math.round(tax.tax_amount_after_discount_amount);
+		}
+
 		tax.tax_amount = flt(tax.tax_amount, precision("tax_amount", tax));
 		tax.tax_amount_after_discount_amount = flt(tax.tax_amount_after_discount_amount, precision("tax_amount", tax));
 	},
 
+	round_off_base_values: function(tax) {
+		if (frappe.flags.round_off_applicable_accounts.includes(tax.account_head)) {
+			tax.base_tax_amount= Math.round(tax.base_tax_amount);
+			tax.base_tax_amount_after_discount_amount = Math.round(tax.base_tax_amount_after_discount_amount);
+		}
+	},
+
 	manipulate_grand_total_for_inclusive_tax: function() {
 		var me = this;
 		// if fully inclusive taxes and diff
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index e5b50d8..fd98f17 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -291,17 +291,15 @@
 			return options[0];
 		}
 	},
-	copy_parent_value_in_all_row: function(doc, dt, dn, table_fieldname, fieldname, parent_fieldname) {
-		var d = locals[dt][dn];
-		if(d[fieldname]){
-			var cl = doc[table_fieldname] || [];
-			for(var i = 0; i < cl.length; i++) {
+	overrides_parent_value_in_all_rows: function(doc, dt, dn, table_fieldname, fieldname, parent_fieldname) {
+		if (doc[parent_fieldname]) {
+			let cl = doc[table_fieldname] || [];
+			for (let i = 0; i < cl.length; i++) {
 				cl[i][fieldname] = doc[parent_fieldname];
 			}
+			frappe.refresh_field(table_fieldname);
 		}
-		refresh_field(table_fieldname);
 	},
-
 	create_new_doc: function (doctype, update_fields) {
 		frappe.model.with_doctype(doctype, function() {
 			var new_doc = frappe.model.get_new_doc(doctype);
diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py
index 605f4e1..59c098c 100644
--- a/erpnext/regional/india/e_invoice/utils.py
+++ b/erpnext/regional/india/e_invoice/utils.py
@@ -466,21 +466,24 @@
 	try:
 		einvoice = safe_json_load(einvoice)
 		einvoice = santize_einvoice_fields(einvoice)
-		validate_totals(einvoice)
-
 	except Exception:
-		log_error(einvoice)
-		link_to_error_list = '<a href="List/Error Log/List?method=E Invoice Request Failed">Error Log</a>'
-		frappe.throw(
-			_('An error occurred while creating e-invoice for {}. Please check {} for more information.').format(
-				invoice.name, link_to_error_list),
-			title=_('E Invoice Creation Failed')
-		)
+		show_link_to_error_log(invoice, einvoice)
+
+	validate_totals(einvoice)
 
 	return einvoice
 
+def show_link_to_error_log(invoice, einvoice):
+	err_log = log_error(einvoice)
+	link_to_error_log = get_link_to_form('Error Log', err_log.name, 'Error Log')
+	frappe.throw(
+		_('An error occurred while creating e-invoice for {}. Please check {} for more information.').format(
+			invoice.name, link_to_error_log),
+		title=_('E Invoice Creation Failed')
+	)
+
 def log_error(data=None):
-	if not isinstance(data, dict):
+	if isinstance(data, six.string_types):
 		data = json.loads(data)
 
 	seperator = "--" * 50
@@ -587,7 +590,7 @@
 			self.credentials = self.e_invoice_settings.credentials[0] if self.e_invoice_settings.credentials else None
 
 	def get_seller_gstin(self):
-		gstin = self.invoice.company_gstin or frappe.db.get_value('Address', self.invoice.company_address, 'gstin')
+		gstin = frappe.db.get_value('Address', self.invoice.company_address, 'gstin')
 		if not gstin:
 			frappe.throw(_('Cannot retrieve Company GSTIN. Please select company address with valid GSTIN.'))
 		return gstin
diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json
index 2104c01..f01934b 100644
--- a/erpnext/selling/doctype/selling_settings/selling_settings.json
+++ b/erpnext/selling/doctype/selling_settings/selling_settings.json
@@ -18,6 +18,8 @@
   "dn_required",
   "sales_update_frequency",
   "maintain_same_sales_rate",
+  "maintain_same_rate_action",
+  "role_to_override_stop_action",
   "editable_price_list_rate",
   "allow_multiple_items",
   "allow_against_multiple_purchase_orders",
@@ -133,6 +135,23 @@
    "fieldname": "hide_tax_id",
    "fieldtype": "Check",
    "label": "Hide Customer's Tax ID from Sales Transactions"
+  },
+  {
+   "default": "Stop",
+   "depends_on": "maintain_same_sales_rate",
+   "description": "Configure the action to stop the transaction or just warn if the same rate is not maintained.",
+   "fieldname": "maintain_same_rate_action",
+   "fieldtype": "Select",
+   "label": "Action If Same Rate is Not Maintained",
+   "mandatory_depends_on": "maintain_same_sales_rate",
+   "options": "Stop\nWarn"
+  },
+  {
+   "depends_on": "eval: doc.maintain_same_rate_action == 'Stop'",
+   "fieldname": "role_to_override_stop_action",
+   "fieldtype": "Link",
+   "label": "Role Allowed to Override Stop Action",
+   "options": "Role"
   }
  ],
  "icon": "fa fa-cog",
@@ -140,7 +159,7 @@
  "index_web_pages_for_search": 1,
  "issingle": 1,
  "links": [],
- "modified": "2021-03-02 17:35:53.603607",
+ "modified": "2021-04-04 20:18:12.814624",
  "modified_by": "Administrator",
  "module": "Selling",
  "name": "Selling Settings",
diff --git a/erpnext/selling/page/point_of_sale/pos_past_order_summary.js b/erpnext/selling/page/point_of_sale/pos_past_order_summary.js
index a5a739c..acf4eb3 100644
--- a/erpnext/selling/page/point_of_sale/pos_past_order_summary.js
+++ b/erpnext/selling/page/point_of_sale/pos_past_order_summary.js
@@ -204,11 +204,11 @@
 	print_receipt() {
 		const frm = this.events.get_frm();
 		frappe.utils.print(
-			frm.doctype,
-			frm.docname,
+			this.doc.doctype,
+			this.doc.name,
 			frm.pos_print_format,
-			frm.doc.letter_head,
-			frm.doc.language || frappe.boot.lang
+			this.doc.letter_head,
+			this.doc.language || frappe.boot.lang
 		);
 	}
 
diff --git a/erpnext/setup/doctype/company/delete_company_transactions.py b/erpnext/setup/doctype/company/delete_company_transactions.py
index 933ed3c..8367a25 100644
--- a/erpnext/setup/doctype/company/delete_company_transactions.py
+++ b/erpnext/setup/doctype/company/delete_company_transactions.py
@@ -15,7 +15,7 @@
 	frappe.only_for("System Manager")
 	doc = frappe.get_doc("Company", company_name)
 
-	if frappe.session.user != doc.owner:
+	if frappe.session.user != doc.owner and frappe.session.user != 'Administrator':
 		frappe.throw(_("Transactions can only be deleted by the creator of the Company"),
 			frappe.PermissionError)
 
diff --git a/erpnext/setup/install.py b/erpnext/setup/install.py
index 82f191d..c7220cb 100644
--- a/erpnext/setup/install.py
+++ b/erpnext/setup/install.py
@@ -8,9 +8,11 @@
 from .default_success_action import get_default_success_action
 from frappe import _
 from frappe.utils import cint
+from frappe.installer import update_site_config
 from frappe.desk.page.setup_wizard.setup_wizard import add_all_roles_to
 from frappe.custom.doctype.custom_field.custom_field import create_custom_field
 from erpnext.setup.default_energy_point_rules import get_default_energy_point_rules
+from six import iteritems
 
 default_mail_footer = """<div style="padding: 7px; text-align: right; color: #888"><small>Sent via
 	<a style="color: #888" href="http://erpnext.org">ERPNext</a></div>"""
@@ -29,6 +31,7 @@
 	add_company_to_session_defaults()
 	add_standard_navbar_items()
 	add_app_name()
+	add_non_standard_user_types()
 	frappe.db.commit()
 
 
@@ -164,3 +167,81 @@
 
 def add_app_name():
 	frappe.db.set_value('System Settings', None, 'app_name', 'ERPNext')
+
+def add_non_standard_user_types():
+	user_types = get_user_types_data()
+
+	user_type_limit = {}
+	for user_type, data in iteritems(user_types):
+		user_type_limit.setdefault(frappe.scrub(user_type), 10)
+
+	update_site_config('user_type_doctype_limit', user_type_limit)
+
+	for user_type, data in iteritems(user_types):
+		create_custom_role(data)
+		create_user_type(user_type, data)
+
+def get_user_types_data():
+	return {
+		'Employee Self Service': {
+			'role': 'Employee Self Service',
+			'apply_user_permission_on': 'Employee',
+			'user_id_field': 'user_id',
+			'doctypes': {
+				'Salary Slip': ['read'],
+				'Employee': ['read', 'write'],
+				'Expense Claim': ['read', 'write', 'create', 'delete'],
+				'Leave Application': ['read', 'write', 'create', 'delete'],
+				'Attendance Request': ['read', 'write', 'create', 'delete'],
+				'Compensatory Leave Request': ['read', 'write', 'create', 'delete'],
+				'Employee Tax Exemption Declaration': ['read', 'write', 'create', 'delete'],
+				'Employee Tax Exemption Proof Submission': ['read', 'write', 'create', 'delete'],
+				'Timesheet': ['read', 'write', 'create', 'delete', 'submit', 'cancel', 'amend']
+			}
+		}
+	}
+
+def create_custom_role(data):
+	if data.get('role') and not frappe.db.exists('Role', data.get('role')):
+		frappe.get_doc({
+			'doctype': 'Role',
+			'role_name': data.get('role'),
+			'desk_access': 1,
+			'is_custom': 1
+		}).insert(ignore_permissions=True)
+
+def create_user_type(user_type, data):
+	if frappe.db.exists('User Type', user_type):
+		doc = frappe.get_cached_doc('User Type', user_type)
+		doc.user_doctypes = []
+	else:
+		doc = frappe.new_doc('User Type')
+		doc.update({
+			'name': user_type,
+			'role': data.get('role'),
+			'user_id_field': data.get('user_id_field'),
+			'apply_user_permission_on': data.get('apply_user_permission_on')
+		})
+
+	create_role_permissions_for_doctype(doc, data)
+	doc.save(ignore_permissions=True)
+
+def create_role_permissions_for_doctype(doc, data):
+	for doctype, perms in iteritems(data.get('doctypes')):
+		args = {'document_type': doctype}
+		for perm in perms:
+			args[perm] = 1
+
+		doc.append('user_doctypes', args)
+
+def update_select_perm_after_install():
+	if not frappe.flags.update_select_perm_after_migrate:
+		return
+
+	frappe.flags.ignore_select_perm = False
+	for row in frappe.get_all('User Type', filters= {'is_standard': 0}):
+		print('Updating user type :- ', row.name)
+		doc = frappe.get_doc('User Type', row.name)
+		doc.save()
+
+	frappe.flags.update_select_perm_after_migrate = False
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index a9e2f77..985901f 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -372,7 +372,8 @@
 		elif sle.voucher_type in ("Purchase Receipt", "Purchase Invoice", "Delivery Note", "Sales Invoice"):
 			if frappe.get_cached_value(sle.voucher_type, sle.voucher_no, "is_return"):
 				from erpnext.controllers.sales_and_purchase_return import get_rate_for_return # don't move this import to top
-				rate = get_rate_for_return(sle.voucher_type, sle.voucher_no, sle.item_code, voucher_detail_no=sle.voucher_detail_no)
+				rate = get_rate_for_return(sle.voucher_type, sle.voucher_no, sle.item_code,
+					voucher_detail_no=sle.voucher_detail_no, sle = sle)
 			else:
 				if sle.voucher_type in ("Purchase Receipt", "Purchase Invoice"):
 					rate_field = "valuation_rate"
diff --git a/erpnext/utilities/transaction_base.py b/erpnext/utilities/transaction_base.py
index b575855..f99da58 100644
--- a/erpnext/utilities/transaction_base.py
+++ b/erpnext/utilities/transaction_base.py
@@ -120,11 +120,11 @@
 		buying_doctypes = ["Purchase Order", "Purchase Invoice", "Purchase Receipt"]
 
 		if self.doctype in buying_doctypes:
-			to_disable = "Maintain same rate throughout Purchase cycle"
-			settings_page = "Buying Settings"
+			action = frappe.db.get_single_value("Buying Settings", "maintain_same_rate_action")
+			settings_doc = "Buying Settings"
 		else:
-			to_disable = "Maintain same rate throughout Sales cycle"
-			settings_page = "Selling Settings"
+			action = frappe.db.get_single_value("Selling Settings", "maintain_same_rate_action")
+			settings_doc = "Selling Settings"
 
 		for ref_dt, ref_dn_field, ref_link_field in ref_details:
 			for d in self.get("items"):
@@ -132,11 +132,16 @@
 					ref_rate = frappe.db.get_value(ref_dt + " Item", d.get(ref_link_field), "rate")
 
 					if abs(flt(d.rate - ref_rate, d.precision("rate"))) >= .01:
-						frappe.msgprint(_("Row #{0}: Rate must be same as {1}: {2} ({3} / {4}) ")
-							.format(d.idx, ref_dt, d.get(ref_dn_field), d.rate, ref_rate))
-						frappe.throw(_("To allow different rates, disable the {0} checkbox in {1}.")
-							.format(frappe.bold(_(to_disable)),
-							get_link_to_form(settings_page, settings_page, frappe.bold(settings_page))))
+						if action == "Stop":
+							role_allowed_to_override = frappe.db.get_single_value(settings_doc, 'role_to_override_stop_action')
+
+							if role_allowed_to_override not in frappe.get_roles():
+								frappe.throw(_("Row #{0}: Rate must be same as {1}: {2} ({3} / {4})").format(
+									d.idx, ref_dt, d.get(ref_dn_field), d.rate, ref_rate))
+						else:
+							frappe.msgprint(_("Row #{0}: Rate must be same as {1}: {2} ({3} / {4})").format(
+								d.idx, ref_dt, d.get(ref_dn_field), d.rate, ref_rate), title=_("Warning"), indicator="orange")
+
 
 	def get_link_filters(self, for_doctype):
 		if hasattr(self, "prev_link_mapper") and self.prev_link_mapper.get(for_doctype):