Merge pull request #33785 from rohitwaghchaure/get-items-from-transit-entry

feat: get items from Transit Stock Entry
diff --git a/erpnext/accounts/doctype/budget/budget.py b/erpnext/accounts/doctype/budget/budget.py
index 53838fb..4c628a4 100644
--- a/erpnext/accounts/doctype/budget/budget.py
+++ b/erpnext/accounts/doctype/budget/budget.py
@@ -184,6 +184,11 @@
 			amount = expense_amount or get_amount(args, budget)
 			yearly_action, monthly_action = get_actions(args, budget)
 
+			if yearly_action in ("Stop", "Warn"):
+				compare_expense_with_budget(
+					args, flt(budget.budget_amount), _("Annual"), yearly_action, budget.budget_against, amount
+				)
+
 			if monthly_action in ["Stop", "Warn"]:
 				budget_amount = get_accumulated_monthly_budget(
 					budget.monthly_distribution, args.posting_date, args.fiscal_year, budget.budget_amount
@@ -195,28 +200,28 @@
 					args, budget_amount, _("Accumulated Monthly"), monthly_action, budget.budget_against, amount
 				)
 
-			if (
-				yearly_action in ("Stop", "Warn")
-				and monthly_action != "Stop"
-				and yearly_action != monthly_action
-			):
-				compare_expense_with_budget(
-					args, flt(budget.budget_amount), _("Annual"), yearly_action, budget.budget_against, amount
-				)
-
 
 def compare_expense_with_budget(args, budget_amount, action_for, action, budget_against, amount=0):
-	actual_expense = amount or get_actual_expense(args)
-	if actual_expense > budget_amount:
-		diff = actual_expense - budget_amount
+	actual_expense = get_actual_expense(args)
+	total_expense = actual_expense + amount
+
+	if total_expense > budget_amount:
+		if actual_expense > budget_amount:
+			error_tense = _("is already")
+			diff = actual_expense - budget_amount
+		else:
+			error_tense = _("will be")
+			diff = total_expense - budget_amount
+
 		currency = frappe.get_cached_value("Company", args.company, "default_currency")
 
