Merge branch 'develop' of https://github.com/frappe/erpnext into #34282-Record-advance-payment-as-a-liability
diff --git a/erpnext/accounts/doctype/party_account/party_account.json b/erpnext/accounts/doctype/party_account/party_account.json
index 6933057..7e345d8 100644
--- a/erpnext/accounts/doctype/party_account/party_account.json
+++ b/erpnext/accounts/doctype/party_account/party_account.json
@@ -6,7 +6,8 @@
  "engine": "InnoDB",
  "field_order": [
   "company",
-  "account"
+  "account",
+  "advance_account"
  ],
  "fields": [
   {
@@ -22,14 +23,20 @@
    "fieldname": "account",
    "fieldtype": "Link",
    "in_list_view": 1,
-   "label": "Account",
+   "label": "Default Account",
+   "options": "Account"
+  },
+  {
+   "fieldname": "advance_account",
+   "fieldtype": "Link",
+   "label": "Advance Account",
    "options": "Account"
   }
  ],
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2022-04-04 12:31:02.994197",
+ "modified": "2023-06-06 14:15:42.053150",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Party Account",
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js
index 2843824..4cebb7b 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js
@@ -318,6 +318,10 @@
 		}
 	},
 
+	company: function(frm){
+		frm.trigger('party');
+	},
+
 	party: function(frm) {
 		if (frm.doc.contact_email || frm.doc.contact_person) {
 			frm.set_value("contact_email", "");
@@ -708,7 +712,6 @@
 				if(r.message) {
 					var total_positive_outstanding = 0;
 					var total_negative_outstanding = 0;
-
 					$.each(r.message, function(i, d) {
 						var c = frm.add_child("references");
 						c.reference_doctype = d.voucher_type;
@@ -719,6 +722,7 @@
 						c.bill_no = d.bill_no;
 						c.payment_term = d.payment_term;
 						c.allocated_amount = d.allocated_amount;
+						c.account = d.account;
 
 						if(!in_list(frm.events.get_order_doctypes(frm), d.voucher_type)) {
 							if(flt(d.outstanding_amount) > 0)
@@ -1434,4 +1438,4 @@
 			});
 		}
 	},
-})
+})
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.json b/erpnext/accounts/doctype/payment_entry/payment_entry.json
index 3927eca..1c330b8 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.json
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.json
@@ -733,7 +733,7 @@
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2023-02-14 04:52:30.478523",
+ "modified": "2023-06-07 14:36:50.521884",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Payment Entry",
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index b6d3e5a..bddce55 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -60,6 +60,7 @@
 	def validate(self):
 		self.setup_party_account_field()
 		self.set_missing_values()
+		self.set_liability_account()
 		self.set_missing_ref_details()
 		self.validate_payment_type()
 		self.validate_party_details()
@@ -92,6 +93,35 @@
 		self.update_payment_schedule()
 		self.set_status()
 
