Skip to content

Commit

Permalink
Merge pull request #2229 from resilient-tech/version-15-hotfix
Browse files Browse the repository at this point in the history
chore: release v15
vorasmit authored Jun 9, 2024
2 parents df925e0 + acaae82 commit 3780b32
Showing 67 changed files with 11,298 additions and 549 deletions.
4 changes: 4 additions & 0 deletions india_compliance/gst_india/api_classes/base.py
Original file line number Diff line number Diff line change
@@ -154,6 +154,10 @@ def _make_request(
)

response_json = self.process_response(response_json)

if response_json.get("error_type") == "invalid_public_key":
return self._make_request(method, endpoint, params, headers, json)

return response_json.get("result", response_json)

except Exception as e:
5 changes: 5 additions & 0 deletions india_compliance/gst_india/api_classes/public.py
Original file line number Diff line number Diff line change
@@ -28,3 +28,8 @@ def get_gstin_info(self, gstin):
)

return response

def get_returns_info(self, gstin, fy):
return self.get(
"returns", params={"action": "RETTRACK", "gstin": gstin, "fy": fy}
)
39 changes: 38 additions & 1 deletion india_compliance/gst_india/api_classes/returns.py
Original file line number Diff line number Diff line change
@@ -22,8 +22,12 @@
class PublicCertificate(BaseAPI):
BASE_PATH = "static"

def get_gstn_public_certificate(self) -> str:
def get_gstn_public_certificate(self, error_message=None) -> str:
response = self.get(endpoint="gstn_g2b_prod_public")

if response.certificate == self.settings.gstn_public_certificate:
frappe.throw(error_message or _("Public Certificate is already up to date"))

self.settings.db_set("gstn_public_certificate", response.certificate)

return response.certificate
@@ -225,13 +229,16 @@ class ReturnsAPI(ReturnsAuthenticate):
"RET2B1023": "not_generated",
"RET2B1016": "no_docs_found",
"RT-3BAS1009": "no_docs_found",
"RET11417": "no_docs_found", # GSTR-1 Exports
"RET2B1018": "requested_before_cutoff_date",
"RTN_24": "queued",
"AUTH158": "invalid_otp", # Invalid OTP
"AUTH4033": "invalid_otp", # Invalid Session
# "AUTH4034": "invalid_otp", # Invalid OTP
"AUTH4038": "authorization_failed", # Session Expired
"RET11402": "authorization_failed", # API Authorization Failed for 2A
"RET2B1010": "authorization_failed", # API Authorization Failed for 2B
"TEC4002": "invalid_public_key",
}

def setup(self, company_gstin):
@@ -336,6 +343,14 @@ def handle_error_response(self, response):
title=_("API Request Failed"),
)

# Handle invalid public key
if response.error_type == "invalid_public_key":
PublicCertificate().get_gstn_public_certificate(
error_message=_(
"Looks like Public Key of GSTN used for encryption is Invalid"
)
)

def is_ignored_error(self, response):
error_code = response.get("error", {}).get("error_cd")

@@ -396,3 +411,25 @@ def get_data(self, action, return_period, otp=None):
endpoint="returns/gstr2a",
otp=otp,
)


class GSTR1API(ReturnsAPI):
API_NAME = "GSTR-1"

def get_gstr_1_data(self, action, return_period, otp=None):
return self.get(
action,
return_period,
params={"ret_period": return_period},
endpoint="returns/gstr1",
otp=otp,
)

