Skip to content

Commit

Permalink
Make STPSource conform to STPPaymentMethod, exposing labels & ima…
Browse files Browse the repository at this point in the history
…ges (#976)

* Make `STPSource`'s implementation of `STPPaymentMethod` public

We originally made it a private implementation because the `STPPaymentMethod` protocol implementations don't return anything useful for `label` and `image` but we're going to improve on that next.

* Add suitable `STPPaymentMethod` protocol implementation in `STPSource`

* Add localization options for [STPSource label]

* Update documentation on `STPPaymentMethod`
  • Loading branch information
joeydong-stripe authored and danj-stripe committed Aug 3, 2018
1 parent a84e0da commit df4fded
Show file tree
Hide file tree
Showing 20 changed files with 474 additions and 44 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
@@ -1,3 +1,6 @@
## XX.Y.Z
* Adds `STPPaymentMethod` protocol implementation for `STPSource`. You can now call `image`/`templatedImage`/`label` on a source. [#976](https://github.com/stripe/stripe-ios/pull/976)

## 13.1.0 2018-07-13
* Adds `STPPaymentIntent` to support PaymentIntents. [#985](https://github.com/stripe/stripe-ios/pull/985), [#986](https://github.com/stripe/stripe-ios/pull/986), [#987](https://github.com/stripe/stripe-ios/pull/987), [#988](https://github.com/stripe/stripe-ios/pull/988)
* Reduce `NSURLSession` memory footprint. [#969](https://github.com/stripe/stripe-ios/pull/969)
Expand Down
28 changes: 26 additions & 2 deletions Stripe.xcodeproj/project.pbxproj
Expand Up @@ -325,6 +325,12 @@
04F94DD41D22A242004FC826 /* NSBundle+Stripe_AppName.m in Sources */ = {isa = PBXBuildFile; fileRef = 049A3F981CC76A2400F57DE7 /* NSBundle+Stripe_AppName.m */; };
04FCFA191BD59A8C00297732 /* STPCategoryLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 04FCFA171BD59A8C00297732 /* STPCategoryLoader.h */; };
8B013C891F1E784A00DD831B /* STPPaymentConfigurationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B013C881F1E784A00DD831B /* STPPaymentConfigurationTest.m */; };
8B39128220E2F99600098401 /* EPSSource.json in Resources */ = {isa = PBXBuildFile; fileRef = 8B39128120E2F99600098401 /* EPSSource.json */; };
8B39128320E2F9A100098401 /* BancontactSource.json in Resources */ = {isa = PBXBuildFile; fileRef = 8B39127F20E2F6A500098401 /* BancontactSource.json */; };
8B39128520E2F9C400098401 /* GiropaySource.json in Resources */ = {isa = PBXBuildFile; fileRef = 8B39128420E2F9C400098401 /* GiropaySource.json */; };
8B39128720E2F9D300098401 /* MultibancoSource.json in Resources */ = {isa = PBXBuildFile; fileRef = 8B39128620E2F9D300098401 /* MultibancoSource.json */; };
8B39128920E2F9E000098401 /* P24Source.json in Resources */ = {isa = PBXBuildFile; fileRef = 8B39128820E2F9E000098401 /* P24Source.json */; };
8B39128B20E2F9F500098401 /* SOFORTSource.json in Resources */ = {isa = PBXBuildFile; fileRef = 8B39128A20E2F9F500098401 /* SOFORTSource.json */; };
8B429AD81EF9D4B400F95F34 /* STPBankAccountParams+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B429AD71EF9D4A300F95F34 /* STPBankAccountParams+Private.h */; };
8B429AD91EF9D4B500F95F34 /* STPBankAccountParams+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B429AD71EF9D4A300F95F34 /* STPBankAccountParams+Private.h */; };
8B429ADE1EF9EFF900F95F34 /* STPFile+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B429ADD1EF9EFF600F95F34 /* STPFile+Private.h */; };
Expand Down Expand Up @@ -1039,6 +1045,12 @@
4A0D74F918F6106100966D7B /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
7E0B1132203572FB00271AD3 /* fi */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = fi; path = Localizations/fi.lproj/Localizable.strings; sourceTree = "<group>"; };
8B013C881F1E784A00DD831B /* STPPaymentConfigurationTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPPaymentConfigurationTest.m; sourceTree = "<group>"; };
8B39127F20E2F6A500098401 /* BancontactSource.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = BancontactSource.json; sourceTree = "<group>"; };
8B39128120E2F99600098401 /* EPSSource.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = EPSSource.json; sourceTree = "<group>"; };
8B39128420E2F9C400098401 /* GiropaySource.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = GiropaySource.json; sourceTree = "<group>"; };
8B39128620E2F9D300098401 /* MultibancoSource.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = MultibancoSource.json; sourceTree = "<group>"; };
8B39128820E2F9E000098401 /* P24Source.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = P24Source.json; sourceTree = "<group>"; };
8B39128A20E2F9F500098401 /* SOFORTSource.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = SOFORTSource.json; sourceTree = "<group>"; };
8B429AD71EF9D4A300F95F34 /* STPBankAccountParams+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "STPBankAccountParams+Private.h"; sourceTree = "<group>"; };
8B429ADD1EF9EFF600F95F34 /* STPFile+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "STPFile+Private.h"; sourceTree = "<group>"; };
8B5B4B431EFDD925005CF475 /* STPSourceOwnerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPSourceOwnerTest.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1584,11 +1596,17 @@
isa = PBXGroup;
children = (
F1BA241F1E57BEC600E4A1CF /* 3DSSource.json */,
F16AA26D1F5A05A100207FFF /* AlipaySource.json */,
8B39127F20E2F6A500098401 /* BancontactSource.json */,
F1BA241C1E57BE5700E4A1CF /* CardSource.json */,
8B39128120E2F99600098401 /* EPSSource.json */,
8B39128420E2F9C400098401 /* GiropaySource.json */,
F152322E1EA9344000D65C67 /* iDEALSource.json */,
8B39128620E2F9D300098401 /* MultibancoSource.json */,
B3BDCADE20F0142C0034F7F5 /* PaymentIntent.json */,
8B39128820E2F9E000098401 /* P24Source.json */,
8BD2133D1F045D31007F6FD1 /* SEPADebitSource.json */,
F16AA26D1F5A05A100207FFF /* AlipaySource.json */,
8B39128A20E2F9F500098401 /* SOFORTSource.json */,
);
name = Source;
sourceTree = "<group>";
Expand All @@ -1597,10 +1615,10 @@
isa = PBXGroup;
children = (
F156753F1DB544D3004468E3 /* STPAddCardViewControllerLocalizationTests.m */,
C1054F901FE197AE0033C87E /* STPPaymentContextSnapshotTests.m */,
F1B980931DB550E60075332E /* STPPaymentMethodsViewControllerLocalizationTests.m */,
C1EF04491DD2396200FBF452 /* STPShippingAddressViewControllerLocalizationTests.m */,
C1EF044A1DD2396200FBF452 /* STPShippingMethodsViewControllerLocalizationTests.m */,
C1054F901FE197AE0033C87E /* STPPaymentContextSnapshotTests.m */,
);
name = Snapshot;
sourceTree = "<group>";
Expand Down Expand Up @@ -2573,11 +2591,17 @@
C1C02CCC1ECCD0ED00DF5643 /* EphemeralKey.json in Resources */,
F1BA24211E57BECA00E4A1CF /* 3DSSource.json in Resources */,
F1BA241E1E57BE5E00E4A1CF /* CardSource.json in Resources */,
8B39128520E2F9C400098401 /* GiropaySource.json in Resources */,
F1343BE91D652CAB00F102D8 /* Card.json in Resources */,
8B39128720E2F9D300098401 /* MultibancoSource.json in Resources */,
8BD213391F0457A1007F6FD1 /* FileUpload.json in Resources */,
C1CFCB7A1ED5F88D00BE45DF /* stp_test_upload_image.jpeg in Resources */,
F152322F1EA9344600D65C67 /* iDEALSource.json in Resources */,
F16AA26F1F5A0F1700207FFF /* AlipaySource.json in Resources */,
8B39128920E2F9E000098401 /* P24Source.json in Resources */,
8B39128220E2F99600098401 /* EPSSource.json in Resources */,
8B39128320E2F9A100098401 /* BancontactSource.json in Resources */,
8B39128B20E2F9F500098401 /* SOFORTSource.json in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
7 changes: 5 additions & 2 deletions Stripe/PublicHeaders/STPPaymentMethod.h
Expand Up @@ -36,9 +36,12 @@ typedef NS_OPTIONS(NSUInteger, STPPaymentMethodType) {
/**
This protocol represents a payment method that a user can select and use to
pay. Currently the only classes that conform to it are `STPCard`, which
represents that the user wants to pay with a specific card, and
represents that the user wants to pay with a specific card,
`STPApplePayPaymentMethod`, which represents that the user wants to pay with
Apple Pay.
Apple Pay, and `STPSource`. Only `STPSource.type == STPSourceTypeCard` payment
methods are supported by `STPPaymentContext` and `STPPaymentMethodViewController`,
but the other types do have basic support for this protocol for use in a custom
integration.
*/
@protocol STPPaymentMethod <NSObject>