-		msg = _("{0} Budget for Account {1} against {2} {3} is {4}. It will exceed by {5}").format(
+		msg = _("{0} Budget for Account {1} against {2} {3} is {4}. It {5} exceed by {6}").format(
 			_(action_for),
 			frappe.bold(args.account),
-			args.budget_against_field,
+			frappe.unscrub(args.budget_against_field),
 			frappe.bold(budget_against),
 			frappe.bold(fmt_money(budget_amount, currency=currency)),
+			error_tense,
 			frappe.bold(fmt_money(diff, currency=currency)),
 		)
 
@@ -227,9 +232,9 @@
 			action = "Warn"
 
 		if action == "Stop":
-			frappe.throw(msg, BudgetError)
+			frappe.throw(msg, BudgetError, title=_("Budget Exceeded"))
 		else:
-			frappe.msgprint(msg, indicator="orange")
+			frappe.msgprint(msg, indicator="orange", title=_("Budget Exceeded"))
 
 
 def get_actions(args, budget):
@@ -351,7 +356,9 @@
 			"""
 		select sum(gle.debit) - sum(gle.credit)
 		from `tabGL Entry` gle
-		where gle.account=%(account)s
+		where
+			is_cancelled = 0
+			and gle.account=%(account)s
 			{condition1}
 			and gle.fiscal_year=%(fiscal_year)s
 			and gle.company=%(company)s
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
index b543016..a1239d6 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
@@ -675,7 +675,7 @@
 
 def get_pos_reserved_qty(item_code, warehouse):
 	reserved_qty = frappe.db.sql(
-		"""select sum(p_item.qty) as qty
+		"""select sum(p_item.stock_qty) as qty
 		from `tabPOS Invoice` p, `tabPOS Invoice Item` p_item
 		where p.name = p_item.parent
 		and ifnull(p.consolidated_invoice, '') = ''
diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py
index 1ce780e..57feaa0 100644
--- a/erpnext/accounts/doctype/pricing_rule/utils.py
+++ b/erpnext/accounts/doctype/pricing_rule/utils.py
@@ -687,11 +687,21 @@
 
 def apply_pricing_rule_for_free_items(doc, pricing_rule_args):
 	if pricing_rule_args:
-		items = tuple((d.item_code, d.pricing_rules) for d in doc.items if d.is_free_item)
+		args = {(d["item_code"], d["pricing_rules"]): d for d in pricing_rule_args}
 
-		for args in pricing_rule_args:
-			if not items or (args.get("item_code"), args.get("pricing_rules")) not in items:
-				doc.append("items", args)
+		for item in doc.items:
+			if not item.is_free_item:
+				continue
+
+			free_item_data = args.get((item.item_code, item.pricing_rules))
+			if free_item_data:
+				free_item_data.pop("item_name")
+				free_item_data.pop("description")
+				item.update(free_item_data)
+				args.pop((item.item_code, item.pricing_rules))
+
+		for free_item in args.values():
+			doc.append("items", free_item)
 
 
 def get_pricing_rule_items(pr_doc, other_items=False) -> list:
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index e96847e..0ffd946 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -1169,6 +1169,46 @@
 
 		frappe.db.sql("delete from `tabPOS Profile`")
 
+	def test_bin_details_of_packed_item(self):
+		from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
+		from erpnext.stock.doctype.item.test_item import make_item
+
+		# test Update Items with product bundle
+		if not frappe.db.exists("Item", "_Test Product Bundle Item New"):
+			bundle_item = make_item("_Test Product Bundle Item New", {"is_stock_item": 0})
+			bundle_item.append(
+				"item_defaults", {"company": "_Test Company", "default_warehouse": "_Test Warehouse - _TC"}
+			)
+			bundle_item.save(ignore_permissions=True)
+
+		make_item("_Packed Item New 1", {"is_stock_item": 1})
+		make_product_bundle("_Test Product Bundle Item New", ["_Packed Item New 1"], 2)
+
+		si = create_sales_invoice(
+			item_code="_Test Product Bundle Item New",
+			update_stock=1,
+			warehouse="_Test Warehouse - _TC",
+			transaction_date=add_days(nowdate(), -1),
+			do_not_submit=1,
+		)
+
+		make_stock_entry(item="_Packed Item New 1", target="_Test Warehouse - _TC", qty=120, rate=100)
+
+		bin_details = frappe.db.get_value(
+			"Bin",
+			{"item_code": "_Packed Item New 1", "warehouse": "_Test Warehouse - _TC"},
+			["actual_qty", "projected_qty", "ordered_qty"],
+			as_dict=1,
+		)
+
+		si.transaction_date = nowdate()
+		si.save()
+
+		packed_item = si.packed_items[0]
+		self.assertEqual(flt(bin_details.actual_qty), flt(packed_item.actual_qty))
+		self.assertEqual(flt(bin_details.projected_qty), flt(packed_item.projected_qty))
+		self.assertEqual(flt(bin_details.ordered_qty), flt(packed_item.ordered_qty))
+
 	def test_pos_si_without_payment(self):
 		make_pos_profile()
 
diff --git a/erpnext/accounts/doctype/tax_withheld_vouchers/tax_withheld_vouchers.json b/erpnext/accounts/doctype/tax_withheld_vouchers/tax_withheld_vouchers.json
index ce8c0c3..46b430c 100644
--- a/erpnext/accounts/doctype/tax_withheld_vouchers/tax_withheld_vouchers.json
+++ b/erpnext/accounts/doctype/tax_withheld_vouchers/tax_withheld_vouchers.json
@@ -1,6 +1,6 @@
 {
  "actions": [],
- "autoname": "autoincrement",
+ "autoname": "hash",
  "creation": "2022-09-13 16:18:59.404842",
  "doctype": "DocType",
  "editable_grid": 1,
@@ -36,11 +36,11 @@
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2022-09-13 23:40:41.479208",
+ "modified": "2023-01-13 13:40:41.479208",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Tax Withheld Vouchers",
- "naming_rule": "Autoincrement",
+ "naming_rule": "Random",
  "owner": "Administrator",
  "permissions": [],
  "sort_field": "modified",
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
index 1bce43f..2c829b2 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -410,12 +410,26 @@
 	tds_amount = 0
 	invoice_filters = {"name": ("in", vouchers), "docstatus": 1, "apply_tds": 1}
 
+	## for TDS to be deducted on advances
+	payment_entry_filters = {
+		"party_type": "Supplier",
+		"party": ("in", parties),
+		"docstatus": 1,
+		"apply_tax_withholding_amount": 1,
+		"unallocated_amount": (">", 0),
+		"posting_date": ["between", (tax_details.from_date, tax_details.to_date)],
+		"tax_withholding_category": tax_details.get("tax_withholding_category"),
+	}
+
 	field = "sum(tax_withholding_net_total)"
 
 	if cint(tax_details.consider_party_ledger_amount):
 		invoice_filters.pop("apply_tds", None)
 		field = "sum(grand_total)"
 
+		payment_entry_filters.pop("apply_tax_withholding_amount", None)
+		payment_entry_filters.pop("tax_withholding_category", None)
+
 	supp_credit_amt = frappe.db.get_value("Purchase Invoice", invoice_filters, field) or 0.0
 
 	supp_jv_credit_amt = (
@@ -427,14 +441,28 @@
 				"party": ("in", parties),
 				"reference_type": ("!=", "Purchase Invoice"),
 			},
-			"sum(credit_in_account_currency)",
+			"sum(credit_in_account_currency - debit_in_account_currency)",
 		)
 		or 0.0
 	)
 
+	# Get Amount via payment entry
+	payment_entry_amounts = frappe.db.get_all(
+		"Payment Entry",
+		filters=payment_entry_filters,
+		fields=["sum(unallocated_amount) as amount", "payment_type"],
+		group_by="payment_type",
+	)
+
 	supp_credit_amt += supp_jv_credit_amt
 	supp_credit_amt += inv.tax_withholding_net_total
 
+	for type in payment_entry_amounts:
+		if type.payment_type == "Pay":
+			supp_credit_amt += type.amount
+		else:
+			supp_credit_amt -= type.amount
+
 	threshold = tax_details.get("threshold", 0)
 	cumulative_threshold = tax_details.get("cumulative_threshold", 0)
 
diff --git a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
index 23caac0..1e86cf5 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/test_tax_withholding_category.py
@@ -16,7 +16,7 @@
 	def setUpClass(self):
 		# create relevant supplier, etc
 		create_records()
-		create_tax_with_holding_category()
+		create_tax_withholding_category_records()
 
 	def tearDown(self):
 		cancel_invoices()
@@ -38,7 +38,7 @@
 		pi = create_purchase_invoice(supplier="Test TDS Supplier")
 		pi.submit()
 
-		# assert equal tax deduction on total invoice amount uptil now
+		# assert equal tax deduction on total invoice amount until now
 		self.assertEqual(pi.taxes_and_charges_deducted, 3000)
 		self.assertEqual(pi.grand_total, 7000)
 		invoices.append(pi)
@@ -47,7 +47,7 @@
 		pi = create_purchase_invoice(supplier="Test TDS Supplier", rate=5000)
 		pi.submit()
 
-		# assert equal tax deduction on total invoice amount uptil now
+		# assert equal tax deduction on total invoice amount until now
 		self.assertEqual(pi.taxes_and_charges_deducted, 500)
 		invoices.append(pi)
 
@@ -130,7 +130,7 @@
 			invoices.append(si)
 
 		# create another invoice whose total when added to previously created invoice,
-		# surpasses cumulative threshhold
+		# surpasses cumulative threshold
 		si = create_sales_invoice(customer="Test TCS Customer", rate=12000)
 		si.submit()
 
@@ -329,6 +329,38 @@
 		for d in reversed(invoices):
 			d.cancel()
 
+	def test_tax_withholding_via_payment_entry_for_advances(self):
+		frappe.db.set_value(
+			"Supplier", "Test TDS Supplier7", "tax_withholding_category", "Advance TDS Category"
+		)
+
+		# create payment entry
+		pe1 = create_payment_entry(
+			payment_type="Pay", party_type="Supplier", party="Test TDS Supplier7", paid_amount=4000
+		)
+		pe1.submit()
+
+		self.assertFalse(pe1.get("taxes"))
+
+		pe2 = create_payment_entry(
+			payment_type="Pay", party_type="Supplier", party="Test TDS Supplier7", paid_amount=4000
+		)
+		pe2.submit()
+
+		self.assertFalse(pe2.get("taxes"))
+
+		pe3 = create_payment_entry(
+			payment_type="Pay", party_type="Supplier", party="Test TDS Supplier7", paid_amount=4000
+		)
+		pe3.apply_tax_withholding_amount = 1
+		pe3.save()
+		pe3.submit()
+
+		self.assertEquals(pe3.get("taxes")[0].tax_amount, 1200)
+		pe1.cancel()
+		pe2.cancel()
+		pe3.cancel()
+
 
 def cancel_invoices():
 	purchase_invoices = frappe.get_all(
@@ -450,6 +482,32 @@
 	return si
 
 
+def create_payment_entry(**args):
+	# return payment entry doc object
+	args = frappe._dict(args)
+	pe = frappe.get_doc(
+		{
+			"doctype": "Payment Entry",
+			"posting_date": today(),
+			"payment_type": args.payment_type,
+			"party_type": args.party_type,
+			"party": args.party,
+			"company": "_Test Company",
+			"paid_from": "Cash - _TC",
+			"paid_to": "Creditors - _TC",
+			"paid_amount": args.paid_amount or 10000,
+			"received_amount": args.paid_amount or 10000,
+			"reference_no": args.reference_no or "12345",
+			"reference_date": today(),
+			"paid_from_account_currency": "INR",
+			"paid_to_account_currency": "INR",
+		}
+	)
+
+	pe.save()
+	return pe
+
+
 def create_records():
 	# create a new suppliers
 	for name in [
@@ -460,6 +518,7 @@
 		"Test TDS Supplier4",
 		"Test TDS Supplier5",
 		"Test TDS Supplier6",
+		"Test TDS Supplier7",
 	]:
 		if frappe.db.exists("Supplier", name):
 			continue
@@ -530,142 +589,129 @@
 		).insert()
 
 
-def create_tax_with_holding_category():
+def create_tax_withholding_category_records():
 	fiscal_year = get_fiscal_year(today(), company="_Test Company")
+	from_date = fiscal_year[1]
+	to_date = fiscal_year[2]
+
 	# Cumulative threshold
-	if not frappe.db.exists("Tax Withholding Category", "Cumulative Threshold TDS"):
-		frappe.get_doc(
-			{
-				"doctype": "Tax Withholding Category",
-				"name": "Cumulative Threshold TDS",
-				"category_name": "10% TDS",
-				"rates": [
-					{
-						"from_date": fiscal_year[1],
-						"to_date": fiscal_year[2],
-						"tax_withholding_rate": 10,
-						"single_threshold": 0,
-						"cumulative_threshold": 30000.00,
-					}
-				],
-				"accounts": [{"company": "_Test Company", "account": "TDS - _TC"}],
-			}
-		).insert()
+	create_tax_withholding_category(
+		category_name="Cumulative Threshold TDS",
+		rate=10,
+		from_date=from_date,
+		to_date=to_date,
+		account="TDS - _TC",
+		single_threshold=0,
+		cumulative_threshold=30000.00,
+	)
 
-	if not frappe.db.exists("Tax Withholding Category", "Cumulative Threshold TCS"):
-		frappe.get_doc(
-			{
-				"doctype": "Tax Withholding Category",
-				"name": "Cumulative Threshold TCS",
-				"category_name": "10% TCS",
-				"rates": [
-					{
-						"from_date": fiscal_year[1],
-						"to_date": fiscal_year[2],
-						"tax_withholding_rate": 10,
-						"single_threshold": 0,
-						"cumulative_threshold": 30000.00,
-					}
-				],
-				"accounts": [{"company": "_Test Company", "account": "TCS - _TC"}],
-			}
-		).insert()
+	# Category for TCS
+	create_tax_withholding_category(
+		category_name="Cumulative Threshold TCS",
+		rate=10,
+		from_date=from_date,
+		to_date=to_date,
+		account="TCS - _TC",
+		single_threshold=0,
+		cumulative_threshold=30000.00,
+	)
 
-	# Single thresold
-	if not frappe.db.exists("Tax Withholding Category", "Single Threshold TDS"):
-		frappe.get_doc(
-			{
-				"doctype": "Tax Withholding Category",
-				"name": "Single Threshold TDS",
-				"category_name": "10% TDS",
-				"rates": [
-					{
-						"from_date": fiscal_year[1],
-						"to_date": fiscal_year[2],
-						"tax_withholding_rate": 10,
-						"single_threshold": 20000.00,
-						"cumulative_threshold": 0,
-					}
-				],
-				"accounts": [{"company": "_Test Company", "account": "TDS - _TC"}],
-			}
-		).insert()
+	# Single threshold
+	create_tax_withholding_category(
+		category_name="Single Threshold TDS",
+		rate=10,
+		from_date=from_date,
+		to_date=to_date,
+		account="TDS - _TC",
+		single_threshold=20000,
+		cumulative_threshold=0,
+	)
 
-	if not frappe.db.exists("Tax Withholding Category", "New TDS Category"):
-		frappe.get_doc(
-			{
-				"doctype": "Tax Withholding Category",
-				"name": "New TDS Category",
-				"category_name": "New TDS Category",
-				"round_off_tax_amount": 1,
-				"consider_party_ledger_amount": 1,
-				"tax_on_excess_amount": 1,
-				"rates": [
-					{
-						"from_date": fiscal_year[1],
-						"to_date": fiscal_year[2],
-						"tax_withholding_rate": 10,
-						"single_threshold": 0,
-						"cumulative_threshold": 30000,
-					}
-				],
-				"accounts": [{"company": "_Test Company", "account": "TDS - _TC"}],
-			}
-		).insert()
+	create_tax_withholding_category(
+		category_name="New TDS Category",
+		rate=10,
+		from_date=from_date,
+		to_date=to_date,
+		account="TDS - _TC",
+		single_threshold=0,
+		cumulative_threshold=30000,
+		round_off_tax_amount=1,
+		consider_party_ledger_amount=1,
+		tax_on_excess_amount=1,
+	)
 
-	if not frappe.db.exists("Tax Withholding Category", "Test Service Category"):
-		frappe.get_doc(
-			{
-				"doctype": "Tax Withholding Category",
-				"name": "Test Service Category",
-				"category_name": "Test Service Category",
-				"rates": [
-					{
-						"from_date": fiscal_year[1],
-						"to_date": fiscal_year[2],
-						"tax_withholding_rate": 10,
-						"single_threshold": 2000,
-						"cumulative_threshold": 2000,
-					}
-				],
-				"accounts": [{"company": "_Test Company", "account": "TDS - _TC"}],
-			}
-		).insert()
+	create_tax_withholding_category(
+		category_name="Test Service Category",
+		rate=10,
+		from_date=from_date,
+		to_date=to_date,
+		account="TDS - _TC",
+		single_threshold=2000,
+		cumulative_threshold=2000,
+	)
 
-	if not frappe.db.exists("Tax Withholding Category", "Test Goods Category"):
-		frappe.get_doc(
-			{
-				"doctype": "Tax Withholding Category",
-				"name": "Test Goods Category",
-				"category_name": "Test Goods Category",
-				"rates": [
-					{
-						"from_date": fiscal_year[1],
-						"to_date": fiscal_year[2],
-						"tax_withholding_rate": 10,
-						"single_threshold": 2000,
-						"cumulative_threshold": 2000,
-					}
-				],
-				"accounts": [{"company": "_Test Company", "account": "TDS - _TC"}],
-			}
-		).insert()
+	create_tax_withholding_category(
+		category_name="Test Goods Category",
+		rate=10,
+		from_date=from_date,
+		to_date=to_date,
+		account="TDS - _TC",
+		single_threshold=2000,
+		cumulative_threshold=2000,
+	)
 
-	if not frappe.db.exists("Tax Withholding Category", "Test Multi Invoice Category"):
+	create_tax_withholding_category(
+		category_name="Test Multi Invoice Category",
+		rate=10,
+		from_date=from_date,
+		to_date=to_date,
+		account="TDS - _TC",
+		single_threshold=5000,
+		cumulative_threshold=10000,
+	)
+
+	create_tax_withholding_category(
+		category_name="Advance TDS Category",
+		rate=10,
+		from_date=from_date,
+		to_date=to_date,
+		account="TDS - _TC",
+		single_threshold=5000,
+		cumulative_threshold=10000,
+		consider_party_ledger_amount=1,
+	)
+
+
+def create_tax_withholding_category(
+	category_name,
+	rate,
+	from_date,
+	to_date,
+	account,
+	single_threshold=0,
+	cumulative_threshold=0,
+	round_off_tax_amount=0,
+	consider_party_ledger_amount=0,
+	tax_on_excess_amount=0,
+):
+	if not frappe.db.exists("Tax Withholding Category", category_name):
 		frappe.get_doc(
 			{
 				"doctype": "Tax Withholding Category",
-				"name": "Test Multi Invoice Category",
-				"category_name": "Test Multi Invoice Category",
+				"name": category_name,
+				"category_name": category_name,
+				"round_off_tax_amount": round_off_tax_amount,
+				"consider_party_ledger_amount": consider_party_ledger_amount,
+				"tax_on_excess_amount": tax_on_excess_amount,
 				"rates": [
 					{
-						"from_date": fiscal_year[1],
-						"to_date": fiscal_year[2],
-						"tax_withholding_rate": 10,
-						"single_threshold": 5000,
-						"cumulative_threshold": 10000,
+						"from_date": from_date,
+						"to_date": to_date,
+						"tax_withholding_rate": rate,
+						"single_threshold": single_threshold,
+						"cumulative_threshold": cumulative_threshold,
 					}
 				],
-				"accounts": [{"company": "_Test Company", "account": "TDS - _TC"}],
+				"accounts": [{"company": "_Test Company", "account": account}],
 			}
 		).insert()
diff --git a/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py b/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py
index 6cc86c3..3e11643 100644
--- a/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py
+++ b/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py
@@ -378,15 +378,14 @@
 		ret += [{}]
 
 		# add total row
-		if ret is not []:
-			if self.filters.type == "Revenue":
-				total_row = frappe._dict({"name": "Total Deferred Income"})
-			elif self.filters.type == "Expense":
-				total_row = frappe._dict({"name": "Total Deferred Expense"})
+		if self.filters.type == "Revenue":
+			total_row = frappe._dict({"name": "Total Deferred Income"})
+		elif self.filters.type == "Expense":
+			total_row = frappe._dict({"name": "Total Deferred Expense"})
 
-			for idx, period in enumerate(self.period_list, 0):
-				total_row[period.key] = self.period_total[idx].total
-			ret.append(total_row)
+		for idx, period in enumerate(self.period_list, 0):
+			total_row[period.key] = self.period_total[idx].total
+		ret.append(total_row)
 
 		return ret
 
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index 572d9d3..f0360b2 100644
--- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py
+++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
@@ -889,6 +889,11 @@
 		self.assertEqual(po.status, "Completed")
 		self.assertEqual(mr.status, "Received")
 
+	def test_variant_item_po(self):
+		po = create_purchase_order(item_code="_Test Variant Item", qty=1, rate=100, do_not_save=1)
+
+		self.assertRaises(frappe.ValidationError, po.save)
+
 
 def prepare_data_for_internal_transfer():
 	from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_internal_supplier
@@ -994,8 +999,8 @@
 			},
 		)
 
-	po.set_missing_values()
 	if not args.do_not_save:
+		po.set_missing_values()
 		po.insert()
 		if not args.do_not_submit:
 			if po.is_subcontracted:
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index cd1168d..8b4d28b 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -22,7 +22,7 @@
 	def onload(self):
 		super(SellingController, self).onload()
 		if self.doctype in ("Sales Order", "Delivery Note", "Sales Invoice"):
-			for item in self.get("items"):
+			for item in self.get("items") + (self.get("packed_items") or []):
 				item.update(get_bin_details(item.item_code, item.warehouse, include_child_warehouses=True))
 
 	def validate(self):
diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py
index d497297..dd2a670 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -58,7 +58,7 @@
 			"eval:(self.per_delivered == 100 or self.skip_delivery_note) and self.per_billed == 100 and self.docstatus == 1",
 		],
 		["Cancelled", "eval:self.docstatus==2"],
-		["Closed", "eval:self.status=='Closed'"],
+		["Closed", "eval:self.status=='Closed' and self.docstatus != 2"],
 		["On Hold", "eval:self.status=='On Hold'"],
 	],
 	"Purchase Order": [
@@ -79,7 +79,7 @@
 		["Delivered", "eval:self.status=='Delivered'"],
 		["Cancelled", "eval:self.docstatus==2"],
 		["On Hold", "eval:self.status=='On Hold'"],
-		["Closed", "eval:self.status=='Closed'"],
+		["Closed", "eval:self.status=='Closed' and self.docstatus != 2"],
 	],
 	"Delivery Note": [
 		["Draft", None],
@@ -87,7 +87,7 @@
 		["Return Issued", "eval:self.per_returned == 100 and self.docstatus == 1"],
 		["Completed", "eval:self.per_billed == 100 and self.docstatus == 1"],
 		["Cancelled", "eval:self.docstatus==2"],
-		["Closed", "eval:self.status=='Closed'"],
+		["Closed", "eval:self.status=='Closed' and self.docstatus != 2"],
 	],
 	"Purchase Receipt": [
 		["Draft", None],
@@ -95,7 +95,7 @@
 		["Return Issued", "eval:self.per_returned == 100 and self.docstatus == 1"],
 		["Completed", "eval:self.per_billed == 100 and self.docstatus == 1"],
 		["Cancelled", "eval:self.docstatus==2"],
-		["Closed", "eval:self.status=='Closed'"],
+		["Closed", "eval:self.status=='Closed' and self.docstatus != 2"],
 	],
 	"Material Request": [
 		["Draft", None],
diff --git a/erpnext/e_commerce/doctype/website_item/test_website_item.py b/erpnext/e_commerce/doctype/website_item/test_website_item.py
index 828c655..bbe04d5 100644
--- a/erpnext/e_commerce/doctype/website_item/test_website_item.py
+++ b/erpnext/e_commerce/doctype/website_item/test_website_item.py
@@ -174,7 +174,10 @@
 	# Website Item Portal Tests Begin
 
 	def test_website_item_breadcrumbs(self):
-		"Check if breadcrumbs include homepage, product listing navigation page, parent item group(s) and item group."
+		"""
+		Check if breadcrumbs include homepage, product listing navigation page,
+		parent item group(s) and item group
+		"""
 		from erpnext.setup.doctype.item_group.item_group import get_parent_item_groups
 
 		item_code = "Test Breadcrumb Item"
@@ -197,7 +200,7 @@
 		breadcrumbs = get_parent_item_groups(item.item_group)
 
 		self.assertEqual(breadcrumbs[0]["name"], "Home")
-		self.assertEqual(breadcrumbs[1]["name"], "Shop by Category")
+		self.assertEqual(breadcrumbs[1]["name"], "All Products")
 		self.assertEqual(breadcrumbs[2]["name"], "_Test Item Group B")  # parent item group
 		self.assertEqual(breadcrumbs[3]["name"], "_Test Item Group B - 1")
 
diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js
index 4dd8205..4304193 100644
--- a/erpnext/manufacturing/doctype/bom/bom.js
+++ b/erpnext/manufacturing/doctype/bom/bom.js
@@ -65,7 +65,21 @@
 		});
 	},
 
-	onload_post_render(frm) {
+	validate: function(frm) {
+		if (frm.doc.fg_based_operating_cost && frm.doc.with_operations) {
+			frappe.throw({message: __("Please check either with operations or FG Based Operating Cost."), title: __("Mandatory")});
+		}
+	},
+
+	with_operations: function(frm) {
+		frm.set_df_property("fg_based_operating_cost", "hidden", frm.doc.with_operations ? 1 : 0);
+	},
+
+	fg_based_operating_cost: function(frm) {
+		frm.set_df_property("with_operations", "hidden", frm.doc.fg_based_operating_cost ? 1 : 0);
+	},
+
+	onload_post_render: function(frm) {
 		frm.get_field("items").grid.set_multiple_add("item_code", "qty");
 	},
 
@@ -532,18 +546,25 @@
 };
 
 erpnext.bom.calculate_op_cost = function(doc) {
-	var op = doc.operations || [];
 	doc.operating_cost = 0.0;
 	doc.base_operating_cost = 0.0;
 
-	for(var i=0;i<op.length;i++) {
-		var operating_cost = flt(flt(op[i].hour_rate) * flt(op[i].time_in_mins) / 60, 2);
-		var base_operating_cost = flt(operating_cost * doc.conversion_rate, 2);
-		frappe.model.set_value('BOM Operation',op[i].name, "operating_cost", operating_cost);
-		frappe.model.set_value('BOM Operation',op[i].name, "base_operating_cost", base_operating_cost);
+	if(doc.with_operations) {
+		doc.operations.forEach((item) => {
+			let operating_cost = flt(flt(item.hour_rate) * flt(item.time_in_mins) / 60, 2);
+			let base_operating_cost = flt(operating_cost * doc.conversion_rate, 2);
+			frappe.model.set_value('BOM Operation',item.name, {
+				"operating_cost": operating_cost,
+				"base_operating_cost": base_operating_cost
+			});
 
-		doc.operating_cost += operating_cost;
-		doc.base_operating_cost += base_operating_cost;
+			doc.operating_cost += operating_cost;
+			doc.base_operating_cost += base_operating_cost;
+		});
+	} else if(doc.fg_based_operating_cost) {
+		let total_operating_cost = doc.quantity * flt(doc.operating_cost_per_bom_quantity);
+		doc.operating_cost = total_operating_cost;
+		doc.base_operating_cost = flt(total_operating_cost * doc.conversion_rate, 2);
 	}
 	refresh_field(['operating_cost', 'base_operating_cost']);
 };
diff --git a/erpnext/manufacturing/doctype/bom/bom.json b/erpnext/manufacturing/doctype/bom/bom.json
index c31b69f..c2b331f 100644
--- a/erpnext/manufacturing/doctype/bom/bom.json
+++ b/erpnext/manufacturing/doctype/bom/bom.json
@@ -33,6 +33,9 @@
   "column_break_23",
   "transfer_material_against",
   "routing",
+  "fg_based_operating_cost",
+  "fg_based_section_section",
+  "operating_cost_per_bom_quantity",
   "operations_section",
   "operations",
   "materials_section",
@@ -575,7 +578,26 @@
   {
    "fieldname": "scrap_items_section",
    "fieldtype": "Section Break",
+   "hide_border": 1,
    "label": "Scrap Items"
+  },
+  {
+   "default": "0",
+   "fieldname": "fg_based_operating_cost",
+   "fieldtype": "Check",
+   "label": "FG based Operating Cost"
+  },
+  {
+   "depends_on": "fg_based_operating_cost",
+   "fieldname": "fg_based_section_section",
+   "fieldtype": "Section Break",
+   "label": "FG Based Operating Cost Section"
+  },
+  {
+   "depends_on": "fg_based_operating_cost",
+   "fieldname": "operating_cost_per_bom_quantity",
+   "fieldtype": "Currency",
+   "label": "Operating Cost Per BOM Quantity"
   }
  ],
  "icon": "fa fa-sitemap",
@@ -583,7 +605,7 @@
  "image_field": "image",
  "is_submittable": 1,
  "links": [],
- "modified": "2023-01-03 18:42:27.732107",
+ "modified": "2023-01-10 07:47:08.652616",
  "modified_by": "Administrator",
  "module": "Manufacturing",
  "name": "BOM",
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 53af28d..8ab79e6 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -614,18 +614,26 @@
 		"""Update workstation rate and calculates totals"""
 		self.operating_cost = 0
 		self.base_operating_cost = 0
-		for d in self.get("operations"):
-			if d.workstation:
-				self.update_rate_and_time(d, update_hour_rate)
+		if self.get("with_operations"):
+			for d in self.get("operations"):
+				if d.workstation:
+					self.update_rate_and_time(d, update_hour_rate)
 
-			operating_cost = d.operating_cost
-			base_operating_cost = d.base_operating_cost
-			if d.set_cost_based_on_bom_qty:
-				operating_cost = flt(d.cost_per_unit) * flt(self.quantity)
-				base_operating_cost = flt(d.base_cost_per_unit) * flt(self.quantity)
+				operating_cost = d.operating_cost
+				base_operating_cost = d.base_operating_cost
+				if d.set_cost_based_on_bom_qty:
+					operating_cost = flt(d.cost_per_unit) * flt(self.quantity)
+					base_operating_cost = flt(d.base_cost_per_unit) * flt(self.quantity)
 
-			self.operating_cost += flt(operating_cost)
-			self.base_operating_cost += flt(base_operating_cost)
+				self.operating_cost += flt(operating_cost)
+				self.base_operating_cost += flt(base_operating_cost)
+
+		elif self.get("fg_based_operating_cost"):
+			total_operating_cost = flt(self.get("quantity")) * flt(
+				self.get("operating_cost_per_bom_quantity")
+			)
+			self.operating_cost = total_operating_cost
+			self.base_operating_cost = flt(total_operating_cost * self.conversion_rate, 2)
 
 	def update_rate_and_time(self, row, update_hour_rate=False):
 		if not row.hour_rate or update_hour_rate:
diff --git a/erpnext/manufacturing/doctype/bom/test_bom.py b/erpnext/manufacturing/doctype/bom/test_bom.py
index 16f5c79..d60feb2 100644
--- a/erpnext/manufacturing/doctype/bom/test_bom.py
+++ b/erpnext/manufacturing/doctype/bom/test_bom.py
@@ -202,6 +202,33 @@
 
 		self.assertEqual(bom.items[0].rate, 20)
 
+	def test_bom_cost_with_fg_based_operating_cost(self):
+		bom = frappe.copy_doc(test_records[4])
+		bom.insert()
+
+		raw_material_cost = 0.0
+		op_cost = 0.0
+
+		op_cost = bom.quantity * bom.operating_cost_per_bom_quantity
+
+		for row in bom.items:
+			raw_material_cost += row.amount
+
+		base_raw_material_cost = raw_material_cost * flt(
+			bom.conversion_rate, bom.precision("conversion_rate")
+		)
+		base_op_cost = op_cost * flt(bom.conversion_rate, bom.precision("conversion_rate"))
+
+		# test amounts in selected currency, almostEqual checks for 7 digits by default
+		self.assertAlmostEqual(bom.operating_cost, op_cost)
+		self.assertAlmostEqual(bom.raw_material_cost, raw_material_cost)
+		self.assertAlmostEqual(bom.total_cost, raw_material_cost + op_cost)
+
+		# test amounts in selected currency
+		self.assertAlmostEqual(bom.base_operating_cost, base_op_cost)
+		self.assertAlmostEqual(bom.base_raw_material_cost, base_raw_material_cost)
+		self.assertAlmostEqual(bom.base_total_cost, base_raw_material_cost + base_op_cost)
+
 	def test_subcontractor_sourced_item(self):
 		item_code = "_Test Subcontracted FG Item 1"
 		set_backflush_based_on("Material Transferred for Subcontract")
diff --git a/erpnext/manufacturing/doctype/bom/test_records.json b/erpnext/manufacturing/doctype/bom/test_records.json
index 507d319..e9cbdfe 100644
--- a/erpnext/manufacturing/doctype/bom/test_records.json
+++ b/erpnext/manufacturing/doctype/bom/test_records.json
@@ -162,5 +162,31 @@
   "item": "_Test Variant Item",
   "quantity": 1.0,
   "with_operations": 1
+ },
+ {
+  "items": [
+   {
+    "amount": 5000.0,
+    "doctype": "BOM Item",
+    "item_code": "_Test Item",
+    "parentfield": "items",
+    "qty": 2.0,
+    "rate": 3000.0,
+    "uom": "_Test UOM",
+    "stock_uom": "_Test UOM",
+    "source_warehouse": "_Test Warehouse - _TC",
+    "include_item_in_manufacturing": 1
+   }
+  ],
+  "docstatus": 1,
+  "doctype": "BOM",
+  "is_active": 1,
+  "is_default": 1,
+  "currency": "USD",
+  "item": "_Test Variant Item",
+  "quantity": 1.0,
+  "with_operations": 0,
+  "fg_based_operating_cost": 1,
+  "operating_cost_per_bom_quantity": 140
  }
 ]
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 41067d8..6744d16 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -324,3 +324,4 @@
 erpnext.patches.v14_0.setup_clear_repost_logs
 erpnext.patches.v14_0.create_accounting_dimensions_for_payment_request
 erpnext.patches.v14_0.update_entry_type_for_journal_entry
+erpnext.patches.v14_0.change_autoname_for_tax_withheld_vouchers
diff --git a/erpnext/patches/v14_0/change_autoname_for_tax_withheld_vouchers.py b/erpnext/patches/v14_0/change_autoname_for_tax_withheld_vouchers.py
new file mode 100644
index 0000000..e20ba73
--- /dev/null
+++ b/erpnext/patches/v14_0/change_autoname_for_tax_withheld_vouchers.py
@@ -0,0 +1,12 @@
+import frappe
+
+
+def execute():
+	if (
+		frappe.db.sql(
+			"""select data_type FROM information_schema.columns
+            where column_name = 'name' and table_name = 'tabTax Withheld Vouchers'"""
+		)[0][0]
+		== "bigint"
+	):
+		frappe.db.change_column_type("Tax Withheld Vouchers", "name", "varchar(140)")
diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py
index 2dde542..ce3ae4f 100755
--- a/erpnext/projects/doctype/task/task.py
+++ b/erpnext/projects/doctype/task/task.py
@@ -80,7 +80,7 @@
 				if frappe.db.get_value("Task", d.task, "status") not in ("Completed", "Cancelled"):
 					frappe.throw(
 						_(
-							"Cannot complete task {0} as its dependant task {1} are not ccompleted / cancelled."
+							"Cannot complete task {0} as its dependant task {1} are not completed / cancelled."
 						).format(frappe.bold(self.name), frappe.bold(d.task))
 					)
 
diff --git a/erpnext/projects/doctype/timesheet/timesheet.py b/erpnext/projects/doctype/timesheet/timesheet.py
index 1179364..f3bd09a 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.py
+++ b/erpnext/projects/doctype/timesheet/timesheet.py
@@ -387,6 +387,9 @@
 				"timesheets",
 				{
 					"time_sheet": timesheet.name,
+					"project_name": time_log.project_name,
+					"from_time": time_log.from_time,
+					"to_time": time_log.to_time,
 					"billing_hours": time_log.billing_hours,
 					"billing_amount": time_log.billing_amount,
 					"timesheet_detail": time_log.name,
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index 1f8a5e3..2ce0c7e 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -122,24 +122,16 @@
 	calculate_item_values() {
 		var me = this;
 		if (!this.discount_amount_applied) {
-			$.each(this.frm.doc["items"] || [], function(i, item) {
+			for (const item of this.frm.doc.items || []) {
 				frappe.model.round_floats_in(item);
 				item.net_rate = item.rate;
-
-				if ((!item.qty) && me.frm.doc.is_return) {
-					item.amount = flt(item.rate * -1, precision("amount", item));
-				} else if ((!item.qty) && me.frm.doc.is_debit_note) {
-					item.amount = flt(item.rate, precision("amount", item));
-				} else {
-					item.amount = flt(item.rate * item.qty, precision("amount", item));
-				}
-
-				item.net_amount = item.amount;
+				item.qty = item.qty === undefined ? (me.frm.doc.is_return ? -1 : 1) : item.qty;
+				item.net_amount = item.amount = flt(item.rate * item.qty, precision("amount", item));
 				item.item_tax_amount = 0.0;
 				item.total_weight = flt(item.weight_per_unit * item.stock_qty);
 
 				me.set_in_company_currency(item, ["price_list_rate", "rate", "amount", "net_rate", "net_amount"]);
-			});
+			}
 		}
 	}
 
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 5c1c6d1..3a778fa 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -1473,6 +1473,7 @@
 					"parenttype": d.parenttype,
 					"parent": d.parent,
 					"pricing_rules": d.pricing_rules,
+					"is_free_item": d.is_free_item,
 					"warehouse": d.warehouse,
 					"serial_no": d.serial_no,
 					"batch_no": d.batch_no,
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index accf5f2..ca6a51a 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -26,7 +26,7 @@
 from erpnext.selling.doctype.customer.customer import check_credit_limit
 from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
 from erpnext.stock.doctype.item.item import get_item_defaults
-from erpnext.stock.get_item_details import get_default_bom
+from erpnext.stock.get_item_details import get_default_bom, get_price_list_rate
 from erpnext.stock.stock_balance import get_reserved_qty, update_bin_qty
 
 form_grid_templates = {"items": "templates/form_grid/item_grid.html"}
@@ -590,6 +590,23 @@
 		target.qty = qty - requested_item_qty.get(source.name, 0)
 		target.stock_qty = flt(target.qty) * flt(target.conversion_factor)
 
+		args = target.as_dict().copy()
+		args.update(
+			{
+				"company": source_parent.get("company"),
+				"price_list": frappe.db.get_single_value("Buying Settings", "buying_price_list"),
+				"currency": source_parent.get("currency"),
+				"conversion_rate": source_parent.get("conversion_rate"),
+			}
+		)
+
+		target.rate = flt(
+			get_price_list_rate(args=args, item_doc=frappe.get_cached_doc("Item", target.item_code)).get(
+				"price_list_rate"
+			)
+		)
+		target.amount = target.qty * target.rate
+
 	doc = get_mapped_doc(
 		"Sales Order",
 		source_name,
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index e777f52..d4d7c58 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -552,6 +552,42 @@
 		workflow.is_active = 0
 		workflow.save()
 
+	def test_bin_details_of_packed_item(self):
+		# test Update Items with product bundle
+		if not frappe.db.exists("Item", "_Test Product Bundle Item New"):
+			bundle_item = make_item("_Test Product Bundle Item New", {"is_stock_item": 0})
+			bundle_item.append(
+				"item_defaults", {"company": "_Test Company", "default_warehouse": "_Test Warehouse - _TC"}
+			)
+			bundle_item.save(ignore_permissions=True)
+
+		make_item("_Packed Item New 1", {"is_stock_item": 1})
+		make_product_bundle("_Test Product Bundle Item New", ["_Packed Item New 1"], 2)
+
+		so = make_sales_order(
+			item_code="_Test Product Bundle Item New",
+			warehouse="_Test Warehouse - _TC",
+			transaction_date=add_days(nowdate(), -1),
+			do_not_submit=1,
+		)
+
+		make_stock_entry(item="_Packed Item New 1", target="_Test Warehouse - _TC", qty=120, rate=100)
+
+		bin_details = frappe.db.get_value(
+			"Bin",
+			{"item_code": "_Packed Item New 1", "warehouse": "_Test Warehouse - _TC"},
+			["actual_qty", "projected_qty", "ordered_qty"],
+			as_dict=1,
+		)
+
+		so.transaction_date = nowdate()
+		so.save()
+
+		packed_item = so.packed_items[0]
+		self.assertEqual(flt(bin_details.actual_qty), flt(packed_item.actual_qty))
+		self.assertEqual(flt(bin_details.projected_qty), flt(packed_item.projected_qty))
+		self.assertEqual(flt(bin_details.ordered_qty), flt(packed_item.ordered_qty))
+
 	def test_update_child_product_bundle(self):
 		# test Update Items with product bundle
 		if not frappe.db.exists("Item", "_Product Bundle Item"):
diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py
index 95bbf84..2fdfcf6 100644
--- a/erpnext/setup/doctype/item_group/item_group.py
+++ b/erpnext/setup/doctype/item_group/item_group.py
@@ -148,12 +148,12 @@
 
 
 def get_parent_item_groups(item_group_name, from_item=False):
-	base_nav_page = {"name": _("Shop by Category"), "route": "/shop-by-category"}
+	base_nav_page = {"name": _("All Products"), "route": "/all-products"}
 
 	if from_item and frappe.request.environ.get("HTTP_REFERER"):
 		# base page after 'Home' will vary on Item page
 		last_page = frappe.request.environ["HTTP_REFERER"].split("/")[-1].split("?")[0]
-		if last_page and last_page in ("shop-by-category", "all-products"):
+		if last_page and last_page == "shop-by-category":
 			base_nav_page_title = " ".join(last_page.split("-")).title()
 			base_nav_page = {"name": _(base_nav_page_title), "route": "/" + last_page}
 
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index d747383..903e2af 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -490,6 +490,46 @@
 
 		self.assertEqual(gle_warehouse_amount, 1400)
 
+	def test_bin_details_of_packed_item(self):
+		from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
+		from erpnext.stock.doctype.item.test_item import make_item
+
+		# test Update Items with product bundle
+		if not frappe.db.exists("Item", "_Test Product Bundle Item New"):
+			bundle_item = make_item("_Test Product Bundle Item New", {"is_stock_item": 0})
+			bundle_item.append(
+				"item_defaults", {"company": "_Test Company", "default_warehouse": "_Test Warehouse - _TC"}
+			)
+			bundle_item.save(ignore_permissions=True)
+
+		make_item("_Packed Item New 1", {"is_stock_item": 1})
+		make_product_bundle("_Test Product Bundle Item New", ["_Packed Item New 1"], 2)
+
+		si = create_delivery_note(
+			item_code="_Test Product Bundle Item New",
+			update_stock=1,
+			warehouse="_Test Warehouse - _TC",
+			transaction_date=add_days(nowdate(), -1),
+			do_not_submit=1,
+		)
+
+		make_stock_entry(item="_Packed Item New 1", target="_Test Warehouse - _TC", qty=120, rate=100)
+
+		bin_details = frappe.db.get_value(
+			"Bin",
+			{"item_code": "_Packed Item New 1", "warehouse": "_Test Warehouse - _TC"},
+			["actual_qty", "projected_qty", "ordered_qty"],
+			as_dict=1,
+		)
+
+		si.transaction_date = nowdate()
+		si.save()
+
+		packed_item = si.packed_items[0]
+		self.assertEqual(flt(bin_details.actual_qty), flt(packed_item.actual_qty))
+		self.assertEqual(flt(bin_details.projected_qty), flt(packed_item.projected_qty))
+		self.assertEqual(flt(bin_details.ordered_qty), flt(packed_item.ordered_qty))
+
 	def test_return_for_serialized_items(self):
 		se = make_serialized_item()
 		serial_no = get_serial_nos(se.get("items")[0].serial_no)[0]
@@ -650,6 +690,11 @@
 		update_delivery_note_status(dn.name, "Closed")
 		self.assertEqual(frappe.db.get_value("Delivery Note", dn.name, "Status"), "Closed")
 
+		# Check cancelling closed delivery note
+		dn.load_from_db()
+		dn.cancel()
+		self.assertEqual(dn.status, "Cancelled")
+
 	def test_dn_billing_status_case1(self):
 		# SO -> DN -> SI
 		so = make_sales_order()
diff --git a/erpnext/stock/doctype/item_attribute/item_attribute.py b/erpnext/stock/doctype/item_attribute/item_attribute.py
index 391ff06..ac4c313 100644
--- a/erpnext/stock/doctype/item_attribute/item_attribute.py
+++ b/erpnext/stock/doctype/item_attribute/item_attribute.py
@@ -74,11 +74,10 @@
 	def validate_duplication(self):
 		values, abbrs = [], []
 		for d in self.item_attribute_values:
-			d.abbr = d.abbr.upper()
-			if d.attribute_value in values:
-				frappe.throw(_("{0} must appear only once").format(d.attribute_value))
+			if d.attribute_value.lower() in map(str.lower, values):
+				frappe.throw(_("Attribute value: {0} must appear only once").format(d.attribute_value.title()))
 			values.append(d.attribute_value)
 
-			if d.abbr in abbrs:
-				frappe.throw(_("{0} must appear only once").format(d.abbr))
+			if d.abbr.lower() in map(str.lower, abbrs):
+				frappe.throw(_("Abbreviation: {0} must appear only once").format(d.abbr.title()))
 			abbrs.append(d.abbr)
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 9c6f4f4..808f19e 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -11,7 +11,7 @@
 from frappe.model.document import Document
 from frappe.model.mapper import map_child_doc
 from frappe.query_builder import Case
-from frappe.query_builder.functions import Locate
+from frappe.query_builder.functions import IfNull, Locate, Sum
 from frappe.utils import cint, floor, flt, today
 from frappe.utils.nestedset import get_descendants_of
 
@@ -503,42 +503,30 @@
 def get_available_item_locations_for_batched_item(
 	item_code, from_warehouses, required_qty, company
 ):
-	warehouse_condition = "and warehouse in %(warehouses)s" if from_warehouses else ""
-	batch_locations = frappe.db.sql(
-		"""
-		SELECT
-			sle.`warehouse`,
-			sle.`batch_no`,
-			SUM(sle.`actual_qty`) AS `qty`
-		FROM
-			`tabStock Ledger Entry` sle, `tabBatch` batch
-		WHERE
-			sle.batch_no = batch.name
-			and sle.`item_code`=%(item_code)s
-			and sle.`company` = %(company)s
-			and batch.disabled = 0
-			and sle.is_cancelled=0
-			and IFNULL(batch.`expiry_date`, '2200-01-01') > %(today)s
-			{warehouse_condition}
-		GROUP BY
-			sle.`warehouse`,
-			sle.`batch_no`,
-			sle.`item_code`
-		HAVING `qty` > 0
-		ORDER BY IFNULL(batch.`expiry_date`, '2200-01-01'), batch.`creation`, sle.`batch_no`, sle.`warehouse`
-	""".format(
-			warehouse_condition=warehouse_condition
-		),
-		{  # nosec
-			"item_code": item_code,
-			"company": company,
-			"today": today(),
-			"warehouses": from_warehouses,
-		},
-		as_dict=1,
+	sle = frappe.qb.DocType("Stock Ledger Entry")
+	batch = frappe.qb.DocType("Batch")
+
+	query = (
+		frappe.qb.from_(sle)
+		.from_(batch)
+		.select(sle.warehouse, sle.batch_no, Sum(sle.actual_qty).as_("qty"))
+		.where(
+			(sle.batch_no == batch.name)
+			& (sle.item_code == item_code)
+			& (sle.company == company)
+			& (batch.disabled == 0)
+			& (sle.is_cancelled == 0)
+			& (IfNull(batch.expiry_date, "2200-01-01") > today())
+		)
+		.groupby(sle.warehouse, sle.batch_no, sle.item_code)
+		.having(Sum(sle.actual_qty) > 0)
+		.orderby(IfNull(batch.expiry_date, "2200-01-01"), batch.creation, sle.batch_no, sle.warehouse)
 	)
 
-	return batch_locations
+	if from_warehouses:
+		query = query.where(sle.warehouse.isin(from_warehouses))
+
+	return query.run(as_dict=True)
 
 
 def get_available_item_locations_for_serial_and_batched_item(
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 363dc0a..5af1441 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -236,8 +236,10 @@
 
 	validate_end_of_life(item.name, item.end_of_life, item.disabled)
 
-	if args.transaction_type == "selling" and cint(item.has_variants):
-		throw(_("Item {0} is a template, please select one of its variants").format(item.name))
+	if cint(item.has_variants):
+		msg = f"Item {item.name} is a template, please select one of its variants"
+
+		throw(_(msg), title=_("Template Item Selected"))
 
 	elif args.transaction_type == "buying" and args.doctype != "Material Request":
 		if args.get("is_subcontracted"):
diff --git a/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json b/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json
index 3675a4e..d77e774 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json
+++ b/erpnext/subcontracting/doctype/subcontracting_order_item/subcontracting_order_item.json
@@ -1,352 +1,353 @@
 {
-    "actions": [],
-    "autoname": "hash",
-    "creation": "2022-04-01 19:26:31.475015",
-    "doctype": "DocType",
-    "document_type": "Document",
-    "editable_grid": 1,
-    "engine": "InnoDB",
-    "field_order": [
-        "item_code",
-        "item_name",
-        "bom",
-        "include_exploded_items",
-        "column_break_3",
-        "schedule_date",
-        "expected_delivery_date",
-        "description_section",
-        "description",
-        "column_break_8",
-        "image",
-        "image_view",
-        "quantity_and_rate_section",
-        "qty",
-        "received_qty",
-        "returned_qty",
-        "column_break_13",
-        "stock_uom",
-        "conversion_factor",
-        "section_break_16",
-        "rate",
-        "amount",
-        "column_break_19",
-        "rm_cost_per_qty",
-        "service_cost_per_qty",
-        "additional_cost_per_qty",
-        "warehouse_section",
-        "warehouse",
-        "accounting_details_section",
-        "expense_account",
-        "manufacture_section",
-        "manufacturer",
-        "manufacturer_part_no",
-        "accounting_dimensions_section",
-        "cost_center",
-        "dimension_col_break",
-        "project",
-        "section_break_34",
-        "page_break"
-    ],
-    "fields": [
-        {
-            "bold": 1,
-            "columns": 2,
-            "fieldname": "item_code",
-            "fieldtype": "Link",
-            "in_list_view": 1,
-            "label": "Item Code",
-            "options": "Item",
-            "read_only": 1,
-            "reqd": 1,
-            "search_index": 1
-        },
-        {
-            "fetch_from": "item_code.item_name",
-            "fetch_if_empty": 1,
-            "fieldname": "item_name",
-            "fieldtype": "Data",
-            "in_global_search": 1,
-            "label": "Item Name",
-            "print_hide": 1,
-            "reqd": 1
-        },
-        {
-            "fieldname": "column_break_3",
-            "fieldtype": "Column Break"
-        },
-        {
-            "bold": 1,
-            "columns": 2,
-            "fieldname": "schedule_date",
-            "fieldtype": "Date",
-            "label": "Required By",
-            "print_hide": 1,
-            "read_only": 1
-        },
-        {
-            "allow_on_submit": 1,
-            "bold": 1,
-            "fieldname": "expected_delivery_date",
-            "fieldtype": "Date",
-            "label": "Expected Delivery Date",
-            "search_index": 1
-        },
-        {
-            "collapsible": 1,
-            "fieldname": "description_section",
-            "fieldtype": "Section Break",
-            "label": "Description"
-        },
-        {
-            "fetch_from": "item_code.description",
-            "fetch_if_empty": 1,
-            "fieldname": "description",
-            "fieldtype": "Text Editor",
-            "label": "Description",
-            "print_width": "300px",
-            "reqd": 1,
-            "width": "300px"
-        },
-        {
-            "fieldname": "column_break_8",
-            "fieldtype": "Column Break"
-        },
-        {
-            "fieldname": "image",
-            "fieldtype": "Attach",
-            "hidden": 1,
-            "label": "Image"
-        },
-        {
-            "fieldname": "image_view",
-            "fieldtype": "Image",
-            "label": "Image View",
-            "options": "image",
-            "print_hide": 1
-        },
-        {
-            "fieldname": "quantity_and_rate_section",
-            "fieldtype": "Section Break",
-            "label": "Quantity and Rate"
-        },
-        {
-            "bold": 1,
-            "columns": 1,
-            "default": "1",
-            "fieldname": "qty",
-            "fieldtype": "Float",
-            "in_list_view": 1,
-            "label": "Quantity",
-            "print_width": "60px",
-            "read_only": 1,
-            "reqd": 1,
-            "width": "60px"
-        },
-        {
-            "fieldname": "column_break_13",
-            "fieldtype": "Column Break",
-            "print_hide": 1
-        },
-        {
-            "fieldname": "stock_uom",
-            "fieldtype": "Link",
-            "label": "Stock UOM",
-            "options": "UOM",
-            "print_width": "100px",
-            "read_only": 1,
-            "reqd": 1,
-            "width": "100px"
-        },
-        {
-            "default": "1",
-            "fieldname": "conversion_factor",
-            "fieldtype": "Float",
-            "hidden": 1,
-            "label": "Conversion Factor",
-            "read_only": 1
-        },
-        {
-            "fieldname": "section_break_16",
-            "fieldtype": "Section Break"
-        },
-        {
-            "bold": 1,
-            "columns": 2,
-            "fetch_from": "item_code.standard_rate",
-            "fetch_if_empty": 1,
-            "fieldname": "rate",
-            "fieldtype": "Currency",
-            "in_list_view": 1,
-            "label": "Rate",
-            "options": "currency",
-            "read_only": 1,
-            "reqd": 1
-        },
-        {
-            "fieldname": "column_break_19",
-            "fieldtype": "Column Break"
-        },
-        {
-            "columns": 2,
-            "fieldname": "amount",
-            "fieldtype": "Currency",
-            "in_list_view": 1,
-            "label": "Amount",
-            "options": "currency",
-            "read_only": 1,
-            "reqd": 1
-        },
-        {
-            "fieldname": "warehouse_section",
-            "fieldtype": "Section Break",
-            "label": "Warehouse Details"
-        },
-        {
-            "fieldname": "warehouse",
-            "fieldtype": "Link",
-            "label": "Warehouse",
-            "options": "Warehouse",
-            "print_hide": 1,
-            "reqd": 1
-        },
-        {
-            "collapsible": 1,
-            "fieldname": "accounting_details_section",
-            "fieldtype": "Section Break",
-            "label": "Accounting Details"
-        },
-        {
-            "fieldname": "expense_account",
-            "fieldtype": "Link",
-            "label": "Expense Account",
-            "options": "Account",
-            "print_hide": 1
-        },
-        {
-            "collapsible": 1,
-            "fieldname": "manufacture_section",
-            "fieldtype": "Section Break",
-            "label": "Manufacture"
-        },
-        {
-            "fieldname": "manufacturer",
-            "fieldtype": "Link",
-            "label": "Manufacturer",
-            "options": "Manufacturer"
-        },
-        {
-            "fieldname": "manufacturer_part_no",
-            "fieldtype": "Data",
-            "label": "Manufacturer Part Number"
-        },
-        {
-            "depends_on": "item_code",
-            "fetch_from": "item_code.default_bom",
-            "fieldname": "bom",
-            "fieldtype": "Link",
-            "in_list_view": 1,
-            "label": "BOM",
-            "options": "BOM",
-            "print_hide": 1,
-            "reqd": 1
-        },
-        {
-            "default": "0",
-            "fieldname": "include_exploded_items",
-            "fieldtype": "Check",
-            "label": "Include Exploded Items",
-            "print_hide": 1
-        },
-        {
-            "fieldname": "service_cost_per_qty",
-            "fieldtype": "Currency",
-            "label": "Service Cost Per Qty",
-            "read_only": 1,
-            "reqd": 1
-        },
-        {
-            "default": "0",
-            "fieldname": "additional_cost_per_qty",
-            "fieldtype": "Currency",
-            "label": "Additional Cost Per Qty",
-            "read_only": 1
-        },
-        {
-            "fieldname": "rm_cost_per_qty",
-            "fieldtype": "Currency",
-            "label": "Raw Material Cost Per Qty",
-            "no_copy": 1,
-            "read_only": 1
-        },
-        {
-            "allow_on_submit": 1,
-            "default": "0",
-            "fieldname": "page_break",
-            "fieldtype": "Check",
-            "label": "Page Break",
-            "no_copy": 1,
-            "print_hide": 1
-        },
-        {
-            "fieldname": "section_break_34",
-            "fieldtype": "Section Break"
-        },
-        {
-            "depends_on": "received_qty",
-            "fieldname": "received_qty",
-            "fieldtype": "Float",
-            "label": "Received Qty",
-            "no_copy": 1,
-            "print_hide": 1,
-            "read_only": 1
-        },
-        {
-            "depends_on": "returned_qty",
-            "fieldname": "returned_qty",
-            "fieldtype": "Float",
-            "label": "Returned Qty",
-            "no_copy": 1,
-            "print_hide": 1,
-            "read_only": 1
-        },
-        {
-            "collapsible": 1,
-            "fieldname": "accounting_dimensions_section",
-            "fieldtype": "Section Break",
-            "label": "Accounting Dimensions"
-        },
-        {
-            "fieldname": "cost_center",
-            "fieldtype": "Link",
-            "label": "Cost Center",
-            "options": "Cost Center"
-        },
-        {
-            "fieldname": "dimension_col_break",
-            "fieldtype": "Column Break"
-        },
-        {
-            "fieldname": "project",
-            "fieldtype": "Link",
-            "label": "Project",
-            "options": "Project"
-        }
-    ],
-    "idx": 1,
-    "index_web_pages_for_search": 1,
-    "istable": 1,
-    "links": [],
-    "modified": "2022-08-15 14:25:45.177703",
-    "modified_by": "Administrator",
-    "module": "Subcontracting",
-    "name": "Subcontracting Order Item",
-    "naming_rule": "Random",
-    "owner": "Administrator",
-    "permissions": [],
-    "quick_entry": 1,
-    "search_fields": "item_name",
-    "sort_field": "modified",
-    "sort_order": "DESC",
-    "states": [],
-    "track_changes": 1
+ "actions": [],
+ "autoname": "hash",
+ "creation": "2022-04-01 19:26:31.475015",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "item_code",
+  "item_name",
+  "bom",
+  "include_exploded_items",
+  "column_break_3",
+  "schedule_date",
+  "expected_delivery_date",
+  "description_section",
+  "description",
+  "column_break_8",
+  "image",
+  "image_view",
+  "quantity_and_rate_section",
+  "qty",
+  "received_qty",
+  "returned_qty",
+  "column_break_13",
+  "stock_uom",
+  "conversion_factor",
+  "section_break_16",
+  "rate",
+  "amount",
+  "column_break_19",
+  "rm_cost_per_qty",
+  "service_cost_per_qty",
+  "additional_cost_per_qty",
+  "warehouse_section",
+  "warehouse",
+  "accounting_details_section",
+  "expense_account",
+  "manufacture_section",
+  "manufacturer",
+  "manufacturer_part_no",
+  "accounting_dimensions_section",
+  "cost_center",
+  "dimension_col_break",
+  "project",
+  "section_break_34",
+  "page_break"
+ ],
+ "fields": [
+  {
+   "bold": 1,
+   "columns": 2,
+   "fieldname": "item_code",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Item Code",
+   "options": "Item",
+   "read_only": 1,
+   "reqd": 1,
+   "search_index": 1
+  },
+  {
+   "fetch_from": "item_code.item_name",
+   "fetch_if_empty": 1,
+   "fieldname": "item_name",
+   "fieldtype": "Data",
+   "in_global_search": 1,
+   "label": "Item Name",
+   "print_hide": 1,
+   "reqd": 1
+  },
+  {
+   "fieldname": "column_break_3",
+   "fieldtype": "Column Break"
+  },
+  {
+   "bold": 1,
+   "columns": 2,
+   "fieldname": "schedule_date",
+   "fieldtype": "Date",
+   "label": "Required By",
+   "print_hide": 1,
+   "read_only": 1
+  },
+  {
+   "allow_on_submit": 1,
+   "bold": 1,
+   "fieldname": "expected_delivery_date",
+   "fieldtype": "Date",
+   "label": "Expected Delivery Date",
+   "search_index": 1
+  },
+  {
+   "collapsible": 1,
+   "fieldname": "description_section",
+   "fieldtype": "Section Break",
+   "label": "Description"
+  },
+  {
+   "fetch_from": "item_code.description",
+   "fetch_if_empty": 1,
+   "fieldname": "description",
+   "fieldtype": "Text Editor",
+   "label": "Description",
+   "print_width": "300px",
+   "reqd": 1,
+   "width": "300px"
+  },
+  {
+   "fieldname": "column_break_8",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "image",
+   "fieldtype": "Attach",
+   "hidden": 1,
+   "label": "Image"
+  },
+  {
+   "fieldname": "image_view",
+   "fieldtype": "Image",
+   "label": "Image View",
+   "options": "image",
+   "print_hide": 1
+  },
+  {
+   "fieldname": "quantity_and_rate_section",
+   "fieldtype": "Section Break",
+   "label": "Quantity and Rate"
+  },
+  {
+   "bold": 1,
+   "columns": 1,
+   "default": "1",
+   "fieldname": "qty",
+   "fieldtype": "Float",
+   "in_list_view": 1,
+   "label": "Quantity",
+   "print_width": "60px",
+   "read_only": 1,
+   "reqd": 1,
+   "width": "60px"
+  },
+  {
+   "fieldname": "column_break_13",
+   "fieldtype": "Column Break",
+   "print_hide": 1
+  },
+  {
+   "fieldname": "stock_uom",
+   "fieldtype": "Link",
+   "label": "Stock UOM",
+   "options": "UOM",
+   "print_width": "100px",
+   "read_only": 1,
+   "reqd": 1,
+   "width": "100px"
+  },
+  {
+   "default": "1",
+   "fieldname": "conversion_factor",
+   "fieldtype": "Float",
+   "hidden": 1,
+   "label": "Conversion Factor",
+   "read_only": 1
+  },
+  {
+   "fieldname": "section_break_16",
+   "fieldtype": "Section Break"
+  },
+  {
+   "bold": 1,
+   "columns": 2,
+   "fetch_from": "item_code.standard_rate",
+   "fetch_if_empty": 1,
+   "fieldname": "rate",
+   "fieldtype": "Currency",
+   "in_list_view": 1,
+   "label": "Rate",
+   "options": "currency",
+   "read_only": 1,
+   "reqd": 1
+  },
+  {
+   "fieldname": "column_break_19",
+   "fieldtype": "Column Break"
+  },
+  {
+   "columns": 2,
+   "fieldname": "amount",
+   "fieldtype": "Currency",
+   "in_list_view": 1,
+   "label": "Amount",
+   "options": "currency",
+   "read_only": 1,
+   "reqd": 1
+  },
+  {
+   "fieldname": "warehouse_section",
+   "fieldtype": "Section Break",
+   "label": "Warehouse Details"
+  },
+  {
+   "fieldname": "warehouse",
+   "fieldtype": "Link",
+   "label": "Warehouse",
+   "options": "Warehouse",
+   "print_hide": 1,
+   "reqd": 1
+  },
+  {
+   "collapsible": 1,
+   "fieldname": "accounting_details_section",
+   "fieldtype": "Section Break",
+   "label": "Accounting Details"
+  },
+  {
+   "fieldname": "expense_account",
+   "fieldtype": "Link",
+   "label": "Expense Account",
+   "options": "Account",
+   "print_hide": 1
+  },
+  {
+   "collapsible": 1,
+   "fieldname": "manufacture_section",
+   "fieldtype": "Section Break",
+   "label": "Manufacture"
+  },
+  {
+   "fieldname": "manufacturer",
+   "fieldtype": "Link",
+   "label": "Manufacturer",
+   "options": "Manufacturer"
+  },
+  {
+   "fieldname": "manufacturer_part_no",
+   "fieldtype": "Data",
+   "label": "Manufacturer Part Number"
+  },
+  {
+   "depends_on": "item_code",
+   "fetch_from": "item_code.default_bom",
+   "fetch_if_empty": 1,
+   "fieldname": "bom",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "BOM",
+   "options": "BOM",
+   "print_hide": 1,
+   "reqd": 1
+  },
+  {
+   "default": "0",
+   "fieldname": "include_exploded_items",
+   "fieldtype": "Check",
+   "label": "Include Exploded Items",
+   "print_hide": 1
+  },
+  {
+   "fieldname": "service_cost_per_qty",
+   "fieldtype": "Currency",
+   "label": "Service Cost Per Qty",
+   "read_only": 1,
+   "reqd": 1
+  },
+  {
+   "default": "0",
+   "fieldname": "additional_cost_per_qty",
+   "fieldtype": "Currency",
+   "label": "Additional Cost Per Qty",
+   "read_only": 1
+  },
+  {
+   "fieldname": "rm_cost_per_qty",
+   "fieldtype": "Currency",
+   "label": "Raw Material Cost Per Qty",
+   "no_copy": 1,
+   "read_only": 1
+  },
+  {
+   "allow_on_submit": 1,
+   "default": "0",
+   "fieldname": "page_break",
+   "fieldtype": "Check",
+   "label": "Page Break",
+   "no_copy": 1,
+   "print_hide": 1
+  },
+  {
+   "fieldname": "section_break_34",
+   "fieldtype": "Section Break"
+  },
+  {
+   "depends_on": "received_qty",
+   "fieldname": "received_qty",
+   "fieldtype": "Float",
+   "label": "Received Qty",
+   "no_copy": 1,
+   "print_hide": 1,
+   "read_only": 1
+  },
+  {
+   "depends_on": "returned_qty",
+   "fieldname": "returned_qty",
+   "fieldtype": "Float",
+   "label": "Returned Qty",
+   "no_copy": 1,
+   "print_hide": 1,
+   "read_only": 1
+  },
+  {
+   "collapsible": 1,
+   "fieldname": "accounting_dimensions_section",
+   "fieldtype": "Section Break",
+   "label": "Accounting Dimensions"
+  },
+  {
+   "fieldname": "cost_center",
+   "fieldtype": "Link",
+   "label": "Cost Center",
+   "options": "Cost Center"
+  },
+  {
+   "fieldname": "dimension_col_break",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "project",
+   "fieldtype": "Link",
+   "label": "Project",
+   "options": "Project"
+  }
+ ],
+ "idx": 1,
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2023-01-20 23:25:45.363281",
+ "modified_by": "Administrator",
+ "module": "Subcontracting",
+ "name": "Subcontracting Order Item",
+ "naming_rule": "Random",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "search_fields": "item_name",
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": [],
+ "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
index e8faa48..f4fd4de 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py
@@ -262,15 +262,17 @@
 	def get_gl_entries(self, warehouse_account=None):
 		from erpnext.accounts.general_ledger import process_gl_map
 
+		if not erpnext.is_perpetual_inventory_enabled(self.company):
+			return []
+
 		gl_entries = []
 		self.make_item_gl_entries(gl_entries, warehouse_account)
 
 		return process_gl_map(gl_entries)
 
 	def make_item_gl_entries(self, gl_entries, warehouse_account=None):
-		if erpnext.is_perpetual_inventory_enabled(self.company):
-			stock_rbnb = self.get_company_default("stock_received_but_not_billed")
-			expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
+		stock_rbnb = self.get_company_default("stock_received_but_not_billed")
+		expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
 
 		warehouse_with_no_account = []