def get_einvoice_data(self, section, return_period, otp=None):
return self.get(
"EINV",
return_period,
params={"ret_period": return_period, "sec": section},
endpoint="returns/einvoice",
otp=otp,
)
43 changes: 15 additions & 28 deletions india_compliance/gst_india/doctype/gst_settings/gst_settings.js
Original file line number Diff line number Diff line change
@@ -51,35 +51,22 @@ function filter_accounts(frm, account_field) {

function show_ic_api_promo(frm) {
if (!frm.doc.__onload?.can_show_promo) return;
const alert_message = `
Looking for API Features?
<a href="/app/india-compliance-account" class="alert-link">
Get started with the India Compliance API!
</a>`;

const alert = $(`
<div
class="alert alert-primary alert-dismissable fade show d-flex justify-content-between border-0"
role="alert"
>
<div>
Looking for API Features?
<a href="/app/india-compliance-account" class="alert-link">
Get started with the India Compliance API!
</a>
</div>
<button
type="button"
class="close"
data-dismiss="alert"
aria-label="Close"
style="outline: 0px solid black !important"
>
<span aria-hidden="true">&times;</span>
</button>
</div>
`).prependTo(frm.layout.wrapper);

alert.on("closed.bs.alert", () => {
frappe.xcall(
"india_compliance.gst_india.doctype.gst_settings.gst_settings.disable_api_promo"
);
});
india_compliance.show_dismissable_alert(
frm.layout.wrapper,
alert_message,
"primary",
() => {
frappe.xcall(
"india_compliance.gst_india.doctype.gst_settings.gst_settings.disable_api_promo"
);
}
);
}

function show_update_gst_category_button(frm) {
Original file line number Diff line number Diff line change
@@ -40,6 +40,12 @@
"column_break_17",
"e_invoice_applicable_from",
"e_invoice_applicable_companies",
"gstr_1_section_break",
"compare_gstr_1_data",
"filing_frequency",
"column_break_cxmn",
"restrict_changes_after_gstr_1",
"role_allowed_to_modify",
"other_apis_section",
"autofill_party_info",
"archive_party_info_days",
@@ -560,12 +566,50 @@
"fieldtype": "Check",
"hidden": 1,
"label": "Is Retry e-Invoice/e-Waybill Pending"
},
{
"fieldname": "gstr_1_section_break",
"fieldtype": "Section Break",
"label": "GSTR-1"
},
{
"fieldname": "column_break_cxmn",
"fieldtype": "Column Break"
},
{
"fieldname": "filing_frequency",
"fieldtype": "Select",
"label": "Filing Frequency",
"options": "Monthly\nQuarterly"
},
{
"depends_on": "eval: doc.restrict_changes_after_gstr_1",
"fieldname": "role_allowed_to_modify",
"fieldtype": "Link",
"label": "Role Allowed to Modify Transactions",
"options": "Role"
},
{
"default": "0",
"depends_on": "eval: india_compliance.is_api_enabled(doc)",
"description": "Prevent any modifications to transactions once they have been reported in GSTR-1",
"fieldname": "restrict_changes_after_gstr_1",
"fieldtype": "Check",
"label": "Restrict Changes to Transactions After Filing"
},
{
"default": "0",
"depends_on": "eval: india_compliance.is_api_enabled(doc)",
"description": "Use APIs to compare records with GST Portal Data Before and After Filing",
"fieldname": "compare_gstr_1_data",
"fieldtype": "Check",
"label": "Compare Data with GST Portal"
}
],
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2024-03-21 19:36:00.878806",
"modified": "2024-06-09 17:27:54.720233",
"modified_by": "Administrator",
"module": "GST India",
"name": "GST Settings",
107 changes: 105 additions & 2 deletions india_compliance/gst_india/doctype/gst_settings/gst_settings.py
Original file line number Diff line number Diff line change
@@ -5,21 +5,21 @@
from frappe import _
from frappe.model.document import Document
from frappe.query_builder.functions import IfNull
from frappe.utils import getdate
from frappe.utils import add_to_date, getdate

from india_compliance.gst_india.constants import GST_ACCOUNT_FIELDS, GST_PARTY_TYPES
from india_compliance.gst_india.constants.custom_fields import (
E_INVOICE_FIELDS,
E_WAYBILL_FIELDS,
SALES_REVERSE_CHARGE_FIELDS,
)
from india_compliance.gst_india.doctype.gstin.gstin import get_gstr_1_filed_upto
from india_compliance.gst_india.page.india_compliance_account import (
_disable_api_promo,
post_login,
)
from india_compliance.gst_india.utils import can_enable_api, is_api_enabled
from india_compliance.gst_india.utils.custom_fields import toggle_custom_fields
from india_compliance.gst_india.utils.e_invoice import get_e_invoice_applicability_date
from india_compliance.gst_india.utils.gstin_info import get_gstin_info

E_INVOICE_START_DATE = "2021-01-01"
@@ -270,6 +270,42 @@ def validate_e_invoice_applicable_companies(self):

company_list.append(row.company)

def is_sek_valid(self, gstin, throw=False, threshold=30):
for credential in self.credentials:
if credential.service == "Returns" and credential.gstin == gstin:
break

