playttm 0.0.1

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.
@@ -0,0 +1,1209 @@
1
+
2
+ import axios from "axios";
3
+ import * as cheerio from "cheerio";
4
+ //@ts-ignore
5
+ import fs from 'fs'
6
+ import { wrapper } from "axios-cookiejar-support";
7
+ import { CookieJar } from "tough-cookie";
8
+
9
+ const jar = new CookieJar();
10
+
11
+ const client = wrapper(
12
+ axios.create({
13
+ jar,
14
+ withCredentials: true,
15
+ })
16
+ );
17
+
18
+ let endpoint = `https://booking.thaiticketmajor.com/booking/3m`
19
+
20
+ // Convert Curl Select Node.js not python
21
+ export class PlayTTM {
22
+
23
+ headers_cookies: any
24
+
25
+ constructor(headers_cookies: any) {
26
+ this.headers_cookies = {
27
+ ...headers_cookies,
28
+ 'referer': 'https://booking.thaiticketmajor.com'
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Response
34
+ * Step 1
35
+ *
36
+ * @example
37
+ * [
38
+ * {
39
+ * url: "https://booking.thaiticketmajor.com/booking/3m/zones.php?query=954",
40
+ * time: "19:50",
41
+ * date: "วันอาทิตย์ที่ 11 ตุลาคม 2569"
42
+ * }
43
+ * {
44
+ * url: "https://booking.thaiticketmajor.com/booking/3m/zones.php?query=954",
45
+ * time: "19:50",
46
+ * date: "วันจันทร์ที่ 12 ตุลาคม 2569"
47
+ * }
48
+ * ]
49
+ */
50
+ public getRounds = async (url: string): Promise<getRoundsResponse[]> => {
51
+
52
+ let html = await client.get(url, { headers: this.headers_cookies })
53
+
54
+ const $ = cheerio.load(html.data);
55
+
56
+ const result: getRoundsResponse[] = $("a[data-button]")
57
+ .map((_, el) => {
58
+ const link = $(el);
59
+
60
+ return {
61
+ url: link.attr("href") ?? "",
62
+ time: link.find(".item-show").text().trim(),
63
+ date: link.closest(".row").find(".date").text().trim(),
64
+ };
65
+ })
66
+ .get();
67
+
68
+ return result;
69
+ }
70
+
71
+ /**
72
+ * Step 2
73
+ *
74
+ * @example
75
+ * {"result":true,"message":"","query":954}
76
+ */
77
+
78
+ public verify_checkcondition = async (query: string): Promise<verify_checkconditionResponse> => {
79
+ const response = await client.post(
80
+ `${endpoint}/verify_checkcondition.php`,
81
+ new URLSearchParams({
82
+ 'rdagree': '1',
83
+ 'rdId': '',
84
+ 'autopopup': '',
85
+ 'query': query
86
+ }),
87
+ { headers: this.headers_cookies }
88
+ );
89
+
90
+ return response.data
91
+ }
92
+
93
+ /**
94
+ * Response
95
+ * Step 3
96
+ *
97
+ * @example
98
+ * {
99
+ * k: 'b3be0e5932b8baa2c9dd9c33206c31b95f78be2f',
100
+ * tk: '2bf55fccc2bb727f39066dd042f0de0fdb7c1be7fdc477ce322b8cafb658abbb',
101
+ * query: '954',
102
+ * rounds: [
103
+ * { id: '81674', label: 'Sun 11 Oct 2026 19:50' },
104
+ * { id: '81697', label: 'Mon 12 Oct 2026 19:50' },
105
+ * { id: '81728', label: 'Tue 13 Oct 2026 19:50' }
106
+ * ]
107
+ * }
108
+ */
109
+ public getZone = async (query: string): Promise<GetRoundsPerformResponse> => {
110
+ const response = await client.get(
111
+ `${endpoint}/zones.php?query=${query}`,
112
+ { headers: this.headers_cookies }
113
+ );
114
+
115
+
116
+ //ต้องเปลี่ยน ไม่งั้นดึงข้อมูลไม่ได้
117
+ // referer = `${endpoint}/zones.php?query=${query}`
118
+
119
+ const $ = cheerio.load(response.data);
120
+
121
+ const data: any = {};
122
+
123
+ // Hidden inputs
124
+ $("#frm input[type='hidden']").each((_, el) => {
125
+ const name = $(el).attr("name");
126
+ const value = $(el).attr("value") ?? "";
127
+
128
+ if (name) {
129
+ data[name] = value;
130
+ }
131
+ });
132
+
133
+ // Rounds
134
+ const rounds = $("#rdId option")
135
+ .filter((_, el) => !!$(el).attr("value"))
136
+ .map((_, el) => {
137
+ const option = $(el);
138
+
139
+ return {
140
+ id: option.attr("value") ?? "",
141
+ label: option.text().trim(),
142
+ };
143
+ })
144
+ .get();
145
+
146
+ // รวม rounds เข้าไป
147
+ data.rounds = rounds;
148
+
149
+ return data;
150
+ };
151
+
152
+ /**
153
+ *
154
+ * Step 4
155
+ *
156
+ * @example
157
+ * [
158
+ * { id: 'E1E', value: 'E1E', available: 0, page: 'fixed.php' },
159
+ * { id: 'E1F', value: 'E1F', available: 0, page: 'fixed.php' },
160
+ * { id: 'E1G', value: 'E1G', available: 0, page: 'fixed.php' },
161
+ * { id: 'E1H', value: 'E1H', available: 27, page: 'fixed.php' },
162
+ * { id: 'E1I', value: 'E1I', available: 0, page: 'festival.php' }, โซนยืน
163
+ * { id: 'E1J', value: 'E1J', available: 0, page: 'fixed.php' },
164
+ * ]
165
+ */
166
+
167
+ public getZoneAvail = async (round: string, tk: string, k: string, query: string): Promise<Zone[]> => {
168
+
169
+ console.log("ZONE AVAIL : ", `https://booking.thaiticketmajor.com/booking/3m/zones.php?rdId=${round}&k=${k}&tk=${tk}&query=${query}`)
170
+
171
+ const response = await client.get(
172
+ `${endpoint}/zonesavail.php?round=${round}&tk=${tk}`,
173
+ {
174
+ headers: {
175
+ ...this.headers_cookies,
176
+ referer: `${endpoint}/zones.php?query=${query}`,
177
+ },
178
+ }
179
+ );
180
+ const $ = cheerio.load(response.data);
181
+
182
+ const zones = $(".table tbody tr")
183
+ .map((_, el) => {
184
+ const row = $(el);
185
+
186
+ const zoneId = row
187
+ .find("td:nth-child(1) a")
188
+ .attr("id") ?? "";
189
+
190
+ const onclick = row.attr("onclick") ?? "";
191
+
192
+ const match = onclick.match(
193
+ /gonextstep\('([^']+)','([^']+)'/
194
+ );
195
+
196
+ const page = match?.[1] ?? "";
197
+ const zoneValue = match?.[2] ?? "";
198
+
199
+ const available = row.find("td:nth-child(2) a").text().trim() == "Available" ? 1 : Number.isNaN(Number(row.find("td:nth-child(2) a").text().trim())) ? 0 : Number(row.find("td:nth-child(2) a").text().trim())
200
+
201
+ console.log("AVAIL TEST : ", available)
202
+
203
+ return {
204
+ id: zoneId,
205
+ value: zoneValue,
206
+ available,
207
+ page,
208
+ };
209
+ })
210
+ .get();
211
+
212
+ return zones
213
+ }
214
+
215
+ /**
216
+ *
217
+ * Step 5
218
+ *
219
+ * @example
220
+ * seats: [
221
+ * * {
222
+ * id: 'checkseat-AV-03',
223
+ * seat: 'AV-03-P*5335',
224
+ * seatk: 'abc62800881d8df5e782f4accd862376'
225
+ * },
226
+ * {
227
+ * id: 'checkseat-AV-02',
228
+ * seat: 'AV-02-P*5335',
229
+ * seatk: '79f89972db1e57bd3513440402487466'
230
+ * },
231
+ * {
232
+ * id: 'checkseat-AV-01',
233
+ * seat: 'AV-01-P*5335',
234
+ * seatk: '34ff19f7c31e7b61dfae3e6a0ebd4c82'
235
+ * }
236
+ * ],
237
+ *
238
+ *
239
+ *
240
+ * @example
241
+ * form: {
242
+ * ehId: '954',
243
+ * curentdate: '2026,09,19,02,16',
244
+ * max_payment: '6',
245
+ * payment_cnt: '0',
246
+ * paytype: 'BOAI',
247
+ * performance: 'The Weeknd : After Hours Til Dawn Tour',
248
+ * pricelist: '',
249
+ * rdId: '81728',
250
+ * seatlist: '',
251
+ * showdate: '13 Oct 2026',
252
+ * showtime: '19:50',
253
+ * venue: 'Rajamangala National Stadium, Bangkok',
254
+ * zone: 'N2A',
255
+ * zoneDesc: 'N2A',
256
+ * travelChild1: '',
257
+ * travelChild2: '',
258
+ * enroll_val: '2',
259
+ * dval: '9343a84c9e564dda211a2c421551cbb2',
260
+ * companyid: '1627',
261
+ * ks: '',
262
+ * inclvat: ''
263
+ * }
264
+ */
265
+
266
+ public getFixed = async (k: string, zone: string, round: string): Promise<FixedResponse> => {
267
+ const response = await client.get(
268
+ `${endpoint}/fixed.php?k=${k}&zone=${zone}&round=${round}`,
269
+ { headers: this.headers_cookies }
270
+ );
271
+
272
+ // referer = `${endpoint}/fixed.php?k=${k}&zone=${zone}&round=${round}`
273
+
274
+ const $ = cheerio.load(response.data);
275
+
276
+ const seats = $("#tableseats .seatuncheck")
277
+ .map((_, el) => {
278
+ const seat = $(el);
279
+
280
+ return {
281
+ id: seat.attr("id") ?? "",
282
+ seat: seat.attr("data-seat") ?? "",
283
+ seatk: seat.attr("data-seatk") ?? "",
284
+ };
285
+ })
286
+ .get();
287
+
288
+ let form: any = {}
289
+
290
+ $("#frmPayment input").each((_, el) => {
291
+ const name = $(el).attr("name");
292
+
293
+ if (name) {
294
+ form[name] = $(el).attr("value") ?? "";
295
+ }
296
+ });
297
+
298
+ return {
299
+ seats,
300
+ form,
301
+ };
302
+ };
303
+
304
+
305
+ /**
306
+ *
307
+ * Step 6
308
+ *
309
+ * @example
310
+ * {"result":true,"status":0,"message":""}
311
+ *
312
+ */
313
+ //zw = zone
314
+ //Remark You have to validate eqaul with the seats you choose if choose 2 seats that means you have to send 2 request
315
+ public validateSeatFix = async (
316
+ k: string,
317
+ zw: string,
318
+ payload: Record<string, any>,
319
+ chkSeats: any,
320
+ book_type: string = "fix"
321
+ ): Promise<ValidateFixedResponse> => {
322
+ let lastResponse: any = null;
323
+ const accumulatedSeats: string[] = [];
324
+
325
+ // Loop through each seat to simulate sequential seat selection
326
+ for (let i = 0; i < chkSeats.length; i++) {
327
+ const currentSeat = chkSeats[i];
328
+
329
+ // Format value as SEAT*PRICE (e.g. UX-07-P*5335)
330
+ const priceVal = currentSeat.price || "5335";
331
+ const seatEntry = `${currentSeat.seat}*${priceVal}`;
332
+
333
+ // Insert newest selected seat at the front of chkSeats[] (index 0)
334
+ accumulatedSeats.unshift(seatEntry);
335
+
336
+ const formData = new URLSearchParams();
337
+
338
+ // 1. chkSeats[] must come first
339
+ for (const seat of accumulatedSeats) {
340
+ formData.append("chkSeats[]", seat);
341
+ }
342
+
343
+ // 2. Base payload
344
+ formData.append("ehId", payload.ehId ?? "");
345
+ formData.append("curentdate", payload.curentdate ?? "");
346
+ formData.append("max_payment", payload.max_payment ?? "6");
347
+ formData.append("payment_cnt", payload.payment_cnt ?? "0");
348
+ formData.append("paytype", payload.paytype ?? "BOAI");
349
+ formData.append("performance", payload.performance ?? "");
350
+ formData.append("pricelist", ""); // Curl uses empty string
351
+ formData.append("rdId", payload.rdId ?? "");
352
+ formData.append("seatlist", ""); // Curl uses empty string
353
+ formData.append("showdate", payload.showdate ?? "");
354
+ formData.append("showtime", payload.showtime ?? "");
355
+ formData.append("venue", payload.venue ?? "");
356
+ formData.append("zone", payload.zone ?? "");
357
+ formData.append("zoneDesc", payload.zoneDesc ?? "");
358
+
359
+ formData.append("travelChild1", "");
360
+ formData.append("travelChild2", "");
361
+ formData.append("travelChild2", "");
362
+
363
+ formData.append("enroll_val", payload.enroll_val ?? "");
364
+ formData.append("dval", payload.dval ?? "");
365
+ formData.append("companyid", payload.companyid ?? "");
366
+ formData.append("ks", payload.ks ?? "");
367
+ formData.append("inclvat", "");
368
+
369
+ // 3. Current seat being added
370
+ const seatParts = currentSeat.seat.split("-");
371
+ const row = seatParts[0]; // UX
372
+ const seatNo = seatParts[1]; // 07 or 08
373
+
374
+ formData.append("row", row);
375
+ formData.append("seat", seatNo);
376
+ formData.append("book_type", book_type);
377
+
378
+ // 4. Send request
379
+ const response = await client.post(
380
+ `${endpoint}/validateseat.php?k=${k}&zw=${zw}`,
381
+ formData.toString(),
382
+ {
383
+ headers: {
384
+ ...this.headers_cookies,
385
+ "content-type": "application/x-www-form-urlencoded; charset=UTF-8",
386
+ "x-requested-with": "XMLHttpRequest",
387
+ "referer": `${endpoint}/fixed.php?k=${k}&zone=${payload.zone}&round=${payload.rdId}`
388
+ },
389
+ }
390
+ );
391
+
392
+ console.log(`#${i} Validate ${seatNo}`)
393
+
394
+ lastResponse = response.data;
395
+ }
396
+
397
+ return lastResponse;
398
+ };
399
+
400
+
401
+ /**
402
+ * Step 7
403
+ *
404
+ * @example
405
+ *
406
+ */
407
+ public bookingSeats = async (
408
+ k: string,
409
+ payload: BookingForm,
410
+ seats: Seats[]
411
+ ): Promise<BookingSeatsResponse> => {
412
+ let pricelistvalue = "";
413
+ let seatlistvalue = "";
414
+ let seatklistvalue = "";
415
+
416
+ seats.forEach((s) => {
417
+ const parts = s.seat.split("*");
418
+ pricelistvalue += `${parts[1] || ""},`;
419
+ seatlistvalue += `${parts[0]},`;
420
+ seatklistvalue += `${s.seatk},`;
421
+ });
422
+
423
+ // คัดลอกและเรียง Key ให้ตรงตาม curl ของจริงเป๊ะๆ
424
+ const bodyParams = new URLSearchParams();
425
+
426
+ bodyParams.set("ehId", payload.ehId || "");
427
+ bodyParams.set("curentdate", payload.curentdate || "");
428
+ bodyParams.set("max_payment", payload.max_payment || "6");
429
+ bodyParams.set("payment_cnt", payload.payment_cnt || "0");
430
+ bodyParams.set("paytype", payload.paytype || "BOAI");
431
+ bodyParams.set("performance", payload.performance || "");
432
+ bodyParams.set("pricelist", pricelistvalue);
433
+ bodyParams.set("rdId", payload.rdId || "");
434
+ bodyParams.set("seatlist", seatlistvalue);
435
+ bodyParams.set("showdate", payload.showdate || "");
436
+ bodyParams.set("showtime", payload.showtime || "");
437
+ bodyParams.set("venue", payload.venue || "");
438
+ bodyParams.set("zone", payload.zone || "");
439
+ bodyParams.set("zoneDesc", payload.zoneDesc || "");
440
+ bodyParams.set("travelChild1", "");
441
+ bodyParams.set("travelChild2", "");
442
+ bodyParams.append("travelChild2", ""); // ใส่ซ้ำ 2 ครั้งตาม curl
443
+ bodyParams.set("enroll_val", payload.enroll_val); // จำนวนบัตรต้องตรงกับจำนวนที่นั่งใน array
444
+ bodyParams.set("dval", payload.dval || "");
445
+ bodyParams.set("companyid", payload.companyid || "");
446
+ bodyParams.set("ks", "");
447
+ bodyParams.set("inclvat", "");
448
+ bodyParams.set("seatklist", seatklistvalue);
449
+
450
+ const response = await client.post(
451
+ `${endpoint}/bookingseats.php?k=${k}`,
452
+ bodyParams.toString(),
453
+ {
454
+ headers: {
455
+ ...this.headers_cookies,
456
+ "accept": "application/json, text/javascript, */*; q=0.01",
457
+ "content-type": "application/x-www-form-urlencoded; charset=UTF-8",
458
+ "x-requested-with": "XMLHttpRequest",
459
+ "referer": `https://booking.thaiticketmajor.com/booking/3m/fixed.php?k=${k}&zone=${payload.zone}&round=${payload.rdId}`,
460
+ "origin": "https://booking.thaiticketmajor.com",
461
+ },
462
+ }
463
+ );
464
+
465
+ return {
466
+ data: response.data,
467
+ nextPayload: bodyParams
468
+ }
469
+ };
470
+
471
+ /**
472
+ * Optional Step Watch enroll_val
473
+ *
474
+ * @example
475
+ *
476
+ */
477
+
478
+ public enroll = async (k: string, zone: string, rdId: string, payload: any): Promise<EnrollResponse> => {
479
+ const response = await client.post(`${endpoint}/enroll.php?k=${k}&zone=${zone}&round=${rdId}`,
480
+ payload,
481
+ {
482
+ headers: {
483
+ ...this.headers_cookies,
484
+ referer: `https://booking.thaiticketmajor.com/booking/3m/fixed.php?k=${k}&zone=${zone}&round=${rdId}`
485
+ },
486
+ }
487
+ );
488
+
489
+ const allowedFields = [
490
+ "txt_fullname[]",
491
+ "txt_email[]",
492
+ "txt_firstname[]",
493
+ "txt_lastname[]",
494
+ "txt_phone[]",
495
+ "sel_options[]",
496
+ "zones[]",
497
+ "ehId",
498
+ "enroll_val",
499
+ "canDuplicate",
500
+ "hasPolicy",
501
+ "isSplitName",
502
+ "festival",
503
+ "debit",
504
+ "zone",
505
+ "zoneDesc",
506
+ "rdId",
507
+ "price",
508
+ "seatklist",
509
+ "mpur",
510
+ "paytype",
511
+ "companyid",
512
+ "rounddate",
513
+ "book_cnt",
514
+ "isThaiOnly",
515
+ "isEngOnly",
516
+ "hasSelect",
517
+ "showEmailFlag",
518
+ "showFullnameFlag",
519
+ "showSplitNameFlag",
520
+ "hasCheckbox",
521
+ "hasPhone",
522
+ "enroll_cnt",
523
+ ];
524
+
525
+ const $ = cheerio.load(response.data);
526
+
527
+ const formData: any = {};
528
+
529
+ $("#form input, #form select").each((_, el) => {
530
+ const name = $(el).attr("name");
531
+
532
+ if (!name || !allowedFields.includes(name)) return;
533
+
534
+ formData[name] =
535
+ $(el).attr("value") ??
536
+ $(el).find("option:selected").attr("value") ??
537
+ "";
538
+ });
539
+
540
+
541
+ return formData
542
+ }
543
+
544
+
545
+ /**
546
+ *
547
+ * Optional Step Watch enroll_val
548
+ *
549
+ * @example
550
+ * { result: true, message: '', query: 954 }
551
+ *
552
+ */
553
+ public enroll_process = async (
554
+ k: string,
555
+ payload: Record<string, any>,
556
+ users: any[]
557
+ ) => {
558
+ const formData = new URLSearchParams();
559
+
560
+ // 1. Append the repeated attendee field blocks at the top
561
+ for (const user of users) {
562
+ const isString = typeof user === "string";
563
+ const fullname = isString ? user : user.fullname;
564
+ const email = isString ? "" : (user.email ?? "");
565
+ const firstname = isString ? "" : (user.firstname ?? "");
566
+ const lastname = isString ? "" : (user.lastname ?? "");
567
+ const phone = isString ? "" : (user.phone ?? "");
568
+ const options = isString ? "" : (user.options ?? "");
569
+
570
+ formData.append("txt_fullname[]", fullname);
571
+ formData.append("txt_email[]", email);
572
+ formData.append("txt_firstname[]", firstname);
573
+ formData.append("txt_lastname[]", lastname);
574
+ formData.append("txt_phone[]", phone);
575
+ formData.append("sel_options[]", options);
576
+ formData.append("zones[]", payload.zone ?? "");
577
+ }
578
+
579
+ // 2. Keys that were already added as repeated arrays (exclude them from base payload)
580
+ const excludedKeys = new Set([
581
+ "txt_fullname[]",
582
+ "txt_email[]",
583
+ "txt_firstname[]",
584
+ "txt_lastname[]",
585
+ "txt_phone[]",
586
+ "sel_options[]",
587
+ "zones[]",
588
+ ]);
589
+
590
+ // 3. Append remaining metadata keys from the payload
591
+ for (const [key, value] of Object.entries(payload)) {
592
+ if (!excludedKeys.has(key)) {
593
+ formData.append(key, value !== undefined && value !== null ? String(value) : "");
594
+ }
595
+ }
596
+
597
+ // console.log("BEFORE SEND ENROLL PROCESS : ", formData)
598
+
599
+ const response = await client.post(
600
+ `${endpoint}/enroll_process.php?k=${k}`,
601
+ formData.toString(),
602
+ {
603
+ headers: {
604
+ ...this.headers_cookies,
605
+ "content-type": "application/x-www-form-urlencoded; charset=UTF-8",
606
+ "x-requested-with": "XMLHttpRequest",
607
+ referer: `https://booking.thaiticketmajor.com/booking/3m/enroll.php?k=${k}&zone=${payload.zone}&round=${payload.rdId}`,
608
+ },
609
+ }
610
+ );
611
+
612
+ return {
613
+ data: response.data,
614
+ nextPayload: formData
615
+ };
616
+ };
617
+
618
+ public getPaymentAll = async (
619
+ k: string,
620
+ formData: any,
621
+ zone: string,
622
+ rdId: string,
623
+ msDelay: number
624
+ ): Promise<PaymentAllResponse> => {
625
+ const response = await client.post(
626
+ `${endpoint}/paymentall.php?k=${k}`,
627
+ formData.toString(),
628
+ {
629
+ headers: {
630
+ ...this.headers_cookies,
631
+ "content-type": "application/x-www-form-urlencoded; charset=UTF-8",
632
+ "x-requested-with": "XMLHttpRequest",
633
+ referer: `https://booking.thaiticketmajor.com/booking/3m/enroll.php?k=${k}&zone=${zone}&round=${rdId}`,
634
+ },
635
+ }
636
+ );
637
+
638
+ const $ = cheerio.load(response.data);
639
+ const hiddenInputs: any = {};
640
+
641
+ // 1. ดึง input ทั้งหมดจาก #frm-confirm (ทั้ง name และ id)
642
+ $("#frm-confirm input").each((_, el) => {
643
+ const key = $(el).attr("name") ?? $(el).attr("id");
644
+ if (key) {
645
+ hiddenInputs[key] = $(el).val()?.toString() ?? "";
646
+ }
647
+ });
648
+
649
+ // 2. สกัดข้อมูลที่อยู่จัดส่งจาก #frm-address
650
+ const addressForm = $("#frm-address");
651
+ if (addressForm.length > 0) {
652
+ const fname = addressForm.find("input[name='c_fname_m']").val()?.toString() ?? "";
653
+ const lname = addressForm.find("input[name='c_lname_m']").val()?.toString() ?? "";
654
+ const address = addressForm.find("textarea[name='c_address_m']").val()?.toString() ?? "";
655
+
656
+ // ดึงค่า value จาก dropdown option ที่ถูก selected
657
+ const ctId = addressForm.find("select[name='c_ctCode'] option:selected").val()?.toString() ?? "";
658
+ const pvId = addressForm.find("select[name='c_pvId'] option:selected").val()?.toString() ?? "";
659
+ const amId = addressForm.find("select[name='c_amId'] option:selected").val()?.toString() ?? "";
660
+
661
+ const zipcode = addressForm.find("input[name='c_PostCode']").val()?.toString() ?? "";
662
+
663
+ // จัดการเบอร์โทรศัพท์ (ถ้าติดรหัสประเทศ 66 ข้างหน้า ให้ตัดออกเพื่อให้ตรงกับ format 95 697 5152)
664
+ let rawPhone = addressForm.find("input[name='c_ContactRecipient']").val()?.toString() ?? "";
665
+ if (rawPhone.startsWith("66")) {
666
+ rawPhone = rawPhone.slice(2);
667
+ }
668
+ // จัด format เว้นวรรคตามตัวอย่าง '95 697 5152' ถ้าต้องการ หรือเก็บเป็นตัวเลขล้วน
669
+ const phoneArea = addressForm.find("input[name='telephoneArea']").val()?.toString() ?? "66";
670
+
671
+ // 3. Map เข้าฟิลด์ adr_* สำหรับ payload ชำระเงิน
672
+ hiddenInputs["adr_fname"] = fname;
673
+ hiddenInputs["adr_lname"] = lname;
674
+ hiddenInputs["adr_address"] = address;
675
+ hiddenInputs["adr_ctId"] = ctId;
676
+ hiddenInputs["adr_pvId"] = pvId;
677
+ hiddenInputs["adr_amId"] = amId;
678
+ hiddenInputs["adr_zipcode"] = zipcode;
679
+ hiddenInputs["adr_mobile"] = rawPhone.replace(/(\d{2})(\d{3})(\d{4})/, "$1 $2 $3");
680
+ hiddenInputs["adr_mobilearea"] = phoneArea;
681
+ }
682
+
683
+ console.log(`Waiting PayCfmall Page loading... ${msDelay} ms`)
684
+
685
+ await new Promise(resolve => setTimeout(resolve, msDelay));
686
+
687
+ // console.log("getPaymentALL : ", hiddenInputs);
688
+ return hiddenInputs;
689
+ };
690
+
691
+
692
+
693
+ /**
694
+ * @example response
695
+ * {
696
+ * ehId: '954',
697
+ * ordernumber: '27016032010849868',
698
+ * amount: '11052',
699
+ * tk: 'f6fe8889391291e5a9a7864ffa9d7f4ba8ba3dae4982573053043ccadb493661'
700
+ * }
701
+ */
702
+
703
+ public getPayCfmall = async (
704
+ k: string,
705
+ payload: PaymentAllResponse,
706
+ deliver: string = "1",
707
+ paytype: string = "KBQR"
708
+ ): Promise<PayCfMallResponse> => {
709
+ // 1. ดึงตัวเลขจาก payload มาคำนวณค่าธรรมเนียมและยอดรวม
710
+ const cntTicket = parseInt(payload.cal_cntticket || "0", 10);
711
+ const amountCode = parseFloat(payload.amountcode || "0");
712
+ const deliverFee = parseFloat(payload.cal_deliverfee || payload.val_deliverfee || "80");
713
+ const addCharge = parseFloat(payload.cal_addcharge || "0");
714
+ const discount = parseFloat(payload.cal_discount || "0");
715
+ const voucher = parseFloat(payload.cal_voucher || "0");
716
+
717
+ // ค่าบริการออกบัตร (Ticket Fee = 191 THB ต่อใบ)
718
+ const ticketFee = cntTicket * 191;
719
+
720
+ // ยอดรวมสุทธิ
721
+ const totalAmount = amountCode + deliverFee + ticketFee + addCharge - discount - voucher;
722
+
723
+ // 2. Clone payload พร้อม override ค่าที่ต้องคำนวณและตั้งค่า
724
+ const computedPayload: Record<string, string> = {
725
+ ...payload,
726
+ paytype: paytype,
727
+ deliver: deliver,
728
+ cal_ticketfee: ticketFee.toString(),
729
+ cal_totalamount: Math.round(totalAmount).toString(),
730
+ };
731
+
732
+ // 3. ประกอบ URLSearchParams ตามลำดับ (ตัด 'check-protect' ออก)
733
+ const formData = new URLSearchParams();
734
+ for (const [key, value] of Object.entries(computedPayload)) {
735
+ if (key !== "check-protect") {
736
+ formData.append(key, value !== undefined && value !== null ? String(value) : "");
737
+ }
738
+ }
739
+
740
+ // 4. ส่ง Request
741
+ const response = await client.post(
742
+ `${endpoint}/paycfmall.php?k=${k}`,
743
+ formData.toString(),
744
+ {
745
+ headers: {
746
+ ...this.headers_cookies,
747
+ "content-type": "application/x-www-form-urlencoded; charset=UTF-8",
748
+ "x-requested-with": "XMLHttpRequest",
749
+ referer: `${endpoint}/paymentall.php?k=${k}`,
750
+ },
751
+ }
752
+ );
753
+
754
+ const $ = cheerio.load(response.data);
755
+
756
+ // console.log(response.data)
757
+
758
+ const nextJsonData: any = {};
759
+
760
+ $("#payallfrm input[type='hidden']").each((_, el) => {
761
+ const name = $(el).attr("name");
762
+ const value = $(el).attr("value") ?? "";
763
+
764
+ if (name) {
765
+ nextJsonData[name] = value;
766
+ }
767
+ });
768
+
769
+ return nextJsonData;
770
+ };
771
+
772
+
773
+ /**
774
+ *
775
+ * @param k
776
+ * @param payload_json
777
+ * @returns
778
+ *
779
+ */
780
+
781
+ public orderenc_kbankqr = async (k: string, payload_json: any): Promise<OrderEncResponse> => {
782
+
783
+ const formData = new URLSearchParams(payload_json);
784
+
785
+ const response = await client.post(
786
+ `${endpoint}/orderenc_kbankqr.php`,
787
+ formData.toString(),
788
+ {
789
+ headers: {
790
+ ...this.headers_cookies,
791
+ "content-type": "application/x-www-form-urlencoded; charset=UTF-8",
792
+ "x-requested-with": "XMLHttpRequest",
793
+ referer: `${endpoint}/paycfmall.php?k=${k}`,
794
+ },
795
+ }
796
+ );
797
+
798
+ const $ = cheerio.load(response.data);
799
+
800
+ const kbankqrData: any = {};
801
+
802
+ $("#kbankqr input[type='hidden']").each((_, el) => {
803
+ const name = $(el).attr("name");
804
+ const value = $(el).attr("value") ?? "";
805
+
806
+ if (name) {
807
+ kbankqrData[name] = value;
808
+ }
809
+ });
810
+
811
+ return kbankqrData
812
+
813
+ }
814
+
815
+ public getkbankqr = async (payload_json: any): Promise<GetKBankQrResponse> => {
816
+
817
+ let formData = new URLSearchParams(payload_json)
818
+
819
+ const response = await client.post(
820
+ `${endpoint}/getkbankqr.php`,
821
+ formData.toString(),
822
+ {
823
+ headers: {
824
+ ...this.headers_cookies,
825
+ "content-type": "application/x-www-form-urlencoded; charset=UTF-8",
826
+ "x-requested-with": "XMLHttpRequest",
827
+ referer: `https://booking.thaiticketmajor.com/booking/3m/orderenc_kbankqr.php`,
828
+ },
829
+ }
830
+ );
831
+
832
+ return response.data
833
+
834
+ }
835
+
836
+ public payment_kbankqr = async (orderenc_json: any, kbank_payload_json: any): Promise<PaymentKbankQrResponse> => {
837
+
838
+ let prepare_payload = {
839
+ ...orderenc_json,
840
+ 'reasoncode': kbank_payload_json.reasoncode,
841
+ 'eventname': kbank_payload_json.eventname,
842
+ 'rounddetail': kbank_payload_json.rounddetail,
843
+ 'totalamount': kbank_payload_json.totalamount,
844
+ 'orderstatus': kbank_payload_json.orderstatus,
845
+ 'kbankqr_txExpiry': kbank_payload_json.kbankqr_txExpiry
846
+ }
847
+
848
+ let formData = new URLSearchParams(prepare_payload)
849
+
850
+ const response = await client.post(
851
+ `${endpoint}/payment_kbankqr.php`,
852
+ formData.toString(),
853
+ {
854
+ headers: {
855
+ ...this.headers_cookies,
856
+ "content-type": "application/x-www-form-urlencoded; charset=UTF-8",
857
+ "x-requested-with": "XMLHttpRequest",
858
+ referer: `https://booking.thaiticketmajor.com/booking/3m/orderenc_kbankqr.php`,
859
+ },
860
+ }
861
+ );
862
+
863
+ const $ = cheerio.load(response.data);
864
+
865
+ const script = $("#kbankpost script[data-order-id]");
866
+
867
+ const orderId = script.attr("data-order-id") ?? "";
868
+ const apiKey = script.attr("data-apikey") ?? "";
869
+
870
+ return {
871
+ orderId,
872
+ apiKey,
873
+ };
874
+ }
875
+
876
+ public QR = async (order_id: string, api_key: string, orderenc_json: any): Promise<QRResponse> => {
877
+
878
+ let prepayload = {
879
+ amount: orderenc_json.amount,
880
+ currency: 'THB', //Don't hard code Next,
881
+ metadata: [],
882
+ order_id: order_id,
883
+ sof: "ThaiQR" //Don't hard code Next,
884
+ }
885
+
886
+ const response = await client.post(
887
+ `https://kpaymentgateway-services.kasikornbank.com/qr/v2/qr`,
888
+ prepayload,
889
+ {
890
+ headers: {
891
+ ...this.headers_cookies,
892
+ referer: `https://kpaymentgateway.kasikornbank.com/`,
893
+ "x-api-key": api_key
894
+ },
895
+ }
896
+ );
897
+
898
+ return response.data
899
+ }
900
+
901
+
902
+ //Festival Way
903
+
904
+ public Festival = async (k: string, tk: string, query: string, zone: string, round: string): Promise<FestivalResponse> => {
905
+
906
+ const response = await client.get(
907
+ `${endpoint}/festival.php?k=${k}&zone=${zone}&round=${round}`,
908
+ {
909
+ headers: {
910
+ ...this.headers_cookies,
911
+ "content-type": "application/x-www-form-urlencoded; charset=UTF-8",
912
+ "x-requested-with": "XMLHttpRequest",
913
+ referer: `https://booking.thaiticketmajor.com/booking/3m/zones.php?rdId=${round}&k=${k}&tk=${tk}&query=${query}`,
914
+ },
915
+ }
916
+ );
917
+
918
+ const $ = cheerio.load(response.data);
919
+
920
+ const formData: any = {};
921
+
922
+ $("#frm input").each((_, el) => {
923
+ const name = $(el).attr("name");
924
+
925
+ if (name) {
926
+ formData[name] = $(el).attr("value") ?? "";
927
+ }
928
+ });
929
+
930
+ return formData
931
+
932
+ }
933
+
934
+ public validateSeatFestival = async (k: string, payload_json: any, book_cnt: string) => {
935
+
936
+ let prepare_payload = {
937
+ ...payload_json,
938
+ 'book_cnt': book_cnt,
939
+ 'book_type': 'fest'
940
+ }
941
+
942
+ let formData = new URLSearchParams(prepare_payload)
943
+
944
+ console.log("TEST JA : ", formData)
945
+
946
+ const response = await client.post(
947
+ `${endpoint}/validateseat.php?k=${k}&zw=${payload_json.zone}`,
948
+ formData.toString(),
949
+ {
950
+ headers: {
951
+ ...this.headers_cookies,
952
+ "content-type": "application/x-www-form-urlencoded; charset=UTF-8",
953
+ "x-requested-with": "XMLHttpRequest",
954
+ referer: `https://booking.thaiticketmajor.com/booking/3m/festival.php?k=${k}&zone=${payload_json.zone}&round=${payload_json.rdId}`,
955
+ },
956
+ }
957
+ );
958
+
959
+ return response.data
960
+ }
961
+
962
+ public BookingFestival = async (k: string, payload: any, book_cnt: string) => {
963
+
964
+ let prepayload = {
965
+ ...payload,
966
+ 'book_cnt': book_cnt
967
+ }
968
+
969
+ let formData = new URLSearchParams(prepayload)
970
+
971
+ const response = await client.post(
972
+ `${endpoint}/bookingfestival.php?k=${k}`,
973
+ formData.toString(),
974
+ {
975
+ headers: {
976
+ ...this.headers_cookies,
977
+ "content-type": "application/x-www-form-urlencoded; charset=UTF-8",
978
+ "x-requested-with": "XMLHttpRequest",
979
+ referer: `https://booking.thaiticketmajor.com/booking/3m/festival.php?k=${k}&zone=${payload.zone}&round=${payload.rdId}`,
980
+ },
981
+ }
982
+ );
983
+
984
+ return response.data
985
+ }
986
+
987
+ public enrollFestival = async (k: string, payload: any, book_cnt: string) => {
988
+
989
+ let prepayload = {
990
+ ...payload,
991
+ 'book_cnt': book_cnt
992
+ }
993
+
994
+ let formData = new URLSearchParams(prepayload)
995
+
996
+ const response = await client.post(
997
+ `${endpoint}/enroll.php?k=${k}`,
998
+ formData.toString(),
999
+ {
1000
+ headers: {
1001
+ ...this.headers_cookies,
1002
+ "content-type": "application/x-www-form-urlencoded; charset=UTF-8",
1003
+ "x-requested-with": "XMLHttpRequest",
1004
+ referer: `https://booking.thaiticketmajor.com/booking/3m/festival.php?k=${k}&zone=${payload.zone}&round=${payload.rdId}`,
1005
+ },
1006
+ }
1007
+ );
1008
+
1009
+ return response.data
1010
+ }
1011
+
1012
+ }
1013
+
1014
+ // const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
1015
+
1016
+
1017
+ // การที่เราไม่ได้ zone เพราะเราไม่เปลี่ยน referer ที่ headers ให้พึงจารณาอันอื่นด้วย
1018
+ // 418 คนยิง serverr มันเยอะมันเลยให้รอแปป
1019
+
1020
+ let my_headers_cookies = {
1021
+ 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
1022
+ 'accept-language': 'en',
1023
+ 'cache-control': 'no-cache',
1024
+ 'pragma': 'no-cache',
1025
+ 'priority': 'u=0, i',
1026
+ 'referer': 'https://www.thaiticketmajor.com/all-event/',
1027
+ 'sec-ch-ua': '"Google Chrome";v="153", "Not_A Brand";v="8", "Chromium";v="153"',
1028
+ 'sec-ch-ua-mobile': '?0',
1029
+ 'sec-ch-ua-platform': '"macOS"',
1030
+ 'sec-fetch-dest': 'document',
1031
+ 'sec-fetch-mode': 'navigate',
1032
+ 'sec-fetch-site': 'same-origin',
1033
+ 'sec-fetch-user': '?1',
1034
+ 'upgrade-insecure-requests': '1',
1035
+ 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/153.0.0.0 Safari/537.36',
1036
+ 'cookie': '__lt__cid=49c63195-5801-44a8-b1e1-b8e8cffe5d88; _tt_enable_cookie=1; _fbp=fb.1.1781174050563.711676052978077861.AQYAAQIB; _ga=GA1.1.599117093.1781174051; _gcl_au=1.1.157871639.1788961562.-.-.1789480295.1055093031.1789573314.1789573314; _ttp=01M0DEAF6B6EP986BDT9E6AZN6_.tt.1; ttkname=%E0%B8%A3%E0%B8%B1%E0%B8%90%E0%B8%99%E0%B8%99%E0%B8%97%E0%B9%8C+%E0%B8%9A%E0%B8%B8%E0%B8%8D%E0%B8%A1%E0%B8%B2%E0%B8%95%E0%B8%B2; tixid=play21947%40gmail.com; tixu=9343a84c9e564dda211a2c421551cbb2; __la=th; _twpid=tw.1789882087962.364890005864940170; ttmfw=7FAF39CA6BD3E694A4EBE7949C719; __PrivacyPolicy=1; _clck=xi2wac%5E2%5Eg9n%5E0%5E2353; HWWAFSESID=06a7f73fc89cbee20c; HWWAFSESTIME=1789973220265; PHPSESSID=db578307a0d52d2efe1b08b5f899a8c5; cdnname=%E0%B8%A3%E0%B8%B1%E0%B8%90%E0%B8%99%E0%B8%99%E0%B8%97%E0%B9%8C+%E0%B8%9A%E0%B8%B8%E0%B8%8D%E0%B8%A1%E0%B8%B2%E0%B8%95%E0%B8%B2; ttkemail=play21947%40gmail.com; _abck=D02884B6241B15884076C3E83B0FAA86~0~YAAQdhGkboPAvpGgAQAAQYmlwxBdca6zpViMmyhsjcciMHER7JC2fwjndIM4xrL3Qcp8gQ6CRSbIQHOqKMHvMXojwsYvF2R4Cix6NuwIl0TkhiYmrvF6INCYZfBUMRaiFfQEw/GdnkrFw6CfiZpUBFxG5FjaG151p5tJ+tJ9ILaiBwK2jIYMcxvGpej5fjCW6AWmRpX69Mu7IM6abo5MnEXm6xrlbJIpKhcQj2gMaDJgV/INcFvpSPcf89U/GUgg9vyufhgDAspzIyxZsvo1BZyEdagq8NB7N13lqvMibsC3ZXRaSUpXC2N4vcGhn2hLVWKGGt+payQZbuITaB7GwPX5thbfI7kScVZhMS4tTOpQyyhDNMNSfbRvL6ukrgK3I2ZmESwpPzjSeieyWYO/KXff9zCUpJ8Hb5lxxnGgsuRkgRaDHShCX55LhFkK0lInsmRVDlOSB+wt9m+o30/QgIWbyT32iXbGNFNSXFB3oz3bUqICZKsm/4gDh5KXcS0XYLIFVeHcoYGKY9jVNt64fUkeptCdzYaKacNqYUvaCJlZndJ5nekJpXk64LTJGpeTp3mZ/9Y2d0OrhTPxkAWxE1XekxM2l+1IBqLWQ0AtvaZNQG2yEURAInyPYmgr4Js0laEWzbPnTB6TbD+CS+Ky1fP4oW771RfcSRoW1iOrD7niAtDk6XJl9cGDAeMpMuxq+QmQwrxNu9XbAuOi9xGopqVvWU0KqmzYcg0N/Pm42alML9tSw5rUMmZqAqi5r/cGHyYUjrrKob4wQXZ6Nc7qj3ihxyVaBEVUFUhfOiDk1pfqm5mWhG5zOMMRC7GY9F4XDvR9qqlUh3mGVlhKDwCPmPofZuFX3CZwDIRQ8jZgIZlG1C+tFQhe7UW924gnoo7t6hROz3pH4hIi84t9Xc6RUHorDY4xCDSVCiwt7H7WZ6PDVQ0Ux7HV9t1FlKiTZoCqgUUzInysYcEZll5hvZqunnzQ/w4yzpqdg5Gt~-1~-1~-1~AAQAAAAG%2f%2f%2f%2f%2f23nAjEK47lsD7yjkP2d9OS8%2f85mZpQRG96ovYkkmAIUxP0cx84t5g3IP28wTkYQuKLHQ5Tw237oOJ7nJUeRPmemaqqvg3+8KH6+3we+jwBogPVEc49kjaQ6l1%2fCi%2fh6vPcNvIrcYbA4QktqkNaaaTdo2qVLVEGHpyhOgWdEaA%3d%3d~-1; bm_sz=5ECA00B535387B6C022507F802FA7670~YAAQdhGkbovAvpGgAQAAqomlwwELcASTBZN49Ty8fQ1X3RvoHTJZZ3VTVgvj3ALJvJwxDcesuQTwxaXZlVN5ZfyjitfRc5UH4SaIgmD+21Q3qFhS0wmnWvcSckqsCmUbqgGYl9ZqR24EqZU6Gv9mVXz1f5MC6imxItRBkYs/a+WPOEjIY8e8TlYpqeyQaqCNHwqV1+U6Kahu4nYGRPRH+ToQabpl1WdtNjauJcNSNNfhpnkFehUM9NpRQfDVLVolRlQlg4Ne70V21yfVtWFLQDonNRgxvilO1lZd5BdDthtS3X4BZzoOUuJE95VZ63kC/DRh1SK532Xbhsn6XwWxXC+PT4IU0Ezl+rV4iZtX5lIR+WsbowMeWO1PK75w5q6E5AgDklhpSIngGNFNhAIisQQZLrxH6YdsoiEc9NjO7Jm0+YuARM9+eurkQyjTEG4+QhRVmiZMXFcg+F6Ns8oygE1Yn5k=~4403252~3621189; ttm_suggestion=1; bm_mi=43C783C2B5DE6317A17EE483DE6D0468~YAAQXKwwF0wbXIygAQAAij8OxAHGgePK0ZpanpcXTRmLowG7zNqltTZUHQAzk4snXfLlZq/ZRcf0WmEt6RokD334bj9SQ5LunQnphg2KkhI8vzLyJjSncAw6laDsf32aavEJ+90YJjr/28IrwR2jRDooWKfbDOD5TdJ1HJd5WGbCvBl+Hy0kQ2SrVXqPMdxbZrIlZ9521MbSx/kOZQcmrwc/KmpuJy6fvITxY+T0iOhQDvksjPq04L+ckyK/01SZiogiQtqRC1+CXtFR0MF3AU+WHx193AIE9dIPxv/XcEue72NFx70yrLdVjWYqJYu0jnoRWfDJV5x7QCMCB8RuXu+jYLt/Y3rBueMK4cX6t/hGcNXnroNdmEL3~1; ak_bmsc=71C843AD61CBEDFD62CECF0C066AE241~000000000000000000000000000000~YAAQXKwwF1QcXIygAQAA3E8OxAF6wKa+zrv5dVedozGE8QyoIPzRAYyi2XkJvztUqwr/yyE0d38zgnzNdUqysnUQ9sl6GBn/pYZ8lJBukLhzWNk6hYSduyyTaE0yOZwv5Kk9cIJSwMar6vGAYOJ1iaMpZ8qp2tHuKoKmGMN+nscsN+4/AC705b4Ru8m99acWQI/zDxzRtIR9FikDCwgdTLEKt2iLqw9jzVMSXu47IoyMYU1z8eSap0heSZXLZegynmI2c18v2j+r1rTzhEuET9rn7w8LEGYHgNEitqQXwUdQzipJlNxW+keWSemvdcRwtpkqzRzjhs8MgyF8bFdWc55OcCsiSIdQQFar7s5RxqHHpiRROkDXHsYO5ScFoe+YIDXefU9bS0LIyxSFhynTgQZmaHpQH4ShNuqG5YzMt9k8Uv/jtpDjz5FMqvFa4mkIyNMnCjrc/oZA1yFnBFQVI3vXCM96o3xuJVaQqf4BeKL1LO9bxDw6Fr6QcVTRsMrZy+Q+q6I=; __gads=ID=94ef2d83d2bb23a9:T=1781174055:RT=1789995673:S=ALNI_MZ8RCfCUCtQaB28kmDimupEsVEnvQ; __gpi=UID=0000144d69861fd3:T=1781174055:RT=1789995673:S=ALNI_MbOsDngY3tU-hJpwRkuS05kPXEXoA; __eoi=ID=6c3d5d2434eb9d89:T=1781174055:RT=1789995673:S=AA-Afja7LnpYJ9UxD_spf4vaUVZ0; __lt__sid=933cffc9-f78f10e9; _ga_VQH8622D4L=GS2.1.s1789987856$o25$g1$t1789995687$j34$l0$h0; _clsk=38ugh9%5E1789995687893%5E18%5E0%5Ej.clarity.ms%2Fcollect; bm_sv=0CC67DCBAF790A199E373058DB6F039A~YAAQ+TQ+F8pO9b+gAQAAwZ8OxAFnrqSfvBmb/sLhhDWBH1NS/444m9yqG5Rlnrgzmohrdqur0mvtqN96ACb6I/1yYipz5cRS5XVz7gnP95NN0QtPXlLQzT/N9H8wJKhTix/sXu/3PgMDqVYc4sltpKl0ePxFMoU0NFg4wV8ET88BvyUOdoYE2g290HOah/z7gn3EBVf31wpEd/D/rxM9DzfQrAAmHebyQbv27YrikxFi2BS16XE5W3pVGL3bpx51cY515PunbwJIgDCdeOX+r6TE~1; ttcsid_D66LMBBC77U5LKV8L9P0=1789993014192::Mwj_C1Zy68qUGm1fqI9i.44.1789995688608.1; ttcsid=1789993014192::htJfx0ykTxT72jhrpR8d.16.1789995688608.0::1.2671102.2674212::2657054.18.372.44::2680075.6.1087; _twsid=1789993007008-949907337.37.1789995697056'
1037
+ }
1038
+
1039
+
1040
+ const main = async () => {
1041
+ let pttm = new PlayTTM(my_headers_cookies)
1042
+
1043
+ let user_pick = 0
1044
+ let tickets = 1
1045
+ let my_zone = "PL1"
1046
+ let users = [
1047
+ {
1048
+ fullname: "SDFXZCVXZASDF",
1049
+ email: "play2@gmail.com",
1050
+ phone: "0956975152",
1051
+ options: "1254783532123"
1052
+ },
1053
+ {
1054
+ fullname: "ZXCZXCSADj",
1055
+ email: "gg@gmail.com",
1056
+ phone: "0956975152",
1057
+ options: "1123457543216"
1058
+ }
1059
+ ]
1060
+
1061
+ let round_json = await pttm.getRounds("https://www.thaiticketmajor.com/concert/joji-solaris-tour-2026.html")
1062
+
1063
+
1064
+ console.log("ROUND_JSON : ", round_json)
1065
+
1066
+ console.log("HERE :", round_json[user_pick].url.split("=")[1])
1067
+
1068
+ let check_res = await pttm.verify_checkcondition(round_json[user_pick].url.split("=")[1])
1069
+
1070
+ console.log("CHECK_RES : ", check_res)
1071
+
1072
+ let zone_json = await pttm.getZone(round_json[user_pick].url.split("=")[1])
1073
+
1074
+ console.log("ZONE_JSON : ", zone_json)
1075
+
1076
+ let pick_date = Number(round_json[user_pick].date.split(" ")[1])
1077
+
1078
+ const pick_rdId = zone_json.rounds.find((item: any) => {
1079
+ return Number(item.label.split(" ")[1]) === Number(pick_date);
1080
+ });
1081
+
1082
+ console.log("USER PICK : ", round_json[user_pick].date.split(" ")[1])
1083
+ console.log("PICK RDID : ", pick_rdId)
1084
+
1085
+ if (!pick_rdId) {
1086
+ throw new Error("Round not found");
1087
+ }
1088
+
1089
+ let zone_avail = await pttm.getZoneAvail(pick_rdId.id, zone_json.tk, zone_json.k, round_json[user_pick].url.split("=")[1])
1090
+
1091
+ let type_perform: any = zone_avail.filter((item: any) => {
1092
+ return item.id == my_zone ? item : null
1093
+ })
1094
+
1095
+ console.log("ZONE_AVAIL : ", zone_avail)
1096
+ console.log("CHECK TYPE PERFORM USER PICK : ", type_perform)
1097
+
1098
+ if (type_perform.length == 0) {
1099
+ console.log("ไม่พบโซนที่เลือก")
1100
+ return
1101
+ }
1102
+
1103
+ if (type_perform[0].page == 'fixed.php') {
1104
+ let all_seats_in_zone = await pttm.getFixed(zone_json.k, my_zone, pick_rdId.id)
1105
+
1106
+ let seats = all_seats_in_zone.seats
1107
+ let seats_json = all_seats_in_zone.form
1108
+
1109
+ let total_seats = []
1110
+
1111
+ for (let i = 0; i < tickets; i++) {
1112
+ const randomIndex = Math.floor(Math.random() * seats.length);
1113
+ let seat_pick = seats[randomIndex]
1114
+ total_seats.push(seat_pick)
1115
+ }
1116
+
1117
+ let seat_valid = await pttm.validateSeatFix(zone_json.k, my_zone, seats_json, total_seats, 'fix')
1118
+
1119
+ if (seat_valid.result == true && seat_valid.status == 0) {
1120
+ let booking_res = await pttm.bookingSeats(zone_json.k, seats_json, total_seats)
1121
+
1122
+ const enrollVal = booking_res.nextPayload.get("enroll_val");
1123
+
1124
+ if (enrollVal == '0') {
1125
+ let paymentall_json = await pttm.getPaymentAll(zone_json.k, booking_res, my_zone, seats_json.rdId, 2000)
1126
+
1127
+ console.log("PaymentAllJSON : ", paymentall_json)
1128
+
1129
+ let paycfmall = await pttm.getPayCfmall(zone_json.k, paymentall_json, '1', 'KBQR')
1130
+
1131
+ console.log("PayCFMALL : ", paycfmall)
1132
+ let orderenc_json = await pttm.orderenc_kbankqr(zone_json.k, paycfmall)
1133
+ console.log("ORDERENC_JSON : ", orderenc_json)
1134
+ let kbank_json = await pttm.getkbankqr(orderenc_json)
1135
+ console.log("KBANK_JSON : ", kbank_json)
1136
+ let data = await pttm.payment_kbankqr(orderenc_json, kbank_json)
1137
+ console.log("PAYMENT_KBANKQR : ", data)
1138
+ let result = await pttm.QR(data.orderId, data.apiKey, orderenc_json)
1139
+ console.log("RESULT : ", data)
1140
+
1141
+ console.log(result)
1142
+ } else {
1143
+ let enroll_json = await pttm.enroll(zone_json.k, my_zone, seats_json.rdId, booking_res.nextPayload)
1144
+ console.log("ENROLL_JSON : ", enroll_json)
1145
+ let enroll_process_status = await pttm.enroll_process(zone_json.k, enroll_json, users)
1146
+ console.log("ENROLL_PROCESS_STATUS : ", enroll_process_status)
1147
+ let paymentall_json = await pttm.getPaymentAll(zone_json.k, enroll_process_status.nextPayload, my_zone, seats_json.rdId, 2000)
1148
+ console.log("PaymentAllJSON : ", paymentall_json)
1149
+ let paycfmall = await pttm.getPayCfmall(zone_json.k, paymentall_json, '1', 'KBQR')
1150
+ console.log("PayCFMALL : ", paycfmall)
1151
+ let orderenc_json = await pttm.orderenc_kbankqr(zone_json.k, paycfmall)
1152
+ console.log("ORDERENC_JSON : ", orderenc_json)
1153
+ let kbank_json = await pttm.getkbankqr(orderenc_json)
1154
+ console.log("KBANK_JSON : ", kbank_json)
1155
+ let data = await pttm.payment_kbankqr(orderenc_json, kbank_json)
1156
+ console.log("PAYMENT_KBANKQR : ", data)
1157
+ let result = await pttm.QR(data.orderId, data.apiKey, orderenc_json)
1158
+ console.log(result)
1159
+ }
1160
+ }
1161
+ } else {
1162
+ console.log("This Perform is under development")
1163
+
1164
+ let festival = await pttm.Festival(zone_json.k, zone_json.tk, zone_json.query, my_zone, pick_rdId.id)
1165
+
1166
+ console.log("FESTIVAL TEST : ", festival)
1167
+
1168
+ let validate_seat_festival = await pttm.validateSeatFestival(zone_json.k, festival, tickets.toString())
1169
+
1170
+ console.log("VALIDATE SEAT FESTIVAL : ", validate_seat_festival)
1171
+
1172
+ if (festival.enroll_val != '0') {
1173
+ let bookingfestival_response = await pttm.BookingFestival(zone_json.k, festival, tickets.toString())
1174
+
1175
+ let enroll_process_test = await pttm.enroll_process(zone_json.k, festival, users)
1176
+
1177
+ let paymentallFesitval = await pttm.getPaymentAll(zone_json.k, bookingfestival_response, festival.zone, festival.rdId, 2000)
1178
+
1179
+ let cf = await pttm.getPayCfmall(zone_json.k, paymentallFesitval, '1', 'KBQR')
1180
+
1181
+ let orderenc_json = await pttm.orderenc_kbankqr(zone_json.k, cf)
1182
+ let kbank_json = await pttm.getkbankqr(orderenc_json)
1183
+
1184
+ let data = await pttm.payment_kbankqr(orderenc_json, kbank_json)
1185
+
1186
+ let result = await pttm.QR(data.orderId, data.apiKey, orderenc_json)
1187
+
1188
+
1189
+ console.log("Booking Festival Response : ", bookingfestival_response)
1190
+
1191
+ console.log("ENROLL PROCESS TEST", enroll_process_test)
1192
+
1193
+ console.log("PaymentallFestival", paymentallFesitval)
1194
+
1195
+ console.log("PAYCFMALL : ", cf)
1196
+
1197
+ console.log("ORDERENC_JSON : ", orderenc_json)
1198
+
1199
+ console.log("KBANK_JSON : ", kbank_json)
1200
+
1201
+ console.log("PAYMENT_KBANKQR : ", data)
1202
+
1203
+ console.log(result)
1204
+ }
1205
+
1206
+ }
1207
+ }
1208
+
1209
+ main()