Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
19d87bd
AGP 9.3.2
vitalii-vanziak-cko Sep 1, 2026
f07a5e9
Add new payment states
vitalii-vanziak-cko Sep 2, 2026
fc6cd58
PONativeAlternativePaymentAvailableAction
vitalii-vanziak-cko Sep 2, 2026
83c5e18
Include `availableActions` in responses
vitalii-vanziak-cko Sep 2, 2026
f95394f
Add PreferredFinalizationMode configuration to POCreateInvoiceRequest
vitalii-vanziak-cko Sep 2, 2026
0621167
AGP 9.4.1
vitalii-vanziak-cko Sep 21, 2026
44a5027
Pass `availableActions` from response to `handlePaymentState()` funct…
vitalii-vanziak-cko Sep 21, 2026
6fbe9a5
KDoc
vitalii-vanziak-cko Sep 23, 2026
2eb0fda
Dispatch manual finalization via delegate
vitalii-vanziak-cko Sep 23, 2026
37e35cf
Interactor: requestManualFinalization() & collectManualFinalizationRe…
vitalii-vanziak-cko Sep 23, 2026
afe1875
Pass `paymentState` via delegate
vitalii-vanziak-cko Sep 28, 2026
6449b39
KDoc
vitalii-vanziak-cko Sep 28, 2026
5669cb5
didRequestManualFinalization
vitalii-vanziak-cko Sep 28, 2026
9184be8
Handle AUTHORIZATION_PENDING and AUTHORIZED
vitalii-vanziak-cko Sep 28, 2026
e9ff725
Request manual finalization
vitalii-vanziak-cko Sep 29, 2026
3a1d64a
Log
vitalii-vanziak-cko Sep 29, 2026
41da891
Handle failure
vitalii-vanziak-cko Sep 29, 2026
86d5c70
fetchPaymentDetails() on successful manual finalization
vitalii-vanziak-cko Oct 1, 2026
6af1725
Handle AUTHORIZATION_PENDING when resolving url
vitalii-vanziak-cko Oct 1, 2026
cf0d9e4
Unify handling of payment state during capture
vitalii-vanziak-cko Oct 5, 2026
11cf334
Ignore `unexpectedRedirectResult` failure code
vitalii-vanziak-cko Oct 5, 2026
110633f
Ignore result from deep link resolving if manual finalization was req…
vitalii-vanziak-cko Oct 5, 2026
d46d10d
Code improvement: filterIsInstance<Element.Instruction>()
vitalii-vanziak-cko Oct 5, 2026
0b1431f
Rename: fetchPaymentDetails() -> fetchPaymentState()
vitalii-vanziak-cko Oct 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension

buildscript {
ext {
androidGradlePluginVersion = '9.3.1'
androidGradlePluginVersion = '9.4.1'
kotlinVersion = '2.1.20'
kspVersion = '2.1.20-1.0.32'
dokkaVersion = '1.9.20'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,26 @@ data class POCreateInvoiceRequest(
@Json(name = "return_url")
val returnUrl: String? = null,
val shipping: POContact? = null,
@Json(name = "payment_configuration")
val paymentConfiguration: PaymentConfiguration? = null,
val device: Map<String, String> = mapOf("channel" to "android"),
val metadata: Map<String, String>? = null
)
) {

@JsonClass(generateAdapter = true)
data class PaymentConfiguration(
val apm: AlternativePaymentConfiguration
)

@JsonClass(generateAdapter = true)
data class AlternativePaymentConfiguration(
@Json(name = "preferred_finalization_mode")
val preferredFinalizationMode: PreferredFinalizationMode
)

@Suppress("EnumEntryName")
@JsonClass(generateAdapter = false)
enum class PreferredFinalizationMode {
automatic, manual
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ import kotlinx.parcelize.Parcelize
* @param[paymentMethod] Payment method details.
* @param[elements] An ordered list of elements that needs to be rendered on the UI during native alternative payment flow.
* @param[redirect] Indicates required redirect.
* @param[availableActions] Available actions to advance the payment.
*/
@Parcelize
data class PONativeAlternativePaymentAuthorizationResponse(
val state: PONativeAlternativePaymentState,
val invoice: Invoice,
val paymentMethod: PONativeAlternativePaymentMethodDetails,
val elements: List<PONativeAlternativePaymentElement>?,
val redirect: PONativeAlternativePaymentRedirect?
val redirect: PONativeAlternativePaymentRedirect?,
val availableActions: List<PONativeAlternativePaymentAvailableAction>?
) : Parcelable {

/**
Expand All @@ -47,5 +49,7 @@ internal data class NativeAlternativePaymentAuthorizationResponseBody(
@Json(name = "payment_method")
val paymentMethod: PONativeAlternativePaymentMethodDetails,
val elements: List<NativeAlternativePaymentElement>?,
val redirect: PONativeAlternativePaymentRedirect?
val redirect: PONativeAlternativePaymentRedirect?,
@Json(name = "available_actions")
val availableActions: List<PONativeAlternativePaymentAvailableAction>?
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.processout.sdk.api.model.response.napm.v2

import com.processout.sdk.core.annotation.ProcessOutInternalApi
import com.squareup.moshi.JsonClass

/**
* Available action to advance the payment.
*/
@JsonClass(generateAdapter = false)
enum class PONativeAlternativePaymentAvailableAction {

/** Authorization is possible. */
AUTHORIZE,

/** Capture is possible. */
CAPTURE,

/**
* Placeholder that allows adding additional cases while staying backward compatible.
* __Warning:__ Do not match this case directly, use _when-else_ instead.
*/
@ProcessOutInternalApi
UNKNOWN
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,19 @@ import com.squareup.moshi.JsonClass
*/
@JsonClass(generateAdapter = false)
enum class PONativeAlternativePaymentState {

/** Next step is required to proceed. */
NEXT_STEP_REQUIRED,

/** Customer interaction completed. Explicit authorization and/or capture is expected to advance the payment. */
CUSTOMER_ACTIONS_COMPLETED,

/** Authorization was requested and it’s still pending. No further actions are expected, payment will advance to next state automatically. */
AUTHORIZATION_PENDING,

/** Authorization was requested and completed. */
AUTHORIZED,

/** Pending payment processing. */
PENDING,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ import kotlinx.parcelize.Parcelize
* @param[paymentMethod] Payment method details.
* @param[elements] An ordered list of elements that needs to be rendered on the UI during native alternative payment flow.
* @param[redirect] Indicates required redirect.
* @param[availableActions] Available actions to advance the payment.
*/
@Parcelize
data class PONativeAlternativePaymentTokenizationResponse(
val state: PONativeAlternativePaymentState,
val paymentMethod: PONativeAlternativePaymentMethodDetails,
val elements: List<PONativeAlternativePaymentElement>?,
val redirect: PONativeAlternativePaymentRedirect?
val redirect: PONativeAlternativePaymentRedirect?,
val availableActions: List<PONativeAlternativePaymentAvailableAction>?
) : Parcelable

@JsonClass(generateAdapter = true)
Expand All @@ -27,5 +29,7 @@ internal data class NativeAlternativePaymentTokenizationResponseBody(
@Json(name = "payment_method")
val paymentMethod: PONativeAlternativePaymentMethodDetails,
val elements: List<NativeAlternativePaymentElement>?,
val redirect: PONativeAlternativePaymentRedirect?
val redirect: PONativeAlternativePaymentRedirect?,
@Json(name = "available_actions")
val availableActions: List<PONativeAlternativePaymentAvailableAction>?
)
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.squareup.moshi.JsonClass
* @param[customerToken] Customer token details if any.
* @param[elements] An ordered list of elements that needs to be rendered on the UI during native alternative payment flow.
* @param[redirect] Indicates required redirect.
* @param[availableActions] Available actions to advance the payment.
*/
@ProcessOutInternalApi
data class PONativeAlternativePaymentUrlResolutionResponse(
Expand All @@ -21,7 +22,8 @@ data class PONativeAlternativePaymentUrlResolutionResponse(
val invoice: PONativeAlternativePaymentInvoice?,
val customerToken: PONativeAlternativePaymentCustomerToken?,
val elements: List<PONativeAlternativePaymentElement>?,
val redirect: PONativeAlternativePaymentRedirect?
val redirect: PONativeAlternativePaymentRedirect?,
val availableActions: List<PONativeAlternativePaymentAvailableAction>?
)

@JsonClass(generateAdapter = true)
Expand All @@ -33,5 +35,7 @@ internal data class NativeAlternativePaymentUrlResolutionResponseBody(
@Json(name = "customer_token")
val customerToken: PONativeAlternativePaymentCustomerToken?,
val elements: List<NativeAlternativePaymentElement>?,
val redirect: PONativeAlternativePaymentRedirect?
val redirect: PONativeAlternativePaymentRedirect?,
@Json(name = "available_actions")
val availableActions: List<PONativeAlternativePaymentAvailableAction>?
)
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ internal class DefaultCustomerTokensRepository(
PONativeAlternativePaymentElement.Unknown
}
},
redirect = redirect
redirect = redirect,
availableActions = availableActions
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,8 @@ internal class DefaultInvoicesRepository(
invoice = invoice,
paymentMethod = paymentMethod,
elements = elements?.map { it.toModel() },
redirect = redirect
redirect = redirect,
availableActions = availableActions
)

private fun NativeAlternativePaymentUrlResolutionResponseBody.toModel() =
Expand All @@ -186,7 +187,8 @@ internal class DefaultInvoicesRepository(
invoice = invoice,
customerToken = customerToken,
elements = elements?.map { it.toModel() },
redirect = redirect
redirect = redirect,
availableActions = availableActions
)

private fun NativeAlternativePaymentElement.toModel() =
Expand Down
1 change: 1 addition & 0 deletions sdk/src/main/kotlin/com/processout/sdk/core/POFailure.kt
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ class POFailure private constructor() {
invalidUrl("request.validation.invalid-url"),
invalidUser("request.validation.invalid-user"),
invalidRedirectResult("request.validation.redirect-result-invalid"),
unexpectedRedirectResult("request.validation.redirect-result-unexpected"),
missingCurrency("request.validation.missing-currency"),
missingCustomerInput("gateway.missing-customer-input"),
missingDescription("request.validation.missing-description"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ package com.processout.sdk.ui.napm
import android.os.SystemClock
import com.processout.sdk.api.model.request.napm.v2.PONativeAlternativePaymentAuthorizationRequest
import com.processout.sdk.api.model.request.napm.v2.PONativeAlternativePaymentTokenizationRequest
import com.processout.sdk.api.model.response.napm.v2.PONativeAlternativePaymentAuthorizationResponse
import com.processout.sdk.api.model.response.napm.v2.PONativeAlternativePaymentElement
import com.processout.sdk.api.model.response.napm.v2.PONativeAlternativePaymentState
import com.processout.sdk.api.model.response.napm.v2.PONativeAlternativePaymentState.SUCCESS
import com.processout.sdk.api.model.response.napm.v2.PONativeAlternativePaymentTokenizationResponse
import com.processout.sdk.api.model.response.napm.v2.*
import com.processout.sdk.api.model.response.napm.v2.PONativeAlternativePaymentAuthorizationResponse.Invoice
import com.processout.sdk.api.model.response.napm.v2.PONativeAlternativePaymentState.AUTHORIZATION_PENDING
import com.processout.sdk.api.model.response.napm.v2.PONativeAlternativePaymentState.PENDING
import com.processout.sdk.api.service.POCustomerTokensService
import com.processout.sdk.api.service.POInvoicesService
import com.processout.sdk.core.POFailure.Code.*
Expand Down Expand Up @@ -41,7 +40,11 @@ internal class NativeAlternativePaymentCapturePoller(

data class CaptureResponse(
val state: PONativeAlternativePaymentState,
val elements: List<PONativeAlternativePaymentElement>?
val invoice: Invoice?,
val paymentMethod: PONativeAlternativePaymentMethodDetails,
val elements: List<PONativeAlternativePaymentElement>?,
val redirect: PONativeAlternativePaymentRedirect?,
val availableActions: List<PONativeAlternativePaymentAvailableAction>?
)

private var backoffIterator = retryStrategy.newBackoffIterator()
Expand Down Expand Up @@ -106,7 +109,7 @@ internal class NativeAlternativePaymentCapturePoller(
private fun isRetryable(
result: ProcessOutResult<CaptureResponse>
): Boolean = result.fold(
onSuccess = { it.state != SUCCESS },
onSuccess = { it.state == PENDING || it.state == AUTHORIZATION_PENDING },
onFailure = { failure ->
val retryableCodes = listOf(
NetworkUnreachable,
Expand All @@ -124,7 +127,11 @@ internal class NativeAlternativePaymentCapturePoller(
ProcessOutResult.Success(
CaptureResponse(
state = it.state,
elements = it.elements
invoice = it.invoice,
paymentMethod = it.paymentMethod,
elements = it.elements,
redirect = it.redirect,
availableActions = it.availableActions
)
)
},
Expand All @@ -138,7 +145,11 @@ internal class NativeAlternativePaymentCapturePoller(
ProcessOutResult.Success(
CaptureResponse(
state = it.state,
elements = it.elements
invoice = null,
paymentMethod = it.paymentMethod,
elements = it.elements,
redirect = it.redirect,
availableActions = it.availableActions
)
)
},
Expand Down
Loading
Loading