@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
@@ -10,7 +10,7 @@ import UIKit
10
10
  @available(iOS 16.0, *)
11
11
  class AdditionalInfoVC: BaseVC {
12
12
 
13
- @IBOutlet weak var viewAdditionalInfo: UIView!
13
+ // @IBOutlet weak var viewAdditionalInfo: UIView!
14
14
  @IBOutlet weak var txtFieldName: UITextField!
15
15
  @IBOutlet weak var txtFieldEmail: UITextField!
16
16
  @IBOutlet weak var txtFieldPhoneNumber: UITextField!
@@ -34,7 +34,7 @@ class AdditionalInfoVC: BaseVC {
34
34
  var expiryDate: String?
35
35
  var cvv: String?
36
36
  var nameOnCard: String?
37
- var billingInfoData: [String: Any]?
37
+ var userEmail: String?
38
38
 
39
39
  var selectedPaymentMethod: String?
40
40
 
@@ -52,6 +52,7 @@ class AdditionalInfoVC: BaseVC {
52
52
  var amount: Int?
53
53
  var cvvText: String?
54
54
  var isFrom = String()
55
+ var isFromm = String()
55
56
 
56
57
  var isSavedNewCard: Bool = false
57
58
 
@@ -66,6 +67,18 @@ class AdditionalInfoVC: BaseVC {
66
67
  var chosenPlan: String?
67
68
  var startDate: String?
68
69
 
70
+ //GrailPay Params
71
+ var grailPayAccountID: String?
72
+ var selectedGrailPayAccountType: String?
73
+ var selectedGrailPayAccountName: String?
74
+
75
+ var billingInfoData: Data?
76
+ var fieldSection: FieldSection?
77
+
78
+ var additionalInfo: [FieldItem]?
79
+ var billingInfo: [FieldItem]?
80
+ var visibility: FieldsVisibility?
81
+
69
82
  override func viewDidLoad() {
70
83
  super.viewDidLoad()
71
84
 
@@ -93,30 +106,65 @@ class AdditionalInfoVC: BaseVC {
93
106
  tapGesture.cancelsTouchesInView = false
94
107
  self.view.addGestureRecognizer(tapGesture)
95
108
 
96
- if let billingInfoData = billingInfoData {
97
- print("Billing Info Data: \(billingInfoData)")
98
-
99
- // Extract the additional_info dictionary
100
- if let additionalInfo = billingInfoData["additional_info"] as? [String: Any] {
101
- // Set the name field
102
- if let name = additionalInfo["name"] as? String {
103
- txtFieldName.text = name
104
- }
105
-
106
- if let email = additionalInfo["email"] as? String {
107
- txtFieldEmail.text = email
108
- }
109
-
110
- if let phoneNumber = additionalInfo["phone_number"] as? String {
111
- txtFieldPhoneNumber.text = phoneNumber
109
+ // Decode fieldSection if it's not already set
110
+ if fieldSection == nil, let billingInfoData = billingInfoData {
111
+ do {
112
+ let decodedFieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
113
+ self.fieldSection = decodedFieldSection
114
+ self.additionalInfo = decodedFieldSection.additional
115
+ self.billingInfo = decodedFieldSection.billing
116
+ self.visibility = decodedFieldSection.visibility
117
+ print("fieldSection decoded successfully")
118
+ } catch {
119
+ print("Failed to decode billing info data: \(error)")
120
+ }
121
+ }
122
+
123
+ if let additionalInfo = additionalInfo {
124
+ for item in additionalInfo {
125
+ switch item.name {
126
+ case "name":
127
+ txtFieldName.text = item.value
128
+ case "email":
129
+ txtFieldEmail.text = item.value
130
+ case "phone_number":
131
+ txtFieldPhoneNumber.text = item.value
132
+ case "description":
133
+ txtFieldDescription.text = item.value
134
+ default:
135
+ break
112
136
  }
137
+ }
138
+ configureFieldVisibility()
139
+ } else if let billingInfoData = billingInfoData {
140
+ do {
141
+ let decodedFieldSection = try JSONDecoder().decode(FieldSection.self, from: billingInfoData)
142
+ self.fieldSection = decodedFieldSection
113
143
 
114
- if let description = additionalInfo["description"] as? String {
115
- txtFieldDescription.text = description
144
+ for item in decodedFieldSection.additional {
145
+ switch item.name {
146
+ case "name":
147
+ txtFieldName.text = item.value
148
+ case "email":
149
+ txtFieldEmail.text = item.value
150
+ case "phone_number":
151
+ txtFieldPhoneNumber.text = item.value
152
+ case "description":
153
+ txtFieldDescription.text = item.value
154
+ default:
155
+ break
156
+ }
116
157
  }
158
+ configureFieldVisibility()
159
+ } catch {
160
+ print("Failed to decode billing info data: \(error)")
117
161
  }
118
162
  }
119
163
 
164
+ if let flag = String.flag(for: "US") {
165
+ lblCountryCode.text = "\(flag) +1"
166
+ }
167
+
120
168
  //Show Default USA code in starting.
121
169
  let usaCountry = Country()
122
170
  usaCountry.name = "United States"
@@ -124,12 +172,11 @@ class AdditionalInfoVC: BaseVC {
124
172
  usaCountry.extensionCode = "1"
125
173
  usaCountry.flag = String.flag(for: "US")
126
174
  lblCountryCode.text = "\(usaCountry.flag ?? "") +\(usaCountry.extensionCode ?? "")"
127
-
128
- print(cvvText ?? "")
129
175
  }
130
176
 
131
177
  override func viewWillAppear(_ animated: Bool) {
132
178
  uiFinishingTouchElements()
179
+ configureFieldVisibility()
133
180
  }
134
181
 
135
182
  func uiFinishingTouchElements() {
@@ -154,10 +201,10 @@ class AdditionalInfoVC: BaseVC {
154
201
  if let secondaryFontColor = UserStoreSingleton.shared.secondary_font_col,
155
202
  let placeholderColor = UIColor(hex: secondaryFontColor) {
156
203
  lblEasyMerchant.textColor = placeholderColor
157
- viewAdditionalInfo.layer.borderColor = placeholderColor.cgColor
204
+ // viewAdditionalInfo.layer.borderColor = placeholderColor.cgColor
158
205
  }
159
206
  else {
160
- viewAdditionalInfo.layer.borderColor = UIColor.systemGray.cgColor
207
+ // viewAdditionalInfo.layer.borderColor = UIColor.systemGray.cgColor
161
208
  }
162
209
 
163
210
  if let borderRadiusString = UserStoreSingleton.shared.border_radious,
@@ -165,17 +212,17 @@ class AdditionalInfoVC: BaseVC {
165
212
  btnPayNow.layer.cornerRadius = CGFloat(borderRadius) // Set corner radius
166
213
  btnPrevious.layer.cornerRadius = CGFloat(borderRadius)
167
214
  btnPrevious.layer.borderWidth = 1
168
- viewAdditionalInfo.layer.cornerRadius = CGFloat(borderRadius)
169
- viewAdditionalInfo.layer.borderWidth = 1
215
+ // viewAdditionalInfo.layer.cornerRadius = CGFloat(borderRadius)
216
+ // viewAdditionalInfo.layer.borderWidth = 1
170
217
  } else {
171
218
  btnPayNow.layer.cornerRadius = 8 // Default value
172
219
  btnPrevious.layer.cornerRadius = 8
173
- viewAdditionalInfo.layer.borderWidth = 1
174
- viewAdditionalInfo.layer.cornerRadius = 8
220
+ // viewAdditionalInfo.layer.borderWidth = 1
221
+ // viewAdditionalInfo.layer.cornerRadius = 8
175
222
  }
176
223
  btnPayNow.layer.masksToBounds = true // Ensure the corners are clipped properly
177
224
  btnPrevious.layer.masksToBounds = true
178
- viewAdditionalInfo.layer.masksToBounds = true
225
+ // viewAdditionalInfo.layer.masksToBounds = true
179
226
 
180
227
  if let primaryFontColor = UserStoreSingleton.shared.primary_font_col,
181
228
  let uiColor = UIColor(hex: primaryFontColor) {
@@ -192,22 +239,36 @@ class AdditionalInfoVC: BaseVC {
192
239
  btnPrevious.titleLabel?.font = UIFont.systemFont(ofSize: fontSize)
193
240
  }
194
241
 
195
- configureFieldVisibility()
242
+ }
243
+
244
+ private func getFieldValue(for name: String) -> String? {
245
+ return fieldSection?.additional.first(where: { $0.name == name })?.value
246
+ }
247
+
248
+ private func setFieldValue(_ name: String, to value: String?) {
249
+ guard let index = fieldSection?.additional.firstIndex(where: { $0.name == name }) else { return }
250
+ fieldSection?.additional[index].value = value ?? ""
196
251
  }
197
252
 
198
253
  private func configureFieldVisibility() {
199
- if let billingInfoData = billingInfoData,
200
- let additionalInfo = billingInfoData["additional_info"] as? [String: Any] {
201
-
202
- let name = additionalInfo["name"] as? String
203
- let email = additionalInfo["email"] as? String
204
- let phoneNumber = additionalInfo["phone_number"] as? String
205
- let description = additionalInfo["description"] as? String
206
-
207
- lblStarNameField.isHidden = name == nil || name?.isEmpty == true
208
- lblStarEmailField.isHidden = email == nil || email?.isEmpty == true
209
- lblStarPhoneField.isHidden = phoneNumber == nil || phoneNumber?.isEmpty == true
210
- lblStarDescriptionField.isHidden = description == nil || description?.isEmpty == true
254
+ guard let additionalFields = fieldSection?.additional else {
255
+ print("No additional fields found")
256
+ return
257
+ }
258
+
259
+ func isFieldRequired(_ name: String) -> Bool {
260
+ let required = additionalFields.first(where: { $0.name == name })?.required == true
261
+ print("Field \(name) required: \(required)")
262
+ return required
263
+ }
264
+
265
+ DispatchQueue.main.async {
266
+ self.lblStarNameField.isHidden = !isFieldRequired("name")
267
+ self.lblStarEmailField.isHidden = !isFieldRequired("email_address")
268
+ self.lblStarPhoneField.isHidden = !isFieldRequired("phone_number")
269
+ self.lblStarDescriptionField.isHidden = !isFieldRequired("description")
270
+ print("Star visibility set")
271
+ self.view.layoutIfNeeded()
211
272
  }
212
273
  }
213
274
 
@@ -226,103 +287,129 @@ class AdditionalInfoVC: BaseVC {
226
287
  navigationController?.popViewController(animated: true)
227
288
  }
228
289
 
229
- @IBAction func actionBtnPayNow(_ sender: UIButton) {
230
- if !lblStarNameField.isHidden &&
231
- txtFieldName.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true {
232
- showAlert(title: "Missing Information", message: "Please enter your name.")
233
- return
234
- }
235
- else if !lblStarEmailField.isHidden &&
236
- txtFieldEmail.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true {
237
- showAlert(title: "Missing Information", message: "Please enter your email address.")
238
- return
290
+ func updateAdditionalInfoData() {
291
+ setAdditionalFieldValue("name", to: txtFieldName.text)
292
+ setAdditionalFieldValue("email", to: txtFieldEmail.text)
293
+ setAdditionalFieldValue("phone_number", to: txtFieldPhoneNumber.text)
294
+ setAdditionalFieldValue("description", to: txtFieldDescription.text)
295
+ additionalInfo = fieldSection?.additional
296
+ }
297
+
298
+ // Helper method
299
+ func setAdditionalFieldValue(_ name: String, to value: String?) {
300
+ if let index = fieldSection?.additional.firstIndex(where: { $0.name == name }) {
301
+ fieldSection?.additional[index].value = value ?? ""
239
302
  }
240
- else if !lblStarPhoneField.isHidden &&
241
- txtFieldPhoneNumber.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true {
303
+ }
304
+
305
+ @IBAction func actionBtnPayNow(_ sender: UIButton) {
306
+ // MARK: - Validation
307
+ if !lblStarPhoneField.isHidden &&
308
+ txtFieldPhoneNumber.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true {
242
309
  showAlert(title: "Missing Information", message: "Please enter your phone number.")
243
310
  return
244
- }
245
- else if !lblStarDescriptionField.isHidden &&
311
+ } else if !lblStarDescriptionField.isHidden &&
246
312
  txtFieldDescription.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty == true {
247
313
  showAlert(title: "Missing Information", message: "Please enter description text.")
248
314
  return
249
315
  }
250
- else {
251
- if isSavedNewCard {
252
- if isFrom == "AddNewCard" {
253
- if request.enable3DS == true {
254
- threeDSecurePaymentAddNewCardApi(customerId: UserStoreSingleton.shared.customerId)
255
- }
256
- else {
257
- self.paymentIntentAddNewCardApi(customerId: UserStoreSingleton.shared.customerId)
258
- }
316
+
317
+ // MARK: - Update Additional Info
318
+ updateAdditionalInfoData()
319
+
320
+ // MARK: - Encode Updated fieldSection to billingInfoData
321
+ if let updatedFieldSection = fieldSection,
322
+ let updatedBillingData = try? JSONEncoder().encode(updatedFieldSection) {
323
+ billingInfoData = updatedBillingData
324
+ } else {
325
+ print("❌ Failed to encode updated additional info")
326
+ return
327
+ }
328
+
329
+ // MARK: - Flow Based on Conditions
330
+ if isSavedForFuture {
331
+ if let emailVerificationVC = self.storyboard?.instantiateViewController(withIdentifier: "EmailVerificationVC") as? EmailVerificationVC {
332
+ // Pass data to EmailVerificationVC
333
+ emailVerificationVC.billingInfoData = billingInfoData
334
+ emailVerificationVC.selectedPaymentMethod = selectedPaymentMethod
335
+ emailVerificationVC.easyPayDelegate = easyPayDelegate
336
+ emailVerificationVC.request = request
337
+ emailVerificationVC.chosenPlan = chosenPlan
338
+ emailVerificationVC.startDate = startDate
339
+ emailVerificationVC.userEmail = userEmail
340
+ emailVerificationVC.billingInfo = fieldSection?.billing
341
+ emailVerificationVC.additionalInfo = fieldSection?.additional
342
+ emailVerificationVC.visibility = fieldSection?.visibility
343
+
344
+ // Extra fields per payment method
345
+ if selectedPaymentMethod == "Card" {
346
+ emailVerificationVC.cardNumber = cardNumber
347
+ emailVerificationVC.expiryDate = expiryDate
348
+ emailVerificationVC.cvv = cvv
349
+ emailVerificationVC.nameOnCard = nameOnCard
350
+ } else if selectedPaymentMethod == "Bank" {
351
+ emailVerificationVC.accountName = accountName
352
+ emailVerificationVC.routingNumber = routingNumber
353
+ emailVerificationVC.accountType = accountType
354
+ emailVerificationVC.accountNumber = accountNumber
355
+ } else if selectedPaymentMethod == "GrailPay" {
356
+ emailVerificationVC.grailPayAccountID = grailPayAccountID
357
+ emailVerificationVC.selectedGrailPayAccountType = selectedGrailPayAccountType
358
+ emailVerificationVC.selectedGrailPayAccountName = selectedGrailPayAccountName
359
+ emailVerificationVC.isSavedForFuture = true
360
+ } else if selectedPaymentMethod == "NewGrailPayAccount" {
361
+ emailVerificationVC.grailPayAccountID = grailPayAccountID
362
+ emailVerificationVC.selectedGrailPayAccountType = selectedGrailPayAccountType
363
+ emailVerificationVC.selectedGrailPayAccountName = selectedGrailPayAccountName
364
+ emailVerificationVC.isSavedForFuture = true
259
365
  }
366
+
367
+ navigationController?.pushViewController(emailVerificationVC, animated: true)
260
368
  }
261
- else {
262
- if isSavedForFuture {
263
- // Navigate to EmailVerificationVC based on the selected payment method
264
- if selectedPaymentMethod == "Card" {
265
- if let emailVerificationVC = self.storyboard?.instantiateViewController(withIdentifier: "EmailVerificationVC") as? EmailVerificationVC {
266
- // Pass any necessary data to EmailVerificationVC
267
- emailVerificationVC.cardNumber = cardNumber
268
- emailVerificationVC.expiryDate = expiryDate
269
- emailVerificationVC.cvv = cvv
270
- emailVerificationVC.nameOnCard = nameOnCard
271
- emailVerificationVC.billingInfoData = billingInfoData
272
- emailVerificationVC.selectedPaymentMethod = selectedPaymentMethod
273
- emailVerificationVC.easyPayDelegate = self.easyPayDelegate
274
- emailVerificationVC.request = self.request
275
- emailVerificationVC.chosenPlan = self.chosenPlan
276
- emailVerificationVC.startDate = self.startDate
277
- self.navigationController?.pushViewController(emailVerificationVC, animated: true)
278
- }
279
- } else if selectedPaymentMethod == "Bank" {
280
- if let emailVerificationVC = self.storyboard?.instantiateViewController(withIdentifier: "EmailVerificationVC") as? EmailVerificationVC {
281
- // Pass any necessary data to EmailVerificationVC
282
- emailVerificationVC.accountName = accountName
283
- emailVerificationVC.routingNumber = routingNumber
284
- emailVerificationVC.accountType = accountType
285
- emailVerificationVC.accountNumber = accountNumber
286
- emailVerificationVC.billingInfoData = billingInfoData
287
- emailVerificationVC.selectedPaymentMethod = selectedPaymentMethod
288
- emailVerificationVC.easyPayDelegate = self.easyPayDelegate
289
- emailVerificationVC.request = self.request
290
- emailVerificationVC.chosenPlan = self.chosenPlan
291
- emailVerificationVC.startDate = self.startDate
292
- self.navigationController?.pushViewController(emailVerificationVC, animated: true)
293
- }
294
- }
295
- } else {
296
- // Proceed with the normal flow
297
- if selectedPaymentMethod == "Card" {
298
- if isFrom == "SavedCards" {
299
- paymentIntentFromShowCardApi()
300
- }
301
- else {
302
- if request.enable3DS == true {
303
- threeDSecurePaymentApi()
304
- }
305
- else {
306
- paymentIntentApi()
307
- }
369
+ }
370
+ else {
371
+ // Direct Payment Flow
372
+ if selectedPaymentMethod == "Card" {
373
+ if isFrom == "SavedCards" {
374
+ paymentIntentFromShowCardApi()
375
+ }
376
+ if isSavedNewCard {
377
+ if isFrom == "AddNewCard" {
378
+ if request.secureAuthentication == true {
379
+ threeDSecurePaymentAddNewCardApi(customerId: UserStoreSingleton.shared.customerId)
380
+ } else {
381
+ paymentIntentAddNewCardApi(customerId: UserStoreSingleton.shared.customerId)
308
382
  }
309
383
  }
310
- else if selectedPaymentMethod == "Bank" {
311
- if isFrom == "SavedBank" {
312
- accountChargeSavedBankAccountApi()
313
- }
314
- else if isFrom == "NormalBankPayWithoutSave" {
315
- accountChargeApi()
316
- }
317
- else if isFrom == "AddNewAccountWithoutSave" {
318
- accountChargeApi()
319
- }
320
- else if isFrom == "AddNewAccountWithSave" {
321
- accountChargeApi(customerId: UserStoreSingleton.shared.customerId)
322
- }
384
+ }
385
+ else {
386
+ if request.secureAuthentication == true {
387
+ threeDSecurePaymentApi()
388
+ } else {
389
+ paymentIntentApi()
323
390
  }
324
391
  }
325
392
  }
393
+ else if selectedPaymentMethod == "Bank" {
394
+ if isFrom == "SavedBank" {
395
+ accountChargeSavedBankAccountApi()
396
+ }
397
+ else if isFrom == "NormalBankPayWithoutSave" {
398
+ accountChargeApi()
399
+ }
400
+ else if isFrom == "AddNewAccountWithoutSave" {
401
+ accountChargeApi()
402
+ }
403
+ else if isFrom == "AddNewAccountWithSave" {
404
+ accountChargeApi(customerId: UserStoreSingleton.shared.customerId)
405
+ }
406
+ }
407
+ else if selectedPaymentMethod == "GrailPay" {
408
+ grailPayAccountChargeApi()
409
+ }
410
+ else if selectedPaymentMethod == "NewGrailPayAccount" {
411
+ grailPayAccountChargeApi()
412
+ }
326
413
  }
327
414
  }
328
415
 
@@ -356,46 +443,43 @@ class AdditionalInfoVC: BaseVC {
356
443
  print("Setting clientToken header: \(token ?? "None")")
357
444
  urlRequest.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
358
445
 
359
- guard let billingInfoData = billingInfoData else {
360
- print("Billing info data is nil")
361
- hideLoadingIndicator()
362
- return
363
- }
364
-
365
446
  // Extract only the digits from the phone number (local only, no country code)
366
447
  let localPhone = txtFieldPhoneNumber.text?.components(separatedBy: CharacterSet.decimalDigits.inverted).joined() ?? ""
367
448
 
368
- let additionalInfo: [String: Any] = [
369
- "name": txtFieldName.text ?? "",
370
- "email": txtFieldEmail.text ?? "",
371
- "phone_number": localPhone,
372
- "description": txtFieldDescription.text ?? ""
373
- ]
374
-
375
- let billingInfo: [String: Any] = [
376
- "address": billingInfoData["address"] as? String ?? "",
377
- "country": billingInfoData["country"] as? String ?? "",
378
- "state": billingInfoData["state"] as? String ?? "",
379
- "city": billingInfoData["city"] as? String ?? "",
380
- "postal_code": billingInfoData["postal_code"] as? String ?? ""
381
- ]
382
-
383
449
  var params: [String: Any] = [
384
- "name": txtFieldName.text ?? "",
385
- "email": txtFieldEmail.text ?? "",
450
+ "name": nameOnCard ?? "",
451
+ "email": userEmail ?? "",
386
452
  "card_number": cardNumber?.replacingOccurrences(of: " ", with: "") ?? "",
387
453
  "cardholder_name": nameOnCard ?? "",
388
454
  "exp_month": expiryDate?.components(separatedBy: "/").first ?? "",
389
455
  "exp_year": expiryDate?.components(separatedBy: "/").last ?? "",
390
456
  "cvc": cvv ?? "",
391
- "description": txtFieldDescription.text ?? "",
392
- "currency": "usd",
393
- "billing_info": billingInfo,
394
- "additional_info": additionalInfo,
395
- "payment_method": "card",
396
- "save_card": 0
457
+ "currency": "usd"
397
458
  ]
398
459
 
460
+ // Conditionally add billing info
461
+ if let visibility = visibility, visibility.billing == true,
462
+ let billing = billingInfo, !billing.isEmpty {
463
+
464
+ var billingInfoDict: [String: Any] = [:]
465
+ for item in billing {
466
+ billingInfoDict[item.name] = item.value
467
+ }
468
+
469
+ params["address"] = billingInfoDict["address"] as? String ?? ""
470
+ params["country"] = billingInfoDict["country"] as? String ?? ""
471
+ params["state"] = billingInfoDict["state"] as? String ?? ""
472
+ params["city"] = billingInfoDict["city"] as? String ?? ""
473
+ params["zip"] = billingInfoDict["postal_code"] as? String ?? ""
474
+ }
475
+
476
+ // Conditionally add additional info
477
+ if let visibility = visibility, visibility.additional == true,
478
+ let additional = additionalInfo, !additional.isEmpty {
479
+ params["description"] = txtFieldDescription.text ?? ""
480
+ params["phone_number"] = localPhone
481
+ }
482
+
399
483
  // Add these if recurring is enabled
400
484
  if let req = request, req.is_recurring == true {
401
485
  if let recurringType = req.recurringStartDateType, recurringType == .custom {
@@ -419,6 +503,8 @@ class AdditionalInfoVC: BaseVC {
419
503
  params["interval"] = chosenPlan?.lowercased()
420
504
  }
421
505
 
506
+ print(params)
507
+
422
508
  do {
423
509
  let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
424
510
  urlRequest.httpBody = jsonData
@@ -466,8 +552,31 @@ class AdditionalInfoVC: BaseVC {
466
552
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
467
553
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
468
554
  // Pass billing and additional info
469
- paymentDoneVC.billingInfo = billingInfo
470
- paymentDoneVC.additionalInfo = additionalInfo
555
+ // Conditionally pass raw FieldItem array
556
+ paymentDoneVC.visibility = self.visibility
557
+
558
+ if self.visibility?.billing == true {
559
+ paymentDoneVC.billingInfoData = self.billingInfo
560
+ var billingDict: [String: Any] = [:]
561
+ self.billingInfo?.forEach { billingDict[$0.name] = $0.value }
562
+ paymentDoneVC.billingInfo = billingDict
563
+ }
564
+
565
+ if self.visibility?.additional == true {
566
+ // Update additionalInfo values before sending
567
+ if let index = self.additionalInfo?.firstIndex(where: { $0.name == "description" }) {
568
+ self.additionalInfo?[index].value = self.txtFieldDescription.text ?? ""
569
+ }
570
+ if let index = self.additionalInfo?.firstIndex(where: { $0.name == "phone_number" }) {
571
+ self.additionalInfo?[index].value = localPhone
572
+ }
573
+
574
+ paymentDoneVC.additionalInfoData = self.additionalInfo
575
+
576
+ var additionalDict: [String: Any] = [:]
577
+ self.additionalInfo?.forEach { additionalDict[$0.name] = $0.value }
578
+ paymentDoneVC.additionalInfo = additionalDict
579
+ }
471
580
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
472
581
  }
473
582
  }
@@ -514,43 +623,12 @@ class AdditionalInfoVC: BaseVC {
514
623
  print("Setting clientToken header: \(token ?? "None")")
515
624
  uRLRequest.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
516
625
 
517
- guard let billingInfoData = billingInfoData else {
518
- print("Billing info data is nil")
519
- return
520
- }
521
-
522
- // // Remove the flag and "+" sign from lblCountryCode.text
523
- // let countryCode = lblCountryCode.text ?? ""
524
- // let cleanedCountryCode = countryCode.replacingOccurrences(of: "[^0-9]", with: "", options: .regularExpression)
525
- // // Format phone number parameter by combining cleaned country code and phone number
526
- // let phoneNumber = "\(cleanedCountryCode)\(txtFieldPhoneNumber.text ?? "")"
527
-
528
626
  // Extract only the digits from the phone number (local only, no country code)
529
627
  let localPhone = txtFieldPhoneNumber.text?.components(separatedBy: CharacterSet.decimalDigits.inverted).joined() ?? ""
530
628
 
531
- let additionalInfo: [String: Any] = [
532
- "name": txtFieldName.text ?? "",
533
- "email": txtFieldEmail.text ?? "",
534
- "phone_number": localPhone,
535
- // "phone_number": phoneNumber,
536
- "description": txtFieldDescription.text ?? ""
537
- ]
538
-
539
- let billingInfo: [String: Any] = [
540
- "address": billingInfoData["address"] as? String ?? "",
541
- "country": billingInfoData["country"] as? String ?? "",
542
- "state": billingInfoData["state"] as? String ?? "",
543
- "city": billingInfoData["city"] as? String ?? "",
544
- "postal_code": billingInfoData["postal_code"] as? String ?? ""
545
- ]
546
-
547
629
  var params: [String: Any] = [
548
- "name": txtFieldName.text ?? "",
549
- "email": txtFieldEmail.text ?? "",
550
630
  "description": txtFieldDescription.text ?? "",
551
631
  "currency": "usd",
552
- "billing_info": billingInfo,
553
- "additional_info": additionalInfo,
554
632
  "payment_method": "card",
555
633
  "save_card": 0,
556
634
  "customer" : selectedCard?.customerId ?? "",
@@ -559,6 +637,57 @@ class AdditionalInfoVC: BaseVC {
559
637
  "cvc" : cvvText ?? ""
560
638
  ]
561
639
 
640
+ // Conditionally add billing info
641
+ if let visibility = visibility, visibility.billing == true,
642
+ let billing = billingInfo, !billing.isEmpty {
643
+
644
+ var billingInfoDict: [String: Any] = [:]
645
+ for item in billing {
646
+ billingInfoDict[item.name] = item.value
647
+ }
648
+
649
+ params["address"] = billingInfoDict["address"] as? String ?? ""
650
+ params["country"] = billingInfoDict["country"] as? String ?? ""
651
+ params["state"] = billingInfoDict["state"] as? String ?? ""
652
+ params["city"] = billingInfoDict["city"] as? String ?? ""
653
+ params["zip"] = billingInfoDict["postal_code"] as? String ?? ""
654
+ }
655
+
656
+ // Default values
657
+ let defaultDescription = "Hosted payment checkout"
658
+ let defaultName = UserStoreSingleton.shared.merchantName ?? ""
659
+ let defaultEmail = UserStoreSingleton.shared.merchantEmail ?? ""
660
+
661
+ // Additional Info
662
+ if let visibility = visibility, visibility.additional == true,
663
+ let additional = additionalInfo, !additional.isEmpty {
664
+
665
+ var additionalInfoDict: [String: Any] = [:]
666
+ for item in additional {
667
+ additionalInfoDict[item.name] = item.value
668
+ }
669
+
670
+ // Description
671
+ let description = (additionalInfoDict["description"] as? String)?.trimmingCharacters(in: .whitespacesAndNewlines)
672
+ params["description"] = (description?.isEmpty == false) ? description! : defaultDescription
673
+
674
+ // Phone
675
+ params["phone_number"] = localPhone
676
+
677
+ // Name
678
+ let name = (additionalInfoDict["name"] as? String)?.trimmingCharacters(in: .whitespacesAndNewlines)
679
+ params["name"] = (name?.isEmpty == false) ? name! : defaultName
680
+
681
+ // Email
682
+ let email = (additionalInfoDict["email"] as? String)?.trimmingCharacters(in: .whitespacesAndNewlines)
683
+ params["email"] = (email?.isEmpty == false) ? email! : defaultEmail
684
+ } else {
685
+ // Fallback if additional section not visible
686
+ params["description"] = defaultDescription
687
+ params["name"] = defaultName
688
+ params["email"] = defaultEmail
689
+ }
690
+
562
691
  // Add these if recurring is enabled
563
692
  if let req = request, req.is_recurring == true {
564
693
  if let recurringType = req.recurringStartDateType, recurringType == .custom {
@@ -628,8 +757,31 @@ class AdditionalInfoVC: BaseVC {
628
757
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
629
758
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
630
759
  // Pass billing and additional info
631
- paymentDoneVC.billingInfo = billingInfo
632
- paymentDoneVC.additionalInfo = additionalInfo
760
+ // Conditionally pass raw FieldItem array
761
+ paymentDoneVC.visibility = self.visibility
762
+
763
+ if self.visibility?.billing == true {
764
+ paymentDoneVC.billingInfoData = self.billingInfo
765
+ var billingDict: [String: Any] = [:]
766
+ self.billingInfo?.forEach { billingDict[$0.name] = $0.value }
767
+ paymentDoneVC.billingInfo = billingDict
768
+ }
769
+
770
+ if self.visibility?.additional == true {
771
+ // Update additionalInfo values before sending
772
+ if let index = self.additionalInfo?.firstIndex(where: { $0.name == "description" }) {
773
+ self.additionalInfo?[index].value = self.txtFieldDescription.text ?? ""
774
+ }
775
+ if let index = self.additionalInfo?.firstIndex(where: { $0.name == "phone_number" }) {
776
+ self.additionalInfo?[index].value = localPhone
777
+ }
778
+
779
+ paymentDoneVC.additionalInfoData = self.additionalInfo
780
+
781
+ var additionalDict: [String: Any] = [:]
782
+ self.additionalInfo?.forEach { additionalDict[$0.name] = $0.value }
783
+ paymentDoneVC.additionalInfo = additionalDict
784
+ }
633
785
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
634
786
  }
635
787
  }
@@ -676,41 +828,20 @@ class AdditionalInfoVC: BaseVC {
676
828
  print("Setting clientToken header: \(token ?? "None")")
677
829
  uRLRequest.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
678
830
 
679
- guard let billingInfoData = billingInfoData else {
680
- print("Billing info data is nil")
681
- return
682
- }
683
-
684
- let additionalInfoFromBilling = billingInfoData["additional_info"] as? [String: Any] ?? [:]
685
-
686
- let additionalInfo: [String: Any] = [
687
- "name": additionalInfoFromBilling["name"] as? String ?? "",
688
- "email": additionalInfoFromBilling["email"] as? String ?? "",
689
- "phone_number": additionalInfoFromBilling["phone_number"] as? String ?? "",
690
- "description": additionalInfoFromBilling["description"] as? String ?? ""
691
- ]
692
-
693
- let billingInfo: [String: Any] = [
694
- "address": billingInfoData["address"] as? String ?? "",
695
- "country": billingInfoData["country"] as? String ?? "",
696
- "state": billingInfoData["state"] as? String ?? "",
697
- "city": billingInfoData["city"] as? String ?? "",
698
- "postal_code": billingInfoData["postal_code"] as? String ?? ""
699
- ]
831
+ // Extract only the digits from the phone number (local only, no country code)
832
+ let localPhone = txtFieldPhoneNumber.text?.components(separatedBy: CharacterSet.decimalDigits.inverted).joined() ?? ""
700
833
 
701
834
  let emailPrefix = UserStoreSingleton.shared.verificationEmail?.components(separatedBy: "@").first ?? ""
702
835
 
703
836
  var params: [String: Any] = [
704
- "name": additionalInfoFromBilling["name"] as? String ?? "",
837
+ "name": nameOnCard ?? "",
838
+ "email": userEmail ?? "",
705
839
  "card_number": cardNumber?.replacingOccurrences(of: " ", with: "") ?? "",
706
840
  "cardholder_name": nameOnCard ?? "",
707
841
  "exp_month": expiryDate?.components(separatedBy: "/").first ?? "",
708
842
  "exp_year": expiryDate?.components(separatedBy: "/").last ?? "",
709
843
  "cvc": cvv ?? "",
710
- "description": additionalInfoFromBilling["description"] as? String ?? "",
711
844
  "currency": "usd",
712
- "billing_info": billingInfo,
713
- "additional_info": additionalInfo,
714
845
  "payment_method": selectedPaymentMethod ?? "",
715
846
  "save_card": isSavedNewCard ? 1 : 0
716
847
  ]
@@ -720,6 +851,29 @@ class AdditionalInfoVC: BaseVC {
720
851
  params["is_default"] = "1"
721
852
  }
722
853
 
854
+ // Conditionally add billing info
855
+ if let visibility = visibility, visibility.billing == true,
856
+ let billing = billingInfo, !billing.isEmpty {
857
+
858
+ var billingInfoDict: [String: Any] = [:]
859
+ for item in billing {
860
+ billingInfoDict[item.name] = item.value
861
+ }
862
+
863
+ params["address"] = billingInfoDict["address"] as? String ?? ""
864
+ params["country"] = billingInfoDict["country"] as? String ?? ""
865
+ params["state"] = billingInfoDict["state"] as? String ?? ""
866
+ params["city"] = billingInfoDict["city"] as? String ?? ""
867
+ params["zip"] = billingInfoDict["postal_code"] as? String ?? ""
868
+ }
869
+
870
+ // Conditionally add additional info
871
+ if let visibility = visibility, visibility.additional == true,
872
+ let additional = additionalInfo, !additional.isEmpty {
873
+ params["description"] = txtFieldDescription.text ?? ""
874
+ params["phone_number"] = localPhone
875
+ }
876
+
723
877
  // Add these if recurring is enabled
724
878
  if let req = request, req.is_recurring == true {
725
879
  if let recurringType = req.recurringStartDateType, recurringType == .custom {
@@ -799,8 +953,31 @@ class AdditionalInfoVC: BaseVC {
799
953
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
800
954
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
801
955
  // Pass billing and additional info
802
- paymentDoneVC.billingInfo = billingInfo
803
- paymentDoneVC.additionalInfo = additionalInfo
956
+ // Conditionally pass raw FieldItem array
957
+ paymentDoneVC.visibility = self.visibility
958
+
959
+ if self.visibility?.billing == true {
960
+ paymentDoneVC.billingInfoData = self.billingInfo
961
+ var billingDict: [String: Any] = [:]
962
+ self.billingInfo?.forEach { billingDict[$0.name] = $0.value }
963
+ paymentDoneVC.billingInfo = billingDict
964
+ }
965
+
966
+ if self.visibility?.additional == true {
967
+ // Update additionalInfo values before sending
968
+ if let index = self.additionalInfo?.firstIndex(where: { $0.name == "description" }) {
969
+ self.additionalInfo?[index].value = self.txtFieldDescription.text ?? ""
970
+ }
971
+ if let index = self.additionalInfo?.firstIndex(where: { $0.name == "phone_number" }) {
972
+ self.additionalInfo?[index].value = localPhone
973
+ }
974
+
975
+ paymentDoneVC.additionalInfoData = self.additionalInfo
976
+
977
+ var additionalDict: [String: Any] = [:]
978
+ self.additionalInfo?.forEach { additionalDict[$0.name] = $0.value }
979
+ paymentDoneVC.additionalInfo = additionalDict
980
+ }
804
981
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
805
982
  }
806
983
  }
@@ -847,43 +1024,14 @@ class AdditionalInfoVC: BaseVC {
847
1024
  print("Setting clientToken header: \(token ?? "None")")
848
1025
  uRLRequest.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
849
1026
 
850
- guard let billingInfoData = billingInfoData else {
851
- print("Billing info data is nil")
852
- return
853
- }
854
-
855
- // // Remove the flag and "+" sign from lblCountryCode.text
856
- // let countryCode = lblCountryCode.text ?? ""
857
- // let cleanedCountryCode = countryCode.replacingOccurrences(of: "[^0-9]", with: "", options: .regularExpression)
858
- // // Format phone number parameter by combining cleaned country code and phone number
859
- // let phoneNumber = "\(cleanedCountryCode)\(txtFieldPhoneNumber.text ?? "")"
860
-
861
1027
  // Extract only the digits from the phone number (local only, no country code)
862
1028
  let localPhone = txtFieldPhoneNumber.text?.components(separatedBy: CharacterSet.decimalDigits.inverted).joined() ?? ""
863
1029
 
864
- let additionalInfo: [String: Any] = [
865
- "name": txtFieldName.text ?? "",
866
- "email": txtFieldEmail.text ?? "",
867
- "phone_number": localPhone,
868
- // "phone_number": phoneNumber,
869
- "description": txtFieldDescription.text ?? ""
870
- ]
871
-
872
- let billingInfo: [String: Any] = [
873
- "address": billingInfoData["address"] as? String ?? "",
874
- "country": billingInfoData["country"] as? String ?? "",
875
- "state": billingInfoData["state"] as? String ?? "",
876
- "city": billingInfoData["city"] as? String ?? "",
877
- "postal_code": billingInfoData["postal_code"] as? String ?? ""
878
- ]
879
-
880
1030
  var params: [String: Any] = [
881
- "name": txtFieldName.text ?? "",
882
- "email": txtFieldEmail.text ?? "",
1031
+ "name": accountName ?? "",
1032
+ "email": userEmail ?? "",
883
1033
  "description": txtFieldDescription.text ?? "",
884
1034
  "currency": "usd",
885
- "billing_info": billingInfo,
886
- "additional_info": additionalInfo,
887
1035
  "account_type": accountType?.lowercased() ?? "",
888
1036
  "routing_number": routingNumber ?? "",
889
1037
  "account_number": accountNumber ?? "",
@@ -892,6 +1040,29 @@ class AdditionalInfoVC: BaseVC {
892
1040
  "levelIndicator": 1,
893
1041
  ]
894
1042
 
1043
+ // Conditionally add billing info
1044
+ if let visibility = visibility, visibility.billing == true,
1045
+ let billing = billingInfo, !billing.isEmpty {
1046
+
1047
+ var billingInfoDict: [String: Any] = [:]
1048
+ for item in billing {
1049
+ billingInfoDict[item.name] = item.value
1050
+ }
1051
+
1052
+ params["address"] = billingInfoDict["address"] as? String ?? ""
1053
+ params["country"] = billingInfoDict["country"] as? String ?? ""
1054
+ params["state"] = billingInfoDict["state"] as? String ?? ""
1055
+ params["city"] = billingInfoDict["city"] as? String ?? ""
1056
+ params["zip"] = billingInfoDict["postal_code"] as? String ?? ""
1057
+ }
1058
+
1059
+ // Conditionally add additional info
1060
+ if let visibility = visibility, visibility.additional == true,
1061
+ let additional = additionalInfo, !additional.isEmpty {
1062
+ params["description"] = txtFieldDescription.text ?? ""
1063
+ params["phone_number"] = localPhone
1064
+ }
1065
+
895
1066
  // Add these if recurring is enabled
896
1067
  if let req = request, req.is_recurring == true {
897
1068
  if let recurringType = req.recurringStartDateType, recurringType == .custom {
@@ -964,8 +1135,31 @@ class AdditionalInfoVC: BaseVC {
964
1135
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
965
1136
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate // Pass the delegate
966
1137
  // Pass billing and additional info
967
- paymentDoneVC.billingInfo = billingInfo
968
- paymentDoneVC.additionalInfo = additionalInfo
1138
+ // Conditionally pass raw FieldItem array
1139
+ paymentDoneVC.visibility = self.visibility
1140
+
1141
+ if self.visibility?.billing == true {
1142
+ paymentDoneVC.billingInfoData = self.billingInfo
1143
+ var billingDict: [String: Any] = [:]
1144
+ self.billingInfo?.forEach { billingDict[$0.name] = $0.value }
1145
+ paymentDoneVC.billingInfo = billingDict
1146
+ }
1147
+
1148
+ if self.visibility?.additional == true {
1149
+ // Update additionalInfo values before sending
1150
+ if let index = self.additionalInfo?.firstIndex(where: { $0.name == "description" }) {
1151
+ self.additionalInfo?[index].value = self.txtFieldDescription.text ?? ""
1152
+ }
1153
+ if let index = self.additionalInfo?.firstIndex(where: { $0.name == "phone_number" }) {
1154
+ self.additionalInfo?[index].value = localPhone
1155
+ }
1156
+
1157
+ paymentDoneVC.additionalInfoData = self.additionalInfo
1158
+
1159
+ var additionalDict: [String: Any] = [:]
1160
+ self.additionalInfo?.forEach { additionalDict[$0.name] = $0.value }
1161
+ paymentDoneVC.additionalInfo = additionalDict
1162
+ }
969
1163
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
970
1164
  }
971
1165
  }
@@ -1012,48 +1206,40 @@ class AdditionalInfoVC: BaseVC {
1012
1206
  print("Setting clientToken header: \(token ?? "None")")
1013
1207
  uRLRequest.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
1014
1208
 
1015
- guard let billingInfoData = billingInfoData else {
1016
- print("Billing info data is nil")
1017
- return
1018
- }
1019
-
1020
- // // Remove the flag and "+" sign from lblCountryCode.text
1021
- // let countryCode = lblCountryCode.text ?? ""
1022
- // let cleanedCountryCode = countryCode.replacingOccurrences(of: "[^0-9]", with: "", options: .regularExpression)
1023
- // // Format phone number parameter by combining cleaned country code and phone number
1024
- // let phoneNumber = "\(cleanedCountryCode)\(txtFieldPhoneNumber.text ?? "")"
1025
-
1026
1209
  // Extract only the digits from the phone number (local only, no country code)
1027
1210
  let localPhone = txtFieldPhoneNumber.text?.components(separatedBy: CharacterSet.decimalDigits.inverted).joined() ?? ""
1028
1211
 
1029
- let additionalInfo: [String: Any] = [
1030
- "name": txtFieldName.text ?? "",
1031
- "email": txtFieldEmail.text ?? "",
1032
- "phone_number": localPhone,
1033
- // "phone_number": phoneNumber,
1034
- "description": txtFieldDescription.text ?? ""
1035
- ]
1036
-
1037
- let billingInfo: [String: Any] = [
1038
- "address": billingInfoData["address"] as? String ?? "",
1039
- "country": billingInfoData["country"] as? String ?? "",
1040
- "state": billingInfoData["state"] as? String ?? "",
1041
- "city": billingInfoData["city"] as? String ?? "",
1042
- "postal_code": billingInfoData["postal_code"] as? String ?? ""
1043
- ]
1044
-
1045
1212
  var params: [String: Any] = [
1046
1213
  "name": UserStoreSingleton.shared.merchantName ?? "",
1047
1214
  "account_id": accountID ?? "",
1048
1215
  "payment_method": "ach",
1049
1216
  "customer": customerID ?? "",
1050
- "address": billingInfoData["address"] as? String ?? "",
1051
- "description": txtFieldDescription.text ?? "",
1052
1217
  "currency": "usd",
1053
- "billing_info": billingInfo,
1054
- "additional_info": additionalInfo
1055
1218
  ]
1056
1219
 
1220
+ // Conditionally add billing info
1221
+ if let visibility = visibility, visibility.billing == true,
1222
+ let billing = billingInfo, !billing.isEmpty {
1223
+
1224
+ var billingInfoDict: [String: Any] = [:]
1225
+ for item in billing {
1226
+ billingInfoDict[item.name] = item.value
1227
+ }
1228
+
1229
+ params["address"] = billingInfoDict["address"] as? String ?? ""
1230
+ params["country"] = billingInfoDict["country"] as? String ?? ""
1231
+ params["state"] = billingInfoDict["state"] as? String ?? ""
1232
+ params["city"] = billingInfoDict["city"] as? String ?? ""
1233
+ params["zip"] = billingInfoDict["postal_code"] as? String ?? ""
1234
+ }
1235
+
1236
+ // Conditionally add additional info
1237
+ if let visibility = visibility, visibility.additional == true,
1238
+ let additional = additionalInfo, !additional.isEmpty {
1239
+ params["description"] = txtFieldDescription.text ?? ""
1240
+ params["phone_number"] = localPhone
1241
+ }
1242
+
1057
1243
  // Add these if recurring is enabled
1058
1244
  if let req = request, req.is_recurring == true {
1059
1245
  if let recurringType = req.recurringStartDateType, recurringType == .custom {
@@ -1126,8 +1312,31 @@ class AdditionalInfoVC: BaseVC {
1126
1312
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
1127
1313
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate // Pass the delegate
1128
1314
  // Pass billing and additional info
1129
- paymentDoneVC.billingInfo = billingInfo
1130
- paymentDoneVC.additionalInfo = additionalInfo
1315
+ // Conditionally pass raw FieldItem array
1316
+ paymentDoneVC.visibility = self.visibility
1317
+
1318
+ if self.visibility?.billing == true {
1319
+ paymentDoneVC.billingInfoData = self.billingInfo
1320
+ var billingDict: [String: Any] = [:]
1321
+ self.billingInfo?.forEach { billingDict[$0.name] = $0.value }
1322
+ paymentDoneVC.billingInfo = billingDict
1323
+ }
1324
+
1325
+ if self.visibility?.additional == true {
1326
+ // Update additionalInfo values before sending
1327
+ if let index = self.additionalInfo?.firstIndex(where: { $0.name == "description" }) {
1328
+ self.additionalInfo?[index].value = self.txtFieldDescription.text ?? ""
1329
+ }
1330
+ if let index = self.additionalInfo?.firstIndex(where: { $0.name == "phone_number" }) {
1331
+ self.additionalInfo?[index].value = localPhone
1332
+ }
1333
+
1334
+ paymentDoneVC.additionalInfoData = self.additionalInfo
1335
+
1336
+ var additionalDict: [String: Any] = [:]
1337
+ self.additionalInfo?.forEach { additionalDict[$0.name] = $0.value }
1338
+ paymentDoneVC.additionalInfo = additionalDict
1339
+ }
1131
1340
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
1132
1341
  }
1133
1342
  }
@@ -1174,37 +1383,15 @@ class AdditionalInfoVC: BaseVC {
1174
1383
  print("Setting clientToken header: \(token ?? "None")")
1175
1384
  uRLRequest.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
1176
1385
 
1177
- guard let billingInfoData = billingInfoData else {
1178
- print("Billing info data is nil")
1179
- return
1180
- }
1181
-
1182
- let additionalInfoFromBilling = billingInfoData["additional_info"] as? [String: Any] ?? [:]
1183
-
1184
- let additionalInfo: [String: Any] = [
1185
- "name": additionalInfoFromBilling["name"] as? String ?? "",
1186
- "email": additionalInfoFromBilling["email"] as? String ?? "",
1187
- "phone_number": additionalInfoFromBilling["phone_number"] as? String ?? "",
1188
- "description": additionalInfoFromBilling["description"] as? String ?? ""
1189
- ]
1190
-
1191
- let billingInfo: [String: Any] = [
1192
- "address": billingInfoData["address"] as? String ?? "",
1193
- "country": billingInfoData["country"] as? String ?? "",
1194
- "state": billingInfoData["state"] as? String ?? "",
1195
- "city": billingInfoData["city"] as? String ?? "",
1196
- "postal_code": billingInfoData["postal_code"] as? String ?? ""
1197
- ]
1386
+ // Extract only the digits from the phone number (local only, no country code)
1387
+ let localPhone = txtFieldPhoneNumber.text?.components(separatedBy: CharacterSet.decimalDigits.inverted).joined() ?? ""
1198
1388
 
1199
1389
  let emailPrefix = UserStoreSingleton.shared.verificationEmail?.components(separatedBy: "@").first ?? ""
1200
1390
 
1201
1391
  var params: [String: Any] = [
1202
- "name": additionalInfoFromBilling["name"] as? String ?? "",
1203
- "email": UserStoreSingleton.shared.verificationEmail ?? "",
1204
- "description": additionalInfoFromBilling["description"] as? String ?? "",
1392
+ "name": accountName ?? "",
1393
+ "email": UserStoreSingleton.shared.merchantEmail ?? "",
1205
1394
  "currency": "usd",
1206
- "billing_info": billingInfo,
1207
- "additional_info": additionalInfo,
1208
1395
  "account_type": accountType?.lowercased() ?? "",
1209
1396
  "routing_number": routingNumber ?? "",
1210
1397
  "account_number": accountNumber ?? "",
@@ -1221,6 +1408,35 @@ class AdditionalInfoVC: BaseVC {
1221
1408
  params["username"] = emailPrefix
1222
1409
  }
1223
1410
 
1411
+ // Conditionally add billing info
1412
+ if let visibility = visibility, visibility.billing == true,
1413
+ let billing = billingInfo, !billing.isEmpty {
1414
+
1415
+ var billingInfoDict: [String: Any] = [:]
1416
+ for item in billing {
1417
+ billingInfoDict[item.name] = item.value
1418
+ }
1419
+
1420
+ params["address"] = billingInfoDict["address"] as? String ?? ""
1421
+ params["country"] = billingInfoDict["country"] as? String ?? ""
1422
+ params["state"] = billingInfoDict["state"] as? String ?? ""
1423
+ params["city"] = billingInfoDict["city"] as? String ?? ""
1424
+ params["zip"] = billingInfoDict["postal_code"] as? String ?? ""
1425
+ }
1426
+
1427
+ // Conditionally add additional info
1428
+ if let visibility = visibility, visibility.additional == true,
1429
+ let additional = additionalInfo, !additional.isEmpty {
1430
+
1431
+ var additionalInfoDict: [String: Any] = [:]
1432
+ for item in additional {
1433
+ additionalInfoDict[item.name] = item.value
1434
+ }
1435
+
1436
+ params["description"] = txtFieldDescription.text ?? ""
1437
+ params["phone_number"] = localPhone
1438
+ }
1439
+
1224
1440
  // Add these if recurring is enabled
1225
1441
  if let req = request, req.is_recurring == true {
1226
1442
  if let recurringType = req.recurringStartDateType, recurringType == .custom {
@@ -1292,8 +1508,31 @@ class AdditionalInfoVC: BaseVC {
1292
1508
  paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
1293
1509
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
1294
1510
  // Pass billing and additional info
1295
- paymentDoneVC.billingInfo = billingInfo
1296
- paymentDoneVC.additionalInfo = additionalInfo
1511
+ // Conditionally pass raw FieldItem array
1512
+ paymentDoneVC.visibility = self.visibility
1513
+
1514
+ if self.visibility?.billing == true {
1515
+ paymentDoneVC.billingInfoData = self.billingInfo
1516
+ var billingDict: [String: Any] = [:]
1517
+ self.billingInfo?.forEach { billingDict[$0.name] = $0.value }
1518
+ paymentDoneVC.billingInfo = billingDict
1519
+ }
1520
+
1521
+ if self.visibility?.additional == true {
1522
+ // Update additionalInfo values before sending
1523
+ if let index = self.additionalInfo?.firstIndex(where: { $0.name == "description" }) {
1524
+ self.additionalInfo?[index].value = self.txtFieldDescription.text ?? ""
1525
+ }
1526
+ if let index = self.additionalInfo?.firstIndex(where: { $0.name == "phone_number" }) {
1527
+ self.additionalInfo?[index].value = localPhone
1528
+ }
1529
+
1530
+ paymentDoneVC.additionalInfoData = self.additionalInfo
1531
+
1532
+ var additionalDict: [String: Any] = [:]
1533
+ self.additionalInfo?.forEach { additionalDict[$0.name] = $0.value }
1534
+ paymentDoneVC.additionalInfo = additionalDict
1535
+ }
1297
1536
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
1298
1537
  }
1299
1538
  }
@@ -1349,46 +1588,44 @@ class AdditionalInfoVC: BaseVC {
1349
1588
  uRLRequest.addValue(apiSecret, forHTTPHeaderField: "x-api-secret")
1350
1589
  }
1351
1590
 
1352
- guard let billingInfoData = billingInfoData else {
1353
- print("Billing info data is nil")
1354
- hideLoadingIndicator()
1355
- return
1356
- }
1357
-
1358
1591
  // Extract only the digits from the phone number (local only, no country code)
1359
1592
  let localPhone = txtFieldPhoneNumber.text?.components(separatedBy: CharacterSet.decimalDigits.inverted).joined() ?? ""
1360
1593
 
1361
- let additionalInfo: [String: Any] = [
1362
- "name": txtFieldName.text ?? "",
1363
- "email": txtFieldEmail.text ?? "",
1364
- "phone_number": localPhone,
1365
- "description": txtFieldDescription.text ?? ""
1366
- ]
1367
-
1368
- let billingInfo: [String: Any] = [
1369
- "address": billingInfoData["address"] as? String ?? "",
1370
- "country": billingInfoData["country"] as? String ?? "",
1371
- "state": billingInfoData["state"] as? String ?? "",
1372
- "city": billingInfoData["city"] as? String ?? "",
1373
- "postal_code": billingInfoData["postal_code"] as? String ?? ""
1374
- ]
1375
-
1376
1594
  var params: [String: Any] = [
1377
1595
  "name": nameOnCard ?? "",
1378
- "email": txtFieldEmail.text ?? "",
1596
+ "email": userEmail ?? "",
1379
1597
  "card_number": cardNumber?.replacingOccurrences(of: " ", with: "") ?? "",
1380
1598
  "cardholder_name": nameOnCard ?? "",
1381
1599
  "exp_month": expiryDate?.components(separatedBy: "/").first ?? "",
1382
1600
  "exp_year": expiryDate?.components(separatedBy: "/").last ?? "",
1383
1601
  "cvc": cvv ?? "",
1384
- "description": "Test",
1385
1602
  "currency": "usd",
1386
- "tokenize": request.tokenOnly ?? false,
1387
- "address": billingInfoData["address"] as? String ?? "",
1388
- "billing_info": billingInfo,
1389
- "additional_info": additionalInfo
1603
+ "tokenize": request.tokenOnly ?? false
1390
1604
  ]
1391
1605
 
1606
+ // Conditionally add billing info
1607
+ if let visibility = visibility, visibility.billing == true,
1608
+ let billing = billingInfo, !billing.isEmpty {
1609
+
1610
+ var billingInfoDict: [String: Any] = [:]
1611
+ for item in billing {
1612
+ billingInfoDict[item.name] = item.value
1613
+ }
1614
+
1615
+ params["address"] = billingInfoDict["address"] as? String ?? ""
1616
+ params["country"] = billingInfoDict["country"] as? String ?? ""
1617
+ params["state"] = billingInfoDict["state"] as? String ?? ""
1618
+ params["city"] = billingInfoDict["city"] as? String ?? ""
1619
+ params["zip"] = billingInfoDict["postal_code"] as? String ?? ""
1620
+ }
1621
+
1622
+ // Conditionally add additional info
1623
+ if let visibility = visibility, visibility.additional == true,
1624
+ let additional = additionalInfo, !additional.isEmpty {
1625
+ params["description"] = txtFieldDescription.text ?? ""
1626
+ params["phone_number"] = localPhone
1627
+ }
1628
+
1392
1629
  // Add these if recurring is enabled
1393
1630
  if let req = request, req.is_recurring == true {
1394
1631
  if let recurringType = req.recurringStartDateType, recurringType == .custom {
@@ -1412,6 +1649,8 @@ class AdditionalInfoVC: BaseVC {
1412
1649
  params["interval"] = chosenPlan?.lowercased()
1413
1650
  }
1414
1651
 
1652
+ print(params)
1653
+
1415
1654
  do {
1416
1655
  let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
1417
1656
  uRLRequest.httpBody = jsonData
@@ -1460,8 +1699,33 @@ class AdditionalInfoVC: BaseVC {
1460
1699
  paymentDoneVC.chargeData = responseObject
1461
1700
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
1462
1701
  // Pass billing and additional info
1463
- paymentDoneVC.billingInfo = billingInfo
1464
- paymentDoneVC.additionalInfo = additionalInfo
1702
+ // Conditionally pass raw FieldItem array
1703
+ paymentDoneVC.visibility = self.visibility
1704
+ paymentDoneVC.amount = self.amount
1705
+
1706
+ if self.visibility?.billing == true {
1707
+ paymentDoneVC.billingInfoData = self.billingInfo
1708
+ var billingDict: [String: Any] = [:]
1709
+ self.billingInfo?.forEach { billingDict[$0.name] = $0.value }
1710
+ paymentDoneVC.billingInfo = billingDict
1711
+ }
1712
+
1713
+ if self.visibility?.additional == true {
1714
+ // Update additionalInfo values before sending
1715
+ if let index = self.additionalInfo?.firstIndex(where: { $0.name == "description" }) {
1716
+ self.additionalInfo?[index].value = self.txtFieldDescription.text ?? ""
1717
+ }
1718
+ if let index = self.additionalInfo?.firstIndex(where: { $0.name == "phone_number" }) {
1719
+ self.additionalInfo?[index].value = localPhone
1720
+ }
1721
+
1722
+ paymentDoneVC.additionalInfoData = self.additionalInfo
1723
+
1724
+ var additionalDict: [String: Any] = [:]
1725
+ self.additionalInfo?.forEach { additionalDict[$0.name] = $0.value }
1726
+ paymentDoneVC.additionalInfo = additionalDict
1727
+ }
1728
+
1465
1729
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
1466
1730
  }
1467
1731
  }
@@ -1515,33 +1779,12 @@ class AdditionalInfoVC: BaseVC {
1515
1779
  uRLRequest.addValue(apiSecret, forHTTPHeaderField: "x-api-secret")
1516
1780
  }
1517
1781
 
1518
- guard let billingInfoData = billingInfoData else {
1519
- print("Billing info data is nil")
1520
- hideLoadingIndicator()
1521
- return
1522
- }
1523
-
1524
1782
  // Extract only the digits from the phone number (local only, no country code)
1525
1783
  let localPhone = txtFieldPhoneNumber.text?.components(separatedBy: CharacterSet.decimalDigits.inverted).joined() ?? ""
1526
1784
 
1527
- let additionalInfo: [String: Any] = [
1528
- "name": txtFieldName.text ?? "",
1529
- "email": txtFieldEmail.text ?? "",
1530
- "phone_number": localPhone,
1531
- "description": txtFieldDescription.text ?? ""
1532
- ]
1533
-
1534
- let billingInfo: [String: Any] = [
1535
- "address": billingInfoData["address"] as? String ?? "",
1536
- "country": billingInfoData["country"] as? String ?? "",
1537
- "state": billingInfoData["state"] as? String ?? "",
1538
- "city": billingInfoData["city"] as? String ?? "",
1539
- "postal_code": billingInfoData["postal_code"] as? String ?? ""
1540
- ]
1541
-
1542
1785
  var params: [String: Any] = [
1543
1786
  "name": nameOnCard ?? "",
1544
- "email": txtFieldEmail.text ?? "",
1787
+ "email": userEmail ?? "",
1545
1788
  "card_number": cardNumber?.replacingOccurrences(of: " ", with: "") ?? "",
1546
1789
  "cardholder_name": nameOnCard ?? "",
1547
1790
  "exp_month": expiryDate?.components(separatedBy: "/").first ?? "",
@@ -1550,9 +1793,6 @@ class AdditionalInfoVC: BaseVC {
1550
1793
  "description": "Test",
1551
1794
  "currency": "usd",
1552
1795
  "tokenize": request.tokenOnly ?? false,
1553
- "address": billingInfoData["address"] as? String ?? "",
1554
- "billing_info": billingInfo,
1555
- "additional_info": additionalInfo,
1556
1796
  "save_card": isSavedNewCard ? 1 : 0,
1557
1797
  "customer_id": customerId ?? ""
1558
1798
  ]
@@ -1562,6 +1802,29 @@ class AdditionalInfoVC: BaseVC {
1562
1802
  params["is_default"] = "1"
1563
1803
  }
1564
1804
 
1805
+ // Conditionally add billing info
1806
+ if let visibility = visibility, visibility.billing == true,
1807
+ let billing = billingInfo, !billing.isEmpty {
1808
+
1809
+ var billingInfoDict: [String: Any] = [:]
1810
+ for item in billing {
1811
+ billingInfoDict[item.name] = item.value
1812
+ }
1813
+
1814
+ params["address"] = billingInfoDict["address"] as? String ?? ""
1815
+ params["country"] = billingInfoDict["country"] as? String ?? ""
1816
+ params["state"] = billingInfoDict["state"] as? String ?? ""
1817
+ params["city"] = billingInfoDict["city"] as? String ?? ""
1818
+ params["zip"] = billingInfoDict["postal_code"] as? String ?? ""
1819
+ }
1820
+
1821
+ // Conditionally add additional info
1822
+ if let visibility = visibility, visibility.additional == true,
1823
+ let additional = additionalInfo, !additional.isEmpty {
1824
+ params["description"] = txtFieldDescription.text ?? ""
1825
+ params["phone_number"] = localPhone
1826
+ }
1827
+
1565
1828
  // Add these if recurring is enabled
1566
1829
  if let req = request, req.is_recurring == true {
1567
1830
  if let recurringType = req.recurringStartDateType, recurringType == .custom {
@@ -1633,8 +1896,221 @@ class AdditionalInfoVC: BaseVC {
1633
1896
  paymentDoneVC.chargeData = responseObject
1634
1897
  paymentDoneVC.easyPayDelegate = self.easyPayDelegate
1635
1898
  // Pass billing and additional info
1636
- paymentDoneVC.billingInfo = billingInfo
1637
- paymentDoneVC.additionalInfo = additionalInfo
1899
+ // Conditionally pass raw FieldItem array
1900
+ paymentDoneVC.visibility = self.visibility
1901
+ paymentDoneVC.amount = self.amount
1902
+
1903
+ if self.visibility?.billing == true {
1904
+ paymentDoneVC.billingInfoData = self.billingInfo
1905
+ var billingDict: [String: Any] = [:]
1906
+ self.billingInfo?.forEach { billingDict[$0.name] = $0.value }
1907
+ paymentDoneVC.billingInfo = billingDict
1908
+ }
1909
+
1910
+ if self.visibility?.additional == true {
1911
+ // Update additionalInfo values before sending
1912
+ if let index = self.additionalInfo?.firstIndex(where: { $0.name == "description" }) {
1913
+ self.additionalInfo?[index].value = self.txtFieldDescription.text ?? ""
1914
+ }
1915
+ if let index = self.additionalInfo?.firstIndex(where: { $0.name == "phone_number" }) {
1916
+ self.additionalInfo?[index].value = localPhone
1917
+ }
1918
+
1919
+ paymentDoneVC.additionalInfoData = self.additionalInfo
1920
+
1921
+ var additionalDict: [String: Any] = [:]
1922
+ self.additionalInfo?.forEach { additionalDict[$0.name] = $0.value }
1923
+ paymentDoneVC.additionalInfo = additionalDict
1924
+ }
1925
+ self.navigationController?.pushViewController(paymentDoneVC, animated: true)
1926
+ }
1927
+ }
1928
+ }
1929
+ } else {
1930
+ self.presentPaymentErrorVC(errorMessage: "Invalid JSON format")
1931
+ }
1932
+ } catch let jsonError {
1933
+ self.presentPaymentErrorVC(errorMessage: "Error parsing JSON: \(jsonError)")
1934
+ }
1935
+ } else {
1936
+ self.presentPaymentErrorVC(errorMessage: "No data received")
1937
+ }
1938
+ } else {
1939
+ if let data = serviceData,
1940
+ let responseObj = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
1941
+ let message = responseObj["message"] as? String {
1942
+ self.presentPaymentErrorVC(errorMessage: message)
1943
+ } else {
1944
+ self.presentPaymentErrorVC(errorMessage: "HTTP Status Code: \(httpResponse.statusCode)")
1945
+ }
1946
+ }
1947
+ }
1948
+ task.resume()
1949
+ }
1950
+
1951
+ //MARK: - GrailPay Account Charge Api if user not saved account but billing info available
1952
+ func grailPayAccountChargeApi() {
1953
+ showLoadingIndicator()
1954
+
1955
+ let fullURL = EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.achCharge.path()
1956
+
1957
+ guard let serviceURL = URL(string: fullURL) else {
1958
+ print("Invalid URL")
1959
+ hideLoadingIndicator()
1960
+ return
1961
+ }
1962
+
1963
+ var uRLRequest = URLRequest(url: serviceURL)
1964
+ uRLRequest.httpMethod = "POST"
1965
+ uRLRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
1966
+
1967
+ let token = UserStoreSingleton.shared.clientToken
1968
+ print("Setting clientToken header: \(token ?? "None")")
1969
+ uRLRequest.addValue(token ?? "", forHTTPHeaderField: "Client-Token")
1970
+
1971
+ if let apiKey = EnvironmentConfig.apiKey {
1972
+ uRLRequest.addValue(apiKey, forHTTPHeaderField: "X-Api-Key")
1973
+ }
1974
+ if let apiSecret = EnvironmentConfig.apiSecret {
1975
+ uRLRequest.addValue(apiSecret, forHTTPHeaderField: "X-Api-Secret")
1976
+ }
1977
+
1978
+ // Extract only the digits from the phone number (local only, no country code)
1979
+ let localPhone = txtFieldPhoneNumber.text?.components(separatedBy: CharacterSet.decimalDigits.inverted).joined() ?? ""
1980
+
1981
+ var params: [String: Any] = [
1982
+ "account_id": self.grailPayAccountID ?? "",
1983
+ "account_type": self.selectedGrailPayAccountType ?? "",
1984
+ "name": self.selectedGrailPayAccountName ?? "",
1985
+ "description": "payment checkout",
1986
+ "email": UserStoreSingleton.shared.merchantEmail ?? ""
1987
+ ]
1988
+
1989
+ // Conditionally add billing info
1990
+ if let visibility = visibility, visibility.billing == true,
1991
+ let billing = billingInfo, !billing.isEmpty {
1992
+
1993
+ var billingInfoDict: [String: Any] = [:]
1994
+ for item in billing {
1995
+ billingInfoDict[item.name] = item.value
1996
+ }
1997
+
1998
+ params["address"] = billingInfoDict["address"] as? String ?? ""
1999
+ params["country"] = billingInfoDict["country"] as? String ?? ""
2000
+ params["state"] = billingInfoDict["state"] as? String ?? ""
2001
+ params["city"] = billingInfoDict["city"] as? String ?? ""
2002
+ params["zip"] = billingInfoDict["postal_code"] as? String ?? ""
2003
+ }
2004
+
2005
+ // Conditionally add additional info
2006
+ if let visibility = visibility, visibility.additional == true,
2007
+ let additional = additionalInfo, !additional.isEmpty {
2008
+
2009
+ var additionalInfoDict: [String: Any] = [:]
2010
+ for item in additional {
2011
+ additionalInfoDict[item.name] = item.value
2012
+ }
2013
+
2014
+ params["description"] = txtFieldDescription.text ?? ""
2015
+ params["phone_number"] = localPhone
2016
+ }
2017
+
2018
+ // Add these if recurring is enabled
2019
+ if let req = request, req.is_recurring == true {
2020
+ if let recurringType = req.recurringStartDateType, recurringType == .custom {
2021
+ // Only send start_date if type is .custom and field is not empty
2022
+ if let startDateText = startDate, !startDateText.isEmpty {
2023
+ let inputFormatter = DateFormatter()
2024
+ inputFormatter.dateFormat = "dd/MM/yyyy"
2025
+
2026
+ let outputFormatter = DateFormatter()
2027
+ outputFormatter.dateFormat = "MM/dd/yyyy"
2028
+
2029
+ if let date = inputFormatter.date(from: startDateText) {
2030
+ let apiFormattedDate = outputFormatter.string(from: date)
2031
+ params["start_date"] = apiFormattedDate
2032
+ } else {
2033
+ print("Invalid date format in startDateText")
2034
+ }
2035
+ }
2036
+ }
2037
+
2038
+ params["interval"] = chosenPlan?.lowercased()
2039
+ }
2040
+
2041
+ print(params)
2042
+
2043
+ do {
2044
+ let jsonData = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
2045
+ uRLRequest.httpBody = jsonData
2046
+ if let jsonString = String(data: jsonData, encoding: .utf8) {
2047
+ print("JSON Payload: \(jsonString)")
2048
+ }
2049
+ } catch let error {
2050
+ print("Error creating JSON data: \(error)")
2051
+ hideLoadingIndicator()
2052
+ return
2053
+ }
2054
+
2055
+ let session = URLSession.shared
2056
+ let task = session.dataTask(with: uRLRequest) { (serviceData, serviceResponse, error) in
2057
+
2058
+ DispatchQueue.main.async {
2059
+ self.hideLoadingIndicator() // Stop loader when response is received
2060
+ }
2061
+
2062
+ if let error = error {
2063
+ self.presentPaymentErrorVC(errorMessage: error.localizedDescription)
2064
+ return
2065
+ }
2066
+
2067
+ guard let httpResponse = serviceResponse as? HTTPURLResponse else {
2068
+ self.presentPaymentErrorVC(errorMessage: "Invalid response")
2069
+ return
2070
+ }
2071
+
2072
+ if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
2073
+ if let data = serviceData {
2074
+ do {
2075
+ if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
2076
+ print("Response Data: \(responseObject)")
2077
+
2078
+ // Check if status is 0 and handle the error
2079
+ if let status = responseObject["status"] as? Int, status == 0 {
2080
+ let errorMessage = responseObject["message"] as? String ?? "Unknown error"
2081
+ self.presentPaymentErrorVC(errorMessage: errorMessage)
2082
+ } else {
2083
+ DispatchQueue.main.async {
2084
+ if let paymentDoneVC = self.storyboard?.instantiateViewController(withIdentifier: "PaymentDoneVC") as? PaymentDoneVC {
2085
+ paymentDoneVC.chargeData = responseObject
2086
+ paymentDoneVC.selectedPaymentMethod = self.selectedPaymentMethod
2087
+ paymentDoneVC.easyPayDelegate = self.easyPayDelegate
2088
+ // Pass billing and additional info
2089
+ // Conditionally pass raw FieldItem array
2090
+ paymentDoneVC.visibility = self.visibility
2091
+
2092
+ if self.visibility?.billing == true {
2093
+ paymentDoneVC.billingInfoData = self.billingInfo
2094
+ var billingDict: [String: Any] = [:]
2095
+ self.billingInfo?.forEach { billingDict[$0.name] = $0.value }
2096
+ paymentDoneVC.billingInfo = billingDict
2097
+ }
2098
+
2099
+ if self.visibility?.additional == true {
2100
+ // Update additionalInfo values before sending
2101
+ if let index = self.additionalInfo?.firstIndex(where: { $0.name == "description" }) {
2102
+ self.additionalInfo?[index].value = self.txtFieldDescription.text ?? ""
2103
+ }
2104
+ if let index = self.additionalInfo?.firstIndex(where: { $0.name == "phone_number" }) {
2105
+ self.additionalInfo?[index].value = localPhone
2106
+ }
2107
+
2108
+ paymentDoneVC.additionalInfoData = self.additionalInfo
2109
+
2110
+ var additionalDict: [String: Any] = [:]
2111
+ self.additionalInfo?.forEach { additionalDict[$0.name] = $0.value }
2112
+ paymentDoneVC.additionalInfo = additionalDict
2113
+ }
1638
2114
  self.navigationController?.pushViewController(paymentDoneVC, animated: true)
1639
2115
  }
1640
2116
  }
@@ -1672,3 +2148,16 @@ extension AdditionalInfoVC: CountryListVCDelegate {
1672
2148
  lblCountryCode.text = "\(country.flag ?? "") +\(country.extensionCode ?? "")"
1673
2149
  }
1674
2150
  }
2151
+
2152
+ extension String {
2153
+ static func flag(for countryCode: String) -> String {
2154
+ let base : UInt32 = 127397
2155
+ var s = ""
2156
+ for v in countryCode.uppercased().unicodeScalars {
2157
+ if let scalar = UnicodeScalar(base + v.value) {
2158
+ s.unicodeScalars.append(scalar)
2159
+ }
2160
+ }
2161
+ return s
2162
+ }
2163
+ }