Skip to content

Commit

Permalink
Adds account_numbers permission and parses unknown enum values to `UN…
Browse files Browse the repository at this point in the history
…KNOWN`. (#5583)

* Adds account number permission.

* Regenerates API.

* Added unknown enum serializer.

* Adds unknown enum test.

* Moves to stripe-core.
  • Loading branch information
carlosmuvi-stripe authored Sep 20, 2022
1 parent 420a500 commit 5701790
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 76 deletions.
66 changes: 1 addition & 65 deletions financial-connections/api/financial-connections.api
Original file line number Diff line number Diff line change
Expand Up @@ -820,19 +820,6 @@ public final class com/stripe/android/financialconnections/model/FinancialConnec
public static fun values ()[Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$Category;
}

public final class com/stripe/android/financialconnections/model/FinancialConnectionsAccount$Category$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
public static final field $stable I
public static final field INSTANCE Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$Category$$serializer;
public static final synthetic field descriptor Lkotlinx/serialization/descriptors/SerialDescriptor;
public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$Category;
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$Category;)V
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
}

public final class com/stripe/android/financialconnections/model/FinancialConnectionsAccount$Category$Companion {
public final fun serializer ()Lkotlinx/serialization/KSerializer;
}
Expand All @@ -850,6 +837,7 @@ public final class com/stripe/android/financialconnections/model/FinancialConnec
}

public final class com/stripe/android/financialconnections/model/FinancialConnectionsAccount$Permissions : java/lang/Enum {
public static final field ACCOUNT_NUMBERS Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$Permissions;
public static final field BALANCES Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$Permissions;
public static final field Companion Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$Permissions$Companion;
public static final field OWNERSHIP Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$Permissions;
Expand All @@ -861,19 +849,6 @@ public final class com/stripe/android/financialconnections/model/FinancialConnec
public static fun values ()[Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$Permissions;
}

public final class com/stripe/android/financialconnections/model/FinancialConnectionsAccount$Permissions$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
public static final field $stable I
public static final field INSTANCE Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$Permissions$$serializer;
public static final synthetic field descriptor Lkotlinx/serialization/descriptors/SerialDescriptor;
public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$Permissions;
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$Permissions;)V
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
}

public final class com/stripe/android/financialconnections/model/FinancialConnectionsAccount$Permissions$Companion {
public final fun serializer ()Lkotlinx/serialization/KSerializer;
}
Expand All @@ -889,19 +864,6 @@ public final class com/stripe/android/financialconnections/model/FinancialConnec
public static fun values ()[Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$Status;
}

public final class com/stripe/android/financialconnections/model/FinancialConnectionsAccount$Status$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
public static final field $stable I
public static final field INSTANCE Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$Status$$serializer;
public static final synthetic field descriptor Lkotlinx/serialization/descriptors/SerialDescriptor;
public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$Status;
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$Status;)V
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
}

public final class com/stripe/android/financialconnections/model/FinancialConnectionsAccount$Status$Companion {
public final fun serializer ()Lkotlinx/serialization/KSerializer;
}
Expand All @@ -920,19 +882,6 @@ public final class com/stripe/android/financialconnections/model/FinancialConnec
public static fun values ()[Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$Subcategory;
}

public final class com/stripe/android/financialconnections/model/FinancialConnectionsAccount$Subcategory$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
public static final field $stable I
public static final field INSTANCE Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$Subcategory$$serializer;
public static final synthetic field descriptor Lkotlinx/serialization/descriptors/SerialDescriptor;
public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$Subcategory;
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$Subcategory;)V
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
}

public final class com/stripe/android/financialconnections/model/FinancialConnectionsAccount$Subcategory$Companion {
public final fun serializer ()Lkotlinx/serialization/KSerializer;
}
Expand All @@ -947,19 +896,6 @@ public final class com/stripe/android/financialconnections/model/FinancialConnec
public static fun values ()[Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$SupportedPaymentMethodTypes;
}

public final class com/stripe/android/financialconnections/model/FinancialConnectionsAccount$SupportedPaymentMethodTypes$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
public static final field $stable I
public static final field INSTANCE Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$SupportedPaymentMethodTypes$$serializer;
public static final synthetic field descriptor Lkotlinx/serialization/descriptors/SerialDescriptor;
public fun childSerializers ()[Lkotlinx/serialization/KSerializer;
public fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$SupportedPaymentMethodTypes;
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/stripe/android/financialconnections/model/FinancialConnectionsAccount$SupportedPaymentMethodTypes;)V
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
}

public final class com/stripe/android/financialconnections/model/FinancialConnectionsAccount$SupportedPaymentMethodTypes$Companion {
public final fun serializer ()Lkotlinx/serialization/KSerializer;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.stripe.android.financialconnections.model

import android.os.Parcelable
import com.stripe.android.core.model.StripeModel
import com.stripe.android.core.model.serializers.EnumIgnoreUnknownSerializer
import kotlinx.parcelize.Parcelize
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
Expand Down Expand Up @@ -109,7 +110,7 @@ data class FinancialConnectionsAccount(
*
* Values: cash,credit,investment,other
*/
@Serializable
@Serializable(with = Category.Serializer::class)
enum class Category(val value: String) {
@SerialName("cash")
CASH("cash"),
Expand All @@ -124,14 +125,17 @@ data class FinancialConnectionsAccount(
OTHER("other"),

UNKNOWN("unknown");

internal object Serializer :
EnumIgnoreUnknownSerializer<Category>(Category.values(), UNKNOWN)
}

/**
* The status of the link to the account.
*
* Values: active,disconnected,inactive
*/
@Serializable
@Serializable(with = Status.Serializer::class)
enum class Status(val value: String) {
@SerialName("active")
ACTIVE("active"),
Expand All @@ -143,6 +147,8 @@ data class FinancialConnectionsAccount(
INACTIVE("inactive"),

UNKNOWN("unknown");

internal object Serializer : EnumIgnoreUnknownSerializer<Status>(Status.values(), UNKNOWN)
}

/**
Expand All @@ -152,7 +158,7 @@ data class FinancialConnectionsAccount(
*
* Values: checking,creditCard,lineOfCredit,mortgage,other,savings
*/
@Serializable
@Serializable(with = Subcategory.Serializer::class)
enum class Subcategory(val value: String) {
@SerialName("checking")
CHECKING("checking"),
Expand All @@ -173,6 +179,9 @@ data class FinancialConnectionsAccount(
SAVINGS("savings"),

UNKNOWN("unknown");

internal object Serializer :
EnumIgnoreUnknownSerializer<Subcategory>(Subcategory.values(), UNKNOWN)
}

/**
Expand All @@ -181,7 +190,7 @@ data class FinancialConnectionsAccount(
*
* Values: link,usBankAccount
*/
@Serializable
@Serializable(with = SupportedPaymentMethodTypes.Serializer::class)
enum class SupportedPaymentMethodTypes(val value: String) {
@SerialName("link")
LINK("link"),
Expand All @@ -190,14 +199,19 @@ data class FinancialConnectionsAccount(
US_BANK_ACCOUNT("us_bank_account"),

UNKNOWN("unknown");

internal object Serializer :
EnumIgnoreUnknownSerializer<SupportedPaymentMethodTypes>(
SupportedPaymentMethodTypes.values(), UNKNOWN
)
}

/**
* The list of permissions granted by this account.
*
* Values: balances,identity,ownership,paymentMethod,transactions
*/
@Serializable
@Serializable(with = Permissions.Serializer::class)
enum class Permissions(val value: String) {
@SerialName("balances")
BALANCES("balances"),
Expand All @@ -211,7 +225,14 @@ data class FinancialConnectionsAccount(
@SerialName("transactions")
TRANSACTIONS("transactions"),

@SerialName("account_numbers")
ACCOUNT_NUMBERS("account_numbers"),

UNKNOWN("unknown");

internal object Serializer : EnumIgnoreUnknownSerializer<Permissions>(
Permissions.values(), UNKNOWN
)
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ class FinancialConnectionsApiRepositoryTest {
)
)

val result = financialConnectionsApiRepository.getFinancialConnectionsSession("client_secret")
val result =
financialConnectionsApiRepository.getFinancialConnectionsSession("client_secret")

assertThat(result.accounts.data.size).isEqualTo(1)
}
Expand All @@ -52,7 +53,8 @@ class FinancialConnectionsApiRepositoryTest {
)
)

val result = financialConnectionsApiRepository.getFinancialConnectionsSession("client_secret")
val result =
financialConnectionsApiRepository.getFinancialConnectionsSession("client_secret")

assertThat(result.accounts.data.size).isEqualTo(1)
}
Expand All @@ -66,7 +68,8 @@ class FinancialConnectionsApiRepositoryTest {
)
)

val result = financialConnectionsApiRepository.getFinancialConnectionsSession("client_secret")
val result =
financialConnectionsApiRepository.getFinancialConnectionsSession("client_secret")

assertThat(result.paymentAccount).isInstanceOf(FinancialConnectionsAccount::class.java)
}
Expand All @@ -80,7 +83,8 @@ class FinancialConnectionsApiRepositoryTest {
)
)

val result = financialConnectionsApiRepository.getFinancialConnectionsSession("client_secret")
val result =
financialConnectionsApiRepository.getFinancialConnectionsSession("client_secret")

assertThat(result.paymentAccount).isInstanceOf(FinancialConnectionsAccount::class.java)
}
Expand All @@ -94,11 +98,30 @@ class FinancialConnectionsApiRepositoryTest {
)
)

