Merge pull request #31690 from phot0n/fix-payments-stuff

diff --git a/.github/helper/install.sh b/.github/helper/install.sh
index a62df32..2bb950f 100644
--- a/.github/helper/install.sh
+++ b/.github/helper/install.sh
@@ -2,13 +2,6 @@
 
 set -e
 
-# Check for merge conflicts before proceeding
-python -m compileall -f "${GITHUB_WORKSPACE}"
-if grep -lr --exclude-dir=node_modules "^<<<<<<< " "${GITHUB_WORKSPACE}"
-    then echo "Found merge conflicts"
-    exit 1
-fi
-
 cd ~ || exit
 
 sudo apt update && sudo apt install redis-server libcups2-dev
diff --git a/.github/workflows/patch.yml b/.github/workflows/patch.yml
index eedb4b4..4d2dc58 100644
--- a/.github/workflows/patch.yml
+++ b/.github/workflows/patch.yml
@@ -34,6 +34,14 @@
       - name: Clone
         uses: actions/checkout@v2
 
+      - name: Check for valid Python & Merge Conflicts
+        run: |
+          python -m compileall -f "${GITHUB_WORKSPACE}"
+          if grep -lr --exclude-dir=node_modules "^<<<<<<< " "${GITHUB_WORKSPACE}"
+              then echo "Found merge conflicts"
+              exit 1
+          fi
+
       - name: Setup Python
         uses: "gabrielfalcao/pyenv-action@v9"
         with:
diff --git a/.github/workflows/server-tests-mariadb.yml b/.github/workflows/server-tests-mariadb.yml
index f65cb46..64134bc 100644
--- a/.github/workflows/server-tests-mariadb.yml
+++ b/.github/workflows/server-tests-mariadb.yml
@@ -61,6 +61,14 @@
         with:
           python-version: '3.10'
 
+      - name: Check for valid Python & Merge Conflicts
+        run: |
+          python -m compileall -f "${GITHUB_WORKSPACE}"
+          if grep -lr --exclude-dir=node_modules "^<<<<<<< " "${GITHUB_WORKSPACE}"
+              then echo "Found merge conflicts"
+              exit 1
+          fi
+
       - name: Setup Node
         uses: actions/setup-node@v2
         with:
diff --git a/.github/workflows/server-tests-postgres.yml b/.github/workflows/server-tests-postgres.yml
index 53a94db..651c935 100644
--- a/.github/workflows/server-tests-postgres.yml
+++ b/.github/workflows/server-tests-postgres.yml
@@ -48,6 +48,14 @@
         with:
           python-version: '3.10'
 
+      - name: Check for valid Python & Merge Conflicts
+        run: |
+          python -m compileall -f "${GITHUB_WORKSPACE}"
+          if grep -lr --exclude-dir=node_modules "^<<<<<<< " "${GITHUB_WORKSPACE}"
+              then echo "Found merge conflicts"
+              exit 1
+          fi
+
       - name: Setup Node
         uses: actions/setup-node@v2
         with:
@@ -90,7 +98,6 @@
           restore-keys: |
             ${{ runner.os }}-yarn-
 
-
       - name: Install
         run: bash ${GITHUB_WORKSPACE}/.github/helper/install.sh
         env:
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 3dca588..e9ed2e4 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
@@ -114,7 +114,7 @@
 			(pcv.name),
 		)
 
-		self.assertEqual(pcv_gle, expected_gle)
+		self.assertSequenceEqual(pcv_gle, expected_gle)
 
 		pcv.reload()
 		pcv.cancel()
@@ -175,7 +175,7 @@
 			(pcv.name),
 		)
 
-		self.assertEqual(pcv_gle, expected_gle)
+		self.assertSequenceEqual(pcv_gle, expected_gle)
 
 	def make_period_closing_voucher(self, submit=True):
 		surplus_account = create_account()
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 775d255..de3927e 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -162,6 +162,7 @@
 		if tds_category and not for_validate:
 			self.apply_tds = 1
 			self.tax_withholding_category = tds_category
+			self.set_onload("supplier_tds", tds_category)
 
 		super(PurchaseInvoice, self).set_missing_values(for_validate)
 
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index 17dd804..1c9d3fb 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -412,7 +412,7 @@
   },
   {
    "default": "0",
-   "depends_on": "eval: doc.is_return && doc.return_against",
+   "depends_on": "eval: doc.is_return",
    "fieldname": "update_billed_amount_in_sales_order",
    "fieldtype": "Check",
    "hide_days": 1,
@@ -2022,7 +2022,7 @@
    "link_fieldname": "consolidated_invoice"
   }
  ],
- "modified": "2022-06-16 16:22:44.870575",
+ "modified": "2022-07-11 17:43:56.435382",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Sales Invoice",
diff --git a/erpnext/accounts/report/accounts_payable/accounts_payable.js b/erpnext/accounts/report/accounts_payable/accounts_payable.js
index f6961eb..7cf14e6 100644
--- a/erpnext/accounts/report/accounts_payable/accounts_payable.js
+++ b/erpnext/accounts/report/accounts_payable/accounts_payable.js
@@ -136,6 +136,11 @@
 			"label": __("Tax Id"),
 			"fieldtype": "Data",
 			"hidden": 1
