Merge pull request #27348 from deepeshgarg007/advance_tds_allocation_gl

fix (refactor): Tax Withholding for Advances using Payment Entry against suppliers
diff --git a/erpnext/accounts/doctype/advance_tax/__init__.py b/erpnext/accounts/doctype/advance_tax/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/doctype/advance_tax/__init__.py
diff --git a/erpnext/accounts/doctype/advance_tax/advance_tax.json b/erpnext/accounts/doctype/advance_tax/advance_tax.json
new file mode 100644
index 0000000..68706ab
--- /dev/null
+++ b/erpnext/accounts/doctype/advance_tax/advance_tax.json
@@ -0,0 +1,56 @@
+{
+ "actions": [],
+ "allow_rename": 1,
+ "creation": "2021-11-25 10:24:39.836195",
+ "doctype": "DocType",
+ "engine": "InnoDB",
+ "field_order": [
+  "reference_type",
+  "reference_name",
+  "reference_detail",
+  "account_head",
+  "allocated_amount"
+ ],
+ "fields": [
+  {
+   "fieldname": "reference_type",
+   "fieldtype": "Link",
+   "label": "Reference Type",
+   "options": "DocType"
+  },
+  {
+   "fieldname": "reference_name",
+   "fieldtype": "Dynamic Link",
+   "label": "Reference Name",
+   "options": "reference_type"
+  },
+  {
+   "fieldname": "reference_detail",
+   "fieldtype": "Data",
+   "label": "Reference Detail"
+  },
+  {
+   "fieldname": "account_head",
+   "fieldtype": "Link",
+   "label": "Account Head",
+   "options": "Account"
+  },
+  {
+   "fieldname": "allocated_amount",
+   "fieldtype": "Currency",
+   "label": "Allocated Amount",
+   "options": "party_account_currency"
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-11-25 10:27:51.712286",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Advance Tax",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC"
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/advance_tax/advance_tax.py b/erpnext/accounts/doctype/advance_tax/advance_tax.py
new file mode 100644
index 0000000..2e784ef
--- /dev/null
+++ b/erpnext/accounts/doctype/advance_tax/advance_tax.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+
+class AdvanceTax(Document):
+	pass
diff --git a/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.json b/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.json
index 4d63499..05b284a 100644
--- a/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.json
+++ b/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.json
@@ -25,8 +25,7 @@
   "allocated_amount",
   "column_break_13",
   "base_tax_amount",
-  "base_total",
-  "base_allocated_amount"
+  "base_total"
  ],
  "fields": [
   {
@@ -169,12 +168,6 @@
    "options": "currency"
   },
   {
-   "fieldname": "base_allocated_amount",
-   "fieldtype": "Currency",
-   "label": "Allocated Amount (Company Currency)",
-   "options": "Company:company:default_currency"
-  },
-  {
    "fetch_from": "account_head.account_currency",
    "fieldname": "currency",
    "fieldtype": "Link",
@@ -186,7 +179,7 @@
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2021-06-09 11:46:58.373170",
+ "modified": "2021-11-25 11:10:10.945027",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Advance Taxes and Charges",
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.json b/erpnext/accounts/doctype/payment_entry/payment_entry.json
index ee2e319..c8d1db9 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.json
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.json
@@ -61,7 +61,6 @@
   "taxes_and_charges_section",
   "purchase_taxes_and_charges_template",
   "sales_taxes_and_charges_template",
-  "advance_tax_account",
   "column_break_55",
   "apply_tax_withholding_amount",
   "tax_withholding_category",
@@ -686,15 +685,6 @@
    "hide_border": 1
   },
   {
-   "depends_on": "eval:doc.apply_tax_withholding_amount",
-   "description": "Provisional tax account for advance tax. Taxes are parked in this account until payments are allocated to invoices",
-   "fieldname": "advance_tax_account",
-   "fieldtype": "Link",
-   "label": "Advance Tax Account",
-   "mandatory_depends_on": "eval:doc.apply_tax_withholding_amount",
-   "options": "Account"
-  },
-  {
    "depends_on": "eval:doc.received_amount && doc.payment_type != 'Internal Transfer'",
    "fieldname": "received_amount_after_tax",
    "fieldtype": "Currency",
@@ -730,7 +720,7 @@
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2021-10-22 17:50:24.632806",
+ "modified": "2021-11-24 18:58:24.919764",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Payment Entry",
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 26fd16a..7aeb872 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -20,7 +20,7 @@
 from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import (
 	get_party_tax_withholding_details,
 )
-from erpnext.accounts.general_ledger import make_gl_entries
+from erpnext.accounts.general_ledger import make_gl_entries, process_gl_map
 from erpnext.accounts.party import get_party_account
 from erpnext.accounts.utils import get_account_currency, get_balance_on, get_outstanding_invoices
 from erpnext.controllers.accounts_controller import (
@@ -433,23 +433,12 @@
 		if not self.apply_tax_withholding_amount:
 			return
 
-		if not self.advance_tax_account:
-			frappe.throw(_("Advance TDS account is mandatory for advance TDS deduction"))
-
 		net_total = self.paid_amount
 
-		for reference in self.get("references"):
-			net_total_for_tds = 0
-			if reference.reference_doctype == 'Purchase Order':
-				net_total_for_tds += flt(frappe.db.get_value('Purchase Order', reference.reference_name, 'net_total'))
-
-			if net_total_for_tds:
-				net_total = net_total_for_tds
-
 		# Adding args as purchase invoice to get TDS amount
 		args = frappe._dict({
 			'company': self.company,
-			'doctype': 'Purchase Invoice',
+			'doctype': 'Payment Entry',
 			'supplier': self.party,
 			'posting_date': self.posting_date,
 			'net_total': net_total
@@ -461,7 +450,6 @@
 			return
 
 		tax_withholding_details.update({
-			'add_deduct_tax': 'Add',
 			'cost_center': self.cost_center or erpnext.get_default_cost_center(self.company)
 		})
 
@@ -689,6 +677,7 @@
 		self.add_deductions_gl_entries(gl_entries)
 		self.add_tax_gl_entries(gl_entries)
 
+		gl_entries = process_gl_map(gl_entries)
 		make_gl_entries(gl_entries, cancel=cancel, adv_adj=adv_adj)
 
 	def add_party_gl_entries(self, gl_entries):
@@ -752,7 +741,8 @@
 					"against": self.party if self.payment_type=="Pay" else self.paid_to,
 					"credit_in_account_currency": self.paid_amount,
 					"credit": self.base_paid_amount,
-					"cost_center": self.cost_center
+					"cost_center": self.cost_center,
+					"post_net_value": True
 				}, item=self)
 			)
 		if self.payment_type in ("Receive", "Internal Transfer"):
@@ -782,14 +772,10 @@
 				rev_dr_or_cr = "credit" if dr_or_cr == "debit" else "debit"
 				against = self.party or self.paid_to
 
-			payment_or_advance_account = self.get_party_account_for_taxes()
+			payment_account = self.get_party_account_for_taxes()
 			tax_amount = d.tax_amount
 			base_tax_amount = d.base_tax_amount
 
-			if self.advance_tax_account:
-				tax_amount = -1 * tax_amount
-				base_tax_amount = -1 * base_tax_amount
-
 			gl_entries.append(
 				self.get_gl_dict({
 					"account": d.account_head,
@@ -798,19 +784,21 @@
 					dr_or_cr + "_in_account_currency": base_tax_amount
 					if account_currency==self.company_currency
 					else d.tax_amount,
-					"cost_center": d.cost_center
+					"cost_center": d.cost_center,
+					"post_net_value": True,
 				}, account_currency, item=d))
 
-			if not d.included_in_paid_amount or self.advance_tax_account:
+			if not d.included_in_paid_amount:
 				gl_entries.append(
 					self.get_gl_dict({
-						"account": payment_or_advance_account,
+						"account": payment_account,
 						"against": against,
 						rev_dr_or_cr: tax_amount,
 						rev_dr_or_cr + "_in_account_currency": base_tax_amount
 						if account_currency==self.company_currency
 						else d.tax_amount,
 						"cost_center": self.cost_center,
+						"post_net_value": True,
 					}, account_currency, item=d))
 
 	def add_deductions_gl_entries(self, gl_entries):
@@ -832,9 +820,7 @@
 				)
 
 	def get_party_account_for_taxes(self):
-		if self.advance_tax_account:
-			return self.advance_tax_account
-		elif self.payment_type == 'Receive':
+		if self.payment_type == 'Receive':
 			return self.paid_to
 		elif self.payment_type in ('Pay', 'Internal Transfer'):
 			return self.paid_from
@@ -1599,13 +1585,6 @@
 			})
 			pe.set_difference_amount()
 
-	if doc.doctype == 'Purchase Order' and doc.apply_tds:
-		pe.apply_tax_withholding_amount = 1
-		pe.tax_withholding_category = doc.tax_withholding_category
-
-		if not pe.advance_tax_account:
-			pe.advance_tax_account = frappe.db.get_value('Company', pe.company, 'unrealized_profit_loss_account')
-
 	return pe
 
 def get_bank_cash_account(doc, bank_account):
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index 03cbc4a..bd01164 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -130,6 +130,7 @@
   "allocate_advances_automatically",
   "get_advances",
   "advances",
+  "advance_tax",
   "payment_schedule_section",
   "payment_terms_template",
   "ignore_default_payment_terms_template",
@@ -1408,13 +1409,21 @@
   {
    "fieldname": "column_break_147",
    "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "advance_tax",
+   "fieldtype": "Table",
+   "hidden": 1,
+   "label": "Advance Tax",
+   "options": "Advance Tax",
+   "read_only": 1
   }
  ],
  "icon": "fa fa-file-text",
  "idx": 204,
  "is_submittable": 1,
  "links": [],
