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

Enable bank payments in native Link #10070

Merged
merged 10 commits into from
Feb 12, 2025
Merged

Conversation

tillh-stripe
Copy link
Collaborator

@tillh-stripe tillh-stripe commented Feb 3, 2025

Summary

This pull request adds support for bank payments to the native Link flow.

  • We add ConsumerPaymentDetails.BankAccount to the supported payment method types, and continue to use the intent’s linkFundingSources when determining which payment details types to show.
  • We use the new LinkCardBrandConfirmationDefinition when attempting to use a bank account in passthrough mode. This invokes the shareLinkCardBrand method with an expectedPaymentMethodType of card.

Motivation

Testing

  • Added tests
  • Modified tests
  • Manually verified

Screenshots

Before After
before screenshot after screenshot

Changelog

Copy link
Contributor

github-actions bot commented Feb 3, 2025

Diffuse output:

OLD: paymentsheet-example-release-master.apk (signature: V1, V2)
NEW: paymentsheet-example-release-pr.apk (signature: V1, V2)

          │            compressed            │          uncompressed          
          ├───────────┬───────────┬──────────┼──────────┬──────────┬──────────
 APK      │ old       │ new       │ diff     │ old      │ new      │ diff     
──────────┼───────────┼───────────┼──────────┼──────────┼──────────┼──────────
      dex │     4 MiB │     4 MiB │ +2.2 KiB │  8.8 MiB │  8.8 MiB │ +5.4 KiB 
     arsc │   2.3 MiB │   2.3 MiB │      0 B │  2.3 MiB │  2.3 MiB │      0 B 
 manifest │   5.1 KiB │   5.1 KiB │      0 B │ 25.7 KiB │ 25.7 KiB │      0 B 
      res │ 910.3 KiB │ 910.3 KiB │      0 B │  1.4 MiB │  1.4 MiB │      0 B 
   native │   2.6 MiB │   2.6 MiB │      0 B │    6 MiB │    6 MiB │      0 B 
    asset │   1.6 MiB │   1.6 MiB │ +1.4 KiB │  1.6 MiB │  1.6 MiB │ +1.4 KiB 
    other │   1.4 MiB │   1.4 MiB │     +3 B │  1.6 MiB │  1.6 MiB │      0 B 
──────────┼───────────┼───────────┼──────────┼──────────┼──────────┼──────────
    total │  12.7 MiB │  12.7 MiB │ +3.6 KiB │ 21.7 MiB │ 21.7 MiB │ +6.8 KiB 

 DEX     │ old   │ new   │ diff            
─────────┼───────┼───────┼─────────────────
   files │     1 │     1 │   0             
 strings │ 41236 │ 41251 │ +15 (+27 -12)   
   types │ 14274 │ 14285 │ +11 (+19 -8)    
 classes │ 11927 │ 11936 │  +9 (+9 -0)     
 methods │ 60552 │ 60589 │ +37 (+269 -232) 
  fields │ 40782 │ 40813 │ +31 (+285 -254) 

 ARSC    │ old  │ new  │ diff 
─────────┼──────┼──────┼──────
 configs │  243 │  243 │  0   
 entries │ 6248 │ 6248 │  0
APK
     compressed      │    uncompressed    │                                           
──────────┬──────────┼─────────┬──────────┤                                           
 size     │ diff     │ size    │ diff     │ path                                      
──────────┼──────────┼─────────┼──────────┼───────────────────────────────────────────
    4 MiB │ +2.2 KiB │ 8.8 MiB │ +5.4 KiB │ ∆ classes.dex                             
  7.8 KiB │ +1.4 KiB │ 7.7 KiB │ +1.4 KiB │ ∆ assets/dexopt/baseline.prof             
    272 B │     +1 B │   120 B │      0 B │ ∆ META-INF/version-control-info.textproto 
 53.7 KiB │     +1 B │ 119 KiB │      0 B │ ∆ META-INF/CERT.SF                        
  1.2 KiB │     +1 B │ 1.2 KiB │      0 B │ ∆ META-INF/CERT.RSA                       
──────────┼──────────┼─────────┼──────────┼───────────────────────────────────────────
  4.1 MiB │ +3.6 KiB │ 8.9 MiB │ +6.8 KiB │ (total)
