diff --git a/india_compliance/gst_india/doctype/gst_return_log/gst_return_log.py b/india_compliance/gst_india/doctype/gst_return_log/gst_return_log.py index a0307cfd5d..81f83fd71a 100644 --- a/india_compliance/gst_india/doctype/gst_return_log/gst_return_log.py +++ b/india_compliance/gst_india/doctype/gst_return_log/gst_return_log.py @@ -7,13 +7,21 @@ import frappe from frappe import _ from frappe.model.document import Document -from frappe.utils import get_datetime, get_datetime_str, get_last_day, getdate +from frappe.utils import ( + get_datetime, + get_datetime_str, + get_last_day, + get_link_to_form, + getdate, +) from india_compliance.gst_india.doctype.gst_return_log.generate_gstr_1 import ( GenerateGSTR1, ) from india_compliance.gst_india.utils import is_production_api_enabled +DOCTYPE = "GST Return Log" + class GSTReturnLog(GenerateGSTR1, Document): @property @@ -199,7 +207,7 @@ def process_gstr_1_returns_info(company, gstin, response): # existing logs gstr1_logs = frappe._dict( frappe.get_all( - "GST Return Log", + DOCTYPE, filters={"name": ("in", list(return_info.keys()))}, fields=["name", "acknowledgement_number"], as_list=1, @@ -234,7 +242,7 @@ def _update_gstr_1_filed_upto(filing_date): if key in gstr1_logs: if gstr1_logs[key] != info["arn"]: - frappe.db.set_value("GST Return Log", key, filing_details) + frappe.db.set_value(DOCTYPE, key, filing_details) _update_gstr_1_filed_upto(filed_upto) # No updates if status is same @@ -242,7 +250,7 @@ def _update_gstr_1_filed_upto(filing_date): frappe.get_doc( { - "doctype": "GST Return Log", + "doctype": DOCTYPE, "company": company, "gstin": gstin, "return_period": info["ret_prd"], @@ -252,6 +260,36 @@ def _update_gstr_1_filed_upto(filing_date): _update_gstr_1_filed_upto(filed_upto) +def get_gst_return_log(posting_date, company_gstin): + period = getdate(posting_date).strftime("%m%Y") + if name := frappe.db.exists(DOCTYPE, f"GSTR1-{period}-{company_gstin}"): + return frappe.get_doc(DOCTYPE, name) + + +def add_comment_to_gst_return_log(doc, action): + if not (log := get_gst_return_log(doc.posting_date, doc.company_gstin)): + return + + log.add_comment( + "Comment", + f"{doc.doctype} : {get_link_to_form(doc.doctype, doc.name)} has been {action} by {frappe.session.user}", + ) + + +def update_is_not_latest_gstr1_data(posting_date, company_gstin): + period = posting_date.strftime("%m%Y") + + frappe.db.set_value( + "GST Return Log", f"GSTR1-{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", + ) + + def get_file_doc(doctype, docname, attached_to_field): try: return frappe.get_doc( diff --git a/india_compliance/gst_india/doctype/gst_settings/gst_settings.py b/india_compliance/gst_india/doctype/gst_settings/gst_settings.py index 4f98e12359..1a33228410 100644 --- a/india_compliance/gst_india/doctype/gst_settings/gst_settings.py +++ b/india_compliance/gst_india/doctype/gst_settings/gst_settings.py @@ -13,6 +13,10 @@ E_WAYBILL_FIELDS, SALES_REVERSE_CHARGE_FIELDS, ) +from india_compliance.gst_india.doctype.gst_return_log.gst_return_log import ( + add_comment_to_gst_return_log, + update_is_not_latest_gstr1_data, +) 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, @@ -496,12 +500,12 @@ def update_not_applicable_status(e_invoice_applicability_date=None, company=None query.run() -def restrict_gstr_1_transaction_for(posting_date, company_gstin, gst_settings=None): +def restrict_gstr_1_transaction_for(doc, gst_settings=None, action="submit"): """ 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 GST Return Log """ - posting_date = getdate(posting_date) + posting_date = getdate(doc.posting_date) if not gst_settings: gst_settings = frappe.get_cached_doc("GST Settings") @@ -511,7 +515,7 @@ def restrict_gstr_1_transaction_for(posting_date, company_gstin, gst_settings=No if not gst_settings.restrict_changes_after_gstr_1: restrict = False - gstr_1_filed_upto = get_gstr_1_filed_upto(company_gstin) + gstr_1_filed_upto = get_gstr_1_filed_upto(doc.company_gstin) if not gstr_1_filed_upto: restrict = False @@ -528,20 +532,8 @@ def restrict_gstr_1_transaction_for(posting_date, company_gstin, gst_settings=No 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") + # postprocess + update_is_not_latest_gstr1_data(posting_date, doc.company_gstin) - frappe.db.set_value( - "GST Return Log", f"GSTR1-{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", - ) + if posting_date <= getdate(gstr_1_filed_upto): + add_comment_to_gst_return_log(doc, action) diff --git a/india_compliance/gst_india/overrides/payment_entry.py b/india_compliance/gst_india/overrides/payment_entry.py index c847a25ccd..b3dc948061 100644 --- a/india_compliance/gst_india/overrides/payment_entry.py +++ b/india_compliance/gst_india/overrides/payment_entry.py @@ -83,8 +83,6 @@ def validate(doc, method=None): return if doc.party_type == "Customer": - validate_backdated_transaction(doc) - # Presume is export with GST if GST accounts are present doc.is_export_with_gst = 1 validate_transaction_for_advance_payment(doc, method) @@ -98,6 +96,9 @@ def validate(doc, method=None): def on_submit(doc, method=None): + if doc.party_type == "Customer": + validate_backdated_transaction(doc) + make_gst_revesal_entry_from_advance_payment(doc) @@ -112,7 +113,7 @@ def before_cancel(doc, method=None): validate_backdated_transaction(doc, action="cancel") -def validate_backdated_transaction(doc, action="create"): +def validate_backdated_transaction(doc, action="submit"): for row in doc.taxes: if row.gst_tax_type in TAX_TYPES and row.tax_amount != 0: _validate_backdated_transaction(doc, action=action) diff --git a/india_compliance/gst_india/overrides/sales_invoice.py b/india_compliance/gst_india/overrides/sales_invoice.py index 1c02e333ea..e4e7fa1ae2 100644 --- a/india_compliance/gst_india/overrides/sales_invoice.py +++ b/india_compliance/gst_india/overrides/sales_invoice.py @@ -58,7 +58,6 @@ def validate(doc, method=None): gst_settings = frappe.get_cached_doc("GST Settings") - validate_backdated_transaction(doc, gst_settings) validate_invoice_number(doc) validate_credit_debit_note(doc) validate_fields_and_set_status_for_e_invoice(doc, gst_settings) @@ -139,6 +138,8 @@ def is_shipping_address_in_india(doc): def on_submit(doc, method=None): + validate_backdated_transaction(doc) + if getattr(doc, "_submitted_from_ui", None) or validate_transaction(doc) is False: return diff --git a/india_compliance/gst_india/overrides/test_transaction.py b/india_compliance/gst_india/overrides/test_transaction.py index 8a2f82c991..44cd549ade 100644 --- a/india_compliance/gst_india/overrides/test_transaction.py +++ b/india_compliance/gst_india/overrides/test_transaction.py @@ -5,7 +5,7 @@ import frappe from frappe.tests import IntegrationTestCase, change_settings -from frappe.utils import today +from frappe.utils import add_days, getdate, today from erpnext.accounts.doctype.purchase_invoice.purchase_invoice import ( make_regional_gl_entries, ) @@ -958,6 +958,10 @@ def get_lead(first_name): class TestSpecificTransactions(IntegrationTestCase): + @classmethod + def tearDown(cls): + frappe.db.rollback() + def test_copy_e_waybill_fields_from_dn_to_si(self): "Make sure e-Waybill fields are copied from Delivery Note to Sales Invoice" dn = create_transaction(doctype="Delivery Note", vehicle_no="GJ01AA1111") @@ -972,6 +976,63 @@ def test_copy_e_waybill_fields_from_si_to_return(self): self.assertEqual(si_return.vehicle_no, None) + @change_settings("GST Settings", {"restrict_changes_after_gstr_1": 1}) + def test_backdated_transaction(self): + si = create_transaction(doctype="Sales Invoice", do_not_submit=True) + + # update filing date + gstin_doc = frappe.new_doc( + "GSTIN", + gstin=si.company_gstin, + status="Active", + gstr_1_filed_upto=add_days(today(), 1), + ) + gstin_doc.save(ignore_permissions=True) + + # create user + test_user = frappe.get_doc("User", {"email": "test@example.com"}) + test_user.add_roles("Accounts User") + frappe.set_user(test_user.name) + + # submit invoice + self.assertRaisesRegex( + frappe.exceptions.ValidationError, + re.compile(r"You are not allowed to submit Sales Invoice"), + si.submit, + ) + + def test_backdated_transaction_with_comment(self): + si = create_transaction(doctype="Sales Invoice", do_not_submit=True) + + # create filing log + posting_date = getdate(si.posting_date) + gst_return_log = frappe.new_doc( + "GST Return Log", + return_period=f"{posting_date.month:02d}{posting_date.year}", + gstin=si.company_gstin, + return_type="GSTR1", + ) + gst_return_log.save() + + # update filing date + gstin_doc = frappe.new_doc( + "GSTIN", + gstin=si.company_gstin, + status="Active", + gstr_1_filed_upto=add_days(today(), 1), + ) + gstin_doc.save(ignore_permissions=True) + + # submit invoice + si.submit() + + comment = frappe.get_value( + "Comment", + {"comment_type": "Comment", "reference_name": gst_return_log.name}, + ["content"], + ) + self.assertTrue(si.name in comment) + def create_cess_accounts(): input_cess_non_advol_account = create_tax_accounts("Input Tax Cess Non Advol") diff --git a/india_compliance/gst_india/overrides/transaction.py b/india_compliance/gst_india/overrides/transaction.py index bc96e87aa6..c906c06ed0 100644 --- a/india_compliance/gst_india/overrides/transaction.py +++ b/india_compliance/gst_india/overrides/transaction.py @@ -660,10 +660,8 @@ def get_source_state_code(doc): return (doc.supplier_gstin or doc.company_gstin)[:2] -def validate_backdated_transaction(doc, gst_settings=None, action="create"): - if gstr_1_filed_upto := restrict_gstr_1_transaction_for( - doc.posting_date, doc.company_gstin, gst_settings - ): +def validate_backdated_transaction(doc, gst_settings=None, action="submit"): + if gstr_1_filed_upto := restrict_gstr_1_transaction_for(doc, gst_settings, action): frappe.throw( _( "You are not allowed to {0} {1} as GSTR-1 has been filed upto {2}"