val result = financialConnectionsApiRepository.getFinancialConnectionsSession("client_secret")
val result =
financialConnectionsApiRepository.getFinancialConnectionsSession("client_secret")

assertThat(result.paymentAccount).isInstanceOf(FinancialConnectionsAccount::class.java)
}

@Test
fun `getFinancialConnectionsSession - account with unknown permissions ignores unknown values`() =
runTest {
givenGetRequestReturns(
readResourceAsString(
"json/linked_account_session_unknown_permission.json"
)
)

val result = financialConnectionsApiRepository
.getFinancialConnectionsSession("client_secret")
val financialConnectionsAccount = result.paymentAccount as FinancialConnectionsAccount
assertThat(financialConnectionsAccount.permissions).containsExactly(
FinancialConnectionsAccount.Permissions.PAYMENT_METHOD,
FinancialConnectionsAccount.Permissions.UNKNOWN,
)
}

@Test
fun `getFinancialConnectionsSession - paymentAccount is BankAccount`() =
runTest {
Expand All @@ -108,7 +131,8 @@ class FinancialConnectionsApiRepositoryTest {
)
)

val result = financialConnectionsApiRepository.getFinancialConnectionsSession("client_secret")
val result =
financialConnectionsApiRepository.getFinancialConnectionsSession("client_secret")

assertThat(result.paymentAccount).isInstanceOf(BankAccount::class.java)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"id": "las_dhgfsklhgfkdsjhgk",
"object": "link_account_session",
"client_secret": "las_client_secret_ldafjlfkjlsfadkjk",
"linked_accounts": {
"object": "list",
"data": [
],
"has_more": false,
"total_count": 0,
"url": "/v1/linked_accounts"
},
"livemode": true,
"payment_account": {
"id": "la_dfsdfasfds",
"object": "financial_connections.account",
"balance": null,
"balance_refresh": null,
"category": "credit",
"created": 1648749414,
"display_name": "CREDIT CARD",
"institution_name": "Chase",
"last4": "5579",
"livemode": true,
"permissions": [
"payment_method",
"hola"
],
"status": "active",
"subcategory": "credit_card",
"supported_payment_method_types": [
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.stripe.android.core.model.serializers

import androidx.annotation.RestrictTo
import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder

/**
* Parses an enum using [values], and on unknown values, falls back to [defaultValue].
*/
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
abstract class EnumIgnoreUnknownSerializer<T : Enum<T>>(
values: Array<out T>,
private val defaultValue: T
) :
KSerializer<T> {
// Alternative to taking values in param, take clazz: Class<T>
// - private val values = clazz.enumConstants
override val descriptor: SerialDescriptor =
PrimitiveSerialDescriptor(values.first()::class.qualifiedName!!, PrimitiveKind.STRING)

// Build maps for faster parsing, used @SerialName annotation if present, fall back to name
private val lookup = values.associateBy({ it }, { it.serialName })
private val revLookup = values.associateBy { it.serialName }

private val Enum<T>.serialName: String
get() = this::class.java.getField(this.name).getAnnotation(SerialName::class.java)?.value
?: name

override fun serialize(encoder: Encoder, value: T) {
encoder.encodeString(lookup.getValue(value))
}

override fun deserialize(decoder: Decoder): T {
// only run 'decoder.decodeString()' once
return revLookup[decoder.decodeString()]
?: defaultValue // map.getOrDefault is not available < API-24
}
}

0 comments on commit 5701790

Please sign in to comment.