@jimrising/easymerchantsdk-react-native 1.3.9 → 1.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/.idea/caches/deviceStreaming.xml +77 -0
  2. package/README.md +140 -81
  3. package/android/.gradle/8.10/checksums/checksums.lock +0 -0
  4. package/android/.gradle/8.10/checksums/md5-checksums.bin +0 -0
  5. package/android/.gradle/8.10/checksums/sha1-checksums.bin +0 -0
  6. package/android/.gradle/8.10/fileHashes/fileHashes.lock +0 -0
  7. package/android/.gradle/8.9/checksums/checksums.lock +0 -0
  8. package/android/.gradle/8.9/checksums/md5-checksums.bin +0 -0
  9. package/android/.gradle/8.9/checksums/sha1-checksums.bin +0 -0
  10. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  11. package/android/.gradle/buildOutputCleanup/cache.properties +1 -1
  12. package/android/build/.transforms/20e1216b87bd06eaab3c9e5c68d4267a/results.bin +1 -0
  13. package/android/build/.transforms/20e1216b87bd06eaab3c9e5c68d4267a/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/BuildConfig.dex +0 -0
  14. package/android/build/.transforms/20e1216b87bd06eaab3c9e5c68d4267a/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule$1.dex +0 -0
  15. package/android/build/.transforms/20e1216b87bd06eaab3c9e5c68d4267a/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule$2.dex +0 -0
  16. package/android/build/.transforms/20e1216b87bd06eaab3c9e5c68d4267a/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule.dex +0 -0
  17. package/android/build/.transforms/20e1216b87bd06eaab3c9e5c68d4267a/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkPackage.dex +0 -0
  18. package/android/build/.transforms/20e1216b87bd06eaab3c9e5c68d4267a/transformed/bundleLibRuntimeToDirDebug/desugar_graph.bin +0 -0
  19. package/android/build/.transforms/e9a664a11ce12edf79cd87b1e07aa243/results.bin +1 -0
  20. package/android/build/.transforms/e9a664a11ce12edf79cd87b1e07aa243/transformed/classes/classes_dex/classes.dex +0 -0
  21. package/android/build/generated/source/buildConfig/debug/com/reactlibrary/BuildConfig.java +10 -0
  22. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +7 -0
  23. package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json +18 -0
  24. package/android/build/intermediates/aar_metadata/debug/writeDebugAarMetadata/aar-metadata.properties +6 -0
  25. package/android/build/intermediates/annotation_processor_list/debug/javaPreCompileDebug/annotationProcessors.json +1 -0
  26. package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  27. package/android/build/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar +0 -0
  28. package/android/build/intermediates/compile_symbol_list/debug/generateDebugRFile/R.txt +0 -0
  29. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -0
  30. package/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +2 -0
  31. package/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +2 -0
  32. package/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +2 -0
  33. package/android/build/intermediates/incremental/packageDebugAssets/merger.xml +2 -0
  34. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/BuildConfig.class +0 -0
  35. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$1.class +0 -0
  36. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$2.class +0 -0
  37. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
  38. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkPackage.class +0 -0
  39. package/android/build/intermediates/local_only_symbol_list/debug/parseDebugLocalResources/R-def.txt +2 -0
  40. package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +7 -0
  41. package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +7 -0
  42. package/android/build/intermediates/navigation_json/debug/extractDeepLinksDebug/navigation.json +1 -0
  43. package/android/build/intermediates/nested_resources_validation_report/debug/generateDebugResources/nestedResourcesValidationReport.txt +1 -0
  44. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/BuildConfig.class +0 -0
  45. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule$1.class +0 -0
  46. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule$2.class +0 -0
  47. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
  48. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkPackage.class +0 -0
  49. package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  50. package/android/build/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt +1 -0
  51. package/android/build/outputs/logs/manifest-merger-debug-report.txt +17 -0
  52. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule$1.class.uniqueId2 +0 -0
  53. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule$2.class.uniqueId0 +0 -0
  54. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule.class.uniqueId3 +0 -0
  55. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkPackage.class.uniqueId1 +0 -0
  56. package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  57. package/android/build.gradle +4 -1
  58. package/android/src/main/java/com/reactlibrary/RNEasymerchantsdkModule.java +158 -36
  59. package/android/src/main/java/com/reactlibrary/RNEasymerchantsdkPackage.java +45 -13
  60. package/ios/Classes/EasyMerchantSdk.m +106 -55
  61. package/ios/Classes/EasyMerchantSdk.swift +199 -77
  62. package/ios/Classes/EasyPayViewController.swift +1 -1
  63. package/ios/CustomComponents/DatePickerHandler.swift +15 -4
  64. package/ios/EnvironmentConfig.swift +32 -30
  65. package/ios/Models/Request.swift +176 -14
  66. package/ios/Models/Result.swift +12 -5
  67. package/ios/Pods/ViewControllers/AdditionalInfoVC.swift +855 -366
  68. package/ios/Pods/ViewControllers/BaseVC.swift +51 -36
  69. package/ios/Pods/ViewControllers/BillingInfoVC/BillingInfoVC.swift +1985 -178
  70. package/ios/Pods/ViewControllers/CountryListVC.swift +20 -1
  71. package/ios/Pods/ViewControllers/CustomOverlay.swift +199 -0
  72. package/ios/Pods/ViewControllers/EmailVerificationVC.swift +74 -5
  73. package/ios/Pods/ViewControllers/GrailPayVC.swift +131 -107
  74. package/ios/Pods/ViewControllers/OTPVerificationVC.swift +296 -106
  75. package/ios/Pods/ViewControllers/PaymentDoneVC.swift +35 -26
  76. package/ios/Pods/ViewControllers/PaymentInformation/PaymentInfoVC.swift +1276 -545
  77. package/ios/Pods/ViewControllers/ThreeDSecurePaymentDoneVC.swift +607 -24
  78. package/ios/easymerchantsdk.podspec +1 -1
  79. package/ios/easymerchantsdk.storyboard +1388 -1165
  80. package/package.json +1 -1
@@ -76,6 +76,8 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
76
76
  @IBOutlet weak var viewTxtFieldStartDateCard: UIView!
77
77
  @IBOutlet weak var imgViewChosePlanCardDropIcon: UIImageView!
78
78
  @IBOutlet weak var imgViewCalenderIconCard: UIImageView!
79
+ @IBOutlet weak var txtFieldEmailCardView: TextFieldStackView!
80
+ @IBOutlet weak var viewTxtFieldEmailCardView: UIView!
79
81
 
80
82
  @IBOutlet weak var btnScanCard: UIButton!
81
83
 
@@ -176,7 +178,10 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
176
178
  @IBOutlet weak var viewTextFieldConfirmAccount: UIView!
177
179
  @IBOutlet weak var txtFieldSelectPlanViewBankFields: TextFieldStackView!
178
180
  @IBOutlet weak var txtFieldSelectDateViewBankFields: TextFieldStackView!
181
+ @IBOutlet weak var txtFieldEmailAccountView: TextFieldStackView!
182
+ @IBOutlet weak var viewTxtFieldEmailAccountView: UIView!
179
183
 
184
+ @IBOutlet weak var viewSaveCardForFutureCardView: UIStackView!
180
185
  @IBOutlet weak var heightViewBankFields: NSLayoutConstraint!
181
186
 
182
187
  //GrailPay
@@ -199,6 +204,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
199
204
  @IBOutlet weak var txtFieldChosePlanGrailPayBankView: TextFieldStackView!
200
205
  @IBOutlet weak var txtFieldSelectDateGrailPayBankView: TextFieldStackView!
201
206
  @IBOutlet weak var bankIconGrailPayBankView: UIImageView!
207
+ @IBOutlet weak var viewSaveAccountForFutureGrailPayView: UIStackView!
202
208
 
203
209
  //New GrailPay Account
204
210
  @IBOutlet weak var viewAddNewGrailPayAccount: UIView!
@@ -223,6 +229,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
223
229
  @IBOutlet weak var txtFieldChosePlanNewGrailPayBankView: TextFieldStackView!
224
230
  @IBOutlet weak var txtFieldSelectDateNewGrailPayBankView: TextFieldStackView!
225
231
  @IBOutlet weak var imgViewBankIconGrailPayNewBank: UIImageView!
232
+ @IBOutlet weak var viewSaveAccountForFututeNewGrailPayAccountView: UIStackView!
226
233
 
227
234
  //SavedBank
228
235
  @IBOutlet weak var viewSingleSavedAccount: UIView!
@@ -265,6 +272,8 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
265
272
 
266
273
  @IBOutlet weak var heightViewNewAccountFields: NSLayoutConstraint!
267
274
  @IBOutlet weak var heightSubViewNewAccountFields: NSLayoutConstraint!
275
+ @IBOutlet weak var viewSaveAccountForFutureNewAccountView: UIStackView!
276
+
268
277
 
269
278
  //Crypto
270
279
  @IBOutlet weak var viewCrypto: UIView!
@@ -339,7 +348,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
339
348
  var selectedBank: BankAccountModel?
340
349
  var isSelectForPayBank: Bool = false
341
350
  var selectedBankIndex: Int? = nil
342
- var arrAccountType = ["Saving", "Checking"]
351
+ var arrAccountType = ["saving", "checking", "ledger"]
343
352
 
344
353
  var agreeTermsAndCondtition: Bool = false
345
354
 
@@ -353,7 +362,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
353
362
  var isFrom = String()
354
363
 
355
364
  //Blink Card
356
- // var blinkCardRecognizer: MBCBlinkCardRecognizer!
365
+ // var blinkCardRecognizer: MBCBlinkCardRecognizer!
357
366
 
358
367
  // Variables for Card Scanning Data Back
359
368
  var cardNumber: String?
@@ -388,6 +397,8 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
388
397
 
389
398
  var startDatePickerHandler: DatePickerHandler?
390
399
 
400
+ var isSavedNewCard: Bool = false
401
+
391
402
  //MARK: - View Did Load
392
403
  override func viewDidLoad() {
393
404
  super.viewDidLoad()
@@ -412,10 +423,13 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
412
423
 
413
424
  //// Check if billingInfoData is available
414
425
  if let billingInfoData = request.billingInfoData,
415
- let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
416
- let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
417
- // If `submitButtonText` is not empty, use it; otherwise, default to "Next (Billing Info)"
418
- let buttonText = (request?.submitButtonText?.isEmpty == false ? request!.submitButtonText! + " (Billing Info)" : "Next (Billing Info)")
426
+ let fieldSection = try? JSONDecoder().decode(FieldSection.self, from: billingInfoData) {
427
+
428
+ let billingVisible = fieldSection.visibility.billing
429
+ let suffix = billingVisible ? " (Billing Info)" : " (Additional Info)"
430
+ let buttonText = (request?.submitButtonText?.isEmpty == false
431
+ ? request!.submitButtonText! + suffix
432
+ : "Next" + suffix)
419
433
 
420
434
  btnNext.setTitle(buttonText, for: .normal)
421
435
  btnPayNowNewCardView.setTitle(buttonText, for: .normal)
@@ -541,10 +555,20 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
541
555
  self.txtFieldSelectDateGrailPayBankView.isHidden = false
542
556
  self.txtFieldSelectDateNewGrailPayBankView.isHidden = false
543
557
 
544
- self.heightViewBankFields.constant = 710
558
+ if request.saveAccount == false {
559
+ self.heightViewBankFields.constant = 790
560
+ self.heightViewNewAccountFields.constant = 788
561
+ } else {
562
+ self.heightViewBankFields.constant = 836
563
+ self.heightViewNewAccountFields.constant = 844
564
+ }
565
+
566
+ if request.saveCard == false {
567
+ self.heightViewNewCardFields.constant = 595
568
+ } else {
569
+ self.heightViewNewCardFields.constant = 648
570
+ }
545
571
 
546
- self.heightViewNewCardFields.constant = 624
547
- self.heightViewNewAccountFields.constant = 808
548
572
  self.heightSubViewNewAccountFields.constant = 738
549
573
  } else {
550
574
  self.txtFieldStartDateCard.isHidden = true
@@ -556,9 +580,20 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
556
580
  self.txtFieldSelectDateGrailPayBankView.isHidden = true
557
581
  self.txtFieldSelectDateNewGrailPayBankView.isHidden = true
558
582
 
559
- self.heightViewBankFields.constant = 600
560
- self.heightViewNewCardFields.constant = 529
561
- self.heightViewNewAccountFields.constant = 713
583
+ if request.saveAccount == false {
584
+ self.heightViewBankFields.constant = 700
585
+ self.heightViewNewAccountFields.constant = 690
586
+ } else {
587
+ self.heightViewBankFields.constant = 740
588
+ self.heightViewNewAccountFields.constant = 738
589
+ }
590
+
591
+ if request.saveCard == false {
592
+ self.heightViewNewCardFields.constant = 500
593
+ } else {
594
+ self.heightViewNewCardFields.constant = 553
595
+ }
596
+
562
597
  self.heightSubViewNewAccountFields.constant = 643
563
598
  }
564
599
 
@@ -588,9 +623,20 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
588
623
  self.txtFieldSelectDateGrailPayBankView.isHidden = true
589
624
  self.txtFieldSelectDateNewGrailPayBankView.isHidden = true
590
625
 
591
- self.heightViewBankFields.constant = 506
592
- self.heightViewNewCardFields.constant = 434
593
- self.heightViewNewAccountFields.constant = 628
626
+ if request.saveAccount == false {
627
+ self.heightViewBankFields.constant = 604
628
+ self.heightViewNewAccountFields.constant = 600
629
+ } else {
630
+ self.heightViewBankFields.constant = 644
631
+ self.heightViewNewAccountFields.constant = 660
632
+ }
633
+
634
+ if request.saveCard == false {
635
+ self.heightViewNewCardFields.constant = 404
636
+ } else {
637
+ self.heightViewNewCardFields.constant = 458
638
+ }
639
+
594
640
  self.heightSubViewNewAccountFields.constant = 558
595
641
  }
596
642
 
@@ -667,10 +713,24 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
667
713
  else {
668
714
  self.viewSingleSavedAccount.isHidden = true
669
715
  self.viewBankFields.isHidden = true
670
- self.viewBtnShowSavedCards.isHidden = false
671
- self.lblBtnShowSaveCard.text = "Show Saved Cards"
672
- self.viewBtnShowSavedCardHeight.constant = 50
673
- self.viewBtnShowSavedCardTopCon.constant = 20
716
+
717
+ // self.viewBtnShowSavedCards.isHidden = false
718
+ // self.lblBtnShowSaveCard.text = "Show Saved Cards"
719
+ // self.viewBtnShowSavedCardHeight.constant = 50
720
+ // self.viewBtnShowSavedCardTopCon.constant = 20
721
+
722
+ if request.saveCard == false {
723
+ self.viewBtnShowSavedCards.isHidden = true
724
+ self.viewBtnShowSavedCardHeight.constant = 0
725
+ self.viewBtnShowSavedCardTopCon.constant = 0
726
+ }
727
+ else {
728
+ self.viewBtnShowSavedCards.isHidden = false
729
+ self.lblBtnShowSaveCard.text = "Show Saved Cards"
730
+ self.viewBtnShowSavedCardHeight.constant = 50
731
+ self.viewBtnShowSavedCardTopCon.constant = 20
732
+ }
733
+
674
734
  self.OTPView.isHidden = true
675
735
  self.emailView.isHidden = true
676
736
  self.viewCardFields.isHidden = false
@@ -779,10 +839,23 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
779
839
  }
