@ibiliaze/stringman 3.7.0 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +6 -8
- package/dist/index.js +15 -0
- package/dist/seat.d.ts +9 -0
- package/dist/seat.js +13 -0
- package/dist/ticket.d.ts +16 -8
- package/dist/ticket.js +83 -46
- package/package.json +2 -2
- package/src/index.ts +1 -0
- package/src/seat.ts +10 -0
- package/src/ticket.ts +80 -49
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export * from './seat';
|
|
1
2
|
/**
|
|
2
3
|
* Clean up extra whitespace in a string.
|
|
3
4
|
*
|
|
@@ -142,11 +143,7 @@ export declare const invalidPw: (password: string, passwordLength?: number) => s
|
|
|
142
143
|
export declare const b36: (n: number) => string;
|
|
143
144
|
export declare const luhn36: (s: string) => string;
|
|
144
145
|
export declare const ticket: {
|
|
145
|
-
getTicketId:
|
|
146
|
-
fixtureId: string;
|
|
147
|
-
sectionName: string;
|
|
148
|
-
seatName: string;
|
|
149
|
-
}) => string;
|
|
146
|
+
getTicketId: any;
|
|
150
147
|
buildTicketCode: (args: {
|
|
151
148
|
venueCode: string;
|
|
152
149
|
fixtureLocalIso: string;
|
|
@@ -154,9 +151,10 @@ export declare const ticket: {
|
|
|
154
151
|
row: number;
|
|
155
152
|
col: number;
|
|
156
153
|
rndLen?: number;
|
|
154
|
+
dashed?: boolean;
|
|
157
155
|
}) => string;
|
|
158
156
|
validateTicketCode: (code: string) => boolean;
|
|
159
|
-
rndBlock:
|
|
160
|
-
fixtureBlock:
|
|
161
|
-
seatBlock:
|
|
157
|
+
rndBlock: any;
|
|
158
|
+
fixtureBlock: any;
|
|
159
|
+
seatBlock: any;
|
|
162
160
|
};
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
17
|
exports.ticket = exports.luhn36 = exports.b36 = exports.invalidPw = exports.getPublicIP = exports.isVideoUrl = exports.getRandomString = exports.extractImageSrcs = exports.select = exports.query = exports.getCloudinaryPublicId = exports.dp = exports.megaTrim = exports.superTrim = void 0;
|
|
18
|
+
__exportStar(require("./seat"), exports);
|
|
4
19
|
const ticket_1 = require("./ticket");
|
|
5
20
|
/**
|
|
6
21
|
* Clean up extra whitespace in a string.
|
package/dist/seat.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const getSeatRowFromName: (seatName: string) => string;
|
|
2
|
+
export declare const getSeatColFromName: (seatName: string) => string;
|
|
3
|
+
export declare const seatMapKey: (row: number, col: number) => string;
|
|
4
|
+
export declare const getItemId: (fixtureId: string, sectionId: string, seatId: string) => string;
|
|
5
|
+
export declare const getFromItemId: (itemId: string) => {
|
|
6
|
+
fixtureId: string;
|
|
7
|
+
sectionId: string;
|
|
8
|
+
seatId: string;
|
|
9
|
+
};
|
package/dist/seat.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getFromItemId = exports.getItemId = exports.seatMapKey = exports.getSeatColFromName = exports.getSeatRowFromName = void 0;
|
|
4
|
+
const getSeatRowFromName = (seatName) => seatName?.split(':')?.[0];
|
|
5
|
+
exports.getSeatRowFromName = getSeatRowFromName;
|
|
6
|
+
const getSeatColFromName = (seatName) => seatName?.split(':')?.[1];
|
|
7
|
+
exports.getSeatColFromName = getSeatColFromName;
|
|
8
|
+
const seatMapKey = (row, col) => `${row}:${col}`;
|
|
9
|
+
exports.seatMapKey = seatMapKey;
|
|
10
|
+
const getItemId = (fixtureId, sectionId, seatId) => JSON.stringify({ fixtureId, sectionId, seatId });
|
|
11
|
+
exports.getItemId = getItemId;
|
|
12
|
+
const getFromItemId = (itemId) => JSON.parse(itemId);
|
|
13
|
+
exports.getFromItemId = getFromItemId;
|
package/dist/ticket.d.ts
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
export declare const
|
|
2
|
-
export declare const
|
|
3
|
-
export declare const
|
|
1
|
+
export declare const luhn10: (digits: string) => string;
|
|
2
|
+
export declare const venueBlockNum: (venueCode: string, len?: number) => string;
|
|
3
|
+
export declare const seatBlockNum: (sectionId: string, row: number, col: number, len?: number) => string;
|
|
4
|
+
export declare const fixtureBlockNum: (fixtureLocalIso: string, len?: number) => string;
|
|
5
|
+
export declare const rndBlockNum: (len?: number) => string;
|
|
6
|
+
export declare const buildTicketCodeNumeric: (args: {
|
|
7
|
+
venueCode: string;
|
|
8
|
+
fixtureLocalIso: string;
|
|
9
|
+
sectionId: string;
|
|
10
|
+
row: number;
|
|
11
|
+
col: number;
|
|
12
|
+
rndLen?: number;
|
|
13
|
+
dashed?: boolean;
|
|
14
|
+
}) => string;
|
|
15
|
+
export declare const validateTicketCodeNumeric: (code: string) => boolean;
|
|
4
16
|
export declare const buildTicketCode: (args: {
|
|
5
17
|
venueCode: string;
|
|
6
18
|
fixtureLocalIso: string;
|
|
@@ -8,10 +20,6 @@ export declare const buildTicketCode: (args: {
|
|
|
8
20
|
row: number;
|
|
9
21
|
col: number;
|
|
10
22
|
rndLen?: number;
|
|
23
|
+
dashed?: boolean;
|
|
11
24
|
}) => string;
|
|
12
25
|
export declare const validateTicketCode: (code: string) => boolean;
|
|
13
|
-
export declare const getTicketId: ({ fixtureId, sectionName, seatName, }: {
|
|
14
|
-
fixtureId: string;
|
|
15
|
-
sectionName: string;
|
|
16
|
-
seatName: string;
|
|
17
|
-
}) => string;
|
package/dist/ticket.js
CHANGED
|
@@ -1,78 +1,115 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.validateTicketCode = exports.buildTicketCode = exports.validateTicketCodeNumeric = exports.buildTicketCodeNumeric = exports.rndBlockNum = exports.fixtureBlockNum = exports.seatBlockNum = exports.venueBlockNum = exports.luhn10 = void 0;
|
|
4
4
|
const node_crypto_1 = require("node:crypto");
|
|
5
|
-
|
|
6
|
-
const
|
|
5
|
+
// ---------- helpers ----------
|
|
6
|
+
const pad = (n, len) => n.toString().padStart(len, '0');
|
|
7
|
+
// Luhn mod-10 for digits
|
|
8
|
+
const luhn10 = (digits) => {
|
|
9
|
+
let sum = 0;
|
|
10
|
+
let dbl = false;
|
|
11
|
+
for (let i = digits.length - 1; i >= 0; i--) {
|
|
12
|
+
let d = digits.charCodeAt(i) - 48; // '0' -> 48
|
|
13
|
+
if (dbl) {
|
|
14
|
+
d *= 2;
|
|
15
|
+
if (d > 9)
|
|
16
|
+
d -= 9;
|
|
17
|
+
}
|
|
18
|
+
sum += d;
|
|
19
|
+
dbl = !dbl;
|
|
20
|
+
}
|
|
21
|
+
const check = (10 - (sum % 10)) % 10;
|
|
22
|
+
return String(check);
|
|
23
|
+
};
|
|
24
|
+
exports.luhn10 = luhn10;
|
|
25
|
+
// ---------- numeric blocks ----------
|
|
26
|
+
const venueBlockNum = (venueCode, len = 2) => {
|
|
7
27
|
try {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const n = (h[0] << 8) | h[1];
|
|
11
|
-
|
|
12
|
-
return code.slice(-len);
|
|
28
|
+
// Small, stable hash of the code -> 0..(10^len - 1)
|
|
29
|
+
const h = (0, node_crypto_1.createHash)('sha1').update(venueCode.toUpperCase()).digest(); // 20 bytes
|
|
30
|
+
const n = ((h[0] << 8) | h[1]) % 10 ** len;
|
|
31
|
+
return pad(n, len);
|
|
13
32
|
}
|
|
14
|
-
catch
|
|
15
|
-
return '';
|
|
33
|
+
catch {
|
|
34
|
+
return ''.padStart(len, '0');
|
|
16
35
|
}
|
|
17
36
|
};
|
|
18
|
-
exports.
|
|
19
|
-
|
|
20
|
-
const fixtureBlock = (fixtureLocalIso) => {
|
|
37
|
+
exports.venueBlockNum = venueBlockNum;
|
|
38
|
+
const seatBlockNum = (sectionId, row, col, len = 3) => {
|
|
21
39
|
try {
|
|
22
|
-
//
|
|
40
|
+
// Hash -> 16-bit -> modulo 10^len
|
|
41
|
+
const h = (0, node_crypto_1.createHash)('sha1').update(`${sectionId}:${row}:${col}`).digest();
|
|
42
|
+
const n16 = (h[0] << 8) | h[1];
|
|
43
|
+
const n = n16 % 10 ** len;
|
|
44
|
+
return pad(n, len);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return ''.padStart(len, '0');
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
exports.seatBlockNum = seatBlockNum;
|
|
51
|
+
const fixtureBlockNum = (fixtureLocalIso, len = 6) => {
|
|
52
|
+
try {
|
|
53
|
+
// Expect "YYYY-MM-DDThh:mm" (local, no Z).
|
|
23
54
|
const m = fixtureLocalIso.match(/^(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2})/);
|
|
24
55
|
if (!m)
|
|
25
56
|
throw new Error('Bad fixtureLocalIso');
|
|
26
57
|
const [_, y, M, d, h, mnt] = m;
|
|
27
|
-
|
|
28
|
-
|
|
58
|
+
// YYMMDDhhmm is 10 digits; compress to len digits via mod 10^len.
|
|
59
|
+
const compact = Number(`${y.slice(2)}${M}${d}${h}${mnt}`); // e.g. 2510312000
|
|
60
|
+
const n = compact % 10 ** len;
|
|
61
|
+
return pad(n, len);
|
|
29
62
|
}
|
|
30
|
-
catch
|
|
31
|
-
return '';
|
|
63
|
+
catch {
|
|
64
|
+
return ''.padStart(len, '0');
|
|
32
65
|
}
|
|
33
66
|
};
|
|
34
|
-
exports.
|
|
35
|
-
|
|
36
|
-
const rndBlock = (len = 3) => {
|
|
67
|
+
exports.fixtureBlockNum = fixtureBlockNum;
|
|
68
|
+
const rndBlockNum = (len = 3) => {
|
|
37
69
|
try {
|
|
38
|
-
//
|
|
39
|
-
const
|
|
40
|
-
return (0,
|
|
70
|
+
// Uniform cryptographic integer in [0, 10^len)
|
|
71
|
+
const max = 10 ** len;
|
|
72
|
+
return pad((0, node_crypto_1.randomInt)(0, max), len);
|
|
41
73
|
}
|
|
42
|
-
catch
|
|
43
|
-
return '';
|
|
74
|
+
catch {
|
|
75
|
+
return ''.padStart(len, '0');
|
|
44
76
|
}
|
|
45
77
|
};
|
|
46
|
-
exports.
|
|
47
|
-
|
|
78
|
+
exports.rndBlockNum = rndBlockNum;
|
|
79
|
+
// ---------- builder & validator (numeric-only) ----------
|
|
80
|
+
const buildTicketCodeNumeric = (args) => {
|
|
48
81
|
try {
|
|
49
|
-
const VV = args.venueCode
|
|
50
|
-
const E = (0, exports.
|
|
51
|
-
const S = (0, exports.
|
|
52
|
-
const R = (0, exports.
|
|
53
|
-
const body = `${VV}${E}${S}${R}`;
|
|
54
|
-
const C = (0,
|
|
55
|
-
|
|
82
|
+
const VV = (0, exports.venueBlockNum)(args.venueCode, 2); // 2 digits
|
|
83
|
+
const E = (0, exports.fixtureBlockNum)(args.fixtureLocalIso, 6); // 6 digits
|
|
84
|
+
const S = (0, exports.seatBlockNum)(args.sectionId, args.row, args.col); // 3 digits
|
|
85
|
+
const R = (0, exports.rndBlockNum)(args.rndLen ?? 3); // 3 digits
|
|
86
|
+
const body = `${VV}${E}${S}${R}`; // 14 digits
|
|
87
|
+
const C = (0, exports.luhn10)(body); // 1 digit
|
|
88
|
+
const numeric = `${body}${C}`; // 15 digits total
|
|
89
|
+
if (args.dashed === false)
|
|
90
|
+
return numeric;
|
|
91
|
+
// Grouping 2-6-3-3-1 for readability
|
|
56
92
|
return `${VV}-${E}-${S}-${R}-${C}`;
|
|
57
93
|
}
|
|
58
|
-
catch
|
|
94
|
+
catch {
|
|
59
95
|
return '';
|
|
60
96
|
}
|
|
61
97
|
};
|
|
62
|
-
exports.
|
|
63
|
-
const
|
|
98
|
+
exports.buildTicketCodeNumeric = buildTicketCodeNumeric;
|
|
99
|
+
const validateTicketCodeNumeric = (code) => {
|
|
64
100
|
try {
|
|
65
|
-
const clean = code.replace(/-/g, '')
|
|
66
|
-
if (
|
|
67
|
-
return false;
|
|
101
|
+
const clean = code.replace(/-/g, '');
|
|
102
|
+
if (!/^\d{15}$/.test(clean))
|
|
103
|
+
return false; // 2+6+3+3+1
|
|
68
104
|
const body = clean.slice(0, -1);
|
|
69
105
|
const check = clean.slice(-1);
|
|
70
|
-
return (0,
|
|
106
|
+
return (0, exports.luhn10)(body) === check;
|
|
71
107
|
}
|
|
72
|
-
catch
|
|
108
|
+
catch {
|
|
73
109
|
return false;
|
|
74
110
|
}
|
|
75
111
|
};
|
|
76
|
-
exports.
|
|
77
|
-
|
|
78
|
-
exports.
|
|
112
|
+
exports.validateTicketCodeNumeric = validateTicketCodeNumeric;
|
|
113
|
+
// ---------- compatibility shim (if you want same names as before) ----------
|
|
114
|
+
exports.buildTicketCode = exports.buildTicketCodeNumeric;
|
|
115
|
+
exports.validateTicketCode = exports.validateTicketCodeNumeric;
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ibiliaze/stringman",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.9.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"build": "tsc",
|
|
9
9
|
"pub": "npm publish --access public",
|
|
10
|
-
"git": "git add .; git commit -m 'changes'; git tag -a v3.
|
|
10
|
+
"git": "git add .; git commit -m 'changes'; git tag -a v3.9.0 -m 'v3.9.0'; git push origin v3.9.0; git push",
|
|
11
11
|
"push": "npm run build; npm run git; npm run pub"
|
|
12
12
|
},
|
|
13
13
|
"author": "Ibi Hasanli",
|
package/src/index.ts
CHANGED
package/src/seat.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const getSeatRowFromName = (seatName: string) => seatName?.split(':')?.[0];
|
|
2
|
+
export const getSeatColFromName = (seatName: string) => seatName?.split(':')?.[1];
|
|
3
|
+
|
|
4
|
+
export const seatMapKey = (row: number, col: number) => `${row}:${col}`;
|
|
5
|
+
|
|
6
|
+
export const getItemId = (fixtureId: string, sectionId: string, seatId: string) =>
|
|
7
|
+
JSON.stringify({ fixtureId, sectionId, seatId });
|
|
8
|
+
|
|
9
|
+
export const getFromItemId = (itemId: string): { fixtureId: string; sectionId: string; seatId: string } =>
|
|
10
|
+
JSON.parse(itemId);
|
package/src/ticket.ts
CHANGED
|
@@ -1,83 +1,114 @@
|
|
|
1
|
-
import { createHash,
|
|
2
|
-
import { b36, luhn36 } from '.';
|
|
1
|
+
import { createHash, randomInt } from 'node:crypto';
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
// ---------- helpers ----------
|
|
4
|
+
const pad = (n: number, len: number) => n.toString().padStart(len, '0');
|
|
5
|
+
|
|
6
|
+
// Luhn mod-10 for digits
|
|
7
|
+
export const luhn10 = (digits: string): string => {
|
|
8
|
+
let sum = 0;
|
|
9
|
+
let dbl = false;
|
|
10
|
+
for (let i = digits.length - 1; i >= 0; i--) {
|
|
11
|
+
let d = digits.charCodeAt(i) - 48; // '0' -> 48
|
|
12
|
+
if (dbl) {
|
|
13
|
+
d *= 2;
|
|
14
|
+
if (d > 9) d -= 9;
|
|
15
|
+
}
|
|
16
|
+
sum += d;
|
|
17
|
+
dbl = !dbl;
|
|
18
|
+
}
|
|
19
|
+
const check = (10 - (sum % 10)) % 10;
|
|
20
|
+
return String(check);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// ---------- numeric blocks ----------
|
|
24
|
+
export const venueBlockNum = (venueCode: string, len = 2) => {
|
|
5
25
|
try {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const n = (h[0] << 8) | h[1];
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return '';
|
|
26
|
+
// Small, stable hash of the code -> 0..(10^len - 1)
|
|
27
|
+
const h = createHash('sha1').update(venueCode.toUpperCase()).digest(); // 20 bytes
|
|
28
|
+
const n = ((h[0] << 8) | h[1]) % 10 ** len;
|
|
29
|
+
return pad(n, len);
|
|
30
|
+
} catch {
|
|
31
|
+
return ''.padStart(len, '0');
|
|
13
32
|
}
|
|
14
33
|
};
|
|
15
34
|
|
|
16
|
-
|
|
17
|
-
export const fixtureBlock = (fixtureLocalIso: string) => {
|
|
35
|
+
export const seatBlockNum = (sectionId: string, row: number, col: number, len = 3) => {
|
|
18
36
|
try {
|
|
19
|
-
//
|
|
37
|
+
// Hash -> 16-bit -> modulo 10^len
|
|
38
|
+
const h = createHash('sha1').update(`${sectionId}:${row}:${col}`).digest();
|
|
39
|
+
const n16 = (h[0] << 8) | h[1];
|
|
40
|
+
const n = n16 % 10 ** len;
|
|
41
|
+
return pad(n, len);
|
|
42
|
+
} catch {
|
|
43
|
+
return ''.padStart(len, '0');
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const fixtureBlockNum = (fixtureLocalIso: string, len = 6) => {
|
|
48
|
+
try {
|
|
49
|
+
// Expect "YYYY-MM-DDThh:mm" (local, no Z).
|
|
20
50
|
const m = fixtureLocalIso.match(/^(\d{4})-(\d{2})-(\d{2})[T ](\d{2}):(\d{2})/);
|
|
21
51
|
if (!m) throw new Error('Bad fixtureLocalIso');
|
|
22
52
|
const [_, y, M, d, h, mnt] = m;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return
|
|
53
|
+
// YYMMDDhhmm is 10 digits; compress to len digits via mod 10^len.
|
|
54
|
+
const compact = Number(`${y.slice(2)}${M}${d}${h}${mnt}`); // e.g. 2510312000
|
|
55
|
+
const n = compact % 10 ** len;
|
|
56
|
+
return pad(n, len);
|
|
57
|
+
} catch {
|
|
58
|
+
return ''.padStart(len, '0');
|
|
27
59
|
}
|
|
28
60
|
};
|
|
29
61
|
|
|
30
|
-
|
|
31
|
-
export const rndBlock = (len = 3) => {
|
|
62
|
+
export const rndBlockNum = (len = 3) => {
|
|
32
63
|
try {
|
|
33
|
-
//
|
|
34
|
-
const
|
|
35
|
-
return
|
|
36
|
-
} catch
|
|
37
|
-
return '';
|
|
64
|
+
// Uniform cryptographic integer in [0, 10^len)
|
|
65
|
+
const max = 10 ** len;
|
|
66
|
+
return pad(randomInt(0, max), len);
|
|
67
|
+
} catch {
|
|
68
|
+
return ''.padStart(len, '0');
|
|
38
69
|
}
|
|
39
70
|
};
|
|
40
71
|
|
|
41
|
-
|
|
42
|
-
|
|
72
|
+
// ---------- builder & validator (numeric-only) ----------
|
|
73
|
+
export const buildTicketCodeNumeric = (args: {
|
|
74
|
+
venueCode: string; // e.g. "SB"
|
|
43
75
|
fixtureLocalIso: string; // "2025-10-31T20:00" in venue TZ
|
|
44
76
|
sectionId: string;
|
|
45
77
|
row: number;
|
|
46
78
|
col: number;
|
|
47
|
-
rndLen?: number; // 3
|
|
79
|
+
rndLen?: number; // default 3 (use 4 if you want more entropy)
|
|
80
|
+
dashed?: boolean; // default true (format with dashes)
|
|
48
81
|
}) => {
|
|
49
82
|
try {
|
|
50
|
-
const VV = args.venueCode
|
|
51
|
-
const E =
|
|
52
|
-
const S =
|
|
53
|
-
const R =
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
83
|
+
const VV = venueBlockNum(args.venueCode, 2); // 2 digits
|
|
84
|
+
const E = fixtureBlockNum(args.fixtureLocalIso, 6); // 6 digits
|
|
85
|
+
const S = seatBlockNum(args.sectionId, args.row, args.col); // 3 digits
|
|
86
|
+
const R = rndBlockNum(args.rndLen ?? 3); // 3 digits
|
|
87
|
+
|
|
88
|
+
const body = `${VV}${E}${S}${R}`; // 14 digits
|
|
89
|
+
const C = luhn10(body); // 1 digit
|
|
90
|
+
const numeric = `${body}${C}`; // 15 digits total
|
|
91
|
+
|
|
92
|
+
if (args.dashed === false) return numeric;
|
|
93
|
+
// Grouping 2-6-3-3-1 for readability
|
|
57
94
|
return `${VV}-${E}-${S}-${R}-${C}`;
|
|
58
|
-
} catch
|
|
95
|
+
} catch {
|
|
59
96
|
return '';
|
|
60
97
|
}
|
|
61
98
|
};
|
|
62
99
|
|
|
63
|
-
export const
|
|
100
|
+
export const validateTicketCodeNumeric = (code: string) => {
|
|
64
101
|
try {
|
|
65
|
-
const clean = code.replace(/-/g, '')
|
|
66
|
-
if (
|
|
102
|
+
const clean = code.replace(/-/g, '');
|
|
103
|
+
if (!/^\d{15}$/.test(clean)) return false; // 2+6+3+3+1
|
|
67
104
|
const body = clean.slice(0, -1);
|
|
68
105
|
const check = clean.slice(-1);
|
|
69
|
-
return
|
|
70
|
-
} catch
|
|
106
|
+
return luhn10(body) === check;
|
|
107
|
+
} catch {
|
|
71
108
|
return false;
|
|
72
109
|
}
|
|
73
110
|
};
|
|
74
111
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
seatName,
|
|
79
|
-
}: {
|
|
80
|
-
fixtureId: string;
|
|
81
|
-
sectionName: string;
|
|
82
|
-
seatName: string;
|
|
83
|
-
}) => `${sectionName}-${seatName}-${fixtureId}`;
|
|
112
|
+
// ---------- compatibility shim (if you want same names as before) ----------
|
|
113
|
+
export const buildTicketCode = buildTicketCodeNumeric;
|
|
114
|
+
export const validateTicketCode = validateTicketCodeNumeric;
|