Merge pull request #36696 from RitvikSardana/develop-ritvik-pos-mode-of-payment

fix: mode of payment fetched from pos profile company in POS
diff --git a/.mergify.yml b/.mergify.yml
index c5f3d83..804b27d 100644
--- a/.mergify.yml
+++ b/.mergify.yml
@@ -15,6 +15,8 @@
         - or:
           - base=version-13
           - base=version-12
+          - base=version-14
+          - base=version-15
     actions:
       close:
       comment:
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.json b/erpnext/accounts/doctype/gl_entry/gl_entry.json
index e6d97a1..5063ec6 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.json
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.json
@@ -32,7 +32,11 @@
   "finance_book",
   "to_rename",
   "due_date",
-  "is_cancelled"
+  "is_cancelled",
+  "transaction_currency",
+  "debit_in_transaction_currency",
+  "credit_in_transaction_currency",
+  "transaction_exchange_rate"
  ],
  "fields": [
   {
@@ -253,15 +257,40 @@
    "fieldname": "is_cancelled",
    "fieldtype": "Check",
    "label": "Is Cancelled"
+  },
+  {
+   "fieldname": "transaction_currency",
+   "fieldtype": "Link",
+   "label": "Transaction Currency",
+   "options": "Currency"
+  },
+  {
+   "fieldname": "transaction_exchange_rate",
+   "fieldtype": "Float",
+   "label": "Transaction Exchange Rate"
+  },
+  {
+   "fieldname": "debit_in_transaction_currency",
+   "fieldtype": "Currency",
+   "label": "Debit Amount in Transaction Currency",
+   "options": "transaction_currency"
+  },
+  {
+   "fieldname": "credit_in_transaction_currency",
+   "fieldtype": "Currency",
+   "label": "Credit Amount in Transaction Currency",
+   "options": "transaction_currency"
   }
  ],
  "icon": "fa fa-list",
  "idx": 1,
  "in_create": 1,
- "modified": "2020-04-07 16:22:33.766994",
+ "links": [],
+ "modified": "2023-08-16 21:38:44.072267",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "GL Entry",
+ "naming_rule": "Expression (old style)",
  "owner": "Administrator",
  "permissions": [
   {
@@ -290,5 +319,6 @@
  "quick_entry": 1,
  "search_fields": "voucher_no,account,posting_date,against_voucher",
  "sort_field": "modified",
- "sort_order": "DESC"
+ "sort_order": "DESC",
+ "states": []
 }
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.json b/erpnext/accounts/doctype/journal_entry/journal_entry.json
index 80df0ff..2eb54a5 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.json
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.json
@@ -89,7 +89,7 @@
    "label": "Entry Type",
    "oldfieldname": "voucher_type",
    "oldfieldtype": "Select",
-   "options": "Journal Entry\nInter Company Journal Entry\nBank Entry\nCash Entry\nCredit Card Entry\nDebit Note\nCredit Note\nContra Entry\nExcise Entry\nWrite Off Entry\nOpening Entry\nDepreciation Entry\nExchange Rate Revaluation\nExchange Gain Or Loss\nDeferred Revenue\nDeferred Expense\nReversal Of ITC",
+   "options": "Journal Entry\nInter Company Journal Entry\nBank Entry\nCash Entry\nCredit Card Entry\nDebit Note\nCredit Note\nContra Entry\nExcise Entry\nWrite Off Entry\nOpening Entry\nDepreciation Entry\nExchange Rate Revaluation\nExchange Gain Or Loss\nDeferred Revenue\nDeferred Expense",
    "reqd": 1,
    "search_index": 1
   },
@@ -555,7 +555,45 @@
  "name": "Journal Entry",
  "naming_rule": "By \"Naming Series\" field",
  "owner": "Administrator",
- "permissions": [],
+ "permissions": [
+  {
+   "amend": 1,
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Accounts User",
+   "share": 1,
+   "submit": 1,
+   "write": 1
+  },
+  {
+   "amend": 1,
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "import": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Accounts Manager",
+   "share": 1,
+   "submit": 1,
+   "write": 1
+  },
+  {
+   "email": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Auditor"
+  }
+ ],
  "search_fields": "voucher_type,posting_date, due_date, cheque_no",
  "sort_field": "modified",
  "sort_order": "DESC",
diff --git a/erpnext/accounts/doctype/loyalty_program/loyalty_program.py b/erpnext/accounts/doctype/loyalty_program/loyalty_program.py
index a134f74..4f58579 100644
--- a/erpnext/accounts/doctype/loyalty_program/loyalty_program.py
+++ b/erpnext/accounts/doctype/loyalty_program/loyalty_program.py
@@ -145,8 +145,8 @@
 
 		loyalty_amount = flt(points_to_redeem * loyalty_program_details.conversion_factor)
 
-		if loyalty_amount > ref_doc.grand_total:
-			frappe.throw(_("You can't redeem Loyalty Points having more value than the Grand Total."))
+		if loyalty_amount > ref_doc.rounded_total:
+			frappe.throw(_("You can't redeem Loyalty Points having more value than the Rounded Total."))
 
 		if not ref_doc.loyalty_amount and ref_doc.loyalty_amount != loyalty_amount:
 			ref_doc.loyalty_amount = loyalty_amount
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 64b4d16..ac31e8a 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -71,7 +71,7 @@
 		self.setup_party_account_field()
 		self.set_missing_values()
 		self.set_liability_account()
-		self.set_missing_ref_details()
+		self.set_missing_ref_details(force=True)
 		self.validate_payment_type()
 		self.validate_party_details()
 		self.set_exchange_rate()
@@ -230,84 +230,88 @@
 		return False
 
 	def validate_allocated_amount_with_latest_data(self):
-		latest_references = get_outstanding_reference_documents(
-			{
-				"posting_date": self.posting_date,
-				"company": self.company,
-				"party_type": self.party_type,
-				"payment_type": self.payment_type,
-				"party": self.party,
-				"party_account": self.paid_from if self.payment_type == "Receive" else self.paid_to,
-				"get_outstanding_invoices": True,
-				"get_orders_to_be_billed": True,
-			},
-			validate=True,
-		)
+		if self.references:
+			uniq_vouchers = set([(x.reference_doctype, x.reference_name) for x in self.references])
+			vouchers = [frappe._dict({"voucher_type": x[0], "voucher_no": x[1]}) for x in uniq_vouchers]
+			latest_references = get_outstanding_reference_documents(
+				{
+					"posting_date": self.posting_date,
+					"company": self.company,
+					"party_type": self.party_type,
+					"payment_type": self.payment_type,
+					"party": self.party,
+					"party_account": self.paid_from if self.payment_type == "Receive" else self.paid_to,
+					"get_outstanding_invoices": True,
+					"get_orders_to_be_billed": True,
+					"vouchers": vouchers,
+				},
+				validate=True,
+			)
 
-		# Group latest_references by (voucher_type, voucher_no)
-		latest_lookup = {}
-		for d in latest_references:
-			d = frappe._dict(d)
-			latest_lookup.setdefault((d.voucher_type, d.voucher_no), frappe._dict())[d.payment_term] = d
+			# Group latest_references by (voucher_type, voucher_no)
+			latest_lookup = {}
+			for d in latest_references:
+				d = frappe._dict(d)
+				latest_lookup.setdefault((d.voucher_type, d.voucher_no), frappe._dict())[d.payment_term] = d
 
-		for idx, d in enumerate(self.get("references"), start=1):
-			latest = latest_lookup.get((d.reference_doctype, d.reference_name)) or frappe._dict()
+			for idx, d in enumerate(self.get("references"), start=1):
+				latest = latest_lookup.get((d.reference_doctype, d.reference_name)) or frappe._dict()
 
-			# If term based allocation is enabled, throw
-			if (
-				d.payment_term is None or d.payment_term == ""
-			) and self.term_based_allocation_enabled_for_reference(
-				d.reference_doctype, d.reference_name
-			):
-				frappe.throw(
-					_(
-						"{0} has Payment Term based allocation enabled. Select a Payment Term for Row #{1} in Payment References section"
-					).format(frappe.bold(d.reference_name), frappe.bold(idx))
-				)
-
-			# if no payment template is used by invoice and has a custom term(no `payment_term`), then invoice outstanding will be in 'None' key
-			latest = latest.get(d.payment_term) or latest.get(None)
-
-			# The reference has already been fully paid
-			if not latest:
-				frappe.throw(
-					_("{0} {1} has already been fully paid.").format(_(d.reference_doctype), d.reference_name)
-				)
-			# The reference has already been partly paid
-			elif latest.outstanding_amount < latest.invoice_amount and flt(
-				d.outstanding_amount, d.precision("outstanding_amount")
-			) != flt(latest.outstanding_amount, d.precision("outstanding_amount")):
-				frappe.throw(
-					_(
-						"{0} {1} has already been partly paid. Please use the 'Get Outstanding Invoice' or the 'Get Outstanding Orders' button to get the latest outstanding amounts."
-					).format(_(d.reference_doctype), d.reference_name)
-				)
-
-			fail_message = _("Row #{0}: Allocated Amount cannot be greater than outstanding amount.")
-
-			if (
-				d.payment_term
-				and (
-					(flt(d.allocated_amount)) > 0
-					and latest.payment_term_outstanding
-					and (flt(d.allocated_amount) > flt(latest.payment_term_outstanding))
-				)
-				and self.term_based_allocation_enabled_for_reference(d.reference_doctype, d.reference_name)
-			):
-				frappe.throw(
-					_(
-						"Row #{0}: Allocated amount:{1} is greater than outstanding amount:{2} for Payment Term {3}"
-					).format(
-						d.idx, d.allocated_amount, latest.payment_term_outstanding, d.payment_term
+				# If term based allocation is enabled, throw
+				if (
+					d.payment_term is None or d.payment_term == ""
+				) and self.term_based_allocation_enabled_for_reference(
+					d.reference_doctype, d.reference_name
+				):
+					frappe.throw(
+						_(
+							"{0} has Payment Term based allocation enabled. Select a Payment Term for Row #{1} in Payment References section"
+						).format(frappe.bold(d.reference_name), frappe.bold(idx))
 					)
-				)
 
-			if (flt(d.allocated_amount)) > 0 and flt(d.allocated_amount) > flt(latest.outstanding_amount):
-				frappe.throw(fail_message.format(d.idx))
+				# if no payment template is used by invoice and has a custom term(no `payment_term`), then invoice outstanding will be in 'None' key
+				latest = latest.get(d.payment_term) or latest.get(None)
 
-			# Check for negative outstanding invoices as well
-			if flt(d.allocated_amount) < 0 and flt(d.allocated_amount) < flt(latest.outstanding_amount):
-				frappe.throw(fail_message.format(d.idx))
+				# The reference has already been fully paid
+				if not latest:
+					frappe.throw(
+						_("{0} {1} has already been fully paid.").format(_(d.reference_doctype), d.reference_name)
+					)
+				# The reference has already been partly paid
+				elif latest.outstanding_amount < latest.invoice_amount and flt(
+					d.outstanding_amount, d.precision("outstanding_amount")
+				) != flt(latest.outstanding_amount, d.precision("outstanding_amount")):
+					frappe.throw(
+						_(
+							"{0} {1} has already been partly paid. Please use the 'Get Outstanding Invoice' or the 'Get Outstanding Orders' button to get the latest outstanding amounts."
+						).format(_(d.reference_doctype), d.reference_name)
+					)
+
+				fail_message = _("Row #{0}: Allocated Amount cannot be greater than outstanding amount.")
+
+				if (
+					d.payment_term
+					and (
+						(flt(d.allocated_amount)) > 0
+						and latest.payment_term_outstanding
+						and (flt(d.allocated_amount) > flt(latest.payment_term_outstanding))
+					)
+					and self.term_based_allocation_enabled_for_reference(d.reference_doctype, d.reference_name)
+				):
+					frappe.throw(
+						_(
+							"Row #{0}: Allocated amount:{1} is greater than outstanding amount:{2} for Payment Term {3}"
+						).format(
+							d.idx, d.allocated_amount, latest.payment_term_outstanding, d.payment_term
+						)
+					)
+
+				if (flt(d.allocated_amount)) > 0 and flt(d.allocated_amount) > flt(latest.outstanding_amount):
+					frappe.throw(fail_message.format(d.idx))
+
+				# Check for negative outstanding invoices as well
+				if flt(d.allocated_amount) < 0 and flt(d.allocated_amount) < flt(latest.outstanding_amount):
+					frappe.throw(fail_message.format(d.idx))
 
 	def delink_advance_entry_references(self):
 		for reference in self.references:
@@ -1587,6 +1591,7 @@
 			min_outstanding=args.get("outstanding_amt_greater_than"),
 			max_outstanding=args.get("outstanding_amt_less_than"),
 			accounting_dimensions=accounting_dimensions_filter,
+			vouchers=args.get("vouchers") or None,
 		)
 
 		outstanding_invoices = split_invoices_based_on_payment_terms(
diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
index a6c0102..faceaf3 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
+++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.js
@@ -153,7 +153,7 @@
 frappe.ui.form.on('POS Closing Entry Detail', {
 	closing_amount: (frm, cdt, cdn) => {
 		const row = locals[cdt][cdn];
-		frappe.model.set_value(cdt, cdn, "difference", flt(row.expected_amount - row.closing_amount));
+		frappe.model.set_value(cdt, cdn, "difference", flt(row.closing_amount - row.expected_amount));
 	}
 })
 
@@ -185,6 +185,7 @@
 		}
 		if (payment) {
 			payment.expected_amount += flt(p.amount);
+			payment.closing_amount = payment.expected_amount;
 			payment.difference = payment.closing_amount - payment.expected_amount;
 		} else {
 			frm.add_child("payment_reconciliation", {
diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json
index 9d15e6c..a98a24c 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json
+++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.json
@@ -221,6 +221,7 @@
    "read_only": 1
   },
   {
+   "default": "Now",
    "fieldname": "posting_time",
    "fieldtype": "Time",
    "label": "Posting Time",
@@ -235,7 +236,7 @@
    "link_fieldname": "pos_closing_entry"
   }
  ],
- "modified": "2022-08-01 11:37:14.991228",
+ "modified": "2023-08-10 16:25:49.322697",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "POS Closing Entry",
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 1deb3c5..93ba90a 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
@@ -8,9 +8,11 @@
 from erpnext.accounts.doctype.pos_closing_entry.pos_closing_entry import (
 	make_closing_entry_from_opening,
 )
+from erpnext.accounts.doctype.pos_invoice.pos_invoice import make_sales_return
 from erpnext.accounts.doctype.pos_invoice.test_pos_invoice import create_pos_invoice
 from erpnext.accounts.doctype.pos_opening_entry.test_pos_opening_entry import create_opening_entry
 from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
+from erpnext.selling.page.point_of_sale.point_of_sale import get_items
 from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
 
 
@@ -67,6 +69,36 @@
 
 		self.assertTrue(pcv_doc.name)
 
+	def test_pos_qty_for_item(self):
+		"""
+		Test if quantity is calculated correctly for an item in POS Closing Entry
+		"""
+		test_user, pos_profile = init_user_and_profile()
+		opening_entry = create_opening_entry(pos_profile, test_user.name)
+
+		test_item_qty = get_test_item_qty(pos_profile)
+
+		pos_inv1 = create_pos_invoice(rate=3500, do_not_submit=1)
+		pos_inv1.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3500})
+		pos_inv1.submit()
+
+		pos_inv2 = create_pos_invoice(rate=3200, do_not_submit=1)
+		pos_inv2.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": 3200})
+		pos_inv2.submit()
+
+		# make return entry of pos_inv2
+		pos_return = make_sales_return(pos_inv2.name)
+		pos_return.paid_amount = pos_return.grand_total
+		pos_return.save()
+		pos_return.submit()
+
+		pcv_doc = make_closing_entry_from_opening(opening_entry)
+		pcv_doc.submit()
+
+		opening_entry = create_opening_entry(pos_profile, test_user.name)
+		test_item_qty_after_sales = get_test_item_qty(pos_profile)
+		self.assertEqual(test_item_qty_after_sales, test_item_qty - 1)
+
 	def test_cancelling_of_pos_closing_entry(self):
 		test_user, pos_profile = init_user_and_profile()
 		opening_entry = create_opening_entry(pos_profile, test_user.name)
