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 support for SEPA Debit in PaymentMethod #1693

Merged
merged 2 commits into from
Oct 11, 2019
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
107 changes: 106 additions & 1 deletion stripe/src/main/java/com/stripe/android/model/PaymentMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public final class PaymentMethod extends StripeModel implements Parcelable {
private static final String FIELD_CARD_PRESENT = "card_present";
private static final String FIELD_FPX = "fpx";
private static final String FIELD_IDEAL = "ideal";
private static final String FIELD_SEPA_DEBIT = "sepa_debit";

@Nullable public final String id;
@Nullable public final Long created;
Expand All @@ -62,6 +63,7 @@ public final class PaymentMethod extends StripeModel implements Parcelable {
@Nullable public final CardPresent cardPresent;
@Nullable public final Fpx fpx;
@Nullable public final Ideal ideal;
@Nullable public final SepaDebit sepaDebit;

public enum Type implements Parcelable {
Card("card"),
Expand Down Expand Up @@ -135,6 +137,7 @@ private PaymentMethod(@NonNull Builder builder) {
cardPresent = builder.mCardPresent;
fpx = builder.mFpx;
ideal = builder.mIdeal;
sepaDebit = builder.mSepaDebit;
}

/**
Expand Down Expand Up @@ -182,6 +185,8 @@ public static PaymentMethod fromJson(@Nullable JSONObject paymentMethod) {
builder.setIdeal(Ideal.fromJson(paymentMethod.optJSONObject(FIELD_IDEAL)));
} else if (FIELD_FPX.equals(type)) {
builder.setFpx(Fpx.fromJson(paymentMethod.optJSONObject(FIELD_FPX)));
} else if (FIELD_SEPA_DEBIT.equals(type)) {
builder.setSepaDebit(SepaDebit.fromJson(paymentMethod.optJSONObject(FIELD_SEPA_DEBIT)));
}

return builder.build();
Expand All @@ -202,6 +207,7 @@ private boolean typedEquals(@NonNull PaymentMethod paymentMethod) {
&& Objects.equals(cardPresent, paymentMethod.cardPresent)
&& Objects.equals(fpx, paymentMethod.fpx)
&& Objects.equals(ideal, paymentMethod.ideal)
&& Objects.equals(sepaDebit, paymentMethod.sepaDebit)
&& Objects.equals(customerId, paymentMethod.customerId);
}

Expand Down Expand Up @@ -232,6 +238,7 @@ public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeParcelable(cardPresent, flags);
dest.writeParcelable(fpx, flags);
dest.writeParcelable(ideal, flags);
dest.writeParcelable(sepaDebit, flags);
dest.writeString(customerId);
dest.writeInt(metadata == null ? -1 : metadata.size());
if (metadata != null) {
Expand All @@ -252,6 +259,7 @@ private PaymentMethod(@NonNull Parcel in) {
cardPresent = in.readParcelable(CardPresent.class.getClassLoader());
fpx = in.readParcelable(Fpx.class.getClassLoader());
ideal = in.readParcelable(Ideal.class.getClassLoader());
sepaDebit = in.readParcelable(SepaDebit.class.getClassLoader());
customerId = in.readString();
final int mapSize = in.readInt();
if (mapSize >= 0) {
Expand Down Expand Up @@ -292,11 +300,11 @@ public static final class Builder implements ObjectBuilder<PaymentMethod> {
private BillingDetails mBillingDetails;
private Map<String, String> mMetadata;
private String mCustomerId;

private Card mCard;
private CardPresent mCardPresent;
private Ideal mIdeal;
private Fpx mFpx;
private SepaDebit mSepaDebit;

@NonNull
public Builder setId(@Nullable String id) {
Expand Down Expand Up @@ -364,6 +372,12 @@ public Builder setFpx(@Nullable Fpx fpx) {
return this;
}

@NonNull
public Builder setSepaDebit(@Nullable SepaDebit sepaDebit) {
this.mSepaDebit = sepaDebit;
return this;
}

@NonNull
public PaymentMethod build() {
return new PaymentMethod(this);
Expand Down Expand Up @@ -1146,6 +1160,97 @@ public Fpx build() {
}
}

public static final class SepaDebit extends PaymentMethodTypeImpl {
private static final String FIELD_BANK_CODE = "bank_code";
private static final String FIELD_BRANCH_CODE = "branch_code";
private static final String FIELD_COUNTRY = "country";
private static final String FIELD_FINGERPRINT = "fingerprint";
private static final String FIELD_LAST4 = "last4";

@Nullable public final String bankCode;
@Nullable public final String branchCode;
@Nullable public final String country;
@Nullable public final String fingerprint;
@Nullable public final String last4;

SepaDebit(
@Nullable String bankCode,
@Nullable String branchCode,
@Nullable String country,
@Nullable String fingerprint,
@Nullable String last4
) {
super(Type.SepaDebit);
this.bankCode = bankCode;
this.branchCode = branchCode;
this.country = country;
this.fingerprint = fingerprint;
this.last4 = last4;
}

private SepaDebit(@NonNull Parcel parcel) {
this(
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readString(),
parcel.readString()
);
}

@Override
public int hashCode() {
return Objects.hash(bankCode, branchCode, country, fingerprint, last4);
}

@Override
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
} else if (other instanceof SepaDebit) {
return typedEquals((SepaDebit) other);
} else {
return false;
}
}

private boolean typedEquals(@NonNull SepaDebit other) {
return Objects.equals(bankCode, other.bankCode) &&
Objects.equals(branchCode, other.branchCode) &&
Objects.equals(country, other.country) &&
Objects.equals(fingerprint, other.fingerprint) &&
Objects.equals(last4, other.last4);
}

protected static final Parcelable.Creator<SepaDebit> CREATOR =
new Parcelable.Creator<SepaDebit>() {
@Override
public SepaDebit createFromParcel(@NonNull Parcel parcel) {
return new SepaDebit(parcel);
}

@Override
public SepaDebit[] newArray(int size) {
return new SepaDebit[size];
}
};

@Nullable
static SepaDebit fromJson(@Nullable JSONObject sepaDebit) {
if (sepaDebit == null) {
return null;
}

return new SepaDebit(
optString(sepaDebit, FIELD_BANK_CODE),
optString(sepaDebit, FIELD_BRANCH_CODE),
optString(sepaDebit, FIELD_COUNTRY),
optString(sepaDebit, FIELD_FINGERPRINT),
optString(sepaDebit, FIELD_LAST4)
);
}
}

private abstract static class PaymentMethodTypeImpl extends StripeModel
implements Parcelable {
@NonNull public final Type type;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.stripe.android.model

import java.util.UUID
import java.util.concurrent.ThreadLocalRandom
import org.json.JSONObject

internal object PaymentMethodFixtures {
@JvmField
Expand Down Expand Up @@ -62,6 +63,41 @@ internal object PaymentMethodFixtures {
.build())
.build()

@JvmField
val SEPA_DEBIT_PAYMENT_METHOD = PaymentMethod.fromJson(JSONObject(
"""
{
"id": "pm_1FSQaJCR",
"object": "payment_method",
"billing_details": {
"address": {
"city": null,
"country": null,
"line1": null,
"line2": null,
"postal_code": null,
"state": null
},
"email": "jrosen@example.com",
"name": "Jenny Rosen",
"phone": null
},
"created": 1570809799,
"customer": null,
"livemode": false,
"metadata": {},
"sepa_debit": {
"bank_code": "3704",
"branch_code": "",
"country": "DE",
"fingerprint": "vIZc7Ywn0",
"last4": "3000"
},
"type": "sepa_debit"
}
""".trimIndent()
))!!

@JvmField
val CARD_PAYMENT_METHODS = listOf(
PaymentMethod.Builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,34 @@ class PaymentMethodTest {
PaymentMethod.fromJson(PM_FPX_JSON))
}

@Test
fun toJson_withSepaDebit_shouldCreateExpectedObject() {
assertEquals(PaymentMethodFixtures.SEPA_DEBIT_PAYMENT_METHOD,
PaymentMethod.Builder()
.setType(PaymentMethod.Type.SepaDebit.code)
.setId("pm_1FSQaJCR")
.setLiveMode(false)
.setCreated(1570809799L)
.setSepaDebit(
PaymentMethod.SepaDebit(
"3704",
null,
"DE",
"vIZc7Ywn0",
"3000"
)
)
.setBillingDetails(
PaymentMethod.BillingDetails.Builder()
.setName("Jenny Rosen")
.setEmail("jrosen@example.com")
.setAddress(Address.Builder().build())
.build()
)
.build()
)
}

@Test
fun equals_withEqualPaymentMethods_shouldReturnTrue() {
assertEquals(PaymentMethodFixtures.CARD_PAYMENT_METHOD,
Expand Down