Merge branch 'develop' into fg_based_operating_cost
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index ac033f7..13712ce 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -471,6 +471,7 @@
 
 	def build_qb_filter_conditions(self, get_invoices=False, get_return_invoices=False):
 		self.common_filter_conditions.clear()
+		self.accounting_dimension_filter_conditions.clear()
 		self.ple_posting_date_filter.clear()
 		ple = qb.DocType("Payment Ledger Entry")
 
diff --git a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html
index 0da44a4..3920d4c 100644
--- a/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html
+++ b/erpnext/accounts/doctype/process_statement_of_accounts/process_statement_of_accounts.html
@@ -49,7 +49,6 @@
 						<br>
 					{% endif %}
 
-					{{ _("Against") }}: {{ row.against }}
 					<br>{{ _("Remarks") }}: {{ row.remarks }}
 					{% if row.bill_no %}
 						<br>{{ _("Supplier Invoice No") }}: {{ row.bill_no }}
diff --git a/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.py b/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.py
index 9f6828f..209cad4 100644
--- a/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.py
+++ b/erpnext/accounts/doctype/repost_payment_ledger/repost_payment_ledger.py
@@ -7,7 +7,6 @@
 from frappe import _, qb
 from frappe.model.document import Document
 from frappe.query_builder.custom import ConstantColumn
-from frappe.utils.background_jobs import is_job_queued
 
 from erpnext.accounts.utils import _delete_pl_entries, create_payment_ledger_entry
 