- "modified": "2021-10-12 20:55:16.145651",
+ "modified": "2021-11-25 13:31:02.716727",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Purchase Invoice",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 62e3dc8..516133a 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -427,6 +427,7 @@
 
 		self.update_project()
 		update_linked_doc(self.doctype, self.name, self.inter_company_invoice_reference)
+		self.update_advance_tax_references()
 
 		self.process_common_party_accounting()
 
@@ -472,8 +473,6 @@
 		self.make_exchange_gain_loss_gl_entries(gl_entries)
 		self.make_internal_transfer_gl_entries(gl_entries)
 
-		self.allocate_advance_taxes(gl_entries)
-
 		gl_entries = make_regional_gl_entries(gl_entries, self)
 
 		gl_entries = merge_similar_entries(gl_entries)
@@ -1074,6 +1073,7 @@
 
 		unlink_inter_company_doc(self.doctype, self.name, self.inter_company_invoice_reference)
 		self.ignore_linked_doctypes = ('GL Entry', 'Stock Ledger Entry', 'Repost Item Valuation')
+		self.update_advance_tax_references(cancel=1)
 
 	def update_project(self):
 		project_list = []
@@ -1150,7 +1150,10 @@
 		if not self.tax_withholding_category:
 			return
 
-		tax_withholding_details = get_party_tax_withholding_details(self, self.tax_withholding_category)
+		tax_withholding_details, advance_taxes = get_party_tax_withholding_details(self, self.tax_withholding_category)
+
+		# Adjust TDS paid on advances
+		self.allocate_advance_tds(tax_withholding_details, advance_taxes)
 
 		if not tax_withholding_details:
 			return
