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
@@ -731,535 +731,2421 @@ afterEach(async () => {
731
731
  message: "cardTypeFilter must contain only supported card types for startCardTransaction",
732
732
  });
733
733
  });
734
- test("[LiveSetup] startCardTransaction() manual mode with MC filter returns manual entry data", async () => {
734
+ test("[UpaAdminTests] startCardTransaction() Contact only returns Success", async () => {
735
735
  const param = new UpaParam_1.UpaParam();
736
- param.timeout = 90;
737
- param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Manual];
738
- param.header = "Manual MC Sale";
736
+ param.timeout = 100;
737
+ param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Contact];
738
+ param.header = "Insert Card";
739
739
  param.displayTotalAmount = "Yes";
740
- param.promptForManual = true;
741
740
  const indicator = new ProcessIndicator_1.ProcessingIndicator();
742
741
  indicator.QuickChip = "Y";
743
- indicator.CheckLuhn = "Y";
744
- indicator.SecurityCode = "Y";
745
- indicator.CardTypeFilter = [CardTypeFilter_1.CardTypeFilter.MC];
742
+ indicator.CheckLuhn = "N";
746
743
  const transData = new UpaTransactionData_1.UpaTransactionData();
747
- transData.totalAmount = 1.0;
744
+ transData.totalAmount = 5.0;
748
745
  transData.cashBackAmount = 0.0;
749
746
  transData.tranDate = new Date();
750
747
  transData.tranTime = new Date();
751
748
  transData.transType = src_1.TransactionType.Sale;
752
- const response = await (0, UpaHelpertest_1.executeLiveStartCardTransaction)(device, param, indicator, transData, "StartCardTransaction manual MC");
753
- if (!response) {
754
- return;
749
+ let response;
750
+ try {
751
+ response = await device.startCardTransaction(param, indicator, transData);
755
752
  }
756
- expect(response.acquisitionType.toUpperCase()).toBe("MANUAL");
757
- if (response.cardBrandShortName) {
758
- expect(response.cardBrandShortName.toUpperCase()).toBe("MC");
753
+ catch (error) {
754
+ if (UpaHelpertest_1.useLiveMic && (0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
755
+ console.warn("StartCardTransaction Contact only timed out while waiting on the device.");
756
+ return;
757
+ }
758
+ throw error;
759
759
  }
760
- if (response.cardBrand) {
761
- expect(response.cardBrand.toUpperCase()).toContain("MASTER");
760
+ expect(response).not.toBeNull();
761
+ expect(response).toBeInstanceOf(UpaGiftCardResponse_1.UpaGiftCardResponse);
762
+ if (UpaHelpertest_1.useLiveMic) {
763
+ if ((0, UpaHelpertest_1.isKnownLiveStartCardTransactionBlocker)(response)) {
764
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "StartCardTransaction Contact only"));
765
+ return;
766
+ }
767
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "StartCardTransaction");
768
+ return;
762
769
  }
763
- expect(response.expiryDate).toBeTruthy();
764
- expect(response.cvv).toBeTruthy();
770
+ expect(response.status).toBe("Success");
765
771
  });
766
- test("[LiveSetup] startCardTransaction() accepts infinite timeout card entry", async () => {
772
+ test("[UpaAdminTests] startCardTransaction() Contactless only returns Success", async () => {
767
773
  const param = new UpaParam_1.UpaParam();
768
- param.timeout = 0;
769
- param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Contact, AcquisitionType_1.AcquisitionType.Swipe];
770
- param.header = "Infinite Timeout";
774
+ param.timeout = 100;
775
+ param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Contactless];
776
+ param.header = "Tap Card";
771
777
  param.displayTotalAmount = "Yes";
772
778
  const indicator = new ProcessIndicator_1.ProcessingIndicator();
773
- indicator.QuickChip = "Y";
774
- indicator.CheckLuhn = "Y";
779
+ indicator.QuickChip = "N";
780
+ indicator.CheckLuhn = "N";
775
781
  const transData = new UpaTransactionData_1.UpaTransactionData();
776
- transData.totalAmount = 1.0;
782
+ transData.totalAmount = 5.0;
777
783
  transData.cashBackAmount = 0.0;
778
784
  transData.tranDate = new Date();
779
785
  transData.tranTime = new Date();
780
786
  transData.transType = src_1.TransactionType.Sale;
781
- const response = await (0, UpaHelpertest_1.executeLiveStartCardTransaction)(device, param, indicator, transData, "StartCardTransaction infinite timeout");
782
- if (!response) {
787
+ let response;
788
+ try {
789
+ response = await device.startCardTransaction(param, indicator, transData);
790
+ }
791
+ catch (error) {
792
+ if (UpaHelpertest_1.useLiveMic && (0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
793
+ console.warn("StartCardTransaction Contactless only timed out while waiting on the device.");
794
+ return;
795
+ }
796
+ throw error;
797
+ }
798
+ expect(response).not.toBeNull();
799
+ expect(response).toBeInstanceOf(UpaGiftCardResponse_1.UpaGiftCardResponse);
800
+ if (UpaHelpertest_1.useLiveMic) {
801
+ if ((0, UpaHelpertest_1.isKnownLiveStartCardTransactionBlocker)(response)) {
802
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "StartCardTransaction Contactless only"));
803
+ return;
804
+ }
805
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "StartCardTransaction");
783
806
  return;
784
807
  }
785
- expect(response.acquisitionType).toBeTruthy();
808
+ expect(response.status).toBe("Success");
786
809
  });
787
- test("[LiveSetup] startCardTransaction() manual VISA flow returns AVS-capable response data", async () => {
810
+ test("[UpaAdminTests] startCardTransaction() Swipe or Contact returns Success", async () => {
788
811
  const param = new UpaParam_1.UpaParam();
789
- param.timeout = 90;
790
- param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Manual];
791
- param.header = "Manual VISA Sale";
812
+ param.timeout = 45;
813
+ param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Swipe, AcquisitionType_1.AcquisitionType.Contact];
814
+ param.header = "Swipe or Insert Card";
792
815
  param.displayTotalAmount = "Yes";
793
- param.promptForManual = true;
794
816
  const indicator = new ProcessIndicator_1.ProcessingIndicator();
795
- indicator.QuickChip = "Y";
817
+ indicator.QuickChip = "N";
796
818
  indicator.CheckLuhn = "Y";
797
819
  indicator.SecurityCode = "Y";
798
- indicator.CardTypeFilter = [CardTypeFilter_1.CardTypeFilter.VISA];
799
820
  const transData = new UpaTransactionData_1.UpaTransactionData();
800
- transData.totalAmount = 1.0;
821
+ transData.totalAmount = 5.0;
801
822
  transData.cashBackAmount = 0.0;
802
823
  transData.tranDate = new Date();
803
824
  transData.tranTime = new Date();
804
825
  transData.transType = src_1.TransactionType.Sale;
805
- const response = await (0, UpaHelpertest_1.executeLiveStartCardTransaction)(device, param, indicator, transData, "StartCardTransaction manual VISA");
806
- if (!response) {
807
- return;
826
+ let response;
827
+ try {
828
+ response = await device.startCardTransaction(param, indicator, transData);
808
829
  }
809
- expect(response.acquisitionType.toUpperCase()).toBe("MANUAL");
810
- if (response.cardBrandShortName) {
811
- expect(response.cardBrandShortName.toUpperCase()).toBe("VI");
830
+ catch (error) {
831
+ if (UpaHelpertest_1.useLiveMic && (0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
832
+ console.warn("StartCardTransaction Swipe or Contact timed out while waiting on the device.");
833
+ return;
834
+ }
835
+ throw error;
812
836
  }
813
- if (response.cardBrand) {
814
- expect(response.cardBrand.toUpperCase()).toContain("VISA");
837
+ expect(response).not.toBeNull();
838
+ expect(response).toBeInstanceOf(UpaGiftCardResponse_1.UpaGiftCardResponse);
839
+ if (UpaHelpertest_1.useLiveMic) {
840
+ if ((0, UpaHelpertest_1.isKnownLiveStartCardTransactionBlocker)(response)) {
841
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "StartCardTransaction Swipe or Contact"));
842
+ return;
843
+ }
844
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "StartCardTransaction");
845
+ expect(response.fallback).toBe("0");
846
+ return;
815
847
  }
816
- if (response.avsFlag) {
817
- expect(response.avsFlag).toBe("1");
848
+ expect(response.status).toBe("Success");
849
+ expect(response.fallback).toBe("0");
850
+ });
851
+ test("[UpaAdminTests] startCardTransaction() with CashBack returns Success", async () => {
852
+ const param = new UpaParam_1.UpaParam();
853
+ param.timeout = 100;
854
+ param.acquisitionTypes = [
855
+ AcquisitionType_1.AcquisitionType.Contact,
856
+ AcquisitionType_1.AcquisitionType.Contactless,
857
+ AcquisitionType_1.AcquisitionType.Swipe,
858
+ ];
859
+ param.header = "Debit Transaction";
860
+ param.displayTotalAmount = "Yes";
861
+ const indicator = new ProcessIndicator_1.ProcessingIndicator();
862
+ indicator.QuickChip = "N";
863
+ indicator.CheckLuhn = "N";
864
+ const transData = new UpaTransactionData_1.UpaTransactionData();
865
+ transData.totalAmount = 5.0;
866
+ transData.cashBackAmount = 10.0;
867
+ transData.tranDate = new Date();
868
+ transData.tranTime = new Date();
869
+ transData.transType = src_1.TransactionType.Sale;
870
+ let response;
871
+ try {
872
+ response = await device.startCardTransaction(param, indicator, transData);
818
873
  }
819
- else {
820
- console.warn("StartCardTransaction manual VISA did not return AVSFlag on the current device configuration.");
874
+ catch (error) {
875
+ if (UpaHelpertest_1.useLiveMic && (0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
876
+ console.warn("StartCardTransaction with CashBack timed out while waiting on the device.");
877
+ return;
878
+ }
879
+ throw error;
880
+ }
881
+ expect(response).not.toBeNull();
882
+ expect(response).toBeInstanceOf(UpaGiftCardResponse_1.UpaGiftCardResponse);
883
+ if (UpaHelpertest_1.useLiveMic) {
884
+ if ((0, UpaHelpertest_1.isKnownLiveStartCardTransactionBlocker)(response)) {
885
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "StartCardTransaction with CashBack"));
886
+ return;
887
+ }
888
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "StartCardTransaction");
889
+ expect(response.fallback).toBe("0");
890
+ return;
821
891
  }
892
+ expect(response.status).toBe("Success");
893
+ expect(response.fallback).toBe("0");
822
894
  });
823
- test("[LiveSetup] startCardTransaction() manual AMEX refund flow returns refund card-entry data", async () => {
895
+ test("[UpaAdminTests] startCardTransaction() Refund returns Success", async () => {
824
896
  const param = new UpaParam_1.UpaParam();
825
- param.timeout = 90;
826
- param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Manual];
827
- param.header = "Manual AMEX Refund";
897
+ param.timeout = 100;
898
+ param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Swipe];
899
+ param.header = "Refund Transaction";
828
900
  param.displayTotalAmount = "Yes";
829
- param.promptForManual = true;
830
901
  const indicator = new ProcessIndicator_1.ProcessingIndicator();
831
- indicator.QuickChip = "Y";
902
+ indicator.QuickChip = "N";
832
903
  indicator.CheckLuhn = "Y";
833
- indicator.SecurityCode = "Y";
834
- indicator.CardTypeFilter = [CardTypeFilter_1.CardTypeFilter.AMEX];
904
+ indicator.SecurityCode = "N";
835
905
  const transData = new UpaTransactionData_1.UpaTransactionData();
836
- transData.totalAmount = 1.0;
906
+ transData.totalAmount = 5.0;
837
907
  transData.cashBackAmount = 0.0;
838
908
  transData.tranDate = new Date();
839
909
  transData.tranTime = new Date();
840
910
  transData.transType = src_1.TransactionType.Refund;
841
- const response = await (0, UpaHelpertest_1.executeLiveStartCardTransaction)(device, param, indicator, transData, "StartCardTransaction manual AMEX refund");
842
- if (!response) {
843
- return;
911
+ let response;
912
+ try {
913
+ response = await device.startCardTransaction(param, indicator, transData);
844
914
  }
845
- expect(response.acquisitionType.toUpperCase()).toBe("MANUAL");
846
- if (response.cardBrandShortName &&
847
- !["AX", "AMEX"].includes(response.cardBrandShortName.toUpperCase())) {
848
- console.warn("StartCardTransaction AMEX refund validation requires an actual AMEX-presented card; the current live run returned a different brand.");
849
- return;
915
+ catch (error) {
916
+ if (UpaHelpertest_1.useLiveMic && (0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
917
+ console.warn("StartCardTransaction Refund timed out while waiting on the device.");
918
+ return;
919
+ }
920
+ throw error;
850
921
  }
851
- if (response.cardBrand &&
852
- !response.cardBrand.toUpperCase().includes("AMEX") &&
853
- !response.cardBrand.toUpperCase().includes("AMERICAN EXPRESS")) {
854
- console.warn("StartCardTransaction AMEX refund validation requires an actual AMEX-presented card; the current live run returned a different brand.");
922
+ expect(response).not.toBeNull();
923
+ expect(response).toBeInstanceOf(UpaGiftCardResponse_1.UpaGiftCardResponse);
924
+ if (UpaHelpertest_1.useLiveMic) {
925
+ if ((0, UpaHelpertest_1.isKnownLiveStartCardTransactionBlocker)(response)) {
926
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "StartCardTransaction Refund"));
927
+ return;
928
+ }
929
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "StartCardTransaction");
855
930
  return;
856
931
  }
857
- expect(response.expiryDate).toBeTruthy();
858
- expect(response.cvv).toBeTruthy();
932
+ expect(response.status).toBe("Success");
859
933
  });
860
- test("[LiveSetup] startCardTransaction() accepts card via Contact|Contactless|Swipe|Manual", async () => {
934
+ test("[UpaAdminTests] startCardTransaction() with VISA and MasterCard filter returns Success", async () => {
861
935
  const param = new UpaParam_1.UpaParam();
862
- param.acquisitionTypes = [
863
- AcquisitionType_1.AcquisitionType.Contact,
864
- AcquisitionType_1.AcquisitionType.Contactless,
865
- AcquisitionType_1.AcquisitionType.Swipe,
866
- AcquisitionType_1.AcquisitionType.Manual,
867
- ];
936
+ param.timeout = 100;
937
+ param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Contact];
938
+ param.header = "VISA and MasterCard Only";
939
+ param.displayTotalAmount = "Yes";
868
940
  const indicator = new ProcessIndicator_1.ProcessingIndicator();
869
- indicator.QuickChip = "Y";
870
- indicator.CheckLuhn = "N";
941
+ indicator.QuickChip = "N";
942
+ indicator.CheckLuhn = "Y";
943
+ indicator.SecurityCode = "Y";
944
+ indicator.CardTypeFilter = [CardTypeFilter_1.CardTypeFilter.VISA, CardTypeFilter_1.CardTypeFilter.MC];
871
945
  const transData = new UpaTransactionData_1.UpaTransactionData();
872
- transData.totalAmount = 1.0;
946
+ transData.totalAmount = 5.0;
873
947
  transData.cashBackAmount = 0.0;
874
948
  transData.tranDate = new Date();
875
949
  transData.tranTime = new Date();
876
950
  transData.transType = src_1.TransactionType.Sale;
877
- const response = await device.startCardTransaction(param, indicator, transData);
951
+ let response;
952
+ try {
953
+ response = await device.startCardTransaction(param, indicator, transData);
954
+ }
955
+ catch (error) {
956
+ if (UpaHelpertest_1.useLiveMic && (0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
957
+ console.warn("StartCardTransaction with VISA/MC filter timed out while waiting on the device.");
958
+ return;
959
+ }
960
+ throw error;
961
+ }
878
962
  expect(response).not.toBeNull();
879
963
  expect(response).toBeInstanceOf(UpaGiftCardResponse_1.UpaGiftCardResponse);
880
- expect(response.status).toBe("Success");
881
- expect(response.deviceResponseCode).toBe("00");
882
- expect(response.acquisitionType?.toUpperCase()).toMatch(/^(CONTACT|CONTACTLESS|SWIPE|MANUAL|INSERT|TAP)$/);
883
- }, 300000);
884
- });
885
- (0, UpaHelpertest_1.describeUpaLive)("UPA Admin – reboot()", () => {
886
- let device;
887
- beforeEach(() => {
888
- device = (0, UpaHelpertest_1.createTestDevice)();
889
- });
890
- test("[UpaAdminTests][UpaMicTests] reboot() returns Success and does not throw", async () => {
891
- const response = await device.reboot();
892
- expect(response).not.toBeNull();
893
- expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
894
964
  if (UpaHelpertest_1.useLiveMic) {
895
- (0, UpaHelpertest_1.expectLiveSuccess)(response, "Reboot");
965
+ if ((0, UpaHelpertest_1.isKnownLiveStartCardTransactionBlocker)(response)) {
966
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "StartCardTransaction VISA/MC filter"));
967
+ return;
968
+ }
969
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "StartCardTransaction");
896
970
  return;
897
971
  }
898
972
  expect(response.status).toBe("Success");
899
- expect(response.deviceResponseCode).toBe("00");
900
973
  });
901
- test("[LiveSetup] reboot() on inactive or unresponsive terminal documents current routing behavior", async () => {
902
- const unavailableDevice = DeviceService_1.DeviceService.create((0, UpaHelpertest_1.buildConfig)());
903
- unavailableDevice.ecrId = "99999999";
974
+ test("[UpaAdminTests] startCardTransaction() with amount less than one dollar returns Success", async () => {
975
+ const param = new UpaParam_1.UpaParam();
976
+ param.timeout = 100;
977
+ param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Contact, AcquisitionType_1.AcquisitionType.Swipe];
978
+ param.header = "Small Amount";
979
+ param.displayTotalAmount = "Yes";
980
+ const indicator = new ProcessIndicator_1.ProcessingIndicator();
981
+ indicator.QuickChip = "Y";
982
+ indicator.CheckLuhn = "N";
983
+ const transData = new UpaTransactionData_1.UpaTransactionData();
984
+ transData.totalAmount = 0.5;
985
+ transData.cashBackAmount = 0.0;
986
+ transData.tranDate = new Date();
987
+ transData.tranTime = new Date();
988
+ transData.transType = src_1.TransactionType.Sale;
989
+ let response;
904
990
  try {
905
- const response = await unavailableDevice.reboot();
906
- expect(response).not.toBeNull();
907
- expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
908
- if ((0, UpaHelpertest_1.isKnownLiveBusyBlocker)(response)) {
909
- console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "Reboot inactive or unresponsive terminal"));
991
+ response = await device.startCardTransaction(param, indicator, transData);
992
+ }
993
+ catch (error) {
994
+ if (UpaHelpertest_1.useLiveMic && (0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
995
+ console.warn("StartCardTransaction with small amount timed out while waiting on the device.");
910
996
  return;
911
997
  }
912
- if (response.status !== "Success" ||
998
+ throw error;
999
+ }
1000
+ expect(response).not.toBeNull();
1001
+ expect(response).toBeInstanceOf(UpaGiftCardResponse_1.UpaGiftCardResponse);
1002
+ if (UpaHelpertest_1.useLiveMic) {
1003
+ if ((0, UpaHelpertest_1.isKnownLiveStartCardTransactionBlocker)(response)) {
1004
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "StartCardTransaction small amount"));
1005
+ return;
1006
+ }
1007
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "StartCardTransaction");
1008
+ expect(response.fallback).toBe("0");
1009
+ return;
1010
+ }
1011
+ expect(response.status).toBe("Success");
1012
+ expect(response.fallback).toBe("0");
1013
+ });
1014
+ test("[UpaAdminTests] startCardTransaction() verifies response fields are populated", async () => {
1015
+ const param = new UpaParam_1.UpaParam();
1016
+ param.timeout = 100;
1017
+ param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Contact];
1018
+ param.header = "Test Transaction";
1019
+ param.displayTotalAmount = "Yes";
1020
+ const indicator = new ProcessIndicator_1.ProcessingIndicator();
1021
+ indicator.QuickChip = "Y";
1022
+ indicator.CheckLuhn = "Y";
1023
+ indicator.SecurityCode = "N";
1024
+ const transData = new UpaTransactionData_1.UpaTransactionData();
1025
+ transData.totalAmount = 5.0;
1026
+ transData.cashBackAmount = 0.0;
1027
+ transData.tranDate = new Date();
1028
+ transData.tranTime = new Date();
1029
+ transData.transType = src_1.TransactionType.Sale;
1030
+ let response;
1031
+ try {
1032
+ response = await device.startCardTransaction(param, indicator, transData);
1033
+ }
1034
+ catch (error) {
1035
+ if (UpaHelpertest_1.useLiveMic && (0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
1036
+ console.warn("StartCardTransaction response fields verification timed out.");
1037
+ return;
1038
+ }
1039
+ throw error;
1040
+ }
1041
+ expect(response).not.toBeNull();
1042
+ expect(response).toBeInstanceOf(UpaGiftCardResponse_1.UpaGiftCardResponse);
1043
+ if (UpaHelpertest_1.useLiveMic) {
1044
+ if ((0, UpaHelpertest_1.isKnownLiveStartCardTransactionBlocker)(response)) {
1045
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "StartCardTransaction response fields"));
1046
+ return;
1047
+ }
1048
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "StartCardTransaction");
1049
+ expect(response.acquisitionType).toBeTruthy();
1050
+ return;
1051
+ }
1052
+ expect(response.status).toBe("Success");
1053
+ expect(response.acquisitionType).toBeTruthy();
1054
+ });
1055
+ test("[UpaAdminTests] startCardTransaction() Contact with infinite timeout returns Success", async () => {
1056
+ const param = new UpaParam_1.UpaParam();
1057
+ param.timeout = 0;
1058
+ param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Contact];
1059
+ param.header = "No Timeout";
1060
+ param.displayTotalAmount = "Yes";
1061
+ const indicator = new ProcessIndicator_1.ProcessingIndicator();
1062
+ indicator.QuickChip = "N";
1063
+ const transData = new UpaTransactionData_1.UpaTransactionData();
1064
+ transData.totalAmount = 5.0;
1065
+ transData.cashBackAmount = 0.0;
1066
+ transData.tranDate = new Date();
1067
+ transData.tranTime = new Date();
1068
+ transData.transType = src_1.TransactionType.Sale;
1069
+ let response;
1070
+ try {
1071
+ response = await device.startCardTransaction(param, indicator, transData);
1072
+ }
1073
+ catch (error) {
1074
+ if (UpaHelpertest_1.useLiveMic && (0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
1075
+ console.warn("StartCardTransaction Contact infinite timeout timed out.");
1076
+ return;
1077
+ }
1078
+ throw error;
1079
+ }
1080
+ expect(response).not.toBeNull();
1081
+ expect(response).toBeInstanceOf(UpaGiftCardResponse_1.UpaGiftCardResponse);
1082
+ if (UpaHelpertest_1.useLiveMic) {
1083
+ if ((0, UpaHelpertest_1.isKnownLiveStartCardTransactionBlocker)(response)) {
1084
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "StartCardTransaction Contact infinite timeout"));
1085
+ return;
1086
+ }
1087
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "StartCardTransaction");
1088
+ return;
1089
+ }
1090
+ expect(response.status).toBe("Success");
1091
+ });
1092
+ test("[UpaAdminTests] startCardTransaction() Contactless with infinite timeout returns Success", async () => {
1093
+ const param = new UpaParam_1.UpaParam();
1094
+ param.timeout = 0;
1095
+ param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Contactless];
1096
+ param.header = "No Timeout";
1097
+ param.displayTotalAmount = "Yes";
1098
+ const indicator = new ProcessIndicator_1.ProcessingIndicator();
1099
+ indicator.QuickChip = "N";
1100
+ const transData = new UpaTransactionData_1.UpaTransactionData();
1101
+ transData.totalAmount = 5.0;
1102
+ transData.cashBackAmount = 0.0;
1103
+ transData.tranDate = new Date();
1104
+ transData.tranTime = new Date();
1105
+ transData.transType = src_1.TransactionType.Sale;
1106
+ let response;
1107
+ try {
1108
+ response = await device.startCardTransaction(param, indicator, transData);
1109
+ }
1110
+ catch (error) {
1111
+ if (UpaHelpertest_1.useLiveMic && (0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
1112
+ console.warn("StartCardTransaction Contactless infinite timeout timed out.");
1113
+ return;
1114
+ }
1115
+ throw error;
1116
+ }
1117
+ expect(response).not.toBeNull();
1118
+ expect(response).toBeInstanceOf(UpaGiftCardResponse_1.UpaGiftCardResponse);
1119
+ if (UpaHelpertest_1.useLiveMic) {
1120
+ if ((0, UpaHelpertest_1.isKnownLiveStartCardTransactionBlocker)(response)) {
1121
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "StartCardTransaction Contactless infinite timeout"));
1122
+ return;
1123
+ }
1124
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "StartCardTransaction");
1125
+ return;
1126
+ }
1127
+ expect(response.status).toBe("Success");
1128
+ });
1129
+ test("[UpaAdminTests] startCardTransaction() with BrandIcons returns Success", async () => {
1130
+ const param = new UpaParam_1.UpaParam();
1131
+ param.timeout = 100;
1132
+ param.acquisitionTypes = [
1133
+ AcquisitionType_1.AcquisitionType.Contact,
1134
+ AcquisitionType_1.AcquisitionType.Swipe,
1135
+ AcquisitionType_1.AcquisitionType.Contactless,
1136
+ ];
1137
+ param.header = "Card Entry";
1138
+ param.displayTotalAmount = "Yes";
1139
+ param.brandIcon1 = 31;
1140
+ param.brandIcon2 = 15;
1141
+ const indicator = new ProcessIndicator_1.ProcessingIndicator();
1142
+ indicator.QuickChip = "Y";
1143
+ indicator.CheckLuhn = "N";
1144
+ const transData = new UpaTransactionData_1.UpaTransactionData();
1145
+ transData.totalAmount = 5.0;
1146
+ transData.cashBackAmount = 0.0;
1147
+ transData.tranDate = new Date();
1148
+ transData.tranTime = new Date();
1149
+ transData.transType = src_1.TransactionType.Sale;
1150
+ let response;
1151
+ try {
1152
+ response = await device.startCardTransaction(param, indicator, transData);
1153
+ }
1154
+ catch (error) {
1155
+ if (UpaHelpertest_1.useLiveMic && (0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
1156
+ console.warn("StartCardTransaction with BrandIcons timed out while waiting on the device.");
1157
+ return;
1158
+ }
1159
+ throw error;
1160
+ }
1161
+ expect(response).not.toBeNull();
1162
+ expect(response).toBeInstanceOf(UpaGiftCardResponse_1.UpaGiftCardResponse);
1163
+ if (UpaHelpertest_1.useLiveMic) {
1164
+ if ((0, UpaHelpertest_1.isKnownLiveStartCardTransactionBlocker)(response)) {
1165
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "StartCardTransaction with BrandIcons"));
1166
+ return;
1167
+ }
1168
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "StartCardTransaction");
1169
+ return;
1170
+ }
1171
+ expect(response.status).toBe("Success");
1172
+ });
1173
+ test("[LiveSetup] startCardTransaction() manual mode with MC filter returns manual entry data", async () => {
1174
+ const param = new UpaParam_1.UpaParam();
1175
+ param.timeout = 90;
1176
+ param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Manual];
1177
+ param.header = "Manual MC Sale";
1178
+ param.displayTotalAmount = "Yes";
1179
+ param.promptForManual = true;
1180
+ const indicator = new ProcessIndicator_1.ProcessingIndicator();
1181
+ indicator.QuickChip = "Y";
1182
+ indicator.CheckLuhn = "Y";
1183
+ indicator.SecurityCode = "Y";
1184
+ indicator.CardTypeFilter = [CardTypeFilter_1.CardTypeFilter.MC];
1185
+ const transData = new UpaTransactionData_1.UpaTransactionData();
1186
+ transData.totalAmount = 1.0;
1187
+ transData.cashBackAmount = 0.0;
1188
+ transData.tranDate = new Date();
1189
+ transData.tranTime = new Date();
1190
+ transData.transType = src_1.TransactionType.Sale;
1191
+ const response = await (0, UpaHelpertest_1.executeLiveStartCardTransaction)(device, param, indicator, transData, "StartCardTransaction manual MC");
1192
+ if (!response) {
1193
+ return;
1194
+ }
1195
+ expect(response.acquisitionType.toUpperCase()).toBe("MANUAL");
1196
+ if (response.cardBrandShortName) {
1197
+ expect(response.cardBrandShortName.toUpperCase()).toBe("MC");
1198
+ }
1199
+ if (response.cardBrand) {
1200
+ expect(response.cardBrand.toUpperCase()).toContain("MASTER");
1201
+ }
1202
+ expect(response.expiryDate).toBeTruthy();
1203
+ expect(response.cvv).toBeTruthy();
1204
+ });
1205
+ test("[LiveSetup] startCardTransaction() accepts infinite timeout card entry", async () => {
1206
+ const param = new UpaParam_1.UpaParam();
1207
+ param.timeout = 0;
1208
+ param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Contact, AcquisitionType_1.AcquisitionType.Swipe];
1209
+ param.header = "Infinite Timeout";
1210
+ param.displayTotalAmount = "Yes";
1211
+ const indicator = new ProcessIndicator_1.ProcessingIndicator();
1212
+ indicator.QuickChip = "Y";
1213
+ indicator.CheckLuhn = "Y";
1214
+ const transData = new UpaTransactionData_1.UpaTransactionData();
1215
+ transData.totalAmount = 1.0;
1216
+ transData.cashBackAmount = 0.0;
1217
+ transData.tranDate = new Date();
1218
+ transData.tranTime = new Date();
1219
+ transData.transType = src_1.TransactionType.Sale;
1220
+ const response = await (0, UpaHelpertest_1.executeLiveStartCardTransaction)(device, param, indicator, transData, "StartCardTransaction infinite timeout");
1221
+ if (!response) {
1222
+ return;
1223
+ }
1224
+ expect(response.acquisitionType).toBeTruthy();
1225
+ });
1226
+ test("[LiveSetup] startCardTransaction() manual VISA flow returns AVS-capable response data", async () => {
1227
+ const param = new UpaParam_1.UpaParam();
1228
+ param.timeout = 90;
1229
+ param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Manual];
1230
+ param.header = "Manual VISA Sale";
1231
+ param.displayTotalAmount = "Yes";
1232
+ param.promptForManual = true;
1233
+ const indicator = new ProcessIndicator_1.ProcessingIndicator();
1234
+ indicator.QuickChip = "Y";
1235
+ indicator.CheckLuhn = "Y";
1236
+ indicator.SecurityCode = "Y";
1237
+ indicator.CardTypeFilter = [CardTypeFilter_1.CardTypeFilter.VISA];
1238
+ const transData = new UpaTransactionData_1.UpaTransactionData();
1239
+ transData.totalAmount = 1.0;
1240
+ transData.cashBackAmount = 0.0;
1241
+ transData.tranDate = new Date();
1242
+ transData.tranTime = new Date();
1243
+ transData.transType = src_1.TransactionType.Sale;
1244
+ const response = await (0, UpaHelpertest_1.executeLiveStartCardTransaction)(device, param, indicator, transData, "StartCardTransaction manual VISA");
1245
+ if (!response) {
1246
+ return;
1247
+ }
1248
+ expect(response.acquisitionType.toUpperCase()).toBe("MANUAL");
1249
+ if (response.cardBrandShortName) {
1250
+ expect(response.cardBrandShortName.toUpperCase()).toBe("VI");
1251
+ }
1252
+ if (response.cardBrand) {
1253
+ expect(response.cardBrand.toUpperCase()).toContain("VISA");
1254
+ }
1255
+ if (response.avsFlag) {
1256
+ expect(response.avsFlag).toBe("1");
1257
+ }
1258
+ else {
1259
+ console.warn("StartCardTransaction manual VISA did not return AVSFlag on the current device configuration.");
1260
+ }
1261
+ });
1262
+ test("[LiveSetup] startCardTransaction() manual AMEX refund flow returns refund card-entry data", async () => {
1263
+ const param = new UpaParam_1.UpaParam();
1264
+ param.timeout = 90;
1265
+ param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Manual];
1266
+ param.header = "Manual AMEX Refund";
1267
+ param.displayTotalAmount = "Yes";
1268
+ param.promptForManual = true;
1269
+ const indicator = new ProcessIndicator_1.ProcessingIndicator();
1270
+ indicator.QuickChip = "Y";
1271
+ indicator.CheckLuhn = "Y";
1272
+ indicator.SecurityCode = "Y";
1273
+ indicator.CardTypeFilter = [CardTypeFilter_1.CardTypeFilter.AMEX];
1274
+ const transData = new UpaTransactionData_1.UpaTransactionData();
1275
+ transData.totalAmount = 1.0;
1276
+ transData.cashBackAmount = 0.0;
1277
+ transData.tranDate = new Date();
1278
+ transData.tranTime = new Date();
1279
+ transData.transType = src_1.TransactionType.Refund;
1280
+ const response = await (0, UpaHelpertest_1.executeLiveStartCardTransaction)(device, param, indicator, transData, "StartCardTransaction manual AMEX refund");
1281
+ if (!response) {
1282
+ return;
1283
+ }
1284
+ expect(response.acquisitionType.toUpperCase()).toBe("MANUAL");
1285
+ if (response.cardBrandShortName &&
1286
+ !["AX", "AMEX"].includes(response.cardBrandShortName.toUpperCase())) {
1287
+ console.warn("StartCardTransaction AMEX refund validation requires an actual AMEX-presented card; the current live run returned a different brand.");
1288
+ return;
1289
+ }
1290
+ if (response.cardBrand &&
1291
+ !response.cardBrand.toUpperCase().includes("AMEX") &&
1292
+ !response.cardBrand.toUpperCase().includes("AMERICAN EXPRESS")) {
1293
+ console.warn("StartCardTransaction AMEX refund validation requires an actual AMEX-presented card; the current live run returned a different brand.");
1294
+ return;
1295
+ }
1296
+ expect(response.expiryDate).toBeTruthy();
1297
+ expect(response.cvv).toBeTruthy();
1298
+ });
1299
+ test("[LiveSetup] startCardTransaction() accepts card via Contact|Contactless|Swipe|Manual", async () => {
1300
+ const param = new UpaParam_1.UpaParam();
1301
+ param.acquisitionTypes = [
1302
+ AcquisitionType_1.AcquisitionType.Contact,
1303
+ AcquisitionType_1.AcquisitionType.Contactless,
1304
+ AcquisitionType_1.AcquisitionType.Swipe,
1305
+ AcquisitionType_1.AcquisitionType.Manual,
1306
+ ];
1307
+ const indicator = new ProcessIndicator_1.ProcessingIndicator();
1308
+ indicator.QuickChip = "Y";
1309
+ indicator.CheckLuhn = "N";
1310
+ const transData = new UpaTransactionData_1.UpaTransactionData();
1311
+ transData.totalAmount = 1.0;
1312
+ transData.cashBackAmount = 0.0;
1313
+ transData.tranDate = new Date();
1314
+ transData.tranTime = new Date();
1315
+ transData.transType = src_1.TransactionType.Sale;
1316
+ const response = await device.startCardTransaction(param, indicator, transData);
1317
+ expect(response).not.toBeNull();
1318
+ expect(response).toBeInstanceOf(UpaGiftCardResponse_1.UpaGiftCardResponse);
1319
+ expect(response.status).toBe("Success");
1320
+ expect(response.deviceResponseCode).toBe("00");
1321
+ expect(response.acquisitionType?.toUpperCase()).toMatch(/^(CONTACT|CONTACTLESS|SWIPE|MANUAL|INSERT|TAP)$/);
1322
+ }, 300000);
1323
+ });
1324
+ (0, UpaHelpertest_1.describeUpaLive)("UPA Admin – reboot()", () => {
1325
+ let device;
1326
+ beforeEach(() => {
1327
+ device = (0, UpaHelpertest_1.createTestDevice)();
1328
+ });
1329
+ test("[UpaAdminTests][UpaMicTests] reboot() returns Success and does not throw", async () => {
1330
+ const response = await device.reboot();
1331
+ expect(response).not.toBeNull();
1332
+ expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
1333
+ if (UpaHelpertest_1.useLiveMic) {
1334
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "Reboot");
1335
+ return;
1336
+ }
1337
+ expect(response.status).toBe("Success");
1338
+ expect(response.deviceResponseCode).toBe("00");
1339
+ });
1340
+ test("[LiveSetup] reboot() on inactive or unresponsive terminal documents current routing behavior", async () => {
1341
+ const unavailableDevice = DeviceService_1.DeviceService.create((0, UpaHelpertest_1.buildConfig)());
1342
+ unavailableDevice.ecrId = "99999999";
1343
+ try {
1344
+ const response = await unavailableDevice.reboot();
1345
+ expect(response).not.toBeNull();
1346
+ expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
1347
+ if ((0, UpaHelpertest_1.isKnownLiveBusyBlocker)(response)) {
1348
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "Reboot inactive or unresponsive terminal"));
1349
+ return;
1350
+ }
1351
+ if (response.status !== "Success" ||
913
1352
  response.deviceResponseCode !== "00" ||
914
1353
  (!!response.responseCode && response.responseCode !== "00")) {
915
1354
  expect(response.deviceResponseCode).not.toBe("00");
916
1355
  return;
917
1356
  }
918
- console.warn("Reboot inactive or unresponsive terminal scenario was accepted by the current terminal routing configuration.");
1357
+ console.warn("Reboot inactive or unresponsive terminal scenario was accepted by the current terminal routing configuration.");
1358
+ }
1359
+ catch (error) {
1360
+ if ((0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
1361
+ console.warn("Reboot inactive or unresponsive terminal timed out while waiting on the device or gateway.");
1362
+ return;
1363
+ }
1364
+ expect(error).toBeInstanceOf(Error);
1365
+ expect(error.message).toBeTruthy();
1366
+ }
1367
+ });
1368
+ test("[Negative] reboot() surfaces network or communication failure", async () => {
1369
+ const communicationFailureDevice = DeviceService_1.DeviceService.create((0, UpaHelpertest_1.buildConfig)({ serviceUrl: "http://127.0.0.1:1" }), "reboot-communication-failure");
1370
+ communicationFailureDevice.ecrId = "13";
1371
+ await expect(communicationFailureDevice.reboot()).rejects.toBeInstanceOf(Error);
1372
+ });
1373
+ });
1374
+ (0, UpaHelpertest_1.describeUpaLive)("UPA Admin – deleteSaf()", () => {
1375
+ let device;
1376
+ async function settle(delayMs = 8000) {
1377
+ if (UpaHelpertest_1.useLiveMic) {
1378
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
1379
+ }
1380
+ }
1381
+ function extractTranNoFromSafReport(safReport) {
1382
+ const buckets = [
1383
+ safReport?.approved,
1384
+ safReport?.pending,
1385
+ safReport?.declined,
1386
+ safReport?.reportResult?.approved,
1387
+ safReport?.reportResult?.pending,
1388
+ safReport?.reportResult?.declined,
1389
+ ];
1390
+ for (const bucket of buckets) {
1391
+ if (!bucket) {
1392
+ continue;
1393
+ }
1394
+ for (const summary of Object.values(bucket)) {
1395
+ const transactions = summary?.transactions ?? [];
1396
+ for (const txn of transactions) {
1397
+ const candidate = txn?.transactionId;
1398
+ if (typeof candidate === "string" && /^\d{4,6}$/.test(candidate)) {
1399
+ return candidate;
1400
+ }
1401
+ if (typeof candidate === "number") {
1402
+ const asString = candidate.toString();
1403
+ if (/^\d{4,6}$/.test(asString)) {
1404
+ return asString;
1405
+ }
1406
+ }
1407
+ }
1408
+ }
1409
+ }
1410
+ return undefined;
1411
+ }
1412
+ beforeEach(() => {
1413
+ device = (0, UpaHelpertest_1.createTestDevice)();
1414
+ });
1415
+ test("[UpaAdminTests:754] deleteSaf() executes over live MITC when a SAF record exists", async () => {
1416
+ const safReport = await (0, UpaHelpertest_1.ensureSafData)(device, UpaHelpertest_1.createLiveSale, settle);
1417
+ if (!safReport) {
1418
+ return;
1419
+ }
1420
+ const safReferenceNumber = (0, UpaHelpertest_1.getFirstSafReferenceNumber)(safReport);
1421
+ if (!safReferenceNumber) {
1422
+ console.warn("deleteSaf() live MITC prerequisite skipped: no SAF records available.");
1423
+ return;
1424
+ }
1425
+ console.log(safReferenceNumber);
1426
+ const response = await device.deleteSaf(safReferenceNumber);
1427
+ expect(response).toBeInstanceOf(UpaSAFResponse_1.UpaSAFResponse);
1428
+ expect(response.command).toBe("DeleteSAF");
1429
+ if (response.status === "Failed") {
1430
+ if (["TRAN001", "TRAN010"].includes(response.deviceResponseCode)) {
1431
+ console.warn(`deleteSaf() reference=${safReferenceNumber} returned spec-valid failure ${response.deviceResponseCode} (${response.deviceResponseText}); only host-declined SAF records are freely deletable per §12.4.25.4.`);
1432
+ return;
1433
+ }
1434
+ throw new Error(`deleteSaf() returned unexpected failure code=${response.deviceResponseCode} status=${response.status} text="${response.deviceResponseText}". Per UPA spec §12.4.25.4 the only permitted failure codes for a well-formed request are TRAN001 or TRAN010.`);
1435
+ }
1436
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "DeleteSAF");
1437
+ });
1438
+ test('[UpaAdminTests:754] deleteSaf() surfaces response="DeleteSAF", cmdResult.result="Success", and transaction details', async () => {
1439
+ const safReport = await (0, UpaHelpertest_1.ensureSafData)(device, UpaHelpertest_1.createLiveSale, settle);
1440
+ if (!safReport) {
1441
+ return;
1442
+ }
1443
+ const safReferenceNumber = (0, UpaHelpertest_1.getFirstSafReferenceNumber)(safReport);
1444
+ if (!safReferenceNumber) {
1445
+ console.warn("deleteSaf() live MITC prerequisite skipped: no SAF records available.");
1446
+ return;
1447
+ }
1448
+ const response = await device.deleteSaf(safReferenceNumber);
1449
+ expect(response).toBeInstanceOf(UpaSAFResponse_1.UpaSAFResponse);
1450
+ expect(response.command).toBe("DeleteSAF");
1451
+ if (response.status === "Failed") {
1452
+ if (["TRAN001", "TRAN010"].includes(response.deviceResponseCode)) {
1453
+ console.warn(`deleteSaf() reference=${safReferenceNumber} returned spec-valid failure ${response.deviceResponseCode} (${response.deviceResponseText}); only host-declined SAF records are freely deletable per §12.4.25.4.`);
1454
+ return;
1455
+ }
1456
+ throw new Error(`deleteSaf() returned unexpected failure code=${response.deviceResponseCode} status=${response.status} text="${response.deviceResponseText}". Per UPA spec §12.4.25.4 the only permitted failure codes for a well-formed request are TRAN001 or TRAN010.`);
1457
+ }
1458
+ expect(response.status).toBe("Success");
1459
+ expect(response.deviceResponseCode).toBe("00");
1460
+ if (response.totalCount !== undefined ||
1461
+ response.totalAmount !== undefined) {
1462
+ expect(response.totalCount).toBeGreaterThanOrEqual(0);
1463
+ expect(response.totalAmount).toBeGreaterThanOrEqual(0);
1464
+ }
1465
+ });
1466
+ test("[UpaAdminTests:754] deleteSaf() by tranNo executes over live MITC", async () => {
1467
+ const safReport = await (0, UpaHelpertest_1.ensureSafData)(device, UpaHelpertest_1.createLiveSale, settle);
1468
+ if (!safReport) {
1469
+ return;
1470
+ }
1471
+ const candidateTranNo = extractTranNoFromSafReport(safReport);
1472
+ if (!candidateTranNo) {
1473
+ console.warn("deleteSaf(by tranNo) live MITC prerequisite skipped: no SAF record exposed a numeric tranNo/transId.");
1474
+ return;
1475
+ }
1476
+ expect(device.deleteSaf.length).toBeGreaterThanOrEqual(2);
1477
+ const response = await device.deleteSaf(undefined, candidateTranNo);
1478
+ expect(response).toBeInstanceOf(UpaSAFResponse_1.UpaSAFResponse);
1479
+ expect(response.command).toBe("DeleteSAF");
1480
+ expect(["Success", "Failed"]).toContain(response.status);
1481
+ if (response.status === "Failed") {
1482
+ expect(["TRAN001", "TRAN010"]).toContain(response.deviceResponseCode);
1483
+ }
1484
+ });
1485
+ test("[UpaAdminTests:754] deleteSaf() with no identifiers deletes all host-declined SAF transactions", async () => {
1486
+ expect(typeof device.deleteSaf).toBe("function");
1487
+ expect(device.deleteSaf.length).toBeGreaterThanOrEqual(0);
1488
+ if (process.env.UPA_DELETE_ALL_SAF !== "true") {
1489
+ console.warn("deleteSaf() delete-all live scenario skipped. Set UPA_DELETE_ALL_SAF=true to execute (DESTRUCTIVE: erases every host-declined SAF record on the device).");
1490
+ return;
1491
+ }
1492
+ // Seed at least one SAF record so the delete-all has something to act on.
1493
+ const safReport = await (0, UpaHelpertest_1.ensureSafData)(device, UpaHelpertest_1.createLiveSale, settle);
1494
+ if (!safReport) {
1495
+ return;
1496
+ }
1497
+ const response = await device.deleteSaf();
1498
+ expect(response).toBeInstanceOf(UpaSAFResponse_1.UpaSAFResponse);
1499
+ expect(response.command).toBe("DeleteSAF");
1500
+ // Success is the expected outcome; Failed with TRAN001
1501
+ // if the batch happens to contain no host-declined records at execution time
1502
+ expect(["Success", "Failed"]).toContain(response.status);
1503
+ });
1504
+ test("[UpaCreditTests] sale() serializes processing indicators without mocked responses", async () => {
1505
+ const saleResponse = await (0, UpaHelpertest_1.createLiveSale)(device);
1506
+ expect(saleResponse.status).toBe("Success");
1507
+ });
1508
+ test("[UpaAdminTests:754] deleteSaf() surfaces TRAN001 (TRANSACTION NOT FOUND) over live MITC", async () => {
1509
+ const unknownSafReferenceNumber = `UNKNOWN-123`;
1510
+ const response = await device.deleteSaf(unknownSafReferenceNumber);
1511
+ expect(response).toBeInstanceOf(UpaSAFResponse_1.UpaSAFResponse);
1512
+ expect(response.command).toBe("DeleteSAF");
1513
+ expect(response.status).toBe("Failed");
1514
+ if (response.deviceResponseCode === "TRAN001") {
1515
+ expect(response.deviceResponseMessage).toMatch(/NOT FOUND/i);
1516
+ return;
1517
+ }
1518
+ console.log(`deleteSaf() unknown reference returned ${response.deviceResponseCode} (${response.deviceResponseMessage}) instead of TRAN001; device firmware may normalize unknown references.`);
1519
+ });
1520
+ test("[UpaAdminTests:754] deleteSaf() surfaces TRAN010 (TRANSACTION CANNOT BE DELETED) over live MITC", async () => {
1521
+ const safReport = await (0, UpaHelpertest_1.ensureSafData)(device, UpaHelpertest_1.createLiveSale, settle);
1522
+ if (!safReport) {
1523
+ return;
1524
+ }
1525
+ const approvedBucket = safReport.reportResult?.approved ?? {};
1526
+ let approvedReferenceNumber;
1527
+ for (const summary of Object.values(approvedBucket)) {
1528
+ const transaction = summary?.transactions?.[0];
1529
+ if (transaction?.referenceNumber) {
1530
+ approvedReferenceNumber = transaction.referenceNumber;
1531
+ break;
1532
+ }
1533
+ }
1534
+ if (!approvedReferenceNumber) {
1535
+ console.warn("deleteSaf() TRAN010 live scenario skipped: no approved (host-authorized) SAF records available. TRAN010 requires a pending or authorized transaction reference per spec §12.4.25.4.");
1536
+ return;
1537
+ }
1538
+ const response = await device.deleteSaf(approvedReferenceNumber);
1539
+ expect(response).toBeInstanceOf(UpaSAFResponse_1.UpaSAFResponse);
1540
+ expect(response.command).toBe("DeleteSAF");
1541
+ expect(response.status).toBe("Failed");
1542
+ if (response.deviceResponseCode === "TRAN010") {
1543
+ expect(response.deviceResponseMessage.toUpperCase()).toContain("CANNOT BE DELETED");
1544
+ return;
1545
+ }
1546
+ console.warn(`deleteSaf() authorized-reference delete returned ${response.deviceResponseCode} (${response.deviceResponseMessage}) instead of TRAN010; device firmware may normalize the authorized-transaction outcome.`);
1547
+ });
1548
+ });
1549
+ (0, UpaHelpertest_1.describeUpaLive)("UPA Admin – cancel()", () => {
1550
+ let device;
1551
+ beforeEach(() => {
1552
+ device = (0, UpaHelpertest_1.createTestDevice)();
1553
+ });
1554
+ function buildCancelableStartCardTransactionRequest() {
1555
+ const param = new UpaParam_1.UpaParam();
1556
+ param.acquisitionTypes = [
1557
+ AcquisitionType_1.AcquisitionType.Contact,
1558
+ AcquisitionType_1.AcquisitionType.Contactless,
1559
+ AcquisitionType_1.AcquisitionType.Swipe,
1560
+ AcquisitionType_1.AcquisitionType.Manual,
1561
+ ];
1562
+ param.header = "Cancel Transaction";
1563
+ param.displayTotalAmount = "Yes";
1564
+ param.promptForManual = false;
1565
+ param.timeout = 30;
1566
+ const indicator = new ProcessIndicator_1.ProcessingIndicator();
1567
+ indicator.QuickChip = "Y";
1568
+ indicator.CheckLuhn = "N";
1569
+ indicator.SecurityCode = "Y";
1570
+ indicator.CardTypeFilter = [
1571
+ CardTypeFilter_1.CardTypeFilter.VISA,
1572
+ CardTypeFilter_1.CardTypeFilter.MC,
1573
+ CardTypeFilter_1.CardTypeFilter.AMEX,
1574
+ CardTypeFilter_1.CardTypeFilter.DISCOVER,
1575
+ ];
1576
+ const transData = new UpaTransactionData_1.UpaTransactionData();
1577
+ transData.totalAmount = 1.0;
1578
+ transData.cashBackAmount = 0.0;
1579
+ transData.tranDate = new Date();
1580
+ transData.tranTime = new Date();
1581
+ transData.transType = src_1.TransactionType.Sale;
1582
+ return [param, indicator, transData];
1583
+ }
1584
+ function timeoutAfter(delayMs, label) {
1585
+ return new Promise((_, reject) => {
1586
+ setTimeout(() => reject(new Error(`${label} timed out after ${delayMs}ms`)), delayMs);
1587
+ });
1588
+ }
1589
+ function sleep(delayMs) {
1590
+ return new Promise((resolve) => setTimeout(resolve, delayMs));
1591
+ }
1592
+ test("[UpaAdminTests:711] cancel() cancels an active startCardTransaction over live MITC", async () => {
1593
+ const [param, indicator, transData] = buildCancelableStartCardTransactionRequest();
1594
+ const activeCommand = device
1595
+ .startCardTransaction(param, indicator, transData)
1596
+ .then((response) => ({ kind: "resolved", response }))
1597
+ .catch((error) => ({ kind: "rejected", error }));
1598
+ await sleep(2000);
1599
+ await expect(device.cancel()).resolves.toBeUndefined();
1600
+ const result = await Promise.race([
1601
+ activeCommand,
1602
+ timeoutAfter(45000, "cancelled startCardTransaction"),
1603
+ ]);
1604
+ if (result.kind === "resolved") {
1605
+ expect(result.response).toBeTruthy();
1606
+ if (result.response instanceof TransactionResponse_1.TransactionResponse) {
1607
+ expect([
1608
+ "StartCardTransaction",
1609
+ "CancelTransaction",
1610
+ "SendCommand",
1611
+ ]).toContain(result.response.command);
1612
+ }
1613
+ return;
1614
+ }
1615
+ expect(result.error).toBeInstanceOf(Error);
1616
+ });
1617
+ test("[UpaAdminTests:711] cancel() sends CancelTransaction without a displayOption parameter", async () => {
1618
+ expect(typeof device.cancel).toBe("function");
1619
+ expect(device.cancel.length).toBe(0);
1620
+ await expect(device.cancel()).resolves.toBeUndefined();
1621
+ });
1622
+ test("[UpaAdminTests:711] cancel() handles APP006 (TRANSACTION CANNOT BE CANCELED) without throwing", async () => {
1623
+ await expect(device.cancel()).resolves.toBeUndefined();
1624
+ });
1625
+ });
1626
+ (0, UpaHelpertest_1.describeUpaLive)("UPA Admin – registerPOS()", () => {
1627
+ let device;
1628
+ beforeEach(() => {
1629
+ device = (0, UpaHelpertest_1.createTestDevice)();
1630
+ });
1631
+ test("[UpaAdminTests:776] registerPOS() executes over live MITC", async () => {
1632
+ const posData = new src_1.POSData();
1633
+ posData.appName = `com.global.testapp.${Date.now()}`;
1634
+ posData.launchOrder = 1;
1635
+ posData.remove = false;
1636
+ posData.silent = 0;
1637
+ try {
1638
+ const response = await device.registerPOS(posData);
1639
+ expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
1640
+ expect(response.status).toBe("Success");
1641
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "RegisterPOS");
1642
+ }
1643
+ catch (err) {
1644
+ const message = err instanceof Error ? err.message : String(err);
1645
+ if (message.includes("SYSTEM_ERROR")) {
1646
+ console.warn("registerPOS() succeeded on the device but GP-API returned SYSTEM_ERROR during response mediation; verify registration state on the terminal.");
1647
+ return;
1648
+ }
1649
+ throw err;
1650
+ }
1651
+ });
1652
+ });
1653
+ // ===========================================================================
1654
+ // verify()
1655
+ // CardVerify command with tokenRequest = "1"
1656
+ // Confirms a multi-use token is created and returned by the host
1657
+ // ===========================================================================
1658
+ (0, UpaHelpertest_1.describeUpaLive)("UPA Admin – verify()", () => {
1659
+ let device;
1660
+ beforeEach(() => {
1661
+ device = (0, UpaHelpertest_1.createTestDevice)();
1662
+ });
1663
+ test("[UpaMicTests] verify() returns expected response", async () => {
1664
+ const response = await device.verify().withEcrId(13).execute();
1665
+ expect(response).not.toBeNull();
1666
+ expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
1667
+ expect(response.status).toBe("Success");
1668
+ expect(response.deviceResponseCode).toBe("00");
1669
+ });
1670
+ test("[UpaMicTests] verify() with tokenRequest = 1 returns a token", async () => {
1671
+ try {
1672
+ const response = await device
1673
+ .verify()
1674
+ .withRequestMultiUseToken(true)
1675
+ .withCardBrandStorage(src_1.StoredCredentialInitiator.CardHolder)
1676
+ .withEcrId(13)
1677
+ .execute();
1678
+ console.log("[VERIFY RESPONSE]", JSON.stringify(response, null, 2));
1679
+ expect(response).not.toBeNull();
1680
+ expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
1681
+ if (UpaHelpertest_1.useLiveMic) {
1682
+ if ((0, UpaHelpertest_1.isKnownLiveBusyBlocker)(response)) {
1683
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "CardVerify tokenRequest"));
1684
+ return;
1685
+ }
1686
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["CardVerify", "SendCommand"]);
1687
+ expect(response.token).toBeTruthy();
1688
+ expect(response.token.length).toBeGreaterThan(0);
1689
+ return;
1690
+ }
1691
+ expect(response.status).toBe("Success");
1692
+ expect(response.deviceResponseCode).toBe("00");
1693
+ // ...existing expects
1694
+ }
1695
+ catch (err) {
1696
+ console.log("[VERIFY ERROR]", err);
1697
+ throw err;
1698
+ }
1699
+ });
1700
+ // ===============================================================//
1701
+ test("[UpaManageTests:600] capture() serializes processCPC indicator", async () => {
1702
+ const controller = src_1.ServicesContainer.instance().getDeviceController();
1703
+ const responseauth = await device
1704
+ .authorize(10.0)
1705
+ .withEcrId(13)
1706
+ .execute();
1707
+ const builder = device
1708
+ .capture()
1709
+ .withTransactionId(responseauth.transactionId)
1710
+ .withAmount(10.0)
1711
+ .withEcrId(13)
1712
+ .withProcessCPC(true);
1713
+ const request = controller.buildManageTransaction(builder).getJsonRequest();
1714
+ console.log("[UpaManageTests:600] Capture with processCPC request payload:\n" +
1715
+ JSON.stringify(request, null, 2));
1716
+ expect(request.data.command).toBe("AuthCompletion");
1717
+ expect(request.data.data.transaction.processCPC).toBe("1");
1718
+ const response = await builder.execute();
1719
+ expect(response.status).toBe("Success");
1720
+ });
1721
+ test("[UpaManageTests:601] capture() serializes processCPC false as 0", async () => {
1722
+ const responseauth = await device
1723
+ .authorize(10.0)
1724
+ .withEcrId(13)
1725
+ .execute();
1726
+ const controller = src_1.ServicesContainer.instance().getDeviceController();
1727
+ sleep(100);
1728
+ const builder = device
1729
+ .capture()
1730
+ .withTransactionId(responseauth.transactionId)
1731
+ .withAmount(10.0)
1732
+ .withEcrId(13)
1733
+ .withProcessCPC(false);
1734
+ const request = controller.buildManageTransaction(builder).getJsonRequest();
1735
+ console.log("[UpaManageTests:601] Capture with processCPC false request payload:\n" +
1736
+ JSON.stringify(request, null, 2));
1737
+ expect(request.data.command).toBe("AuthCompletion");
1738
+ expect(request.data.data.transaction.processCPC).toBe("0");
1739
+ const response = await builder.execute();
1740
+ expect(response.status).toBe("Success");
1741
+ });
1742
+ });
1743
+ // ===========================================================================
1744
+ // processingIndicators – StartCardTransaction Workflow
1745
+ // Per UPA spec §12.4.x: quickChip, checkLuhn, securityCode
1746
+ // ===========================================================================
1747
+ (0, UpaHelpertest_1.describeUpaLive)("UPA Admin – StartCardTransaction processingIndicators workflow", () => {
1748
+ let device;
1749
+ beforeEach(() => {
1750
+ device = (0, UpaHelpertest_1.createTestDevice)();
1751
+ });
1752
+ test("[ProcessingIndicators:StartCardTransaction] quickChip='Y' (Quick Chip EMV)", async () => {
1753
+ const param = new UpaParam_1.UpaParam();
1754
+ param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Contact];
1755
+ param.header = "Quick Chip Sale";
1756
+ param.displayTotalAmount = "Yes";
1757
+ param.timeout = 90;
1758
+ const indicator = new ProcessIndicator_1.ProcessingIndicator();
1759
+ indicator.QuickChip = "Y"; // Quick Chip enabled
1760
+ const transData = new UpaTransactionData_1.UpaTransactionData();
1761
+ transData.totalAmount = 10.0;
1762
+ transData.cashBackAmount = 0.0;
1763
+ transData.tranDate = new Date();
1764
+ transData.tranTime = new Date();
1765
+ transData.transType = src_1.TransactionType.Sale;
1766
+ let response;
1767
+ try {
1768
+ response = await device.startCardTransaction(param, indicator, transData);
1769
+ }
1770
+ catch (error) {
1771
+ if (UpaHelpertest_1.useLiveMic && (0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
1772
+ console.warn("StartCardTransaction quickChip='Y' timed out while waiting on the device.");
1773
+ return;
1774
+ }
1775
+ throw error;
1776
+ }
1777
+ expect(response).not.toBeNull();
1778
+ expect(response).toBeInstanceOf(UpaGiftCardResponse_1.UpaGiftCardResponse);
1779
+ if (UpaHelpertest_1.useLiveMic) {
1780
+ if ((0, UpaHelpertest_1.isKnownLiveStartCardTransactionBlocker)(response)) {
1781
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "StartCardTransaction quickChip='Y'"));
1782
+ return;
1783
+ }
1784
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "StartCardTransaction");
1785
+ // Quick Chip should result in Contact/Contactless acquisition
1786
+ expect(["CONTACT", "CONTACTLESS", "INSERT", "TAP"].some((x) => response.acquisitionType?.toUpperCase().includes(x))).toBe(true);
1787
+ return;
1788
+ }
1789
+ expect(response.status).toBe("Success");
1790
+ });
1791
+ test("[ProcessingIndicators:StartCardTransaction] quickChip='N' (Traditional EMV)", async () => {
1792
+ const param = new UpaParam_1.UpaParam();
1793
+ param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Contact];
1794
+ param.header = "Traditional EMV Sale";
1795
+ param.displayTotalAmount = "Yes";
1796
+ param.timeout = 90;
1797
+ const indicator = new ProcessIndicator_1.ProcessingIndicator();
1798
+ indicator.QuickChip = "N"; // Traditional EMV
1799
+ const transData = new UpaTransactionData_1.UpaTransactionData();
1800
+ transData.totalAmount = 15.0;
1801
+ transData.cashBackAmount = 0.0;
1802
+ transData.tranDate = new Date();
1803
+ transData.tranTime = new Date();
1804
+ transData.transType = src_1.TransactionType.Sale;
1805
+ let response;
1806
+ try {
1807
+ response = await device.startCardTransaction(param, indicator, transData);
1808
+ }
1809
+ catch (error) {
1810
+ if (UpaHelpertest_1.useLiveMic && (0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
1811
+ console.warn("StartCardTransaction quickChip='N' timed out while waiting on the device.");
1812
+ return;
1813
+ }
1814
+ throw error;
1815
+ }
1816
+ expect(response).not.toBeNull();
1817
+ if (UpaHelpertest_1.useLiveMic) {
1818
+ if ((0, UpaHelpertest_1.isKnownLiveStartCardTransactionBlocker)(response)) {
1819
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "StartCardTransaction quickChip='N'"));
1820
+ return;
1821
+ }
1822
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "StartCardTransaction");
1823
+ expect(response.acquisitionType).toBeTruthy();
1824
+ return;
1825
+ }
1826
+ expect(response.status).toBe("Success");
1827
+ });
1828
+ test("[ProcessingIndicators:StartCardTransaction] checkLuhn='Y' (with LUHN validation for manual entry)", async () => {
1829
+ const param = new UpaParam_1.UpaParam();
1830
+ param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Manual];
1831
+ param.header = "Manual Entry with LUHN Check";
1832
+ param.displayTotalAmount = "Yes";
1833
+ param.promptForManual = true;
1834
+ param.timeout = 90;
1835
+ const indicator = new ProcessIndicator_1.ProcessingIndicator();
1836
+ indicator.QuickChip = "Y";
1837
+ indicator.CheckLuhn = "Y"; // LUHN validation enabled
1838
+ const transData = new UpaTransactionData_1.UpaTransactionData();
1839
+ transData.totalAmount = 20.0;
1840
+ transData.cashBackAmount = 0.0;
1841
+ transData.tranDate = new Date();
1842
+ transData.tranTime = new Date();
1843
+ transData.transType = src_1.TransactionType.Sale;
1844
+ let response;
1845
+ try {
1846
+ response = await device.startCardTransaction(param, indicator, transData);
1847
+ }
1848
+ catch (error) {
1849
+ if (UpaHelpertest_1.useLiveMic && (0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
1850
+ console.warn("StartCardTransaction checkLuhn='Y' timed out while waiting on the device.");
1851
+ return;
1852
+ }
1853
+ throw error;
1854
+ }
1855
+ expect(response).not.toBeNull();
1856
+ if (UpaHelpertest_1.useLiveMic) {
1857
+ if ((0, UpaHelpertest_1.isKnownLiveStartCardTransactionBlocker)(response)) {
1858
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "StartCardTransaction checkLuhn='Y'"));
1859
+ return;
1860
+ }
1861
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "StartCardTransaction");
1862
+ // Manual entry should be recorded
1863
+ expect(response.acquisitionType?.toUpperCase()).toBe("MANUAL");
1864
+ return;
1865
+ }
1866
+ expect(response.status).toBe("Success");
1867
+ });
1868
+ test("[ProcessingIndicators:StartCardTransaction] checkLuhn='N' (skip LUHN validation)", async () => {
1869
+ const param = new UpaParam_1.UpaParam();
1870
+ param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Manual];
1871
+ param.header = "Manual Entry without LUHN Check";
1872
+ param.displayTotalAmount = "Yes";
1873
+ param.promptForManual = true;
1874
+ param.timeout = 90;
1875
+ const indicator = new ProcessIndicator_1.ProcessingIndicator();
1876
+ indicator.QuickChip = "Y";
1877
+ indicator.CheckLuhn = "N"; // LUHN validation disabled
1878
+ const transData = new UpaTransactionData_1.UpaTransactionData();
1879
+ transData.totalAmount = 25.0;
1880
+ transData.cashBackAmount = 0.0;
1881
+ transData.tranDate = new Date();
1882
+ transData.tranTime = new Date();
1883
+ transData.transType = src_1.TransactionType.Sale;
1884
+ let response;
1885
+ try {
1886
+ response = await device.startCardTransaction(param, indicator, transData);
1887
+ }
1888
+ catch (error) {
1889
+ if (UpaHelpertest_1.useLiveMic && (0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
1890
+ console.warn("StartCardTransaction checkLuhn='N' timed out while waiting on the device.");
1891
+ return;
1892
+ }
1893
+ throw error;
1894
+ }
1895
+ expect(response).not.toBeNull();
1896
+ if (UpaHelpertest_1.useLiveMic) {
1897
+ if ((0, UpaHelpertest_1.isKnownLiveStartCardTransactionBlocker)(response)) {
1898
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "StartCardTransaction checkLuhn='N'"));
1899
+ return;
1900
+ }
1901
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "StartCardTransaction");
1902
+ return;
1903
+ }
1904
+ expect(response.status).toBe("Success");
1905
+ });
1906
+ test("[ProcessingIndicators:StartCardTransaction] securityCode='Y' (prompt for CVV)", async () => {
1907
+ const param = new UpaParam_1.UpaParam();
1908
+ param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Manual];
1909
+ param.header = "Manual Entry with CVV Prompt";
1910
+ param.displayTotalAmount = "Yes";
1911
+ param.promptForManual = true;
1912
+ param.timeout = 90;
1913
+ const indicator = new ProcessIndicator_1.ProcessingIndicator();
1914
+ indicator.QuickChip = "Y";
1915
+ indicator.CheckLuhn = "Y";
1916
+ indicator.SecurityCode = "Y"; // Request CVV/CVC
1917
+ const transData = new UpaTransactionData_1.UpaTransactionData();
1918
+ transData.totalAmount = 30.0;
1919
+ transData.cashBackAmount = 0.0;
1920
+ transData.tranDate = new Date();
1921
+ transData.tranTime = new Date();
1922
+ transData.transType = src_1.TransactionType.Sale;
1923
+ let response;
1924
+ try {
1925
+ response = await device.startCardTransaction(param, indicator, transData);
1926
+ }
1927
+ catch (error) {
1928
+ if (UpaHelpertest_1.useLiveMic && (0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
1929
+ console.warn("StartCardTransaction securityCode='Y' timed out while waiting on the device.");
1930
+ return;
1931
+ }
1932
+ throw error;
1933
+ }
1934
+ expect(response).not.toBeNull();
1935
+ if (UpaHelpertest_1.useLiveMic) {
1936
+ if ((0, UpaHelpertest_1.isKnownLiveStartCardTransactionBlocker)(response)) {
1937
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "StartCardTransaction securityCode='Y'"));
1938
+ return;
1939
+ }
1940
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "StartCardTransaction");
1941
+ // CVV should be present in manual entry response
1942
+ if (response.acquisitionType?.toUpperCase() === "MANUAL") {
1943
+ expect(response.cvv).toBeTruthy();
1944
+ }
1945
+ return;
1946
+ }
1947
+ expect(response.status).toBe("Success");
1948
+ });
1949
+ test("[ProcessingIndicators:StartCardTransaction] securityCode='N' (skip CVV prompt)", async () => {
1950
+ const param = new UpaParam_1.UpaParam();
1951
+ param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Manual];
1952
+ param.header = "Manual Entry without CVV Prompt";
1953
+ param.displayTotalAmount = "Yes";
1954
+ param.promptForManual = true;
1955
+ param.timeout = 90;
1956
+ const indicator = new ProcessIndicator_1.ProcessingIndicator();
1957
+ indicator.QuickChip = "Y";
1958
+ indicator.CheckLuhn = "Y";
1959
+ indicator.SecurityCode = "N"; // Skip CVV prompt
1960
+ const transData = new UpaTransactionData_1.UpaTransactionData();
1961
+ transData.totalAmount = 35.0;
1962
+ transData.cashBackAmount = 0.0;
1963
+ transData.tranDate = new Date();
1964
+ transData.tranTime = new Date();
1965
+ transData.transType = src_1.TransactionType.Sale;
1966
+ let response;
1967
+ try {
1968
+ response = await device.startCardTransaction(param, indicator, transData);
1969
+ }
1970
+ catch (error) {
1971
+ if (UpaHelpertest_1.useLiveMic && (0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
1972
+ console.warn("StartCardTransaction securityCode='N' timed out while waiting on the device.");
1973
+ return;
1974
+ }
1975
+ throw error;
1976
+ }
1977
+ expect(response).not.toBeNull();
1978
+ if (UpaHelpertest_1.useLiveMic) {
1979
+ if ((0, UpaHelpertest_1.isKnownLiveStartCardTransactionBlocker)(response)) {
1980
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "StartCardTransaction securityCode='N'"));
1981
+ return;
1982
+ }
1983
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "StartCardTransaction");
1984
+ return;
1985
+ }
1986
+ expect(response.status).toBe("Success");
1987
+ });
1988
+ test("[ProcessingIndicators:StartCardTransaction] All indicators combined (quickChip=Y, checkLuhn=Y, securityCode=Y)", async () => {
1989
+ const param = new UpaParam_1.UpaParam();
1990
+ param.acquisitionTypes = [
1991
+ AcquisitionType_1.AcquisitionType.Contact,
1992
+ AcquisitionType_1.AcquisitionType.Contactless,
1993
+ AcquisitionType_1.AcquisitionType.Swipe,
1994
+ AcquisitionType_1.AcquisitionType.Manual,
1995
+ ];
1996
+ param.header = "Full Processing Indicators";
1997
+ param.displayTotalAmount = "Yes";
1998
+ param.timeout = 90;
1999
+ const indicator = new ProcessIndicator_1.ProcessingIndicator();
2000
+ indicator.QuickChip = "Y";
2001
+ indicator.CheckLuhn = "Y";
2002
+ indicator.SecurityCode = "Y";
2003
+ const transData = new UpaTransactionData_1.UpaTransactionData();
2004
+ transData.totalAmount = 50.0;
2005
+ transData.cashBackAmount = 5.0;
2006
+ transData.tranDate = new Date();
2007
+ transData.tranTime = new Date();
2008
+ transData.transType = src_1.TransactionType.Sale;
2009
+ let response;
2010
+ try {
2011
+ response = await device.startCardTransaction(param, indicator, transData);
2012
+ }
2013
+ catch (error) {
2014
+ if (UpaHelpertest_1.useLiveMic && (0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
2015
+ console.warn("StartCardTransaction combined indicators timed out while waiting on the device.");
2016
+ return;
2017
+ }
2018
+ throw error;
2019
+ }
2020
+ expect(response).not.toBeNull();
2021
+ expect(response).toBeInstanceOf(UpaGiftCardResponse_1.UpaGiftCardResponse);
2022
+ if (UpaHelpertest_1.useLiveMic) {
2023
+ if ((0, UpaHelpertest_1.isKnownLiveStartCardTransactionBlocker)(response)) {
2024
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "StartCardTransaction combined indicators"));
2025
+ return;
2026
+ }
2027
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "StartCardTransaction");
2028
+ (0, UpaHelpertest_1.expectParsedStartCardTransactionResponse)(response);
2029
+ return;
2030
+ }
2031
+ expect(response.status).toBe("Success");
2032
+ expect(response.deviceResponseCode).toBe("00");
2033
+ });
2034
+ });
2035
+ // ===========================================================================
2036
+ // processingIndicators – Response Indicators Validation
2037
+ // Per UPA spec: luhnCheckPassed, fallback, pinVerified, qpsQualified, etc.
2038
+ // ===========================================================================
2039
+ (0, UpaHelpertest_1.describeUpaLive)("UPA Admin – processingIndicators response indicators", () => {
2040
+ let device;
2041
+ beforeEach(() => {
2042
+ device = (0, UpaHelpertest_1.createTestDevice)();
2043
+ });
2044
+ test("[ResponseIndicators] StartCardTransaction manual entry returns luhnCheckPassed indicator", async () => {
2045
+ const param = new UpaParam_1.UpaParam();
2046
+ param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Manual];
2047
+ param.header = "LUHN Validation Response";
2048
+ param.displayTotalAmount = "Yes";
2049
+ param.promptForManual = true;
2050
+ param.timeout = 90;
2051
+ const indicator = new ProcessIndicator_1.ProcessingIndicator();
2052
+ indicator.QuickChip = "Y";
2053
+ indicator.CheckLuhn = "Y"; // Enable LUHN check
2054
+ const transData = new UpaTransactionData_1.UpaTransactionData();
2055
+ transData.totalAmount = 10.0;
2056
+ transData.cashBackAmount = 0.0;
2057
+ transData.tranDate = new Date();
2058
+ transData.tranTime = new Date();
2059
+ transData.transType = src_1.TransactionType.Sale;
2060
+ let response;
2061
+ try {
2062
+ response = await device.startCardTransaction(param, indicator, transData);
919
2063
  }
920
2064
  catch (error) {
921
- if ((0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
922
- console.warn("Reboot inactive or unresponsive terminal timed out while waiting on the device or gateway.");
2065
+ if (UpaHelpertest_1.useLiveMic && (0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
2066
+ console.warn("StartCardTransaction luhnCheckPassed response timed out.");
923
2067
  return;
924
2068
  }
925
- expect(error).toBeInstanceOf(Error);
926
- expect(error.message).toBeTruthy();
2069
+ throw error;
2070
+ }
2071
+ expect(response).not.toBeNull();
2072
+ if (UpaHelpertest_1.useLiveMic) {
2073
+ if ((0, UpaHelpertest_1.isKnownLiveStartCardTransactionBlocker)(response)) {
2074
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "Response luhnCheckPassed indicator"));
2075
+ return;
2076
+ }
2077
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "StartCardTransaction");
2078
+ // Per UPA spec: luhnCheckPassed should be present when checkLuhn='Y'
2079
+ if (response.acquisitionType?.toUpperCase() === "MANUAL") {
2080
+ // Response may include luhnCheckPassed as response indicator
2081
+ // Document current behavior: presence depends on implementation
2082
+ if (response.luhnCheckPassed !== undefined) {
2083
+ expect([response.luhnCheckPassed]).toContain(response.luhnCheckPassed);
2084
+ }
2085
+ }
2086
+ return;
927
2087
  }
2088
+ expect(response.status).toBe("Success");
928
2089
  });
929
- test("[Negative] reboot() surfaces network or communication failure", async () => {
930
- const communicationFailureDevice = DeviceService_1.DeviceService.create((0, UpaHelpertest_1.buildConfig)({ serviceUrl: "http://127.0.0.1:1" }), "reboot-communication-failure");
931
- communicationFailureDevice.ecrId = "13";
932
- await expect(communicationFailureDevice.reboot()).rejects.toBeInstanceOf(Error);
2090
+ test("[ResponseIndicators] StartCardTransaction returns response indicators (status, code, acquisitionType)", async () => {
2091
+ const param = new UpaParam_1.UpaParam();
2092
+ param.acquisitionTypes = [
2093
+ AcquisitionType_1.AcquisitionType.Contact,
2094
+ AcquisitionType_1.AcquisitionType.Contactless,
2095
+ AcquisitionType_1.AcquisitionType.Swipe,
2096
+ ];
2097
+ param.header = "Response Indicator Validation";
2098
+ param.displayTotalAmount = "Yes";
2099
+ param.timeout = 60;
2100
+ const indicator = new ProcessIndicator_1.ProcessingIndicator();
2101
+ indicator.QuickChip = "Y";
2102
+ indicator.CheckLuhn = "N";
2103
+ indicator.SecurityCode = "Y";
2104
+ const transData = new UpaTransactionData_1.UpaTransactionData();
2105
+ transData.totalAmount = 20.0;
2106
+ transData.cashBackAmount = 0.0;
2107
+ transData.tranDate = new Date();
2108
+ transData.tranTime = new Date();
2109
+ transData.transType = src_1.TransactionType.Sale;
2110
+ let response;
2111
+ try {
2112
+ response = await device.startCardTransaction(param, indicator, transData);
2113
+ }
2114
+ catch (error) {
2115
+ if (UpaHelpertest_1.useLiveMic && (0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
2116
+ console.warn("StartCardTransaction response indicators timed out.");
2117
+ return;
2118
+ }
2119
+ throw error;
2120
+ }
2121
+ expect(response).not.toBeNull();
2122
+ expect(response).toBeInstanceOf(UpaGiftCardResponse_1.UpaGiftCardResponse);
2123
+ if (UpaHelpertest_1.useLiveMic) {
2124
+ if ((0, UpaHelpertest_1.isKnownLiveStartCardTransactionBlocker)(response)) {
2125
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "Response indicator validation"));
2126
+ return;
2127
+ }
2128
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "StartCardTransaction");
2129
+ // Per UPA spec §12.4.x: response should include these fields
2130
+ expect(response.status).toBe("Success");
2131
+ expect(response.deviceResponseCode).toBe("00");
2132
+ expect(response.acquisitionType).toBeTruthy();
2133
+ // Document optional response indicators
2134
+ console.log("Response indicators: acquisitionType=%s, cardBrand=%s", response.acquisitionType, response.cardBrand);
2135
+ return;
2136
+ }
2137
+ expect(response.status).toBe("Success");
2138
+ expect(response.deviceResponseCode).toBe("00");
2139
+ expect(response.acquisitionType).toBeTruthy();
2140
+ });
2141
+ test("[ResponseIndicators] StartCardTransaction with cardTypeFilter returns restricted card brands", async () => {
2142
+ const param = new UpaParam_1.UpaParam();
2143
+ param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Manual];
2144
+ param.header = "Card Type Filter Response";
2145
+ param.displayTotalAmount = "Yes";
2146
+ param.promptForManual = true;
2147
+ param.timeout = 90;
2148
+ const indicator = new ProcessIndicator_1.ProcessingIndicator();
2149
+ indicator.QuickChip = "Y";
2150
+ indicator.CardTypeFilter = [CardTypeFilter_1.CardTypeFilter.VISA, CardTypeFilter_1.CardTypeFilter.MC]; // Restrict to VISA/MC
2151
+ const transData = new UpaTransactionData_1.UpaTransactionData();
2152
+ transData.totalAmount = 15.0;
2153
+ transData.cashBackAmount = 0.0;
2154
+ transData.tranDate = new Date();
2155
+ transData.tranTime = new Date();
2156
+ transData.transType = src_1.TransactionType.Sale;
2157
+ let response;
2158
+ try {
2159
+ response = await device.startCardTransaction(param, indicator, transData);
2160
+ }
2161
+ catch (error) {
2162
+ if (UpaHelpertest_1.useLiveMic && (0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
2163
+ console.warn("StartCardTransaction cardTypeFilter response timed out.");
2164
+ return;
2165
+ }
2166
+ throw error;
2167
+ }
2168
+ expect(response).not.toBeNull();
2169
+ if (UpaHelpertest_1.useLiveMic) {
2170
+ if ((0, UpaHelpertest_1.isKnownLiveStartCardTransactionBlocker)(response)) {
2171
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "Response cardTypeFilter validation"));
2172
+ return;
2173
+ }
2174
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, "StartCardTransaction");
2175
+ // Per cardTypeFilter=[VISA, MC], response should reflect only those brands
2176
+ if (response.cardBrandShortName) {
2177
+ expect(["VI", "MC"].some((b) => response.cardBrandShortName?.toUpperCase().includes(b))).toBe(true);
2178
+ }
2179
+ return;
2180
+ }
2181
+ expect(response.status).toBe("Success");
933
2182
  });
934
2183
  });
935
- (0, UpaHelpertest_1.describeUpaLive)("UPA Admin – deleteSaf()", () => {
2184
+ // ===========================================================================
2185
+ // Direct Marketing Fields – Sale, Refund, PreAuth, TipAdjust, etc.
2186
+ // Per UPA spec: directMktInvoiceNbr, directMktShipMonth, directMktShipDay
2187
+ // ===========================================================================
2188
+ /**
2189
+ * Helper: Generate Direct Marketing fields with correct date handling
2190
+ * Per UPA spec: if directMktInvoiceNbr provided, directMktShipMonth and directMktShipDay are required
2191
+ */
2192
+ function buildDirectMarketingFields(invoiceNumber, shipDate) {
2193
+ const date = shipDate || new Date();
2194
+ // Correct JavaScript date handling:
2195
+ // getMonth() returns 0-11 (Jan=0, Aug=7), so add 1 and pad
2196
+ // getDate() returns 1-31 (correct day of month)
2197
+ const month = String(date.getMonth() + 1).padStart(2, "0");
2198
+ const day = String(date.getDate()).padStart(2, "0");
2199
+ return {
2200
+ directMktInvoiceNbr: invoiceNumber,
2201
+ directMktShipMonth: month,
2202
+ directMktShipDay: day,
2203
+ };
2204
+ }
2205
+ (0, UpaHelpertest_1.describeUpaLive)("UPA Admin – Direct Marketing Fields (Sale/Refund/PreAuth)", () => {
936
2206
  let device;
937
- async function settle(delayMs = 8000) {
2207
+ beforeEach(() => {
2208
+ device = (0, UpaHelpertest_1.createTestDevice)();
2209
+ });
2210
+ test("[DirectMarketing:Sale] Sale with directMktInvoiceNbr, directMktShipMonth, directMktShipDay", async () => {
2211
+ const directMktFields = buildDirectMarketingFields("INV20260817001");
2212
+ const response = (await device
2213
+ .sale(5.0)
2214
+ .withEcrId(13)
2215
+ .withClerkId(123)
2216
+ .withDirectMktInvoiceNbr(directMktFields.directMktInvoiceNbr)
2217
+ .withDirectMktShipMonth(directMktFields.directMktShipMonth)
2218
+ .withDirectMktShipDay(directMktFields.directMktShipDay)
2219
+ .execute());
2220
+ expect(response).not.toBeNull();
2221
+ expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
938
2222
  if (UpaHelpertest_1.useLiveMic) {
939
- await new Promise((resolve) => setTimeout(resolve, delayMs));
2223
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(response)) {
2224
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "Sale with Direct Marketing fields"));
2225
+ return;
2226
+ }
2227
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["Sale", "SendCommand"]);
2228
+ expect(response.terminalRefNumber).toBeTruthy();
2229
+ return;
940
2230
  }
941
- }
942
- function extractTranNoFromSafReport(safReport) {
943
- const buckets = [
944
- safReport?.approved,
945
- safReport?.pending,
946
- safReport?.declined,
947
- safReport?.reportResult?.approved,
948
- safReport?.reportResult?.pending,
949
- safReport?.reportResult?.declined,
950
- ];
951
- for (const bucket of buckets) {
952
- if (!bucket) {
953
- continue;
2231
+ expect(response.status).toBe("Success");
2232
+ expect(response.deviceResponseCode).toBe("00");
2233
+ });
2234
+ test("[DirectMarketing:Sale] Sale returns directMktInvoiceNbr, directMktShipMonth, directMktShipDay in response", async () => {
2235
+ const directMktFields = buildDirectMarketingFields("INV20260817002", new Date(2026, 7, 17));
2236
+ const response = (await device
2237
+ .sale(10.0)
2238
+ .withEcrId(13)
2239
+ .withClerkId(123)
2240
+ .withDirectMktInvoiceNbr(directMktFields.directMktInvoiceNbr)
2241
+ .withDirectMktShipMonth(directMktFields.directMktShipMonth)
2242
+ .withDirectMktShipDay(directMktFields.directMktShipDay)
2243
+ .execute());
2244
+ expect(response).not.toBeNull();
2245
+ if (UpaHelpertest_1.useLiveMic) {
2246
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(response)) {
2247
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "Sale Direct Marketing response field validation"));
2248
+ return;
954
2249
  }
955
- for (const summary of Object.values(bucket)) {
956
- const transactions = summary?.transactions ?? [];
957
- for (const txn of transactions) {
958
- const candidate = txn?.transactionId;
959
- if (typeof candidate === "string" && /^\d{4,6}$/.test(candidate)) {
960
- return candidate;
961
- }
962
- if (typeof candidate === "number") {
963
- const asString = candidate.toString();
964
- if (/^\d{4,6}$/.test(asString)) {
965
- return asString;
966
- }
967
- }
2250
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["Sale", "SendCommand"]);
2251
+ // Per UPA spec: response should echo direct marketing fields
2252
+ if (response.directMktInvoiceNbr) {
2253
+ expect(response.directMktInvoiceNbr).toBe(directMktFields.directMktInvoiceNbr);
2254
+ }
2255
+ if (response.directMktShipMonth) {
2256
+ expect(response.directMktShipMonth).toBe("08");
2257
+ }
2258
+ if (response.directMktShipDay) {
2259
+ expect(response.directMktShipDay).toBe("17");
2260
+ }
2261
+ return;
2262
+ }
2263
+ expect(response.status).toBe("Success");
2264
+ });
2265
+ test("[DirectMarketing:Refund] Refund with directMktInvoiceNbr, directMktShipMonth, directMktShipDay", async () => {
2266
+ // Prerequisite: create a sale first
2267
+ let saleResponse;
2268
+ try {
2269
+ saleResponse = await (0, UpaHelpertest_1.createLiveSale)(device);
2270
+ if (saleResponse.deviceResponseCode !== "00") {
2271
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(saleResponse)) {
2272
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(saleResponse, "Sale prerequisite"));
2273
+ return;
968
2274
  }
2275
+ throw new Error((0, UpaHelpertest_1.formatLiveFailure)(saleResponse, "Sale prerequisite"));
2276
+ }
2277
+ }
2278
+ catch (error) {
2279
+ if ((0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
2280
+ console.warn("Refund with Direct Marketing fields prerequisite timed out.");
2281
+ return;
2282
+ }
2283
+ throw error;
2284
+ }
2285
+ const directMktFields = buildDirectMarketingFields("REFUND20260817001");
2286
+ const refundResponse = (await device
2287
+ .refund(1.0)
2288
+ .withEcrId(13)
2289
+ .withTransactionId(saleResponse.transactionId)
2290
+ .withDirectMktInvoiceNbr(directMktFields.directMktInvoiceNbr)
2291
+ .withDirectMktShipMonth(directMktFields.directMktShipMonth)
2292
+ .withDirectMktShipDay(directMktFields.directMktShipDay)
2293
+ .execute());
2294
+ expect(refundResponse).not.toBeNull();
2295
+ if (UpaHelpertest_1.useLiveMic) {
2296
+ if ((0, UpaHelpertest_1.isKnownLiveBusyBlocker)(refundResponse)) {
2297
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(refundResponse, "Refund with Direct Marketing fields"));
2298
+ return;
2299
+ }
2300
+ (0, UpaHelpertest_1.expectLiveSuccess)(refundResponse, ["Refund", "SendCommand"]);
2301
+ return;
2302
+ }
2303
+ expect(refundResponse.status).toBe("Success");
2304
+ });
2305
+ test("[DirectMarketing:PreAuth] PreAuth (OpenTab) with directMktInvoiceNbr, directMktShipMonth, directMktShipDay", async () => {
2306
+ const directMktFields = buildDirectMarketingFields("PRETAB20260817001");
2307
+ const response = (await device
2308
+ .authorize(15.0)
2309
+ .withEcrId(13)
2310
+ .withClerkId(123)
2311
+ .withDirectMktInvoiceNbr(directMktFields.directMktInvoiceNbr)
2312
+ .withDirectMktShipMonth(directMktFields.directMktShipMonth)
2313
+ .withDirectMktShipDay(directMktFields.directMktShipDay)
2314
+ .execute());
2315
+ expect(response).not.toBeNull();
2316
+ if (UpaHelpertest_1.useLiveMic) {
2317
+ if ((0, UpaHelpertest_1.isKnownLiveBusyBlocker)(response)) {
2318
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "PreAuth with Direct Marketing fields"));
2319
+ return;
2320
+ }
2321
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["PreAuth", "SendCommand"]);
2322
+ expect(response.transactionId).toBeTruthy();
2323
+ return;
2324
+ }
2325
+ expect(response.status).toBe("Success");
2326
+ expect(response.deviceResponseCode).toBe("00");
2327
+ });
2328
+ test("[DirectMarketing:Validation] Missing directMktShipMonth and directMktShipDay when directMktInvoiceNbr provided should be caught", async () => {
2329
+ // Per UPA spec: if directMktInvoiceNbr is provided, directMktShipMonth and directMktShipDay must be provided too
2330
+ // This test documents the behavior:
2331
+ // If only invoice number is provided without month/day, the request should fail or device should reject it
2332
+ try {
2333
+ const response = (await device
2334
+ .sale(5.0)
2335
+ .withEcrId(13)
2336
+ .withClerkId(123)
2337
+ .withDirectMktInvoiceNbr("INCOMPLETE001")
2338
+ // Intentionally omit directMktShipMonth and directMktShipDay
2339
+ .execute());
2340
+ expect(response).not.toBeNull();
2341
+ // Per spec: incomplete direct marketing fields should result in failure
2342
+ if (UpaHelpertest_1.useLiveMic && response.deviceResponseCode !== "00") {
2343
+ console.log("[Validation] Incomplete Direct Marketing fields rejected:", response.deviceResponseCode, response.deviceResponseText);
2344
+ expect(response.deviceResponseCode).not.toBe("00");
2345
+ return;
2346
+ }
2347
+ console.warn("[Validation] Terminal accepted incomplete Direct Marketing fields; device may have looser validation");
2348
+ }
2349
+ catch (error) {
2350
+ if ((0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
2351
+ console.warn("Incomplete Direct Marketing fields validation timed out.");
2352
+ return;
2353
+ }
2354
+ // Expected: ArgumentError or validation error
2355
+ expect(error).toBeInstanceOf(Error);
2356
+ }
2357
+ });
2358
+ test("[DirectMarketing:DateHandling] Correct JavaScript date handling (getMonth() + 1, getDate())", async () => {
2359
+ // Test date: August 17, 2026
2360
+ const testDate = new Date(2026, 7, 17); // Month is 0-indexed, so 7 = August
2361
+ const directMktFields = buildDirectMarketingFields("DATE_TEST_20260817", testDate);
2362
+ // Verify correct month conversion (0-11 → 01-12)
2363
+ expect(directMktFields.directMktShipMonth).toBe("08");
2364
+ // Verify correct day (1-31)
2365
+ expect(directMktFields.directMktShipDay).toBe("17");
2366
+ const response = (await device
2367
+ .sale(5.0)
2368
+ .withEcrId(13)
2369
+ .withClerkId(123)
2370
+ .withDirectMktInvoiceNbr(directMktFields.directMktInvoiceNbr)
2371
+ .withDirectMktShipMonth(directMktFields.directMktShipMonth)
2372
+ .withDirectMktShipDay(directMktFields.directMktShipDay)
2373
+ .execute());
2374
+ expect(response).not.toBeNull();
2375
+ if (UpaHelpertest_1.useLiveMic) {
2376
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(response)) {
2377
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "Date handling validation"));
2378
+ return;
2379
+ }
2380
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["Sale", "SendCommand"]);
2381
+ console.log("[DateHandling] Verified: Month=%s, Day=%s", directMktFields.directMktShipMonth, directMktFields.directMktShipDay);
2382
+ return;
2383
+ }
2384
+ expect(response.status).toBe("Success");
2385
+ });
2386
+ test("[DirectMarketing:EdgeCase] Month boundaries (January=01, December=12)", async () => {
2387
+ // Test January (month=0)
2388
+ const januaryFields = buildDirectMarketingFields("JAN_TEST_001", new Date(2026, 0, 1));
2389
+ expect(januaryFields.directMktShipMonth).toBe("01");
2390
+ // Test December (month=11)
2391
+ const decemberFields = buildDirectMarketingFields("DEC_TEST_001", new Date(2026, 11, 31));
2392
+ expect(decemberFields.directMktShipMonth).toBe("12");
2393
+ console.log("[EdgeCase] Month boundaries verified: Jan=%s, Dec=%s", januaryFields.directMktShipMonth, decemberFields.directMktShipMonth);
2394
+ });
2395
+ test("[DirectMarketing:EdgeCase] Day padding (single digit days 01-09)", async () => {
2396
+ // Test day 1 (should be "01", not "1")
2397
+ const dayOneFields = buildDirectMarketingFields("DAY_01_TEST", new Date(2026, 7, 1));
2398
+ expect(dayOneFields.directMktShipDay).toBe("01");
2399
+ // Test day 9 (should be "09", not "9")
2400
+ const dayNineFields = buildDirectMarketingFields("DAY_09_TEST", new Date(2026, 7, 9));
2401
+ expect(dayNineFields.directMktShipDay).toBe("09");
2402
+ console.log("[EdgeCase] Day padding verified: 01=%s, 09=%s", dayOneFields.directMktShipDay, dayNineFields.directMktShipDay);
2403
+ });
2404
+ });
2405
+ (0, UpaHelpertest_1.describeUpaLive)("UPA Admin – Parameterized Direct Marketing Tests", () => {
2406
+ let device;
2407
+ beforeEach(() => {
2408
+ device = (0, UpaHelpertest_1.createTestDevice)();
2409
+ });
2410
+ const testCases = [
2411
+ {
2412
+ name: "Current Date Sale",
2413
+ amount: 5.0,
2414
+ invoicePrefix: "CURRENT",
2415
+ shipDate: new Date(),
2416
+ },
2417
+ {
2418
+ name: "Future Date Sale",
2419
+ amount: 10.0,
2420
+ invoicePrefix: "FUTURE",
2421
+ shipDate: new Date(2026, 8, 30), // Sept 30, 2026
2422
+ },
2423
+ {
2424
+ name: "Past Date Sale",
2425
+ amount: 7.5,
2426
+ invoicePrefix: "PAST",
2427
+ shipDate: new Date(2026, 6, 15), // July 15, 2026
2428
+ },
2429
+ {
2430
+ name: "Year-End Sale",
2431
+ amount: 25.0,
2432
+ invoicePrefix: "YEAREND",
2433
+ shipDate: new Date(2026, 11, 31), // Dec 31, 2026
2434
+ },
2435
+ ];
2436
+ test.each(testCases)("[Parameterized:DirectMarketing] $name with Direct Marketing fields", async (testCase) => {
2437
+ const directMktFields = buildDirectMarketingFields(`${testCase.invoicePrefix}${Date.now()}`, testCase.shipDate);
2438
+ const response = (await device
2439
+ .sale(testCase.amount)
2440
+ .withEcrId(13)
2441
+ .withClerkId(123)
2442
+ .withDirectMktInvoiceNbr(directMktFields.directMktInvoiceNbr)
2443
+ .withDirectMktShipMonth(directMktFields.directMktShipMonth)
2444
+ .withDirectMktShipDay(directMktFields.directMktShipDay)
2445
+ .execute());
2446
+ expect(response).not.toBeNull();
2447
+ if (UpaHelpertest_1.useLiveMic) {
2448
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(response)) {
2449
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, `${testCase.name} Direct Marketing`));
2450
+ return;
969
2451
  }
2452
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["Sale", "SendCommand"]);
2453
+ expect(response.terminalRefNumber).toBeTruthy();
2454
+ return;
970
2455
  }
971
- return undefined;
972
- }
2456
+ expect(response.status).toBe("Success");
2457
+ expect(response.deviceResponseCode).toBe("00");
2458
+ });
2459
+ });
2460
+ // ===========================================================================
2461
+ // UPA Spec Parameters – cardOnFileIndicator, cardBrandTransId, merchantDecision
2462
+ // Per UPA Integrators Guide 02.20.02.B
2463
+ // ===========================================================================
2464
+ (0, UpaHelpertest_1.describeUpaLive)("UPA Spec Parameters – cardOnFileIndicator (Request)", () => {
2465
+ let device;
973
2466
  beforeEach(() => {
974
2467
  device = (0, UpaHelpertest_1.createTestDevice)();
975
2468
  });
976
- test("[UpaAdminTests:754] deleteSaf() executes over live MITC when a SAF record exists", async () => {
977
- const safReport = await (0, UpaHelpertest_1.ensureSafData)(device, UpaHelpertest_1.createLiveSale, settle);
978
- if (!safReport) {
979
- return;
980
- }
981
- const safReferenceNumber = (0, UpaHelpertest_1.getFirstSafReferenceNumber)(safReport);
982
- if (!safReferenceNumber) {
983
- console.warn("deleteSaf() live MITC prerequisite skipped: no SAF records available.");
2469
+ test("[SpecCompliance:cardOnFileIndicator] Sale with cardOnFileIndicator='C' (Cardholder Initiated)", async () => {
2470
+ const response = (await device
2471
+ .sale(5.0)
2472
+ .withEcrId(13)
2473
+ .withClerkId(123)
2474
+ .withRequestMultiUseToken(true)
2475
+ .withCardOnFileIndicator(src_1.StoredCredentialInitiator.CardHolder)
2476
+ .execute());
2477
+ expect(response).not.toBeNull();
2478
+ expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
2479
+ if (UpaHelpertest_1.useLiveMic) {
2480
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(response)) {
2481
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "cardOnFileIndicator='C' Sale"));
2482
+ return;
2483
+ }
2484
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["Sale", "SendCommand"]);
2485
+ expect(response.terminalRefNumber).toBeTruthy();
984
2486
  return;
985
2487
  }
986
- console.log(safReferenceNumber);
987
- const response = await device.deleteSaf(safReferenceNumber);
988
- expect(response).toBeInstanceOf(UpaSAFResponse_1.UpaSAFResponse);
989
- expect(response.command).toBe("DeleteSAF");
990
- if (response.status === "Failed") {
991
- if (["TRAN001", "TRAN010"].includes(response.deviceResponseCode)) {
992
- console.warn(`deleteSaf() reference=${safReferenceNumber} returned spec-valid failure ${response.deviceResponseCode} (${response.deviceResponseText}); only host-declined SAF records are freely deletable per §12.4.25.4.`);
2488
+ expect(response.status).toBe("Success");
2489
+ expect(response.deviceResponseCode).toBe("00");
2490
+ });
2491
+ test("[SpecCompliance:cardOnFileIndicator] Sale with cardOnFileIndicator='M' (Merchant Initiated)", async () => {
2492
+ const response = (await device
2493
+ .sale(5.0)
2494
+ .withEcrId(13)
2495
+ .withClerkId(123)
2496
+ .withRequestMultiUseToken(true)
2497
+ .withCardOnFileIndicator(src_1.StoredCredentialInitiator.Merchant)
2498
+ .execute());
2499
+ expect(response).not.toBeNull();
2500
+ expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
2501
+ if (UpaHelpertest_1.useLiveMic) {
2502
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(response)) {
2503
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "cardOnFileIndicator='M' Sale"));
993
2504
  return;
994
2505
  }
995
- throw new Error(`deleteSaf() returned unexpected failure code=${response.deviceResponseCode} status=${response.status} text="${response.deviceResponseText}". Per UPA spec §12.4.25.4 the only permitted failure codes for a well-formed request are TRAN001 or TRAN010.`);
2506
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["Sale", "SendCommand"]);
2507
+ expect(response.terminalRefNumber).toBeTruthy();
2508
+ return;
996
2509
  }
997
- (0, UpaHelpertest_1.expectLiveSuccess)(response, "DeleteSAF");
2510
+ expect(response.status).toBe("Success");
2511
+ expect(response.deviceResponseCode).toBe("00");
998
2512
  });
999
- test('[UpaAdminTests:754] deleteSaf() surfaces response="DeleteSAF", cmdResult.result="Success", and transaction details', async () => {
1000
- const safReport = await (0, UpaHelpertest_1.ensureSafData)(device, UpaHelpertest_1.createLiveSale, settle);
1001
- if (!safReport) {
2513
+ test("[SpecCompliance:cardOnFileIndicator] Refund with cardOnFileIndicator='C'", async () => {
2514
+ const sale = await (0, UpaHelpertest_1.createLiveSale)(device);
2515
+ if (!sale || !sale.transactionId) {
2516
+ console.warn("Refund cardOnFileIndicator test: Sale prerequisite failed");
1002
2517
  return;
1003
2518
  }
1004
- const safReferenceNumber = (0, UpaHelpertest_1.getFirstSafReferenceNumber)(safReport);
1005
- if (!safReferenceNumber) {
1006
- console.warn("deleteSaf() live MITC prerequisite skipped: no SAF records available.");
2519
+ const response = (await device
2520
+ .refund(5.0)
2521
+ .withEcrId(13)
2522
+ .withClerkId(123)
2523
+ .withTransactionId(sale.transactionId)
2524
+ .withRequestMultiUseToken(true)
2525
+ .withCardOnFileIndicator(src_1.StoredCredentialInitiator.CardHolder)
2526
+ .execute());
2527
+ expect(response).not.toBeNull();
2528
+ expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
2529
+ if (UpaHelpertest_1.useLiveMic) {
2530
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(response)) {
2531
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "cardOnFileIndicator='C' Refund"));
2532
+ return;
2533
+ }
2534
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["Refund", "SendCommand"]);
1007
2535
  return;
1008
2536
  }
1009
- const response = await device.deleteSaf(safReferenceNumber);
1010
- expect(response).toBeInstanceOf(UpaSAFResponse_1.UpaSAFResponse);
1011
- expect(response.command).toBe("DeleteSAF");
1012
- if (response.status === "Failed") {
1013
- if (["TRAN001", "TRAN010"].includes(response.deviceResponseCode)) {
1014
- console.warn(`deleteSaf() reference=${safReferenceNumber} returned spec-valid failure ${response.deviceResponseCode} (${response.deviceResponseText}); only host-declined SAF records are freely deletable per §12.4.25.4.`);
2537
+ expect(response.status).toBe("Success");
2538
+ });
2539
+ test("[SpecCompliance:cardOnFileIndicator] PreAuth with cardOnFileIndicator='M'", async () => {
2540
+ const response = (await device
2541
+ .authorize(10.0)
2542
+ .withEcrId(13)
2543
+ .withClerkId(123)
2544
+ .withRequestMultiUseToken(true)
2545
+ .withCardOnFileIndicator(src_1.StoredCredentialInitiator.Merchant)
2546
+ .execute());
2547
+ expect(response).not.toBeNull();
2548
+ expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
2549
+ if (UpaHelpertest_1.useLiveMic) {
2550
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(response)) {
2551
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "cardOnFileIndicator='M' PreAuth"));
1015
2552
  return;
1016
2553
  }
1017
- throw new Error(`deleteSaf() returned unexpected failure code=${response.deviceResponseCode} status=${response.status} text="${response.deviceResponseText}". Per UPA spec §12.4.25.4 the only permitted failure codes for a well-formed request are TRAN001 or TRAN010.`);
2554
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["PreAuth", "SendCommand"]);
2555
+ expect(response.transactionId).toBeTruthy();
2556
+ return;
1018
2557
  }
1019
2558
  expect(response.status).toBe("Success");
1020
- expect(response.deviceResponseCode).toBe("00");
1021
- if (response.totalCount !== undefined ||
1022
- response.totalAmount !== undefined) {
1023
- expect(response.totalCount).toBeGreaterThanOrEqual(0);
1024
- expect(response.totalAmount).toBeGreaterThanOrEqual(0);
1025
- }
1026
2559
  });
1027
- test("[UpaAdminTests:754] deleteSaf() by tranNo executes over live MITC", async () => {
1028
- const safReport = await (0, UpaHelpertest_1.ensureSafData)(device, UpaHelpertest_1.createLiveSale, settle);
1029
- if (!safReport) {
2560
+ });
2561
+ // ===========================================================================
2562
+ // UPA Spec Parameters – cardBrandTransId Response Validation
2563
+ // Per UPA spec: cardBrandTransId echoed in response for Sale, Refund, PreAuth, AuthCompletion
2564
+ // ===========================================================================
2565
+ (0, UpaHelpertest_1.describeUpaLive)("UPA Spec Parameters – cardBrandTransId Response", () => {
2566
+ let device;
2567
+ beforeEach(() => {
2568
+ device = (0, UpaHelpertest_1.createTestDevice)();
2569
+ });
2570
+ test("[SpecCompliance:cardBrandTransId] Sale with cardBrandTransId parameter", async () => {
2571
+ const testTransId = "VISA_TRANS_20260817_001";
2572
+ const response = (await device
2573
+ .sale(5.0)
2574
+ .withEcrId(13)
2575
+ .withClerkId(123)
2576
+ .withCardBrandTransId(testTransId)
2577
+ .execute());
2578
+ expect(response).not.toBeNull();
2579
+ expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
2580
+ if (UpaHelpertest_1.useLiveMic) {
2581
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(response)) {
2582
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "cardBrandTransId Sale request"));
2583
+ return;
2584
+ }
2585
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["Sale", "SendCommand"]);
2586
+ // Per spec: cardBrandTransId should be echoed in response
2587
+ if (response.cardBrandTransId) {
2588
+ console.log("cardBrandTransId in response: %s", response.cardBrandTransId);
2589
+ }
1030
2590
  return;
1031
2591
  }
1032
- const candidateTranNo = extractTranNoFromSafReport(safReport);
1033
- if (!candidateTranNo) {
1034
- console.warn("deleteSaf(by tranNo) live MITC prerequisite skipped: no SAF record exposed a numeric tranNo/transId.");
2592
+ expect(response.status).toBe("Success");
2593
+ });
2594
+ test("[SpecCompliance:cardBrandTransId] Refund preserves cardBrandTransId", async () => {
2595
+ const sale = await (0, UpaHelpertest_1.createLiveSale)(device);
2596
+ if (!sale || !sale.transactionId) {
2597
+ console.warn("Refund cardBrandTransId test: Sale prerequisite failed");
1035
2598
  return;
1036
2599
  }
1037
- expect(device.deleteSaf.length).toBeGreaterThanOrEqual(2);
1038
- const response = await device.deleteSaf(undefined, candidateTranNo);
1039
- expect(response).toBeInstanceOf(UpaSAFResponse_1.UpaSAFResponse);
1040
- expect(response.command).toBe("DeleteSAF");
1041
- expect(["Success", "Failed"]).toContain(response.status);
1042
- if (response.status === "Failed") {
1043
- expect(["TRAN001", "TRAN010"]).toContain(response.deviceResponseCode);
2600
+ const testTransId = "MC_TRANS_20260817_002";
2601
+ const response = (await device
2602
+ .refund(5.0)
2603
+ .withEcrId(13)
2604
+ .withClerkId(123)
2605
+ .withTransactionId(sale.transactionId)
2606
+ .withCardBrandTransId(testTransId)
2607
+ .execute());
2608
+ expect(response).not.toBeNull();
2609
+ expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
2610
+ if (UpaHelpertest_1.useLiveMic) {
2611
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(response)) {
2612
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "cardBrandTransId Refund request"));
2613
+ return;
2614
+ }
2615
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["Refund", "SendCommand"]);
2616
+ return;
1044
2617
  }
2618
+ expect(response.status).toBe("Success");
1045
2619
  });
1046
- test("[UpaAdminTests:754] deleteSaf() with no identifiers deletes all host-declined SAF transactions", async () => {
1047
- expect(typeof device.deleteSaf).toBe("function");
1048
- expect(device.deleteSaf.length).toBeGreaterThanOrEqual(0);
1049
- if (process.env.UPA_DELETE_ALL_SAF !== "true") {
1050
- console.warn("deleteSaf() delete-all live scenario skipped. Set UPA_DELETE_ALL_SAF=true to execute (DESTRUCTIVE: erases every host-declined SAF record on the device).");
2620
+ test("[SpecCompliance:cardBrandTransId] PreAuth with cardBrandTransId echoed in response", async () => {
2621
+ const testTransId = "AMEX_TRANS_20260817_003";
2622
+ const response = (await device
2623
+ .authorize(15.0)
2624
+ .withEcrId(13)
2625
+ .withClerkId(123)
2626
+ .withCardBrandTransId(testTransId)
2627
+ .execute());
2628
+ expect(response).not.toBeNull();
2629
+ expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
2630
+ if (UpaHelpertest_1.useLiveMic) {
2631
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(response)) {
2632
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "cardBrandTransId PreAuth request"));
2633
+ return;
2634
+ }
2635
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["PreAuth", "SendCommand"]);
2636
+ expect(response.transactionId).toBeTruthy();
2637
+ // Verify cardBrandTransId presence
2638
+ if (response.cardBrandTransId) {
2639
+ console.log("PreAuth cardBrandTransId in response: %s", response.cardBrandTransId);
2640
+ }
1051
2641
  return;
1052
2642
  }
1053
- // Seed at least one SAF record so the delete-all has something to act on.
1054
- const safReport = await (0, UpaHelpertest_1.ensureSafData)(device, UpaHelpertest_1.createLiveSale, settle);
1055
- if (!safReport) {
2643
+ expect(response.status).toBe("Success");
2644
+ });
2645
+ });
2646
+ // ===========================================================================
2647
+ // UPA Spec Parameters – Direct Marketing Response Fields
2648
+ // Per UPA spec: directMktInvoiceNbr, directMktShipMonth, directMktShipDay echoed in response
2649
+ // ===========================================================================
2650
+ (0, UpaHelpertest_1.describeUpaLive)("UPA Spec Parameters – Direct Marketing Response Fields", () => {
2651
+ let device;
2652
+ beforeEach(() => {
2653
+ device = (0, UpaHelpertest_1.createTestDevice)();
2654
+ });
2655
+ test("[SpecCompliance:DirectMkt] Sale response contains directMktInvoiceNbr", async () => {
2656
+ const directMktFields = buildDirectMarketingFields("INV20260817_RESP_001");
2657
+ const response = (await device
2658
+ .sale(5.0)
2659
+ .withEcrId(13)
2660
+ .withClerkId(123)
2661
+ .withDirectMktInvoiceNbr(directMktFields.directMktInvoiceNbr)
2662
+ .withDirectMktShipMonth(directMktFields.directMktShipMonth)
2663
+ .withDirectMktShipDay(directMktFields.directMktShipDay)
2664
+ .execute());
2665
+ expect(response).not.toBeNull();
2666
+ expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
2667
+ if (UpaHelpertest_1.useLiveMic) {
2668
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(response)) {
2669
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "directMktInvoiceNbr response"));
2670
+ return;
2671
+ }
2672
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["Sale", "SendCommand"]);
2673
+ // Per UPA spec: directMktInvoiceNbr should be in response
2674
+ if (response.directMktInvoiceNbr) {
2675
+ expect(response.directMktInvoiceNbr).toBe(directMktFields.directMktInvoiceNbr);
2676
+ console.log("✓ Sale response contains directMktInvoiceNbr: %s", response.directMktInvoiceNbr);
2677
+ }
2678
+ else {
2679
+ console.warn("⚠ Sale response missing directMktInvoiceNbr field (device may not support)");
2680
+ }
1056
2681
  return;
1057
2682
  }
1058
- const response = await device.deleteSaf();
1059
- expect(response).toBeInstanceOf(UpaSAFResponse_1.UpaSAFResponse);
1060
- expect(response.command).toBe("DeleteSAF");
1061
- // Success is the expected outcome; Failed with TRAN001
1062
- // if the batch happens to contain no host-declined records at execution time
1063
- expect(["Success", "Failed"]).toContain(response.status);
2683
+ expect(response.status).toBe("Success");
1064
2684
  });
1065
- test("[UpaCreditTests] sale() serializes processing indicators without mocked responses", async () => {
1066
- const saleResponse = await (0, UpaHelpertest_1.createLiveSale)(device);
1067
- expect(saleResponse.status).toBe("Success");
2685
+ test("[SpecCompliance:DirectMkt] Sale response contains directMktShipMonth (01-12 format)", async () => {
2686
+ const directMktFields = buildDirectMarketingFields("INV20260817_MONTH_001");
2687
+ const response = (await device
2688
+ .sale(5.0)
2689
+ .withEcrId(13)
2690
+ .withClerkId(123)
2691
+ .withDirectMktInvoiceNbr(directMktFields.directMktInvoiceNbr)
2692
+ .withDirectMktShipMonth(directMktFields.directMktShipMonth)
2693
+ .withDirectMktShipDay(directMktFields.directMktShipDay)
2694
+ .execute());
2695
+ expect(response).not.toBeNull();
2696
+ if (UpaHelpertest_1.useLiveMic) {
2697
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(response)) {
2698
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "directMktShipMonth response"));
2699
+ return;
2700
+ }
2701
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["Sale", "SendCommand"]);
2702
+ // Verify month format (01-12)
2703
+ if (response.directMktShipMonth) {
2704
+ expect(/^(0[1-9]|1[0-2])$/.test(response.directMktShipMonth)).toBe(true);
2705
+ expect(response.directMktShipMonth).toBe(directMktFields.directMktShipMonth);
2706
+ console.log("✓ Sale response contains directMktShipMonth: %s (valid format)", response.directMktShipMonth);
2707
+ }
2708
+ else {
2709
+ console.warn("⚠ Sale response missing directMktShipMonth field (device may not support)");
2710
+ }
2711
+ return;
2712
+ }
2713
+ expect(response.status).toBe("Success");
1068
2714
  });
1069
- test("[UpaAdminTests:754] deleteSaf() surfaces TRAN001 (TRANSACTION NOT FOUND) over live MITC", async () => {
1070
- const unknownSafReferenceNumber = `UNKNOWN-123`;
1071
- const response = await device.deleteSaf(unknownSafReferenceNumber);
1072
- expect(response).toBeInstanceOf(UpaSAFResponse_1.UpaSAFResponse);
1073
- expect(response.command).toBe("DeleteSAF");
1074
- expect(response.status).toBe("Failed");
1075
- if (response.deviceResponseCode === "TRAN001") {
1076
- expect(response.deviceResponseMessage).toMatch(/NOT FOUND/i);
2715
+ test("[SpecCompliance:DirectMkt] Sale response contains directMktShipDay (01-31 format)", async () => {
2716
+ const directMktFields = buildDirectMarketingFields("INV20260817_DAY_001");
2717
+ const response = (await device
2718
+ .sale(5.0)
2719
+ .withEcrId(13)
2720
+ .withClerkId(123)
2721
+ .withDirectMktInvoiceNbr(directMktFields.directMktInvoiceNbr)
2722
+ .withDirectMktShipMonth(directMktFields.directMktShipMonth)
2723
+ .withDirectMktShipDay(directMktFields.directMktShipDay)
2724
+ .execute());
2725
+ expect(response).not.toBeNull();
2726
+ if (UpaHelpertest_1.useLiveMic) {
2727
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(response)) {
2728
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "directMktShipDay response"));
2729
+ return;
2730
+ }
2731
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["Sale", "SendCommand"]);
2732
+ // Verify day format (01-31)
2733
+ if (response.directMktShipDay) {
2734
+ expect(/^(0[1-9]|[12][0-9]|3[01])$/.test(response.directMktShipDay)).toBe(true);
2735
+ expect(response.directMktShipDay).toBe(directMktFields.directMktShipDay);
2736
+ console.log("✓ Sale response contains directMktShipDay: %s (valid format)", response.directMktShipDay);
2737
+ }
2738
+ else {
2739
+ console.warn("⚠ Sale response missing directMktShipDay field (device may not support)");
2740
+ }
1077
2741
  return;
1078
2742
  }
1079
- console.log(`deleteSaf() unknown reference returned ${response.deviceResponseCode} (${response.deviceResponseMessage}) instead of TRAN001; device firmware may normalize unknown references.`);
2743
+ expect(response.status).toBe("Success");
1080
2744
  });
1081
- test("[UpaAdminTests:754] deleteSaf() surfaces TRAN010 (TRANSACTION CANNOT BE DELETED) over live MITC", async () => {
1082
- const safReport = await (0, UpaHelpertest_1.ensureSafData)(device, UpaHelpertest_1.createLiveSale, settle);
1083
- if (!safReport) {
2745
+ test("[SpecCompliance:DirectMkt] Refund response contains Direct Marketing fields", async () => {
2746
+ const sale = await (0, UpaHelpertest_1.createLiveSale)(device);
2747
+ if (!sale || !sale.transactionId) {
2748
+ console.warn("Refund Direct Marketing response test: Sale prerequisite failed");
1084
2749
  return;
1085
2750
  }
1086
- const approvedBucket = safReport.reportResult?.approved ?? {};
1087
- let approvedReferenceNumber;
1088
- for (const summary of Object.values(approvedBucket)) {
1089
- const transaction = summary?.transactions?.[0];
1090
- if (transaction?.referenceNumber) {
1091
- approvedReferenceNumber = transaction.referenceNumber;
1092
- break;
2751
+ const directMktFields = buildDirectMarketingFields("INV20260817_REFUND");
2752
+ const response = (await device
2753
+ .refund(5.0)
2754
+ .withEcrId(13)
2755
+ .withClerkId(123)
2756
+ .withTransactionId(sale.transactionId)
2757
+ .withDirectMktInvoiceNbr(directMktFields.directMktInvoiceNbr)
2758
+ .withDirectMktShipMonth(directMktFields.directMktShipMonth)
2759
+ .withDirectMktShipDay(directMktFields.directMktShipDay)
2760
+ .execute());
2761
+ expect(response).not.toBeNull();
2762
+ if (UpaHelpertest_1.useLiveMic) {
2763
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(response)) {
2764
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "Refund Direct Marketing response"));
2765
+ return;
2766
+ }
2767
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["Refund", "SendCommand"]);
2768
+ // Validate all three fields
2769
+ if (response.directMktInvoiceNbr) {
2770
+ expect(response.directMktInvoiceNbr).toBe(directMktFields.directMktInvoiceNbr);
2771
+ }
2772
+ if (response.directMktShipMonth) {
2773
+ expect(response.directMktShipMonth).toBe(directMktFields.directMktShipMonth);
2774
+ }
2775
+ if (response.directMktShipDay) {
2776
+ expect(response.directMktShipDay).toBe(directMktFields.directMktShipDay);
1093
2777
  }
1094
- }
1095
- if (!approvedReferenceNumber) {
1096
- console.warn("deleteSaf() TRAN010 live scenario skipped: no approved (host-authorized) SAF records available. TRAN010 requires a pending or authorized transaction reference per spec §12.4.25.4.");
1097
2778
  return;
1098
2779
  }
1099
- const response = await device.deleteSaf(approvedReferenceNumber);
1100
- expect(response).toBeInstanceOf(UpaSAFResponse_1.UpaSAFResponse);
1101
- expect(response.command).toBe("DeleteSAF");
1102
- expect(response.status).toBe("Failed");
1103
- if (response.deviceResponseCode === "TRAN010") {
1104
- expect(response.deviceResponseMessage.toUpperCase()).toContain("CANNOT BE DELETED");
2780
+ expect(response.status).toBe("Success");
2781
+ });
2782
+ test("[SpecCompliance:DirectMkt] PreAuth response contains Direct Marketing fields", async () => {
2783
+ const directMktFields = buildDirectMarketingFields("INV20260817_PREAUTH");
2784
+ const response = (await device
2785
+ .authorize(10.0)
2786
+ .withEcrId(13)
2787
+ .withClerkId(123)
2788
+ .withDirectMktInvoiceNbr(directMktFields.directMktInvoiceNbr)
2789
+ .withDirectMktShipMonth(directMktFields.directMktShipMonth)
2790
+ .withDirectMktShipDay(directMktFields.directMktShipDay)
2791
+ .execute());
2792
+ expect(response).not.toBeNull();
2793
+ if (UpaHelpertest_1.useLiveMic) {
2794
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(response)) {
2795
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "PreAuth Direct Marketing response"));
2796
+ return;
2797
+ }
2798
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["PreAuth", "SendCommand"]);
2799
+ // All three Direct Marketing fields should be present
2800
+ expect(response.transactionId).toBeTruthy();
2801
+ if (response.directMktInvoiceNbr) {
2802
+ console.log("✓ PreAuth response directMktInvoiceNbr: %s", response.directMktInvoiceNbr);
2803
+ }
1105
2804
  return;
1106
2805
  }
1107
- console.warn(`deleteSaf() authorized-reference delete returned ${response.deviceResponseCode} (${response.deviceResponseMessage}) instead of TRAN010; device firmware may normalize the authorized-transaction outcome.`);
2806
+ expect(response.status).toBe("Success");
1108
2807
  });
1109
2808
  });
1110
- (0, UpaHelpertest_1.describeUpaLive)("UPA Admin – cancel()", () => {
1111
- let device;
1112
- beforeEach(() => {
1113
- device = (0, UpaHelpertest_1.createTestDevice)();
1114
- });
1115
- function buildCancelableStartCardTransactionRequest() {
1116
- const param = new UpaParam_1.UpaParam();
1117
- param.acquisitionTypes = [
1118
- AcquisitionType_1.AcquisitionType.Contact,
1119
- AcquisitionType_1.AcquisitionType.Contactless,
1120
- AcquisitionType_1.AcquisitionType.Swipe,
1121
- AcquisitionType_1.AcquisitionType.Manual,
1122
- ];
1123
- param.header = "Cancel Transaction";
2809
+ // ===========================================================================
2810
+ // UPA Spec Parameters – merchantDecision EMV Flow
2811
+ // Per UPA spec: Used in ProcessCardTransaction, ContinueCardTransaction, ContinueEMVTransaction
2812
+ // ===========================================================================
2813
+ (0, UpaHelpertest_1.describeUpaLive)("UPA Spec Parameters – merchantDecision EMV Flow", () => {
2814
+ let device;
2815
+ beforeEach(() => {
2816
+ device = (0, UpaHelpertest_1.createTestDevice)();
2817
+ });
2818
+ test("[SpecCompliance:merchantDecision] ProcessCardTransaction with merchantDecision='Approve'", async () => {
2819
+ // Note: ProcessCardTransaction requires an active EMV flow which needs live MITC device
2820
+ // This test documents the expected behavior per UPA spec
2821
+ const param = new UpaParam_1.UpaParam();
2822
+ param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Contact];
2823
+ param.timeout = 60;
2824
+ param.header = "EMV Merchant Decision";
1124
2825
  param.displayTotalAmount = "Yes";
1125
- param.promptForManual = false;
1126
- param.timeout = 30;
1127
2826
  const indicator = new ProcessIndicator_1.ProcessingIndicator();
1128
2827
  indicator.QuickChip = "Y";
1129
- indicator.CheckLuhn = "N";
1130
- indicator.SecurityCode = "Y";
1131
- indicator.CardTypeFilter = [
1132
- CardTypeFilter_1.CardTypeFilter.VISA,
1133
- CardTypeFilter_1.CardTypeFilter.MC,
1134
- CardTypeFilter_1.CardTypeFilter.AMEX,
1135
- CardTypeFilter_1.CardTypeFilter.DISCOVER,
1136
- ];
1137
2828
  const transData = new UpaTransactionData_1.UpaTransactionData();
1138
- transData.totalAmount = 1.0;
2829
+ transData.totalAmount = 10.0;
1139
2830
  transData.cashBackAmount = 0.0;
1140
2831
  transData.tranDate = new Date();
1141
2832
  transData.tranTime = new Date();
1142
2833
  transData.transType = src_1.TransactionType.Sale;
1143
- return [param, indicator, transData];
1144
- }
1145
- function timeoutAfter(delayMs, label) {
1146
- return new Promise((_, reject) => {
1147
- setTimeout(() => reject(new Error(`${label} timed out after ${delayMs}ms`)), delayMs);
1148
- });
1149
- }
1150
- function sleep(delayMs) {
1151
- return new Promise((resolve) => setTimeout(resolve, delayMs));
1152
- }
1153
- test("[UpaAdminTests:711] cancel() cancels an active startCardTransaction over live MITC", async () => {
1154
- const [param, indicator, transData] = buildCancelableStartCardTransactionRequest();
1155
- const activeCommand = device
1156
- .startCardTransaction(param, indicator, transData)
1157
- .then((response) => ({ kind: "resolved", response }))
1158
- .catch((error) => ({ kind: "rejected", error }));
1159
- await sleep(2000);
1160
- await expect(device.cancel()).resolves.toBeUndefined();
1161
- const result = await Promise.race([
1162
- activeCommand,
1163
- timeoutAfter(45000, "cancelled startCardTransaction"),
1164
- ]);
1165
- if (result.kind === "resolved") {
1166
- expect(result.response).toBeTruthy();
1167
- if (result.response instanceof TransactionResponse_1.TransactionResponse) {
1168
- expect([
1169
- "StartCardTransaction",
1170
- "CancelTransaction",
1171
- "SendCommand",
1172
- ]).toContain(result.response.command);
2834
+ try {
2835
+ const response = await device.startCardTransaction(param, indicator, transData);
2836
+ expect(response).not.toBeNull();
2837
+ if (UpaHelpertest_1.useLiveMic) {
2838
+ // Per UPA spec: merchantDecision parameter is used in EMV processing
2839
+ console.log("merchantDecision='Approve' would be used during EMV transaction processing");
2840
+ // In live flow, this would be part of ContinueCardTransaction or ProcessCardTransaction
1173
2841
  }
1174
- return;
1175
2842
  }
1176
- expect(result.error).toBeInstanceOf(Error);
1177
- });
1178
- test("[UpaAdminTests:711] cancel() sends CancelTransaction without a displayOption parameter", async () => {
1179
- expect(typeof device.cancel).toBe("function");
1180
- expect(device.cancel.length).toBe(0);
1181
- await expect(device.cancel()).resolves.toBeUndefined();
1182
- });
1183
- test("[UpaAdminTests:711] cancel() handles APP006 (TRANSACTION CANNOT BE CANCELED) without throwing", async () => {
1184
- await expect(device.cancel()).resolves.toBeUndefined();
2843
+ catch (error) {
2844
+ if ((0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
2845
+ console.warn("merchantDecision='Approve' test timed out (expected for device awaiting card)");
2846
+ return;
2847
+ }
2848
+ // Expected in test environment without live device
2849
+ }
1185
2850
  });
1186
2851
  });
1187
- (0, UpaHelpertest_1.describeUpaLive)("UPA Admin – registerPOS()", () => {
2852
+ // ===========================================================================
2853
+ // UPA Spec Parameters – lineItemDisplay (lineItemLeft, lineItemRight)
2854
+ // Per UPA Integrators Guide 02.20.02.B – Display-only parameters for terminal UI
2855
+ // ===========================================================================
2856
+ (0, UpaHelpertest_1.describeUpaLive)("UPA Spec Parameters – lineItemDisplay", () => {
1188
2857
  let device;
1189
2858
  beforeEach(() => {
1190
2859
  device = (0, UpaHelpertest_1.createTestDevice)();
1191
2860
  });
1192
- test("[UpaAdminTests:776] registerPOS() executes over live MITC", async () => {
1193
- const posData = new src_1.POSData();
1194
- posData.appName = `com.global.testapp.${Date.now()}`;
1195
- posData.launchOrder = 1;
1196
- posData.remove = false;
1197
- posData.silent = 0;
1198
- try {
1199
- const response = await device.registerPOS(posData);
1200
- expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
1201
- expect(response.status).toBe("Success");
1202
- (0, UpaHelpertest_1.expectLiveSuccess)(response, "RegisterPOS");
2861
+ test("[SpecCompliance:lineItemDisplay] Sale with lineItemLeft and lineItemRight display parameters", async () => {
2862
+ const response = (await device
2863
+ .sale(10.0)
2864
+ .withEcrId(13)
2865
+ .withClerkId(123)
2866
+ .withLineItemLeft("Widget - Product 1")
2867
+ .withLineItemRight("Qty: 1 @ $10.00")
2868
+ .execute());
2869
+ expect(response).not.toBeNull();
2870
+ expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
2871
+ if (UpaHelpertest_1.useLiveMic) {
2872
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(response)) {
2873
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "lineItem display Sale"));
2874
+ return;
2875
+ }
2876
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["Sale", "SendCommand"]);
2877
+ return;
1203
2878
  }
1204
- catch (err) {
1205
- const message = err instanceof Error ? err.message : String(err);
1206
- if (message.includes("SYSTEM_ERROR")) {
1207
- console.warn("registerPOS() succeeded on the device but GP-API returned SYSTEM_ERROR during response mediation; verify registration state on the terminal.");
2879
+ expect(response.status).toBe("Success");
2880
+ expect(response.deviceResponseCode).toBe("00");
2881
+ });
2882
+ test("[DirectMarketing:lineItemDisplay] Sale with lineItemLeft/Right and Direct Marketing fields", async () => {
2883
+ const directMktFields = buildDirectMarketingFields("INV987654");
2884
+ const response = (await device
2885
+ .sale(25.5)
2886
+ .withEcrId(13)
2887
+ .withClerkId(123)
2888
+ .withLineItemLeft("Coffee Cup - Medium")
2889
+ .withLineItemRight("QTY: 2 @ $12.75")
2890
+ .withDirectMktInvoiceNbr(directMktFields.directMktInvoiceNbr)
2891
+ .withDirectMktShipMonth(directMktFields.directMktShipMonth)
2892
+ .withDirectMktShipDay(directMktFields.directMktShipDay)
2893
+ .execute());
2894
+ expect(response).not.toBeNull();
2895
+ expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
2896
+ if (UpaHelpertest_1.useLiveMic) {
2897
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(response)) {
2898
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "lineItem + directMkt combined Sale"));
1208
2899
  return;
1209
2900
  }
1210
- throw err;
2901
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["Sale", "SendCommand"]);
2902
+ // Verify direct marketing fields are echoed in response
2903
+ expect(response.directMktInvoiceNbr).toBe(directMktFields.directMktInvoiceNbr);
2904
+ expect(response.directMktShipMonth).toBe(directMktFields.directMktShipMonth);
2905
+ expect(response.directMktShipDay).toBe(directMktFields.directMktShipDay);
2906
+ return;
2907
+ }
2908
+ expect(response.status).toBe("Success");
2909
+ // In mock mode, direct marketing fields should be echoed
2910
+ if (response.directMktInvoiceNbr) {
2911
+ expect(response.directMktInvoiceNbr).toBe(directMktFields.directMktInvoiceNbr);
2912
+ }
2913
+ });
2914
+ test("[SpecCompliance:lineItemDisplay] Refund with lineItemLeft display text", async () => {
2915
+ const sale = await (0, UpaHelpertest_1.createLiveSale)(device);
2916
+ if (!sale || !sale.transactionId) {
2917
+ console.warn("lineItem Refund test: Sale prerequisite failed");
2918
+ return;
2919
+ }
2920
+ const response = (await device
2921
+ .refund(15.0)
2922
+ .withEcrId(13)
2923
+ .withClerkId(123)
2924
+ .withTransactionId(sale.transactionId)
2925
+ .withLineItemLeft("Refund - Original Sale")
2926
+ .withLineItemRight("Qty: 1")
2927
+ .execute());
2928
+ expect(response).not.toBeNull();
2929
+ expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
2930
+ if (UpaHelpertest_1.useLiveMic) {
2931
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(response)) {
2932
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "lineItem Refund"));
2933
+ return;
2934
+ }
2935
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["Refund", "SendCommand"]);
2936
+ return;
1211
2937
  }
2938
+ expect(response.status).toBe("Success");
1212
2939
  });
1213
2940
  });
1214
2941
  // ===========================================================================
1215
- // verify()
1216
- // CardVerify command with tokenRequest = "1"
1217
- // Confirms a multi-use token is created and returned by the host
2942
+ // UPA Spec Parameters – preAuthAmount
2943
+ // Per UPA Integrators Guide 02.20.02.B – Pre-authorization amount (tip allowance workflow)
1218
2944
  // ===========================================================================
1219
- (0, UpaHelpertest_1.describeUpaLive)("UPA Admin – verify()", () => {
2945
+ (0, UpaHelpertest_1.describeUpaLive)("UPA Spec Parameters – preAuthAmount", () => {
1220
2946
  let device;
1221
2947
  beforeEach(() => {
1222
2948
  device = (0, UpaHelpertest_1.createTestDevice)();
1223
2949
  });
1224
- test("[UpaMicTests] verify() returns expected response", async () => {
1225
- const response = await device.verify().withEcrId(13).execute();
2950
+ test("[SpecCompliance:preAuthAmount] PreAuth with base authorization and higher preAuthAmount (tip allowance)", async () => {
2951
+ const baseAmount = 25.0;
2952
+ const preAuthAmount = 35.0;
2953
+ const response = (await device
2954
+ .authorize(baseAmount) // Base authorization amount
2955
+ .withEcrId(13)
2956
+ .withClerkId(123)
2957
+ .withPreAuthAmount(preAuthAmount) // Hold amount (includes tip allowance)
2958
+ .execute());
1226
2959
  expect(response).not.toBeNull();
1227
2960
  expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
2961
+ if (UpaHelpertest_1.useLiveMic) {
2962
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(response)) {
2963
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "preAuthAmount PreAuth"));
2964
+ return;
2965
+ }
2966
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["PreAuth", "SendCommand"]);
2967
+ expect(response.transactionId).toBeTruthy();
2968
+ return;
2969
+ }
1228
2970
  expect(response.status).toBe("Success");
1229
2971
  expect(response.deviceResponseCode).toBe("00");
1230
2972
  });
1231
- test("[UpaMicTests] verify() with tokenRequest = 1 returns a token", async () => {
1232
- try {
1233
- const response = await device
1234
- .verify()
1235
- .withRequestMultiUseToken(true)
1236
- .withCardBrandStorage(src_1.StoredCredentialInitiator.CardHolder)
1237
- .withEcrId(13)
1238
- .execute();
1239
- console.log("[VERIFY RESPONSE]", JSON.stringify(response, null, 2));
1240
- expect(response).not.toBeNull();
1241
- expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
1242
- if (UpaHelpertest_1.useLiveMic) {
1243
- if ((0, UpaHelpertest_1.isKnownLiveBusyBlocker)(response)) {
1244
- console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "CardVerify tokenRequest"));
1245
- return;
1246
- }
1247
- (0, UpaHelpertest_1.expectLiveSuccess)(response, ["CardVerify", "SendCommand"]);
1248
- expect(response.token).toBeTruthy();
1249
- expect(response.token.length).toBeGreaterThan(0);
2973
+ test("[SpecCompliance:preAuthAmount] Refund of preAuthorized transaction", async () => {
2974
+ const authResponse = (await device
2975
+ .authorize(25.0)
2976
+ .withEcrId(13)
2977
+ .withClerkId(123)
2978
+ .withPreAuthAmount(35.0)
2979
+ .execute());
2980
+ if (!authResponse || !authResponse.transactionId) {
2981
+ console.warn("preAuthAmount Refund: PreAuth prerequisite failed");
2982
+ return;
2983
+ }
2984
+ // Refund the actual used amount, not the preAuthAmount hold
2985
+ const refundResponse = (await device
2986
+ .refund(25.0)
2987
+ .withEcrId(13)
2988
+ .withClerkId(123)
2989
+ .withTransactionId(authResponse.transactionId)
2990
+ .execute());
2991
+ expect(refundResponse).not.toBeNull();
2992
+ expect(refundResponse).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
2993
+ if (UpaHelpertest_1.useLiveMic) {
2994
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(refundResponse)) {
2995
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(refundResponse, "preAuthAmount Refund"));
1250
2996
  return;
1251
2997
  }
1252
- expect(response.status).toBe("Success");
1253
- expect(response.deviceResponseCode).toBe("00");
1254
- // ...existing expects
2998
+ (0, UpaHelpertest_1.expectLiveSuccess)(refundResponse, ["Refund", "SendCommand"]);
2999
+ return;
1255
3000
  }
1256
- catch (err) {
1257
- console.log("[VERIFY ERROR]", err);
1258
- throw err;
3001
+ expect(refundResponse.status).toBe("Success");
3002
+ });
3003
+ test("[SpecCompliance:preAuthAmount] PreAuth with preAuthAmount less than base authorization (decline allowance)", async () => {
3004
+ // Scenario: Merchant wants to allow refund but NOT tip (e.g., phone order)
3005
+ const baseAmount = 50.0;
3006
+ const preAuthAmount = 50.0; // No tip allowance
3007
+ const response = (await device
3008
+ .authorize(baseAmount)
3009
+ .withEcrId(13)
3010
+ .withClerkId(123)
3011
+ .withPreAuthAmount(preAuthAmount)
3012
+ .execute());
3013
+ expect(response).not.toBeNull();
3014
+ expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
3015
+ if (UpaHelpertest_1.useLiveMic) {
3016
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(response)) {
3017
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(response, "preAuthAmount no-tip PreAuth"));
3018
+ return;
3019
+ }
3020
+ (0, UpaHelpertest_1.expectLiveSuccess)(response, ["PreAuth", "SendCommand"]);
3021
+ expect(response.transactionId).toBeTruthy();
3022
+ return;
3023
+ }
3024
+ expect(response.status).toBe("Success");
3025
+ });
3026
+ test("[SpecCompliance:preAuthAmount] AuthCompletion with preAuthAmount establishes hold", async () => {
3027
+ const authResponse = (await device
3028
+ .authorize(30.0)
3029
+ .withEcrId(13)
3030
+ .withClerkId(123)
3031
+ .withPreAuthAmount(40.0)
3032
+ .execute());
3033
+ if (!authResponse || !authResponse.transactionId) {
3034
+ console.warn("preAuthAmount AuthCompletion: PreAuth prerequisite failed");
3035
+ return;
3036
+ }
3037
+ // Complete auth with the established preAuthAmount hold
3038
+ const completeResponse = (await device
3039
+ .authCompletion()
3040
+ .withEcrId(13)
3041
+ .withTransactionId(authResponse.transactionId)
3042
+ .withAmount(35.0) // Actual tip + base amount used
3043
+ .execute());
3044
+ expect(completeResponse).not.toBeNull();
3045
+ expect(completeResponse).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
3046
+ if (UpaHelpertest_1.useLiveMic) {
3047
+ if ((0, UpaHelpertest_1.isKnownLiveSaleBlocker)(completeResponse)) {
3048
+ console.warn((0, UpaHelpertest_1.formatLiveFailure)(completeResponse, "preAuthAmount AuthCompletion"));
3049
+ return;
3050
+ }
3051
+ (0, UpaHelpertest_1.expectLiveSuccess)(completeResponse, ["AuthCompletion", "SendCommand"]);
3052
+ return;
1259
3053
  }
3054
+ expect(completeResponse.status).toBe("Success");
3055
+ });
3056
+ });
3057
+ // ===========================================================================
3058
+ // JIRA Story Requirements – Value Mapping Validation
3059
+ // ===========================================================================
3060
+ describe("JIRA Story: UPA Transaction Processing – Value Mapping", () => {
3061
+ /**
3062
+ * Verify that cardOnFileIndicator values map correctly:
3063
+ * CardHolder -> 'C', Merchant -> 'M'
3064
+ */
3065
+ test("[Mapping:cardOnFileIndicator] Enum values map to correct UPA strings", () => {
3066
+ // The enum itself stores the mapped values
3067
+ expect(src_1.StoredCredentialInitiator.CardHolder).toBe("C");
3068
+ expect(src_1.StoredCredentialInitiator.Merchant).toBe("M");
3069
+ });
3070
+ /**
3071
+ * Verify acquisitionTypes can be joined for UPA format
3072
+ */
3073
+ test("[Mapping:acquisitionTypes] Array joins correctly for UPA request", () => {
3074
+ const types = [
3075
+ AcquisitionType_1.AcquisitionType.Contact,
3076
+ AcquisitionType_1.AcquisitionType.Contactless,
3077
+ AcquisitionType_1.AcquisitionType.Swipe,
3078
+ ];
3079
+ const joined = types.join("|");
3080
+ expect(joined).toMatch(/Contact\|Contactless\|Swipe/);
1260
3081
  });
1261
3082
  });
1262
3083
  // ===========================================================================
3084
+ // JIRA Story Requirements – Acceptance Conditions
3085
+ // ===========================================================================
3086
+ describe("JIRA Story: UPA Transaction Processing – Acceptance Criteria", () => {
3087
+ /**
3088
+ * Acceptance Criteria:
3089
+ * Region: US
3090
+ * Gateway: GP-API
3091
+ * Environment: Sandbox
3092
+ * Devices: UPA
3093
+ * Payment Types: MC, VISA, Amex
3094
+ * Credentials: Non-specific
3095
+ *
3096
+ * GIVEN: Node SDK is used
3097
+ * WHEN: Tests run with all required fields
3098
+ * THEN: Request goes through to UPA and transaction processes successfully
3099
+ */
3100
+ test("[Acceptance:Criteria] All JIRA requirements are testable", () => {
3101
+ // This test verifies the structure supports the acceptance criteria
3102
+ const device = (0, UpaHelpertest_1.createTestDevice)();
3103
+ // Verify device is properly configured
3104
+ expect(device).toBeDefined();
3105
+ expect(device).toHaveProperty("sale");
3106
+ expect(device).toHaveProperty("authorize");
3107
+ expect(device).toHaveProperty("refund");
3108
+ // Verify all builder methods are available
3109
+ const saleBuilder = device.sale(10.0);
3110
+ const requiredMethods = [
3111
+ "withClerkId",
3112
+ "withCardOnFileIndicator",
3113
+ "withCardBrandTransId",
3114
+ "withLineItemLeft",
3115
+ "withLineItemRight",
3116
+ "withLanguage",
3117
+ "withMerchantDecision",
3118
+ "withAcquisitionTypes",
3119
+ "withPreAuthAmount",
3120
+ "execute",
3121
+ ];
3122
+ for (const method of requiredMethods) {
3123
+ expect(saleBuilder).toHaveProperty(method);
3124
+ expect(typeof saleBuilder[method]).toBe("function");
3125
+ }
3126
+ });
3127
+ /**
3128
+ * Verify no manual code is needed - SDK handles everything
3129
+ */
3130
+ test.only("[Acceptance:NoManualCode] SDK methods handle all required fields", () => {
3131
+ const device = (0, UpaHelpertest_1.createTestDevice)();
3132
+ const builder = device
3133
+ .sale(100.0)
3134
+ .withClerkId(1)
3135
+ .withCardOnFileIndicator(src_1.StoredCredentialInitiator.CardHolder)
3136
+ .withCardBrandTransId("BRAND-001")
3137
+ .withLineItemLeft("Test Item")
3138
+ .withLineItemRight("$100.00")
3139
+ .withLanguage("en")
3140
+ .withMerchantDecision("Approve")
3141
+ .withAcquisitionTypes([AcquisitionType_1.AcquisitionType.Contact])
3142
+ .withPreAuthAmount(125.0);
3143
+ // All fields should be set without manual property access
3144
+ expect(builder.amount).toBe(100.0);
3145
+ expect(builder.clerkId).toBe(1);
3146
+ expect(builder.cardOnFileIndicator).toBe(src_1.StoredCredentialInitiator.CardHolder);
3147
+ });
3148
+ });
1263
3149
  // refund() with all administrative enhancements
1264
3150
  // ===========================================================================
1265
3151
  (0, UpaHelpertest_1.describeUpaLive)("UPA Credit – refund() with enhanced fields", () => {
@@ -1273,8 +3159,7 @@ afterEach(async () => {
1273
3159
  .refund(2)
1274
3160
  .withEcrId(13)
1275
3161
  .withReferenceNumber(saleresponse.terminalRefNumber)
1276
- .withClerkId(1234);
1277
- console.log("\n===== EXECUTING REFUND WITH CLERK ID =====");
3162
+ .withClerkId(123);
1278
3163
  const response = await builder.execute();
1279
3164
  console.log("Response Status:", response.status);
1280
3165
  expect(response).toBeDefined();
@@ -1291,23 +3176,9 @@ afterEach(async () => {
1291
3176
  .execute();
1292
3177
  expect(response).toBeDefined();
1293
3178
  expect(response.status).toBe("Success");
3179
+ expect(response.transactionAmount).toBe(10);
1294
3180
  console.log(`[Refund By TransID] Amount: ${response.transactionAmount}, Status: ${response.status}`);
1295
3181
  });
1296
- test("refund() includes totalAmount correctly", async () => {
1297
- const saleResponse = await device.sale(10).withEcrId(13).execute();
1298
- expect(saleResponse).toBeDefined();
1299
- expect(saleResponse.status).toBe("Success");
1300
- const response = await device
1301
- .refund(10.5)
1302
- .withEcrId(13)
1303
- .withTransactionId(saleResponse.gatewayTxnId)
1304
- .execute();
1305
- expect(response).toBeDefined();
1306
- expect(response.transactionAmount).toBe(10.5);
1307
- expect(response.status).not.toBe("Failed");
1308
- expect(response.deviceResponseCode).not.toBe("32");
1309
- console.log(`[Refund Amount] Amount: ${response.transactionAmount}, Status: ${response.status}`);
1310
- });
1311
3182
  });
1312
3183
  // ===========================================================================
1313
3184
  // verify() with all administrative enhancements
@@ -1328,43 +3199,13 @@ afterEach(async () => {
1328
3199
  .verify()
1329
3200
  .withEcrId(13)
1330
3201
  .withAddress(address)
3202
+ .withClerkId(1234)
1331
3203
  .execute();
1332
3204
  expect(response).toBeDefined();
1333
3205
  expect(response.status).toBe("Success");
1334
- console.log(`[Verify Address] AVS Code: ${response.avsResponseCode}, Status: ${response.status}`);
1335
- });
1336
- test("verify() cvv verification", async () => {
1337
- const response = await device
1338
- .verify()
1339
- .withEcrId(13)
1340
- .withSecurityCode(true)
1341
- .execute();
1342
- expect(response).toBeDefined();
1343
- expect(response.status).toBe("Success");
1344
- expect(response.deviceResponseCode).toBe("00");
1345
3206
  expect(response.maskedCardNumber).toBeDefined();
1346
3207
  expect(response.cardType).toBeDefined();
1347
- console.log(`[Verify CVV] Card: ${response.cardType}, Status: ${response.status}`);
1348
- });
1349
- test("verify() includes clerkId in request", async () => {
1350
- const response = await device
1351
- .verify()
1352
- .withEcrId(13)
1353
- .withClerkId(1234)
1354
- .execute();
1355
- expect(response).toBeDefined();
1356
- expect(response.status).toBe("Success");
1357
- console.log(`[Verify ClerkId] Status: ${response.status}`);
1358
- });
1359
- test("verify() includes languageCode in request", async () => {
1360
- const response = await device
1361
- .verify()
1362
- .withEcrId(13)
1363
- .withLanguage("es-ES")
1364
- .execute();
1365
- expect(response).toBeDefined();
1366
- expect(response.status).toBe("Success");
1367
- console.log(`[Verify Language] Status: ${response.status}`);
3208
+ console.log(`[Verify Address] AVS Code: ${response.avsResponseCode}, Status: ${response.status}`);
1368
3209
  });
1369
3210
  });
1370
3211
  // ===========================================================================
@@ -1408,45 +3249,4 @@ afterEach(async () => {
1408
3249
  }
1409
3250
  });
1410
3251
  });
1411
- // ===========================================================================
1412
- // Integration tests for all admin enhancements together
1413
- // ===========================================================================
1414
- (0, UpaHelpertest_1.describeUpaLive)("UPA Credit – Complete admin enhancements integration", () => {
1415
- let device;
1416
- beforeEach(() => {
1417
- device = (0, UpaHelpertest_1.createTestDevice)();
1418
- });
1419
- test("refund() with all admin fields builds complete request", async () => {
1420
- const saleResponse = await device.sale(60).withEcrId(12).execute();
1421
- const response = await device
1422
- .refund(25)
1423
- .withEcrId(12)
1424
- .withClerkId(1234)
1425
- .withAuthCode("")
1426
- .withCardBrandTransId("TRANSID2025")
1427
- .withReferenceNumber(saleResponse.terminalRefNumber)
1428
- .execute();
1429
- expect(response).toBeDefined();
1430
- expect(response.status).toBe("Success");
1431
- console.log(`[Refund AllFields] Amount: ${response.transactionAmount}, Status: ${response.status}`);
1432
- });
1433
- test("verify() with all admin fields builds complete request", async () => {
1434
- const address = new src_1.Address();
1435
- address.streetAddress1 = "456 Oak Ave";
1436
- address.city = "Los Angeles";
1437
- address.state = "CA";
1438
- address.postalCode = "90001";
1439
- const response = await device
1440
- .verify()
1441
- .withEcrId(13)
1442
- .withAddress(address)
1443
- .withClerkId(1234)
1444
- .withLanguage("en-US")
1445
- .withSecurityCode(true)
1446
- .execute();
1447
- expect(response).toBeDefined();
1448
- expect(response.status).toBe("Success");
1449
- console.log(`[Verify AllFields] Status: ${response.status}, AVS: ${response.avsResponseCode}`);
1450
- });
1451
- });
1452
3252
  //# sourceMappingURL=UpaAdmin.test.js.map