diff --git a/erpnext/accounts/doctype/advance_taxes_and_charges/__init__.py b/erpnext/accounts/doctype/advance_taxes_and_charges/__init__.py new file mode 100644 index 0000000000..e69de29bb2 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 new file mode 100644 index 0000000000..4d63499431 --- /dev/null +++ b/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.json @@ -0,0 +1,197 @@ +{ + "actions": [], + "creation": "2020-09-12 22:26:19.594367", + "doctype": "DocType", + "document_type": "Setup", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "add_deduct_tax", + "charge_type", + "row_id", + "account_head", + "col_break_1", + "description", + "included_in_paid_amount", + "accounting_dimensions_section", + "cost_center", + "dimension_col_break", + "section_break_8", + "rate", + "section_break_9", + "currency", + "tax_amount", + "total", + "allocated_amount", + "column_break_13", + "base_tax_amount", + "base_total", + "base_allocated_amount" + ], + "fields": [ + { + "columns": 2, + "fieldname": "charge_type", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Type", + "oldfieldname": "charge_type", + "oldfieldtype": "Select", + "options": "\nActual\nOn Paid Amount\nOn Previous Row Amount\nOn Previous Row Total", + "reqd": 1 + }, + { + "depends_on": "eval:[\"On Previous Row Amount\", \"On Previous Row Total\"].indexOf(doc.charge_type)!==-1", + "fieldname": "row_id", + "fieldtype": "Data", + "label": "Reference Row #", + "oldfieldname": "row_id", + "oldfieldtype": "Data" + }, + { + "columns": 2, + "fieldname": "account_head", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Account Head", + "oldfieldname": "account_head", + "oldfieldtype": "Link", + "options": "Account", + "reqd": 1, + "search_index": 1 + }, + { + "fieldname": "col_break_1", + "fieldtype": "Column Break", + "width": "50%" + }, + { + "fieldname": "description", + "fieldtype": "Small Text", + "label": "Description", + "oldfieldname": "description", + "oldfieldtype": "Small Text", + "print_width": "300px", + "reqd": 1, + "width": "300px" + }, + { + "fieldname": "accounting_dimensions_section", + "fieldtype": "Section Break", + "label": "Accounting Dimensions" + }, + { + "default": ":Company", + "fieldname": "cost_center", + "fieldtype": "Link", + "label": "Cost Center", + "oldfieldname": "cost_center_other_charges", + "oldfieldtype": "Link", + "options": "Cost Center" + }, + { + "fieldname": "dimension_col_break", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_8", + "fieldtype": "Section Break" + }, + { + "columns": 2, + "fieldname": "rate", + "fieldtype": "Float", + "in_list_view": 1, + "label": "Rate", + "oldfieldname": "rate", + "oldfieldtype": "Currency" + }, + { + "fieldname": "section_break_9", + "fieldtype": "Section Break" + }, + { + "columns": 2, + "fieldname": "tax_amount", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Amount", + "options": "currency" + }, + { + "columns": 2, + "fieldname": "total", + "fieldtype": "Currency", + "in_list_view": 1, + "label": "Total", + "options": "currency", + "read_only": 1 + }, + { + "fieldname": "column_break_13", + "fieldtype": "Column Break" + }, + { + "fieldname": "base_tax_amount", + "fieldtype": "Currency", + "label": "Amount (Company Currency)", + "oldfieldname": "tax_amount", + "oldfieldtype": "Currency", + "options": "Company:company:default_currency", + "read_only": 1 + }, + { + "fieldname": "base_total", + "fieldtype": "Currency", + "label": "Total (Company Currency)", + "oldfieldname": "total", + "oldfieldtype": "Currency", + "options": "Company:company:default_currency", + "read_only": 1 + }, + { + "fieldname": "add_deduct_tax", + "fieldtype": "Select", + "label": "Add Or Deduct", + "options": "Add\nDeduct", + "reqd": 1 + }, + { + "default": "0", + "fieldname": "included_in_paid_amount", + "fieldtype": "Check", + "label": "Considered In Paid Amount" + }, + { + "fieldname": "allocated_amount", + "fieldtype": "Currency", + "label": "Allocated Amount", + "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", + "label": "Account Currency", + "options": "Currency", + "read_only": 1 + } + ], + "index_web_pages_for_search": 1, + "istable": 1, + "links": [], + "modified": "2021-06-09 11:46:58.373170", + "modified_by": "Administrator", + "module": "Accounts", + "name": "Advance Taxes and Charges", + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "ASC" +} \ No newline at end of file diff --git a/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.py b/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.py new file mode 100644 index 0000000000..597d2ccc62 --- /dev/null +++ b/erpnext/accounts/doctype/advance_taxes_and_charges/advance_taxes_and_charges.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +# import frappe +from frappe.model.document import Document + +class AdvanceTaxesandCharges(Document): + pass diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index b80e8ada38..939f3546ff 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) { @@ -91,6 +93,16 @@ frappe.ui.form.on('Payment Entry', { } }); + frm.set_query("advance_tax_account", function() { + return { + filters: { + "company": frm.doc.company, + "root_type": ["in", ["Asset", "Liability"]], + "is_group": 0 + } + } + }); + frm.set_query("reference_doctype", "references", function() { if (frm.doc.party_type == "Customer") { var doctypes = ["Sales Order", "Sales Invoice", "Journal Entry", "Dunning"]; @@ -182,6 +194,8 @@ frappe.ui.form.on('Payment Entry', { 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 @@ -216,7 +230,7 @@ frappe.ui.form.on('Payment Entry', { var company_currency = frm.doc.company? frappe.get_doc(":Company", frm.doc.company).default_currency: ""; frm.set_currency_labels(["base_paid_amount", "base_received_amount", "base_total_allocated_amount", - "difference_amount"], company_currency); + "difference_amount", "base_paid_amount_after_tax", "base_received_amount_after_tax"], company_currency); frm.set_currency_labels(["paid_amount"], frm.doc.paid_from_account_currency); frm.set_currency_labels(["received_amount"], frm.doc.paid_to_account_currency); @@ -224,11 +238,13 @@ frappe.ui.form.on('Payment Entry', { var party_account_currency = frm.doc.payment_type=="Receive" ? frm.doc.paid_from_account_currency : frm.doc.paid_to_account_currency; - frm.set_currency_labels(["total_allocated_amount", "unallocated_amount"], party_account_currency); + frm.set_currency_labels(["total_allocated_amount", "unallocated_amount", + "total_taxes_and_charges"], party_account_currency); var currency_field = (frm.doc.payment_type=="Receive") ? "paid_from_account_currency" : "paid_to_account_currency" frm.set_df_property("total_allocated_amount", "options", currency_field); frm.set_df_property("unallocated_amount", "options", currency_field); + frm.set_df_property("total_taxes_and_charges", "options", currency_field); frm.set_df_property("party_balance", "options", currency_field); frm.set_currency_labels(["total_amount", "outstanding_amount", "allocated_amount"], @@ -364,6 +380,16 @@ frappe.ui.form.on('Payment Entry', { } }, + apply_tax_withholding_amount: function(frm) { + if (!frm.doc.apply_tax_withholding_amount) { + frm.set_value("tax_withholding_category", ''); + } else { + frappe.db.get_value('Supplier', frm.doc.party, 'tax_withholding_category', (values) => { + frm.set_value("tax_withholding_category", values.tax_withholding_category); + }); + } + }, + paid_from: function(frm) { if(frm.set_party_account_based_on_party) return; @@ -843,12 +869,12 @@ frappe.ui.form.on('Payment Entry', { 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 +900,8 @@ frappe.ui.form.on('Payment Entry', { 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 +1029,203 @@ frappe.ui.form.on('Payment Entry', { } }); } - } + }, + + 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.events.apply_taxes(frm); + frm.events.set_unallocated_amount(frm); + } + } + } + }); + }, + + apply_taxes: function(frm) { + frm.events.initialize_taxes(frm); + frm.events.determine_exclusive_rate(frm); + frm.events.calculate_taxes(frm); + }, + + initialize_taxes: function(frm) { + $.each(frm.doc["taxes"] || [], function(i, tax) { + tax.item_wise_tax_detail = {}; + let tax_fields = ["total", "tax_fraction_for_current_item", + "grand_total_fraction_for_current_item"]; + + if (cstr(tax.charge_type) != "Actual") { + tax_fields.push("tax_amount"); + } + + $.each(tax_fields, function(i, fieldname) { tax[fieldname] = 0.0; }); + + frm.doc.paid_amount_after_tax = frm.doc.paid_amount; + }); + }, + + determine_exclusive_rate: function(frm) { + let has_inclusive_tax = false; + $.each(frm.doc["taxes"] || [], function(i, row) { + if(cint(row.included_in_paid_amount)) has_inclusive_tax = true; + }); + if(has_inclusive_tax==false) return; + + let cumulated_tax_fraction = 0.0; + $.each(frm.doc["taxes"] || [], function(i, tax) { + let current_tax_fraction = frm.events.get_current_tax_fraction(frm, tax); + tax.tax_fraction_for_current_item = current_tax_fraction[0]; + + if(i==0) { + tax.grand_total_fraction_for_current_item = 1 + tax.tax_fraction_for_current_item; + } else { + tax.grand_total_fraction_for_current_item = + me.frm.doc["taxes"][i-1].grand_total_fraction_for_current_item + + tax.tax_fraction_for_current_item; + } + + cumulated_tax_fraction += tax.tax_fraction_for_current_item; + frm.doc.paid_amount_after_tax = flt(frm.doc.paid_amount/(1+cumulated_tax_fraction)) + }); + }, + + get_current_tax_fraction: function(frm, tax) { + let current_tax_fraction = 0.0; + + if(cint(tax.included_in_paid_amount)) { + let tax_rate = tax.rate; + + if (tax.charge_type == "Actual") { + current_tax_fraction = tax.tax_amount/(frm.doc.paid_amount_after_tax + frm.doc.tax_amount); + } else if(tax.charge_type == "On Paid Amount") { + current_tax_fraction = (tax_rate / 100.0); + } else if(tax.charge_type == "On Previous Row Amount") { + current_tax_fraction = (tax_rate / 100.0) * + frm.doc["taxes"][cint(tax.row_id) - 1].tax_fraction_for_current_item; + } else if(tax.charge_type == "On Previous Row Total") { + current_tax_fraction = (tax_rate / 100.0) * + frm.doc["taxes"][cint(tax.row_id) - 1].grand_total_fraction_for_current_item; + } + } + + if(tax.add_deduct_tax && tax.add_deduct_tax == "Deduct") { + current_tax_fraction *= -1; + inclusive_tax_amount_per_qty *= -1; + } + return current_tax_fraction; + }, + + + calculate_taxes: function(frm) { + frm.doc.total_taxes_and_charges = 0.0; + frm.doc.base_total_taxes_and_charges = 0.0; + + let actual_tax_dict = {}; + + // maintain actual tax rate based on idx + $.each(frm.doc["taxes"] || [], function(i, tax) { + if (tax.charge_type == "Actual") { + actual_tax_dict[tax.idx] = flt(tax.tax_amount, precision("tax_amount", tax)); + } + }); + + $.each(me.frm.doc["taxes"] || [], function(i, tax) { + let current_tax_amount = frm.events.get_current_tax_amount(frm, tax); + + // Adjust divisional loss to the last item + if (tax.charge_type == "Actual") { + actual_tax_dict[tax.idx] -= current_tax_amount; + if (i == frm.doc["taxes"].length - 1) { + current_tax_amount += actual_tax_dict[tax.idx]; + } + } + + 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_after_tax + 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'); + }); + }, + + get_current_tax_amount: function(frm, 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 = flt((tax_rate / 100.0) * frm.doc.paid_amount_after_tax); + } else if(tax.charge_type == "On Previous Row Amount") { + current_tax_amount = flt((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 = flt((tax_rate / 100.0) * + frm.doc["taxes"][cint(tax.row_id) - 1].total); + } + + return current_tax_amount; + }, }); @@ -1049,6 +1272,33 @@ frappe.ui.form.on('Payment Entry Reference', { } }) +frappe.ui.form.on('Advance Taxes and Charges', { + rate: function(frm) { + frm.events.apply_taxes(frm); + frm.events.set_unallocated_amount(frm); + }, + + tax_amount : function(frm) { + frm.events.apply_taxes(frm); + frm.events.set_unallocated_amount(frm); + }, + + row_id: function(frm) { + frm.events.apply_taxes(frm); + frm.events.set_unallocated_amount(frm); + }, + + taxes_remove: function(frm) { + frm.events.apply_taxes(frm); + frm.events.set_unallocated_amount(frm); + }, + + included_in_paid_amount: function(frm) { + frm.events.apply_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 328584a61a..54623dd6cd 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.json +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.json @@ -35,12 +35,16 @@ "paid_to_account_balance", "payment_amounts_section", "paid_amount", + "paid_amount_after_tax", "source_exchange_rate", "base_paid_amount", + "base_paid_amount_after_tax", "column_break_21", "received_amount", + "received_amount_after_tax", "target_exchange_rate", "base_received_amount", + "base_received_amount_after_tax", "section_break_14", "get_outstanding_invoice", "references", @@ -52,6 +56,17 @@ "unallocated_amount", "difference_amount", "write_off_difference_amount", + "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", + "section_break_56", + "taxes", + "base_total_taxes_and_charges", + "total_taxes_and_charges", "deductions_or_loss_section", "deductions", "transaction_references", @@ -320,6 +335,7 @@ "reqd": 1 }, { + "depends_on": "doc.received_amount", "fieldname": "base_received_amount", "fieldtype": "Currency", "label": "Received Amount (Company Currency)", @@ -584,12 +600,114 @@ "fieldname": "custom_remarks", "fieldtype": "Check", "label": "Custom Remarks" + }, + { + "depends_on": "eval:doc.apply_tax_withholding_amount", + "fieldname": "tax_withholding_category", + "fieldtype": "Link", + "label": "Tax Withholding Category", + "mandatory_depends_on": "eval:doc.apply_tax_withholding_amount", + "options": "Tax Withholding Category" + }, + { + "default": "0", + "depends_on": "eval:doc.party_type == 'Supplier'", + "fieldname": "apply_tax_withholding_amount", + "fieldtype": "Check", + "label": "Apply Tax Withholding Amount" + }, + { + "collapsible": 1, + "fieldname": "taxes_and_charges_section", + "fieldtype": "Section Break", + "label": "Taxes and Charges" + }, + { + "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" + }, + { + "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" + }, + { + "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" + }, + { + "fieldname": "base_total_taxes_and_charges", + "fieldtype": "Currency", + "label": "Total Taxes and Charges (Company Currency)", + "options": "Company:company:default_currency", + "read_only": 1 + }, + { + "fieldname": "total_taxes_and_charges", + "fieldtype": "Currency", + "label": "Total Taxes and Charges", + "read_only": 1 + }, + { + "fieldname": "paid_amount_after_tax", + "fieldtype": "Currency", + "hidden": 1, + "label": "Paid Amount After Tax", + "options": "paid_from_account_currency", + "read_only": 1 + }, + { + "fieldname": "base_paid_amount_after_tax", + "fieldtype": "Currency", + "label": "Paid Amount After Tax (Company Currency)", + "options": "Company:company:default_currency", + "read_only": 1 + }, + { + "fieldname": "column_break_55", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_56", + "fieldtype": "Section Break", + "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", + "fieldname": "received_amount_after_tax", + "fieldtype": "Currency", + "label": "Received Amount After Tax", + "options": "paid_to_account_currency" + }, + { + "depends_on": "doc.received_amount", + "fieldname": "base_received_amount_after_tax", + "fieldtype": "Currency", + "label": "Received Amount After Tax (Company Currency)", + "options": "Company:company:default_currency" } ], "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2021-03-08 13:05:16.958866", + "modified": "2021-06-09 11:55:04.215050", "modified_by": "Administrator", "module": "Accounts", "name": "Payment Entry", @@ -633,4 +751,4 @@ "sort_order": "DESC", "title_field": "title", "track_changes": 1 -} +} \ No newline at end of file diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index e01c651a93..edca210142 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.hr.doctype.expense_claim.expense_claim import update_reimbursed_amo 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 @@ class PaymentEntry(AccountsController): self.set_exchange_rate() self.validate_mandatory() self.validate_reference_documents() + self.set_tax_withholding() + self.apply_taxes() self.set_amounts() self.clear_unallocated_reference_document_rows() self.validate_payment_against_negative_invoice() @@ -310,7 +313,6 @@ class PaymentEntry(AccountsController): + "

