feat: Tax deduction against advance payments
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js
index b80e8ad..29e4a31 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js
@@ -3,6 +3,8 @@
 {% include "erpnext/public/js/controllers/accounts.js" %}
 frappe.provide("erpnext.accounts.dimensions");
 
+cur_frm.cscript.tax_table = "Advance Taxes and Charges";
+
 frappe.ui.form.on('Payment Entry', {
 	onload: function(frm) {
 		if(frm.doc.__islocal) {
@@ -182,6 +184,8 @@
 			frm.doc.paid_from_account_currency != frm.doc.paid_to_account_currency));
 
 		frm.toggle_display("base_paid_amount", frm.doc.paid_from_account_currency != company_currency);
+		frm.toggle_display("base_total_taxes_and_charges", frm.doc.total_taxes_and_charges &&
+			(frm.doc.paid_from_account_currency != company_currency));
 
 		frm.toggle_display("base_received_amount", (
 			frm.doc.paid_to_account_currency != company_currency
@@ -843,12 +847,12 @@
 			if(frm.doc.payment_type == "Receive"
 				&& frm.doc.base_total_allocated_amount < frm.doc.base_received_amount + total_deductions
 				&& frm.doc.total_allocated_amount < frm.doc.paid_amount + (total_deductions / frm.doc.source_exchange_rate)) {
-					unallocated_amount = (frm.doc.base_received_amount + total_deductions
-						- frm.doc.base_total_allocated_amount) / frm.doc.source_exchange_rate;
+					unallocated_amount = (frm.doc.base_received_amount + total_deductions + frm.doc.base_total_taxes_and_charges
+						+ frm.doc.base_total_allocated_amount) / frm.doc.source_exchange_rate;
 			} else if (frm.doc.payment_type == "Pay"
 				&& frm.doc.base_total_allocated_amount < frm.doc.base_paid_amount - total_deductions
 				&& frm.doc.total_allocated_amount < frm.doc.received_amount + (total_deductions / frm.doc.target_exchange_rate)) {
-					unallocated_amount = (frm.doc.base_paid_amount - (total_deductions
+					unallocated_amount = (frm.doc.base_paid_amount + frm.doc.base_total_taxes_and_charges - (total_deductions
 						+ frm.doc.base_total_allocated_amount)) / frm.doc.target_exchange_rate;
 			}
 		}
@@ -874,7 +878,8 @@
 		var total_deductions = frappe.utils.sum($.map(frm.doc.deductions || [],
 			function(d) { return flt(d.amount) }));
 
-		frm.set_value("difference_amount", difference_amount - total_deductions);
+		frm.set_value("difference_amount", difference_amount - total_deductions +
+			frm.doc.base_total_taxes_and_charges);
 
 		frm.events.hide_unhide_fields(frm);
 	},
@@ -1002,7 +1007,107 @@
 				}
 			});
 		}
