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 FPX offline status endpoint #1422

Merged
merged 9 commits into from
Oct 24, 2019
12 changes: 12 additions & 0 deletions Stripe.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,10 @@
0731329E2277ABF60019CE3F /* STPPinManagementService.m in Sources */ = {isa = PBXBuildFile; fileRef = 0731328E2277A3F60019CE3F /* STPPinManagementService.m */; };
0731329F227CFE410019CE3F /* STPIssuingCardPin.h in Headers */ = {isa = PBXBuildFile; fileRef = 073132932277A72D0019CE3F /* STPIssuingCardPin.h */; settings = {ATTRIBUTES = (Public, ); }; };
3142E72722FCC19800DDA097 /* STPFPXBankBrand.h in Headers */ = {isa = PBXBuildFile; fileRef = 31F5B33322FCAC4000A71C64 /* STPFPXBankBrand.h */; settings = {ATTRIBUTES = (Public, ); }; };
314F9CC0235E66920059E2F6 /* STPFPXBankStatusResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 314F9CBE235E66920059E2F6 /* STPFPXBankStatusResponse.h */; };
314F9CC1235E66920059E2F6 /* STPFPXBankStatusResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 314F9CBE235E66920059E2F6 /* STPFPXBankStatusResponse.h */; };
314F9CC2235E66920059E2F6 /* STPFPXBankStatusResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 314F9CBF235E66920059E2F6 /* STPFPXBankStatusResponse.m */; };
314F9CC3235E66920059E2F6 /* STPFPXBankStatusResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 314F9CBF235E66920059E2F6 /* STPFPXBankStatusResponse.m */; };
315CB85322E7BD0E00E612A3 /* libStripe3DS2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 315CB85222E7BD0D00E612A3 /* libStripe3DS2.a */; };
315CB85522E7BD1400E612A3 /* Stripe3DS2.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 315CB85422E7BD1400E612A3 /* Stripe3DS2.bundle */; };
315CB86222E7D13600E612A3 /* libStripe3DS2.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 315CB85222E7BD0D00E612A3 /* libStripe3DS2.a */; };
Expand Down Expand Up @@ -1594,6 +1598,8 @@
3142E72A22FCC26600DDA097 /* [email protected] */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "[email protected]"; sourceTree = "<group>"; };
3142E72B22FCC26600DDA097 /* [email protected] */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "[email protected]"; sourceTree = "<group>"; };
3142E72C22FCC26600DDA097 /* [email protected] */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "[email protected]"; sourceTree = "<group>"; };
314F9CBE235E66920059E2F6 /* STPFPXBankStatusResponse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = STPFPXBankStatusResponse.h; sourceTree = "<group>"; };
314F9CBF235E66920059E2F6 /* STPFPXBankStatusResponse.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPFPXBankStatusResponse.m; sourceTree = "<group>"; };
315CB85222E7BD0D00E612A3 /* libStripe3DS2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libStripe3DS2.a; path = InternalFrameworks/libStripe3DS2.a; sourceTree = "<group>"; };
315CB85422E7BD1400E612A3 /* Stripe3DS2.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = Stripe3DS2.bundle; path = ../InternalFrameworks/Stripe3DS2.bundle; sourceTree = "<group>"; };
315CB8A322E7D95E00E612A3 /* STDSChallengeStatusReceiver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = STDSChallengeStatusReceiver.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3037,6 +3043,8 @@
8B429ADD1EF9EFF600F95F34 /* STPFile+Private.h */,
04CDB4C41A5F30A700B854EE /* STPFormEncoder.h */,
04CDB4C51A5F30A700B854EE /* STPFormEncoder.m */,
314F9CBE235E66920059E2F6 /* STPFPXBankStatusResponse.h */,
314F9CBF235E66920059E2F6 /* STPFPXBankStatusResponse.m */,
B32B175C20F6D2C4000D6EF8 /* STPGenericStripeObject.h */,
B32B175D20F6D2C4000D6EF8 /* STPGenericStripeObject.m */,
36239BB022960D52004FB1A5 /* STPIntentAction+Private.h */,
Expand Down Expand Up @@ -3442,6 +3450,7 @@
04F94DD31D22A23F004FC826 /* NSBundle+Stripe_AppName.h in Headers */,
3604007C22C18DB3004CF80B /* STPThreeDSUICustomization.h in Headers */,
F1D3A25B1EB014BD0095BFA9 /* UIImage+Stripe.h in Headers */,
314F9CC1235E66920059E2F6 /* STPFPXBankStatusResponse.h in Headers */,
B6B41F8022348A1E0020BA7F /* STPPaymentMethodiDEALParams.h in Headers */,
319A609A22E9186B00AACF66 /* STDSTextFieldCustomization.h in Headers */,
3142E72722FCC19800DDA097 /* STPFPXBankBrand.h in Headers */,
Expand Down Expand Up @@ -3746,6 +3755,7 @@
049880FC1CED5A2300EA4FFD /* STPPaymentConfiguration.h in Headers */,
C15608DD1FE08F2E0032AE66 /* UIView+Stripe_SafeAreaBounds.h in Headers */,
3621DDCA22A5E4FD00281BC4 /* STPAuthenticationContext.h in Headers */,
314F9CC0235E66920059E2F6 /* STPFPXBankStatusResponse.h in Headers */,
F1852F931D80B6EC00367C86 /* STPStringUtils.h in Headers */,
B6A46F7622FCDB81001991B2 /* STPPaymentIntentLastPaymentError.h in Headers */,
049A3FAE1CC9AA9900F57DE7 /* STPAddressViewModel.h in Headers */,
Expand Down Expand Up @@ -4643,6 +4653,7 @@
04B31DE91D09D25F00EF1631 /* STPPaymentOptionsInternalViewController.m in Sources */,
F12C8DC51D63DE9F00ADA0D7 /* STPPaymentContextAmountModel.m in Sources */,
04633B011CD129CB009D4FB5 /* STPPhoneNumberValidator.m in Sources */,
314F9CC3235E66920059E2F6 /* STPFPXBankStatusResponse.m in Sources */,
F152322D1EA9306100D65C67 /* NSURLComponents+Stripe.m in Sources */,
C159933F1D88089B0047950D /* STPShippingMethodsViewController.m in Sources */,
0413CB27233FECD5006429EA /* STPPushProvisioningDetails.m in Sources */,
Expand Down Expand Up @@ -4811,6 +4822,7 @@
31B9609222FE128C00DC6FD9 /* STPBankSelectionViewController.m in Sources */,
B63E42762231D78D007B5B95 /* STPPaymentMethodCardParams.m in Sources */,
049A3FAF1CC9AA9900F57DE7 /* STPAddressViewModel.m in Sources */,
314F9CC2235E66920059E2F6 /* STPFPXBankStatusResponse.m in Sources */,
073132972277A72D0019CE3F /* STPIssuingCardPin.m in Sources */,
04695ADC1C77F9EF00E08063 /* STPPhoneNumberValidator.m in Sources */,
C1785F5E1EC60B5E00E9CFAC /* STPCardIOProxy.m in Sources */,
Expand Down
9 changes: 9 additions & 0 deletions Stripe/PublicHeaders/STPBlocks.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
@class STPSetupIntent;
@class STPPaymentMethod;
@class STPIssuingCardPin;
@class STPFPXBankStatusResponse;

