Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: GST Transporter ID Refactor #2198

Merged
merged 8 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1162,9 +1162,7 @@ async function update_gst_tranporter_id(dialog) {
}

function set_gst_transporter_id_status(dialog) {
const gst_transporter_id_field = dialog.get_field("gst_transporter_id");

india_compliance.set_gstin_status(gst_transporter_id_field);
india_compliance.validate_gst_transporter_id(dialog.get_value("gst_transporter_id"));
}

function update_generation_dialog(dialog, doc) {
Expand Down
2 changes: 1 addition & 1 deletion india_compliance/gst_india/client_scripts/supplier.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ frappe.ui.form.on(DOCTYPE, {
return;

gst_transporter_id_field = frm.get_field("gst_transporter_id");
india_compliance.set_gstin_status(gst_transporter_id_field);
india_compliance.validate_gst_transporter_id(gst_transporter_id_field.value);
vishakhdesai marked this conversation as resolved.
Show resolved Hide resolved
},
});
6 changes: 5 additions & 1 deletion india_compliance/gst_india/doctype/gstin/gstin.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ frappe.ui.form.on("GSTIN", {
refresh(frm) {
frm.disable_form();

frm.add_custom_button(__("Refresh Now"), () => {
frm.add_custom_button(__("Refresh GSTIN Status"), () => {
frm.call("update_gstin_status");
});

frm.add_custom_button(__("Refresh Transporter ID Status"), () => {
frm.call("update_transporter_id_status");
});
},
});
15 changes: 11 additions & 4 deletions india_compliance/gst_india/doctype/gstin/gstin.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
"is_blocked",
"column_break_nrjd",
"last_updated_on",
"cancelled_date"
"cancelled_date",
"transporter_id_status"
],
"fields": [
{
Expand All @@ -28,8 +29,7 @@
"fieldtype": "Data",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Status",
"reqd": 1
"label": "Status"
},
{
"fieldname": "registration_date",
Expand Down Expand Up @@ -59,12 +59,19 @@
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Is Blocked"
},
{
"fieldname": "transporter_id_status",
"fieldtype": "Data",
vorasmit marked this conversation as resolved.
Show resolved Hide resolved
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Transporter ID Status"
}
],
"in_create": 1,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2024-03-29 11:54:43.241749",
"modified": "2024-05-21 12:59:58.322776",
"modified_by": "Administrator",
"module": "GST India",
"name": "GSTIN",
Expand Down
113 changes: 90 additions & 23 deletions india_compliance/gst_india/doctype/gstin/gstin.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
from frappe.model.document import Document
from frappe.utils import date_diff, format_date, get_datetime

from india_compliance.exceptions import GSPServerError
from india_compliance.gst_india.api_classes.e_invoice import EInvoiceAPI
from india_compliance.gst_india.api_classes.e_waybill import EWaybillAPI
from india_compliance.gst_india.api_classes.public import PublicAPI
from india_compliance.gst_india.utils import (
is_api_enabled,
parse_datetime,
validate_gstin,
validate_gstin_check_digit,
)

GSTIN_STATUS = {
Expand Down Expand Up @@ -40,7 +42,15 @@
"""
Permission check not required as GSTIN details are public and user has access to doc.
"""
create_or_update_gstin_status(self.gstin)
# hard refresh will always use public API
create_or_update_gstin_status(self.gstin, use_public_api=True)

Check warning on line 46 in india_compliance/gst_india/doctype/gstin/gstin.py

View check run for this annotation

Codecov / codecov/patch

india_compliance/gst_india/doctype/gstin/gstin.py#L46

Added line #L46 was not covered by tests

@frappe.whitelist()
def update_transporter_id_status(self):
"""
Permission check not required as GSTIN details are public and user has access to doc.
"""
create_or_update_gstin_status(self.gstin, is_transporter_id=True)

Check warning on line 53 in india_compliance/gst_india/doctype/gstin/gstin.py

View check run for this annotation

Codecov / codecov/patch

india_compliance/gst_india/doctype/gstin/gstin.py#L53

Added line #L53 was not covered by tests


@frappe.whitelist()
Expand All @@ -61,25 +71,23 @@

return frappe.get_doc("GSTIN", gstin)

return get_updated_gstin(gstin, transaction_date, is_request_from_ui)
return get_updated_gstin(gstin, transaction_date, is_request_from_ui, force_update)

Check warning on line 74 in india_compliance/gst_india/doctype/gstin/gstin.py

View check run for this annotation

Codecov / codecov/patch

india_compliance/gst_india/doctype/gstin/gstin.py#L74

Added line #L74 was not covered by tests


def get_updated_gstin(gstin, transaction_date=None, is_request_from_ui=0):
def get_updated_gstin(
gstin, transaction_date=None, is_request_from_ui=0, force_update=0
):
if is_request_from_ui:
return create_or_update_gstin_status(gstin)

if gstin[:2] == "88":
callback = _validate_gst_transporter_id_info
else:
callback = _validate_gstin_info
# hard refresh from UI will always use public API
return create_or_update_gstin_status(gstin, use_public_api=force_update)

Check warning on line 82 in india_compliance/gst_india/doctype/gstin/gstin.py

View check run for this annotation

Codecov / codecov/patch

india_compliance/gst_india/doctype/gstin/gstin.py#L82

Added line #L82 was not covered by tests

frappe.enqueue(
create_or_update_gstin_status,
enqueue_after_commit=True,
queue="short",
gstin=gstin,
transaction_date=transaction_date,
callback=callback,
callback=_validate_gstin_info,
)


Expand All @@ -88,13 +96,17 @@
response=None,
transaction_date=None,
callback=None,
use_public_api=False,
is_transporter_id=False,
):
doctype = "GSTIN"

if gstin and gstin[:2] == "88":
if is_transporter_id:
response = get_transporter_id_info(gstin)
else:
response = _get_gstin_info(gstin=gstin, response=response)
response = _get_gstin_info(
gstin=gstin, response=response, use_public_api=use_public_api
)

if not response:
return
Expand All @@ -113,16 +125,19 @@
return doc


def _get_gstin_info(*, gstin=None, response=None):
def _get_gstin_info(*, gstin=None, response=None, use_public_api=False):
if response:
return get_formatted_response(response)

validate_gstin(gstin)

try:
if frappe.cache.get_value("gst_server_error"):
return

Check warning on line 136 in india_compliance/gst_india/doctype/gstin/gstin.py

View check run for this annotation

Codecov / codecov/patch

india_compliance/gst_india/doctype/gstin/gstin.py#L136

Added line #L136 was not covered by tests

company_gstin = get_company_gstin()

if not company_gstin:
if use_public_api or not company_gstin:
response = PublicAPI().get_gstin_info(gstin)
return get_formatted_response(response)

Expand All @@ -137,7 +152,10 @@
}
)