780
840
  else {
781
841
  // self.viewBankFields.isHidden = false
782
- self.viewBtnShowSavedCards.isHidden = false
783
- self.lblBtnShowSaveCard.text = "Show Saved Accounts"
784
- self.viewBtnShowSavedCardHeight.constant = 50
785
- self.viewBtnShowSavedCardTopCon.constant = 20
842
+ // self.viewBtnShowSavedCards.isHidden = false
843
+ // self.lblBtnShowSaveCard.text = "Show Saved Accounts"
844
+ // self.viewBtnShowSavedCardHeight.constant = 50
845
+ // self.viewBtnShowSavedCardTopCon.constant = 20
846
+
847
+ if request.saveAccount == false {
848
+ self.viewBtnShowSavedCards.isHidden = true
849
+ self.viewBtnShowSavedCardHeight.constant = 0
850
+ self.viewBtnShowSavedCardTopCon.constant = 0
851
+ }
852
+ else {
853
+ self.viewBtnShowSavedCards.isHidden = false
854
+ self.lblBtnShowSaveCard.text = "Show Saved Accounts"
855
+ self.viewBtnShowSavedCardHeight.constant = 50
856
+ self.viewBtnShowSavedCardTopCon.constant = 20
857
+ }
858
+
786
859
  self.OTPView.isHidden = true
787
860
  self.emailView.isHidden = true
788
861
  self.viewCardFields.isHidden = true
@@ -1162,6 +1235,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
1162
1235
  cardExpiryTextField.textField.delegate = self
1163
1236
  cardCvvTextField.textField.delegate = self
1164
1237
  cardNameTextField.textField.delegate = self
1238
+ txtFieldEmailCardView.textField.delegate = self
1165
1239
 
1166
1240
  txtFieldEmail.delegate = self
1167
1241
 
@@ -1185,20 +1259,42 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
1185
1259
  txtFieldAccountTypeNewAccountView.delegate = self
1186
1260
  txtFieldAccountNumber.delegate = self
1187
1261
  txtFieldConfirmBankAccount.delegate = self
1262
+ txtFieldEmailAccountView.textField.delegate = self
1188
1263
  }
1189
1264
 
1190
1265
  private func updateSaveButtons() {
1191
1266
  let isSavedCard = request?.saveCard ?? false
1192
1267
  let isSavedAccount = request?.saveAccount ?? false
1193
1268
 
1194
- let cardImageName = isSavedCard ? "checkmark.square.fill" : "square"
1195
- let accountImageName = isSavedAccount ? "checkmark.square.fill" : "square"
1269
+ let defaultImageName = "square" // always show unselected initially
1196
1270
 
1197
- btnCheckBoxSavedCard.setImage(UIImage(systemName: cardImageName), for: .normal)
1198
- btnSavedCardForFutureNewCardView.setImage(UIImage(systemName: cardImageName), for: .normal)
1271
+ // Card Buttons: Show/hide based on saveCard
1272
+ btnCheckBoxSavedCard.isHidden = !isSavedCard
1273
+ btnSavedCardForFutureNewCardView.isHidden = !isSavedCard
1199
1274
 
1200
- btnCheckSavedAccountForFuture.setImage(UIImage(systemName: accountImageName), for: .normal)
1201
- btnSavedNewAccountForFuture.setImage(UIImage(systemName: accountImageName), for: .normal)
1275
+ if isSavedCard {
1276
+ btnCheckBoxSavedCard.setImage(UIImage(systemName: defaultImageName), for: .normal)
1277
+ btnSavedCardForFutureNewCardView.setImage(UIImage(systemName: defaultImageName), for: .normal)
1278
+ }
1279
+
1280
+ // Account Buttons: Show/hide based on saveAccount
1281
+ let accountButtons: [UIButton] = [
1282
+ btnCheckBoxGrailPaySaveAccount,
1283
+ btnCheckBoxGrailPayNewAccountSaveAccount
1284
+ ]
1285
+
1286
+ for button in accountButtons {
1287
+ button.isHidden = !isSavedAccount
1288
+ if isSavedAccount {
1289
+ button.setImage(UIImage(systemName: defaultImageName), for: .normal)
1290
+ }
1291
+ }
1292
+
1293
+ // Other related UI changes for account
1294
+ viewSaveCardForFutureCardView?.isHidden = !isSavedAccount
1295
+ viewSaveAccountForFutureNewAccountView?.isHidden = !isSavedAccount
1296
+ viewSaveAccountForFutureGrailPayView?.isHidden = !isSavedAccount
1297
+ viewSaveAccountForFututeNewGrailPayAccountView?.isHidden = !isSavedAccount
1202
1298
  }
1203
1299
 
1204
1300
  //MARK: - Term & Conditions setup for normal bank fields view
@@ -1760,53 +1856,88 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
1760
1856
  let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
1761
1857
  print("Billing Info Data: \(jsonDict)")
1762
1858
 
