Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds account_numbers permission and parses unknown enum values to UNKNOWN. #5583

Merged
merged 5 commits into from
Sep 20, 2022
Merged
Show file tree
Hide file tree
Changes from 3 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
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.financialconnections.model.serializer.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,11 +225,19 @@ 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 {
internal const val OBJECT_OLD = "linked_account"
internal const val OBJECT_NEW = "financial_connections.account"
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.stripe.android.financialconnections.model.serializer
ccen-stripe marked this conversation as resolved.
Show resolved Hide resolved

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].
*/
internal 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
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,23 @@ class FinancialConnectionsApiRepositoryTest {
assertThat(result.paymentAccount).isInstanceOf(FinancialConnectionsAccount::class.java)
}

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

val result = financialConnectionsApiRepository.getFinancialConnectionsSession("client_secret")

val paymentAccount = result.paymentAccount
assertThat(paymentAccount).isInstanceOf(FinancialConnectionsAccount::class.java)
assertThat((paymentAccount as FinancialConnectionsAccount).permissions)
.containsExactly(FinancialConnectionsAccount.Permissions.PAYMENT_METHOD)
}

@Test
fun `getFinancialConnectionsSession - paymentAccount is BankAccount`() =
runTest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
"last4": "5579",
"livemode": true,
"permissions": [
"payment_method"
"payment_method",
"hola"
],
"status": "active",
"subcategory": "credit_card",
Expand Down