-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/add dropin advanced flow ios #32
Merged
Merged
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/ios/Classes/CheckoutPlatformApi.swift b/ios/Classes/CheckoutPlatformApi.swift index 49d9dfe..4d4a355 100644 --- a/ios/Classes/CheckoutPlatformApi.swift +++ b/ios/Classes/CheckoutPlatformApi.swift @@ -1,16 +1,10 @@ -// -// CheckoutApi.swift -// adyen_checkout -// -// Created by Robert Schulze Dieckhoff on 07/08/2023. -// import Foundation @_spi(AdyenInternal) import Adyen +@_spi(AdyenInternal) import AdyenNetworking - //Todo Add config: // 1) Add Info.plist for adding photo library usage description // 2) Add url scheme @@ -21,7 +15,8 @@ class CheckoutPlatformApi : CheckoutPlatformInterface { private var session: AdyenSession? private var dropInComponent: DropInComponent? private var viewController : UIViewController? - + private let jsonDecoder = JSONDecoder() + init(checkoutFlutterApi: CheckoutFlutterApi) { self.checkoutFlutterApi = checkoutFlutterApi } @@ -43,8 +38,7 @@ class CheckoutPlatformApi : CheckoutPlatformInterface { switch result { case let .success(session): self?.session = session - let paymentMethods = session.sessionContext.paymentMethods - let dropInConfiguration = self?.createDropInConfiguration(paymentMethods: paymentMethods) + let dropInConfiguration = self?.createDropInConfiguration() let dropInComponent = DropInComponent(paymentMethods: session.sessionContext.paymentMethods, context: adyenContext, configuration: dropInConfiguration!) @@ -66,7 +60,19 @@ class CheckoutPlatformApi : CheckoutPlatformInterface { func startDropInAdvancedFlowPayment(dropInConfiguration: DropInConfiguration, paymentMethodsResponse: String) { - + do { + viewController = UIApplication.shared.adyen.mainKeyWindow?.rootViewController + let adyenContext = try createAdyenContext(dropInConfiguration: dropInConfiguration) + let paymentMethods = try jsonDecoder.decode(PaymentMethods.self, from:Data(paymentMethodsResponse.utf8)) + let configuration = createDropInConfiguration() + let dropInComponent = DropInComponent(paymentMethods: paymentMethods,context: adyenContext,configuration: configuration) + dropInComponent.delegate = self + dropInComponent.storedPaymentMethodsDelegate = self + self.dropInComponent = dropInComponent + viewController?.present(dropInComponent.viewController, animated: true) + } catch let error { + checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel: PlatformCommunicationModel(type: PlatformCommunicationType.result, dropInResult: DropInResult(type: DropInResultEnum.error, reason: error.localizedDescription)), completion: {}) + } } func getReturnUrl(completion: @escaping (Result<String, Error>) -> Void) { @@ -74,11 +80,13 @@ class CheckoutPlatformApi : CheckoutPlatformInterface { } func onPaymentsResult(paymentsResult: DropInResult) throws { - + print(paymentsResult) + handleResponse(result: paymentsResult) } - + func onPaymentsDetailsResult(paymentsDetailsResult: DropInResult) throws { - + print(paymentsDetailsResult) + handleResponse(result: paymentsDetailsResult) } private func createAdyenContext(dropInConfiguration: DropInConfiguration) throws -> AdyenContext { @@ -109,11 +117,43 @@ class CheckoutPlatformApi : CheckoutPlatformInterface { } } - private func createDropInConfiguration(paymentMethods: PaymentMethods) -> DropInComponent.Configuration { + private func createDropInConfiguration() -> DropInComponent.Configuration { let dropInConfiguration = DropInComponent.Configuration() return dropInConfiguration } + private func handleResponse(result: [String : Any?]) { + do { + if let action = result["action"] { + let jsonData = try JSONSerialization.data(withJSONObject: action, options: []) + let decoder = JSONDecoder() + let result = try decoder.decode(Action.self, from: jsonData) + self.dropInComponent?.handle(result) + } else if result.keys.contains("resultCode") { + + let resultCode = ResultCode(rawValue: result["resultCode"] as! String) + + let success = resultCode == .authorised || resultCode == .received || resultCode == .pending + self.dropInComponent?.finalizeIfNeeded(with: success) { [weak self] in + print("dismiss") + + self?.dropInComponent?.viewController.dismiss(animated: false) + self?.dropInComponent?.viewController.dismiss(animated: false) + } + } + } catch let error { + print(error) + } + + } + + + private func finalize(_ success: Bool, _ message: String) { + dropInComponent?.finalizeIfNeeded(with: success) { [weak self] in + guard let self = self else { return } + self.viewController?.dismiss(animated: true) + } + } } extension CheckoutPlatformApi: AdyenSessionDelegate { @@ -142,3 +182,70 @@ extension CheckoutPlatformApi: PresentationDelegate { //This is required later when integrating components } } + + +//AdvancedFlow +extension CheckoutPlatformApi: DropInComponentDelegate { + + func didSubmit(_ data: PaymentComponentData, from component: PaymentComponent, in dropInComponent: AnyDropInComponent) { + do { + let componentData = PaymentComponentDataResponse(amount: data.amount, paymentMethod: data.paymentMethod.encodable, storePaymentMethod: data.storePaymentMethod, order: data.order, amountToPay: data.order?.remainingAmount, installments: data.installments, shopperName: data.shopperName, emailAddress: data.emailAddress, telephoneNumber: data.telephoneNumber, browserInfo: data.browserInfo, checkoutAttemptId: data.checkoutAttemptId, billingAddress: data.billingAddress, deliveryAddress: data.deliveryAddress, socialSecurityNumber: data.socialSecurityNumber, delegatedAuthenticationData: data.delegatedAuthenticationData) + + let json = try JSONEncoder().encode(componentData) + let jsonString = String(data: json, encoding: .utf8) + //TODO discuss to use an actual class instead of json + checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel:PlatformCommunicationModel(type: PlatformCommunicationType.paymentComponent, data:jsonString ), completion: {}) + } catch let error { + print(error.localizedDescription) + } + } + + func didFail(with error: Error, from component: PaymentComponent, in dropInComponent: AnyDropInComponent) { + print(error) + self.dropInComponent?.viewController.dismiss(animated: true) + } + + func didProvide(_ data: ActionComponentData, from component: ActionComponent, in dropInComponent: AnyDropInComponent) { + print("did provide") + do { + let actionComponentData = ActionComponentDataModel(details: data.details.encodable, paymentData: data.paymentData) + let json = try JSONEncoder().encode(actionComponentData) + let jsonString = String(data: json, encoding: .utf8) + checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel:PlatformCommunicationModel(type: PlatformCommunicationType.additionalDetails, data:jsonString ), completion: {}) + } catch let error { + print(error.localizedDescription) + } + } + + func didComplete(from component: ActionComponent, in dropInComponent: AnyDropInComponent) { + print("did complete") + } + + func didFail(with error: Error, from component: ActionComponent, in dropInComponent: AnyDropInComponent) { + print(error) + self.dropInComponent?.viewController.dismiss(animated: true) + } + + internal func didCancel(component: PaymentComponent, from dropInComponent: AnyDropInComponent) { + // Handle the event when the user closes a PresentableComponent. + print("User did close: \(component.paymentMethod.name)") + self.dropInComponent?.viewController.dismiss(animated: true) + } + + internal func didFail(with error: Error, from dropInComponent: AnyDropInComponent) { + print(error) + self.dropInComponent?.viewController.dismiss(animated: true) + } + + private func handleAction(action: Action) { + print("has action") + self.dropInComponent?.handle(action) + } + +} + +extension CheckoutPlatformApi: StoredPaymentMethodsDelegate { + internal func disable(storedPaymentMethod: StoredPaymentMethod, completion: @escaping (Bool) -> Void) { + print("stored disabled") + } +} diff --git a/ios/Classes/models/ActionComponentDataModel.swift b/ios/Classes/models/ActionComponentDataModel.swift new file mode 100644 index 0000000..367c273 --- /dev/null +++ b/ios/Classes/models/ActionComponentDataModel.swift @@ -0,0 +1,16 @@ +// +// ActionComponentDataModel.swift +// adyen_checkout +// +// Created by Robert Schulze Dieckhoff on 30/08/2023. +// + +import Foundation +import Adyen + +struct ActionComponentDataModel : Encodable { + + let details: AnyEncodable + + let paymentData: String? +} diff --git a/ios/Classes/models/PaymentComponentDataResponse.swift b/ios/Classes/models/PaymentComponentDataResponse.swift new file mode 100644 index 0000000..3ca8a86 --- /dev/null +++ b/ios/Classes/models/PaymentComponentDataResponse.swift @@ -0,0 +1,55 @@ +import Foundation +@_spi(AdyenInternal) +import Adyen + + +struct PaymentComponentDataResponse : Encodable { + + let amount: Adyen.Amount? + + let paymentMethod: AnyEncodable? + + let storePaymentMethod: Bool? + + let order: PartialPaymentOrder? + + @available(*, deprecated, message: "This property is deprecated. Use the amount property if needed.") + let amountToPay: Adyen.Amount? + + let installments: Installments? + + let supportNativeRedirect: Bool = true + + let shopperName: ShopperName? + + let emailAddress: String? + + let telephoneNumber: String? + + let browserInfo: BrowserInfo? + + let checkoutAttemptId: String? + + let billingAddress: PostalAddress? + + let deliveryAddress: PostalAddress? + + let socialSecurityNumber: String? + + let delegatedAuthenticationData: DelegatedAuthenticationData? + + + + + enum CodingKeys: String, CodingKey { + case amount, paymentMethod, storePaymentMethod, order, amountToPay, installments, supportNativeRedirect,shopperName,emailAddress, telephoneNumber, browserInfo, checkoutAttemptId, billingAddress, deliveryAddress, socialSecurityNumber, delegatedAuthenticationData + } +} + + +struct PaymentMethodDetailsModel: Details, Encodable { + + var checkoutAttemptId: String? +} + + diff --git a/ios/Classes/models/ResultCode.swift b/ios/Classes/models/ResultCode.swift new file mode 100644 index 0000000..7d1c6ce --- /dev/null +++ b/ios/Classes/models/ResultCode.swift @@ -0,0 +1,21 @@ +// +// ResultCode.swift +// adyen_checkout +// +// Created by Robert Schulze Dieckhoff on 30/08/2023. +// + +import Foundation + +enum ResultCode: String, Decodable { + case authorised = "Authorised" + case refused = "Refused" + case pending = "Pending" + case cancelled = "Cancelled" + case error = "Error" + case received = "Received" + case redirectShopper = "RedirectShopper" + case identifyShopper = "IdentifyShopper" + case challengeShopper = "ChallengeShopper" + case presentToShopper = "PresentToShopper" +}
diff --git a/ios/Classes/models/ActionComponentDataModel.swift b/ios/Classes/models/ActionComponentDataModel.swift index 367c273..e5ffda0 100644 --- a/ios/Classes/models/ActionComponentDataModel.swift +++ b/ios/Classes/models/ActionComponentDataModel.swift @@ -1,10 +1,3 @@ -// -// ActionComponentDataModel.swift -// adyen_checkout -// -// Created by Robert Schulze Dieckhoff on 30/08/2023. -// - import Foundation import Adyen diff --git a/ios/Classes/models/PaymentComponentDataResponse.swift b/ios/Classes/models/PaymentComponentDataResponse.swift index 3ca8a86..d2e13b0 100644 --- a/ios/Classes/models/PaymentComponentDataResponse.swift +++ b/ios/Classes/models/PaymentComponentDataResponse.swift @@ -2,7 +2,6 @@ import Foundation @_spi(AdyenInternal) import Adyen - struct PaymentComponentDataResponse : Encodable { let amount: Adyen.Amount? @@ -10,7 +9,7 @@ struct PaymentComponentDataResponse : Encodable { let paymentMethod: AnyEncodable? let storePaymentMethod: Bool? - + let order: PartialPaymentOrder? @available(*, deprecated, message: "This property is deprecated. Use the amount property if needed.") @@ -21,13 +20,13 @@ struct PaymentComponentDataResponse : Encodable { let supportNativeRedirect: Bool = true let shopperName: ShopperName? - + let emailAddress: String? let telephoneNumber: String? let browserInfo: BrowserInfo? - + let checkoutAttemptId: String? let billingAddress: PostalAddress? @@ -37,19 +36,8 @@ struct PaymentComponentDataResponse : Encodable { let socialSecurityNumber: String? let delegatedAuthenticationData: DelegatedAuthenticationData? - - - enum CodingKeys: String, CodingKey { case amount, paymentMethod, storePaymentMethod, order, amountToPay, installments, supportNativeRedirect,shopperName,emailAddress, telephoneNumber, browserInfo, checkoutAttemptId, billingAddress, deliveryAddress, socialSecurityNumber, delegatedAuthenticationData } } - - -struct PaymentMethodDetailsModel: Details, Encodable { - - var checkoutAttemptId: String? -} - -
diff --git a/example/lib/network/service.dart b/example/lib/network/service.dart index cb0dac1..430dc35 100644 --- a/example/lib/network/service.dart +++ b/example/lib/network/service.dart @@ -39,7 +39,8 @@ class Service { return jsonDecode(response.body); } - Future<Map<String, dynamic>> postPaymentsDetails(Map<String, dynamic> body) async { + Future<Map<String, dynamic>> postPaymentsDetails( + Map<String, dynamic> body) async { final response = await http.post( Uri.https(Config.baseUrl, "/${Config.apiVersion}/payments/details"), headers: _createHeaders(), diff --git a/ios/Classes/CheckoutPlatformApi.swift b/ios/Classes/CheckoutPlatformApi.swift index 4d4a355..e21152f 100644 --- a/ios/Classes/CheckoutPlatformApi.swift +++ b/ios/Classes/CheckoutPlatformApi.swift @@ -1,4 +1,3 @@ - import Foundation @_spi(AdyenInternal) import Adyen @@ -11,12 +10,16 @@ import AdyenNetworking // 3) Add AppDelegate redirect class CheckoutPlatformApi : CheckoutPlatformInterface { + var dropInComponent: DropInComponent? + private let jsonDecoder = JSONDecoder() private let checkoutFlutterApi: CheckoutFlutterApi - private var session: AdyenSession? - private var dropInComponent: DropInComponent? private var viewController : UIViewController? - private let jsonDecoder = JSONDecoder() - + private var session: AdyenSession? + private var dropInSessionsDelegate : AdyenSessionDelegate? + private var dropInSessionsPresentationDelegate : PresentationDelegate? + private var dropInAdvancedFlowDelegate : DropInComponentDelegate? + private var storedPaymentMethodsDelegate : StoredPaymentMethodsDelegate? + init(checkoutFlutterApi: CheckoutFlutterApi) { self.checkoutFlutterApi = checkoutFlutterApi } @@ -28,50 +31,55 @@ class CheckoutPlatformApi : CheckoutPlatformInterface { func startDropInSessionPayment(dropInConfiguration: DropInConfiguration, session: Session) { do { - viewController = UIApplication.shared.adyen.mainKeyWindow?.rootViewController + guard let viewController = UIApplication.shared.adyen.mainKeyWindow?.rootViewController else { + return + } + + self.viewController = viewController + dropInSessionsDelegate = DropInSessionsDelegate(viewController: viewController, checkoutFlutterApi: checkoutFlutterApi) + dropInSessionsPresentationDelegate = DropInSessionsPresentationDelegate() let adyenContext = try createAdyenContext(dropInConfiguration: dropInConfiguration) - let configuration = AdyenSession.Configuration(sessionIdentifier: session.id, - initialSessionData: session.sessionData, - context: adyenContext) - DispatchQueue.main.async { - AdyenSession.initialize(with: configuration, delegate: self, presentationDelegate: self) { [weak self] result in - switch result { - case let .success(session): - self?.session = session - let dropInConfiguration = self?.createDropInConfiguration() - let dropInComponent = DropInComponent(paymentMethods: session.sessionContext.paymentMethods, - context: adyenContext, - configuration: dropInConfiguration!) - dropInComponent.delegate = session - dropInComponent.partialPaymentDelegate = session - self?.dropInComponent = dropInComponent - self?.viewController?.present(dropInComponent.viewController, animated: true) - case let .failure(error): - print("Native sdk error: \(error.localizedDescription)") - self?.checkoutFlutterApi.onDropInSessionResult(sessionPaymentResult: PaymentResult(type: PaymentResultEnum.error, reason: error.localizedDescription)) {} - } + let configuration = AdyenSession.Configuration(sessionIdentifier: session.id, initialSessionData: session.sessionData, context: adyenContext) + AdyenSession.initialize(with: configuration, delegate: self.dropInSessionsDelegate!, presentationDelegate: self.dropInSessionsPresentationDelegate!) { [weak self] result in + switch result { + case let .success(session): + self?.session = session + let dropInConfiguration = self?.createDropInConfiguration() + let dropInComponent = DropInComponent(paymentMethods: session.sessionContext.paymentMethods, context: adyenContext, configuration: dropInConfiguration!) + dropInComponent.delegate = session + dropInComponent.partialPaymentDelegate = session + self?.dropInComponent = dropInComponent + self?.viewController?.present(dropInComponent.viewController, animated: true) + case let .failure(error): + self?.checkoutFlutterApi.onDropInSessionResult(sessionDropInResult: DropInResult(type: DropInResultEnum.error, reason: error.localizedDescription)) {} } } } catch let error { - print("Native sdk error: \(error.localizedDescription)") - checkoutFlutterApi.onDropInSessionResult(sessionPaymentResult: PaymentResult(type: PaymentResultEnum.error, reason: error.localizedDescription)) {} + checkoutFlutterApi.onDropInSessionResult(sessionDropInResult: DropInResult(type: DropInResultEnum.error, reason: error.localizedDescription)) {} } } func startDropInAdvancedFlowPayment(dropInConfiguration: DropInConfiguration, paymentMethodsResponse: String) { do { - viewController = UIApplication.shared.adyen.mainKeyWindow?.rootViewController + guard let viewController = UIApplication.shared.adyen.mainKeyWindow?.rootViewController else { + return + } + + self.viewController = viewController let adyenContext = try createAdyenContext(dropInConfiguration: dropInConfiguration) let paymentMethods = try jsonDecoder.decode(PaymentMethods.self, from:Data(paymentMethodsResponse.utf8)) let configuration = createDropInConfiguration() let dropInComponent = DropInComponent(paymentMethods: paymentMethods,context: adyenContext,configuration: configuration) - dropInComponent.delegate = self - dropInComponent.storedPaymentMethodsDelegate = self + dropInAdvancedFlowDelegate = DropInAdvancedFlowDelegate(checkoutFlutterApi: checkoutFlutterApi, component: dropInComponent) + storedPaymentMethodsDelegate = DropInAdvancedFlowStoredPaymentMethodsDelegate() + dropInComponent.delegate = dropInAdvancedFlowDelegate + dropInComponent.storedPaymentMethodsDelegate = storedPaymentMethodsDelegate self.dropInComponent = dropInComponent - viewController?.present(dropInComponent.viewController, animated: true) + self.viewController?.present(dropInComponent.viewController, animated: true) } catch let error { - checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel: PlatformCommunicationModel(type: PlatformCommunicationType.result, dropInResult: DropInResult(type: DropInResultEnum.error, reason: error.localizedDescription)), completion: {}) + let platformCommunicationModel = PlatformCommunicationModel(type: PlatformCommunicationType.result, dropInResult: DropInResult(type: DropInResultEnum.error, reason: error.localizedDescription)) + checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel: platformCommunicationModel, completion: {}) } } @@ -79,13 +87,11 @@ class CheckoutPlatformApi : CheckoutPlatformInterface { completion(Result.success("")) } - func onPaymentsResult(paymentsResult: DropInResult) throws { - print(paymentsResult) + func onPaymentsResult(paymentsResult: DropInResult) { handleResponse(result: paymentsResult) } - func onPaymentsDetailsResult(paymentsDetailsResult: DropInResult) throws { - print(paymentsDetailsResult) + func onPaymentsDetailsResult(paymentsDetailsResult: DropInResult) { handleResponse(result: paymentsDetailsResult) } @@ -124,30 +130,26 @@ class CheckoutPlatformApi : CheckoutPlatformInterface { private func handleResponse(result: [String : Any?]) { do { - if let action = result["action"] { - let jsonData = try JSONSerialization.data(withJSONObject: action, options: []) - let decoder = JSONDecoder() - let result = try decoder.decode(Action.self, from: jsonData) + if (result.keys.contains("action")) { + let action = result["action"] + let jsonData = try JSONSerialization.data(withJSONObject: action as! [String: Any], options: []) + let result = try JSONDecoder().decode(Action.self, from: jsonData) self.dropInComponent?.handle(result) - } else if result.keys.contains("resultCode") { - + } else if (result.keys.contains("resultCode")) { let resultCode = ResultCode(rawValue: result["resultCode"] as! String) - let success = resultCode == .authorised || resultCode == .received || resultCode == .pending self.dropInComponent?.finalizeIfNeeded(with: success) { [weak self] in - print("dismiss") - - self?.dropInComponent?.viewController.dismiss(animated: false) - self?.dropInComponent?.viewController.dismiss(animated: false) + self?.dropInComponent?.viewController.presentingViewController?.dismiss(animated: false, completion: { + let dropInResult = DropInResult(type: DropInResultEnum.finished, result: PaymentResult(resultCode: resultCode?.rawValue)) + self?.checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel: PlatformCommunicationModel(type: PlatformCommunicationType.result, dropInResult: dropInResult), completion: {}) + }) } } } catch let error { print(error) } - } - private func finalize(_ success: Bool, _ message: String) { dropInComponent?.finalizeIfNeeded(with: success) { [weak self] in guard let self = self else { return } @@ -155,97 +157,3 @@ class CheckoutPlatformApi : CheckoutPlatformInterface { } } } - -extension CheckoutPlatformApi: AdyenSessionDelegate { - func didComplete(with resultCode: SessionPaymentResultCode, component: Component, session: AdyenSession) { - self.viewController?.dismiss(animated: false, completion: { - self.checkoutFlutterApi.onDropInSessionResult(sessionPaymentResult: PaymentResult( - type: PaymentResultEnum.finished, - result: SessionPaymentResultModel(sessionId: session.sessionContext.identifier, sessionData: session.sessionContext.data, resultCode: resultCode.rawValue)), completion: {}) - }) - } - - func didFail(with error: Error, from component: Component, session: AdyenSession) { - self.viewController?.dismiss(animated: true) - print("Native sdk error: \(error.localizedDescription)") - checkoutFlutterApi.onDropInSessionResult(sessionPaymentResult: PaymentResult(type: PaymentResultEnum.cancelledByUser, reason: error.localizedDescription)) {} - } - - func didOpenExternalApplication(component: ActionComponent, session: AdyenSession) { - print("external") - } -} - -extension CheckoutPlatformApi: PresentationDelegate { - func present(component: PresentableComponent) { - print("presentable component") - //This is required later when integrating components - } -} - - -//AdvancedFlow -extension CheckoutPlatformApi: DropInComponentDelegate { - - func didSubmit(_ data: PaymentComponentData, from component: PaymentComponent, in dropInComponent: AnyDropInComponent) { - do { - let componentData = PaymentComponentDataResponse(amount: data.amount, paymentMethod: data.paymentMethod.encodable, storePaymentMethod: data.storePaymentMethod, order: data.order, amountToPay: data.order?.remainingAmount, installments: data.installments, shopperName: data.shopperName, emailAddress: data.emailAddress, telephoneNumber: data.telephoneNumber, browserInfo: data.browserInfo, checkoutAttemptId: data.checkoutAttemptId, billingAddress: data.billingAddress, deliveryAddress: data.deliveryAddress, socialSecurityNumber: data.socialSecurityNumber, delegatedAuthenticationData: data.delegatedAuthenticationData) - - let json = try JSONEncoder().encode(componentData) - let jsonString = String(data: json, encoding: .utf8) - //TODO discuss to use an actual class instead of json - checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel:PlatformCommunicationModel(type: PlatformCommunicationType.paymentComponent, data:jsonString ), completion: {}) - } catch let error { - print(error.localizedDescription) - } - } - - func didFail(with error: Error, from component: PaymentComponent, in dropInComponent: AnyDropInComponent) { - print(error) - self.dropInComponent?.viewController.dismiss(animated: true) - } - - func didProvide(_ data: ActionComponentData, from component: ActionComponent, in dropInComponent: AnyDropInComponent) { - print("did provide") - do { - let actionComponentData = ActionComponentDataModel(details: data.details.encodable, paymentData: data.paymentData) - let json = try JSONEncoder().encode(actionComponentData) - let jsonString = String(data: json, encoding: .utf8) - checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel:PlatformCommunicationModel(type: PlatformCommunicationType.additionalDetails, data:jsonString ), completion: {}) - } catch let error { - print(error.localizedDescription) - } - } - - func didComplete(from component: ActionComponent, in dropInComponent: AnyDropInComponent) { - print("did complete") - } - - func didFail(with error: Error, from component: ActionComponent, in dropInComponent: AnyDropInComponent) { - print(error) - self.dropInComponent?.viewController.dismiss(animated: true) - } - - internal func didCancel(component: PaymentComponent, from dropInComponent: AnyDropInComponent) { - // Handle the event when the user closes a PresentableComponent. - print("User did close: \(component.paymentMethod.name)") - self.dropInComponent?.viewController.dismiss(animated: true) - } - - internal func didFail(with error: Error, from dropInComponent: AnyDropInComponent) { - print(error) - self.dropInComponent?.viewController.dismiss(animated: true) - } - - private func handleAction(action: Action) { - print("has action") - self.dropInComponent?.handle(action) - } - -} - -extension CheckoutPlatformApi: StoredPaymentMethodsDelegate { - internal func disable(storedPaymentMethod: StoredPaymentMethod, completion: @escaping (Bool) -> Void) { - print("stored disabled") - } -} diff --git a/ios/Classes/dropInSessions/DropInSessionsDelegate.swift b/ios/Classes/dropInSessions/DropInSessionsDelegate.swift new file mode 100644 index 0000000..f59bae1 --- /dev/null +++ b/ios/Classes/dropInSessions/DropInSessionsDelegate.swift @@ -0,0 +1,34 @@ +import Adyen +import AdyenNetworking + +class DropInSessionsDelegate : AdyenSessionDelegate { + private let viewController : UIViewController? + private let checkoutFlutterApi: CheckoutFlutterApi + + init(viewController: UIViewController, checkoutFlutterApi: CheckoutFlutterApi) { + self.viewController = viewController + self.checkoutFlutterApi = checkoutFlutterApi + } + + func didComplete(with resultCode: SessionPaymentResultCode, component: Component, session: AdyenSession) { + viewController?.dismiss(animated: false, completion: { + let paymentResult = PaymentResult(sessionId: session.sessionContext.identifier, sessionData: session.sessionContext.data, resultCode: resultCode.rawValue) + self.checkoutFlutterApi.onDropInSessionResult(sessionDropInResult: DropInResult(type: DropInResultEnum.finished,result: paymentResult), completion: {}) + }) + } + + func didFail(with error: Error, from component: Component, session: AdyenSession) { + viewController?.dismiss(animated: true, completion: { + switch (error) { + case ComponentError.cancelled: + self.checkoutFlutterApi.onDropInSessionResult(sessionDropInResult: DropInResult(type: DropInResultEnum.cancelledByUser, reason: error.localizedDescription)) {} + default: + self.checkoutFlutterApi.onDropInSessionResult(sessionDropInResult: DropInResult(type: DropInResultEnum.error, reason: error.localizedDescription)) {} + } + }) + } + + func didOpenExternalApplication(component: ActionComponent, session: AdyenSession) { + print("external") + } +} diff --git a/ios/Classes/dropInSessions/DropInSessionsPresentationDelegate.swift b/ios/Classes/dropInSessions/DropInSessionsPresentationDelegate.swift new file mode 100644 index 0000000..74a5eb4 --- /dev/null +++ b/ios/Classes/dropInSessions/DropInSessionsPresentationDelegate.swift @@ -0,0 +1,8 @@ +import Adyen + +class DropInSessionsPresentationDelegate : PresentationDelegate { + func present(component: PresentableComponent) { + print("presentable component") + //This is required later when integrating components + } +} diff --git a/ios/Classes/dropinAdvancedFlow/DropInAdvancedFlowDelegate.swift b/ios/Classes/dropinAdvancedFlow/DropInAdvancedFlowDelegate.swift new file mode 100644 index 0000000..b8baac3 --- /dev/null +++ b/ios/Classes/dropinAdvancedFlow/DropInAdvancedFlowDelegate.swift @@ -0,0 +1,68 @@ +import Adyen +import AdyenNetworking + +class DropInAdvancedFlowDelegate : DropInComponentDelegate { + private let checkoutFlutterApi : CheckoutFlutterApi + private let component: DropInComponent + + init(checkoutFlutterApi : CheckoutFlutterApi, component: DropInComponent) { + self.checkoutFlutterApi = checkoutFlutterApi + self.component = component + } + + func didSubmit(_ data: PaymentComponentData, from component: PaymentComponent, in dropInComponent: AnyDropInComponent) { + do { + let paymentComponentData = PaymentComponentDataResponse(amount: data.amount, paymentMethod: data.paymentMethod.encodable, storePaymentMethod: data.storePaymentMethod, order: data.order, amountToPay: data.order?.remainingAmount, installments: data.installments, shopperName: data.shopperName, emailAddress: data.emailAddress, telephoneNumber: data.telephoneNumber, browserInfo: data.browserInfo, checkoutAttemptId: data.checkoutAttemptId, billingAddress: data.billingAddress, deliveryAddress: data.deliveryAddress, socialSecurityNumber: data.socialSecurityNumber, delegatedAuthenticationData: data.delegatedAuthenticationData) + let json = try JSONEncoder().encode(paymentComponentData) + let jsonString = String(data: json, encoding: .utf8) + checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel:PlatformCommunicationModel(type: PlatformCommunicationType.paymentComponent, data:jsonString ), completion: {}) + } catch let error { + self.sendErrorToFlutterLayer(error: error) + } + } + + func didProvide(_ data: ActionComponentData, from component: ActionComponent, in dropInComponent: AnyDropInComponent) { + do { + let actionComponentData = ActionComponentDataModel(details: data.details.encodable, paymentData: data.paymentData) + let json = try JSONEncoder().encode(actionComponentData) + let jsonString = String(data: json, encoding: .utf8) + checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel:PlatformCommunicationModel(type: PlatformCommunicationType.additionalDetails, data:jsonString ), completion: {}) + } catch let error { + self.sendErrorToFlutterLayer(error: error) + } + } + + func didComplete(from component: ActionComponent, in dropInComponent: AnyDropInComponent) { + print("did complete") + } + + func didFail(with error: Error, from component: PaymentComponent, in dropInComponent: AnyDropInComponent) { + dropInComponent.viewController.presentedViewController?.dismiss(animated: true, completion: { + self.sendErrorToFlutterLayer(error: error) + }) + } + + func didFail(with error: Error, from component: ActionComponent, in dropInComponent: AnyDropInComponent) { + dropInComponent.viewController.presentedViewController?.dismiss(animated: true, completion: { + self.sendErrorToFlutterLayer(error: error) + }) + } + + func didFail(with error: Error, from dropInComponent: Adyen.AnyDropInComponent) { + dropInComponent.viewController.dismiss(animated: true, completion: { + switch (error) { + case ComponentError.cancelled: + let platformCommunicationModel = PlatformCommunicationModel(type: PlatformCommunicationType.result, dropInResult: DropInResult(type: DropInResultEnum.cancelledByUser, reason: error.localizedDescription)) + self.checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel: platformCommunicationModel, completion: {}) + default: + self.sendErrorToFlutterLayer(error: error) + } + }) + } + + private func sendErrorToFlutterLayer(error: Error) { + print(error.localizedDescription) + let platformCommunicationModel = PlatformCommunicationModel(type: PlatformCommunicationType.result, dropInResult: DropInResult(type: DropInResultEnum.error, reason: error.localizedDescription)) + checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel: platformCommunicationModel, completion: {}) + } +} diff --git a/ios/Classes/dropinAdvancedFlow/DropInAdvancedFlowStoredPaymentMethodsDelegate.swift b/ios/Classes/dropinAdvancedFlow/DropInAdvancedFlowStoredPaymentMethodsDelegate.swift new file mode 100644 index 0000000..aaa0e13 --- /dev/null +++ b/ios/Classes/dropinAdvancedFlow/DropInAdvancedFlowStoredPaymentMethodsDelegate.swift @@ -0,0 +1,7 @@ +import Adyen + +class DropInAdvancedFlowStoredPaymentMethodsDelegate : StoredPaymentMethodsDelegate { + internal func disable(storedPaymentMethod: StoredPaymentMethod, completion: @escaping (Bool) -> Void) { + print("stored disabled") + } +} diff --git a/ios/Classes/models/ActionComponentDataModel.swift b/ios/Classes/dropinAdvancedFlow/models/ActionComponentDataModel.swift similarity index 55% rename from ios/Classes/models/ActionComponentDataModel.swift rename to ios/Classes/dropinAdvancedFlow/models/ActionComponentDataModel.swift index e5ffda0..4c001ba 100644 --- a/ios/Classes/models/ActionComponentDataModel.swift +++ b/ios/Classes/dropinAdvancedFlow/models/ActionComponentDataModel.swift @@ -1,3 +1,10 @@ +// +// ActionComponentDataModel.swift +// adyen_checkout +// +// Created by Robert Schulze Dieckhoff on 01/09/2023. +// + import Foundation import Adyen diff --git a/ios/Classes/models/PaymentComponentDataResponse.swift b/ios/Classes/dropinAdvancedFlow/models/PaymentComponentDataResponse.swift similarity index 100% rename from ios/Classes/models/PaymentComponentDataResponse.swift rename to ios/Classes/dropinAdvancedFlow/models/PaymentComponentDataResponse.swift diff --git a/ios/Classes/models/ResultCode.swift b/ios/Classes/dropinAdvancedFlow/models/ResultCode.swift similarity index 80% rename from ios/Classes/models/ResultCode.swift rename to ios/Classes/dropinAdvancedFlow/models/ResultCode.swift index 7d1c6ce..3c562b0 100644 --- a/ios/Classes/models/ResultCode.swift +++ b/ios/Classes/dropinAdvancedFlow/models/ResultCode.swift @@ -1,10 +1,3 @@ -// -// ResultCode.swift -// adyen_checkout -// -// Created by Robert Schulze Dieckhoff on 30/08/2023. -// - import Foundation enum ResultCode: String, Decodable {
diff --git a/example/lib/main.dart b/example/lib/main.dart index 2a443aa..bc2e104 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -126,12 +126,18 @@ class _MyAppState extends State<MyApp> { } _dialogBuilder(BuildContext context, PaymentResult dropInResult) { + String message = ""; + if (dropInResult.result != null) { + message = "Result code: ${dropInResult.result?.resultCode}"; + } else { + message = "Error: ${dropInResult.errorReason}"; + } return showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text(dropInResult.type.name), - content: Text("Result code: ${dropInResult.result?.resultCode}"), + content: Text(message), actions: <Widget>[ TextButton( style: TextButton.styleFrom( diff --git a/ios/Classes/CheckoutPlatformApi.swift b/ios/Classes/CheckoutPlatformApi.swift index 385ba9b..c065d73 100644 --- a/ios/Classes/CheckoutPlatformApi.swift +++ b/ios/Classes/CheckoutPlatformApi.swift @@ -51,11 +51,11 @@ class CheckoutPlatformApi : CheckoutPlatformInterface { self?.dropInComponent = dropInComponent self?.viewController?.present(dropInComponent.viewController, animated: true) case let .failure(error): - self?.checkoutFlutterApi.onDropInSessionResult(sessionDropInResult: DropInResult(type: DropInResultEnum.error, reason: error.localizedDescription)) {} + self?.checkoutFlutterApi.onDropInSessionResult(sessionDropInResult: DropInResult(type: DropInResultEnum.error, errorReason: error.localizedDescription)) {} } } } catch let error { - checkoutFlutterApi.onDropInSessionResult(sessionDropInResult: DropInResult(type: DropInResultEnum.error, reason: error.localizedDescription)) {} + checkoutFlutterApi.onDropInSessionResult(sessionDropInResult: DropInResult(type: DropInResultEnum.error, errorReason: error.localizedDescription)) {} } } @@ -78,7 +78,7 @@ class CheckoutPlatformApi : CheckoutPlatformInterface { self.dropInComponent = dropInComponent self.viewController?.present(dropInComponent.viewController, animated: true) } catch let error { - let platformCommunicationModel = PlatformCommunicationModel(type: PlatformCommunicationType.result, dropInResult: DropInResult(type: DropInResultEnum.error, reason: error.localizedDescription)) + let platformCommunicationModel = PlatformCommunicationModel(type: PlatformCommunicationType.result, dropInResult: DropInResult(type: DropInResultEnum.error, errorReason: error.localizedDescription)) checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel: platformCommunicationModel, completion: {}) } } @@ -94,7 +94,7 @@ class CheckoutPlatformApi : CheckoutPlatformInterface { func onPaymentsDetailsResult(paymentsDetailsResult: DropInResult) { handleResponse(result: paymentsDetailsResult) } - + private func createAdyenContext(dropInConfiguration: DropInConfiguration) throws -> AdyenContext { let apiContext = try APIContext(environment: mapToEnvironment(environment: dropInConfiguration.environment), clientKey: dropInConfiguration.clientKey) let value: Int = Int(dropInConfiguration.amount.value) @@ -145,7 +145,7 @@ class CheckoutPlatformApi : CheckoutPlatformInterface { }) } } else { - let dropInResult = DropInResult(type: DropInResultEnum.error, reason: "\(result)") + let dropInResult = DropInResult(type: DropInResultEnum.error, errorReason: "\(String(describing: result["message"]!!))") self.checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel: PlatformCommunicationModel(type: PlatformCommunicationType.result, dropInResult: dropInResult), completion: {}) self.finalize(false, "\(result)") } diff --git a/ios/Classes/dropInSessions/DropInSessionsDelegate.swift b/ios/Classes/dropInSessions/DropInSessionsDelegate.swift index f59bae1..ff51117 100644 --- a/ios/Classes/dropInSessions/DropInSessionsDelegate.swift +++ b/ios/Classes/dropInSessions/DropInSessionsDelegate.swift @@ -21,9 +21,9 @@ class DropInSessionsDelegate : AdyenSessionDelegate { viewController?.dismiss(animated: true, completion: { switch (error) { case ComponentError.cancelled: - self.checkoutFlutterApi.onDropInSessionResult(sessionDropInResult: DropInResult(type: DropInResultEnum.cancelledByUser, reason: error.localizedDescription)) {} + self.checkoutFlutterApi.onDropInSessionResult(sessionDropInResult: DropInResult(type: DropInResultEnum.cancelledByUser, errorReason: error.localizedDescription)) {} default: - self.checkoutFlutterApi.onDropInSessionResult(sessionDropInResult: DropInResult(type: DropInResultEnum.error, reason: error.localizedDescription)) {} + self.checkoutFlutterApi.onDropInSessionResult(sessionDropInResult: DropInResult(type: DropInResultEnum.error, errorReason: error.localizedDescription)) {} } }) } diff --git a/ios/Classes/dropinAdvancedFlow/DropInAdvancedFlowDelegate.swift b/ios/Classes/dropinAdvancedFlow/DropInAdvancedFlowDelegate.swift index b8baac3..aa14ac6 100644 --- a/ios/Classes/dropinAdvancedFlow/DropInAdvancedFlowDelegate.swift +++ b/ios/Classes/dropinAdvancedFlow/DropInAdvancedFlowDelegate.swift @@ -52,7 +52,7 @@ class DropInAdvancedFlowDelegate : DropInComponentDelegate { dropInComponent.viewController.dismiss(animated: true, completion: { switch (error) { case ComponentError.cancelled: - let platformCommunicationModel = PlatformCommunicationModel(type: PlatformCommunicationType.result, dropInResult: DropInResult(type: DropInResultEnum.cancelledByUser, reason: error.localizedDescription)) + let platformCommunicationModel = PlatformCommunicationModel(type: PlatformCommunicationType.result, dropInResult: DropInResult(type: DropInResultEnum.cancelledByUser, errorReason: error.localizedDescription)) self.checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel: platformCommunicationModel, completion: {}) default: self.sendErrorToFlutterLayer(error: error) @@ -62,7 +62,7 @@ class DropInAdvancedFlowDelegate : DropInComponentDelegate { private func sendErrorToFlutterLayer(error: Error) { print(error.localizedDescription) - let platformCommunicationModel = PlatformCommunicationModel(type: PlatformCommunicationType.result, dropInResult: DropInResult(type: DropInResultEnum.error, reason: error.localizedDescription)) + let platformCommunicationModel = PlatformCommunicationModel(type: PlatformCommunicationType.result, dropInResult: DropInResult(type: DropInResultEnum.error, errorReason: error.localizedDescription)) checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel: platformCommunicationModel, completion: {}) } } diff --git a/lib/src/platform/adyen_checkout_api.dart b/lib/src/platform/adyen_checkout_api.dart index 4632fc7..a282882 100644 --- a/lib/src/platform/adyen_checkout_api.dart +++ b/lib/src/platform/adyen_checkout_api.dart @@ -37,7 +37,4 @@ class AdyenCheckoutApi implements AdyenCheckoutPlatformInterface { @OverRide void onPaymentsDetailsResult(DropInResult paymentsDetailsResult) => checkoutApi.onPaymentsDetailsResult(paymentsDetailsResult); - - @OverRide - void hide() => checkoutApi.hide(); }
Robert-SD
force-pushed
the
feature/add_dropin_advanced_flow_ios
branch
from
September 7, 2023 14:47
d044208
to
10e40a7
Compare
nauaros
reviewed
Sep 12, 2023
ios/Classes/dropInAdvancedFlow/models/PaymentComponentDataResponse.swift
Outdated
Show resolved
Hide resolved
nauaros
approved these changes
Sep 12, 2023
…they are not supported in beta version
OscarSpruit
reviewed
Sep 12, 2023
OscarSpruit
approved these changes
Sep 13, 2023
jreij
approved these changes
Sep 13, 2023
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
Added drop in advanced flow for iOS