@jimrising/easymerchantsdk-react-native 2.0.7 → 2.0.9

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 (121) hide show
  1. package/README.md +129 -1806
  2. package/android/build/.transforms/15b6a8a60a6b32d0dcaf609723cf365b/transformed/classes/classes_dex/classes.dex +0 -0
  3. package/android/build/.transforms/8508f1428f740032c45a43f48b1bbe1e/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule$1$1.dex +0 -0
  4. package/android/build/.transforms/8508f1428f740032c45a43f48b1bbe1e/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule$1.dex +0 -0
  5. package/android/build/.transforms/8508f1428f740032c45a43f48b1bbe1e/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule$2.dex +0 -0
  6. package/android/build/.transforms/8508f1428f740032c45a43f48b1bbe1e/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule.dex +0 -0
  7. package/android/build/.transforms/eef2d06269ef2e204b4f065513034fca/transformed/classes/classes_dex/classes.dex +0 -0
  8. package/android/build/.transforms/ffabb40f9809b32eb9546ce76fc51764/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/com/reactlibrary/RNEasymerchantsdkModule$1$1.dex +0 -0
  9. package/android/build/.transforms/ffabb40f9809b32eb9546ce76fc51764/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/com/reactlibrary/RNEasymerchantsdkModule$1.dex +0 -0
  10. package/android/build/.transforms/ffabb40f9809b32eb9546ce76fc51764/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/com/reactlibrary/RNEasymerchantsdkModule$2.dex +0 -0
  11. package/android/build/.transforms/ffabb40f9809b32eb9546ce76fc51764/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/com/reactlibrary/RNEasymerchantsdkModule.dex +0 -0
  12. package/android/build/intermediates/aar_main_jar/release/syncReleaseLibJars/classes.jar +0 -0
  13. package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
  14. package/android/build/intermediates/compile_library_classes_jar/release/bundleLibCompileToJarRelease/classes.jar +0 -0
  15. package/android/build/intermediates/full_jar/release/createFullJarRelease/full.jar +0 -0
  16. package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
  17. package/android/build/intermediates/incremental/lintVitalAnalyzeRelease/release-artifact-dependencies.xml +4 -4
  18. package/android/build/intermediates/incremental/lintVitalAnalyzeRelease/release-artifact-libraries.xml +4 -4
  19. package/android/build/intermediates/incremental/release/mergeReleaseResources/compile-file-map.properties +838 -838
  20. package/android/build/intermediates/incremental/release/mergeReleaseResources/merger.xml +3 -3
  21. package/android/build/intermediates/incremental/release/packageReleaseResources/compile-file-map.properties +1 -1
  22. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$1$1.class +0 -0
  23. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$1.class +0 -0
  24. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$2.class +0 -0
  25. package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
  26. package/android/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$1$1.class +0 -0
  27. package/android/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$1.class +0 -0
  28. package/android/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$2.class +0 -0
  29. package/android/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
  30. package/android/build/intermediates/lint-cache/lintVitalAnalyzeRelease/maven.google/androidx/core/group-index.xml +4 -3
  31. package/android/build/intermediates/lint-cache/lintVitalAnalyzeRelease/maven.google/androidx/lifecycle/group-index.xml +165 -165
  32. package/android/build/intermediates/lint-cache/lintVitalAnalyzeRelease/maven.google/com/android/tools/build/group-index.xml +15 -15
  33. package/android/build/intermediates/lint-cache/lintVitalAnalyzeRelease/sdk_index/snapshot.gz +0 -0
  34. package/android/build/intermediates/lint_model/release/generateReleaseLintModel/release-artifact-dependencies.xml +4 -4
  35. package/android/build/intermediates/lint_model/release/generateReleaseLintModel/release-artifact-libraries.xml +4 -4
  36. package/android/build/intermediates/lint_vital_lint_model/release/generateReleaseLintVitalModel/release-artifact-dependencies.xml +4 -4
  37. package/android/build/intermediates/lint_vital_lint_model/release/generateReleaseLintVitalModel/release-artifact-libraries.xml +4 -4
  38. package/android/build/intermediates/local_aar_for_lint/release/out.aar +0 -0
  39. package/android/build/intermediates/merged_res/release/mergeReleaseResources/layout/activity_card_addition_ifo.xml +1 -0
  40. package/android/build/intermediates/merged_res/release/mergeReleaseResources/layout/activity_card_billing_info.xml +1 -0
  41. package/android/build/intermediates/merged_res/release/mergeReleaseResources/layout/activity_card_scan.xml +1 -0
  42. package/android/build/intermediates/merged_res/release/mergeReleaseResources/layout/activity_payment_done.xml +1 -0
  43. package/android/build/intermediates/merged_res/release/mergeReleaseResources/layout/activity_payment_done_url.xml +1 -0
  44. package/android/build/intermediates/merged_res/release/mergeReleaseResources/layout/activity_payment_error.xml +1 -0
  45. package/android/build/intermediates/merged_res/release/mergeReleaseResources/layout/activity_select_payment_method.xml +1 -0
  46. package/android/build/intermediates/merged_res/release/mergeReleaseResources/layout/activity_verify_email.xml +1 -0
  47. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/multi-v2/values-night-v8.json +19 -19
  48. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/multi-v2/values.json +38 -38
  49. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/anim-v21.json +9 -9
  50. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/anim.json +24 -24
  51. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/animator-v21.json +1 -1
  52. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/animator.json +34 -34
  53. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/color-night-v8.json +3 -3
  54. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/color-v31.json +10 -10
  55. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/color.json +153 -153
  56. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-hdpi-v4.json +1 -1
  57. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-mdpi-v4.json +1 -1
  58. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-v21.json +3 -3
  59. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-v23.json +7 -7
  60. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-xhdpi-v4.json +1 -1
  61. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-xxhdpi-v4.json +1 -1
  62. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-xxxhdpi-v4.json +1 -1
  63. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable.json +391 -391
  64. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/font.json +9 -9
  65. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/interpolator-v21.json +10 -10
  66. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/interpolator.json +11 -11
  67. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/layout-land.json +3 -3
  68. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/layout-sw600dp-v13.json +2 -2
  69. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/layout-v26.json +1 -1
  70. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/layout.json +98 -98
  71. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-anydpi-v26.json +2 -2
  72. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-hdpi-v4.json +2 -2
  73. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-mdpi-v4.json +2 -2
  74. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-xhdpi-v4.json +2 -2
  75. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-xxhdpi-v4.json +2 -2
  76. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-xxxhdpi-v4.json +2 -2
  77. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/raw.json +46 -46
  78. package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/xml.json +3 -3
  79. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule$1$1.class +0 -0
  80. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule$1.class +0 -0
  81. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule$2.class +0 -0
  82. package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
  83. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/com/reactlibrary/RNEasymerchantsdkModule$1$1.class +0 -0
  84. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/com/reactlibrary/RNEasymerchantsdkModule$1.class +0 -0
  85. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/com/reactlibrary/RNEasymerchantsdkModule$2.class +0 -0
  86. package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
  87. package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
  88. package/android/build/intermediates/runtime_library_classes_jar/release/bundleLibRuntimeToJarRelease/classes.jar +0 -0
  89. package/android/build/intermediates/source_set_path_map/release/mapReleaseSourceSetPaths/file-map.txt +24 -24
  90. package/android/build/intermediates/verified_library_resources/release/verifyReleaseResources/compiled/layout_activity_card_addition_ifo.xml.flat +0 -0
  91. package/android/build/intermediates/verified_library_resources/release/verifyReleaseResources/compiled/layout_activity_card_billing_info.xml.flat +0 -0
  92. package/android/build/intermediates/verified_library_resources/release/verifyReleaseResources/compiled/layout_activity_card_scan.xml.flat +0 -0
  93. package/android/build/intermediates/verified_library_resources/release/verifyReleaseResources/compiled/layout_activity_payment_done.xml.flat +0 -0
  94. package/android/build/intermediates/verified_library_resources/release/verifyReleaseResources/compiled/layout_activity_payment_done_url.xml.flat +0 -0
  95. package/android/build/intermediates/verified_library_resources/release/verifyReleaseResources/compiled/layout_activity_payment_error.xml.flat +0 -0
  96. package/android/build/intermediates/verified_library_resources/release/verifyReleaseResources/compiled/layout_activity_select_payment_method.xml.flat +0 -0
  97. package/android/build/intermediates/verified_library_resources/release/verifyReleaseResources/compiled/layout_activity_verify_email.xml.flat +0 -0
  98. package/android/build/outputs/aar/jimrising_easymerchantsdk-react-native-release.aar +0 -0
  99. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule$1$1.class.uniqueId1 +0 -0
  100. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule$1.class.uniqueId0 +0 -0
  101. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule$2.class.uniqueId3 +0 -0
  102. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule.class.uniqueId2 +0 -0
  103. package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkPackage.class.uniqueId4 +0 -0
  104. package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
  105. package/android/build/tmp/compileReleaseJavaWithJavac/previous-compilation-data.bin +0 -0
  106. package/android/build.gradle +1 -1
  107. package/android/src/main/java/com/reactlibrary/RNEasymerchantsdkModule.java +93 -26
  108. package/ios/Classes/EasyMerchantSdk.m +4 -4
  109. package/ios/Classes/EasyMerchantSdk.swift +116 -60
  110. package/ios/Classes/EasyPayViewController.swift +3 -5
  111. package/ios/CustomComponents/CheckboxButton.swift +66 -0
  112. package/ios/Helper/GrailPayHelper.swift +1 -0
  113. package/ios/Models/Request.swift +8 -8
  114. package/ios/Pods/ViewControllers/AdditionalInfoVC.swift +233 -97
  115. package/ios/Pods/ViewControllers/BillingInfoVC/BillingInfoVC.swift +376 -104
  116. package/ios/Pods/ViewControllers/OTPVerificationVC.swift +28 -27
  117. package/ios/Pods/ViewControllers/PaymentErrorVC.swift +22 -25
  118. package/ios/Pods/ViewControllers/PaymentInformation/PaymentInfoVC.swift +575 -190
  119. package/ios/easymerchantsdk.podspec +1 -1
  120. package/ios/easymerchantsdk.storyboard +15 -15
  121. package/package.json +1 -1