/**
These values control the labels used in the shipping info collection form.
Expand Down Expand Up @@ -229,6 +230,14 @@ typedef void (^STPPinCompletionBlock)(STPIssuingCardPin * __nullable cardPin, ST
*/
typedef void (^STP3DS2AuthenticateCompletionBlock)(STP3DS2AuthenticateResponse * _Nullable authenticateResponse, NSError * _Nullable error);

/**
A callback to be run with a response from the Stripe API containing information about the online status of FPX banks.

@param bankStatusResponse The response from Stripe containing the status of the various banks. Will be nil if an error occurs. @see STPFPXBankStatusResponse
@param error The error returned from the response, or nil if none occurs.
*/
typedef void (^STPFPXBankStatusCompletionBlock)(STPFPXBankStatusResponse * _Nullable bankStatusResponse, NSError * _Nullable error);

/**
A block called with a payment status and an optional error.

Expand Down
17 changes: 14 additions & 3 deletions Stripe/PublicHeaders/STPFPXBankBrand.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ typedef NS_ENUM(NSInteger, STPFPXBankBrand) {
Returns a string representation for the provided bank brand;
i.e. `[NSString stringFromBrand:STPCardBrandUob] == @"UOB Bank"`.

@param brand the brand you want to convert to a string
@param brand The brand you want to convert to a string

@return A string representing the brand, suitable for displaying to a user.
*/
Expand All @@ -133,8 +133,19 @@ STPFPXBankBrand STPFPXBankBrandFromIdentifier(NSString *identifier);
Returns a string representation identifying the provided bank brand;
i.e. `STPIdentifierFromFPXBankBrand(STPCardBrandUob) == @"uob"`.

