Merge branch 'develop' into fg_based_operating_cost
diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js
index 28e79b5..c083189 100644
--- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js
+++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js
@@ -21,13 +21,22 @@
 		frm.trigger('bank_account');
 	},
 
+	filter_by_reference_date: function (frm) {
+		if (frm.doc.filter_by_reference_date) {
+			frm.set_value("bank_statement_from_date", "");
+			frm.set_value("bank_statement_to_date", "");
+		} else {
+			frm.set_value("from_reference_date", "");
+			frm.set_value("to_reference_date", "");
+		}
+	},
+
 	refresh: function (frm) {
 		frappe.require("bank-reconciliation-tool.bundle.js", () =>
 			frm.trigger("make_reconciliation_tool")
 		);
-		frm.upload_statement_button = frm.page.set_secondary_action(
-			__("Upload Bank Statement"),
-			() =>
+
+		frm.add_custom_button(__("Upload Bank Statement"), () =>
 				frappe.call({
 					method:
 						"erpnext.accounts.doctype.bank_statement_import.bank_statement_import.upload_bank_statement",
@@ -49,6 +58,20 @@
 					},
 				})
 		);
+
+		frm.add_custom_button(__('Auto Reconcile'), function() {
+			frappe.call({
+				method: "erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.auto_reconcile_vouchers",
+				args: {
+					bank_account: frm.doc.bank_account,
+					from_date: frm.doc.bank_statement_from_date,
+					to_date: frm.doc.bank_statement_to_date,
+					filter_by_reference_date: frm.doc.filter_by_reference_date,
+					from_reference_date: frm.doc.from_reference_date,
+					to_reference_date: frm.doc.to_reference_date,
+				},
+			})
+		});
 	},
 
 	after_save: function (frm) {
@@ -160,6 +183,9 @@
 					).$wrapper,
 					bank_statement_from_date: frm.doc.bank_statement_from_date,
 					bank_statement_to_date: frm.doc.bank_statement_to_date,
+					filter_by_reference_date: frm.doc.filter_by_reference_date,
+					from_reference_date: frm.doc.from_reference_date,
+					to_reference_date: frm.doc.to_reference_date,
 					bank_statement_closing_balance:
 						frm.doc.bank_statement_closing_balance,
 					cards_manager: frm.cards_manager,
diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json
index f666101..80993d6 100644
--- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json
+++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.json
@@ -10,6 +10,9 @@
   "column_break_1",
   "bank_statement_from_date",
   "bank_statement_to_date",
+  "from_reference_date",
+  "to_reference_date",
+  "filter_by_reference_date",
   "column_break_2",
   "account_opening_balance",
   "bank_statement_closing_balance",
@@ -36,13 +39,13 @@
    "fieldtype": "Column Break"
   },
   {
-   "depends_on": "eval: doc.bank_account",
+   "depends_on": "eval: doc.bank_account && !doc.filter_by_reference_date",
    "fieldname": "bank_statement_from_date",
    "fieldtype": "Date",
    "label": "From Date"
   },
   {
-   "depends_on": "eval: doc.bank_statement_from_date",
+   "depends_on": "eval: doc.bank_account && !doc.filter_by_reference_date",
    "fieldname": "bank_statement_to_date",
    "fieldtype": "Date",
    "label": "To Date"
@@ -81,14 +84,33 @@
   },
   {
    "fieldname": "no_bank_transactions",
-   "fieldtype": "HTML"
+   "fieldtype": "HTML",
+   "options": "<div class=\"text-muted text-center\">No Matching Bank Transactions Found</div>"
+  },
+  {
+   "depends_on": "eval:doc.filter_by_reference_date",
+   "fieldname": "from_reference_date",
+   "fieldtype": "Date",
+   "label": "From Reference Date"
+  },
+  {
+   "depends_on": "eval:doc.filter_by_reference_date",
+   "fieldname": "to_reference_date",
+   "fieldtype": "Date",
+   "label": "To Reference Date"
+  },
+  {
+   "default": "0",
+   "fieldname": "filter_by_reference_date",
+   "fieldtype": "Check",
+   "label": "Filter by Reference Date"
   }
  ],
  "hide_toolbar": 1,
  "index_web_pages_for_search": 1,
  "issingle": 1,
  "links": [],
- "modified": "2021-04-21 11:13:49.831769",
+ "modified": "2023-01-13 13:00:02.022919",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Bank Reconciliation Tool",
@@ -107,5 +129,6 @@
  ],
  "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/bank_reconciliation_tool/bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py
