Skip to content

Commit

Permalink
Merge pull request #42 from Adyen/feature/ImproveStoredPaymentMethodR…
Browse files Browse the repository at this point in the history
…emovalError

Added error message for removal of a stored payment method and improv…
  • Loading branch information
Robert-SD authored Oct 4, 2023
2 parents b970ffc + a5d3a3c commit 92edf6e
Show file tree
Hide file tree
Showing 15 changed files with 124 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,13 @@ class CheckoutPlatformApi(private val checkoutFlutterApi: CheckoutFlutterApi?) :
DropInPaymentMethodDeletionResultMessenger.sendResult(deleteStoredPaymentMethodResultDTO)
}

private suspend fun createCheckoutSession(
override fun cleanUpDropIn() {
DropInServiceResultMessenger.instance().removeObservers(activity)
DropInPaymentMethodDeletionPlatformMessenger.instance().removeObservers(activity)
DropInAdditionalDetailsPlatformMessenger.instance().removeObservers(activity)
}

private suspend fun createCheckoutSession(
sessionModel: com.adyen.checkout.sessions.core.SessionModel,
dropInConfiguration: com.adyen.checkout.dropin.DropInConfiguration,
): CheckoutSession {
Expand Down
18 changes: 18 additions & 0 deletions android/src/main/kotlin/com/adyen/adyen_checkout/PlatformApi.kt
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,7 @@ interface CheckoutPlatformInterface {
fun onPaymentsResult(paymentsResult: DropInResultDTO)
fun onPaymentsDetailsResult(paymentsDetailsResult: DropInResultDTO)
fun onDeleteStoredPaymentMethodResult(deleteStoredPaymentMethodResultDTO: DeletedStoredPaymentMethodResultDTO)
fun cleanUpDropIn()

companion object {
/** The codec used by CheckoutPlatformInterface. */
Expand Down Expand Up @@ -885,6 +886,23 @@ interface CheckoutPlatformInterface {
channel.setMessageHandler(null)
}
}
run {
val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.adyen_checkout.CheckoutPlatformInterface.cleanUpDropIn", codec)
if (api != null) {
channel.setMessageHandler { _, reply ->
var wrapped: List<Any?>
try {
api.cleanUpDropIn()
wrapped = listOf<Any?>(null)
} catch (exception: Throwable) {
wrapped = wrapError(exception)
}
reply.reply(wrapped)
}
} else {
channel.setMessageHandler(null)
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ class AdvancedFlowDropInService : DropInService(), LifecycleOwner {
return if (deleteStoredPaymentMethodResultDTO?.isSuccessfullyRemoved == true) {
RecurringDropInServiceResult.PaymentMethodRemoved(deleteStoredPaymentMethodResultDTO.storedPaymentMethodId)
} else {
RecurringDropInServiceResult.Error(errorDialog = ErrorDialog())
//TODO - the error message should be provided by the native SDK
RecurringDropInServiceResult.Error(errorDialog = ErrorDialog(message = "Removal of the stored payment method failed. Please try again later."))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ class SessionDropInService : SessionDropInService(), LifecycleOwner {
return if (deleteStoredPaymentMethodResultDTO?.isSuccessfullyRemoved == true) {
RecurringDropInServiceResult.PaymentMethodRemoved(deleteStoredPaymentMethodResultDTO.storedPaymentMethodId)
} else {
RecurringDropInServiceResult.Error(errorDialog = ErrorDialog())
//TODO - the error message should be provided by the native SDK
RecurringDropInServiceResult.Error(errorDialog = ErrorDialog(message = "Removal of the stored payment method failed. Please try again later."))
}
}

Expand Down
29 changes: 20 additions & 9 deletions ios/Classes/CheckoutPlatformApi.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ class CheckoutPlatformApi : CheckoutPlatformInterface {
let sessionConfiguration = AdyenSession.Configuration(sessionIdentifier: session.id,
initialSessionData: session.sessionData,
context: adyenContext)
self.dropInSessionStoredPaymentMethodsDelegate = DropInSessionsStoredPaymentMethodsDelegate(checkoutFlutterApi: self.checkoutFlutterApi)
dropInSessionStoredPaymentMethodsDelegate = DropInSessionsStoredPaymentMethodsDelegate(viewController: viewController,
checkoutFlutterApi: checkoutFlutterApi)

AdyenSession.initialize(with: sessionConfiguration,
delegate: dropInSessionDelegate!,
Expand Down Expand Up @@ -89,9 +90,11 @@ class CheckoutPlatformApi : CheckoutPlatformInterface {
context: adyenContext,
configuration: configuration)
dropInAdvancedFlowDelegate = DropInAdvancedFlowDelegate(checkoutFlutterApi: checkoutFlutterApi, component: dropInComponent)
dropInAdvancedFlowStoredPaymentMethodsDelegate = DropInAdvancedFlowStoredPaymentMethodsDelegate(checkoutFlutterApi: checkoutFlutterApi)
dropInComponent.delegate = dropInAdvancedFlowDelegate

if (dropInConfigurationDTO.isRemoveStoredPaymentMethodEnabled == true) {
dropInAdvancedFlowStoredPaymentMethodsDelegate = DropInAdvancedFlowStoredPaymentMethodsDelegate(viewController:viewController,
checkoutFlutterApi: checkoutFlutterApi)
dropInComponent.storedPaymentMethodsDelegate = dropInAdvancedFlowStoredPaymentMethodsDelegate
}
self.dropInComponent = dropInComponent
Expand Down Expand Up @@ -119,6 +122,14 @@ class CheckoutPlatformApi : CheckoutPlatformInterface {
dropInAdvancedFlowStoredPaymentMethodsDelegate?.handleDisableResult(isSuccessfullyRemoved: deleteStoredPaymentMethodResultDTO.isSuccessfullyRemoved)
}

func cleanUpDropIn() {
dropInSessionDelegate = nil
dropInSessionPresentationDelegate = nil
dropInSessionStoredPaymentMethodsDelegate = nil
dropInAdvancedFlowDelegate = nil
dropInAdvancedFlowStoredPaymentMethodsDelegate = nil
}

private func getViewController() -> UIViewController? {
var rootViewController = UIApplication.shared.adyen.mainKeyWindow?.rootViewController
while let presentedViewController = rootViewController?.presentedViewController {
Expand Down Expand Up @@ -173,15 +184,15 @@ class CheckoutPlatformApi : CheckoutPlatformInterface {
}
} catch let error {
let paymentResult = PaymentResultDTO(type: PaymentResultEnum.error, reason: error.localizedDescription)
self.checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel: PlatformCommunicationModel(type: PlatformCommunicationType.result, paymentResult: paymentResult), completion: {})
self.finalize(false, "\(error.localizedDescription)")
checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel: PlatformCommunicationModel(type: PlatformCommunicationType.result, paymentResult: paymentResult), completion: {})
finalize(false, "\(error.localizedDescription)")
}
}

private func onDropInResultFinished(dropInResult: DropInResultDTO) {
let resultCode = ResultCode(rawValue: dropInResult.result ?? "")
let success = resultCode == .authorised || resultCode == .received || resultCode == .pending
self.dropInComponent?.finalizeIfNeeded(with: success) { [weak self] in
dropInComponent?.finalizeIfNeeded(with: success) { [weak self] in
self?.dropInComponent?.viewController.presentingViewController?.dismiss(animated: false, completion: {
let paymentResult = PaymentResultDTO(type: PaymentResultEnum.finished, result: PaymentResultModelDTO(resultCode: resultCode?.rawValue))
self?.checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel: PlatformCommunicationModel(type: PlatformCommunicationType.result, paymentResult: paymentResult), completion: {})
Expand All @@ -192,13 +203,13 @@ class CheckoutPlatformApi : CheckoutPlatformInterface {
private func onDropInResultAction(dropInResult: DropInResultDTO) throws {
let jsonData = try JSONSerialization.data(withJSONObject: dropInResult.actionResponse as Any, options: [])
let result = try JSONDecoder().decode(Action.self, from: jsonData)
self.dropInComponent?.handle(result)
dropInComponent?.handle(result)
}

private func onDropInResultError(dropInResult: DropInResultDTO) {
let paymentResult = PaymentResultDTO(type: PaymentResultEnum.error, reason: dropInResult.error?.errorMessage)
self.checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel: PlatformCommunicationModel(type: PlatformCommunicationType.result, paymentResult: paymentResult), completion: {})
self.finalize(false, dropInResult.error?.errorMessage ?? "")
checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel: PlatformCommunicationModel(type: PlatformCommunicationType.result, paymentResult: paymentResult), completion: {})
finalize(false, dropInResult.error?.errorMessage ?? "")
}

private func finalize(_ success: Bool, _ message: String) {
Expand All @@ -214,7 +225,7 @@ class CheckoutPlatformApi : CheckoutPlatformInterface {
return PaymentMethods(regular: paymentMethods, stored: storedPaymentMethods)
}

func sendSessionError(error: Error) {
private func sendSessionError(error: Error) {
let platformCommunicationModel = PlatformCommunicationModel(type: PlatformCommunicationType.result, paymentResult: PaymentResultDTO(type: PaymentResultEnum.error, reason: error.localizedDescription))
checkoutFlutterApi.onDropInSessionPlatformCommunication(platformCommunicationModel: platformCommunicationModel, completion: {})
}
Expand Down
14 changes: 14 additions & 0 deletions ios/Classes/PlatformApi.swift
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,7 @@ protocol CheckoutPlatformInterface {
func onPaymentsResult(paymentsResult: DropInResultDTO) throws
func onPaymentsDetailsResult(paymentsDetailsResult: DropInResultDTO) throws
func onDeleteStoredPaymentMethodResult(deleteStoredPaymentMethodResultDTO: DeletedStoredPaymentMethodResultDTO) throws
func cleanUpDropIn() throws
}

/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
Expand Down Expand Up @@ -815,6 +816,19 @@ class CheckoutPlatformInterfaceSetup {
} else {
onDeleteStoredPaymentMethodResultChannel.setMessageHandler(nil)
}
let cleanUpDropInChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.adyen_checkout.CheckoutPlatformInterface.cleanUpDropIn", binaryMessenger: binaryMessenger, codec: codec)
if let api = api {
cleanUpDropInChannel.setMessageHandler { _, reply in
do {
try api.cleanUpDropIn()
reply(wrapResult(nil))
} catch {
reply(wrapError(error))
}
}
} else {
cleanUpDropInChannel.setMessageHandler(nil)
}
}
}
private class CheckoutFlutterApiCodecReader: FlutterStandardReader {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
@_spi(AdyenInternal)
import Adyen

class DropInAdvancedFlowStoredPaymentMethodsDelegate : StoredPaymentMethodsDelegate {
private let checkoutFlutterApi: CheckoutFlutterApi
private let viewController : UIViewController
private var completionHandler: ((Bool) -> Void)?

init(checkoutFlutterApi: CheckoutFlutterApi) {
init(viewController: UIViewController, checkoutFlutterApi: CheckoutFlutterApi) {
self.checkoutFlutterApi = checkoutFlutterApi
self.viewController = viewController
}

internal func disable(storedPaymentMethod: StoredPaymentMethod, completion: @escaping (Bool) -> Void) {
Expand All @@ -15,6 +18,11 @@ class DropInAdvancedFlowStoredPaymentMethodsDelegate : StoredPaymentMethodsDeleg
}

func handleDisableResult(isSuccessfullyRemoved: Bool) {
if (isSuccessfullyRemoved == false) {
let errorAlert = TemporaryAlertHelper.buildPaymentMethodDeletionErrorAlert()
viewController.adyen.topPresenter.present(errorAlert, animated: true)
}

completionHandler?(isSuccessfullyRemoved)
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
@_spi(AdyenInternal)
import Adyen

class DropInSessionsStoredPaymentMethodsDelegate : StoredPaymentMethodsDelegate {
private let checkoutFlutterApi: CheckoutFlutterApi
private let viewController : UIViewController
private var completionHandler: ((Bool) -> Void)?

init(checkoutFlutterApi: CheckoutFlutterApi) {
init(viewController: UIViewController, checkoutFlutterApi: CheckoutFlutterApi) {
self.checkoutFlutterApi = checkoutFlutterApi
self.viewController = viewController
}

internal func disable(storedPaymentMethod: StoredPaymentMethod, completion: @escaping (Bool) -> Void) {
Expand All @@ -15,6 +18,11 @@ class DropInSessionsStoredPaymentMethodsDelegate : StoredPaymentMethodsDelegate
}

func handleDisableResult(isSuccessfullyRemoved: Bool) {
if (isSuccessfullyRemoved == false) {
let errorAlert = TemporaryAlertHelper.buildPaymentMethodDeletionErrorAlert()
viewController.adyen.topPresenter.present(errorAlert, animated: true)
}

completionHandler?(isSuccessfullyRemoved)
}
}
Expand Down
9 changes: 9 additions & 0 deletions ios/Classes/utils/TemporaryAlertHelper.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class TemporaryAlertHelper {

static func buildPaymentMethodDeletionErrorAlert() -> UIAlertController {
//TODO - this should be part of the native SDK and be translated there
let alertController = UIAlertController(title: "Error", message: "Removal of the stored payment method failed. Please try again later.", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "OK", style: .cancel))
return alertController;
}
}
2 changes: 2 additions & 0 deletions lib/src/adyen_checkout.dart
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class AdyenCheckout implements AdyenCheckoutInterface {
});

return dropInSessionCompleter.future.then((value) {
AdyenCheckoutPlatformInterface.instance.cleanUpDropIn();
_resultApi.dropInSessionPlatformCommunicationStream.close();
return value.fromDTO();
});
Expand Down Expand Up @@ -153,6 +154,7 @@ class AdyenCheckout implements AdyenCheckoutInterface {
});

return dropInAdvancedFlowCompleter.future.then((value) {
AdyenCheckoutPlatformInterface.instance.cleanUpDropIn();
_resultApi.dropInAdvancedFlowPlatformCommunicationStream.close();
return value.fromDTO();
});
Expand Down
22 changes: 22 additions & 0 deletions lib/src/generated/platform_api.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -903,6 +903,28 @@ class CheckoutPlatformInterface {
return;
}
}

Future<void> cleanUpDropIn() async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.adyen_checkout.CheckoutPlatformInterface.cleanUpDropIn', codec,
binaryMessenger: _binaryMessenger);
final List<Object?>? replyList =
await channel.send(null) as List<Object?>?;
if (replyList == null) {
throw PlatformException(
code: 'channel-error',
message: 'Unable to establish connection on channel.',
);
} else if (replyList.length > 1) {
throw PlatformException(
code: replyList[0]! as String,
message: replyList[1] as String?,
details: replyList[2],
);
} else {
return;
}
}
}

class _CheckoutFlutterApiCodec extends StandardMessageCodec {
Expand Down
3 changes: 3 additions & 0 deletions lib/src/platform/adyen_checkout_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,7 @@ class AdyenCheckoutApi implements AdyenCheckoutPlatformInterface {
deleteStoredPaymentMethodResultDTO) =>
checkoutApi.onDeleteStoredPaymentMethodResult(
deleteStoredPaymentMethodResultDTO);

@override
void cleanUpDropIn() => checkoutApi.cleanUpDropIn();
}
2 changes: 2 additions & 0 deletions lib/src/platform/adyen_checkout_platform_interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,6 @@ abstract class AdyenCheckoutPlatformInterface extends PlatformInterface {

void onDeleteStoredPaymentMethodResult(
DeletedStoredPaymentMethodResultDTO deleteStoredPaymentMethodResultDTO);

void cleanUpDropIn();
}
2 changes: 2 additions & 0 deletions pigeons/platform_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,8 @@ abstract class CheckoutPlatformInterface {

void onDeleteStoredPaymentMethodResult(
DeletedStoredPaymentMethodResultDTO deleteStoredPaymentMethodResultDTO);

void cleanUpDropIn();
}

@FlutterApi()
Expand Down
3 changes: 3 additions & 0 deletions test/adyen_checkout_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ class MockAdyenCheckoutPlatform
@override
void onDeleteStoredPaymentMethodResult(
DeletedStoredPaymentMethodResultDTO deleteStoredPaymentMethodResultDTO) {}

@override
void cleanUpDropIn() {}
}

void main() {
Expand Down

0 comments on commit 92edf6e

Please sign in to comment.