@param brand the brand you want to convert to a string
@param brand The brand you want to convert to a string

@return A string representing the brand, suitable for using with the service.
@return A string representing the brand, suitable for using with the Stripe API.
*/
NSString * STPIdentifierFromFPXBankBrand(STPFPXBankBrand brand);

/**
Returns the code identifying the provided bank brand in the FPX status API;
i.e. `STPIdentifierFromFPXBankBrand(STPCardBrandUob) == @"UOB0226"`.

@param brand The brand you want to convert to an FPX bank code
@param isBusiness Requests the code for the business version of this bank brand, which may be different from the code used for individual accounts

@return A string representing the brand, suitable for checking against the FPX status API.
*/
NSString * STPBankCodeFromFPXBankBrand(STPFPXBankBrand brand, BOOL isBusiness);
12 changes: 12 additions & 0 deletions Stripe/STPAPIClient+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,4 +166,16 @@ fromCustomerUsingKey:(STPEphemeralKey *)ephemeralKey
+ (NSArray<NSString *> *)supportedPKPaymentNetworks;

@end

@interface STPAPIClient (FPXPrivate)

/**
Retrieves the online status of the FPX banks from the Stripe API.

@param completion The callback to run with the returned FPX bank list, or an error.
*/
- (void)retrieveFPXBankStatusWithCompletion:(STPFPXBankStatusCompletionBlock)completion;

@end

NS_ASSUME_NONNULL_END
14 changes: 14 additions & 0 deletions Stripe/STPAPIClient.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#import "STPEmptyStripeResponse.h"
#import "STPEphemeralKey.h"
#import "STPFormEncoder.h"
#import "STPFPXBankStatusResponse.h"
#import "STPGenericStripeObject.h"
#import "STPAppInfo.h"
#import "STPMultipartFormDataEncoder.h"
Expand Down Expand Up @@ -61,6 +62,7 @@
static NSString * const APIEndpointSetupIntents = @"setup_intents";
static NSString * const APIEndpointPaymentMethods = @"payment_methods";
static NSString * const APIEndpoint3DS2 = @"3ds2";
static NSString * const APIEndpointFPXStatus = @"fpx/bank_statuses";

#pragma mark - Stripe

Expand Down Expand Up @@ -813,4 +815,16 @@ - (void)createPaymentMethodWithParams:(STPPaymentMethodParams *)paymentMethodPar

}

#pragma mark - FPX

- (void)retrieveFPXBankStatusWithCompletion:(STPFPXBankStatusCompletionBlock)completion {
[STPAPIRequest<STPFPXBankStatusResponse *> getWithAPIClient:self
Copy link
Contributor

Choose a reason for hiding this comment

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

ooc, does this handle errors/exceptions?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, I don't think there's anything useful we could do with such an error. We could log them to the console, I guess.

Copy link
Contributor

Choose a reason for hiding this comment

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

it does in the sense that we will generate an error if the response is not parseable for instance

Copy link
Contributor Author

@davidme-stripe davidme-stripe Oct 23, 2019

Choose a reason for hiding this comment

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

I can't determine if we have any standardized way to communicate these sort of errors up to developers. retrieveFPXBankStatusWithCompletion will return an error to the completion block if the response isn't parseable, but the BankSelectionViewController can't do anything sensible with that other than silently failing. We could NSLog() a warning, but we don't have any precedent for that.

endpoint:APIEndpointFPXStatus
parameters:@{ @"account_holder_type": @"individual" }
deserializer:[STPFPXBankStatusResponse new]
completion:^(STPFPXBankStatusResponse *statusResponse, __unused NSHTTPURLResponse *response, NSError *error) {
completion(statusResponse, error);
}];
}

@end
2 changes: 1 addition & 1 deletion Stripe/STPBankSelectionTableViewCell.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ NS_ASSUME_NONNULL_BEGIN

@interface STPBankSelectionTableViewCell : UITableViewCell