Expand Down
2 changes: 1 addition & 1 deletion Stripe/PublicHeaders/STPSource.h
Expand Up @@ -25,7 +25,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
Representation of a customer's payment instrument created with the Stripe API. @see https://stripe.com/docs/api#sources
*/
@interface STPSource : NSObject<STPAPIResponseDecodable, STPSourceProtocol>
@interface STPSource : NSObject<STPAPIResponseDecodable, STPSourceProtocol, STPPaymentMethod>

/**
You cannot directly instantiate an `STPSource`. You should only use one that
Expand Down
35 changes: 34 additions & 1 deletion Stripe/Resources/Localizations/en.lproj/Localizable.strings
@@ -1,6 +1,9 @@
/* {card brand} ending in {last4} */
"%@ Ending In %@" = "%1$@ Ending In %2$@";

/* Source type brand name */
"3D Secure" = "3D Secure";

/* Title for Add a Card view */
"Add a Card" = "Add a Card";

Expand All @@ -10,12 +13,18 @@
/* Caption for Address field on address form */
"Address" = "Address";

/* Source type brand name */
"Alipay" = "Alipay";

/* Text for Apple Pay payment method */
"Apple Pay" = "Apple Pay";

/* Caption for Apartment/Address line 2 field on address form */
"Apt." = "Apt.";