index f5f04ae..4ba6146 100644
--- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py
+++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py
@@ -8,7 +8,7 @@
 from frappe import _
 from frappe.model.document import Document
 from frappe.query_builder.custom import ConstantColumn
-from frappe.utils import flt
+from frappe.utils import cint, flt
 
 from erpnext.accounts.doctype.bank_transaction.bank_transaction import get_paid_amount
 from erpnext.accounts.report.bank_reconciliation_statement.bank_reconciliation_statement import (
@@ -50,6 +50,7 @@
 			"party",
 		],
 		filters=filters,
+		order_by="date",
 	)
 	return transactions
 
@@ -266,6 +267,80 @@
 
 
 @frappe.whitelist()
+def auto_reconcile_vouchers(
+	bank_account,
+	from_date=None,
+	to_date=None,
+	filter_by_reference_date=None,
+	from_reference_date=None,
+	to_reference_date=None,
+):
+	frappe.flags.auto_reconcile_vouchers = True
+	document_types = ["payment_entry", "journal_entry"]
+	bank_transactions = get_bank_transactions(bank_account)
+	matched_transaction = []
+	for transaction in bank_transactions:
+		linked_payments = get_linked_payments(
+			transaction.name,
+			document_types,
+			from_date,
+			to_date,
+			filter_by_reference_date,
+			from_reference_date,
+			to_reference_date,
+		)
+		vouchers = []
+		for r in linked_payments:
+			vouchers.append(
+				{
+					"payment_doctype": r[1],
+					"payment_name": r[2],
+					"amount": r[4],
+				}
+			)
+		transaction = frappe.get_doc("Bank Transaction", transaction.name)
+		account = frappe.db.get_value("Bank Account", transaction.bank_account, "account")
+		matched_trans = 0
+		for voucher in vouchers:
+			gl_entry = frappe.db.get_value(
+				"GL Entry",
+				dict(
+					account=account, voucher_type=voucher["payment_doctype"], voucher_no=voucher["payment_name"]
+				),
+				["credit", "debit"],
+				as_dict=1,
+			)
+			gl_amount, transaction_amount = (
+				(gl_entry.credit, transaction.deposit)
+				if gl_entry.credit > 0
+				else (gl_entry.debit, transaction.withdrawal)
+			)
+			allocated_amount = gl_amount if gl_amount >= transaction_amount else transaction_amount
+			transaction.append(
+				"payment_entries",
+				{
+					"payment_document": voucher["payment_doctype"],
+					"payment_entry": voucher["payment_name"],
+					"allocated_amount": allocated_amount,
+				},
+			)
+			matched_transaction.append(str(transaction.name))
+		transaction.save()
+		transaction.update_allocations()
+	matched_transaction_len = len(set(matched_transaction))
+	if matched_transaction_len == 0:
+		frappe.msgprint(_("No matching references found for auto reconciliation"))
+	elif matched_transaction_len == 1:
+		frappe.msgprint(_("{0} transaction is reconcilied").format(matched_transaction_len))
+	else:
+		frappe.msgprint(_("{0} transactions are reconcilied").format(matched_transaction_len))
+
+	frappe.flags.auto_reconcile_vouchers = False
+
+	return frappe.get_doc("Bank Transaction", transaction.name)
+
+
+@frappe.whitelist()
 def reconcile_vouchers(bank_transaction_name, vouchers):
 	# updated clear date of all the vouchers based on the bank transaction
 	vouchers = json.loads(vouchers)
@@ -327,20 +402,58 @@
 
 
 @frappe.whitelist()
-def get_linked_payments(bank_transaction_name, document_types=None):
+def get_linked_payments(
+	bank_transaction_name,
+	document_types=None,
+	from_date=None,
+	to_date=None,
+	filter_by_reference_date=None,
+	from_reference_date=None,
+	to_reference_date=None,
+):
 	# get all matching payments for a bank transaction
 	transaction = frappe.get_doc("Bank Transaction", bank_transaction_name)
 	bank_account = frappe.db.get_values(
 		"Bank Account", transaction.bank_account, ["account", "company"], as_dict=True
 	)[0]
 	(account, company) = (bank_account.account, bank_account.company)
-	matching = check_matching(account, company, transaction, document_types)
+	matching = check_matching(
+		account,
+		company,
+		transaction,
+		document_types,
+		from_date,
+		to_date,
+		filter_by_reference_date,
+		from_reference_date,
+		to_reference_date,
+	)
 	return matching
 
 