" + _("If this is undesirable please cancel the corresponding Payment Entry."), title=_("Warning"), indicator="orange") - def validate_journal_entry(self): for d in self.get("references"): if d.allocated_amount and d.reference_doctype == "Journal Entry": @@ -391,12 +393,110 @@ class PaymentEntry(AccountsController): self.db_set('status', self.status, update_modified = True) + def set_tax_withholding(self): + if not self.party_type == 'Supplier': + return + + 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")) + + reference_doclist = [] + net_total = self.paid_amount + included_in_paid_amount = 0 + + if self.get('references'): + for doc in self.get('references'): + if doc.reference_doctype == 'Purchase Order': + reference_doclist.append(doc.reference_name) + + if reference_doclist: + order_amount = frappe.db.get_all('Purchase Order', fields=['sum(net_total)'], + filters = {'name': ('in', reference_doclist), 'docstatus': 1, + 'apply_tds': 1}, as_list=1) + + if order_amount: + net_total = order_amount[0][0] + included_in_paid_amount = 1 + + # Adding args as purchase invoice to get TDS amount + args = frappe._dict({ + 'company': self.company, + 'doctype': 'Purchase Invoice', + 'supplier': self.party, + 'posting_date': self.posting_date, + 'net_total': net_total + }) + + tax_withholding_details = get_party_tax_withholding_details(args, self.tax_withholding_category) + + if not tax_withholding_details: + return + + tax_withholding_details.update({ + 'included_in_paid_amount': included_in_paid_amount, + 'cost_center': self.cost_center or erpnext.get_default_cost_center(self.company) + }) + + accounts = [] + for d in self.taxes: + if d.account_head == tax_withholding_details.get("account_head"): + + # Preserve user updated included in paid amount + if d.included_in_paid_amount: + tax_withholding_details.update({'included_in_paid_amount': d.included_in_paid_amount}) + + 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 apply_taxes(self): + self.initialize_taxes() + self.determine_exclusive_rate() + self.calculate_taxes() + def set_amounts(self): + self.set_received_amount() self.set_amounts_in_company_currency() + self.set_amounts_after_tax() self.set_total_allocated_amount() self.set_unallocated_amount() self.set_difference_amount() + def set_received_amount(self): + self.base_received_amount = self.base_paid_amount + + def set_amounts_after_tax(self): + applicable_tax = 0 + base_applicable_tax = 0 + for tax in self.get('taxes'): + if not tax.included_in_paid_amount: + amount = -1 * tax.tax_amount if tax.add_deduct_tax == 'Deduct' else tax.tax_amount + base_amount = -1 * tax.base_tax_amount if tax.add_deduct_tax == 'Deduct' else tax.base_tax_amount + + applicable_tax += amount + base_applicable_tax += base_amount + + self.paid_amount_after_tax = flt(flt(self.paid_amount) + flt(applicable_tax), + self.precision("paid_amount_after_tax")) + self.base_paid_amount_after_tax = flt(flt(self.paid_amount_after_tax) * flt(self.source_exchange_rate), + self.precision("base_paid_amount_after_tax")) + + self.received_amount_after_tax = flt(flt(self.received_amount) + flt(applicable_tax), + self.precision("paid_amount_after_tax")) + self.base_received_amount_after_tax = flt(flt(self.received_amount_after_tax) * flt(self.target_exchange_rate), + self.precision("base_paid_amount_after_tax")) + def set_amounts_in_company_currency(self): self.base_paid_amount, self.base_received_amount, self.difference_amount = 0, 0, 0 if self.paid_amount: @@ -426,15 +526,15 @@ class PaymentEntry(AccountsController): if self.party: total_deductions = sum([flt(d.amount) for d in self.get("deductions")]) 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.base_total_allocated_amount) / self.source_exchange_rate + and self.base_total_allocated_amount < self.base_received_amount_after_tax + total_deductions \ + and self.total_allocated_amount < self.paid_amount_after_tax + (total_deductions / self.source_exchange_rate): + self.unallocated_amount = (self.received_amount_after_tax + 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.base_total_allocated_amount)) / self.target_exchange_rate + and self.base_total_allocated_amount < (self.base_paid_amount_after_tax - total_deductions) \ + and self.total_allocated_amount < self.received_amount_after_tax + (total_deductions / self.target_exchange_rate): + self.unallocated_amount = (self.base_paid_amount_after_tax - (total_deductions + + self.base_total_allocated_amount)) / self.target_exchange_rate def set_difference_amount(self): base_unallocated_amount = flt(self.unallocated_amount) * (flt(self.source_exchange_rate) @@ -443,11 +543,11 @@ class PaymentEntry(AccountsController): base_party_amount = flt(self.base_total_allocated_amount) + flt(base_unallocated_amount) if self.payment_type == "Receive": - self.difference_amount = base_party_amount - self.base_received_amount + self.difference_amount = base_party_amount - self.base_received_amount_after_tax elif self.payment_type == "Pay": - self.difference_amount = self.base_paid_amount - base_party_amount + self.difference_amount = self.base_paid_amount_after_tax - base_party_amount else: - self.difference_amount = self.base_paid_amount - flt(self.base_received_amount) + self.difference_amount = self.base_paid_amount_after_tax - flt(self.base_received_amount_after_tax) total_deductions = sum([flt(d.amount) for d in self.get("deductions")]) @@ -537,6 +637,7 @@ class PaymentEntry(AccountsController): 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) @@ -576,7 +677,7 @@ class PaymentEntry(AccountsController): gl_entries.append(gle) if self.unallocated_amount: - base_unallocated_amount = base_unallocated_amount = self.unallocated_amount * \ + base_unallocated_amount = self.unallocated_amount * \ (self.source_exchange_rate if self.payment_type=="Receive" else self.target_exchange_rate) gle = party_gl_dict.copy() @@ -595,8 +696,8 @@ class PaymentEntry(AccountsController): "account": self.paid_from, "account_currency": self.paid_from_account_currency, "against": self.party if self.payment_type=="Pay" else self.paid_to, - "credit_in_account_currency": self.paid_amount, - "credit": self.base_paid_amount, + "credit_in_account_currency": self.paid_amount_after_tax, + "credit": self.base_paid_amount_after_tax, "cost_center": self.cost_center }, item=self) ) @@ -606,12 +707,48 @@ class PaymentEntry(AccountsController): "account": self.paid_to, "account_currency": self.paid_to_account_currency, "against": self.party if self.payment_type=="Receive" else self.paid_from, - "debit_in_account_currency": self.received_amount, - "debit": self.base_received_amount, + "debit_in_account_currency": self.received_amount_after_tax, + "debit": self.base_received_amount_after_tax, "cost_center": self.cost_center }, 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)) + + if (self.payment_type == 'Pay' and self.advance_tax_account) or self.payment_type == 'Receive': + dr_or_cr = "debit" if d.add_deduct_tax == "Add" else "credit" + elif (self.payment_type == 'Receive' and self.advance_tax_account) or self.payment_type == 'Pay': + dr_or_cr = "credit" if d.add_deduct_tax == "Add" else "debit" + + payment_or_advance_account = self.get_party_account_for_taxes() + + 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)) + + #Intentionally use -1 to get net values in party account + gl_entries.append( + self.get_gl_dict({ + "account": payment_or_advance_account, + "against": self.party if self.payment_type=="Receive" else self.paid_from, + dr_or_cr: -1 * d.base_tax_amount, + dr_or_cr + "_in_account_currency": -1*d.base_tax_amount + if account_currency==self.company_currency + else d.tax_amount, + "cost_center": self.cost_center, + }, account_currency, item=d)) + def add_deductions_gl_entries(self, gl_entries): for d in self.get("deductions"): if d.amount: @@ -630,6 +767,14 @@ class PaymentEntry(AccountsController): }, item=d) ) + def get_party_account_for_taxes(self): + if self.advance_tax_account: + return self.advance_tax_account + elif self.payment_type == 'Pay': + return self.paid_from + elif self.payment_type == 'Receive': + return self.paid_to + def update_advance_paid(self): if self.payment_type in ("Receive", "Pay") and self.party: for d in self.get("references"): @@ -676,6 +821,121 @@ class PaymentEntry(AccountsController): self.append('deductions', row) self.set_unallocated_amount() + def initialize_taxes(self): + for tax in self.get("taxes"): + tax_fields = ["total", "tax_fraction_for_current_item", "grand_total_fraction_for_current_item"] + + if tax.charge_type != "Actual": + tax_fields.append("tax_amount") + + for fieldname in tax_fields: + tax.set(fieldname, 0.0) + + self.paid_amount_after_tax = self.paid_amount + + def determine_exclusive_rate(self): + if not any((cint(tax.included_in_paid_amount) for tax in self.get("taxes"))): + return + + cumulated_tax_fraction = 0 + for i, tax in enumerate(self.get("taxes")): + tax.tax_fraction_for_current_item = self.get_current_tax_fraction(tax) + if i==0: + tax.grand_total_fraction_for_current_item = 1 + tax.tax_fraction_for_current_item + else: + tax.grand_total_fraction_for_current_item = \ + self.get("taxes")[i-1].grand_total_fraction_for_current_item \ + + tax.tax_fraction_for_current_item + + cumulated_tax_fraction += tax.tax_fraction_for_current_item + + self.paid_amount_after_tax = flt(self.paid_amount/(1+cumulated_tax_fraction)) + + def calculate_taxes(self): + self.total_taxes_and_charges = 0.0 + self.base_total_taxes_and_charges = 0.0 + + actual_tax_dict = dict([[tax.idx, flt(tax.tax_amount, tax.precision("tax_amount"))] + for tax in self.get("taxes") if tax.charge_type == "Actual"]) + + for i, tax in enumerate(self.get('taxes')): + current_tax_amount = self.get_current_tax_amount(tax) + + if tax.charge_type == "Actual": + actual_tax_dict[tax.idx] -= current_tax_amount + if i == len(self.get("taxes")) - 1: + current_tax_amount += actual_tax_dict[tax.idx] + + 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_after_tax + current_tax_amount, self.precision("total", tax)) + else: + tax.total = flt(self.get('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 + + if self.get('taxes'): + self.paid_amount_after_tax = self.get('taxes')[-1].base_total + + def get_current_tax_amount(self, tax): + tax_rate = tax.rate + + # 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_after_tax + elif tax.charge_type == "On Previous Row Amount": + current_tax_amount = (tax_rate / 100.0) * \ + self.get('taxes')[cint(tax.row_id) - 1].tax_amount + + elif tax.charge_type == "On Previous Row Total": + current_tax_amount = (tax_rate / 100.0) * \ + self.get('taxes')[cint(tax.row_id) - 1].total + + return current_tax_amount + + def get_current_tax_fraction(self, tax): + current_tax_fraction = 0 + + if cint(tax.included_in_paid_amount): + tax_rate = tax.rate + + if tax.charge_type == 'Actual': + current_tax_fraction = tax.tax_amount/ (self.paid_amount_after_tax + tax.tax_amount) + elif tax.charge_type == "On Paid Amount": + current_tax_fraction = tax_rate / 100.0 + + elif tax.charge_type == "On Previous Row Amount": + current_tax_fraction = (tax_rate / 100.0) * \ + self.get("taxes")[cint(tax.row_id) - 1].tax_fraction_for_current_item + + elif tax.charge_type == "On Previous Row Total": + current_tax_fraction = (tax_rate / 100.0) * \ + self.get("taxes")[cint(tax.row_id) - 1].grand_total_fraction_for_current_item + + if getattr(tax, "add_deduct_tax", None) and tax.add_deduct_tax == "Deduct": + current_tax_fraction *= -1.0 + + return current_tax_fraction + @frappe.whitelist() def get_outstanding_reference_documents(args): @@ -1241,6 +1501,13 @@ def get_payment_entry(dt, dn, party_amount=None, bank_account=None, bank_amount= }) 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/payment_entry_deduction/payment_entry_deduction.json b/erpnext/accounts/doctype/payment_entry_deduction/payment_entry_deduction.json index 7060d11691..61a1462dd7 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/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json index 9157821520..a714ac7827 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json @@ -175,7 +175,9 @@ "hidden": 1, "label": "Title", "no_copy": 1, - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "naming_series", @@ -187,7 +189,9 @@ "options": "ACC-PINV-.YYYY.-\nACC-PINV-RET-.YYYY.-", "print_hide": 1, "reqd": 1, - "set_only_once": 1 + "set_only_once": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "supplier", @@ -199,7 +203,9 @@ "options": "Supplier", "print_hide": 1, "reqd": 1, - "search_index": 1 + "search_index": 1, + "show_days": 1, + "show_seconds": 1 }, { "bold": 1, @@ -211,7 +217,9 @@ "label": "Supplier Name", "oldfieldname": "supplier_name", "oldfieldtype": "Data", - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fetch_from": "supplier.tax_id", @@ -219,21 +227,27 @@ "fieldtype": "Read Only", "label": "Tax Id", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "due_date", "fieldtype": "Date", "label": "Due Date", "oldfieldname": "due_date", - "oldfieldtype": "Date" + "oldfieldtype": "Date", + "show_days": 1, + "show_seconds": 1 }, { "default": "0", "fieldname": "is_paid", "fieldtype": "Check", "label": "Is Paid", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "default": "0", @@ -241,19 +255,25 @@ "fieldtype": "Check", "label": "Is Return (Debit Note)", "no_copy": 1, - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "default": "0", "fieldname": "apply_tds", "fieldtype": "Check", "label": "Apply Tax Withholding Amount", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "column_break1", "fieldtype": "Column Break", "oldfieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1, "width": "50%" }, { @@ -263,13 +283,17 @@ "label": "Company", "options": "Company", "print_hide": 1, - "remember_last_selected_value": 1 + "remember_last_selected_value": 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 }, { "default": "Today", @@ -281,7 +305,9 @@ "oldfieldtype": "Date", "print_hide": 1, "reqd": 1, - "search_index": 1 + "search_index": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "posting_time", @@ -290,6 +316,8 @@ "no_copy": 1, "print_hide": 1, "print_width": "100px", + "show_days": 1, + "show_seconds": 1, "width": "100px" }, { @@ -298,7 +326,9 @@ "fieldname": "set_posting_time", "fieldtype": "Check", "label": "Edit Posting Date and Time", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "amended_from", @@ -310,44 +340,58 @@ "oldfieldtype": "Link", "options": "Purchase Invoice", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, "collapsible_depends_on": "eval:doc.on_hold", "fieldname": "sb_14", "fieldtype": "Section Break", - "label": "Hold Invoice" + "label": "Hold Invoice", + "show_days": 1, + "show_seconds": 1 }, { "default": "0", "fieldname": "on_hold", "fieldtype": "Check", - "label": "Hold Invoice" + "label": "Hold Invoice", + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "eval:doc.on_hold", "description": "Once set, this invoice will be on hold till the set date", "fieldname": "release_date", "fieldtype": "Date", - "label": "Release Date" + "label": "Release Date", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "cb_17", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "eval:doc.on_hold", "fieldname": "hold_comment", "fieldtype": "Small Text", - "label": "Reason For Putting On Hold" + "label": "Reason For Putting On Hold", + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, "collapsible_depends_on": "bill_no", "fieldname": "supplier_invoice_details", "fieldtype": "Section Break", - "label": "Supplier Invoice Details" + "label": "Supplier Invoice Details", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "bill_no", @@ -355,11 +399,15 @@ "label": "Supplier Invoice No", "oldfieldname": "bill_no", "oldfieldtype": "Data", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "column_break_15", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "bill_date", @@ -368,13 +416,17 @@ "no_copy": 1, "oldfieldname": "bill_date", "oldfieldtype": "Date", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "return_against", "fieldname": "returns", "fieldtype": "Section Break", - "label": "Returns" + "label": "Returns", + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "return_against", @@ -384,26 +436,34 @@ "no_copy": 1, "options": "Purchase Invoice", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, "fieldname": "section_addresses", "fieldtype": "Section Break", - "label": "Address and Contact" + "label": "Address and Contact", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "supplier_address", "fieldtype": "Link", "label": "Select Supplier Address", "options": "Address", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "address_display", "fieldtype": "Small Text", "label": "Address", - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "contact_person", @@ -411,51 +471,67 @@ "in_global_search": 1, "label": "Contact Person", "options": "Contact", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "contact_display", "fieldtype": "Small Text", "label": "Contact", - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "contact_mobile", "fieldtype": "Small Text", "label": "Mobile No", - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "contact_email", "fieldtype": "Small Text", "label": "Contact Email", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "col_break_address", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "shipping_address", "fieldtype": "Link", "label": "Select Shipping Address", "options": "Address", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "shipping_address_display", "fieldtype": "Small Text", "label": "Shipping Address", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, "fieldname": "currency_and_price_list", "fieldtype": "Section Break", "label": "Currency and Price List", - "options": "fa fa-tag" + "options": "fa fa-tag", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "currency", @@ -464,7 +540,9 @@ "oldfieldname": "currency", "oldfieldtype": "Select", "options": "Currency", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "conversion_rate", @@ -473,18 +551,24 @@ "oldfieldname": "conversion_rate", "oldfieldtype": "Currency", "precision": "9", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "column_break2", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "buying_price_list", "fieldtype": "Link", "label": "Price List", "options": "Price List", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "price_list_currency", @@ -492,14 +576,18 @@ "label": "Price List Currency", "options": "Currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "plc_conversion_rate", "fieldtype": "Float", "label": "Price List Exchange Rate", "precision": "9", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "default": "0", @@ -508,11 +596,15 @@ "label": "Ignore Pricing Rule", "no_copy": 1, "permlevel": 1, - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "sec_warehouse", - "fieldtype": "Section Break" + "fieldtype": "Section Break", + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "update_stock", @@ -521,7 +613,9 @@ "fieldtype": "Link", "label": "Set Accepted Warehouse", "options": "Warehouse", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "update_stock", @@ -531,11 +625,15 @@ "label": "Rejected Warehouse", "no_copy": 1, "options": "Warehouse", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "col_break_warehouse", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "default": "No", @@ -543,25 +641,33 @@ "fieldtype": "Select", "label": "Raw Materials Supplied", "options": "No\nYes", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "items_section", "fieldtype": "Section Break", "oldfieldtype": "Section Break", - "options": "fa fa-shopping-cart" + "options": "fa fa-shopping-cart", + "show_days": 1, + "show_seconds": 1 }, { "default": "0", "fieldname": "update_stock", "fieldtype": "Check", "label": "Update Stock", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "scan_barcode", "fieldtype": "Data", - "label": "Scan Barcode" + "label": "Scan Barcode", + "show_days": 1, + "show_seconds": 1 }, { "allow_bulk_edit": 1, @@ -571,42 +677,56 @@ "oldfieldname": "entries", "oldfieldtype": "Table", "options": "Purchase Invoice Item", - "reqd": 1 + "reqd": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "pricing_rule_details", "fieldtype": "Section Break", - "label": "Pricing Rules" + "label": "Pricing Rules", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "pricing_rules", "fieldtype": "Table", "label": "Pricing Rule Detail", "options": "Pricing Rule Detail", - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "collapsible_depends_on": "supplied_items", "fieldname": "raw_materials_supplied", "fieldtype": "Section Break", - "label": "Raw Materials Supplied" + "label": "Raw Materials Supplied", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "supplied_items", "fieldtype": "Table", "label": "Supplied Items", "options": "Purchase Receipt Item Supplied", - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "section_break_26", - "fieldtype": "Section Break" + "fieldtype": "Section Break", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "total_qty", "fieldtype": "Float", "label": "Total Quantity", - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "base_total", @@ -614,7 +734,9 @@ "label": "Total (Company Currency)", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "base_net_total", @@ -624,18 +746,24 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "column_break_28", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "total", "fieldtype": "Currency", "label": "Total", "options": "currency", - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "net_total", @@ -645,42 +773,56 @@ "oldfieldtype": "Currency", "options": "currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "total_net_weight", "fieldtype": "Float", "label": "Total Net Weight", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "taxes_section", "fieldtype": "Section Break", "oldfieldtype": "Section Break", - "options": "fa fa-money" + "options": "fa fa-money", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "tax_category", "fieldtype": "Link", "label": "Tax Category", "options": "Tax Category", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "column_break_49", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "shipping_rule", "fieldtype": "Link", "label": "Shipping Rule", "options": "Shipping Rule", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "section_break_51", - "fieldtype": "Section Break" + "fieldtype": "Section Break", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "taxes_and_charges", @@ -689,7 +831,9 @@ "oldfieldname": "purchase_other_charges", "oldfieldtype": "Link", "options": "Purchase Taxes and Charges Template", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "taxes", @@ -697,13 +841,17 @@ "label": "Purchase Taxes and Charges", "oldfieldname": "purchase_tax_details", "oldfieldtype": "Table", - "options": "Purchase Taxes and Charges" + "options": "Purchase Taxes and Charges", + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, "fieldname": "sec_tax_breakup", "fieldtype": "Section Break", - "label": "Tax Breakup" + "label": "Tax Breakup", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "other_charges_calculation", @@ -712,13 +860,17 @@ "no_copy": 1, "oldfieldtype": "HTML", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "totals", "fieldtype": "Section Break", "oldfieldtype": "Section Break", - "options": "fa fa-money" + "options": "fa fa-money", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "base_taxes_and_charges_added", @@ -728,7 +880,9 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "base_taxes_and_charges_deducted", @@ -738,7 +892,9 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "base_total_taxes_and_charges", @@ -748,11 +904,15 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "column_break_40", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "taxes_and_charges_added", @@ -762,7 +922,9 @@ "oldfieldtype": "Currency", "options": "currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "taxes_and_charges_deducted", @@ -772,7 +934,9 @@ "oldfieldtype": "Currency", "options": "currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "total_taxes_and_charges", @@ -780,14 +944,18 @@ "label": "Total Taxes and Charges", "options": "currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, "collapsible_depends_on": "discount_amount", "fieldname": "section_break_44", "fieldtype": "Section Break", - "label": "Additional Discount" + "label": "Additional Discount", + "show_days": 1, + "show_seconds": 1 }, { "default": "Grand Total", @@ -795,7 +963,9 @@ "fieldtype": "Select", "label": "Apply Additional Discount On", "options": "\nGrand Total\nNet Total", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "base_discount_amount", @@ -803,28 +973,38 @@ "label": "Additional Discount Amount (Company Currency)", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "column_break_46", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "additional_discount_percentage", "fieldtype": "Float", "label": "Additional Discount Percentage", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "discount_amount", "fieldtype": "Currency", "label": "Additional Discount Amount", "options": "currency", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "section_break_49", - "fieldtype": "Section Break" + "fieldtype": "Section Break", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "base_grand_total", @@ -834,7 +1014,9 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "eval:!doc.disable_rounded_total", @@ -844,7 +1026,9 @@ "no_copy": 1, "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "eval:!doc.disable_rounded_total", @@ -854,7 +1038,9 @@ "no_copy": 1, "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "base_in_words", @@ -864,13 +1050,17 @@ "oldfieldname": "in_words", "oldfieldtype": "Data", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "column_break8", "fieldtype": "Column Break", "oldfieldtype": "Column Break", "print_hide": 1, + "show_days": 1, + "show_seconds": 1, "width": "50%" }, { @@ -881,7 +1071,9 @@ "oldfieldname": "grand_total_import", "oldfieldtype": "Currency", "options": "currency", - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "eval:!doc.disable_rounded_total", @@ -891,7 +1083,9 @@ "no_copy": 1, "options": "currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "eval:!doc.disable_rounded_total", @@ -901,7 +1095,9 @@ "no_copy": 1, "options": "currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "in_words", @@ -911,7 +1107,9 @@ "oldfieldname": "in_words_import", "oldfieldtype": "Data", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "total_advance", @@ -922,7 +1120,9 @@ "oldfieldtype": "Currency", "options": "party_account_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "outstanding_amount", @@ -933,14 +1133,18 @@ "oldfieldtype": "Currency", "options": "party_account_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "default": "0", "depends_on": "grand_total", "fieldname": "disable_rounded_total", "fieldtype": "Check", - "label": "Disable Rounded Total" + "label": "Disable Rounded Total", + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, @@ -948,20 +1152,26 @@ "depends_on": "eval:doc.is_paid===1||(doc.advances && doc.advances.length>0)", "fieldname": "payments_section", "fieldtype": "Section Break", - "label": "Payments" + "label": "Payments", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "mode_of_payment", "fieldtype": "Link", "label": "Mode of Payment", "options": "Mode of Payment", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "cash_bank_account", "fieldtype": "Link", "label": "Cash/Bank Account", - "options": "Account" + "options": "Account", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "clearance_date", @@ -969,11 +1179,15 @@ "label": "Clearance Date", "no_copy": 1, "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "col_br_payments", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "is_paid", @@ -982,7 +1196,9 @@ "label": "Paid Amount", "no_copy": 1, "options": "currency", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "base_paid_amount", @@ -991,7 +1207,9 @@ "no_copy": 1, "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, @@ -999,7 +1217,9 @@ "depends_on": "grand_total", "fieldname": "write_off", "fieldtype": "Section Break", - "label": "Write Off" + "label": "Write Off", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "write_off_amount", @@ -1007,7 +1227,9 @@ "label": "Write Off Amount", "no_copy": 1, "options": "currency", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "base_write_off_amount", @@ -1016,11 +1238,15 @@ "no_copy": 1, "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "column_break_61", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "eval:flt(doc.write_off_amount)!=0", @@ -1028,7 +1254,9 @@ "fieldtype": "Link", "label": "Write Off Account", "options": "Account", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "eval:flt(doc.write_off_amount)!=0", @@ -1036,7 +1264,9 @@ "fieldtype": "Link", "label": "Write Off Cost Center", "options": "Cost Center", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, @@ -1046,13 +1276,17 @@ "label": "Advance Payments", "oldfieldtype": "Section Break", "options": "fa fa-money", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "default": "0", "fieldname": "allocate_advances_automatically", "fieldtype": "Check", - "label": "Set Advances and Allocate (FIFO)" + "label": "Set Advances and Allocate (FIFO)", + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "eval:!doc.allocate_advances_automatically", @@ -1060,7 +1294,9 @@ "fieldtype": "Button", "label": "Get Advances Paid", "oldfieldtype": "Button", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "advances", @@ -1070,20 +1306,26 @@ "oldfieldname": "advance_allocation_details", "oldfieldtype": "Table", "options": "Purchase Invoice Advance", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, "collapsible_depends_on": "eval:(!doc.is_return)", "fieldname": "payment_schedule_section", "fieldtype": "Section Break", - "label": "Payment Terms" + "label": "Payment Terms", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "payment_terms_template", "fieldtype": "Link", "label": "Payment Terms Template", - "options": "Payment Terms Template" + "options": "Payment Terms Template", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "payment_schedule", @@ -1091,7 +1333,9 @@ "label": "Payment Schedule", "no_copy": 1, "options": "Payment Schedule", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, @@ -1099,25 +1343,33 @@ "fieldname": "terms_section_break", "fieldtype": "Section Break", "label": "Terms and Conditions", - "options": "fa fa-legal" + "options": "fa fa-legal", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "tc_name", "fieldtype": "Link", "label": "Terms", "options": "Terms and Conditions", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "terms", "fieldtype": "Text Editor", - "label": "Terms and Conditions1" + "label": "Terms and Conditions1", + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, "fieldname": "printing_settings", "fieldtype": "Section Break", - "label": "Printing Settings" + "label": "Printing Settings", + "show_days": 1, + "show_seconds": 1 }, { "allow_on_submit": 1, @@ -1125,7 +1377,9 @@ "fieldtype": "Link", "label": "Letter Head", "options": "Letter Head", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "allow_on_submit": 1, @@ -1133,11 +1387,15 @@ "fieldname": "group_same_items", "fieldtype": "Check", "label": "Group same items", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "column_break_112", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "allow_on_submit": 1, @@ -1149,14 +1407,18 @@ "oldfieldtype": "Link", "options": "Print Heading", "print_hide": 1, - "report_hide": 1 + "report_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "language", "fieldtype": "Data", "label": "Print Language", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, @@ -1165,7 +1427,9 @@ "label": "More Information", "oldfieldtype": "Section Break", "options": "fa fa-file-text", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "credit_to", @@ -1176,7 +1440,9 @@ "options": "Account", "print_hide": 1, "reqd": 1, - "search_index": 1 + "search_index": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "party_account_currency", @@ -1186,7 +1452,9 @@ "no_copy": 1, "options": "Currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "default": "No", @@ -1196,7 +1464,9 @@ "oldfieldname": "is_opening", "oldfieldtype": "Select", "options": "No\nYes", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "against_expense_account", @@ -1206,11 +1476,15 @@ "no_copy": 1, "oldfieldname": "against_expense_account", "oldfieldtype": "Small Text", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "column_break_63", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "default": "Draft", @@ -1219,7 +1493,9 @@ "in_standard_filter": 1, "label": "Status", "options": "\nDraft\nReturn\nDebit Note Issued\nSubmitted\nPaid\nUnpaid\nOverdue\nCancelled\nInternal Transfer", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "inter_company_invoice_reference", @@ -1228,7 +1504,9 @@ "no_copy": 1, "options": "Sales Invoice", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "remarks", @@ -1237,14 +1515,18 @@ "no_copy": 1, "oldfieldname": "remarks", "oldfieldtype": "Text", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, "fieldname": "subscription_section", "fieldtype": "Section Break", "label": "Subscription Section", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "allow_on_submit": 1, @@ -1253,7 +1535,9 @@ "fieldtype": "Date", "label": "From Date", "no_copy": 1, - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "allow_on_submit": 1, @@ -1262,11 +1546,15 @@ "fieldtype": "Date", "label": "To Date", "no_copy": 1, - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "column_break_114", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "auto_repeat", @@ -1275,24 +1563,32 @@ "no_copy": 1, "options": "Auto Repeat", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "allow_on_submit": 1, "depends_on": "eval: doc.auto_repeat", "fieldname": "update_auto_repeat_reference", "fieldtype": "Button", - "label": "Update Auto Repeat Reference" + "label": "Update Auto Repeat Reference", + "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": "0", @@ -1300,7 +1596,9 @@ "fieldname": "is_internal_supplier", "fieldtype": "Check", "label": "Is Internal Supplier", - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "tax_withholding_category", @@ -1308,19 +1606,25 @@ "hidden": 1, "label": "Tax Withholding Category", "options": "Tax Withholding Category", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "billing_address", "fieldtype": "Link", "label": "Select Billing Address", - "options": "Address" + "options": "Address", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "billing_address_display", "fieldtype": "Small Text", "label": "Billing Address", - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "project", @@ -1334,7 +1638,9 @@ "fieldname": "unrealized_profit_loss_account", "fieldtype": "Link", "label": "Unrealized Profit / Loss Account", - "options": "Account" + "options": "Account", + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "eval:doc.is_internal_supplier", @@ -1343,7 +1649,9 @@ "fieldname": "represents_company", "fieldtype": "Link", "label": "Represents Company", - "options": "Company" + "options": "Company", + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "eval:doc.update_stock && doc.is_internal_supplier", @@ -1355,6 +1663,8 @@ "options": "Warehouse", "print_hide": 1, "print_width": "50px", + "show_days": 1, + "show_seconds": 1, "width": "50px" }, { diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 83e9f7583e..0ee0bc7e11 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -68,9 +68,6 @@ class PurchaseInvoice(BuyingController): super(PurchaseInvoice, self).validate() - # apply tax withholding only if checked and applicable - self.set_tax_withholding() - if not self.is_return: self.po_required() self.pr_required() @@ -251,11 +248,9 @@ class PurchaseInvoice(BuyingController): if self.update_stock and (not item.from_warehouse): if for_validate and item.expense_account and item.expense_account != warehouse_account[item.warehouse]["account"]: - msg = _("Row {}: Expense Head changed to {} ").format(item.idx, frappe.bold(warehouse_account[item.warehouse]["account"])) - msg += _("because account {} is not linked to warehouse {} ").format(frappe.bold(item.expense_account), frappe.bold(item.warehouse)) - msg += _("or it is not the default inventory account") + msg = _("Row {0}: Expense Head changed to {1} because account {2} is not linked to warehouse {3} or it is not the default inventory account").format( + item.idx, frappe.bold(warehouse_account[item.warehouse]["account"]), frappe.bold(item.expense_account), frappe.bold(item.warehouse)) frappe.msgprint(msg, title=_("Expense Head Changed")) - item.expense_account = warehouse_account[item.warehouse]["account"] else: # check if 'Stock Received But Not Billed' account is credited in Purchase receipt or not @@ -266,8 +261,8 @@ class PurchaseInvoice(BuyingController): if negative_expense_booked_in_pr: if for_validate and item.expense_account and item.expense_account != stock_not_billed_account: - msg = _("Row {}: Expense Head changed to {} ").format(item.idx, frappe.bold(stock_not_billed_account)) - msg += _("because expense is booked against this account in Purchase Receipt {}").format(frappe.bold(item.purchase_receipt)) + msg = _("Row {0}: Expense Head changed to {1} because expense is booked against this account in Purchase Receipt {2}").format( + item.idx, frappe.bold(stock_not_billed_account), frappe.bold(item.purchase_receipt)) frappe.msgprint(msg, title=_("Expense Head Changed")) item.expense_account = stock_not_billed_account @@ -275,8 +270,9 @@ class PurchaseInvoice(BuyingController): # If no purchase receipt present then book expense in 'Stock Received But Not Billed' # This is done in cases when Purchase Invoice is created before Purchase Receipt if for_validate and item.expense_account and item.expense_account != stock_not_billed_account: - msg = _("Row {}: Expense Head changed to {} ").format(item.idx, frappe.bold(stock_not_billed_account)) - msg += _("as no Purchase Receipt is created against Item {}. ").format(frappe.bold(item.item_code)) + msg = _("Row {0}: Expense Head changed to {1} as no Purchase Receipt is created against Item {2}.").format( + item.idx, frappe.bold(stock_not_billed_account), frappe.bold(item.item_code)) + msg += "
" msg += _("This is done to handle accounting for cases when Purchase Receipt is created after Purchase Invoice") frappe.msgprint(msg, title=_("Expense Head Changed")) @@ -308,8 +304,8 @@ class PurchaseInvoice(BuyingController): if not d.purchase_order: msg = _("Purchase Order Required for item {}").format(frappe.bold(d.item_code)) msg += "