+		},
+		{
+			"fieldname": "show_future_payments",
+			"label": __("Show Future Payments"),
+			"fieldtype": "Check",
 		}
 	],
 
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 411b313..c7c746b 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -164,6 +164,8 @@
 			"range3",
 			"range4",
 			"range5",
+			"future_amount",
+			"remaining_balance"
 		]
 
 	def get_voucher_balance(self, ple):
@@ -545,7 +547,7 @@
 				jea.party,
 				jea.party_type,
 				je.posting_date as future_date,
-				sum({0}) as future_amount,
+				sum('{0}') as future_amount,
 				je.cheque_no as future_ref
 			from
 				`tabJournal Entry` as je inner join `tabJournal Entry Account` as jea
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index 34d374c..986b700 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -133,7 +133,7 @@
 			order by account""",
 			pi.name,
 		)
-		self.assertEqual(gle, expected_gle)
+		self.assertSequenceEqual(gle, expected_gle)
 
 		pi.cancel()
 		asset.cancel()
@@ -208,7 +208,7 @@
 			order by account""",
 			asset.journal_entry_for_scrap,
 		)
-		self.assertEqual(gle, expected_gle)
+		self.assertSequenceEqual(gle, expected_gle)
 
 		restore_asset(asset.name)
 
@@ -253,7 +253,7 @@
 			si.name,
 		)
 
-		self.assertEqual(gle, expected_gle)
+		self.assertSequenceEqual(gle, expected_gle)
 
 		si.cancel()
 		self.assertEqual(frappe.db.get_value("Asset", asset.name, "status"), "Partially Depreciated")
@@ -361,7 +361,7 @@
 			pr.name,
 		)
 
-		self.assertEqual(pr_gle, expected_gle)
+		self.assertSequenceEqual(pr_gle, expected_gle)
 
 		pi = make_invoice(pr.name)
 		pi.submit()
@@ -381,7 +381,7 @@
 			pi.name,
 		)
 
-		self.assertEqual(pi_gle, expected_gle)
+		self.assertSequenceEqual(pi_gle, expected_gle)
 
 		asset = frappe.db.get_value("Asset", {"purchase_receipt": pr.name, "docstatus": 0}, "name")
 
@@ -414,7 +414,7 @@
 			asset_doc.name,
 		)
 
-		self.assertEqual(gle, expected_gle)
+		self.assertSequenceEqual(gle, expected_gle)
 
 	def test_asset_cwip_toggling_cases(self):
 		cwip = frappe.db.get_value("Asset Category", "Computers", "enable_cwip_accounting")
@@ -1287,7 +1287,7 @@
 			asset.name,
 		)
 
-		self.assertEqual(gle, expected_gle)
+		self.assertSequenceEqual(gle, expected_gle)
 		self.assertEqual(asset.get("value_after_depreciation"), 0)
 
 	def test_expected_value_change(self):
diff --git a/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py
index ebeb174..62c6366 100644
--- a/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py
+++ b/erpnext/assets/doctype/asset_value_adjustment/test_asset_value_adjustment.py
@@ -91,7 +91,7 @@
 			adj_doc.journal_entry,
 		)
 
-		self.assertEqual(gle, expected_gle)
+		self.assertSequenceEqual(gle, expected_gle)
 
 
 def make_asset_value_adjustment(**args):
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index e5e317c..adfb39c 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -1620,6 +1620,65 @@
 		so.load_from_db()
 		self.assertEqual(so.billing_status, "Fully Billed")
 