@@ -27,7 +26,7 @@
 	"""
 	if docname:
 		repost_doc = frappe.get_doc("Repost Payment Ledger", docname)
-		if repost_doc.docstatus == 1 and repost_doc.repost_status in ["Queued", "Failed"]:
+		if repost_doc.docstatus.is_submitted() and repost_doc.repost_status in ["Queued", "Failed"]:
 			try:
 				for entry in repost_doc.repost_vouchers:
 					doc = frappe.get_doc(entry.voucher_type, entry.voucher_no)
@@ -102,10 +101,9 @@
 
 	job_name = "payment_ledger_repost_" + docname
 
-	if not is_job_queued(job_name):
-		frappe.enqueue(
-			method="erpnext.accounts.doctype.repost_payment_ledger.repost_payment_ledger.start_payment_ledger_repost",
-			docname=docname,
-			is_async=True,
-			job_name=job_name,
-		)
+	frappe.enqueue(
+		method="erpnext.accounts.doctype.repost_payment_ledger.repost_payment_ledger.start_payment_ledger_repost",
+		docname=docname,
+		is_async=True,
+		job_name=job_name,
+	)
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.html b/erpnext/accounts/report/general_ledger/general_ledger.html
index c04f518..475be92 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.html
+++ b/erpnext/accounts/report/general_ledger/general_ledger.html
@@ -25,8 +25,8 @@
 	<thead>
 		<tr>
 			<th style="width: 12%">{%= __("Date") %}</th>
-			<th style="width: 15%">{%= __("Ref") %}</th>
-			<th style="width: 25%">{%= __("Party") %}</th>
+			<th style="width: 15%">{%= __("Reference") %}</th>
+			<th style="width: 25%">{%= __("Remarks") %}</th>
 			<th style="width: 15%">{%= __("Debit") %}</th>
 			<th style="width: 15%">{%= __("Credit") %}</th>
 			<th style="width: 18%">{%= __("Balance (Dr - Cr)") %}</th>
@@ -45,7 +45,6 @@
 						<br>
 					{% } %}
 
-					{{ __("Against") }}: {%= data[i].against %}
 					<br>{%= __("Remarks") %}: {%= data[i].remarks %}
 					{% if(data[i].bill_no) { %}
 						<br>{%= __("Supplier Invoice No") %}: {%= data[i].bill_no %}
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 445dcc5..a03de9e 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -439,8 +439,7 @@
 		# cancel advance entry
 		doc = frappe.get_doc(voucher_type, voucher_no)
 		frappe.flags.ignore_party_validation = True
-		gl_map = doc.build_gl_map()
-		create_payment_ledger_entry(gl_map, cancel=1, adv_adj=1)
+		_delete_pl_entries(voucher_type, voucher_no)
 
 		for entry in entries:
 			check_if_advance_entry_modified(entry)
@@ -452,11 +451,23 @@
 			else:
 				update_reference_in_payment_entry(entry, doc, do_not_save=True)
 
+		if doc.doctype == "Journal Entry":
+			try:
+				doc.validate_total_debit_and_credit()
+			except Exception as validation_exception:
+				raise frappe.ValidationError(_(f"Validation Error for {doc.name}")) from validation_exception
+
 		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()
-		create_payment_ledger_entry(gl_map, cancel=0, adv_adj=1)
+		create_payment_ledger_entry(gl_map, update_outstanding="No", cancel=0, adv_adj=1)
+
+		# Only update outstanding for newly linked vouchers
+		for entry in entries:
+			update_voucher_outstanding(
+				entry.against_voucher_type, entry.against_voucher, entry.account, entry.party_type, entry.party
+			)
 
 		frappe.flags.ignore_party_validation = False
 
diff --git a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
index 7d3b645..62a3483 100644
--- a/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
+++ b/erpnext/assets/doctype/asset_capitalization/asset_capitalization.py
@@ -8,7 +8,6 @@
 # import erpnext
 from frappe import _
 from frappe.utils import cint, flt, get_link_to_form
-from six import string_types
 
 import erpnext
 from erpnext.assets.doctype.asset.depreciation import (
@@ -626,7 +625,7 @@
 
 @frappe.whitelist()
 def get_consumed_stock_item_details(args):
-	if isinstance(args, string_types):
+	if isinstance(args, str):
 		args = json.loads(args)
 
 	args = frappe._dict(args)
@@ -678,7 +677,7 @@
 
 @frappe.whitelist()
 def get_warehouse_details(args):
-	if isinstance(args, string_types):
+	if isinstance(args, str):
 		args = json.loads(args)
 
 	args = frappe._dict(args)
@@ -694,7 +693,7 @@
 
 @frappe.whitelist()
 def get_consumed_asset_details(args):
-	if isinstance(args, string_types):
+	if isinstance(args, str):
 		args = json.loads(args)
 
 	args = frappe._dict(args)
@@ -746,7 +745,7 @@
 
 @frappe.whitelist()
 def get_service_item_details(args):
-	if isinstance(args, string_types):
+	if isinstance(args, str):
 		args = json.loads(args)
 
 	args = frappe._dict(args)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 788dc49..6fa44c9 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -394,7 +394,7 @@
 				self.get("inter_company_reference")
 				or self.get("inter_company_invoice_reference")
 				or self.get("inter_company_order_reference")
-			):
+			) and not self.get("is_return"):
 				msg = _("Internal Sale or Delivery Reference missing.")
 				msg += _("Please create purchase from internal sale or delivery document itself")
 				frappe.throw(msg, title=_("Internal Sales Reference Missing"))
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index 15c82af..8bd0998 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -37,7 +37,7 @@
 		if (
 			ref_doc.company == doc.company
 			and ref_doc.get(party_type) == doc.get(party_type)
-			and ref_doc.docstatus == 1
+			and ref_doc.docstatus.is_submitted()
 		):
 			# validate posting date time
 			return_posting_datetime = "%s %s" % (doc.posting_date, doc.get("posting_time") or "00:00:00")
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index c6a634b..8c403aa 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -6,6 +6,7 @@
 
 import frappe
 from frappe import _, scrub
+from frappe.model.document import Document
 from frappe.utils import cint, flt, round_based_on_smallest_currency_fraction
 
 import erpnext
@@ -20,7 +21,7 @@
 
 
 class calculate_taxes_and_totals(object):
-	def __init__(self, doc):
+	def __init__(self, doc: Document):
 		self.doc = doc
 		frappe.flags.round_off_applicable_accounts = []
 		get_round_off_applicable_accounts(self.doc.company, frappe.flags.round_off_applicable_accounts)
@@ -677,7 +678,7 @@
 			)
 
 	def calculate_total_advance(self):
-		if self.doc.docstatus < 2:
+		if not self.doc.docstatus.is_cancelled():
 			total_allocated_amount = sum(
 				flt(adv.allocated_amount, adv.precision("allocated_amount"))
 				for adv in self.doc.get("advances")
@@ -708,7 +709,7 @@
 					)
 				)
 
-			if self.doc.docstatus == 0:
+			if self.doc.docstatus.is_draft():
 				if self.doc.get("write_off_outstanding_amount_automatically"):
 					self.doc.write_off_amount = 0
 
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 7495ab8..cba1ecc 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -269,6 +269,7 @@
 erpnext.patches.v13_0.create_accounting_dimensions_for_asset_repair
 erpnext.patches.v15_0.delete_taxjar_doctypes
 erpnext.patches.v15_0.create_asset_depreciation_schedules_from_assets
+erpnext.patches.v14_0.update_reference_due_date_in_journal_entry
 
 [post_model_sync]
 execute:frappe.delete_doc_if_exists('Workspace', 'ERPNext Integrations Settings')
diff --git a/erpnext/patches/v14_0/update_reference_due_date_in_journal_entry.py b/erpnext/patches/v14_0/update_reference_due_date_in_journal_entry.py
new file mode 100644
index 0000000..7000312
--- /dev/null
+++ b/erpnext/patches/v14_0/update_reference_due_date_in_journal_entry.py
@@ -0,0 +1,12 @@
+import frappe
+
+
+def execute():
+	if frappe.db.get_value("Journal Entry Account", {"reference_due_date": ""}):
+		frappe.db.sql(
+			"""
+			UPDATE `tabJournal Entry Account`
+			SET reference_due_date = NULL
+			WHERE reference_due_date = ''
+		"""
+		)
diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py
index 484b8c9..6836d56 100644
--- a/erpnext/selling/doctype/quotation/quotation.py
+++ b/erpnext/selling/doctype/quotation/quotation.py
@@ -194,14 +194,7 @@
 
 
 @frappe.whitelist()
-def make_sales_order(source_name, target_doc=None):
-	quotation = frappe.db.get_value(
-		"Quotation", source_name, ["transaction_date", "valid_till"], as_dict=1
-	)
-	if quotation.valid_till and (
-		quotation.valid_till < quotation.transaction_date or quotation.valid_till < getdate(nowdate())
-	):
-		frappe.throw(_("Validity period of this quotation has ended."))
+def make_sales_order(source_name: str, target_doc=None):
 	return _make_sales_order(source_name, target_doc)
 
 
diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py
index b151dd5..5aaba4f 100644
--- a/erpnext/selling/doctype/quotation/test_quotation.py
+++ b/erpnext/selling/doctype/quotation/test_quotation.py
@@ -136,17 +136,20 @@
 			sales_order.payment_schedule[1].due_date, getdate(add_days(quotation.transaction_date, 30))
 		)
 
-	def test_valid_till(self):
-		from erpnext.selling.doctype.quotation.quotation import make_sales_order
-
+	def test_valid_till_before_transaction_date(self):
 		quotation = frappe.copy_doc(test_records[0])
 		quotation.valid_till = add_days(quotation.transaction_date, -1)
 		self.assertRaises(frappe.ValidationError, quotation.validate)
 
+	def test_so_from_expired_quotation(self):
+		from erpnext.selling.doctype.quotation.quotation import make_sales_order
+
+		quotation = frappe.copy_doc(test_records[0])
 		quotation.valid_till = add_days(nowdate(), -1)
 		quotation.insert()
 		quotation.submit()
-		self.assertRaises(frappe.ValidationError, make_sales_order, quotation.name)
+
+		make_sales_order(quotation.name)
 
 	def test_shopping_cart_without_website_item(self):
 		if frappe.db.exists("Website Item", {"item_code": "_Test Item Home Desktop 100"}):
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 7c0601e..accf5f2 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -208,7 +208,7 @@
 		for quotation in set(d.prevdoc_docname for d in self.get("items")):
 			if quotation:
 				doc = frappe.get_doc("Quotation", quotation)
-				if doc.docstatus == 2:
+				if doc.docstatus.is_cancelled():
 					frappe.throw(_("Quotation {0} is cancelled").format(quotation))
 
 				doc.set_status(update=True)
diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
index 134b5ea..d0dabad 100644
--- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json
+++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
@@ -638,7 +638,6 @@
    "width": "70px"
   },
   {
-   "allow_on_submit": 1,
    "fieldname": "ordered_qty",
    "fieldtype": "Float",
    "label": "Ordered Qty",
@@ -865,7 +864,7 @@
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-01-12 13:13:28.691585",
+ "modified": "2022-12-25 02:51:10.247569",
  "modified_by": "Administrator",
  "module": "Selling",
  "name": "Sales Order Item",
diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py
index 7e426ae..53f6b7f 100644
--- a/erpnext/stock/doctype/item/test_item.py
+++ b/erpnext/stock/doctype/item/test_item.py
@@ -106,7 +106,6 @@
 			"conversion_factor": 1.0,
 			"reserved_qty": 1,
 			"actual_qty": 5,
-			"ordered_qty": 10,
 			"projected_qty": 14,
 		}
 
diff --git a/erpnext/stock/doctype/pick_list/pick_list_dashboard.py b/erpnext/stock/doctype/pick_list/pick_list_dashboard.py
index 92e57be..7fbcbaf 100644
--- a/erpnext/stock/doctype/pick_list/pick_list_dashboard.py
+++ b/erpnext/stock/doctype/pick_list/pick_list_dashboard.py
@@ -1,7 +1,10 @@
 def get_data():
 	return {
 		"fieldname": "pick_list",
+		"internal_links": {
+			"Sales Order": ["locations", "sales_order"],
+		},
 		"transactions": [
-			{"items": ["Stock Entry", "Delivery Note"]},
+			{"items": ["Stock Entry", "Sales Order", "Delivery Note"]},
 		],
 	}
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index f7fcb30..363dc0a 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -1181,7 +1181,7 @@
 
 @frappe.whitelist()
 def get_bin_details(item_code, warehouse, company=None, include_child_warehouses=False):
-	bin_details = {"projected_qty": 0, "actual_qty": 0, "reserved_qty": 0, "ordered_qty": 0}
+	bin_details = {"projected_qty": 0, "actual_qty": 0, "reserved_qty": 0}
 
 	if warehouse:
 		from frappe.query_builder.functions import Coalesce, Sum
@@ -1197,7 +1197,6 @@
 				Coalesce(Sum(bin.projected_qty), 0).as_("projected_qty"),
 				Coalesce(Sum(bin.actual_qty), 0).as_("actual_qty"),
 				Coalesce(Sum(bin.reserved_qty), 0).as_("reserved_qty"),
-				Coalesce(Sum(bin.ordered_qty), 0).as_("ordered_qty"),
 			)
 			.where((bin.item_code == item_code) & (bin.warehouse.isin(warehouses)))
 		).run(as_dict=True)[0]
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
index 7e1915b..e8faa48 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
@@ -63,6 +63,11 @@
 		self.set_items_expense_account()
 
 	def validate(self):
+		if (
+			frappe.db.get_single_value("Buying Settings", "backflush_raw_materials_of_subcontract_based_on")
+			== "BOM"
+		):
+			self.supplied_items = []
 		super(SubcontractingReceipt, self).validate()
 		self.set_missing_values()
 		self.validate_posting_time()