" - msg += _("To submit the invoice without purchase order please set {} ").format(frappe.bold(_('Purchase Order Required'))) - msg += _("as {} in {}").format(frappe.bold('No'), get_link_to_form('Buying Settings', 'Buying Settings', 'Buying Settings')) + msg += _("To submit the invoice without purchase order please set {0} as {1} in {2}").format( + frappe.bold(_('Purchase Order Required')), frappe.bold('No'), get_link_to_form('Buying Settings', 'Buying Settings', 'Buying Settings')) throw(msg, title=_("Mandatory Purchase Order")) def pr_required(self): @@ -323,8 +319,8 @@ class PurchaseInvoice(BuyingController): if not d.purchase_receipt and d.item_code in stock_items: msg = _("Purchase Receipt Required for item {}").format(frappe.bold(d.item_code)) msg += "

" - msg += _("To submit the invoice without purchase receipt please set {} ").format(frappe.bold(_('Purchase Receipt Required'))) - msg += _("as {} in {}").format(frappe.bold('No'), get_link_to_form('Buying Settings', 'Buying Settings', 'Buying Settings')) + msg += _("To submit the invoice without purchase receipt please set {0} as {1} in {2}").format( + frappe.bold(_('Purchase Receipt Required')), frappe.bold('No'), get_link_to_form('Buying Settings', 'Buying Settings', 'Buying Settings')) throw(msg, title=_("Mandatory Purchase Receipt")) def validate_write_off_account(self): @@ -456,6 +452,8 @@ class PurchaseInvoice(BuyingController): self.make_tax_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) @@ -1090,6 +1088,7 @@ class PurchaseInvoice(BuyingController): 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: diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 53db689c84..723d151ad8 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -16,6 +16,7 @@ from erpnext.stock.doctype.stock_entry.test_stock_entry import get_qty_after_tra from erpnext.projects.doctype.project.test_project import make_project from erpnext.accounts.doctype.account.test_account import get_inventory_account, create_account from erpnext.stock.doctype.item.test_item import create_item +from erpnext.buying.doctype.supplier.test_supplier import create_supplier test_dependencies = ["Item", "Cost Center", "Payment Term", "Payment Terms Template"] test_ignore = ["Serial No"] @@ -950,6 +951,102 @@ class TestPurchaseInvoice(unittest.TestCase): acc_settings.submit_journal_entriessubmit_journal_entries = 0 acc_settings.save() + def test_purchase_invoice_advance_taxes(self): + from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order + from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry + from erpnext.buying.doctype.purchase_order.purchase_order import get_mapped_purchase_invoice + + # create a new supplier to test + supplier = create_supplier(supplier_name = '_Test TDS Advance Supplier', + tax_withholding_category = 'TDS - 194 - Dividends - Individual') + + # Update tax withholding category with current fiscal year and rate details + update_tax_witholding_category('_Test Company', 'TDS Payable - _TC', nowdate()) + + # Create Purchase Order with TDS applied + po = create_purchase_order(do_not_save=1, supplier=supplier.name, rate=3000) + 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.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], + ['TDS Payable - _TC', 0, 3000], + ] + + gl_entries = frappe.db.sql("""select account, debit, credit + from `tabGL Entry` + where voucher_type='Payment Entry' and voucher_no=%s + order by account asc""", (payment_entry.name), as_dict=1) + + for i, gle in enumerate(gl_entries): + self.assertEqual(expected_gle[i][0], gle.account) + self.assertEqual(expected_gle[i][1], gle.debit) + self.assertEqual(expected_gle[i][2], gle.credit) + + # Create Purchase Invoice against Purchase Order + purchase_invoice = get_mapped_purchase_invoice(po.name) + purchase_invoice.allocate_advances_automatically = 1 + purchase_invoice.items[0].expense_account = '_Test Account Cost for Goods Sold - _TC' + purchase_invoice.save() + purchase_invoice.submit() + + # Check GLE for Purchase Invoice + # Zero net effect on final TDS Payable on invoice + expected_gle = [ + ['_Test Account Cost for Goods Sold - _TC', 30000, 0], + ['_Test Account Excise Duty - _TC', 0, 3000], + ['Creditors - _TC', 0, 27000], + ['TDS Payable - _TC', 3000, 3000] + ] + + gl_entries = frappe.db.sql("""select account, debit, credit + from `tabGL Entry` + where voucher_type='Purchase Invoice' and voucher_no=%s + order by account asc""", (purchase_invoice.name), as_dict=1) + + for i, gle in enumerate(gl_entries): + self.assertEqual(expected_gle[i][0], gle.account) + self.assertEqual(expected_gle[i][1], gle.debit) + self.assertEqual(expected_gle[i][2], gle.credit) + +def update_tax_witholding_category(company, account, date): + from erpnext.accounts.utils import get_fiscal_year + + fiscal_year = get_fiscal_year(date=date, company=company) + + if not frappe.db.get_value('Tax Withholding Rate', + {'parent': 'TDS - 194 - Dividends - Individual', 'fiscal_year': fiscal_year[0]}): + tds_category = frappe.get_doc('Tax Withholding Category', 'TDS - 194 - Dividends - Individual') + tds_category.append('rates', { + 'fiscal_year': fiscal_year[0], + 'tax_withholding_rate': 10, + 'single_threshold': 2500, + 'cumulative_threshold': 0 + }) + tds_category.save() + + if not frappe.db.get_value('Tax Withholding Account', + {'parent': 'TDS - 194 - Dividends - Individual', 'account': account}): + tds_category = frappe.get_doc('Tax Withholding Category', 'TDS - 194 - Dividends - Individual') + tds_category.append('accounts', { + 'company': company, + 'account': account + }) + tds_category.save() def unlink_payment_on_cancel_of_invoice(enable=1): accounts_settings = frappe.get_doc("Accounts Settings") diff --git a/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json b/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json index f9fdc4b605..9b07645ccc 100644 --- a/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json +++ b/erpnext/accounts/doctype/purchase_taxes_and_charges/purchase_taxes_and_charges.json @@ -12,6 +12,7 @@ "charge_type", "row_id", "included_in_print_rate", + "included_in_paid_amount", "col_break1", "account_head", "description", @@ -21,6 +22,7 @@ "cost_center", "dimension_col_break", "section_break_9", + "currency", "tax_amount", "tax_amount_after_discount_amount", "total", @@ -205,12 +207,27 @@ { "fieldname": "dimension_col_break", "fieldtype": "Column Break" + }, + { + "fetch_from": "account_head.account_currency", + "fieldname": "currency", + "fieldtype": "Link", + "label": "Account Currency", + "options": "Currency", + "read_only": 1 + }, + { + "default": "0", + "description": "If checked, the tax amount will be considered as already included in the Paid Amount in Payment Entry", + "fieldname": "included_in_paid_amount", + "fieldtype": "Check", + "label": "Considered In Paid Amount" } ], "idx": 1, "istable": 1, "links": [], - "modified": "2020-09-18 17:26:09.703215", + "modified": "2021-06-09 11:48:25.335733", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Taxes and Charges", diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 0b8d28aef0..e14f305fc5 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -842,6 +842,8 @@ class SalesInvoice(SellingController): self.make_tax_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) # merge gl entries before adding pos entries diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json b/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json index 3c8cb6b851..170d34e651 100644 --- a/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json +++ b/erpnext/accounts/doctype/sales_taxes_and_charges/sales_taxes_and_charges.json @@ -1,8 +1,10 @@ { + "actions": [], "creation": "2013-04-24 11:39:32", "doctype": "DocType", "document_type": "Setup", "editable_grid": 1, + "engine": "InnoDB", "field_order": [ "charge_type", "row_id", @@ -10,12 +12,14 @@ "col_break_1", "description", "included_in_print_rate", + "included_in_paid_amount", "accounting_dimensions_section", "cost_center", "dimension_col_break", "section_break_8", "rate", "section_break_9", + "currency", "tax_amount", "total", "tax_amount_after_discount_amount", @@ -23,8 +27,7 @@ "base_tax_amount", "base_total", "base_tax_amount_after_discount_amount", - "item_wise_tax_detail", - "parenttype" + "item_wise_tax_detail" ], "fields": [ { @@ -173,17 +176,6 @@ "oldfieldtype": "Small Text", "read_only": 1 }, - { - "fieldname": "parenttype", - "fieldtype": "Data", - "hidden": 1, - "in_filter": 1, - "label": "Parenttype", - "oldfieldname": "parenttype", - "oldfieldtype": "Data", - "print_hide": 1, - "search_index": 1 - }, { "fieldname": "accounting_dimensions_section", "fieldtype": "Section Break", @@ -192,15 +184,33 @@ { "fieldname": "dimension_col_break", "fieldtype": "Column Break" + }, + { + "fetch_from": "account_head.account_currency", + "fieldname": "currency", + "fieldtype": "Link", + "label": "Account Currency", + "options": "Currency", + "read_only": 1 + }, + { + "default": "0", + "description": "If checked, the tax amount will be considered as already included in the Paid Amount in Payment Entry", + "fieldname": "included_in_paid_amount", + "fieldtype": "Check", + "label": "Considered In Paid Amount" } ], "idx": 1, + "index_web_pages_for_search": 1, "istable": 1, - "modified": "2019-05-25 22:59:38.740883", + "links": [], + "modified": "2021-06-09 11:48:04.691596", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Taxes and Charges", "owner": "Administrator", "permissions": [], + "sort_field": "modified", "sort_order": "ASC" } \ No newline at end of file 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 5c1cbaa4aa..b9ee4a0963 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py @@ -49,7 +49,7 @@ def get_party_tax_withholding_details(inv, tax_withholding_category=None): if not parties: parties.append(party) - fiscal_year = get_fiscal_year(inv.posting_date, company=inv.company) + fiscal_year = get_fiscal_year(inv.get('posting_date') or inv.get('transaction_date'), company=inv.company) tax_details = get_tax_withholding_details(tax_withholding_category, fiscal_year[0], inv.company) if not tax_details: @@ -154,7 +154,7 @@ def get_tax_amount(party_type, parties, inv, tax_details, fiscal_year_details, p tax_deducted = get_deducted_tax(taxable_vouchers, fiscal_year, tax_details) tax_amount = 0 - posting_date = inv.posting_date + posting_date = inv.get('posting_date') or inv.get('transaction_date') if party_type == 'Supplier': ldc = get_lower_deduction_certificate(fiscal_year, pan_no) if tax_deducted: @@ -257,7 +257,7 @@ def get_tds_amount(ldc, parties, inv, tax_details, fiscal_year_details, tax_dedu if ((threshold and inv.net_total >= threshold) or (cumulative_threshold and supp_credit_amt >= cumulative_threshold)): if ldc and is_valid_certificate( ldc.valid_from, ldc.valid_upto, - inv.posting_date, tax_deducted, + inv.get('posting_date') or inv.get('transaction_date'), tax_deducted, inv.net_total, ldc.certificate_limit ): tds_amount = get_ltds_amount(supp_credit_amt, 0, ldc.certificate_limit, ldc.rate, tax_details) diff --git a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.js b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.js index 344539eef6..72de318a48 100644 --- a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.js +++ b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.js @@ -54,6 +54,32 @@ frappe.query_reports["TDS Payable Monthly"] = { frappe.query_report.refresh(); } }, + { + "fieldname":"purchase_order", + "label": __("Purchase Order"), + "fieldtype": "Link", + "options": "Purchase Order", + "get_query": function() { + return { + "filters": { + "name": ["in", frappe.query_report.invoices] + } + } + }, + on_change: function() { + let supplier = frappe.query_report.get_filter_value('supplier'); + if(!supplier) return; // return if no supplier selected + + // filter invoices based on selected supplier + let invoices = []; + frappe.query_report.invoice_data.map(d => { + if(d.supplier==supplier) + invoices.push(d.name) + }); + frappe.query_report.invoices = invoices; + frappe.query_report.refresh(); + } + }, { "fieldname":"from_date", "label": __("From Date"), @@ -75,15 +101,17 @@ frappe.query_reports["TDS Payable Monthly"] = { onload: function(report) { // fetch all tds applied invoices frappe.call({ - "method": "erpnext.accounts.report.tds_payable_monthly.tds_payable_monthly.get_tds_invoices", + "method": "erpnext.accounts.report.tds_payable_monthly.tds_payable_monthly.get_tds_invoices_and_orders", callback: function(r) { let invoices = []; + r.message.map(d => { invoices.push(d.name); }); - report["invoice_data"] = r.message; + report["invoice_data"] = r.message.invoices; report["invoices"] = invoices; + } }); } diff --git a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py index a9fb237a04..ceefa31cfa 100644 --- a/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py +++ b/erpnext/accounts/report/tds_payable_monthly/tds_payable_monthly.py @@ -11,11 +11,14 @@ def execute(filters=None): validate_filters(filters) set_filters(filters) + # TDS payment entries + payment_entries = get_payment_entires(filters) + columns = get_columns(filters) - if not filters["invoices"]: + if not filters.get("invoices"): return columns, [] - res = get_result(filters) + res = get_result(filters, payment_entries) return columns, res @@ -27,8 +30,9 @@ def validate_filters(filters): def set_filters(filters): invoices = [] - if not filters["invoices"]: - filters["invoices"] = get_tds_invoices() + if not filters.get("invoices"): + filters["invoices"] = get_tds_invoices_and_orders() + if filters.supplier and filters.purchase_invoice: for d in filters["invoices"]: if d.name == filters.purchase_invoice and d.supplier == filters.supplier: @@ -41,13 +45,29 @@ def set_filters(filters): for d in filters["invoices"]: if d.name == filters.purchase_invoice: invoices.append(d) + elif filters.supplier and filters.purchase_order: + for d in filters.get("invoices"): + if d.name == filters.purchase_order and d.supplier == filters.supplier: + invoices.append(d) + elif filters.supplier and not filters.purchase_order: + for d in filters.get("invoices"): + if d.supplier == filters.supplier: + invoices.append(d) + elif filters.purchase_order and not filters.supplier: + for d in filters.get("invoices"): + if d.name == filters.purchase_order: + invoices.append(d) filters["invoices"] = invoices if invoices else filters["invoices"] filters.naming_series = frappe.db.get_single_value('Buying Settings', 'supp_master_name') -def get_result(filters): - supplier_map, tds_docs = get_supplier_map(filters) - gle_map = get_gle_map(filters) + #print(filters.get('invoices')) + +def get_result(filters, payment_entries): + supplier_map, tds_docs = get_supplier_map(filters, payment_entries) + documents = [d.get('name') for d in filters.get('invoices')] + [d.get('name') for d in payment_entries] + + gle_map = get_gle_map(filters, documents) out = [] for d in gle_map: @@ -62,10 +82,11 @@ def get_result(filters): for k in gle_map[d]: if k.party == supplier_map[d] and k.credit > 0: - total_amount_credited += k.credit - elif account_list and k.account == account and k.credit > 0: - tds_deducted = k.credit - total_amount_credited += k.credit + total_amount_credited += (k.credit - k.debit) + elif account_list and k.account == account and (k.credit - k.debit) > 0: + tds_deducted = (k.credit - k.debit) + total_amount_credited += (k.credit - k.debit) + voucher_type = k.voucher_type rate = [i.tax_withholding_rate for i in tds_doc.rates if i.fiscal_year == gle_map[d][0].fiscal_year] @@ -73,32 +94,36 @@ def get_result(filters): if rate and len(rate) > 0 and tds_deducted: rate = rate[0] - if getdate(filters.from_date) <= gle_map[d][0].posting_date \ - and getdate(filters.to_date) >= gle_map[d][0].posting_date: - row = [supplier.pan, supplier.name] + row = [supplier.pan, supplier.name] - if filters.naming_series == 'Naming Series': - row.append(supplier.supplier_name) + if filters.naming_series == 'Naming Series': + row.append(supplier.supplier_name) - row.extend([tds_doc.name, supplier.supplier_type, rate, total_amount_credited, - tds_deducted, gle_map[d][0].posting_date, "Purchase Invoice", d]) - out.append(row) + row.extend([tds_doc.name, supplier.supplier_type, rate, total_amount_credited, + tds_deducted, gle_map[d][0].posting_date, voucher_type, d]) + out.append(row) return out -def get_supplier_map(filters): +def get_supplier_map(filters, payment_entries): # create a supplier_map of the form {"purchase_invoice": {supplier_name, pan, tds_name}} # pre-fetch all distinct applicable tds docs supplier_map, tds_docs = {}, {} pan = "pan" if frappe.db.has_column("Supplier", "pan") else "tax_id" + supplier_list = [d.supplier for d in filters["invoices"]] + supplier_detail = frappe.db.get_all('Supplier', - {"name": ["in", [d.supplier for d in filters["invoices"]]]}, + {"name": ["in", supplier_list]}, ["tax_withholding_category", "name", pan+" as pan", "supplier_type", "supplier_name"]) for d in filters["invoices"]: supplier_map[d.get("name")] = [k for k in supplier_detail if k.name == d.get("supplier")][0] + for d in payment_entries: + supplier_map[d.get("name")] = [k for k in supplier_detail + if k.name == d.get("supplier")][0] + for d in supplier_detail: if d.get("tax_withholding_category") not in tds_docs: tds_docs[d.get("tax_withholding_category")] = \ @@ -106,13 +131,19 @@ def get_supplier_map(filters): return supplier_map, tds_docs -def get_gle_map(filters): +def get_gle_map(filters, documents): # create gle_map of the form # {"purchase_invoice": list of dict of all gle created for this invoice} gle_map = {} - gle = frappe.db.get_all('GL Entry',\ - {"voucher_no": ["in", [d.get("name") for d in filters["invoices"]]], 'is_cancelled': 0}, - ["fiscal_year", "credit", "debit", "account", "voucher_no", "posting_date"]) + + gle = frappe.db.get_all('GL Entry', + { + "voucher_no": ["in", documents], + 'is_cancelled': 0, + 'posting_date': ("between", [filters.get('from_date'), filters.get('to_date')]), + }, + ["fiscal_year", "credit", "debit", "account", "voucher_no", "posting_date", "voucher_type"], + ) for d in gle: if not d.voucher_no in gle_map: @@ -201,8 +232,26 @@ def get_columns(filters): return columns +def get_payment_entires(filters): + filter_dict = { + 'posting_date': ("between", [filters.get('from_date'), filters.get('to_date')]), + 'party_type': 'Supplier', + 'apply_tax_withholding_amount': 1 + } + + if filters.get('purchase_invoice') or filters.get('purchase_order'): + parent = frappe.db.get_all('Payment Entry Reference', + {'reference_name': ('in', [d.get('name') for d in filters.get('invoices')])}, ['parent']) + + filter_dict.update({'name': ('in', [d.get('parent') for d in parent])}) + + payment_entries = frappe.get_all('Payment Entry', fields=['name', 'party_name as supplier'], + filters=filter_dict) + + return payment_entries + @frappe.whitelist() -def get_tds_invoices(): +def get_tds_invoices_and_orders(): # fetch tds applicable supplier and fetch invoices for these suppliers suppliers = [d.name for d in frappe.db.get_list("Supplier", {"tax_withholding_category": ["!=", ""]}, ["name"])] @@ -210,7 +259,12 @@ def get_tds_invoices(): invoices = frappe.db.get_list("Purchase Invoice", {"supplier": ["in", suppliers]}, ["name", "supplier"]) + orders = frappe.db.get_list("Purchase Order", + {"supplier": ["in", suppliers]}, ["name", "supplier"]) + + invoices = invoices + orders invoices = [d for d in invoices if d.supplier] + frappe.cache().hset("invoices", frappe.session.user, invoices) return invoices diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index dd0f065848..0f6d927b36 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -45,6 +45,14 @@ frappe.ui.form.on("Purchase Order", { }); erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype); + }, + + apply_tds: function(frm) { + if (!frm.doc.apply_tds) { + frm.set_value("tax_withholding_category", ''); + } else { + frm.set_value("tax_withholding_category", frm.supplier_tds); + } } }); @@ -313,7 +321,8 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( if(me.values) { me.values.sub_con_rm_items.map((row,i) => { if (!row.item_code || !row.rm_item_code || !row.warehouse || !row.qty || row.qty === 0) { - frappe.throw(__("Item Code, warehouse, quantity are required on row {0}", [i+1])); + let row_id = i+1; + frappe.throw(__("Item Code, warehouse and quantity are required on row {0}", [row_id])); } }) me._make_rm_stock_entry(me.dialog.fields_dict.sub_con_rm_items.grid.get_selected_children()) @@ -509,7 +518,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( args: { reference_doctype: me.frm.doctype, reference_name: me.frm.docname, - content: __('Reason for hold: ')+data.reason_for_hold, + content: __('Reason for hold:') + " " +data.reason_for_hold, comment_email: frappe.session.user, comment_by: frappe.session.user_fullname }, diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json index 8677c71bc5..41668c6291 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.json +++ b/erpnext/buying/doctype/purchase_order/purchase_order.json @@ -14,6 +14,8 @@ "supplier", "get_items_from_open_material_requests", "supplier_name", + "apply_tds", + "tax_withholding_category", "column_break1", "company", "transaction_date", @@ -142,7 +144,9 @@ { "fieldname": "supplier_section", "fieldtype": "Section Break", - "options": "fa fa-user" + "options": "fa fa-user", + "show_days": 1, + "show_seconds": 1 }, { "allow_on_submit": 1, @@ -152,7 +156,9 @@ "hidden": 1, "label": "Title", "no_copy": 1, - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "naming_series", @@ -164,7 +170,9 @@ "options": "PUR-ORD-.YYYY.-", "print_hide": 1, "reqd": 1, - "set_only_once": 1 + "set_only_once": 1, + "show_days": 1, + "show_seconds": 1 }, { "bold": 1, @@ -178,14 +186,18 @@ "options": "Supplier", "print_hide": 1, "reqd": 1, - "search_index": 1 + "search_index": 1, + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "eval:doc.supplier && doc.docstatus===0 && (!(doc.items && doc.items.length) || (doc.items.length==1 && !doc.items[0].item_code))", "description": "Fetch items based on Default Supplier.", "fieldname": "get_items_from_open_material_requests", "fieldtype": "Button", - "label": "Get Items from Open Material Requests" + "label": "Get Items from Open Material Requests", + "show_days": 1, + "show_seconds": 1 }, { "bold": 1, @@ -194,7 +206,9 @@ "fieldtype": "Data", "in_global_search": 1, "label": "Supplier Name", - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "company", @@ -206,13 +220,17 @@ "options": "Company", "print_hide": 1, "remember_last_selected_value": 1, - "reqd": 1 + "reqd": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "column_break1", "fieldtype": "Column Break", "oldfieldtype": "Column Break", "print_width": "50%", + "show_days": 1, + "show_seconds": 1, "width": "50%" }, { @@ -224,27 +242,35 @@ "oldfieldname": "transaction_date", "oldfieldtype": "Date", "reqd": 1, - "search_index": 1 + "search_index": 1, + "show_days": 1, + "show_seconds": 1 }, { "allow_on_submit": 1, "fieldname": "schedule_date", "fieldtype": "Date", - "label": "Required By" + "label": "Required By", + "show_days": 1, + "show_seconds": 1 }, { "allow_on_submit": 1, "depends_on": "eval:doc.docstatus===1", "fieldname": "order_confirmation_no", "fieldtype": "Data", - "label": "Order Confirmation No" + "label": "Order Confirmation No", + "show_days": 1, + "show_seconds": 1 }, { "allow_on_submit": 1, "depends_on": "eval:doc.order_confirmation_no", "fieldname": "order_confirmation_date", "fieldtype": "Date", - "label": "Order Confirmation Date" + "label": "Order Confirmation Date", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "amended_from", @@ -256,19 +282,25 @@ "oldfieldtype": "Data", "options": "Purchase Order", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "drop_ship", "fieldtype": "Section Break", - "label": "Drop Ship" + "label": "Drop Ship", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "customer", "fieldtype": "Link", "label": "Customer", "options": "Customer", - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "bold": 1, @@ -276,31 +308,41 @@ "fieldtype": "Data", "label": "Customer Name", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "column_break_19", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "customer_contact_person", "fieldtype": "Link", "label": "Customer Contact", - "options": "Contact" + "options": "Contact", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "customer_contact_display", "fieldtype": "Small Text", "hidden": 1, "label": "Customer Contact", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "customer_contact_mobile", "fieldtype": "Small Text", "hidden": 1, "label": "Customer Mobile No", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "customer_contact_email", @@ -308,27 +350,35 @@ "hidden": 1, "label": "Customer Contact Email", "options": "Email", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, "fieldname": "section_addresses", "fieldtype": "Section Break", - "label": "Address and Contact" + "label": "Address and Contact", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "supplier_address", "fieldtype": "Link", "label": "Supplier Address", "options": "Address", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "contact_person", "fieldtype": "Link", "label": "Supplier Contact", "options": "Contact", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "address_display", @@ -355,32 +405,42 @@ "label": "Contact Email", "options": "Email", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "col_break_address", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "shipping_address", "fieldtype": "Link", "label": "Company Shipping Address", "options": "Address", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "shipping_address_display", "fieldtype": "Small Text", "label": "Shipping Address Details", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, "fieldname": "currency_and_price_list", "fieldtype": "Section Break", "label": "Currency and Price List", - "options": "fa fa-tag" + "options": "fa fa-tag", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "currency", @@ -390,7 +450,9 @@ "oldfieldtype": "Select", "options": "Currency", "print_hide": 1, - "reqd": 1 + "reqd": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "conversion_rate", @@ -400,18 +462,24 @@ "oldfieldtype": "Currency", "precision": "9", "print_hide": 1, - "reqd": 1 + "reqd": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "cb_price_list", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "buying_price_list", "fieldtype": "Link", "label": "Price List", "options": "Price List", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "price_list_currency", @@ -419,14 +487,18 @@ "label": "Price List Currency", "options": "Currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "plc_conversion_rate", "fieldtype": "Float", "label": "Price List Exchange Rate", "precision": "9", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "default": "0", @@ -435,7 +507,9 @@ "label": "Ignore Pricing Rule", "no_copy": 1, "permlevel": 1, - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "sec_warehouse", @@ -448,11 +522,15 @@ "fieldtype": "Link", "label": "Set Target Warehouse", "options": "Warehouse", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "col_break_warehouse", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "default": "No", @@ -461,26 +539,34 @@ "in_standard_filter": 1, "label": "Supply Raw Materials", "options": "No\nYes", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "eval:doc.is_subcontracted==\"Yes\"", "fieldname": "supplier_warehouse", "fieldtype": "Link", "label": "Supplier Warehouse", - "options": "Warehouse" + "options": "Warehouse", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "items_section", "fieldtype": "Section Break", "hide_border": 1, "oldfieldtype": "Section Break", - "options": "fa fa-shopping-cart" + "options": "fa fa-shopping-cart", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "scan_barcode", "fieldtype": "Data", - "label": "Scan Barcode" + "label": "Scan Barcode", + "show_days": 1, + "show_seconds": 1 }, { "allow_bulk_edit": 1, @@ -490,26 +576,34 @@ "oldfieldname": "po_details", "oldfieldtype": "Table", "options": "Purchase Order Item", - "reqd": 1 + "reqd": 1, + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, "fieldname": "section_break_48", "fieldtype": "Section Break", - "label": "Pricing Rules" + "label": "Pricing Rules", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "pricing_rules", "fieldtype": "Table", "label": "Purchase Order Pricing Rule", "options": "Pricing Rule Detail", - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "collapsible_depends_on": "supplied_items", "fieldname": "raw_material_details", "fieldtype": "Section Break", - "label": "Raw Materials Supplied" + "label": "Raw Materials Supplied", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "supplied_items", @@ -519,17 +613,23 @@ "oldfieldtype": "Table", "options": "Purchase Order Item Supplied", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "sb_last_purchase", - "fieldtype": "Section Break" + "fieldtype": "Section Break", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "total_qty", "fieldtype": "Float", "label": "Total Quantity", - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "base_total", @@ -537,7 +637,9 @@ "label": "Total (Company Currency)", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "base_net_total", @@ -548,18 +650,24 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "column_break_26", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "total", "fieldtype": "Currency", "label": "Total", "options": "currency", - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "net_total", @@ -569,20 +677,26 @@ "oldfieldtype": "Currency", "options": "currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "total_net_weight", "fieldtype": "Float", "label": "Total Net Weight", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "taxes_section", "fieldtype": "Section Break", "oldfieldtype": "Section Break", - "options": "fa fa-money" + "options": "fa fa-money", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "taxes_and_charges", @@ -591,18 +705,24 @@ "oldfieldname": "purchase_other_charges", "oldfieldtype": "Link", "options": "Purchase Taxes and Charges Template", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "column_break_50", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "shipping_rule", "fieldtype": "Link", "label": "Shipping Rule", "options": "Shipping Rule", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "section_break_52", @@ -615,13 +735,17 @@ "label": "Purchase Taxes and Charges", "oldfieldname": "purchase_tax_details", "oldfieldtype": "Table", - "options": "Purchase Taxes and Charges" + "options": "Purchase Taxes and Charges", + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, "fieldname": "sec_tax_breakup", "fieldtype": "Section Break", - "label": "Tax Breakup" + "label": "Tax Breakup", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "other_charges_calculation", @@ -630,14 +754,18 @@ "no_copy": 1, "oldfieldtype": "HTML", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "totals", "fieldtype": "Section Break", "label": "Taxes and Charges", "oldfieldtype": "Section Break", - "options": "fa fa-money" + "options": "fa fa-money", + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "base_taxes_and_charges_added", @@ -648,7 +776,9 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "base_taxes_and_charges_deducted", @@ -659,7 +789,9 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "base_total_taxes_and_charges", @@ -671,11 +803,15 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "column_break_39", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "taxes_and_charges_added", @@ -686,7 +822,9 @@ "oldfieldtype": "Currency", "options": "currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "taxes_and_charges_deducted", @@ -697,7 +835,9 @@ "oldfieldtype": "Currency", "options": "currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "total_taxes_and_charges", @@ -706,14 +846,18 @@ "label": "Total Taxes and Charges", "options": "currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, "collapsible_depends_on": "apply_discount_on", "fieldname": "discount_section", "fieldtype": "Section Break", - "label": "Additional Discount" + "label": "Additional Discount", + "show_days": 1, + "show_seconds": 1 }, { "default": "Grand Total", @@ -721,7 +865,9 @@ "fieldtype": "Select", "label": "Apply Additional Discount On", "options": "\nGrand Total\nNet Total", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "base_discount_amount", @@ -729,24 +875,32 @@ "label": "Additional Discount Amount (Company Currency)", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "column_break_45", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "additional_discount_percentage", "fieldtype": "Float", "label": "Additional Discount Percentage", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "discount_amount", "fieldtype": "Currency", "label": "Additional Discount Amount", "options": "currency", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "totals_section", @@ -762,7 +916,9 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "eval:!doc.disable_rounded_total", @@ -772,7 +928,9 @@ "no_copy": 1, "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "description": "In Words will be visible once you save the Purchase Order.", @@ -783,7 +941,9 @@ "oldfieldname": "in_words", "oldfieldtype": "Data", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "base_rounded_total", @@ -793,12 +953,16 @@ "oldfieldtype": "Currency", "options": "Company:company:default_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "column_break4", "fieldtype": "Column Break", - "oldfieldtype": "Column Break" + "oldfieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "grand_total", @@ -808,7 +972,9 @@ "oldfieldname": "grand_total_import", "oldfieldtype": "Currency", "options": "currency", - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "eval:!doc.disable_rounded_total", @@ -818,20 +984,26 @@ "no_copy": 1, "options": "currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "rounded_total", "fieldtype": "Currency", "label": "Rounded Total", "options": "currency", - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "default": "0", "fieldname": "disable_rounded_total", "fieldtype": "Check", - "label": "Disable Rounded Total" + "label": "Disable Rounded Total", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "in_words", @@ -841,7 +1013,9 @@ "oldfieldname": "in_words_import", "oldfieldtype": "Data", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "advance_paid", @@ -850,19 +1024,25 @@ "no_copy": 1, "options": "party_account_currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, "fieldname": "payment_schedule_section", "fieldtype": "Section Break", - "label": "Payment Terms" + "label": "Payment Terms", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "payment_terms_template", "fieldtype": "Link", "label": "Payment Terms Template", - "options": "Payment Terms Template" + "options": "Payment Terms Template", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "payment_schedule", @@ -870,7 +1050,9 @@ "label": "Payment Schedule", "no_copy": 1, "options": "Payment Schedule", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, @@ -879,7 +1061,9 @@ "fieldtype": "Section Break", "label": "Terms and Conditions", "oldfieldtype": "Section Break", - "options": "fa fa-legal" + "options": "fa fa-legal", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "tc_name", @@ -888,21 +1072,27 @@ "oldfieldname": "tc_name", "oldfieldtype": "Link", "options": "Terms and Conditions", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "terms", "fieldtype": "Text Editor", "label": "Terms and Conditions", "oldfieldname": "terms", - "oldfieldtype": "Text Editor" + "oldfieldtype": "Text Editor", + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, "fieldname": "more_info", "fieldtype": "Section Break", "label": "More Information", - "oldfieldtype": "Section Break" + "oldfieldtype": "Section Break", + "show_days": 1, + "show_seconds": 1 }, { "default": "Draft", @@ -917,7 +1107,9 @@ "print_hide": 1, "read_only": 1, "reqd": 1, - "search_index": 1 + "search_index": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "ref_sq", @@ -928,7 +1120,9 @@ "oldfieldtype": "Data", "options": "Supplier Quotation", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "party_account_currency", @@ -938,18 +1132,24 @@ "no_copy": 1, "options": "Currency", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "inter_company_order_reference", "fieldtype": "Link", "label": "Inter Company Order Reference", "options": "Sales Order", - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "column_break_74", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "eval:!doc.__islocal", @@ -959,7 +1159,9 @@ "label": "% Received", "no_copy": 1, "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "eval:!doc.__islocal", @@ -969,7 +1171,9 @@ "label": "% Billed", "no_copy": 1, "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, @@ -979,6 +1183,8 @@ "oldfieldtype": "Column Break", "print_hide": 1, "print_width": "50%", + "show_days": 1, + "show_seconds": 1, "width": "50%" }, { @@ -989,7 +1195,9 @@ "oldfieldname": "letter_head", "oldfieldtype": "Select", "options": "Letter Head", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "allow_on_submit": 1, @@ -1001,11 +1209,15 @@ "oldfieldtype": "Link", "options": "Print Heading", "print_hide": 1, - "report_hide": 1 + "report_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "column_break_86", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "allow_on_submit": 1, @@ -1013,19 +1225,25 @@ "fieldname": "group_same_items", "fieldtype": "Check", "label": "Group same items", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "language", "fieldtype": "Data", "label": "Print Language", - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, "fieldname": "subscription_section", "fieldtype": "Section Break", - "label": "Subscription Section" + "label": "Subscription Section", + "show_days": 1, + "show_seconds": 1 }, { "allow_on_submit": 1, @@ -1033,7 +1251,9 @@ "fieldtype": "Date", "label": "From Date", "no_copy": 1, - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "allow_on_submit": 1, @@ -1041,11 +1261,15 @@ "fieldtype": "Date", "label": "To Date", "no_copy": 1, - "print_hide": 1 + "print_hide": 1, + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "column_break_97", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "auto_repeat", @@ -1054,27 +1278,35 @@ "no_copy": 1, "options": "Auto Repeat", "print_hide": 1, - "read_only": 1 + "read_only": 1, + "show_days": 1, + "show_seconds": 1 }, { "allow_on_submit": 1, "depends_on": "eval: doc.auto_repeat", "fieldname": "update_auto_repeat_reference", "fieldtype": "Button", - "label": "Update Auto Repeat Reference" + "label": "Update Auto Repeat Reference", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "tax_category", "fieldtype": "Link", "label": "Tax Category", - "options": "Tax Category" + "options": "Tax Category", + "show_days": 1, + "show_seconds": 1 }, { "depends_on": "supplied_items", "fieldname": "set_reserve_warehouse", "fieldtype": "Link", "label": "Set Reserve Warehouse", - "options": "Warehouse" + "options": "Warehouse", + "show_days": 1, + "show_seconds": 1 }, { "collapsible": 1, @@ -1084,7 +1316,9 @@ }, { "fieldname": "column_break_75", - "fieldtype": "Column Break" + "fieldtype": "Column Break", + "show_days": 1, + "show_seconds": 1 }, { "fieldname": "billing_address", @@ -1120,6 +1354,23 @@ "label": "Represents Company", "options": "Company", "read_only": 1 + }, + { + "default": "0", + "fieldname": "apply_tds", + "fieldtype": "Check", + "label": "Apply Tax Withholding Amount", + "show_days": 1, + "show_seconds": 1 + }, + { + "depends_on": "eval: doc.apply_tds", + "fieldname": "tax_withholding_category", + "fieldtype": "Link", + "label": "Tax Withholding Category", + "options": "Tax Withholding Category", + "show_days": 1, + "show_seconds": 1 } ], "icon": "fa fa-file-text", diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.py b/erpnext/buying/doctype/purchase_order/purchase_order.py index ef9372eeb6..782593a5c5 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/purchase_order.py @@ -17,6 +17,7 @@ from erpnext.accounts.party import get_party_account_currency from six import string_types from erpnext.stock.doctype.item.item import get_item_defaults from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults +from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import get_party_tax_withholding_details from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_doc,\ unlink_inter_company_doc @@ -39,11 +40,18 @@ class PurchaseOrder(BuyingController): 'percent_join_field': 'material_request' }] + def onload(self): + supplier_tds = frappe.db.get_value("Supplier", self.supplier, "tax_withholding_category") + self.set_onload("supplier_tds", supplier_tds) + def validate(self): super(PurchaseOrder, self).validate() self.set_status() + # apply tax withholding only if checked and applicable + self.set_tax_withholding() + self.validate_supplier() self.validate_schedule_date() validate_for_items(self) @@ -87,6 +95,33 @@ class PurchaseOrder(BuyingController): if cint(frappe.db.get_single_value('Buying Settings', 'maintain_same_rate')): self.validate_rate_with_reference_doc([["Supplier Quotation", "supplier_quotation", "supplier_quotation_item"]]) + def set_tax_withholding(self): + if not self.apply_tds: + return + + tax_withholding_details = get_party_tax_withholding_details(self, 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) + + # calculate totals again after applying TDS + self.calculate_taxes_and_totals() + def validate_supplier(self): prevent_po = frappe.db.get_value("Supplier", self.supplier, 'prevent_pos') if prevent_po: diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index aaa98f2f1f..39171960d8 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -1111,7 +1111,7 @@ def create_purchase_order(**args): po.schedule_date = add_days(nowdate(), 1) po.company = args.company or "_Test Company" - po.supplier = args.customer or "_Test Supplier" + po.supplier = args.supplier or "_Test Supplier" po.is_subcontracted = args.is_subcontracted or "No" po.currency = args.currency or frappe.get_cached_value('Company', po.company, "default_currency") po.conversion_factor = args.conversion_factor or 1 diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 401dfdf0df..53ded33b6f 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -116,6 +116,8 @@ class AccountsController(TransactionBase): 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" @@ -700,6 +702,7 @@ class AccountsController(TransactionBase): 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) @@ -707,6 +710,87 @@ class AccountsController(TransactionBase): if frappe.db.get_single_value('Accounts Settings', 'unlink_advance_payment_on_cancelation_of_order'): unlink_ref_doc_from_payment_entries(self) + def get_tax_map(self): + tax_map = {} + for tax in self.get('taxes'): + tax_map.setdefault(tax.account_head, 0.0) + tax_map[tax.account_head] += tax.tax_amount + + 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 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 = "credit" if tax.add_deduct_tax == "Add" else "debit" + rev_dr_cr = "debit" if tax.add_deduct_tax == "Add" else "credit" + else: + dr_or_cr = "debit" if tax.add_deduct_tax == "Add" else "credit" + rev_dr_cr = "credit" if tax.add_deduct_tax == "Add" else "debit" + + 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 item_allowance = {} @@ -1240,7 +1324,6 @@ def get_advance_payment_entries(party_type, party, party_account, order_doctype, return list(payment_entries_against_order) + list(unallocated_payment_entries) - def update_invoice_status(): # Daily update the status of the invoices diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index fb22a1d608..0b4fb3a3ed 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -686,7 +686,6 @@ class calculate_taxes_and_totals(object): self.calculate_paid_amount() - def get_itemised_tax_breakup_html(doc): if not doc.taxes: return diff --git a/erpnext/public/js/controllers/accounts.js b/erpnext/public/js/controllers/accounts.js index ceeecb28a2..7b997a1153 100644 --- a/erpnext/public/js/controllers/accounts.js +++ b/erpnext/public/js/controllers/accounts.js @@ -156,31 +156,31 @@ cur_frm.cscript.validate_taxes_and_charges = function(cdt, cdn) { var d = locals[cdt][cdn]; var msg = ""; - if(d.account_head && !d.description) { + if (d.account_head && !d.description) { // set description from account head d.description = d.account_head.split(' - ').slice(0, -1).join(' - '); } - if(!d.charge_type && (d.row_id || d.rate || d.tax_amount)) { + if (!d.charge_type && (d.row_id || d.rate || d.tax_amount)) { 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) { + } else if ((d.charge_type == 'On Previous Row Amount' || d.charge_type == 'On Previous Row Total') && d.row_id) { if (d.idx == 1) { msg = __("Cannot select charge type as 'On Previous Row Amount' or 'On Previous Row Total' for first row"); d.charge_type = ''; } else if (!d.row_id) { msg = __("Please specify a valid Row ID for row {0} in table {1}", [d.idx, __(d.doctype)]); d.row_id = ""; - } else if(d.row_id && d.row_id >= d.idx) { + } else if (d.row_id && d.row_id >= d.idx) { msg = __("Cannot refer row number greater than or equal to current row number for this Charge type"); d.row_id = ""; } } - if(msg) { + if (msg) { frappe.validated = false; refresh_field("taxes"); frappe.throw(msg); diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js index 0b9d771119..e5a5fcfe3b 100644 --- a/erpnext/public/js/controllers/taxes_and_totals.js +++ b/erpnext/public/js/controllers/taxes_and_totals.js @@ -531,7 +531,7 @@ erpnext.taxes_and_totals = erpnext.payments.extend({ }, calculate_totals: function() { - // Changing sequence can cause rounding_adjustmentng issue and on-screen discrepency + // Changing sequence can because of rounding adjustment issue and on-screen discrepancy var me = this; var tax_count = this.frm.doc["taxes"] ? this.frm.doc["taxes"].length : 0; this.frm.doc.grand_total = flt(tax_count diff --git a/erpnext/public/js/payment/payments.js b/erpnext/public/js/payment/payments.js index 0d656bc1fb..ddf8706809 100644 --- a/erpnext/public/js/payment/payments.js +++ b/erpnext/public/js/payment/payments.js @@ -8,24 +8,23 @@ erpnext.payments = erpnext.stock.StockController.extend({ this.dialog = new frappe.ui.Dialog({ title: 'Payment' }); - + this.dialog.show(); this.$body = this.dialog.body; this.set_payment_primary_action(); this.make_keyboard(); - this.select_text() + this.select_text(); }, - select_text: function(){ - var me = this; - $(this.$body).find('.form-control').click(function(){ + select_text() { + $(this.$body).find('.form-control').click(function() { $(this).select(); - }) + }); }, - set_payment_primary_action: function(){ + set_payment_primary_action: function() { var me = this; - + this.dialog.set_primary_action(__("Submit"), function() { // Allow no ZERO payment $.each(me.frm.doc.payments, function (index, data) { @@ -38,20 +37,20 @@ erpnext.payments = erpnext.stock.StockController.extend({ }) }, - make_keyboard: function(){ + make_keyboard: function() { var me = this; $(this.$body).empty(); $(this.$body).html(frappe.render_template('pos_payment', this.frm.doc)) this.show_payment_details(); - this.bind_keyboard_event() - this.clear_amount() + this.bind_keyboard_event(); + this.clear_amount(); }, - make_multimode_payment: function(){ + make_multimode_payment: function() { var me = this; - if(this.frm.doc.change_amount > 0){ - me.payment_val = me.doc.outstanding_amount + if (this.frm.doc.change_amount > 0) { + me.payment_val = me.doc.outstanding_amount; } this.payments = frappe.model.add_child(this.frm.doc, 'Multi Mode Payment', "payments"); @@ -59,11 +58,11 @@ erpnext.payments = erpnext.stock.StockController.extend({ this.payments.amount = flt(this.payment_val); }, - show_payment_details: function(){ + show_payment_details: function() { var me = this; var multimode_payments = $(this.$body).find('.multimode-payments').empty(); - if(this.frm.doc.payments.length){ - $.each(this.frm.doc.payments, function(index, data){ + if (this.frm.doc.payments.length) { + $.each(this.frm.doc.payments, function(index, data) { $(frappe.render_template('payment_details', { mode_of_payment: data.mode_of_payment, amount: data.amount, @@ -84,92 +83,90 @@ erpnext.payments = erpnext.stock.StockController.extend({ } }, - set_outstanding_amount: function(){ + set_outstanding_amount: function() { this.selected_mode = $(this.$body).find(repl("input[idx='%(idx)s']",{'idx': this.idx})); - this.highlight_selected_row() - this.payment_val = 0.0 - if(this.frm.doc.outstanding_amount > 0 && flt(this.selected_mode.val()) == 0.0){ + this.highlight_selected_row(); + this.payment_val = 0.0; + if (this.frm.doc.outstanding_amount > 0 && flt(this.selected_mode.val()) == 0.0) { //When user first time click on row this.payment_val = flt(this.frm.doc.outstanding_amount / this.frm.doc.conversion_rate, precision("outstanding_amount")) this.selected_mode.val(format_currency(this.payment_val, this.frm.doc.currency)); - this.update_payment_amount() - }else if(flt(this.selected_mode.val()) > 0){ + this.update_payment_amount(); + } else if (flt(this.selected_mode.val()) > 0) { //If user click on existing row which has value this.payment_val = flt(this.selected_mode.val()); } this.selected_mode.select() this.bind_amount_change_event(); }, - - bind_keyboard_event: function(){ - var me = this; + + bind_keyboard_event() { this.payment_val = ''; this.bind_form_control_event(); this.bind_numeric_keys_event(); }, - bind_form_control_event: function(){ + bind_form_control_event: function() { var me = this; - $(this.$body).find('.pos-payment-row').click(function(){ + $(this.$body).find('.pos-payment-row').click(function() { me.idx = $(this).attr("idx"); - me.set_outstanding_amount() - }) - - $(this.$body).find('.form-control').click(function(){ + me.set_outstanding_amount(); + }); + + $(this.$body).find('.form-control').click(function() { me.idx = $(this).attr("idx"); me.set_outstanding_amount(); me.update_paid_amount(true); - }) - - $(this.$body).find('.write_off_amount').change(function(){ + }); + + $(this.$body).find('.write_off_amount').change(function() { me.write_off_amount(flt($(this).val()), precision("write_off_amount")); - }) - - $(this.$body).find('.change_amount').change(function(){ + }); + + $(this.$body).find('.change_amount').change(function() { me.change_amount(flt($(this).val()), precision("change_amount")); - }) + }); }, - highlight_selected_row: function(){ - var me = this; - var selected_row = $(this.$body).find(repl(".pos-payment-row[idx='%(idx)s']",{'idx': this.idx})); - $(this.$body).find('.pos-payment-row').removeClass('selected-payment-mode') - selected_row.addClass('selected-payment-mode') + highlight_selected_row() { + var selected_row = $(this.$body).find(repl(".pos-payment-row[idx='%(idx)s']", {'idx': this.idx})); + $(this.$body).find('.pos-payment-row').removeClass('selected-payment-mode'); + selected_row.addClass('selected-payment-mode'); $(this.$body).find('.amount').attr('disabled', true); this.selected_mode.attr('disabled', false); }, - - bind_numeric_keys_event: function(){ + + bind_numeric_keys_event: function() { var me = this; $(this.$body).find('.pos-keyboard-key').click(function(){ me.payment_val += $(this).text(); - me.selected_mode.val(format_currency(me.payment_val, me.frm.doc.currency)) - me.idx = me.selected_mode.attr("idx") - me.update_paid_amount() - }) - - $(this.$body).find('.delete-btn').click(function(){ + me.selected_mode.val(format_currency(me.payment_val, me.frm.doc.currency)); + me.idx = me.selected_mode.attr("idx"); + me.update_paid_amount(); + }); + + $(this.$body).find('.delete-btn').click(function() { me.payment_val = cstr(flt(me.selected_mode.val())).slice(0, -1); me.selected_mode.val(format_currency(me.payment_val, me.frm.doc.currency)); - me.idx = me.selected_mode.attr("idx") + me.idx = me.selected_mode.attr("idx"); me.update_paid_amount(); }) }, - - bind_amount_change_event: function(){ + + bind_amount_change_event() { var me = this; - this.selected_mode.change(function(){ + this.selected_mode.change(function() { me.payment_val = flt($(this).val()) || 0.0; - me.selected_mode.val(format_currency(me.payment_val, me.frm.doc.currency)) - me.idx = me.selected_mode.attr("idx") - me.update_payment_amount() - }) + me.selected_mode.val(format_currency(me.payment_val, me.frm.doc.currency)); + me.idx = me.selected_mode.attr("idx"); + me.update_payment_amount(); + }); }, clear_amount: function() { var me = this; - $(this.$body).find('.clr').click(function(e){ + $(this.$body).find('.clr').click(function(e) { e.stopPropagation(); me.idx = $(this).attr("idx"); me.selected_mode = $(me.$body).find(repl("input[idx='%(idx)s']",{'idx': me.idx})); @@ -177,50 +174,48 @@ erpnext.payments = erpnext.stock.StockController.extend({ me.selected_mode.val(0.0); me.highlight_selected_row(); me.update_payment_amount(); - }) + }); }, - write_off_amount: function(write_off_amount) { - var me = this; - + write_off_amount(write_off_amount) { this.frm.doc.write_off_amount = flt(write_off_amount, precision("write_off_amount")); this.frm.doc.base_write_off_amount = flt(this.frm.doc.write_off_amount * this.frm.doc.conversion_rate, precision("base_write_off_amount")); - this.calculate_outstanding_amount(false) - this.show_amounts() + this.calculate_outstanding_amount(false); + this.show_amounts(); }, change_amount: function(change_amount) { var me = this; this.frm.doc.change_amount = flt(change_amount, precision("change_amount")); - this.calculate_write_off_amount() - this.show_amounts() + this.calculate_write_off_amount(); + this.show_amounts(); }, update_paid_amount: function(update_write_off) { var me = this; - if(in_list(['change_amount', 'write_off_amount'], this.idx)){ + if (in_list(['change_amount', 'write_off_amount'], this.idx)) { var value = me.selected_mode.val(); - if(me.idx == 'change_amount'){ - me.change_amount(value) - } else{ + if (me.idx == 'change_amount') { + me.change_amount(value); + } else { if(flt(value) == 0 && update_write_off && me.frm.doc.outstanding_amount > 0) { value = flt(me.frm.doc.outstanding_amount / me.frm.doc.conversion_rate, precision(me.idx)); } - me.write_off_amount(value) + me.write_off_amount(value); } - }else{ - this.update_payment_amount() + } else { + this.update_payment_amount(); } }, - update_payment_amount: function(){ + update_payment_amount: function() { var me = this; - $.each(this.frm.doc.payments, function(index, data){ - if(cint(me.idx) == cint(data.idx)){ - data.amount = flt(me.selected_mode.val(), 2) + $.each(this.frm.doc.payments, function(index, data) { + if (cint(me.idx) == cint(data.idx)) { + data.amount = flt(me.selected_mode.val(), 2); } }) @@ -228,12 +223,12 @@ erpnext.payments = erpnext.stock.StockController.extend({ this.show_amounts(); }, - show_amounts: function(){ + show_amounts: function() { var me = this; $(this.$body).find(".write_off_amount").val(format_currency(this.frm.doc.write_off_amount, this.frm.doc.currency)); $(this.$body).find('.paid_amount').text(format_currency(this.frm.doc.paid_amount, this.frm.doc.currency)); - $(this.$body).find('.change_amount').val(format_currency(this.frm.doc.change_amount, this.frm.doc.currency)) - $(this.$body).find('.outstanding_amount').text(format_currency(this.frm.doc.outstanding_amount, frappe.get_doc(":Company", this.frm.doc.company).default_currency)) + $(this.$body).find('.change_amount').val(format_currency(this.frm.doc.change_amount, this.frm.doc.currency)); + $(this.$body).find('.outstanding_amount').text(format_currency(this.frm.doc.outstanding_amount, frappe.get_doc(":Company", this.frm.doc.company).default_currency)); this.update_invoice(); } }) \ No newline at end of file diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js index b24048d1ce..d05541b634 100644 --- a/erpnext/setup/doctype/company/company.js +++ b/erpnext/setup/doctype/company/company.js @@ -269,7 +269,7 @@ erpnext.company.setup_queries = function(frm) { ["expenses_included_in_asset_valuation", {"account_type": "Expenses Included In Asset Valuation"}], ["capital_work_in_progress_account", {"account_type": "Capital Work in Progress"}], ["asset_received_but_not_billed", {"account_type": "Asset Received But Not Billed"}], - ["unrealized_profit_loss_account", {"root_type": "Liability"},] + ["unrealized_profit_loss_account", {"root_type": ["in", ["Liability", "Asset"]]}] ], function(i, v) { erpnext.company.set_custom_query(frm, v); });