@capawesome/capacitor-square-mobile-payments 0.0.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.
Files changed (82) hide show
  1. package/CapawesomeCapacitorSquareMobilePayments.podspec +17 -0
  2. package/Package.swift +30 -0
  3. package/README.md +1183 -0
  4. package/android/build.gradle +63 -0
  5. package/android/src/main/AndroidManifest.xml +7 -0
  6. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/SquareMobilePayments.java +774 -0
  7. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/SquareMobilePaymentsPlugin.java +460 -0
  8. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/CustomException.java +20 -0
  9. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/CustomExceptions.java +41 -0
  10. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/events/AvailableCardInputMethodsDidChangeEvent.java +27 -0
  11. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/events/PaymentDidCancelEvent.java +24 -0
  12. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/events/PaymentDidFailEvent.java +34 -0
  13. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/events/PaymentDidFinishEvent.java +22 -0
  14. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/events/ReaderDidChangeEvent.java +27 -0
  15. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/events/ReaderPairingDidFailEvent.java +28 -0
  16. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/events/ReaderWasAddedEvent.java +22 -0
  17. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/events/ReaderWasRemovedEvent.java +22 -0
  18. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/options/AuthorizeOptions.java +29 -0
  19. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/options/ForgetReaderOptions.java +29 -0
  20. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/options/InitializeOptions.java +29 -0
  21. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/options/Money.java +29 -0
  22. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/options/PaymentParameters.java +126 -0
  23. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/options/PromptParameters.java +47 -0
  24. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/options/RetryConnectionOptions.java +29 -0
  25. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/options/StartPaymentOptions.java +39 -0
  26. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/results/Card.java +51 -0
  27. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/results/CardPaymentDetails.java +30 -0
  28. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/results/GetAvailableCardInputMethodsResult.java +29 -0
  29. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/results/GetReadersResult.java +29 -0
  30. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/results/GetSettingsResult.java +28 -0
  31. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/results/IsAuthorizedResult.java +22 -0
  32. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/results/IsPairingInProgressResult.java +22 -0
  33. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/results/MoneyResult.java +27 -0
  34. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/results/Payment.java +87 -0
  35. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/results/ReaderInfo.java +82 -0
  36. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/classes/results/UnavailableReasonInfo.java +30 -0
  37. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/interfaces/Callback.java +5 -0
  38. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/interfaces/EmptyCallback.java +5 -0
  39. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/interfaces/NonEmptyCallback.java +7 -0
  40. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/interfaces/NonEmptyResultCallback.java +7 -0
  41. package/android/src/main/java/io/capawesome/capacitorjs/plugins/squaremobilepayments/interfaces/Result.java +7 -0
  42. package/android/src/main/res/.gitkeep +0 -0
  43. package/dist/docs.json +2999 -0
  44. package/dist/esm/definitions.d.ts +1468 -0
  45. package/dist/esm/definitions.js +519 -0
  46. package/dist/esm/definitions.js.map +1 -0
  47. package/dist/esm/index.d.ts +4 -0
  48. package/dist/esm/index.js +7 -0
  49. package/dist/esm/index.js.map +1 -0
  50. package/dist/esm/web.d.ts +21 -0
  51. package/dist/esm/web.js +55 -0
  52. package/dist/esm/web.js.map +1 -0
  53. package/dist/plugin.cjs.js +588 -0
  54. package/dist/plugin.cjs.js.map +1 -0
  55. package/dist/plugin.js +591 -0
  56. package/dist/plugin.js.map +1 -0
  57. package/ios/Plugin/Classes/Options/AuthorizeOptions.swift +17 -0
  58. package/ios/Plugin/Classes/Options/ForgetReaderOptions.swift +17 -0
  59. package/ios/Plugin/Classes/Options/InitializeOptions.swift +17 -0
  60. package/ios/Plugin/Classes/Options/Money.swift +12 -0
  61. package/ios/Plugin/Classes/Options/PaymentParameters.swift +49 -0
  62. package/ios/Plugin/Classes/Options/PromptParameters.swift +17 -0
  63. package/ios/Plugin/Classes/Options/RetryConnectionOptions.swift +17 -0
  64. package/ios/Plugin/Classes/Options/StartPaymentOptions.swift +19 -0
  65. package/ios/Plugin/Classes/Results/Card.swift +34 -0
  66. package/ios/Plugin/Classes/Results/CardPaymentDetails.swift +34 -0
  67. package/ios/Plugin/Classes/Results/GetAvailableCardInputMethodsResult.swift +16 -0
  68. package/ios/Plugin/Classes/Results/GetReadersResult.swift +16 -0
  69. package/ios/Plugin/Classes/Results/GetSettingsResult.swift +19 -0
  70. package/ios/Plugin/Classes/Results/IsAuthorizedResult.swift +16 -0
  71. package/ios/Plugin/Classes/Results/IsPairingInProgressResult.swift +16 -0
  72. package/ios/Plugin/Classes/Results/MoneyResult.swift +19 -0
  73. package/ios/Plugin/Classes/Results/Payment.swift +58 -0
  74. package/ios/Plugin/Classes/Results/ReaderInfo.swift +46 -0
  75. package/ios/Plugin/Classes/Results/UnavailableReasonInfo.swift +19 -0
  76. package/ios/Plugin/Enums/CustomError.swift +81 -0
  77. package/ios/Plugin/Info.plist +24 -0
  78. package/ios/Plugin/Protocols/Result.swift +6 -0
  79. package/ios/Plugin/SquareMobilePayments.swift +632 -0
  80. package/ios/Plugin/SquareMobilePaymentsHelper.swift +212 -0
  81. package/ios/Plugin/SquareMobilePaymentsPlugin.swift +347 -0
  82. package/package.json +93 -0