-def check_matching(bank_account, company, transaction, document_types):
+def check_matching(
+	bank_account,
+	company,
+	transaction,
+	document_types,
+	from_date,
+	to_date,
+	filter_by_reference_date,
+	from_reference_date,
+	to_reference_date,
+):
 	# combine all types of vouchers
-	subquery = get_queries(bank_account, company, transaction, document_types)
+	subquery = get_queries(
+		bank_account,
+		company,
+		transaction,
+		document_types,
+		from_date,
+		to_date,
+		filter_by_reference_date,
+		from_reference_date,
+		to_reference_date,
+	)
 	filters = {
 		"amount": transaction.unallocated_amount,
 		"payment_type": "Receive" if transaction.deposit > 0 else "Pay",
@@ -361,11 +474,20 @@
 				filters,
 			)
 		)
-
 	return sorted(matching_vouchers, key=lambda x: x[0], reverse=True) if matching_vouchers else []
 
 
-def get_queries(bank_account, company, transaction, document_types):
+def get_queries(
+	bank_account,
+	company,
+	transaction,
+	document_types,
+	from_date,
+	to_date,
+	filter_by_reference_date,
+	from_reference_date,
+	to_reference_date,
+):
 	# get queries to get matching vouchers
 	amount_condition = "=" if "exact_match" in document_types else "<="
 	account_from_to = "paid_to" if transaction.deposit > 0 else "paid_from"
@@ -381,6 +503,11 @@
 				document_types,
 				amount_condition,
 				account_from_to,
+				from_date,
+				to_date,
+				filter_by_reference_date,
+				from_reference_date,
+				to_reference_date,
 			)
 			or []
 		)
@@ -389,15 +516,42 @@
 
 
 def get_matching_queries(
-	bank_account, company, transaction, document_types, amount_condition, account_from_to
+	bank_account,
+	company,
+	transaction,
+	document_types,
+	amount_condition,
+	account_from_to,
+	from_date,
+	to_date,
+	filter_by_reference_date,
+	from_reference_date,
+	to_reference_date,
 ):
 	queries = []
 	if "payment_entry" in document_types:
-		pe_amount_matching = get_pe_matching_query(amount_condition, account_from_to, transaction)
+		pe_amount_matching = get_pe_matching_query(
+			amount_condition,
+			account_from_to,
+			transaction,
+			from_date,
+			to_date,
+			filter_by_reference_date,
+			from_reference_date,
+			to_reference_date,
+		)
 		queries.extend([pe_amount_matching])
 
 	if "journal_entry" in document_types:
-		je_amount_matching = get_je_matching_query(amount_condition, transaction)
+		je_amount_matching = get_je_matching_query(
+			amount_condition,
+			transaction,
+			from_date,
+			to_date,
+			filter_by_reference_date,
+			from_reference_date,
+			to_reference_date,
+		)
 		queries.extend([je_amount_matching])
 
 	if transaction.deposit > 0 and "sales_invoice" in document_types:
@@ -504,47 +658,81 @@
 	return vouchers
 
 
-def get_pe_matching_query(amount_condition, account_from_to, transaction):
+def get_pe_matching_query(
+	amount_condition,
+	account_from_to,
+	transaction,
+	from_date,
+	to_date,
+	filter_by_reference_date,
+	from_reference_date,
+	to_reference_date,
+):
 	# get matching payment entries query
 	if transaction.deposit > 0:
 		currency_field = "paid_to_account_currency as currency"
 	else:
 		currency_field = "paid_from_account_currency as currency"
