From ad6165563ae7d8542c259d4031cbcf2f5b23821e Mon Sep 17 00:00:00 2001 From: ozgur <6615094+ozgur00@users.noreply.github.com> Date: Tue, 7 Jan 2025 14:16:49 +0100 Subject: [PATCH] Propagate additionalDetails on native 3ds2 cancel flow COAND-1057 --- .../internal/ui/DefaultAdyen3DS2Delegate.kt | 19 ++++++++++++++----- .../ui/DefaultAdyen3DS2DelegateTest.kt | 9 ++++----- RELEASE_NOTES.md | 1 + 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/3ds2/src/main/java/com/adyen/checkout/adyen3ds2/internal/ui/DefaultAdyen3DS2Delegate.kt b/3ds2/src/main/java/com/adyen/checkout/adyen3ds2/internal/ui/DefaultAdyen3DS2Delegate.kt index 83f38fda4a..6286ce8ca5 100644 --- a/3ds2/src/main/java/com/adyen/checkout/adyen3ds2/internal/ui/DefaultAdyen3DS2Delegate.kt +++ b/3ds2/src/main/java/com/adyen/checkout/adyen3ds2/internal/ui/DefaultAdyen3DS2Delegate.kt @@ -15,7 +15,6 @@ import androidx.annotation.VisibleForTesting import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.SavedStateHandle import com.adyen.checkout.adyen3ds2.Authentication3DS2Exception -import com.adyen.checkout.adyen3ds2.Cancelled3DS2Exception import com.adyen.checkout.adyen3ds2.internal.analytics.ThreeDS2Events import com.adyen.checkout.adyen3ds2.internal.data.api.SubmitFingerprintRepository import com.adyen.checkout.adyen3ds2.internal.data.model.Adyen3DS2Serializer @@ -573,10 +572,20 @@ internal class DefaultAdyen3DS2Delegate( } } - private fun onCancelled() { + private fun onCancelled(result: ChallengeResult.Cancelled) { adyenLog(AdyenLogLevel.DEBUG) { "challenge cancelled" } - emitError(Cancelled3DS2Exception("Challenge canceled.")) - closeTransaction() + try { + val details = makeDetails(result.transactionStatus, result.additionalDetails) + emitDetails(details) + } catch (e: CheckoutException) { + trackChallengeErrorEvent( + errorEvent = ErrorEvent.THREEDS2_CHALLENGE_HANDLING, + message = "Challenge is cancelled and details cannot be created", + ) + emitError(e) + } finally { + closeTransaction() + } } private fun onTimeout(result: ChallengeResult.Timeout) { @@ -615,7 +624,7 @@ internal class DefaultAdyen3DS2Delegate( when (result) { is ChallengeResult.Cancelled -> { trackChallengeCompletedEvent(ThreeDS2Events.Result.CANCELLED) - onCancelled() + onCancelled(result) } is ChallengeResult.Completed -> { diff --git a/3ds2/src/test/java/com/adyen/checkout/adyen3ds2/internal/ui/DefaultAdyen3DS2DelegateTest.kt b/3ds2/src/test/java/com/adyen/checkout/adyen3ds2/internal/ui/DefaultAdyen3DS2DelegateTest.kt index cec5f7ea90..1a099a3768 100644 --- a/3ds2/src/test/java/com/adyen/checkout/adyen3ds2/internal/ui/DefaultAdyen3DS2DelegateTest.kt +++ b/3ds2/src/test/java/com/adyen/checkout/adyen3ds2/internal/ui/DefaultAdyen3DS2DelegateTest.kt @@ -16,7 +16,6 @@ import android.content.Context import android.content.Intent import androidx.lifecycle.SavedStateHandle import com.adyen.checkout.adyen3ds2.Authentication3DS2Exception -import com.adyen.checkout.adyen3ds2.Cancelled3DS2Exception import com.adyen.checkout.adyen3ds2.internal.analytics.ThreeDS2Events import com.adyen.checkout.adyen3ds2.internal.data.api.SubmitFingerprintRepository import com.adyen.checkout.adyen3ds2.internal.data.model.Adyen3DS2Serializer @@ -489,8 +488,8 @@ internal class DefaultAdyen3DS2DelegateTest( } @Test - fun `cancelled, then an error is emitted`() = runTest { - val exceptionFlow = delegate.exceptionFlow.test(testScheduler) + fun `cancelled, then details are emitted`() = runTest { + val detailsFlow = delegate.detailsFlow.test(testScheduler) delegate.onCompletion( result = ChallengeResult.Cancelled( @@ -499,11 +498,11 @@ internal class DefaultAdyen3DS2DelegateTest( ), ) - assertTrue(exceptionFlow.latestValue is Cancelled3DS2Exception) + assertNotNull(detailsFlow.latestValue.details) } @Test - fun `timedout, then details are emitted`() = runTest { + fun `timed out, then details are emitted`() = runTest { val detailsFlow = delegate.detailsFlow.test(testScheduler) delegate.onCompletion( diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index ab6d91f712..d252aeed13 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -11,6 +11,7 @@ ## New - Launch Google Pay with `submit()` to get rid of the deprecated activity result handling. - For drop-in, show a toolbar on every intermediary screen, so shoppers can always easily navigate back. +- For 3DS2 native flow, cancellations by shopper trigger `onAdditionalDetails()` now. With this change, merchants will be able to make a `/payments/details` call so that they can get more insight on the transaction. ## Fixed