From 2d8a7ee81fb13ec38df7946291b0ab8685febd2a Mon Sep 17 00:00:00 2001 From: Saurabh Date: Fri, 11 May 2018 13:16:16 +0530 Subject: [PATCH 1/5] Bootstrap 'TDS' via fixture --- .../in_standard_chart_of_accounts.json | 3 + erpnext/hr/doctype/employee/employee.json | 2 +- erpnext/regional/india/setup.py | 58 +++++++++++++++---- 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json b/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json index bc7f9659564..f2c767f7cd5 100644 --- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json +++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json @@ -139,6 +139,9 @@ "Creditors": { "account_type": "Payable" }, + "TDS": { + "account_type": "Payable" + }, "Payroll Payable": {} }, "Stock Liabilities": { diff --git a/erpnext/hr/doctype/employee/employee.json b/erpnext/hr/doctype/employee/employee.json index 3527197edc1..cc3fb7ff20b 100644 --- a/erpnext/hr/doctype/employee/employee.json +++ b/erpnext/hr/doctype/employee/employee.json @@ -2766,7 +2766,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-05-10 07:52:24.326361", + "modified": "2018-05-11 12:48:46.435484", "modified_by": "Administrator", "module": "HR", "name": "Employee", diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index 0073d3311c2..f035249aa43 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -16,7 +16,7 @@ def setup(company=None, patch=True): add_print_formats() if not patch: update_address_template() - make_fixtures() + make_fixtures(company) def update_address_template(): with open(os.path.join(os.path.dirname(__file__), 'address_template.html'), 'r') as f: @@ -189,15 +189,13 @@ def make_custom_fields(): create_custom_fields(custom_fields, ignore_validate = frappe.flags.in_patch) -def make_fixtures(): - docs = [ - {'doctype': 'Salary Component', 'salary_component': 'Professional Tax', 'description': 'Professional Tax', 'type': 'Deduction'}, - {'doctype': 'Salary Component', 'salary_component': 'Provident Fund', 'description': 'Provident fund', 'type': 'Deduction'}, - {'doctype': 'Salary Component', 'salary_component': 'House Rent Allowance', 'description': 'House Rent Allowance', 'type': 'Earning'}, - {'doctype': 'Salary Component', 'salary_component': 'Basic', 'description': 'Basic', 'type': 'Earning'}, - {'doctype': 'Salary Component', 'salary_component': 'Arrear', 'description': 'Arrear', 'type': 'Earning'}, - {'doctype': 'Salary Component', 'salary_component': 'Leave Encashment', 'description': 'Leave Encashment', 'type': 'Earning'} - ] +def make_fixtures(company=None): + docs = [] + company = company.name if company else frappe.db.get_value("Global Defaults", None, "default_company") + + set_salary_components(docs) + set_tds_account(docs, company) + set_tax_withholding_category(docs, company) for d in docs: try: @@ -206,3 +204,43 @@ def make_fixtures(): doc.insert() except frappe.NameError: pass + +def set_salary_components(docs): + docs.extend([ + {'doctype': 'Salary Component', 'salary_component': 'Professional Tax', 'description': 'Professional Tax', 'type': 'Deduction'}, + {'doctype': 'Salary Component', 'salary_component': 'Provident Fund', 'description': 'Provident fund', 'type': 'Deduction'}, + {'doctype': 'Salary Component', 'salary_component': 'House Rent Allowance', 'description': 'House Rent Allowance', 'type': 'Earning'}, + {'doctype': 'Salary Component', 'salary_component': 'Basic', 'description': 'Basic', 'type': 'Earning'}, + {'doctype': 'Salary Component', 'salary_component': 'Arrear', 'description': 'Arrear', 'type': 'Earning'}, + {'doctype': 'Salary Component', 'salary_component': 'Leave Encashment', 'description': 'Leave Encashment', 'type': 'Earning'} + ]) + +def set_tax_withholding_category(docs, company): + accounts = [] + tds_account = frappe.db.get_value("Account", filter={"account_type": "Payable", + "account_name": "TDS", "company": company}) + + if company and tds_account: + accounts = [ + { + 'company': company, + 'account': tds_account + } + ] + + docs.extend([ + { + 'doctype': 'Tax Withholding Category', '__newname': 'TDS', + 'percent_of_tax_withheld': 10,'threshold': 150000, 'book_on_invoice': 1, + 'book_on_advance': 0, "withhold_cumulative_tax_amount": 0, + 'accounts': accounts + } + ]) + +def set_tds_account(docs, company): + docs.extend([ + { + 'doctype': 'Account', 'account_name': 'TDS', 'account_type': 'Payable', + 'parent_account': 'Accounts Payable', 'company': company + } + ]) \ No newline at end of file From 3b4a6be4d029be652903bfba57807789d0bff450 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Fri, 11 May 2018 14:02:25 +0530 Subject: [PATCH 2/5] Supplier Tax Withholding Config --- .../party_tax_withholding_config/__init__.py | 0 .../party_tax_withholding_config.json | 166 ++++++++++++++++++ .../party_tax_withholding_config.py | 10 ++ erpnext/buying/doctype/supplier/supplier.json | 65 ++++++- 4 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 erpnext/buying/doctype/party_tax_withholding_config/__init__.py create mode 100644 erpnext/buying/doctype/party_tax_withholding_config/party_tax_withholding_config.json create mode 100644 erpnext/buying/doctype/party_tax_withholding_config/party_tax_withholding_config.py diff --git a/erpnext/buying/doctype/party_tax_withholding_config/__init__.py b/erpnext/buying/doctype/party_tax_withholding_config/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/buying/doctype/party_tax_withholding_config/party_tax_withholding_config.json b/erpnext/buying/doctype/party_tax_withholding_config/party_tax_withholding_config.json new file mode 100644 index 00000000000..320485b318b --- /dev/null +++ b/erpnext/buying/doctype/party_tax_withholding_config/party_tax_withholding_config.json @@ -0,0 +1,166 @@ +{ + "allow_copy": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "beta": 0, + "creation": "2018-05-11 13:32:33.825307", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 1, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "tax_withholding_category", + "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": "Tax Withholding Category", + "length": 0, + "no_copy": 0, + "options": "Tax Withholding Category", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "valid_till", + "fieldtype": "Date", + "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": "Valid Till", + "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": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "applicable_percent", + "fieldtype": "Float", + "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": "Applicable Percent", + "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": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "certificate_received", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Certificate Received", + "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": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + } + ], + "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": "2018-05-11 13:35:44.424855", + "modified_by": "Administrator", + "module": "Buying", + "name": "Party Tax Withholding Config", + "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": 1, + "track_seen": 0 +} \ No newline at end of file diff --git a/erpnext/buying/doctype/party_tax_withholding_config/party_tax_withholding_config.py b/erpnext/buying/doctype/party_tax_withholding_config/party_tax_withholding_config.py new file mode 100644 index 00000000000..bec7e83f237 --- /dev/null +++ b/erpnext/buying/doctype/party_tax_withholding_config/party_tax_withholding_config.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2018, 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 PartyTaxWithholdingConfig(Document): + pass diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json index d342e115b75..508389f39d0 100644 --- a/erpnext/buying/doctype/supplier/supplier.json +++ b/erpnext/buying/doctype/supplier/supplier.json @@ -960,6 +960,69 @@ "translatable": 0, "unique": 0 }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 1, + "columns": 0, + "fieldname": "default_tax_withholding_config", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Default Tax Withholding Config", + "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": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "tax_withholding_account", + "fieldtype": "Table", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Tax Withholding Account", + "length": 0, + "no_copy": 0, + "options": "Party Tax Withholding Config", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -1163,7 +1226,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-05-11 12:19:52.519026", + "modified": "2018-05-11 14:00:36.204532", "modified_by": "Administrator", "module": "Buying", "name": "Supplier", From b9d3385fec886168cd9a34143a06749a1509b21b Mon Sep 17 00:00:00 2001 From: Saurabh Date: Sat, 12 May 2018 17:42:20 +0530 Subject: [PATCH 3/5] calculate TDS on Sales Invoice Amount --- .../in_standard_chart_of_accounts.json | 8 +-- .../purchase_invoice/purchase_invoice.py | 21 +++++- .../tax_withholding_category.json | 64 ++++++++++++++++++- .../tax_withholding_category.py | 5 +- erpnext/accounts/party.py | 61 +++++++++++++++++- erpnext/buying/doctype/supplier/supplier.json | 38 +---------- erpnext/regional/india/setup.py | 4 +- 7 files changed, 153 insertions(+), 48 deletions(-) diff --git a/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json b/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json index f2c767f7cd5..2ec0b7f70c8 100644 --- a/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json +++ b/erpnext/accounts/doctype/account/chart_of_accounts/verified/in_standard_chart_of_accounts.json @@ -139,9 +139,6 @@ "Creditors": { "account_type": "Payable" }, - "TDS": { - "account_type": "Payable" - }, "Payroll Payable": {} }, "Stock Liabilities": { @@ -150,8 +147,9 @@ } }, "Duties and Taxes": { - "account_type": "Tax", - "is_group": 1 + "TDS": { + "account_type": "Tax" + } }, "Loans (Liabilities)": { "Secured Loans": {}, diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 3e375e50511..0b544b13a30 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -8,7 +8,7 @@ from frappe import _, throw import frappe.defaults from erpnext.controllers.buying_controller import BuyingController -from erpnext.accounts.party import get_party_account, get_due_date +from erpnext.accounts.party import get_party_account, get_due_date, get_patry_tax_withholding_details from erpnext.accounts.utils import get_account_currency, get_fiscal_year from erpnext.stock.doctype.purchase_receipt.purchase_receipt import update_billed_amount_based_on_po from erpnext.stock import get_warehouse_account_map @@ -46,6 +46,7 @@ class PurchaseInvoice(BuyingController): self.is_opening = 'No' self.validate_posting_time() + self.set_tax_withholding() super(PurchaseInvoice, self).validate() if not self.is_return: @@ -53,7 +54,6 @@ class PurchaseInvoice(BuyingController): self.pr_required() self.validate_supplier_invoice() - # validate cash purchase if (self.is_paid == 1): self.validate_cash() @@ -168,7 +168,6 @@ class PurchaseInvoice(BuyingController): super(PurchaseInvoice, self).validate_warehouse() - def validate_item_code(self): for d in self.get('items'): if not d.item_code: @@ -731,6 +730,22 @@ class PurchaseInvoice(BuyingController): def on_recurring(self, reference_doc, subscription_doc): self.due_date = None + def set_tax_withholding(self): + """ + 1. Get TDS Configurations against Supplier or Pull Default One. + 2. Form Purchase Order, identify partial payments + 3. If sum of all invoices grand total is greater than threshold and If TDS not deducted in previos Invoices + then deduct TDS for sum amount else deduct TDS for current Invoice + """ + if not self.get("__islocal"): + return + + tax_withholding_details = get_patry_tax_withholding_details(self) + + if tax_withholding_details and\ + flt(self.get("rounded_total") or self.grand_total) >= flt(tax_withholding_details['threshold']): + self.append('taxes', tax_withholding_details['taxes']) + @frappe.whitelist() def make_debit_note(source_name, target_doc=None): from erpnext.controllers.sales_and_purchase_return import make_return_doc diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json index f02a52043ef..a590776e684 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.json @@ -13,6 +13,68 @@ "editable_grid": 1, "engine": "InnoDB", "fields": [ + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "is_default", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Is Default", + "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": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fieldname": "enabled", + "fieldtype": "Check", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Enabled", + "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": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, { "allow_bulk_edit": 0, "allow_on_submit": 0, @@ -271,7 +333,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-04-13 19:17:12.494050", + "modified": "2018-05-11 14:25:07.474461", "modified_by": "Administrator", "module": "Accounts", "name": "Tax Withholding Category", 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 4940c4f3feb..61f4b60c8b1 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py @@ -7,4 +7,7 @@ import frappe from frappe.model.document import Document class TaxWithholdingCategory(Document): - pass + def validate(self): + if not frappe.db.get_value("Tax Withholding Category", + {"is_default": 1, "name": ("!=", self.name)}, "name"): + self.is_default = 1 \ No newline at end of file diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index 652272dbe13..6c778f99c81 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -448,7 +448,6 @@ def get_dashboard_info(party_type, party): return info - def get_party_shipping_address(doctype, name): """ Returns an Address name (best guess) for the given doctype and name for which `address_type == 'Shipping'` is true. @@ -476,3 +475,63 @@ def get_party_shipping_address(doctype, name): return out[0][0] else: return '' + +def get_patry_tax_withholding_details(ref_doc): + supplier = frappe.get_doc("Supplier", ref_doc.supplier) + tax_withholding_details = {} + + for tax in supplier.tax_withholding_config: + tax_mapper = get_tax_mapper() + + set_tax_withholding_details(tax_mapper, ref_doc, tax_withholding_category=tax.tax_withholding_category) + + if tax.valid_till and date_diff(tax.valid_till, ref_doc.posting_date) > 0: + tax_mapper.update({ + "rate": tax.applicable_percentage + }) + + prepare_tax_withholding_details(tax_mapper, tax_withholding_details) + + if not tax_withholding_details: + tax_mapper = get_tax_mapper() + set_tax_withholding_details(tax_mapper, ref_doc, use_default=1) + prepare_tax_withholding_details(tax_mapper, tax_withholding_details) + + return tax_withholding_details + +def prepare_tax_withholding_details(tax_mapper, tax_withholding_details): + if tax_mapper.get('account_head'): + tax_withholding_details.update({ + "threshold": tax_mapper['threshold'], + "taxes": tax_mapper + }) + del tax_mapper['threshold'] + +def set_tax_withholding_details(tax_mapper, ref_doc, tax_withholding_category=None, use_default=0): + if tax_withholding_category: + tax_withholding = frappe.get_doc("Tax Withholding Category", tax_withholding_category) + else: + tax_withholding = frappe.get_doc("Tax Withholding Category", {'is_default': 1, 'enabled': 1}) + + if tax_withholding.book_on_invoice and ref_doc.doctype=='Purchase Invoice' \ + or tax_withholding.book_on_advance and ref_doc.doctype in ('Payment Entry', 'Journal Entry'): + + for account_detail in tax_withholding.accounts: + if ref_doc.company == account_detail.company: + tax_mapper.update({ + "account_head": account_detail.account, + "rate": tax_withholding.percent_of_tax_withheld, + "threshold": tax_withholding.threshold, + "description": tax_withholding.name + }) + +def get_tax_mapper(): + return { + "category": "Total", + "add_deduct_tax": "Deduct", + "charge_type": "On Net Total", + "rate": 0, + "description": '', + "account_head": '', + "threshold": 0.0 + } \ No newline at end of file diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json index 508389f39d0..eedbac1dffe 100644 --- a/erpnext/buying/doctype/supplier/supplier.json +++ b/erpnext/buying/doctype/supplier/supplier.json @@ -233,7 +233,7 @@ "read_only": 0, "remember_last_selected_value": 0, "report_hide": 0, - "reqd": 1, + "reqd": 0, "search_index": 0, "set_only_once": 0, "translatable": 0, @@ -997,7 +997,7 @@ "bold": 0, "collapsible": 0, "columns": 0, - "fieldname": "tax_withholding_account", + "fieldname": "tax_withholding_config", "fieldtype": "Table", "hidden": 0, "ignore_user_permissions": 0, @@ -1180,38 +1180,6 @@ "set_only_once": 0, "translatable": 0, "unique": 0 - }, - { - "allow_bulk_edit": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "tax_withholding_category", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Tax Withholding Category", - "length": 0, - "no_copy": 0, - "options": "Tax Withholding Category", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 } ], "has_web_view": 0, @@ -1226,7 +1194,7 @@ "issingle": 0, "istable": 0, "max_attachments": 0, - "modified": "2018-05-11 14:00:36.204532", + "modified": "2018-05-11 15:15:19.912308", "modified_by": "Administrator", "module": "Buying", "name": "Supplier", diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py index f035249aa43..70960d714bd 100644 --- a/erpnext/regional/india/setup.py +++ b/erpnext/regional/india/setup.py @@ -240,7 +240,7 @@ def set_tax_withholding_category(docs, company): def set_tds_account(docs, company): docs.extend([ { - 'doctype': 'Account', 'account_name': 'TDS', 'account_type': 'Payable', - 'parent_account': 'Accounts Payable', 'company': company + 'doctype': 'Account', 'account_name': 'TDS', 'account_type': 'Tax', + 'parent_account': 'Duties and Taxes', 'company': company } ]) \ No newline at end of file From f3f438ad183e13ba9ea56fe96dd11941fc6d203f Mon Sep 17 00:00:00 2001 From: Saurabh Date: Mon, 14 May 2018 20:19:39 +0530 Subject: [PATCH 4/5] tds fixed for PI --- .../purchase_invoice/purchase_invoice.py | 18 ++++++++---------- erpnext/accounts/party.py | 17 +++++++---------- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 0b544b13a30..c9cf47d114a 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -732,19 +732,17 @@ class PurchaseInvoice(BuyingController): def set_tax_withholding(self): """ - 1. Get TDS Configurations against Supplier or Pull Default One. - 2. Form Purchase Order, identify partial payments - 3. If sum of all invoices grand total is greater than threshold and If TDS not deducted in previos Invoices - then deduct TDS for sum amount else deduct TDS for current Invoice + 1. Get TDS Configurations against Supplier """ - if not self.get("__islocal"): - return tax_withholding_details = get_patry_tax_withholding_details(self) - - if tax_withholding_details and\ - flt(self.get("rounded_total") or self.grand_total) >= flt(tax_withholding_details['threshold']): - self.append('taxes', tax_withholding_details['taxes']) + for tax_details in tax_withholding_details: + if flt(self.get("rounded_total") or self.grand_total) >= flt(tax_details['threshold']): + if self.taxes: + if tax_details['tax']['description'] not in [tax.description for tax in self.taxes]: + self.append('taxes', tax_details['tax']) + else: + self.append('taxes', tax_details['tax']) @frappe.whitelist() def make_debit_note(source_name, target_doc=None): diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index 6c778f99c81..75089b2ff4c 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -478,8 +478,8 @@ def get_party_shipping_address(doctype, name): def get_patry_tax_withholding_details(ref_doc): supplier = frappe.get_doc("Supplier", ref_doc.supplier) - tax_withholding_details = {} - + tax_withholding_details = [] + print(supplier) for tax in supplier.tax_withholding_config: tax_mapper = get_tax_mapper() @@ -492,19 +492,16 @@ def get_patry_tax_withholding_details(ref_doc): prepare_tax_withholding_details(tax_mapper, tax_withholding_details) - if not tax_withholding_details: - tax_mapper = get_tax_mapper() - set_tax_withholding_details(tax_mapper, ref_doc, use_default=1) - prepare_tax_withholding_details(tax_mapper, tax_withholding_details) - return tax_withholding_details def prepare_tax_withholding_details(tax_mapper, tax_withholding_details): if tax_mapper.get('account_head'): - tax_withholding_details.update({ + + tax_withholding_details.append({ "threshold": tax_mapper['threshold'], - "taxes": tax_mapper + "tax": tax_mapper }) + del tax_mapper['threshold'] def set_tax_withholding_details(tax_mapper, ref_doc, tax_withholding_category=None, use_default=0): @@ -534,4 +531,4 @@ def get_tax_mapper(): "description": '', "account_head": '', "threshold": 0.0 - } \ No newline at end of file + } From 4ae089d6a12dd7a096d92b200f529d087c7e8685 Mon Sep 17 00:00:00 2001 From: Saurabh Date: Mon, 14 May 2018 20:20:12 +0530 Subject: [PATCH 5/5] Provision to deduct TDS on Advance --- .../doctype/payment_entry/payment_entry.py | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index f983868a0f0..0a22ae0a471 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -7,7 +7,7 @@ import frappe, erpnext, json from frappe import _, scrub, ValidationError from frappe.utils import flt, comma_or, nowdate 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.party import get_party_account, get_patry_tax_withholding_details from erpnext.accounts.doctype.journal_entry.journal_entry import get_default_bank_cash_account from erpnext.setup.utils import get_exchange_rate from erpnext.accounts.general_ledger import make_gl_entries @@ -43,6 +43,7 @@ class PaymentEntry(AccountsController): def validate(self): self.setup_party_account_field() + self.set_tax_withholding() self.set_missing_values() self.validate_payment_type() self.validate_party_details() @@ -510,6 +511,27 @@ class PaymentEntry(AccountsController): def on_recurring(self, reference_doc, subscription_doc): self.reference_no = reference_doc.name self.reference_date = nowdate() + + def set_tax_withholding(self): + if self.party_type != 'Supplier': + return + + self.supplier = self.party + tax_withholding_details = get_patry_tax_withholding_details(self) + + for tax_details in tax_withholding_details: + if self.deductions: + if tax_details['tax']['account_head'] not in [deduction.account for deduction in self.deductions]: + self.append('deductions', self.calculate_deductions(tax_details)) + else: + self.append('deductions', self.calculate_deductions(tax_details)) + + def calculate_deductions(self, tax_details): + return { + "account": tax_details['tax']['account_head'], + "cost_center": frappe.db.get_value("Company", self.company, "cost_center"), + "amount": self.total_allocated_amount * (tax_details['tax']['rate'] / 100) + } @frappe.whitelist() def get_outstanding_reference_documents(args):