fix(GSTIN Validation - india): added checksum validation for GSTIN
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 9b7edc5..c4bfe91 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -12,8 +12,8 @@
doc.gstin = doc.gstin.upper()
if doc.gstin not in ["NA", "na"]:
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 or Enter NA for Unregistered"))
+ if not p.match(doc.gstin) or doc.gstin != get_gstin_with_check_digit(doc.gstin[:-1]):
+ frappe.throw(_("Invalid GSTIN!! Check for typos or Enter NA for Unregistered"))
if not doc.gst_state:
if doc.state in states:
@@ -25,6 +25,28 @@
frappe.throw(_("First 2 digits of GSTIN should match with State number {0}")
.format(doc.gst_state_number))
+def get_gstin_with_check_digit(gstin_without_check_digit):
+ ''' Function to get the check digit for the gstin.
+
+ param: gstin_without_check_digit
+ return: GSTIN with check digit
+ '''
+ factor = 1
+ total = 0
+ code_point_chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ input_chars = gstin_without_check_digit.strip()
+ if not input_chars:
+ frappe.throw(_("GSTIN supplied for checkdigit calculation is blank"))
+ mod = len(code_point_chars)
+ for char in input_chars:
+ digit = factor * code_point_chars.find(char)
+ if digit < 0:
+ frappe.throw(_("GSTIN supplied for checkdigit contains invalid character"))
+ digit = (digit / mod) + (digit % mod)
+ total += digit
+ factor = 2 if factor == 1 else 1
+ return ''.join([gstin_without_check_digit,code_point_chars[((mod - (total % mod)) % mod)]])
+
def get_itemised_tax_breakup_header(item_doctype, tax_accounts):
if frappe.get_meta(item_doctype).has_field('gst_hsn_code'):
return [_("HSN/SAC"), _("Taxable Amount")] + tax_accounts