@@ -0,0 +1,632 @@
1
+ import Foundation
2
+ import Capacitor
3
+ import SquareMobilePaymentsSDK
4
+ import CoreLocation
5
+ import CoreBluetooth
6
+
7
+ @objc public class SquareMobilePayments: NSObject {
8
+ private weak var plugin: SquareMobilePaymentsPlugin?
9
+ private var pairingHandle: SquareMobilePaymentsSDK.PairingHandle?
10
+ private var paymentHandle: SquareMobilePaymentsSDK.PaymentHandle?
11
+ private var squareApplicationId: String?
12
+ private var locationId: String?
13
+ private var locationManager: CLLocationManager?
14
+ private var bluetoothManager: CBCentralManager?
15
+ private var locationPermissionCompletion: ((CLAuthorizationStatus) -> Void)?
16
+ private var bluetoothPermissionCompletion: (() -> Void)?
17
+
18
+ init(plugin: SquareMobilePaymentsPlugin) {
19
+ self.plugin = plugin
20
+ super.init()
21
+ }
22
+
23
+ @objc public func initialize(_ options: InitializeOptions, completion: @escaping (_ error: Error?) -> Void) throws {
24
+ // Store location ID for later use during authorization
25
+ self.locationId = options.locationId
26
+
27
+ // Note: According to Square's docs, MobilePaymentsSDK.initialize should be called in AppDelegate
28
+ // For now, we'll just store the location ID and skip actual initialization here
29
+ completion(nil)
30
+ }
31
+
32
+ @objc public func authorize(_ options: AuthorizeOptions, completion: @escaping (_ error: Error?) -> Void) throws {
33
+ guard let locationId = self.locationId else {
34
+ throw CustomError.notInitialized
35
+ }
36
+
37
+ let accessToken = options.accessToken
38
+ let authManager = MobilePaymentsSDK.shared.authorizationManager
39
+
40
+ guard authManager.state == .notAuthorized else {
41
+ // Already authorized
42
+ completion(nil)
43
+ return
44
+ }
45
+
46
+ authManager.authorize(withAccessToken: accessToken, locationID: locationId) { error in
47
+ if let error = error {
48
+ completion(error)
49
+ } else {
50
+ // Add observer for reader changes after authorization
51
+ MobilePaymentsSDK.shared.readerManager.add(self)
52
+ // Add observer for available card input methods
53
+ MobilePaymentsSDK.shared.paymentManager.add(self)
54
+ completion(nil)
55
+ }
56
+ }
57
+ }
58
+
59
+ @objc public func isAuthorized(completion: @escaping (_ result: IsAuthorizedResult?, _ error: Error?) -> Void) throws {
60
+ let authManager = MobilePaymentsSDK.shared.authorizationManager
61
+ let authorized = authManager.state == .authorized
62
+ let result = IsAuthorizedResult(authorized: authorized)
63
+ completion(result, nil)
64
+ }
65
+
66
+ @objc public func deauthorize(completion: @escaping (_ error: Error?) -> Void) throws {
67
+ guard locationId != nil else {
68
+ throw CustomError.notInitialized
69
+ }
70
+
71
+ let authManager = MobilePaymentsSDK.shared.authorizationManager
72
+
73
+ guard authManager.state != .notAuthorized else {
74
+ // Already deauthorized
75
+ completion(nil)
76
+ return
77
+ }
78
+
79
+ // Remove observers
80
+ MobilePaymentsSDK.shared.readerManager.remove(self)
81
+ MobilePaymentsSDK.shared.paymentManager.remove(self)
82
+
83
+ authManager.deauthorize {
84
+ completion(nil)
85
+ }
86
+ }
87
+
88
+ @objc public func showSettings(completion: @escaping (_ error: Error?) -> Void) throws {
89
+ guard locationId != nil else {
90
+ throw CustomError.notInitialized
91
+ }
92
+ guard MobilePaymentsSDK.shared.authorizationManager.state == .authorized else {
93
+ throw CustomError.notAuthorized
94
+ }
95
+
96
+ guard let viewController = plugin?.bridge?.viewController else {
97
+ completion(NSError(domain: "SquareMobilePayments", code: -1, userInfo: [NSLocalizedDescriptionKey: "View controller not available"]))
98
+ return
99
+ }
100
+
101
+ MobilePaymentsSDK.shared.settingsManager.presentSettings(with: viewController) { error in
102
+ completion(error)
103
+ }
104
+ }
105
+
106
+ @objc public func getSettings(completion: @escaping (_ result: GetSettingsResult?, _ error: Error?) -> Void) throws {
107
+ guard locationId != nil else {
108
+ throw CustomError.notInitialized
109
+ }
110
+
111
+ let settings = MobilePaymentsSDK.shared.settingsManager
112
+ let version = settings.sdkSettings.version
113
+ let environment = SquareMobilePaymentsHelper.convertEnvironment(settings.sdkSettings.environment)
114
+
115
+ let result = GetSettingsResult(version: version, environment: environment)
116
+ completion(result, nil)
117
+ }
118
+
119
+ @objc public func startPairing(completion: @escaping (_ error: Error?) -> Void) throws {
120
+ guard locationId != nil else {
121
+ throw CustomError.notInitialized
122
+ }
123
+ guard MobilePaymentsSDK.shared.authorizationManager.state == .authorized else {
124
+ throw CustomError.notAuthorized
125
+ }
126
+
127
+ let readerManager = MobilePaymentsSDK.shared.readerManager
128
+ if readerManager.isPairingInProgress {
129
+ throw CustomError.pairingAlreadyInProgress
130
+ }
131
+
132
+ pairingHandle = readerManager.startPairing(with: self)
133
+ completion(nil)
134
+ }
135
+
136
+ @objc public func stopPairing(completion: @escaping (_ error: Error?) -> Void) throws {
137
+ guard locationId != nil else {
138
+ throw CustomError.notInitialized
139
+ }
140
+
141
+ pairingHandle?.stop()
142
+ pairingHandle = nil
143
+ completion(nil)
144
+ }
145
+
146
+ @objc public func isPairingInProgress(completion: @escaping (_ result: IsPairingInProgressResult?, _ error: Error?) -> Void) throws {
147
+ guard locationId != nil else {
148
+ throw CustomError.notInitialized
149
+ }
150
+
151
+ let inProgress = MobilePaymentsSDK.shared.readerManager.isPairingInProgress
152
+ let result = IsPairingInProgressResult(inProgress: inProgress)
153
+ completion(result, nil)
154
+ }
155
+
156
+ @objc public func getReaders(completion: @escaping (_ result: GetReadersResult?, _ error: Error?) -> Void) throws {
157
+ guard locationId != nil else {
158
+ throw CustomError.notInitialized
159
+ }
160
+
161
+ let sdkReaders = MobilePaymentsSDK.shared.readerManager.readers
162
+ let readers = sdkReaders.map { convertSdkReaderToReaderInfo($0) }
163
+
164
+ let result = GetReadersResult(readers: readers)
165
+ completion(result, nil)
166
+ }
167
+
168
+ @objc public func forgetReader(_ options: ForgetReaderOptions, completion: @escaping (_ error: Error?) -> Void) throws {
169
+ guard locationId != nil else {
170
+ throw CustomError.notInitialized
171
+ }
172
+
173
+ let serialNumber = options.serialNumber
174
+ let readerManager = MobilePaymentsSDK.shared.readerManager
175
+
176
+ guard let reader = readerManager.readers.first(where: { $0.serialNumber == serialNumber }) else {
177
+ throw CustomError.readerNotFound
178
+ }
179
+
180
+ readerManager.forget(reader)
181
+ completion(nil)
182
+ }
183
+
184
+ @objc public func retryConnection(_ options: RetryConnectionOptions, completion: @escaping (_ error: Error?) -> Void) throws {
185
+ guard locationId != nil else {
186
+ throw CustomError.notInitialized
187
+ }
188
+
189
+ let serialNumber = options.serialNumber
190
+ let readerManager = MobilePaymentsSDK.shared.readerManager
191
+
192
+ guard let reader = readerManager.readers.first(where: { $0.serialNumber == serialNumber }) else {
193
+ throw CustomError.readerNotFound
194
+ }
195
+
196
+ readerManager.retryConnection(reader)
197
+ completion(nil)
198
+ }
199
+
200
+ @objc public func startPayment(_ options: StartPaymentOptions, completion: @escaping (_ error: Error?) -> Void) throws {
201
+ guard locationId != nil else {
202
+ throw CustomError.notInitialized
203
+ }
204
+ guard MobilePaymentsSDK.shared.authorizationManager.state == .authorized else {
205
+ throw CustomError.notAuthorized
206
+ }
207
+
208
+ guard let viewController = plugin?.bridge?.viewController else {
209
+ completion(NSError(domain: "SquareMobilePayments", code: -1, userInfo: [NSLocalizedDescriptionKey: "View controller not available"]))
210
+ return
211
+ }
212
+
213
+ let params = options.paymentParameters
214
+ let promptParams = options.promptParameters
215
+
216
+ // Create Money object
217
+ let currency = SquareMobilePaymentsHelper.convertToCurrency(params.amountMoney.currency)
218
+ let money = SquareMobilePaymentsSDK.Money(amount: UInt(params.amountMoney.amount), currency: currency)
219
+
220
+ // Create PaymentParameters
221
+ let processingMode = SquareMobilePaymentsHelper.convertToProcessingMode(params.processingMode)
222
+ let paymentParams = SquareMobilePaymentsSDK.PaymentParameters(
223
+ paymentAttemptID: params.paymentAttemptId,
224
+ amountMoney: money,
225
+ processingMode: processingMode
226
+ )
227
+
228
+ // Set optional parameters
229
+ if let referenceId = params.referenceId {
230
+ paymentParams.referenceID = referenceId
231
+ }
232
+ if let note = params.note {
233
+ paymentParams.note = note
234
+ }
235
+ if let orderId = params.orderId {
236
+ paymentParams.orderID = orderId
237
+ }
238
+ if let tipMoney = params.tipMoney {
239
+ let tipCurrency = SquareMobilePaymentsHelper.convertToCurrency(tipMoney.currency)
240
+ paymentParams.tipMoney = SquareMobilePaymentsSDK.Money(amount: UInt(tipMoney.amount), currency: tipCurrency)
241
+ }
242
+ if let applicationFee = params.applicationFee {
243
+ let feeCurrency = SquareMobilePaymentsHelper.convertToCurrency(applicationFee.currency)
244
+ paymentParams.appFeeMoney = SquareMobilePaymentsSDK.Money(amount: UInt(applicationFee.amount), currency: feeCurrency)
245
+ }
246
+ if let autocomplete = params.autocomplete {
247
+ paymentParams.autocomplete = autocomplete
248
+ }
249
+ if let delayDuration = params.delayDuration {
250
+ // Parse ISO 8601 duration string (e.g., "PT1H" = 1 hour = 3600 seconds)
251
+ paymentParams.delayDuration = parseISO8601Duration(delayDuration)
252
+ }
253
+ if let delayAction = params.delayAction,
254
+ let action = SquareMobilePaymentsHelper.convertToDelayAction(delayAction) {
255
+ paymentParams.delayAction = action
256
+ }
257
+
258
+ // Create PromptParameters
259
+ let mode = SquareMobilePaymentsHelper.convertToPromptMode(promptParams.mode)
260
+ let additionalMethods = SquareMobilePaymentsHelper.convertToAdditionalMethods(promptParams.additionalMethods)
261
+ let squarePromptParams = SquareMobilePaymentsSDK.PromptParameters(
262
+ mode: mode,
263
+ additionalMethods: additionalMethods
264
+ )
265
+
266
+ // Start payment
267
+ paymentHandle = MobilePaymentsSDK.shared.paymentManager.startPayment(
268
+ paymentParams,
269
+ promptParameters: squarePromptParams,
270
+ from: viewController,
271
+ delegate: self
272
+ )
273
+
274
+ completion(nil)
275
+ }
276
+
277
+ @objc public func cancelPayment(completion: @escaping (_ error: Error?) -> Void) throws {
278
+ guard locationId != nil else {
279
+ throw CustomError.notInitialized
280
+ }
281
+
282
+ guard let handle = paymentHandle else {
283
+ throw CustomError.noPaymentInProgress
284
+ }
285
+
286
+ if handle.isPaymentCancelable {
287
+ handle.cancelPayment()
288
+ completion(nil)
289
+ } else {
290
+ completion(NSError(domain: "SquareMobilePayments", code: -1, userInfo: [NSLocalizedDescriptionKey: "Payment cannot be canceled at this time"]))
291
+ }
292
+ }
293
+
294
+ @objc public func getAvailableCardInputMethods(completion: @escaping (_ result: GetAvailableCardInputMethodsResult?, _ error: Error?) -> Void) throws {
295
+ guard locationId != nil else {
296
+ throw CustomError.notInitialized
297
+ }
298
+
299
+ let methods = MobilePaymentsSDK.shared.paymentManager.availableCardInputMethods
300
+ let cardInputMethods = SquareMobilePaymentsHelper.convertCardInputMethods(methods)
301
+
302
+ let result = GetAvailableCardInputMethodsResult(cardInputMethods: cardInputMethods)
303
+ completion(result, nil)
304
+ }
305
+
306
+ // MARK: - Helper Methods
307
+
308
+ private func convertSdkReaderToReaderInfo(_ sdkReader: SquareMobilePaymentsSDK.ReaderInfo) -> ReaderInfo {
309
+ let serialNumber = sdkReader.serialNumber ?? ""
310
+ let model = SquareMobilePaymentsHelper.convertReaderModel(sdkReader.model)
311
+ let status = SquareMobilePaymentsHelper.convertReaderStatus(sdkReader.statusInfo.status)
312
+ let firmwareVersion = sdkReader.firmwareInfo?.version
313
+ let batteryLevel = sdkReader.batteryStatus?.percentage != nil ? Int(sdkReader.batteryStatus!.percentage) : nil
314
+ let isCharging = sdkReader.batteryStatus?.isCharging
315
+ let supportedCardInputMethods = SquareMobilePaymentsHelper.convertCardInputMethods(sdkReader.supportedInputMethods)
316
+
317
+ var unavailableReasonInfo: UnavailableReasonInfo?
318
+ if let reasonInfo = sdkReader.statusInfo.unavailableReasonInfo {
319
+ let reason = SquareMobilePaymentsHelper.convertUnavailableReason(reasonInfo.reason)
320
+ let message = reasonInfo.title
321
+ unavailableReasonInfo = UnavailableReasonInfo(reason: reason, message: message)
322
+ }
323
+
324
+ return ReaderInfo(
325
+ serialNumber: serialNumber,
326
+ model: model,
327
+ status: status,
328
+ firmwareVersion: firmwareVersion,
329
+ batteryLevel: batteryLevel,
330
+ isCharging: isCharging,
331
+ supportedCardInputMethods: supportedCardInputMethods,
332
+ unavailableReasonInfo: unavailableReasonInfo
333
+ )
334
+ }
335
+
336
+ private func convertSdkPaymentToPayment(_ sdkPayment: SquareMobilePaymentsSDK.Payment) -> Payment {
337
+ let id: String?
338
+ let status: String
339
+ var cardDetails: CardPaymentDetails?
340
+
341
+ // Handle OnlinePayment vs OfflinePayment
342
+ if let onlinePayment = sdkPayment as? SquareMobilePaymentsSDK.OnlinePayment {
343
+ id = onlinePayment.id
344
+ status = SquareMobilePaymentsHelper.convertPaymentStatus(onlinePayment.status)
345
+
346
+ if let details = onlinePayment.cardDetails {
347
+ if let cardInfo = details.card {
348
+ let card = Card(
349
+ brand: SquareMobilePaymentsHelper.convertCardBrand(cardInfo.cardBrand),
350
+ lastFourDigits: cardInfo.last4 ?? "",
351
+ cardholderName: cardInfo.cardholderName,
352
+ expirationMonth: Int(cardInfo.expMonth),
353
+ expirationYear: Int(cardInfo.expYear)
354
+ )
355
+
356
+ cardDetails = CardPaymentDetails(
357
+ card: card,
358
+ entryMethod: SquareMobilePaymentsHelper.convertCardInputMethodFromString(nil),
359
+ authorizationCode: details.authResultCode,
360
+ applicationName: details.applicationName,
361
+ applicationId: details.applicationIdentifier
362
+ )
363
+ }
364
+ }
365
+ } else if let offlinePayment = sdkPayment as? SquareMobilePaymentsSDK.OfflinePayment {
366
+ id = offlinePayment.id
367
+ // OfflineStatus is different, map to our PaymentStatus
368
+ switch offlinePayment.status {
369
+ case .queued: status = "PENDING"
370
+ case .uploaded: status = "PENDING"
371
+ case .processed: status = "COMPLETED"
372
+ case .failedToUpload: status = "FAILED"
373
+ case .failedToProcess: status = "FAILED"
374
+ case .unknown: status = "PENDING"
375
+ @unknown default: status = "PENDING"
376
+ }
377
+
378
+ // Note: OfflinePayment has OfflineCardPaymentDetails, which may have a different structure
379
+ // For now, we'll skip card details for offline payments
380
+ } else {
381
+ id = nil
382
+ status = "PENDING"
383
+ }
384
+
385
+ let type = SquareMobilePaymentsHelper.convertPaymentType(sdkPayment)
386
+
387
+ let amountMoney = MoneyResult(
388
+ amount: Int(sdkPayment.totalMoney.amount),
389
+ currency: getCurrencyString(sdkPayment.totalMoney.currency)
390
+ )
391
+
392
+ var tipMoney: MoneyResult?
393
+ if let tip = sdkPayment.tipMoney {
394
+ tipMoney = MoneyResult(amount: Int(tip.amount), currency: getCurrencyString(tip.currency))
395
+ }
396
+
397
+ var applicationFee: MoneyResult?
398
+ if let fee = sdkPayment.appFeeMoney {
399
+ applicationFee = MoneyResult(amount: Int(fee.amount), currency: getCurrencyString(fee.currency))
400
+ }
401
+
402
+ let referenceId = sdkPayment.referenceID
403
+ let orderId = sdkPayment.orderID
404
+
405
+ let createdAt = sdkPayment.createdAt.iso8601String
406
+ let updatedAt = sdkPayment.updatedAt.iso8601String
407
+
408
+ return Payment(
409
+ id: id,
410
+ type: type,
411
+ status: status,
412
+ amountMoney: amountMoney,
413
+ tipMoney: tipMoney,
414
+ applicationFee: applicationFee,
415
+ referenceId: referenceId,
416
+ orderId: orderId,
417
+ cardDetails: cardDetails,
418
+ createdAt: createdAt,
419
+ updatedAt: updatedAt
420
+ )
421
+ }
422
+
423
+ // MARK: - Helper Functions
424
+
425
+ private func getCurrencyString(_ currency: SquareMobilePaymentsSDK.Currency) -> String {
426
+ switch currency {
427
+ case .USD: return "USD"
428
+ case .CAD: return "CAD"
429
+ case .AUD: return "AUD"
430
+ case .GBP: return "GBP"
431
+ case .EUR: return "EUR"
432
+ case .JPY: return "JPY"
433
+ @unknown default: return "USD"
434
+ }
435
+ }
436
+
437
+ private func parseISO8601Duration(_ duration: String) -> TimeInterval {
438
+ // Simple parser for ISO 8601 durations (e.g., "PT1H" = 1 hour)
439
+ // Format: P[n]Y[n]M[n]DT[n]H[n]M[n]S
440
+ var seconds: TimeInterval = 0
441
+
442
+ let pattern = "PT(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+)S)?"
443
+ if let regex = try? NSRegularExpression(pattern: pattern, options: []),
444
+ let match = regex.firstMatch(in: duration, options: [], range: NSRange(duration.startIndex..., in: duration)) {
445
+
446
+ if let hoursRange = Range(match.range(at: 1), in: duration),
447
+ let hours = Double(duration[hoursRange]) {
448
+ seconds += hours * 3600
449
+ }
450
+ if let minutesRange = Range(match.range(at: 2), in: duration),
451
+ let minutes = Double(duration[minutesRange]) {
452
+ seconds += minutes * 60
453
+ }
454
+ if let secondsRange = Range(match.range(at: 3), in: duration),
455
+ let secs = Double(duration[secondsRange]) {
456
+ seconds += secs
457
+ }
458
+ }
459
+
460
+ return seconds > 0 ? seconds : 60 // Default to 60 seconds minimum
461
+ }
462
+ }
463
+
464
+ // MARK: - ReaderPairingDelegate
465
+
466
+ extension SquareMobilePayments: ReaderPairingDelegate {
467
+ public func readerPairingDidBegin() {
468
+ plugin?.notifyListeners("readerPairingDidBegin", data: [:])
469
+ }
470
+
471
+ public func readerPairingDidSucceed() {
472
+ pairingHandle = nil
473
+ plugin?.notifyListeners("readerPairingDidSucceed", data: [:])
474
+ }
475
+
476
+ public func readerPairingDidFail(with error: Error) {
477
+ pairingHandle = nil
478
+ var data: [String: Any] = ["message": error.localizedDescription]
479
+ if let nsError = error as NSError? {
480
+ data["code"] = nsError.domain
481
+ }
482
+ plugin?.notifyListeners("readerPairingDidFail", data: data)
483
+ }
484
+ }
485
+
486
+ // MARK: - ReaderObserver
487
+
488
+ extension SquareMobilePayments: ReaderObserver {
489
+ public func readerWasAdded(_ readerInfo: SquareMobilePaymentsSDK.ReaderInfo) {
490
+ let reader = convertSdkReaderToReaderInfo(readerInfo)
491
+ if let data = reader.toJSObject() as? JSObject {
492
+ plugin?.notifyListeners("readerWasAdded", data: ["reader": data])
493
+ }
494
+ }
495
+
496
+ public func readerWasRemoved(_ readerInfo: SquareMobilePaymentsSDK.ReaderInfo) {
497
+ let reader = convertSdkReaderToReaderInfo(readerInfo)
498
+ if let data = reader.toJSObject() as? JSObject {
499
+ plugin?.notifyListeners("readerWasRemoved", data: ["reader": data])
500
+ }
501
+ }
502
+
503
+ public func readerDidChange(_ readerInfo: SquareMobilePaymentsSDK.ReaderInfo, change: SquareMobilePaymentsSDK.ReaderChange) {
504
+ let reader = convertSdkReaderToReaderInfo(readerInfo)
505
+ let changeStr = SquareMobilePaymentsHelper.convertReaderChange(change)
506
+ if let data = reader.toJSObject() as? JSObject {
507
+ plugin?.notifyListeners("readerDidChange", data: ["reader": data, "change": changeStr])
508
+ }
509
+ }
510
+ }
511
+
512
+ // MARK: - AvailableCardInputMethodsObserver
513
+
514
+ extension SquareMobilePayments: AvailableCardInputMethodsObserver {
515
+ public func availableCardInputMethodsDidChange(_ cardInputMethods: SquareMobilePaymentsSDK.CardInputMethods) {
516
+ let methods = SquareMobilePaymentsHelper.convertCardInputMethods(cardInputMethods)
517
+ plugin?.notifyListeners("availableCardInputMethodsDidChange", data: ["cardInputMethods": methods])
518
+ }
519
+ }
520
+
521
+ // MARK: - PaymentManagerDelegate
522
+
523
+ extension SquareMobilePayments: PaymentManagerDelegate {
524
+ public func paymentManager(_ paymentManager: SquareMobilePaymentsSDK.PaymentManager, didFinish payment: SquareMobilePaymentsSDK.Payment) {
525
+ paymentHandle = nil
526
+ let paymentResult = convertSdkPaymentToPayment(payment)
527
+ if let data = paymentResult.toJSObject() as? JSObject {
528
+ plugin?.notifyListeners("paymentDidFinish", data: ["payment": data])
529
+ }
530
+ }
531
+
532
+ public func paymentManager(_ paymentManager: SquareMobilePaymentsSDK.PaymentManager, didFail payment: SquareMobilePaymentsSDK.Payment, withError error: Error) {
533
+ paymentHandle = nil
534
+ let paymentResult = convertSdkPaymentToPayment(payment)
535
+ var data: [String: Any] = ["message": error.localizedDescription]
536
+ if let paymentData = paymentResult.toJSObject() as? JSObject {
537
+ data["payment"] = paymentData
538
+ }
539
+ if let nsError = error as NSError? {
540
+ data["code"] = nsError.domain
541
+ }
542
+ plugin?.notifyListeners("paymentDidFail", data: data)
543
+ }
544
+
545
+ public func paymentManager(_ paymentManager: SquareMobilePaymentsSDK.PaymentManager, didCancel payment: SquareMobilePaymentsSDK.Payment) {
546
+ paymentHandle = nil
547
+ let paymentResult = convertSdkPaymentToPayment(payment)
548
+ var data: [String: Any] = [:]
549
+ if let paymentData = paymentResult.toJSObject() as? JSObject {
550
+ data["payment"] = paymentData
551
+ }
552
+ plugin?.notifyListeners("paymentDidCancel", data: data)
553
+ }
554
+
555
+ // MARK: - Permission Methods
556
+
557
+ @objc public func checkLocationPermission() -> CLAuthorizationStatus {
558
+ if #available(iOS 14.0, *) {
559
+ if locationManager == nil {
560
+ locationManager = CLLocationManager()
561
+ locationManager?.delegate = self
562
+ }
563
+ return locationManager?.authorizationStatus ?? .notDetermined
564
+ } else {
565
+ return CLLocationManager.authorizationStatus()
566
+ }
567
+ }
568
+
569
+ @objc public func requestLocationPermission(completion: @escaping (CLAuthorizationStatus) -> Void) {
570
+ if locationManager == nil {
571
+ locationManager = CLLocationManager()
572
+ locationManager?.delegate = self
573
+ }
574
+ locationPermissionCompletion = completion
575
+ locationManager?.requestWhenInUseAuthorization()
576
+ }
577
+
578
+ @objc public func checkBluetoothPermission() -> CBManagerAuthorization {
579
+ if #available(iOS 13.1, *) {
580
+ return CBCentralManager.authorization
581
+ } else {
582
+ return .allowedAlways
583
+ }
584
+ }
585
+
586
+ @objc public func requestBluetoothPermission(completion: @escaping () -> Void) {
587
+ guard CBCentralManager.authorization == .notDetermined else {
588
+ completion()
589
+ return
590
+ }
591
+
592
+ bluetoothPermissionCompletion = completion
593
+ bluetoothManager = CBCentralManager(
594
+ delegate: self,
595
+ queue: .main,
596
+ options: nil
597
+ )
598
+ }
599
+ }
600
+
601
+ // MARK: - CLLocationManagerDelegate
602
+
603
+ extension SquareMobilePayments: CLLocationManagerDelegate {
604
+ public func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
605
+ let status: CLAuthorizationStatus
606
+ if #available(iOS 14.0, *) {
607
+ status = manager.authorizationStatus
608
+ } else {
609
+ status = CLLocationManager.authorizationStatus()
610
+ }
611
+ locationPermissionCompletion?(status)
612
+ locationPermissionCompletion = nil
613
+ }
614
+ }
615
+
616
+ // MARK: - CBCentralManagerDelegate
617
+
618
+ extension SquareMobilePayments: CBCentralManagerDelegate {
619
+ public func centralManagerDidUpdateState(_ central: CBCentralManager) {
620
+ bluetoothPermissionCompletion?()
621
+ bluetoothPermissionCompletion = nil
622
+ }
623
+ }
624
+
625
+ // MARK: - Date Extension
626
+
627
+ extension Date {
628
+ var iso8601String: String {
629
+ let formatter = ISO8601DateFormatter()
630
+ return formatter.string(from: self)
631
+ }
632
+ }