globalpayments-api 3.11.4 → 3.13.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.
Files changed (37) hide show
  1. package/CHANGELOG.md +15 -1
  2. package/lib/src/Builders/AuthorizationBuilder.d.ts +0 -1
  3. package/lib/src/Builders/AuthorizationBuilder.js +0 -4
  4. package/lib/src/Builders/AuthorizationBuilder.js.map +1 -1
  5. package/lib/src/Builders/RecurringBuilder.js +12 -1
  6. package/lib/src/Builders/RecurringBuilder.js.map +1 -1
  7. package/lib/src/Terminals/Builders/TerminalAuthBuilder.d.ts +17 -4
  8. package/lib/src/Terminals/Builders/TerminalAuthBuilder.js +38 -5
  9. package/lib/src/Terminals/Builders/TerminalAuthBuilder.js.map +1 -1
  10. package/lib/src/Terminals/Builders/TerminalBuilder.d.ts +0 -1
  11. package/lib/src/Terminals/Builders/TerminalBuilder.js +0 -1
  12. package/lib/src/Terminals/Builders/TerminalBuilder.js.map +1 -1
  13. package/lib/src/Terminals/Builders/TerminalManageBuilder.d.ts +5 -0
  14. package/lib/src/Terminals/Builders/TerminalManageBuilder.js +16 -0
  15. package/lib/src/Terminals/Builders/TerminalManageBuilder.js.map +1 -1
  16. package/lib/src/Terminals/TerminalResponse.d.ts +4 -0
  17. package/lib/src/Terminals/TerminalResponse.js +4 -0
  18. package/lib/src/Terminals/TerminalResponse.js.map +1 -1
  19. package/lib/src/Terminals/UPA/Reponses/TransactionResponse.d.ts +7 -0
  20. package/lib/src/Terminals/UPA/Reponses/TransactionResponse.js +38 -0
  21. package/lib/src/Terminals/UPA/Reponses/TransactionResponse.js.map +1 -1
  22. package/lib/src/Terminals/UPA/UpaController.js +116 -17
  23. package/lib/src/Terminals/UPA/UpaController.js.map +1 -1
  24. package/lib/test/Integration/Gateways/GpApiConnector/GpApiMMAAccount.test.d.ts +1 -0
  25. package/lib/test/Integration/Gateways/GpApiConnector/GpApiMMAAccount.test.js +177 -0
  26. package/lib/test/Integration/Gateways/GpApiConnector/GpApiMMAAccount.test.js.map +1 -0
  27. package/lib/test/Unit/Gateways/GpApiConnector/GpApiMMAAccount.test.d.ts +1 -0
  28. package/lib/test/Unit/Gateways/GpApiConnector/GpApiMMAAccount.test.js +29 -0
  29. package/lib/test/Unit/Gateways/GpApiConnector/GpApiMMAAccount.test.js.map +1 -0
  30. package/lib/test/Unit/Terminals/Builders/TerminalBuilderParityTests.test.d.ts +17 -0
  31. package/lib/test/Unit/Terminals/Builders/TerminalBuilderParityTests.test.js +325 -0
  32. package/lib/test/Unit/Terminals/Builders/TerminalBuilderParityTests.test.js.map +1 -0
  33. package/lib/test/Unit/Terminals/UPA/UpaAdmin.test.js +2246 -446
  34. package/lib/test/Unit/Terminals/UPA/UpaAdmin.test.js.map +1 -1
  35. package/lib/test/Unit/Terminals/UPA/UpaCredit.test.js +703 -26
  36. package/lib/test/Unit/Terminals/UPA/UpaCredit.test.js.map +1 -1
  37. package/package.json +2 -2
@@ -430,32 +430,433 @@ afterEach(async () => {
430
430
  console.warn(`updateLodginDetail() ERR010 scenario not reproduced: device accepted the malformed amount with status="${response?.status}" code="${response?.deviceResponseCode}". Per UPA doc an amount missing the leading zero SHOULD be rejected — the current firmware may be tolerating the drift.`);
431
431
  });
432
432
  });
433
+ (0, UpaHelpertest_1.describeUpaLive)("UPA void test case void support and response parsing ", () => {
434
+ let device;
435
+ beforeEach(() => {
436
+ device = (0, UpaHelpertest_1.createTestDevice)();
437
+ });
438
+ test("void support ", async () => {
439
+ const saleResponse = (await device
440
+ .sale(75.0)
441
+ .withEcrId(12)
442
+ .withClerkId(789)
443
+ .execute());
444
+ expect(saleResponse.status).toBe("Success");
445
+ const voidResponse = (await device
446
+ .void()
447
+ .withEcrId(12)
448
+ .withTerminalRefNumber(saleResponse.terminalRefNumber)
449
+ .withTransactionId(saleResponse.transactionId)
450
+ .withAmount(saleResponse.transactionAmount)
451
+ .execute());
452
+ expect(voidResponse).not.toBeNull();
453
+ expect(voidResponse.status).toBe("Success");
454
+ });
455
+ });
456
+ (0, UpaHelpertest_1.describeUpaLive)("UPA test for capture/Authcompletion ", () => {
457
+ let device;
458
+ beforeEach(() => {
459
+ device = (0, UpaHelpertest_1.createTestDevice)();
460
+ });
461
+ /**
462
+ * Test 1: Basic Capture
463
+ * Per UPA Spec §12.4.16 - AuthCompletion with mandatory fields
464
+ * Mandatory: referenceNumber, amount
465
+ */
466
+ test("UPA Capture - Basic (Auth → Capture)", async () => {
467
+ const authAmount = 10.0;
468
+ const captureAmount = 10.0;
469
+ const ecrId = "1";
470
+ // Step 1: Authorize to get transaction ID
471
+ const authResponse = await device
472
+ .authorize(authAmount)
473
+ .withEcrId(ecrId)
474
+ .execute();
475
+ expect(authResponse).toBeDefined();
476
+ expect(authResponse.status).toBe("Success");
477
+ expect(authResponse.transactionId).toBeTruthy();
478
+ await settleDevice();
479
+ // Step 2: Capture the authorized amount
480
+ const captureResponse = (await device
481
+ .capture(captureAmount)
482
+ .withEcrId(ecrId)
483
+ .withTransactionId(authResponse.transactionId)
484
+ .execute());
485
+ expect(captureResponse).toBeDefined();
486
+ expect(captureResponse.status).toBe("Success");
487
+ expect(captureResponse.deviceResponseCode).toBe("00");
488
+ expect(captureResponse.cardType).toBeDefined();
489
+ expect(captureResponse.transactionId).toBeTruthy();
490
+ // Note: transactionAmount may include device surcharges
491
+ expect(captureResponse.transactionAmount).toBeGreaterThanOrEqual(captureAmount);
492
+ console.log(`[Capture Basic] TransId: ${captureResponse.transactionId}, Amount: ${captureResponse.transactionAmount}`);
493
+ });
494
+ /**
495
+ * Test 2: Capture with Tax and Tip
496
+ * Per UPA Spec §12.4.16 - Optional fields: taxAmount, tipAmount
497
+ * Verifies proper amount aggregation
498
+ */
499
+ test("UPA Capture - with Tax and Tip", async () => {
500
+ const authAmount = 50.0;
501
+ const taxAmount = 5.0;
502
+ const tipAmount = 10.0;
503
+ const ecrId = "1";
504
+ // Step 1: Authorize
505
+ const authResponse = await device
506
+ .authorize(authAmount)
507
+ .withEcrId(ecrId)
508
+ .execute();
509
+ expect(authResponse).toBeDefined();
510
+ expect(authResponse.status).toBe("Success");
511
+ expect(authResponse.transactionId).toBeTruthy();
512
+ await settleDevice();
513
+ // Step 2: Capture with tax and tip
514
+ const captureResponse = (await device
515
+ .capture(authAmount)
516
+ .withEcrId(ecrId)
517
+ .withTransactionId(authResponse.transactionId)
518
+ .withTaxAmount(taxAmount)
519
+ .withGratuity(tipAmount)
520
+ .execute());
521
+ expect(captureResponse).toBeDefined();
522
+ expect(captureResponse.status).toBe("Success");
523
+ expect(captureResponse.deviceResponseCode).toBe("00");
524
+ // Verify amounts
525
+ // Note: Device may or may not aggregate tax and tip into total amount
526
+ // At minimum, should have at least the base authorized amount
527
+ expect(captureResponse.transactionAmount).toBeGreaterThanOrEqual(authAmount);
528
+ // Log actual values received for debugging
529
+ console.log(`[Capture Tax+Tip] Amount: ${captureResponse.transactionAmount}, Tax: ${captureResponse.taxAmount}, Tip: ${captureResponse.tipAmount}`);
530
+ // Verify tax and tip if populated (may be undefined depending on device response format)
531
+ if (captureResponse.taxAmount !== undefined) {
532
+ expect(captureResponse.taxAmount).toBeCloseTo(taxAmount, 2);
533
+ }
534
+ if (captureResponse.tipAmount !== undefined) {
535
+ expect(captureResponse.tipAmount).toBeCloseTo(tipAmount, 2);
536
+ }
537
+ });
538
+ /**
539
+ * Test 3: Capture with Tax Indicator (Tax Exempt)
540
+ * Per UPA Spec §12.4.16 - taxIndicator: 0 or 1
541
+ * 0 = tax applicable, 1 = tax exempt
542
+ */
543
+ test("UPA Capture - with Tax Indicator (Tax Exempt)", async () => {
544
+ const authAmount = 30.0;
545
+ const ecrId = "1";
546
+ const taxIndicator = 1; // 1 = tax exempt
547
+ // Step 1: Authorize
548
+ const authResponse = await device
549
+ .authorize(authAmount)
550
+ .withEcrId(ecrId)
551
+ .execute();
552
+ expect(authResponse).toBeDefined();
553
+ expect(authResponse.status).toBe("Success");
554
+ await settleDevice();
555
+ // Step 2: Capture with tax exempt indicator
556
+ const captureResponse = (await device
557
+ .capture(authAmount)
558
+ .withEcrId(ecrId)
559
+ .withTransactionId(authResponse.transactionId)
560
+ .withTaxIndicator(taxIndicator)
561
+ .execute());
562
+ expect(captureResponse).toBeDefined();
563
+ expect(captureResponse.status).toBe("Success");
564
+ // Note: Device may add surcharges, so check for >= base amount
565
+ expect(captureResponse.transactionAmount).toBeGreaterThanOrEqual(authAmount);
566
+ console.log(`[Capture TaxExempt] Amount: ${captureResponse.transactionAmount}, TaxIndicator: ${taxIndicator}`);
567
+ });
568
+ /**
569
+ * Test 4: Capture with Invoice Number
570
+ * Per UPA Spec §12.4.16 - invoiceNbr: AN(1-16)
571
+ */
572
+ test("UPA Capture - with Invoice Number", async () => {
573
+ const authAmount = 25.0;
574
+ const ecrId = "1";
575
+ const invoiceNum = "INV-" + Date.now().toString().slice(-8);
576
+ // Step 1: Authorize
577
+ const authResponse = await device
578
+ .authorize(authAmount)
579
+ .withEcrId(ecrId)
580
+ .execute();
581
+ expect(authResponse).toBeDefined();
582
+ expect(authResponse.status).toBe("Success");
583
+ await settleDevice();
584
+ // Step 2: Capture with invoice number
585
+ const captureResponse = (await device
586
+ .capture(authAmount)
587
+ .withEcrId(ecrId)
588
+ .withTransactionId(authResponse.transactionId)
589
+ .withInvoiceNumber(invoiceNum)
590
+ .execute());
591
+ expect(captureResponse).toBeDefined();
592
+ expect(captureResponse.status).toBe("Success");
593
+ // Invoice number may not be returned in response - if it is, verify it matches
594
+ if (captureResponse.invoiceNumber !== undefined &&
595
+ captureResponse.invoiceNumber !== "") {
596
+ expect(captureResponse.invoiceNumber).toBe(invoiceNum);
597
+ }
598
+ // Amount check (with device surcharges allowance)
599
+ expect(captureResponse.transactionAmount).toBeGreaterThanOrEqual(authAmount);
600
+ console.log(`[Capture Invoice] Invoice: ${captureResponse.invoiceNumber}, Amount: ${captureResponse.transactionAmount}`);
601
+ });
602
+ /**
603
+ * Test 5: Capture with Processing CPC (Commercial Card Processing)
604
+ * Per UPA Spec §12.4.16 - processCPC: 0 or 1
605
+ * 0 = No, 1 = Yes
606
+ */
607
+ test("UPA Capture - with Processing CPC", async () => {
608
+ const authAmount = 100.0;
609
+ const ecrId = "1";
610
+ // Step 1: Authorize
611
+ const authResponse = await device
612
+ .authorize(authAmount)
613
+ .withEcrId(ecrId)
614
+ .execute();
615
+ expect(authResponse).toBeDefined();
616
+ expect(authResponse.status).toBe("Success");
617
+ await settleDevice();
618
+ // Step 2: Capture with CPC processing
619
+ const captureResponse = (await device
620
+ .capture(authAmount)
621
+ .withEcrId(ecrId)
622
+ .withTransactionId(authResponse.transactionId)
623
+ .withProcessCPC(true)
624
+ .execute());
625
+ expect(captureResponse).toBeDefined();
626
+ expect(captureResponse.status).toBe("Success");
627
+ // Device may add surcharges, so check for >= base amount
628
+ expect(captureResponse.transactionAmount).toBeGreaterThanOrEqual(authAmount);
629
+ console.log(`[Capture CPC] Amount: ${captureResponse.transactionAmount}, ProcessCPC: true`);
630
+ });
631
+ /**
632
+ * Test 6: Capture with All Fields
633
+ * Per UPA Spec §12.4.16 - Comprehensive test with all optional fields
634
+ * Fields: amount, preAuthAmount, taxAmount, tipAmount, taxIndicator, processCPC
635
+ */
636
+ test("UPA Capture - with All Fields", async () => {
637
+ const authAmount = 75.0;
638
+ const taxAmount = 7.5;
639
+ const tipAmount = 15.0;
640
+ const ecrId = "1";
641
+ const invoiceNum = "FULL-" + Date.now().toString().slice(-6);
642
+ const taxIndicator = 0; // 0 = tax applicable
643
+ // Step 1: Authorize
644
+ const authResponse = await device
645
+ .authorize(authAmount)
646
+ .withEcrId(ecrId)
647
+ .execute();
648
+ expect(authResponse).toBeDefined();
649
+ expect(authResponse.status).toBe("Success");
650
+ await settleDevice();
651
+ // Step 2: Capture with all fields
652
+ const captureResponse = (await device
653
+ .capture(authAmount)
654
+ .withEcrId(ecrId)
655
+ .withTransactionId(authResponse.transactionId)
656
+ .withTaxAmount(taxAmount)
657
+ .withGratuity(tipAmount)
658
+ .withTaxIndicator(taxIndicator)
659
+ .withInvoiceNumber(invoiceNum)
660
+ .withProcessCPC(true)
661
+ .execute());
662
+ expect(captureResponse).toBeDefined();
663
+ expect(captureResponse.status).toBe("Success");
664
+ expect(captureResponse.deviceResponseCode).toBe("00");
665
+ // Verify all fields
666
+ expect(captureResponse.transactionId).toBeTruthy();
667
+ // Device may not aggregate all tax/tip components into total - at minimum check base amount
668
+ expect(captureResponse.transactionAmount).toBeGreaterThanOrEqual(authAmount);
669
+ // Tax and tip may be undefined or may be populated
670
+ if (captureResponse.taxAmount !== undefined &&
671
+ captureResponse.taxAmount > 0) {
672
+ expect(captureResponse.taxAmount).toBeGreaterThanOrEqual(0);
673
+ }
674
+ if (captureResponse.tipAmount !== undefined &&
675
+ captureResponse.tipAmount > 0) {
676
+ expect(captureResponse.tipAmount).toBeGreaterThanOrEqual(0);
677
+ }
678
+ expect(captureResponse.cardType).toBeDefined();
679
+ expect(captureResponse.maskedCardNumber).toBeDefined();
680
+ console.log(`[Capture AllFields] Amount: ${captureResponse.transactionAmount}, Tax: ${captureResponse.taxAmount}, Tip: ${captureResponse.tipAmount}, Invoice: ${captureResponse.invoiceNumber}, ClerkId: ${captureResponse.clerkId}`);
681
+ });
682
+ /**
683
+ * Test 7: Capture Response Field Parsing
684
+ * Per UPA Spec §12.4.16.5 - Validates all output parameters
685
+ * Verifies proper response parsing from device
686
+ */
687
+ test("UPA Capture - Response Field Parsing", async () => {
688
+ const authAmount = 40.0;
689
+ const ecrId = "1";
690
+ // Step 1: Authorize
691
+ const authResponse = await device
692
+ .authorize(authAmount)
693
+ .withEcrId(ecrId)
694
+ .execute();
695
+ expect(authResponse).toBeDefined();
696
+ expect(authResponse.status).toBe("Success");
697
+ await settleDevice();
698
+ // Step 2: Capture to validate response parsing
699
+ const captureResponse = (await device
700
+ .capture(authAmount)
701
+ .withEcrId(ecrId)
702
+ .withTransactionId(authResponse.transactionId)
703
+ .execute());
704
+ // Core transaction identifiers (per §12.4.16.5)
705
+ expect(captureResponse.transactionId).toBeTruthy(); // responseId: N16
706
+ expect(captureResponse.terminalRefNumber).toBeTruthy(); // tranNo: N4
707
+ expect(captureResponse.approvalCode).toBeTruthy(); // approvalCode: AN6
708
+ // Response codes (per §12.4.16.5)
709
+ expect(typeof captureResponse.responseCode).toBe("string");
710
+ expect(typeof captureResponse.responseText).toBe("string");
711
+ expect(typeof captureResponse.deviceResponseCode).toBe("string");
712
+ expect(typeof captureResponse.deviceResponseText).toBe("string");
713
+ // Card information (per §12.4.16.5)
714
+ expect(typeof captureResponse.cardType).toBe("string");
715
+ expect(typeof captureResponse.maskedCardNumber).toBe("string");
716
+ expect(captureResponse.maskedCardNumber).toMatch(/^\d{0,25}$/);
717
+ // Status validation
718
+ expect(captureResponse.status).toBe("Success");
719
+ expect(captureResponse.deviceResponseCode).toBe("00"); // "00" = Success
720
+ // Amount validation
721
+ expect(captureResponse.transactionAmount).toBeCloseTo(authAmount, 2);
722
+ expect(typeof captureResponse.transactionAmount).toBe("number");
723
+ // Gateway response info (per §12.4.16.5)
724
+ expect(typeof captureResponse.gatewayResponseCode).toBe("string");
725
+ expect(typeof captureResponse.gatewayResponseMessage).toBe("string");
726
+ console.log(`[Capture ResponseParsing] TransId: ${captureResponse.transactionId}, RefNum: ${captureResponse.terminalRefNumber}, ApprovalCode: ${captureResponse.approvalCode}, CardType: ${captureResponse.cardType}`);
727
+ });
728
+ });
433
729
  // ===========================================================================
434
- // sale() with enhanced field support
730
+ // COMPREHENSIVE INTEGRATED TEST SCENARIOS FROM SPEC
435
731
  // ===========================================================================
436
- (0, UpaHelpertest_1.describeUpaLive)("UPA Credit – sale() with enhanced fields", () => {
732
+ (0, UpaHelpertest_1.describeUpaLive)("UPA Credit – Comprehensive Builder Scenarios (Spec Compliance)", () => {
437
733
  let device;
438
734
  beforeEach(() => {
439
735
  device = (0, UpaHelpertest_1.createTestDevice)();
440
736
  });
441
- test("sale() includes clerkId field", async () => {
442
- const response = await device
443
- .sale(10)
737
+ test("[UpaCreditTests:SPEC-001] Sale with ClerkId + TaxAmount", async () => {
738
+ const builder = device
739
+ .sale(25.0)
740
+ .withEcrId(13)
741
+ .withClerkId(1234)
742
+ .withTaxAmount(2.5);
743
+ const response = await builder.execute();
744
+ expect(response.status).toBe("Success");
745
+ expect(response.deviceResponseCode).toBe("00");
746
+ });
747
+ test("[UpaCreditTests:SPEC-003] Sale with CardBrandTransId", async () => {
748
+ const request = device
749
+ .sale(75.0)
750
+ .withEcrId(13)
751
+ .withCardBrandTransId("MCC0484550831");
752
+ const response = await request.execute();
753
+ expect(response).toBeDefined();
754
+ expect(response.status).toBe("Success");
755
+ expect(response.deviceResponseCode).toBe("00");
756
+ expect(response.command).toBe("Sale");
757
+ expect(response.cardBrandTransId).toBeDefined();
758
+ });
759
+ test("[UpaCreditTests:SPEC-004] PreAuth with ClerkId + TaxAmount", async () => {
760
+ const authresponse = await device
761
+ .authorize(10.0)
444
762
  .withEcrId(13)
445
- .withClerkId(123)
446
763
  .execute();
764
+ expect(authresponse).toBeDefined();
765
+ expect(authresponse.status).toBe("Success");
766
+ expect(authresponse.deviceResponseCode).toBe("00");
767
+ const controller = src_1.ServicesContainer.instance().getDeviceController();
768
+ const builder = device
769
+ .capture(100.0)
770
+ .withEcrId(13)
771
+ .withClerkId(1111)
772
+ .withTransactionId(authresponse.transactionId)
773
+ .withTaxAmount(5.0);
774
+ const request = controller
775
+ .buildProcessTransaction(builder)
776
+ .getJsonRequest();
777
+ expect(request.data.command).toBe("AuthCompletion");
778
+ expect(request.data.data.params.clerkId).toBe(1111);
779
+ expect(request.data.data.transaction.taxAmount).toBe("5.00");
780
+ const response = await builder.execute();
781
+ expect(response).toBeDefined();
782
+ expect(response.status).toBe("Success");
783
+ expect(response.deviceResponseCode).toBe("00");
784
+ });
785
+ test("[UpaCreditTests:SPEC-005] Incremental Auth with preAuthAmount - toFixed(2) validation", async () => {
786
+ const controller = src_1.ServicesContainer.instance().getDeviceController();
787
+ const builder = device
788
+ .authorize(10.123)
789
+ .withEcrId(13)
790
+ .withPreAuthAmount(10.123);
791
+ const request = controller
792
+ .buildProcessTransaction(builder)
793
+ .getJsonRequest();
794
+ const response = await builder.execute();
795
+ expect(response).toBeDefined();
796
+ expect(response.status).toBe("Success");
797
+ expect(response.deviceResponseCode).toBe("00");
798
+ console.log(`[UpaCreditTests:SPEC-005] PreAuth amount 10.123 formatted as:\n` +
799
+ JSON.stringify(request.data.data.transaction.preAuthAmount, null, 2));
800
+ // Verify correct toFixed(2) formatting in REQUEST (device doesn't echo preAuthAmount back)
801
+ expect(request.data.data.transaction.preAuthAmount).toBe("10.12");
802
+ // Note: preAuthAmount is request-only; device does not echo it in response
803
+ console.log(`[UpaCreditTests:SPEC-005] Response preAuthAmount: "${response.preAuthAmount ?? "not returned by device"}"`);
804
+ });
805
+ test("[UpaCreditTests:SPEC-011] Tax Amount Variants", async () => {
806
+ const controller = src_1.ServicesContainer.instance().getDeviceController();
807
+ const builder = device
808
+ .sale(100.0)
809
+ .withEcrId(13)
810
+ .withTaxAmount(5.25);
811
+ const request = controller
812
+ .buildProcessTransaction(builder)
813
+ .getJsonRequest();
814
+ console.log(`[UpaCreditTests:SPEC-011] TaxAmount Standard tax:\n` +
815
+ JSON.stringify(request.data.data.transaction.taxAmount));
816
+ const response = await builder.execute();
447
817
  expect(response).toBeDefined();
448
818
  expect(response.status).toBe("Success");
449
- console.log(`[Sale ClerkId] Amount: ${response.transactionAmount}, Status: ${response.status}`);
819
+ expect(response.deviceResponseCode).toBe("00");
820
+ expect(request.data.data.transaction.taxAmount).toBe("5.25");
450
821
  });
451
- test("sale() includes cardBrandTransId field", async () => {
822
+ test("[UpaCreditTests:506] sale() serializes prescription amount", async () => {
823
+ const controller = src_1.ServicesContainer.instance().getDeviceController();
824
+ const builder = device
825
+ .sale(6.0)
826
+ .withEcrId(13)
827
+ .withPrescriptionAmount(25.5)
828
+ .withClinicAmount(35.75)
829
+ .withDentalAmount(40.25);
830
+ const request = controller
831
+ .buildProcessTransaction(builder)
832
+ .getJsonRequest();
833
+ const response = await builder.execute();
834
+ expect(response).toBeDefined();
835
+ expect(response.status).toBe("Success");
836
+ expect(response.deviceResponseCode).toBe("00");
837
+ expect(request.data.command).toBe("Sale");
838
+ expect(request.data.data.transaction.prescriptionAmount).toBe("25.50");
839
+ expect(request.data.data.transaction.clinicAmount).toBe("35.75");
840
+ expect(request.data.data.transaction.dentalAmount).toBe("40.25");
841
+ });
842
+ });
843
+ // ===========================================================================
844
+ // sale() with enhanced field support
845
+ // ===========================================================================
846
+ (0, UpaHelpertest_1.describeUpaLive)("UPA Credit – sale() with enhanced fields", () => {
847
+ let device;
848
+ beforeEach(() => {
849
+ device = (0, UpaHelpertest_1.createTestDevice)();
850
+ });
851
+ test("verify() includes cardBrandTransId field", async () => {
452
852
  const response = await device
453
- .sale(15)
853
+ .verify()
454
854
  .withEcrId(13)
455
- .withCardBrandTransId("CARD-BRAND-ID-123")
855
+ .withCardBrandTransId("MCC0484550831")
456
856
  .execute();
457
857
  expect(response).toBeDefined();
458
858
  expect(response.status).toBe("Success");
859
+ expect(response.cardBrandTransId).toBeDefined();
459
860
  console.log(`[Sale CardBrandTransId] Amount: ${response.transactionAmount}, Status: ${response.status}`);
460
861
  });
461
862
  test("sale() includes directMkt fields (shippingDate)", async () => {
@@ -464,25 +865,11 @@ afterEach(async () => {
464
865
  .sale(20)
465
866
  .withEcrId(13)
466
867
  .withShippingDate(shippingDate)
467
- .withInvoiceNumber("INV-2025-001")
868
+ .withInvoiceNumber("INV2025001")
468
869
  .execute();
469
870
  expect(response).toBeDefined();
470
871
  expect(response.status).toBe("Success");
471
872
  });
472
- test("sale() includes acquisitionTypes in request", async () => {
473
- const builder = device
474
- .sale(10)
475
- .withEcrId(13)
476
- .withAcquisitionTypes([
477
- AcquisitionType_1.AcquisitionType.Chip,
478
- AcquisitionType_1.AcquisitionType.Contactless,
479
- ]);
480
- console.log("\n===== EXECUTING SALE WITH ACQUISITION TYPES =====");
481
- const response = await builder.execute();
482
- console.log("Response Status:", response.status);
483
- console.log("Response:", JSON.stringify(response, null, 2));
484
- expect(response).toBeDefined();
485
- });
486
873
  });
487
874
  // ===========================================================================
488
875
  // authorize() with enhanced field support
@@ -507,7 +894,7 @@ afterEach(async () => {
507
894
  const response = await device
508
895
  .authorize(30)
509
896
  .withEcrId(12)
510
- .withCardBrandTransId("BRAND-TRANS-456")
897
+ .withCardBrandTransId("MCC0484550831")
511
898
  .execute();
512
899
  expect(response).toBeDefined();
513
900
  expect(response.status).toBe("Success");
@@ -524,4 +911,294 @@ afterEach(async () => {
524
911
  console.log(`[Auth PreAuthAmount] Amount: ${response.transactionAmount}, Status: ${response.status}`);
525
912
  });
526
913
  });
914
+ // ===========================================================================
915
+ // JIRA Story Requirements – Field Validation
916
+ // ===========================================================================
917
+ describe("JIRA Story: UPA Transaction Processing – Field Validation", () => {
918
+ let device;
919
+ beforeEach(() => {
920
+ device = (0, UpaHelpertest_1.createTestDevice)();
921
+ });
922
+ /**
923
+ * Requirement: clerkId
924
+ * Status: withClerkId() method should be available on builder
925
+ */
926
+ test("[Requirement:clerkId] Builder has withClerkId method", async () => {
927
+ const builder = device.sale(10.0);
928
+ expect(builder).toHaveProperty("withClerkId");
929
+ expect(typeof builder.withClerkId).toBe("function");
930
+ // Should be chainable
931
+ const chained = builder.withClerkId(123);
932
+ const result = await chained.withEcrId("13").execute();
933
+ expect(result.status).toBe("Success");
934
+ expect(chained).toBeDefined();
935
+ expect(chained).toEqual(builder); // Returns self for chaining
936
+ });
937
+ /**
938
+ * Requirement: cardBrandTransId
939
+ * Status: withCardBrandTransId() method should exist and work
940
+ */
941
+ test("[Requirement:cardBrandTransId] Builder has withCardBrandTransId method", async () => {
942
+ const builder = device.sale(10.0).withEcrId("13");
943
+ const transId = "ABC123XYZ";
944
+ expect(builder).toHaveProperty("withCardBrandTransId");
945
+ expect(typeof builder.withCardBrandTransId).toBe("function");
946
+ // Should be chainable and store value
947
+ const chained = builder.withCardBrandTransId(transId);
948
+ const response = await chained.execute();
949
+ expect(response.status).toBe("Success");
950
+ expect(chained).toBeDefined();
951
+ expect(chained).toEqual(builder);
952
+ expect(builder.cardBrandTransId).toBe(transId);
953
+ });
954
+ /**
955
+ * Requirement: cardOnFileIndicator
956
+ * Status: Should support CardHolder ('C'), Merchant ('M')
957
+ * Note: R (Recurring) and I (Installment) may require additional enum values
958
+ */
959
+ test("[Requirement:cardOnFileIndicator] Builder supports CardHolder and Merchant indicators", async () => {
960
+ const builderCH = device
961
+ .sale(10.0)
962
+ .withCardOnFileIndicator(src_1.StoredCredentialInitiator.CardHolder);
963
+ const builderM = device
964
+ .sale(10.0)
965
+ .withCardOnFileIndicator(src_1.StoredCredentialInitiator.Merchant);
966
+ expect(builderCH.cardOnFileIndicator).toBe(src_1.StoredCredentialInitiator.CardHolder);
967
+ expect(builderM.cardOnFileIndicator).toBe(src_1.StoredCredentialInitiator.Merchant);
968
+ const responseCH = await builderCH.withEcrId("13").execute();
969
+ const responseM = await builderM.withEcrId("13").execute();
970
+ expect(responseCH.status).toBe("Success");
971
+ expect(responseM.status).toBe("Success");
972
+ });
973
+ /**
974
+ * Requirement: preAuthAmount
975
+ * Status: withPreAuthAmount() should exist and use proper formatting
976
+ */
977
+ test("[Requirement:preAuthAmount] Builder has withPreAuthAmount with proper formatting", async () => {
978
+ const builder = device.authorize(15.0);
979
+ const preAuthAmt = 25.99;
980
+ expect(builder).toHaveProperty("withPreAuthAmount");
981
+ expect(typeof builder.withPreAuthAmount).toBe("function");
982
+ builder.withPreAuthAmount(preAuthAmt);
983
+ expect(builder.preAuthAmount).toBe(preAuthAmt);
984
+ const response = await builder.withEcrId("13").execute();
985
+ expect(response.status).toBe("Success");
986
+ });
987
+ /**
988
+ * Requirement: Processing Indicators
989
+ * Status: Builder should support quickChip, checkLuhn, securityCode
990
+ */
991
+ test("[Requirement:processingIndicators] Builder supports processing indicator flags", async () => {
992
+ const builder = device.sale(10.0);
993
+ // These should be properties on the builder
994
+ expect(builder).toHaveProperty("isQuickChip");
995
+ expect(builder).toHaveProperty("hasCheckLuhn");
996
+ expect(builder).toHaveProperty("hasSecurityCode");
997
+ const response = await builder.withEcrId("13").execute();
998
+ expect(response.status).toBe("Success");
999
+ });
1000
+ });
1001
+ // ===========================================================================
1002
+ // JIRA Story Requirements – Method Chaining
1003
+ // ===========================================================================
1004
+ describe("JIRA Story: UPA Transaction Processing – Method Chaining", () => {
1005
+ let device;
1006
+ beforeEach(() => {
1007
+ device = (0, UpaHelpertest_1.createTestDevice)();
1008
+ });
1009
+ /**
1010
+ * All required methods should be chainable
1011
+ */
1012
+ test("[MethodChaining] All required methods are chainable", () => {
1013
+ const result = device
1014
+ .sale(25.0)
1015
+ .withClerkId(101)
1016
+ .withCardOnFileIndicator(src_1.StoredCredentialInitiator.CardHolder)
1017
+ .withCardBrandTransId("TransID123")
1018
+ .withLineItemLeft("Item Description")
1019
+ .withLineItemRight("$25.00")
1020
+ .withLanguage("en")
1021
+ .withMerchantDecision("Approve")
1022
+ .withAcquisitionTypes([AcquisitionType_1.AcquisitionType.Contact])
1023
+ .withPreAuthAmount(50.0);
1024
+ // Verify all values are set
1025
+ expect(result.amount).toBe(25.0);
1026
+ expect(result.clerkId).toBe(101);
1027
+ expect(result.cardOnFileIndicator).toBe(src_1.StoredCredentialInitiator.CardHolder);
1028
+ expect(result.cardBrandTransId).toBe("TransID123");
1029
+ expect(result.lineItemLeft).toBe("Item Description");
1030
+ expect(result.lineItemRight).toBe("$25.00");
1031
+ expect(result.language).toBe("en");
1032
+ expect(result.merchantDecision).toBe("Approve");
1033
+ expect(result.acquisitionTypes).toEqual([AcquisitionType_1.AcquisitionType.Contact]);
1034
+ expect(result.preAuthAmount).toBe(50.0);
1035
+ });
1036
+ });
1037
+ // ===========================================================================
1038
+ // JIRA Story Requirements – Comprehensive Integration Test
1039
+ // ===========================================================================
1040
+ describe("JIRA Story: UPA Transaction Processing – Comprehensive Integration", () => {
1041
+ let device;
1042
+ beforeEach(() => {
1043
+ device = (0, UpaHelpertest_1.createTestDevice)();
1044
+ });
1045
+ /**
1046
+ * Complete transaction with all fields
1047
+ */
1048
+ test("[Integration:Complete] Sale with all JIRA story requirements", async () => {
1049
+ // Build complete sale transaction matching JIRA requirements
1050
+ const builder = device
1051
+ .sale(99.99)
1052
+ .withClerkId(42)
1053
+ .withCardOnFileIndicator(src_1.StoredCredentialInitiator.CardHolder)
1054
+ .withCardBrandTransId("BrandTxnId-2026-001")
1055
+ .withPreAuthAmount(150.0)
1056
+ .withInvoiceNumber("INV-2026-0001")
1057
+ .withRequestMultiUseToken(true);
1058
+ // Verify all properties are accessible (without execution)
1059
+ const builderAsAny = builder;
1060
+ expect(builderAsAny.amount).toBe(99.99);
1061
+ expect(builderAsAny.clerkId).toBe(42);
1062
+ expect(builderAsAny.cardOnFileIndicator).toBe(src_1.StoredCredentialInitiator.CardHolder);
1063
+ expect(builderAsAny.cardBrandTransId).toBe("BrandTxnId-2026-001");
1064
+ expect(builderAsAny.preAuthAmount).toBe(150.0);
1065
+ expect(builderAsAny.invoiceNumber).toBe("INV-2026-0001");
1066
+ expect(builderAsAny.requestMultiUseToken).toBe(true);
1067
+ const response = await builder.withEcrId("13").execute();
1068
+ expect(response.status).toBe("Success");
1069
+ });
1070
+ /**
1071
+ * Refund with cardOnFileIndicator - Merchant initiated
1072
+ *
1073
+ * NOTE: Refund-by-reference with GP-API has a limitation:
1074
+ * - UPA spec requires referenceNumber as AN(4-16)
1075
+ * - Device reference numbers are 12 digits (valid for UPA)
1076
+ * - But GP-API's validation layer expects GatewayTxnId (29 chars)
1077
+ * - This creates a constraint where refund-by-reference through GP-API fails
1078
+ *
1079
+ * Solution: Use refund without reference (card-on-file without transaction ID)
1080
+ * This requires either:
1081
+ * 1. CardData for manual refund
1082
+ * 2. Token from previous tokenized transaction
1083
+ * 3. Or wait for GP-API to support device reference numbers
1084
+ */
1085
+ test("[Integration:Refund] Refund with Merchant cardOnFileIndicator", async () => {
1086
+ // For now, test that refund builder supports cardOnFileIndicator properly
1087
+ // Full refund-by-reference will work once GP-API layer is fixed
1088
+ const refundBuilder = device
1089
+ .refund(50.0)
1090
+ .withClerkId(101)
1091
+ .withCardOnFileIndicator(src_1.StoredCredentialInitiator.Merchant)
1092
+ .withEcrId("13");
1093
+ const builderAsAny = refundBuilder;
1094
+ expect(builderAsAny.amount).toBe(50.0);
1095
+ expect(builderAsAny.clerkId).toBe(101);
1096
+ expect(builderAsAny.cardOnFileIndicator).toBe(src_1.StoredCredentialInitiator.Merchant);
1097
+ const response = await refundBuilder.execute();
1098
+ expect(response.status).toBe("Success");
1099
+ // Note: Actual refund execution requires CardData or reference that GP-API accepts
1100
+ // This test verifies the builder supports the JIRA requirements
1101
+ });
1102
+ /**
1103
+ * Pre-Authorization with all fields
1104
+ */
1105
+ test("[Integration:PreAuth] Pre-Auth with preAuthAmount and processing indicators", async () => {
1106
+ const builder = device
1107
+ .authorize(200.0)
1108
+ .withClerkId(55)
1109
+ .withCardBrandTransId("PreAuthBrandId")
1110
+ .withPreAuthAmount(250.0);
1111
+ const builderAsAny = builder;
1112
+ expect(builderAsAny.amount).toBe(200.0);
1113
+ expect(builderAsAny.clerkId).toBe(55);
1114
+ expect(builderAsAny.cardBrandTransId).toBe("PreAuthBrandId");
1115
+ expect(builderAsAny.preAuthAmount).toBe(250.0);
1116
+ const response = await builder.withEcrId("13").execute();
1117
+ expect(response.status).toBe("Success");
1118
+ });
1119
+ });
1120
+ // ===========================================================================
1121
+ // processCPC serialization for Sale and PreAuth
1122
+ // ===========================================================================
1123
+ (0, UpaHelpertest_1.describeUpaLive)("UPA Credit – processCPC serialization", () => {
1124
+ let device;
1125
+ beforeEach(() => {
1126
+ device = (0, UpaHelpertest_1.createTestDevice)();
1127
+ });
1128
+ test("[UpaCreditTests:ProcessCPC-001] sale() with ProcessCPC(true) serializes processCPC as '1'", async () => {
1129
+ const controller = src_1.ServicesContainer.instance().getDeviceController();
1130
+ const builder = device
1131
+ .sale(10.0)
1132
+ .withEcrId(13)
1133
+ .withProcessCPC(true);
1134
+ // Verify request serialization (processCPC is sent to device)
1135
+ const request = controller
1136
+ .buildProcessTransaction(builder)
1137
+ .getJsonRequest();
1138
+ console.log("[UpaCreditTests:ProcessCPC-001] Sale with ProcessCPC(true) request payload:\n" +
1139
+ JSON.stringify(request, null, 2));
1140
+ expect(request.data.command).toBe("Sale");
1141
+ expect(request.data.data.transaction.processCPC).toBe("1");
1142
+ // Execute transaction and verify success
1143
+ const response = await builder.execute();
1144
+ expect(response.status).toBe("Success");
1145
+ expect(response.deviceResponseCode).toBe("00");
1146
+ console.log("[UpaCreditTests:ProcessCPC-001] Sale response:\n" +
1147
+ JSON.stringify(response, null, 2));
1148
+ // Note: processCPC is request-only; device may not echo it back in response
1149
+ // If device does return it, it will be populated in response.processCPC
1150
+ console.log(`[UpaCreditTests:ProcessCPC-001] Response processCPC value: "${response.processCPC ?? "not returned by device"}"`);
1151
+ });
1152
+ test("[UpaCreditTests:ProcessCPC-002] sale() with ProcessCPC(false) serializes processCPC as '0'", async () => {
1153
+ const controller = src_1.ServicesContainer.instance().getDeviceController();
1154
+ const builder = device
1155
+ .sale(10.0)
1156
+ .withEcrId(13)
1157
+ .withProcessCPC(false);
1158
+ const request = controller
1159
+ .buildProcessTransaction(builder)
1160
+ .getJsonRequest();
1161
+ const response = await builder.execute();
1162
+ expect(response.status).toBe("Success");
1163
+ expect(response.deviceResponseCode).toBe("00");
1164
+ expect(request.data.command).toBe("Sale");
1165
+ expect(request.data.data.transaction.processCPC).toBe("0");
1166
+ });
1167
+ test("[UpaCreditTests:ProcessCPC-003] sale() without ProcessCPC omits processCPC from request", async () => {
1168
+ const controller = src_1.ServicesContainer.instance().getDeviceController();
1169
+ const builder = device.sale(10.0).withEcrId(13);
1170
+ const response = await builder.execute();
1171
+ expect(response.status).toBe("Success");
1172
+ expect(response.deviceResponseCode).toBe("00");
1173
+ const request = controller
1174
+ .buildProcessTransaction(builder)
1175
+ .getJsonRequest();
1176
+ expect(request.data.command).toBe("Sale");
1177
+ expect(request.data.data.transaction.processCPC).toBeUndefined();
1178
+ });
1179
+ test("[UpaCreditTests:ProcessCPC-004] capture() uses totalAmount (not baseAmount)", async () => {
1180
+ const controller = src_1.ServicesContainer.instance().getDeviceController();
1181
+ const authresponse = await device
1182
+ .authorize(10.0)
1183
+ .withEcrId(13)
1184
+ .execute();
1185
+ expect(authresponse.status).toBe("Success");
1186
+ expect(authresponse.deviceResponseCode).toBe("00");
1187
+ const builder = device
1188
+ .capture()
1189
+ .withTransactionId(authresponse.transactionId)
1190
+ .withProcessCPC(true)
1191
+ .withAmount(10.0)
1192
+ .withEcrId(13);
1193
+ const request = controller
1194
+ .buildProcessTransaction(builder)
1195
+ .getJsonRequest();
1196
+ const response = await builder.execute();
1197
+ expect(response.status).toBe("Success");
1198
+ expect(response.deviceResponseCode).toBe("00");
1199
+ expect(request.data.command).toBe("AuthCompletion");
1200
+ expect(request.data.data.transaction.totalAmount).toBe("10.00");
1201
+ expect(request.data.data.transaction.baseAmount).toBeUndefined();
1202
+ });
1203
+ });
527
1204
  //# sourceMappingURL=UpaCredit.test.js.map