- (void)configureWithBank:(STPFPXBankBrand)bankBrand theme:(STPTheme *)theme selected:(BOOL)selected enabled:(BOOL)enabled;
- (void)configureWithBank:(STPFPXBankBrand)bankBrand theme:(STPTheme *)theme selected:(BOOL)selected offline:(BOOL)offline enabled:(BOOL)enabled;

@end

Expand Down
7 changes: 6 additions & 1 deletion Stripe/STPBankSelectionTableViewCell.m
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#import "STPCard.h"
#import "STPImageLibrary+Private.h"
#import "STPSource.h"
#import "STPLocalizationUtils.h"
#import "STPTheme.h"

@interface STPBankSelectionTableViewCell ()
Expand Down Expand Up @@ -82,7 +83,7 @@ - (void)layoutSubviews {
self.titleLabel.frame = labelFrame;
}

- (void)configureWithBank:(STPFPXBankBrand)bankBrand theme:(STPTheme *)theme selected:(BOOL)selected enabled:(BOOL)enabled {
- (void)configureWithBank:(STPFPXBankBrand)bankBrand theme:(STPTheme *)theme selected:(BOOL)selected offline:(BOOL)offline enabled:(BOOL)enabled {
self.bank = bankBrand;
self.theme = theme;

Expand All @@ -95,6 +96,10 @@ - (void)configureWithBank:(STPFPXBankBrand)bankBrand theme:(STPTheme *)theme sel
// Title label
self.titleLabel.font = theme.font;
self.titleLabel.text = STPStringFromFPXBankBrand(self.bank);
if (offline) {
self.titleLabel.text = [self.titleLabel.text stringByAppendingString:@" - "];
davidme-stripe marked this conversation as resolved.
Show resolved Hide resolved
self.titleLabel.text = [self.titleLabel.text stringByAppendingString:STPLocalizedString(@"Offline", @"Appended to bank name when bank is offline for maintenance.")];
}
self.titleLabel.textColor = [self primaryColorForPaymentOptionWithSelected:self.selected enabled:enabled];

// Loading indicator
Expand Down
30 changes: 29 additions & 1 deletion Stripe/STPBankSelectionViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#import "NSArray+Stripe.h"
#import "STPAPIClient+Private.h"
#import "STPFPXBankStatusResponse.h"
#import "STPColorUtils.h"
#import "STPCoreTableViewController+Private.h"
#import "STPDispatchFunctions.h"
Expand All @@ -34,6 +35,7 @@ @interface STPBankSelectionViewController () <UITableViewDataSource, UITableView
@property (nonatomic, weak) UIImageView *imageView;
@property (nonatomic) STPSectionHeaderView *headerView;
@property (nonatomic) BOOL loading;
@property (nonatomic) STPFPXBankStatusResponse *bankStatus;
@end

@implementation STPBankSelectionViewController
Expand All @@ -52,11 +54,27 @@ - (instancetype)initWithBankMethod:(STPBankSelectionMethod)bankMethod
_configuration = configuration;
_selectedBank = STPFPXBankBrandUnknown;
_apiClient = [[STPAPIClient alloc] initWithConfiguration:configuration];
if (bankMethod == STPBankSelectionMethodFPX) {
[self refreshFPXStatus];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshFPXStatus) name:UIApplicationDidBecomeActiveNotification object:nil];
}
self.title = STPLocalizedString(@"Bank Account", @"Title for bank account selector");
}
return self;
}

- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)refreshFPXStatus {
davidme-stripe marked this conversation as resolved.
Show resolved Hide resolved
[self.apiClient retrieveFPXBankStatusWithCompletion:^(STPFPXBankStatusResponse * _Nullable bankStatusResponse, NSError * _Nullable error) {
if (error == nil && bankStatusResponse != nil) {
[self updateWithBankStatus:bankStatusResponse];
}
}];
}