+	def set_liability_account(self):
+		book_advance_payments_as_liability = frappe.get_value(
+			"Company", {"company_name": self.company}, "book_advance_payments_as_liability"
+		)
+		if not book_advance_payments_as_liability:
+			return
+		account_type = frappe.get_value(
+			"Account", {"name": self.party_account, "company": self.company}, "account_type"
+		)
+		if (account_type == "Payable" and self.party_type == "Customer") or (
+			account_type == "Receivable" and self.party_type == "Supplier"
+		):
+			return
+		if self.unallocated_amount == 0:
+			for d in self.references:
+				if d.reference_doctype in ["Sales Order", "Purchase Order"]:
+					break
+			else:
+				return
+		liability_account = get_party_account(
+			self.party_type, self.party, self.company, include_advance=True
+		)[1]
+		self.set(self.party_account_field, liability_account)
+		msg = "Book Advance Payments as Liability option is chosen. Paid From account changed from {0} to {1}.".format(
+			frappe.bold(self.party_account),
+			frappe.bold(liability_account),
+		)
+		frappe.msgprint(_(msg), alert=True)
+
 	def on_cancel(self):
 		self.ignore_linked_doctypes = (
 			"GL Entry",
@@ -368,13 +398,6 @@
 						elif self.party_type == "Employee":
 							ref_party_account = ref_doc.payable_account
 
-						if ref_party_account != self.party_account:
-							frappe.throw(
-								_("{0} {1} is associated with {2}, but Party Account is {3}").format(
-									d.reference_doctype, d.reference_name, ref_party_account, self.party_account
-								)
-							)
-
 						if ref_doc.doctype == "Purchase Invoice" and ref_doc.get("on_hold"):
 							frappe.throw(
 								_("{0} {1} is on hold").format(d.reference_doctype, d.reference_name),
@@ -887,12 +910,12 @@
 
 		self.set("remarks", "\n".join(remarks))
 
-	def build_gl_map(self):
+	def build_gl_map(self, is_reconcile=True):
 		if self.payment_type in ("Receive", "Pay") and not self.get("party_account_field"):
 			self.setup_party_account_field()
 
 		gl_entries = []
-		self.add_party_gl_entries(gl_entries)
+		self.add_party_gl_entries(gl_entries, is_reconcile)
 		self.add_bank_gl_entries(gl_entries)
 		self.add_deductions_gl_entries(gl_entries)
 		self.add_tax_gl_entries(gl_entries)
@@ -903,14 +926,16 @@
 		gl_entries = process_gl_map(gl_entries)
 		make_gl_entries(gl_entries, cancel=cancel, adv_adj=adv_adj)
 
-	def add_party_gl_entries(self, gl_entries):
+	def add_party_gl_entries(self, gl_entries, is_reconcile):
 		if self.party_account:
 			if self.payment_type == "Receive":
 				against_account = self.paid_to
+				dr_or_cr = "credit"
 			else:
 				against_account = self.paid_from
+				dr_or_cr = "debit"
 
-			party_gl_dict = self.get_gl_dict(
+			party_dict = self.get_gl_dict(
 				{
 					"account": self.party_account,
 					"party_type": self.party_type,
@@ -921,50 +946,110 @@
 				},
 				item=self,
 			)
-
-			dr_or_cr = (
-				"credit" if erpnext.get_party_account_type(self.party_type) == "Receivable" else "debit"
-			)
+			is_advance = self.get_advance_flag()
 
 			for d in self.get("references"):
-				cost_center = self.cost_center
-				if d.reference_doctype == "Sales Invoice" and not cost_center:
-					cost_center = frappe.db.get_value(d.reference_doctype, d.reference_name, "cost_center")
-				gle = party_gl_dict.copy()
-				gle.update(
-					{
-						"against_voucher_type": d.reference_doctype,
-						"against_voucher": d.reference_name,
-						"cost_center": cost_center,
-					}
+				gle = party_dict.copy()
+				book_advance_payments_as_liability = frappe.get_value(
+					"Company", {"company_name": self.company}, "book_advance_payments_as_liability"
 				)
+				if (
+					d.reference_doctype in ["Sales Invoice", "Purchase Invoice"]
+					and book_advance_payments_as_liability
+					and (is_advance or is_reconcile)
+				):
+					self.make_invoice_liability_entry(gl_entries, d)
+					gle.update(
+						{
+							"against_voucher_type": "Payment Entry",
+							"against_voucher": self.name,
+						}
+					)
 
 				allocated_amount_in_company_currency = self.calculate_base_allocated_amount_for_reference(d)
-
 				gle.update(
 					{
-						dr_or_cr + "_in_account_currency": d.allocated_amount,
 						dr_or_cr: allocated_amount_in_company_currency,
+						dr_or_cr + "_in_account_currency": d.allocated_amount,
 					}
 				)
-
+				if not gle.get("against_voucher_type"):
+					gle.update(
+						{
+							"against_voucher_type": d.reference_doctype if is_advance else "Payment Entry",
+							"against_voucher": d.reference_name if is_advance else self.name,
+						}
+					)
 				gl_entries.append(gle)
 
 			if self.unallocated_amount:
 				exchange_rate = self.get_exchange_rate()
 				base_unallocated_amount = self.unallocated_amount * exchange_rate
 
-				gle = party_gl_dict.copy()
-
+				gle = party_dict.copy()
 				gle.update(
 					{
 						dr_or_cr + "_in_account_currency": self.unallocated_amount,
 						dr_or_cr: base_unallocated_amount,
+						"against_voucher_type": "Payment Entry",
+						"against_voucher": self.name,
 					}
 				)
 
 				gl_entries.append(gle)
 
+	def get_advance_flag(self):
+		for d in self.get("references"):
+			if d.reference_doctype == "Sales Order":
+				return True
+		if self.unallocated_amount > 0:
+			return True
+		return False
+
+	def make_invoice_liability_entry(self, gl_entries, invoice):
+		args_dict = {
+			"party_type": self.party_type,
+			"party": self.party,
+			"account_currency": self.party_account_currency,
+			"cost_center": self.cost_center,
+			"voucher_type": "Payment Entry",
+			"voucher_no": self.name,
+		}
+
+		dr_or_cr = "credit" if invoice.reference_doctype == "Sales Invoice" else "debit"
+		args_dict["account"] = invoice.account
+		args_dict[dr_or_cr] = invoice.allocated_amount
+		args_dict[dr_or_cr + "_in_account_currency"] = invoice.allocated_amount
+		args_dict.update(
+			{
+				"against_voucher_type": invoice.reference_doctype,
+				"against_voucher": invoice.reference_name,
+			}
+		)
+		gle = self.get_gl_dict(
+			args_dict,
+			item=self,
+		)
+		gl_entries.append(gle)
+
+		args_dict[dr_or_cr] = 0
+		args_dict[dr_or_cr + "_in_account_currency"] = 0
+		dr_or_cr = "debit" if dr_or_cr == "credit" else "credit"
+		args_dict["account"] = self.party_account
+		args_dict[dr_or_cr] = invoice.allocated_amount
+		args_dict[dr_or_cr + "_in_account_currency"] = invoice.allocated_amount
+		args_dict.update(
+			{
+				"against_voucher_type": "Payment Entry",
+				"against_voucher": self.name,
+			}
+		)
+		gle = self.get_gl_dict(
+			args_dict,
+			item=self,
+		)
+		gl_entries.append(gle)
+
 	def add_bank_gl_entries(self, gl_entries):
 		if self.payment_type in ("Pay", "Internal Transfer"):
 			gl_entries.append(
@@ -1439,6 +1524,7 @@
 										"outstanding_amount": flt(d.outstanding_amount),
 										"payment_amount": payment_term.payment_amount,
 										"payment_term": payment_term.payment_term,
+										"account": d.account,
 									}
 								)
 							)
@@ -1563,6 +1649,7 @@
 	condition=None,
 ):
 	voucher_type = "Sales Invoice" if party_type == "Customer" else "Purchase Invoice"
+	account = "debit_to" if voucher_type == "Sales Invoice" else "credit_to"
 	supplier_condition = ""
 	if voucher_type == "Purchase Invoice":
 		supplier_condition = "and (release_date is null or release_date <= CURRENT_DATE)"
@@ -1576,7 +1663,7 @@
 	return frappe.db.sql(
 		"""
 		select
-			"{voucher_type}" as voucher_type, name as voucher_no,
+			"{voucher_type}" as voucher_type, name as voucher_no, {account} as account,
 			if({rounded_total_field}, {rounded_total_field}, {grand_total_field}) as invoice_amount,
 			outstanding_amount, posting_date,
 			due_date, conversion_rate as exchange_rate
@@ -1599,6 +1686,7 @@
 				"party_type": scrub(party_type),
 				"party_account": "debit_to" if party_type == "Customer" else "credit_to",
 				"cost_center": cost_center,
+				"account": account,
 			}
 		),
 		(party, party_account),
@@ -1613,7 +1701,6 @@
 		frappe.throw(_("Invalid {0}: {1}").format(party_type, party))
 
 	party_account = get_party_account(party_type, party, company)
-
 	account_currency = get_account_currency(party_account)
 	account_balance = get_balance_on(party_account, date, cost_center=cost_center)
 	_party_name = "title" if party_type == "Shareholder" else party_type.lower() + "_name"
@@ -1686,7 +1773,7 @@
 
 @frappe.whitelist()
 def get_reference_details(reference_doctype, reference_name, party_account_currency):
-	total_amount = outstanding_amount = exchange_rate = None
+	total_amount = outstanding_amount = exchange_rate = account = None
 
 	ref_doc = frappe.get_doc(reference_doctype, reference_name)
 	company_currency = ref_doc.get("company_currency") or erpnext.get_company_currency(
@@ -1724,6 +1811,9 @@
 
 		if reference_doctype in ("Sales Invoice", "Purchase Invoice"):
 			outstanding_amount = ref_doc.get("outstanding_amount")
+			account = (
+				ref_doc.get("debit_to") if reference_doctype == "Sales Invoice" else ref_doc.get("credit_to")
+			)
 		else:
 			outstanding_amount = flt(total_amount) - flt(ref_doc.get("advance_paid"))
 
@@ -1731,7 +1821,7 @@
 		# Get the exchange rate based on the posting date of the ref doc.
 		exchange_rate = get_exchange_rate(party_account_currency, company_currency, ref_doc.posting_date)
 
-	return frappe._dict(
+	res = frappe._dict(
 		{
 			"due_date": ref_doc.get("due_date"),
 			"total_amount": flt(total_amount),
@@ -1740,6 +1830,9 @@
 			"bill_no": ref_doc.get("bill_no"),
 		}
 	)
+	if account:
+		res.update({"account": account})
+	return res
 
 
 @frappe.whitelist()
diff --git a/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json b/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json
index 3003c68..12aa0b5 100644
--- a/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json
+++ b/erpnext/accounts/doctype/payment_entry_reference/payment_entry_reference.json
@@ -15,7 +15,8 @@
   "outstanding_amount",
   "allocated_amount",
   "exchange_rate",
-  "exchange_gain_loss"
+  "exchange_gain_loss",
+  "account"
  ],
  "fields": [
   {
@@ -101,12 +102,18 @@
    "label": "Exchange Gain/Loss",
    "options": "Company:company:default_currency",
    "read_only": 1
+  },
+  {
+   "fieldname": "account",
+   "fieldtype": "Link",
+   "label": "Account",
+   "options": "Account"
   }
  ],
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2022-12-12 12:31:44.919895",
+ "modified": "2023-06-08 07:40:38.487874",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Payment Entry Reference",
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
index 2283677..bd931f1 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.js
@@ -29,6 +29,16 @@
 			};
 		});
 
+		this.frm.set_query('default_advance_account', () => {
+			return {
+				filters: {
+					"company": this.frm.doc.company,
+					"is_group": 0,
+					"root_type": this.frm.doc.party_type == 'Customer' ? "Liability": "Asset"
+				}
+			};
+		});
+
 		this.frm.set_query('bank_cash_account', () => {
 			return {
 				filters:[
@@ -124,19 +134,20 @@
 		this.frm.trigger("clear_child_tables");
 
 		if (!this.frm.doc.receivable_payable_account && this.frm.doc.party_type && this.frm.doc.party) {
-			return frappe.call({
+			frappe.call({
 				method: "erpnext.accounts.party.get_party_account",
 				args: {
 					company: this.frm.doc.company,
 					party_type: this.frm.doc.party_type,
-					party: this.frm.doc.party
+					party: this.frm.doc.party,
+					include_advance: 1
 				},
 				callback: (r) => {
 					if (!r.exc && r.message) {
-						this.frm.set_value("receivable_payable_account", r.message);
+						this.frm.set_value("receivable_payable_account", r.message[0]);
+						this.frm.set_value("default_advance_account", r.message[1]);
 					}
 					this.frm.refresh();
-
 				}
 			});
 		}
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json
index 18d3485..5f6c703 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.json
@@ -10,6 +10,7 @@
   "column_break_4",
   "party",
   "receivable_payable_account",
+  "default_advance_account",
   "col_break1",
   "from_invoice_date",
   "from_payment_date",
@@ -185,13 +186,21 @@
    "fieldtype": "Link",
    "label": "Cost Center",
    "options": "Cost Center"
+  },
+  {
+   "depends_on": "eval:doc.party",
+   "fieldname": "default_advance_account",
+   "fieldtype": "Link",
+   "label": "Default Advance Account",
+   "mandatory_depends_on": "doc.party_type",
+   "options": "Account"
   }
  ],
  "hide_toolbar": 1,
  "icon": "icon-resize-horizontal",
  "issingle": 1,
  "links": [],
- "modified": "2022-04-29 15:37:10.246831",
+ "modified": "2023-06-09 13:02:48.718362",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Payment Reconciliation",
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index 2c8faec..9d869f2 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -12,12 +12,16 @@
 from erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation import (
 	is_any_doc_running,
 )
+from erpnext.accounts.general_ledger import make_gl_entries
 from erpnext.accounts.utils import (
 	QueryPaymentLedger,
 	get_outstanding_invoices,
 	reconcile_against_document,
 )
-from erpnext.controllers.accounts_controller import get_advance_payment_entries
+from erpnext.controllers.accounts_controller import (
+	get_advance_payment_entries,
+	make_advance_liability_entry,
+)
 
 
 class PaymentReconciliation(Document):
@@ -55,12 +59,25 @@
 		self.add_payment_entries(non_reconciled_payments)
 
 	def get_payment_entries(self):
+		party_account = [self.receivable_payable_account, self.default_advance_account]
+
 		order_doctype = "Sales Order" if self.party_type == "Customer" else "Purchase Order"
-		condition = self.get_conditions(get_payments=True)
+		condition = frappe._dict(
+			{
+				"company": self.get("company"),
+				"get_payments": True,
+				"cost_center": self.get("cost_center"),
+				"from_payment_date": self.get("from_payment_date"),
+				"to_payment_date": self.get("to_payment_date"),
+				"maximum_payment_amount": self.get("maximum_payment_amount"),
+				"minimum_payment_amount": self.get("minimum_payment_amount"),
+			}
+		)
+
 		payment_entries = get_advance_payment_entries(
 			self.party_type,
 			self.party,
-			self.receivable_payable_account,
+			party_account,
 			order_doctype,
 			against_all_orders=True,
 			limit=self.payment_limit,
@@ -335,6 +352,12 @@
 		for row in self.get("allocation"):
 			reconciled_entry = []
 			if row.invoice_number and row.allocated_amount:
+				if row.invoice_type in ["Sales Invoice", "Purchase Invoice"]:
+					gl_entries = []
+					make_advance_liability_entry(
+						gl_entries, row.reference_name, row.allocated_amount, row.invoice_number, self.party_type
+					)
+					make_gl_entries(gl_entries)
 				if row.reference_type in ["Sales Invoice", "Purchase Invoice"]:
 					reconciled_entry = dr_or_cr_notes
 				else:
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index 0c18f5e..e247e80 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -1088,6 +1088,7 @@
    "fieldtype": "Button",
    "label": "Get Advances Paid",
    "oldfieldtype": "Button",
+   "options": "set_advances",
    "print_hide": 1
   },
   {
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 230a8b3..68fa7bf 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -33,7 +33,10 @@
 from erpnext.assets.doctype.asset.asset import get_asset_account, is_cwip_accounting_enabled
 from erpnext.assets.doctype.asset_category.asset_category import get_asset_category_account
 from erpnext.buying.utils import check_on_hold_or_closed_status
-from erpnext.controllers.accounts_controller import validate_account_head
+from erpnext.controllers.accounts_controller import (
+	check_advance_liability_entry,
+	validate_account_head,
+)
 from erpnext.controllers.buying_controller import BuyingController
 from erpnext.stock import get_warehouse_account_map
 from erpnext.stock.doctype.purchase_receipt.purchase_receipt import (
@@ -573,6 +576,15 @@
 		gl_entries = []
 
 		self.make_supplier_gl_entry(gl_entries)
+
+		check_advance_liability_entry(
+			gl_entries,
+			company=self.company,
+			advances=self.advances,
+			invoice=self.name,
+			party_type="Supplier",
+		)
+
 		self.make_item_gl_entries(gl_entries)
 		self.make_precision_loss_gl_entry(gl_entries)
 
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index 45bddfc..02d60dc 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -1664,6 +1664,50 @@
 
 		self.assertTrue(return_pi.docstatus == 1)
 
+	def test_advance_entries_as_liability(self):
+		from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_entry
+
+		set_advance_flag(company="_Test Company", flag=1, default_account="Debtors - _TC")
+
+		pe = create_payment_entry(
+			company="_Test Company",
+			payment_type="Pay",
+			party_type="Supplier",
+			party="_Test Supplier",
+			paid_from="Cash - _TC",
+			paid_to="Creditors - _TC",
+			paid_amount=500,
+		)
+		pe.submit()
+
+		pi = make_purchase_invoice(
+			company="_Test Company",
+			customer="_Test Supplier",
+			do_not_save=True,
+			do_not_submit=True,
+			rate=1000,
+			price_list_rate=1000,
+			qty=1,
+		)
+		pi.base_grand_total = 1000
+		pi.grand_total = 1000
+		pi.set_advances()
+		for advance in pi.advances:
+			advance.allocated_amount = 500 if advance.reference_name == pe.name else 0
+		pi.save()
+		pi.submit()
+
+		self.assertEqual(pi.advances[0].allocated_amount, 500)
+		expected_gle = [
+			["Creditors - _TC", 500, 1000, nowdate()],
+			["Debtors - _TC", 0.0, 500, nowdate()],
+			["Stock Received But Not Billed - _TC", 1000, 0.0, nowdate()],
+		]
+		check_gl_entries(self, pi.name, expected_gle, nowdate())
+		self.assertEqual(pi.outstanding_amount, 500)
+
+		set_advance_flag(company="_Test Company", flag=0, default_account="")
+
 	def test_gl_entries_for_standalone_debit_note(self):
 		make_purchase_invoice(qty=5, rate=500, update_stock=True)
 
@@ -1680,16 +1724,32 @@
 		self.assertAlmostEqual(returned_inv.items[0].rate, rate)
 
 
-def check_gl_entries(doc, voucher_no, expected_gle, posting_date):
-	gl_entries = frappe.db.sql(
-		"""select account, debit, credit, posting_date
-		from `tabGL Entry`
-		where voucher_type='Purchase Invoice' and voucher_no=%s and posting_date >= %s
-		order by posting_date asc, account asc""",
-		(voucher_no, posting_date),
-		as_dict=1,
+def set_advance_flag(company, flag, default_account):
+	frappe.db.set_value(
+		"Company",
+		company,
+		{
+			"book_advance_payments_as_liability": flag,
+			"default_advance_paid_account": default_account,
+		},
 	)
 
+
+def check_gl_entries(doc, voucher_no, expected_gle, posting_date):
+	gl = frappe.qb.DocType("GL Entry")
+	q = (
+		frappe.qb.from_(gl)
+		.select(gl.account, gl.debit, gl.credit, gl.posting_date)
+		.where(
+			(gl.voucher_type == "Sales Invoice")
+			& (gl.voucher_no == voucher_no)
+			& (gl.posting_date >= posting_date)
+			& (gl.is_cancelled == 0)
+		)
+		.orderby(gl.posting_date, gl.account)
+	)
+	gl_entries = q.run(as_dict=True)
+
 	for i, gle in enumerate(gl_entries):
 		doc.assertEqual(expected_gle[i][0], gle.account)
 		doc.assertEqual(expected_gle[i][1], gle.debit)
diff --git a/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json b/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json
index 9fcbf5c..9082115 100644
--- a/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json
+++ b/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json
@@ -14,7 +14,8 @@
   "advance_amount",
   "allocated_amount",
   "exchange_gain_loss",
-  "ref_exchange_rate"
+  "ref_exchange_rate",
+  "account"
  ],
  "fields": [
   {
@@ -111,13 +112,20 @@
    "label": "Reference Exchange Rate",
    "non_negative": 1,
    "read_only": 1
+  },
+  {
+   "fieldname": "account",
+   "fieldtype": "Link",
+   "label": "Account",
+   "options": "Account",
+   "read_only": 1
   }
  ],
  "idx": 1,
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2021-09-26 15:47:28.167371",
+ "modified": "2023-06-01 16:56:48.530169",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Purchase Invoice Advance",
@@ -125,5 +133,6 @@
  "permissions": [],
  "quick_entry": 1,
  "sort_field": "modified",
- "sort_order": "DESC"
+ "sort_order": "DESC",
+ "states": []
 }
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 7ab1c89..d2cd95f 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -32,7 +32,10 @@
 	reset_depreciation_schedule,
 	reverse_depreciation_entry_made_after_disposal,
 )
-from erpnext.controllers.accounts_controller import validate_account_head
+from erpnext.controllers.accounts_controller import (
+	check_advance_liability_entry,
+	validate_account_head,
+)
 from erpnext.controllers.selling_controller import SellingController
 from erpnext.projects.doctype.timesheet.timesheet import get_projectwise_timesheet_data
 from erpnext.setup.doctype.company.company import update_company_current_month_sales
@@ -1059,6 +1062,14 @@
 
 		self.make_customer_gl_entry(gl_entries)
 
+		check_advance_liability_entry(
+			gl_entries,
+			company=self.company,
+			advances=self.advances,
+			invoice=self.name,
+			party_type="Customer",
+		)
+
 		self.make_tax_gl_entries(gl_entries)
 		self.make_exchange_gain_loss_gl_entries(gl_entries)
 		self.make_internal_transfer_gl_entries(gl_entries)
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 784bdf6..c23ef34 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -3310,6 +3310,61 @@
 		)
 		self.assertRaises(frappe.ValidationError, si.submit)
 
+	def test_advance_entries_as_liability(self):
+		from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_entry
+		from erpnext.accounts.report.accounts_receivable.accounts_receivable import execute
+
+		set_advance_flag(company="_Test Company", flag=1, default_account="Creditors - _TC")
+
+		pe = create_payment_entry(
+			company="_Test Company",
+			payment_type="Receive",
+			party_type="Customer",
+			party="_Test Customer",
+			paid_from="Debtors - _TC",
+			paid_to="Cash - _TC",
+			paid_amount=1000,
+		)
+		pe.submit()
+
+		si = create_sales_invoice(
+			company="_Test Company",
+			customer="_Test Customer",
+			do_not_save=True,
+			do_not_submit=True,
+			rate=500,
+			price_list_rate=500,
+		)
+		si.base_grand_total = 500
+		si.grand_total = 500
+		si.set_advances()
+		for advance in si.advances:
+			advance.allocated_amount = 500 if advance.reference_name == pe.name else 0
+		si.save()
+		si.submit()
+
+		self.assertEqual(si.advances[0].allocated_amount, 500)
+		expected_gle = [
+			["Creditors - _TC", 500, 0.0, nowdate()],
+			["Debtors - _TC", 500, 500, nowdate()],
+			["Sales - _TC", 0.0, 500, nowdate()],
+		]
+		check_gl_entries(self, si.name, expected_gle, nowdate())
+		self.assertEqual(si.outstanding_amount, 0)
+
+		set_advance_flag(company="_Test Company", flag=0, default_account="")
+
+
+def set_advance_flag(company, flag, default_account):
+	frappe.db.set_value(
+		"Company",
+		company,
+		{
+			"book_advance_payments_as_liability": flag,
+			"default_advance_received_account": default_account,
+		},
+	)
+
 
 def get_sales_invoice_for_e_invoice():
 	si = make_sales_invoice_for_ewaybill()
@@ -3347,15 +3402,19 @@
 
 
 def check_gl_entries(doc, voucher_no, expected_gle, posting_date):
-	gl_entries = frappe.db.sql(
-		"""select account, debit, credit, posting_date
-		from `tabGL Entry`
-		where voucher_type='Sales Invoice' and voucher_no=%s and posting_date > %s
-		and is_cancelled = 0
-		order by posting_date asc, account asc""",
-		(voucher_no, posting_date),
-		as_dict=1,
+	gl = frappe.qb.DocType("GL Entry")
+	q = (
+		frappe.qb.from_(gl)
+		.select(gl.account, gl.debit, gl.credit, gl.posting_date)
+		.where(
+			(gl.voucher_type == "Sales Invoice")
+			& (gl.voucher_no == voucher_no)
+			& (gl.posting_date >= posting_date)
+			& (gl.is_cancelled == 0)
+		)
+		.orderby(gl.posting_date, gl.account)
 	)
+	gl_entries = q.run(as_dict=True)
 
 	for i, gle in enumerate(gl_entries):
 		doc.assertEqual(expected_gle[i][0], gle.account)
diff --git a/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json b/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json
index f92b57a..aa52b1c 100644
--- a/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json
+++ b/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json
@@ -14,7 +14,8 @@
   "advance_amount",
   "allocated_amount",
   "exchange_gain_loss",
-  "ref_exchange_rate"
+  "ref_exchange_rate",
+  "account"
  ],
  "fields": [
   {
@@ -112,13 +113,20 @@
    "label": "Reference Exchange Rate",
    "non_negative": 1,
    "read_only": 1
+  },
+  {
+    "fieldname": "account",
+    "fieldtype": "Link",
+    "label": "Account",
+    "options": "Account",
+    "read_only": 1
   }
  ],
  "idx": 1,
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2021-09-26 15:47:46.911595",
+ "modified": "2023-05-31 11:47:00.191681",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Sales Invoice Advance",
@@ -126,5 +134,6 @@
  "permissions": [],
  "quick_entry": 1,
  "sort_field": "modified",
- "sort_order": "DESC"
+ "sort_order": "DESC",
+ "states": []
 }
\ No newline at end of file
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index a929ff1..a0954a9 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -223,6 +223,7 @@
 		"party_type",
 		"project",
 		"finance_book",
+		"voucher_no",
 	]
 
 	if dimensions:
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index 07b865e..d6aa7d8 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -367,7 +367,7 @@
 
 
 @frappe.whitelist()
-def get_party_account(party_type, party=None, company=None):
+def get_party_account(party_type, party=None, company=None, include_advance=False):
 	"""Returns the account for the given `party`.
 	Will first search in party (Customer / Supplier) record, if not found,
 	will search in group (Customer Group / Supplier Group),
@@ -408,6 +408,36 @@
 		if (account and account_currency != existing_gle_currency) or not account:
 			account = get_party_gle_account(party_type, party, company)
 
+	if include_advance and party_type in ["Customer", "Supplier"]:
+		advance_account = get_party_advance_account(party_type, party, company)
+		return [account, advance_account]
+	return account
+
+
+def get_party_advance_account(party_type, party, company):
+	account = frappe.db.get_value(
+		"Party Account",
+		{"parenttype": party_type, "parent": party, "company": company},
+		"advance_account",
+	)
+
+	if not account:
+		party_group_doctype = "Customer Group" if party_type == "Customer" else "Supplier Group"
+		group = frappe.get_cached_value(party_type, party, scrub(party_group_doctype))
+		account = frappe.db.get_value(
+			"Party Account",
+			{"parenttype": party_group_doctype, "parent": group, "company": company},
+			"advance_account",
+		)
+
+	if not account:
+		account_name = (
+			"default_advance_received_account"
+			if party_type == "Customer"
+			else "default_advance_paid_account"
+		)
+		account = frappe.get_cached_value("Company", company, account_name)
+
 	return account
 
 
@@ -517,7 +547,10 @@
 				)
 
 		# validate if account is mapped for same company
-		validate_account_head(account.idx, account.account, account.company)
+		if account.account:
+			validate_account_head(account.idx, account.account, account.company)
+		if account.advance_account:
+			validate_account_head(account.idx, account.advance_account, account.company)
 
 
 @frappe.whitelist()
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 0ee06e8..e69dcd4 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -436,7 +436,9 @@
 	return cc.name
 
 
-def reconcile_against_document(args, skip_ref_details_update_for_pe=False):  # nosemgrep
+def reconcile_against_document(
+	args, skip_ref_details_update_for_pe=False, is_reconcile=True
+):  # nosemgrep
 	"""
 	Cancel PE or JV, Update against document, split if required and resubmit
 	"""
@@ -472,7 +474,7 @@
 		doc.save(ignore_permissions=True)
 		# re-submit advance entry
 		doc = frappe.get_doc(entry.voucher_type, entry.voucher_no)
-		gl_map = doc.build_gl_map()
+		gl_map = doc.build_gl_map(is_reconcile)
 		create_payment_ledger_entry(gl_map, update_outstanding="No", cancel=0, adv_adj=1)
 
 		# Only update outstanding for newly linked vouchers
@@ -495,50 +497,58 @@
 
 	ret = None
 	if args.voucher_type == "Journal Entry":
-		ret = frappe.db.sql(
-			"""
-			select t2.{dr_or_cr} from `tabJournal Entry` t1, `tabJournal Entry Account` t2
-			where t1.name = t2.parent and t2.account = %(account)s
-			and t2.party_type = %(party_type)s and t2.party = %(party)s
-			and (t2.reference_type is null or t2.reference_type in ('', 'Sales Order', 'Purchase Order'))
-			and t1.name = %(voucher_no)s and t2.name = %(voucher_detail_no)s
-			and t1.docstatus=1 """.format(
-				dr_or_cr=args.get("dr_or_cr")
-			),
-			args,
+		journal_entry = frappe.qb.DocType("Journal Entry")
+		journal_acc = frappe.qb.DocType("Journal Entry Account")
+
+		q = (
+			frappe.qb.from_(journal_entry)
+			.innerjoin(journal_acc)
+			.on(journal_entry.name == journal_acc.parent)
 		)
+
+		if args.get("dr_or_cr") == "debit_in_account_currency":
+			q = q.select(journal_acc.debit_in_account_currency)
+		else:
+			q = q.select(journal_acc.credit_in_account_currency)
+
+		q = q.where(
+			(journal_acc.account == args.get("account"))
+			& ((journal_acc.party_type == args.get("party_type")))
+			& ((journal_acc.party == args.get("party")))
+			& (
+				(journal_acc.reference_type == None)
+				| (journal_acc.reference_type.isin(["", "Sales Order", "Purchase Order"]))
+			)
+			& ((journal_entry.name == args.get("voucher_no")))
+			& ((journal_acc.name == args.get("voucher_detail_no")))
+			& ((journal_entry.docstatus == 1))
+		)
+
 	else:
-		party_account_field = (
-			"paid_from" if erpnext.get_party_account_type(args.party_type) == "Receivable" else "paid_to"
+		payment_entry = frappe.qb.DocType("Payment Entry")
+		payment_ref = frappe.qb.DocType("Payment Entry Reference")
+
+		q = (
+			frappe.qb.from_(payment_entry)
+			.select(payment_entry.name)
+			.where(payment_entry.name == args.get("voucher_no"))
+			.where(payment_entry.docstatus == 1)
+			.where(payment_entry.party_type == args.get("party_type"))
+			.where(payment_entry.party == args.get("party"))
 		)
 
 		if args.voucher_detail_no:
-			ret = frappe.db.sql(
-				"""select t1.name
-				from `tabPayment Entry` t1, `tabPayment Entry Reference` t2
-				where
-					t1.name = t2.parent and t1.docstatus = 1
-					and t1.name = %(voucher_no)s and t2.name = %(voucher_detail_no)s
-					and t1.party_type = %(party_type)s and t1.party = %(party)s and t1.{0} = %(account)s
-					and t2.reference_doctype in ('', 'Sales Order', 'Purchase Order')
-					and t2.allocated_amount = %(unreconciled_amount)s
-			""".format(
-					party_account_field
-				),
-				args,
+			q = (
+				q.inner_join(payment_ref)
+				.on(payment_entry.name == payment_ref.parent)
+				.where(payment_ref.name == args.get("voucher_detail_no"))
+				.where(payment_ref.reference_doctype.isin(("", "Sales Order", "Purchase Order")))
+				.where(payment_ref.allocated_amount == args.get("unreconciled_amount"))
 			)
 		else:
-			ret = frappe.db.sql(
-				"""select name from `tabPayment Entry`
-				where
-					name = %(voucher_no)s and docstatus = 1
-					and party_type = %(party_type)s and party = %(party)s and {0} = %(account)s
-					and unallocated_amount = %(unreconciled_amount)s
-			""".format(
-					party_account_field
-				),
-				args,
-			)
+			q = q.where(payment_entry.unallocated_amount == args.get("unreconciled_amount"))
+
+	ret = q.run(as_dict=True)
 
 	if not ret:
 		throw(_("""Payment Entry has been modified after you pulled it. Please pull it again."""))
@@ -617,6 +627,7 @@
 		if not d.exchange_gain_loss
 		else payment_entry.get_exchange_rate(),
 		"exchange_gain_loss": d.exchange_gain_loss,  # only populated from invoice in case of advance allocation
+		"account": d.account,
 	}
 
 	if d.voucher_detail_no:
@@ -920,6 +931,7 @@
 							"outstanding_amount": outstanding_amount,
 							"due_date": d.due_date,
 							"currency": d.currency,
+							"account": d.account,
 						}
 					)
 				)
