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

Add Boleto to PaymentSheet. #7282

Merged
merged 11 commits into from
Sep 12, 2023
Merged

Add Boleto to PaymentSheet. #7282

merged 11 commits into from
Sep 12, 2023

Conversation

jaynewstrom-stripe
Copy link
Collaborator

@jaynewstrom-stripe jaynewstrom-stripe commented Sep 8, 2023

Summary

Add boleto, also a bunch of changes to our test harness to be able to E2E test QR code based LPMs in PS.

Motivation

LPM Sprint

Testing

  • Added tests
  • Modified tests
  • Manually verified

Screenshots

Changelog

PaymentSheet

  • [ADDED] PaymentSheet now supports the following payment methods for SetupIntents and PaymentIntents with setup for future usage:

@github-actions
Copy link
Contributor

github-actions bot commented Sep 8, 2023

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 │   3.5 MiB │   3.5 MiB │ +1.4 KiB │   7.8 MiB │   7.8 MiB │ +3.2 KiB 
     arsc │   2.2 MiB │   2.2 MiB │   +716 B │   2.2 MiB │   2.2 MiB │   +716 B 
 manifest │   4.9 KiB │   4.9 KiB │      0 B │  24.1 KiB │  24.1 KiB │      0 B 
      res │ 880.5 KiB │ 881.2 KiB │   +651 B │   1.4 MiB │   1.4 MiB │ +1.4 KiB 
   native │   2.6 MiB │   2.6 MiB │      0 B │     6 MiB │     6 MiB │      0 B 
    asset │     3 MiB │     3 MiB │     +5 B │     3 MiB │     3 MiB │   +473 B 
    other │ 200.2 KiB │ 200.2 KiB │    +52 B │ 447.8 KiB │ 447.9 KiB │   +164 B 
──────────┼───────────┼───────────┼──────────┼───────────┼───────────┼──────────
    total │  12.3 MiB │  12.3 MiB │ +2.8 KiB │  20.7 MiB │  20.8 MiB │   +6 KiB 

 DEX     │ old   │ new   │ diff              
─────────┼───────┼───────┼───────────────────
   files │     1 │     1 │   0               
 strings │ 38319 │ 38336 │ +17 (+41 -24)     
   types │ 12686 │ 12691 │  +5 (+28 -23)     
 classes │ 10711 │ 10715 │  +4 (+7 -3)       
 methods │ 56199 │ 56223 │ +24 (+1230 -1206) 
  fields │ 35266 │ 35249 │ -17 (+986 -1003)  

 ARSC    │ old  │ new  │ diff       
─────────┼──────┼──────┼────────────
 configs │  290 │  290 │  0         
 entries │ 6943 │ 6945 │ +2 (+2 -0)
APK
     compressed      │     uncompressed     │                                
──────────┬──────────┼───────────┬──────────┤                                
 size     │ diff     │ size      │ diff     │ path                           
──────────┼──────────┼───────────┼──────────┼────────────────────────────────
  3.5 MiB │ +1.4 KiB │   7.8 MiB │ +3.2 KiB │ ∆ classes.dex                  
  2.2 MiB │   +716 B │   2.2 MiB │   +716 B │ ∆ resources.arsc               
    651 B │   +651 B │   1.4 KiB │ +1.4 KiB │ + res/pU.xml                   
  2.8 KiB │    +39 B │  23.2 KiB │   +507 B │ ∆ assets/lpms.json             
  6.4 KiB │    -36 B │   6.2 KiB │    -36 B │ ∆ assets/dexopt/baseline.prof  
 48.8 KiB │    +31 B │ 141.3 KiB │    +82 B │ ∆ META-INF/MANIFEST.MF         
 62.9 KiB │    +23 B │ 141.4 KiB │    +82 B │ ∆ META-INF/CERT.SF             
    762 B │     +2 B │     630 B │     +2 B │ ∆ assets/dexopt/baseline.profm 
  1.2 KiB │     -2 B │   1.2 KiB │      0 B │ ∆ META-INF/CERT.RSA            
──────────┼──────────┼───────────┼──────────┼────────────────────────────────
  5.8 MiB │ +2.8 KiB │  10.2 MiB │   +6 KiB │ (total)