1763
- let cvvText = txtFieldCVVSingleSavedCard.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
1764
-
1765
- if cvvText.isEmpty {
1766
- self.showAlert(title: "Missing CVV", message: "Please enter the CVV to proceed.")
1767
- return
1768
- } else if cvvText.count < 3 {
1769
- self.showAlert(title: "Invalid CVV", message: "CVV must be at least 3 digits.")
1770
- return
1771
- }
1772
-
1773
- // Recurring Plan + Date Validation (only if is_recurring is true)
1774
- if let req = self.request, req.is_recurring == true {
1775
- if txtFieldSelectPlanSingleSavedCard.text.isEmpty {
1776
- self.showAlert(title: "Missing Information", message: "Please choose your plan.")
1777
- return
1778
- }
1859
+ do {
1860
+ let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
1779
1861
 
1780
- if let recurringType = req.recurringStartDateType, recurringType == .custom {
1781
- if txtFieldSelectDateSingleSavedCard.text.isEmpty {
1782
- self.showAlert(title: "Missing Information", message: "Please select a plan start date.")
1862
+ DispatchQueue.main.async {
1863
+ let cvvText = self.txtFieldCVVSingleSavedCard.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
1864
+
1865
+ if cvvText.isEmpty {
1866
+ self.showAlert(title: "Missing CVV", message: "Please enter the CVV to proceed.")
1867
+ return
1868
+ } else if cvvText.count < 3 {
1869
+ self.showAlert(title: "Invalid CVV", message: "CVV must be at least 3 digits.")
1783
1870
  return
1784
1871
  }
1872
+
1873
+ // Recurring Plan + Date Validation (only if is_recurring is true)
1874
+ if let req = self.request, req.is_recurring == true {
1875
+ if self.txtFieldSelectPlanSingleSavedCard.text.isEmpty {
1876
+ self.showAlert(title: "Missing Information", message: "Please choose your plan.")
1877
+ return
1878
+ }
1879
+
1880
+ if let recurringType = req.recurringStartDateType, recurringType == .custom {
1881
+ if self.txtFieldSelectDateSingleSavedCard.text.isEmpty {
1882
+ self.showAlert(title: "Missing Information", message: "Please select a plan start date.")
1883
+ return
1884
+ }
1885
+ }
1886
+ }
1887
+
1888
+ // Redirect based on billing visibility
1889
+ if fieldSection.visibility.billing {
1890
+ // Instantiate BillingInfoVC and pass the selected card data and CVV text
1891
+ let billingInfoVC = UIStoryboard(name: "easymerchantsdk", bundle: .easyPayBundle).instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
1892
+
1893
+ billingInfoVC.isFrom = "SavedCards"
1894
+ billingInfoVC.selectedCard = self.selectedCard // Passing the selected card data
1895
+ billingInfoVC.cvvText = cvvText // Passing the CVV text
1896
+ billingInfoVC.amount = Int(self.request.amount ?? 0)
1897
+ billingInfoVC.selectedPaymentMethod = self.selectedPaymentMethod
1898
+
1899
+ if let billingInfoData = self.request.billingInfoData {
1900
+ billingInfoVC.billingInfoData = billingInfoData
1901
+ }
1902
+
1903
+ billingInfoVC.request = self.request
1904
+ billingInfoVC.chosenPlan = self.txtFieldSelectPlanSingleSavedCard.text
1905
+ billingInfoVC.startDate = self.txtFieldSelectDateSingleSavedCard.text
1906
+
1907
+ billingInfoVC.billingInfo = fieldSection.billing
1908
+ billingInfoVC.additionalInfo = fieldSection.additional
1909
+ billingInfoVC.visibility = fieldSection.visibility
1910
+
1911
+ // Navigate to BillingInfoVC
1912
+ self.navigationController?.pushViewController(billingInfoVC, animated: true)
1913
+ }
1914
+ else {
1915
+ let additionalInfoVC = UIStoryboard(name: "easymerchantsdk", bundle: .easyPayBundle).instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
1916
+ additionalInfoVC.isFrom = "SavedCards"
1917
+ additionalInfoVC.selectedCard = self.selectedCard // Passing the selected card data
1918
+ additionalInfoVC.cvvText = cvvText // Passing the CVV text
1919
+ additionalInfoVC.amount = Int(self.request.amount ?? 0)
1920
+ additionalInfoVC.selectedPaymentMethod = self.selectedPaymentMethod
1921
+
1922
+ if let billingInfoData = self.request.billingInfoData {
1923
+ additionalInfoVC.billingInfoData = billingInfoData
1924
+ }
1925
+
1926
+ additionalInfoVC.request = self.request
1927
+ additionalInfoVC.chosenPlan = self.txtFieldSelectPlanSingleSavedCard.text
1928
+ additionalInfoVC.startDate = self.txtFieldSelectDateSingleSavedCard.text
1929
+
1930
+ additionalInfoVC.billingInfo = fieldSection.billing
1931
+ additionalInfoVC.additionalInfo = fieldSection.additional
1932
+ additionalInfoVC.visibility = fieldSection.visibility
1933
+
1934
+ self.navigationController?.pushViewController(additionalInfoVC, animated: true)
1935
+ }
1785
1936
  }
1786
1937
  }
1787
-
1788
- // Instantiate BillingInfoVC and pass the selected card data and CVV text
1789
- let billingInfoVC = UIStoryboard(name: "easymerchantsdk", bundle: .easyPayBundle).instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
1790
-
1791
- billingInfoVC.isFrom = "SavedCards"
1792
- billingInfoVC.selectedCard = selectedCard // Passing the selected card data
1793
- billingInfoVC.cvvText = cvvText // Passing the CVV text
1794
- billingInfoVC.amount = Int(request.amount)
1795
- billingInfoVC.selectedPaymentMethod = selectedPaymentMethod
1796
-
1797
- // Pass the billing info data and auth token
1798
- if let billingInfoData = request.billingInfoData,
1799
- let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
1800
- let jsonDict = json as? [String: Any] {
1801
- billingInfoVC.billingInfoData = jsonDict
1938
+ catch {
1939
+ print("Failed to decode billingInfoData: \(error.localizedDescription)")
1802
1940
  }
1803
-
1804
- billingInfoVC.request = self.request
1805
- billingInfoVC.chosenPlan = txtFieldSelectPlanSingleSavedCard.text
1806
- billingInfoVC.startDate = txtFieldSelectDateSingleSavedCard.text
1807
-
1808
- // Navigate to BillingInfoVC
1809
- self.navigationController?.pushViewController(billingInfoVC, animated: true)
1810
1941
  }
1811
1942
  else {
1812
1943
  // If billingInfoData is nil or empty, set the button title to "Pay Now"
@@ -1887,99 +2018,140 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
1887
2018
  let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
1888
2019
  print("Billing Info Data: \(jsonDict)")
1889
2020
 
1890
- // Retrieve and trim text field values (removing leading and trailing whitespace)
1891
- let cardNumber = txtFieldCardNumberNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
1892
- let expiryDate = txtFieldExpiryDateNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
1893
- let cvv = txtFieldCVVNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
1894
- let nameOnCard = txtFieldNameOnCardNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
1895
-
1896
- // Check if any field is empty
1897
- if cardNumber.isEmpty || expiryDate.isEmpty || cvv.isEmpty || nameOnCard.isEmpty {
1898
- let alert = UIAlertController(title: "Missing Information", message: "Please fill in all card details.", preferredStyle: .alert)
1899
- alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
1900
- self.present(alert, animated: true, completion: nil)
1901
- return
1902
- }
1903
-
1904
- // Validate expiry date format
1905
- let expiryDateFormat = "MM/yyyy"
1906
- let dateFormatter = DateFormatter()
1907
- dateFormatter.dateFormat = expiryDateFormat
1908
- dateFormatter.locale = Locale(identifier: "en_US_POSIX")
1909
-
1910
- // Split the expiry date and validate its format
1911
- let exp = expiryDate.split(separator: "/")
1912
- if exp.count != 2 || exp[0].count != 2 || exp[1].count != 4 {
1913
- let alert = UIAlertController(title: "Invalid Expiry Date", message: "Please enter the expiry date in the format MM/yyyy.", preferredStyle: .alert)
1914
- alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
1915
- self.present(alert, animated: true, completion: nil)
1916
- return
1917
- }
1918
-
1919
- // Check if the expiry date is valid
1920
- if let expiryDateObj = dateFormatter.date(from: expiryDate) {
1921
- // Check if the expiry date is in the past
1922
- let currentDate = Date()
1923
- let calendar = Calendar.current
1924
- let currentMonthYear = calendar.date(from: calendar.dateComponents([.year, .month], from: currentDate))
1925
- if expiryDateObj < currentMonthYear! {
1926
- let alert = UIAlertController(title: "Expired Card", message: "The expiry date cannot be in the past. Please enter a valid expiry date.", preferredStyle: .alert)
1927
- alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
1928
- self.present(alert, animated: true, completion: nil)
1929
- return
1930
- }
1931
- } else {
1932
- let alert = UIAlertController(title: "Invalid Expiry Date", message: "Please enter the expiry date in the format MM/yyyy.", preferredStyle: .alert)
1933
- alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
1934
- self.present(alert, animated: true, completion: nil)
1935
- return
1936
- }
1937
-
1938
- // Recurring Plan + Date Validation (only if is_recurring is true)
1939
- if let req = self.request, req.is_recurring == true {
1940
- if txtFieldSelectPlanNewCardView.text.isEmpty {
1941
- self.showAlert(title: "Missing Information", message: "Please choose your plan.")
1942
- return
1943
- }
2021
+ do {
2022
+ let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
1944
2023
 
1945
- if let recurringType = req.recurringStartDateType, recurringType == .custom {
1946
- if txtFieldSelectDateNewCardView.text.isEmpty {
1947
- self.showAlert(title: "Missing Information", message: "Please select a plan start date.")
2024
+ DispatchQueue.main.async {
2025
+ // Retrieve and trim text field values (removing leading and trailing whitespace)
2026
+ let cardNumber = self.txtFieldCardNumberNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
2027
+ let expiryDate = self.txtFieldExpiryDateNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
2028
+ let cvv = self.txtFieldCVVNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
2029
+ let nameOnCard = self.txtFieldNameOnCardNewCardView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
2030
+
2031
+ // Check if any field is empty
2032
+ if cardNumber.isEmpty || expiryDate.isEmpty || cvv.isEmpty || nameOnCard.isEmpty {
2033
+ let alert = UIAlertController(title: "Missing Information", message: "Please fill in all card details.", preferredStyle: .alert)
2034
+ alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
2035
+ self.present(alert, animated: true, completion: nil)
1948
2036
  return
1949
2037
  }
2038
+
2039
+ // Validate expiry date format
2040
+ let expiryDateFormat = "MM/yyyy"
2041
+ let dateFormatter = DateFormatter()
2042
+ dateFormatter.dateFormat = expiryDateFormat
2043
+ dateFormatter.locale = Locale(identifier: "en_US_POSIX")
2044
+
2045
+ // Split the expiry date and validate its format
2046
+ let exp = expiryDate.split(separator: "/")
2047
+ if exp.count != 2 || exp[0].count != 2 || exp[1].count != 4 {
2048
+ let alert = UIAlertController(title: "Invalid Expiry Date", message: "Please enter the expiry date in the format MM/yyyy.", preferredStyle: .alert)
2049
+ alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
2050
+ self.present(alert, animated: true, completion: nil)
2051
+ return
2052
+ }
2053
+
2054
+ // Check if the expiry date is valid
2055
+ if let expiryDateObj = dateFormatter.date(from: expiryDate) {
2056
+ // Check if the expiry date is in the past
2057
+ let currentDate = Date()
2058
+ let calendar = Calendar.current
2059
+ let currentMonthYear = calendar.date(from: calendar.dateComponents([.year, .month], from: currentDate))
2060
+ if expiryDateObj < currentMonthYear! {
2061
+ let alert = UIAlertController(title: "Expired Card", message: "The expiry date cannot be in the past. Please enter a valid expiry date.", preferredStyle: .alert)
2062
+ alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
2063
+ self.present(alert, animated: true, completion: nil)
2064
+ return
2065
+ }
2066
+ } else {
2067
+ let alert = UIAlertController(title: "Invalid Expiry Date", message: "Please enter the expiry date in the format MM/yyyy.", preferredStyle: .alert)
2068
+ alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
2069
+ self.present(alert, animated: true, completion: nil)
2070
+ return
2071
+ }
2072
+
2073
+ // Recurring Plan + Date Validation (only if is_recurring is true)
2074
+ if let req = self.request, req.is_recurring == true {
2075
+ if self.txtFieldSelectPlanNewCardView.text.isEmpty {
2076
+ self.showAlert(title: "Missing Information", message: "Please choose your plan.")
2077
+ return
2078
+ }
2079
+
2080
+ if let recurringType = req.recurringStartDateType, recurringType == .custom {
2081
+ if self.txtFieldSelectDateNewCardView.text.isEmpty {
2082
+ self.showAlert(title: "Missing Information", message: "Please select a plan start date.")
2083
+ return
2084
+ }
2085
+ }
2086
+ }
2087
+
2088
+ // Redirect based on billing visibility
2089
+ if fieldSection.visibility.billing {
2090
+ // Instantiate BillingInfoVC and pass the card details
2091
+ let billingInfoVC = UIStoryboard(name: "easymerchantsdk", bundle: .easyPayBundle).instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
2092
+
2093
+ // Pass the card details
2094
+ billingInfoVC.cardNumber = cardNumber
2095
+ billingInfoVC.expiryDate = expiryDate
2096
+ billingInfoVC.cvv = cvv
2097
+ billingInfoVC.nameOnCard = nameOnCard
2098
+ billingInfoVC.isSavedNewCard = self.isSavedNewCardForFuture
2099
+
2100
+ billingInfoVC.isFrom = "AddNewCard"
2101
+ billingInfoVC.amount = Int(self.request.amount ?? 0)
2102
+ billingInfoVC.selectedPaymentMethod = self.selectedPaymentMethod
2103
+
2104
+ if let billingInfoData = self.request.billingInfoData {
2105
+ billingInfoVC.billingInfoData = billingInfoData
2106
+ }
2107
+
2108
+ billingInfoVC.request = self.request
2109
+ billingInfoVC.chosenPlan = self.txtFieldSelectPlanNewCardView.text
2110
+ billingInfoVC.startDate = self.txtFieldSelectDateNewCardView.text
2111
+
2112
+ billingInfoVC.billingInfo = fieldSection.billing
2113
+ billingInfoVC.additionalInfo = fieldSection.additional
2114
+ billingInfoVC.visibility = fieldSection.visibility
2115
+
2116
+ // Navigate to BillingInfoVC
2117
+ self.navigationController?.pushViewController(billingInfoVC, animated: true)
2118
+ }
2119
+ else {
2120
+ let additionalInfoVC = UIStoryboard(name: "easymerchantsdk", bundle: .easyPayBundle).instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
2121
+
2122
+ // Pass the card details
2123
+ additionalInfoVC.cardNumber = cardNumber
2124
+ additionalInfoVC.expiryDate = expiryDate
2125
+ additionalInfoVC.cvv = cvv
2126
+ additionalInfoVC.nameOnCard = nameOnCard
2127
+ additionalInfoVC.isSavedNewCard = self.isSavedNewCardForFuture
2128
+
2129
+ additionalInfoVC.isFrom = "AddNewCard"
2130
+ additionalInfoVC.amount = Int(self.request.amount ?? 0)
2131
+ additionalInfoVC.selectedPaymentMethod = self.selectedPaymentMethod
2132
+
2133
+ if let billingInfoData = self.request.billingInfoData {
2134
+ additionalInfoVC.billingInfoData = billingInfoData
2135
+ }
2136
+
2137
+ additionalInfoVC.request = self.request
2138
+ additionalInfoVC.chosenPlan = self.txtFieldSelectPlanNewCardView.text
2139
+ additionalInfoVC.startDate = self.txtFieldSelectDateNewCardView.text
2140
+
2141
+ additionalInfoVC.billingInfo = fieldSection.billing
2142
+ additionalInfoVC.additionalInfo = fieldSection.additional
2143
+ additionalInfoVC.visibility = fieldSection.visibility
2144
+
2145
+ self.navigationController?.pushViewController(additionalInfoVC, animated: true)
2146
+ }
1950
2147
  }
1951
2148
  }
1952
-
1953
- // Instantiate BillingInfoVC and pass the card details
1954
- let billingInfoVC = UIStoryboard(name: "easymerchantsdk", bundle: .easyPayBundle).instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
1955
-
1956
- // Pass the card details
1957
- billingInfoVC.cardNumber = cardNumber
1958
- billingInfoVC.expiryDate = expiryDate
1959
- billingInfoVC.cvv = cvv
1960
- billingInfoVC.nameOnCard = nameOnCard
1961
- billingInfoVC.isSavedNewCard = isSavedNewCardForFuture
1962
-
1963
- billingInfoVC.isFrom = "AddNewCard"
1964
- billingInfoVC.amount = Int(request.amount)
1965
- billingInfoVC.selectedPaymentMethod = selectedPaymentMethod
1966
-
1967
- // Pass the billing info data and auth token
1968
- if let billingInfoData = request.billingInfoData,
1969
- let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
1970
- let jsonDict = json as? [String: Any] {
1971
- billingInfoVC.billingInfoData = jsonDict
2149
+ catch {
2150
+ print("Failed to decode billingInfoData: \(error.localizedDescription)")
1972
2151
  }
1973
-
1974
- billingInfoVC.request = self.request
1975
- billingInfoVC.chosenPlan = txtFieldSelectPlanNewCardView.text
1976
- billingInfoVC.startDate = txtFieldSelectDateNewCardView.text
1977
-
1978
- // Navigate to BillingInfoVC
1979
- self.navigationController?.pushViewController(billingInfoVC, animated: true)
1980
2152
  }
1981
2153
  else {
1982
- if request.enable3DS == true {
2154
+ if request.secureAuthentication == true {
1983
2155
  threeDSecurePaymentNewCardApi(customerId: UserStoreSingleton.shared.customerId ?? "")
1984
2156
  }
1985
2157
  else {
@@ -2398,24 +2570,146 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
2398
2570
  }
2399
2571
 
2400
2572
  guard agreeTermsAndCondtition else {
2401
- self.showAlert(title: "Terms and Conditions", message: "Please agree to the terms and conditions")
2573
+ self.showAlert(title: "Terms and Conditions", message: "Please agree to the terms and conditions.")
2402
2574
  return
2403
2575
  }
2404
2576
 
2405
2577
  if isSavedForFuture {
2406
- // Navigate to next screen without calling the API
2407
- let vc = easymerchantsdk.instantiateViewController(withIdentifier: "EmailVerificationVC") as! EmailVerificationVC
2408
- vc.selectedPaymentMethod = "GrailPay"
2409
- vc.easyPayDelegate = self.easyPayDelegate
2410
- vc.grailPayAccountID = self.grailPayAccountID
2411
- vc.selectedGrailPayAccountType = self.selectedGrailPayAccountType
2412
- vc.selectedGrailPayAccountName = self.selectedGrailPayAccountName
2413
- self.navigationController?.pushViewController(vc, animated: true)
2578
+ //If billing info is available
2579
+ if let billingInfoData = request.billingInfoData {
2580
+ do {
2581
+ let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
2582
+
2583
+ DispatchQueue.main.async {
2584
+
2585
+ if let billingInfoData = self.request.billingInfoData,
2586
+ let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
2587
+ let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
2588
+ print("Billing Info Data: \(jsonDict)")
2589
+
2590
+ // Redirect based on billing visibility
2591
+ if fieldSection.visibility.billing {
2592
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
2593
+ vc.billingInfoData = billingInfoData
2594
+ vc.request = self.request
2595
+ vc.chosenPlan = self.txtFieldChosePlanGrailPayBankView.text
2596
+ vc.startDate = self.txtFieldSelectDateGrailPayBankView.text
2597
+ vc.selectedPaymentMethod = "GrailPay"
2598
+ vc.isSavedForFuture = self.isSavedForFuture
2599
+ vc.grailPayAccountID = self.grailPayAccountID
2600
+ vc.selectedGrailPayAccountType = self.selectedGrailPayAccountType
2601
+ vc.selectedGrailPayAccountName = self.selectedGrailPayAccountName
2602
+ vc.amount = self.amount
2603
+ vc.billingInfo = fieldSection.billing
2604
+ vc.additionalInfo = fieldSection.additional
2605
+ vc.visibility = fieldSection.visibility
2606
+ vc.easyPayDelegate = self.easyPayDelegate
2607
+ self.navigationController?.pushViewController(vc, animated: true)
2608
+ }
2609
+ else {
2610
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
2611
+ vc.billingInfoData = billingInfoData
2612
+ vc.request = self.request
2613
+ vc.chosenPlan = self.txtFieldChosePlanGrailPayBankView.text
2614
+ vc.startDate = self.txtFieldSelectDateGrailPayBankView.text
2615
+ vc.selectedPaymentMethod = "GrailPay"
2616
+ vc.isSavedForFuture = self.isSavedForFuture
2617
+ vc.grailPayAccountID = self.grailPayAccountID
2618
+ vc.selectedGrailPayAccountType = self.selectedGrailPayAccountType
2619
+ vc.selectedGrailPayAccountName = self.selectedGrailPayAccountName
2620
+ vc.amount = self.amount
2621
+ vc.billingInfo = fieldSection.billing
2622
+ vc.additionalInfo = fieldSection.additional
2623
+ vc.visibility = fieldSection.visibility
2624
+ vc.easyPayDelegate = self.easyPayDelegate
2625
+ self.navigationController?.pushViewController(vc, animated: true)
2626
+ }
2627
+ }
2628
+ }
2629
+ }
2630
+ catch {
2631
+ print("Failed to decode billingInfoData: \(error.localizedDescription)")
2632
+ }
2633
+ }
2634
+ else {
2635
+ //If billing info is nil
2636
+ // Navigate to EmailVerificationVC directly
2637
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "EmailVerificationVC") as! EmailVerificationVC
2638
+ vc.easyPayDelegate = self.easyPayDelegate
2639
+ vc.grailPayAccountID = self.grailPayAccountID
2640
+ vc.selectedGrailPayAccountType = self.selectedGrailPayAccountType
2641
+ vc.selectedGrailPayAccountName = self.selectedGrailPayAccountName
2642
+ vc.chosenPlan = self.txtFieldChosePlanGrailPayBankView.text
2643
+ vc.startDate = self.txtFieldSelectDateGrailPayBankView.text
2644
+ vc.request = self.request
2645
+ vc.isSavedForFuture = self.isSavedForFuture
2646
+ vc.selectedPaymentMethod = "GrailPay"
2647
+ self.navigationController?.pushViewController(vc, animated: true)
2648
+ }
2414
2649
  } else {
2415
- // Proceed to call API if not saving for future
2416
- grailPayAccountChargeApi()
2650
+ // Check if billing info data exists and is valid JSON without save
2651
+ if let billingInfoData = request.billingInfoData {
2652
+ do {
2653
+ let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
2654
+
2655
+ DispatchQueue.main.async {
2656
+
2657
+ if let billingInfoData = self.request.billingInfoData,
2658
+ let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
2659
+ let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
2660
+ print("Billing Info Data: \(jsonDict)")
2661
+
2662
+ // Redirect based on billing visibility
2663
+ if fieldSection.visibility.billing {
2664
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
2665
+ vc.billingInfoData = billingInfoData
2666
+ vc.request = self.request
2667
+ vc.chosenPlan = self.txtFieldChosePlanGrailPayBankView.text
2668
+ vc.startDate = self.txtFieldSelectDateGrailPayBankView.text
2669
+ vc.selectedPaymentMethod = "GrailPay"
2670
+ vc.isSavedForFuture = self.isSavedForFuture
2671
+ vc.grailPayAccountID = self.grailPayAccountID
2672
+ vc.selectedGrailPayAccountType = self.selectedGrailPayAccountType
2673
+ vc.selectedGrailPayAccountName = self.selectedGrailPayAccountName
2674
+ vc.amount = self.amount
2675
+ vc.billingInfo = fieldSection.billing
2676
+ vc.additionalInfo = fieldSection.additional
2677
+ vc.visibility = fieldSection.visibility
2678
+ vc.easyPayDelegate = self.easyPayDelegate
2679
+ self.navigationController?.pushViewController(vc, animated: true)
2680
+ }
2681
+ else {
2682
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
2683
+ vc.billingInfoData = billingInfoData
2684
+ vc.request = self.request
2685
+ vc.chosenPlan = self.txtFieldChosePlanGrailPayBankView.text
2686
+ vc.startDate = self.txtFieldSelectDateGrailPayBankView.text
2687
+ vc.selectedPaymentMethod = "GrailPay"
2688
+ vc.isSavedForFuture = self.isSavedForFuture
2689
+ vc.grailPayAccountID = self.grailPayAccountID
2690
+ vc.selectedGrailPayAccountType = self.selectedGrailPayAccountType
2691
+ vc.selectedGrailPayAccountName = self.selectedGrailPayAccountName
2692
+ vc.amount = self.amount
2693
+ vc.billingInfo = fieldSection.billing
2694
+ vc.additionalInfo = fieldSection.additional
2695
+ vc.visibility = fieldSection.visibility
2696
+ vc.easyPayDelegate = self.easyPayDelegate
2697
+ self.navigationController?.pushViewController(vc, animated: true)
2698
+ }
2699
+ }
2700
+ }
2701
+ }
2702
+ catch {
2703
+ print("Failed to decode billingInfoData: \(error.localizedDescription)")
2704
+ }
2705
+ }
2706
+ else {
2707
+ // Proceed to call API if billing info not available
2708
+ grailPayAccountChargeApi()
2709
+ }
2417
2710
  }
2418
2711
  } else {
2712
+ // Launch GrailPay account linking
2419
2713
  grailPaySource = .existingAccount
2420
2714
  launchGrailPay()
2421
2715
  }
@@ -2444,10 +2738,124 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
2444
2738
  }
2445
2739
 
2446
2740
  if isSavedForFuture {
2447
- grailPayNewAccountSavingChargeApi()
2741
+ //If billing info is available
2742
+ if let billingInfoData = request.billingInfoData {
2743
+ do {
2744
+ let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
2745
+
2746
+ DispatchQueue.main.async {
2747
+
2748
+ if let billingInfoData = self.request.billingInfoData,
2749
+ let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
2750
+ let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
2751
+ print("Billing Info Data: \(jsonDict)")
2752
+
2753
+ // Redirect based on billing visibility
2754
+ if fieldSection.visibility.billing {
2755
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
2756
+ vc.billingInfoData = billingInfoData
2757
+ vc.request = self.request
2758
+ vc.chosenPlan = self.txtFieldChosePlanNewGrailPayBankView.text
2759
+ vc.startDate = self.txtFieldSelectDateNewGrailPayBankView.text
2760
+ vc.selectedPaymentMethod = "NewGrailPayAccount"
2761
+ vc.isSavedForFuture = self.isSavedForFuture
2762
+ vc.grailPayAccountID = self.newGrailPayAccountID
2763
+ vc.selectedGrailPayAccountType = self.selectedNewGrailPayAccountType
2764
+ vc.selectedGrailPayAccountName = self.selectedNewGrailPayAccountName
2765
+ vc.amount = self.amount
2766
+ vc.billingInfo = fieldSection.billing
2767
+ vc.additionalInfo = fieldSection.additional
2768
+ vc.visibility = fieldSection.visibility
2769
+ vc.easyPayDelegate = self.easyPayDelegate
2770
+ self.navigationController?.pushViewController(vc, animated: true)
2771
+ }
2772
+ else {
2773
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
2774
+ vc.billingInfoData = billingInfoData
2775
+ vc.request = self.request
2776
+ vc.chosenPlan = self.txtFieldChosePlanNewGrailPayBankView.text
2777
+ vc.startDate = self.txtFieldSelectDateNewGrailPayBankView.text
2778
+ vc.selectedPaymentMethod = "NewGrailPayAccount"
2779
+ vc.isSavedForFuture = self.isSavedForFuture
2780
+ vc.grailPayAccountID = self.newGrailPayAccountID
2781
+ vc.selectedGrailPayAccountType = self.selectedNewGrailPayAccountType
2782
+ vc.selectedGrailPayAccountName = self.selectedNewGrailPayAccountName
2783
+ vc.amount = self.amount
2784
+ vc.billingInfo = fieldSection.billing
2785
+ vc.additionalInfo = fieldSection.additional
2786
+ vc.visibility = fieldSection.visibility
2787
+ vc.easyPayDelegate = self.easyPayDelegate
2788
+ self.navigationController?.pushViewController(vc, animated: true)
2789
+ }
2790
+ }
2791
+ }
2792
+ }
2793
+ catch {
2794
+ print("Failed to decode billingInfoData: \(error.localizedDescription)")
2795
+ }
2796
+ }
2448
2797
  }
2449
2798
  else {
2450
- grailPayNewAccountChargeApi()
2799
+ // Check if billing info data exists and is valid JSON without save
2800
+ if let billingInfoData = request.billingInfoData {
2801
+ do {
2802
+ let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
2803
+
2804
+ DispatchQueue.main.async {
2805
+
2806
+ if let billingInfoData = self.request.billingInfoData,
2807
+ let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
2808
+ let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
2809
+ print("Billing Info Data: \(jsonDict)")
2810
+
2811
+ // Redirect based on billing visibility
2812
+ if fieldSection.visibility.billing {
2813
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
2814
+ vc.billingInfoData = billingInfoData
2815
+ vc.request = self.request
2816
+ vc.chosenPlan = self.txtFieldChosePlanNewGrailPayBankView.text
2817
+ vc.startDate = self.txtFieldSelectDateNewGrailPayBankView.text
2818
+ vc.selectedPaymentMethod = "NewGrailPayAccount"
2819
+ vc.isSavedForFuture = self.isSavedForFuture
2820
+ vc.grailPayAccountID = self.newGrailPayAccountID
2821
+ vc.selectedGrailPayAccountType = self.selectedNewGrailPayAccountType
2822
+ vc.selectedGrailPayAccountName = self.selectedNewGrailPayAccountName
2823
+ vc.amount = self.amount
2824
+ vc.billingInfo = fieldSection.billing
2825
+ vc.additionalInfo = fieldSection.additional
2826
+ vc.visibility = fieldSection.visibility
2827
+ vc.easyPayDelegate = self.easyPayDelegate
2828
+ self.navigationController?.pushViewController(vc, animated: true)
2829
+ }
2830
+ else {
2831
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
2832
+ vc.billingInfoData = billingInfoData
2833
+ vc.request = self.request
2834
+ vc.chosenPlan = self.txtFieldChosePlanNewGrailPayBankView.text
2835
+ vc.startDate = self.txtFieldSelectDateNewGrailPayBankView.text
2836
+ vc.selectedPaymentMethod = "NewGrailPayAccount"
2837
+ vc.isSavedForFuture = self.isSavedForFuture
2838
+ vc.grailPayAccountID = self.newGrailPayAccountID
2839
+ vc.selectedGrailPayAccountType = self.selectedNewGrailPayAccountType
2840
+ vc.selectedGrailPayAccountName = self.selectedNewGrailPayAccountName
2841
+ vc.amount = self.amount
2842
+ vc.billingInfo = fieldSection.billing
2843
+ vc.additionalInfo = fieldSection.additional
2844
+ vc.visibility = fieldSection.visibility
2845
+ vc.easyPayDelegate = self.easyPayDelegate
2846
+ self.navigationController?.pushViewController(vc, animated: true)
2847
+ }
2848
+ }
2849
+ }
2850
+ }
2851
+ catch {
2852
+ print("Failed to decode billingInfoData: \(error.localizedDescription)")
2853
+ }
2854
+ }
2855
+ else {
2856
+ // Proceed to call API if billing info not available
2857
+ grailPayNewAccountChargeApi()
2858
+ }
2451
2859
  }
2452
2860
  } else {
2453
2861
  grailPaySource = .newAccount
@@ -2468,30 +2876,30 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
2468
2876
  case .success:
2469
2877
  if let chargeData = result.chargeData,
2470
2878
  let dataArray = chargeData["data"] as? [[String: Any]],
2471
- let firstAccount = dataArray.first {
2879
+ let selectedAccount = dataArray.first {
2472
2880
 
2473
- print("✅ Bank connected: \(firstAccount)")
2474
- self.selectedGrailPayAccountType = firstAccount["account_type"] as? String
2475
- self.selectedGrailPayAccountName = firstAccount["name"] as? String
2881
+ print("✅ Bank connected: \(selectedAccount)")
2882
+ self.selectedGrailPayAccountType = selectedAccount["account_type"] as? String
2883
+ self.selectedGrailPayAccountName = selectedAccount["name"] as? String
2476
2884
 
2477
2885
  if self.grailPaySource == .existingAccount {
2478
- self.accountConnectApi(account: firstAccount)
2886
+ self.accountConnectApi(account: selectedAccount)
2479
2887
  self.lblGrailPayAabandonError.text = "Default account successfully set"
2480
2888
  self.viewGrailPayAbandon.isHidden = false
2481
2889
  } else if self.grailPaySource == .newAccount {
2482
- self.newGrailPayAccountConnectApi(account: firstAccount)
2890
+ self.newGrailPayAccountConnectApi(account: selectedAccount)
2483
2891
  self.lblAbandonGrailPayNewAccountView.text = "Default account successfully set"
2484
2892
  self.viewAbandonGrailPayNewAccountView.isHidden = false
2485
2893
 
2486
- self.selectedNewGrailPayAccountType = firstAccount["account_type"] as? String
2487
- self.selectedNewGrailPayAccountName = firstAccount["name"] as? String
2894
+ self.selectedNewGrailPayAccountType = selectedAccount["account_type"] as? String
2895
+ self.selectedNewGrailPayAccountName = selectedAccount["name"] as? String
2488
2896
  }
2489
2897
 
2490
2898
  if self.selectedPaymentMethod == "Bank" {
2491
2899
  self.viewBtnShowSavedCards.isHidden = true
2492
2900
  }
2493
2901
 
2494
- let amountText = String(format: "$%.2f", self.request.amount)
2902
+ let amountText = String(format: "$%.2f", self.request.amount ?? 0)
2495
2903
  let submitText = self.request.submitButtonText
2496
2904
  let defaultTitle = (submitText?.isEmpty == false)
2497
2905
  ? "\(submitText!) (\(amountText))"
@@ -2571,7 +2979,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
2571
2979
  "account_type": self.selectedGrailPayAccountType ?? "",
2572
2980
  "name": self.selectedGrailPayAccountName ?? "",
2573
2981
  "description": "payment checkout",
2574
- "email": "newmerchantadminuser12@test.com"
2982
+ "email": UserStoreSingleton.shared.merchantEmail ?? ""
2575
2983
  ]
2576
2984
 
2577
2985
  // Add these if recurring is enabled
@@ -2644,7 +3052,32 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
2644
3052
  paymentDoneVC.chargeData = responseObject
2645
3053
  // Pass the selected payment method
2646
3054
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
2647
- paymentDoneVC.easyPayDelegate = self.easyPayDelegate // Pass the delegate
3055
+ paymentDoneVC.easyPayDelegate = self.easyPayDelegate
3056
+ // Pass billingInfo and additionalInfo
3057
+ if let billingData = self.request.billingInfoData,
3058
+ let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
3059
+
3060
+ // Extract main billing fields
3061
+ let cleanBillingInfo: [String: Any] = [
3062
+ "postal_code": billingInfoDict["postal_code"] ?? "",
3063
+ "country": billingInfoDict["country"] ?? "",
3064
+ "city": billingInfoDict["city"] ?? "",
3065
+ "address": billingInfoDict["address"] ?? "",
3066
+ "state": billingInfoDict["state"] ?? ""
3067
+ ]
3068
+ paymentDoneVC.billingInfo = cleanBillingInfo
3069
+
3070
+ // Extract additional_info
3071
+ if let additional = billingInfoDict["additional_info"] as? [String: Any] {
3072
+ let cleanAdditionalInfo: [String: Any] = [
3073
+ "email": additional["email"] ?? "",
3074
+ "phone_number": additional["phone_number"] ?? "",
3075
+ "name": additional["name"] ?? "",
3076
+ "country_code": additional["country_code"] ?? ""
3077
+ ]
3078
+ paymentDoneVC.additionalInfo = cleanAdditionalInfo
3079
+ }
3080
+ }
2648
3081
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
2649
3082
  }
2650
3083
  }
