Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import kotlinx.serialization.encoding.Encoder
public data class ApiPaymentMethodResponse(
@SerialName(value = "payment_method_type")
val paymentMethodType: ApiPaymentMethodType = ApiPaymentMethodType.UNSUPPORTED,
@SerialName(value = "requires_paypal_secure_element")
val requiresPaypalSecureElement: Boolean,
val id: String?,
val summary: Summary?,
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@ public enum class ApiPaymentMethodType {
@SerialName(value = "cash")
CASH,

@SerialName(value = "psp_provided")
PSP_PROVIDED,

@SerialName(value = "stripe")
STRIPE,

Expand All @@ -37,7 +34,6 @@ internal object ApiPaymentMethodTypeSerializer : KSerializer<ApiPaymentMethodTyp

override fun deserialize(decoder: Decoder): ApiPaymentMethodType = when (decoder.decodeString()) {
"cash" -> ApiPaymentMethodType.CASH
"psp_provided" -> ApiPaymentMethodType.PSP_PROVIDED
"stripe" -> ApiPaymentMethodType.STRIPE
"logpay" -> ApiPaymentMethodType.LOGPAY
"public_transport_ticket" -> ApiPaymentMethodType.PUBLIC_TRANSPORT_TICKET
Expand All @@ -50,7 +46,6 @@ internal object ApiPaymentMethodTypeSerializer : KSerializer<ApiPaymentMethodTyp
encoder.encodeString(
when (value) {
ApiPaymentMethodType.CASH -> "cash"
ApiPaymentMethodType.PSP_PROVIDED -> "psp_provided"
ApiPaymentMethodType.STRIPE -> "stripe"
ApiPaymentMethodType.LOGPAY -> "logpay"
ApiPaymentMethodType.PUBLIC_TRANSPORT_TICKET -> "public_transport_ticket"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,35 @@
package com.ioki.passenger.api.models

import com.ioki.passenger.api.models.ApiProvider.PaymentMethodType
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.builtins.NothingSerializer
import kotlinx.serialization.builtins.serializer
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import kotlinx.serialization.json.JsonDecoder
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive

@Serializable
public data class ApiProvider(
val name: String,
@SerialName(value = "psp")
val paymentServiceProvider: PaymentServiceProvider,
@SerialName(value = "payment_service_provider")
val paymentServiceProvider: PaymentServiceProvider?,
@SerialName(value = "ride_payment_method_types")
val ridePaymentMethodTypes: Set<ApiPaymentMethodType>,
val ridePaymentMethodTypes: Set<PaymentMethodType>,
@SerialName(value = "ticketing_payment_method_types")
val ticketingPaymentMethodTypes: Set<ApiPaymentMethodType>,
val ticketingPaymentMethodTypes: Set<PaymentMethodType>,
@SerialName(value = "service_credit_payment_method_types")
val serviceCreditPaymentMethodTypes: Set<ApiPaymentMethodType>,
val serviceCreditPaymentMethodTypes: Set<PaymentMethodType>,
@SerialName(value = "personal_discount_payment_method_types")
val personalDiscountPaymentMethodTypes: Set<ApiPaymentMethodType>,
val personalDiscountPaymentMethodTypes: Set<PaymentMethodType>,
@SerialName(value = "tip_payment_method_types")
val tipPaymentMethodTypes: Set<ApiPaymentMethodType>,
@SerialName(value = "stripe_payment_method_types")
val stripeTypes: Set<ApiStripeType>?,
@SerialName(value = "logpay_payment_method_types")
val logPayTypes: Set<ApiLogPayType>?,
val tipPaymentMethodTypes: Set<PaymentMethodType>,
@SerialName(value = "service_credit_options") val creditOptions: CreditOptions?,
@SerialName(value = "stripe_account_id") val stripeAccountId: String?,
@SerialName(value = "merchant_name") val merchantName: String?,
@SerialName(value = "country_code") val countryCode: String,
val features: Features,
Expand All @@ -38,18 +44,6 @@ public data class ApiProvider(
@Serializable
public data class CreditOptions(val packages: List<ApiOfferedCreditPackage>)

@Serializable
public enum class PaymentServiceProvider {
@SerialName(value = "no_psp")
NONE,

@SerialName(value = "logpay")
LOGPAY,

@SerialName(value = "stripe")
STRIPE,
}

@Serializable
public data class Features(
@SerialName(value = "payment") val paymentEnabled: Boolean,
Expand Down Expand Up @@ -111,14 +105,101 @@ public data class ApiProvider(
)
}
}

@Serializable(with = PaymentMethodTypeSerializer::class)
public enum class PaymentMethodType {
@SerialName(value = "cash")
CASH,

@SerialName(value = "psp_provided")
PSP_PROVIDED,

@SerialName(value = "public_transport_ticket")
PUBLIC_TRANSPORT_TICKET,

@SerialName(value = "service_credits")
SERVICE_CREDITS,

@SerialName(value = "pos_payment")
POS_PAYMENT,
UNSUPPORTED,
}
}

internal object PaymentMethodTypeSerializer : KSerializer<PaymentMethodType> {
override val descriptor = String.serializer().descriptor

override fun deserialize(decoder: Decoder): PaymentMethodType = when (decoder.decodeString()) {
"cash" -> PaymentMethodType.CASH
"psp_provided" -> PaymentMethodType.PSP_PROVIDED
"public_transport_ticket" -> PaymentMethodType.PUBLIC_TRANSPORT_TICKET
"service_credits" -> PaymentMethodType.SERVICE_CREDITS
"pos_payment" -> PaymentMethodType.POS_PAYMENT
else -> PaymentMethodType.UNSUPPORTED
}

override fun serialize(encoder: Encoder, value: PaymentMethodType) {
encoder.encodeString(
when (value) {
PaymentMethodType.CASH -> "cash"
PaymentMethodType.PSP_PROVIDED -> "psp_provided"
PaymentMethodType.PUBLIC_TRANSPORT_TICKET -> "public_transport_ticket"
PaymentMethodType.SERVICE_CREDITS -> "service_credits"
PaymentMethodType.POS_PAYMENT -> "pos_payment"
PaymentMethodType.UNSUPPORTED -> "unsupported"
},
)
}
}

public val ApiProvider.Features.permissionCenterEnabled: Boolean
get() = analyticsTracking || marketingAutomation || newsletterEnabled || receiptsEnabled

public val ApiProvider.allPaymentMethodTypes: Set<ApiPaymentMethodType>
public val ApiProvider.allPaymentMethodTypes: Set<PaymentMethodType>
get() =
ridePaymentMethodTypes +
serviceCreditPaymentMethodTypes +
personalDiscountPaymentMethodTypes +
tipPaymentMethodTypes

internal object PaymentServiceProviderSerializer : KSerializer<PaymentServiceProvider?> {
override val descriptor: SerialDescriptor = PaymentServiceProvider.Stripe.serializer().descriptor

@OptIn(ExperimentalSerializationApi::class)
override fun serialize(encoder: Encoder, value: PaymentServiceProvider?) = when (value) {
is PaymentServiceProvider.Stripe ->
encoder.encodeNullableSerializableValue(PaymentServiceProvider.Stripe.serializer(), value)
is PaymentServiceProvider.LogPay ->
encoder.encodeNullableSerializableValue(PaymentServiceProvider.LogPay.serializer(), value)
else -> encoder.encodeNullableSerializableValue(NothingSerializer(), null)
}

override fun deserialize(decoder: Decoder): PaymentServiceProvider? {
val input = decoder as? JsonDecoder ?: error("Only Json format is supported")
val element = input.decodeJsonElement()
val type = element.jsonObject["type"]?.jsonPrimitive?.content
return when (type) {
"payment_service_provider/stripe" ->
input.json.decodeFromJsonElement(PaymentServiceProvider.Stripe.serializer(), element)
"payment_service_provider/logpay" ->
input.json.decodeFromJsonElement(PaymentServiceProvider.LogPay.serializer(), element)
else -> null
}
}
}

@Serializable(PaymentServiceProviderSerializer::class)
public sealed class PaymentServiceProvider {
@Serializable
public data class Stripe(
@SerialName(value = "stripe_account_id") val stripeAccountId: String?,
@SerialName(value = "stripe_payment_method_types") val stripeTypes: List<ApiStripeType>?,
@SerialName(value = "google_pay_supported") val googlePaySupported: Boolean,
) : PaymentServiceProvider()

@Serializable
public data class LogPay(
@SerialName(value = "logpay_payment_method_types") val logPayTypes: List<ApiLogPayType>?,
@SerialName(value = "use_legacy_paypal_flow") val useLegacyPaypalFlow: Boolean,
) : PaymentServiceProvider()
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ public enum class ApiStripeType {
@SerialName(value = "sepa_debit")
SEPA_DEBIT,

@SerialName(value = "google_pay")
GOOGLE_PAY,
UNSUPPORTED,
}

Expand All @@ -28,7 +26,6 @@ internal object ApiStripeTypeSerializer : KSerializer<ApiStripeType> {
when (value) {
ApiStripeType.CARD -> "card"
ApiStripeType.SEPA_DEBIT -> "sepa_debit"
ApiStripeType.GOOGLE_PAY -> "google_pay"
ApiStripeType.UNSUPPORTED -> "unsupported"
},
)
Expand All @@ -37,7 +34,6 @@ internal object ApiStripeTypeSerializer : KSerializer<ApiStripeType> {
override fun deserialize(decoder: Decoder): ApiStripeType = when (decoder.decodeString()) {
"card" -> ApiStripeType.CARD
"sepa_debit" -> ApiStripeType.SEPA_DEBIT
"google_pay" -> ApiStripeType.GOOGLE_PAY
else -> ApiStripeType.UNSUPPORTED
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,44 @@
package com.ioki.passenger.api.models

import com.ioki.passenger.api.test.models.createApiBootstrapResponse
import com.ioki.passenger.api.test.models.createApiClientInfoResponse
import com.ioki.passenger.api.test.models.createApiProvider
import kotlin.test.Test

internal class ApiBootstrapResponseTest : IokiApiModelTest() {
@Test
fun serializationMinimal() {
testJsonStringCanBeConvertedToModel(
createApiBootstrapResponse(
provider = createApiProvider(
name = "Some Company Inc.",
countryCode = "DE",
features = ApiProvider.Features.NONE,
),
client = createApiClientInfoResponse(
distributionUrl = "url",
termsOfServiceUrl = "https://example.com/terms_of_service.html",
privacyPolicyUrl = "https://example.com/privacy_policy.html",
imprintUrl = "https://example.com/imprint_url.html",
phoneNumberRequired = false,
emailAddressRequired = false,
),
products = emptyList(),
ridesWithFailedPayments = emptyList(),
renewableTicketingVouchers = emptyList(),
productSupportUris = emptyList(),
),
bootstrapMinimal,
)
}

@Test
fun serialization() {
testJsonStringCanBeConvertedToModel(
ApiBootstrapResponse(
createApiBootstrapResponse(
provider = createApiProvider(
name = "Some Company Inc.",
countryCode = "DE",
paymentServiceProvider = ApiProvider.PaymentServiceProvider.NONE,
features = ApiProvider.Features.NONE,
),
client = createApiClientInfoResponse(
Expand All @@ -33,13 +59,56 @@ internal class ApiBootstrapResponseTest : IokiApiModelTest() {
}
}

private val bootstrapMinimal =
"""
{
"provider": {
"name": "Some Company Inc.",
"country_code": "DE",
"ride_payment_method_types": [],
"ticketing_payment_method_types": [],
"service_credit_payment_method_types": [],
"personal_discount_payment_method_types": [],
"tip_payment_method_types": [],
"custom_urls": [],
"features": {
"non_purchasable_personal_discounts" : false,
"payment":false,
"promo_codes" : false,
"purchasable_personal_discounts" : false,
"service_credits" : false,
"analytics_tracking" : false,
"user_email_required" : false,
"marketing_automation": false,
"newsletter": false,
"receipts": false,
"apply_for_non_purchasable_personal_discounts": false,
"tickets": false
}
},
"products": [],
"client": {
"distribution_url": "url",
"terms_of_service_url": "https://example.com/terms_of_service.html",
"privacy_policy_url": "https://example.com/privacy_policy.html",
"imprint_url": "https://example.com/imprint_url.html",
"phone_number_required": false,
"email_address_required": false,
"signin_verification_channels": [],
"signup_verification_channels": []
},
"rides_with_failed_payments": [],
"renewable_ticketing_vouchers": [],
"product_support_uris": []
}
"""

private val bootstrap =
"""
{
"provider": {
"name": "Some Company Inc.",
"country_code": "DE",
"psp": "no_psp",
"ride_payment_method_types": [],
"ticketing_payment_method_types": [],
"service_credit_payment_method_types": [],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
package com.ioki.passenger.api.models

import com.ioki.passenger.api.test.models.createApiPaymentMethodResponse
import com.ioki.passenger.api.test.models.createApiPaymentMethodResponseSummary
import kotlin.test.Test

internal class ApiPaymentMethodResponseTest : IokiApiModelTest() {
@Test
fun serializationMinimal() {
testJsonStringCanBeConvertedToModel(
ApiPaymentMethodResponse(ApiPaymentMethodType.CASH, null, null),
createApiPaymentMethodResponse(paymentMethodType = ApiPaymentMethodType.CASH),
paymentMethodMinimal,
)
}

@Test
fun serialization() {
testJsonStringCanBeConvertedToModel(
expectedModel = ApiPaymentMethodResponse(
expectedModel = createApiPaymentMethodResponse(
paymentMethodType = ApiPaymentMethodType.STRIPE,
requiresPaypalSecureElement = false,
id = "someId",
summary = ApiPaymentMethodResponse.Summary(
summary = createApiPaymentMethodResponseSummary(
kind = ApiPaymentMethodResponse.Summary.Kind.CREDIT_CARD,
wallet = ApiPaymentMethodResponse.Summary.Wallet.GOOGLE_PAY,
brand = ApiPaymentMethodResponse.Summary.Brand.VISA,
title = "Visa (*1234)",
last4 = "1234",
expiration = "11/20",
mandateUrl = null,
),
),
jsonString = paymentMethod,
Expand All @@ -35,14 +37,16 @@ internal class ApiPaymentMethodResponseTest : IokiApiModelTest() {
private val paymentMethodMinimal =
"""
{
"payment_method_type": "cash"
"payment_method_type": "cash",
"requires_paypal_secure_element": false
}
"""

private val paymentMethod =
"""
{
"payment_method_type": "stripe",
"requires_paypal_secure_element": false,
"id": "someId",
"summary": {
"kind": "card",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ internal class ApiPaymentMethodResponseTypeTest {
companion object {
fun data(): Collection<Array<Any>> = listOf(
arrayOf(ApiPaymentMethodType.CASH, "\"cash\""),
arrayOf(ApiPaymentMethodType.PSP_PROVIDED, "\"psp_provided\""),
arrayOf(ApiPaymentMethodType.STRIPE, "\"stripe\""),
arrayOf(ApiPaymentMethodType.LOGPAY, "\"logpay\""),
arrayOf(
Expand Down
Loading