@@ -423,6 +423,9 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
423
423
  self.request?.paymentIntentApi { success in
424
424
  if success {
425
425
  print("Payment Intent completed")
426
+ DispatchQueue.main.async {
427
+ self.lblEasyMerchantOne.text = "POWERED BY \(UserStoreSingleton.shared.companyName?.uppercased() ?? "")"
428
+ }
426
429
  // Continue flow
427
430
  } else {
428
431
  print("Payment Intent failed")
@@ -449,7 +452,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
449
452
  tapGesture.cancelsTouchesInView = false
450
453
  self.view.addGestureRecognizer(tapGesture)
451
454
 
452
- if let billingInfoData = request.billingInfoData,
455
+ if let billingInfoData = request.fields,
453
456
  let fieldSection = try? JSONDecoder().decode(FieldSection.self, from: billingInfoData) {
454
457
 
455
458
  let billingVisible = fieldSection.visibility.billing
@@ -610,7 +613,6 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
610
613
  }
611
614
  }
612
615
 
613
- print(request.metadata ?? "")
614
616
  }
615
617
 
616
618
  //MARK: - View Wiil Appear
@@ -847,11 +849,12 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
847
849
 
848
850
  if isFrom == "NewAccount" {
849
851
  viewNewBankAccount.isHidden = false
850
- } else {
851
- viewSingleSavedAccount.isHidden = false
852
852
  }
853
+ // else {
854
+ // viewSingleSavedAccount.isHidden = false
855
+ // }
853
856
 
854
- self.viewSingleSavedAccount.isHidden = false
857
+ // self.viewSingleSavedAccount.isHidden = false
855
858
  self.viewBankFields.isHidden = true
856
859
  self.viewBtnShowSavedCards.isHidden = true
857
860
  self.viewBtnShowSavedCardHeight.constant = 0
@@ -914,7 +917,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
914
917
  self.grailPayBankLinkView.isHidden = true
915
918
  self.viewSingleSavedAccount.isHidden = true
916
919
  }
917
- // self.grailPayBankLinkView.isHidden = false
920
+ // self.grailPayBankLinkView.isHidden = false
918
921
  self.btnNext.isHidden = true
919
922
  self.btnNextHeight.constant = 0
920
923
  self.btnNextTopCon.constant = 0
@@ -938,12 +941,12 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
938
941
  self.viewBtnShowSavedCardHeight.constant = 0
939
942
  self.viewBtnShowSavedCardTopCon.constant = 0
940
943
  }
941
- else {
942
- self.viewBtnShowSavedCards.isHidden = false
943
- self.lblBtnShowSaveCard.text = "Show Saved Accounts"
944
- self.viewBtnShowSavedCardHeight.constant = 50
945
- self.viewBtnShowSavedCardTopCon.constant = 20
946
- }
944
+ // else {
945
+ // self.viewBtnShowSavedCards.isHidden = false
946
+ // self.lblBtnShowSaveCard.text = "Show Saved Accounts"
947
+ // self.viewBtnShowSavedCardHeight.constant = 50
948
+ // self.viewBtnShowSavedCardTopCon.constant = 20
949
+ // }
947
950
 
948
951
  self.OTPView.isHidden = true
949
952
  self.emailView.isHidden = true
@@ -1891,8 +1894,13 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
1891
1894
  UserStoreSingleton.shared.clearUserData()
1892
1895
  UserStoreSingleton.shared.isLoggedIn = false
1893
1896
 
1894
- // Notify delegate about cancellation with custom message
1895
- let result = SDKResult(type: .cancelled, chargeData: ["message": "You’ve exited the payment screen. No transaction was made."])
1897
+ // Directly send as dictionary like in Android
1898
+ let cancelData: [String: Any] = [
1899
+ "status": false,
1900
+ "message": "User cancelled the payment."
1901
+ ]
1902
+
1903
+ let result = SDKResult(type: .cancelled, chargeData: cancelData)
1896
1904
  self.delegate?.easyPayController(self.navigationController as! EasyPayViewController, didFinishWith: result)
1897
1905
 
1898
1906
  self.dismiss(animated: true)
@@ -1997,7 +2005,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
1997
2005
 