@@ -2775,140 +3208,32 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
2775
3208
  paymentDoneVC.chargeData = responseObject
2776
3209
  // Pass the selected payment method
2777
3210
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
2778
- paymentDoneVC.easyPayDelegate = self.easyPayDelegate // Pass the delegate
2779
- self.navigationController?.pushViewController(paymentDoneVC, animated: true)
2780
- }
2781
- }
2782
- }
2783
- } else {
2784
- self.presentPaymentErrorVC(errorMessage: "Invalid JSON format")
2785
- }
2786
- } catch let jsonError {
2787
- self.presentPaymentErrorVC(errorMessage: "Error parsing JSON: \(jsonError)")
2788
- }
2789
- } else {
2790
- self.presentPaymentErrorVC(errorMessage: "No data received")
2791
- }
2792
- } else {
2793
- if let data = serviceData,
2794
- let responseObj = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
2795
- let message = responseObj["message"] as? String {
2796
- self.presentPaymentErrorVC(errorMessage: message)
2797
- } else {
2798
- self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
2799
- }
2800
- }
2801
- }
2802
- task.resume()
2803
- }
2804
-
2805
- //MARK: - GrailPay New Account Banking Payment Charge Api with saving bank.
2806
- func grailPayNewAccountSavingChargeApi() {
2807
- showLoadingIndicator()
2808
- let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.achCharge.path()
2809
-
2810
- guard let serviceURL = URL(string: fullURL) else {
2811
- print("Invalid URL")
2812
- hideLoadingIndicator()
2813
- return
2814
- }
2815
-
2816
- var uRLRequest = URLRequest(url: serviceURL)
2817
- uRLRequest.httpMethod = "POST"
2818
- uRLRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
2819
-
2820
- let token = UserStoreSingleton.shared.clientToken
2821
- print("Setting clientToken header: \(token ?? "None")")
2822
- uRLRequest.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
2823
-
2824
- if let apiKey = EnvironmentConfig.apiKey {
2825
- uRLRequest.addValue(apiKey, forHTTPHeaderField: "X-Api-Key")
2826
- }
2827
- if let apiSecret = EnvironmentConfig.apiSecret {
2828
- uRLRequest.addValue(apiSecret, forHTTPHeaderField: "X-Api-Secret")
2829
- }
2830
-
2831
- var params: [String: Any] = [
2832
- "account_id": self.newGrailPayAccountID ?? "",
2833
- "account_type": self.selectedNewGrailPayAccountType ?? "",
2834
- "name": self.selectedNewGrailPayAccountName ?? "",
2835
- "description": "payment checkout",
2836
- "customer_id": self.grailPayNewAccountCustomerID ?? "",
2837
- "save_account" : 1,
2838
- "is_default": 1
2839
- ]
2840
-
2841
- // Add these if recurring is enabled
2842
- if let req = request, req.is_recurring == true {
2843
- if let recurringType = req.recurringStartDateType, recurringType == .custom {
2844
- // Only send start_date if type is .custom and field is not empty
2845
- if let startDateText = txtFieldSelectDateNewGrailPayBankView?.text, !startDateText.isEmpty {
2846
- let inputFormatter = DateFormatter()
2847
- inputFormatter.dateFormat = "dd/MM/yyyy"
2848
-
2849
- let outputFormatter = DateFormatter()
2850
- outputFormatter.dateFormat = "MM/dd/yyyy"
2851
-
2852
- if let date = inputFormatter.date(from: startDateText) {
2853
- let apiFormattedDate = outputFormatter.string(from: date)
2854
- params["start_date"] = apiFormattedDate
2855
- } else {
2856
- print("Invalid date format in startDateText")
2857
- }
2858
- }
2859
- }
2860
-
2861
- params["interval"] = txtFieldChosePlanNewGrailPayBankView.text.lowercased()
2862
- }
2863
-
2864
- print(params)
2865
-
2866
- do {
2867
- let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
2868
- uRLRequest.httpBody = jsonData
2869
- if let jsonString = String(data: jsonData, encoding: .utf8) {
2870
- print("JSON Payload: \(jsonString)")
2871
- }
2872
- } catch let error {
2873
- print("Error creating JSON data: \(error)")
2874
- hideLoadingIndicator()
2875
- return
2876
- }
2877
-
2878
- let session = URLSession.shared
2879
- let task = session.dataTask(with: uRLRequest) { (serviceData, serviceResponse, error) in
2880
-
2881
- DispatchQueue.main.async {
2882
- self.hideLoadingIndicator() // Stop loader when response is received
2883
- }
2884
-
2885
- if let error = error {
2886
- print("Error: \(error.localizedDescription)")
2887
- return
2888
- }
2889
-
2890
- guard let httpResponse = serviceResponse as? HTTPURLResponse else {
2891
- print("Invalid response")
2892
- return
2893
- }
2894
-
2895
- if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
2896
- if let data = serviceData {
2897
- do {
2898
- if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
2899
- print("Response Data: \(responseObject)")
2900
-
2901
- // Check if status is 0 and handle the error
2902
- if let status = responseObject["status"] as? Int, status == 0 {
2903
- let errorMessage = responseObject["message"] as? String ?? "Unknown error"
2904
- self.presentPaymentErrorVC(errorMessage: errorMessage)
2905
- } else {
2906
- DispatchQueue.main.async {
2907
- if let paymentDoneVC = self.storyboard?.instantiateViewController(withIdentifier: "PaymentDoneVC") as? PaymentDoneVC {
2908
- paymentDoneVC.chargeData = responseObject
2909
- // Pass the selected payment method
2910
- paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
2911
- paymentDoneVC.easyPayDelegate = self.easyPayDelegate // Pass the delegate
3211
+ paymentDoneVC.easyPayDelegate = self.easyPayDelegate
3212
+ // Pass billingInfo and additionalInfo
3213
+ if let billingData = self.request.billingInfoData,
3214
+ let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
3215
+
3216
+ // Extract main billing fields
3217
+ let cleanBillingInfo: [String: Any] = [
3218
+ "postal_code": billingInfoDict["postal_code"] ?? "",
3219
+ "country": billingInfoDict["country"] ?? "",
3220
+ "city": billingInfoDict["city"] ?? "",
3221
+ "address": billingInfoDict["address"] ?? "",
3222
+ "state": billingInfoDict["state"] ?? ""
3223
+ ]
3224
+ paymentDoneVC.billingInfo = cleanBillingInfo
3225
+
3226
+ // Extract additional_info
3227
+ if let additional = billingInfoDict["additional_info"] as? [String: Any] {
3228
+ let cleanAdditionalInfo: [String: Any] = [
3229
+ "email": additional["email"] ?? "",
3230
+ "phone_number": additional["phone_number"] ?? "",
3231
+ "name": additional["name"] ?? "",
3232
+ "country_code": additional["country_code"] ?? ""
3233
+ ]
3234
+ paymentDoneVC.additionalInfo = cleanAdditionalInfo
3235
+ }
3236
+ }
2912
3237
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
2913
3238
  }
2914
3239
  }
@@ -3070,34 +3395,20 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3070
3395
  @IBAction func actionBtnNext(_ sender: UIButton) {
3071
3396
  // Check if billing info data exists and is valid JSON
3072
3397
  if let billingInfoData = request.billingInfoData {
3073
- DispatchQueue.global(qos: .userInitiated).async { [weak self] in
3074
- // Perform JSON parsing in a background thread
3075
- guard let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
3076
- let jsonDict = json as? [String: Any], !jsonDict.isEmpty else {
3077
- return
3078
- }
3398
+ do {
3399
+ let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
3079
3400
 
3080
3401
  DispatchQueue.main.async {
3081
- // Ensure UI updates happen on the main thread
3082
- guard let self = self else { return }
3083
-
3084
3402
  if self.selectedPaymentMethod == "Card" {
3085
- // Trim whitespace and newlines
3086
3403
  let cardNumber = self.cardNumberTextField.text.trimmingCharacters(in: .whitespacesAndNewlines)
3087
3404
  let expiryDate = self.cardExpiryTextField.text.trimmingCharacters(in: .whitespacesAndNewlines)
3088
3405
  let cvv = self.cardCvvTextField.text.trimmingCharacters(in: .whitespacesAndNewlines)
3089
3406
  let cardName = self.cardNameTextField.text.trimmingCharacters(in: .whitespacesAndNewlines)
3090
-
3091
- // Remove spaces from card number for validation
3407
+ let email = self.txtFieldEmailCardView.text.trimmingCharacters(in: .whitespacesAndNewlines)
3092
3408
  let sanitizedCardNumber = cardNumber.replacingOccurrences(of: " ", with: "")
3093
-
3094
- // Regular expression for expiry date format MM/yyyy
3095
3409
  let expiryDateRegex = #"^(0[1-9]|1[0-2])\/\d{4}$"#
3096
-
3097
- // Regular expression for a valid name (only letters and spaces)
3098
3410
  let nameRegex = #"^[A-Za-z\s]+$"#
3099
3411
 
3100
- // Validation checks
3101
3412
  if cardNumber.isEmpty {
3102
3413
  self.showAlert(title: "Missing Information", message: "Card Number is required.")
3103
3414
  return
@@ -3107,22 +3418,17 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3107
3418
  } else if expiryDate.isEmpty {
3108
3419
  self.showAlert(title: "Missing Information", message: "Card Expiry Date is required.")
3109
3420
  return
3110
- }
3111
- else if !expiryDate.matches(expiryDateRegex) {
3421
+ } else if !expiryDate.matches(expiryDateRegex) {
3112
3422
  self.showAlert(title: "Invalid Expiry Date", message: "Expiry Date must be in format MM/yyyy (e.g., 02/2026).")
3113
3423
  return
3114
- }
3115
- else {
3116
- // Check if expiry date is past tomorrow
3424
+ } else {
3117
3425
  let dateFormatter = DateFormatter()
3118
3426
  dateFormatter.dateFormat = "MM/yyyy"
3119
3427
  dateFormatter.timeZone = TimeZone.current
3120
3428
  if let expDate = dateFormatter.date(from: expiryDate) {
3121
3429
  let calendar = Calendar.current
3122
- // Get start of the month following expiry
3123
3430
  let expiryMonthStart = calendar.date(from: calendar.dateComponents([.year, .month], from: expDate))!
3124
3431
  let endOfMonth = calendar.date(byAdding: DateComponents(month: 1, day: -1), to: expiryMonthStart)!
3125
-
3126
3432
  let tomorrow = calendar.date(byAdding: .day, value: 1, to: Date())!
3127
3433
  if endOfMonth < tomorrow {
3128
3434
  self.showAlert(title: "Expired Card", message: "Card is expired or please enter a valid expiry date.")
@@ -3146,9 +3452,15 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3146
3452
  } else if !cardName.matches(nameRegex) {
3147
3453
  self.showAlert(title: "Invalid Name", message: "Name must contain only letters and spaces.")
3148
3454
  return
3455
+ } else if email.isEmpty {
3456
+ self.showAlert(title: "Missing Information", message: "Please enter an email address.")
3457
+ return
3458
+ } else if !self.isValidEmail(email) {
3459
+ self.showAlert(title: "Invalid Email", message: "Please enter a valid email address.")
3460
+ return
3149
3461
  }
3150
3462
 
3151
- // Recurring Plan + Date Validation (only if is_recurring is true)
3463
+ // Recurring plan validation
3152
3464
  if let req = self.request, req.is_recurring == true {
3153
3465
  if self.txtFieldChosePlanCard.text.isEmpty {
3154
3466
  self.showAlert(title: "Missing Information", message: "Please choose your plan.")
@@ -3163,22 +3475,51 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3163
3475
  }
3164
3476
  }
3165
3477
 
3166
- // Proceed to BillingInfoVC
3167
- let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
3168
- vc.billingInfoData = jsonDict
3169
- vc.cardNumber = cardNumber
3170
- vc.expiryDate = expiryDate
3171
- vc.cvv = cvv
3172
- vc.nameOnCard = cardName
3173
- vc.selectedPaymentMethod = self.selectedPaymentMethod
3174
- vc.isSavedForFuture = self.isSavedForFuture
3175
- vc.request = self.request
3176
- vc.chosenPlan = self.txtFieldChosePlanCard.text
3177
- vc.startDate = self.txtFieldStartDateCard.text
3178
- self.navigationController?.pushViewController(vc, animated: true)
3478
+ // Redirect based on billing visibility
3479
+ if fieldSection.visibility.billing {
3480
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
3481
+ vc.billingInfoData = billingInfoData
3482
+ vc.cardNumber = cardNumber
3483
+ vc.expiryDate = expiryDate
3484
+ vc.cvv = cvv
3485
+ vc.nameOnCard = cardName
3486
+ vc.selectedPaymentMethod = self.selectedPaymentMethod
3487
+ vc.isSavedForFuture = self.isSavedForFuture
3488
+ vc.request = self.request
3489
+ vc.chosenPlan = self.txtFieldChosePlanCard.text
3490
+ vc.startDate = self.txtFieldStartDateCard.text
3491
+ vc.userEmail = self.txtFieldEmailCardView.text
3492
+ vc.amount = self.amount
3493
+ vc.billingInfo = fieldSection.billing
3494
+ vc.additionalInfo = fieldSection.additional
3495
+ vc.visibility = fieldSection.visibility
3496
+ vc.easyPayDelegate = self.easyPayDelegate
3497
+ self.navigationController?.pushViewController(vc, animated: true)
3498
+ } else {
3499
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
3500
+ vc.billingInfoData = billingInfoData
3501
+ vc.cardNumber = cardNumber
3502
+ vc.expiryDate = expiryDate
3503
+ vc.cvv = cvv
3504
+ vc.nameOnCard = cardName
3505
+ vc.selectedPaymentMethod = self.selectedPaymentMethod
3506
+ vc.isSavedForFuture = self.isSavedForFuture
3507
+ vc.request = self.request
3508
+ vc.chosenPlan = self.txtFieldChosePlanCard.text
3509
+ vc.startDate = self.txtFieldStartDateCard.text
3510
+ vc.userEmail = self.txtFieldEmailCardView.text
3511
+ vc.billingInfo = fieldSection.billing
3512
+ vc.additionalInfo = fieldSection.additional
3513
+ vc.amount = self.amount
3514
+ vc.visibility = fieldSection.visibility
3515
+ vc.easyPayDelegate = self.easyPayDelegate
3516
+ self.navigationController?.pushViewController(vc, animated: true)
3517
+ }
3179
3518
  }
3180
3519
  else if self.selectedPaymentMethod == "Bank" {
3181
3520
  // Bank Case
3521
+ let email = self.txtFieldEmailAccountView.text.trimmingCharacters(in: .whitespacesAndNewlines)
3522
+
3182
3523
  if self.txtFieldAccountName.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true {
3183
3524
  self.showAlert(title: "Missing Information", message: "Bank account name is required.")
3184
3525
  return
@@ -3205,6 +3546,14 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3205
3546
  self.showAlert(title: "Account Mismatch", message: "Bank account number and confirmation do not match.")
3206
3547
  return
3207
3548
  }
3549
+ else if email.isEmpty {
3550
+ self.showAlert(title: "Missing Information", message: "Please enter an email address.")
3551
+ return
3552
+ } else if !self.isValidEmail(email) {
3553
+ self.showAlert(title: "Invalid Email", message: "Please enter a valid email address.")
3554
+ return
3555
+ }
3556
+
3208
3557
  else if !self.agreeTermsAndCondtition {
3209
3558
  self.showAlert(title: "Terms and Conditions", message: "Please agree to the terms and conditions")
3210
3559
  return
@@ -3225,24 +3574,59 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3225
3574
  }
3226
3575
  }
3227
3576
 
3228
- // Proceed to BillingInfoVC
3229
- let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
3230
- vc.accountName = self.txtFieldAccountName.text
3231
- vc.routingNumber = self.txtFieldRoutingNumber.text
3232
- vc.accountType = self.txtFieldAccountType.text
3233
- vc.accountNumber = self.txtFieldAccountNumber.text
3234
- vc.billingInfoData = jsonDict
3235
- vc.selectedPaymentMethod = self.selectedPaymentMethod
3236
- vc.isSavedForFuture = self.isSavedForFuture
3237
- vc.isFrom = "NormalBankPayWithoutSave"
3238
- vc.chosenPlan = self.txtFieldSelectPlanViewBankFields.text
3239
- vc.startDate = self.txtFieldSelectDateViewBankFields.text
3240
- vc.request = self.request
3241
- self.navigationController?.pushViewController(vc, animated: true)
3577
+ // Redirect based on billing visibility
3578
+ if fieldSection.visibility.billing {
3579
+ // Proceed to BillingInfoVC
3580
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
3581
+ vc.accountName = self.txtFieldAccountName.text
3582
+ vc.routingNumber = self.txtFieldRoutingNumber.text
3583
+ vc.accountType = self.txtFieldAccountType.text
3584
+ vc.accountNumber = self.txtFieldAccountNumber.text
3585
+ // vc.billingInfoData = jsonDict
3586
+ vc.billingInfoData = billingInfoData
3587
+ vc.selectedPaymentMethod = self.selectedPaymentMethod
3588
+ vc.isSavedForFuture = self.isSavedForFuture
3589
+ vc.isFrom = "NormalBankPayWithoutSave"
3590
+ vc.chosenPlan = self.txtFieldSelectPlanViewBankFields.text
3591
+ vc.startDate = self.txtFieldSelectDateViewBankFields.text
3592
+ vc.request = self.request
3593
+ vc.userEmail = self.txtFieldEmailAccountView.text
3594
+ vc.amount = self.amount
3595
+ vc.billingInfo = fieldSection.billing
3596
+ vc.additionalInfo = fieldSection.additional
3597
+ vc.visibility = fieldSection.visibility
3598
+ vc.easyPayDelegate = self.easyPayDelegate
3599
+ self.navigationController?.pushViewController(vc, animated: true)
3600
+ }
3601
+ else {
3602
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
3603
+ vc.accountName = self.txtFieldAccountName.text
3604
+ vc.routingNumber = self.txtFieldRoutingNumber.text
3605
+ vc.accountType = self.txtFieldAccountType.text
3606
+ vc.accountNumber = self.txtFieldAccountNumber.text
3607
+ // vc.billingInfoData = jsonDict
3608
+ vc.billingInfoData = billingInfoData
3609
+ vc.selectedPaymentMethod = self.selectedPaymentMethod
3610
+ vc.isSavedForFuture = self.isSavedForFuture
3611
+ vc.isFrom = "NormalBankPayWithoutSave"
3612
+ vc.chosenPlan = self.txtFieldSelectPlanViewBankFields.text
3613
+ vc.startDate = self.txtFieldSelectDateViewBankFields.text
3614
+ vc.request = self.request
3615
+ vc.userEmail = self.txtFieldEmailAccountView.text
3616
+ vc.amount = self.amount
3617
+ vc.billingInfo = fieldSection.billing
3618
+ vc.additionalInfo = fieldSection.additional
3619
+ vc.visibility = fieldSection.visibility
3620
+ vc.easyPayDelegate = self.easyPayDelegate
3621
+ self.navigationController?.pushViewController(vc, animated: true)
3622
+ }
3242
3623
  }
3243
3624
  }
3625
+ } catch {
3626
+ print("Failed to decode billingInfoData: \(error.localizedDescription)")
3244
3627
  }
3245
- } else {
3628
+ }
3629
+ else {
3246
3630
  // Billing info is nil or empty
3247
3631
  if selectedPaymentMethod == "Card" {
3248
3632
  /// Card Case
@@ -3252,6 +3636,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3252
3636
  let expiryDate = self.cardExpiryTextField.text.trimmingCharacters(in: .whitespacesAndNewlines)
3253
3637
  let cvv = self.cardCvvTextField.text.trimmingCharacters(in: .whitespacesAndNewlines)
3254
3638
  let cardName = self.cardNameTextField.text.trimmingCharacters(in: .whitespacesAndNewlines)
3639
+ let email = self.txtFieldEmailCardView.text.trimmingCharacters(in: .whitespacesAndNewlines)
3255
3640
 
3256
3641
  // Remove spaces from card number for validation
3257
3642
  let sanitizedCardNumber = cardNumber.replacingOccurrences(of: " ", with: "")
@@ -3312,6 +3697,13 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3312
3697
  self.showAlert(title: "Invalid Name", message: "Name must contain only letters and spaces.")
3313
3698
  return
3314
3699
  }
3700
+ else if email.isEmpty {
3701
+ self.showAlert(title: "Missing Information", message: "Please enter an email address.")
3702
+ return
3703
+ } else if !self.isValidEmail(email) {
3704
+ self.showAlert(title: "Invalid Email", message: "Please enter a valid email address.")
3705
+ return
3706
+ }
3315
3707
 
3316
3708
  // Recurring Plan + Date Validation (only if is_recurring is true)
3317
3709
  if let req = self.request, req.is_recurring == true {
@@ -3332,7 +3724,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3332
3724
  if isSavedForFuture {
3333
3725
  navigateCardDataToEmailVerificationVC()
3334
3726
  } else {
3335
- if request.enable3DS == true {
3727
+ if request.secureAuthentication == true {
3336
3728
  threeDSecurePaymentApi()
3337
3729
  }
3338
3730
  else {
@@ -3342,6 +3734,8 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3342
3734
  }
3343
3735
  else if selectedPaymentMethod == "Bank" {
3344
3736
  // Bank Case
3737
+ let email = self.txtFieldEmailAccountView.text.trimmingCharacters(in: .whitespacesAndNewlines)
3738
+
3345
3739
  if txtFieldAccountName.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true {
3346
3740
  showAlert(title: "Missing Information", message: "Bank account name is required.")
3347
3741
  return
@@ -3370,6 +3764,13 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3370
3764
  self.showAlert(title: "Account Mismatch", message: "Bank account number and confirmation do not match.")
3371
3765
  return
3372
3766
  }
3767
+ else if email.isEmpty {
3768
+ self.showAlert(title: "Missing Information", message: "Please enter an email address.")
3769
+ return
3770
+ } else if !self.isValidEmail(email) {
3771
+ self.showAlert(title: "Invalid Email", message: "Please enter a valid email address.")
3772
+ return
3773
+ }
3373
3774
  else if !agreeTermsAndCondtition {
3374
3775
  showAlert(title: "Terms and Conditions", message: "Please agree to the terms and conditions")
3375
3776
  return
@@ -3452,10 +3853,23 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3452
3853
  if selectedPaymentMethod == "Card" {
3453
3854
  self.viewSingleSavedAccount.isHidden = true
3454
3855
  self.viewBankFields.isHidden = true
3455
- self.viewBtnShowSavedCards.isHidden = false
3456
- self.lblBtnShowSaveCard.text = "Show Saved Cards"
3457
- self.viewBtnShowSavedCardHeight.constant = 50
3458
- self.viewBtnShowSavedCardTopCon.constant = 20
3856
+ // self.viewBtnShowSavedCards.isHidden = false
3857
+ // self.lblBtnShowSaveCard.text = "Show Saved Cards"
3858
+ // self.viewBtnShowSavedCardHeight.constant = 50
3859
+ // self.viewBtnShowSavedCardTopCon.constant = 20
3860
+
3861
+ if request.saveCard == false {
3862
+ self.viewBtnShowSavedCards.isHidden = true
3863
+ self.viewBtnShowSavedCardHeight.constant = 0
3864
+ self.viewBtnShowSavedCardTopCon.constant = 0
3865
+ }
3866
+ else {
3867
+ self.viewBtnShowSavedCards.isHidden = false
3868
+ self.lblBtnShowSaveCard.text = "Show Saved Cards"
3869
+ self.viewBtnShowSavedCardHeight.constant = 50
3870
+ self.viewBtnShowSavedCardTopCon.constant = 20
3871
+ }
3872
+
3459
3873
  self.OTPView.isHidden = true
3460
3874
  self.emailView.isHidden = true
3461
3875
  self.viewCardFields.isHidden = false
@@ -3471,10 +3885,23 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3471
3885
  }
3472
3886
  else if selectedPaymentMethod == "Bank" {
3473
3887
  self.viewBankFields.isHidden = false
3474
- self.viewBtnShowSavedCards.isHidden = false
3475
- self.lblBtnShowSaveCard.text = "Show Saved Accounts"
3476
- self.viewBtnShowSavedCardHeight.constant = 50
3477
- self.viewBtnShowSavedCardTopCon.constant = 20
3888
+ // self.viewBtnShowSavedCards.isHidden = false
3889
+ // self.lblBtnShowSaveCard.text = "Show Saved Accounts"
3890
+ // self.viewBtnShowSavedCardHeight.constant = 50
3891
+ // self.viewBtnShowSavedCardTopCon.constant = 20
3892
+
3893
+ if request.saveAccount == false {
3894
+ self.viewBtnShowSavedCards.isHidden = true
3895
+ self.viewBtnShowSavedCardHeight.constant = 0
3896
+ self.viewBtnShowSavedCardTopCon.constant = 0
3897
+ }
3898
+ else {
3899
+ self.viewBtnShowSavedCards.isHidden = false
3900
+ self.lblBtnShowSaveCard.text = "Show Saved Accounts"
3901
+ self.viewBtnShowSavedCardHeight.constant = 50
3902
+ self.viewBtnShowSavedCardTopCon.constant = 20
3903
+ }
3904
+
3478
3905
  self.OTPView.isHidden = true
3479
3906
  self.emailView.isHidden = true
3480
3907
  self.viewCardFields.isHidden = true
@@ -3618,42 +4045,80 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3618
4045
  grailPayAaccountChargeSingleSavedAccountApi()
3619
4046
  } else {
3620
4047
  // Check if billingInfoData is not nil or empty
3621
- if let billingInfoData = request.billingInfoData,
3622
- let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
3623
- let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
3624
-
3625
- // Recurring Plan + Date Validation (only if is_recurring is true)
3626
- if let req = self.request, req.is_recurring == true {
3627
- if txtFieldSelectPlanSingleSavedBankView.text.isEmpty {
3628
- self.showAlert(title: "Missing Information", message: "Please choose your plan.")
3629
- return
3630
- }
4048
+ if let billingInfoData = request.billingInfoData {
4049
+ do {
4050
+ let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
3631
4051
 
3632
- if let recurringType = req.recurringStartDateType, recurringType == .custom {
3633
- if txtFieldSelectDateSingleSavedBankView.text.isEmpty {
3634
- self.showAlert(title: "Missing Information", message: "Please select a plan start date.")
3635
- return
4052
+ DispatchQueue.main.async {
4053
+
4054
+ if let billingInfoData = self.request.billingInfoData,
4055
+ let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
4056
+ let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
4057
+
4058
+ // Recurring Plan + Date Validation (only if is_recurring is true)
4059
+ if let req = self.request, req.is_recurring == true {
4060
+ if self.txtFieldSelectPlanSingleSavedBankView.text.isEmpty {
4061
+ self.showAlert(title: "Missing Information", message: "Please choose your plan.")
4062
+ return
4063
+ }
4064
+
4065
+ if let recurringType = req.recurringStartDateType, recurringType == .custom {
4066
+ if self.txtFieldSelectDateSingleSavedBankView.text.isEmpty {
4067
+ self.showAlert(title: "Missing Information", message: "Please select a plan start date.")
4068
+ return
4069
+ }
4070
+ }
4071
+ }
4072
+
4073
+ // Check if the terms and conditions are agreed
4074
+ if !self.agreeTermsAndCondtition {
4075
+ self.showAlert(title: "Terms and Conditions", message: "Please agree to the terms and conditions")
4076
+ return
4077
+ }
4078
+
4079
+ // Redirect based on billing visibility
4080
+ if fieldSection.visibility.billing {
4081
+ // Proceed with the Pay Now action
4082
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
4083
+ // Pass the customer_id and account_id to BillingInfoVC
4084
+ vc.customerID = self.selectedbankAccounts?.customer_id
4085
+ vc.accountID = self.selectedbankAccounts?.account_id
4086
+ vc.billingInfoData = billingInfoData
4087
+ vc.isFrom = "SavedBank"
4088
+ vc.selectedPaymentMethod = "Bank"
4089
+ vc.chosenPlan = self.txtFieldSelectPlanSingleSavedBankView.text
4090
+ vc.startDate = self.txtFieldSelectDateSingleSavedBankView.text
4091
+ vc.request = self.request
4092
+ vc.amount = self.amount
4093
+ vc.billingInfo = fieldSection.billing
4094
+ vc.additionalInfo = fieldSection.additional
4095
+ vc.visibility = fieldSection.visibility
4096
+ vc.easyPayDelegate = self.easyPayDelegate
4097
+ self.navigationController?.pushViewController(vc, animated: true)
4098
+ }
4099
+ else {
4100
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
4101
+ vc.customerID = self.selectedbankAccounts?.customer_id
4102
+ vc.accountID = self.selectedbankAccounts?.account_id
4103
+ vc.billingInfoData = billingInfoData
4104
+ vc.isFrom = "SavedBank"
4105
+ vc.selectedPaymentMethod = "Bank"
4106
+ vc.chosenPlan = self.txtFieldSelectPlanSingleSavedBankView.text
4107
+ vc.startDate = self.txtFieldSelectDateSingleSavedBankView.text
4108
+ vc.request = self.request
4109
+ vc.amount = self.amount
4110
+ vc.billingInfo = fieldSection.billing
4111
+ vc.additionalInfo = fieldSection.additional
4112
+ vc.visibility = fieldSection.visibility
4113
+ vc.easyPayDelegate = self.easyPayDelegate
4114
+ self.navigationController?.pushViewController(vc, animated: true)
4115
+ }
3636
4116
  }
3637
4117
  }
3638
4118
  }
3639
-
3640
- // Check if the terms and conditions are agreed
3641
- if !agreeTermsAndCondtition {
3642
- showAlert(title: "Terms and Conditions", message: "Please agree to the terms and conditions")
3643
- return
4119
+ catch {
4120
+ print("Failed to decode billingInfoData: \(error.localizedDescription)")
3644
4121
  }
3645
- // Proceed with the Pay Now action
3646
- let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
3647
- // Pass the customer_id and account_id to BillingInfoVC
3648
- vc.customerID = selectedbankAccounts?.customer_id
3649
- vc.accountID = selectedbankAccounts?.account_id
3650
- vc.billingInfoData = jsonDict
3651
- vc.isFrom = "SavedBank"
3652
- vc.selectedPaymentMethod = "Bank"
3653
- vc.chosenPlan = self.txtFieldSelectPlanSingleSavedBankView.text
3654
- vc.startDate = self.txtFieldSelectDateSingleSavedBankView.text
3655
- vc.request = self.request
3656
- self.navigationController?.pushViewController(vc, animated: true)
3657
4122
  }
3658
4123
  else {
3659
4124
  //If Billing info is nil or empty
@@ -3701,72 +4166,115 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3701
4166
 
3702
4167
  @IBAction func actionBtnPayNowNewAccountView(_ sender: UIButton) {
3703
4168
  // Check if billingInfoData is not nil or empty
3704
- if let billingInfoData = request.billingInfoData,
3705
- let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
3706
- let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
3707
- print("Billing Info Data: \(jsonDict)")
3708
-
3709
- // Retrieve and trim text field values (removing leading and trailing whitespace)
3710
- let accountName = txtFieldAccountNameNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
3711
- let routingNumber = txtFieldRoutingNumberNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
3712
- let accountType = txtFieldAccountTypeNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
3713
- let accountNumber = txtFieldAccountNumberNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
3714
- let confirmAccountNumber = txtFieldConfirmAccountNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
3715
-
3716
- // Check if any field is empty
3717
- if accountName.isEmpty || routingNumber.isEmpty || accountType.isEmpty || accountNumber.isEmpty || confirmAccountNumber.isEmpty {
3718
- let alert = UIAlertController(title: "Missing Information", message: "Please fill in all bank details.", preferredStyle: .alert)
3719
- alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
3720
- self.present(alert, animated: true, completion: nil)
3721
- return
3722
- }
3723
-
3724
- // Check if routing number is exactly 9 digits and numeric
3725
- if routingNumber.count != 9 || !CharacterSet.decimalDigits.isSuperset(of: CharacterSet(charactersIn: routingNumber)) {
3726
- self.showAlert(title: "Invalid Routing Number", message: "Routing number is not correct. It must be exactly 9 digits.")
3727
- return
3728
- }
3729
-
3730
- // Check if account number and confirmation match
3731
- if accountNumber != confirmAccountNumber {
3732
- self.showAlert(title: "Account Mismatch", message: "Bank account number and confirmation do not match.")
3733
- return
3734
- }
3735
-
3736
- // Recurring Plan + Date Validation (only if is_recurring is true)
3737
- if let req = self.request, req.is_recurring == true {
3738
- if txtFieldSelectPlanNewAccountView.text.isEmpty {
3739
- self.showAlert(title: "Missing Information", message: "Please choose your plan.")
3740
- return
3741
- }
4169
+ if let billingInfoData = request.billingInfoData {
4170
+ do {
4171
+ let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
3742
4172
 
3743
- if let recurringType = req.recurringStartDateType, recurringType == .custom {
3744
- if txtFieldSelectDateNewAccountView.text.isEmpty {
3745
- self.showAlert(title: "Missing Information", message: "Please select a plan start date.")
3746
- return
4173
+ DispatchQueue.main.async {
4174
+
4175
+ if let billingInfoData = self.request.billingInfoData,
4176
+ let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
4177
+ let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
4178
+ print("Billing Info Data: \(jsonDict)")
4179
+
4180
+ // Retrieve and trim text field values (removing leading and trailing whitespace)
4181
+ let accountName = self.txtFieldAccountNameNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
4182
+ let routingNumber = self.txtFieldRoutingNumberNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
4183
+ let accountType = self.txtFieldAccountTypeNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
4184
+ let accountNumber = self.txtFieldAccountNumberNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
4185
+ let confirmAccountNumber = self.txtFieldConfirmAccountNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
4186
+
4187
+ // Check if any field is empty
4188
+ if accountName.isEmpty || routingNumber.isEmpty || accountType.isEmpty || accountNumber.isEmpty || confirmAccountNumber.isEmpty {
4189
+ let alert = UIAlertController(title: "Missing Information", message: "Please fill in all bank details.", preferredStyle: .alert)
4190
+ alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
4191
+ self.present(alert, animated: true, completion: nil)
4192
+ return
4193
+ }
4194
+
4195
+ // Check if routing number is exactly 9 digits and numeric
4196
+ if routingNumber.count != 9 || !CharacterSet.decimalDigits.isSuperset(of: CharacterSet(charactersIn: routingNumber)) {
4197
+ self.showAlert(title: "Invalid Routing Number", message: "Routing number is not correct. It must be exactly 9 digits.")
4198
+ return
4199
+ }
4200
+
4201
+ // Check if account number and confirmation match
4202
+ if accountNumber != confirmAccountNumber {
4203
+ self.showAlert(title: "Account Mismatch", message: "Bank account number and confirmation do not match.")
4204
+ return
4205
+ }
4206
+
4207
+ // Recurring Plan + Date Validation (only if is_recurring is true)
4208
+ if let req = self.request, req.is_recurring == true {
4209
+ if self.txtFieldSelectPlanNewAccountView.text.isEmpty {
4210
+ self.showAlert(title: "Missing Information", message: "Please choose your plan.")
4211
+ return
4212
+ }
4213
+
4214
+ if let recurringType = req.recurringStartDateType, recurringType == .custom {
4215
+ if self.txtFieldSelectDateNewAccountView.text.isEmpty {
4216
+ self.showAlert(title: "Missing Information", message: "Please select a plan start date.")
4217
+ return
4218
+ }
4219
+ }
4220
+ }
4221
+
4222
+ // Determine the vc.isFrom value based on isSavedNewAccount
4223
+ let isSavedNewAccount = self.isSavedNewAccount
4224
+ let isFromValue = isSavedNewAccount ? "AddNewAccountWithSave" : "AddNewAccountWithoutSave"
4225
+
4226
+ // Redirect based on billing visibility
4227
+ if fieldSection.visibility.billing {
4228
+ // Proceed with the Pay Now action
4229
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
4230
+ vc.accountName = accountName
4231
+ vc.routingNumber = routingNumber
4232
+ vc.accountType = accountType
4233
+ vc.accountNumber = accountNumber
4234
+ vc.billingInfoData = billingInfoData
4235
+ vc.selectedPaymentMethod = "Bank"
4236
+ vc.isFrom = isFromValue
4237
+ vc.isSavedNewAccount = isSavedNewAccount
4238
+ vc.delegate = self
4239
+ vc.chosenPlan = self.txtFieldSelectPlanNewAccountView.text
4240
+ vc.startDate = self.txtFieldSelectDateNewAccountView.text
4241
+ vc.request = self.request
4242
+ vc.selectedPaymentMethod = self.selectedPaymentMethod
4243
+ vc.amount = self.amount
4244
+ vc.billingInfo = fieldSection.billing
4245
+ vc.additionalInfo = fieldSection.additional
4246
+ vc.visibility = fieldSection.visibility
4247
+ vc.easyPayDelegate = self.easyPayDelegate
4248
+ self.navigationController?.pushViewController(vc, animated: true)
4249
+ }
4250
+ else {
4251
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "AdditionalInfoVC") as! AdditionalInfoVC
4252
+ vc.accountName = accountName
4253
+ vc.routingNumber = routingNumber
4254
+ vc.accountType = accountType
4255
+ vc.accountNumber = accountNumber
4256
+ vc.billingInfoData = billingInfoData
4257
+ vc.selectedPaymentMethod = "Bank"
4258
+ vc.isFrom = isFromValue
4259
+ vc.isSavedNewAccount = isSavedNewAccount
4260
+ // vc.delegate = self
4261
+ vc.chosenPlan = self.txtFieldSelectPlanNewAccountView.text
4262
+ vc.startDate = self.txtFieldSelectDateNewAccountView.text
4263
+ vc.request = self.request
4264
+ vc.selectedPaymentMethod = self.selectedPaymentMethod
4265
+ vc.amount = self.amount
4266
+ vc.billingInfo = fieldSection.billing
4267
+ vc.additionalInfo = fieldSection.additional
4268
+ vc.visibility = fieldSection.visibility
4269
+ vc.easyPayDelegate = self.easyPayDelegate
4270
+ self.navigationController?.pushViewController(vc, animated: true)
4271
+ }
3747
4272
  }
3748
4273
  }
3749
4274
  }
3750
-
3751
- // Determine the vc.isFrom value based on isSavedNewAccount
3752
- let isSavedNewAccount = isSavedNewAccount
3753
- let isFromValue = isSavedNewAccount ? "AddNewAccountWithSave" : "AddNewAccountWithoutSave"
3754
-
3755
- // Proceed with the Pay Now action
3756
- let vc = easymerchantsdk.instantiateViewController(withIdentifier: "BillingInfoVC") as! BillingInfoVC
3757
- vc.accountName = accountName
3758
- vc.routingNumber = routingNumber
3759
- vc.accountType = accountType
3760
- vc.accountNumber = accountNumber
3761
- vc.billingInfoData = jsonDict
3762
- vc.selectedPaymentMethod = "Bank"
3763
- vc.isFrom = isFromValue
3764
- vc.isSavedNewAccount = isSavedNewAccount
3765
- vc.delegate = self
3766
- vc.chosenPlan = self.txtFieldSelectPlanNewAccountView.text
3767
- vc.startDate = self.txtFieldSelectDateNewAccountView.text
3768
- vc.request = self.request
3769
- self.navigationController?.pushViewController(vc, animated: true)
4275
+ catch {
4276
+ print("Failed to decode billingInfoData: \(error.localizedDescription)")
4277
+ }
3770
4278
  }
3771
4279
  else {
3772
4280
  //If Billing info is nil or empty
@@ -3944,38 +4452,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3944
4452
 
3945
4453
  //MARK: - Card Scan Button Action
3946
4454
  @IBAction func actionButtonScanCard(_ sender: UIButton) {
3947
- // // Validate BlinkCard License
3948
- // let licenseErrorMessage = BlinkCardHelper.setupLicense()
3949
- // if !licenseErrorMessage.isEmpty {
3950
- // // Show alert if the license is invalid or expired
3951
- // showLicenseErrorAlert(message: licenseErrorMessage)
3952
- // return
3953
- // }
3954
- //
3955
- // // Proceed with card scanning if the license is valid
3956
- // blinkCardRecognizer = MBCBlinkCardRecognizer()
3957
- // blinkCardRecognizer.returnFullDocumentImage = true
3958
- //
3959
- // let recognizerList = [blinkCardRecognizer!]
3960
- // let recognizerCollection = MBCRecognizerCollection(recognizers: recognizerList)
3961
- //
3962
- // let customOverlayViewController: CustomOverlay = CustomOverlay.initFromStoryboard()
3963
- //
3964
- // // Reconfigure recognizers with the overlay
3965
- // customOverlayViewController.reconfigureRecognizers(recognizerCollection)
3966
- //
3967
- // // Create the recognizer runner view controller with custom overlay
3968
- // guard let recognizerRunnerViewController =
3969
- // MBCViewControllerFactory.recognizerRunnerViewController(withOverlayViewController: customOverlayViewController) else {
3970
- // showLicenseErrorAlert(message: "Failed to initialize the recognizer view controller.")
3971
- // return
3972
- // }
3973
- //
3974
- // customOverlayViewController.delegate = self
3975
- // recognizerRunnerViewController.modalPresentationStyle = .fullScreen
3976
- //
3977
- // // Present the recognizer runner view controller
3978
- // self.present(recognizerRunnerViewController, animated: true, completion: nil)
4455
+
3979
4456
  }
3980
4457
 
3981
4458
  private func showLicenseErrorAlert(message: String) {
@@ -4481,6 +4958,32 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
4481
4958
  paymentDoneVC.chargeData = responseObject
4482
4959
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
4483
4960
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
4961
+
4962
+ // Pass billingInfo and additionalInfo
4963
+ if let billingData = self.request.billingInfoData,
4964
+ let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
4965
+
4966
+ // Extract main billing fields
4967
+ let cleanBillingInfo: [String: Any] = [
4968
+ "postal_code": billingInfoDict["postal_code"] ?? "",
4969
+ "country": billingInfoDict["country"] ?? "",
4970
+ "city": billingInfoDict["city"] ?? "",
4971
+ "address": billingInfoDict["address"] ?? "",
4972
+ "state": billingInfoDict["state"] ?? ""
4973
+ ]
4974
+ paymentDoneVC.billingInfo = cleanBillingInfo
4975
+
4976
+ // Extract additional_info
4977
+ if let additional = billingInfoDict["additional_info"] as? [String: Any] {
4978
+ let cleanAdditionalInfo: [String: Any] = [
4979
+ "email": additional["email"] ?? "",
4980
+ "phone_number": additional["phone_number"] ?? "",
4981
+ "name": additional["name"] ?? "",
4982
+ "country_code": additional["country_code"] ?? ""
4983
+ ]
4984
+ paymentDoneVC.additionalInfo = cleanAdditionalInfo
4985
+ }
4986
+ }
4484
4987
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
4485
4988
  }
4486
4989
  }
@@ -4538,24 +5041,6 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
4538
5041
  uRLRequest.addValue(apiSecret, forHTTPHeaderField: "x-api-secret")
4539
5042
  }
4540
5043
 
4541
- ///OLD Params
4542
- // // Prepare parameters
4543
- // let email = UserStoreSingleton.shared.verificationEmail ?? ""
4544
- // let namePart = email.split(separator: "@").first.map(String.init) ?? ""
4545
- //
4546
- // var params: [String: Any] = [
4547
- // "name": namePart,
4548
- // "email": email,
4549
- // "description": "TestDescription",
4550
- // "currency": "usd",
4551
- // "payment_method": "card",
4552
- // "save_card": 0,
4553
- // "customer": selectedCard?.customerId ?? "",
4554
- // "card_id": selectedCard?.cardId ?? "",
4555
- // "cvc": txtFieldCVVSingleSavedCard.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "",
4556
- // "customer_id": selectedCard?.customerId ?? ""
4557
- // ]
4558
-
4559
5044
  var params: [String: Any] = [
4560
5045
  "description": "payment checkout",
4561
5046
  "currency": "usd",
@@ -4633,6 +5118,32 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
4633
5118
  paymentDoneVC.chargeData = responseObject
4634
5119
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
4635
5120
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
5121
+
5122
+ // Pass billingInfo and additionalInfo
5123
+ if let billingData = self.request.billingInfoData,
5124
+ let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
5125
+
5126
+ // Extract main billing fields
5127
+ let cleanBillingInfo: [String: Any] = [
5128
+ "postal_code": billingInfoDict["postal_code"] ?? "",
5129
+ "country": billingInfoDict["country"] ?? "",
5130
+ "city": billingInfoDict["city"] ?? "",
5131
+ "address": billingInfoDict["address"] ?? "",
5132
+ "state": billingInfoDict["state"] ?? ""
5133
+ ]
5134
+ paymentDoneVC.billingInfo = cleanBillingInfo
5135
+
5136
+ // Extract additional_info
5137
+ if let additional = billingInfoDict["additional_info"] as? [String: Any] {
5138
+ let cleanAdditionalInfo: [String: Any] = [
5139
+ "email": additional["email"] ?? "",
5140
+ "phone_number": additional["phone_number"] ?? "",
5141
+ "name": additional["name"] ?? "",
5142
+ "country_code": additional["country_code"] ?? ""
5143
+ ]
5144
+ paymentDoneVC.additionalInfo = cleanAdditionalInfo
5145
+ }
5146
+ }
4636
5147
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
4637
5148
  }
4638
5149
  }
@@ -4851,6 +5362,31 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
4851
5362
  paymentDoneVC.chargeData = responseObject
4852
5363
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
4853
5364
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
5365
+ // Pass billingInfo and additionalInfo
5366
+ if let billingData = self.request.billingInfoData,
5367
+ let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
5368
+
5369
+ // Extract main billing fields
5370
+ let cleanBillingInfo: [String: Any] = [
5371
+ "postal_code": billingInfoDict["postal_code"] ?? "",
5372
+ "country": billingInfoDict["country"] ?? "",
5373
+ "city": billingInfoDict["city"] ?? "",
5374
+ "address": billingInfoDict["address"] ?? "",
5375
+ "state": billingInfoDict["state"] ?? ""
5376
+ ]
5377
+ paymentDoneVC.billingInfo = cleanBillingInfo
5378
+
5379
+ // Extract additional_info
5380
+ if let additional = billingInfoDict["additional_info"] as? [String: Any] {
5381
+ let cleanAdditionalInfo: [String: Any] = [
5382
+ "email": additional["email"] ?? "",
5383
+ "phone_number": additional["phone_number"] ?? "",
5384
+ "name": additional["name"] ?? "",
5385
+ "country_code": additional["country_code"] ?? ""
5386
+ ]
5387
+ paymentDoneVC.additionalInfo = cleanAdditionalInfo
5388
+ }
5389
+ }
4854
5390
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
4855
5391
  }
4856
5392
  }
@@ -5384,7 +5920,32 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
5384
5920
  paymentDoneVC.chargeData = responseObject
5385
5921
  // Pass the selected payment method
5386
5922
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
5387
- paymentDoneVC.easyPayDelegate = self.easyPayDelegate // Pass the delegate
5923
+ paymentDoneVC.easyPayDelegate = self.easyPayDelegate
5924
+ // Pass billingInfo and additionalInfo
5925
+ if let billingData = self.request.billingInfoData,
5926
+ let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
5927
+
5928
+ // Extract main billing fields
5929
+ let cleanBillingInfo: [String: Any] = [
5930
+ "postal_code": billingInfoDict["postal_code"] ?? "",
5931
+ "country": billingInfoDict["country"] ?? "",
5932
+ "city": billingInfoDict["city"] ?? "",
5933
+ "address": billingInfoDict["address"] ?? "",
5934
+ "state": billingInfoDict["state"] ?? ""
5935
+ ]
5936
+ paymentDoneVC.billingInfo = cleanBillingInfo
5937
+
5938
+ // Extract additional_info
5939
+ if let additional = billingInfoDict["additional_info"] as? [String: Any] {
5940
+ let cleanAdditionalInfo: [String: Any] = [
5941
+ "email": additional["email"] ?? "",
5942
+ "phone_number": additional["phone_number"] ?? "",
5943
+ "name": additional["name"] ?? "",
5944
+ "country_code": additional["country_code"] ?? ""
5945
+ ]
5946
+ paymentDoneVC.additionalInfo = cleanAdditionalInfo
5947
+ }
5948
+ }
5388
5949
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
5389
5950
  }
5390
5951
  }
@@ -5516,7 +6077,32 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
5516
6077
  paymentDoneVC.chargeData = responseObject
5517
6078
  // Pass the selected payment method
5518
6079
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
5519
- paymentDoneVC.easyPayDelegate = self.easyPayDelegate // Pass the delegate
6080
+ paymentDoneVC.easyPayDelegate = self.easyPayDelegate
6081
+ // Pass billingInfo and additionalInfo
6082
+ if let billingData = self.request.billingInfoData,
6083
+ let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
6084
+
6085
+ // Extract main billing fields
6086
+ let cleanBillingInfo: [String: Any] = [
6087
+ "postal_code": billingInfoDict["postal_code"] ?? "",
6088
+ "country": billingInfoDict["country"] ?? "",
6089
+ "city": billingInfoDict["city"] ?? "",
6090
+ "address": billingInfoDict["address"] ?? "",
6091
+ "state": billingInfoDict["state"] ?? ""
6092
+ ]
6093
+ paymentDoneVC.billingInfo = cleanBillingInfo
6094
+
6095
+ // Extract additional_info
6096
+ if let additional = billingInfoDict["additional_info"] as? [String: Any] {
6097
+ let cleanAdditionalInfo: [String: Any] = [
6098
+ "email": additional["email"] ?? "",
6099
+ "phone_number": additional["phone_number"] ?? "",
6100
+ "name": additional["name"] ?? "",
6101
+ "country_code": additional["country_code"] ?? ""
6102
+ ]
6103
+ paymentDoneVC.additionalInfo = cleanAdditionalInfo
6104
+ }
6105
+ }
5520
6106
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
5521
6107
  }
5522
6108
  }
@@ -5658,7 +6244,32 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
5658
6244
  paymentDoneVC.chargeData = responseObject
5659
6245
  // Pass the selected payment method
5660
6246
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
5661
- paymentDoneVC.easyPayDelegate = self.easyPayDelegate // Pass the delegate
6247
+ paymentDoneVC.easyPayDelegate = self.easyPayDelegate
6248
+ // Pass billingInfo and additionalInfo
6249
+ if let billingData = self.request.billingInfoData,
6250
+ let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
6251
+
6252
+ // Extract main billing fields
6253
+ let cleanBillingInfo: [String: Any] = [
6254
+ "postal_code": billingInfoDict["postal_code"] ?? "",
6255
+ "country": billingInfoDict["country"] ?? "",
6256
+ "city": billingInfoDict["city"] ?? "",
6257
+ "address": billingInfoDict["address"] ?? "",
6258
+ "state": billingInfoDict["state"] ?? ""
6259
+ ]
6260
+ paymentDoneVC.billingInfo = cleanBillingInfo
6261
+
6262
+ // Extract additional_info
6263
+ if let additional = billingInfoDict["additional_info"] as? [String: Any] {
6264
+ let cleanAdditionalInfo: [String: Any] = [
6265
+ "email": additional["email"] ?? "",
6266
+ "phone_number": additional["phone_number"] ?? "",
6267
+ "name": additional["name"] ?? "",
6268
+ "country_code": additional["country_code"] ?? ""
6269
+ ]
6270
+ paymentDoneVC.additionalInfo = cleanAdditionalInfo
6271
+ }
6272
+ }
5662
6273
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
5663
6274
  }
5664
6275
  }
@@ -5811,6 +6422,31 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
5811
6422
  paymentDoneVC.chargeData = responseObject
5812
6423
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
5813
6424
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
6425
+ // Pass billingInfo and additionalInfo
6426
+ if let billingData = self.request.billingInfoData,
6427
+ let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
6428
+
6429
+ // Extract main billing fields
6430
+ let cleanBillingInfo: [String: Any] = [
6431
+ "postal_code": billingInfoDict["postal_code"] ?? "",
6432
+ "country": billingInfoDict["country"] ?? "",
6433
+ "city": billingInfoDict["city"] ?? "",
6434
+ "address": billingInfoDict["address"] ?? "",
6435
+ "state": billingInfoDict["state"] ?? ""
6436
+ ]
6437
+ paymentDoneVC.billingInfo = cleanBillingInfo
6438
+
6439
+ // Extract additional_info
6440
+ if let additional = billingInfoDict["additional_info"] as? [String: Any] {
6441
+ let cleanAdditionalInfo: [String: Any] = [
6442
+ "email": additional["email"] ?? "",
6443
+ "phone_number": additional["phone_number"] ?? "",
6444
+ "name": additional["name"] ?? "",
6445
+ "country_code": additional["country_code"] ?? ""
6446
+ ]
6447
+ paymentDoneVC.additionalInfo = cleanAdditionalInfo
6448
+ }
6449
+ }
5814
6450
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
5815
6451
  }
5816
6452
  }
@@ -6198,6 +6834,8 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
6198
6834
  params["interval"] = txtFieldChosePlanCard.text.lowercased()
6199
6835
  }
6200
6836
 
6837
+ print(params)
6838
+
6201
6839
  do {
6202
6840
  let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
6203
6841
  uRLRequest.httpBody = jsonData
@@ -6245,7 +6883,32 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
6245
6883
  paymentDoneVC.redirectURL = urlString
6246
6884
  paymentDoneVC.chargeData = responseObject
6247
6885
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
6248
-
6886
+ paymentDoneVC.amount = self.amount
6887
+ // Pass billingInfo and additionalInfo
6888
+ if let billingData = self.request.billingInfoData,
6889
+ let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
6890
+
6891
+ // Extract main billing fields
6892
+ let cleanBillingInfo: [String: Any] = [
6893
+ "postal_code": billingInfoDict["postal_code"] ?? "",
6894
+ "country": billingInfoDict["country"] ?? "",
6895
+ "city": billingInfoDict["city"] ?? "",
6896
+ "address": billingInfoDict["address"] ?? "",
6897
+ "state": billingInfoDict["state"] ?? ""
6898
+ ]
6899
+ paymentDoneVC.billingInfo = cleanBillingInfo
6900
+
6901
+ // Extract additional_info
6902
+ if let additional = billingInfoDict["additional_info"] as? [String: Any] {
6903
+ let cleanAdditionalInfo: [String: Any] = [
6904
+ "email": additional["email"] ?? "",
6905
+ "phone_number": additional["phone_number"] ?? "",
6906
+ "name": additional["name"] ?? "",
6907
+ "country_code": additional["country_code"] ?? ""
6908
+ ]
6909
+ paymentDoneVC.additionalInfo = cleanAdditionalInfo
6910
+ }
6911
+ }
6249
6912
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
6250
6913
  }
