From 39278fd1437d8b43cc2c63b961e2eab702396d99 Mon Sep 17 00:00:00 2001 From: Sagar Vora Date: Thu, 9 Mar 2023 18:03:17 +0530 Subject: [PATCH] feat: ability to edit Place of Supply (cherry picked from commit 22588a166989be07b36e8bb90be5158b735bae49) --- .../gst_india/constants/custom_fields.py | 21 +++++-- .../gst_india/overrides/test_transaction.py | 23 +++++++- .../gst_india/overrides/transaction.py | 15 +++-- india_compliance/patches.txt | 2 +- india_compliance/public/js/transaction.js | 55 ++++++++++++++----- 5 files changed, 92 insertions(+), 24 deletions(-) diff --git a/india_compliance/gst_india/constants/custom_fields.py b/india_compliance/gst_india/constants/custom_fields.py index 5ea162de5..aaa589e21 100644 --- a/india_compliance/gst_india/constants/custom_fields.py +++ b/india_compliance/gst_india/constants/custom_fields.py @@ -8,6 +8,17 @@ gst_category_options = "\n".join(GST_CATEGORIES) default_gst_category = "Unregistered" + +def get_place_of_supply_options(): + options = [] + + for state_name, state_number in STATE_NUMBERS.items(): + options.append(f"{state_number}-{state_name}") + + options.append("96-Other Countries") + return "\n".join(sorted(options)) + + party_fields = [ { "fieldname": "tax_details_section", @@ -83,10 +94,11 @@ { "fieldname": "place_of_supply", "label": "Place of Supply", - "fieldtype": "Data", + "fieldtype": "Autocomplete", + "options": get_place_of_supply_options(), "insert_after": "company_gstin", "print_hide": 1, - "read_only": 1, + "read_only": 0, "translatable": 0, }, { @@ -164,10 +176,11 @@ { "fieldname": "place_of_supply", "label": "Place of Supply", - "fieldtype": "Data", + "fieldtype": "Autocomplete", + "options": get_place_of_supply_options(), "insert_after": "gst_category", "print_hide": 1, - "read_only": 1, + "read_only": 0, "length": 50, "translatable": 0, }, diff --git a/india_compliance/gst_india/overrides/test_transaction.py b/india_compliance/gst_india/overrides/test_transaction.py index dba224801..263baa028 100644 --- a/india_compliance/gst_india/overrides/test_transaction.py +++ b/india_compliance/gst_india/overrides/test_transaction.py @@ -431,13 +431,34 @@ def test_purchase_from_unregistered_supplier(self): doc.insert, ) + def test_purchase_with_different_place_of_supply(self): + if self.is_sales_doctype: + return + + doc = create_transaction( + **self.transaction_details, + is_out_state=True, + do_not_save=True, + ) + + doc.place_of_supply = "96-Other Countries" + doc.save() + + # place of supply shouldn't get overwritten + self.assertEqual(doc.place_of_supply, "96-Other Countries") + + # IGST should get applied + self.assertIn("IGST", doc.taxes[-1].description) + def test_invalid_gst_account_type(self): doc = create_transaction(**self.transaction_details, do_not_save=True) doc.append( "taxes", { "charge_type": "On Net Total", - "account_head": f"{'Input' if self.is_sales_doctype else 'Output'} Tax IGST - _TIRC", + "account_head": ( + f"{'Input' if self.is_sales_doctype else 'Output'} Tax IGST - _TIRC" + ), "description": "IGST", "rate": 18, "cost_center": "Main - _TIRC", diff --git a/india_compliance/gst_india/overrides/transaction.py b/india_compliance/gst_india/overrides/transaction.py index 624ba7593..c161008cb 100644 --- a/india_compliance/gst_india/overrides/transaction.py +++ b/india_compliance/gst_india/overrides/transaction.py @@ -347,7 +347,8 @@ def validate_items(doc): def set_place_of_supply(doc, method=None): - doc.place_of_supply = get_place_of_supply(doc, doc.doctype) + if not doc.place_of_supply: + doc.place_of_supply = get_place_of_supply(doc, doc.doctype) def is_inter_state_supply(doc): @@ -479,11 +480,13 @@ def get_regional_round_off_accounts(company, account_list): def update_party_details(party_details, doctype, company): - party_details.update(get_gst_details(party_details, doctype, company)) + party_details.update( + get_gst_details(party_details, doctype, company, update_place_of_supply=True) + ) @frappe.whitelist() -def get_gst_details(party_details, doctype, company): +def get_gst_details(party_details, doctype, company, *, update_place_of_supply=False): """ This function does not check for permissions since it returns insensitive data based on already sensitive input (party details) @@ -512,7 +515,11 @@ def get_gst_details(party_details, doctype, company): party_details.update(party_gst_details) gst_details.update(party_gst_details) - gst_details.place_of_supply = get_place_of_supply(party_details, doctype) + gst_details.place_of_supply = ( + party_details.place_of_supply + if (not update_place_of_supply and party_details.place_of_supply) + else get_place_of_supply(party_details, doctype) + ) if is_sales_transaction: source_gstin = party_details.company_gstin diff --git a/india_compliance/patches.txt b/india_compliance/patches.txt index 81b6124a4..41585a914 100644 --- a/india_compliance/patches.txt +++ b/india_compliance/patches.txt @@ -3,7 +3,7 @@ [post_model_sync] india_compliance.patches.v14.set_default_for_overridden_accounts_setting -execute:from india_compliance.gst_india.setup import create_custom_fields; create_custom_fields() #5 +execute:from india_compliance.gst_india.setup import create_custom_fields; create_custom_fields() #6 execute:from india_compliance.gst_india.setup import create_property_setters; create_property_setters() india_compliance.patches.post_install.update_custom_role_for_e_invoice_summary india_compliance.patches.v14.remove_ecommerce_gstin_from_purchase_invoice diff --git a/india_compliance/public/js/transaction.js b/india_compliance/public/js/transaction.js index bd2441d13..8c68dc7fd 100644 --- a/india_compliance/public/js/transaction.js +++ b/india_compliance/public/js/transaction.js @@ -17,7 +17,7 @@ for (const doctype of TRANSACTION_DOCTYPES) { } function fetch_gst_details(doctype) { - const event_fields = ["tax_category", "company_gstin"]; + const event_fields = ["tax_category", "company_gstin", "place_of_supply"]; // we are using address below to prevent multiple event triggers if (in_list(frappe.boot.sales_doctypes, doctype)) { @@ -31,24 +31,46 @@ function fetch_gst_details(doctype) { } const events = Object.fromEntries( - event_fields.map(field => [field, update_gst_details]) + event_fields.map(field => [field, frm => update_gst_details(frm, field)]) ); frappe.ui.form.on(doctype, events); } -async function update_gst_details(frm) { - if (frm.__gst_update_triggered || frm.updating_party_details || !frm.doc.company) return; +async function update_gst_details(frm, event) { + if ( + frm.updating_party_details || + !frm.doc.company || + (event === "place_of_supply" && frm.__updating_gst_details) + ) + return; const party_type = india_compliance.get_party_type(frm.doc.doctype).toLowerCase(); const party_fieldname = frm.doc.doctype === "Quotation" ? "party_name" : party_type; const party = frm.doc[party_fieldname]; if (!party) return; + if (in_list(["company_gstin", "customer_address", "supplier_address"], event)) { + frm.__update_place_of_supply = true; + } + + if (frm.__gst_update_triggered) return; frm.__gst_update_triggered = true; + const args = { + doctype: frm.doc.doctype, + company: frm.doc.company, + }; + // wait for GSTINs to get fetched - await frappe.after_ajax().then(() => frm.__gst_update_triggered = false); + await frappe.after_ajax().then(() => { + frm.__gst_update_triggered = false; + + if (frm.__update_place_of_supply) { + args.update_place_of_supply = 1; + frm.__update_place_of_supply = false; + } + }); const party_details = {}; @@ -57,8 +79,12 @@ async function update_gst_details(frm) { party_details[party_type] = party; } - - const fieldnames_to_set = ["tax_category", "gst_category", "company_gstin"]; + const fieldnames_to_set = [ + "tax_category", + "gst_category", + "company_gstin", + "place_of_supply", + ]; if (in_list(frappe.boot.sales_doctypes, frm.doc.doctype)) { fieldnames_to_set.push( @@ -75,16 +101,17 @@ async function update_gst_details(frm) { party_details[fieldname] = frm.doc[fieldname]; } + args.party_details = JSON.stringify(party_details); + frappe.call({ method: "india_compliance.gst_india.overrides.transaction.get_gst_details", - args: { - party_details: JSON.stringify(party_details), - doctype: frm.doc.doctype, - company: frm.doc.company, - }, - callback(r) { + args, + async callback(r) { if (!r.message) return; - frm.set_value(r.message); + + frm.__updating_gst_details = true; + await frm.set_value(r.message); + frm.__updating_gst_details = false; }, }); }