+	filter_by_date = f"AND posting_date between '{from_date}' and '{to_date}'"
+	order_by = " posting_date"
+	filter_by_reference_no = ""
+	if cint(filter_by_reference_date):
+		filter_by_date = f"AND reference_date between '{from_reference_date}' and '{to_reference_date}'"
+		order_by = " reference_date"
+	if frappe.flags.auto_reconcile_vouchers == True:
+		filter_by_reference_no = f"AND reference_no = '{transaction.reference_number}'"
 	return f"""
-	SELECT
-		(CASE WHEN reference_no=%(reference_no)s THEN 1 ELSE 0 END
-		+ CASE WHEN (party_type = %(party_type)s AND party = %(party)s ) THEN 1 ELSE 0  END
-		+ 1 ) AS rank,
-		'Payment Entry' as doctype,
-		name,
-		paid_amount,
-		reference_no,
-		reference_date,
-		party,
-		party_type,
-		posting_date,
-		{currency_field}
-	FROM
-		`tabPayment Entry`
-	WHERE
-		paid_amount {amount_condition} %(amount)s
-		AND docstatus = 1
-		AND payment_type IN (%(payment_type)s, 'Internal Transfer')
-		AND ifnull(clearance_date, '') = ""
-		AND {account_from_to} = %(bank_account)s
+		SELECT
+			(CASE WHEN reference_no=%(reference_no)s THEN 1 ELSE 0 END
+			+ CASE WHEN (party_type = %(party_type)s AND party = %(party)s ) THEN 1 ELSE 0  END
+			+ 1 ) AS rank,
+			'Payment Entry' as doctype,
+			name,
+			paid_amount,
+			reference_no,
+			reference_date,
+			party,
+			party_type,
+			posting_date,
+			{currency_field}
+		FROM
+			`tabPayment Entry`
+		WHERE
+			paid_amount {amount_condition} %(amount)s
+			AND docstatus = 1
+			AND payment_type IN (%(payment_type)s, 'Internal Transfer')
+			AND ifnull(clearance_date, '') = ""
+			AND {account_from_to} = %(bank_account)s
+			{filter_by_date}
+			{filter_by_reference_no}
+		order by{order_by}
+
 	"""
 
 
-def get_je_matching_query(amount_condition, transaction):
+def get_je_matching_query(
+	amount_condition,
+	transaction,
+	from_date,
+	to_date,
+	filter_by_reference_date,
+	from_reference_date,
+	to_reference_date,
+):
 	# get matching journal entry query
-
 	# We have mapping at the bank level
 	# So one bank could have both types of bank accounts like asset and liability
 	# So cr_or_dr should be judged only on basis of withdrawal and deposit and not account type
 	cr_or_dr = "credit" if transaction.withdrawal > 0 else "debit"
-
+	filter_by_date = f"AND je.posting_date between '{from_date}' and '{to_date}'"
+	order_by = " je.posting_date"
+	filter_by_reference_no = ""
+	if cint(filter_by_reference_date):
+		filter_by_date = f"AND je.cheque_date between '{from_reference_date}' and '{to_reference_date}'"
+		order_by = " je.cheque_date"
+	if frappe.flags.auto_reconcile_vouchers == True:
+		filter_by_reference_no = f"AND je.cheque_no = '{transaction.reference_number}'"
 	return f"""
-
 		SELECT
 			(CASE WHEN je.cheque_no=%(reference_no)s THEN 1 ELSE 0 END
 			+ 1) AS rank ,
@@ -568,6 +756,9 @@
 			AND jea.account = %(bank_account)s
 			AND jea.{cr_or_dr}_in_account_currency {amount_condition} %(amount)s
 			AND je.docstatus = 1
+			{filter_by_date}
+			{filter_by_reference_no}
+			order by {order_by}
 	"""
 
 
diff --git a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py
index a5d0413..f900e07 100644
--- a/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py
+++ b/erpnext/accounts/doctype/bank_transaction/test_bank_transaction.py
@@ -5,6 +5,7 @@
 import unittest
 
 import frappe
+from frappe import utils
 from frappe.tests.utils import FrappeTestCase
 
 from erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool import (
@@ -40,7 +41,12 @@
 			"Bank Transaction",
 			dict(description="Re 95282925234 FE/000002917 AT171513000281183046 Conrad Electronic"),
 		)
-		linked_payments = get_linked_payments(bank_transaction.name, ["payment_entry", "exact_match"])
+		linked_payments = get_linked_payments(
+			bank_transaction.name,
+			["payment_entry", "exact_match"],
+			from_date=bank_transaction.date,
+			to_date=utils.today(),
+		)
 		self.assertTrue(linked_payments[0][6] == "Conrad Electronic")
 
 	# This test validates a simple reconciliation leading to the clearance of the bank transaction and the payment
@@ -81,7 +87,12 @@
 			"Bank Transaction",
 			dict(description="Auszahlung Karte MC/000002916 AUTOMAT 698769 K002 27.10. 14:07"),
 		)