diff --git a/erpnext/buying/doctype/supplier/supplier.js b/erpnext/buying/doctype/supplier/supplier.js
index 1ae6f03..a5bf4b2 100644
--- a/erpnext/buying/doctype/supplier/supplier.js
+++ b/erpnext/buying/doctype/supplier/supplier.js
@@ -8,7 +8,7 @@
 			frm.set_value("represents_company", "");
 		}
 		frm.set_query('account', 'accounts', function (doc, cdt, cdn) {
-			var d = locals[cdt][cdn];
+			let d = locals[cdt][cdn];
 			return {
 				filters: {
 					'account_type': 'Payable',
@@ -17,6 +17,18 @@
 				}
 			}
 		});
+
+		frm.set_query('advance_account', 'accounts', function (doc, cdt, cdn) {
+			let d = locals[cdt][cdn];
+			return {
+				filters: {
+					"account_type": "Receivable",
+					"company": d.company,
+					"is_group": 0
+				}
+			}
+		});
+
 		frm.set_query("default_bank_account", function() {
 			return {
 				filters: {
diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json
index 1bf7f58..86e5eee 100644
--- a/erpnext/buying/doctype/supplier/supplier.json
+++ b/erpnext/buying/doctype/supplier/supplier.json
@@ -53,6 +53,7 @@
   "primary_address",
   "accounting_tab",
   "payment_terms",
+  "default_accounts_section",
   "accounts",
   "settings_tab",
   "allow_purchase_invoice_creation_without_purchase_order",
@@ -445,6 +446,11 @@
   {
    "fieldname": "column_break_59",
    "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "default_accounts_section",
+   "fieldtype": "Section Break",
+   "label": "Default Accounts"
   }
  ],
  "icon": "fa fa-user",
@@ -457,7 +463,7 @@
    "link_fieldname": "party"
   }
  ],
- "modified": "2023-02-18 11:05:50.592270",
+ "modified": "2023-05-29 15:23:11.709415",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Supplier",
@@ -489,7 +495,6 @@
    "read": 1,
    "report": 1,
    "role": "Purchase Master Manager",
-   "set_user_permissions": 1,
    "share": 1,
    "write": 1
   },
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index c83e28d..dc499b9 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -7,6 +7,7 @@
 import frappe
 from frappe import _, bold, throw
 from frappe.model.workflow import get_workflow_name, is_transition_condition_satisfied