6251
6914
  }
@@ -6455,7 +7118,32 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
6455
7118
  paymentDoneVC.redirectURL = urlString
6456
7119
  paymentDoneVC.chargeData = responseObject
6457
7120
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
6458
-
7121
+ paymentDoneVC.amount = self.amount
7122
+ // Pass billingInfo and additionalInfo
7123
+ if let billingData = self.request.billingInfoData,
7124
+ let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
7125
+
7126
+ // Extract main billing fields
7127
+ let cleanBillingInfo: [String: Any] = [
7128
+ "postal_code": billingInfoDict["postal_code"] ?? "",
7129
+ "country": billingInfoDict["country"] ?? "",
7130
+ "city": billingInfoDict["city"] ?? "",
7131
+ "address": billingInfoDict["address"] ?? "",
7132
+ "state": billingInfoDict["state"] ?? ""
7133
+ ]
7134
+ paymentDoneVC.billingInfo = cleanBillingInfo
7135
+
7136
+ // Extract additional_info
7137
+ if let additional = billingInfoDict["additional_info"] as? [String: Any] {
7138
+ let cleanAdditionalInfo: [String: Any] = [
7139
+ "email": additional["email"] ?? "",
7140
+ "phone_number": additional["phone_number"] ?? "",
7141
+ "name": additional["name"] ?? "",
7142
+ "country_code": additional["country_code"] ?? ""
7143
+ ]
7144
+ paymentDoneVC.additionalInfo = cleanAdditionalInfo
7145
+ }
7146
+ }
6459
7147
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
6460
7148
  }