DEX
STRINGS:

   old   │ new   │ diff          
  ───────┼───────┼───────────────
   41236 │ 41251 │ +15 (+27 -12) 
  
  + , canAddNewPaymentMethod=
  + , expectedPaymentMethodType=
  + <a href="https://link.com/terms/ach-authorization">
  + Ld7/c;
  + Ld7/d;
  + Ld7/e;
  + Ld7/f;
  + Ld7/g;
  + Ld7/h;
  + LinkCardBrandConfirmationOption(paymentDetailsId=
  + Lr6/E;
  + Ly6/u;
  + Ly6/v;
  + VLLLLLZLLZZLLL
  + VLLZLZZLLLL
  + [Ld7/c;
  + [Ld7/f;
  + [Ld7/h;
  + [Lh6/b;
  + [Lh6/d;
  + [Ll3/f;
  + [Ln7/e;
  + [Lq6/m;
  + [Lu8/n;
  + [Lv8/d;
  + expectedPaymentMethodType
  + ~~R8{"backend":"dex","compilation-mode":"release","has-checksums":false,"min-api":21,"pg-map-id":"d30fe0f","r8-mode":"full","version":"8.7.14"}
  
  - <a href="https://stripe.com/legal/ach-payments/authorization">
  - VLLLLLZLLZZLL
  - VLLZLZLLLL
  - [Ld7/b;
  - [Lh6/a;
  - [Lh6/c;
  - [Ll3/d;
  - [Ln7/c;
  - [Lq6/k;
  - [Lu8/m;
  - [Lv8/c;
  - ~~R8{"backend":"dex","compilation-mode":"release","has-checksums":false,"min-api":21,"pg-map-id":"2344f2d","r8-mode":"full","version":"8.7.14"}
  

TYPES:

   old   │ new   │ diff         
  ───────┼───────┼──────────────
   14274 │ 14285 │ +11 (+19 -8) 
  
  + Ld7/c;
  + Ld7/d;
  + Ld7/e;
  + Ld7/f;
  + Ld7/g;
  + Ld7/h;
  + Lr6/E;
  + Ly6/u;
  + Ly6/v;
  + [Ld7/c;
  + [Ld7/f;
  + [Ld7/h;
  + [Lh6/b;
  + [Lh6/d;
  + [Ll3/f;
  + [Ln7/e;
  + [Lq6/m;
  + [Lu8/n;
  + [Lv8/d;
  
  - [Ld7/b;
  - [Lh6/a;
  - [Lh6/c;
  - [Ll3/d;
  - [Ln7/c;
  - [Lq6/k;
  - [Lu8/m;
  - [Lv8/c;
  

METHODS:

   old   │ new   │ diff            
  ───────┼───────┼─────────────────
   60552 │ 60589 │ +37 (+269 -232) 
  
  + A5.H0 <init>(Locale, a, e, O, I, j)
  + A5.c0 <init>(j, M, e, a)
  + C.D0 <init>(e, g, Application, P, g0, f)
  + D5.e <init>(b, X, c, E, w, P0, d)
  + D6.n <init>(S, M, z, r, c, d)
  + F6.d <init>(z, b, r, W0, d, j, c)
  + G6.r <init>(z, c, d, w, g0, c, c, a)
  + H6.p <init>(b, r, c, d, boolean, a, a, a)
  + I6.F <init>(z, b, r, W0, d, c, c, c)
  + I6.t <init>(List, w, boolean, c, boolean, boolean, c, a, a, c)
  + I6.t c() → t
  + R6.w <init>(String, boolean)
  + T7.e a() → r
  + U5.r <init>(h, X, w, M, N0, I, r, e, P, C, H0, E, d)
  + V5.p <init>(E, L, c)
  + X6.b <init>(r)
  + X6.b h(f, c) → Object
  + X6.b i(f, c) → Object
  + com.stripe.android.link.LinkActivity d(n)
  + com.stripe.android.link.NativeLinkActivityContract e(Intent, int) → n
  + com.stripe.android.link.WebLinkActivityContract e(Intent, int) → n
  + d7.a <init>(n)
  + d7.b <init>(Y)
  + d7.c <clinit>()
  + d7.c <init>(Y)
  + d7.c describeContents() → int
  + d7.c equals(Object) → boolean
  + d7.c hashCode() → int
  + d7.c toString() → String
  + d7.c writeToParcel(Parcel, int)
  + d7.d <init>(b, c)
  + d7.d o(Object) → Object
  + d7.e <init>(b, c)
  + d7.e o(Object) → Object
  + d7.f <clinit>()
  + d7.f <init>(String, String)
  + d7.f describeContents() → int
  + d7.f equals(Object) → boolean
  + d7.f hashCode() → int
  + d7.f toString() → String
  + d7.f writeToParcel(Parcel, int)
  + d7.g <init>(D, E, x)
  + d7.g <init>(T, a, E)
  + d7.g a(m, e, J) → Object
  + d7.g b(c, n) → Object
  + d7.g c(m, e) → boolean
  + d7.g d(Object)
  + d7.g e(m, e, j, Parcelable) → j
  + d7.g f(Object, Object, m, e)
  + d7.g g(m) → m
  + d7.g getKey() → String
  + d7.g h(h, c) → Object
  + d7.g i(h, S, c) → Object
  + d7.g j(h, c) → Object
  + d7.g k(h) → W
  + d7.g l(c)
  + d7.h <clinit>()
  + d7.h <init>(z, boolean)
  + d7.h describeContents() → int
  + d7.h equals(Object) → boolean
  + d7.h hashCode() → int
  + d7.h toString() → String
  + d7.h writeToParcel(Parcel, int)
  + e7.d <init>(g, c)
  + e7.e <init>(g, c)
  + e7.f <init>(g, c)
  + g7.z <init>(h, h, h, h, h, h, h, h, int)
  + g8.v <init>(c, c, q, j, g, d, b, f, i, c, E, N0, j, a)
  + h6.a <init>(int)
  + h6.a createFromParcel(Parcel) → Object
  + h6.a newArray(int) → Object[]
  + h6.b <clinit>()
  + h6.b <init>(h)
  + h6.b describeContents() → int
  + h6.b equals(Object) → boolean
  + h6.b hashCode() → int
  + h6.b toString() → String
  + h6.b writeToParcel(Parcel, int)
  + h6.d <clinit>()
  + h6.d <init>(s2)
  + h6.d describeContents() → int
  + h6.d equals(Object) → boolean
  + h6.d hashCode() → int
  + h6.d toString() → String
  + h6.d writeToParcel(Parcel, int)
  + h6.e <init>(g0, d)
  + h8.A1 D(r) → b
  + h8.N0 c(w, a, p, int)
  + l3.c <init>(int)
  + l3.c createFromParcel(Parcel) → Object
  + l3.c newArray(int) → Object[]
  + l3.e <init>(String, ArrayList)
  + l3.f <clinit>()
  + l3.f <init>(int, a, q)
 
...✂

@tillh-stripe tillh-stripe force-pushed the tillh/native-link-bank-payments branch 9 times, most recently from 29d7d6a to 80c3035 Compare February 10, 2025 16:01
@tillh-stripe tillh-stripe marked this pull request as ready for review February 10, 2025 16:19
@tillh-stripe tillh-stripe requested review from a team as code owners February 10, 2025 16:19
@tillh-stripe tillh-stripe force-pushed the tillh/native-link-bank-payments branch 3 times, most recently from 94b512e to aa0ad65 Compare February 11, 2025 01:12
@tillh-stripe tillh-stripe marked this pull request as draft February 11, 2025 19:52
Comment on lines 110 to 116
private fun String.parsePaymentMethod(): PaymentMethod? = try {
val json = JSONObject(this)
val paymentMethod = PaymentMethodJsonParser().parse(json)
paymentMethod
} catch (e: Exception) {
null
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wdyt about using runCatching here to avoid the lint baseline update?

Comment on lines 184 to 200
private val ConsumerPaymentDetails.PaymentDetails.useLinkCardBrandConfirmation: Boolean
get() = type == "bank_account" && configuration.passthroughModeEnabled

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wdyt about using ConsumerPaymentDetails.BankAccount.TYPE instead of a string literal?

Comment on lines 40 to 41
internal class LinkApiRepository @Inject constructor(
context: Context,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wish we had an annotation saying this is an application context. Seeing this field in the constructor is a little scary

GIT_VALID_PII_OVERRIDE
- If Link card brand and ACH enabled, then use `bank_account`
- Rename `shareLinkCardBrand` to `sharePaymentDetails`
- Inject `Application` instead of `Context`
@tillh-stripe tillh-stripe force-pushed the tillh/native-link-bank-payments branch from 3e43e91 to 1d56f20 Compare February 12, 2025 15:28
Copy link
Contributor

@toluo-stripe toluo-stripe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM otherwise

Comment on lines +203 to +220
@JvmSuppressWildcards
@Provides
@IntoSet
fun providesLinkCardBrandConfirmationDefinition(
linkAccountManager: DefaultLinkAccountManager
): ConfirmationDefinition<*, *, *, *> {
return LinkCardBrandConfirmationDefinition(
linkAccountManager = linkAccountManager,
)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be in a LinkCardBrandConfirmationModule in com.stripe.android.paymentelement.confirmation.link

@tillh-stripe tillh-stripe force-pushed the tillh/native-link-bank-payments branch from a36b55a to 0fdf9e4 Compare February 12, 2025 18:05
@tillh-stripe tillh-stripe marked this pull request as ready for review February 12, 2025 18:52
@tillh-stripe tillh-stripe merged commit 51c5733 into master Feb 12, 2025
16 checks passed
@tillh-stripe tillh-stripe deleted the tillh/native-link-bank-payments branch February 12, 2025 21:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants