Skip to content

Commit

Permalink
Moved drop in result handling to merchant side
Browse files Browse the repository at this point in the history
  • Loading branch information
Robert-SD committed Sep 7, 2023
1 parent e4374ad commit d044208
Show file tree
Hide file tree
Showing 17 changed files with 131 additions and 148 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import CheckoutFlutterApi
import CheckoutPlatformInterface
import PaymentResult
import PaymentResultEnum
import PaymentResultModel
import PlatformCommunicationModel
import PlatformCommunicationType
import SessionPaymentResultModel
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
Expand Down Expand Up @@ -96,7 +96,7 @@ class AdyenCheckoutPlugin : FlutterPlugin, ActivityAware {

is SessionDropInResult.Finished -> PaymentResult(
PaymentResultEnum.FINISHED, result = with(sessionDropInResult.result) {
SessionPaymentResultModel(
PaymentResultModel(
sessionId,
sessionData,
resultCode,
Expand All @@ -123,7 +123,7 @@ class AdyenCheckoutPlugin : FlutterPlugin, ActivityAware {
)

is DropInResult.Finished -> PaymentResult(
PaymentResultEnum.FINISHED, result = SessionPaymentResultModel(
PaymentResultEnum.FINISHED, result = PaymentResultModel(
resultCode = dropInAdvancedFlowResult.result
)
)
Expand Down
20 changes: 10 additions & 10 deletions android/src/main/kotlin/com/adyen/adyen_checkout/PlatformApi.kt
Original file line number Diff line number Diff line change
Expand Up @@ -184,16 +184,16 @@ data class DropInConfiguration (
data class PaymentResult (
val type: PaymentResultEnum,
val reason: String? = null,
val result: SessionPaymentResultModel? = null
val result: PaymentResultModel? = null

) {
companion object {
@Suppress("UNCHECKED_CAST")
fun fromList(list: List<Any?>): PaymentResult {
val type = PaymentResultEnum.ofRaw(list[0] as Int)!!
val reason = list[1] as String?
val result: SessionPaymentResultModel? = (list[2] as List<Any?>?)?.let {
SessionPaymentResultModel.fromList(it)
val result: PaymentResultModel? = (list[2] as List<Any?>?)?.let {
PaymentResultModel.fromList(it)
}
return PaymentResult(type, reason, result)
}
Expand All @@ -208,7 +208,7 @@ data class PaymentResult (
}

/** Generated class from Pigeon that represents data sent in messages. */
data class SessionPaymentResultModel (
data class PaymentResultModel (
val sessionId: String? = null,
val sessionData: String? = null,
val resultCode: String? = null,
Expand All @@ -217,14 +217,14 @@ data class SessionPaymentResultModel (
) {
companion object {
@Suppress("UNCHECKED_CAST")
fun fromList(list: List<Any?>): SessionPaymentResultModel {
fun fromList(list: List<Any?>): PaymentResultModel {
val sessionId = list[0] as String?
val sessionData = list[1] as String?
val resultCode = list[2] as String?
val order: OrderResponseModel? = (list[3] as List<Any?>?)?.let {
OrderResponseModel.fromList(it)
}
return SessionPaymentResultModel(sessionId, sessionData, resultCode, order)
return PaymentResultModel(sessionId, sessionData, resultCode, order)
}
}
fun toList(): List<Any?> {
Expand Down Expand Up @@ -565,12 +565,12 @@ private object CheckoutFlutterApiCodec : StandardMessageCodec() {
}
131.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
PlatformCommunicationModel.fromList(it)
PaymentResultModel.fromList(it)
}
}
132.toByte() -> {
return (readValue(buffer) as? List<Any?>)?.let {
SessionPaymentResultModel.fromList(it)
PlatformCommunicationModel.fromList(it)
}
}
else -> super.readValueOfType(type, buffer)
Expand All @@ -590,11 +590,11 @@ private object CheckoutFlutterApiCodec : StandardMessageCodec() {
stream.write(130)
writeValue(stream, value.toList())
}
is PlatformCommunicationModel -> {
is PaymentResultModel -> {
stream.write(131)
writeValue(stream, value.toList())
}
is SessionPaymentResultModel -> {
is PlatformCommunicationModel -> {
stream.write(132)
writeValue(stream, value.toList())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class AdvancedFlowDropInService : DropInService(), LifecycleOwner {
return@observe
}

val dropInServiceResult = mapToDropInServiceResult(message.contentIfNotHandled)
val dropInServiceResult = mapToDropInResult(message.contentIfNotHandled)
sendResult(dropInServiceResult)
}
}
Expand All @@ -64,12 +64,12 @@ class AdvancedFlowDropInService : DropInService(), LifecycleOwner {
return@observe
}

val dropInServiceResult = mapToDropInServiceResult(message.contentIfNotHandled)
val dropInServiceResult = mapToDropInResult(message.contentIfNotHandled)
sendResult(dropInServiceResult)
}
}

private fun mapToDropInServiceResult(dropInResult: DropInResult?): DropInServiceResult {
private fun mapToDropInResult(dropInResult: DropInResult?): DropInServiceResult {
return when (dropInResult?.dropInResultType) {
FINISHED -> DropInServiceResult.Finished(result = "${dropInResult.result}")

Expand Down
2 changes: 0 additions & 2 deletions example/lib/config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ class Config {
static const String baseUrl = "checkout-test.adyen.com";
static const String apiVersion = "v70";
static const String iOSReturnUrl = "ui-host://payments";
static const String channel = "Android";
static const String shopperIp = "142.12.31.22";

//Example data
static Amount amount = Amount(currency: "EUR", value: 2100);
Expand Down
15 changes: 8 additions & 7 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class _MyAppState extends State<MyApp> {
);

return await _adyenCheckout.startPayment(
paymentFlow: PaymentFlow.dropIn(
paymentFlow: DropInSession(
dropInConfiguration: dropInConfiguration,
session: session,
),
Expand All @@ -116,7 +116,7 @@ class _MyAppState extends State<MyApp> {
);

return await _adyenCheckout.startPayment(
paymentFlow: PaymentFlow.dropInAdvanced(
paymentFlow: DropInAdvancedFlow(
dropInConfiguration: dropInConfiguration,
paymentMethodsResponse: paymentMethodsResponse,
postPayments: _adyenSessionRepository.postPayments,
Expand All @@ -125,18 +125,19 @@ class _MyAppState extends State<MyApp> {
);
}

_dialogBuilder(BuildContext context, PaymentResult dropInResult) {
_dialogBuilder(BuildContext context, PaymentResult paymentResult) {
String message = "";
if (dropInResult.result != null) {
message = "Result code: ${dropInResult.result?.resultCode}";
if (paymentResult.result != null) {
message = "Result code: ${paymentResult.result?.resultCode}";
} else {
message = "Error: ${dropInResult.errorReason}";
message = "Error: ${paymentResult.reason}";
}

return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(dropInResult.type.name),
title: Text(paymentResult.type.name),
content: Text(message),
actions: <Widget>[
TextButton(
Expand Down
17 changes: 14 additions & 3 deletions example/lib/repositories/adyen_sessions_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class AdyenSessionsRepository {
return await _service.fetchPaymentMethods(PaymentMethodsRequestNetworkModel(
merchantAccount: Config.merchantAccount,
countryCode: Config.countryCode,
channel: Config.channel,
channel: _determineChannel(),
));
}

Expand All @@ -66,9 +66,8 @@ class AdyenSessionsRepository {
value: Config.amount.value,
currency: Config.amount.currency,
),
shopperIP: Config.shopperIp,
countryCode: Config.countryCode,
channel: Config.channel,
channel: _determineChannel(),
additionalData: AdditionalData(allow3DS2: true, executeThreeD: true),
threeDS2RequestData: ThreeDS2RequestDataRequest(),
threeDSAuthenticationOnly: false,
Expand Down Expand Up @@ -98,4 +97,16 @@ class AdyenSessionsRepository {
throw Exception("Unsupported platform");
}
}

String _determineChannel() {
if (Platform.isAndroid) {
return "Android";
}

if (Platform.isIOS) {
return "iOS";
}

throw Exception("Unsupported platform");
}
}
2 changes: 1 addition & 1 deletion example/lib/repositories/drop_in_outcome_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class DropInOutcomeHandler {
static const resultCodeKey = "resultCode";
static const actionKey = "action";
static const orderKey = "order";
static const messageKey = "messageKey";
static const messageKey = "message";

DropInOutcome handleResponse(Map<String, dynamic> jsonResponse) {
if (_isError(jsonResponse)) {
Expand Down
68 changes: 33 additions & 35 deletions ios/Classes/CheckoutPlatformApi.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,11 @@ class CheckoutPlatformApi : CheckoutPlatformInterface {
private var dropInSessionsPresentationDelegate : PresentationDelegate?
private var dropInAdvancedFlowDelegate : DropInComponentDelegate?
private var storedPaymentMethodsDelegate : StoredPaymentMethodsDelegate?
private let actionKey = "action"
private let resultCodeKey = "resultCode"

init(checkoutFlutterApi: CheckoutFlutterApi) {
self.checkoutFlutterApi = checkoutFlutterApi
}

func getPlatformVersion(completion: @escaping (Result<String, Error>) -> Void) {
let systemVersion = UIDevice.current.systemVersion
completion(Result.success(systemVersion))
Expand All @@ -36,7 +34,7 @@ class CheckoutPlatformApi : CheckoutPlatformInterface {
guard let viewController = UIApplication.shared.adyen.mainKeyWindow?.rootViewController else {
return
}

self.viewController = viewController
dropInSessionsDelegate = DropInSessionsDelegate(viewController: viewController, checkoutFlutterApi: checkoutFlutterApi)
dropInSessionsPresentationDelegate = DropInSessionsPresentationDelegate()
Expand All @@ -53,21 +51,21 @@ 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, errorReason: error.localizedDescription)) {}
self?.checkoutFlutterApi.onDropInSessionResult(sessionPaymentResult: PaymentResult(type: PaymentResultEnum.error, reason: error.localizedDescription)) {}
}
}
} catch let error {
checkoutFlutterApi.onDropInSessionResult(sessionDropInResult: DropInResult(type: DropInResultEnum.error, errorReason: error.localizedDescription)) {}
checkoutFlutterApi.onDropInSessionResult(sessionPaymentResult: PaymentResult(type: PaymentResultEnum.error, reason: error.localizedDescription)) {}
}
}


func startDropInAdvancedFlowPayment(dropInConfiguration: DropInConfiguration, paymentMethodsResponse: String) {
do {
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))
Expand All @@ -80,23 +78,23 @@ 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, errorReason: error.localizedDescription))
let platformCommunicationModel = PlatformCommunicationModel(type: PlatformCommunicationType.result, paymentResult: PaymentResult(type: PaymentResultEnum.error, reason: error.localizedDescription))
checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel: platformCommunicationModel, completion: {})
}
}

func getReturnUrl(completion: @escaping (Result<String, Error>) -> Void) {
completion(Result.failure(PlatformError(errorDescription: "Please use your app url type instead of this method.")))
}

func onPaymentsResult(paymentsResult: DropInResult) {
handleResponse(result: paymentsResult)
handleDropInResult(dropInResult: paymentsResult)
}

func onPaymentsDetailsResult(paymentsDetailsResult: DropInResult) {
handleResponse(result: paymentsDetailsResult)
handleDropInResult(dropInResult: 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)
Expand All @@ -123,39 +121,39 @@ class CheckoutPlatformApi : CheckoutPlatformInterface {
return Adyen.Environment.liveApse
}
}

private func createDropInConfiguration() -> DropInComponent.Configuration {
return DropInComponent.Configuration()
}

private func handleResponse(result: [String : Any?]) {
private func handleDropInResult(dropInResult: DropInResult) {
do {
if (result.keys.contains(actionKey)) {
let action = result[actionKey]
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(resultCodeKey)) {
let resultCode = ResultCode(rawValue: result[resultCodeKey] as! String)
switch dropInResult.dropInResultType {
case .finished:
let resultCode = ResultCode(rawValue: dropInResult.result ?? "")
let success = resultCode == .authorised || resultCode == .received || resultCode == .pending
self.dropInComponent?.finalizeIfNeeded(with: success) { [weak self] in
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: {})
let paymentResult = PaymentResult(type: PaymentResultEnum.finished, result: PaymentResultModel(resultCode: resultCode?.rawValue))
self?.checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel: PlatformCommunicationModel(type: PlatformCommunicationType.result, paymentResult: paymentResult), completion: {})
})
}
} else {
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)")
case .action:
let jsonData = try JSONSerialization.data(withJSONObject: dropInResult.actionResponse!, options: [])
let result = try JSONDecoder().decode(Action.self, from: jsonData)
self.dropInComponent?.handle(result)
case .error:
let dropInResult = PaymentResult(type: PaymentResultEnum.error, reason: dropInResult.error?.errorMessage)
self.checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel: PlatformCommunicationModel(type: PlatformCommunicationType.result, paymentResult: dropInResult), completion: {})
self.finalize(false, dropInResult.reason ?? "")
}
} catch let error {
let dropInResult = DropInResult(type: DropInResultEnum.error, errorReason: error.localizedDescription)
self.checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel: PlatformCommunicationModel(type: PlatformCommunicationType.result, dropInResult: dropInResult), completion: {})
self.finalize(false, "\(result)")
let dropInResult = PaymentResult(type: PaymentResultEnum.error, reason: error.localizedDescription)
self.checkoutFlutterApi.onDropInAdvancedFlowPlatformCommunication(platformCommunicationModel: PlatformCommunicationModel(type: PlatformCommunicationType.result, paymentResult: dropInResult), completion: {})
self.finalize(false, "\(error.localizedDescription)")
}
}

private func finalize(_ success: Bool, _ message: String) {
dropInComponent?.finalizeIfNeeded(with: success) { [weak self] in
guard let self = self else { return }
Expand Down
Loading

0 comments on commit d044208

Please sign in to comment.