Merge branch 'develop' into common-party-acc
diff --git a/erpnext/accounts/doctype/finance_book/test_finance_book.py b/erpnext/accounts/doctype/finance_book/test_finance_book.py
index cd8e204..2ba2139 100644
--- a/erpnext/accounts/doctype/finance_book/test_finance_book.py
+++ b/erpnext/accounts/doctype/finance_book/test_finance_book.py
@@ -9,19 +9,8 @@
 import unittest
 
 class TestFinanceBook(unittest.TestCase):
-	def create_finance_book(self):
-		if not frappe.db.exists("Finance Book", "_Test Finance Book"):
-			finance_book = frappe.get_doc({
-				"doctype": "Finance Book",
-				"finance_book_name": "_Test Finance Book"
-			}).insert()
-		else:
-			finance_book = frappe.get_doc("Finance Book", "_Test Finance Book")
-
-		return finance_book
-
 	def test_finance_book(self):
-		finance_book = self.create_finance_book()
+		finance_book = create_finance_book()
 
 		# create jv entry
 		jv = make_journal_entry("_Test Bank - _TC",
@@ -41,3 +30,14 @@
 
 		for gl_entry in gl_entries:
 			self.assertEqual(gl_entry.finance_book, finance_book.name)
+
+def create_finance_book():
+	if not frappe.db.exists("Finance Book", "_Test Finance Book"):
+		finance_book = frappe.get_doc({
+			"doctype": "Finance Book",
+			"finance_book_name": "_Test Finance Book"
+		}).insert()
+	else:
+		finance_book = frappe.get_doc("Finance Book", "_Test Finance Book")
+
+	return finance_book
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js
index 439b1ed..d96bc27 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js
@@ -533,8 +533,8 @@
 	source_exchange_rate: function(frm) {
 		if (frm.doc.paid_amount) {
 			frm.set_value("base_paid_amount", flt(frm.doc.paid_amount) * flt(frm.doc.source_exchange_rate));
-			if(!frm.set_paid_amount_based_on_received_amount &&
-					(frm.doc.paid_from_account_currency == frm.doc.paid_to_account_currency)) {
+			// target exchange rate should always be same as source if both account currencies is same
+			if(frm.doc.paid_from_account_currency == frm.doc.paid_to_account_currency) {
 				frm.set_value("target_exchange_rate", frm.doc.source_exchange_rate);
 				frm.set_value("base_received_amount", frm.doc.base_paid_amount);
 			}
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index d2dffde..abacee9 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -55,14 +55,17 @@
 		self.validate_mandatory()
 		self.validate_reference_documents()
 		self.set_tax_withholding()
-		self.apply_taxes()
 		self.set_amounts()
+		self.validate_amounts()
+		self.apply_taxes()
+		self.set_amounts_after_tax()
 		self.clear_unallocated_reference_document_rows()
 		self.validate_payment_against_negative_invoice()
 		self.validate_transaction_reference()
 		self.set_title()
 		self.set_remarks()
 		self.validate_duplicate_entry()
+		self.validate_payment_type_with_outstanding()
 		self.validate_allocated_amount()
 		self.validate_paid_invoices()
 		self.ensure_supplier_is_not_blocked()
@@ -118,6 +121,11 @@
 			if not self.get(field):
 				self.set(field, bank_data.account)
 
+	def validate_payment_type_with_outstanding(self):
+		total_outstanding = sum(d.allocated_amount for d in self.get('references'))
+		if total_outstanding < 0 and self.party_type == 'Customer' and self.payment_type == 'Receive':
+			frappe.throw(_("Cannot receive from customer against negative outstanding"), title=_("Incorrect Payment Type"))
+
 	def validate_allocated_amount(self):
 		for d in self.get("references"):
 			if (flt(d.allocated_amount))> 0:
@@ -236,7 +244,9 @@
 						self.company_currency, self.posting_date)
 
 	def set_target_exchange_rate(self, ref_doc=None):
-		if self.paid_to and not self.target_exchange_rate:
+		if self.paid_from_account_currency == self.paid_to_account_currency:
+			self.target_exchange_rate = self.source_exchange_rate
+		elif self.paid_to and not self.target_exchange_rate:
 			if ref_doc:
 				if self.paid_to_account_currency == ref_doc.currency:
 					self.target_exchange_rate = ref_doc.get("exchange_rate")
@@ -468,13 +478,22 @@
 	def set_amounts(self):
 		self.set_received_amount()
 		self.set_amounts_in_company_currency()
-		self.set_amounts_after_tax()
 		self.set_total_allocated_amount()
 		self.set_unallocated_amount()
 		self.set_difference_amount()
 
+	def validate_amounts(self):
+		self.validate_received_amount()
+	
+	def validate_received_amount(self):
+		if self.paid_from_account_currency == self.paid_to_account_currency:
+			if self.paid_amount != self.received_amount:
+				frappe.throw(_("Received Amount cannot be greater than Paid Amount"))
+
 	def set_received_amount(self):
 		self.base_received_amount = self.base_paid_amount
+		if self.paid_from_account_currency == self.paid_to_account_currency:
+			self.received_amount = self.paid_amount
 
 	def set_amounts_after_tax(self):
 		applicable_tax = 0
diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
index 801dadc..dac927b 100644
--- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
@@ -107,7 +107,7 @@
 		pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC")
 		pe.reference_no = "1"
 		pe.reference_date = "2016-01-01"
-		pe.target_exchange_rate = 50
+		pe.source_exchange_rate = 50
 		pe.insert()
 		pe.submit()
 
@@ -154,7 +154,7 @@
 		pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC")
 		pe.reference_no = "1"
 		pe.reference_date = "2016-01-01"
-		pe.target_exchange_rate = 50
+		pe.source_exchange_rate = 50
 		pe.insert()
 		pe.submit()
 
@@ -491,7 +491,7 @@
 		pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC")
 		pe.reference_no = "1"
 		pe.reference_date = "2016-01-01"
-		pe.target_exchange_rate = 55
+		pe.source_exchange_rate = 55
 
 		pe.append("deductions", {
 			"account": "_Test Exchange Gain/Loss - _TC",
diff --git a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py
index a6e3bd9..289278e 100644
--- a/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py
+++ b/erpnext/accounts/doctype/period_closing_voucher/period_closing_voucher.py
@@ -50,9 +50,13 @@
 				.format(pce[0][0], self.posting_date))
 
 	def make_gl_entries(self):
+		gl_entries = self.get_gl_entries()
+		if gl_entries:
+			from erpnext.accounts.general_ledger import make_gl_entries
+			make_gl_entries(gl_entries)
+	
+	def get_gl_entries(self):
 		gl_entries = []
-		net_pl_balance = 0
-
 		pl_accounts = self.get_pl_balances()
 
 		for acc in pl_accounts:
@@ -60,6 +64,7 @@
 				gl_entries.append(self.get_gl_dict({
 					"account": acc.account,
 					"cost_center": acc.cost_center,
+					"finance_book": acc.finance_book,
 					"account_currency": acc.account_currency,
 					"debit_in_account_currency": abs(flt(acc.bal_in_account_currency)) if flt(acc.bal_in_account_currency) < 0 else 0,
 					"debit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) < 0 else 0,
@@ -67,35 +72,13 @@
 					"credit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) > 0 else 0
 				}, item=acc))
 
-				net_pl_balance += flt(acc.bal_in_company_currency)
+		if gl_entries:
+			gle_for_net_pl_bal = self.get_pnl_gl_entry(pl_accounts)
+			gl_entries += gle_for_net_pl_bal
 
-		if net_pl_balance:
-			if self.cost_center_wise_pnl:
-				costcenter_wise_gl_entries = self.get_costcenter_wise_pnl_gl_entries(pl_accounts)
-				gl_entries += costcenter_wise_gl_entries
-			else:
-				gl_entry = self.get_pnl_gl_entry(net_pl_balance)
-				gl_entries.append(gl_entry)
-
-		from erpnext.accounts.general_ledger import make_gl_entries
-		make_gl_entries(gl_entries)
-
-	def get_pnl_gl_entry(self, net_pl_balance):
-		cost_center = frappe.db.get_value("Company", self.company, "cost_center")
-		gl_entry = self.get_gl_dict({
-			"account": self.closing_account_head,
-			"debit_in_account_currency": abs(net_pl_balance) if net_pl_balance > 0 else 0,
-			"debit": abs(net_pl_balance) if net_pl_balance > 0 else 0,
-			"credit_in_account_currency": abs(net_pl_balance) if net_pl_balance < 0 else 0,
-			"credit": abs(net_pl_balance) if net_pl_balance < 0 else 0,
-			"cost_center": cost_center
-		})
-
-		self.update_default_dimensions(gl_entry)
-
-		return gl_entry
-
-	def get_costcenter_wise_pnl_gl_entries(self, pl_accounts):
+		return gl_entries
+	
+	def get_pnl_gl_entry(self, pl_accounts):
 		company_cost_center = frappe.db.get_value("Company", self.company, "cost_center")
 		gl_entries = []
 
@@ -104,6 +87,7 @@
 				gl_entry = self.get_gl_dict({
 					"account": self.closing_account_head,
 					"cost_center": acc.cost_center or company_cost_center,
+					"finance_book": acc.finance_book,
 					"account_currency": acc.account_currency,
 					"debit_in_account_currency": abs(flt(acc.bal_in_account_currency)) if flt(acc.bal_in_account_currency) > 0 else 0,
 					"debit": abs(flt(acc.bal_in_company_currency)) if flt(acc.bal_in_company_currency) > 0 else 0,
@@ -130,7 +114,7 @@
 	def get_pl_balances(self):
 		"""Get balance for dimension-wise pl accounts"""
 
-		dimension_fields = ['t1.cost_center']
+		dimension_fields = ['t1.cost_center', 't1.finance_book']
 
 		self.accounting_dimensions = get_accounting_dimensions()
 		for dimension in self.accounting_dimensions:
diff --git a/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py b/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py
index f17a5c5..2d19391 100644
--- a/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py
+++ b/erpnext/accounts/doctype/period_closing_voucher/test_period_closing_voucher.py
@@ -8,6 +8,7 @@
 from frappe.utils import flt, today
 from erpnext.accounts.utils import get_fiscal_year, now
 from erpnext.accounts.doctype.journal_entry.test_journal_entry import make_journal_entry
+from erpnext.accounts.doctype.finance_book.test_finance_book import create_finance_book
 from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
 
 class TestPeriodClosingVoucher(unittest.TestCase):
@@ -118,6 +119,58 @@
 
 		self.assertTrue(pcv_gle, expected_gle)
 
+	def test_period_closing_with_finance_book_entries(self):
+		frappe.db.sql("delete from `tabGL Entry` where company='Test PCV Company'")
+
+		company = create_company()
+		surplus_account = create_account()
+		cost_center = create_cost_center("Test Cost Center 1")
+
+		create_sales_invoice(
+			company=company,
+			income_account="Sales - TPC",
+			expense_account="Cost of Goods Sold - TPC",
+			cost_center=cost_center,
+			rate=400,
+			debit_to="Debtors - TPC"
+		)
+		jv = make_journal_entry(
+			account1="Cash - TPC",
+			account2="Sales - TPC",
+			amount=400,
+			cost_center=cost_center,
+			posting_date=now()
+		)
+		jv.company = company
+		jv.finance_book = create_finance_book().name
+		jv.save()
+		jv.submit()
+
+		pcv = frappe.get_doc({
+			"transaction_date": today(),
+			"posting_date": today(),
+			"fiscal_year": get_fiscal_year(today())[0],
+			"company": company,
+			"closing_account_head": surplus_account,
+			"remarks": "Test",
+			"doctype": "Period Closing Voucher"
+		})
+		pcv.insert()
+		pcv.submit()
+
+		expected_gle = (
+			(surplus_account, 0.0, 400.0, ''),
+			(surplus_account, 0.0, 400.0, jv.finance_book),
+			('Sales - TPC', 400.0, 0.0, ''),
+			('Sales - TPC', 400.0, 0.0, jv.finance_book)
+		)
+
+		pcv_gle = frappe.db.sql("""
+			select account, debit, credit, finance_book from `tabGL Entry` where voucher_no=%s
+		""", (pcv.name))
+
+		self.assertTrue(pcv_gle, expected_gle)
+
 	def make_period_closing_voucher(self):
 		pcv = frappe.get_doc({
 			"doctype": "Period Closing Voucher",
diff --git a/erpnext/accounts/doctype/pos_closing_entry/test_pos_closing_entry.py b/erpnext/accounts/doctype/pos_closing_entry/test_pos_closing_entry.py
index b596c0c..5b18ebb 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/test_pos_closing_entry.py
+++ b/erpnext/accounts/doctype/pos_closing_entry/test_pos_closing_entry.py
@@ -85,9 +85,15 @@
 
 		pcv_doc.load_from_db()
 		pcv_doc.cancel()
-		si_doc.load_from_db()
+
+		cancelled_invoice = frappe.db.get_value(
+			'POS Invoice Merge Log', {'pos_closing_entry': pcv_doc.name},
+			'consolidated_invoice'
+		)
+		docstatus = frappe.db.get_value("Sales Invoice", cancelled_invoice, 'docstatus')
+		self.assertEqual(docstatus, 2)
+
 		pos_inv1.load_from_db()
-		self.assertEqual(si_doc.docstatus, 2)
 		self.assertEqual(pos_inv1.status, 'Paid')
 
 
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.js b/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
index 181e9f8..15c2922 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.js
@@ -16,7 +16,7 @@
 
 	onload(doc) {
 		super.onload();
-		this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice Merge Log'];
+		this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice Merge Log', 'POS Closing Entry'];
 		if(doc.__islocal && doc.is_pos && frappe.get_route_str() !== 'point-of-sale') {
 			this.frm.script_manager.trigger("is_pos");
 			this.frm.refresh_fields();
@@ -111,16 +111,12 @@
 	}
 
 	write_off_outstanding_amount_automatically() {
-		if(cint(this.frm.doc.write_off_outstanding_amount_automatically)) {
+		if (cint(this.frm.doc.write_off_outstanding_amount_automatically)) {
 			frappe.model.round_floats_in(this.frm.doc, ["grand_total", "paid_amount"]);
 			// this will make outstanding amount 0
 			this.frm.set_value("write_off_amount",
 				flt(this.frm.doc.grand_total - this.frm.doc.paid_amount - this.frm.doc.total_advance, precision("write_off_amount"))
 			);
-			this.frm.toggle_enable("write_off_amount", false);
-
-		} else {
-			this.frm.toggle_enable("write_off_amount", true);
 		}
 
 		this.calculate_outstanding_amount(false);
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
index fcccb39..b819537 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json
@@ -99,6 +99,7 @@
   "loyalty_redemption_account",
   "loyalty_redemption_cost_center",
   "section_break_49",
+  "coupon_code",
   "apply_discount_on",
   "base_discount_amount",
   "column_break_51",
@@ -1183,7 +1184,8 @@
    "label": "Write Off Amount",
    "no_copy": 1,
    "options": "currency",
-   "print_hide": 1
+   "print_hide": 1,
+   "read_only_depends_on": "eval: doc.write_off_outstanding_amount_automatically"
   },
   {
    "fieldname": "base_write_off_amount",
@@ -1549,12 +1551,20 @@
    "no_copy": 1,
    "options": "Sales Invoice",
    "read_only": 1
+  },
+  {
+   "depends_on": "coupon_code",
+   "fieldname": "coupon_code",
+   "fieldtype": "Link",
+   "label": "Coupon Code",
+   "options": "Coupon Code",
+   "print_hide": 1
   }
  ],
  "icon": "fa fa-file-text",
  "is_submittable": 1,
  "links": [],
- "modified": "2021-08-17 20:13:44.255437",
+ "modified": "2021-08-18 16:13:52.080543",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "POS Invoice",
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
index 8ec4ef2..034a217 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
@@ -44,6 +44,9 @@
 		self.validate_pos()
 		self.validate_payment_amount()
 		self.validate_loyalty_transaction()
+		if self.coupon_code:
+			from erpnext.accounts.doctype.pricing_rule.utils import validate_coupon_code
+			validate_coupon_code(self.coupon_code)
 
 	def on_submit(self):
 		# create the loyalty point ledger entry if the customer is enrolled in any loyalty program
@@ -58,6 +61,10 @@
 		self.check_phone_payments()
 		self.set_status(update=True)
 
+		if self.coupon_code:
+			from erpnext.accounts.doctype.pricing_rule.utils import update_coupon_code_count
+			update_coupon_code_count(self.coupon_code,'used')
+
 	def before_cancel(self):
 		if self.consolidated_invoice and frappe.db.get_value('Sales Invoice', self.consolidated_invoice, 'docstatus') == 1:
 			pos_closing_entry = frappe.get_all(
@@ -84,6 +91,10 @@
 			against_psi_doc.delete_loyalty_point_entry()
 			against_psi_doc.make_loyalty_point_entry()
 
+		if self.coupon_code:
+			from erpnext.accounts.doctype.pricing_rule.utils import update_coupon_code_count
+			update_coupon_code_count(self.coupon_code,'cancelled')
+
 	def check_phone_payments(self):
 		for pay in self.payments:
 			if pay.type == "Phone" and pay.amount >= 0:
@@ -127,7 +138,7 @@
 						.format(item.idx, bold_delivered_serial_nos), title=_("Item Unavailable"))
 
 	def validate_stock_availablility(self):
-		if self.is_return:
+		if self.is_return or self.docstatus != 1:
 			return
 
 		allow_negative_stock = frappe.db.get_single_value('Stock Settings', 'allow_negative_stock')
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
index 556f49d..4903c50 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
@@ -198,12 +198,19 @@
 	set_serial_nos_based_on_fifo = frappe.db.get_single_value("Stock Settings",
 		"automatically_set_serial_nos_based_on_fifo")
 
+	item_code_list = tuple(item.get('item_code') for item in item_list)
+	query_items = frappe.get_all('Item', fields=['item_code','has_serial_no'], filters=[['item_code','in',item_code_list]],as_list=1)
+	serialized_items = dict()
+	for item_code, val in query_items:
+		serialized_items.setdefault(item_code, val)
+	
 	for item in item_list:
 		args_copy = copy.deepcopy(args)
 		args_copy.update(item)
 		data = get_pricing_rule_for_item(args_copy, item.get('price_list_rate'), doc=doc)
 		out.append(data)
-		if not item.get("serial_no") and set_serial_nos_based_on_fifo and not args.get('is_return'):
+		
+		if serialized_items.get(item.get('item_code')) and not item.get("serial_no") and set_serial_nos_based_on_fifo and not args.get('is_return'):
 			out[0].update(get_serial_no_for_item(args_copy))
 
 	return out
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 8d65101..2071827 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -324,16 +324,12 @@
 	}
 
 	write_off_outstanding_amount_automatically() {
-		if(cint(this.frm.doc.write_off_outstanding_amount_automatically)) {
+		if (cint(this.frm.doc.write_off_outstanding_amount_automatically)) {
 			frappe.model.round_floats_in(this.frm.doc, ["grand_total", "paid_amount"]);
 			// this will make outstanding amount 0
 			this.frm.set_value("write_off_amount",
 				flt(this.frm.doc.grand_total - this.frm.doc.paid_amount - this.frm.doc.total_advance, precision("write_off_amount"))
 			);
-			this.frm.toggle_enable("write_off_amount", false);
-
-		} else {
-			this.frm.toggle_enable("write_off_amount", true);
 		}
 
 		this.calculate_outstanding_amount(false);
@@ -787,8 +783,6 @@
 		if (frappe.boot.sysdefaults.country == 'India') unhide_field(['c_form_applicable', 'c_form_no']);
 		else hide_field(['c_form_applicable', 'c_form_no']);
 
-		frm.toggle_enable("write_off_amount", !!!cint(doc.write_off_outstanding_amount_automatically));
-
 		frm.refresh_fields();
 	},
 
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index e317443..5023c9c 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -1444,7 +1444,8 @@
    "label": "Write Off Amount",
    "no_copy": 1,
    "options": "currency",
-   "print_hide": 1
+   "print_hide": 1,
+   "read_only_depends_on": "eval:doc.write_off_outstanding_amount_automatically"
   },
   {
    "fieldname": "base_write_off_amount",
@@ -2014,7 +2015,7 @@
    "link_fieldname": "consolidated_invoice"
   }
  ],
- "modified": "2021-08-17 20:16:12.737743",
+ "modified": "2021-08-18 16:07:45.122570",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Sales Invoice",
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index c454a86..b48dc92 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -26,6 +26,7 @@
 from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
 from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
 from erpnext.stock.utils import get_incoming_rate
+from erpnext.accounts.utils import PaymentEntryUnlinkError
 
 class TestSalesInvoice(unittest.TestCase):
 	def make(self):
@@ -136,7 +137,7 @@
 		pe.paid_to_account_currency = si.currency
 		pe.source_exchange_rate = 1
 		pe.target_exchange_rate = 1
-		pe.paid_amount = si.grand_total
+		pe.paid_amount = si.outstanding_amount
 		pe.insert()
 		pe.submit()
 
@@ -145,6 +146,42 @@
 		self.assertRaises(frappe.LinkExistsError, si.cancel)
 		unlink_payment_on_cancel_of_invoice()
 
+	def test_payment_entry_unlink_against_standalone_credit_note(self):
+		from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry
+		si1 = create_sales_invoice(rate=1000)
+		si2 = create_sales_invoice(rate=300)
+		si3 = create_sales_invoice(qty=-1, rate=300, is_return=1)
+		
+
+		pe = get_payment_entry("Sales Invoice", si1.name, bank_account="_Test Bank - _TC")
+		pe.append('references', {
+			'reference_doctype': 'Sales Invoice',
+			'reference_name': si2.name,
+			'total_amount': si2.grand_total,
+			'outstanding_amount': si2.outstanding_amount,
+			'allocated_amount': si2.outstanding_amount
+		})
+
+		pe.append('references', {
+			'reference_doctype': 'Sales Invoice',
+			'reference_name': si3.name,
+			'total_amount': si3.grand_total,
+			'outstanding_amount': si3.outstanding_amount,
+			'allocated_amount': si3.outstanding_amount
+		})
+
+		pe.reference_no = 'Test001'
+		pe.reference_date = nowdate()
+		pe.save()
+		pe.submit()
+
+		si2.load_from_db()
+		si2.cancel()
+
+		si1.load_from_db()
+		self.assertRaises(PaymentEntryUnlinkError, si1.cancel)
+
+
 	def test_sales_invoice_calculation_export_currency(self):
 		si = frappe.copy_doc(test_records[2])
 		si.currency = "USD"
@@ -2014,7 +2051,7 @@
 
 		data = get_ewb_data("Sales Invoice", [si.name])
 
-		self.assertEqual(data['version'], '1.0.1118')
+		self.assertEqual(data['version'], '1.0.0421')
 		self.assertEqual(data['billLists'][0]['fromGstin'], '27AAECE4835E1ZR')
 		self.assertEqual(data['billLists'][0]['fromTrdName'], '_Test Company')
 		self.assertEqual(data['billLists'][0]['toTrdName'], '_Test Customer')
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index 4c7c567..3126138 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -101,7 +101,7 @@
 
 def check_if_in_list(gle, gl_map, dimensions=None):
 	account_head_fieldnames = ['voucher_detail_no', 'party', 'against_voucher',
-			'cost_center', 'against_voucher_type', 'party_type', 'project']
+			'cost_center', 'against_voucher_type', 'party_type', 'project', 'finance_book']
 
 	if dimensions:
 		account_head_fieldnames = account_head_fieldnames + dimensions
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index b54646f..cedfc0f 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -535,6 +535,8 @@
 		if getdate(entry_date) > getdate(self.filters.report_date):
 			row.range1 = row.range2 = row.range3 = row.range4 = row.range5 = 0.0
 
+		row.total_due = row.range1 + row.range2 + row.range3 + row.range4 + row.range5
+
 	def get_ageing_data(self, entry_date, row):
 		# [0-30, 30-60, 60-90, 90-120, 120-above]
 		row.range1 = row.range2 = row.range3 = row.range4 = row.range5 = 0.0
diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
index e94b309..4bfb022 100644
--- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
+++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
@@ -82,6 +82,7 @@
 			"range3": 0.0,
 			"range4": 0.0,
 			"range5": 0.0,
+			"total_due": 0.0,
 			"sales_person": []
 		}))
 
@@ -135,3 +136,6 @@
 			"{range3}-{range4}".format(range3=cint(self.filters["range3"])+ 1, range4=self.filters["range4"]),
 			"{range4}-{above}".format(range4=cint(self.filters["range4"])+ 1, above=_("Above"))]):
 				self.add_column(label=label, fieldname='range' + str(i+1))
+
+		# Add column for total due amount
+		self.add_column(label="Total Amount Due", fieldname='total_due')
diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
index 56a67bb..fc42127 100644
--- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
+++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
@@ -210,10 +210,10 @@
 	company_currency = get_company_currency(filters)
 
 	if filters.filter_based_on == 'Fiscal Year':
-		start_date = fiscal_year.year_start_date
+		start_date = fiscal_year.year_start_date if filters.report != 'Balance Sheet' else None
 		end_date = fiscal_year.year_end_date
 	else:
-		start_date = filters.period_start_date
+		start_date = filters.period_start_date if filters.report != 'Balance Sheet' else None
 		end_date = filters.period_end_date
 
 	gl_entries_by_account = {}
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index eca1e26..118f628 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -19,6 +19,7 @@
 
 class StockValueAndAccountBalanceOutOfSync(frappe.ValidationError): pass
 class FiscalYearError(frappe.ValidationError): pass
+class PaymentEntryUnlinkError(frappe.ValidationError): pass
 
 @frappe.whitelist()
 def get_fiscal_year(date=None, fiscal_year=None, label="Date", verbose=1, company=None, as_dict=False):
@@ -555,10 +556,16 @@
 			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()
+			try:
+				pe_doc = frappe.get_doc("Payment Entry", pe)
+				pe_doc.set_amounts()
+				pe_doc.clear_unallocated_reference_document_rows()
+				pe_doc.validate_payment_type_with_outstanding()
+			except Exception as e:
+				msg = _("There were issues unlinking payment entry {0}.").format(pe_doc.name)
+				msg += '<br>'
+				msg += _("Please cancel payment entry manually first")
+				frappe.throw(msg, exc=PaymentEntryUnlinkError, title=_("Payment Unlink Error"))
 
 			frappe.db.sql("""update `tabPayment Entry` set total_allocated_amount=%s,
 				base_total_allocated_amount=%s, unallocated_amount=%s, modified=%s, modified_by=%s
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 61582b1..dfe26fa 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1896,6 +1896,11 @@
 
 	for d in data:
 		new_child_flag = False
+
+		if not d.get("item_code"):
+			# ignore empty rows
+			continue
+
 		if not d.get("docname"):
 			new_child_flag = True
 			check_doc_permissions(parent, 'create')
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index 80ccc6d..5ee1f2f 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -329,7 +329,6 @@
 			target_doc.po_detail = source_doc.po_detail
 			target_doc.pr_detail = source_doc.pr_detail
 			target_doc.purchase_invoice_item = source_doc.name
-			target_doc.price_list_rate = 0
 
 		elif doctype == "Delivery Note":
 			returned_qty_map = get_returned_qty_map_for_row(source_doc.name, doctype)
@@ -360,7 +359,6 @@
 			else:
 				target_doc.pos_invoice_item = source_doc.name
 
-			target_doc.price_list_rate = 0
 			if default_warehouse_for_sales_return:
 				target_doc.warehouse = default_warehouse_for_sales_return
 
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 05edb25..7c6d355 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -595,7 +595,8 @@
 				self.doc.precision("outstanding_amount"))
 
 			if self.doc.doctype == 'Sales Invoice' and self.doc.get('is_pos') and self.doc.get('is_return'):
-			 	self.update_paid_amount_for_return(total_amount_to_pay)
+				self.set_total_amount_to_default_mop(total_amount_to_pay)
+				self.calculate_paid_amount()
 
 	def calculate_paid_amount(self):
 
@@ -675,7 +676,7 @@
 	def set_item_wise_tax_breakup(self):
 		self.doc.other_charges_calculation = get_itemised_tax_breakup_html(self.doc)
 
-	def update_paid_amount_for_return(self, total_amount_to_pay):
+	def set_total_amount_to_default_mop(self, total_amount_to_pay):
 		default_mode_of_payment = frappe.db.get_value('POS Payment Method',
 			{'parent': self.doc.pos_profile, 'default': 1}, ['mode_of_payment'], as_dict=1)
 
@@ -685,9 +686,7 @@
 				'mode_of_payment': default_mode_of_payment.mode_of_payment,
 				'amount': total_amount_to_pay,
 				'default': 1
-			})
-
-		self.calculate_paid_amount()
+			})	
 
 def get_itemised_tax_breakup_html(doc):
 	if not doc.taxes:
diff --git a/erpnext/payroll/doctype/salary_component/salary_component.js b/erpnext/payroll/doctype/salary_component/salary_component.js
index e9e6f81..dbf7514 100644
--- a/erpnext/payroll/doctype/salary_component/salary_component.js
+++ b/erpnext/payroll/doctype/salary_component/salary_component.js
@@ -4,18 +4,11 @@
 frappe.ui.form.on('Salary Component', {
 	setup: function(frm) {
 		frm.set_query("account", "accounts", function(doc, cdt, cdn) {
-			let d = frappe.get_doc(cdt, cdn);
-
-			let root_type = "Liability";
-			if (frm.doc.type == "Deduction") {
-				root_type = "Expense";
-			}
-
+			var d = locals[cdt][cdn];
 			return {
 				filters: {
 					"is_group": 0,
-					"company": d.company,
-					"root_type": root_type
+					"company": d.company
 				}
 			};
 		});
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index e8f3122..702064f 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -754,8 +754,6 @@
 			}
 		});
 		this.frm.refresh_fields();
-
-		this.calculate_paid_amount();
 	}
 
 	set_default_payment(total_amount_to_pay, update_paid_amount) {
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 9375e35..2538852 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -2242,12 +2242,19 @@
 
 	coupon_code() {
 		var me = this;
-		frappe.run_serially([
-			() => this.frm.doc.ignore_pricing_rule=1,
-			() => me.ignore_pricing_rule(),
-			() => this.frm.doc.ignore_pricing_rule=0,
-			() => me.apply_pricing_rule()
-		]);
+		if (this.frm.doc.coupon_code) {
+			frappe.run_serially([
+				() => this.frm.doc.ignore_pricing_rule=1,
+				() => me.ignore_pricing_rule(),
+				() => this.frm.doc.ignore_pricing_rule=0,
+				() => me.apply_pricing_rule()
+			]);
+		} else {
+			frappe.run_serially([
+				() => this.frm.doc.ignore_pricing_rule=1,
+				() => me.ignore_pricing_rule()
+			]);
+		}
 	}
 };
 
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index f1b9235..f240b8c 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -563,7 +563,7 @@
 			},
 		],
 		primary_action: function() {
-			const trans_items = this.get_values()["trans_items"];
+			const trans_items = this.get_values()["trans_items"].filter((item) => !!item.item_code);
 			frappe.call({
 				method: 'erpnext.controllers.accounts_controller.update_child_qty_rate',
 				freeze: true,
diff --git a/erpnext/public/scss/point-of-sale.scss b/erpnext/public/scss/point-of-sale.scss
index c77b2ce..1677e9b 100644
--- a/erpnext/public/scss/point-of-sale.scss
+++ b/erpnext/public/scss/point-of-sale.scss
@@ -860,6 +860,8 @@
 
 				.invoice-fields {
 					overflow-y: scroll;
+					height: 100%;
+					padding-right: var(--padding-sm);
 				}
 			}
 
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index a6ab6ab..4db5551 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -531,6 +531,7 @@
 				fieldtype='Link', options='Salary Component', insert_after='hra_section'),
 			dict(fieldname='hra_component', label='HRA Component',
 				fieldtype='Link', options='Salary Component', insert_after='basic_component'),
+			dict(fieldname='hra_column_break', fieldtype='Column Break', insert_after='hra_component'),
 			dict(fieldname='arrear_component', label='Arrear Component',
 				fieldtype='Link', options='Salary Component', insert_after='hra_component'),
 			dict(fieldname='non_profit_section', label='Non Profit Settings',
@@ -539,6 +540,7 @@
 				fieldtype='Data', insert_after='non_profit_section'),
 			dict(fieldname='with_effect_from', label='80G With Effect From',
 				fieldtype='Date', insert_after='company_80g_number'),
+			dict(fieldname='non_profit_column_break', fieldtype='Column Break', insert_after='with_effect_from'),
 			dict(fieldname='pan_details', label='PAN Number',
 				fieldtype='Data', insert_after='with_effect_from')
 		],
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 4e4dcf8..ce5aa10 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -475,7 +475,7 @@
 		ewaybills.append(data)
 
 	data = {
-		'version': '1.0.1118',
+		'version': '1.0.0421',
 		'billLists': ewaybills
 	}
 
diff --git a/erpnext/regional/italy/utils.py b/erpnext/regional/italy/utils.py
index ba1aeaf..56f609e 100644
--- a/erpnext/regional/italy/utils.py
+++ b/erpnext/regional/italy/utils.py
@@ -6,9 +6,8 @@
 from frappe.utils import flt, cstr
 from erpnext.controllers.taxes_and_totals import get_itemised_tax
 from frappe import _
-from frappe.core.doctype.file.file import remove_file
+from frappe.utils.file_manager import remove_file
 from six import string_types
-from frappe.desk.form.load import get_attachments
 from erpnext.regional.italy import state_codes
 
 
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index 22bf3fc..2de57c8 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -394,6 +394,10 @@
 	}
 
 	_set_batch_number(doc) {
+		if (doc.batch_no) {
+			return
+		}
+
 		let args = {'item_code': doc.item_code, 'warehouse': doc.warehouse, 'qty': flt(doc.qty) * flt(doc.conversion_factor)};
 		if (doc.has_serial_no && doc.serial_no) {
 			args['serial_no'] = doc.serial_no
diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js
index 8f83d3c..56700af 100644
--- a/erpnext/setup/doctype/company/company.js
+++ b/erpnext/setup/doctype/company/company.js
@@ -46,6 +46,43 @@
 		});
 	},
 
+	change_abbreviation(frm) {
+		var dialog = new frappe.ui.Dialog({
+			title: "Replace Abbr",
+			fields: [
+				{"fieldtype": "Data", "label": "New Abbreviation", "fieldname": "new_abbr",
+					"reqd": 1 },
+				{"fieldtype": "Button", "label": "Update", "fieldname": "update"},
+			]
+		});
+	
+		dialog.fields_dict.update.$input.click(function() {
+			var args = dialog.get_values();
+			if (!args) return; 
+			frappe.show_alert(__("Update in progress. It might take a while."));
+			return frappe.call({
+				method: "erpnext.setup.doctype.company.company.enqueue_replace_abbr",
+				args: {
+					"company": frm.doc.name,
+					"old": frm.doc.abbr,
+					"new": args.new_abbr
+				},
+				callback: function(r) {
+					if (r.exc) {
+						frappe.msgprint(__("There were errors."));
+						return;
+					} else {
+						frm.set_value("abbr", args.new_abbr);
+					}
+					dialog.hide();
+					frm.refresh();
+				},
+				btn: this
+			});
+		});
+		dialog.show();
+	},
+
 	company_name: function(frm) {
 		if(frm.doc.__islocal) {
 			// add missing " " arg in split method
@@ -127,6 +164,10 @@
 					}, __('Manage'));
 				}
 			}
+
+			frm.add_custom_button(__('Change Abbreviation'), () => {
+				frm.trigger('change_abbreviation');
+			}, __('Manage'));
 		}
 
 		erpnext.company.set_chart_of_accounts_options(frm.doc);
@@ -204,43 +245,6 @@
 	}
 }
 
-cur_frm.cscript.change_abbr = function() {
-	var dialog = new frappe.ui.Dialog({
-		title: "Replace Abbr",
-		fields: [
-			{"fieldtype": "Data", "label": "New Abbreviation", "fieldname": "new_abbr",
-				"reqd": 1 },
-			{"fieldtype": "Button", "label": "Update", "fieldname": "update"},
-		]
-	});
-
-	dialog.fields_dict.update.$input.click(function() {
-		var args = dialog.get_values();
-		if(!args) return;
-		frappe.show_alert(__("Update in progress. It might take a while."));
-		return frappe.call({
-			method: "erpnext.setup.doctype.company.company.enqueue_replace_abbr",
-			args: {
-				"company": cur_frm.doc.name,
-				"old": cur_frm.doc.abbr,
-				"new": args.new_abbr
-			},
-			callback: function(r) {
-				if(r.exc) {
-					frappe.msgprint(__("There were errors."));
-					return;
-				} else {
-					cur_frm.set_value("abbr", args.new_abbr);
-				}
-				dialog.hide();
-				cur_frm.refresh();
-			},
-			btn: this
-		})
-	});
-	dialog.show();
-}
-
 erpnext.company.setup_queries = function(frm) {
 	$.each([
 		["default_bank_account", {"account_type": "Bank"}],
diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json
index e6ec496..e4ee3ec 100644
--- a/erpnext/setup/doctype/company/company.json
+++ b/erpnext/setup/doctype/company/company.json
@@ -12,33 +12,48 @@
   "details",
   "company_name",
   "abbr",
-  "change_abbr",
+  "default_currency",
+  "country",
   "is_group",
   "cb0",
-  "domain",
-  "parent_company",
-  "charts_section",
-  "default_currency",
   "default_letter_head",
-  "default_holiday_list",
-  "default_finance_book",
-  "default_selling_terms",
-  "default_buying_terms",
-  "default_warehouse_for_sales_return",
-  "default_in_transit_warehouse",
-  "column_break_10",
-  "country",
-  "create_chart_of_accounts_based_on",
-  "chart_of_accounts",
-  "existing_company",
   "tax_id",
+  "domain",
   "date_of_establishment",
+  "parent_company",
+  "company_info",
+  "company_logo",
+  "date_of_incorporation",
+  "phone_no",
+  "email",
+  "company_description",
+  "column_break1",
+  "date_of_commencement",
+  "fax",
+  "website",
+  "address_html",
+  "section_break_28",
+  "create_chart_of_accounts_based_on",
+  "existing_company",
+  "column_break_26",
+  "chart_of_accounts",
+  "charts_section",
   "sales_settings",
-  "monthly_sales_target",
+  "default_buying_terms",
   "sales_monthly_history",
-  "column_break_goals",
-  "transactions_annual_history",
+  "monthly_sales_target",
   "total_monthly_sales",
+  "column_break_goals",
+  "default_selling_terms",
+  "default_warehouse_for_sales_return",
+  "credit_limit",
+  "transactions_annual_history",
+  "hr_settings_section",
+  "default_holiday_list",
+  "default_expense_claim_payable_account",
+  "column_break_10",
+  "default_employee_advance_account",
+  "default_payroll_payable_account",
   "default_settings",
   "default_bank_account",
   "default_cash_account",
@@ -52,24 +67,20 @@
   "column_break0",
   "allow_account_creation_against_child_company",
   "default_payable_account",
-  "default_employee_advance_account",
   "default_expense_account",
   "default_income_account",
   "default_deferred_revenue_account",
   "default_deferred_expense_account",
-  "default_payroll_payable_account",
-  "default_expense_claim_payable_account",
   "default_discount_account",
-  "section_break_22",
-  "cost_center",
-  "column_break_26",
-  "credit_limit",
   "payment_terms",
+  "cost_center",
+  "default_finance_book",
   "auto_accounting_for_stock_settings",
   "enable_perpetual_inventory",
   "enable_perpetual_inventory_for_non_stock_items",
   "default_inventory_account",
   "stock_adjustment_account",
+  "default_in_transit_warehouse",
   "column_break_32",
   "stock_received_but_not_billed",
   "service_received_but_not_billed",
@@ -79,25 +90,14 @@
   "depreciation_expense_account",
   "series_for_depreciation_entry",
   "expenses_included_in_asset_valuation",
+  "repair_and_maintenance_account",
   "column_break_40",
   "disposal_account",
   "depreciation_cost_center",
   "capital_work_in_progress_account",
-  "repair_and_maintenance_account",
   "asset_received_but_not_billed",
   "budget_detail",
   "exception_budget_approver_role",
-  "company_info",
-  "company_logo",
-  "date_of_incorporation",
-  "address_html",
-  "date_of_commencement",
-  "phone_no",
-  "fax",
-  "email",
-  "website",
-  "column_break1",
-  "company_description",
   "registration_info",
   "registration_details",
   "lft",
@@ -128,12 +128,6 @@
    "reqd": 1
   },
   {
-   "depends_on": "eval:!doc.__islocal && in_list(frappe.user_roles, \"System Manager\")",
-   "fieldname": "change_abbr",
-   "fieldtype": "Button",
-   "label": "Change Abbreviation"
-  },
-  {
    "bold": 1,
    "default": "0",
    "fieldname": "is_group",
@@ -176,10 +170,9 @@
    "label": "Company Description"
   },
   {
-   "collapsible": 1,
    "fieldname": "sales_settings",
    "fieldtype": "Section Break",
-   "label": "Sales Settings"
+   "label": "Buying & Selling Settings"
   },
   {
    "fieldname": "sales_monthly_history",
@@ -443,10 +436,6 @@
    "options": "Account"
   },
   {
-   "fieldname": "section_break_22",
-   "fieldtype": "Section Break"
-  },
-  {
    "depends_on": "eval:!doc.__islocal",
    "fieldname": "cost_center",
    "fieldtype": "Link",
@@ -456,10 +445,6 @@
    "options": "Cost Center"
   },
   {
-   "fieldname": "column_break_26",
-   "fieldtype": "Column Break"
-  },
-  {
    "depends_on": "eval:!doc.__islocal",
    "fieldname": "credit_limit",
    "fieldtype": "Currency",
@@ -589,10 +574,10 @@
   },
   {
    "collapsible": 1,
-   "description": "For reference only.",
+   "depends_on": "eval: doc.docstatus == 0 && doc.__islocal != 1",
    "fieldname": "company_info",
    "fieldtype": "Section Break",
-   "label": "Company Info"
+   "label": "Address & Contact"
   },
   {
    "fieldname": "date_of_incorporation",
@@ -741,6 +726,20 @@
    "fieldtype": "Link",
    "label": "Repair and Maintenance Account",
    "options": "Account"
+  },
+  {
+   "fieldname": "section_break_28",
+   "fieldtype": "Section Break",
+   "label": "Chart of Accounts"
+  },
+  {
+   "fieldname": "hr_settings_section",
+   "fieldtype": "Section Break",
+   "label": "HR & Payroll Settings"
+  },
+  {
+   "fieldname": "column_break_26",
+   "fieldtype": "Column Break"
   }
  ],
  "icon": "fa fa-building",
@@ -748,7 +747,7 @@
  "image_field": "company_logo",
  "is_tree": 1,
  "links": [],
- "modified": "2021-05-12 16:51:08.187233",
+ "modified": "2021-07-12 11:27:06.353860",
  "modified_by": "Administrator",
  "module": "Setup",
  "name": "Company",
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.json b/erpnext/stock/doctype/stock_entry/stock_entry.json
index e6ce3c8..2f37778 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.json
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.json
@@ -84,8 +84,6 @@
    "oldfieldtype": "Section Break"
   },
   {
-   "allow_on_submit": 1,
-   "default": "{purpose}",
    "fieldname": "title",
    "fieldtype": "Data",
    "hidden": 1,
@@ -630,7 +628,7 @@
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2021-08-17 20:16:12.737743",
+ "modified": "2021-08-20 19:19:31.514846",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Stock Entry",
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 90a33d3..0b4592c 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -58,6 +58,7 @@
 
 		self.validate_posting_time()
 		self.validate_purpose()
+		self.set_title()
 		self.validate_item()
 		self.validate_customer_provided_item()
 		self.validate_qty()
@@ -1608,6 +1609,14 @@
 
 		return sorted(list(set(get_serial_nos(self.pro_doc.serial_no)) - set(used_serial_nos)))
 
+	def set_title(self):
+		if frappe.flags.in_import and self.title:
+			# Allow updating title during data import/update
+			return
+
+		self.title = self.purpose
+
+
 @frappe.whitelist()
 def move_sample_to_retention_warehouse(company, items):
 	if isinstance(items, string_types):
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index a0fbcec..c72073c 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -278,6 +278,10 @@
 		else:
 			args.uom = item.stock_uom
 
+	if (args.get("batch_no") and
+		item.name != frappe.get_cached_value('Batch', args.get("batch_no"), 'item')):
+		args['batch_no'] = ''
+
 	out = frappe._dict({
 		"item_code": item.name,
 		"item_name": item.item_name,
diff --git a/erpnext/stock/report/stock_analytics/stock_analytics.js b/erpnext/stock/report/stock_analytics/stock_analytics.js
index 6b384e2..78afe6d 100644
--- a/erpnext/stock/report/stock_analytics/stock_analytics.js
+++ b/erpnext/stock/report/stock_analytics/stock_analytics.js
@@ -37,11 +37,25 @@
 			default: "",
 		},
 		{
+			fieldname: "company",
+			label: __("Company"),
+			fieldtype: "Link",
+			options: "Company",
+			default: frappe.defaults.get_user_default("Company"),
+			reqd: 1,
+		},
+		{
 			fieldname: "warehouse",
 			label: __("Warehouse"),
 			fieldtype: "Link",
-			options:"Warehouse",
+			options: "Warehouse",
 			default: "",
+			get_query: function() {
+				const company = frappe.query_report.get_filter_value('company');
+				return {
+					filters: { 'company': company }
+				}
+			}
 		},
 		{
 			fieldname: "from_date",
diff --git a/erpnext/stock/report/stock_analytics/stock_analytics.py b/erpnext/stock/report/stock_analytics/stock_analytics.py
index d62abed..a1e1e7f 100644
--- a/erpnext/stock/report/stock_analytics/stock_analytics.py
+++ b/erpnext/stock/report/stock_analytics/stock_analytics.py
@@ -1,14 +1,15 @@
 # Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
 # For license information, please see license.txt
+import datetime
 
-from __future__ import unicode_literals
 import frappe
 from frappe import _, scrub
-from frappe.utils import getdate, flt
+from frappe.utils import getdate, get_quarter_start, get_first_day_of_week
+from frappe.utils import get_first_day as get_first_day_of_month
+
 from erpnext.stock.report.stock_balance.stock_balance import (get_items, get_stock_ledger_entries, get_item_details)
 from erpnext.accounts.utils import get_fiscal_year
 from erpnext.stock.utils import is_reposting_item_valuation_in_progress
-from six import iteritems
 
 def execute(filters=None):
 	is_reposting_item_valuation_in_progress()
@@ -71,7 +72,8 @@
 
 def get_period_date_ranges(filters):
 		from dateutil.relativedelta import relativedelta
-		from_date, to_date = getdate(filters.from_date), getdate(filters.to_date)
+		from_date = round_down_to_nearest_frequency(filters.from_date, filters.range)
+		to_date = getdate(filters.to_date)
 
 		increment = {
 			"Monthly": 1,
@@ -97,6 +99,31 @@
 
 		return periodic_daterange
 
+
+def round_down_to_nearest_frequency(date: str, frequency: str) -> datetime.datetime:
+	"""Rounds down the date to nearest frequency unit.
+	example:
+
+	>>> round_down_to_nearest_frequency("2021-02-21", "Monthly")
+	datetime.datetime(2021, 2, 1)
+
+	>>> round_down_to_nearest_frequency("2021-08-21", "Yearly")
+	datetime.datetime(2021, 1, 1)
+	"""
+
+	def _get_first_day_of_fiscal_year(date):
+		fiscal_year = get_fiscal_year(date)
+		return fiscal_year and fiscal_year[1] or date
+
+	round_down_function = {
+		"Monthly": get_first_day_of_month,
+		"Quarterly": get_quarter_start,
+		"Weekly": get_first_day_of_week,
+		"Yearly": _get_first_day_of_fiscal_year,
+	}.get(frequency, getdate)
+	return round_down_function(date)
+
+
 def get_period(posting_date, filters):
 	months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
 
@@ -177,7 +204,7 @@
 	periodic_data = get_periodic_data(sle, filters)
 	ranges = get_period_date_ranges(filters)
 
-	for dummy, item_data in iteritems(item_details):
+	for dummy, item_data in item_details.items():
 		row = {
 			"name": item_data.name,
 			"item_name": item_data.item_name,
diff --git a/erpnext/stock/report/stock_analytics/test_stock_analytics.py b/erpnext/stock/report/stock_analytics/test_stock_analytics.py
new file mode 100644
index 0000000..00e268b
--- /dev/null
+++ b/erpnext/stock/report/stock_analytics/test_stock_analytics.py
@@ -0,0 +1,35 @@
+import datetime
+import unittest
+
+from frappe import _dict
+from erpnext.accounts.utils import get_fiscal_year
+
+from erpnext.stock.report.stock_analytics.stock_analytics import get_period_date_ranges
+
+
+class TestStockAnalyticsReport(unittest.TestCase):
+	def test_get_period_date_ranges(self):
+
+		filters = _dict(range="Monthly", from_date="2020-12-28", to_date="2021-02-06")
+
+		ranges = get_period_date_ranges(filters)
+
+		expected_ranges = [
+			[datetime.date(2020, 12, 1), datetime.date(2020, 12, 31)],
+			[datetime.date(2021, 1, 1), datetime.date(2021, 1, 31)],
+			[datetime.date(2021, 2, 1), datetime.date(2021, 2, 6)],
+		]
+
+		self.assertEqual(ranges, expected_ranges)
+
+	def test_get_period_date_ranges_yearly(self):
+
+		filters = _dict(range="Yearly", from_date="2021-01-28", to_date="2021-02-06")
+
+		ranges = get_period_date_ranges(filters)
+		first_date = get_fiscal_year("2021-01-28")[1]
+		expected_ranges = [
+			[first_date, datetime.date(2021, 2, 6)],
+		]
+
+		self.assertEqual(ranges, expected_ranges)
diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py
index 8909f21..b6923e9 100644
--- a/erpnext/stock/report/stock_ledger/stock_ledger.py
+++ b/erpnext/stock/report/stock_ledger/stock_ledger.py
@@ -23,6 +23,7 @@
 	conversion_factors = []
 	if opening_row:
 		data.append(opening_row)
+		conversion_factors.append(0)
 
 	actual_qty = stock_value = 0