- (void)createAndSetupViews {
[super createAndSetupViews];

Expand All @@ -76,6 +94,12 @@ - (BOOL)useSystemBackButton {
return YES;
}

- (void)updateWithBankStatus:(STPFPXBankStatusResponse *)bankStatusResponse {
davidme-stripe marked this conversation as resolved.
Show resolved Hide resolved
self.bankStatus = bankStatusResponse;

[self.tableView reloadData];
davidme-stripe marked this conversation as resolved.
Show resolved Hide resolved
}

#pragma mark - UITableView

- (NSInteger)numberOfSectionsInTableView:(__unused UITableView *)tableView {
Expand All @@ -91,7 +115,11 @@ - (UITableViewCell *)tableView:(UITableView *)tableView
STPBankSelectionTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:STPBankSelectionCellReuseIdentifier forIndexPath:indexPath];
STPFPXBankBrand bankBrand = indexPath.row;
BOOL selected = self.selectedBank == bankBrand;
[cell configureWithBank:bankBrand theme:self.theme selected:selected enabled:!self.loading];
BOOL offline = NO;
if (self.bankStatus && ![self.bankStatus bankBrandIsOnline:bankBrand]) {
davidme-stripe marked this conversation as resolved.
Show resolved Hide resolved
offline = YES;
}
[cell configureWithBank:bankBrand theme:self.theme selected:selected offline:offline enabled:!self.loading];
return cell;
}

Expand Down
97 changes: 97 additions & 0 deletions Stripe/STPFPXBankBrand.m
Original file line number Diff line number Diff line change
Expand Up @@ -152,3 +152,100 @@ STPFPXBankBrand STPFPXBankBrandFromIdentifier(NSString *identifier) {
return @"unknown";
}
}

NSString * STPBankCodeFromFPXBankBrand(STPFPXBankBrand brand, BOOL isBusiness) {
switch (brand) {
case STPFPXBankBrandAffinBank:
if (isBusiness)
return @"ABB0232";
else
return @"ABB0233";
case STPFPXBankBrandAllianceBank:
if (isBusiness)
return @"ABMB0213";
else
return @"ABMB0212";
case STPFPXBankBrandAmbank:
if (isBusiness)
return @"AMBB0208";
else
return @"AMBB0209";
case STPFPXBankBrandBankIslam:
if (isBusiness)
return nil;
else
return @"BIMB0340";
case STPFPXBankBrandBankMuamalat:
if (isBusiness)
return @"BMMB0342";
else
return @"BMMB0341";
case STPFPXBankBrandBankRakyat:
if (isBusiness)
return @"BKRM0602";
else
return @"BKRM0602";
case STPFPXBankBrandBSN:
if (isBusiness)
return nil;
else
return @"BSN0601";
case STPFPXBankBrandCIMB:
if (isBusiness)
return @"BCBB0235";
else
return @"BCBB0235";
case STPFPXBankBrandHongLeongBank:
if (isBusiness)
return @"HLB0224";
else
return @"HLB0224";
case STPFPXBankBrandHSBC:
if (isBusiness)
return @"HSBC0223";
else
return @"HSBC0223";
case STPFPXBankBrandKFH:
if (isBusiness)
return @"KFH0346";
else
return @"KFH0346";
case STPFPXBankBrandMaybank2E:
if (isBusiness)
return @"MBB0228";
else
return @"MBB0228";
case STPFPXBankBrandMaybank2U:
if (isBusiness)
return nil;
else
return @"MB2U0227";
case STPFPXBankBrandOcbc:
if (isBusiness)
return @"OCBC0229";
else
return @"OCBC0229";
case STPFPXBankBrandPublicBank:
if (isBusiness)
return @"PBB0233";
else
return @"PBB0233";
case STPFPXBankBrandRHB:
if (isBusiness)
return @"RHB0218";
else
return @"RHB0218";
case STPFPXBankBrandStandardChartered:
if (isBusiness)
return @"SCB0215";
else
return @"SCB0216";
case STPFPXBankBrandUOB:
if (isBusiness)
return @"UOB0227";
else
return @"UOB0226";
case STPFPXBankBrandUnknown:
return @"unknown";
}
}
22 changes: 22 additions & 0 deletions Stripe/STPFPXBankStatusResponse.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//
// STPFPXBankStatusResponse.h
// Stripe
//
// Created by David Estes on 10/21/19.
// Copyright © 2019 Stripe, Inc. All rights reserved.
//

#import <Foundation/Foundation.h>

#import "STPAPIResponseDecodable.h"
#import "STPFPXBankBrand.h"

NS_ASSUME_NONNULL_BEGIN

@interface STPFPXBankStatusResponse : NSObject <STPAPIResponseDecodable>

- (BOOL)bankBrandIsOnline:(STPFPXBankBrand)bankBrand;

@end

NS_ASSUME_NONNULL_END
Loading