@jimrising/easymerchantsdk-react-native 2.2.9 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.idea/caches/deviceStreaming.xml +11 -0
- package/README.md +310 -171
- package/android/build/.transforms/20e1216b87bd06eaab3c9e5c68d4267a/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule$2.dex +0 -0
- package/android/build/.transforms/20e1216b87bd06eaab3c9e5c68d4267a/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule$3.dex +0 -0
- package/android/build/.transforms/20e1216b87bd06eaab3c9e5c68d4267a/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule.dex +0 -0
- package/android/build/.transforms/20e1216b87bd06eaab3c9e5c68d4267a/transformed/bundleLibRuntimeToDirDebug/desugar_graph.bin +0 -0
- package/android/build/.transforms/3f3a228346492fb34e3f574e941b632f/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/com/reactlibrary/RNEasymerchantsdkModule$2.dex +0 -0
- package/android/build/.transforms/3f3a228346492fb34e3f574e941b632f/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/com/reactlibrary/RNEasymerchantsdkModule$3.dex +0 -0
- package/android/build/.transforms/3f3a228346492fb34e3f574e941b632f/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/com/reactlibrary/RNEasymerchantsdkModule.dex +0 -0
- package/android/build/.transforms/3f3a228346492fb34e3f574e941b632f/transformed/bundleLibRuntimeToDirRelease/desugar_graph.bin +0 -0
- package/android/build/.transforms/58b147bdc43284da2468dab19bc4a64d/transformed/classes/classes_dex/classes.dex +0 -0
- package/android/build/.transforms/e9a664a11ce12edf79cd87b1e07aa243/transformed/classes/classes_dex/classes.dex +0 -0
- package/android/build/intermediates/aar_main_jar/release/syncReleaseLibJars/classes.jar +0 -0
- package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
- package/android/build/intermediates/compile_library_classes_jar/release/bundleLibCompileToJarRelease/classes.jar +0 -0
- package/android/build/intermediates/full_jar/release/createFullJarRelease/full.jar +0 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
- package/android/build/intermediates/incremental/lintVitalAnalyzeRelease/release-artifact-dependencies.xml +4 -4
- package/android/build/intermediates/incremental/lintVitalAnalyzeRelease/release-artifact-libraries.xml +4 -4
- package/android/build/intermediates/incremental/release/mergeReleaseResources/compile-file-map.properties +916 -916
- package/android/build/intermediates/incremental/release/mergeReleaseResources/merger.xml +3 -3
- package/android/build/intermediates/incremental/release/packageReleaseResources/compile-file-map.properties +1 -1
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$2.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$3.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
- package/android/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$2.class +0 -0
- package/android/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$3.class +0 -0
- package/android/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
- package/android/build/intermediates/lint-cache/lintVitalAnalyzeRelease/maven.google/com/android/tools/build/group-index.xml +22 -0
- package/android/build/intermediates/lint_model/release/generateReleaseLintModel/release-artifact-dependencies.xml +4 -4
- package/android/build/intermediates/lint_model/release/generateReleaseLintModel/release-artifact-libraries.xml +4 -4
- package/android/build/intermediates/lint_vital_lint_model/release/generateReleaseLintVitalModel/release-artifact-dependencies.xml +4 -4
- package/android/build/intermediates/lint_vital_lint_model/release/generateReleaseLintVitalModel/release-artifact-libraries.xml +4 -4
- package/android/build/intermediates/local_aar_for_lint/release/out.aar +0 -0
- package/android/build/intermediates/merged_res/release/mergeReleaseResources/layout/activity_payment_done_url.xml +2 -1
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/multi-v2/values-night-v8.json +2 -2
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/multi-v2/values.json +38 -38
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/anim-v21.json +9 -9
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/anim.json +24 -24
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/animator-v21.json +1 -1
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/animator.json +34 -34
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/color-night-v8.json +3 -3
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/color-v31.json +10 -10
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/color.json +153 -153
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-anydpi-v21.json +6 -6
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-hdpi-v4.json +13 -13
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-ldpi-v4.json +6 -6
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-mdpi-v4.json +12 -12
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-v21.json +4 -4
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-v23.json +7 -7
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-v29.json +1 -1
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-xhdpi-v4.json +12 -12
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-xxhdpi-v4.json +7 -7
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-xxxhdpi-v4.json +7 -7
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable.json +395 -395
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/font.json +9 -9
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/interpolator-v21.json +10 -10
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/interpolator.json +11 -11
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/layout-land.json +3 -3
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/layout-sw600dp-v13.json +2 -2
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/layout-v21.json +4 -4
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/layout-v26.json +1 -1
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/layout.json +108 -108
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-anydpi-v26.json +2 -2
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-hdpi-v4.json +2 -2
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-mdpi-v4.json +2 -2
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-xhdpi-v4.json +2 -2
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-xxhdpi-v4.json +2 -2
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-xxxhdpi-v4.json +2 -2
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/raw.json +46 -46
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/xml.json +3 -3
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule$2.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule$3.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/com/reactlibrary/RNEasymerchantsdkModule$2.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/com/reactlibrary/RNEasymerchantsdkModule$3.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
- package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
- package/android/build/intermediates/runtime_library_classes_jar/release/bundleLibRuntimeToJarRelease/classes.jar +0 -0
- package/android/build/intermediates/source_set_path_map/release/mapReleaseSourceSetPaths/file-map.txt +38 -38
- package/android/build/intermediates/verified_library_resources/release/verifyReleaseResources/compiled/layout_activity_payment_done_url.xml.flat +0 -0
- package/android/build/outputs/aar/jimrising_easymerchantsdk-react-native-release.aar +0 -0
- package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
- package/android/build/tmp/compileReleaseJavaWithJavac/previous-compilation-data.bin +0 -0
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/reactlibrary/RNEasymerchantsdkModule.java +56 -1
- package/ios/Classes/EasyMerchantSdk.m +124 -141
- package/ios/Classes/EasyMerchantSdk.swift +270 -502
- package/ios/Classes/EasyPayViewController.swift +18 -15
- package/ios/CustomComponents/TextFieldStackView.swift +16 -46
- package/ios/EnvironmentConfig.swift +16 -0
- package/ios/Example/ViewController.swift +513 -76
- package/ios/Models/Request.swift +365 -171
- package/ios/Pods/UserDefaults/UserStoreSingleton.swift +116 -12
- package/ios/Pods/ViewControllers/AdditionalInfoVC.swift +2 -32
- package/ios/Pods/ViewControllers/GrailPayVC.swift +258 -18
- package/ios/Pods/ViewControllers/OTPVerificationVC.swift +1 -66
- package/ios/Pods/ViewControllers/PaymentInformation/PaymentInfoVC.swift +571 -369
- package/ios/Pods/ViewControllers/ThreeDSecurePaymentDoneVC.swift +18 -9
- package/ios/easymerchantsdk.podspec +1 -1
- package/ios/easymerchantsdk.storyboard +108 -85
- package/package.json +1 -1
package/ios/Models/Request.swift
CHANGED
|
@@ -59,9 +59,9 @@ public struct ThemeConfiguration: Codable {
|
|
|
59
59
|
public struct GrailPayRequest: Codable {
|
|
60
60
|
// public let accessToken: String
|
|
61
61
|
// public let vendorId: String
|
|
62
|
+
// public let isSandbox: Bool
|
|
62
63
|
public let role: String
|
|
63
64
|
public let timeout: Int
|
|
64
|
-
public let isSandbox: Bool
|
|
65
65
|
public let brandingName: String
|
|
66
66
|
public let finderSubtitle: String
|
|
67
67
|
public let searchPlaceholder: String
|
|
@@ -69,18 +69,18 @@ public struct GrailPayRequest: Codable {
|
|
|
69
69
|
public init(
|
|
70
70
|
// accessToken: String,
|
|
71
71
|
// vendorId: String,
|
|
72
|
+
// isSandbox: Bool,
|
|
72
73
|
role: String,
|
|
73
74
|
timeout: Int,
|
|
74
|
-
isSandbox: Bool,
|
|
75
75
|
brandingName: String,
|
|
76
76
|
finderSubtitle: String,
|
|
77
77
|
searchPlaceholder: String
|
|
78
78
|
) {
|
|
79
79
|
// self.accessToken = accessToken
|
|
80
80
|
// self.vendorId = vendorId
|
|
81
|
+
// self.isSandbox = isSandbox
|
|
81
82
|
self.role = role
|
|
82
83
|
self.timeout = timeout
|
|
83
|
-
self.isSandbox = isSandbox
|
|
84
84
|
self.brandingName = brandingName
|
|
85
85
|
self.finderSubtitle = finderSubtitle
|
|
86
86
|
self.searchPlaceholder = searchPlaceholder
|
|
@@ -146,11 +146,11 @@ public struct FieldSection: Codable {
|
|
|
146
146
|
|
|
147
147
|
@objc
|
|
148
148
|
public final class Request: NSObject {
|
|
149
|
-
public
|
|
149
|
+
public var amount: Double?
|
|
150
150
|
public let currency: String?
|
|
151
151
|
public let fields: Data?
|
|
152
152
|
public let appearanceSettings: ThemeConfiguration?
|
|
153
|
-
public
|
|
153
|
+
public var selectedPaymentMethods: [PaymentMethod]
|
|
154
154
|
public let tokenOnly: Bool?
|
|
155
155
|
public let saveCard: Bool?
|
|
156
156
|
public let saveAccount: Bool?
|
|
@@ -172,8 +172,11 @@ public final class Request: NSObject {
|
|
|
172
172
|
public let email: String?
|
|
173
173
|
public let name: String?
|
|
174
174
|
|
|
175
|
+
public let clientToken: String?
|
|
176
|
+
|
|
175
177
|
public var metadata: [String: Any]?
|
|
176
|
-
|
|
178
|
+
public private(set) var initializationErrorMessage: String?
|
|
179
|
+
|
|
177
180
|
public init(
|
|
178
181
|
amount: Double? = nil,
|
|
179
182
|
currency: String? = nil,
|
|
@@ -200,28 +203,13 @@ public final class Request: NSObject {
|
|
|
200
203
|
isEmail: Bool = false,
|
|
201
204
|
email: String? = nil,
|
|
202
205
|
name: String? = nil,
|
|
206
|
+
clientToken: String? = nil,
|
|
207
|
+
metadata: [String: Any]? = nil,
|
|
203
208
|
|
|
204
|
-
|
|
209
|
+
environment: EnvironmentConfig.Environment? = nil,
|
|
210
|
+
apiKey: String? = nil,
|
|
211
|
+
apiSecret: String? = nil
|
|
205
212
|
) {
|
|
206
|
-
// Validate if amount is provided, must be ≥ 0.50
|
|
207
|
-
if let amt = amount, amt < 0.50 {
|
|
208
|
-
DispatchQueue.main.async {
|
|
209
|
-
if let topVC = UIApplication.topViewController() {
|
|
210
|
-
let alert = UIAlertController(title: "Invalid Amount",
|
|
211
|
-
message: "Amount must be at least $0.50.",
|
|
212
|
-
preferredStyle: .alert)
|
|
213
|
-
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in
|
|
214
|
-
if let easyPayVC = UIApplication.findEasyPayViewController(from: topVC) {
|
|
215
|
-
easyPayVC.dismiss(animated: true)
|
|
216
|
-
} else {
|
|
217
|
-
// fallback: dismiss topVC itself if it's presented modally
|
|
218
|
-
topVC.dismiss(animated: true)
|
|
219
|
-
}
|
|
220
|
-
}))
|
|
221
|
-
topVC.present(alert, animated: true)
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
213
|
|
|
226
214
|
self.amount = amount
|
|
227
215
|
self.currency = currency
|
|
@@ -248,8 +236,20 @@ public final class Request: NSObject {
|
|
|
248
236
|
self.email = email
|
|
249
237
|
self.name = name
|
|
250
238
|
|
|
239
|
+
self.clientToken = clientToken
|
|
240
|
+
|
|
251
241
|
self.metadata = metadata
|
|
252
242
|
|
|
243
|
+
// Configure environment if provided
|
|
244
|
+
if let environment = environment {
|
|
245
|
+
EnvironmentConfig.setEnvironment(environment)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Configure API credentials if provided
|
|
249
|
+
if let key = apiKey, let secret = apiSecret {
|
|
250
|
+
EnvironmentConfig.configure(apiKey: key, apiSecret: secret)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
253
|
// Conditionally assign recurring fields only if is_recurring == true
|
|
254
254
|
if is_recurring {
|
|
255
255
|
self.is_recurring = true
|
|
@@ -289,21 +289,127 @@ public final class Request: NSObject {
|
|
|
289
289
|
}
|
|
290
290
|
|
|
291
291
|
super.init()
|
|
292
|
+
|
|
293
|
+
// Environment must be set by host app
|
|
294
|
+
// if EnvironmentConfig.isEnvironmentSet == false {
|
|
295
|
+
// self.initializationErrorMessage = "environment not set"
|
|
296
|
+
// Request.notifyValidationError(self.initializationErrorMessage!)
|
|
297
|
+
// return
|
|
298
|
+
// }
|
|
299
|
+
|
|
300
|
+
// ✅ Override amount if clientToken flow is used
|
|
301
|
+
if let token = clientToken, !token.isEmpty {
|
|
302
|
+
if let savedAmount = UserStoreSingleton.shared.amount,
|
|
303
|
+
let doubleAmount = Double(savedAmount) {
|
|
304
|
+
self.amount = doubleAmount
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// API keys presence validation for non-clientToken case
|
|
309
|
+
if clientToken == nil {
|
|
310
|
+
let hasKey = (EnvironmentConfig.apiKey?.isEmpty == false)
|
|
311
|
+
let hasSecret = (EnvironmentConfig.apiSecret?.isEmpty == false)
|
|
312
|
+
if !hasKey && !hasSecret {
|
|
313
|
+
self.initializationErrorMessage = "Api Key and Secret not found"
|
|
314
|
+
Request.notifyValidationError(self.initializationErrorMessage!)
|
|
315
|
+
return
|
|
316
|
+
}
|
|
317
|
+
if hasKey && !hasSecret {
|
|
318
|
+
self.initializationErrorMessage = "Secret Key not found"
|
|
319
|
+
Request.notifyValidationError(self.initializationErrorMessage!)
|
|
320
|
+
return
|
|
321
|
+
}
|
|
322
|
+
if !hasKey && hasSecret {
|
|
323
|
+
self.initializationErrorMessage = "Api Key not found"
|
|
324
|
+
Request.notifyValidationError(self.initializationErrorMessage!)
|
|
325
|
+
return
|
|
326
|
+
}
|
|
327
|
+
} else {
|
|
328
|
+
// Validate clientToken is not empty
|
|
329
|
+
if clientToken?.isEmpty ?? true {
|
|
330
|
+
self.initializationErrorMessage = "Client token cannot be empty"
|
|
331
|
+
Request.notifyValidationError(self.initializationErrorMessage!)
|
|
332
|
+
return
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Payment methods: at least one required if provided
|
|
337
|
+
if let pm = paymentMethods, pm.isEmpty {
|
|
338
|
+
self.initializationErrorMessage = "paymentMethods param minimum one payment method required"
|
|
339
|
+
Request.notifyValidationError(self.initializationErrorMessage!)
|
|
340
|
+
return
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Validate amount (must be ≥ 0.50)
|
|
344
|
+
if let amt = amount, amt < 0.50 {
|
|
345
|
+
self.initializationErrorMessage = "Amount must be at least $0.50."
|
|
346
|
+
Request.notifyValidationError(self.initializationErrorMessage!)
|
|
347
|
+
return
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// ✅ Use recurring details from HostedCheckout API only if clientToken is present
|
|
351
|
+
if let token = clientToken, !token.isEmpty {
|
|
352
|
+
if let savedIsRecurring = UserStoreSingleton.shared.isRecurring,
|
|
353
|
+
savedIsRecurring == "1" { // API returns "1" for true
|
|
354
|
+
self.is_recurring = true
|
|
355
|
+
|
|
356
|
+
if let cycles = UserStoreSingleton.shared.allowCycles,
|
|
357
|
+
let num = Int(cycles) {
|
|
358
|
+
self.numOfCycle = num
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if let intervals = UserStoreSingleton.shared.interval {
|
|
362
|
+
// API gives "daily,weekly,monthly" → split into array
|
|
363
|
+
let parts = intervals.split(separator: ",").map { String($0).trimmingCharacters(in: .whitespaces) }
|
|
364
|
+
self.recurringIntervals = parts.compactMap { RecurringIntervals(rawValue: $0) }
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if let startType = UserStoreSingleton.shared.startDateType {
|
|
368
|
+
self.recurringStartDateType = RecurringStartDateType(rawValue: startType)
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if let startDate = UserStoreSingleton.shared.startDate {
|
|
372
|
+
self.recurringStartDate = startDate
|
|
373
|
+
}
|
|
374
|
+
} else {
|
|
375
|
+
self.is_recurring = false
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Validate recurring start date not in past
|
|
380
|
+
if let startDateString = recurringStartDate,
|
|
381
|
+
let startDate = DateFormatter.recurringDateFormatter.date(from: startDateString) {
|
|
382
|
+
let today = Calendar.current.startOfDay(for: Date())
|
|
383
|
+
let startDay = Calendar.current.startOfDay(for: startDate)
|
|
384
|
+
if startDay < today {
|
|
385
|
+
self.initializationErrorMessage = "The recurring start date cannot be in the past. Please select today or a future date."
|
|
386
|
+
Request.notifyValidationError(self.initializationErrorMessage!)
|
|
387
|
+
return
|
|
388
|
+
}
|
|
389
|
+
} else if recurringStartDate != nil {
|
|
390
|
+
// Provided but invalid format
|
|
391
|
+
self.initializationErrorMessage = "Recurring date format should be dd/MM/yyyy"
|
|
392
|
+
Request.notifyValidationError(self.initializationErrorMessage!)
|
|
393
|
+
return
|
|
394
|
+
}
|
|
292
395
|
|
|
293
396
|
// Validate metadata limits
|
|
294
397
|
if let metadata = metadata {
|
|
295
398
|
if metadata.count > 50 {
|
|
296
|
-
|
|
399
|
+
self.initializationErrorMessage = "Metadata must contain no more than 50 keys."
|
|
400
|
+
Request.notifyValidationError(self.initializationErrorMessage!)
|
|
297
401
|
return
|
|
298
402
|
}
|
|
299
403
|
|
|
300
404
|
for (key, value) in metadata {
|
|
301
405
|
if key.count > 40 {
|
|
302
|
-
|
|
406
|
+
self.initializationErrorMessage = "Metadata key '\(key)' exceeds 40 characters."
|
|
407
|
+
Request.notifyValidationError(self.initializationErrorMessage!)
|
|
303
408
|
return
|
|
304
409
|
}
|
|
305
410
|
if let stringValue = value as? String, stringValue.count > 500 {
|
|
306
|
-
|
|
411
|
+
self.initializationErrorMessage = "Value for key '\(key)' exceeds 500 characters."
|
|
412
|
+
Request.notifyValidationError(self.initializationErrorMessage!)
|
|
307
413
|
return
|
|
308
414
|
}
|
|
309
415
|
}
|
|
@@ -313,50 +419,49 @@ public final class Request: NSObject {
|
|
|
313
419
|
self.metadata = nil
|
|
314
420
|
}
|
|
315
421
|
|
|
316
|
-
// Validate recurring intervals
|
|
422
|
+
// Validate recurring intervals and required recurring params
|
|
317
423
|
if is_recurring == true {
|
|
318
|
-
|
|
424
|
+
// if numOfCycle == nil { self.initializationErrorMessage = "numOfCycle object not defined"; Request.notifyValidationError(self.initializationErrorMessage!); return }
|
|
319
425
|
|
|
320
|
-
if
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
preferredStyle: .alert
|
|
327
|
-
)
|
|
328
|
-
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in
|
|
329
|
-
if let easyPayVC = UIApplication.findEasyPayViewController(from: topVC) {
|
|
330
|
-
easyPayVC.dismiss(animated: true)
|
|
331
|
-
} else {
|
|
332
|
-
topVC.dismiss(animated: true)
|
|
333
|
-
}
|
|
334
|
-
}))
|
|
335
|
-
topVC.present(alert, animated: true)
|
|
336
|
-
}
|
|
426
|
+
// ✅ Skip numOfCycle validation if clientToken is provided and not empty
|
|
427
|
+
if (clientToken == nil || clientToken?.isEmpty == true) {
|
|
428
|
+
if numOfCycle == nil {
|
|
429
|
+
self.initializationErrorMessage = "numOfCycle object not defined"
|
|
430
|
+
Request.notifyValidationError(self.initializationErrorMessage!)
|
|
431
|
+
return
|
|
337
432
|
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if recurringIntervals == nil { self.initializationErrorMessage = "recurringIntervals object not defined"; Request.notifyValidationError(self.initializationErrorMessage!); return }
|
|
436
|
+
if recurringStartDateType == nil { self.initializationErrorMessage = "recurringStartDateType object not defined"; Request.notifyValidationError(self.initializationErrorMessage!); return }
|
|
437
|
+
if recurringStartDate == nil { self.initializationErrorMessage = "recurringStartDate object not defined"; Request.notifyValidationError(self.initializationErrorMessage!); return }
|
|
438
|
+
// Check cycle count
|
|
439
|
+
if let cycles = numOfCycle, cycles < 2 {
|
|
440
|
+
self.initializationErrorMessage = "Number of cycle count for recurring must be minimum 2."
|
|
441
|
+
Request.notifyValidationError(self.initializationErrorMessage!)
|
|
338
442
|
return
|
|
339
443
|
}
|
|
340
|
-
|
|
444
|
+
|
|
445
|
+
let intervals = recurringIntervals ?? []
|
|
446
|
+
// if intervals.count < 2 {
|
|
447
|
+
// self.initializationErrorMessage = "Please add minimum two intervals for recurring."
|
|
448
|
+
// Request.notifyValidationError(self.initializationErrorMessage!)
|
|
449
|
+
// return
|
|
450
|
+
// }
|
|
451
|
+
|
|
341
452
|
let uniqueIntervals = Set(intervals)
|
|
342
453
|
if uniqueIntervals.count < intervals.count {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
topVC.dismiss(animated: true)
|
|
355
|
-
}
|
|
356
|
-
}))
|
|
357
|
-
topVC.present(alert, animated: true)
|
|
358
|
-
}
|
|
359
|
-
}
|
|
454
|
+
self.initializationErrorMessage = "Duplicate interval values"
|
|
455
|
+
Request.notifyValidationError(self.initializationErrorMessage!)
|
|
456
|
+
return
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// GrailPay validations when authenticatedACH is true
|
|
461
|
+
if authenticatedACH == true {
|
|
462
|
+
if grailPayParams == nil {
|
|
463
|
+
self.initializationErrorMessage = "grailPayParams should be json object"
|
|
464
|
+
Request.notifyValidationError(self.initializationErrorMessage!)
|
|
360
465
|
return
|
|
361
466
|
}
|
|
362
467
|
}
|
|
@@ -372,12 +477,27 @@ public final class Request: NSObject {
|
|
|
372
477
|
}
|
|
373
478
|
}
|
|
374
479
|
else {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
480
|
+
if clientToken == nil {
|
|
481
|
+
// Proceed with normal payment flow for API key/secret case
|
|
482
|
+
self.paymentIntentApi { success in
|
|
483
|
+
if success {
|
|
484
|
+
print("Payment Intent API call succeeded")
|
|
485
|
+
UserStoreSingleton.shared.price = String(self.amount ?? 0)
|
|
486
|
+
print("Saved amount: \(UserStoreSingleton.shared.price ?? "No amount")")
|
|
487
|
+
} else {
|
|
488
|
+
print("Payment Intent API call failed")
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
} else {
|
|
492
|
+
// For clientToken case, directly call hostedCheckoutsApi
|
|
493
|
+
UserStoreSingleton.shared.clientToken = clientToken
|
|
494
|
+
self.hostedCheckoutsApi { success in
|
|
495
|
+
if success {
|
|
496
|
+
print("Hosted Checkout API call succeeded")
|
|
497
|
+
UserStoreSingleton.shared.price = String(self.amount ?? 0)
|
|
498
|
+
} else {
|
|
499
|
+
print("Hosted Checkout API call failed")
|
|
500
|
+
}
|
|
381
501
|
}
|
|
382
502
|
}
|
|
383
503
|
}
|
|
@@ -394,7 +514,8 @@ public final class Request: NSObject {
|
|
|
394
514
|
//MARK: - Payment Intent Api
|
|
395
515
|
func paymentIntentApi(completion: @escaping (Bool) -> Void) {
|
|
396
516
|
guard let serviceURL = URL(string: EnvironmentConfig.baseURL + EnvironmentConfig.Endpoints.paymentIntent.path()) else {
|
|
397
|
-
|
|
517
|
+
Request.notifyValidationError("Invalid payment URL.")
|
|
518
|
+
print("Invalid payment URL for Payment Intent API")
|
|
398
519
|
completion(false)
|
|
399
520
|
return
|
|
400
521
|
}
|
|
@@ -412,10 +533,16 @@ public final class Request: NSObject {
|
|
|
412
533
|
let startDay = Calendar.current.startOfDay(for: startDate)
|
|
413
534
|
|
|
414
535
|
if startDay < today {
|
|
415
|
-
|
|
536
|
+
Request.notifyValidationError("The recurring start date cannot be in the past. Please select today or a future date.")
|
|
537
|
+
print("Recurring start date validation failed")
|
|
416
538
|
completion(false)
|
|
417
539
|
return
|
|
418
540
|
}
|
|
541
|
+
} else if recurringStartDate != nil {
|
|
542
|
+
Request.notifyValidationError("Recurring date format should be dd/MM/yyyy")
|
|
543
|
+
print("Invalid recurring date format")
|
|
544
|
+
completion(false)
|
|
545
|
+
return
|
|
419
546
|
}
|
|
420
547
|
|
|
421
548
|
let params: [String: Any] = [
|
|
@@ -427,94 +554,102 @@ public final class Request: NSObject {
|
|
|
427
554
|
"recurring_start_date_type": recurringStartDateType?.rawValue ?? ""
|
|
428
555
|
]
|
|
429
556
|
|
|
430
|
-
print(params)
|
|
557
|
+
print("Payment Intent API Request Params: \(params)")
|
|
431
558
|
|
|
432
559
|
do {
|
|
433
560
|
request.httpBody = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
434
561
|
} catch {
|
|
435
|
-
|
|
562
|
+
Request.notifyValidationError("Failed to encode Payment Intent API data: \(error.localizedDescription)")
|
|
563
|
+
print("Error encoding Payment Intent API data: \(error)")
|
|
436
564
|
completion(false)
|
|
437
565
|
return
|
|
438
566
|
}
|
|
439
567
|
|
|
440
568
|
let task = URLSession.shared.dataTask(with: request) { data, response, error in
|
|
441
|
-
|
|
442
|
-
|
|
569
|
+
if let error = error {
|
|
570
|
+
Request.notifyValidationError("Payment Intent API error: \(error.localizedDescription)")
|
|
571
|
+
print("Payment Intent API error: \(error)")
|
|
443
572
|
completion(false)
|
|
444
573
|
return
|
|
445
574
|
}
|
|
446
575
|
|
|
576
|
+
guard let httpResponse = response as? HTTPURLResponse else {
|
|
577
|
+
Request.notifyValidationError("Invalid response from Payment Intent API")
|
|
578
|
+
print("Invalid response from Payment Intent API")
|
|
579
|
+
completion(false)
|
|
580
|
+
return
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
print("Payment Intent API Response Status Code: \(httpResponse.statusCode)")
|
|
584
|
+
|
|
447
585
|
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
448
586
|
if let data = data {
|
|
449
587
|
do {
|
|
450
588
|
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
|
|
589
|
+
print("Payment Intent API Response: \(responseObject)")
|
|
451
590
|
if let clientToken = responseObject["client_token"] as? String {
|
|
452
591
|
UserStoreSingleton.shared.clientToken = clientToken
|
|
453
|
-
|
|
592
|
+
print("Received clientToken: \(clientToken)")
|
|
593
|
+
} else {
|
|
594
|
+
Request.notifyValidationError("No client_token in Payment Intent API response")
|
|
595
|
+
print("No client_token in Payment Intent API response")
|
|
596
|
+
completion(false)
|
|
597
|
+
return
|
|
454
598
|
}
|
|
455
599
|
if let paymentIntent = responseObject["payment_intent"] as? String {
|
|
456
600
|
UserStoreSingleton.shared.paymentIntent = paymentIntent
|
|
601
|
+
print("Received paymentIntent: \(paymentIntent)")
|
|
457
602
|
}
|
|
458
603
|
self.hostedCheckoutsApi { success in
|
|
459
604
|
completion(success)
|
|
460
605
|
}
|
|
461
606
|
return
|
|
462
607
|
} else {
|
|
463
|
-
|
|
608
|
+
Request.notifyValidationError("Invalid response format from Payment Intent API")
|
|
609
|
+
print("Invalid response format from Payment Intent API")
|
|
610
|
+
completion(false)
|
|
464
611
|
}
|
|
465
612
|
} catch {
|
|
466
|
-
|
|
613
|
+
Request.notifyValidationError("Failed to parse Payment Intent API response: \(error.localizedDescription)")
|
|
614
|
+
print("Error parsing Payment Intent API response: \(error)")
|
|
615
|
+
completion(false)
|
|
467
616
|
}
|
|
468
617
|
} else {
|
|
469
|
-
|
|
618
|
+
Request.notifyValidationError("No response data received from Payment Intent API")
|
|
619
|
+
print("No response data received from Payment Intent API")
|
|
620
|
+
completion(false)
|
|
470
621
|
}
|
|
471
622
|
} else {
|
|
472
|
-
var message = "Payment
|
|
623
|
+
var message = "Payment Intent API failed with status code: \(httpResponse.statusCode)"
|
|
473
624
|
if let data = data,
|
|
474
625
|
let responseObj = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
|
|
475
|
-
let msg = responseObj["message"] as? String {
|
|
626
|
+
let msg = responseObj["message"] as? String, !msg.isEmpty {
|
|
476
627
|
message = msg
|
|
477
628
|
}
|
|
478
|
-
|
|
629
|
+
Request.notifyValidationError(message)
|
|
630
|
+
print("Payment Intent API error: \(message)")
|
|
631
|
+
completion(false)
|
|
479
632
|
}
|
|
480
|
-
completion(false)
|
|
481
633
|
}
|
|
482
634
|
task.resume()
|
|
483
635
|
}
|
|
484
|
-
|
|
636
|
+
|
|
485
637
|
private static func showErrorAndDismissForMetaData(message: String) {
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { _ in
|
|
492
|
-
if let easyPayVC = UIApplication.findEasyPayViewController(from: topVC) {
|
|
493
|
-
easyPayVC.dismiss(animated: true)
|
|
494
|
-
} else {
|
|
495
|
-
topVC.dismiss(animated: true)
|
|
496
|
-
}
|
|
497
|
-
}))
|
|
498
|
-
topVC.present(alert, animated: true)
|
|
499
|
-
}
|
|
500
|
-
}
|
|
638
|
+
Request.notifyValidationError(message)
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
private func showErrorAndDismiss(message: String) {
|
|
642
|
+
Request.notifyValidationError(message)
|
|
501
643
|
}
|
|
502
644
|
|
|
503
|
-
|
|
645
|
+
private static func notifyValidationError(_ message: String) {
|
|
504
646
|
DispatchQueue.main.async {
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
easyPayVC.dismiss(animated: true)
|
|
512
|
-
} else {
|
|
513
|
-
topVC.dismiss(animated: true)
|
|
514
|
-
}
|
|
515
|
-
}))
|
|
516
|
-
topVC.present(alert, animated: true)
|
|
517
|
-
}
|
|
647
|
+
let chargeData: [String: Any] = [
|
|
648
|
+
"status": false,
|
|
649
|
+
"message": message
|
|
650
|
+
]
|
|
651
|
+
let result = SDKResult(type: .error, chargeData: chargeData, billingInfo: nil, additionalInfo: nil)
|
|
652
|
+
NotificationCenter.default.post(name: NSNotification.Name("EasyPayResult"), object: result)
|
|
518
653
|
}
|
|
519
654
|
}
|
|
520
655
|
|
|
@@ -522,7 +657,8 @@ public final class Request: NSObject {
|
|
|
522
657
|
func hostedCheckoutsApi(completion: @escaping (Bool) -> Void) {
|
|
523
658
|
// Build the URL using EnvironmentConfig
|
|
524
659
|
guard let baseURL = URL(string: EnvironmentConfig.baseURL) else {
|
|
525
|
-
|
|
660
|
+
Request.notifyValidationError("Invalid base URL for Hosted Checkout API")
|
|
661
|
+
print("Invalid base URL for Hosted Checkout API")
|
|
526
662
|
completion(false)
|
|
527
663
|
return
|
|
528
664
|
}
|
|
@@ -533,36 +669,47 @@ public final class Request: NSObject {
|
|
|
533
669
|
var request = URLRequest(url: serviceURL)
|
|
534
670
|
request.httpMethod = "POST"
|
|
535
671
|
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
536
|
-
request.addValue(UserStoreSingleton.shared.clientToken ?? "", forHTTPHeaderField: "clientToken")
|
|
537
672
|
|
|
538
|
-
let
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
print(params)
|
|
543
|
-
|
|
544
|
-
do {
|
|
545
|
-
request.httpBody = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted)
|
|
546
|
-
} catch {
|
|
547
|
-
print("Error creating JSON data: \(error)")
|
|
673
|
+
let token = clientToken ?? UserStoreSingleton.shared.clientToken ?? ""
|
|
674
|
+
if token.isEmpty {
|
|
675
|
+
Request.notifyValidationError("No valid client token provided for Hosted Checkout API")
|
|
676
|
+
print("No valid client token provided for Hosted Checkout API")
|
|
548
677
|
completion(false)
|
|
549
678
|
return
|
|
550
679
|
}
|
|
680
|
+
request.addValue(token, forHTTPHeaderField: "clientToken")
|
|
681
|
+
|
|
682
|
+
// print("➡️ Hosted Checkout API Request URL: \(serviceURL.absoluteString)")
|
|
683
|
+
// print("➡️ Hosted Checkout API clientToken: \(token)")
|
|
684
|
+
// print("➡️ Headers: \(request.allHTTPHeaderFields ?? [:])")
|
|
551
685
|
|
|
552
686
|
let task = URLSession.shared.dataTask(with: request) { data, response, error in
|
|
687
|
+
if let error = error {
|
|
688
|
+
Request.notifyValidationError("Hosted Checkout API error: \(error.localizedDescription)")
|
|
689
|
+
print("Hosted Checkout API error: \(error)")
|
|
690
|
+
completion(false)
|
|
691
|
+
return
|
|
692
|
+
}
|
|
553
693
|
|
|
554
|
-
guard let httpResponse = response as? HTTPURLResponse
|
|
555
|
-
|
|
694
|
+
guard let httpResponse = response as? HTTPURLResponse else {
|
|
695
|
+
Request.notifyValidationError("Invalid response from Hosted Checkout API")
|
|
696
|
+
print("Invalid response from Hosted Checkout API")
|
|
556
697
|
completion(false)
|
|
557
698
|
return
|
|
558
699
|
}
|
|
559
700
|
|
|
701
|
+
print("Hosted Checkout API Response Status Code: \(httpResponse.statusCode)")
|
|
702
|
+
|
|
560
703
|
if httpResponse.statusCode == 200 || httpResponse.statusCode == 201 {
|
|
561
704
|
if let data = data {
|
|
562
705
|
do {
|
|
563
706
|
if let responseObject = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
|
|
564
707
|
let dataObject = responseObject["data"] as? [String: Any] {
|
|
565
|
-
print(dataObject)
|
|
708
|
+
print("Hosted Checkout API Response: \(dataObject)")
|
|
709
|
+
|
|
710
|
+
// Persist the exact token used for the request (header value),
|
|
711
|
+
// not self.clientToken which may be nil on first-run flows.
|
|
712
|
+
UserStoreSingleton.shared.clientToken = token
|
|
566
713
|
|
|
567
714
|
// Save merchant details
|
|
568
715
|
if let merchantEmail = dataObject["merchant_email"] as? String {
|
|
@@ -624,6 +771,40 @@ public final class Request: NSObject {
|
|
|
624
771
|
print("Saved payment methods: \(paymentMethodNames)")
|
|
625
772
|
}
|
|
626
773
|
|
|
774
|
+
// Save payment intent amount
|
|
775
|
+
if let paymentAmount = dataObject["payment_intent_amount"] {
|
|
776
|
+
UserStoreSingleton.shared.amount = "\(paymentAmount)"
|
|
777
|
+
print("Saved payment_intent_amount: \(paymentAmount)")
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// Save recurring details
|
|
781
|
+
if let recurringDetails = dataObject["recurring_details"] as? [String: Any] {
|
|
782
|
+
if let allowedCycles = recurringDetails["allowed_cycles"] {
|
|
783
|
+
UserStoreSingleton.shared.allowCycles = "\(allowedCycles)"
|
|
784
|
+
print("Saved allowed_cycles: \(allowedCycles)")
|
|
785
|
+
}
|
|
786
|
+
if let interval = recurringDetails["interval"] {
|
|
787
|
+
UserStoreSingleton.shared.interval = "\(interval)"
|
|
788
|
+
print("Saved interval: \(interval)")
|
|
789
|
+
}
|
|
790
|
+
if let isRecurring = recurringDetails["is_recurring"] {
|
|
791
|
+
UserStoreSingleton.shared.isRecurring = "\(isRecurring)"
|
|
792
|
+
print("Saved is_recurring: \(isRecurring)")
|
|
793
|
+
}
|
|
794
|
+
if let paymentIntentId = recurringDetails["payment_intent_id"] {
|
|
795
|
+
UserStoreSingleton.shared.paymentIntentId = "\(paymentIntentId)"
|
|
796
|
+
print("Saved payment_intent_id: \(paymentIntentId)")
|
|
797
|
+
}
|
|
798
|
+
if let startDate = recurringDetails["start_date"] {
|
|
799
|
+
UserStoreSingleton.shared.startDate = "\(startDate)"
|
|
800
|
+
print("Saved start_date: \(startDate)")
|
|
801
|
+
}
|
|
802
|
+
if let startDateType = recurringDetails["start_date_type"] {
|
|
803
|
+
UserStoreSingleton.shared.startDateType = "\(startDateType)"
|
|
804
|
+
print("Saved start_date_type: \(startDateType)")
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
|
|
627
808
|
if self.appearanceSettings == nil, let appearanceSettings = dataObject["apperance_settings"] as? [String: Any] {
|
|
628
809
|
UserStoreSingleton.shared.body_bg_col = appearanceSettings["body_bg_col"] as? String
|
|
629
810
|
UserStoreSingleton.shared.border_radious = appearanceSettings["border_radious"] as? String
|
|
@@ -637,26 +818,34 @@ public final class Request: NSObject {
|
|
|
637
818
|
UserStoreSingleton.shared.secondary_btn_hover_col = appearanceSettings["secondary_btn_hover_col"] as? String
|
|
638
819
|
UserStoreSingleton.shared.secondary_font_col = appearanceSettings["secondary_font_col"] as? String
|
|
639
820
|
|
|
640
|
-
// Clearing the font size value
|
|
641
821
|
UserStoreSingleton.shared.fontSize = nil
|
|
642
822
|
}
|
|
643
823
|
|
|
644
824
|
completion(true)
|
|
645
|
-
|
|
646
825
|
} else {
|
|
647
|
-
|
|
826
|
+
Request.notifyValidationError("Invalid JSON format or 'data' key missing in Hosted Checkout API response")
|
|
827
|
+
print("Invalid JSON format or 'data' key missing in Hosted Checkout API response")
|
|
648
828
|
completion(false)
|
|
649
829
|
}
|
|
650
830
|
} catch {
|
|
651
|
-
|
|
831
|
+
Request.notifyValidationError("Failed to parse Hosted Checkout API response: \(error.localizedDescription)")
|
|
832
|
+
print("Error parsing Hosted Checkout API response: \(error)")
|
|
652
833
|
completion(false)
|
|
653
834
|
}
|
|
654
835
|
} else {
|
|
655
|
-
|
|
836
|
+
Request.notifyValidationError("No response data received from Hosted Checkout API")
|
|
837
|
+
print("No response data received from Hosted Checkout API")
|
|
656
838
|
completion(false)
|
|
657
839
|
}
|
|
658
840
|
} else {
|
|
659
|
-
|
|
841
|
+
var message = "Hosted Checkout API failed with status code: \(httpResponse.statusCode)"
|
|
842
|
+
if let data = data,
|
|
843
|
+
let responseObj = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
|
|
844
|
+
let msg = responseObj["message"] as? String, !msg.isEmpty {
|
|
845
|
+
message = msg
|
|
846
|
+
}
|
|
847
|
+
Request.notifyValidationError(message)
|
|
848
|
+
print("Hosted Checkout API error: \(message)")
|
|
660
849
|
completion(false)
|
|
661
850
|
}
|
|
662
851
|
}
|
|
@@ -678,9 +867,12 @@ public final class Request: NSObject {
|
|
|
678
867
|
uRLRequest.httpMethod = "GET"
|
|
679
868
|
uRLRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
|
|
680
869
|
|
|
681
|
-
let
|
|
682
|
-
print("Setting customerToken header: \(
|
|
683
|
-
uRLRequest.addValue(
|
|
870
|
+
// let tokenn = UserStoreSingleton.shared.customerToken
|
|
871
|
+
// print("Setting customerToken header: \(tokenn ?? "None")")
|
|
872
|
+
// uRLRequest.addValue(tokenn ?? "", forHTTPHeaderField: "Customer-Token")
|
|
873
|
+
|
|
874
|
+
let token = clientToken ?? UserStoreSingleton.shared.clientToken ?? ""
|
|
875
|
+
uRLRequest.addValue(token, forHTTPHeaderField: "clientToken")
|
|
684
876
|
|
|
685
877
|
// Add API key/secret headers
|
|
686
878
|
if let apiKey = EnvironmentConfig.apiKey,
|
|
@@ -722,41 +914,43 @@ public final class Request: NSObject {
|
|
|
722
914
|
extension DateFormatter {
|
|
723
915
|
static let recurringDateFormatter: DateFormatter = {
|
|
724
916
|
let formatter = DateFormatter()
|
|
725
|
-
formatter.dateFormat = "MM/
|
|
917
|
+
formatter.dateFormat = "dd/MM/yyyy"
|
|
726
918
|
formatter.timeZone = .current
|
|
727
919
|
return formatter
|
|
728
920
|
}()
|
|
729
921
|
}
|
|
730
922
|
|
|
731
|
-
extension UIApplication {
|
|
732
|
-
static func topViewController(base: UIViewController? = UIApplication.shared.connectedScenes
|
|
733
|
-
.compactMap { ($0 as? UIWindowScene)?.windows.first(where: \.isKeyWindow) }
|
|
734
|
-
.first?.rootViewController) -> UIViewController? {
|
|
735
|
-
if let nav = base as? UINavigationController {
|
|
736
|
-
return topViewController(base: nav.visibleViewController)
|
|
737
|
-
}
|
|
738
|
-
if let tab = base as? UITabBarController {
|
|
739
|
-
if let selected = tab.selectedViewController {
|
|
740
|
-
return topViewController(base: selected)
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
if let presented = base?.presentedViewController {
|
|
744
|
-
return topViewController(base: presented)
|
|
745
|
-
}
|
|
746
|
-
return base
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
923
|
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
static func
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
}
|
|
924
|
+
|
|
925
|
+
//extension UIApplication {
|
|
926
|
+
// static func topViewController(base: UIViewController? = UIApplication.shared.connectedScenes
|
|
927
|
+
// .compactMap { ($0 as? UIWindowScene)?.windows.first(where: \.isKeyWindow) }
|
|
928
|
+
// .first?.rootViewController) -> UIViewController? {
|
|
929
|
+
// if let nav = base as? UINavigationController {
|
|
930
|
+
// return topViewController(base: nav.visibleViewController)
|
|
931
|
+
// }
|
|
932
|
+
// if let tab = base as? UITabBarController {
|
|
933
|
+
// if let selected = tab.selectedViewController {
|
|
934
|
+
// return topViewController(base: selected)
|
|
935
|
+
// }
|
|
936
|
+
// }
|
|
937
|
+
// if let presented = base?.presentedViewController {
|
|
938
|
+
// return topViewController(base: presented)
|
|
939
|
+
// }
|
|
940
|
+
// return base
|
|
941
|
+
// }
|
|
942
|
+
//}
|
|
943
|
+
|
|
944
|
+
//extension UIApplication {
|
|
945
|
+
// // Recursively find the presented EasyPayViewController (if any)
|
|
946
|
+
// static func findEasyPayViewController(from vc: UIViewController?) -> EasyPayViewController? {
|
|
947
|
+
// if let easyPayVC = vc as? EasyPayViewController {
|
|
948
|
+
// return easyPayVC
|
|
949
|
+
// }
|
|
950
|
+
// if let presented = vc?.presentedViewController {
|
|
951
|
+
// return findEasyPayViewController(from: presented)
|
|
952
|
+
// }
|
|
953
|
+
// return nil
|
|
954
|
+
// }
|
|
955
|
+
//}
|
|
762
956
|
|