else:
if throw:
frappe.throw(
_(
"No credential found for the GSTIN {0} in the GST Settings"
).format(gstin)
)

return False

if credential.session_expiry and credential.session_expiry > add_to_date(
None, minutes=threshold * -1
):
return True

def has_valid_credentials(self, gstin, service, throw=False):
for credential in self.credentials:
if credential.gstin == gstin and credential.service == service:
break
else:
message = _(
"No credential found for the GSTIN {0} in the GST Settings"
).format(gstin)

if throw:
frappe.throw(message)

return False

return True


@frappe.whitelist()
def disable_api_promo():
@@ -345,6 +381,24 @@ def update_e_invoice_status():
update_not_applicable_status(e_invoice_applicability_date, company)


def get_e_invoice_applicability_date(company, settings=None, throw=True):
if not settings:
settings = frappe.get_cached_doc("GST Settings")

e_invoice_applicable_from = settings.e_invoice_applicable_from

if settings.apply_e_invoice_only_for_selected_companies:
for row in settings.e_invoice_applicable_companies:
if company == row.company:
e_invoice_applicable_from = row.applicable_from
break

else:
return

return e_invoice_applicable_from


def update_pending_status(e_invoice_applicability_date, company=None):
if not e_invoice_applicability_date:
return
@@ -394,3 +448,52 @@ def update_not_applicable_status(e_invoice_applicability_date=None, company=None
company = query.where(sales_invoice.company == company)

query.run()


def restrict_gstr_1_transaction_for(posting_date, company_gstin, gst_settings=None):
"""
Check if the user is allowed to modify transactions before the GSTR-1 filing date
Additionally, update the `is_not_latest_gstr1_data` field in the GSTR-1 Log
"""
posting_date = getdate(posting_date)

if not gst_settings:
gst_settings = frappe.get_cached_doc("GST Settings")

restrict = True

if not gst_settings.restrict_changes_after_gstr_1:
restrict = False

gstr_1_filed_upto = get_gstr_1_filed_upto(company_gstin)

if not gstr_1_filed_upto:
return False

if posting_date > getdate(gstr_1_filed_upto):
restrict = False

if (
gst_settings.role_allowed_to_modify in frappe.get_roles()
or frappe.session.user == "Administrator"
):
restrict = False

if restrict:
return gstr_1_filed_upto

update_is_not_latest_gstr1_data(posting_date, company_gstin)

return None


def update_is_not_latest_gstr1_data(posting_date, company_gstin):
period = posting_date.strftime("%m%Y")

frappe.db.set_value("GSTR-1 Log", f"{period}-{company_gstin}", "is_latest_data", 0)

frappe.publish_realtime(
"is_not_latest_data",
message={"filters": {"company_gstin": company_gstin, "period": period}},
doctype="GSTR-1 Beta",
)
16 changes: 14 additions & 2 deletions india_compliance/gst_india/doctype/gstin/gstin.json
Original file line number Diff line number Diff line change
@@ -12,7 +12,9 @@
"is_blocked",
"column_break_nrjd",
"last_updated_on",
"cancelled_date"
"cancelled_date",
"section_break_ttzc",
"gstr_1_filed_upto"
],
"fields": [
{
@@ -59,12 +61,22 @@
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Is Blocked"
},
{
"fieldname": "section_break_ttzc",
"fieldtype": "Section Break"
},
{
"fieldname": "gstr_1_filed_upto",
"fieldtype": "Date",
"hidden": 1,
"label": "GSTR-1 Filed Upto"
}
],
"in_create": 1,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2023-08-17 11:32:42.332746",
"modified": "2024-05-17 15:38:05.867522",
"modified_by": "Administrator",
"module": "GST India",
"name": "GSTIN",
7 changes: 7 additions & 0 deletions india_compliance/gst_india/doctype/gstin/gstin.py
Original file line number Diff line number Diff line change
@@ -304,3 +304,10 @@ def get_transporter_id_info(transporter_id):
"status": "Active" if response.transin else "Invalid",
}
)


def get_gstr_1_filed_upto(gstin):
if not gstin:
return

return frappe.db.get_value("GSTIN", gstin, "gstr_1_filed_upto")
Empty file.
Loading

0 comments on commit 3780b32

Please sign in to comment.