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) {