globalpayments-api 3.12.0 → 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.
- package/CHANGELOG.md +8 -1
- package/README.md +0 -18
- package/lib/src/Terminals/Builders/TerminalAuthBuilder.d.ts +2 -0
- package/lib/src/Terminals/Builders/TerminalAuthBuilder.js +5 -1
- package/lib/src/Terminals/Builders/TerminalAuthBuilder.js.map +1 -1
- package/lib/src/Terminals/Builders/TerminalBuilder.d.ts +0 -1
- package/lib/src/Terminals/Builders/TerminalBuilder.js +0 -1
- package/lib/src/Terminals/Builders/TerminalBuilder.js.map +1 -1
- package/lib/src/Terminals/Builders/TerminalManageBuilder.d.ts +5 -0
- package/lib/src/Terminals/Builders/TerminalManageBuilder.js +14 -0
- package/lib/src/Terminals/Builders/TerminalManageBuilder.js.map +1 -1
- package/lib/src/Terminals/TerminalResponse.d.ts +4 -0
- package/lib/src/Terminals/TerminalResponse.js +4 -0
- package/lib/src/Terminals/TerminalResponse.js.map +1 -1
- package/lib/src/Terminals/UPA/Reponses/TransactionResponse.d.ts +4 -1
- package/lib/src/Terminals/UPA/Reponses/TransactionResponse.js +15 -1
- package/lib/src/Terminals/UPA/Reponses/TransactionResponse.js.map +1 -1
- package/lib/src/Terminals/UPA/UpaController.js +11 -4
- package/lib/src/Terminals/UPA/UpaController.js.map +1 -1
- package/lib/test/Integration/Gateways/GpApiConnector/GpApiMMAAccount.test.js +29 -1
- package/lib/test/Integration/Gateways/GpApiConnector/GpApiMMAAccount.test.js.map +1 -1
- package/lib/test/Unit/Terminals/UPA/UpaAdmin.test.js +2233 -388
- package/lib/test/Unit/Terminals/UPA/UpaAdmin.test.js.map +1 -1
- package/lib/test/Unit/Terminals/UPA/UpaCredit.test.js +504 -1
- package/lib/test/Unit/Terminals/UPA/UpaCredit.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -731,574 +731,2419 @@ afterEach(async () => {
|
|
|
731
731
|
message: "cardTypeFilter must contain only supported card types for startCardTransaction",
|
|
732
732
|
});
|
|
733
733
|
});
|
|
734
|
-
test("[
|
|
734
|
+
test("[UpaAdminTests] startCardTransaction() Contact only returns Success", async () => {
|
|
735
735
|
const param = new UpaParam_1.UpaParam();
|
|
736
|
-
param.timeout =
|
|
737
|
-
param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.
|
|
738
|
-
param.header = "
|
|
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 = "
|
|
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 =
|
|
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
|
-
|
|
753
|
-
|
|
754
|
-
|
|
749
|
+
let response;
|
|
750
|
+
try {
|
|
751
|
+
response = await device.startCardTransaction(param, indicator, transData);
|
|
755
752
|
}
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
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
|
-
|
|
761
|
-
|
|
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.
|
|
764
|
-
expect(response.cvv).toBeTruthy();
|
|
770
|
+
expect(response.status).toBe("Success");
|
|
765
771
|
});
|
|
766
|
-
test("[
|
|
772
|
+
test("[UpaAdminTests] startCardTransaction() Contactless only returns Success", async () => {
|
|
767
773
|
const param = new UpaParam_1.UpaParam();
|
|
768
|
-
param.timeout =
|
|
769
|
-
param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.
|
|
770
|
-
param.header = "
|
|
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 = "
|
|
774
|
-
indicator.CheckLuhn = "
|
|
779
|
+
indicator.QuickChip = "N";
|
|
780
|
+
indicator.CheckLuhn = "N";
|
|
775
781
|
const transData = new UpaTransactionData_1.UpaTransactionData();
|
|
776
|
-
transData.totalAmount =
|
|
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
|
-
|
|
782
|
-
|
|
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.
|
|
808
|
+
expect(response.status).toBe("Success");
|
|
786
809
|
});
|
|
787
|
-
test("[
|
|
810
|
+
test("[UpaAdminTests] startCardTransaction() Swipe or Contact returns Success", async () => {
|
|
788
811
|
const param = new UpaParam_1.UpaParam();
|
|
789
|
-
param.timeout =
|
|
790
|
-
param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.
|
|
791
|
-
param.header = "
|
|
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 = "
|
|
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 =
|
|
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
|
-
|
|
806
|
-
|
|
807
|
-
|
|
826
|
+
let response;
|
|
827
|
+
try {
|
|
828
|
+
response = await device.startCardTransaction(param, indicator, transData);
|
|
808
829
|
}
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
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
|
-
|
|
814
|
-
|
|
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
|
-
|
|
817
|
-
|
|
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
|
-
|
|
820
|
-
|
|
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("[
|
|
895
|
+
test("[UpaAdminTests] startCardTransaction() Refund returns Success", async () => {
|
|
824
896
|
const param = new UpaParam_1.UpaParam();
|
|
825
|
-
param.timeout =
|
|
826
|
-
param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.
|
|
827
|
-
param.header = "
|
|
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 = "
|
|
902
|
+
indicator.QuickChip = "N";
|
|
832
903
|
indicator.CheckLuhn = "Y";
|
|
833
|
-
indicator.SecurityCode = "
|
|
834
|
-
indicator.CardTypeFilter = [CardTypeFilter_1.CardTypeFilter.AMEX];
|
|
904
|
+
indicator.SecurityCode = "N";
|
|
835
905
|
const transData = new UpaTransactionData_1.UpaTransactionData();
|
|
836
|
-
transData.totalAmount =
|
|
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
|
-
|
|
842
|
-
|
|
843
|
-
|
|
911
|
+
let response;
|
|
912
|
+
try {
|
|
913
|
+
response = await device.startCardTransaction(param, indicator, transData);
|
|
844
914
|
}
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
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
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
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.
|
|
858
|
-
expect(response.cvv).toBeTruthy();
|
|
932
|
+
expect(response.status).toBe("Success");
|
|
859
933
|
});
|
|
860
|
-
test("[
|
|
934
|
+
test("[UpaAdminTests] startCardTransaction() with VISA and MasterCard filter returns Success", async () => {
|
|
861
935
|
const param = new UpaParam_1.UpaParam();
|
|
862
|
-
param.
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
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 = "
|
|
870
|
-
indicator.CheckLuhn = "
|
|
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 =
|
|
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
|
-
|
|
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.
|
|
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("[
|
|
902
|
-
const
|
|
903
|
-
|
|
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
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
if ((0, UpaHelpertest_1.
|
|
909
|
-
console.warn(
|
|
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
|
-
|
|
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("
|
|
2065
|
+
if (UpaHelpertest_1.useLiveMic && (0, UpaHelpertest_1.isKnownLiveTransportTimeout)(error)) {
|
|
2066
|
+
console.warn("StartCardTransaction luhnCheckPassed response timed out.");
|
|
923
2067
|
return;
|
|
924
2068
|
}
|
|
925
|
-
|
|
926
|
-
|
|
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("[
|
|
930
|
-
const
|
|
931
|
-
|
|
932
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
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
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
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;
|
|
969
2353
|
}
|
|
2354
|
+
// Expected: ArgumentError or validation error
|
|
2355
|
+
expect(error).toBeInstanceOf(Error);
|
|
970
2356
|
}
|
|
971
|
-
|
|
972
|
-
|
|
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;
|
|
973
2407
|
beforeEach(() => {
|
|
974
2408
|
device = (0, UpaHelpertest_1.createTestDevice)();
|
|
975
2409
|
});
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
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;
|
|
2451
|
+
}
|
|
2452
|
+
(0, UpaHelpertest_1.expectLiveSuccess)(response, ["Sale", "SendCommand"]);
|
|
2453
|
+
expect(response.terminalRefNumber).toBeTruthy();
|
|
979
2454
|
return;
|
|
980
2455
|
}
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
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;
|
|
2466
|
+
beforeEach(() => {
|
|
2467
|
+
device = (0, UpaHelpertest_1.createTestDevice)();
|
|
2468
|
+
});
|
|
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
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
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
|
-
|
|
2506
|
+
(0, UpaHelpertest_1.expectLiveSuccess)(response, ["Sale", "SendCommand"]);
|
|
2507
|
+
expect(response.terminalRefNumber).toBeTruthy();
|
|
2508
|
+
return;
|
|
996
2509
|
}
|
|
997
|
-
(
|
|
2510
|
+
expect(response.status).toBe("Success");
|
|
2511
|
+
expect(response.deviceResponseCode).toBe("00");
|
|
998
2512
|
});
|
|
999
|
-
test(
|
|
1000
|
-
const
|
|
1001
|
-
if (!
|
|
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
|
|
1005
|
-
|
|
1006
|
-
|
|
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
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
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
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
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
|
-
|
|
1038
|
-
const response = await device
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
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("[
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
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
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
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
|
-
|
|
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("[
|
|
1066
|
-
const
|
|
1067
|
-
|
|
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("[
|
|
1070
|
-
const
|
|
1071
|
-
const response = await device
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
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
|
-
|
|
2743
|
+
expect(response.status).toBe("Success");
|
|
1080
2744
|
});
|
|
1081
|
-
test("[
|
|
1082
|
-
const
|
|
1083
|
-
if (!
|
|
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
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
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);
|
|
2777
|
+
}
|
|
2778
|
+
return;
|
|
2779
|
+
}
|
|
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);
|
|
1093
2803
|
}
|
|
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
|
-
return;
|
|
1098
|
-
}
|
|
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");
|
|
1105
2804
|
return;
|
|
1106
2805
|
}
|
|
1107
|
-
|
|
2806
|
+
expect(response.status).toBe("Success");
|
|
1108
2807
|
});
|
|
1109
2808
|
});
|
|
1110
|
-
|
|
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", () => {
|
|
1111
2814
|
let device;
|
|
1112
2815
|
beforeEach(() => {
|
|
1113
2816
|
device = (0, UpaHelpertest_1.createTestDevice)();
|
|
1114
2817
|
});
|
|
1115
|
-
|
|
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
|
|
1116
2821
|
const param = new UpaParam_1.UpaParam();
|
|
1117
|
-
param.acquisitionTypes = [
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
AcquisitionType_1.AcquisitionType.Swipe,
|
|
1121
|
-
AcquisitionType_1.AcquisitionType.Manual,
|
|
1122
|
-
];
|
|
1123
|
-
param.header = "Cancel Transaction";
|
|
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 =
|
|
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
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
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
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
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
|
-
|
|
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("[
|
|
1193
|
-
const
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
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
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
1216
|
-
//
|
|
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
|
|
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("[
|
|
1225
|
-
const
|
|
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("[
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
console.
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
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
|
-
|
|
1253
|
-
|
|
1254
|
-
// ...existing expects
|
|
1255
|
-
}
|
|
1256
|
-
catch (err) {
|
|
1257
|
-
console.log("[VERIFY ERROR]", err);
|
|
1258
|
-
throw err;
|
|
2998
|
+
(0, UpaHelpertest_1.expectLiveSuccess)(refundResponse, ["Refund", "SendCommand"]);
|
|
2999
|
+
return;
|
|
1259
3000
|
}
|
|
3001
|
+
expect(refundResponse.status).toBe("Success");
|
|
1260
3002
|
});
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
const
|
|
1264
|
-
const
|
|
1265
|
-
|
|
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)
|
|
1266
3009
|
.withEcrId(13)
|
|
1267
|
-
.
|
|
1268
|
-
|
|
1269
|
-
.
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
.
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
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
|
+
}
|
|
1280
3024
|
expect(response.status).toBe("Success");
|
|
1281
3025
|
});
|
|
1282
|
-
test("[
|
|
1283
|
-
const
|
|
1284
|
-
.authorize(
|
|
3026
|
+
test("[SpecCompliance:preAuthAmount] AuthCompletion with preAuthAmount establishes hold", async () => {
|
|
3027
|
+
const authResponse = (await device
|
|
3028
|
+
.authorize(30.0)
|
|
1285
3029
|
.withEcrId(13)
|
|
1286
|
-
.
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
.
|
|
1291
|
-
|
|
1292
|
-
|
|
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()
|
|
1293
3040
|
.withEcrId(13)
|
|
1294
|
-
.
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
expect(
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
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;
|
|
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/);
|
|
3081
|
+
});
|
|
3082
|
+
});
|
|
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);
|
|
1302
3147
|
});
|
|
1303
3148
|
});
|
|
1304
3149
|
// refund() with all administrative enhancements
|