1998
2006
  @IBAction func actionBtnPayNowSingleSavedCard(_ sender: UIButton) {
1999
2007
  // Check if billingInfoData is not nil or empty
2000
- if let billingInfoData = request.billingInfoData,
2008
+ if let billingInfoData = request.fields,
2001
2009
  let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
2002
2010
  let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
2003
2011
  print("Billing Info Data: \(jsonDict)")
@@ -2048,7 +2056,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
2048
2056
  billingInfoVC.amount = Double(self.request.amount ?? 0)
2049
2057
  billingInfoVC.selectedPaymentMethod = self.selectedPaymentMethod
2050
2058
 
2051
- if let billingInfoData = self.request.billingInfoData {
2059
+ if let billingInfoData = self.request.fields {
2052
2060
  billingInfoVC.billingInfoData = billingInfoData
2053
2061
  }
2054
2062
 
@@ -2072,7 +2080,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
2072
2080
  additionalInfoVC.amount = Double(self.request.amount ?? 0)
2073
2081
  additionalInfoVC.selectedPaymentMethod = self.selectedPaymentMethod
2074
2082
 
2075
- if let billingInfoData = self.request.billingInfoData {
2083
+ if let billingInfoData = self.request.fields {
2076
2084
  additionalInfoVC.billingInfoData = billingInfoData
2077
2085
  }
2078
2086
 
@@ -2165,7 +2173,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
2165
2173
  @IBAction func actionBtnPayNowNewCardView(_ sender: UIButton) {
2166
2174
  if UserStoreSingleton.shared.isLoggedIn == true {
2167
2175
  //if billing info is availbale
2168
- if let billingInfoData = request.billingInfoData,
2176
+ if let billingInfoData = request.fields,
2169
2177
  let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
2170
2178
  let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
2171
2179
  print("Billing Info Data: \(jsonDict)")
@@ -2261,7 +2269,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
2261
2269
  billingInfoVC.amount = Double(self.request.amount ?? 0)
2262
2270
  billingInfoVC.selectedPaymentMethod = self.selectedPaymentMethod
2263
2271
 
2264
- if let billingInfoData = self.request.billingInfoData {
2272
+ if let billingInfoData = self.request.fields {
2265
2273
  billingInfoVC.billingInfoData = billingInfoData
2266
2274
  }
2267
2275
 
@@ -2288,7 +2296,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
2288
2296
  additionalInfoVC.amount = Double(self.request.amount ?? 0)
2289
2297
  additionalInfoVC.selectedPaymentMethod = self.selectedPaymentMethod
2290
2298
 
2291
- if let billingInfoData = self.request.billingInfoData {
2299
+ if let billingInfoData = self.request.fields {
2292
2300
  additionalInfoVC.billingInfoData = billingInfoData
2293
2301
  }
2294
2302
 
@@ -2757,13 +2765,13 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
2757
2765
 
2758
2766
  if isSavedForFuture {
2759
2767
  //If billing info is available
2760
- if let billingInfoData = request.billingInfoData {
2768
+ if let billingInfoData = request.fields {
2761
2769
  do {
2762
2770
  let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
2763
2771
 
2764
2772
  DispatchQueue.main.async {
2765
2773
 
2766
- if let billingInfoData = self.request.billingInfoData,
2774
+ if let billingInfoData = self.request.fields,
2767
2775
  let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
2768
2776
  let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
2769
2777
  print("Billing Info Data: \(jsonDict)")
@@ -2772,26 +2780,31 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
2772
2780
  let showAdditional = fieldSection.visibility.additional
2773
2781
 
2774
2782
  if !showBilling && !showAdditional {
2775
- // Navigate directly to EmailVerificationVC
2776
- // let vc = easymerchantsdk.instantiateViewController(withIdentifier: "EmailVerificationVC") as! EmailVerificationVC
2777
- let vc = easymerchantsdk.instantiateViewController(withIdentifier: "OTPVerificationVC") as! OTPVerificationVC
2778
- vc.easyPayDelegate = self.easyPayDelegate
2779
- vc.grailPayAccountID = self.grailPayAccountID
2780
- vc.selectedGrailPayAccountType = self.selectedGrailPayAccountType
2781
- vc.selectedGrailPayAccountName = self.selectedGrailPayAccountName
2782
- vc.chosenPlan = self.txtFieldChosePlanGrailPayBankView.text
2783
- vc.startDate = self.txtFieldSelectDateGrailPayBankView.text
2784
- vc.request = self.request
2785
- vc.isSavedForFuture = self.isSavedForFuture
2786
- vc.selectedPaymentMethod = "GrailPay"
2787
- vc.userEmail = self.txtFieldEmailGrailPayView.text
2788
- vc.billingInfoData = billingInfoData // Send the data even if not shown
2789
- vc.billingInfo = fieldSection.billing
2790
- vc.additionalInfo = fieldSection.additional
2791
- vc.visibility = fieldSection.visibility
2792
- vc.amount = self.amount
2793
- vc.email = self.txtFieldEmailGrailPayView.text
2794
- self.navigationController?.pushViewController(vc, animated: true)
2783
+ if UserStoreSingleton.shared.isLoggedIn == true {
2784
+ self.grailPayAccountChargeWithSaveApi()
2785
+ }
2786
+ else {
2787
+ // Navigate directly to EmailVerificationVC
2788
+ // let vc = easymerchantsdk.instantiateViewController(withIdentifier: "EmailVerificationVC") as! EmailVerificationVC
2789
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "OTPVerificationVC") as! OTPVerificationVC
2790
+ vc.easyPayDelegate = self.easyPayDelegate
2791
+ vc.grailPayAccountID = self.grailPayAccountID
2792
+ vc.selectedGrailPayAccountType = self.selectedGrailPayAccountType
2793
+ vc.selectedGrailPayAccountName = self.selectedGrailPayAccountName
2794
+ vc.chosenPlan = self.txtFieldChosePlanGrailPayBankView.text
2795
+ vc.startDate = self.txtFieldSelectDateGrailPayBankView.text
2796
+ vc.request = self.request
2797
+ vc.isSavedForFuture = self.isSavedForFuture
2798
+ vc.selectedPaymentMethod = "GrailPay"
2799
+ vc.userEmail = self.txtFieldEmailGrailPayView.text
2800
+ vc.billingInfoData = billingInfoData // Send the data even if not shown
2801
+ vc.billingInfo = fieldSection.billing
2802
+ vc.additionalInfo = fieldSection.additional
2803
+ vc.visibility = fieldSection.visibility
2804
+ vc.amount = self.amount
2805
+ vc.email = self.txtFieldEmailGrailPayView.text
2806
+ self.navigationController?.pushViewController(vc, animated: true)
2807
+ }
2795
2808
  }
2796
2809
  else if showBilling {
2797
2810
  // Push to BillingInfoVC
@@ -2842,31 +2855,35 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
2842
2855
  }
2843
2856
  else {
2844
2857
  //If billing info is nil
2845
- // Navigate to EmailVerificationVC directly
2846
- // let vc = easymerchantsdk.instantiateViewController(withIdentifier: "EmailVerificationVC") as! EmailVerificationVC
2847
- let vc = easymerchantsdk.instantiateViewController(withIdentifier: "OTPVerificationVC") as! OTPVerificationVC
2848
- vc.easyPayDelegate = self.easyPayDelegate
2849
- vc.grailPayAccountID = self.grailPayAccountID
2850
- vc.selectedGrailPayAccountType = self.selectedGrailPayAccountType
2851
- vc.selectedGrailPayAccountName = self.selectedGrailPayAccountName
2852
- vc.chosenPlan = self.txtFieldChosePlanGrailPayBankView.text
2853
- vc.startDate = self.txtFieldSelectDateGrailPayBankView.text
2854
- vc.request = self.request
2855
- vc.isSavedForFuture = self.isSavedForFuture
2856
- vc.selectedPaymentMethod = "GrailPay"
2857
- vc.email = self.txtFieldEmailGrailPayView.text
2858
- vc.amount = self.amount
2859
- self.navigationController?.pushViewController(vc, animated: true)
2858
+ if UserStoreSingleton.shared.isLoggedIn == true {
2859
+ grailPayAccountChargeWithSaveApi()
2860
+ } else {
2861
+ // Navigate to EmailVerificationVC directly
2862
+ // let vc = easymerchantsdk.instantiateViewController(withIdentifier: "EmailVerificationVC") as! EmailVerificationVC
2863
+ let vc = easymerchantsdk.instantiateViewController(withIdentifier: "OTPVerificationVC") as! OTPVerificationVC
2864
+ vc.easyPayDelegate = self.easyPayDelegate
2865
+ vc.grailPayAccountID = self.grailPayAccountID
2866
+ vc.selectedGrailPayAccountType = self.selectedGrailPayAccountType
2867
+ vc.selectedGrailPayAccountName = self.selectedGrailPayAccountName
2868
+ vc.chosenPlan = self.txtFieldChosePlanGrailPayBankView.text
2869
+ vc.startDate = self.txtFieldSelectDateGrailPayBankView.text
2870
+ vc.request = self.request
2871
+ vc.isSavedForFuture = self.isSavedForFuture
2872
+ vc.selectedPaymentMethod = "GrailPay"
2873
+ vc.email = self.txtFieldEmailGrailPayView.text
2874
+ vc.amount = self.amount
2875
+ self.navigationController?.pushViewController(vc, animated: true)
2876
+ }
2860
2877
  }
2861
2878
  } else {
2862
2879
  // Check if billing info data exists and is valid JSON without save
2863
- if let billingInfoData = request.billingInfoData {
2880
+ if let billingInfoData = request.fields {
2864
2881
  do {
2865
2882
  let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
2866
2883
 
2867
2884
  DispatchQueue.main.async {
2868
2885
 
2869
- if let billingInfoData = self.request.billingInfoData,
2886
+ if let billingInfoData = self.request.fields,
2870
2887
  let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
2871
2888
  let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
2872
2889
  print("Billing Info Data: \(jsonDict)")
@@ -2960,13 +2977,13 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
2960
2977
 
2961
2978
  if isSavedForFuture {
2962
2979
  //If billing info is available
2963
- if let billingInfoData = request.billingInfoData {
2980
+ if let billingInfoData = request.fields {
2964
2981
  do {
2965
2982
  let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
2966
2983
 
2967
2984
  DispatchQueue.main.async {
2968
2985
 
2969
- if let billingInfoData = self.request.billingInfoData,
2986
+ if let billingInfoData = self.request.fields,
2970
2987
  let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
2971
2988
  let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
2972
2989
  print("Billing Info Data: \(jsonDict)")
@@ -3025,13 +3042,13 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3025
3042
  }
3026
3043
  else {
3027
3044
  // Check if billing info data exists and is valid JSON without save
3028
- if let billingInfoData = request.billingInfoData {
3045
+ if let billingInfoData = request.fields {
3029
3046
  do {
3030
3047
  let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
3031
3048
 
3032
3049
  DispatchQueue.main.async {
3033
3050
 
3034
- if let billingInfoData = self.request.billingInfoData,
3051
+ if let billingInfoData = self.request.fields,
3035
3052
  let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
3036
3053
  let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
3037
3054
  print("Billing Info Data: \(jsonDict)")
@@ -3199,6 +3216,9 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3199
3216
 
3200
3217
  if self.selectedPaymentMethod == "Bank" {
3201
3218
  self.viewBtnShowSavedCards.isHidden = true
3219
+ self.btnShowSavedCard.isHidden = true
3220
+ self.viewBtnShowSavedCardHeight.constant = 0
3221
+ self.viewBtnShowSavedCardTopCon.constant = 0
3202
3222
  }
3203
3223
 
3204
3224
  let amountText = String(format: "$%.2f", self.request.amount ?? 0)
@@ -3299,7 +3319,237 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3299
3319
  "email": txtFieldEmailGrailPayView.text
3300
3320
  ]
3301
3321
 
3302
- if let billingInfoData = request.billingInfoData {
3322
+ if let billingInfoData = request.fields {
3323
+ do {
3324
+ let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
3325
+
3326
+ // Billing Info
3327
+ let billing = fieldSection.billing
3328
+ if !billing.isEmpty {
3329
+ var billingDict: [String: Any] = [:]
3330
+ billing.forEach { billingDict[$0.name] = $0.value }
3331
+
3332
+ if let address = billingDict["address"] as? String, !address.isEmpty {
3333
+ params["address"] = address
3334
+ }
3335
+ if let country = billingDict["country"] as? String, !country.isEmpty {
3336
+ params["country"] = country
3337
+ }
3338
+ if let state = billingDict["state"] as? String, !state.isEmpty {
3339
+ params["state"] = state
3340
+ }
3341
+ if let city = billingDict["city"] as? String, !city.isEmpty {
3342
+ params["city"] = city
3343
+ }
3344
+ if let postalCode = billingDict["postal_code"] as? String, !postalCode.isEmpty {
3345
+ params["zip"] = postalCode
3346
+ }
3347
+ }
3348
+
3349
+ // Additional Info
3350
+ let additional = fieldSection.additional
3351
+ if !additional.isEmpty {
3352
+ var additionalDict: [String: Any] = [:]
3353
+ additional.forEach { additionalDict[$0.name] = $0.value }
3354
+
3355
+ if let desc = additionalDict["description"] as? String, !desc.isEmpty {
3356
+ params["description"] = desc
3357
+ } else {
3358
+ params["description"] = "Hosted payment checkout"
3359
+ }
3360
+
3361
+ if let phone = additionalDict["phone_number"] as? String, !phone.isEmpty {
3362
+ params["phone_number"] = phone
3363
+ }
3364
+ if let email = additionalDict["email"] as? String, !email.isEmpty {
3365
+ params["email"] = email
3366
+ }
3367
+ if let name = additionalDict["name"] as? String, !name.isEmpty {
3368
+ params["name"] = name
3369
+ }
3370
+ } else {
3371
+ // If no description in additional info, set default
3372
+ params["description"] = "Hosted payment checkout"
3373
+ }
3374
+
3375
+ } catch {
3376
+ print("Failed to decode FieldSection: \(error)")
3377
+ params["description"] = "Hosted payment checkout"
3378
+ }
3379
+ } else {
3380
+ // Fallback if billingInfoData is missing
3381
+ params["description"] = "Hosted payment checkout"
3382
+ }
3383
+
3384
+ // Add these if recurring is enabled
3385
+ if let req = request, req.is_recurring == true {
3386
+ if let recurringType = req.recurringStartDateType, recurringType == .custom {
3387
+ // Only send start_date if type is .custom and field is not empty
3388
+ if let startDateText = txtFieldSelectDateGrailPayBankView?.text, !startDateText.isEmpty {
3389
+ let inputFormatter = DateFormatter()
3390
+ inputFormatter.dateFormat = "dd/MM/yyyy"
3391
+
3392
+ let outputFormatter = DateFormatter()
3393
+ outputFormatter.dateFormat = "MM/dd/yyyy"
3394
+
3395
+ if let date = inputFormatter.date(from: startDateText) {
3396
+ let apiFormattedDate = outputFormatter.string(from: date)
3397
+ params["start_date"] = apiFormattedDate
3398
+ } else {
3399
+ print("Invalid date format in startDateText")
3400
+ }
3401
+ }
3402
+ }
3403
+
3404
+ params["interval"] = txtFieldChosePlanGrailPayBankView.text.lowercased()
3405
+ }
3406
+
3407
+ // ✅ Include metadata only if it has at least 1 key-value pair
3408
+ if let metadata = request?.metadata, !metadata.isEmpty {
3409
+ params["metadata"] = metadata
3410
+ }
3411
+
3412
+ print(params)
3413
+
3414
+ do {
3415
+ let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
3416
+ uRLRequest.httpBody = jsonData
3417
+ if let jsonString = String(data: jsonData, encoding: .utf8) {
3418
+ print("JSON Payload: \(jsonString)")
3419
+ }
3420
+ } catch let error {
3421
+ print("Error creating JSON data: \(error)")
3422
+ hideLoadingIndicator()
3423
+ return
3424
+ }
3425
+
3426
+ let session = URLSession.shared
3427
+ let task = session.dataTask(with: uRLRequest) { (serviceData, serviceResponse, error) in
3428
+
3429
+ DispatchQueue.main.async {
3430
+ self.hideLoadingIndicator() // Stop loader when response is received
3431
+ }
3432
+
3433
+ if let error = error {
3434
+ print("Error: \(error.localizedDescription)")
3435
+ return
3436
+ }
3437
+
3438
+ guard let httpResponse = serviceResponse as? HTTPURLResponse else {
3439
+ print("Invalid response")
3440
+ return
3441
+ }
3442
+
3443
+ if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
3444
+ if let data = serviceData {
3445
+ do {
3446
+ if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
3447
+ print("Response Data: \(responseObject)")
3448
+
3449
+ // Check if status is 0 and handle the error
3450
+ if let status = responseObject["status"] as? Int, status == 0 {
3451
+ let errorMessage = responseObject["message"] as? String ?? "Unknown error"
3452
+ self.presentPaymentErrorVC(errorMessage: errorMessage)
3453
+ } else {
3454
+ DispatchQueue.main.async {
3455
+ if let paymentDoneVC = self.storyboard?.instantiateViewController(withIdentifier: "PaymentDoneVC") as? PaymentDoneVC {
3456
+ paymentDoneVC.chargeData = responseObject
3457
+ // Pass the selected payment method
3458
+ paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
3459
+ paymentDoneVC.easyPayDelegate = self.easyPayDelegate
3460
+ paymentDoneVC.request = self.request
3461
+ // Pass billing info and additional info if available
3462
+ if let billingInfoData = self.request.fields,
3463
+ let fieldSection = try? JSONDecoder().decode(FieldSection.self, from: billingInfoData) {
3464
+
3465
+ paymentDoneVC.billingInfoData = fieldSection.billing
3466
+ var billingDict: [String: Any] = [:]
3467
+ fieldSection.billing.forEach { billingDict[$0.name] = $0.value }
3468
+ paymentDoneVC.billingInfo = billingDict
3469
+
3470
+ paymentDoneVC.additionalInfoData = fieldSection.additional
3471
+ var additionalDict: [String: Any] = [:]
3472
+ fieldSection.additional.forEach { additionalDict[$0.name] = $0.value }
3473
+ paymentDoneVC.additionalInfo = additionalDict
3474
+ }
3475
+ self.navigationController?.pushViewController(paymentDoneVC, animated: true)
3476
+ }
3477
+ }
3478
+ }
3479
+ } else {
3480
+ self.presentPaymentErrorVC(errorMessage: "Invalid JSON format")
3481
+ }
3482
+ } catch let jsonError {
3483
+ self.presentPaymentErrorVC(errorMessage: "Error parsing JSON: \(jsonError)")
3484
+ }
3485
+ } else {
3486
+ self.presentPaymentErrorVC(errorMessage: "No data received")
3487
+ }
3488
+ } else {
3489
+ if let data = serviceData,
3490
+ let responseObj = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
3491
+ let message = responseObj["message"] as? String {
3492
+ self.presentPaymentErrorVC(errorMessage: message)
3493
+ } else {
3494
+ self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
3495
+ }
3496
+ }
3497
+ }
3498
+ task.resume()
3499
+ }
3500
+
3501
+ //MARK: - Grail Pay Banking Payment Charge Api with saving bank and with Login
3502
+ func grailPayAccountChargeWithSaveApi() {
3503
+ showLoadingIndicator()
3504
+ let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.achCharge.path()
3505
+
3506
+ guard let serviceURL = URL(string: fullURL) else {
3507
+ print("Invalid URL")
3508
+ hideLoadingIndicator()
3509
+ return
3510
+ }
3511
+
3512
+ var uRLRequest = URLRequest(url: serviceURL)
3513
+ uRLRequest.httpMethod = "POST"
3514
+ uRLRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
3515
+
3516
+ let token = UserStoreSingleton.shared.clientToken
3517
+ print("Setting clientToken header: \(token ?? "None")")
3518
+ uRLRequest.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
3519
+
3520
+ if let apiKey = EnvironmentConfig.apiKey {
3521
+ uRLRequest.addValue(apiKey, forHTTPHeaderField: "X-Api-Key")
3522
+ }
3523
+ if let apiSecret = EnvironmentConfig.apiSecret {
3524
+ uRLRequest.addValue(apiSecret, forHTTPHeaderField: "X-Api-Secret")
3525
+ }
3526
+
3527
+ let emailText = txtFieldEmailGrailPayView.text
3528
+ let emailPrefix = emailText.components(separatedBy: "@").first ?? ""
3529
+
3530
+ var params: [String: Any] = [
3531
+ "account_id": self.grailPayAccountID ?? "",
3532
+ "account_type": self.selectedGrailPayAccountType ?? "",
3533
+ "name": self.selectedGrailPayAccountName ?? "",
3534
+ "description": "payment checkout",
3535
+ "email": txtFieldEmailGrailPayView.text,
3536
+ "save_account": 1,
3537
+ "is_default": 1,
3538
+ "customer_id": UserStoreSingleton.shared.customerId ?? "",
3539
+ "create_customer": "1",
3540
+ ]
3541
+
3542
+ if let customerId = UserStoreSingleton.shared.customerId {
3543
+ params["customer"] = customerId
3544
+ } else {
3545
+ params["username"] = emailPrefix
3546
+ }
3547
+
3548
+ if UserStoreSingleton.shared.customerId == nil {
3549
+ params["create_customer"] = "1"
3550
+ }
3551
+
3552
+ if let billingInfoData = request.fields {
3303
3553
  do {
3304
3554
  let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
3305
3555
 
@@ -3384,6 +3634,12 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3384
3634
  params["interval"] = txtFieldChosePlanGrailPayBankView.text.lowercased()
3385
3635
  }
3386
3636
 
3637
+ // ✅ Include metadata only if it has at least 1 key-value pair
3638
+ if let metadata = request?.metadata, !metadata.isEmpty {
3639
+ params["metadata"] = metadata
3640
+ }
3641
+
3642
+
3387
3643
  print(params)
3388
3644
 
3389
3645
  do {
@@ -3434,7 +3690,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3434
3690
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
3435
3691
  paymentDoneVC.request = self.request
3436
3692
  // Pass billing info and additional info if available
3437
- if let billingInfoData = self.request.billingInfoData,
3693
+ if let billingInfoData = self.request.fields,
3438
3694
  let fieldSection = try? JSONDecoder().decode(FieldSection.self, from: billingInfoData) {
3439
3695
 
3440
3696
  paymentDoneVC.billingInfoData = fieldSection.billing
@@ -3514,7 +3770,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3514
3770
  params["is_default"] = 1
3515
3771
  }
3516
3772
 
3517
- if let billingInfoData = request.billingInfoData {
3773
+ if let billingInfoData = request.fields {
3518
3774
  do {
3519
3775
  let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
3520
3776
 
@@ -3599,6 +3855,11 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3599
3855
  params["interval"] = txtFieldChosePlanNewGrailPayBankView.text.lowercased()
3600
3856
  }
3601
3857
 
3858
+ // ✅ Include metadata only if it has at least 1 key-value pair
3859
+ if let metadata = request?.metadata, !metadata.isEmpty {
3860
+ params["metadata"] = metadata
3861
+ }
3862
+
3602
3863
  print(params)
3603
3864
 
3604
3865
  do {
@@ -3650,7 +3911,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3650
3911
  paymentDoneVC.request = self.request
3651
3912
 
3652
3913
  // Pass billing info and additional info if available
3653
- if let billingInfoData = self.request.billingInfoData,
3914
+ if let billingInfoData = self.request.fields,
3654
3915
  let fieldSection = try? JSONDecoder().decode(FieldSection.self, from: billingInfoData) {
3655
3916
 
3656
3917
  paymentDoneVC.billingInfoData = fieldSection.billing
@@ -3724,7 +3985,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3724
3985
  "email": UserStoreSingleton.shared.verificationEmail ?? "",
3725
3986
  ]
3726
3987
 
3727
- if let billingInfoData = request.billingInfoData {
3988
+ if let billingInfoData = request.fields {
3728
3989
  do {
3729
3990
  let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
3730
3991
 
@@ -3809,6 +4070,11 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3809
4070
  params["interval"] = txtFieldSelectPlanSingleSavedBankView.text.lowercased()
3810
4071
  }
3811
4072
 
4073
+ // ✅ Include metadata only if it has at least 1 key-value pair
4074
+ if let metadata = request?.metadata, !metadata.isEmpty {
4075
+ params["metadata"] = metadata
4076
+ }
4077
+
3812
4078
  print(params)
3813
4079
 
3814
4080
  do {
@@ -3860,7 +4126,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3860
4126
  paymentDoneVC.request = self.request
3861
4127
 
3862
4128
  // Pass billing info and additional info if available
3863
- if let billingInfoData = self.request.billingInfoData,
4129
+ if let billingInfoData = self.request.fields,
3864
4130
  let fieldSection = try? JSONDecoder().decode(FieldSection.self, from: billingInfoData) {
3865
4131
 
3866
4132
  paymentDoneVC.billingInfoData = fieldSection.billing
@@ -3933,7 +4199,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
3933
4199
  // MARK: - Action Button Next
3934
4200
  @IBAction func actionBtnNext(_ sender: UIButton) {
3935
4201
  // Check if billing info data exists and is valid JSON
3936
- if let billingInfoData = request.billingInfoData {
4202
+ if let billingInfoData = request.fields {
3937
4203
  do {
3938
4204
  let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
3939
4205
 
@@ -4019,7 +4285,15 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
4019
4285
 
4020
4286
  if !showBilling && !showAdditional {
4021
4287
  if self.isSavedForFuture {
4022
- self.navigateCardDataToEmailVerificationVC()
4288
+ if UserStoreSingleton.shared.isLoggedIn == true {
4289
+ if self.request.secureAuthentication == true {
4290
+ self.threeDSecurePaymentApi()
4291
+ } else {
4292
+ self.paymentIntentCardApi()
4293
+ }
4294
+ } else {
4295
+ self.navigateCardDataToEmailVerificationVC()
4296
+ }
4023
4297
  } else {
4024
4298
  if self.request.secureAuthentication == true {
4025
4299
  self.threeDSecurePaymentApi()
@@ -4134,7 +4408,11 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
4134
4408
 
4135
4409
  if !showBilling && !showAdditional {
4136
4410
  if self.isSavedForFuture {
4137
- self.navigateBankDataToEmailVerificationVC()
4411
+ if UserStoreSingleton.shared.isLoggedIn == true {
4412
+ self.accountBankChargeApi()
4413
+ } else {
4414
+ self.navigateBankDataToEmailVerificationVC()
4415
+ }
4138
4416
  } else {
4139
4417
  self.accountBankChargeApi()
4140
4418
  }
@@ -4287,21 +4565,29 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
4287
4565
 
4288
4566
  // Navigate to EmailVerificationVC if isSavedForFuture is true, else call paymentIntentApi
4289
4567
  if isSavedForFuture {
4290
- if let vc = storyboard?.instantiateViewController(withIdentifier: "OTPVerificationVC") as? OTPVerificationVC {
4291
- vc.cardNumber = self.cardNumberTextField.text
4292
- vc.expiryDate = self.cardExpiryTextField.text
4293
- vc.cvv = self.cardCvvTextField.text
4294
- vc.nameOnCard = self.cardNameTextField.text
4295
- vc.selectedPaymentMethod = self.selectedPaymentMethod
4296
- vc.isSavedForFuture = isSavedForFuture
4297
- vc.easyPayDelegate = self.easyPayDelegate // Pass delegate if needed
4298
- vc.request = self.request
4299
- vc.chosenPlan = self.txtFieldChosePlanCard.text
4300
- vc.startDate = self.txtFieldStartDateCard.text
4301
- vc.userEmail = self.txtFieldEmailCardView.text
4302
- vc.email = self.txtFieldEmailCardView.text
4303
- vc.amount = self.amount
4304
- self.navigationController?.pushViewController(vc, animated: true)
4568
+ if UserStoreSingleton.shared.isLoggedIn == true {
4569
+ if request.secureAuthentication == true {
4570
+ threeDSecurePaymentApi()
4571
+ } else {
4572
+ paymentIntentApi()
4573
+ }
4574
+ } else {
4575
+ if let vc = storyboard?.instantiateViewController(withIdentifier: "OTPVerificationVC") as? OTPVerificationVC {
4576
+ vc.cardNumber = self.cardNumberTextField.text
4577
+ vc.expiryDate = self.cardExpiryTextField.text
4578
+ vc.cvv = self.cardCvvTextField.text
4579
+ vc.nameOnCard = self.cardNameTextField.text
4580
+ vc.selectedPaymentMethod = self.selectedPaymentMethod
4581
+ vc.isSavedForFuture = isSavedForFuture
4582
+ vc.easyPayDelegate = self.easyPayDelegate // Pass delegate if needed
4583
+ vc.request = self.request
4584
+ vc.chosenPlan = self.txtFieldChosePlanCard.text
4585
+ vc.startDate = self.txtFieldStartDateCard.text
4586
+ vc.userEmail = self.txtFieldEmailCardView.text
4587
+ vc.email = self.txtFieldEmailCardView.text
4588
+ vc.amount = self.amount
4589
+ self.navigationController?.pushViewController(vc, animated: true)
4590
+ }
4305
4591
  }
4306
4592
  } else {
4307
4593
  if request.secureAuthentication == true {
@@ -4372,7 +4658,11 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
4372
4658
  }
4373
4659
 
4374
4660
  if isSavedForFuture {
4375
- navigateBankDataToEmailVerificationVC()
4661
+ if UserStoreSingleton.shared.isLoggedIn == true {
4662
+ accountChargeApi()
4663
+ } else {
4664
+ navigateBankDataToEmailVerificationVC()
4665
+ }
4376
4666
  } else {
4377
4667
  accountChargeApi()
4378
4668
  }
@@ -4384,7 +4674,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
4384
4674
  func navigateCardDataToEmailVerificationVC() {
4385
4675
  // if let emailVerificationVC = storyboard?.instantiateViewController(withIdentifier: "EmailVerificationVC") as? EmailVerificationVC {
4386
4676
  if let emailVerificationVC = storyboard?.instantiateViewController(withIdentifier: "OTPVerificationVC") as? OTPVerificationVC {
4387
- if let billingInfoData = request.billingInfoData {
4677
+ if let billingInfoData = request.fields {
4388
4678
  do {
4389
4679
  let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
4390
4680
  emailVerificationVC.billingInfoData = billingInfoData
@@ -4418,7 +4708,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
4418
4708
  func navigateBankDataToEmailVerificationVC() {
4419
4709
  // if let emailVerificationVC = storyboard?.instantiateViewController(withIdentifier: "EmailVerificationVC") as? EmailVerificationVC {
4420
4710
  if let emailVerificationVC = storyboard?.instantiateViewController(withIdentifier: "OTPVerificationVC") as? OTPVerificationVC {
4421
- if let billingInfoData = request.billingInfoData {
4711
+ if let billingInfoData = request.fields {
4422
4712
  do {
4423
4713
  let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
4424
4714
  emailVerificationVC.billingInfoData = billingInfoData
@@ -4533,7 +4823,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
4533
4823
 
4534
4824
  if self.request?.authenticatedACH == true {
4535
4825
  self.viewBankFields.isHidden = true
4536
- self.viewBtnShowSavedCards.isHidden = true
4826
+ // self.viewBtnShowSavedCards.isHidden = true
4537
4827
  self.btnNext.isHidden = true
4538
4828
  // self.viewTermsAndConditions.isHidden = true
4539
4829
  self.btnNextHeight.constant = 0
@@ -4667,13 +4957,13 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
4667
4957
  grailPayAaccountChargeSingleSavedAccountApi()
4668
4958
  } else {
4669
4959
  // Check if billingInfoData is not nil or empty
4670
- if let billingInfoData = request.billingInfoData {
4960
+ if let billingInfoData = request.fields {
4671
4961
  do {
4672
4962
  let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
4673
4963
 
4674
4964
  DispatchQueue.main.async {
4675
4965
 
4676
- if let billingInfoData = self.request.billingInfoData,
4966
+ if let billingInfoData = self.request.fields,
4677
4967
  let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
4678
4968
  let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
4679
4969
 
@@ -4798,13 +5088,13 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
4798
5088
 
4799
5089
  @IBAction func actionBtnPayNowNewAccountView(_ sender: UIButton) {
4800
5090
  // Check if billingInfoData is not nil or empty
4801
- if let billingInfoData = request.billingInfoData {
5091
+ if let billingInfoData = request.fields {
4802
5092
  do {
4803
5093
  let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
4804
5094
 
4805
5095
  DispatchQueue.main.async {
4806
5096
 
4807
- if let billingInfoData = self.request.billingInfoData,
5097
+ if let billingInfoData = self.request.fields,
4808
5098
  let json = try? JSONSerialization.jsonObject(with: billingInfoData, options: []),
4809
5099
  let jsonDict = json as? [String: Any], !jsonDict.isEmpty {
4810
5100
  print("Billing Info Data: \(jsonDict)")
@@ -5520,6 +5810,26 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
5520
5810
  "currency": "usd"
5521
5811
  ]
5522
5812
 
5813
+ // ✅ Only for logged-in users
5814
+ if UserStoreSingleton.shared.isLoggedIn == true {
5815
+ let emailText = txtFieldEmailCardView.text
5816
+ let emailPrefix = emailText.components(separatedBy: "@").first ?? ""
5817
+
5818
+ requestBody["save_card"] = 1
5819
+ requestBody["is_default"] = "1"
5820
+
5821
+ if let customerId = UserStoreSingleton.shared.customerId {
5822
+ requestBody["customer"] = customerId
5823
+ requestBody["customer_id"] = customerId
5824
+ } else {
5825
+ requestBody["username"] = emailPrefix
5826
+ }
5827
+
5828
+ if UserStoreSingleton.shared.customerId == nil {
5829
+ requestBody["create_customer"] = "1"
5830
+ }
5831
+ }
5832
+
5523
5833
  if let req = request, req.is_recurring == true {
5524
5834
  if let recurringType = req.recurringStartDateType, recurringType == .custom,
5525
5835
  let startDateText = txtFieldStartDateCard?.text, !startDateText.isEmpty {
@@ -5541,16 +5851,9 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
5541
5851
  }
5542
5852
  }
5543
5853
 
5544
- // // ✅ Include metadata only if it has at least 1 key-value pair
5545
- // if let metadata = request?.metadata, !metadata.isEmpty {
5546
- // requestBody["metadata"] = metadata
5547
- // }
5548
-
5549
- // ✅ Flatten metadata into requestBody
5854
+ // ✅ Include metadata only if it has at least 1 key-value pair
5550
5855
  if let metadata = request?.metadata, !metadata.isEmpty {
5551
- for (key, value) in metadata {
5552
- requestBody[key] = value
5553
- }
5856
+ requestBody["metadata"] = metadata
5554
5857
  }
5555
5858
 
5556
5859
  print("Request Body: \(requestBody)")
@@ -5578,7 +5881,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
5578
5881
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
5579
5882
  paymentDoneVC.request = self.request
5580
5883
 
5581
- if let billingData = self.request.billingInfoData,
5884
+ if let billingData = self.request.fields,
5582
5885
  let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
5583
5886
 
5584
5887
  let cleanBillingInfo: [String: Any] = [
@@ -5634,7 +5937,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
5634
5937
  "currency": "usd"
5635
5938
  ]
5636
5939
 
5637
- if let billingInfoData = request.billingInfoData {
5940
+ if let billingInfoData = request.fields {
5638
5941
  do {
5639
5942
  let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
5640
5943
 
@@ -5719,15 +6022,30 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
5719
6022
  params["interval"] = txtFieldChosePlanCard.text.lowercased()
5720
6023
  }
5721
6024
 
5722
- // // ✅ Include metadata only if it has at least 1 key-value pair
5723
- // if let metadata = request?.metadata, !metadata.isEmpty {
5724
- // requestBody["metadata"] = metadata
5725
- // }
5726
-
5727
- // ✅ Flatten metadata into requestBody
6025
+ // ✅ Include metadata only if it has at least 1 key-value pair
5728
6026
  if let metadata = request?.metadata, !metadata.isEmpty {
5729
- for (key, value) in metadata {
5730
- params[key] = value
6027
+ params["metadata"] = metadata
6028
+ }
6029
+
6030
+ // ✅ Only for logged-in users
6031
+ if UserStoreSingleton.shared.isLoggedIn == true {
6032
+ let emailText = txtFieldEmailCardView.text
6033
+ let emailPrefix = emailText.components(separatedBy: "@").first ?? ""
6034
+
6035
+ params["save_card"] = 1
6036
+ params["is_default"] = "1"
6037
+ params["tokenize"] = request.tokenOnly ?? ""
6038
+ params["username"] = emailPrefix
6039
+
6040
+ if let customerId = UserStoreSingleton.shared.customerId {
6041
+ params["customer"] = customerId
6042
+ params["customer_id"] = customerId
6043
+ } else {
6044
+ params["create_customer"] = "1"
6045
+ }
6046
+
6047
+ if UserStoreSingleton.shared.customerId == nil {
6048
+ params["create_customer"] = "1"
5731
6049
  }
5732
6050
  }
5733
6051
 
@@ -5756,7 +6074,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
5756
6074
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
5757
6075
  paymentDoneVC.request = self.request
5758
6076
  // Pass billing info and additional info if available
5759
- if let billingInfoData = self.request.billingInfoData,
6077
+ if let billingInfoData = self.request.fields,
5760
6078
  let fieldSection = try? JSONDecoder().decode(FieldSection.self, from: billingInfoData) {
5761
6079
 
5762
6080
  // Filter billing info: only include non-empty values
@@ -5828,16 +6146,9 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
5828
6146
  params["interval"] = txtFieldSelectPlanSingleSavedCard.text.lowercased()
5829
6147
  }
5830
6148
 
5831
- // // ✅ Include metadata only if it has at least 1 key-value pair
5832
- // if let metadata = request?.metadata, !metadata.isEmpty {
5833
- // requestBody["metadata"] = metadata
5834
- // }
5835
-
5836
- // ✅ Flatten metadata into requestBody
6149
+ // ✅ Include metadata only if it has at least 1 key-value pair
5837
6150
  if let metadata = request?.metadata, !metadata.isEmpty {
5838
- for (key, value) in metadata {
5839
- params[key] = value
5840
- }
6151
+ params["metadata"] = metadata
5841
6152
  }
5842
6153
 
5843
6154
  print("Request Params: \(params)")
@@ -5865,7 +6176,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
5865
6176
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
5866
6177
  paymentDoneVC.request = self.request
5867
6178
  // Pass billingInfo and additionalInfo
5868
- if let billingData = self.request.billingInfoData,
6179
+ if let billingData = self.request.fields,
5869
6180
  let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
5870
6181
 
5871
6182
  // Extract main billing fields
@@ -5938,7 +6249,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
5938
6249
  "email": UserStoreSingleton.shared.verificationEmail ?? ""
5939
6250
  ]
5940
6251
 
5941
- if let billingInfoData = request.billingInfoData {
6252
+ if let billingInfoData = request.fields {
5942
6253
  do {
5943
6254
  let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
5944
6255
 
@@ -6023,16 +6334,9 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
6023
6334
  params["interval"] = txtFieldSelectPlanSingleSavedCard.text.lowercased()
6024
6335
  }
6025
6336
 
6026
- // // ✅ Include metadata only if it has at least 1 key-value pair
6027
- // if let metadata = request?.metadata, !metadata.isEmpty {
6028
- // requestBody["metadata"] = metadata
6029
- // }
6030
-
6031
- // ✅ Flatten metadata into requestBody
6337
+ // ✅ Include metadata only if it has at least 1 key-value pair
6032
6338
  if let metadata = request?.metadata, !metadata.isEmpty {
6033
- for (key, value) in metadata {
6034
- params[key] = value
6035
- }
6339
+ params["metadata"] = metadata
6036
6340
  }
6037
6341
 
6038
6342
  print(params)
@@ -6084,7 +6388,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
6084
6388
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
6085
6389
  paymentDoneVC.request = self.request
6086
6390
  // Pass billing info and additional info if available
6087
- if let billingInfoData = self.request.billingInfoData,
6391
+ if let billingInfoData = self.request.fields,
6088
6392
  let fieldSection = try? JSONDecoder().decode(FieldSection.self, from: billingInfoData) {
6089
6393
 
6090
6394
  // Filter billing info: only include non-empty values
@@ -6272,6 +6576,11 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
6272
6576
  params["interval"] = txtFieldSelectPlanNewCardView.text.lowercased()
6273
6577
  }
6274
6578
 
6579
+ // ✅ Include metadata only if it has at least 1 key-value pair
6580
+ if let metadata = request?.metadata, !metadata.isEmpty {
6581
+ params["metadata"] = metadata
6582
+ }
6583
+
6275
6584
  print(params)
6276
6585
 
6277
6586
  do {
@@ -6321,7 +6630,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
6321
6630
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
6322
6631
  paymentDoneVC.request = self.request
6323
6632
  // Pass billingInfo and additionalInfo
6324
- if let billingData = self.request.billingInfoData,
6633
+ if let billingData = self.request.fields,
6325
6634
  let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
6326
6635
 
6327
6636
  // Extract main billing fields
@@ -6418,7 +6727,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
6418
6727
  params["is_default"] = "1"
6419
6728
  }
6420
6729
 
6421
- if let billingInfoData = request.billingInfoData {
6730
+ if let billingInfoData = request.fields {
6422
6731
  do {
6423
6732
  let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
6424
6733
 
@@ -6511,16 +6820,9 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
6511
6820
  params["email"] = UserStoreSingleton.shared.verificationEmail
6512
6821
  }
6513
6822
 
6514
- // // ✅ Include metadata only if it has at least 1 key-value pair
6515
- // if let metadata = request?.metadata, !metadata.isEmpty {
6516
- // requestBody["metadata"] = metadata
6517
- // }
6518
-
6519
- // ✅ Flatten metadata into requestBody
6823
+ // ✅ Include metadata only if it has at least 1 key-value pair
6520
6824
  if let metadata = request?.metadata, !metadata.isEmpty {
6521
- for (key, value) in metadata {
6522
- params[key] = value
6523
- }
6825
+ params["metadata"] = metadata
6524
6826
  }
6525
6827
 
6526
6828
  print(params)
@@ -6572,7 +6874,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
6572
6874
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
6573
6875
  paymentDoneVC.request = self.request
6574
6876
  // Pass billing info and additional info if available
6575
- if let billingInfoData = self.request.billingInfoData,
6877
+ if let billingInfoData = self.request.fields,
6576
6878
  let fieldSection = try? JSONDecoder().decode(FieldSection.self, from: billingInfoData) {
6577
6879
 
6578
6880
  // Filter billing info: only include non-empty values
@@ -6957,24 +7259,8 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
6957
7259
  self.btnNextTopCon.constant = 20
6958
7260
  }
6959
7261
 
6960
- //// self.viewBankFields.isHidden = false
6961
- //// self.btnNext.isHidden = false
6962
- //// self.btnNextHeight.constant = 50
6963
- //// self.btnNextTopCon.constant = 20
6964
-
6965
- // self.viewBtnShowSavedCards.isHidden = false
6966
- // self.viewBtnShowSavedCardHeight.constant = 50
6967
- // self.viewBtnShowSavedCardTopCon.constant = 20
6968
- // self.btnShowSavedCard.isHidden = false
6969
-
6970
7262
  return
6971
7263
  }
6972
- // else {
6973
- // self.viewBtnShowSavedCards.isHidden = true
6974
- // self.viewBtnShowSavedCardHeight.constant = 0
6975
- // self.viewBtnShowSavedCardTopCon.constant = 0
6976
- // self.btnShowSavedCard.isHidden = false
6977
- // }
6978
7264
 
6979
7265
  if let firstAccount = self.bankAccounts.first {
6980
7266
  self.selectedbankAccounts = firstAccount
@@ -7090,8 +7376,27 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
7090
7376
  "payment_mode": "auth_and_capture",
7091
7377
  "payment_intent": UserStoreSingleton.shared.paymentIntent ?? "",
7092
7378
  "levelIndicator": 1,
7379
+ "payment_method": "ach"
7093
7380
  ]
7094
7381
 
7382
+ // ✅ Only for logged-in users
7383
+ if UserStoreSingleton.shared.isLoggedIn == true {
7384
+ let emailText = txtFieldEmailAccountView.text
7385
+ let emailPrefix = emailText.components(separatedBy: "@").first ?? ""
7386
+
7387
+ params["save_account"] = 1
7388
+
7389
+ if let customerId = UserStoreSingleton.shared.customerId, !customerId.isEmpty {
7390
+ params["customer"] = customerId
7391
+ } else {
7392
+ params["username"] = emailPrefix
7393
+ }
7394
+
7395
+ if UserStoreSingleton.shared.customerId == nil {
7396
+ params["create_customer"] = "1"
7397
+ }
7398
+ }
7399
+
7095
7400
  // Add these if recurring is enabled
7096
7401
  if let req = request, req.is_recurring == true {
7097
7402
  if let recurringType = req.recurringStartDateType, recurringType == .custom {
@@ -7115,6 +7420,11 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
7115
7420
  params["interval"] = txtFieldSelectPlanViewBankFields.text.lowercased()
7116
7421
  }
7117
7422
 
7423
+ // ✅ Include metadata only if it has at least 1 key-value pair
7424
+ if let metadata = request?.metadata, !metadata.isEmpty {
7425
+ params["metadata"] = metadata
7426
+ }
7427
+
7118
7428
  print(params)
7119
7429
 
7120
7430
  do {
@@ -7166,7 +7476,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
7166
7476
  paymentDoneVC.bankPaymentParams = params
7167
7477
  paymentDoneVC.request = self.request
7168
7478
  // Pass billingInfo and additionalInfo
7169
- if let billingData = self.request.billingInfoData,
7479
+ if let billingData = self.request.fields,
7170
7480
  let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
7171
7481
 
7172
7482
  // Extract main billing fields
@@ -7253,9 +7563,28 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
7253
7563
  "payment_mode": "auth_and_capture",
7254
7564
  "payment_intent": UserStoreSingleton.shared.paymentIntent ?? "",
7255
7565
  "levelIndicator": 1,
7566
+ "payment_method": "ach"
7256
7567
  ]
7257
7568
 
7258
- if let billingInfoData = request.billingInfoData {
7569
+ // Only for logged-in users
7570
+ if UserStoreSingleton.shared.isLoggedIn == true {
7571
+ let emailText = txtFieldEmailAccountView.text
7572
+ let emailPrefix = emailText.components(separatedBy: "@").first ?? ""
7573
+
7574
+ params["save_account"] = 1
7575
+
7576
+ if let customerId = UserStoreSingleton.shared.customerId, !customerId.isEmpty {
7577
+ params["customer"] = customerId
7578
+ } else {
7579
+ params["username"] = emailPrefix
7580
+ }
7581
+
7582
+ if UserStoreSingleton.shared.customerId == nil {
7583
+ params["create_customer"] = "1"
7584
+ }
7585
+ }
7586
+
7587
+ if let billingInfoData = request.fields {
7259
7588
  do {
7260
7589
  let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
7261
7590
 
@@ -7340,6 +7669,11 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
7340
7669
  params["interval"] = txtFieldSelectPlanViewBankFields.text.lowercased()
7341
7670
  }
7342
7671
 
7672
+ // ✅ Include metadata only if it has at least 1 key-value pair
7673
+ if let metadata = request?.metadata, !metadata.isEmpty {
7674
+ params["metadata"] = metadata
7675
+ }
7676
+
7343
7677
  print(params)
7344
7678
 
7345
7679
  do {
@@ -7391,7 +7725,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
7391
7725
  paymentDoneVC.bankPaymentParams = params
7392
7726
  paymentDoneVC.request = self.request
7393
7727
  // Pass billing info and additional info if available
7394
- if let billingInfoData = self.request.billingInfoData,
7728
+ if let billingInfoData = self.request.fields,
7395
7729
  let fieldSection = try? JSONDecoder().decode(FieldSection.self, from: billingInfoData) {
7396
7730
 
7397
7731
  // Filter billing info: only include non-empty values
@@ -7493,6 +7827,11 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
7493
7827
  params["interval"] = txtFieldSelectPlanSingleSavedBankView.text.lowercased()
7494
7828
  }
7495
7829
 
7830
+ // ✅ Include metadata only if it has at least 1 key-value pair
7831
+ if let metadata = request?.metadata, !metadata.isEmpty {
7832
+ params["metadata"] = metadata
7833
+ }
7834
+
7496
7835
  print(params)
7497
7836
 
7498
7837
  do {
@@ -7544,7 +7883,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
7544
7883
  paymentDoneVC.bankPaymentParams = params
7545
7884
  paymentDoneVC.request = self.request
7546
7885
  // Pass billingInfo and additionalInfo
7547
- if let billingData = self.request.billingInfoData,
7886
+ if let billingData = self.request.fields,
7548
7887
  let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
7549
7888
 
7550
7889
  // Extract main billing fields
@@ -7630,7 +7969,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
7630
7969
  "email": UserStoreSingleton.shared.verificationEmail ?? ""
7631
7970
  ]
7632
7971
 
7633
- if let billingInfoData = request.billingInfoData {
7972
+ if let billingInfoData = request.fields {
7634
7973
  do {
7635
7974
  let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
7636
7975
 
@@ -7715,6 +8054,11 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
7715
8054
  params["interval"] = txtFieldSelectPlanSingleSavedBankView.text.lowercased()
7716
8055
  }
7717
8056
 
8057
+ // ✅ Include metadata only if it has at least 1 key-value pair
8058
+ if let metadata = request?.metadata, !metadata.isEmpty {
8059
+ params["metadata"] = metadata
8060
+ }
8061
+
7718
8062
  print(params)
7719
8063
 
7720
8064
  do {
@@ -7766,7 +8110,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
7766
8110
  paymentDoneVC.bankPaymentParams = params
7767
8111
  paymentDoneVC.request = self.request
7768
8112
  // Pass billing info and additional info if available
7769
- if let billingInfoData = self.request.billingInfoData,
8113
+ if let billingInfoData = self.request.fields,
7770
8114
  let fieldSection = try? JSONDecoder().decode(FieldSection.self, from: billingInfoData) {
7771
8115
 
7772
8116
  // Filter billing info: only include non-empty values
@@ -7842,7 +8186,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
7842
8186
  let accountNumber = txtFieldAccountNumberNewAccountView.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
7843
8187
 
7844
8188
  var params: [String: Any] = [
7845
- // "name": accountName,
8189
+ // "name": accountName,
7846
8190
  "name": !(request.name?.isEmpty ?? true) ? request.name! : (accountName),
7847
8191
  "email": UserStoreSingleton.shared.verificationEmail ?? "",
7848
8192
  "description": "Test Description",
@@ -7878,6 +8222,11 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
7878
8222
  params["interval"] = txtFieldSelectPlanNewAccountView.text.lowercased()
7879
8223
  }
7880
8224
 
8225
+ // ✅ Include metadata only if it has at least 1 key-value pair
8226
+ if let metadata = request?.metadata, !metadata.isEmpty {
8227
+ params["metadata"] = metadata
8228
+ }
8229
+
7881
8230
  print(params)
7882
8231
 
7883
8232
  do {
@@ -7929,7 +8278,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
7929
8278
  paymentDoneVC.bankPaymentParams = params
7930
8279
  paymentDoneVC.request = self.request
7931
8280
  // Pass billingInfo and additionalInfo
7932
- if let billingData = self.request.billingInfoData,
8281
+ if let billingData = self.request.fields,
7933
8282
  let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
7934
8283
 
7935
8284
  // Extract main billing fields
@@ -8024,7 +8373,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
8024
8373
  "levelIndicator": 1,
8025
8374
  ]
8026
8375
 
8027
- if let billingInfoData = request.billingInfoData {
8376
+ if let billingInfoData = request.fields {
8028
8377
  do {
8029
8378
  let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
8030
8379
 
@@ -8109,6 +8458,11 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
8109
8458
  params["interval"] = txtFieldSelectPlanNewAccountView.text.lowercased()
8110
8459
  }
8111
8460
 
8461
+ // ✅ Include metadata only if it has at least 1 key-value pair
8462
+ if let metadata = request?.metadata, !metadata.isEmpty {
8463
+ params["metadata"] = metadata
8464
+ }
8465
+
8112
8466
  print(params)
8113
8467
 
8114
8468
  do {
@@ -8160,7 +8514,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
8160
8514
  paymentDoneVC.bankPaymentParams = params
8161
8515
  paymentDoneVC.request = self.request
8162
8516
  // Pass billing info and additional info if available
8163
- if let billingInfoData = self.request.billingInfoData,
8517
+ if let billingInfoData = self.request.fields,
8164
8518
  let fieldSection = try? JSONDecoder().decode(FieldSection.self, from: billingInfoData) {
8165
8519
 
8166
8520
  // Filter billing info: only include non-empty values
@@ -8282,6 +8636,11 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
8282
8636
  params["interval"] = txtFieldSelectPlanNewAccountView.text.lowercased()
8283
8637
  }
8284
8638
 
8639
+ // ✅ Include metadata only if it has at least 1 key-value pair
8640
+ if let metadata = request?.metadata, !metadata.isEmpty {
8641
+ params["metadata"] = metadata
8642
+ }
8643
+
8285
8644
  print(params)
8286
8645
 
8287
8646
  do {
@@ -8332,7 +8691,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
8332
8691
  paymentDoneVC.bankPaymentParams = params
8333
8692
  paymentDoneVC.request = self.request
8334
8693
  // Pass billingInfo and additionalInfo
8335
- if let billingData = self.request.billingInfoData,
8694
+ if let billingData = self.request.fields,
8336
8695
  let billingInfoDict = try? JSONSerialization.jsonObject(with: billingData, options: []) as? [String: Any] {
8337
8696
 
8338
8697
  // Extract main billing fields
@@ -8476,22 +8835,22 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
8476
8835
  return
8477
8836
  }
8478
8837
 
8479
- var request = URLRequest(url: serviceURL)
8480
- request.httpMethod = "POST"
8481
- request.addValue("application/json", forHTTPHeaderField: "Content-Type")
8838
+ var urlRequest = URLRequest(url: serviceURL)
8839
+ urlRequest.httpMethod = "POST"
8840
+ urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
8482
8841
 
8483
8842
  let token = UserStoreSingleton.shared.clientToken
8484
8843
  print("Setting clientToken header: \(token ?? "None")")
8485
- request.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
8844
+ urlRequest.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
8486
8845
 
8487
8846
  // Add API headers
8488
8847
  if let apiKey = EnvironmentConfig.apiKey,
8489
8848
  let apiSecret = EnvironmentConfig.apiSecret {
8490
- request.addValue(apiKey, forHTTPHeaderField: "x-api-key")
8491
- request.addValue(apiSecret, forHTTPHeaderField: "x-api-secret")
8849
+ urlRequest.addValue(apiKey, forHTTPHeaderField: "x-api-key")
8850
+ urlRequest.addValue(apiSecret, forHTTPHeaderField: "x-api-secret")
8492
8851
  }
8493
8852
 
8494
- let params: [String: Any] = [
8853
+ var params: [String: Any] = [
8495
8854
  "name": UserStoreSingleton.shared.merchantName ?? "",
8496
8855
  "email": UserStoreSingleton.shared.merchantEmail ?? "",
8497
8856
  "description": "Payment checkout",
@@ -8502,11 +8861,16 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
8502
8861
  "callback_url": "https://stage-api.stage-easymerchant.io/webhook/crypto"
8503
8862
  ]
8504
8863
 
8864
+ // ✅ Include metadata only if it has at least 1 key-value pair
8865
+ if let metadata = request?.metadata, !metadata.isEmpty {
8866
+ params["metadata"] = metadata
8867
+ }
8868
+
8505
8869
  print(params)
8506
8870
 
8507
8871
  do {
8508
8872
  let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
8509
- request.httpBody = jsonData
8873
+ urlRequest.httpBody = jsonData
8510
8874
  if let jsonString = String(data: jsonData, encoding: .utf8) {
8511
8875
  print("JSON Payload: \(jsonString)")
8512
8876
  }
@@ -8517,7 +8881,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
8517
8881
  }
8518
8882
 
8519
8883
  let session = URLSession.shared
8520
- let task = session.dataTask(with: request) { (serviceData, serviceResponse, error) in
8884
+ let task = session.dataTask(with: urlRequest) { (serviceData, serviceResponse, error) in
8521
8885
 
8522
8886
  DispatchQueue.main.async {
8523
8887
  self.hideLoadingIndicator() // Stop loader when response is received
@@ -8719,7 +9083,29 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
8719
9083
  "tokenize": request.tokenOnly ?? false,
8720
9084
  ]
8721
9085
 
8722
- if let billingInfoData = request.billingInfoData {
9086
+ // Only for logged-in users
9087
+ if UserStoreSingleton.shared.isLoggedIn == true {
9088
+ let emailText = txtFieldEmailCardView.text
9089
+ let emailPrefix = emailText.components(separatedBy: "@").first ?? ""
9090
+
9091
+ params["save_card"] = 1
9092
+ params["is_default"] = "1"
9093
+ params["tokenize"] = request.tokenOnly ?? ""
9094
+ params["username"] = emailPrefix
9095
+
9096
+ if let customerId = UserStoreSingleton.shared.customerId {
9097
+ params["customer"] = customerId
9098
+ params["customer_id"] = customerId
9099
+ } else {
9100
+ params["create_customer"] = "1"
9101
+ }
9102
+
9103
+ if UserStoreSingleton.shared.customerId == nil {
9104
+ params["create_customer"] = "1"
9105
+ }
9106
+ }
9107
+
9108
+ if let billingInfoData = request.fields {
8723
9109
  do {
8724
9110
  let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
8725
9111
 
@@ -8857,7 +9243,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
8857
9243
  paymentDoneVC.cardApiParams = params
8858
9244
  paymentDoneVC.request = self.request
8859
9245
  // Pass billing info and additional info if available
8860
- if let billingInfoData = self.request.billingInfoData,
9246
+ if let billingInfoData = self.request.fields,
8861
9247
  let fieldSection = try? JSONDecoder().decode(FieldSection.self, from: billingInfoData) {
8862
9248
 
8863
9249
  // Filter billing info: only include non-empty values
@@ -9013,7 +9399,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
9013
9399
  params["is_default"] = "1"
9014
9400
  }
9015
9401
 
9016
- if let billingInfoData = request.billingInfoData {
9402
+ if let billingInfoData = request.fields {
9017
9403
  do {
9018
9404
  let fieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
9019
9405
 
@@ -9149,7 +9535,7 @@ class PaymentInfoVC: BaseVC, BillingInfoVCDelegate {
9149
9535
  paymentDoneVC.cardApiParams = params
9150
9536
  paymentDoneVC.request = self.request
9151
9537
  // Pass billing info and additional info if available
9152
- if let billingInfoData = self.request.billingInfoData,
9538
+ if let billingInfoData = self.request.fields,
9153
9539
  let fieldSection = try? JSONDecoder().decode(FieldSection.self, from: billingInfoData) {
9154
9540
 
9155
9541
  // Filter billing info: only include non-empty values
@@ -9425,13 +9811,12 @@ extension PaymentInfoVC: UICollectionViewDelegate, UICollectionViewDataSource, U
9425
9811
  }
9426
9812
 
9427
9813
  }
9428
-
9429
9814
  } else {
9430
9815
  self.lblBtnShowSaveCard.text = "Show Saved Account"
9431
9816
  self.viewCardFields.isHidden = true
9432
9817
  self.viewChangeCard.isHidden = true
9433
9818
  self.viewAddNewCard.isHidden = true
9434
- // self.viewBtnShowSavedCards.isHidden = false
9819
+ // self.viewBtnShowSavedCards.isHidden = false
9435
9820
 
9436
9821
  if request?.authenticatedACH == true {
9437
9822
  self.viewBankFields.isHidden = true