+from frappe.query_builder.custom import ConstantColumn
 from frappe.query_builder.functions import Abs, Sum
 from frappe.utils import (
 	add_days,
@@ -858,7 +859,6 @@
 				amount = self.get("base_rounded_total") or self.base_grand_total
 			else:
 				amount = self.get("rounded_total") or self.grand_total
-
 			allocated_amount = min(amount - advance_allocated, d.amount)
 			advance_allocated += flt(allocated_amount)
 
@@ -872,24 +872,29 @@
 				"allocated_amount": allocated_amount,
 				"ref_exchange_rate": flt(d.exchange_rate),  # exchange_rate of advance entry
 			}
+			if d.get("paid_from"):
+				advance_row["account"] = d.paid_from
+			if d.get("paid_to"):
+				advance_row["account"] = d.paid_to
 
 			self.append("advances", advance_row)
 
 	def get_advance_entries(self, include_unallocated=True):
 		if self.doctype == "Sales Invoice":
-			party_account = self.debit_to
 			party_type = "Customer"
 			party = self.customer
 			amount_field = "credit_in_account_currency"
 			order_field = "sales_order"
 			order_doctype = "Sales Order"
 		else:
-			party_account = self.credit_to
 			party_type = "Supplier"
 			party = self.supplier
 			amount_field = "debit_in_account_currency"
 			order_field = "purchase_order"
 			order_doctype = "Purchase Order"