6461
7149
  }
@@ -6531,20 +7219,6 @@ extension PaymentInfoVC: UICollectionViewDelegate, UICollectionViewDataSource, U
6531
7219
  }
6532
7220
  }
6533
7221
 
6534
- // // Update border color based on selection
6535
- // if selectedIndex == indexPath {
6536
- // if let primaryBackGroundColor = UserStoreSingleton.shared.primary_btn_bg_col,
6537
- // let uiColor = UIColor(hex: primaryBackGroundColor) {
6538
- // cell.vwMain.layer.borderColor = uiColor.cgColor // Convert UIColor to CGColor
6539
- // cell.imgVwPayments.tintColor = uiColor
6540
- // cell.lblPayment.textColor = uiColor
6541
- // }
6542
- // } else {
6543
- // cell.vwMain.layer.borderColor = UIColor.gray.cgColor
6544
- // cell.imgVwPayments.tintColor = .systemGray
6545
- // cell.lblPayment.textColor = .systemGray
6546
- // }
6547
-
6548
7222
  return cell
6549
7223
  }
6550
7224
 
@@ -6596,10 +7270,23 @@ extension PaymentInfoVC: UICollectionViewDelegate, UICollectionViewDataSource, U
6596
7270
  if UserStoreSingleton.shared.isLoggedIn == false {
6597
7271
  self.viewSingleSavedAccount.isHidden = true
6598
7272
  self.viewBankFields.isHidden = true
6599
- self.viewBtnShowSavedCards.isHidden = false
6600
- self.lblBtnShowSaveCard.text = "Show Saved Cards"
6601
- self.viewBtnShowSavedCardHeight.constant = 50
6602
- self.viewBtnShowSavedCardTopCon.constant = 20
7273
+ // self.viewBtnShowSavedCards.isHidden = false
7274
+ // self.lblBtnShowSaveCard.text = "Show Saved Cards"
7275
+ // self.viewBtnShowSavedCardHeight.constant = 50
7276
+ // self.viewBtnShowSavedCardTopCon.constant = 20
7277
+
7278
+ if request.saveCard == false {
7279
+ self.viewBtnShowSavedCards.isHidden = true
7280
+ self.viewBtnShowSavedCardHeight.constant = 0
7281
+ self.viewBtnShowSavedCardTopCon.constant = 0
7282
+ }
7283
+ else {
7284
+ self.viewBtnShowSavedCards.isHidden = false
7285
+ self.lblBtnShowSaveCard.text = "Show Saved Cards"
7286
+ self.viewBtnShowSavedCardHeight.constant = 50
7287
+ self.viewBtnShowSavedCardTopCon.constant = 20
7288
+ }
7289
+
6603
7290
  self.btnShowSavedCard.isHidden = false
6604
7291
  self.OTPView.isHidden = true
6605
7292
  self.emailView.isHidden = true
@@ -6669,10 +7356,23 @@ extension PaymentInfoVC: UICollectionViewDelegate, UICollectionViewDataSource, U
6669
7356
  case "Bank":
6670
7357
  if UserStoreSingleton.shared.isLoggedIn == false {
6671
7358
  // self.viewBankFields.isHidden = false
6672
- self.viewBtnShowSavedCards.isHidden = false
6673
- self.lblBtnShowSaveCard.text = "Show Saved Accounts"
6674
- self.viewBtnShowSavedCardHeight.constant = 50
6675
- self.viewBtnShowSavedCardTopCon.constant = 20
7359
+ // self.viewBtnShowSavedCards.isHidden = false
7360
+ // self.lblBtnShowSaveCard.text = "Show Saved Accounts"
7361
+ // self.viewBtnShowSavedCardHeight.constant = 50
7362
+ // self.viewBtnShowSavedCardTopCon.constant = 20
7363
+
7364
+ if request.saveAccount == false {
7365
+ self.viewBtnShowSavedCards.isHidden = true
7366
+ self.viewBtnShowSavedCardHeight.constant = 0
7367
+ self.viewBtnShowSavedCardTopCon.constant = 0
7368
+ }
7369
+ else {
7370
+ self.viewBtnShowSavedCards.isHidden = false
7371
+ self.lblBtnShowSaveCard.text = "Show Saved Cards"
7372
+ self.viewBtnShowSavedCardHeight.constant = 50
7373
+ self.viewBtnShowSavedCardTopCon.constant = 20
7374
+ }
7375
+
6676
7376
  self.OTPView.isHidden = true
6677
7377
  self.emailView.isHidden = true
6678
7378
  self.viewCardFields.isHidden = true
@@ -7481,6 +8181,13 @@ extension PaymentInfoVC: UITextFieldDelegate {
7481
8181
  } else {
7482
8182
  viewTxtFieldNameOnCard.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
7483
8183
  }
8184
+ } else if textField == txtFieldEmailCardView.textField {
8185
+ if let primaryBtnFontColor = UserStoreSingleton.shared.primary_btn_bg_col,
8186
+ let uiColor = UIColor(hex: primaryBtnFontColor) {
8187
+ viewTxtFieldEmailCardView.layer.borderColor = uiColor.cgColor
8188
+ } else {
8189
+ viewTxtFieldEmailCardView.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
8190
+ }
7484
8191
  }
7485
8192
  else if textField == txtFieldEmail {
7486
8193
  if let primaryBtnFontColor = UserStoreSingleton.shared.primary_btn_bg_col,
@@ -7598,6 +8305,14 @@ extension PaymentInfoVC: UITextFieldDelegate {
7598
8305
  viewTextFieldConfirmAccount.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
7599
8306
  }
7600
8307
  }
8308
+ else if textField == txtFieldEmailAccountView.textField {
8309
+ if let primaryBtnFontColor = UserStoreSingleton.shared.primary_btn_bg_col,
8310
+ let uiColor = UIColor(hex: primaryBtnFontColor) {
8311
+ viewTxtFieldEmailAccountView.layer.borderColor = uiColor.cgColor
8312
+ } else {
8313
+ viewTxtFieldEmailAccountView.layer.borderColor = UIColor._1757D9.withAlphaComponent(1).cgColor
8314
+ }
8315
+ }
7601
8316
  //New Bank Account View
7602
8317
  else if textField == txtFieldAccountNameNewAccountView {
7603
8318
  if let primaryBtnFontColor = UserStoreSingleton.shared.primary_btn_bg_col,
@@ -7674,6 +8389,14 @@ extension PaymentInfoVC: UITextFieldDelegate {
7674
8389
  viewTxtFieldNameOnCard.layer.borderColor = UIColor.systemGray.cgColor
7675
8390
  }
7676
8391
  }
8392
+ else if textField == txtFieldEmailCardView.textField {
8393
+ if let bodyBackgroundColor = UserStoreSingleton.shared.secondary_font_col,
8394
+ let borderColor = UIColor(hex: bodyBackgroundColor) {
8395
+ viewTxtFieldEmailCardView.layer.borderColor = borderColor.cgColor
8396
+ } else {
8397
+ viewTxtFieldEmailCardView.layer.borderColor = UIColor.systemGray.cgColor
8398
+ }
8399
+ }
7677
8400
  else if textField == txtFieldEmail {
7678
8401
  if let bodyBackgroundColor = UserStoreSingleton.shared.secondary_font_col,
7679
8402
  let borderColor = UIColor(hex: bodyBackgroundColor) {
@@ -7789,6 +8512,14 @@ extension PaymentInfoVC: UITextFieldDelegate {
7789
8512
  viewTextFieldConfirmAccount.layer.borderColor = UIColor.systemGray.cgColor
7790
8513
  }
7791
8514
  }
8515
+ else if textField == txtFieldEmailAccountView.textField {
8516
+ if let bodyBackgroundColor = UserStoreSingleton.shared.secondary_font_col,
8517
+ let borderColor = UIColor(hex: bodyBackgroundColor) {
8518
+ viewTxtFieldEmailAccountView.layer.borderColor = borderColor.cgColor
8519
+ } else {
8520
+ viewTxtFieldEmailAccountView.layer.borderColor = UIColor.systemGray.cgColor
8521
+ }
8522
+ }
7792
8523
  //New Bank Account View
7793
8524
  else if textField == txtFieldAccountNameNewAccountView {
7794
8525
  if let bodyBackgroundColor = UserStoreSingleton.shared.secondary_font_col,