| Line 183... |
Line 183... |
| 183 |
result = false;
|
183 |
result = false;
|
| 184 |
}
|
184 |
}
|
| 185 |
return result;
|
185 |
return result;
|
| 186 |
}
|
186 |
}
|
| 187 |
|
187 |
|
| - |
|
188 |
/** Characters of a GSTIN, in the order the checksum weights them. */
|
| - |
|
189 |
private static final String GSTIN_ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
| - |
|
190 |
|
| - |
|
191 |
/**
|
| - |
|
192 |
* 2-digit state code, 10-char PAN (5 letters, 4 digits, 1 letter), entity number,
|
| - |
|
193 |
* the literal Z, then the checksum character.
|
| - |
|
194 |
*/
|
| - |
|
195 |
private static final java.util.regex.Pattern GSTIN_PATTERN =
|
| - |
|
196 |
java.util.regex.Pattern.compile("^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z][1-9A-Z]Z[0-9A-Z]$");
|
| - |
|
197 |
|
| - |
|
198 |
/** State codes issued by GSTN: 01-38, plus 97 (other territory) and 99 (centre). */
|
| - |
|
199 |
private static final java.util.regex.Pattern GSTIN_STATE_CODE =
|
| - |
|
200 |
java.util.regex.Pattern.compile("^(0[1-9]|[12][0-9]|3[0-8]|97|99)$");
|
| - |
|
201 |
|
| - |
|
202 |
/**
|
| - |
|
203 |
* Whether a GSTIN is well formed: shape, a real state code, and the mod-36 checksum in the
|
| - |
|
204 |
* 15th character. A blank is still allowed - the field is optional for stores that have no
|
| - |
|
205 |
* registration - so callers that need one present must check for that themselves.
|
| - |
|
206 |
* <p>
|
| - |
|
207 |
* It used to accept any 15-character string, which let a pincode ({@code 110095}, rejected
|
| - |
|
208 |
* only for being 6 characters) and outright junk ({@code Hdjiekwbdbsjskz}) reach
|
| - |
|
209 |
* fofo_store.gst_number, where billing reads it. NIC then rejects the invoice and the goods
|
| - |
|
210 |
* cannot ship. The checksum is worth having on top of the shape: of 1,570 well-formed
|
| - |
|
211 |
* partner GSTINs on record exactly one fails it, so it costs nothing and catches the
|
| - |
|
212 |
* transposed or O-for-0 typo that the pattern alone cannot see.
|
| - |
|
213 |
*/
|
| 188 |
public static boolean isValidGstNumber(String gstNumber) {
|
214 |
public static boolean isValidGstNumber(String gstNumber) {
|
| 189 |
if(gstNumber == null || gstNumber.isEmpty() || gstNumber.length() == 15) {
|
215 |
if(gstNumber == null || gstNumber.trim().isEmpty()) {
|
| 190 |
return true;
|
216 |
return true;
|
| 191 |
}
|
217 |
}
|
| - |
|
218 |
String gstin = normalizeGstNumber(gstNumber);
|
| - |
|
219 |
if(!GSTIN_PATTERN.matcher(gstin).matches()) {
|
| 192 |
return false;
|
220 |
return false;
|
| - |
|
221 |
}
|
| - |
|
222 |
if(!GSTIN_STATE_CODE.matcher(gstin.substring(0, 2)).matches()) {
|
| - |
|
223 |
return false;
|
| - |
|
224 |
}
|
| - |
|
225 |
return gstin.charAt(14) == gstinChecksum(gstin);
|
| - |
|
226 |
}
|
| - |
|
227 |
|
| - |
|
228 |
/** Trimmed and upper-cased, so the same registration is never stored two ways. */
|
| - |
|
229 |
public static String normalizeGstNumber(String gstNumber) {
|
| - |
|
230 |
return gstNumber == null ? null : gstNumber.trim().toUpperCase();
|
| - |
|
231 |
}
|
| - |
|
232 |
|
| - |
|
233 |
/**
|
| - |
|
234 |
* GSTN's mod-36 check character over the first 14 characters: each is weighted 1, 2, 1, 2 ...
|
| - |
|
235 |
* and the two digits of each product are added separately before the total is complemented.
|
| - |
|
236 |
*/
|
| - |
|
237 |
private static char gstinChecksum(String gstin) {
|
| - |
|
238 |
int total = 0;
|
| - |
|
239 |
for(int i = 0; i < 14; i++) {
|
| - |
|
240 |
int product = GSTIN_ALPHABET.indexOf(gstin.charAt(i)) * (i % 2 == 0 ? 1 : 2);
|
| - |
|
241 |
total += product / 36 + product % 36;
|
| - |
|
242 |
}
|
| - |
|
243 |
return GSTIN_ALPHABET.charAt((36 - total % 36) % 36);
|
| 193 |
}
|
244 |
}
|
| 194 |
|
245 |
|
| 195 |
public static List<String> getDuplicateElements(List<String> elements){
|
246 |
public static List<String> getDuplicateElements(List<String> elements){
|
| 196 |
List<String> duplicates = new ArrayList<>();
|
247 |
List<String> duplicates = new ArrayList<>();
|
| 197 |
for(int i = 0; i < elements.size(); i++){
|
248 |
for(int i = 0; i < elements.size(); i++){
|