Merge pull request #39462 from GursheenK/pdf-party-ap-ar

fix: party field in PDF for AP / AR reports
diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
index 9cf4e4f..26984d9 100644
--- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
+++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json
@@ -64,6 +64,7 @@
   "warehouse",
   "from_warehouse",
   "quality_inspection",
+  "add_serial_batch_bundle",
   "serial_and_batch_bundle",
   "serial_no",
   "col_br_wh",
@@ -913,12 +914,18 @@
    "fieldtype": "Link",
    "label": "WIP Composite Asset",
    "options": "Asset"
+  },
+  {
+   "depends_on": "eval:parent.update_stock === 1",
+   "fieldname": "add_serial_batch_bundle",
+   "fieldtype": "Button",
+   "label": "Add Serial / Batch No"
   }
  ],
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2023-12-25 22:00:28.043555",
+ "modified": "2024-01-21 19:46:25.537861",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Purchase Invoice Item",
diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py
index 004a929..aadd873 100644
--- a/erpnext/accounts/report/financial_statements.py
+++ b/erpnext/accounts/report/financial_statements.py
@@ -8,17 +8,7 @@
 
 import frappe
 from frappe import _
-from frappe.utils import (
-	add_days,
-	add_months,
-	cint,
-	cstr,
-	flt,
-	formatdate,
-	get_first_day,
-	getdate,
-	today,
-)
+from frappe.utils import add_days, add_months, cint, cstr, flt, formatdate, get_first_day, getdate
 
 from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import (
 	get_accounting_dimensions,
@@ -53,8 +43,6 @@
 		year_start_date = getdate(period_start_date)
 		year_end_date = getdate(period_end_date)
 
-	year_end_date = getdate(today()) if year_end_date > getdate(today()) else year_end_date
-
 	months_to_add = {"Yearly": 12, "Half-Yearly": 6, "Quarterly": 3, "Monthly": 1}[periodicity]
 
 	period_list = []
diff --git a/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py b/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py
index d045d91..4a80dd0 100644
--- a/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py
+++ b/erpnext/accounts/report/tax_withholding_details/tax_withholding_details.py
@@ -46,12 +46,10 @@
 
 	out = []
 	for name, details in gle_map.items():
-		tax_amount, total_amount, grand_total, base_total = 0, 0, 0, 0
-		bill_no, bill_date = "", ""
-		tax_withholding_category = tax_category_map.get(name)
-		rate = tax_rate_map.get(tax_withholding_category)
-
 		for entry in details:
+			tax_amount, total_amount, grand_total, base_total = 0, 0, 0, 0
+			tax_withholding_category, rate = None, None
+			bill_no, bill_date = "", ""
 			party = entry.party or entry.against
 			posting_date = entry.posting_date
 			voucher_type = entry.voucher_type
@@ -61,12 +59,19 @@
 				if party_list:
 					party = party_list[0]
 
-			if not tax_withholding_category:
-				tax_withholding_category = party_map.get(party, {}).get("tax_withholding_category")
-				rate = tax_rate_map.get(tax_withholding_category)
-
-			if entry.account in tds_accounts:
+			if entry.account in tds_accounts.keys():
 				tax_amount += entry.credit - entry.debit
+				# infer tax withholding category from the account if it's the single account for this category
+				tax_withholding_category = tds_accounts.get(entry.account)
+				rate = tax_rate_map.get(tax_withholding_category)
+				# or else the consolidated value from the voucher document
+				if not tax_withholding_category:
+					# or else from the party default
+					tax_withholding_category = tax_category_map.get(name)
+					rate = tax_rate_map.get(tax_withholding_category)
+				if not tax_withholding_category:
+					tax_withholding_category = party_map.get(party, {}).get("tax_withholding_category")
+					rate = tax_rate_map.get(tax_withholding_category)
 
 			if net_total_map.get(name):
 				if voucher_type == "Journal Entry" and tax_amount and rate:
@@ -80,41 +85,41 @@
 			else:
 				total_amount += entry.credit
 
-		if tax_amount:
-			if party_map.get(party, {}).get("party_type") == "Supplier":
-				party_name = "supplier_name"
-				party_type = "supplier_type"
-			else:
-				party_name = "customer_name"
-				party_type = "customer_type"
+			if tax_amount:
+				if party_map.get(party, {}).get("party_type") == "Supplier":
+					party_name = "supplier_name"
+					party_type = "supplier_type"
+				else:
+					party_name = "customer_name"
+					party_type = "customer_type"
 
-			row = {
-				"pan"
-				if frappe.db.has_column(filters.party_type, "pan")
-				else "tax_id": party_map.get(party, {}).get("pan"),
-				"party": party_map.get(party, {}).get("name"),
-			}
-
-			if filters.naming_series == "Naming Series":
-				row.update({"party_name": party_map.get(party, {}).get(party_name)})
-
-			row.update(
-				{
-					"section_code": tax_withholding_category or "",
-					"entity_type": party_map.get(party, {}).get(party_type),
-					"rate": rate,
-					"total_amount": total_amount,
-					"grand_total": grand_total,
-					"base_total": base_total,
-					"tax_amount": tax_amount,
-					"transaction_date": posting_date,
-					"transaction_type": voucher_type,
-					"ref_no": name,
-					"supplier_invoice_no": bill_no,
-					"supplier_invoice_date": bill_date,
+				row = {
+					"pan"
+					if frappe.db.has_column(filters.party_type, "pan")
+					else "tax_id": party_map.get(party, {}).get("pan"),
+					"party": party_map.get(party, {}).get("name"),
 				}
-			)
-			out.append(row)
+
+				if filters.naming_series == "Naming Series":
+					row.update({"party_name": party_map.get(party, {}).get(party_name)})
+
+				row.update(
+					{
+						"section_code": tax_withholding_category or "",
+						"entity_type": party_map.get(party, {}).get(party_type),
+						"rate": rate,
+						"total_amount": total_amount,
+						"grand_total": grand_total,
+						"base_total": base_total,
+						"tax_amount": tax_amount,
+						"transaction_date": posting_date,
+						"transaction_type": voucher_type,
+						"ref_no": name,
+						"supplier_invoice_no": bill_no,
+						"supplier_invoice_date": bill_date,
+					}
+				)
+				out.append(row)
 
 	out.sort(key=lambda x: x["section_code"])
 
@@ -282,11 +287,20 @@
 	journal_entry_party_map = frappe._dict()
 	bank_accounts = frappe.get_all("Account", {"is_group": 0, "account_type": "Bank"}, pluck="name")
 
-	tds_accounts = frappe.get_all(
-		"Tax Withholding Account", {"company": filters.get("company")}, pluck="account"
+	_tds_accounts = frappe.get_all(
+		"Tax Withholding Account",
+		{"company": filters.get("company")},
+		["account", "parent"],
 	)
+	tds_accounts = {}
+	for tds_acc in _tds_accounts:
+		# if it turns out not to be the only tax withholding category, then don't include in the map
+		if tds_accounts.get(tds_acc["account"]):
+			tds_accounts[tds_acc["account"]] = None
+		else:
+			tds_accounts[tds_acc["account"]] = tds_acc["parent"]
 
-	tds_docs = get_tds_docs_query(filters, bank_accounts, tds_accounts).run(as_dict=True)
+	tds_docs = get_tds_docs_query(filters, bank_accounts, list(tds_accounts.keys())).run(as_dict=True)
 
 	for d in tds_docs:
 		if d.voucher_type == "Purchase Invoice":
diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py
index aa5db57..f6e9a07 100644
--- a/erpnext/manufacturing/doctype/work_order/test_work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py
@@ -998,12 +998,6 @@
 
 		make_job_card(wo_order.name, operations)
 		job_card = frappe.db.get_value("Job Card", {"work_order": wo_order.name, "docstatus": 0}, "name")
-		update_job_card(job_card, 10, 2)
-
-		stock_entry = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 10))
-		for row in stock_entry.items:
-			if row.is_scrap_item:
-				self.assertEqual(row.qty, 2)
 
 	def test_close_work_order(self):
 		items = [
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index a6206ac..0370666 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -439,7 +439,7 @@
 		reposting_data = get_reposting_data(doc.reposting_data_file)
 
 	if reposting_data and reposting_data.distinct_item_and_warehouse:
-		return reposting_data.distinct_item_and_warehouse
+		return parse_distinct_items_and_warehouses(reposting_data.distinct_item_and_warehouse)
 
 	distinct_item_warehouses = {}
 
@@ -457,6 +457,16 @@
 	return distinct_item_warehouses
 
 
+def parse_distinct_items_and_warehouses(distinct_items_and_warehouses):
+	new_dict = frappe._dict({})
+
+	# convert string keys to tuple
+	for k, v in distinct_items_and_warehouses.items():
+		new_dict[frappe.safe_eval(k)] = frappe._dict(v)
+
+	return new_dict
+
+
 def get_affected_transactions(doc, reposting_data=None) -> Set[Tuple[str, str]]:
 	if not reposting_data and doc and doc.reposting_data_file:
 		reposting_data = get_reposting_data(doc.reposting_data_file)