Item Wise TDS Calculation

This commit is contained in:
niralisatapara
2022-10-19 14:33:02 +05:30
parent f844097f8e
commit 21d09c5bf2
6 changed files with 1607 additions and 1590 deletions

View File

@@ -12,23 +12,39 @@
"supplier", "supplier",
"supplier_name", "supplier_name",
"tax_id", "tax_id",
"due_date",
"tax_withholding_category",
"column_break1",
"company", "company",
"column_break_6",
"posting_date", "posting_date",
"posting_time", "posting_time",
"set_posting_time", "set_posting_time",
"due_date",
"column_break1",
"is_paid", "is_paid",
"is_return", "is_return",
"return_against",
"apply_tds", "apply_tds",
"tax_withholding_category",
"amended_from", "amended_from",
"accounting_dimensions_section", "accounting_dimensions_section",
"cost_center", "cost_center",
"dimension_col_break", "dimension_col_break",
"project", "project",
"supplier_invoice_details",
"bill_no",
"column_break_15",
"bill_date",
"returns",
"return_against",
"section_addresses",
"supplier_address",
"address_display",
"contact_person",
"contact_display",
"contact_mobile",
"contact_email",
"col_break_address",
"shipping_address",
"shipping_address_display",
"billing_address",
"billing_address_display",
"currency_and_price_list", "currency_and_price_list",
"currency", "currency",
"conversion_rate", "conversion_rate",
@@ -38,33 +54,41 @@
"plc_conversion_rate", "plc_conversion_rate",
"ignore_pricing_rule", "ignore_pricing_rule",
"sec_warehouse", "sec_warehouse",
"scan_barcode",
"col_break_warehouse",
"update_stock",
"set_warehouse", "set_warehouse",
"set_from_warehouse",
"is_subcontracted",
"rejected_warehouse", "rejected_warehouse",
"col_break_warehouse",
"set_from_warehouse",
"supplier_warehouse", "supplier_warehouse",
"is_subcontracted",
"items_section", "items_section",
"update_stock",
"scan_barcode",
"items", "items",
"pricing_rule_details",
"pricing_rules",
"raw_materials_supplied",
"supplied_items",
"section_break_26", "section_break_26",
"total_qty", "total_qty",
"total_net_weight",
"column_break_50",
"base_total", "base_total",
"base_net_total", "base_net_total",
"column_break_28", "column_break_28",
"total_net_weight",
"total", "total",
"net_total", "net_total",
"tax_withholding_net_total",
"base_tax_withholding_net_total",
"taxes_section", "taxes_section",
"taxes_and_charges",
"column_break_58",
"tax_category", "tax_category",
"column_break_49", "column_break_49",
"shipping_rule", "shipping_rule",
"section_break_51", "section_break_51",
"taxes_and_charges",
"taxes", "taxes",
"tax_withheld_vouchers_section",
"tax_withheld_vouchers",
"sec_tax_breakup",
"other_charges_calculation",
"totals", "totals",
"base_taxes_and_charges_added", "base_taxes_and_charges_added",
"base_taxes_and_charges_deducted", "base_taxes_and_charges_deducted",
@@ -73,6 +97,12 @@
"taxes_and_charges_added", "taxes_and_charges_added",
"taxes_and_charges_deducted", "taxes_and_charges_deducted",
"total_taxes_and_charges", "total_taxes_and_charges",
"section_break_44",
"apply_discount_on",
"base_discount_amount",
"column_break_46",
"additional_discount_percentage",
"discount_amount",
"section_break_49", "section_break_49",
"base_grand_total", "base_grand_total",
"base_rounding_adjustment", "base_rounding_adjustment",
@@ -86,58 +116,24 @@
"total_advance", "total_advance",
"outstanding_amount", "outstanding_amount",
"disable_rounded_total", "disable_rounded_total",
"section_break_44",
"apply_discount_on",
"base_discount_amount",
"additional_discount_account",
"column_break_46",
"additional_discount_percentage",
"discount_amount",
"tax_withheld_vouchers_section",
"tax_withheld_vouchers",
"sec_tax_breakup",
"other_charges_calculation",
"pricing_rule_details",
"pricing_rules",
"raw_materials_supplied",
"supplied_items",
"payments_tab",
"payments_section", "payments_section",
"mode_of_payment", "mode_of_payment",
"base_paid_amount", "cash_bank_account",
"clearance_date", "clearance_date",
"col_br_payments", "col_br_payments",
"cash_bank_account",
"paid_amount", "paid_amount",
"advances_section", "base_paid_amount",
"allocate_advances_automatically",
"get_advances",
"advances",
"advance_tax",
"write_off", "write_off",
"write_off_amount", "write_off_amount",
"base_write_off_amount", "base_write_off_amount",
"column_break_61", "column_break_61",
"write_off_account", "write_off_account",
"write_off_cost_center", "write_off_cost_center",
"address_and_contact_tab", "advances_section",
"section_addresses", "allocate_advances_automatically",
"supplier_address", "get_advances",
"address_display", "advances",
"col_break_address", "advance_tax",
"contact_person",
"contact_display",
"contact_mobile",
"contact_email",
"company_shipping_address_section",
"shipping_address",
"column_break_126",
"shipping_address_display",
"company_billing_address_section",
"billing_address",
"column_break_130",
"billing_address_display",
"terms_tab",
"payment_schedule_section", "payment_schedule_section",
"payment_terms_template", "payment_terms_template",
"ignore_default_payment_terms_template", "ignore_default_payment_terms_template",
@@ -145,15 +141,23 @@
"terms_section_break", "terms_section_break",
"tc_name", "tc_name",
"terms", "terms",
"more_info_tab", "printing_settings",
"status_section", "letter_head",
"select_print_heading",
"column_break_112",
"group_same_items",
"language",
"sb_14",
"on_hold",
"release_date",
"cb_17",
"hold_comment",
"more_info",
"status", "status",
"column_break_177", "inter_company_invoice_reference",
"per_received", "represents_company",
"supplier_invoice_details", "column_break_147",
"bill_no", "is_internal_supplier",
"column_break_15",
"bill_date",
"accounting_details_section", "accounting_details_section",
"credit_to", "credit_to",
"party_account_currency", "party_account_currency",
@@ -161,32 +165,15 @@
"against_expense_account", "against_expense_account",
"column_break_63", "column_break_63",
"unrealized_profit_loss_account", "unrealized_profit_loss_account",
"remarks",
"subscription_section", "subscription_section",
"auto_repeat",
"update_auto_repeat_reference",
"column_break_114",
"from_date", "from_date",
"to_date", "to_date",
"printing_settings", "column_break_114",
"letter_head", "auto_repeat",
"group_same_items", "update_auto_repeat_reference",
"column_break_112", "per_received",
"select_print_heading", "is_old_subcontracting_flow"
"language",
"sb_14",
"on_hold",
"release_date",
"cb_17",
"hold_comment",
"additional_info_section",
"is_internal_supplier",
"represents_company",
"column_break_147",
"inter_company_invoice_reference",
"is_old_subcontracting_flow",
"remarks",
"connections_tab",
"column_break_38"
], ],
"fields": [ "fields": [
{ {
@@ -369,7 +356,7 @@
"collapsible_depends_on": "bill_no", "collapsible_depends_on": "bill_no",
"fieldname": "supplier_invoice_details", "fieldname": "supplier_invoice_details",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Supplier Invoice" "label": "Supplier Invoice Details"
}, },
{ {
"fieldname": "bill_no", "fieldname": "bill_no",
@@ -392,6 +379,12 @@
"oldfieldtype": "Date", "oldfieldtype": "Date",
"print_hide": 1 "print_hide": 1
}, },
{
"depends_on": "return_against",
"fieldname": "returns",
"fieldtype": "Section Break",
"label": "Returns"
},
{ {
"depends_on": "return_against", "depends_on": "return_against",
"fieldname": "return_against", "fieldname": "return_against",
@@ -403,9 +396,10 @@
"read_only": 1 "read_only": 1
}, },
{ {
"collapsible": 1,
"fieldname": "section_addresses", "fieldname": "section_addresses",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Supplier Address" "label": "Address and Contact"
}, },
{ {
"fieldname": "supplier_address", "fieldname": "supplier_address",
@@ -526,12 +520,11 @@
}, },
{ {
"fieldname": "sec_warehouse", "fieldname": "sec_warehouse",
"fieldtype": "Section Break", "fieldtype": "Section Break"
"hide_border": 1,
"label": "Items"
}, },
{ {
"depends_on": "update_stock", "depends_on": "update_stock",
"description": "Sets 'Accepted Warehouse' in each row of the items table.",
"fieldname": "set_warehouse", "fieldname": "set_warehouse",
"fieldtype": "Link", "fieldtype": "Link",
"label": "Set Accepted Warehouse", "label": "Set Accepted Warehouse",
@@ -540,6 +533,7 @@
}, },
{ {
"depends_on": "update_stock", "depends_on": "update_stock",
"description": "Warehouse where you are maintaining stock of rejected items",
"fieldname": "rejected_warehouse", "fieldname": "rejected_warehouse",
"fieldtype": "Link", "fieldtype": "Link",
"label": "Rejected Warehouse", "label": "Rejected Warehouse",
@@ -562,7 +556,6 @@
{ {
"fieldname": "items_section", "fieldname": "items_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hide_border": 1,
"oldfieldtype": "Section Break", "oldfieldtype": "Section Break",
"options": "fa fa-shopping-cart" "options": "fa fa-shopping-cart"
}, },
@@ -590,7 +583,6 @@
"reqd": 1 "reqd": 1
}, },
{ {
"collapsible": 1,
"fieldname": "pricing_rule_details", "fieldname": "pricing_rule_details",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Pricing Rules" "label": "Pricing Rules"
@@ -603,7 +595,6 @@
"read_only": 1 "read_only": 1
}, },
{ {
"collapsible": 1,
"collapsible_depends_on": "supplied_items", "collapsible_depends_on": "supplied_items",
"fieldname": "raw_materials_supplied", "fieldname": "raw_materials_supplied",
"fieldtype": "Section Break", "fieldtype": "Section Break",
@@ -667,7 +658,6 @@
"read_only": 1 "read_only": 1
}, },
{ {
"depends_on": "total_net_weight",
"fieldname": "total_net_weight", "fieldname": "total_net_weight",
"fieldtype": "Float", "fieldtype": "Float",
"label": "Total Net Weight", "label": "Total Net Weight",
@@ -677,8 +667,6 @@
{ {
"fieldname": "taxes_section", "fieldname": "taxes_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"hide_border": 1,
"label": "Taxes and Charges",
"oldfieldtype": "Section Break", "oldfieldtype": "Section Break",
"options": "fa fa-money" "options": "fa fa-money"
}, },
@@ -702,8 +690,7 @@
}, },
{ {
"fieldname": "section_break_51", "fieldname": "section_break_51",
"fieldtype": "Section Break", "fieldtype": "Section Break"
"hide_border": 1
}, },
{ {
"fieldname": "taxes_and_charges", "fieldname": "taxes_and_charges",
@@ -807,6 +794,7 @@
}, },
{ {
"collapsible": 1, "collapsible": 1,
"collapsible_depends_on": "discount_amount",
"fieldname": "section_break_44", "fieldname": "section_break_44",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Additional Discount" "label": "Additional Discount"
@@ -846,8 +834,7 @@
}, },
{ {
"fieldname": "section_break_49", "fieldname": "section_break_49",
"fieldtype": "Section Break", "fieldtype": "Section Break"
"label": "Totals"
}, },
{ {
"fieldname": "base_grand_total", "fieldname": "base_grand_total",
@@ -1018,6 +1005,8 @@
}, },
{ {
"collapsible": 1, "collapsible": 1,
"collapsible_depends_on": "write_off_amount",
"depends_on": "grand_total",
"fieldname": "write_off", "fieldname": "write_off",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Write Off" "label": "Write Off"
@@ -1094,6 +1083,7 @@
"print_hide": 1 "print_hide": 1
}, },
{ {
"collapsible": 1,
"collapsible_depends_on": "eval:(!doc.is_return)", "collapsible_depends_on": "eval:(!doc.is_return)",
"fieldname": "payment_schedule_section", "fieldname": "payment_schedule_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
@@ -1114,6 +1104,8 @@
"print_hide": 1 "print_hide": 1
}, },
{ {
"collapsible": 1,
"collapsible_depends_on": "terms",
"fieldname": "terms_section_break", "fieldname": "terms_section_break",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Terms and Conditions", "label": "Terms and Conditions",
@@ -1129,13 +1121,13 @@
{ {
"fieldname": "terms", "fieldname": "terms",
"fieldtype": "Text Editor", "fieldtype": "Text Editor",
"label": "Terms and Conditions" "label": "Terms and Conditions1"
}, },
{ {
"collapsible": 1, "collapsible": 1,
"fieldname": "printing_settings", "fieldname": "printing_settings",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Print Settings" "label": "Printing Settings"
}, },
{ {
"allow_on_submit": 1, "allow_on_submit": 1,
@@ -1176,6 +1168,15 @@
"print_hide": 1, "print_hide": 1,
"read_only": 1 "read_only": 1
}, },
{
"collapsible": 1,
"fieldname": "more_info",
"fieldtype": "Section Break",
"label": "More Information",
"oldfieldtype": "Section Break",
"options": "fa fa-file-text",
"print_hide": 1
},
{ {
"default": "0", "default": "0",
"fetch_from": "supplier.is_internal_supplier", "fetch_from": "supplier.is_internal_supplier",
@@ -1261,7 +1262,7 @@
"collapsible": 1, "collapsible": 1,
"fieldname": "subscription_section", "fieldname": "subscription_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Subscription", "label": "Subscription Section",
"print_hide": 1 "print_hide": 1
}, },
{ {
@@ -1357,6 +1358,7 @@
}, },
{ {
"depends_on": "eval:doc.update_stock && doc.is_internal_supplier", "depends_on": "eval:doc.update_stock && doc.is_internal_supplier",
"description": "Sets 'From Warehouse' in each row of the items table.",
"fieldname": "set_from_warehouse", "fieldname": "set_from_warehouse",
"fieldtype": "Link", "fieldtype": "Link",
"label": "Set From Warehouse", "label": "Set From Warehouse",
@@ -1422,7 +1424,15 @@
"read_only": 1 "read_only": 1
}, },
{ {
"collapsible_depends_on": "tax_withheld_vouchers", "default": "0",
"fieldname": "tax_withholding_net_total",
"fieldtype": "Currency",
"label": "Tax Withholding Net Total",
"no_copy": 1,
"options": "currency",
"read_only": 1
},
{
"fieldname": "tax_withheld_vouchers_section", "fieldname": "tax_withheld_vouchers_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
"label": "Tax Withheld Vouchers" "label": "Tax Withheld Vouchers"
@@ -1431,95 +1441,24 @@
"fieldname": "tax_withheld_vouchers", "fieldname": "tax_withheld_vouchers",
"fieldtype": "Table", "fieldtype": "Table",
"label": "Tax Withheld Vouchers", "label": "Tax Withheld Vouchers",
"no_copy": 1,
"options": "Tax Withheld Vouchers", "options": "Tax Withheld Vouchers",
"read_only": 1 "read_only": 1
}, },
{ {
"fieldname": "payments_tab", "fieldname": "base_tax_withholding_net_total",
"fieldtype": "Tab Break", "fieldtype": "Currency",
"label": "Payments" "label": "Base Tax Withholding Net Total",
}, "no_copy": 1,
{ "options": "currency",
"fieldname": "address_and_contact_tab", "print_hide": 1,
"fieldtype": "Tab Break", "read_only": 1
"label": "Address & Contact"
},
{
"fieldname": "terms_tab",
"fieldtype": "Tab Break",
"label": "Terms"
},
{
"fieldname": "more_info_tab",
"fieldtype": "Tab Break",
"label": "More Info"
},
{
"fieldname": "connections_tab",
"fieldtype": "Tab Break",
"label": "Connections",
"show_dashboard": 1
},
{
"fieldname": "column_break_6",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_38",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_50",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_58",
"fieldtype": "Column Break"
},
{
"fieldname": "company_shipping_address_section",
"fieldtype": "Section Break",
"label": "Company Shipping Address"
},
{
"fieldname": "column_break_126",
"fieldtype": "Column Break"
},
{
"fieldname": "company_billing_address_section",
"fieldtype": "Section Break",
"label": "Company Billing Address"
},
{
"fieldname": "column_break_130",
"fieldtype": "Column Break"
},
{
"collapsible": 1,
"fieldname": "status_section",
"fieldtype": "Section Break",
"label": "Status"
},
{
"fieldname": "column_break_177",
"fieldtype": "Column Break"
},
{
"collapsible": 1,
"fieldname": "additional_info_section",
"fieldtype": "Section Break",
"label": "Additional Info",
"oldfieldtype": "Section Break",
"options": "fa fa-file-text",
"print_hide": 1
} }
], ],
"icon": "fa fa-file-text", "icon": "fa fa-file-text",
"idx": 204, "idx": 204,
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"modified": "2022-10-11 13:04:44.304389", "modified": "2022-09-27 13:52:55.766844",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Accounts", "module": "Accounts",
"name": "Purchase Invoice", "name": "Purchase Invoice",

View File

@@ -61,6 +61,9 @@ def get_party_details(inv):
def get_party_tax_withholding_details(inv, tax_withholding_category=None): def get_party_tax_withholding_details(inv, tax_withholding_category=None):
if inv.doctype == "Payment Entry":
inv.tax_withholding_net_total = inv.net_total
pan_no = "" pan_no = ""
parties = [] parties = []
party_type, party = get_party_details(inv) party_type, party = get_party_details(inv)
@@ -428,11 +431,11 @@ def get_tds_amount(ldc, parties, inv, tax_details, tax_deducted, vouchers):
): ):
# Get net total again as TDS is calculated on net total # Get net total again as TDS is calculated on net total
# Grand is used to just check for threshold breach # Grand is used to just check for threshold breach
net_total = 0 net_total = (
if vouchers: frappe.db.get_value("Purchase Invoice", invoice_filters, "sum(tax_withholding_net_total)")
net_total = frappe.db.get_value("Purchase Invoice", invoice_filters, "sum(net_total)") or 0.0
)
net_total += inv.net_total net_total += inv.tax_withholding_net_total
supp_credit_amt = net_total - cumulative_threshold supp_credit_amt = net_total - cumulative_threshold
if ldc and is_valid_certificate( if ldc and is_valid_certificate(

View File

@@ -186,6 +186,46 @@ class TestTaxWithholdingCategory(unittest.TestCase):
for d in reversed(invoices): for d in reversed(invoices):
d.cancel() d.cancel()
def test_tds_calculation_on_net_total_partial_tds(self):
frappe.db.set_value(
"Supplier", "Test TDS Supplier4", "tax_withholding_category", "Cumulative Threshold TDS"
)
invoices = []
pi = create_purchase_invoice(supplier="Test TDS Supplier4", rate=20000, do_not_save=True)
pi.extend(
"items",
[
{
"doctype": "Purchase Invoice Item",
"item_code": frappe.db.get_value("Item", {"item_name": "TDS Item"}, "name"),
"qty": 1,
"rate": 20000,
"cost_center": "Main - _TC",
"expense_account": "Stock Received But Not Billed - _TC",
"apply_tds": 0,
},
{
"doctype": "Purchase Invoice Item",
"item_code": frappe.db.get_value("Item", {"item_name": "TDS Item"}, "name"),
"qty": 1,
"rate": 35000,
"cost_center": "Main - _TC",
"expense_account": "Stock Received But Not Billed - _TC",
"apply_tds": 1,
},
],
)
pi.save()
pi.submit()
invoices.append(pi)
self.assertEqual(pi.taxes[0].tax_amount, 5500)
# cancel invoices to avoid clashing
for d in reversed(invoices):
d.cancel()
def test_multi_category_single_supplier(self): def test_multi_category_single_supplier(self):
frappe.db.set_value( frappe.db.set_value(
"Supplier", "Test TDS Supplier5", "tax_withholding_category", "Test Service Category" "Supplier", "Test TDS Supplier5", "tax_withholding_category", "Test Service Category"

View File

@@ -64,6 +64,18 @@ class calculate_taxes_and_totals(object):
self._cleanup() self._cleanup()
self.calculate_total_net_weight() self.calculate_total_net_weight()
def calculate_tax_withholding_net_total(self):
if hasattr(self.doc, "tax_withholding_net_total"):
sum_net_amount = 0
sum_base_net_amount = 0
for item in self.doc.get("items"):
if hasattr(item, "apply_tds") and item.apply_tds:
sum_net_amount += item.net_amount
sum_base_net_amount += item.base_net_amount
self.doc.tax_withholding_net_total = sum_net_amount
self.doc.base_tax_withholding_net_total = sum_base_net_amount
def validate_item_tax_template(self): def validate_item_tax_template(self):
for item in self.doc.get("items"): for item in self.doc.get("items"):
if item.item_code and item.get("item_tax_template"): if item.item_code and item.get("item_tax_template"):

View File

@@ -316,3 +316,4 @@ erpnext.patches.v14_0.create_accounting_dimensions_in_subcontracting_doctypes
erpnext.patches.v14_0.fix_subcontracting_receipt_gl_entries erpnext.patches.v14_0.fix_subcontracting_receipt_gl_entries
erpnext.patches.v14_0.migrate_remarks_from_gl_to_payment_ledger erpnext.patches.v14_0.migrate_remarks_from_gl_to_payment_ledger
erpnext.patches.v14_0.create_accounting_dimensions_for_asset_capitalization erpnext.patches.v14_0.create_accounting_dimensions_for_asset_capitalization
erpnext.patches.v14_0.update_tds_fields

View File

@@ -0,0 +1,22 @@
import frappe
def execute():
frappe.db.sql("""
UPDATE
`tabPurchase Invoice Item`
INNER JOIN
`tabPurchase Invoice`
ON
`tabPurchase Invoice`.name = `tabPurchase Invoice Item`.parent
SET
`tabPurchase Invoice Item`.apply_tds = 1
WHERE
`tabPurchase Invoice`.apply_tds = 1
and `tabPurchase Invoice`.docstatus = 1
""")
frappe.db.sql("""
UPDATE `tabPurchase Invoice`
SET tax_withholding_net_total = net_total,
base_tax_withholding_net_total = base_net_total
WHERE apply_tds = 1 and docstatus = 1""")