+	def test_so_billing_status_with_crnote_against_sales_return(self):
+		"""
+		| Step | Document creation                    |                               |
+		|------+--------------------------------------+-------------------------------|
+		|    1 | SO -> DN -> SI                       | SO Fully Billed and Completed |
+		|    2 | DN -> Sales Return(Partial)          | SO 50% Delivered, 100% billed |
+		|    3 | Sales Return(Partial) -> Credit Note | SO 50% Delivered, 50% billed  |
+
+		"""
+		from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+
+		so = make_sales_order(uom="Nos", do_not_save=1)
+		so.save()
+		so.submit()
+
+		self.assertEqual(so.billing_status, "Not Billed")
+
+		dn1 = make_delivery_note(so.name)
+		dn1.taxes_and_charges = ""
+		dn1.taxes.clear()
+		dn1.save().submit()
+
+		si = create_sales_invoice(qty=10, do_not_save=1)
+		si.items[0].sales_order = so.name
+		si.items[0].so_detail = so.items[0].name
+		si.items[0].delivery_note = dn1.name
+		si.items[0].dn_detail = dn1.items[0].name
+		si.save()
+		si.submit()
+
+		so.reload()
+		self.assertEqual(so.billing_status, "Fully Billed")
+		self.assertEqual(so.status, "Completed")
+
+		from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
+
+		dn1.reload()
+		dn_ret = create_delivery_note(is_return=1, return_against=dn1.name, qty=-5, do_not_submit=True)
+		dn_ret.items[0].against_sales_order = so.name
+		dn_ret.items[0].so_detail = so.items[0].name
+		dn_ret.submit()
+
+		so.reload()
+		self.assertEqual(so.per_billed, 100)
+		self.assertEqual(so.per_delivered, 50)
+
+		cr_note = create_sales_invoice(is_return=1, qty=-1, do_not_submit=True)
+		cr_note.items[0].qty = -5
+		cr_note.items[0].sales_order = so.name
+		cr_note.items[0].so_detail = so.items[0].name
+		cr_note.items[0].delivery_note = dn_ret.name
+		cr_note.items[0].dn_detail = dn_ret.items[0].name
+		cr_note.update_billed_amount_in_sales_order = True
+		cr_note.submit()
+
+		so.reload()
+		self.assertEqual(so.per_billed, 50)
+		self.assertEqual(so.per_delivered, 50)
+
 	def test_so_back_updated_from_wo_via_mr(self):
 		"SO -> MR (Manufacture) -> WO. Test if WO Qty is updated in SO."
 		from erpnext.manufacturing.doctype.work_order.work_order import (
diff --git a/erpnext/setup/doctype/global_defaults/global_defaults.py b/erpnext/setup/doctype/global_defaults/global_defaults.py
index 984bab4..16e9434 100644
--- a/erpnext/setup/doctype/global_defaults/global_defaults.py
+++ b/erpnext/setup/doctype/global_defaults/global_defaults.py
@@ -30,18 +30,20 @@
 			frappe.db.set_default(key, self.get(keydict[key], ""))
 
 		# update year start date and year end date from fiscal_year
-		year_start_end_date = frappe.db.sql(
-			"""select year_start_date, year_end_date
-			from `tabFiscal Year` where name=%s""",
-			self.current_fiscal_year,
-		)
-		if year_start_end_date:
-			ysd = year_start_end_date[0][0] or ""
-			yed = year_start_end_date[0][1] or ""
+		if self.current_fiscal_year:
+			if fiscal_year := frappe.get_all(
+				"Fiscal Year",
+				filters={"name": self.current_fiscal_year},
+				fields=["year_start_date", "year_end_date"],
+				limit=1,
+				order_by=None,
+			):
+				ysd = fiscal_year[0].year_start_date or ""
+				yed = fiscal_year[0].year_end_date or ""
 
-			if ysd and yed:
-				frappe.db.set_default("year_start_date", ysd.strftime("%Y-%m-%d"))
-				frappe.db.set_default("year_end_date", yed.strftime("%Y-%m-%d"))
+				if ysd and yed:
+					frappe.db.set_default("year_start_date", ysd.strftime("%Y-%m-%d"))
+					frappe.db.set_default("year_end_date", yed.strftime("%Y-%m-%d"))
 
 		# enable default currency
 		if self.default_currency:
@@ -50,7 +52,6 @@
 		self.toggle_rounded_total()
 		self.toggle_in_words()
 
-		# clear cache
 		frappe.clear_cache()
 
 	@frappe.whitelist()
diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.py b/erpnext/stock/report/stock_ageing/stock_ageing.py
index 1956238..7c430e4 100644
--- a/erpnext/stock/report/stock_ageing/stock_ageing.py
+++ b/erpnext/stock/report/stock_ageing/stock_ageing.py
@@ -34,6 +34,9 @@
 	precision = cint(frappe.db.get_single_value("System Settings", "float_precision", cache=True))
 
 	for item, item_dict in item_details.items():
+		if not flt(item_dict.get("total_qty"), precision):
+			continue
+
 		earliest_age, latest_age = 0, 0
 		details = item_dict["details"]
 
diff --git a/erpnext/templates/pages/home.css b/erpnext/templates/pages/home.css
index 785d805..f266149 100644
--- a/erpnext/templates/pages/home.css
+++ b/erpnext/templates/pages/home.css
@@ -1,7 +1,6 @@
 /* csslint ignore:start */
 {% if homepage.hero_image %}
 .hero-image {
-	background-image: url("{{ homepage.hero_image }}");
 	background-size: cover;
 	padding: 10rem 0;
 }
diff --git a/erpnext/templates/pages/home.html b/erpnext/templates/pages/home.html
index 9a61eab..4c69b83 100644
--- a/erpnext/templates/pages/home.html
+++ b/erpnext/templates/pages/home.html
@@ -5,7 +5,11 @@
 {% block content %}
 <main>
 	{% if homepage.hero_section_based_on == 'Default' %}
-	<section class="hero-section border-bottom {%if homepage.hero_image%}hero-image{%endif%}">
+	<section class="hero-section border-bottom {%if homepage.hero_image%}hero-image{%endif%}"
+		{% if homepage.hero_image %}
+		style="background-image: url('{{ homepage.hero_image }}');"
+		{%- endif %}
+	>
 		<div class="container py-5">
 			<h1 class="d-none d-sm-block display-4">{{ homepage.tag_line }}</h1>
 			<h1 class="d-block d-sm-none">{{ homepage.tag_line }}</h1>