/* Source type brand name */
"Bancontact" = "Bancontact";

/* Title for billing address entry section */
"Billing Address" = "Billing Address";

Expand Down Expand Up @@ -46,27 +55,42 @@
/* Caption for Email field on address form */
"Email" = "Email";

/* Source type brand name */
"EPS" = "EPS";

/* accessibility label for text field */
"expiration date" = "expiration date";

/* Label for free shipping method */
"Free" = "Free";

/* Source type brand name */
"Giropay" = "Giropay";

/* Source type brand name */
"iDEAL" = "iDEAL";

/* Shipping form error message */
"Invalid Shipping Address" = "Invalid Shipping Address";

/* Title for screen when data is still loading from the network. */
"Loading…" = "Loading…";

/* Source type brand name */
"Multibanco" = "Multibanco";

/* Caption for Name field on address form */
"Name" = "Name";

/* Button to move to the next text entry field */
"Next" = "Next";

/* No comment provided by engineer. */
/* ok button */
"OK" = "OK";

/* Source type brand name */
"P24" = "P24";

/* Title for Payment Method screen */
"Payment Method" = "Payment Method";

Expand All @@ -85,6 +109,9 @@
/* Text for button to scan a credit card */
"Scan Card" = "Scan Card";

/* Source type brand name */
"SEPA Direct Debit" = "SEPA Direct Debit";

/* Title for shipping info form */
"Shipping" = "Shipping";

Expand All @@ -94,6 +121,9 @@
/* Label for shipping method form */
"Shipping Method" = "Shipping Method";

/* Source type brand name */
"SOFORT" = "SOFORT";

/* Caption for State field on address form (only countries that use state , like United States) */
"State" = "State";

Expand All @@ -106,6 +136,9 @@
/* Unexpected error, such as a 500 from Stripe or a JSON parse error */
"There was an unexpected error -- try again in a few seconds" = "There was an unexpected error -- try again in a few seconds";

/* Default missing source type label */
"Unknown" = "Unknown";

/* Button to fill shipping address from billing address. */
"Use Billing" = "Use Billing";

Expand Down
2 changes: 1 addition & 1 deletion Stripe/STPSource+Private.h
Expand Up @@ -11,7 +11,7 @@

NS_ASSUME_NONNULL_BEGIN

@interface STPSource () <STPInternalAPIResponseDecodable, STPPaymentMethod>
@interface STPSource () <STPInternalAPIResponseDecodable>

+ (STPSourceType)typeFromString:(NSString *)string;
+ (nullable NSString *)stringFromType:(STPSourceType)type;
Expand Down
45 changes: 33 additions & 12 deletions Stripe/STPSource.m
Expand Up @@ -269,8 +269,7 @@ + (instancetype)decodedObjectFromAPIResponse:(NSDictionary *)response {
#pragma mark - STPPaymentMethod

- (UIImage *)image {
if (self.type == STPSourceTypeCard
&& self.cardDetails != nil) {
if (self.type == STPSourceTypeCard && self.cardDetails != nil) {
return [STPImageLibrary brandImageForCardBrand:self.cardDetails.brand];
}
else {
Expand All @@ -279,8 +278,7 @@ - (UIImage *)image {
}

- (UIImage *)templateImage {
if (self.type == STPSourceTypeCard
&& self.cardDetails != nil) {
if (self.type == STPSourceTypeCard && self.cardDetails != nil) {
return [STPImageLibrary templatedBrandImageForCardBrand:self.cardDetails.brand];
}
else {
Expand All @@ -289,15 +287,38 @@ - (UIImage *)templateImage {
}

- (NSString *)label {
if (self.type == STPSourceTypeCard
&& self.cardDetails != nil) {
NSString *brand = [STPCard stringFromBrand:self.cardDetails.brand];
return [NSString stringWithFormat:@"%@ %@", brand, self.cardDetails.last4];;
}
else {
return [STPCard stringFromBrand:STPCardBrandUnknown];
switch (self.type) {
case STPSourceTypeBancontact:
return STPLocalizedString(@"Bancontact", @"Source type brand name");
case STPSourceTypeCard:
if (self.cardDetails != nil) {
NSString *brand = [STPCard stringFromBrand:self.cardDetails.brand];
return [NSString stringWithFormat:@"%@ %@", brand, self.cardDetails.last4];
}
else {
return [STPCard stringFromBrand:STPCardBrandUnknown];
}
case STPSourceTypeGiropay:
return STPLocalizedString(@"Giropay", @"Source type brand name");
case STPSourceTypeIDEAL:
return STPLocalizedString(@"iDEAL", @"Source type brand name");
case STPSourceTypeSEPADebit:
return STPLocalizedString(@"SEPA Direct Debit", @"Source type brand name");
case STPSourceTypeSofort:
return STPLocalizedString(@"SOFORT", @"Source type brand name");
case STPSourceTypeThreeDSecure:
return STPLocalizedString(@"3D Secure", @"Source type brand name");
case STPSourceTypeAlipay:
return STPLocalizedString(@"Alipay", @"Source type brand name");
case STPSourceTypeP24:
return STPLocalizedString(@"P24", @"Source type brand name");
case STPSourceTypeEPS:
return STPLocalizedString(@"EPS", @"Source type brand name");
case STPSourceTypeMultibanco:
return STPLocalizedString(@"Multibanco", @"Source type brand name");
case STPSourceTypeUnknown:
return STPLocalizedString(@"Unknown", @"Default missing source type label");
}
}


@end
23 changes: 12 additions & 11 deletions Tests/Tests/AlipaySource.json
@@ -1,3 +1,4 @@
// Source: https://stripe.com/docs/sources/alipay
{
"id": "src_123",
"object": "source",
Expand All @@ -8,19 +9,19 @@
"flow": "redirect",
"livemode": true,
"owner": {
"address": null,
"email": null,
"name": null,
"phone": null,
"verified_address": null,
"verified_email": null,
"verified_name": null,
"verified_phone": null,
"address": null,
"email": null,
"name": null,
"phone": null,
"verified_address": null,
"verified_email": null,
"verified_name": null,
"verified_phone": null,
},
"redirect": {
"return_url": "https://shop.foo.com/crtABC",
"status": "pending",
"url": "https://pay.stripe.com/redirect/src_123?client_secret=src_client_secret_123"
"return_url": "https://shop.foo.com/crtABC",
"status": "pending",
"url": "https://pay.stripe.com/redirect/src_123?client_secret=src_client_secret_123"
},
"statement_descriptor": null,
"status": "pending",
Expand Down
38 changes: 38 additions & 0 deletions Tests/Tests/BancontactSource.json
@@ -0,0 +1,38 @@
// Source: https://stripe.com/docs/sources/bancontact
{
"id": "src_16xhynE8WzK49JbAs9M21jaR",
"object": "source",
"amount": 1099,
"client_secret": "src_client_secret_UfwvW2WHpZ0s3QEn9g5x7waU",
"created": 1445277809,
"currency": "eur",
"statement_descriptor": null,
"flow": "redirect",
"livemode": true,
"owner": {
"address": null,
"email": null,
"name": "Jenny Rosen",
"phone": null,
"verified_address": null,
"verified_email": null,
"verified_name": "Jenny Rosen",
"verified_phone": null
},
"redirect": {
"return_url": "https://shop.example.com/crtA6B28E1",
"status": "pending",
"url": "https://pay.stripe.com/redirect/src_16xhynE8WzK49JbAs9M21jaR?client_secret=src_client_secret_UfwvW2WHpZ0s3QEn9g5x7waU"
},
"status": "pending",
"type": "bancontact",
"usage": "single_use",
"bancontact": {
"bank_code": null,
"bic": null,
"bank_name": null,
"iban_last4": null,
"statement_descriptor": null,
"preferred_language": null
}
}
1 change: 1 addition & 0 deletions Tests/Tests/CardSource.json
@@ -1,3 +1,4 @@
// Source: https://stripe.com/docs/sources/cards
{
"id": "src_123",
"object": "source",
Expand Down
34 changes: 34 additions & 0 deletions Tests/Tests/EPSSource.json
@@ -0,0 +1,34 @@
// Source: https://stripe.com/docs/sources/eps
{
"id": "src_16xhynE8WzK49JbAs9M21jaR",
"object": "source",
"amount": 1099,
"client_secret": "src_client_secret_UfwvW2WHpZ0s3QEn9g5x7waU",
"created": 1445277809,
"currency": "eur",
"flow": "redirect",
"livemode": true,
"owner": {
"address": null,
"email": null,
"name": "Jenny Rosen",
"phone": null,
"verified_address": null,
"verified_email": null,
"verified_name": "Jenny Rosen",
"verified_phone": null
},
"redirect": {
"return_url": "https://shop.example.com/crtA6B28E1",
"status": "pending",
"url": "https://pay.stripe.com/redirect/src_16xhynE8WzK49JbAs9M21jaR?client_secret=src_client_secret_UfwvW2WHpZ0s3QEn9g5x7waU"
},
"statement_descriptor": null,
"status": "pending",
"type": "eps",
"usage": "single_use",
"eps": {
"reference": null,
"statement_descriptor": null,
}
}

0 comments on commit df4fded

Please sign in to comment.