-		linked_payments = get_linked_payments(bank_transaction.name, ["payment_entry", "exact_match"])
+		linked_payments = get_linked_payments(
+			bank_transaction.name,
+			["payment_entry", "exact_match"],
+			from_date=bank_transaction.date,
+			to_date=utils.today(),
+		)
 		self.assertTrue(linked_payments[0][3])
 
 	# Check error if already reconciled
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py
index 5a4168a..2415aec 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.py
@@ -219,20 +219,16 @@
 					else:
 						if not frappe.get_value("Item", item.fg_item, "is_sub_contracted_item"):
 							frappe.throw(
-								_(
-									"Row #{0}: Finished Good Item {1} must be a sub-contracted item for service item {2}"
-								).format(item.idx, item.fg_item, item.item_code)
+								_("Row #{0}: Finished Good Item {1} must be a sub-contracted item").format(
+									item.idx, item.fg_item
+								)
 							)
 						elif not frappe.get_value("Item", item.fg_item, "default_bom"):
 							frappe.throw(
 								_("Row #{0}: Default BOM not found for FG Item {1}").format(item.idx, item.fg_item)
 							)
 					if not item.fg_item_qty:
-						frappe.throw(
-							_("Row #{0}: Finished Good Item Qty is not specified for service item {0}").format(
-								item.idx, item.item_code
-							)
-						)
+						frappe.throw(_("Row #{0}: Finished Good Item Qty can not be zero").format(item.idx))
 		else:
 			for item in self.items:
 				item.set("fg_item", None)
diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py
index 335d92f..a9561fe 100644
--- a/erpnext/controllers/subcontracting_controller.py
+++ b/erpnext/controllers/subcontracting_controller.py
@@ -74,24 +74,25 @@
 			)
 
 			if not is_stock_item:
-				msg = f"Item {item.item_name} must be a stock item."
-				frappe.throw(_(msg))
+				frappe.throw(_("Row {0}: Item {1} must be a stock item.").format(item.idx, item.item_name))
 
 			if not is_sub_contracted_item:
-				msg = f"Item {item.item_name} must be a subcontracted item."
-				frappe.throw(_(msg))
+				frappe.throw(
+					_("Row {0}: Item {1} must be a subcontracted item.").format(item.idx, item.item_name)
+				)
 
 			if item.bom:
 				bom = frappe.get_doc("BOM", item.bom)
 				if not bom.is_active:
-					msg = f"Please select an active BOM for Item {item.item_name}."
-					frappe.throw(_(msg))
+					frappe.throw(
+						_("Row {0}: Please select an active BOM for Item {1}.").format(item.idx, item.item_name)
+					)
 				if bom.item != item.item_code:
-					msg = f"Please select an valid BOM for Item {item.item_name}."
-					frappe.throw(_(msg))
+					frappe.throw(
+						_("Row {0}: Please select an valid BOM for Item {1}.").format(item.idx, item.item_name)
+					)
 			else:
-				msg = f"Please select a BOM for Item {item.item_name}."
-				frappe.throw(_(msg))
+				frappe.throw(_("Row {0}: Please select a BOM for Item {1}.").format(item.idx, item.item_name))
 
 	def __get_data_before_save(self):
 		item_dict = {}
diff --git a/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js b/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js
index 9ef8ce6..f7c19a1 100644
--- a/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js
+++ b/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js
@@ -5,7 +5,12 @@
 		Object.assign(this, opts);
 		this.dialog_manager = new erpnext.accounts.bank_reconciliation.DialogManager(
 			this.company,
-			this.bank_account
+			this.bank_account,
+			this.bank_statement_from_date,
+			this.bank_statement_to_date,
+			this.filter_by_reference_date,
+			this.from_reference_date,
+			this.to_reference_date
 		);
 		this.make_dt();
 	}
@@ -17,6 +22,8 @@
 				"erpnext.accounts.doctype.bank_reconciliation_tool.bank_reconciliation_tool.get_bank_transactions",
 			args: {
 				bank_account: this.bank_account,
+				from_date: this.bank_statement_from_date,
+				to_date: this.bank_statement_to_date
 			},
 			callback: function (response) {
 				me.format_data(response.message);
diff --git a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js
index b5e6ab8..51664f8 100644
--- a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js
+++ b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js
@@ -5,8 +5,12 @@
 		this.bank_account = bank_account;
 		this.company = company;
 		this.make_dialog();
+		this.bank_statement_from_date = bank_statement_from_date;
+		this.bank_statement_to_date = bank_statement_to_date;
+		this.filter_by_reference_date = filter_by_reference_date;
+		this.from_reference_date = from_reference_date;
+		this.to_reference_date = to_reference_date;
 	}
-
 	show_dialog(bank_transaction_name, update_dt_cards) {
 		this.bank_transaction_name = bank_transaction_name;
 		this.update_dt_cards = update_dt_cards;
@@ -35,13 +39,13 @@
 				if (r.message) {
 					this.bank_transaction = r.message;
 					r.message.payment_entry = 1;
+					r.message.journal_entry = 1;
 					this.dialog.set_values(r.message);
 					this.dialog.show();
 				}
 			},
 		});
 	}
