fix: GST Validation for UIN and OIDAR (#17866)
* fix: GST Validation for UIN and OIDAR
* fix: Define GST category
* fix: Get gst category only for Customer and Supplier
* fix: GST validation
* fix: GST validation fixes
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 8893cab..19022e1 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -14,6 +14,15 @@
if not hasattr(doc, 'gstin') or not doc.gstin:
return
+ gst_category = []
+
+ if len(doc.links):
+ link_doctype = doc.links[0].get("link_doctype")
+ link_name = doc.links[0].get("link_name")
+
+ if link_doctype in ["Customer", "Supplier"]:
+ gst_category = frappe.db.get_value(link_doctype, {'name': link_name}, ['gst_category'])
+
doc.gstin = doc.gstin.upper().strip()
if not doc.gstin or doc.gstin == 'NA':
return
@@ -21,26 +30,31 @@
if len(doc.gstin) != 15:
frappe.throw(_("Invalid GSTIN! A GSTIN must have 15 characters."))
- p = re.compile("^[0-9]{2}[A-Z]{4}[0-9A-Z]{1}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}[1-9A-Z]{1}[0-9A-Z]{1}$")
- if not p.match(doc.gstin):
- frappe.throw(_("Invalid GSTIN! The input you've entered doesn't match the format of GSTIN."))
+ if gst_category and gst_category == 'UIN Holders':
+ p = re.compile("^[0-9]{4}[A-Z]{3}[0-9]{5}[0-9A-Z]{3}")
+ if not p.match(doc.gstin):
+ frappe.throw(_("Invalid GSTIN! The input you've entered doesn't match the GSTIN format for UIN Holders or Non-Resident OIDAR Service Providers"))
+ else:
+ p = re.compile("^[0-9]{2}[A-Z]{4}[0-9A-Z]{1}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}[1-9A-Z]{1}[0-9A-Z]{1}$")
+ if not p.match(doc.gstin):
+ frappe.throw(_("Invalid GSTIN! The input you've entered doesn't match the format of GSTIN."))
- validate_gstin_check_digit(doc.gstin)
+ validate_gstin_check_digit(doc.gstin)
- if not doc.gst_state:
- if not doc.state:
- return
- state = doc.state.lower()
- states_lowercase = {s.lower():s for s in states}
- if state in states_lowercase:
- doc.gst_state = states_lowercase[state]
- else:
- return
+ if not doc.gst_state:
+ if not doc.state:
+ return
+ state = doc.state.lower()
+ states_lowercase = {s.lower():s for s in states}
+ if state in states_lowercase:
+ doc.gst_state = states_lowercase[state]
+ else:
+ return
- doc.gst_state_number = state_numbers[doc.gst_state]
- if doc.gst_state_number != doc.gstin[:2]:
- frappe.throw(_("Invalid GSTIN! First 2 digits of GSTIN should match with State number {0}.")
- .format(doc.gst_state_number))
+ doc.gst_state_number = state_numbers[doc.gst_state]
+ if doc.gst_state_number != doc.gstin[:2]:
+ frappe.throw(_("Invalid GSTIN! First 2 digits of GSTIN should match with State number {0}.")
+ .format(doc.gst_state_number))
def validate_gstin_check_digit(gstin):
''' Function to validate the check digit of the GSTIN.'''