-	}
+	},
+
+	sales_taxes_and_charges_template: function(frm) {
+		frm.trigger('fetch_taxes_from_template');
+	},
+
+	purchase_taxes_and_charges_template: function(frm) {
+		frm.trigger('fetch_taxes_from_template');
+	},
+
+	fetch_taxes_from_template: function(frm) {
+		let master_doctype = '';
+		let taxes_and_charges = '';
+
+		if (frm.doc.party_type == 'Supplier') {
+			master_doctype = 'Purchase Taxes and Charges Template';
+			taxes_and_charges = frm.doc.purchase_taxes_and_charges_template;
+		} else if (frm.doc.party_type == 'Customer') {
+			master_doctype = 'Sales Taxes and Charges Template';
+			taxes_and_charges = frm.doc.sales_taxes_and_charges_template;
+		}
+
+		if (!taxes_and_charges) {
+			return;
+		}
+
+		frappe.call({
+			method: "erpnext.controllers.accounts_controller.get_taxes_and_charges",
+			args: {
+				"master_doctype": master_doctype,
+				"master_name": taxes_and_charges
+			},
+			callback: function(r) {
+				if(!r.exc && r.message) {
+					// set taxes table
+					if(r.message) {
+						for (let tax of r.message) {
+							if (tax.charge_type === 'On Net Total') {
+								tax.charge_type = 'On Paid Amount';
+							}
+							me.frm.add_child("taxes", tax);
+						}
+						frm.trigger('calculate_taxes');
+						frm.events.set_unallocated_amount(frm);
+					}
+				}
+			}
+		});
+	},
+
+	calculate_taxes: function(frm) {
+		frm.doc.total_taxes_and_charges = 0.0;
+		frm.doc.base_total_taxes_and_charges = 0.0;
+
+		$.each(me.frm.doc["taxes"] || [], function(i, tax) {
+			let tax_rate = tax.rate;
+			let current_tax_amount = 0.0;
+
+			// To set row_id by default as previous row.
+			if(["On Previous Row Amount", "On Previous Row Total"].includes(tax.charge_type)) {
+				if (tax.idx === 1) {
+					frappe.throw(__("Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row"));
+				}
+				if (!tax.row_id) {
+					tax.row_id = tax.idx - 1;
+				}
+			}
+
+			if(tax.charge_type == "Actual") {
+				current_tax_amount = flt(tax.tax_amount, precision("tax_amount", tax));
+			} else if(tax.charge_type == "On Paid Amount") {
+				current_tax_amount = (tax_rate / 100.0) * frm.doc.paid_amount;
+			} else if(tax.charge_type == "On Previous Row Amount") {
+				current_tax_amount = (tax_rate / 100.0) *
+					frm.doc["taxes"][cint(tax.row_id) - 1].tax_amount;
+
+			} else if(tax.charge_type == "On Previous Row Total") {
+				current_tax_amount = (tax_rate / 100.0) *
+					frm.doc["taxes"][cint(tax.row_id) - 1].total;
+			}
+
+			tax.tax_amount = current_tax_amount;
+			tax.base_tax_amount = tax.tax_amount * frm.doc.source_exchange_rate;
+
+			current_tax_amount *= (tax.add_deduct_tax == "Deduct") ? -1.0 : 1.0;
+
+			if(i==0) {
+				tax.total = flt(frm.doc.paid_amount + current_tax_amount, precision("total", tax));
+			} else {
+				tax.total = flt(frm.doc["taxes"][i-1].total + current_tax_amount, precision("total", tax));
+			}
+
+			tax.base_total = tax.total * frm.doc.source_exchange_rate;
+			frm.doc.total_taxes_and_charges += current_tax_amount;
+			frm.doc.base_total_taxes_and_charges += current_tax_amount * frm.doc.source_exchange_rate;
+
+			frm.refresh_field('taxes');
+			frm.refresh_field('total_taxes_and_charges');
+			frm.refresh_field('base_total_taxes_and_charges');
+		});
+	},
 });
 
 
@@ -1049,6 +1154,28 @@
 	}
 })
 