except Exception:
except Exception as e:
if isinstance(e, GSPServerError):
frappe.cache.set_value("gst_server_error", True, expires_in_sec=60)

Check warning on line 157 in india_compliance/gst_india/doctype/gstin/gstin.py

View check run for this annotation

Codecov / codecov/patch

india_compliance/gst_india/doctype/gstin/gstin.py#L157

Added line #L157 was not covered by tests

frappe.log_error(
title=_("Error fetching GSTIN status"),
message=frappe.get_traceback(),
Expand Down Expand Up @@ -197,7 +215,7 @@
)


def _validate_gst_transporter_id_info(transporter_id_info, **kwargs):
def _validate_gst_transporter_id_info(transporter_id_info, *args, **kwargs):
if not transporter_id_info:
return

Expand All @@ -213,7 +231,7 @@
message=message,
)

if transporter_id_info.status != "Active":
if transporter_id_info.transporter_id_status != "Active":

Check warning on line 234 in india_compliance/gst_india/doctype/gstin/gstin.py

View check run for this annotation

Codecov / codecov/patch

india_compliance/gst_india/doctype/gstin/gstin.py#L234

Added line #L234 was not covered by tests
return _throw(
_(
"Transporter ID {0} is not Active. Please make sure that transporter ID is valid."
Expand Down Expand Up @@ -250,11 +268,6 @@
if not doc:
return True

# Transporter ID status is never cancelled
is_transporter_id = gstin[:2] == "88"
if is_transporter_id:
return False

if not transaction_date: # not from transactions
return False

Expand Down Expand Up @@ -301,6 +314,60 @@
return frappe._dict(
{
"gstin": transporter_id,
"status": "Active" if response.transin else "Invalid",
"transporter_id_status": "Active" if response.transin else "Invalid",
}
)


@frappe.whitelist()
def validate_gst_transporter_id(transporter_id):
"""
Validates GST Transporter ID and warns user if transporter_id is not Active

Args:
transporter_id (str): GST Transporter ID
"""
if not transporter_id:
return

Check warning on line 331 in india_compliance/gst_india/doctype/gstin/gstin.py

View check run for this annotation

Codecov / codecov/patch

india_compliance/gst_india/doctype/gstin/gstin.py#L331

Added line #L331 was not covered by tests

gstin = None

# Check if GSTIN doc exists
if frappe.db.exists("GSTIN", transporter_id):
gstin = frappe.get_doc("GSTIN", transporter_id)

Check warning on line 337 in india_compliance/gst_india/doctype/gstin/gstin.py

View check run for this annotation

Codecov / codecov/patch

india_compliance/gst_india/doctype/gstin/gstin.py#L337

Added line #L337 was not covered by tests

# Check if transporter_id starts with 88 or is not valid GSTIN and use Transporter ID API
elif transporter_id[:2] == "88" or not validate_gstin_check_digit(
transporter_id, throw=False
):
gstin = create_or_update_gstin_status(
transporter_id,
is_transporter_id=True,
callback=_validate_gst_transporter_id_info,
)

# Use GSTIN API
else:
gstin = create_or_update_gstin_status(
transporter_id, callback=_validate_gstin_info
)

if not gstin:
return

# If GSTIN status is not Active and transporter_id_status is None, use Transporter ID API
if gstin.status != "Active" and not gstin.transporter_id_status:
gstin = create_or_update_gstin_status(

Check warning on line 360 in india_compliance/gst_india/doctype/gstin/gstin.py

View check run for this annotation

Codecov / codecov/patch

india_compliance/gst_india/doctype/gstin/gstin.py#L359-L360

Added lines #L359 - L360 were not covered by tests
transporter_id,
is_transporter_id=True,
callback=_validate_gst_transporter_id_info,
)

# Return if GSTIN or transporter_id_status is Active
if gstin.status == "Active" or gstin.transporter_id_status == "Active":
return

Check warning on line 368 in india_compliance/gst_india/doctype/gstin/gstin.py

View check run for this annotation

Codecov / codecov/patch

india_compliance/gst_india/doctype/gstin/gstin.py#L367-L368

Added lines #L367 - L368 were not covered by tests

frappe.msgprint(

Check warning on line 370 in india_compliance/gst_india/doctype/gstin/gstin.py

View check run for this annotation

Codecov / codecov/patch

india_compliance/gst_india/doctype/gstin/gstin.py#L370

Added line #L370 was not covered by tests
_("Transporter ID {0} seems to be Inactive").format(transporter_id),
indicator="orange",
)
70 changes: 33 additions & 37 deletions india_compliance/gst_india/doctype/gstin/test_gstin.py
Original file line number Diff line number Diff line change
@@ -1,48 +1,44 @@
# Copyright (c) 2023, Resilient Tech and Contributors
# See license.txt
import re
import responses
from responses import matchers

import frappe
from frappe.tests.utils import FrappeTestCase, change_settings
from frappe.utils import now

from india_compliance.gst_india.utils.tests import create_transaction
from india_compliance.gst_india.doctype.gstin.gstin import validate_gst_transporter_id

TEST_GSTIN = "24AANFA2641L1ZK"

TRANSPORTER_ID_API_RESPONSE = {
"success": True,
"message": "Transporter details are fetched successfully",
"result": {
"transin": TEST_GSTIN,
"tradeName": "_Test Transporter ID Comapany",
"legalName": "_Test Transporter ID Comapany",
"address1": "address 1",
"address2": "address 2",
"stateCode": "24",
"pinCode": "390020",
},
}


class TestGSTIN(FrappeTestCase):
@responses.activate
@change_settings("GST Settings", {"validate_gstin_status": 1, "sandbox_mode": 0})
def test_validate_gst_transporter_id_info(self):
# customer gstin
frappe.get_doc(
{
"doctype": "GSTIN",
"gstin": "24AANFA2641L1ZF",
"registration_date": "2021-01-01",
"status": "Active",
"last_updated_on": now(),
}
).insert(ignore_if_duplicate=True)

# gst transporter id
frappe.get_doc(
{
"doctype": "GSTIN",
"gstin": "88AABCM9407D1ZS",
"status": "Invalid",
"last_updated_on": now(),
}
).insert(ignore_if_duplicate=True)

si = create_transaction(
doctype="Sales Invoice",
gst_transporter_id="88AABCM9407D1ZS",
do_not_save=True,
)
def test_validate_gst_transporter_id(self):
self.mock_get_transporter_details_response()

validate_gst_transporter_id(TEST_GSTIN)

def mock_get_transporter_details_response(self):
url = "https://asp.resilient.tech/ewb/Master/GetTransporterDetails"

self.assertRaisesRegex(
frappe.ValidationError,
re.compile(
r"^(.*is not Active. Please make sure that transporter ID is valid.*)$"
),
si.save,
responses.add(
responses.GET,
url,
json=TRANSPORTER_ID_API_RESPONSE,
match=[matchers.query_param_matcher({"trn_no": TEST_GSTIN})],
status=200,
)
11 changes: 4 additions & 7 deletions india_compliance/gst_india/overrides/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
)
from india_compliance.gst_india.constants.custom_fields import E_WAYBILL_INV_FIELDS
from india_compliance.gst_india.doctype.gstin.gstin import (
_validate_gst_transporter_id_info,
_validate_gstin_info,
get_gstin_status,
)
from india_compliance.gst_india.doctype.gstin.gstin import (
validate_gst_transporter_id as _validate_gst_transporter_id,
)
from india_compliance.gst_india.utils import (
get_all_gst_accounts,
get_gst_accounts_by_tax_type,
Expand Down Expand Up @@ -1311,12 +1313,7 @@ def validate_gst_transporter_id(doc):
doc.gst_transporter_id, label="GST Transporter ID", is_transporter_id=True
)

gstin_doc = get_gstin_status(doc.gst_transporter_id)

if not gstin_doc:
return

_validate_gst_transporter_id_info(gstin_doc, throw=True)
_validate_gst_transporter_id(doc.gst_transporter_id)


def validate_company_address_field(doc):
Expand Down
Loading