@@ -123,3 +155,19 @@
 	pos_profile.save()
 
 	return test_user, pos_profile
+
+
+def get_test_item_qty(pos_profile):
+	test_item_pos = get_items(
+		start=0,
+		page_length=5,
+		price_list="Standard Selling",
+		pos_profile=pos_profile.name,
+		search_term="_Test Item",
+		item_group="All Item Groups",
+	)
+
+	test_item_qty = [item for item in test_item_pos["items"] if item["item_code"] == "_Test Item"][
+		0
+	].get("actual_qty")
+	return test_item_qty
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
index ecf9af1..842f159 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
@@ -552,6 +552,7 @@
 		is_stock_item = True
 		bin_qty = get_bin_qty(item_code, warehouse)
 		pos_sales_qty = get_pos_reserved_qty(item_code, warehouse)
+
 		return bin_qty - pos_sales_qty, is_stock_item
 	else:
 		is_stock_item = True
@@ -605,7 +606,6 @@
 		.where(
 			(p_inv.name == p_item.parent)
 			& (IfNull(p_inv.consolidated_invoice, "") == "")
-			& (p_inv.is_return == 0)
 			& (p_item.docstatus == 1)
 			& (p_item.item_code == item_code)
 			& (p_item.warehouse == warehouse)
diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
index d8cbcc1..b587ce6 100644
--- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
+++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
@@ -95,7 +95,6 @@
 			sales_invoice = self.process_merging_into_sales_invoice(sales)
 
 		self.save()  # save consolidated_sales_invoice & consolidated_credit_note ref in merge log
-
 		self.update_pos_invoices(pos_invoice_docs, sales_invoice, credit_note)
 
 	def on_cancel(self):
@@ -108,7 +107,6 @@
 
 	def process_merging_into_sales_invoice(self, data):
 		sales_invoice = self.get_new_sales_invoice()
-
 		sales_invoice = self.merge_pos_invoice_into(sales_invoice, data)
 
 		sales_invoice.is_consolidated = 1
@@ -165,8 +163,7 @@
 				for i in items:
 					if (
 						i.item_code == item.item_code
-						and not i.serial_no
-						and not i.batch_no
+						and not i.serial_and_batch_bundle
 						and i.uom == item.uom
 						and i.net_rate == item.net_rate
 						and i.warehouse == item.warehouse
@@ -385,6 +382,7 @@
 		for d in invoices
 		if d.is_return and d.return_against
 	]
+
 	for pos_invoice in pos_return_docs:
 		for item in pos_invoice.items:
 			if not item.serial_no and not item.serial_and_batch_bundle:
diff --git a/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.json b/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.json
index 8bb7092..1a1ab4d 100644
--- a/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.json
+++ b/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.json
@@ -146,7 +146,7 @@
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2023-04-21 17:19:30.912953",
+ "modified": "2023-08-11 10:56:51.699137",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Process Payment Reconciliation",
@@ -154,15 +154,25 @@
  "owner": "Administrator",
  "permissions": [
   {
+   "amend": 1,
+   "cancel": 1,
    "create": 1,
    "delete": 1,
-   "email": 1,
-   "export": 1,
-   "print": 1,
    "read": 1,
-   "report": 1,
-   "role": "System Manager",
+   "role": "Accounts Manager",
    "share": 1,
+   "submit": 1,
+   "write": 1
+  },
+  {
+   "amend": 1,
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "read": 1,
+   "role": "Accounts User",
+   "share": 1,
+   "submit": 1,
    "write": 1
   }
  ],
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 63c0c45..f9cfe5a 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -3376,6 +3376,7 @@
 
 		set_advance_flag(company="_Test Company", flag=0, default_account="")
 
+	@change_settings("Selling Settings", {"allow_negative_rates_for_items": 0})
 	def test_sales_return_negative_rate(self):
 		si = create_sales_invoice(is_return=1, qty=-2, rate=-10, do_not_save=True)
 		self.assertRaises(frappe.ValidationError, si.save)
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
index e66a886..954b4e7 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -100,11 +100,14 @@
 	tax_details = get_tax_withholding_details(tax_withholding_category, posting_date, inv.company)
 
 	if not tax_details:
-		frappe.throw(
-			_("Please set associated account in Tax Withholding Category {0} against Company {1}").format(
-				tax_withholding_category, inv.company
-			)
+		frappe.msgprint(
+			_(
+				"Skipping Tax Withholding Category {0} as there is no associated account set for Company {1} in it."
+			).format(tax_withholding_category, inv.company)
 		)
+		if inv.doctype == "Purchase Invoice":
+			return {}, [], {}
+		return {}
 
 	if party_type == "Customer" and not tax_details.cumulative_threshold:
 		# TCS is only chargeable on sum of invoiced value
@@ -262,14 +265,20 @@
 		if tax_deducted:
 			net_total = inv.tax_withholding_net_total
 			if ldc:
-				tax_amount = get_tds_amount_from_ldc(ldc, parties, tax_details, posting_date, net_total)
+				limit_consumed = get_limit_consumed(ldc, parties)
+				if is_valid_certificate(ldc, posting_date, limit_consumed):
+					tax_amount = get_lower_deduction_amount(
+						net_total, limit_consumed, ldc.certificate_limit, ldc.rate, tax_details
+					)
+				else:
+					tax_amount = net_total * tax_details.rate / 100 if net_total > 0 else 0
 			else:
 				tax_amount = net_total * tax_details.rate / 100 if net_total > 0 else 0
 
 			# once tds is deducted, not need to add vouchers in the invoice
 			voucher_wise_amount = {}
 		else:
-			tax_amount = get_tds_amount(ldc, parties, inv, tax_details, tax_deducted, vouchers)
+			tax_amount = get_tds_amount(ldc, parties, inv, tax_details, vouchers)
 
 	elif party_type == "Customer":
 		if tax_deducted:
@@ -416,7 +425,7 @@
 	return sum(entries)
 
 
-def get_tds_amount(ldc, parties, inv, tax_details, tax_deducted, vouchers):
+def get_tds_amount(ldc, parties, inv, tax_details, vouchers):
 	tds_amount = 0
 	invoice_filters = {"name": ("in", vouchers), "docstatus": 1, "apply_tds": 1}
 
@@ -496,15 +505,10 @@
 			net_total += inv.tax_withholding_net_total
 			supp_credit_amt = net_total - cumulative_threshold
 
-		if ldc and is_valid_certificate(
-			ldc.valid_from,
-			ldc.valid_upto,
-			inv.get("posting_date") or inv.get("transaction_date"),
-			tax_deducted,
-			inv.tax_withholding_net_total,
-			ldc.certificate_limit,
-		):
-			tds_amount = get_ltds_amount(supp_credit_amt, 0, ldc.certificate_limit, ldc.rate, tax_details)
+		if ldc and is_valid_certificate(ldc, inv.get("posting_date") or inv.get("transaction_date"), 0):
+			tds_amount = get_lower_deduction_amount(
+				supp_credit_amt, 0, ldc.certificate_limit, ldc.rate, tax_details
+			)
 		else:
 			tds_amount = supp_credit_amt * tax_details.rate / 100 if supp_credit_amt > 0 else 0
 
@@ -582,8 +586,7 @@
 	return inv.grand_total - tcs_tax_row_amount
 
 
-def get_tds_amount_from_ldc(ldc, parties, tax_details, posting_date, net_total):
-	tds_amount = 0
+def get_limit_consumed(ldc, parties):
 	limit_consumed = frappe.db.get_value(
 		"Purchase Invoice",
 		{
@@ -597,37 +600,29 @@
 		"sum(tax_withholding_net_total)",
 	)
 
-	if is_valid_certificate(
-		ldc.valid_from, ldc.valid_upto, posting_date, limit_consumed, net_total, ldc.certificate_limit
-	):
-		tds_amount = get_ltds_amount(
-			net_total, limit_consumed, ldc.certificate_limit, ldc.rate, tax_details
-		)
-
-	return tds_amount
+	return limit_consumed
 
 
-def get_ltds_amount(current_amount, deducted_amount, certificate_limit, rate, tax_details):
-	if certificate_limit - flt(deducted_amount) - flt(current_amount) >= 0:
+def get_lower_deduction_amount(
+	current_amount, limit_consumed, certificate_limit, rate, tax_details
+):
+	if certificate_limit - flt(limit_consumed) - flt(current_amount) >= 0:
 		return current_amount * rate / 100
 	else:
-		ltds_amount = certificate_limit - flt(deducted_amount)
+		ltds_amount = certificate_limit - flt(limit_consumed)
 		tds_amount = current_amount - ltds_amount
 
 		return ltds_amount * rate / 100 + tds_amount * tax_details.rate / 100
 
 
-def is_valid_certificate(
-	valid_from, valid_upto, posting_date, deducted_amount, current_amount, certificate_limit
-):
-	valid = False
+def is_valid_certificate(ldc, posting_date, limit_consumed):
+	available_amount = flt(ldc.certificate_limit) - flt(limit_consumed)
+	if (
+		getdate(ldc.valid_from) <= getdate(posting_date) <= getdate(ldc.valid_upto)
+	) and available_amount > 0:
+		return True
 
-	available_amount = flt(certificate_limit) - flt(deducted_amount)
-
-	if (getdate(valid_from) <= getdate(posting_date) <= getdate(valid_upto)) and available_amount > 0:
-		valid = True
-
-	return valid
+	return False
 
 
 def normal_round(number):
diff --git a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
index 80220e4..0fbaf23 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
@@ -4,6 +4,7 @@
 import unittest
 
 import frappe
+from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
 from frappe.utils import today
 
 from erpnext.accounts.utils import get_fiscal_year
@@ -17,6 +18,7 @@
 		# create relevant supplier, etc
 		create_records()
 		create_tax_withholding_category_records()
+		make_pan_no_field()
 
 	def tearDown(self):
 		cancel_invoices()
@@ -451,6 +453,40 @@
 		pe2.cancel()
 		pe3.cancel()
 
+	def test_lower_deduction_certificate_application(self):
+		frappe.db.set_value(
+			"Supplier",
+			"Test LDC Supplier",
+			{
+				"tax_withholding_category": "Test Service Category",
+				"pan": "ABCTY1234D",
+			},
+		)
+
+		create_lower_deduction_certificate(
+			supplier="Test LDC Supplier",
+			certificate_no="1AE0423AAJ",
+			tax_withholding_category="Test Service Category",
+			tax_rate=2,
+			limit=50000,
+		)
+
+		pi1 = create_purchase_invoice(supplier="Test LDC Supplier", rate=35000)
+		pi1.submit()
+		self.assertEqual(pi1.taxes[0].tax_amount, 700)
+
+		pi2 = create_purchase_invoice(supplier="Test LDC Supplier", rate=35000)
+		pi2.submit()
+		self.assertEqual(pi2.taxes[0].tax_amount, 2300)
+
+		pi3 = create_purchase_invoice(supplier="Test LDC Supplier", rate=35000)
+		pi3.submit()
+		self.assertEqual(pi3.taxes[0].tax_amount, 3500)
+
+		pi1.cancel()
+		pi2.cancel()
+		pi3.cancel()
+
 
 def cancel_invoices():
 	purchase_invoices = frappe.get_all(
@@ -610,6 +646,7 @@
 		"Test TDS Supplier6",
 		"Test TDS Supplier7",
 		"Test TDS Supplier8",
+		"Test LDC Supplier",
 	]:
 		if frappe.db.exists("Supplier", name):
 			continue
@@ -806,3 +843,39 @@
 				"accounts": [{"company": "_Test Company", "account": account}],
 			}
 		).insert()
+
+
+def create_lower_deduction_certificate(
+	supplier, tax_withholding_category, tax_rate, certificate_no, limit
+):
+	fiscal_year = get_fiscal_year(today(), company="_Test Company")
+	if not frappe.db.exists("Lower Deduction Certificate", certificate_no):
+		frappe.get_doc(
+			{
+				"doctype": "Lower Deduction Certificate",
+				"company": "_Test Company",
+				"supplier": supplier,
+				"certificate_no": certificate_no,
+				"tax_withholding_category": tax_withholding_category,
+				"fiscal_year": fiscal_year[0],
+				"valid_from": fiscal_year[1],
+				"valid_upto": fiscal_year[2],
+				"rate": tax_rate,
+				"certificate_limit": limit,
+			}
+		).insert()
+
+
+def make_pan_no_field():
+	pan_field = {
+		"Supplier": [
+			{
+				"fieldname": "pan",
+				"label": "PAN",
+				"fieldtype": "Data",
+				"translatable": 0,
+			}
+		]
+	}
+
+	create_custom_fields(pan_field, update=1)
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index 895c314..0d67752 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -707,6 +707,7 @@
 	if party_type not in ("Customer", "Supplier"):
 		return
 	template = None
+
 	if party_type == "Customer":
 		customer = frappe.get_cached_value(
 			"Customer", party_name, fieldname=["payment_terms", "customer_group"], as_dict=1
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 11bbb6f..f78a840 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -436,12 +436,11 @@
 	def allocate_outstanding_based_on_payment_terms(self, row):
 		self.get_payment_terms(row)
 		for term in row.payment_terms:
-
-			# update "paid" and "oustanding" for this term
+			# update "paid" and "outstanding" for this term
 			if not term.paid:
 				self.allocate_closing_to_term(row, term, "paid")
 
-			# update "credit_note" and "oustanding" for this term
+			# update "credit_note" and "outstanding" for this term
 			if term.outstanding:
 				self.allocate_closing_to_term(row, term, "credit_note")
 
@@ -453,7 +452,8 @@
 			"""
 			select
 				si.name, si.party_account_currency, si.currency, si.conversion_rate,
-				ps.due_date, ps.payment_term, ps.payment_amount, ps.description, ps.paid_amount, ps.discounted_amount
+				si.total_advance, ps.due_date, ps.payment_term, ps.payment_amount, ps.base_payment_amount,
+				ps.description, ps.paid_amount, ps.discounted_amount
 			from `tab{0}` si, `tabPayment Schedule` ps
 			where
 				si.name = ps.parent and
@@ -469,6 +469,10 @@
 		original_row = frappe._dict(row)
 		row.payment_terms = []
 
+		# Advance allocated during invoicing is not considered in payment terms
+		# Deduct that from paid amount pre allocation
+		row.paid -= flt(payment_terms_details[0].total_advance)
+
 		# If no or single payment terms, no need to split the row
 		if len(payment_terms_details) <= 1:
 			return
@@ -483,7 +487,7 @@
 		) and d.currency == d.party_account_currency:
 			invoiced = d.payment_amount
 		else:
-			invoiced = flt(flt(d.payment_amount) * flt(d.conversion_rate), self.currency_precision)
+			invoiced = d.base_payment_amount
 
 		row.payment_terms.append(
 			term.update(
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 080e45a..0051ba6 100644
--- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
+++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
@@ -744,13 +744,18 @@
 	if from_date:
 		additional_conditions.append(gle.posting_date >= from_date)
 
-	finance_book = filters.get("finance_book")
-	company_fb = frappe.get_cached_value("Company", d.name, "default_finance_book")
+	finance_books = []
+	finance_books.append("")
+	if filter_fb := filters.get("finance_book"):
+		finance_books.append(filter_fb)
 
 	if filters.get("include_default_book_entries"):
-		additional_conditions.append((gle.finance_book.isin([finance_book, company_fb, "", None])))
+		if company_fb := frappe.get_cached_value("Company", d.name, "default_finance_book"):
+			finance_books.append(company_fb)
+
+		additional_conditions.append((gle.finance_book.isin(finance_books)) | gle.finance_book.isnull())
 	else:
-		additional_conditions.append((gle.finance_book.isin([finance_book, "", None])))
+		additional_conditions.append((gle.finance_book.isin(finance_books)) | gle.finance_book.isnull())
 
 	return additional_conditions
 
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index a76dea6..693725d 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -335,12 +335,10 @@
 			for period in period_list:
 				total_row.setdefault(period.key, 0.0)
 				total_row[period.key] += row.get(period.key, 0.0)
-				row[period.key] = row.get(period.key, 0.0)
 
 			total_row.setdefault("total", 0.0)
 			total_row["total"] += flt(row["total"])
 			total_row["opening_balance"] += row["opening_balance"]
-			row["total"] = ""
 
 	if "total" in total_row:
 		out.append(total_row)
@@ -639,7 +637,13 @@
 	if periodicity != "Yearly":
 		if not accumulated_values:
 			columns.append(
-				{"fieldname": "total", "label": _("Total"), "fieldtype": "Currency", "width": 150}
+				{
+					"fieldname": "total",
+					"label": _("Total"),
+					"fieldtype": "Currency",
+					"width": 150,
+					"options": "currency",
+				}
 			)
 
 	return columns
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js
index 57a9091..37d0659 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.js
+++ b/erpnext/accounts/report/general_ledger/general_ledger.js
@@ -188,6 +188,11 @@
 			"fieldname": "show_net_values_in_party_account",
 			"label": __("Show Net Values in Party Account"),
 			"fieldtype": "Check"
+		},
+		{
+			"fieldname": "add_values_in_transaction_currency",
+			"label": __("Add Columns in Transaction Currency"),
+			"fieldtype": "Check"
 		}
 	]
 }
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.py b/erpnext/accounts/report/general_ledger/general_ledger.py
index d7af167..e05a4e7 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.py
+++ b/erpnext/accounts/report/general_ledger/general_ledger.py
@@ -182,12 +182,18 @@
 	if accounting_dimensions:
 		dimension_fields = ", ".join(accounting_dimensions) + ","
 
+	transaction_currency_fields = ""
+	if filters.get("add_values_in_transaction_currency"):
+		transaction_currency_fields = (
+			"debit_in_transaction_currency, credit_in_transaction_currency, transaction_currency,"
+		)
+
 	gl_entries = frappe.db.sql(
 		"""
 		select
 			name as gl_entry, posting_date, account, party_type, party,
 			voucher_type, voucher_no, {dimension_fields}
-			cost_center, project,
+			cost_center, project, {transaction_currency_fields}
 			against_voucher_type, against_voucher, account_currency,
 			remarks, against, is_opening, creation {select_fields}
 		from `tabGL Entry`
@@ -195,6 +201,7 @@
 		{order_by_statement}
 	""".format(
 			dimension_fields=dimension_fields,
+			transaction_currency_fields=transaction_currency_fields,
 			select_fields=select_fields,
 			conditions=get_conditions(filters),
 			order_by_statement=order_by_statement,
@@ -562,6 +569,34 @@
 			"fieldtype": "Float",
 			"width": 130,
 		},
+	]
+
+	if filters.get("add_values_in_transaction_currency"):
+		columns += [
+			{
+				"label": _("Debit (Transaction)"),
+				"fieldname": "debit_in_transaction_currency",
+				"fieldtype": "Currency",
+				"width": 130,
+				"options": "transaction_currency",
+			},
+			{
+				"label": _("Credit (Transaction)"),
+				"fieldname": "credit_in_transaction_currency",
+				"fieldtype": "Currency",
+				"width": 130,
+				"options": "transaction_currency",
+			},
+			{
+				"label": "Transaction Currency",
+				"fieldname": "transaction_currency",
+				"fieldtype": "Link",
+				"options": "Currency",
+				"width": 70,
+			},
+		]
+
+	columns += [
 		{"label": _("Voucher Type"), "fieldname": "voucher_type", "width": 120},
 		{
 			"label": _("Voucher No"),
diff --git a/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.js b/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.js
index b66a555..8808165 100644
--- a/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.js
+++ b/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.js
@@ -33,7 +33,14 @@
 					frappe.throw(__("Please select Party Type first"));
 				}
 				return party_type;
-			}
+			},
+			"get_query": function() {
+				return {
+					"filters": {
+						"tax_withholding_category": ["!=",""],
+					}
+				}
+			},
 		},
 		{
 			"fieldname":"from_date",
diff --git a/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py b/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py
index ddd049a..7d16661 100644
--- a/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py
+++ b/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py
@@ -7,19 +7,26 @@
 
 
 def execute(filters=None):
+	if filters.get("party_type") == "Customer":
+		party_naming_by = frappe.db.get_single_value("Selling Settings", "cust_master_name")
+	else:
+		party_naming_by = frappe.db.get_single_value("Buying Settings", "supp_master_name")
+
+	filters.update({"naming_series": party_naming_by})
+
 	validate_filters(filters)
 	(
 		tds_docs,
 		tds_accounts,
 		tax_category_map,
 		journal_entry_party_map,
-		invoice_net_total_map,
+		net_total_map,
 	) = get_tds_docs(filters)
 
 	columns = get_columns(filters)
 
 	res = get_result(
-		filters, tds_docs, tds_accounts, tax_category_map, journal_entry_party_map, invoice_net_total_map
+		filters, tds_docs, tds_accounts, tax_category_map, journal_entry_party_map, net_total_map
 	)
 	return columns, res
 
@@ -31,7 +38,7 @@
 
 
 def get_result(
-	filters, tds_docs, tds_accounts, tax_category_map, journal_entry_party_map, invoice_net_total_map
+	filters, tds_docs, tds_accounts, tax_category_map, journal_entry_party_map, net_total_map
 ):
 	party_map = get_party_pan_map(filters.get("party_type"))
 	tax_rate_map = get_tax_rate_map(filters)
@@ -39,7 +46,7 @@
 
 	out = []
 	for name, details in gle_map.items():
-		tax_amount, total_amount = 0, 0
+		tax_amount, total_amount, grand_total, base_total = 0, 0, 0, 0
 		tax_withholding_category = tax_category_map.get(name)
 		rate = tax_rate_map.get(tax_withholding_category)
 
@@ -60,8 +67,8 @@
 			if entry.account in tds_accounts:
 				tax_amount += entry.credit - entry.debit
 
-			if invoice_net_total_map.get(name):
-				total_amount = invoice_net_total_map.get(name)
+			if net_total_map.get(name):
+				total_amount, grand_total, base_total = net_total_map.get(name)
 			else:
 				total_amount += entry.credit
 
@@ -69,15 +76,13 @@
 			if party_map.get(party, {}).get("party_type") == "Supplier":
 				party_name = "supplier_name"
 				party_type = "supplier_type"
-				table_name = "Supplier"
 			else:
 				party_name = "customer_name"
 				party_type = "customer_type"
-				table_name = "Customer"
 
 			row = {
 				"pan"
-				if frappe.db.has_column(table_name, "pan")
+				if frappe.db.has_column(filters.party_type, "pan")
 				else "tax_id": party_map.get(party, {}).get("pan"),
 				"party": party_map.get(party, {}).get("name"),
 			}
@@ -91,6 +96,8 @@
 					"entity_type": party_map.get(party, {}).get(party_type),
 					"rate": rate,
 					"total_amount": total_amount,
+					"grand_total": grand_total,
+					"base_total": base_total,
 					"tax_amount": tax_amount,
 					"transaction_date": posting_date,
 					"transaction_type": voucher_type,
@@ -144,9 +151,9 @@
 
 
 def get_columns(filters):
-	pan = "pan" if frappe.db.has_column("Supplier", "pan") else "tax_id"
+	pan = "pan" if frappe.db.has_column(filters.party_type, "pan") else "tax_id"
 	columns = [
-		{"label": _(frappe.unscrub(pan)), "fieldname": pan, "fieldtype": "Data", "width": 90},
+		{"label": _(frappe.unscrub(pan)), "fieldname": pan, "fieldtype": "Data", "width": 60},
 		{
 			"label": _(filters.get("party_type")),
 			"fieldname": "party",
@@ -158,25 +165,30 @@
 
 	if filters.naming_series == "Naming Series":
 		columns.append(
-			{"label": _("Party Name"), "fieldname": "party_name", "fieldtype": "Data", "width": 180}
+			{
+				"label": _(filters.party_type + " Name"),
+				"fieldname": "party_name",
+				"fieldtype": "Data",
+				"width": 180,
+			}
 		)
 
 	columns.extend(
 		[
 			{
+				"label": _("Date of Transaction"),
+				"fieldname": "transaction_date",
+				"fieldtype": "Date",
+				"width": 100,
+			},
+			{
 				"label": _("Section Code"),
 				"options": "Tax Withholding Category",
 				"fieldname": "section_code",
 				"fieldtype": "Link",
-				"width": 180,
-			},
-			{"label": _("Entity Type"), "fieldname": "entity_type", "fieldtype": "Data", "width": 120},
-			{
-				"label": _("TDS Rate %") if filters.get("party_type") == "Supplier" else _("TCS Rate %"),
-				"fieldname": "rate",
-				"fieldtype": "Percent",
 				"width": 90,
 			},
+			{"label": _("Entity Type"), "fieldname": "entity_type", "fieldtype": "Data", "width": 100},
 			{
 				"label": _("Total Amount"),
 				"fieldname": "total_amount",
@@ -184,15 +196,27 @@
 				"width": 90,
 			},
 			{
-				"label": _("TDS Amount") if filters.get("party_type") == "Supplier" else _("TCS Amount"),
+				"label": _("TDS Rate %") if filters.get("party_type") == "Supplier" else _("TCS Rate %"),
+				"fieldname": "rate",
+				"fieldtype": "Percent",
+				"width": 90,
+			},
+			{
+				"label": _("Tax Amount"),
 				"fieldname": "tax_amount",
 				"fieldtype": "Float",
 				"width": 90,
 			},
 			{
-				"label": _("Date of Transaction"),
-				"fieldname": "transaction_date",
-				"fieldtype": "Date",
+				"label": _("Grand Total"),
+				"fieldname": "grand_total",
+				"fieldtype": "Float",
+				"width": 90,
+			},
+			{
+				"label": _("Base Total"),
+				"fieldname": "base_total",
+				"fieldtype": "Float",
 				"width": 90,
 			},
 			{"label": _("Transaction Type"), "fieldname": "transaction_type", "width": 100},
@@ -216,7 +240,7 @@
 	payment_entries = []
 	journal_entries = []
 	tax_category_map = frappe._dict()
-	invoice_net_total_map = frappe._dict()
+	net_total_map = frappe._dict()
 	or_filters = frappe._dict()
 	journal_entry_party_map = frappe._dict()
 	bank_accounts = frappe.get_all("Account", {"is_group": 0, "account_type": "Bank"}, pluck="name")
@@ -260,13 +284,13 @@
 		tds_documents.append(d.voucher_no)
 
 	if purchase_invoices:
-		get_doc_info(purchase_invoices, "Purchase Invoice", tax_category_map, invoice_net_total_map)
+		get_doc_info(purchase_invoices, "Purchase Invoice", tax_category_map, net_total_map)
 
 	if sales_invoices:
-		get_doc_info(sales_invoices, "Sales Invoice", tax_category_map, invoice_net_total_map)
+		get_doc_info(sales_invoices, "Sales Invoice", tax_category_map, net_total_map)
 
 	if payment_entries:
-		get_doc_info(payment_entries, "Payment Entry", tax_category_map)
+		get_doc_info(payment_entries, "Payment Entry", tax_category_map, net_total_map)
 
 	if journal_entries:
 		journal_entry_party_map = get_journal_entry_party_map(journal_entries)
@@ -277,7 +301,7 @@
 		tds_accounts,
 		tax_category_map,
 		journal_entry_party_map,
-		invoice_net_total_map,
+		net_total_map,
 	)
 
 
@@ -295,11 +319,25 @@
 	return journal_entry_party_map
 
 
-def get_doc_info(vouchers, doctype, tax_category_map, invoice_net_total_map=None):
+def get_doc_info(vouchers, doctype, tax_category_map, net_total_map=None):
 	if doctype == "Purchase Invoice":
-		fields = ["name", "tax_withholding_category", "base_tax_withholding_net_total"]
-	if doctype == "Sales Invoice":
-		fields = ["name", "base_net_total"]
+		fields = [
+			"name",
+			"tax_withholding_category",
+			"base_tax_withholding_net_total",
+			"grand_total",
+			"base_total",
+		]
+	elif doctype == "Sales Invoice":
+		fields = ["name", "base_net_total", "grand_total", "base_total"]
+	elif doctype == "Payment Entry":
+		fields = [
+			"name",
+			"tax_withholding_category",
+			"paid_amount",
+			"paid_amount_after_tax",
+			"base_paid_amount",
+		]
 	else:
 		fields = ["name", "tax_withholding_category"]
 
@@ -308,9 +346,15 @@
 	for entry in entries:
 		tax_category_map.update({entry.name: entry.tax_withholding_category})
 		if doctype == "Purchase Invoice":
-			invoice_net_total_map.update({entry.name: entry.base_tax_withholding_net_total})
-		if doctype == "Sales Invoice":
-			invoice_net_total_map.update({entry.name: entry.base_net_total})
+			net_total_map.update(
+				{entry.name: [entry.base_tax_withholding_net_total, entry.grand_total, entry.base_total]}
+			)
+		elif doctype == "Sales Invoice":
+			net_total_map.update({entry.name: [entry.base_net_total, entry.grand_total, entry.base_total]})
+		elif doctype == "Payment Entry":
+			net_total_map.update(
+				{entry.name: [entry.paid_amount, entry.paid_amount_after_tax, entry.base_paid_amount]}
+			)
 
 
 def get_tax_rate_map(filters):
diff --git a/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.js b/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.js
index d334846..a0be1b5 100644
--- a/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.js
+++ b/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.js
@@ -12,17 +12,35 @@
 			"default": frappe.defaults.get_default('company')
 		},
 		{
-			"fieldname":"supplier",
-			"label": __("Supplier"),
-			"fieldtype": "Link",
-			"options": "Supplier",
+			"fieldname":"party_type",
+			"label": __("Party Type"),
+			"fieldtype": "Select",
+			"options": ["Supplier", "Customer"],
+			"reqd": 1,
+			"default": "Supplier",
+			"on_change": function(){
+				frappe.query_report.set_filter_value("party", "");
+			}
+		},
+		{
+			"fieldname":"party",
+			"label": __("Party"),
+			"fieldtype": "Dynamic Link",
+			"get_options": function() {
+				var party_type = frappe.query_report.get_filter_value('party_type');
+				var party = frappe.query_report.get_filter_value('party');
+				if(party && !party_type) {
+					frappe.throw(__("Please select Party Type first"));
+				}
+				return party_type;
+			},
 			"get_query": function() {
 				return {
 					"filters": {
 						"tax_withholding_category": ["!=",""],
 					}
 				}
-			}
+			},
 		},
 		{
 			"fieldname":"from_date",
diff --git a/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py b/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py
index c6aa21c..82f97f1 100644
--- a/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py
+++ b/erpnext/accounts/report/tds_computation_summary/tds_computation_summary.py
@@ -9,9 +9,14 @@
 
 
 def execute(filters=None):
-	validate_filters(filters)
+	if filters.get("party_type") == "Customer":
+		party_naming_by = frappe.db.get_single_value("Selling Settings", "cust_master_name")
+	else:
+		party_naming_by = frappe.db.get_single_value("Buying Settings", "supp_master_name")
 
-	filters.naming_series = frappe.db.get_single_value("Buying Settings", "supp_master_name")
+	filters.update({"naming_series": party_naming_by})
+
+	validate_filters(filters)
 
 	columns = get_columns(filters)
 	(
@@ -25,7 +30,7 @@
 	res = get_result(
 		filters, tds_docs, tds_accounts, tax_category_map, journal_entry_party_map, invoice_total_map
 	)
-	final_result = group_by_supplier_and_category(res)
+	final_result = group_by_party_and_category(res, filters)
 
 	return columns, final_result
 
@@ -43,60 +48,67 @@
 	filters["fiscal_year"] = from_year
 
 
-def group_by_supplier_and_category(data):
-	supplier_category_wise_map = {}
+def group_by_party_and_category(data, filters):
+	party_category_wise_map = {}
 
 	for row in data:
-		supplier_category_wise_map.setdefault(
-			(row.get("supplier"), row.get("section_code")),
+		party_category_wise_map.setdefault(
+			(row.get("party"), row.get("section_code")),
 			{
 				"pan": row.get("pan"),
-				"supplier": row.get("supplier"),
-				"supplier_name": row.get("supplier_name"),
+				"tax_id": row.get("tax_id"),
+				"party": row.get("party"),
+				"party_name": row.get("party_name"),
 				"section_code": row.get("section_code"),
 				"entity_type": row.get("entity_type"),
-				"tds_rate": row.get("tds_rate"),
-				"total_amount_credited": 0.0,
-				"tds_deducted": 0.0,
+				"rate": row.get("rate"),
+				"total_amount": 0.0,
+				"tax_amount": 0.0,
 			},
 		)
 
-		supplier_category_wise_map.get((row.get("supplier"), row.get("section_code")))[
-			"total_amount_credited"
-		] += row.get("total_amount_credited", 0.0)
+		party_category_wise_map.get((row.get("party"), row.get("section_code")))[
+			"total_amount"
+		] += row.get("total_amount", 0.0)
 
-		supplier_category_wise_map.get((row.get("supplier"), row.get("section_code")))[
-			"tds_deducted"
-		] += row.get("tds_deducted", 0.0)
+		party_category_wise_map.get((row.get("party"), row.get("section_code")))[
+			"tax_amount"
+		] += row.get("tax_amount", 0.0)
 
-	final_result = get_final_result(supplier_category_wise_map)
+	final_result = get_final_result(party_category_wise_map)
 
 	return final_result
 
 
-def get_final_result(supplier_category_wise_map):
+def get_final_result(party_category_wise_map):
 	out = []
-	for key, value in supplier_category_wise_map.items():
+	for key, value in party_category_wise_map.items():
 		out.append(value)
 
 	return out
 
 
 def get_columns(filters):
+	pan = "pan" if frappe.db.has_column(filters.party_type, "pan") else "tax_id"
 	columns = [
-		{"label": _("PAN"), "fieldname": "pan", "fieldtype": "Data", "width": 90},
+		{"label": _(frappe.unscrub(pan)), "fieldname": pan, "fieldtype": "Data", "width": 90},
 		{
-			"label": _("Supplier"),
-			"options": "Supplier",
-			"fieldname": "supplier",
-			"fieldtype": "Link",
+			"label": _(filters.get("party_type")),
+			"fieldname": "party",
+			"fieldtype": "Dynamic Link",
+			"options": "party_type",
 			"width": 180,
 		},
 	]
 
 	if filters.naming_series == "Naming Series":
 		columns.append(
-			{"label": _("Supplier Name"), "fieldname": "supplier_name", "fieldtype": "Data", "width": 180}
+			{
+				"label": _(filters.party_type + " Name"),
+				"fieldname": "party_name",
+				"fieldtype": "Data",
+				"width": 180,
+			}
 		)
 
 	columns.extend(
@@ -109,18 +121,23 @@
 				"width": 180,
 			},
 			{"label": _("Entity Type"), "fieldname": "entity_type", "fieldtype": "Data", "width": 180},
-			{"label": _("TDS Rate %"), "fieldname": "tds_rate", "fieldtype": "Percent", "width": 90},
 			{
-				"label": _("Total Amount Credited"),
-				"fieldname": "total_amount_credited",
-				"fieldtype": "Float",
-				"width": 90,
+				"label": _("TDS Rate %") if filters.get("party_type") == "Supplier" else _("TCS Rate %"),
+				"fieldname": "rate",
+				"fieldtype": "Percent",
+				"width": 120,
 			},
 			{
-				"label": _("Amount of TDS Deducted"),
-				"fieldname": "tds_deducted",
+				"label": _("Total Amount"),
+				"fieldname": "total_amount",
 				"fieldtype": "Float",
-				"width": 90,
+				"width": 120,
+			},
+			{
+				"label": _("Tax Amount"),
+				"fieldname": "tax_amount",
+				"fieldtype": "Float",
+				"width": 120,
 			},
 		]
 	)
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index c24442e..bccf6f1 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -908,6 +908,7 @@
 	min_outstanding=None,
 	max_outstanding=None,
 	accounting_dimensions=None,
+	vouchers=None,
 ):
 
 	ple = qb.DocType("Payment Ledger Entry")
@@ -933,6 +934,7 @@
 
 	ple_query = QueryPaymentLedger()
 	invoice_list = ple_query.get_voucher_outstandings(
+		vouchers=vouchers,
 		common_filter=common_filter,
 		posting_date=posting_date,
 		min_outstanding=min_outstanding,
diff --git a/erpnext/accounts/workspace/accounting/accounting.json b/erpnext/accounts/workspace/accounting/accounting.json
index c27ede2..dfdae1d 100644
--- a/erpnext/accounts/workspace/accounting/accounting.json
+++ b/erpnext/accounts/workspace/accounting/accounting.json
@@ -5,7 +5,7 @@
    "label": "Profit and Loss"
   }
  ],
- "content": "[{\"id\":\"MmUf9abwxg\",\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"Accounts\",\"col\":12}},{\"id\":\"i0EtSjDAXq\",\"type\":\"chart\",\"data\":{\"chart_name\":\"Profit and Loss\",\"col\":12}},{\"id\":\"X78jcbq1u3\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"vikWSkNm6_\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"col\":12}},{\"id\":\"pMywM0nhlj\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Chart of Accounts\",\"col\":3}},{\"id\":\"_pRdD6kqUG\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Invoice\",\"col\":3}},{\"id\":\"G984SgVRJN\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Purchase Invoice\",\"col\":3}},{\"id\":\"1ArNvt9qhz\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Journal Entry\",\"col\":3}},{\"id\":\"F9f4I1viNr\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Payment Entry\",\"col\":3}},{\"id\":\"4IBBOIxfqW\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Accounts Receivable\",\"col\":3}},{\"id\":\"El2anpPaFY\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"General Ledger\",\"col\":3}},{\"id\":\"1nwcM9upJo\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Trial Balance\",\"col\":3}},{\"id\":\"OF9WOi1Ppc\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"id\":\"iAwpe-Chra\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Learn Accounting\",\"col\":3}},{\"id\":\"B7-uxs8tkU\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"tHb3yxthkR\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports &amp; Masters</b></span>\",\"col\":12}},{\"id\":\"DnNtsmxpty\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounting Masters\",\"col\":4}},{\"id\":\"nKKr6fjgjb\",\"type\":\"card\",\"data\":{\"card_name\":\"General Ledger\",\"col\":4}},{\"id\":\"xOHTyD8b5l\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounts Receivable\",\"col\":4}},{\"id\":\"_Cb7C8XdJJ\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounts Payable\",\"col\":4}},{\"id\":\"p7NY6MHe2Y\",\"type\":\"card\",\"data\":{\"card_name\":\"Financial Statements\",\"col\":4}},{\"id\":\"KlqilF5R_V\",\"type\":\"card\",\"data\":{\"card_name\":\"Taxes\",\"col\":4}},{\"id\":\"jTUy8LB0uw\",\"type\":\"card\",\"data\":{\"card_name\":\"Cost Center and Budgeting\",\"col\":4}},{\"id\":\"Wn2lhs7WLn\",\"type\":\"card\",\"data\":{\"card_name\":\"Multi Currency\",\"col\":4}},{\"id\":\"PAQMqqNkBM\",\"type\":\"card\",\"data\":{\"card_name\":\"Bank Statement\",\"col\":4}},{\"id\":\"Q_hBCnSeJY\",\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}},{\"id\":\"3AK1Zf0oew\",\"type\":\"card\",\"data\":{\"card_name\":\"Profitability\",\"col\":4}},{\"id\":\"kxhoaiqdLq\",\"type\":\"card\",\"data\":{\"card_name\":\"Opening and Closing\",\"col\":4}},{\"id\":\"q0MAlU2j_Z\",\"type\":\"card\",\"data\":{\"card_name\":\"Subscription Management\",\"col\":4}},{\"id\":\"ptm7T6Hwu-\",\"type\":\"card\",\"data\":{\"card_name\":\"Share Management\",\"col\":4}},{\"id\":\"OX7lZHbiTr\",\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}}]",
+ "content": "[{\"id\":\"MmUf9abwxg\",\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"Accounts\",\"col\":12}},{\"id\":\"VVvJ1lUcfc\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Outgoing Bills\",\"col\":3}},{\"id\":\"Vlj2FZtlHV\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Incoming Bills\",\"col\":3}},{\"id\":\"VVVjQVAhPf\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Incoming Payment\",\"col\":3}},{\"id\":\"DySNdlysIW\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Outgoing Payment\",\"col\":3}},{\"id\":\"i0EtSjDAXq\",\"type\":\"chart\",\"data\":{\"chart_name\":\"Profit and Loss\",\"col\":12}},{\"id\":\"X78jcbq1u3\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"vikWSkNm6_\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Your Shortcuts</b></span>\",\"col\":12}},{\"id\":\"pMywM0nhlj\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Chart of Accounts\",\"col\":3}},{\"id\":\"_pRdD6kqUG\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Invoice\",\"col\":3}},{\"id\":\"G984SgVRJN\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Purchase Invoice\",\"col\":3}},{\"id\":\"1ArNvt9qhz\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Journal Entry\",\"col\":3}},{\"id\":\"F9f4I1viNr\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Payment Entry\",\"col\":3}},{\"id\":\"4IBBOIxfqW\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Accounts Receivable\",\"col\":3}},{\"id\":\"El2anpPaFY\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"General Ledger\",\"col\":3}},{\"id\":\"1nwcM9upJo\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Trial Balance\",\"col\":3}},{\"id\":\"OF9WOi1Ppc\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"id\":\"iAwpe-Chra\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Learn Accounting\",\"col\":3}},{\"id\":\"B7-uxs8tkU\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"tHb3yxthkR\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports &amp; Masters</b></span>\",\"col\":12}},{\"id\":\"DnNtsmxpty\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounting Masters\",\"col\":4}},{\"id\":\"nKKr6fjgjb\",\"type\":\"card\",\"data\":{\"card_name\":\"General Ledger\",\"col\":4}},{\"id\":\"xOHTyD8b5l\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounts Receivable\",\"col\":4}},{\"id\":\"_Cb7C8XdJJ\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounts Payable\",\"col\":4}},{\"id\":\"p7NY6MHe2Y\",\"type\":\"card\",\"data\":{\"card_name\":\"Financial Statements\",\"col\":4}},{\"id\":\"KlqilF5R_V\",\"type\":\"card\",\"data\":{\"card_name\":\"Taxes\",\"col\":4}},{\"id\":\"jTUy8LB0uw\",\"type\":\"card\",\"data\":{\"card_name\":\"Cost Center and Budgeting\",\"col\":4}},{\"id\":\"Wn2lhs7WLn\",\"type\":\"card\",\"data\":{\"card_name\":\"Multi Currency\",\"col\":4}},{\"id\":\"PAQMqqNkBM\",\"type\":\"card\",\"data\":{\"card_name\":\"Bank Statement\",\"col\":4}},{\"id\":\"Q_hBCnSeJY\",\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}},{\"id\":\"3AK1Zf0oew\",\"type\":\"card\",\"data\":{\"card_name\":\"Profitability\",\"col\":4}},{\"id\":\"kxhoaiqdLq\",\"type\":\"card\",\"data\":{\"card_name\":\"Opening and Closing\",\"col\":4}},{\"id\":\"q0MAlU2j_Z\",\"type\":\"card\",\"data\":{\"card_name\":\"Subscription Management\",\"col\":4}},{\"id\":\"ptm7T6Hwu-\",\"type\":\"card\",\"data\":{\"card_name\":\"Share Management\",\"col\":4}},{\"id\":\"OX7lZHbiTr\",\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}}]",
  "creation": "2020-03-02 15:41:59.515192",
  "custom_blocks": [],
  "docstatus": 0,
@@ -1061,11 +1061,28 @@
    "type": "Link"
   }
  ],
- "modified": "2023-07-04 14:32:15.842044",
+ "modified": "2023-08-10 17:41:14.059005",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Accounting",
- "number_cards": [],
+ "number_cards": [
+  {
+   "label": "Total Outgoing Bills",
+   "number_card_name": "Total Outgoing Bills"
+  },
+  {
+   "label": "Total Incoming Bills",
+   "number_card_name": "Total Incoming Bills"
+  },
+  {
+   "label": "Total Incoming Payment",
+   "number_card_name": "Total Incoming Payment"
+  },
+  {
+   "label": "Total Outgoing Payment",
+   "number_card_name": "Total Outgoing Payment"
+  }
+ ],
  "owner": "Administrator",
  "parent_page": "",
  "public": 1,
diff --git a/erpnext/assets/doctype/asset_category/asset_category.js b/erpnext/assets/doctype/asset_category/asset_category.js
index c702687..7dde14e 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.js
+++ b/erpnext/assets/doctype/asset_category/asset_category.js
@@ -33,6 +33,7 @@
 			var d  = locals[cdt][cdn];
 			return {
 				"filters": {
+					"account_type": "Depreciation",
 					"root_type": ["in", ["Expense", "Income"]],
 					"is_group": 0,
 					"company": d.company_name
diff --git a/erpnext/assets/doctype/asset_category/asset_category.py b/erpnext/assets/doctype/asset_category/asset_category.py
index 2e1def9..8d35141 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.py
+++ b/erpnext/assets/doctype/asset_category/asset_category.py
@@ -53,7 +53,7 @@
 		account_type_map = {
 			"fixed_asset_account": {"account_type": ["Fixed Asset"]},
 			"accumulated_depreciation_account": {"account_type": ["Accumulated Depreciation"]},
-			"depreciation_expense_account": {"root_type": ["Expense", "Income"]},
+			"depreciation_expense_account": {"account_type": ["Depreciation"]},
 			"capital_work_in_progress_account": {"account_type": ["Capital Work in Progress"]},
 		}
 		for d in self.accounts:
diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
index 94c77ea..bf62a8f 100644
--- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
+++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
@@ -7,13 +7,14 @@
 import frappe
 from frappe import _
 from frappe.query_builder.functions import IfNull, Sum
-from frappe.utils import cstr, flt, formatdate, getdate
+from frappe.utils import add_months, cstr, flt, formatdate, getdate, nowdate, today
 
 from erpnext.accounts.report.financial_statements import (
 	get_fiscal_year_data,
 	get_period_list,
 	validate_fiscal_year,
 )
+from erpnext.accounts.utils import get_fiscal_year
 from erpnext.assets.doctype.asset.asset import get_asset_value_after_depreciation
 
 
@@ -37,15 +38,26 @@
 
 	if filters.get("company"):
 		conditions["company"] = filters.company
+
 	if filters.filter_based_on == "Date Range":
+		if not filters.from_date and not filters.to_date:
+			filters.from_date = add_months(nowdate(), -12)
+			filters.to_date = nowdate()
+
 		conditions[date_field] = ["between", [filters.from_date, filters.to_date]]
-	if filters.filter_based_on == "Fiscal Year":
+	elif filters.filter_based_on == "Fiscal Year":
+		if not filters.from_fiscal_year and not filters.to_fiscal_year:
+			default_fiscal_year = get_fiscal_year(today())[0]
+			filters.from_fiscal_year = default_fiscal_year
+			filters.to_fiscal_year = default_fiscal_year
+
 		fiscal_year = get_fiscal_year_data(filters.from_fiscal_year, filters.to_fiscal_year)
 		validate_fiscal_year(fiscal_year, filters.from_fiscal_year, filters.to_fiscal_year)
 		filters.year_start_date = getdate(fiscal_year.year_start_date)
 		filters.year_end_date = getdate(fiscal_year.year_end_date)
 
 		conditions[date_field] = ["between", [filters.year_start_date, filters.year_end_date]]
+
 	if filters.get("only_existing_assets"):
 		conditions["is_existing_asset"] = filters.get("only_existing_assets")
 	if filters.get("asset_category"):
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
index e938577..56840c1 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
@@ -193,7 +193,7 @@
 				"supplier": data.get("supplier"),
 				"supplier_name": data.get("supplier_name"),
 				"update_password_link": f'<a href="{update_password_link}" class="btn btn-default btn-xs" target="_blank">{_("Set Password")}</a>',
-				"portal_link": f'<a href="{rfq_link}" class="btn btn-default btn-sm" target="_blank"> {_("Submit your Quotation")} </a>',
+				"portal_link": f'<a href="{rfq_link}" class="btn btn-default btn-xs" target="_blank"> {_("Submit your Quotation")} </a>',
 				"user_fullname": full_name,
 			}
 		)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index fbf97aa..340ec01 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -716,7 +716,9 @@
 
 	def validate_enabled_taxes_and_charges(self):
 		taxes_and_charges_doctype = self.meta.get_options("taxes_and_charges")
-		if frappe.get_cached_value(taxes_and_charges_doctype, self.taxes_and_charges, "disabled"):
+		if self.taxes_and_charges and frappe.get_cached_value(
+			taxes_and_charges_doctype, self.taxes_and_charges, "disabled"
+		):
 			frappe.throw(
 				_("{0} '{1}' is disabled").format(taxes_and_charges_doctype, self.taxes_and_charges)
 			)
@@ -803,8 +805,28 @@
 				gl_dict, account_currency, self.get("conversion_rate"), self.company_currency
 			)
 
+		# Update details in transaction currency
+		gl_dict.update(
+			{
+				"transaction_currency": self.get("currency") or self.company_currency,
+				"transaction_exchange_rate": self.get("conversion_rate", 1),
+				"debit_in_transaction_currency": self.get_value_in_transaction_currency(
+					account_currency, args, "debit"
+				),
+				"credit_in_transaction_currency": self.get_value_in_transaction_currency(
+					account_currency, args, "credit"
+				),
+			}
+		)
+
 		return gl_dict
 
+	def get_value_in_transaction_currency(self, account_currency, args, field):
+		if account_currency == self.get("currency"):
+			return args.get(field + "_in_account_currency")
+		else:
+			return flt(args.get(field, 0) / self.get("conversion_rate", 1))
+
 	def validate_qty_is_not_zero(self):
 		if self.doctype != "Purchase Receipt":
 			for item in self.items:
diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py
index a4bc4a9..73a248f 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -5,7 +5,7 @@
 import frappe
 from frappe import _
 from frappe.model.document import Document
-from frappe.utils import comma_or, flt, getdate, now, nowdate
+from frappe.utils import comma_or, flt, get_link_to_form, getdate, now, nowdate
 
 
 class OverAllowanceError(frappe.ValidationError):
@@ -233,8 +233,17 @@
 				if hasattr(d, "qty") and d.qty > 0 and self.get("is_return"):
 					frappe.throw(_("For an item {0}, quantity must be negative number").format(d.item_code))
 
-				if hasattr(d, "item_code") and hasattr(d, "rate") and d.rate < 0:
-					frappe.throw(_("For an item {0}, rate must be a positive number").format(d.item_code))
+				if not frappe.db.get_single_value("Selling Settings", "allow_negative_rates_for_items"):
+					if hasattr(d, "item_code") and hasattr(d, "rate") and flt(d.rate) < 0:
+						frappe.throw(
+							_(
+								"For item {0}, rate must be a positive number. To Allow negative rates, enable {1} in {2}"
+							).format(
+								frappe.bold(d.item_code),
+								frappe.bold(_("`Allow Negative rates for Items`")),
+								get_link_to_form("Selling Settings", "Selling Settings"),
+							),
+						)
 
 				if d.doctype == args["source_dt"] and d.get(args["join_field"]):
 					args["name"] = d.get(args["join_field"])
diff --git a/erpnext/e_commerce/web_template/hero_slider/hero_slider.html b/erpnext/e_commerce/web_template/hero_slider/hero_slider.html
index e560f4a..fe4fee3 100644
--- a/erpnext/e_commerce/web_template/hero_slider/hero_slider.html
+++ b/erpnext/e_commerce/web_template/hero_slider/hero_slider.html
@@ -1,7 +1,7 @@
 {%- macro slide(image, title, subtitle, action, label, index, align="Left", theme="Dark") -%}
 {%- set align_class = resolve_class({
 	'text-right': align == 'Right',
-	'text-centre': align == 'Centre',
+	'text-center': align == 'Centre',
 	'text-left': align == 'Left',
 }) -%}
 
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 44c68dc..7eaa146 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -70,6 +70,19 @@
 	"Department",
 ]
 
+demo_master_doctypes = [
+	"item_group",
+	"item",
+	"customer_group",
+	"supplier_group",
+	"customer",
+	"supplier",
+]
+demo_transaction_doctypes = [
+	"purchase_order",
+	"sales_order",
+]
+
 jinja = {
 	"methods": [
 		"erpnext.stock.serial_batch_bundle.get_serial_or_batch_nos",
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.json b/erpnext/manufacturing/doctype/work_order/work_order.json
index a236f2a..1996e19 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.json
+++ b/erpnext/manufacturing/doctype/work_order/work_order.json
@@ -404,6 +404,8 @@
    "read_only": 1
   },
   {
+   "fetch_from": "production_item.stock_uom",
+   "fetch_if_empty": 1,
    "fieldname": "stock_uom",
    "fieldtype": "Link",
    "label": "Stock UOM",
@@ -590,7 +592,7 @@
  "image_field": "image",
  "is_submittable": 1,
  "links": [],
- "modified": "2023-06-09 13:20:09.154362",
+ "modified": "2023-08-11 18:35:49.852069",
  "modified_by": "Administrator",
  "module": "Manufacturing",
  "name": "Work Order",
@@ -610,7 +612,6 @@
    "read": 1,
    "report": 1,
    "role": "Manufacturing User",
-   "set_user_permissions": 1,
    "share": 1,
    "submit": 1,
    "write": 1
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index d035ad6..a25c7c2 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -322,8 +322,6 @@
 execute:frappe.db.set_single_value("Accounts Settings", "merge_similar_account_heads", 0)
 erpnext.patches.v14_0.update_reference_type_in_journal_entry_accounts
 erpnext.patches.v14_0.update_subscription_details
-# below migration patches should always run last
-erpnext.patches.v14_0.migrate_gl_to_payment_ledger
 execute:frappe.delete_doc_if_exists("Report", "Tax Detail")
 erpnext.patches.v15_0.enable_all_leads
 erpnext.patches.v14_0.update_company_in_ldc
@@ -340,3 +338,6 @@
 execute:frappe.defaults.clear_default("fiscal_year")
 erpnext.patches.v15_0.remove_exotel_integration
 erpnext.patches.v14_0.single_to_multi_dunning
+execute:frappe.db.set_single_value('Selling Settings', 'allow_negative_rates_for_items', 0)
+# below migration patch should always run last
+erpnext.patches.v14_0.migrate_gl_to_payment_ledger
diff --git a/erpnext/projects/report/billing_summary.py b/erpnext/projects/report/billing_summary.py
index bc8f2af..ac1524a 100644
--- a/erpnext/projects/report/billing_summary.py
+++ b/erpnext/projects/report/billing_summary.py
@@ -98,9 +98,11 @@
 	record_filters = [
 		["start_date", "<=", filters.to_date],
 		["end_date", ">=", filters.from_date],
-		["docstatus", "=", 1],
 	]
-
+	if not filters.get("include_draft_timesheets"):
+		record_filters.append(["docstatus", "=", 1])
+	else:
+		record_filters.append(["docstatus", "!=", 2])
 	if "employee" in filters:
 		record_filters.append(["employee", "=", filters.employee])
 
diff --git a/erpnext/projects/report/employee_billing_summary/employee_billing_summary.js b/erpnext/projects/report/employee_billing_summary/employee_billing_summary.js
index 8566b1f..2c25465 100644
--- a/erpnext/projects/report/employee_billing_summary/employee_billing_summary.js
+++ b/erpnext/projects/report/employee_billing_summary/employee_billing_summary.js
@@ -25,5 +25,10 @@
 			default: frappe.datetime.add_days(frappe.datetime.month_start(), -1),
 			reqd: 1
 		},
+		{
+			fieldname:"include_draft_timesheets",
+			label: __("Include Timesheets in Draft Status"),
+			fieldtype: "Check",
+		},
 	]
 }
diff --git a/erpnext/projects/report/project_billing_summary/project_billing_summary.js b/erpnext/projects/report/project_billing_summary/project_billing_summary.js
index 0242036..fce0c68 100644
--- a/erpnext/projects/report/project_billing_summary/project_billing_summary.js
+++ b/erpnext/projects/report/project_billing_summary/project_billing_summary.js
@@ -25,5 +25,10 @@
 			default: frappe.datetime.add_days(frappe.datetime.month_start(),-1),
 			reqd: 1
 		},
+		{
+			fieldname:"include_draft_timesheets",
+			label: __("Include Timesheets in Draft Status"),
+			fieldtype: "Check",
+		},
 	]
 }
diff --git a/erpnext/public/build.json b/erpnext/public/build.json
deleted file mode 100644
index b9b48ab..0000000
--- a/erpnext/public/build.json
+++ /dev/null
@@ -1,68 +0,0 @@
-{
-	"css/erpnext.css": [
-		"public/less/erpnext.less",
-		"public/scss/call_popup.scss",
-		"public/scss/point-of-sale.scss"
-	],
-	"js/erpnext-web.min.js": [
-		"public/js/website_utils.js",
-		"public/js/shopping_cart.js",
-		"public/js/wishlist.js"
-	],
-	"css/erpnext-web.css": [
-		"public/scss/website.scss",
-		"public/scss/shopping_cart.scss"
-	],
-	"js/erpnext.min.js": [
-		"public/js/conf.js",
-		"public/js/utils.js",
-		"public/js/queries.js",
-		"public/js/sms_manager.js",
-		"public/js/utils/party.js",
-		"public/js/controllers/stock_controller.js",
-		"public/js/payment/payments.js",
-		"public/js/controllers/taxes_and_totals.js",
-		"public/js/controllers/transaction.js",
-		"public/js/templates/item_selector.html",
-		"public/js/utils/item_selector.js",
-		"public/js/help_links.js",
-		"public/js/templates/item_quick_entry.html",
-		"public/js/utils/customer_quick_entry.js",
-		"public/js/utils/supplier_quick_entry.js",
-		"public/js/education/student_button.html",
-		"public/js/education/assessment_result_tool.html",
-		"public/js/call_popup/call_popup.js",
-		"public/js/utils/dimension_tree_filter.js",
-		"public/js/telephony.js",
-		"public/js/templates/call_link.html",
-		"public/js/bulk_transaction_processing.js"
-	],
-	"js/item-dashboard.min.js": [
-		"stock/dashboard/item_dashboard.html",
-		"stock/dashboard/item_dashboard_list.html",
-		"stock/dashboard/item_dashboard.js",
-		"stock/page/warehouse_capacity_summary/warehouse_capacity_summary.html",
-		"stock/page/warehouse_capacity_summary/warehouse_capacity_summary_header.html"
-	],
-	"js/point-of-sale.min.js": [
-		"selling/page/point_of_sale/pos_item_selector.js",
-		"selling/page/point_of_sale/pos_item_cart.js",
-		"selling/page/point_of_sale/pos_item_details.js",
-		"selling/page/point_of_sale/pos_number_pad.js",
-		"selling/page/point_of_sale/pos_payment.js",
-		"selling/page/point_of_sale/pos_past_order_list.js",
-		"selling/page/point_of_sale/pos_past_order_summary.js",
-		"selling/page/point_of_sale/pos_controller.js"
-	],
-	"js/bank-reconciliation-tool.min.js": [
-		"public/js/bank_reconciliation_tool/data_table_manager.js",
-		"public/js/bank_reconciliation_tool/number_card.js",
-		"public/js/bank_reconciliation_tool/dialog_manager.js"
-	],
-	"js/e-commerce.min.js": [
-		"e_commerce/product_ui/views.js",
-		"e_commerce/product_ui/grid.js",
-		"e_commerce/product_ui/list.js",
-		"e_commerce/product_ui/search.js"
-	]
-}
diff --git a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js
index cbb64ca..52fa8ab 100644
--- a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js
+++ b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js
@@ -104,6 +104,9 @@
 				name: __("Document Name"),
 				editable: false,
 				width: 1,
+				format: (value, row) => {
+					return frappe.form.formatters.Link(value, {options: row[2].content});
+				},
 			},
 			{
 				name: __("Reference Date"),
@@ -132,7 +135,7 @@
 	format_row(row) {
 		return [
 			row[1], // Document Type
-			frappe.form.formatters.Link(row[2], {options: row[1]}), // Document Name
+			row[2], // Document Name
 			row[5] || row[8], // Reference Date
 			format_currency(row[3], row[9]), // Remaining
 			row[4], // Reference Number
diff --git a/erpnext/public/js/controllers/stock_controller.js b/erpnext/public/js/controllers/stock_controller.js
index 720423b..e9c409e 100644
--- a/erpnext/public/js/controllers/stock_controller.js
+++ b/erpnext/public/js/controllers/stock_controller.js
@@ -57,7 +57,8 @@
 					from_date: me.frm.doc.posting_date,
 					to_date: moment(me.frm.doc.modified).format('YYYY-MM-DD'),
 					company: me.frm.doc.company,
-					show_cancelled_entries: me.frm.doc.docstatus === 2
+					show_cancelled_entries: me.frm.doc.docstatus === 2,
+					ignore_prepared_report: true
 				};
 				frappe.set_route("query-report", "Stock Ledger");
 			}, __("View"));
@@ -75,7 +76,8 @@
 					to_date: moment(me.frm.doc.modified).format('YYYY-MM-DD'),
 					company: me.frm.doc.company,
 					group_by: "Group by Voucher (Consolidated)",
-					show_cancelled_entries: me.frm.doc.docstatus === 2
+					show_cancelled_entries: me.frm.doc.docstatus === 2,
+					ignore_prepared_report: true
 				};
 				frappe.set_route("query-report", "General Ledger");
 			}, __("View"));
diff --git a/erpnext/public/js/erpnext.bundle.js b/erpnext/public/js/erpnext.bundle.js
index d7bea7b..966a9e1 100644
--- a/erpnext/public/js/erpnext.bundle.js
+++ b/erpnext/public/js/erpnext.bundle.js
@@ -28,5 +28,6 @@
 import "./utils/landed_taxes_and_charges_common.js";
 import "./utils/sales_common.js";
 import "./controllers/buying.js";
+import "./utils/demo.js";
 
 // import { sum } from 'frappe/public/utils/util.js'
diff --git a/erpnext/public/js/setup_wizard.js b/erpnext/public/js/setup_wizard.js
index 934fd1f..ba200ef 100644
--- a/erpnext/public/js/setup_wizard.js
+++ b/erpnext/public/js/setup_wizard.js
@@ -40,6 +40,12 @@
 			{ fieldname: 'fy_start_date', label: __('Financial Year Begins On'), fieldtype: 'Date', reqd: 1 },
 			// end date should be hidden (auto calculated)
 			{ fieldname: 'fy_end_date', label: __('End Date'), fieldtype: 'Date', reqd: 1, hidden: 1 },
+			{ fieldtype: "Section Break" },
+			{
+				fieldname: 'setup_demo',
+				label: __('Generate Demo Data for Exploration'),
+				fieldtype: 'Check',
+				description: 'If checked, we will create demo data for you to explore the system. This demo data can be erased later.'},
 		],
 
 		onload: function (slide) {
diff --git a/erpnext/public/js/utils/demo.js b/erpnext/public/js/utils/demo.js
new file mode 100644
index 0000000..3ebc5ef
--- /dev/null
+++ b/erpnext/public/js/utils/demo.js
@@ -0,0 +1,91 @@
+$(document).on("toolbar_setup", function () {
+	if (frappe.boot.sysdefaults.demo_company) {
+		render_clear_demo_button();
+	}
+
+	// for first load after setup.
+	frappe.realtime.on("demo_data_complete", () => {
+		render_clear_demo_button();
+	});
+});
+
+function render_clear_demo_button() {
+	let wait_for_onboaring_tours = setInterval(() => {
+		if ($("#driver-page-overlay").length || $("#show-dialog").length) {
+			return;
+		}
+		setup_clear_demo_button();
+		clearInterval(wait_for_onboaring_tours);
+	}, 2000);
+}
+
+function setup_clear_demo_button() {
+	let message_string = __(
+		"Demo data is present on the system, erase data before starting real usage."
+	);
+	let $floatingBar = $(`
+		<div class="flex justify-content-center" style="width: 100%;">
+			<div class="flex justify-content-center flex-col shadow rounded p-2"
+					style="
+						background-color: #e0f2fe;
+						position: fixed;
+						bottom: 20px;
+						z-index: 1;">
+			<p style="margin: auto 0; padding-left: 10px; margin-right: 20px; font-size: 15px;">
+					${message_string}
+				</p>
+				<button id="clear-demo" type="button"
+					class="
+						px-4
+						py-2
+						border
+						border-transparent
+						text-white
+					"
+					style="
+						margin: auto 0;
+						height: fit-content;
+						background-color: #007bff;
+						border-radius: 5px;
+						margin-right: 10px
+					"
+				>
+					Clear Demo Data
+				</button>
+
+	 			<a type="button" id="dismiss-demo-banner" class="text-muted" style="align-self: center">
+					<svg class="icon" style="">
+						<use class="" href="#icon-close"></use>
+					</svg>
+				</a>
+			</div>
+		</div>
+	`);
+
+	$("footer").append($floatingBar);
+
+	$("#clear-demo").on("click", function () {
+		frappe.confirm(
+			__("Are you sure you want to clear all demo data?"),
+			() => {
+				frappe.call({
+					method: "erpnext.setup.demo.clear_demo_data",
+					freeze: true,
+					freeze_message: __("Clearing Demo Data..."),
+					callback: function (r) {
+						frappe.ui.toolbar.clear_cache();
+						frappe.show_alert({
+							message: __("Demo data cleared"),
+							indicator: "green",
+						});
+						$("footer").remove($floatingBar);
+					},
+				});
+			}
+		);
+	});
+
+	$("#dismiss-demo-banner").on("click", function () {
+		$floatingBar.remove();
+	});
+}
diff --git a/erpnext/public/scss/point-of-sale.scss b/erpnext/public/scss/point-of-sale.scss
index c9d001c..ba64b59 100644
--- a/erpnext/public/scss/point-of-sale.scss
+++ b/erpnext/public/scss/point-of-sale.scss
@@ -53,7 +53,7 @@
 
 	.seperator {
 		margin-left: var(--margin-sm);
-		margin-right: var(--margin-sm);
+		margin-right: var(--margin-md);
 		border-bottom: 1px solid var(--gray-300);
 	}
 
@@ -381,6 +381,7 @@
 						align-items: center;
 						padding: var(--padding-sm);
 						border-radius: var(--border-radius-md);
+						margin-right: var(--margin-sm);
 
 						&:hover {
 							background-color: var(--control-bg);
@@ -858,13 +859,10 @@
 
 			> .fields-section {
 				flex: 1;
-				position: absolute;
 				display: flex;
 				flex-direction: column;
 				width: 50%;
 				height: 100%;
-				top: 0;
-				left: 0;
 				padding-bottom: var(--margin-md);
 
 				.invoice-fields {
@@ -1152,3 +1150,62 @@
 		}
 	}
 }
+
+@media screen and (max-width: 620px) {
+	.point-of-sale-app {
+		grid-template-columns: repeat(1, minmax(0, 1fr));
+
+		> .items-selector {
+			grid-column: span 6 / span 1  !important;
+			> .items-container {
+			grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
+			}
+		}
+
+		> .item-details-container, .customer-cart-container {
+			grid-column: span 6 / span 1;
+		}
+
+		> .payment-container {
+			overflow: scroll;
+			> .fields-numpad-container {
+				flex-direction: column-reverse;
+				> .number-pad {
+					display: none;
+				}
+				> .fields-section {
+					width: 100%;
+				}
+			}
+		}
+
+		> .past-order-summary{
+			> .invoice-summary-wrapper {
+				width: 100%;
+			}
+		}
+
+		.numpad-totals {
+			> span {
+				padding: 0 5px;
+				font-size: var(--text-sm);
+			}
+		}
+
+		.col > * {
+			font-size: var(--text-sm) !important;
+		}
+
+		.control-input-wrapper {
+			padding-left: 0.15rem;
+		}
+
+		.pay-amount {
+			margin-left: 0.2rem;
+		}
+
+		.past-order-list {
+			grid-column: span 6 / span 1;
+		}
+	}
+}
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index ca669f6..cc141ff 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -108,18 +108,26 @@
 				and customer = %s",
 				(self.po_no, self.name, self.customer),
 			)
-			if (
-				so
-				and so[0][0]
-				and not cint(
+			if so and so[0][0]:
+				if cint(
 					frappe.db.get_single_value("Selling Settings", "allow_against_multiple_purchase_orders")
-				)
-			):
-				frappe.msgprint(
-					_("Warning: Sales Order {0} already exists against Customer's Purchase Order {1}").format(
-						so[0][0], self.po_no
+				):
+					frappe.msgprint(
+						_("Warning: Sales Order {0} already exists against Customer's Purchase Order {1}").format(
+							frappe.bold(so[0][0]), frappe.bold(self.po_no)
+						)
 					)
-				)
+				else:
+					frappe.throw(
+						_(
+							"Sales Order {0} already exists against Customer's Purchase Order {1}. To allow multiple Sales Orders, Enable {2} in {3}"
+						).format(
+							frappe.bold(so[0][0]),
+							frappe.bold(self.po_no),
+							frappe.bold(_("'Allow Multiple Sales Orders Against a Customer's Purchase Order'")),
+							get_link_to_form("Selling Settings", "Selling Settings"),
+						)
+					)
 
 	def validate_for_items(self):
 		for d in self.get("items"):
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index c85a4fb..954393f 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -2055,7 +2055,7 @@
 	so.company = args.company or "_Test Company"
 	so.customer = args.customer or "_Test Customer"
 	so.currency = args.currency or "INR"
-	so.po_no = args.po_no or "12345"
+	so.po_no = args.po_no or ""
 	if args.selling_price_list:
 		so.selling_price_list = args.selling_price_list
 
diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json
index 045227f..6855012 100644
--- a/erpnext/selling/doctype/selling_settings/selling_settings.json
+++ b/erpnext/selling/doctype/selling_settings/selling_settings.json
@@ -20,6 +20,7 @@
   "editable_price_list_rate",
   "validate_selling_price",
   "editable_bundle_item_rates",
+  "allow_negative_rates_for_items",
   "sales_transactions_settings_section",
   "so_required",
   "dn_required",
@@ -85,7 +86,7 @@
    "fieldname": "sales_update_frequency",
    "fieldtype": "Select",
    "label": "Sales Update Frequency in Company and Project",
-   "options": "Each Transaction\nDaily\nMonthly",
+   "options": "Monthly\nEach Transaction\nDaily",
    "reqd": 1
   },
   {
@@ -193,6 +194,12 @@
    "fieldname": "dont_reserve_sales_order_qty_on_sales_return",
    "fieldtype": "Check",
    "label": "Don't Reserve Sales Order Qty on Sales Return"
+  },
+  {
+   "default": "0",
+   "fieldname": "allow_negative_rates_for_items",
+   "fieldtype": "Check",
+   "label": "Allow Negative rates for Items"
   }
  ],
  "icon": "fa fa-cog",
@@ -200,7 +207,7 @@
  "index_web_pages_for_search": 1,
  "issingle": 1,
  "links": [],
- "modified": "2023-02-04 12:37:53.380857",
+ "modified": "2023-08-14 20:33:05.693667",
  "modified_by": "Administrator",
  "module": "Selling",
  "name": "Selling Settings",
@@ -229,4 +236,4 @@
  "sort_order": "DESC",
  "states": [],
  "track_changes": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js
index 720d142..db6255a 100644
--- a/erpnext/selling/page/point_of_sale/pos_controller.js
+++ b/erpnext/selling/page/point_of_sale/pos_controller.js
@@ -225,6 +225,7 @@
 		voucher.pos_opening_entry = this.pos_opening;
 		voucher.period_end_date = frappe.datetime.now_datetime();
 		voucher.posting_date = frappe.datetime.now_date();
+		voucher.posting_time = frappe.datetime.now_time();
 		frappe.set_route('Form', 'POS Closing Entry', voucher.name);
 	}
 
diff --git a/erpnext/selling/page/point_of_sale/pos_item_cart.js b/erpnext/selling/page/point_of_sale/pos_item_cart.js
index 46490c4..193048f 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_cart.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_cart.js
@@ -286,7 +286,7 @@
 			this.item_is_selected = false;
 			this.$cart_container.find('.cart-item-wrapper').css("background-color", "");
 		} else {
-			$cart_item.css("background-color", "var(--gray-50)");
+			$cart_item.css("background-color", "var(--control-bg)");
 			this.item_is_selected = true;
 			this.$cart_container.find('.cart-item-wrapper').not(item).css("background-color", "");
 		}
diff --git a/erpnext/setup/demo.py b/erpnext/setup/demo.py
new file mode 100644
index 0000000..926283f
--- /dev/null
+++ b/erpnext/setup/demo.py
@@ -0,0 +1,210 @@
+# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+import json
+import os
+from random import randint
+
+import frappe
+from frappe import _
+from frappe.utils import add_days, getdate
+
+from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
+from erpnext.accounts.utils import get_fiscal_year
+from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_invoice
+from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
+from erpnext.setup.setup_wizard.operations.install_fixtures import create_bank_account
+
+
+def setup_demo_data():
+	from frappe.utils.telemetry import capture
+
+	capture("demo_data_creation_started", "erpnext")
+	try:
+		company = create_demo_company()
+		process_masters()
+		make_transactions(company)
+		frappe.cache.delete_keys("bootinfo")
+		frappe.publish_realtime("demo_data_complete")
+	except Exception:
+		frappe.log_error("Failed to create demo data")
+		capture("demo_data_creation_failed", "erpnext", properties={"exception": frappe.get_traceback()})
+		raise
+	capture("demo_data_creation_completed", "erpnext")
+
+
+@frappe.whitelist()
+def clear_demo_data():
+	from frappe.utils.telemetry import capture
+
+	frappe.only_for("System Manager")
+
+	capture("demo_data_erased", "erpnext")
+	try:
+		company = frappe.db.get_single_value("Global Defaults", "demo_company")
+		create_transaction_deletion_record(company)
+		clear_masters()
+		delete_company(company)
+		default_company = frappe.db.get_single_value("Global Defaults", "default_company")
+		frappe.db.set_default("company", default_company)
+	except Exception:
+		frappe.db.rollback()
+		frappe.log_error("Failed to erase demo data")
+		frappe.throw(
+			_("Failed to erase demo data, please delete the demo company manually."),
+			title=_("Could Not Delete Demo Data"),
+		)
+
+
+def create_demo_company():
+	company = frappe.db.get_all("Company")[0].name
+	company_doc = frappe.get_doc("Company", company)
+
+	# Make a dummy company
+	new_company = frappe.new_doc("Company")
+	new_company.company_name = company_doc.company_name + " (Demo)"
+	new_company.abbr = company_doc.abbr + "D"
+	new_company.enable_perpetual_inventory = 1
+	new_company.default_currency = company_doc.default_currency
+	new_company.country = company_doc.country
+	new_company.chart_of_accounts_based_on = "Standard Template"
+	new_company.chart_of_accounts = company_doc.chart_of_accounts
+	new_company.insert()
+
+	# Set Demo Company as default to
+	frappe.db.set_single_value("Global Defaults", "demo_company", new_company.name)
+	frappe.db.set_default("company", new_company.name)
+
+	bank_account = create_bank_account({"company_name": new_company.name})
+	frappe.db.set_value("Company", new_company.name, "default_bank_account", bank_account.name)
+
+	return new_company.name
+
+
+def process_masters():
+	for doctype in frappe.get_hooks("demo_master_doctypes"):
+		data = read_data_file_using_hooks(doctype)
+		if data:
+			for item in json.loads(data):
+				create_demo_record(item)
+
+
+def create_demo_record(doctype):
+	frappe.get_doc(doctype).insert(ignore_permissions=True)
+
+
+def make_transactions(company):
+	frappe.db.set_single_value("Stock Settings", "allow_negative_stock", 1)
+	start_date = get_fiscal_year(date=getdate())[1]
+
+	for doctype in frappe.get_hooks("demo_transaction_doctypes"):
+		data = read_data_file_using_hooks(doctype)
+		if data:
+			for item in json.loads(data):
+				create_transaction(item, company, start_date)
+
+	convert_order_to_invoices()
+	frappe.db.set_single_value("Stock Settings", "allow_negative_stock", 0)
+
+
+def create_transaction(doctype, company, start_date):
+	document_type = doctype.get("doctype")
+	warehouse = get_warehouse(company)
+
+	if document_type == "Purchase Order":
+		posting_date = get_random_date(start_date, 1, 30)
+	else:
+		posting_date = get_random_date(start_date, 31, 364)
+
+	doctype.update(
+		{
+			"company": company,
+			"set_posting_time": 1,
+			"transaction_date": posting_date,
+			"schedule_date": posting_date,
+			"delivery_date": posting_date,
+			"set_warehouse": warehouse,
+		}
+	)
+
+	doc = frappe.get_doc(doctype)
+	doc.save(ignore_permissions=True)
+	doc.submit()
+
+
+def convert_order_to_invoices():
+	for document in ["Purchase Order", "Sales Order"]:
+		# Keep some orders intentionally unbilled/unpaid
+		for i, order in enumerate(
+			frappe.db.get_all(
+				document, filters={"docstatus": 1}, fields=["name", "transaction_date"], limit=6
+			)
+		):
+
+			if document == "Purchase Order":
+				invoice = make_purchase_invoice(order.name)
+			elif document == "Sales Order":
+				invoice = make_sales_invoice(order.name)
+
+			invoice.set_posting_time = 1
+			invoice.posting_date = order.transaction_date
+			invoice.due_date = order.transaction_date
+			invoice.update_stock = 1
+			invoice.submit()
+
+			if i % 2 != 0:
+				payment = get_payment_entry(invoice.doctype, invoice.name)
+				payment.reference_no = invoice.name
+				payment.submit()
+
+
+def get_random_date(start_date, start_range, end_range):
+	return add_days(start_date, randint(start_range, end_range))
+
+
+def create_transaction_deletion_record(company):
+	transaction_deletion_record = frappe.new_doc("Transaction Deletion Record")
+	transaction_deletion_record.company = company
+	transaction_deletion_record.save(ignore_permissions=True)
+	transaction_deletion_record.submit()
+
+
+def clear_masters():
+	for doctype in frappe.get_hooks("demo_master_doctypes")[::-1]:
+		data = read_data_file_using_hooks(doctype)
+		if data:
+			for item in json.loads(data):
+				clear_demo_record(item)
+
+
+def clear_demo_record(document):
+	document_type = document.get("doctype")
+	del document["doctype"]
+
+	valid_columns = frappe.get_meta(document_type).get_valid_columns()
+
+	filters = document
+	for key in list(filters):
+		if key not in valid_columns:
+			filters.pop(key, None)
+
+	doc = frappe.get_doc(document_type, filters)
+	doc.delete(ignore_permissions=True)
+
+
+def delete_company(company):
+	frappe.db.set_single_value("Global Defaults", "demo_company", "")
+	frappe.delete_doc("Company", company, ignore_permissions=True)
+
+
+def read_data_file_using_hooks(doctype):
+	path = os.path.join(os.path.dirname(__file__), "demo_data")
+	with open(os.path.join(path, doctype + ".json"), "r") as f:
+		data = f.read()
+
+	return data
+
+
+def get_warehouse(company):
+	warehouses = frappe.db.get_all("Warehouse", {"company": company, "is_group": 0})
+	return warehouses[randint(0, 3)].name
diff --git a/erpnext/setup/demo_data/customer.json b/erpnext/setup/demo_data/customer.json
new file mode 100644
index 0000000..1b47906
--- /dev/null
+++ b/erpnext/setup/demo_data/customer.json
@@ -0,0 +1,20 @@
+[
+    {
+        "doctype": "Customer",
+        "customer_group": "Demo Customer Group",
+        "territory": "All Territories",
+        "customer_name": "Grant Plastics Ltd."
+    },
+    {
+        "doctype": "Customer",
+        "customer_group": "Demo Customer Group",
+        "territory": "All Territories",
+        "customer_name": "West View Software Ltd."
+    },
+    {
+        "doctype": "Customer",
+        "customer_group": "Demo Customer Group",
+        "territory": "All Territories",
+        "customer_name": "Palmer Productions Ltd."
+    }
+]
\ No newline at end of file
diff --git a/erpnext/setup/demo_data/customer_group.json b/erpnext/setup/demo_data/customer_group.json
new file mode 100644
index 0000000..7543335
--- /dev/null
+++ b/erpnext/setup/demo_data/customer_group.json
@@ -0,0 +1,6 @@
+[
+    {
+        "doctype": "Customer Group",
+        "customer_group_name": "Demo Customer Group"
+    }
+]
\ No newline at end of file
diff --git a/erpnext/setup/demo_data/item.json b/erpnext/setup/demo_data/item.json
new file mode 100644
index 0000000..330e114
--- /dev/null
+++ b/erpnext/setup/demo_data/item.json
@@ -0,0 +1,82 @@
+[
+    {
+        "doctype": "Item",
+        "item_group": "Demo Item Group",
+        "item_code": "SKU001",
+        "item_name": "T-shirt",
+        "gst_hsn_code": "999512",
+        "image": "https://images.pexels.com/photos/1484808/pexels-photo-1484808.jpeg"
+    },
+    {
+        "doctype": "Item",
+        "item_group": "Demo Item Group",
+        "item_code": "SKU002",
+        "item_name": "Laptop",
+        "gst_hsn_code": "999512",
+        "image": "https://images.pexels.com/photos/3999538/pexels-photo-3999538.jpeg"
+    },
+    {
+        "doctype": "Item",
+        "item_group": "Demo Item Group",
+        "item_code": "SKU003",
+        "item_name": "Book",
+        "gst_hsn_code": "999512",
+        "image": "https://images.pexels.com/photos/2422178/pexels-photo-2422178.jpeg"
+    },
+    {
+        "doctype": "Item",
+        "item_group": "Demo Item Group",
+        "item_code": "SKU004",
+        "item_name": "Smartphone",
+        "gst_hsn_code": "999512",
+        "image": "https://images.pexels.com/photos/1647976/pexels-photo-1647976.jpeg"
+    },
+    {
+        "doctype": "Item",
+        "item_group": "Demo Item Group",
+        "item_code": "SKU005",
+        "item_name": "Sneakers",
+        "gst_hsn_code": "999512",
+        "image": "https://images.pexels.com/photos/1598505/pexels-photo-1598505.jpeg"
+    },
+    {
+        "doctype": "Item",
+        "item_group": "Demo Item Group",
+        "item_code": "SKU006",
+        "item_name": "Coffee Mug",
+        "gst_hsn_code": "999512",
+        "image": "https://images.pexels.com/photos/585753/pexels-photo-585753.jpeg"
+    },
+    {
+        "doctype": "Item",
+        "item_group": "Demo Item Group",
+        "item_code": "SKU007",
+        "item_name": "Television",
+        "gst_hsn_code": "999512",
+        "image": "https://images.pexels.com/photos/8059376/pexels-photo-8059376.jpeg"
+    },
+    {
+        "doctype": "Item",
+        "item_group": "Demo Item Group",
+        "item_code": "SKU008",
+        "item_name": "Backpack",
+        "gst_hsn_code": "999512",
+        "image": "https://images.pexels.com/photos/3731256/pexels-photo-3731256.jpeg"
+    },
+    {
+        "doctype": "Item",
+        "item_group": "Demo Item Group",
+        "item_code": "SKU009",
+        "item_name": "Headphones",
+        "gst_hsn_code": "999512",
+        "image": "https://images.pexels.com/photos/3587478/pexels-photo-3587478.jpeg"
+    },
+    {
+        "doctype": "Item",
+        "item_group": "Demo Item Group",
+        "item_code": "SKU010",
+        "item_name": "Camera",
+        "gst_hsn_code": "999512",
+        "image": "https://images.pexels.com/photos/51383/photo-camera-subject-photographer-51383.jpeg"
+    }
+]
diff --git a/erpnext/setup/demo_data/item_group.json b/erpnext/setup/demo_data/item_group.json
new file mode 100644
index 0000000..f96944d
--- /dev/null
+++ b/erpnext/setup/demo_data/item_group.json
@@ -0,0 +1,6 @@
+[
+    {
+        "doctype": "Item Group",
+        "item_group_name": "Demo Item Group"
+    }
+]
diff --git a/erpnext/setup/demo_data/journal_entry.json b/erpnext/setup/demo_data/journal_entry.json
new file mode 100644
index 0000000..b751c7c
--- /dev/null
+++ b/erpnext/setup/demo_data/journal_entry.json
@@ -0,0 +1,25 @@
+[
+    {
+        "cheque_date": "2023-03-14",
+        "cheque_no": "33",
+        "doctype": "Journal Entry",
+        "accounts": [
+         {
+          "party_type": "Customer",
+          "party": "ABC Enterprises",
+          "credit_in_account_currency": 40000.0,
+          "debit_in_account_currency": 0.0,
+          "doctype": "Journal Entry Account",
+          "parentfield": "accounts",
+         },
+         {
+          "credit_in_account_currency": 0.0,
+          "debit_in_account_currency": 40000.0,
+          "doctype": "Journal Entry Account",
+          "parentfield": "accounts",
+         }
+        ],
+        "user_remark": "test",
+        "voucher_type": "Bank Entry"
+    }
+]
\ No newline at end of file
diff --git a/erpnext/setup/demo_data/payment_entry.json b/erpnext/setup/demo_data/payment_entry.json
new file mode 100644
index 0000000..c0767c3
--- /dev/null
+++ b/erpnext/setup/demo_data/payment_entry.json
@@ -0,0 +1,57 @@
+[
+    {
+        "doctype": "Payment Entry",
+        "payment_type": "Receive",
+        "party_type": "Customer",
+        "party": "ABC Enterprises",
+        "paid_amount": 67000,
+        "received_amount": 67000,
+        "reference_no": "#ref0001",
+        "source_exchange_rate": 1,
+        "target_exchange_rate": 1
+    },
+    {
+        "doctype": "Payment Entry",
+        "payment_type": "Receive",
+        "party_type": "Customer",
+        "party": "XYZ Corporation",
+        "paid_amount": 500000,
+        "received_amount": 500000,
+        "reference_no": "#ref0001",
+        "source_exchange_rate": 1,
+        "target_exchange_rate": 1
+    },
+    {
+        "doctype": "Payment Entry",
+        "payment_type": "Receive",
+        "party_type": "Customer",
+        "party": "KJPR Pvt. Ltd.",
+        "paid_amount": 300000,
+        "received_amount": 30000,
+        "reference_no": "#ref0001",
+        "source_exchange_rate": 1,
+        "target_exchange_rate": 1
+    },
+    {
+        "doctype": "Payment Entry",
+        "payment_type": "Pay",
+        "party_type": "Supplier",
+        "party": "DQ Industries",
+        "paid_amount": 85000,
+        "received_amount": 85000,
+        "reference_no": "#ref0005",
+        "source_exchange_rate": 1,
+        "target_exchange_rate": 1
+    },
+    {
+        "doctype": "Payment Entry",
+        "payment_type": "Pay",
+        "party_type": "Supplier",
+        "party": "KC Corp.",
+        "paid_amount": 100000,
+        "received_amount": 100000,
+        "reference_no": "#ref0006",
+        "source_exchange_rate": 1,
+        "target_exchange_rate": 1
+    }
+]
\ No newline at end of file
diff --git a/erpnext/setup/demo_data/purchase_order.json b/erpnext/setup/demo_data/purchase_order.json
new file mode 100644
index 0000000..318a865
--- /dev/null
+++ b/erpnext/setup/demo_data/purchase_order.json
@@ -0,0 +1,172 @@
+[
+    {
+        "conversion_rate": 1.0,
+        "supplier": "Zuckerman Security Ltd.",
+        "doctype": "Purchase Order",
+        "update_stock": 1,
+        "disable_rounded_total": 1,
+        "items": [
+            {
+                "doctype": "Purchase Order Item",
+                "item_code": "SKU001",
+                "parentfield": "items",
+                "qty": 100.0,
+                "rate": 400.0,
+                "conversion_factor": 1
+            }
+        ]
+    },
+    {
+        "conversion_rate": 1.0,
+        "supplier": "MA Inc.",
+        "doctype": "Purchase Order",
+        "update_stock": 1,
+        "disable_rounded_total": 1,
+        "items": [
+            {
+                "doctype": "Purchase Order Item",
+                "item_code": "SKU002",
+                "parentfield": "items",
+                "qty": 50.0,
+                "rate": 300.0,
+                "conversion_factor": 1
+            }
+        ]
+    },
+    {
+        "conversion_rate": 1.0,
+        "supplier": "Summit Traders Ltd.",
+        "doctype": "Purchase Order",
+        "update_stock": 1,
+        "disable_rounded_total": 1,
+        "items": [
+            {
+                "doctype": "Purchase Order Item",
+                "item_code": "SKU003",
+                "parentfield": "items",
+                "qty": 200.0,
+                "rate": 523.0,
+                "conversion_factor": 1
+            }
+        ]
+    },
+    {
+        "conversion_rate": 1.0,
+        "supplier": "Zuckerman Security Ltd.",
+        "doctype": "Purchase Order",
+        "update_stock": 1,
+        "disable_rounded_total": 1,
+        "items": [
+            {
+                "doctype": "Purchase Order Item",
+                "item_code": "SKU004",
+                "parentfield": "items",
+                "qty": 60.0,
+                "rate": 725.0,
+                "conversion_factor": 1
+            }
+        ]
+    },
+    {
+        "conversion_rate": 1.0,
+        "supplier": "MA Inc.",
+        "doctype": "Purchase Order",
+        "update_stock": 1,
+        "disable_rounded_total": 1,
+        "items": [
+            {
+                "doctype": "Purchase Order Item",
+                "item_code": "SKU005",
+                "parentfield": "items",
+                "qty": 182.0,
+                "rate": 222.0,
+                "conversion_factor": 1
+            }
+        ]
+    },
+    {
+        "conversion_rate": 1.0,
+        "supplier": "Summit Traders Ltd.",
+        "doctype": "Purchase Order",
+        "update_stock": 1,
+        "disable_rounded_total": 1,
+        "items": [
+            {
+                "doctype": "Purchase Order Item",
+                "item_code": "SKU006",
+                "parentfield": "items",
+                "qty": 250.0,
+                "rate": 420.0,
+                "conversion_factor": 1
+            }
+        ]
+    },
+    {
+        "conversion_rate": 1.0,
+        "supplier": "Zuckerman Security Ltd.",
+        "doctype": "Purchase Order",
+        "update_stock": 1,
+        "disable_rounded_total": 1,
+        "items": [
+            {
+                "doctype": "Purchase Order Item",
+                "item_code": "SKU007",
+                "parentfield": "items",
+                "qty": 190.0,
+                "rate": 375.0,
+                "conversion_factor": 1
+            }
+        ]
+    },
+    {
+        "conversion_rate": 1.0,
+        "supplier": "MA Inc.",
+        "doctype": "Purchase Order",
+        "update_stock": 1,
+        "disable_rounded_total": 1,
+        "items": [
+            {
+                "doctype": "Purchase Order Item",
+                "item_code": "SKU008",
+                "parentfield": "items",
+                "qty": 121.0,
+                "rate": 333.0,
+                "conversion_factor": 1
+            }
+        ]
+    },
+    {
+        "conversion_rate": 1.0,
+        "supplier": "Summit Traders Ltd.",
+        "doctype": "Purchase Order",
+        "update_stock": 1,
+        "disable_rounded_total": 1,
+        "items": [
+            {
+                "doctype": "Purchase Order Item",
+                "item_code": "SKU009",
+                "parentfield": "items",
+                "qty": 76.0,
+                "rate": 700.0,
+                "conversion_factor": 1
+            }
+        ]
+    },
+    {
+        "conversion_rate": 1.0,
+        "supplier": "Zuckerman Security Ltd.",
+        "doctype": "Purchase Order",
+        "update_stock": 1,
+        "disable_rounded_total": 1,
+        "items": [
+            {
+                "doctype": "Purchase Order Item",
+                "item_code": "SKU010",
+                "parentfield": "items",
+                "qty": 78.0,
+                "rate": 500.0,
+                "conversion_factor": 1
+            }
+        ]
+    }
+]
\ No newline at end of file
diff --git a/erpnext/setup/demo_data/sales_order.json b/erpnext/setup/demo_data/sales_order.json
new file mode 100644
index 0000000..29bffc3
--- /dev/null
+++ b/erpnext/setup/demo_data/sales_order.json
@@ -0,0 +1,127 @@
+[
+    {
+        "conversion_rate": 1.0,
+        "customer": "Grant Plastics Ltd.",
+        "doctype": "Sales Order",
+        "update_stock": 1,
+        "disable_rounded_total": 1,
+        "items": [
+            {
+                "doctype": "Sales Order Item",
+                "item_code": "SKU004",
+                "parentfield": "items",
+                "qty": 20.0,
+                "rate": 1000.0,
+                "conversion_factor": 1
+            }
+        ]
+    },
+    {
+        "conversion_rate": 1.0,
+        "customer": "West View Software Ltd.",
+        "doctype": "Sales Order",
+        "update_stock": 1,
+        "disable_rounded_total": 1,
+        "items": [
+            {
+                "doctype": "Sales Order Item",
+                "item_code": "SKU001",
+                "parentfield": "items",
+                "qty": 25.0,
+                "rate": 800.0,
+                "conversion_factor": 1
+            },
+            {
+                "doctype": "Sales Order Item",
+                "item_code": "SKU002",
+                "parentfield": "items",
+                "qty": 15.0,
+                "rate": 800.0,
+                "conversion_factor": 1
+            }
+        ]
+    },
+    {
+        "conversion_rate": 1.0,
+        "customer": "West View Software Ltd.",
+        "doctype": "Sales Order",
+        "update_stock": 1,
+        "disable_rounded_total": 1,
+        "items": [
+            {
+                "doctype": "Sales Order Item",
+                "item_code": "SKU003",
+                "parentfield": "items",
+                "qty": 100,
+                "rate": 500.0,
+                "conversion_factor": 1
+            },
+            {
+                "doctype": "Sales Order Item",
+                "item_code": "SKU006",
+                "parentfield": "items",
+                "qty": 100,
+                "rate": 890.0,
+                "conversion_factor": 1
+            },
+            {
+                "doctype": "Sales Order Item",
+                "item_code": "SKU007",
+                "parentfield": "items",
+                "qty": 100,
+                "rate": 900.0,
+                "conversion_factor": 1
+            }
+        ]
+    },
+    {
+        "conversion_rate": 1.0,
+        "customer": "Palmer Productions Ltd.",
+        "doctype": "Sales Order",
+        "update_stock": 1,
+        "disable_rounded_total": 1,
+        "items": [
+            {
+                "doctype": "Sales Order Item",
+                "item_code": "SKU005",
+                "parentfield": "items",
+                "qty": 150.0,
+                "rate": 100.0,
+                "conversion_factor": 1
+            }
+        ]
+    },
+    {
+        "conversion_rate": 1.0,
+        "customer": "Grant Plastics Ltd.",
+        "doctype": "Sales Order",
+        "update_stock": 1,
+        "disable_rounded_total": 1,
+        "items": [
+            {
+                "doctype": "Sales Order Item",
+                "item_code": "SKU008",
+                "parentfield": "items",
+                "qty": 20.0,
+                "rate": 500.0,
+                "conversion_factor": 1
+            },
+            {
+                "doctype": "Sales Order Item",
+                "item_code": "SKU009",
+                "parentfield": "items",
+                "qty": 40.0,
+                "rate": 300.0,
+                "conversion_factor": 1
+            },
+            {
+                "doctype": "Sales Order Item",
+                "item_code": "SKU010",
+                "parentfield": "items",
+                "qty": 50.0,
+                "rate": 900.0,
+                "conversion_factor": 1
+            }
+        ]
+    }
+]
\ No newline at end of file
diff --git a/erpnext/setup/demo_data/supplier.json b/erpnext/setup/demo_data/supplier.json
new file mode 100644
index 0000000..01a4e89
--- /dev/null
+++ b/erpnext/setup/demo_data/supplier.json
@@ -0,0 +1,17 @@
+[
+    {
+        "doctype": "Supplier",
+        "supplier_group": "Demo Supplier Group",
+        "supplier_name": "Zuckerman Security Ltd."
+    },
+    {
+        "doctype": "Supplier",
+        "supplier_group": "Demo Supplier Group",
+        "supplier_name": "MA Inc."
+    },
+    {
+        "doctype": "Supplier",
+        "supplier_group": "Demo Supplier Group",
+        "supplier_name": "Summit Traders Ltd."
+    }
+]
\ No newline at end of file
diff --git a/erpnext/setup/demo_data/supplier_group.json b/erpnext/setup/demo_data/supplier_group.json
new file mode 100644
index 0000000..17070bf
--- /dev/null
+++ b/erpnext/setup/demo_data/supplier_group.json
@@ -0,0 +1,6 @@
+[
+    {
+        "doctype": "Supplier Group",
+        "supplier_group_name": "Demo Supplier Group"
+    }
+]
\ No newline at end of file
diff --git a/erpnext/setup/doctype/company/test_company.py b/erpnext/setup/doctype/company/test_company.py
index fd2fe30..babd7dd 100644
--- a/erpnext/setup/doctype/company/test_company.py
+++ b/erpnext/setup/doctype/company/test_company.py
@@ -195,6 +195,22 @@
 		child_company.save()
 		self.test_basic_tree()
 
+	def test_demo_data(self):
+		from erpnext.setup.demo import clear_demo_data, setup_demo_data
+
+		setup_demo_data()
+		company_name = frappe.db.get_value("Company", {"name": ("like", "%(Demo)")})
+		self.assertTrue(company_name)
+
+		for transaction in frappe.get_hooks("demo_transaction_doctypes"):
+			self.assertTrue(frappe.db.exists(frappe.unscrub(transaction), {"company": company_name}))
+
+		clear_demo_data()
+		company_name = frappe.db.get_value("Company", {"name": ("like", "%(Demo)")})
+		self.assertFalse(company_name)
+		for transaction in frappe.get_hooks("demo_transaction_doctypes"):
+			self.assertFalse(frappe.db.exists(frappe.unscrub(transaction), {"company": company_name}))
+
 
 def create_company_communication(doctype, docname):
 	comm = frappe.get_doc(
diff --git a/erpnext/setup/doctype/global_defaults/global_defaults.json b/erpnext/setup/doctype/global_defaults/global_defaults.json
index 823d2ba..bd80e1d 100644
--- a/erpnext/setup/doctype/global_defaults/global_defaults.json
+++ b/erpnext/setup/doctype/global_defaults/global_defaults.json
@@ -12,7 +12,8 @@
   "default_currency",
   "hide_currency_symbol",
   "disable_rounded_total",
-  "disable_in_words"
+  "disable_in_words",
+  "demo_company"
  ],
  "fields": [
   {
@@ -71,6 +72,14 @@
    "fieldtype": "Check",
    "in_list_view": 1,
    "label": "Disable In Words"
+  },
+  {
+   "fieldname": "demo_company",
+   "fieldtype": "Link",
+   "hidden": 1,
+   "label": "Demo Company",
+   "options": "Company",
+   "read_only": 1
   }
  ],
  "icon": "fa fa-cog",
diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py
index 535c87d..ae6881b 100644
--- a/erpnext/setup/setup_wizard/operations/install_fixtures.py
+++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py
@@ -490,7 +490,7 @@
 
 def create_bank_account(args):
 	if not args.get("bank_account"):
-		return
+		args["bank_account"] = _("Bank Account")
 
 	company_name = args.get("company_name")
 	bank_account_group = frappe.db.get_value(
diff --git a/erpnext/setup/setup_wizard/setup_wizard.py b/erpnext/setup/setup_wizard/setup_wizard.py
index 65b268e..2da107e 100644
--- a/erpnext/setup/setup_wizard/setup_wizard.py
+++ b/erpnext/setup/setup_wizard/setup_wizard.py
@@ -5,7 +5,8 @@
 import frappe
 from frappe import _
 
-from .operations import install_fixtures as fixtures
+from erpnext.setup.demo import setup_demo_data
+from erpnext.setup.setup_wizard.operations import install_fixtures as fixtures
 
 
 def get_setup_stages(args=None):
@@ -37,6 +38,11 @@
 				],
 			},
 			{
+				"status": _("Setting up demo data"),
+				"fail_msg": _("Failed to setup demo data"),
+				"tasks": [{"fn": setup_demo, "args": args, "fail_msg": _("Failed to setup demo data")}],
+			},
+			{
 				"status": _("Wrapping up"),
 				"fail_msg": _("Failed to login"),
 				"tasks": [{"fn": fin, "args": args, "fail_msg": _("Failed to login")}],
@@ -63,6 +69,11 @@
 	login_as_first_user(args)
 
 
+def setup_demo(args):
+	if args.get("setup_demo"):
+		frappe.enqueue(setup_demo_data, enqueue_after_commit=True, at_front=True)
+
+
 def login_as_first_user(args):
 	if args.get("email") and hasattr(frappe.local, "login_manager"):
 		frappe.local.login_manager.login_as(args.get("email"))
diff --git a/erpnext/startup/boot.py b/erpnext/startup/boot.py
index db1cc49..bdbf8b4 100644
--- a/erpnext/startup/boot.py
+++ b/erpnext/startup/boot.py
@@ -61,6 +61,8 @@
 		)
 		bootinfo.party_account_types = frappe._dict(party_account_types)
 
+		bootinfo.sysdefaults.demo_company = frappe.db.get_single_value("Global Defaults", "demo_company")
+
 
 def update_page_info(bootinfo):
 	bootinfo.page_info.update(
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index 0ef3027..48b8ab7 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -703,7 +703,7 @@
 
 	def test_dn_billing_status_case1(self):
 		# SO -> DN -> SI
-		so = make_sales_order()
+		so = make_sales_order(po_no="12345")
 		dn = create_dn_against_so(so.name, delivered_qty=2)
 
 		self.assertEqual(dn.status, "To Bill")
@@ -730,7 +730,7 @@
 			make_sales_invoice,
 		)
 
-		so = make_sales_order()
+		so = make_sales_order(po_no="12345")
 
 		si = make_sales_invoice(so.name)
 		si.get("items")[0].qty = 5
@@ -774,7 +774,7 @@
 
 		frappe.db.set_single_value("Stock Settings", "allow_negative_stock", 1)
 
-		so = make_sales_order()
+		so = make_sales_order(po_no="12345")
 
 		dn1 = make_delivery_note(so.name)
 		dn1.get("items")[0].qty = 2
@@ -820,7 +820,7 @@
 		from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_delivery_note
 		from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
 
-		so = make_sales_order()
+		so = make_sales_order(po_no="12345")
 
 		si = make_sales_invoice(so.name)
 		si.submit()
@@ -1227,6 +1227,7 @@
 		self.assertEqual(get_reserved_qty(item, warehouse), 0 if dont_reserve_qty else qty_to_reserve)
 
 	def tearDown(self):
+		frappe.db.rollback()
 		frappe.db.set_single_value("Selling Settings", "dont_reserve_sales_order_qty_on_sales_return", 0)
 
 
diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.json b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.json
index 15bd2f0..d46b07a 100644
--- a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.json
+++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.json
@@ -115,7 +115,8 @@
    "fieldtype": "Dynamic Link",
    "label": "Voucher No",
    "no_copy": 1,
-   "options": "voucher_type"
+   "options": "voucher_type",
+   "search_index": 1
   },
   {
    "default": "0",
@@ -229,7 +230,8 @@
    "fieldtype": "Data",
    "label": "Voucher Detail No",
    "no_copy": 1,
-   "read_only": 1
+   "read_only": 1,
+   "search_index": 1
   },
   {
    "allow_bulk_edit": 1,
@@ -248,7 +250,7 @@
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2023-07-26 12:56:03.072224",
+ "modified": "2023-07-28 12:56:03.072224",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Serial and Batch Bundle",
diff --git a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py
index 43bd7ac..1f90c5b 100644
--- a/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py
+++ b/erpnext/stock/doctype/serial_and_batch_bundle/serial_and_batch_bundle.py
@@ -3,7 +3,7 @@
 
 import collections
 import csv
-from collections import defaultdict
+from collections import Counter, defaultdict
 from typing import Dict, List
 
 import frappe
@@ -1197,6 +1197,7 @@
 		filters=[
 			["POS Invoice", "consolidated_invoice", "is", "not set"],
 			["POS Invoice", "docstatus", "=", 1],
+			["POS Invoice", "is_return", "=", 0],
 			["POS Invoice Item", "item_code", "=", kwargs.item_code],
 			["POS Invoice", "name", "!=", kwargs.ignore_voucher_no],
 		],
@@ -1214,7 +1215,6 @@
 	for d in get_serial_batch_ledgers(kwargs.item_code, docstatus=1, name=ids):
 		ignore_serial_nos.append(d.serial_no)
 
-	# Will be deprecated in v16
 	returned_serial_nos = []
 	for pos_invoice in pos_invoices:
 		if pos_invoice.serial_no:
@@ -1242,8 +1242,13 @@
 				child_doc, parent_doc, ignore_voucher_detail_no=kwargs.get("ignore_voucher_detail_no")
 			)
 		)
+	# Counter is used to create a hashmap of serial nos, which contains count of each serial no
+	# so we subtract returned serial nos from ignore serial nos after creating a counter of each to get the items which we need 	to ignore(which are sold)
 
-	return list(set(ignore_serial_nos) - set(returned_serial_nos))
+	ignore_serial_nos_counter = Counter(ignore_serial_nos)
+	returned_serial_nos_counter = Counter(returned_serial_nos)
+
+	return list(ignore_serial_nos_counter - returned_serial_nos_counter)
 
 
 def get_reserved_batches_for_pos(kwargs):
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index 248b705..258a503 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -647,7 +647,7 @@
 
 	def update_distinct_item_warehouses(self, dependant_sle):
 		key = (dependant_sle.item_code, dependant_sle.warehouse)
-		val = frappe._dict({"sle": dependant_sle, "dependent_voucher_detail_nos": []})
+		val = frappe._dict({"sle": dependant_sle})
 
 		if key not in self.distinct_item_warehouses:
 			self.distinct_item_warehouses[key] = val
@@ -661,6 +661,8 @@
 
 			if getdate(dependant_sle.posting_date) < getdate(existing_sle_posting_date):
 				val.sle_changed = True
+				dependent_voucher_detail_nos.append(dependant_sle.voucher_detail_no)
+				val.dependent_voucher_detail_nos = dependent_voucher_detail_nos
 				self.distinct_item_warehouses[key] = val
 				self.new_items_found = True
 			elif dependant_sle.voucher_detail_no not in set(dependent_voucher_detail_nos):
diff --git a/erpnext/templates/includes/order/order_taxes.html b/erpnext/templates/includes/order/order_taxes.html
index 0060ab3..d7b9620 100644
--- a/erpnext/templates/includes/order/order_taxes.html
+++ b/erpnext/templates/includes/order/order_taxes.html
@@ -19,7 +19,7 @@
 					{{ d.description }}
 				</div>
 				<div class="item-grand-total col-4 text-right pr-0">
-					{{ doc.get_formatted("net_total") }}
+					{{ d.get_formatted("base_tax_amount") }}
 				</div>
 			</div>
 		</div>