-
 	get_linked_vouchers(document_types) {
 		frappe.call({
 			method:
@@ -49,6 +53,11 @@
 			args: {
 				bank_transaction_name: this.bank_transaction_name,
 				document_types: document_types,
+				from_date: this.bank_statement_from_date,
+				to_date: this.bank_statement_to_date,
+				filter_by_reference_date: this.filter_by_reference_date,
+				from_reference_date:this.from_reference_date,
+				to_reference_date:this.to_reference_date
 			},
 
 			callback: (result) => {
@@ -66,6 +75,7 @@
 							row[1],
 							row[2],
 							reference_date,
+							row[8],
 							format_currency(row[3], row[9]),
 							row[6],
 							row[4],
@@ -102,6 +112,11 @@
 				width: 120,
 			},
 			{
+				name: "Posting Date",
+				editable: false,
+				width: 120,
+			},
+			{
 				name: __("Amount"),
 				editable: false,
 				width: 100,
@@ -578,4 +593,4 @@
 		}
 	}
 
-};
+};
\ No newline at end of file
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 d0dabad..134b5ea 100644
--- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json
+++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json
@@ -638,6 +638,7 @@
    "width": "70px"
   },
   {
+   "allow_on_submit": 1,
    "fieldname": "ordered_qty",
    "fieldtype": "Float",
    "label": "Ordered Qty",
@@ -864,7 +865,7 @@
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2022-12-25 02:51:10.247569",
+ "modified": "2023-01-12 13:13:28.691585",
  "modified_by": "Administrator",
  "module": "Selling",
  "name": "Sales Order Item",
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 65a792f..9e6aead 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -230,7 +230,8 @@
 			frappe.throw(_("Qty of Finished Goods Item should be greater than 0."))
 
 	def before_print(self, settings=None):
-		self.group_similar_items()
+		if self.group_same_items:
+			self.group_similar_items()
 
 	def group_similar_items(self):
 		group_item_qty = defaultdict(float)
diff --git a/erpnext/stock/doctype/pick_list/test_pick_list.py b/erpnext/stock/doctype/pick_list/test_pick_list.py
index f552299..71663e8 100644
--- a/erpnext/stock/doctype/pick_list/test_pick_list.py
+++ b/erpnext/stock/doctype/pick_list/test_pick_list.py
@@ -445,6 +445,20 @@
 		pl.before_print()
 		self.assertEqual(len(pl.locations), 4)
 
+		# grouping should not happen if group_same_items is False
+		pl = frappe.get_doc(
+			doctype="Pick List",
+			group_same_items=False,
+			locations=[
+				_dict(item_code="A", warehouse="X", qty=5, picked_qty=1),
+				_dict(item_code="B", warehouse="Y", qty=4, picked_qty=2),
+				_dict(item_code="A", warehouse="X", qty=3, picked_qty=2),
+				_dict(item_code="B", warehouse="Y", qty=2, picked_qty=2),
+			],
+		)
+		pl.before_print()
+		self.assertEqual(len(pl.locations), 4)
+
 		# grouping should halve the number of items
 		pl = frappe.get_doc(
 			doctype="Pick List",
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
index bce5360..7e1915b 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
@@ -57,6 +57,7 @@
 
 	def before_validate(self):
 		super(SubcontractingReceipt, self).before_validate()
+		self.validate_items_qty()
 		self.set_items_bom()
 		self.set_items_cost_center()
 		self.set_items_expense_account()
@@ -157,7 +158,7 @@
 
 		total_qty = total_amount = 0
 		for item in self.items:
-			if item.name in rm_supp_cost:
+			if item.qty and item.name in rm_supp_cost:
 				item.rm_supp_cost = rm_supp_cost[item.name]
 				item.rm_cost_per_qty = item.rm_supp_cost / item.qty
 				rm_supp_cost.pop(item.name)
@@ -194,6 +195,13 @@
 					).format(item.idx)
 				)
 
+	def validate_items_qty(self):
+		for item in self.items:
+			if not (item.qty or item.rejected_qty):
+				frappe.throw(
+					_("Row {0}: Accepted Qty and Rejected Qty can't be zero at the same time.").format(item.idx)
+				)
+
 	def set_items_bom(self):
 		if self.is_return:
 			for item in self.items: