@jimrising/easymerchantsdk-react-native 1.3.5 → 1.3.7
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/README.md +11 -4
- package/android/.gradle/8.10/checksums/checksums.lock +0 -0
- package/android/.gradle/8.10/dependencies-accessors/gc.properties +0 -0
- package/android/.gradle/8.10/fileChanges/last-build.bin +0 -0
- package/android/.gradle/8.10/fileHashes/fileHashes.bin +0 -0
- package/android/.gradle/8.10/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.10/gc.properties +0 -0
- package/android/.gradle/8.9/checksums/checksums.lock +0 -0
- package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
- package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
- package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.9/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
- package/android/.gradle/nb-cache/trust/0B5D6BE682AD6AEE9815EC13516BF075752CAE5AD5BECDCC00315C37622C2FD3 +1 -0
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/ios/Classes/EasyMerchantSdk.m +42 -29
- package/ios/Classes/EasyMerchantSdk.swift +68 -9
- package/ios/CustomComponents/PlanSelector.swift +28 -30
- package/ios/EnvironmentConfig.swift +30 -30
- package/ios/Example/ViewController.swift +47 -51
- package/ios/Models/AdditionalInfo.swift +43 -6
- package/ios/Models/BillingInfo.swift +50 -6
- package/ios/Models/RecurringIntervals.swift +34 -0
- package/ios/Models/RecurringStartDateType.swift +13 -0
- package/ios/Models/Request.swift +120 -11
- package/ios/Pods/ViewControllers/AdditionalInfoVC.swift +609 -79
- package/ios/Pods/ViewControllers/BillingInfoVC/BillingInfoVC.swift +72 -25
- package/ios/Pods/ViewControllers/EmailVerificationVC.swift +14 -0
- package/ios/Pods/ViewControllers/OTPVerificationVC.swift +459 -42
- package/ios/Pods/ViewControllers/PaymentDoneVC.swift +16 -2
- package/ios/Pods/ViewControllers/PaymentErrorVC.swift +0 -2
- package/ios/Pods/ViewControllers/PaymentInformation/PaymentInfoVC.swift +1553 -372
- package/ios/Pods/ViewControllers/PaymentInformation/SavedAccountsTVC/SavedAccountTVC.swift +6 -2
- package/ios/Pods/ViewControllers/PaymentInformation/SavedCardsTVC/SavedCardsTVC.swift +6 -1
- package/ios/Pods/ViewControllers/ThreeDSecurePaymentDoneVC.swift +105 -0
- package/ios/easymerchantsdk.podspec +1 -1
- package/ios/easymerchantsdk.storyboard +554 -57
- package/package.json +2 -2
- package/.idea/caches/deviceStreaming.xml +0 -571
- package/.idea/em-MobileCheckoutSDK-ReactNative.iml +0 -9
- package/.idea/misc.xml +0 -5
- package/.idea/modules.xml +0 -8
- package/.idea/vcs.xml +0 -6
|
@@ -60,6 +60,11 @@ class OTPVerificationVC: BaseVC {
|
|
|
60
60
|
var selectedGrailPayAccountType: String?
|
|
61
61
|
var selectedGrailPayAccountName: String?
|
|
62
62
|
|
|
63
|
+
var request: Request!
|
|
64
|
+
|
|
65
|
+
var chosenPlan: String?
|
|
66
|
+
var startDate: String?
|
|
67
|
+
|
|
63
68
|
override func viewDidLoad() {
|
|
64
69
|
super.viewDidLoad()
|
|
65
70
|
|
|
@@ -228,19 +233,19 @@ class OTPVerificationVC: BaseVC {
|
|
|
228
233
|
return
|
|
229
234
|
}
|
|
230
235
|
|
|
231
|
-
var
|
|
232
|
-
|
|
233
|
-
|
|
236
|
+
var uRLRequest = URLRequest(url: serviceURL)
|
|
237
|
+
uRLRequest.httpMethod = "POST"
|
|
238
|
+
uRLRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
234
239
|
|
|
235
240
|
let token = UserStoreSingleton.shared.clientToken
|
|
236
241
|
print("Setting clientToken header: \(token ?? "None")")
|
|
237
|
-
|
|
242
|
+
uRLRequest.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
238
243
|
|
|
239
244
|
// Add API headers
|
|
240
245
|
if let apiKey = EnvironmentConfig.apiKey,
|
|
241
246
|
let apiSecret = EnvironmentConfig.apiSecret {
|
|
242
|
-
|
|
243
|
-
|
|
247
|
+
uRLRequest.addValue(apiKey, forHTTPHeaderField: "x-api-key")
|
|
248
|
+
uRLRequest.addValue(apiSecret, forHTTPHeaderField: "x-api-secret")
|
|
244
249
|
}
|
|
245
250
|
|
|
246
251
|
let params: [String: Any] = [
|
|
@@ -251,7 +256,7 @@ class OTPVerificationVC: BaseVC {
|
|
|
251
256
|
|
|
252
257
|
do {
|
|
253
258
|
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
254
|
-
|
|
259
|
+
uRLRequest.httpBody = jsonData
|
|
255
260
|
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
256
261
|
print("JSON Payload: \(jsonString)")
|
|
257
262
|
}
|
|
@@ -262,7 +267,7 @@ class OTPVerificationVC: BaseVC {
|
|
|
262
267
|
}
|
|
263
268
|
|
|
264
269
|
let session = URLSession.shared
|
|
265
|
-
let task = session.dataTask(with:
|
|
270
|
+
let task = session.dataTask(with: uRLRequest) { (serviceData, serviceResponse, error) in
|
|
266
271
|
|
|
267
272
|
DispatchQueue.main.async {
|
|
268
273
|
self.hideLoadingIndicator() // Stop loader when response is received
|
|
@@ -289,10 +294,22 @@ class OTPVerificationVC: BaseVC {
|
|
|
289
294
|
let customerId = innerData["customer_id"] as? String {
|
|
290
295
|
print("Extracted customer_id: \(customerId)")
|
|
291
296
|
if self.billingInfoData == nil {
|
|
292
|
-
self.
|
|
297
|
+
if self.request.enable3DS == true {
|
|
298
|
+
self.threeDSecurePaymentApi(customerId: customerId)
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
self.paymentIntentWithSavedCardApi(customerId: customerId)
|
|
302
|
+
}
|
|
293
303
|
}
|
|
294
304
|
else {
|
|
295
|
-
self.paymentIntentApi(customerId: customerId)
|
|
305
|
+
// self.paymentIntentApi(customerId: customerId)
|
|
306
|
+
if let request = self.request {
|
|
307
|
+
if request.enable3DS == true {
|
|
308
|
+
self.threeDSecurePaymentSavedCardApi(customerId: customerId)
|
|
309
|
+
} else {
|
|
310
|
+
self.paymentIntentApi(customerId: customerId)
|
|
311
|
+
}
|
|
312
|
+
}
|
|
296
313
|
}
|
|
297
314
|
} else {
|
|
298
315
|
print("customer_id not found in nested data. Falling back to nil.")
|
|
@@ -444,19 +461,19 @@ class OTPVerificationVC: BaseVC {
|
|
|
444
461
|
return
|
|
445
462
|
}
|
|
446
463
|
|
|
447
|
-
var
|
|
448
|
-
|
|
449
|
-
|
|
464
|
+
var uRLRequest = URLRequest(url: serviceURL)
|
|
465
|
+
uRLRequest.httpMethod = "POST"
|
|
466
|
+
uRLRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
450
467
|
|
|
451
468
|
let token = UserStoreSingleton.shared.clientToken
|
|
452
469
|
print("Setting clientToken header: \(token ?? "None")")
|
|
453
|
-
|
|
470
|
+
uRLRequest.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
454
471
|
|
|
455
472
|
// Add API headers
|
|
456
473
|
if let apiKey = EnvironmentConfig.apiKey,
|
|
457
474
|
let apiSecret = EnvironmentConfig.apiSecret {
|
|
458
|
-
|
|
459
|
-
|
|
475
|
+
uRLRequest.addValue(apiKey, forHTTPHeaderField: "x-api-key")
|
|
476
|
+
uRLRequest.addValue(apiSecret, forHTTPHeaderField: "x-api-secret")
|
|
460
477
|
}
|
|
461
478
|
|
|
462
479
|
guard let billingInfoData = billingInfoData else {
|
|
@@ -507,11 +524,34 @@ class OTPVerificationVC: BaseVC {
|
|
|
507
524
|
params["email"] = email ?? ""
|
|
508
525
|
}
|
|
509
526
|
|
|
527
|
+
// Add these if recurring is enabled
|
|
528
|
+
if let req = request, req.is_recurring == true {
|
|
529
|
+
if let recurringType = req.recurringStartDateType, recurringType == .custom {
|
|
530
|
+
// Only send start_date if type is .custom and field is not empty
|
|
531
|
+
if let startDateText = startDate, !startDateText.isEmpty {
|
|
532
|
+
let inputFormatter = DateFormatter()
|
|
533
|
+
inputFormatter.dateFormat = "dd/MM/yyyy"
|
|
534
|
+
|
|
535
|
+
let outputFormatter = DateFormatter()
|
|
536
|
+
outputFormatter.dateFormat = "MM/dd/yyyy"
|
|
537
|
+
|
|
538
|
+
if let date = inputFormatter.date(from: startDateText) {
|
|
539
|
+
let apiFormattedDate = outputFormatter.string(from: date)
|
|
540
|
+
params["start_date"] = apiFormattedDate
|
|
541
|
+
} else {
|
|
542
|
+
print("Invalid date format in startDateText")
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
params["interval"] = chosenPlan?.lowercased()
|
|
548
|
+
}
|
|
549
|
+
|
|
510
550
|
print(params)
|
|
511
551
|
|
|
512
552
|
do {
|
|
513
553
|
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
514
|
-
|
|
554
|
+
uRLRequest.httpBody = jsonData
|
|
515
555
|
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
516
556
|
print("JSON Payload: \(jsonString)")
|
|
517
557
|
}
|
|
@@ -522,7 +562,7 @@ class OTPVerificationVC: BaseVC {
|
|
|
522
562
|
}
|
|
523
563
|
|
|
524
564
|
let session = URLSession.shared
|
|
525
|
-
let task = session.dataTask(with:
|
|
565
|
+
let task = session.dataTask(with: uRLRequest) { (serviceData, serviceResponse, error) in
|
|
526
566
|
|
|
527
567
|
DispatchQueue.main.async {
|
|
528
568
|
self.hideLoadingIndicator() // Stop loader when response is received
|
|
@@ -592,19 +632,19 @@ class OTPVerificationVC: BaseVC {
|
|
|
592
632
|
return
|
|
593
633
|
}
|
|
594
634
|
|
|
595
|
-
var
|
|
596
|
-
|
|
597
|
-
|
|
635
|
+
var urlRequest = URLRequest(url: serviceURL)
|
|
636
|
+
urlRequest.httpMethod = "POST"
|
|
637
|
+
urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
598
638
|
|
|
599
639
|
let token = UserStoreSingleton.shared.clientToken
|
|
600
640
|
print("Setting clientToken header: \(token ?? "None")")
|
|
601
|
-
|
|
641
|
+
urlRequest.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
602
642
|
|
|
603
643
|
// Add API headers
|
|
604
644
|
if let apiKey = EnvironmentConfig.apiKey,
|
|
605
645
|
let apiSecret = EnvironmentConfig.apiSecret {
|
|
606
|
-
|
|
607
|
-
|
|
646
|
+
urlRequest.addValue(apiKey, forHTTPHeaderField: "x-api-key")
|
|
647
|
+
urlRequest.addValue(apiSecret, forHTTPHeaderField: "x-api-secret")
|
|
608
648
|
}
|
|
609
649
|
|
|
610
650
|
let emailPrefix = email?.components(separatedBy: "@").first ?? ""
|
|
@@ -631,11 +671,34 @@ class OTPVerificationVC: BaseVC {
|
|
|
631
671
|
params["email"] = email ?? ""
|
|
632
672
|
}
|
|
633
673
|
|
|
674
|
+
// Add these if recurring is enabled
|
|
675
|
+
if let req = request, req.is_recurring == true {
|
|
676
|
+
if let recurringType = req.recurringStartDateType, recurringType == .custom {
|
|
677
|
+
// Only send start_date if type is .custom and field is not empty
|
|
678
|
+
if let startDateText = startDate, !startDateText.isEmpty {
|
|
679
|
+
let inputFormatter = DateFormatter()
|
|
680
|
+
inputFormatter.dateFormat = "dd/MM/yyyy"
|
|
681
|
+
|
|
682
|
+
let outputFormatter = DateFormatter()
|
|
683
|
+
outputFormatter.dateFormat = "MM/dd/yyyy"
|
|
684
|
+
|
|
685
|
+
if let date = inputFormatter.date(from: startDateText) {
|
|
686
|
+
let apiFormattedDate = outputFormatter.string(from: date)
|
|
687
|
+
params["start_date"] = apiFormattedDate
|
|
688
|
+
} else {
|
|
689
|
+
print("Invalid date format in startDateText")
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
params["interval"] = chosenPlan?.lowercased()
|
|
695
|
+
}
|
|
696
|
+
|
|
634
697
|
print(params)
|
|
635
698
|
|
|
636
699
|
do {
|
|
637
700
|
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
638
|
-
|
|
701
|
+
urlRequest.httpBody = jsonData
|
|
639
702
|
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
640
703
|
print("JSON Payload: \(jsonString)")
|
|
641
704
|
}
|
|
@@ -646,7 +709,7 @@ class OTPVerificationVC: BaseVC {
|
|
|
646
709
|
}
|
|
647
710
|
|
|
648
711
|
let session = URLSession.shared
|
|
649
|
-
let task = session.dataTask(with:
|
|
712
|
+
let task = session.dataTask(with: urlRequest) { (serviceData, serviceResponse, error) in
|
|
650
713
|
|
|
651
714
|
DispatchQueue.main.async {
|
|
652
715
|
self.hideLoadingIndicator() // Stop loader when response is received
|
|
@@ -726,19 +789,19 @@ class OTPVerificationVC: BaseVC {
|
|
|
726
789
|
return
|
|
727
790
|
}
|
|
728
791
|
|
|
729
|
-
var
|
|
730
|
-
|
|
731
|
-
|
|
792
|
+
var uRLRequest = URLRequest(url: serviceURL)
|
|
793
|
+
uRLRequest.httpMethod = "POST"
|
|
794
|
+
uRLRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
732
795
|
|
|
733
796
|
let token = UserStoreSingleton.shared.clientToken
|
|
734
797
|
print("Setting clientToken header: \(token ?? "None")")
|
|
735
|
-
|
|
798
|
+
uRLRequest.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
736
799
|
|
|
737
800
|
// Add API headers
|
|
738
801
|
if let apiKey = EnvironmentConfig.apiKey,
|
|
739
802
|
let apiSecret = EnvironmentConfig.apiSecret {
|
|
740
|
-
|
|
741
|
-
|
|
803
|
+
uRLRequest.addValue(apiKey, forHTTPHeaderField: "x-api-key")
|
|
804
|
+
uRLRequest.addValue(apiSecret, forHTTPHeaderField: "x-api-secret")
|
|
742
805
|
}
|
|
743
806
|
|
|
744
807
|
guard let billingInfoData = billingInfoData else {
|
|
@@ -788,11 +851,34 @@ class OTPVerificationVC: BaseVC {
|
|
|
788
851
|
params["username"] = emailPrefix
|
|
789
852
|
}
|
|
790
853
|
|
|
854
|
+
// Add these if recurring is enabled
|
|
855
|
+
if let req = request, req.is_recurring == true {
|
|
856
|
+
if let recurringType = req.recurringStartDateType, recurringType == .custom {
|
|
857
|
+
// Only send start_date if type is .custom and field is not empty
|
|
858
|
+
if let startDateText = startDate, !startDateText.isEmpty {
|
|
859
|
+
let inputFormatter = DateFormatter()
|
|
860
|
+
inputFormatter.dateFormat = "dd/MM/yyyy"
|
|
861
|
+
|
|
862
|
+
let outputFormatter = DateFormatter()
|
|
863
|
+
outputFormatter.dateFormat = "MM/dd/yyyy"
|
|
864
|
+
|
|
865
|
+
if let date = inputFormatter.date(from: startDateText) {
|
|
866
|
+
let apiFormattedDate = outputFormatter.string(from: date)
|
|
867
|
+
params["start_date"] = apiFormattedDate
|
|
868
|
+
} else {
|
|
869
|
+
print("Invalid date format in startDateText")
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
params["interval"] = chosenPlan?.lowercased()
|
|
875
|
+
}
|
|
876
|
+
|
|
791
877
|
print(params)
|
|
792
878
|
|
|
793
879
|
do {
|
|
794
880
|
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
795
|
-
|
|
881
|
+
uRLRequest.httpBody = jsonData
|
|
796
882
|
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
797
883
|
print("JSON Payload: \(jsonString)")
|
|
798
884
|
}
|
|
@@ -803,7 +889,7 @@ class OTPVerificationVC: BaseVC {
|
|
|
803
889
|
}
|
|
804
890
|
|
|
805
891
|
let session = URLSession.shared
|
|
806
|
-
let task = session.dataTask(with:
|
|
892
|
+
let task = session.dataTask(with: uRLRequest) { (serviceData, serviceResponse, error) in
|
|
807
893
|
|
|
808
894
|
DispatchQueue.main.async {
|
|
809
895
|
self.hideLoadingIndicator() // Stop loader when response is received
|
|
@@ -873,19 +959,19 @@ class OTPVerificationVC: BaseVC {
|
|
|
873
959
|
return
|
|
874
960
|
}
|
|
875
961
|
|
|
876
|
-
var
|
|
877
|
-
|
|
878
|
-
|
|
962
|
+
var uRLRequest = URLRequest(url: serviceURL)
|
|
963
|
+
uRLRequest.httpMethod = "POST"
|
|
964
|
+
uRLRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
879
965
|
|
|
880
966
|
let token = UserStoreSingleton.shared.clientToken
|
|
881
967
|
print("Setting clientToken header: \(token ?? "None")")
|
|
882
|
-
|
|
968
|
+
uRLRequest.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
883
969
|
|
|
884
970
|
// Add API headers
|
|
885
971
|
if let apiKey = EnvironmentConfig.apiKey,
|
|
886
972
|
let apiSecret = EnvironmentConfig.apiSecret {
|
|
887
|
-
|
|
888
|
-
|
|
973
|
+
uRLRequest.addValue(apiKey, forHTTPHeaderField: "x-api-key")
|
|
974
|
+
uRLRequest.addValue(apiSecret, forHTTPHeaderField: "x-api-secret")
|
|
889
975
|
}
|
|
890
976
|
|
|
891
977
|
let emailPrefix = email?.components(separatedBy: "@").first ?? ""
|
|
@@ -911,11 +997,34 @@ class OTPVerificationVC: BaseVC {
|
|
|
911
997
|
params["username"] = emailPrefix
|
|
912
998
|
}
|
|
913
999
|
|
|
1000
|
+
// Add these if recurring is enabled
|
|
1001
|
+
if let req = request, req.is_recurring == true {
|
|
1002
|
+
if let recurringType = req.recurringStartDateType, recurringType == .custom {
|
|
1003
|
+
// Only send start_date if type is .custom and field is not empty
|
|
1004
|
+
if let startDateText = startDate, !startDateText.isEmpty {
|
|
1005
|
+
let inputFormatter = DateFormatter()
|
|
1006
|
+
inputFormatter.dateFormat = "dd/MM/yyyy"
|
|
1007
|
+
|
|
1008
|
+
let outputFormatter = DateFormatter()
|
|
1009
|
+
outputFormatter.dateFormat = "MM/dd/yyyy"
|
|
1010
|
+
|
|
1011
|
+
if let date = inputFormatter.date(from: startDateText) {
|
|
1012
|
+
let apiFormattedDate = outputFormatter.string(from: date)
|
|
1013
|
+
params["start_date"] = apiFormattedDate
|
|
1014
|
+
} else {
|
|
1015
|
+
print("Invalid date format in startDateText")
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
params["interval"] = chosenPlan?.lowercased()
|
|
1021
|
+
}
|
|
1022
|
+
|
|
914
1023
|
print(params)
|
|
915
1024
|
|
|
916
1025
|
do {
|
|
917
1026
|
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
918
|
-
|
|
1027
|
+
uRLRequest.httpBody = jsonData
|
|
919
1028
|
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
920
1029
|
print("JSON Payload: \(jsonString)")
|
|
921
1030
|
}
|
|
@@ -926,7 +1035,7 @@ class OTPVerificationVC: BaseVC {
|
|
|
926
1035
|
}
|
|
927
1036
|
|
|
928
1037
|
let session = URLSession.shared
|
|
929
|
-
let task = session.dataTask(with:
|
|
1038
|
+
let task = session.dataTask(with: uRLRequest) { (serviceData, serviceResponse, error) in
|
|
930
1039
|
|
|
931
1040
|
DispatchQueue.main.async {
|
|
932
1041
|
self.hideLoadingIndicator() // Stop loader when response is received
|
|
@@ -1094,6 +1203,314 @@ class OTPVerificationVC: BaseVC {
|
|
|
1094
1203
|
task.resume()
|
|
1095
1204
|
}
|
|
1096
1205
|
|
|
1206
|
+
// MARK: - 3DS Functionality
|
|
1207
|
+
|
|
1208
|
+
// MARK: - Credit Card Charge Api If Billing info is nil and Without Login.
|
|
1209
|
+
func threeDSecurePaymentApi(customerId: String?) {
|
|
1210
|
+
showLoadingIndicator()
|
|
1211
|
+
|
|
1212
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.threeDSecure.path()
|
|
1213
|
+
|
|
1214
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
1215
|
+
print("Invalid URL")
|
|
1216
|
+
hideLoadingIndicator()
|
|
1217
|
+
return
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
var uRLRequest = URLRequest(url: serviceURL)
|
|
1221
|
+
uRLRequest.httpMethod = "POST"
|
|
1222
|
+
uRLRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
1223
|
+
|
|
1224
|
+
let token = UserStoreSingleton.shared.clientToken
|
|
1225
|
+
print("Setting clientToken header: \(token ?? "None")")
|
|
1226
|
+
uRLRequest.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
1227
|
+
|
|
1228
|
+
// Add API headers
|
|
1229
|
+
if let apiKey = EnvironmentConfig.apiKey,
|
|
1230
|
+
let apiSecret = EnvironmentConfig.apiSecret {
|
|
1231
|
+
uRLRequest.addValue(apiKey, forHTTPHeaderField: "x-api-key")
|
|
1232
|
+
uRLRequest.addValue(apiSecret, forHTTPHeaderField: "x-api-secret")
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
var params: [String: Any] = [
|
|
1236
|
+
"name": nameOnCard ?? "",
|
|
1237
|
+
"email": UserStoreSingleton.shared.merchantEmail ?? "",
|
|
1238
|
+
"card_number": cardNumber?.replacingOccurrences(of: " ", with: "") ?? "",
|
|
1239
|
+
"cardholder_name": nameOnCard ?? "",
|
|
1240
|
+
"exp_month": expiryDate?.components(separatedBy: "/").first ?? "",
|
|
1241
|
+
"exp_year": expiryDate?.components(separatedBy: "/").last ?? "",
|
|
1242
|
+
"cvc": cvv ?? "",
|
|
1243
|
+
"description": "payment checkout",
|
|
1244
|
+
"currency": "usd",
|
|
1245
|
+
"payment_method": "card",
|
|
1246
|
+
"tokenize": request.tokenOnly ?? false,
|
|
1247
|
+
"save_card": 1,
|
|
1248
|
+
"is_default": "1",
|
|
1249
|
+
"customer_id": customerId ?? ""
|
|
1250
|
+
]
|
|
1251
|
+
|
|
1252
|
+
// Add these if recurring is enabled
|
|
1253
|
+
if let req = request, req.is_recurring == true {
|
|
1254
|
+
if let recurringType = req.recurringStartDateType, recurringType == .custom {
|
|
1255
|
+
// Only send start_date if type is .custom and field is not empty
|
|
1256
|
+
if let startDateText = startDate, !startDateText.isEmpty {
|
|
1257
|
+
let inputFormatter = DateFormatter()
|
|
1258
|
+
inputFormatter.dateFormat = "dd/MM/yyyy"
|
|
1259
|
+
|
|
1260
|
+
let outputFormatter = DateFormatter()
|
|
1261
|
+
outputFormatter.dateFormat = "MM/dd/yyyy"
|
|
1262
|
+
|
|
1263
|
+
if let date = inputFormatter.date(from: startDateText) {
|
|
1264
|
+
let apiFormattedDate = outputFormatter.string(from: date)
|
|
1265
|
+
params["start_date"] = apiFormattedDate
|
|
1266
|
+
} else {
|
|
1267
|
+
print("Invalid date format in startDateText")
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
params["interval"] = chosenPlan?.lowercased()
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
do {
|
|
1276
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
1277
|
+
uRLRequest.httpBody = jsonData
|
|
1278
|
+
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
1279
|
+
print("JSON Payload: \(jsonString)")
|
|
1280
|
+
}
|
|
1281
|
+
} catch let error {
|
|
1282
|
+
print("Error creating JSON data: \(error)")
|
|
1283
|
+
hideLoadingIndicator()
|
|
1284
|
+
return
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
let session = URLSession.shared
|
|
1288
|
+
let task = session.dataTask(with: uRLRequest) { (serviceData, serviceResponse, error) in
|
|
1289
|
+
|
|
1290
|
+
DispatchQueue.main.async {
|
|
1291
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
if let error = error {
|
|
1295
|
+
print("Error: \(error.localizedDescription)")
|
|
1296
|
+
return
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
1300
|
+
print("Invalid response")
|
|
1301
|
+
return
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
1305
|
+
if let data = serviceData {
|
|
1306
|
+
do {
|
|
1307
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
1308
|
+
print("Response Data: \(responseObject)")
|
|
1309
|
+
|
|
1310
|
+
// Check if status is 0 and handle the error
|
|
1311
|
+
if let status = responseObject["status"] as? Int, status == 0 {
|
|
1312
|
+
let errorMessage = responseObject["message"] as? String ?? "Unknown error"
|
|
1313
|
+
self.presentPaymentErrorVC(errorMessage: errorMessage)
|
|
1314
|
+
} else {
|
|
1315
|
+
DispatchQueue.main.async {
|
|
1316
|
+
if let paymentDoneVC = self.storyboard?.instantiateViewController(withIdentifier: "ThreeDSecurePaymentDoneVC") as? ThreeDSecurePaymentDoneVC {
|
|
1317
|
+
|
|
1318
|
+
let urlString = responseObject["redirect_url"] as? String ?? responseObject["location_url"] as? String ?? ""
|
|
1319
|
+
paymentDoneVC.redirectURL = urlString
|
|
1320
|
+
paymentDoneVC.chargeData = responseObject
|
|
1321
|
+
paymentDoneVC.easyPayDelegate = self.easyPayDelegate
|
|
1322
|
+
|
|
1323
|
+
self.navigationController?.pushViewController(paymentDoneVC, animated: true)
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
} else {
|
|
1328
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid JSON format")
|
|
1329
|
+
}
|
|
1330
|
+
} catch let jsonError {
|
|
1331
|
+
self.presentPaymentErrorVC(errorMessage: "Error parsing JSON: \(jsonError)")
|
|
1332
|
+
}
|
|
1333
|
+
} else {
|
|
1334
|
+
self.presentPaymentErrorVC(errorMessage: "No data received")
|
|
1335
|
+
}
|
|
1336
|
+
} else {
|
|
1337
|
+
if let data = serviceData,
|
|
1338
|
+
let responseObj = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
|
|
1339
|
+
let message = responseObj["message"] as? String {
|
|
1340
|
+
self.presentPaymentErrorVC(errorMessage: message)
|
|
1341
|
+
} else {
|
|
1342
|
+
self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
task.resume()
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
// MARK: - Credit Card Charge Api If Billing info is not nil and Without Login.
|
|
1350
|
+
func threeDSecurePaymentSavedCardApi(customerId: String?) {
|
|
1351
|
+
showLoadingIndicator()
|
|
1352
|
+
|
|
1353
|
+
let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.threeDSecure.path()
|
|
1354
|
+
|
|
1355
|
+
guard let serviceURL = URL(string: fullURL) else {
|
|
1356
|
+
print("Invalid URL")
|
|
1357
|
+
hideLoadingIndicator()
|
|
1358
|
+
return
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
var uRLRequest = URLRequest(url: serviceURL)
|
|
1362
|
+
uRLRequest.httpMethod = "POST"
|
|
1363
|
+
uRLRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
1364
|
+
|
|
1365
|
+
let token = UserStoreSingleton.shared.clientToken
|
|
1366
|
+
print("Setting clientToken header: \(token ?? "None")")
|
|
1367
|
+
uRLRequest.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
|
|
1368
|
+
|
|
1369
|
+
// Add API headers
|
|
1370
|
+
if let apiKey = EnvironmentConfig.apiKey,
|
|
1371
|
+
let apiSecret = EnvironmentConfig.apiSecret {
|
|
1372
|
+
uRLRequest.addValue(apiKey, forHTTPHeaderField: "x-api-key")
|
|
1373
|
+
uRLRequest.addValue(apiSecret, forHTTPHeaderField: "x-api-secret")
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
guard let billingInfoData = billingInfoData else {
|
|
1377
|
+
print("Billing info data is nil")
|
|
1378
|
+
return
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
let additionalInfoFromBilling = billingInfoData["additional_info"] as? [String: Any] ?? [:]
|
|
1382
|
+
|
|
1383
|
+
let additionalInfo: [String: Any] = [
|
|
1384
|
+
"name": additionalInfoFromBilling["name"] as? String ?? "",
|
|
1385
|
+
"email": additionalInfoFromBilling["email"] as? String ?? "",
|
|
1386
|
+
"phone_number": additionalInfoFromBilling["phone_number"] as? String ?? "",
|
|
1387
|
+
"description": additionalInfoFromBilling["description"] as? String ?? ""
|
|
1388
|
+
]
|
|
1389
|
+
|
|
1390
|
+
let billingInfo: [String: Any] = [
|
|
1391
|
+
"address": billingInfoData["address"] as? String ?? "",
|
|
1392
|
+
"country": billingInfoData["country"] as? String ?? "",
|
|
1393
|
+
"state": billingInfoData["state"] as? String ?? "",
|
|
1394
|
+
"city": billingInfoData["city"] as? String ?? "",
|
|
1395
|
+
"postal_code": billingInfoData["postal_code"] as? String ?? ""
|
|
1396
|
+
]
|
|
1397
|
+
|
|
1398
|
+
var params: [String: Any] = [
|
|
1399
|
+
"name": nameOnCard ?? "",
|
|
1400
|
+
"email": email ?? "",
|
|
1401
|
+
"card_number": cardNumber?.replacingOccurrences(of: " ", with: "") ?? "",
|
|
1402
|
+
"cardholder_name": nameOnCard ?? "",
|
|
1403
|
+
"exp_month": expiryDate?.components(separatedBy: "/").first ?? "",
|
|
1404
|
+
"exp_year": expiryDate?.components(separatedBy: "/").last ?? "",
|
|
1405
|
+
"cvc": cvv ?? "",
|
|
1406
|
+
"description": "Test",
|
|
1407
|
+
"currency": "usd",
|
|
1408
|
+
"tokenize": request.tokenOnly ?? false,
|
|
1409
|
+
"address": billingInfoData["address"] as? String ?? "",
|
|
1410
|
+
"billing_info": billingInfo,
|
|
1411
|
+
"additional_info": additionalInfo,
|
|
1412
|
+
"save_card": "1",
|
|
1413
|
+
"is_default": "1",
|
|
1414
|
+
"customer_id": customerId ?? ""
|
|
1415
|
+
]
|
|
1416
|
+
|
|
1417
|
+
// Add these if recurring is enabled
|
|
1418
|
+
if let req = request, req.is_recurring == true {
|
|
1419
|
+
if let recurringType = req.recurringStartDateType, recurringType == .custom {
|
|
1420
|
+
// Only send start_date if type is .custom and field is not empty
|
|
1421
|
+
if let startDateText = startDate, !startDateText.isEmpty {
|
|
1422
|
+
let inputFormatter = DateFormatter()
|
|
1423
|
+
inputFormatter.dateFormat = "dd/MM/yyyy"
|
|
1424
|
+
|
|
1425
|
+
let outputFormatter = DateFormatter()
|
|
1426
|
+
outputFormatter.dateFormat = "MM/dd/yyyy"
|
|
1427
|
+
|
|
1428
|
+
if let date = inputFormatter.date(from: startDateText) {
|
|
1429
|
+
let apiFormattedDate = outputFormatter.string(from: date)
|
|
1430
|
+
params["start_date"] = apiFormattedDate
|
|
1431
|
+
} else {
|
|
1432
|
+
print("Invalid date format in startDateText")
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
params["interval"] = chosenPlan?.lowercased()
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
do {
|
|
1441
|
+
let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
1442
|
+
uRLRequest.httpBody = jsonData
|
|
1443
|
+
if let jsonString = String(data: jsonData, encoding: .utf8) {
|
|
1444
|
+
print("JSON Payload: \(jsonString)")
|
|
1445
|
+
}
|
|
1446
|
+
} catch let error {
|
|
1447
|
+
print("Error creating JSON data: \(error)")
|
|
1448
|
+
hideLoadingIndicator()
|
|
1449
|
+
return
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
let session = URLSession.shared
|
|
1453
|
+
let task = session.dataTask(with: uRLRequest) { (serviceData, serviceResponse, error) in
|
|
1454
|
+
|
|
1455
|
+
DispatchQueue.main.async {
|
|
1456
|
+
self.hideLoadingIndicator() // Stop loader when response is received
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
if let error = error {
|
|
1460
|
+
print("Error: \(error.localizedDescription)")
|
|
1461
|
+
return
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
guard let httpResponse = serviceResponse as? HTTPURLResponse else {
|
|
1465
|
+
print("Invalid response")
|
|
1466
|
+
return
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
1470
|
+
if let data = serviceData {
|
|
1471
|
+
do {
|
|
1472
|
+
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
1473
|
+
print("Response Data: \(responseObject)")
|
|
1474
|
+
|
|
1475
|
+
// Check if status is 0 and handle the error
|
|
1476
|
+
if let status = responseObject["status"] as? Int, status == 0 {
|
|
1477
|
+
let errorMessage = responseObject["message"] as? String ?? "Unknown error"
|
|
1478
|
+
self.presentPaymentErrorVC(errorMessage: errorMessage)
|
|
1479
|
+
} else {
|
|
1480
|
+
DispatchQueue.main.async {
|
|
1481
|
+
if let paymentDoneVC = self.storyboard?.instantiateViewController(withIdentifier: "ThreeDSecurePaymentDoneVC") as? ThreeDSecurePaymentDoneVC {
|
|
1482
|
+
|
|
1483
|
+
let urlString = responseObject["redirect_url"] as? String ?? responseObject["location_url"] as? String ?? ""
|
|
1484
|
+
paymentDoneVC.redirectURL = urlString
|
|
1485
|
+
paymentDoneVC.chargeData = responseObject
|
|
1486
|
+
paymentDoneVC.easyPayDelegate = self.easyPayDelegate
|
|
1487
|
+
|
|
1488
|
+
self.navigationController?.pushViewController(paymentDoneVC, animated: true)
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
} else {
|
|
1493
|
+
self.presentPaymentErrorVC(errorMessage: "Invalid JSON format")
|
|
1494
|
+
}
|
|
1495
|
+
} catch let jsonError {
|
|
1496
|
+
self.presentPaymentErrorVC(errorMessage: "Error parsing JSON: \(jsonError)")
|
|
1497
|
+
}
|
|
1498
|
+
} else {
|
|
1499
|
+
self.presentPaymentErrorVC(errorMessage: "No data received")
|
|
1500
|
+
}
|
|
1501
|
+
} else {
|
|
1502
|
+
if let data = serviceData,
|
|
1503
|
+
let responseObj = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
|
|
1504
|
+
let message = responseObj["message"] as? String {
|
|
1505
|
+
self.presentPaymentErrorVC(errorMessage: message)
|
|
1506
|
+
} else {
|
|
1507
|
+
self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
task.resume()
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1097
1514
|
@IBAction func actionBtnCancel(_ sender: UIButton) {
|
|
1098
1515
|
stopTimer()
|
|
1099
1516
|
for viewController in self.navigationController?.viewControllers ?? [] {
|