+frappe.ui.form.on('Advance Taxes and Charges', {
+	rate: function(frm) {
+		frm.events.calculate_taxes(frm);
+		frm.events.set_unallocated_amount(frm);
+	},
+
+	tax_amount : function(frm) {
+		frm.events.calculate_taxes(frm);
+		frm.events.set_unallocated_amount(frm);
+	},
+
+	row_id: function(frm) {
+		frm.events.calculate_taxes(frm);
+		frm.events.set_unallocated_amount(frm);
+	},
+
+	taxes_remove: function(frm) {
+		frm.events.calculate_taxes(frm);
+		frm.events.set_unallocated_amount(frm);
+	}
+})
+
 frappe.ui.form.on('Payment Entry Deduction', {
 	amount: function(frm) {
 		frm.events.set_unallocated_amount(frm);
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.json b/erpnext/accounts/doctype/payment_entry/payment_entry.json
index 328584a..11ae170 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.json
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.json
@@ -24,6 +24,10 @@
   "party_bank_account",
   "contact_person",
   "contact_email",
+  "tds_details_section",
+  "tax_withholding_category",
+  "column_break_20",
+  "apply_tax_withholding_amount",
   "payment_accounts_section",
   "party_balance",
   "paid_from",
@@ -52,6 +56,12 @@
   "unallocated_amount",
   "difference_amount",
   "write_off_difference_amount",
+  "taxes_and_charges_section",
+  "purchase_taxes_and_charges_template",
+  "sales_taxes_and_charges_template",
+  "taxes",
+  "base_total_taxes_and_charges",
+  "total_taxes_and_charges",
   "deductions_or_loss_section",
   "deductions",
   "transaction_references",
@@ -82,7 +92,9 @@
   {
    "fieldname": "type_of_payment",
    "fieldtype": "Section Break",
-   "label": "Type of Payment"
+   "label": "Type of Payment",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "bold": 1,
@@ -92,7 +104,9 @@
    "options": "ACC-PAY-.YYYY.-",
    "print_hide": 1,
    "reqd": 1,
-   "set_only_once": 1
+   "set_only_once": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "bold": 1,
@@ -103,11 +117,15 @@
    "label": "Payment Type",
    "options": "Receive\nPay\nInternal Transfer",
    "print_hide": 1,
-   "reqd": 1
+   "reqd": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "column_break_5",
-   "fieldtype": "Column Break"
+   "fieldtype": "Column Break",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "bold": 1,
@@ -116,7 +134,9 @@
    "fieldtype": "Date",
    "in_list_view": 1,
    "label": "Posting Date",
-   "reqd": 1
+   "reqd": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "company",
@@ -125,26 +145,34 @@
    "options": "Company",
    "print_hide": 1,
    "remember_last_selected_value": 1,
-   "reqd": 1
+   "reqd": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "cost_center",
    "fieldtype": "Link",
    "label": "Cost Center",
-   "options": "Cost Center"
+   "options": "Cost Center",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "mode_of_payment",
    "fieldtype": "Link",
    "in_list_view": 1,
    "label": "Mode of Payment",
-   "options": "Mode of Payment"
+   "options": "Mode of Payment",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "depends_on": "eval:in_list([\"Receive\", \"Pay\"], doc.payment_type)",
    "fieldname": "party_section",
    "fieldtype": "Section Break",
-   "label": "Payment From / To"
+   "label": "Payment From / To",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "depends_on": "eval:in_list([\"Receive\", \"Pay\"], doc.payment_type) && doc.docstatus==0",
@@ -154,7 +182,9 @@
    "label": "Party Type",
    "options": "DocType",
    "print_hide": 1,
-   "search_index": 1
+   "search_index": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "bold": 1,
@@ -163,7 +193,9 @@
    "fieldtype": "Dynamic Link",
    "in_standard_filter": 1,
    "label": "Party",
-   "options": "party_type"
+   "options": "party_type",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "allow_on_submit": 1,
@@ -171,18 +203,24 @@
    "fieldname": "party_name",
    "fieldtype": "Data",
    "in_global_search": 1,
-   "label": "Party Name"
+   "label": "Party Name",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "column_break_11",
-   "fieldtype": "Column Break"
+   "fieldtype": "Column Break",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "depends_on": "party",
    "fieldname": "contact_person",
    "fieldtype": "Link",
    "label": "Contact",
-   "options": "Contact"
+   "options": "Contact",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "depends_on": "contact_person",
@@ -190,13 +228,17 @@
    "fieldtype": "Data",
    "label": "Email",
    "options": "Email",
-   "read_only": 1
+   "read_only": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "collapsible": 1,
    "fieldname": "payment_accounts_section",
    "fieldtype": "Section Break",
-   "label": "Accounts"
+   "label": "Accounts",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "depends_on": "party",
@@ -204,7 +246,9 @@
    "fieldtype": "Currency",
    "label": "Party Balance",
    "print_hide": 1,
-   "read_only": 1
+   "read_only": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "bold": 1,
@@ -215,7 +259,9 @@
    "label": "Account Paid From",
    "options": "Account",
    "print_hide": 1,
-   "reqd": 1
+   "reqd": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "depends_on": "paid_from",
@@ -225,7 +271,9 @@
    "options": "Currency",
    "print_hide": 1,
    "read_only": 1,
-   "reqd": 1
+   "reqd": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "depends_on": "paid_from",
@@ -234,11 +282,15 @@
    "label": "Account Balance",
    "options": "paid_from_account_currency",
    "print_hide": 1,
-   "read_only": 1
+   "read_only": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "column_break_18",
-   "fieldtype": "Column Break"
+   "fieldtype": "Column Break",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "depends_on": "eval:(in_list([\"Internal Transfer\", \"Receive\"], doc.payment_type) || doc.party)",
@@ -248,7 +300,9 @@
    "label": "Account Paid To",
    "options": "Account",
    "print_hide": 1,
-   "reqd": 1
+   "reqd": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "depends_on": "paid_to",
@@ -258,7 +312,9 @@
    "options": "Currency",
    "print_hide": 1,
    "read_only": 1,
-   "reqd": 1
+   "reqd": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "depends_on": "paid_to",
@@ -267,13 +323,17 @@
    "label": "Account Balance",
    "options": "paid_to_account_currency",
    "print_hide": 1,
-   "read_only": 1
+   "read_only": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "depends_on": "eval:(doc.paid_to && doc.paid_from)",
    "fieldname": "payment_amounts_section",
    "fieldtype": "Section Break",
-   "label": "Amount"
+   "label": "Amount",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "bold": 1,
@@ -281,14 +341,18 @@
    "fieldtype": "Currency",
    "label": "Paid Amount",
    "options": "paid_from_account_currency",
-   "reqd": 1
+   "reqd": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "source_exchange_rate",
    "fieldtype": "Float",
    "label": "Exchange Rate",
    "print_hide": 1,
-   "reqd": 1
+   "reqd": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "base_paid_amount",
@@ -297,11 +361,15 @@
    "options": "Company:company:default_currency",
    "print_hide": 1,
    "read_only": 1,
-   "reqd": 1
+   "reqd": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "column_break_21",
-   "fieldtype": "Column Break"
+   "fieldtype": "Column Break",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "bold": 1,
@@ -310,14 +378,18 @@
    "label": "Received Amount",
    "options": "paid_to_account_currency",
    "print_hide": 1,
-   "reqd": 1
+   "reqd": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "target_exchange_rate",
    "fieldtype": "Float",
    "label": "Exchange Rate",
    "print_hide": 1,
-   "reqd": 1
+   "reqd": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "base_received_amount",
@@ -326,30 +398,40 @@
    "options": "Company:company:default_currency",
    "print_hide": 1,
    "read_only": 1,
-   "reqd": 1
+   "reqd": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "depends_on": "eval:(doc.party && doc.paid_from && doc.paid_to && doc.paid_amount && doc.received_amount)",
    "fieldname": "section_break_14",
    "fieldtype": "Section Break",
-   "label": "Reference"
+   "label": "Reference",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "depends_on": "eval:doc.docstatus==0",
    "fieldname": "get_outstanding_invoice",
    "fieldtype": "Button",
-   "label": "Get Outstanding Invoice"
+   "label": "Get Outstanding Invoice",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "references",
    "fieldtype": "Table",
    "label": "Payment References",
-   "options": "Payment Entry Reference"
+   "options": "Payment Entry Reference",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "section_break_34",
    "fieldtype": "Section Break",
-   "label": "Writeoff"
+   "label": "Writeoff",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "bold": 1,
@@ -358,7 +440,9 @@
    "fieldtype": "Currency",
    "label": "Total Allocated Amount",
    "print_hide": 1,
-   "read_only": 1
+   "read_only": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "base_total_allocated_amount",
@@ -366,23 +450,31 @@
    "label": "Total Allocated Amount (Company Currency)",
    "options": "Company:company:default_currency",
    "print_hide": 1,
-   "read_only": 1
+   "read_only": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "set_exchange_gain_loss",
    "fieldtype": "Button",
-   "label": "Set Exchange Gain / Loss"
+   "label": "Set Exchange Gain / Loss",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "column_break_36",
-   "fieldtype": "Column Break"
+   "fieldtype": "Column Break",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "depends_on": "eval:(doc.paid_amount && doc.received_amount && doc.references)",
    "fieldname": "unallocated_amount",
    "fieldtype": "Currency",
    "label": "Unallocated Amount",
-   "print_hide": 1
+   "print_hide": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "bold": 1,
@@ -392,13 +484,17 @@
    "label": "Difference Amount (Company Currency)",
    "options": "Company:company:default_currency",
    "print_hide": 1,
-   "read_only": 1
+   "read_only": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "depends_on": "difference_amount",
    "fieldname": "write_off_difference_amount",
    "fieldtype": "Button",
-   "label": "Write Off Difference Amount"
+   "label": "Write Off Difference Amount",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "collapsible": 1,
@@ -406,29 +502,39 @@
    "depends_on": "eval:(doc.paid_amount && doc.received_amount)",
    "fieldname": "deductions_or_loss_section",
    "fieldtype": "Section Break",
-   "label": "Deductions or Loss"
+   "label": "Deductions or Loss",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "deductions",
    "fieldtype": "Table",
    "label": "Payment Deductions or Loss",
-   "options": "Payment Entry Deduction"
+   "options": "Payment Entry Deduction",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "transaction_references",
    "fieldtype": "Section Break",
-   "label": "Transaction ID"
+   "label": "Transaction ID",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "bold": 1,
    "depends_on": "eval:(doc.paid_from && doc.paid_to)",
    "fieldname": "reference_no",
    "fieldtype": "Data",
-   "label": "Cheque/Reference No"
+   "label": "Cheque/Reference No",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "column_break_23",
-   "fieldtype": "Column Break"
+   "fieldtype": "Column Break",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "bold": 1,
@@ -436,7 +542,9 @@
    "fieldname": "reference_date",
    "fieldtype": "Date",
    "label": "Cheque/Reference Date",
-   "search_index": 1
+   "search_index": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "depends_on": "eval:doc.docstatus==1",
@@ -445,21 +553,27 @@
    "label": "Clearance Date",
    "no_copy": 1,
    "print_hide": 1,
-   "read_only": 1
+   "read_only": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "collapsible": 1,
    "depends_on": "eval:(doc.paid_from && doc.paid_to && doc.paid_amount && doc.received_amount)",
    "fieldname": "section_break_12",
    "fieldtype": "Section Break",
-   "label": "More Information"
+   "label": "More Information",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "project",
    "fieldtype": "Link",
    "label": "Project",
    "options": "Project",
-   "print_hide": 1
+   "print_hide": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "remarks",
@@ -470,33 +584,43 @@
   },
   {
    "fieldname": "column_break_16",
-   "fieldtype": "Column Break"
+   "fieldtype": "Column Break",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "letter_head",
    "fieldtype": "Link",
    "label": "Letter Head",
    "options": "Letter Head",
-   "print_hide": 1
+   "print_hide": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "print_heading",
    "fieldtype": "Link",
    "label": "Print Heading",
    "options": "Print Heading",
-   "print_hide": 1
+   "print_hide": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fetch_from": "bank_account.bank",
    "fieldname": "bank",
    "fieldtype": "Read Only",
-   "label": "Bank"
+   "label": "Bank",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fetch_from": "bank_account.bank_account_no",
    "fieldname": "bank_account_no",
    "fieldtype": "Read Only",
-   "label": "Bank Account No"
+   "label": "Bank Account No",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "payment_order",
@@ -505,12 +629,16 @@
    "no_copy": 1,
    "options": "Payment Order",
    "print_hide": 1,
-   "read_only": 1
+   "read_only": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "subscription_section",
    "fieldtype": "Section Break",
-   "label": "Subscription Section"
+   "label": "Subscription Section",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "allow_on_submit": 1,
@@ -520,7 +648,9 @@
    "no_copy": 1,
    "options": "Auto Repeat",
    "print_hide": 1,
-   "read_only": 1
+   "read_only": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "amended_from",
@@ -529,7 +659,9 @@
    "no_copy": 1,
    "options": "Payment Entry",
    "print_hide": 1,
-   "read_only": 1
+   "read_only": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "title",
@@ -544,14 +676,18 @@
    "fieldname": "bank_account",
    "fieldtype": "Link",
    "label": "Company Bank Account",
-   "options": "Bank Account"
+   "options": "Bank Account",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "depends_on": "party",
    "fieldname": "party_bank_account",
    "fieldtype": "Link",
    "label": "Party Bank Account",
-   "options": "Bank Account"
+   "options": "Bank Account",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "payment_order_status",
@@ -559,17 +695,23 @@
    "hidden": 1,
    "label": "Payment Order Status",
    "options": "Initiated\nPayment Ordered",
-   "read_only": 1
+   "read_only": 1,
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "collapsible": 1,
    "fieldname": "accounting_dimensions_section",
    "fieldtype": "Section Break",
-   "label": "Accounting Dimensions"
+   "label": "Accounting Dimensions",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "fieldname": "dimension_col_break",
-   "fieldtype": "Column Break"
+   "fieldtype": "Column Break",
+   "show_days": 1,
+   "show_seconds": 1
   },
   {
    "default": "Draft",
@@ -584,12 +726,94 @@
    "fieldname": "custom_remarks",
    "fieldtype": "Check",
    "label": "Custom Remarks"
+  },
+  {
+   "depends_on": "eval: doc.payment_type == 'Pay' && doc.party_type == 'Supplier'",
+   "fieldname": "tds_details_section",
+   "fieldtype": "Section Break",
+   "label": "TDS Details",
+   "show_days": 1,
+   "show_seconds": 1
+  },
+  {
+   "fieldname": "tax_withholding_category",
+   "fieldtype": "Link",
+   "label": "Tax Withholding Category",
+   "options": "Tax Withholding Category",
+   "show_days": 1,
+   "show_seconds": 1
+  },
+  {
+   "default": "0",
+   "fieldname": "apply_tax_withholding_amount",
+   "fieldtype": "Check",
+   "label": "Apply Tax Withholding Amount",
+   "show_days": 1,
+   "show_seconds": 1
+  },
+  {
+   "fieldname": "column_break_20",
+   "fieldtype": "Column Break",
+   "show_days": 1,
+   "show_seconds": 1
+  },
+  {
+   "collapsible": 1,
+   "fieldname": "taxes_and_charges_section",
+   "fieldtype": "Section Break",
+   "label": "Taxes and Charges",
+   "show_days": 1,
+   "show_seconds": 1
+  },
+  {
+   "depends_on": "eval:doc.party_type == 'Supplier'",
+   "fieldname": "purchase_taxes_and_charges_template",
+   "fieldtype": "Link",
+   "label": "Taxes and Charges Template",
+   "options": "Purchase Taxes and Charges Template",
+   "show_days": 1,
+   "show_seconds": 1
+  },
+  {
+   "depends_on": "eval: doc.party_type == 'Customer'",
+   "fieldname": "sales_taxes_and_charges_template",
+   "fieldtype": "Link",
+   "label": "Taxes and Charges Template",
+   "options": "Sales Taxes and Charges Template",
+   "show_days": 1,
+   "show_seconds": 1
+  },
+  {
+   "depends_on": "eval: doc.party_type == 'Supplier' || doc.party_type == 'Customer'",
+   "fieldname": "taxes",
+   "fieldtype": "Table",
+   "label": "Advance Taxes and Charges",
+   "options": "Advance Taxes and Charges",
+   "show_days": 1,
+   "show_seconds": 1
+  },
+  {
+   "fieldname": "base_total_taxes_and_charges",
+   "fieldtype": "Currency",
+   "label": "Total Taxes and Charges (Company Currency)",
+   "options": "Company:company:default_currency",
+   "read_only": 1,
+   "show_days": 1,
+   "show_seconds": 1
+  },
+  {
+   "fieldname": "total_taxes_and_charges",
+   "fieldtype": "Currency",
+   "label": "Total Taxes and Charges",
+   "read_only": 1,
+   "show_days": 1,
+   "show_seconds": 1
   }
  ],
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2021-03-08 13:05:16.958866",
+ "modified": "2020-09-13 22:33:59.860146",
  "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 62ab76c..a41b451 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -5,7 +5,7 @@
 from __future__ import unicode_literals
 import frappe, erpnext, json
 from frappe import _, scrub, ValidationError
-from frappe.utils import flt, comma_or, nowdate, getdate
+from frappe.utils import flt, comma_or, nowdate, getdate, cint
 from erpnext.accounts.utils import get_outstanding_invoices, get_account_currency, get_balance_on
 from erpnext.accounts.party import get_party_account
 from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account
@@ -15,6 +15,7 @@
 from erpnext.accounts.doctype.bank_account.bank_account import get_party_bank_account, get_bank_account_details
 from erpnext.controllers.accounts_controller import AccountsController, get_supplier_block_status
 from erpnext.accounts.doctype.invoice_discounting.invoice_discounting import get_party_account_based_on_invoice_discounting
+from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import get_party_tax_withholding_details
 
 from six import string_types, iteritems
 
@@ -52,6 +53,8 @@
 		self.set_exchange_rate()
 		self.validate_mandatory()
 		self.validate_reference_documents()
+		self.set_tax_withholding()
+		self.calculate_taxes()
 		self.set_amounts()
 		self.clear_unallocated_reference_document_rows()
 		self.validate_payment_against_negative_invoice()
@@ -386,6 +389,43 @@
 		else:
 			self.status = 'Draft'
 
+	def set_tax_withholding(self):
+		if not self.party_type == 'Supplier':
+			return
+
+		if not self.apply_tax_withholding_amount:
+			return
+
+		if self.references:
+			return
+
+		args = frappe._dict({
+			'company': self.company,
+			'supplier': self.party,
+			'posting_date': self.posting_date,
+			'net_total': self.paid_amount
+		})
+
+		tax_withholding_details = get_party_tax_withholding_details(args, self.tax_withholding_category)
+
+		if not tax_withholding_details:
+			return
+
+		accounts = []
+		for d in self.taxes:
+			if d.account_head == tax_withholding_details.get("account_head"):
+				d.update(tax_withholding_details)
+			accounts.append(d.account_head)
+
+		if not accounts or tax_withholding_details.get("account_head") not in accounts:
+			self.append("taxes", tax_withholding_details)
+
+		to_remove = [d for d in self.taxes
+			if not d.tax_amount and d.account_head == tax_withholding_details.get("account_head")]
+
+		for d in to_remove:
+			self.remove(d)
+
 	def set_amounts(self):
 		self.set_amounts_in_company_currency()
 		self.set_total_allocated_amount()
@@ -423,12 +463,12 @@
 			if self.payment_type == "Receive" \
 				and self.base_total_allocated_amount < self.base_received_amount + total_deductions \
 				and self.total_allocated_amount < self.paid_amount + (total_deductions / self.source_exchange_rate):
-					self.unallocated_amount = (self.base_received_amount + total_deductions -
+					self.unallocated_amount = (self.base_received_amount + self.base_total_taxes_and_charges + total_deductions -
 						self.base_total_allocated_amount) / self.source_exchange_rate
 			elif self.payment_type == "Pay" \
 				and self.base_total_allocated_amount < (self.base_paid_amount - total_deductions) \
 				and self.total_allocated_amount < self.received_amount + (total_deductions / self.target_exchange_rate):
-					self.unallocated_amount = (self.base_paid_amount - (total_deductions +
+					self.unallocated_amount = (self.base_paid_amount + self.base_total_taxes_and_charges - (total_deductions +
 						self.base_total_allocated_amount)) / self.target_exchange_rate
 
 	def set_difference_amount(self):
@@ -446,7 +486,7 @@
 
 		total_deductions = sum([flt(d.amount) for d in self.get("deductions")])
 
-		self.difference_amount = flt(self.difference_amount - total_deductions,
+		self.difference_amount = flt(self.difference_amount - total_deductions + self.base_total_taxes_and_charges,
 			self.precision("difference_amount"))
 
 	# Paid amount is auto allocated in the reference document by default.
@@ -532,6 +572,7 @@
 		self.add_party_gl_entries(gl_entries)
 		self.add_bank_gl_entries(gl_entries)
 		self.add_deductions_gl_entries(gl_entries)
+		self.add_tax_gl_entries(gl_entries)
 
 		make_gl_entries(gl_entries, cancel=cancel, adv_adj=adv_adj)
 
@@ -607,6 +648,26 @@
 				}, item=self)
 			)
 
+	def add_tax_gl_entries(self, gl_entries):
+		for d in self.get('taxes'):
+			account_currency = get_account_currency(d.account_head)
+			if account_currency != self.company_currency:
+				frappe.throw(_("Currency for {0} must be {1}").format(d.account_head, self.company_currency))
+
+			dr_or_cr = "credit" if d.add_deduct_tax == "Add" else "debit"
+
+			gl_entries.append(
+				self.get_gl_dict({
+					"account": d.account_head,
+					"against": self.party if self.payment_type=="Receive" else self.paid_from,
+					dr_or_cr: d.base_tax_amount,
+					dr_or_cr + "_in_account_currency": d.base_tax_amount \
+						if account_currency==self.company_currency \
+						else d.tax_amount,
+					"cost_center": d.cost_center
+				}, account_currency, item=d)
+			)
+
 	def add_deductions_gl_entries(self, gl_entries):
 		for d in self.get("deductions"):
 			if d.amount:
@@ -671,6 +732,51 @@
 		self.append('deductions', row)
 		self.set_unallocated_amount()
 
+	def calculate_taxes(self):
+		self.total_taxes_and_charges = 0.0
+		self.base_total_taxes_and_charges = 0.0
+
+		for i, tax in enumerate(self.taxes):
+			tax_rate = tax.rate
+			current_tax_rate = 0.0
+
+			# To set row_id by default as previous row.
+			if tax.charge_type in ["On Previous Row Amount", "On Previous Row Total"]:
+				if tax.idx == 1:
+					frappe.throw(_("Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row"))
+
+				if not tax.row_id:
+					tax.row_id = tax.idx - 1
+
+			if tax.charge_type == "Actual":
+				current_tax_amount = flt(tax.tax_amount, self.precision("tax_amount", tax))
+			elif tax.charge_type == "On Paid Amount":
+				current_tax_amount = (tax_rate / 100.0) * self.paid_amount
+			elif tax.charge_type == "On Previous Row Amount":
+				current_tax_amount = (tax_rate / 100.0) * \
+					self.taxes[cint(tax.row_id) - 1].tax_amount
+
+			elif tax.charge_type == "On Previous Row Total":
+				current_tax_amount = (tax_rate / 100.0) * \
+					self.taxes[cint(tax.row_id) - 1].total
+
+			tax.tax_amount = current_tax_amount
+			tax.base_tax_amount = tax.tax_amount * self.source_exchange_rate
+
+			if tax.add_deduct_tax == "Deduct":
+				current_tax_amount *= -1.0
+			else:
+				current_tax_amount *= 1.0
+
+			if i == 0:
+				tax.total = flt(self.paid_amount + current_tax_amount, self.precision("total", tax))
+			else:
+				tax.total = flt(self.taxes[i-1].total + current_tax_amount, self.precision("total", tax))
+
+			tax.base_total = tax.total * self.source_exchange_rate
+			self.total_taxes_and_charges += current_tax_amount
+			self.base_total_taxes_and_charges += current_tax_amount * self.source_exchange_rate
+
 @frappe.whitelist()
 def get_outstanding_reference_documents(args):
 
diff --git a/erpnext/accounts/doctype/payment_entry_deduction/payment_entry_deduction.json b/erpnext/accounts/doctype/payment_entry_deduction/payment_entry_deduction.json
index 7060d11..61a1462 100644
--- a/erpnext/accounts/doctype/payment_entry_deduction/payment_entry_deduction.json
+++ b/erpnext/accounts/doctype/payment_entry_deduction/payment_entry_deduction.json
@@ -1,140 +1,70 @@
 {
- "allow_copy": 0, 
- "allow_events_in_timeline": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 0, 
- "beta": 0, 
- "creation": "2016-06-15 15:56:30.815503", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "", 
- "editable_grid": 1, 
+ "actions": [],
+ "creation": "2016-06-15 15:56:30.815503",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "field_order": [
+  "account",
+  "cost_center",
+  "amount",
+  "column_break_2",
+  "description"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "account", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Account", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Account", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "account",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Account",
+   "options": "Account",
+   "reqd": 1,
+   "show_days": 1,
+   "show_seconds": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "cost_center", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Cost Center", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Cost Center", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "cost_center",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Cost Center",
+   "options": "Cost Center",
+   "print_hide": 1,
+   "reqd": 1,
+   "show_days": 1,
+   "show_seconds": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "amount", 
-   "fieldtype": "Currency", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Amount", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
+   "fieldname": "amount",
+   "fieldtype": "Currency",
+   "in_list_view": 1,
+   "label": "Amount",
+   "reqd": 1,
+   "show_days": 1,
+   "show_seconds": 1
+  },
+  {
+   "fieldname": "column_break_2",
+   "fieldtype": "Column Break",
+   "show_days": 1,
+   "show_seconds": 1
+  },
+  {
+   "fieldname": "description",
+   "fieldtype": "Small Text",
+   "label": "Description",
+   "show_days": 1,
+   "show_seconds": 1
   }
- ], 
- "has_web_view": 0, 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "idx": 0, 
- "image_view": 0, 
- "in_create": 0, 
- "is_submittable": 0, 
- "issingle": 0, 
- "istable": 1, 
- "max_attachments": 0, 
- "modified": "2019-01-07 16:52:07.040146", 
- "modified_by": "Administrator", 
- "module": "Accounts", 
- "name": "Payment Entry Deduction", 
- "name_case": "", 
- "owner": "Administrator", 
- "permissions": [], 
- "quick_entry": 1, 
- "read_only": 0, 
- "read_only_onload": 0, 
- "show_name_in_global_search": 0, 
- "sort_field": "modified", 
- "sort_order": "DESC", 
- "track_changes": 0, 
- "track_seen": 0, 
- "track_views": 0
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2020-09-12 20:38:08.110674",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Payment Entry Deduction",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC"
 }
\ No newline at end of file
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 544e624..65e5823 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -617,6 +617,10 @@
 		payment_entries = get_advance_payment_entries(party_type, party, party_account,
 			order_doctype, order_list, include_unallocated)
 
+		payment_entry_list = [d.reference_name for d in payment_entries]
+
+		payment_entry_taxes = get_payment_entry_taxes(payment_entry_list)
+
 		res = journal_entries + payment_entries
 
 		return res
@@ -1241,6 +1245,12 @@
 
 	return list(payment_entries_against_order) + list(unallocated_payment_entries)
 
+def get_payment_entry_taxes(payment_entry_list):
+	taxes = frappe.db.sql("""
+		SELECT t.parent, t.add_deduct_tax, t.charge_type, t.account_head, t.cost_center,
+		t.tax_amount FROM `tabAdvance Taxes and Charges` where t.parent in %s"""
+	,(payment_entry_list, ), as_dict=1)
+
 
 def update_invoice_status():
 	# Daily update the status of the invoices
diff --git a/erpnext/public/js/controllers/accounts.js b/erpnext/public/js/controllers/accounts.js
index ceeecb2..23d6360 100644
--- a/erpnext/public/js/controllers/accounts.js
+++ b/erpnext/public/js/controllers/accounts.js
@@ -165,7 +165,7 @@
 		msg = __("Please select Charge Type first");
 		d.row_id = "";
 		d.rate = d.tax_amount = 0.0;
-	} else if((d.charge_type == 'Actual' || d.charge_type == 'On Net Total') && d.row_id) {
+	} else if((d.charge_type == 'Actual' || d.charge_type == 'On Net Total' || d.charge_type == 'On Paid Amount') && d.row_id) {
 		msg = __("Can refer row only if the charge type is 'On Previous Row Amount' or 'Previous Row Total'");
 		d.row_id = "";
 	} else if((d.charge_type == 'On Previous Row Amount' || d.charge_type == 'On Previous Row Total') && d.row_id) {