@@ -1174,6 +1177,39 @@
 		# calculate totals again after applying TDS
 		self.calculate_taxes_and_totals()
 
+	def allocate_advance_tds(self, tax_withholding_details, advance_taxes):
+		self.set('advance_tax', [])
+		for tax in advance_taxes:
+			allocated_amount = 0
+			pending_amount = flt(tax.tax_amount - tax.allocated_amount)
+			if flt(tax_withholding_details.get('tax_amount')) >= pending_amount:
+				tax_withholding_details['tax_amount'] -= pending_amount
+				allocated_amount = pending_amount
+			elif flt(tax_withholding_details.get('tax_amount')) and flt(tax_withholding_details.get('tax_amount')) < pending_amount:
+				allocated_amount = tax_withholding_details['tax_amount']
+				tax_withholding_details['tax_amount'] = 0
+
+			self.append('advance_tax', {
+				'reference_type': 'Payment Entry',
+				'reference_name': tax.parent,
+				'reference_detail': tax.name,
+				'account_head': tax.account_head,
+				'allocated_amount': allocated_amount
+			})
+
+	def update_advance_tax_references(self, cancel=0):
+		for tax in self.get('advance_tax'):
+			at = frappe.qb.DocType("Advance Taxes and Charges").as_("at")
+
+			if cancel:
+				frappe.qb.update(at).set(
+					at.allocated_amount, at.allocated_amount - tax.allocated_amount
+				).where(at.name == tax.reference_detail).run()
+			else:
+				frappe.qb.update(at).set(
+					at.allocated_amount, at.allocated_amount + tax.allocated_amount
+				).where(at.name == tax.reference_detail).run()
+
 	def set_status(self, update=False, status=None, update_modified=True):
 		if self.is_new():
 			if self.get('amended_from'):
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index 78396a5..aa2408e 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -1160,25 +1160,21 @@
 		# Create Purchase Order with TDS applied
 		po = create_purchase_order(do_not_save=1, supplier=supplier.name, rate=3000, item='_Test Non Stock Item',
 			posting_date='2021-09-15')
-		po.apply_tds = 1
-		po.tax_withholding_category = 'TDS - 194 - Dividends - Individual'
 		po.save()
 		po.submit()
 
-		# Update Unrealized Profit / Loss Account which is used as default advance tax account
-		frappe.db.set_value('Company', '_Test Company', 'unrealized_profit_loss_account', '_Test Account Excise Duty - _TC')
-
 		# Create Payment Entry Against the order
 		payment_entry = get_payment_entry(dt='Purchase Order', dn=po.name)
 		payment_entry.paid_from = 'Cash - _TC'
+		payment_entry.apply_tax_withholding_amount = 1
+		payment_entry.tax_withholding_category = 'TDS - 194 - Dividends - Individual'
 		payment_entry.save()
 		payment_entry.submit()
 
 		# Check GLE for Payment Entry
 		expected_gle = [
-			['_Test Account Excise Duty - _TC', 3000, 0],
 			['Cash - _TC', 0, 27000],
-			['Creditors - _TC', 27000, 0],
+			['Creditors - _TC', 30000, 0],
 			['TDS Payable - _TC', 0, 3000],
 		]
 
@@ -1204,9 +1200,7 @@
 		# Zero net effect on final TDS Payable on invoice
 		expected_gle = [
 			['_Test Account Cost for Goods Sold - _TC', 30000],
-			['_Test Account Excise Duty - _TC', -3000],
-			['Creditors - _TC', -27000],
-			['TDS Payable - _TC', 0]
+			['Creditors - _TC', -30000]
 		]
 
 		gl_entries = frappe.db.sql("""select account, sum(debit - credit) as amount
@@ -1219,6 +1213,14 @@
 			self.assertEqual(expected_gle[i][0], gle.account)
 			self.assertEqual(expected_gle[i][1], gle.amount)
 
+		payment_entry.load_from_db()
+		self.assertEqual(payment_entry.taxes[0].allocated_amount, 3000)
+
+		purchase_invoice.cancel()
+
+		payment_entry.load_from_db()
+		self.assertEqual(payment_entry.taxes[0].allocated_amount, 0)
+
 def check_gl_entries(doc, voucher_no, expected_gle, posting_date):
 	gl_entries = frappe.db.sql("""select account, debit, credit, posting_date
 		from `tabGL Entry`
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 59d46fc..c4d59f1 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -842,8 +842,6 @@
 		self.make_exchange_gain_loss_gl_entries(gl_entries)
 		self.make_internal_transfer_gl_entries(gl_entries)
 
-		self.allocate_advance_taxes(gl_entries)
-
 		self.make_item_gl_entries(gl_entries)
 		self.make_discount_gl_entries(gl_entries)
 
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 dc1818a..5bb9b93 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -95,7 +95,7 @@
 		frappe.throw(_('Tax Withholding Category {} against Company {} for Customer {} should have Cumulative Threshold value.')
 			.format(tax_withholding_category, inv.company, party))
 
-	tax_amount, tax_deducted = get_tax_amount(
+	tax_amount, tax_deducted, tax_deducted_on_advances = get_tax_amount(
 		party_type, parties,
 		inv, tax_details,
 		posting_date, pan_no
@@ -106,7 +106,10 @@
 	else:
 		tax_row = get_tax_row_for_tcs(inv, tax_details, tax_amount, tax_deducted)
 
-	return tax_row
+	if inv.doctype == 'Purchase Invoice':
+		return tax_row, tax_deducted_on_advances
+	else:
+		return tax_row
 
 def get_tax_withholding_details(tax_withholding_category, posting_date, company):
 	tax_withholding = frappe.get_doc("Tax Withholding Category", tax_withholding_category)
@@ -194,6 +197,10 @@
 	advance_vouchers = get_advance_vouchers(parties, company=inv.company, from_date=tax_details.from_date,
 		to_date=tax_details.to_date, party_type=party_type)
 	taxable_vouchers = vouchers + advance_vouchers
+	tax_deducted_on_advances = 0
+
+	if inv.doctype == 'Purchase Invoice':
+		tax_deducted_on_advances = get_taxes_deducted_on_advances_allocated(inv, tax_details)
 
 	tax_deducted = 0
 	if taxable_vouchers:
@@ -223,7 +230,7 @@
 	if cint(tax_details.round_off_tax_amount):
 		tax_amount = round(tax_amount)
 
-	return tax_amount, tax_deducted
+	return tax_amount, tax_deducted, tax_deducted_on_advances
 
 def get_invoice_vouchers(parties, tax_details, company, party_type='Supplier'):
 	dr_or_cr = 'credit' if party_type == 'Supplier' else 'debit'
@@ -281,6 +288,29 @@
 
 	return frappe.get_all('GL Entry', filters=filters, distinct=1, pluck='voucher_no') or [""]
 
+def get_taxes_deducted_on_advances_allocated(inv, tax_details):
+	advances = [d.reference_name for d in inv.get('advances')]
+	tax_info = []
+
+	if advances:
+		pe = frappe.qb.DocType("Payment Entry").as_("pe")
+		at = frappe.qb.DocType("Advance Taxes and Charges").as_("at")
+
+		tax_info = frappe.qb.from_(at).inner_join(pe).on(
+			pe.name == at.parent
+		).select(
+			at.parent, at.name, at.tax_amount, at.allocated_amount
+		).where(
+			pe.tax_withholding_category == tax_details.get('tax_withholding_category')
+		).where(
+			at.parent.isin(advances)
+		).where(
+			at.account_head == tax_details.account_head
+		).run(as_dict=True)
+
+	return tax_info
+
+
 def get_deducted_tax(taxable_vouchers, tax_details):
 	# check if TDS / TCS account is already charged on taxable vouchers
 	filters = {
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index 8ef7d7e..1836db6 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -73,8 +73,28 @@
 				flt(entry.debit_in_account_currency) - flt(entry.credit_in_account_currency)
 			entry.credit_in_account_currency = 0.0
 
+		update_net_values(entry)
+
 	return gl_map
 
+def update_net_values(entry):
+	# In some scenarios net value needs to be shown in the ledger
+	# This method updates net values as debit or credit
+	if entry.post_net_value and entry.debit and entry.credit:
+		if entry.debit > entry.credit:
+			entry.debit = entry.debit - entry.credit
+			entry.debit_in_account_currency = entry.debit_in_account_currency \
+				- entry.credit_in_account_currency
+			entry.credit = 0
+			entry.credit_in_account_currency = 0
+		else:
+			entry.credit = entry.credit - entry.debit
+			entry.credit_in_account_currency = entry.credit_in_account_currency \
+				- entry.debit_in_account_currency
+
+			entry.debit = 0
+			entry.debit_in_account_currency = 0
+
 def merge_similar_entries(gl_map, precision=None):
 	merged_gl_map = []
 	accounting_dimensions = get_accounting_dimensions()
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 1654ac9..0ee884e 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -145,11 +145,6 @@
 		self.validate_party()
 		self.validate_currency()
 
-		if self.doctype == 'Purchase Invoice':
-			self.calculate_paid_amount()
-			# apply tax withholding only if checked and applicable
-			self.set_tax_withholding()
-
 		if self.doctype in ['Purchase Invoice', 'Sales Invoice']:
 			pos_check_field = "is_pos" if self.doctype=="Sales Invoice" else "is_paid"
 			if cint(self.allocate_advances_automatically) and not cint(self.get(pos_check_field)):
@@ -164,6 +159,11 @@
 
 			self.set_inter_company_account()
 
+		if self.doctype == 'Purchase Invoice':
+			self.calculate_paid_amount()
+			# apply tax withholding only if checked and applicable
+			self.set_tax_withholding()
+
 		validate_regional(self)
 
 		if self.doctype != 'Material Request':
@@ -524,7 +524,8 @@
 			'is_opening': self.get("is_opening") or "No",
 			'party_type': None,
 			'party': None,
-			'project': self.get("project")
+			'project': self.get("project"),
+			'post_net_value': args.get('post_net_value')
 		})
 
 		accounting_dimensions = get_accounting_dimensions()
@@ -805,7 +806,6 @@
 		from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries
 
 		if self.doctype in ["Sales Invoice", "Purchase Invoice"]:
-			self.update_allocated_advance_taxes_on_cancel()
 			if frappe.db.get_single_value('Accounts Settings', 'unlink_payment_on_cancellation_of_invoice'):
 				unlink_ref_doc_from_payment_entries(self)
 
@@ -853,29 +853,6 @@
 
 		return tax_map
 
-	def update_allocated_advance_taxes_on_cancel(self):
-		if self.get('advances'):
-			tax_accounts = [d.account_head for d in self.get('taxes')]
-			allocated_tax_map = frappe._dict(frappe.get_all('GL Entry', fields=['account', 'sum(credit - debit)'],
-				filters={'voucher_no': self.name, 'account': ('in', tax_accounts)},
-				group_by='account', as_list=1))
-
-			tax_map = self.get_tax_map()
-
-			for pe in self.get('advances'):
-				if pe.reference_type == 'Payment Entry':
-					pe = frappe.get_doc('Payment Entry', pe.reference_name)
-					for tax in pe.get('taxes'):
-						allocated_amount = tax_map.get(tax.account_head) - allocated_tax_map.get(tax.account_head)
-						if allocated_amount > tax.tax_amount:
-							allocated_amount = tax.tax_amount
-
-						if allocated_amount:
-							frappe.db.set_value('Advance Taxes and Charges', tax.name, 'allocated_amount',
-								tax.allocated_amount - allocated_amount)
-							tax_map[tax.account_head] -= allocated_amount
-							allocated_tax_map[tax.account_head] -= allocated_amount
-
 	def get_amount_and_base_amount(self, item, enable_discount_accounting):
 		amount = item.net_amount
 		base_amount = item.base_net_amount
@@ -959,55 +936,6 @@
 					}, item=self)
 				)
 
-	def allocate_advance_taxes(self, gl_entries):
-		tax_map = self.get_tax_map()
-		for pe in self.get("advances"):
-			if pe.reference_type == "Payment Entry" and \
-				frappe.db.get_value('Payment Entry', pe.reference_name, 'advance_tax_account'):
-				pe = frappe.get_doc("Payment Entry", pe.reference_name)
-				for tax in pe.get("taxes"):
-					account_currency = get_account_currency(tax.account_head)
-
-					if self.doctype == "Purchase Invoice":
-						dr_or_cr = "debit" if tax.add_deduct_tax == "Add" else "credit"
-						rev_dr_cr = "credit" if tax.add_deduct_tax == "Add" else "debit"
-					else:
-						dr_or_cr = "credit" if tax.add_deduct_tax == "Add" else "debit"
-						rev_dr_cr = "debit" if tax.add_deduct_tax == "Add" else "credit"
-
-					party = self.supplier if self.doctype == "Purchase Invoice" else self.customer
-					unallocated_amount = tax.tax_amount - tax.allocated_amount
-					if tax_map.get(tax.account_head):
-						amount = tax_map.get(tax.account_head)
-						if amount < unallocated_amount:
-							unallocated_amount = amount
-
-						gl_entries.append(
-							self.get_gl_dict({
-								"account": tax.account_head,
-								"against": party,
-								dr_or_cr: unallocated_amount,
-								dr_or_cr + "_in_account_currency": unallocated_amount
-								if account_currency==self.company_currency
-								else unallocated_amount,
-								"cost_center": tax.cost_center
-							}, account_currency, item=tax))
-
-						gl_entries.append(
-							self.get_gl_dict({
-								"account": pe.advance_tax_account,
-								"against": party,
-								rev_dr_cr: unallocated_amount,
-								rev_dr_cr + "_in_account_currency": unallocated_amount
-								if account_currency==self.company_currency
-								else unallocated_amount,
-								"cost_center": tax.cost_center
-							}, account_currency, item=tax))
-
-						frappe.db.set_value("Advance Taxes and Charges", tax.name, "allocated_amount",
-							tax.allocated_amount + unallocated_amount)
-
-						tax_map[tax.account_head] -= unallocated_amount
 
 	def validate_multiple_billing(self, ref_dt, item_ref_dn, based_on, parentfield):
 		from erpnext.controllers.status_updater import get_allowance_for