+		party_account = [
+			get_party_account(party_type, party=party, company=self.company, include_advance=True)[1]
+		]
 
 		order_list = list(set(d.get(order_field) for d in self.get("items") if d.get(order_field)))
 
@@ -1020,7 +1025,7 @@
 						)
 					)
 
-	def update_against_document_in_jv(self):
+	def update_against_document_in_jv(self, is_reconcile=True):
 		"""
 		Links invoice and advance voucher:
 		        1. cancel advance voucher
@@ -1077,7 +1082,7 @@
 		if lst:
 			from erpnext.accounts.utils import reconcile_against_document
 
-			reconcile_against_document(lst)
+			reconcile_against_document(lst, is_reconcile)
 
 	def on_cancel(self):
 		from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries
@@ -2140,45 +2145,49 @@
 	order_list,
 	include_unallocated=True,
 ):
-	dr_or_cr = (
-		"credit_in_account_currency" if party_type == "Customer" else "debit_in_account_currency"
+	journal_entry = frappe.qb.DocType("Journal Entry")
+	journal_acc = frappe.qb.DocType("Journal Entry Account")
+	q = (
+		frappe.qb.from_(journal_entry)
+		.inner_join(journal_acc)
+		.on(journal_entry.name == journal_acc.parent)
+		.select(
+			ConstantColumn("Journal Entry").as_("reference_type"),
+			(journal_entry.name).as_("reference_name"),
+			(journal_entry.remark).as_("remarks"),
+			(
+				journal_acc.debit_in_account_currency
+				if party_type == "Supplier"
+				else journal_acc.credit_in_account_currency
+			).as_("amount"),
+			(journal_acc.name).as_("reference_row"),
+			(journal_acc.reference_name).as_("against_order"),
+			(journal_acc.exchange_rate),
+		)
+		.where(
+			journal_acc.account.isin(party_account)
+			& (journal_acc.party_type == party_type)
+			& (journal_acc.party == party)
+			& (journal_acc.is_advance == "Yes")
+			& (journal_entry.docstatus == 1)
+		)
 	)
+	if party_type == "Customer":
+		q = q.where(journal_acc.credit_in_account_currency > 0)
 
-	conditions = []
-	if include_unallocated:
-		conditions.append("ifnull(t2.reference_name, '')=''")
+	else:
+		q = q.where(journal_acc.debit_in_account_currency > 0)
 
 	if order_list:
-		order_condition = ", ".join(["%s"] * len(order_list))
-		conditions.append(
-			" (t2.reference_type = '{0}' and ifnull(t2.reference_name, '') in ({1}))".format(
-				order_doctype, order_condition
-			)
-		)
+		q = q.where(journal_acc.reference_type == order_doctype)
+		if include_unallocated:
+			q = q.where(journal_acc.reference_name.isin(order_list) | (journal_acc.reference_name == ""))
+		else:
+			q = q.where(journal_acc.reference_name.isin(order_list))
 
-	reference_condition = " and (" + " or ".join(conditions) + ")" if conditions else ""
+	q = q.orderby(journal_entry.posting_date)
 
-	# nosemgrep
-	journal_entries = frappe.db.sql(
-		"""
-		select
-			'Journal Entry' as reference_type, t1.name as reference_name,
-			t1.remark as remarks, t2.{0} as amount, t2.name as reference_row,
-			t2.reference_name as against_order, t2.exchange_rate
-		from
-			`tabJournal Entry` t1, `tabJournal Entry Account` t2
-		where
-			t1.name = t2.parent and t2.account = %s
-			and t2.party_type = %s and t2.party = %s
-			and t2.is_advance = 'Yes' and t1.docstatus = 1
-			and {1} > 0 {2}
-		order by t1.posting_date""".format(
-			amount_field, dr_or_cr, reference_condition
-		),
-		[party_account, party_type, party] + order_list,
-		as_dict=1,
-	)
-
+	journal_entries = q.run(as_dict=True)
 	return list(journal_entries)
 
 
@@ -2193,65 +2202,126 @@
 	limit=None,
 	condition=None,
 ):
-	party_account_field = "paid_from" if party_type == "Customer" else "paid_to"
-	currency_field = (
-		"paid_from_account_currency" if party_type == "Customer" else "paid_to_account_currency"
+
+	q = build_query(
+		party_type,
+		party,
+		party_account,
+		order_doctype,
+		order_list,
+		include_unallocated,
+		against_all_orders,
+		limit,
+		condition,
 	)
+
+	payment_entries = q.run(as_dict=True)
+
+	return list(payment_entries)
+
+
+def build_query(
+	party_type,
+	party,
+	party_account,
+	order_doctype,
+	order_list,
+	include_unallocated,
+	against_all_orders,
+	limit,
+	condition,
+):
 	payment_type = "Receive" if party_type == "Customer" else "Pay"
-	exchange_rate_field = (
-		"source_exchange_rate" if payment_type == "Receive" else "target_exchange_rate"
+	payment_entry = frappe.qb.DocType("Payment Entry")
+	payment_ref = frappe.qb.DocType("Payment Entry Reference")
+
+	q = (
+		frappe.qb.from_(payment_entry)
+		.select(
+			ConstantColumn("Payment Entry").as_("reference_type"),
+			(payment_entry.name).as_("reference_name"),
+			payment_entry.posting_date,
+			(payment_entry.remarks).as_("remarks"),
+		)
+		.where(payment_entry.payment_type == payment_type)
+		.where(payment_entry.party_type == party_type)
+		.where(payment_entry.party == party)
+		.where(payment_entry.docstatus == 1)
 	)
 
-	payment_entries_against_order, unallocated_payment_entries = [], []
-	limit_cond = "limit %s" % limit if limit else ""
+	if party_type == "Customer":
+		q = q.select(payment_entry.paid_from_account_currency)
+		q = q.select(payment_entry.paid_from)
+		q = q.where(payment_entry.paid_from.isin(party_account))
+	else:
+		q = q.select(payment_entry.paid_to_account_currency)
+		q = q.select(payment_entry.paid_to)
+		q = q.where(payment_entry.paid_to.isin(party_account))
 
-	if order_list or against_all_orders:
-		if order_list:
-			reference_condition = " and t2.reference_name in ({0})".format(
-				", ".join(["%s"] * len(order_list))
-			)
-		else:
-			reference_condition = ""
-			order_list = []
-
-		payment_entries_against_order = frappe.db.sql(
-			"""
-			select
-				'Payment Entry' as reference_type, t1.name as reference_name,
-				t1.remarks, t2.allocated_amount as amount, t2.name as reference_row,
-				t2.reference_name as against_order, t1.posting_date,
-				t1.{0} as currency, t1.{4} as exchange_rate
-			from `tabPayment Entry` t1, `tabPayment Entry Reference` t2
-			where
-				t1.name = t2.parent and t1.{1} = %s and t1.payment_type = %s
-				and t1.party_type = %s and t1.party = %s and t1.docstatus = 1
-				and t2.reference_doctype = %s {2}
-			order by t1.posting_date {3}
-		""".format(
-				currency_field, party_account_field, reference_condition, limit_cond, exchange_rate_field
-			),
-			[party_account, payment_type, party_type, party, order_doctype] + order_list,
-			as_dict=1,
-		)
+	if payment_type == "Receive":
+		q = q.select(payment_entry.source_exchange_rate)
+	else:
+		q.select(payment_entry.target_exchange_rate)
 
 	if include_unallocated:
-		unallocated_payment_entries = frappe.db.sql(
-			"""
-				select 'Payment Entry' as reference_type, name as reference_name, posting_date,
-				remarks, unallocated_amount as amount, {2} as exchange_rate, {3} as currency
-				from `tabPayment Entry`
-				where
-					{0} = %s and party_type = %s and party = %s and payment_type = %s
-					and docstatus = 1 and unallocated_amount > 0 {condition}
-				order by posting_date {1}
-			""".format(
-				party_account_field, limit_cond, exchange_rate_field, currency_field, condition=condition or ""
-			),
-			(party_account, party_type, party, payment_type),
-			as_dict=1,
+		q = q.select((payment_entry.unallocated_amount).as_("amount"))
+		q = q.where(payment_entry.unallocated_amount > 0)
+
+		if condition:
+			q = q.where(payment_entry.company == condition["company"])
+			q = (
+				q.where(payment_entry.posting_date >= condition["from_payment_date"])
+				if condition.get("from_payment_date")
+				else q
+			)
+			q = (
+				q.where(payment_entry.posting_date <= condition["to_payment_date"])
+				if condition.get("to_payment_date")
+				else q
+			)
+			if condition.get("get_payments") == True:
+				q = (
+					q.where(payment_entry.cost_center == condition["cost_center"])
+					if condition.get("cost_center")
+					else q
+				)
+				q = (
+					q.where(payment_entry.unallocated_amount >= condition["minimum_payment_amount"])
+					if condition.get("minimum_payment_amount")
+					else q
+				)
+				q = (
+					q.where(payment_entry.unallocated_amount <= condition["maximum_payment_amount"])
+					if condition.get("maximum_payment_amount")
+					else q
+				)
+			else:
+				q = (
+					q.where(payment_entry.total_debit >= condition["minimum_payment_amount"])
+					if condition.get("minimum_payment_amount")
+					else q
+				)
+				q = (
+					q.where(payment_entry.total_debit <= condition["maximum_payment_amount"])
+					if condition.get("maximum_payment_amount")
+					else q
+				)
+
+	elif order_list or against_all_orders:
+		q = q.inner_join(payment_ref).on(payment_entry.name == payment_ref.parent)
+		q = q.select(
+			(payment_ref.allocated_amount).as_("amount"),
+			(payment_ref.name).as_("reference_row"),
+			(payment_ref.reference_name).as_("against_order"),
+			payment_ref.reference_doctype == order_doctype,
 		)
 
-	return list(payment_entries_against_order) + list(unallocated_payment_entries)
+		if order_list:
+			q = q.where(payment_ref.reference_name.isin(order_list))
+
+	q = q.orderby(payment_entry.posting_date)
+	q = q.limit(limit) if limit else q
+	return q
 
 
 def update_invoice_status():
@@ -2842,6 +2912,84 @@
 			parent.create_stock_reservation_entries()
 
 
+def make_advance_liability_entry(
+	gl_entries, pe, allocated_amount, invoice, party_type, references=False
+):
+	pe = frappe.get_doc("Payment Entry", pe)
+	if party_type == "Customer":
+		invoice = frappe.get_doc("Sales Invoice", invoice)
+		account = pe.paid_from
+		dr_or_cr = "debit"
+		rev = "credit"
+		against = invoice.debit_to
+		party = invoice.customer
+	else:
+		invoice = frappe.get_doc("Purchase Invoice", invoice)
+		account = pe.paid_to
+		dr_or_cr = "credit"
+		rev = "debit"
+		against = invoice.credit_to
+		party = invoice.supplier
+	gl_entries.append(
+		pe.get_gl_dict(
+			{
+				"account": account,
+				"party_type": party_type,
+				"party": party,
+				"due_date": invoice.due_date,
+				"against": against,
+				dr_or_cr: allocated_amount,
+				dr_or_cr + "_in_account_currency": allocated_amount,
+				rev: 0,
+				rev + "_in_account_currency": 0,
+				"cost_center": invoice.cost_center,
+				"project": invoice.project,
+				"against_voucher_type": "Payment Entry",
+				"against_voucher": pe.name,
+			},
+			invoice.party_account_currency,
+			item=pe,
+		)
+	)
+
+	(dr_or_cr, rev) = ("credit", "debit") if party_type == "Customer" else ("debit", "credit")
+	gl_entries.append(
+		pe.get_gl_dict(
+			{
+				"account": against,
+				"party_type": party_type,
+				"party": party,
+				"due_date": invoice.due_date,
+				dr_or_cr: allocated_amount,
+				dr_or_cr + "_in_account_currency": allocated_amount,
+				rev: 0,
+				rev + "_in_account_currency": 0,
+				"cost_center": invoice.cost_center,
+				"project": invoice.project,
+				"against_voucher_type": invoice.doctype,
+				"against_voucher": invoice.name,
+			},
+			invoice.party_account_currency,
+			item=pe,
+		)
+	)
+
+
+def check_advance_liability_entry(gl_entries, company, advances, invoice, party_type):
+	advance_payments_as_liability = frappe.db.get_value(
+		"Company", {"company_name": company}, "book_advance_payments_as_liability"
+	)
+	if advance_payments_as_liability:
+		for advance_entry in advances:
+			make_advance_liability_entry(
+				gl_entries,
+				advance_entry.reference_name,
+				advance_entry.allocated_amount,
+				invoice=invoice,
+				party_type=party_type,
+			)
+
+
 @erpnext.allow_regional
 def validate_regional(doc):
 	pass
diff --git a/erpnext/selling/doctype/customer/customer.js b/erpnext/selling/doctype/customer/customer.js
index b53f339..408e89b 100644
--- a/erpnext/selling/doctype/customer/customer.js
+++ b/erpnext/selling/doctype/customer/customer.js
@@ -20,8 +20,8 @@
 		frm.set_query('customer_group', {'is_group': 0});
 		frm.set_query('default_price_list', { 'selling': 1});
 		frm.set_query('account', 'accounts', function(doc, cdt, cdn) {
-			var d  = locals[cdt][cdn];
-			var filters = {
+			let d  = locals[cdt][cdn];
+			let filters = {
 				'account_type': 'Receivable',
 				'company': d.company,
 				"is_group": 0
@@ -35,6 +35,18 @@
 			}
 		});
 
+		frm.set_query('advance_account', 'accounts', function (doc, cdt, cdn) {
+			let d = locals[cdt][cdn];
+			return {
+				filters: {
+					"account_type": 'Payable',
+					"company": d.company,
+					"is_group": 0
+				}
+			}
+		});
+
+
 		if (frm.doc.__islocal == 1) {
 			frm.set_value("represents_company", "");
 		}
diff --git a/erpnext/selling/doctype/customer/customer.json b/erpnext/selling/doctype/customer/customer.json
index c133cd3..46b1035 100644
--- a/erpnext/selling/doctype/customer/customer.json
+++ b/erpnext/selling/doctype/customer/customer.json
@@ -334,15 +334,15 @@
   {
    "fieldname": "default_receivable_accounts",
    "fieldtype": "Section Break",
-   "label": "Default Receivable Accounts"
+   "label": "Default Accounts"
   },
   {
-   "description": "Mention if a non-standard receivable account",
-   "fieldname": "accounts",
-   "fieldtype": "Table",
-   "label": "Receivable Accounts",
-   "options": "Party Account"
-  },
+    "description": "Mention if non-standard Receivable account",
+    "fieldname": "accounts",
+    "fieldtype": "Table",
+    "label": "Accounts",
+    "options": "Party Account"
+   },
   {
    "fieldname": "credit_limit_section",
    "fieldtype": "Section Break",
@@ -568,7 +568,7 @@
    "link_fieldname": "party"
   }
  ],
- "modified": "2023-02-18 11:04:46.343527",
+ "modified": "2023-06-05 13:48:46.152659",
  "modified_by": "Administrator",
  "module": "Selling",
  "name": "Customer",
@@ -607,7 +607,6 @@
    "read": 1,
    "report": 1,
    "role": "Sales Master Manager",
-   "set_user_permissions": 1,
    "share": 1,
    "write": 1
   },
diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js
index e50ce44..089e20d 100644
--- a/erpnext/setup/doctype/company/company.js
+++ b/erpnext/setup/doctype/company/company.js
@@ -226,7 +226,9 @@
 		["capital_work_in_progress_account", {"account_type": "Capital Work in Progress"}],
 		["asset_received_but_not_billed", {"account_type": "Asset Received But Not Billed"}],
 		["unrealized_profit_loss_account", {"root_type": ["in", ["Liability", "Asset"]]}],
-		["default_provisional_account", {"root_type": ["in", ["Liability", "Asset"]]}]
+		["default_provisional_account", {"root_type": ["in", ["Liability", "Asset"]]}],
+		["default_advance_received_account", {"account_type": "Payable"}],
+		["default_advance_paid_account", {"account_type": "Receivable"}],
 	], function(i, v) {
 		erpnext.company.set_custom_query(frm, v);
 	});
diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json
index f087d99..611e2ab 100644
--- a/erpnext/setup/doctype/company/company.json
+++ b/erpnext/setup/doctype/company/company.json
@@ -70,6 +70,11 @@
   "payment_terms",
   "cost_center",
   "default_finance_book",
+  "advance_payments_section",
+  "book_advance_payments_as_liability",
+  "column_break_fwcf",
+  "default_advance_received_account",
+  "default_advance_paid_account",
   "auto_accounting_for_stock_settings",
   "enable_perpetual_inventory",
   "enable_provisional_accounting_for_non_stock_items",
@@ -694,6 +699,38 @@
    "label": "Default Provisional Account",
    "no_copy": 1,
    "options": "Account"
+  },
+  {
+   "default": "0",
+   "description": "Enabling this option will allow you to record - <br><br> 1. Advances Received in a <b>Liability Account</b> instead of the <b>Receivable Account</b><br><br>2. Advances Paid in an <b>Asset Account</b> instead of the <b> Payable Account</b>",
+   "fieldname": "book_advance_payments_as_liability",
+   "fieldtype": "Check",
+   "label": "Book Advance Payments in Separate Party Account"
+  },
+  {
+   "fieldname": "advance_payments_section",
+   "fieldtype": "Section Break",
+   "label": "Advance Payments"
+  },
+  {
+   "depends_on": "eval:doc.book_advance_payments_as_liability",
+   "fieldname": "default_advance_received_account",
+   "fieldtype": "Link",
+   "label": "Default Advance Received Account",
+   "mandatory_depends_on": "book_advance_payments_as_liability",
+   "options": "Account"
+  },
+  {
+   "depends_on": "eval:doc.book_advance_payments_as_liability",
+   "fieldname": "default_advance_paid_account",
+   "fieldtype": "Link",
+   "label": "Default Advance Paid Account",
+   "mandatory_depends_on": "book_advance_payments_as_liability",
+   "options": "Account"
+  },
+  {
+   "fieldname": "column_break_fwcf",
+   "fieldtype": "Column Break"
   }
  ],
  "icon": "fa fa-building",
@@ -701,7 +738,7 @@
  "image_field": "company_logo",
  "is_tree": 1,
  "links": [],
- "modified": "2022-08-16 16:09:02.327724",
+ "modified": "2023-06-16 13:32:48.790947",
  "modified_by": "Administrator",
  "module": "Setup",
  "name": "Company",
diff --git a/erpnext/setup/doctype/customer_group/customer_group.js b/erpnext/setup/doctype/customer_group/customer_group.js
index 44a5019..ed98933 100644
--- a/erpnext/setup/doctype/customer_group/customer_group.js
+++ b/erpnext/setup/doctype/customer_group/customer_group.js
@@ -16,23 +16,35 @@
 	}
 }
 
-//get query select Customer Group
-cur_frm.fields_dict['parent_customer_group'].get_query = function(doc,cdt,cdn) {
-	return {
-		filters: {
-			'is_group': 1,
-			'name': ['!=', cur_frm.doc.customer_group_name]
-		}
-	}
-}
+frappe.ui.form.on("Customer Group", {
+	setup: function(frm){
+		frm.set_query('parent_customer_group', function (doc) {
+			return {
+				filters: {
+					'is_group': 1,
+					'name': ['!=', cur_frm.doc.customer_group_name]
+				}
+			}
+		});
 
-cur_frm.fields_dict['accounts'].grid.get_field('account').get_query = function(doc, cdt, cdn) {
-	var d  = locals[cdt][cdn];
-	return {
-		filters: {
-			'account_type': 'Receivable',
-			'company': d.company,
-			"is_group": 0
-		}
+		frm.set_query('account', 'accounts', function (doc, cdt, cdn) {
+			return {
+				filters: {
+					"account_type": 'Receivable',
+					"company": locals[cdt][cdn].company,
+					"is_group": 0
+				}
+			}
+		});
+
+		frm.set_query('advance_account', 'accounts', function (doc, cdt, cdn) {
+			return {
+				filters: {
+					"root_type": 'Liability',
+					"company": locals[cdt][cdn].company,
+					"is_group": 0
+				}
+			}
+		});
 	}
-}
+});
diff --git a/erpnext/setup/doctype/customer_group/customer_group.json b/erpnext/setup/doctype/customer_group/customer_group.json
index d6a431e..4c36bc7 100644
--- a/erpnext/setup/doctype/customer_group/customer_group.json
+++ b/erpnext/setup/doctype/customer_group/customer_group.json
@@ -113,7 +113,7 @@
   {
    "fieldname": "default_receivable_account",
    "fieldtype": "Section Break",
-   "label": "Default Receivable Account"
+   "label": "Default Accounts"
   },
   {
    "depends_on": "eval:!doc.__islocal",
@@ -139,7 +139,7 @@
  "idx": 1,
  "is_tree": 1,
  "links": [],
- "modified": "2022-12-24 11:15:17.142746",
+ "modified": "2023-06-02 13:40:34.435822",
  "modified_by": "Administrator",
  "module": "Setup",
  "name": "Customer Group",
@@ -171,7 +171,6 @@
    "read": 1,
    "report": 1,
    "role": "Sales Master Manager",
-   "set_user_permissions": 1,
    "share": 1,
    "write": 1
   },
diff --git a/erpnext/setup/doctype/supplier_group/supplier_group.js b/erpnext/setup/doctype/supplier_group/supplier_group.js
index e75030d..ac5904f 100644
--- a/erpnext/setup/doctype/supplier_group/supplier_group.js
+++ b/erpnext/setup/doctype/supplier_group/supplier_group.js
@@ -16,23 +16,35 @@
 	}
 };
 
-// get query select Customer Group
-cur_frm.fields_dict['parent_supplier_group'].get_query = function() {
-	return {
-		filters: {
-			'is_group': 1,
-			'name': ['!=', cur_frm.doc.supplier_group_name]
-		}
-	};
-};
+frappe.ui.form.on("Supplier Group", {
+	setup: function(frm){
+		frm.set_query('parent_supplier_group', function (doc) {
+			return {
+				filters: {
+					'is_group': 1,
+					'name': ['!=', cur_frm.doc.supplier_group_name]
+				}
+			}
+		});
 
-cur_frm.fields_dict['accounts'].grid.get_field('account').get_query = function(doc, cdt, cdn) {
-	var d  = locals[cdt][cdn];
-	return {
-		filters: {
-			'account_type': 'Payable',
-			'company': d.company,
-			"is_group": 0
-		}
-	};
-};
+		frm.set_query('account', 'accounts', function (doc, cdt, cdn) {
+			return {
+				filters: {
+					'account_type': 'Payable',
+					'company': locals[cdt][cdn].company,
+					"is_group": 0
+				}
+			}
+		});
+
+		frm.set_query('advance_account', 'accounts', function (doc, cdt, cdn) {
+			return {
+				filters: {
+					"root_type": 'Asset',
+					"company": locals[cdt][cdn].company,
+					"is_group": 0
+				}
+			}
+		});
+	}
+});