DEX
STRINGS:

   old   │ new   │ diff          
  ───────┼───────┼───────────────
   38319 │ 38336 │ +17 (+41 -24) 
  + Boleto
  + BoletoTaxIdSpec(apiPath=
  + DisplayBoletoDetails
  + DisplayBoletoDetails(hostedVoucherUrl=
  + Lcd/n5;
  + Ldd/b0;
  + Lfg/d7;
  + Lfg/e7;
  + Lfg/f7;
  + Ljf/n1;
  + Lsd/v0;
  + [Lbg/e;
  + [Lcd/b5;
  + [Lcd/f5;
  + [Lcd/j5;
  + [Lcd/n5;
  + [Led/b;
  + [Lff/e;
  + [Lfg/d3;
  + [Lfg/d4;
  + [Lfg/h5;
  + [Lfg/m0;
  + [Lfg/s3;
  + [Lfg/z6;
  + [Ljf/b1;
  + [Lkf/a;
  + [Lkf/d;
  + [Lkf/g;
  + [Lrd/v1;
  + [Lsd/s;
  + [Ltg/r0;
  + [Ltg/z;
  + boleto
  + boleto[tax_id]
  + boleto_display_details
  + boleto_tax_id
  + com.stripe.android.ui.core.elements.BoletoTaxIdSpec
  + keyboardType
  + null cannot be cast to non-null type com.stripe.android.model.StripeIntent.NextActionData.DisplayBoletoDetails
  + null hostedVoucherUrl for DisplayBoletoDetails
  + ~~R8{backend:dex,compilation-mode:release,has-checksums:false,min-api:21,pg-map-id:7685fc2,r8-mode:full,version:8.0.46}
  
  - Lkf/k;
  - Lne/s;
  - Ltd/f;
  - [Lbg/d;
  - [Lcd/c5;
  - [Lcd/i5;
  - [Lcd/k5;
  - [Led/a;
  - [Lff/d;
  - [Lfg/a3;
  - [Lfg/a4;
  - [Lfg/e5;
  - [Lfg/j0;
  - [Lfg/p3;
  - [Lfg/w6;
  - [Ljf/a1;
  - [Lkf/b;
  - [Lkf/f;
  - [Lkf/k;
  - [Lrd/u1;
  - [Lsd/r;
  - [Ltg/q0;
  - [Ltg/y;
  - ~~R8{backend:dex,compilation-mode:release,has-checksums:false,min-api:21,pg-map-id:d53acea,r8-mode:full,version:8.0.46}
  

TYPES:

   old   │ new   │ diff         
  ───────┼───────┼──────────────
   12686 │ 12691 │ +5 (+28 -23) 
  + Lcd/n5;
  + Ldd/b0;
  + Lfg/d7;
  + Lfg/e7;
  + Lfg/f7;
  + Ljf/n1;
  + Lsd/v0;
  + [Lbg/e;
  + [Lcd/b5;
  + [Lcd/f5;
  + [Lcd/j5;
  + [Lcd/n5;
  + [Led/b;
  + [Lff/e;
  + [Lfg/d3;
  + [Lfg/d4;
  + [Lfg/h5;
  + [Lfg/m0;
  + [Lfg/s3;
  + [Lfg/z6;
  + [Ljf/b1;
  + [Lkf/a;
  + [Lkf/d;
  + [Lkf/g;
  + [Lrd/v1;
  + [Lsd/s;
  + [Ltg/r0;
  + [Ltg/z;
  
  - Lkf/k;
  - Lne/s;
  - Ltd/f;
  - [Lbg/d;
  - [Lcd/c5;
  - [Lcd/i5;
  - [Lcd/k5;
  - [Led/a;
  - [Lff/d;
  - [Lfg/a3;
  - [Lfg/a4;
  - [Lfg/e5;
  - [Lfg/j0;
  - [Lfg/p3;
  - [Lfg/w6;
  - [Ljf/a1;
  - [Lkf/b;
  - [Lkf/f;
  - [Lkf/k;
  - [Lrd/u1;
  - [Lsd/r;
  - [Ltg/q0;
  - [Ltg/y;
  

METHODS:

   old   │ new   │ diff              
  ───────┼───────┼───────────────────
   56199 │ 56223 │ +24 (+1230 -1206) 
  + a0.r h(boolean, c1, Set, t0, i, int)
  + a4.k A(i) → i0
  + a4.k B(InputFilter[]) → InputFilter[]
  + a4.k C() → v1
  + a4.k D(KeyListener) → KeyListener
  + a4.k E(String) → ArrayList
  + a4.k F(String, JSONObject) → String
  + a4.k G(PackageManager, String) → Signature[]
  + a4.k H(i) → s8
  + a4.k I(InputConnection, Editable, int, int, boolean) → boolean
  + a4.k J()
  + a4.k K(Activity)
  + a4.k L() → boolean
  + a4.k N(Spannable) → boolean
  + a4.k O(int) → boolean
  + a4.k P(InputConnection, EditorInfo) → InputConnection
  + a4.k Q(JSONObject) → b
  + a4.k R(boolean)
  + a4.k V()
  + a4.k W(View)
  + a4.k X(TransformationMethod) → TransformationMethod
  + a4.k h(a) → w
  + a4.k s(h3, String, m, l3, int) → n
  + a4.k u(Activity, w)
  + a4.k v(String) → i
  + a4.k w(String) → String
  + a4.k x(String, Object[]) → String
  + a4.k y(String) → i
  + a4.k z(String) → List
  + ac.v2 f() → j5
  + af.n o(h5)
  + ah.f b(boolean, s0, Set, t0, i, int)
  + ah.f l0(JSONObject) → j5
  + androidx.appcompat.widget.w <init>(Context, n2, e0, Object, Set, e2)
  + androidx.appcompat.widget.w <init>(Object, b, n, l1, Application, int)
  + androidx.appcompat.widget.w <init>(b, b, n, l1, Application)
  + androidx.appcompat.widget.w <init>(e, b, n, l1, Application)
  + androidx.appcompat.widget.w h() → j
  + androidx.emoji2.text.b0 N(Spannable) → boolean
  + androidx.emoji2.text.d G(PackageManager, String) → Signature[]
  + b0.g d0(JSONObject) → g5
  + bg.a <init>(int)
  + bg.a <init>(int, int)
  + bg.a a(Map, List, String)
  + bg.a b(Bitmap, Rect, Rect) → m
  + bg.a c(String) → String
  + bg.a d(String) → h3
  + bg.a e(String, String) → i1
  + bg.a f(String) → u1
  + bg.a g(b) → d
  + bg.a h(c) → c
  + bg.a i() → boolean
  + bg.a j(String) → String
  + bg.a k(Integer, List) → n2
  + bg.b <init>(c, d)
  + bg.b j(Object) → Object
  + bg.c <init>(Context, a)
  + bg.c a(d) → Object
  + bg.c c() → a
  + bg.d <init>(b)
  + bg.d equals(Object) → boolean
  + bg.d hashCode() → int
  + bg.d toString() → String
  + bg.e <clinit>()
  + bg.e <init>(String, int)
  + bg.e valueOf(String) → e
  + bg.e values() → e[]
  + bg.f <init>(e, float, float, 
...✂
ARSC
ENTRIES:

   old  │ new  │ diff       
  ──────┼──────┼────────────
   6943 │ 6945 │ +2 (+2 -0) 
  + drawable/stripe_ic_paymentsheet_pm_boleto
  + string/stripe_paymentsheet_payment_method_boleto

samer-stripe
samer-stripe previously approved these changes Sep 12, 2023
CHANGELOG.md Outdated
Comment on lines 6 to 7
* [ADDED] PaymentSheet now supports the following payment methods for SetupIntents and PaymentIntents with setup for future usage:
* [7282](https://github.com/stripe/stripe-android/pull/7282) Boleto
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: Should make this a single line if we don’t end up adding the same support for more payment methods in this release.

requestOptions: ApiRequest.Options
) {
(authenticatable.nextActionData as NextActionData.DisplayBoletoDetails).let { detailsData ->
if (detailsData.hostedVoucherUrl == null) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can this even happen?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I copied what Oxxo was doing. In theory it could? In practice probably not.

@@ -84,6 +84,13 @@ internal class WebIntentAuthenticator @Inject constructor(
returnUrl = null
shouldCancelIntentOnUserNavigation = false
}
is StripeIntent.NextActionData.DisplayBoletoDetails -> {
// nextActionData.hostedVoucherUrl will never be null as AuthenticatorRegistry won't direct it here
authUrl = nextActionData.hostedVoucherUrl.takeIf { it!!.isNotEmpty() }
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we need this check here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I just copied Oxxo. 🤷


@Serializable
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
data class BoletoTaxIdSpec(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we need to do any validation of the input here, or limit it to a certain length?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The backend does validation. Talked over slack, and planning to do the minimum here for now. If it gets traction, we can add client side validation as a future improvement.

requestOptions: ApiRequest.Options
) {
(authenticatable.nextActionData as NextActionData.DisplayBoletoDetails).let { detailsData ->
if (detailsData.hostedVoucherUrl == null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there ever a case where hostedVoucherUrl is null? And if it is null, what do we do instead?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We wouldn't choose this authenticator. Likely a server bug that we shouldn't crash from, but an error they'd need to fix.

AFAIK, hostedVoucherUrl should never be null.

@jaynewstrom-stripe jaynewstrom-stripe merged commit 3549ea8 into master Sep 12, 2023
@jaynewstrom-stripe jaynewstrom-stripe deleted the jaynewstrom/boleto branch September 12, 2023 17:24
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.

4 participants