Merge pull request #697 from stripe/bg-customer-shipping
Retrieve and update customer.shipping info via ephemeral key
This commit is contained in:
commit
74bf34c7d6
|
@ -176,7 +176,10 @@ class CheckoutViewController: UIViewController, STPPaymentContextDelegate {
|
|||
// MARK: STPPaymentContextDelegate
|
||||
|
||||
func paymentContext(_ paymentContext: STPPaymentContext, didCreatePaymentResult paymentResult: STPPaymentResult, completion: @escaping STPErrorBlock) {
|
||||
MyAPIClient.sharedClient.completeCharge(paymentResult, amount: self.paymentContext.paymentAmount,
|
||||
MyAPIClient.sharedClient.completeCharge(paymentResult,
|
||||
amount: self.paymentContext.paymentAmount,
|
||||
shippingAddress: self.paymentContext.shippingAddress,
|
||||
shippingMethod: self.paymentContext.selectedShippingMethod,
|
||||
completion: completion)
|
||||
}
|
||||
|
||||
|
|
|
@ -22,12 +22,18 @@ class MyAPIClient: NSObject, STPEphemeralKeyProvider {
|
|||
}
|
||||
}
|
||||
|
||||
func completeCharge(_ result: STPPaymentResult, amount: Int, completion: @escaping STPErrorBlock) {
|
||||
func completeCharge(_ result: STPPaymentResult,
|
||||
amount: Int,
|
||||
shippingAddress: STPAddress?,
|
||||
shippingMethod: PKShippingMethod?,
|
||||
completion: @escaping STPErrorBlock) {
|
||||
let url = self.baseURL.appendingPathComponent("charge")
|
||||
Alamofire.request(url, method: .post, parameters: [
|
||||
var params: [String: Any] = [
|
||||
"source": result.source.stripeID,
|
||||
"amount": amount
|
||||
])
|
||||
]
|
||||
params["shipping"] = STPAddress.shippingInfoForCharge(with: shippingAddress, shippingMethod: shippingMethod)
|
||||
Alamofire.request(url, method: .post, parameters: params)
|
||||
.validate(statusCode: 200..<300)
|
||||
.responseString { response in
|
||||
switch response.result {
|
||||
|
@ -42,7 +48,7 @@ class MyAPIClient: NSObject, STPEphemeralKeyProvider {
|
|||
func createCustomerKey(withAPIVersion apiVersion: String, completion: @escaping STPJSONResponseCompletionBlock) {
|
||||
let url = self.baseURL.appendingPathComponent("ephemeral_keys")
|
||||
Alamofire.request(url, method: .post, parameters: [
|
||||
"api_version": apiVersion
|
||||
"api_version": apiVersion,
|
||||
])
|
||||
.validate(statusCode: 200..<300)
|
||||
.responseJSON { responseJSON in
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
4. Instead of using the initializers for `STPPaymentContext` or `STPPaymentMethodsViewController` that take an `STPBackendAPIAdapter` parameter, you should use the new initializers that take an `STPCustomerContext` parameter. You'll need to set up your instance of `STPCustomerContext` using the key provider you set up in (2).
|
||||
- For a more detailed overview of the new integration, you can refer to our tutorial at https://stripe.com/docs/mobile/ios/standard
|
||||
- Fixed nullability annotation for `[STPFile stringFromPurpose:]` which returns `nil` for `STPFilePurposeUnknown`. Will return a non-nil value for all other `STPFilePurpose`.
|
||||
- We've removed the `email` and `phone` properties in `STPUserInformation`. You can now pre-fill this information in the shipping form using the new `shippingAddress` property.
|
||||
|
||||
### Migrating from versions < 10.2.0
|
||||
- `paymentRequestWithMerchantIdentifier:` has been deprecated. You should instead use `paymentRequestWithMerchantIdentifier:country:currency:`. Apple Pay is now available in many countries and currencies, and you should use the appropriate values for your business.
|
||||
|
|
|
@ -485,6 +485,8 @@
|
|||
C15993471D8829C00047950D /* stp_shipping_form@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = C15993221D8807930047950D /* stp_shipping_form@3x.png */; };
|
||||
C15B02731EA176090026E606 /* StripeErrorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = C15B02721EA176090026E606 /* StripeErrorTest.m */; };
|
||||
C16F66AB1CA21BAC006A21B5 /* STPFormTextFieldTest.m in Sources */ = {isa = PBXBuildFile; fileRef = C16F66AA1CA21BAC006A21B5 /* STPFormTextFieldTest.m */; };
|
||||
C16FC79D1EEB39C3001CBD3A /* STPCustomerContext+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = C16FC79C1EEB39C3001CBD3A /* STPCustomerContext+Private.h */; };
|
||||
C16FC79E1EEB39C3001CBD3A /* STPCustomerContext+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = C16FC79C1EEB39C3001CBD3A /* STPCustomerContext+Private.h */; };
|
||||
C1717DB11CC00ED60009CF4A /* STPAddress.h in Headers */ = {isa = PBXBuildFile; fileRef = C1080F471CBECF7B007B2D89 /* STPAddress.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C1785F5C1EC60B5E00E9CFAC /* STPCardIOProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = C1785F5A1EC60B5E00E9CFAC /* STPCardIOProxy.h */; };
|
||||
C1785F5D1EC60B5E00E9CFAC /* STPCardIOProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = C1785F5A1EC60B5E00E9CFAC /* STPCardIOProxy.h */; };
|
||||
|
@ -518,6 +520,8 @@
|
|||
C19D09931EAEAE5E00A4AB3E /* STPTelemetryClientTest.m in Sources */ = {isa = PBXBuildFile; fileRef = C19D09911EAEAE5200A4AB3E /* STPTelemetryClientTest.m */; };
|
||||
C1A06F101E1D8A7F004DCA06 /* STPCard+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = C1A06F0F1E1D8A6E004DCA06 /* STPCard+Private.h */; };
|
||||
C1A06F111E1D8A7F004DCA06 /* STPCard+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = C1A06F0F1E1D8A6E004DCA06 /* STPCard+Private.h */; };
|
||||
C1A5E5F41ED3A71C00C79B0F /* StripeError+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = C1A5E5F31ED3A71C00C79B0F /* StripeError+Private.h */; };
|
||||
C1A5E5F51ED3A71C00C79B0F /* StripeError+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = C1A5E5F31ED3A71C00C79B0F /* StripeError+Private.h */; };
|
||||
C1AED1561EE0C8C6008BEFBF /* STPApplePayTest.m in Sources */ = {isa = PBXBuildFile; fileRef = C1AED1551EE0C8C6008BEFBF /* STPApplePayTest.m */; };
|
||||
C1B630BB1D1D860100A05285 /* stp_card_amex.png in Resources */ = {isa = PBXBuildFile; fileRef = 0438EF891B741C2800D506CC /* stp_card_amex.png */; };
|
||||
C1B630BC1D1D860100A05285 /* stp_card_amex@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 0438EF8A1B741C2800D506CC /* stp_card_amex@2x.png */; };
|
||||
|
@ -1101,6 +1105,7 @@
|
|||
C16F66AA1CA21BAC006A21B5 /* STPFormTextFieldTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPFormTextFieldTest.m; sourceTree = "<group>"; };
|
||||
C1785F5A1EC60B5E00E9CFAC /* STPCardIOProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPCardIOProxy.h; sourceTree = "<group>"; };
|
||||
C1785F5B1EC60B5E00E9CFAC /* STPCardIOProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPCardIOProxy.m; sourceTree = "<group>"; };
|
||||
C16FC79C1EEB39C3001CBD3A /* STPCustomerContext+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "STPCustomerContext+Private.h"; sourceTree = "<group>"; };
|
||||
C17A030B1CBEE7A2006C819F /* STPAddressFieldTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STPAddressFieldTableViewCell.h; sourceTree = "<group>"; };
|
||||
C17A030C1CBEE7A2006C819F /* STPAddressFieldTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPAddressFieldTableViewCell.m; sourceTree = "<group>"; };
|
||||
C17D24ED1E37DBAC005CB188 /* STPSourceTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPSourceTest.m; sourceTree = "<group>"; };
|
||||
|
@ -1118,6 +1123,7 @@
|
|||
C19D098E1EAEAE4000A4AB3E /* STPTelemetryClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPTelemetryClient.m; sourceTree = "<group>"; };
|
||||
C19D09911EAEAE5200A4AB3E /* STPTelemetryClientTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPTelemetryClientTest.m; sourceTree = "<group>"; };
|
||||
C1A06F0F1E1D8A6E004DCA06 /* STPCard+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "STPCard+Private.h"; sourceTree = "<group>"; };
|
||||
C1A5E5F31ED3A71C00C79B0F /* StripeError+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "StripeError+Private.h"; sourceTree = "<group>"; };
|
||||
C1AED1551EE0C8C6008BEFBF /* STPApplePayTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPApplePayTest.m; sourceTree = "<group>"; };
|
||||
C1B630B31D1D817900A05285 /* Stripe.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Stripe.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
C1B630B51D1D817900A05285 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
|
@ -1682,6 +1688,8 @@
|
|||
04A4C3881C4F25F900B3B290 /* UIViewController+Stripe_ParentViewController.m */,
|
||||
045D711E1CEFA57000F6CD65 /* UIViewController+Stripe_Promises.h */,
|
||||
045D711F1CEFA57000F6CD65 /* UIViewController+Stripe_Promises.m */,
|
||||
C1A5E5F31ED3A71C00C79B0F /* StripeError+Private.h */,
|
||||
C1C1B6E71EFC05F800BD1A36 /* StripeError+Private.m */,
|
||||
);
|
||||
name = Categories;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1837,7 +1845,6 @@
|
|||
04BC29B41CD9AE0000318357 /* STPCheckoutBootstrapResponse.m */,
|
||||
F1D3A2631EBA5BAE0095BFA9 /* STPPaymentCardTextField+Private.h */,
|
||||
04B31DD81D09A4DC00EF1631 /* STPPaymentConfiguration+Private.h */,
|
||||
04E39F5A1CECFAFD00AF3B96 /* STPPaymentContext+Private.h */,
|
||||
F12C8DBE1D63DE9F00ADA0D7 /* STPPaymentContextAmountModel.h */,
|
||||
F12C8DBF1D63DE9F00ADA0D7 /* STPPaymentContextAmountModel.m */,
|
||||
04E39F501CECF7A100AF3B96 /* STPPaymentMethodTuple.h */,
|
||||
|
@ -1870,6 +1877,8 @@
|
|||
F1728CF41EAAA457002E0C29 /* PaymentContext */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
04E39F5A1CECFAFD00AF3B96 /* STPPaymentContext+Private.h */,
|
||||
C16FC79C1EEB39C3001CBD3A /* STPCustomerContext+Private.h */,
|
||||
);
|
||||
name = PaymentContext;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2083,6 +2092,7 @@
|
|||
C1A06F111E1D8A7F004DCA06 /* STPCard+Private.h in Headers */,
|
||||
04F94DBA1D229F8A004FC826 /* PKPaymentAuthorizationViewController+Stripe_Blocks.h in Headers */,
|
||||
04F94DD31D22A23F004FC826 /* NSBundle+Stripe_AppName.h in Headers */,
|
||||
C1A5E5F51ED3A71C00C79B0F /* StripeError+Private.h in Headers */,
|
||||
F1D3A25B1EB014BD0095BFA9 /* UIImage+Stripe.h in Headers */,
|
||||
04F94DC31D22A1F7004FC826 /* STPCheckoutAccount.h in Headers */,
|
||||
F1852F941D80B6EC00367C86 /* STPStringUtils.h in Headers */,
|
||||
|
@ -2119,6 +2129,7 @@
|
|||
04F94DA51D229F21004FC826 /* STPPaymentContext+Private.h in Headers */,
|
||||
F12829DB1D7747E4008B10D6 /* STPBundleLocator.h in Headers */,
|
||||
8BD87B891EFB131800269C2B /* STPSourceCardDetails+Private.h in Headers */,
|
||||
C16FC79E1EEB39C3001CBD3A /* STPCustomerContext+Private.h in Headers */,
|
||||
04827D161D257764002DB3E8 /* STPImageLibrary+Private.h in Headers */,
|
||||
049E84EC1A605EF0000B66CD /* StripeError.h in Headers */,
|
||||
046FE9A31CE5608000DA6A7B /* STPPaymentActivityIndicatorView.h in Headers */,
|
||||
|
@ -2258,6 +2269,7 @@
|
|||
04BC29C21CE2A48000318357 /* STPSMSCodeViewController.h in Headers */,
|
||||
C11810891CC6B00D0022FB55 /* STPApplePayPaymentMethod.h in Headers */,
|
||||
0426B9721CEAE3EB006AC8DD /* UITableViewCell+Stripe_Borders.h in Headers */,
|
||||
C1A5E5F41ED3A71C00C79B0F /* StripeError+Private.h in Headers */,
|
||||
04CDE5C91BC20B1D00548833 /* STPBankAccountParams.h in Headers */,
|
||||
049A3F891CC73C7100F57DE7 /* STPPaymentContext.h in Headers */,
|
||||
04E39F541CECF7A100AF3B96 /* STPPaymentMethodTuple.h in Headers */,
|
||||
|
@ -2307,6 +2319,7 @@
|
|||
04B31DE61D09D25F00EF1631 /* STPPaymentMethodsInternalViewController.h in Headers */,
|
||||
04CDB4FE1A5F30A700B854EE /* STPAPIClient.h in Headers */,
|
||||
045D712C1CF4ED7600F6CD65 /* STPBINRange.h in Headers */,
|
||||
C16FC79D1EEB39C3001CBD3A /* STPCustomerContext+Private.h in Headers */,
|
||||
C1D7B51A1E36B8B9002181F5 /* STPSourceParams.h in Headers */,
|
||||
04827D101D2575C6002DB3E8 /* STPImageLibrary.h in Headers */,
|
||||
F152322A1EA9306100D65C67 /* NSURLComponents+Stripe.h in Headers */,
|
||||
|
@ -2823,6 +2836,7 @@
|
|||
04F94DA21D229F14004FC826 /* STPAddressFieldTableViewCell.m in Sources */,
|
||||
049A3FB71CCA6B8900F57DE7 /* STPAddress.m in Sources */,
|
||||
04F94DD41D22A242004FC826 /* NSBundle+Stripe_AppName.m in Sources */,
|
||||
C1C1B6E91EFC05F800BD1A36 /* StripeError+Private.m in Sources */,
|
||||
F152321E1EA92FC100D65C67 /* STPRedirectContext.m in Sources */,
|
||||
C126553A1CAA2392006F7265 /* STPAddCardViewController.m in Sources */,
|
||||
04633B151CD4521F009D4FB5 /* STPAPIClient+ApplePay.m in Sources */,
|
||||
|
@ -2968,6 +2982,7 @@
|
|||
F15232261EA9303800D65C67 /* STPURLCallbackHandler.m in Sources */,
|
||||
049952D01BCF13510088C703 /* STPAPIRequest.m in Sources */,
|
||||
F1D3A24B1EB012010095BFA9 /* STPFile.m in Sources */,
|
||||
C1C1B6E81EFC05F800BD1A36 /* StripeError+Private.m in Sources */,
|
||||
049A3F9A1CC76A2400F57DE7 /* NSBundle+Stripe_AppName.m in Sources */,
|
||||
049A3F7B1CC18D5300F57DE7 /* UIView+Stripe_FirstResponder.m in Sources */,
|
||||
04CDE5C51BC20AF800548833 /* STPBankAccountParams.m in Sources */,
|
||||
|
|
|
@ -94,6 +94,19 @@ typedef NS_ENUM(NSUInteger, STPBillingAddressFields) {
|
|||
*/
|
||||
@property (nonatomic, copy, nullable) NSString *email;
|
||||
|
||||
/**
|
||||
* When creating a charge on your backend, you can attach shipping information
|
||||
* to prevent fraud on a physical good. You can use this method to turn your user's
|
||||
* shipping address and selected shipping method into a hash suitable for attaching
|
||||
* to a charge. You should pass this to your backend, and use it as the `shipping`
|
||||
* parameter when creating a charge.
|
||||
* @see https://stripe.com/docs/api#create_charge-shipping
|
||||
*
|
||||
* @param address The user's shipping address. If nil, this method will return nil.
|
||||
* @param method The user's selected shipping method. May be nil.
|
||||
*/
|
||||
+ (NSDictionary *)shippingInfoForChargeWithAddress:(nullable STPAddress *)address
|
||||
shippingMethod:(nullable PKShippingMethod *)method;
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated"
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#import "STPAPIResponseDecodable.h"
|
||||
#import "STPSourceProtocol.h"
|
||||
|
||||
@class STPAddress;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
|
@ -50,6 +52,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
@property(nonatomic, readonly) NSArray<id<STPSourceProtocol>> *sources;
|
||||
|
||||
/**
|
||||
* The customer's shipping address.
|
||||
*/
|
||||
@property(nonatomic, readonly) STPAddress *shippingAddress;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
|
|
|
@ -46,10 +46,16 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@property(nonatomic)STPBillingAddressFields requiredBillingAddressFields;
|
||||
|
||||
/**
|
||||
* The billing address fields the user must fill out when prompted for their shipping info.
|
||||
* The shipping address fields the user must fill out when prompted for their shipping info.
|
||||
*/
|
||||
@property(nonatomic)PKAddressField requiredShippingAddressFields;
|
||||
|
||||
/**
|
||||
* Whether the user should be prompted to verify prefilled shipping information.
|
||||
* The default value is YES.
|
||||
*/
|
||||
@property(nonatomic)BOOL verifyPrefilledShippingAddress;
|
||||
|
||||
/**
|
||||
* The type of shipping for this purchase. This property sets the labels displayed when the user is prompted for shipping info, and whether they should also be asked to select a shipping method. The default value is STPShippingTypeShipping.
|
||||
*/
|
||||
|
|
|
@ -148,6 +148,25 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
/**
|
||||
* The user's shipping address. May be nil.
|
||||
* If you've already collected a shipping address from your user, you may
|
||||
* prefill it by setting a shippingAddress in PaymentContext's prefilledInformation.
|
||||
* When your user enters a new shipping address, PaymentContext will save it to
|
||||
* the current customer object. When PaymentContext loads, if you haven't
|
||||
* manually set a prefilled value, any shipping information saved on the customer
|
||||
* will be used to prefill the shipping address form. Note that because your
|
||||
* customer's email may not be the same as the email provided with their shipping
|
||||
* info, PaymentContext will not prefill the shipping form's email using your
|
||||
* customer's email.
|
||||
*
|
||||
* You should not rely on the shipping information stored on the Stripe customer
|
||||
* for order fulfillment, as your user may change this information if they make
|
||||
* multiple purchases. We recommend adding shipping information when you create
|
||||
* a charge (which can also help prevent fraud), or saving it to your own
|
||||
* database. https://stripe.com/docs/api#create_charge-shipping
|
||||
*
|
||||
* Note: by default, your user will still be prompted to verify a prefilled
|
||||
* shipping address. To change this behavior, you can set
|
||||
* `verifyPrefilledShippingAddress` to NO in your `STPPaymentConfiguration`.
|
||||
*/
|
||||
@property(nonatomic, readonly, nullable)STPAddress *shippingAddress;
|
||||
|
||||
|
|
|
@ -12,26 +12,27 @@
|
|||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* You can use this class to specify information that you've already collected from your user. You can then set the `prefilledInformation` property on `STPPaymentContext`, `STPAddCardViewController`, etc and it will pre-fill this information whenever possible.
|
||||
* You can use this class to specify information that you've already collected
|
||||
* from your user. You can then set the `prefilledInformation` property on
|
||||
* `STPPaymentContext`, `STPAddCardViewController`, etc and it will pre-fill
|
||||
* this information whenever possible.
|
||||
*/
|
||||
@interface STPUserInformation : NSObject<NSCopying>
|
||||
|
||||
/**
|
||||
* The user's email address.
|
||||
*/
|
||||
@property(nonatomic, copy, nullable)NSString *email;
|
||||
|
||||
/**
|
||||
* The user's phone number. When set, this property will automatically strip out any non-numeric characters from the string you specify.
|
||||
*/
|
||||
@property(nonatomic, copy, nullable)NSString *phone;
|
||||
|
||||
/**
|
||||
* The user's billing address. When set, the add card form will be filled with this address.
|
||||
* The user will also have the option to fill their shipping address using this address.
|
||||
* The user's billing address. When set, the add card form will be filled with
|
||||
* this address. The user will also have the option to fill their shipping address
|
||||
* using this address.
|
||||
*/
|
||||
@property(nonatomic, strong, nullable)STPAddress *billingAddress;
|
||||
|
||||
/**
|
||||
* The user's shipping address. When set, the shipping address form will be filled
|
||||
* with this address. The user will also have the option to fill their billing
|
||||
* address using this address.
|
||||
*/
|
||||
@property(nonatomic, strong, nullable)STPAddress *shippingAddress;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -135,10 +135,7 @@ typedef NS_ENUM(NSUInteger, STPPaymentCardSection) {
|
|||
self.cardImageView = cardImageView;
|
||||
self.tableView.tableHeaderView = cardImageView;
|
||||
self.emailCell = [[STPRememberMeEmailCell alloc] initWithDelegate:self];
|
||||
if ([STPEmailAddressValidator stringIsValidEmailAddress:self.prefilledInformation.email]) {
|
||||
self.emailCell.contents = self.prefilledInformation.email;
|
||||
}
|
||||
|
||||
|
||||
STPRememberMePaymentCell *paymentCell = [[STPRememberMePaymentCell alloc] init];
|
||||
paymentCell.paymentField.delegate = self;
|
||||
self.paymentCell = paymentCell;
|
||||
|
@ -154,7 +151,6 @@ typedef NS_ENUM(NSUInteger, STPPaymentCardSection) {
|
|||
|
||||
self.rememberMePhoneCell = [[STPAddressFieldTableViewCell alloc] initWithType:STPAddressFieldTypePhone contents:nil lastInList:YES delegate:self];
|
||||
self.rememberMePhoneCell.caption = STPLocalizedString(@"Phone", nil);
|
||||
self.rememberMePhoneCell.contents = self.prefilledInformation.phone;
|
||||
|
||||
self.rememberMeTermsView = [STPRememberMeTermsView new];
|
||||
self.rememberMeTermsView.textView.alpha = 0;
|
||||
|
|
|
@ -29,6 +29,26 @@ NSString *stringIfHasContentsElseNil(NSString *string);
|
|||
|
||||
@implementation STPAddress
|
||||
|
||||
+ (NSDictionary *)shippingInfoForChargeWithAddress:(nullable STPAddress *)address
|
||||
shippingMethod:(nullable PKShippingMethod *)method {
|
||||
if (!address) {
|
||||
return nil;
|
||||
}
|
||||
NSMutableDictionary *params = [NSMutableDictionary new];
|
||||
params[@"name"] = address.name;
|
||||
params[@"phone"] = address.phone;
|
||||
params[@"carrier"] = method.label;
|
||||
NSMutableDictionary *addressDict = [NSMutableDictionary new];
|
||||
addressDict[@"line1"] = address.line1;
|
||||
addressDict[@"line2"] = address.line2;
|
||||
addressDict[@"city"] = address.city;
|
||||
addressDict[@"state"] = address.state;
|
||||
addressDict[@"postal_code"] = address.postalCode;
|
||||
addressDict[@"country"] = address.country;
|
||||
params[@"address"] = [addressDict copy];
|
||||
return [params copy];
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated"
|
||||
|
||||
|
|
|
@ -8,15 +8,18 @@
|
|||
|
||||
#import "STPCustomer.h"
|
||||
|
||||
#import "STPAddress.h"
|
||||
#import "STPCard.h"
|
||||
#import "STPSource.h"
|
||||
#import "StripeError.h"
|
||||
#import "NSDictionary+Stripe.h"
|
||||
|
||||
@interface STPCustomer()
|
||||
|
||||
@property(nonatomic, copy)NSString *stripeID;
|
||||
@property(nonatomic) id<STPSourceProtocol> defaultSource;
|
||||
@property(nonatomic) NSArray<id<STPSourceProtocol>> *sources;
|
||||
@property(nonatomic) STPAddress *shippingAddress;
|
||||
@property (nonatomic, readwrite, nonnull, copy) NSDictionary *allResponseFields;
|
||||
|
||||
@end
|
||||
|
@ -57,16 +60,69 @@
|
|||
return @[@"id"];
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated"
|
||||
+ (instancetype)decodedObjectFromAPIResponse:(NSDictionary *)response {
|
||||
STPCustomerDeserializer *deserializer = [[STPCustomerDeserializer alloc] initWithJSONResponse:response];
|
||||
return deserializer.customer;
|
||||
NSDictionary *dict = [response stp_dictionaryByRemovingNullsValidatingRequiredFields:[self requiredFields]];
|
||||
if (!dict) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
STPCustomer *customer = [STPCustomer new];
|
||||
customer.stripeID = dict[@"id"];
|
||||
NSString *defaultSourceId;
|
||||
if ([dict[@"default_source"] isKindOfClass:[NSString class]]) {
|
||||
defaultSourceId = dict[@"default_source"];
|
||||
}
|
||||
if ([dict[@"shipping"] isKindOfClass:[NSDictionary class]]) {
|
||||
NSDictionary *shippingDict = dict[@"shipping"];
|
||||
STPAddress *shipping = [STPAddress new];
|
||||
shipping.name = shippingDict[@"name"];
|
||||
shipping.phone = shippingDict[@"phone"];
|
||||
shipping.line1 = shippingDict[@"address"][@"line1"];
|
||||
shipping.line2 = shippingDict[@"address"][@"line2"];
|
||||
shipping.city = shippingDict[@"address"][@"city"];
|
||||
shipping.state = shippingDict[@"address"][@"state"];
|
||||
shipping.postalCode = shippingDict[@"address"][@"postal_code"];
|
||||
shipping.country = shippingDict[@"address"][@"country"];
|
||||
customer.shippingAddress = shipping;
|
||||
}
|
||||
NSMutableArray *sources = [NSMutableArray array];
|
||||
if ([dict[@"sources"] isKindOfClass:[NSDictionary class]] && [dict[@"sources"][@"data"] isKindOfClass:[NSArray class]]) {
|
||||
for (id contents in dict[@"sources"][@"data"]) {
|
||||
if ([contents isKindOfClass:[NSDictionary class]]) {
|
||||
// eventually support other source types
|
||||
if ([contents[@"object"] isEqualToString:@"card"]) {
|
||||
STPCard *card = [STPCard decodedObjectFromAPIResponse:contents];
|
||||
// ignore apple pay cards from the response
|
||||
if (card && !card.isApplePayCard) {
|
||||
[sources addObject:card];
|
||||
if (defaultSourceId && [card.stripeID isEqualToString:defaultSourceId]) {
|
||||
customer.defaultSource = card;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ([contents[@"object"] isEqualToString:@"source"]) {
|
||||
STPSource *source = [STPSource decodedObjectFromAPIResponse:contents];
|
||||
if (source) {
|
||||
[sources addObject:source];
|
||||
if (defaultSourceId && [source.stripeID isEqualToString:defaultSourceId]) {
|
||||
customer.defaultSource = source;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
customer.sources = sources;
|
||||
}
|
||||
customer.allResponseFields = dict;
|
||||
return customer;
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
NOTE: STPCustomerDeserializer has been deprecated. When we remove
|
||||
STPBackendAPIAdapter, we should also remove STPCustomerDeserializer.
|
||||
*/
|
||||
@interface STPCustomerDeserializer()
|
||||
|
||||
@property(nonatomic, nullable)STPCustomer *customer;
|
||||
|
@ -106,45 +162,12 @@
|
|||
- (instancetype)initWithJSONResponse:(id)json {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
if (![json isKindOfClass:[NSDictionary class]] || ![json[@"id"] isKindOfClass:[NSString class]]) {
|
||||
STPCustomer *customer = [STPCustomer decodedObjectFromAPIResponse:json];
|
||||
if (!customer) {
|
||||
_error = [NSError stp_genericFailedToParseResponseError];
|
||||
return self;
|
||||
} else {
|
||||
_customer = customer;
|
||||
}
|
||||
STPCustomer *customer = [STPCustomer new];
|
||||
customer.stripeID = json[@"id"];
|
||||
NSString *defaultSourceId;
|
||||
if ([json[@"default_source"] isKindOfClass:[NSString class]]) {
|
||||
defaultSourceId = json[@"default_source"];
|
||||
}
|
||||
NSMutableArray *sources = [NSMutableArray array];
|
||||
if ([json[@"sources"] isKindOfClass:[NSDictionary class]] && [json[@"sources"][@"data"] isKindOfClass:[NSArray class]]) {
|
||||
for (id contents in json[@"sources"][@"data"]) {
|
||||
if ([contents isKindOfClass:[NSDictionary class]]) {
|
||||
// eventually support other source types
|
||||
if ([contents[@"object"] isEqualToString:@"card"]) {
|
||||
STPCard *card = [STPCard decodedObjectFromAPIResponse:contents];
|
||||
// ignore apple pay cards from the response
|
||||
if (card && !card.isApplePayCard) {
|
||||
[sources addObject:card];
|
||||
if (defaultSourceId && [card.stripeID isEqualToString:defaultSourceId]) {
|
||||
customer.defaultSource = card;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ([contents[@"object"] isEqualToString:@"source"]) {
|
||||
STPSource *source = [STPSource decodedObjectFromAPIResponse:contents];
|
||||
if (source) {
|
||||
[sources addObject:source];
|
||||
if (defaultSourceId && [source.stripeID isEqualToString:defaultSourceId]) {
|
||||
customer.defaultSource = source;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
customer.sources = sources;
|
||||
}
|
||||
_customer = customer;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// STPCustomerContext+Private.h
|
||||
// Stripe
|
||||
//
|
||||
// Created by Ben Guo on 6/9/17.
|
||||
// Copyright © 2017 Stripe, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Stripe/Stripe.h>
|
||||
|
||||
#import "STPBlocks.h"
|
||||
|
||||
@class STPAddress;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface STPCustomerContext (Private)
|
||||
|
||||
- (void)updateCustomerWithShippingAddress:(STPAddress *)shipping completion:(nullable STPErrorBlock)completion;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -139,4 +139,32 @@ static NSTimeInterval const CachedCustomerMaxAge = 60;
|
|||
}];
|
||||
}
|
||||
|
||||
- (void)updateCustomerWithShippingAddress:(STPAddress *)shipping completion:(STPErrorBlock)completion {
|
||||
[self.keyManager getCustomerKey:^(STPEphemeralKey *ephemeralKey, NSError *retrieveKeyError) {
|
||||
if (retrieveKeyError) {
|
||||
if (completion) {
|
||||
stpDispatchToMainThreadIfNecessary(^{
|
||||
completion(retrieveKeyError);
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
NSMutableDictionary *params = [NSMutableDictionary new];
|
||||
params[@"shipping"] = [STPAddress shippingInfoForChargeWithAddress:shipping
|
||||
shippingMethod:nil];
|
||||
[STPAPIClient updateCustomerWithParameters:[params copy]
|
||||
usingKey:ephemeralKey
|
||||
completion:^(STPCustomer *customer, NSError *error) {
|
||||
if (customer) {
|
||||
self.customer = customer;
|
||||
}
|
||||
if (completion) {
|
||||
stpDispatchToMainThreadIfNecessary(^{
|
||||
completion(error);
|
||||
});
|
||||
}
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
_additionalPaymentMethods = STPPaymentMethodTypeAll;
|
||||
_requiredBillingAddressFields = STPBillingAddressFieldsNone;
|
||||
_requiredShippingAddressFields = PKAddressFieldNone;
|
||||
_verifyPrefilledShippingAddress = YES;
|
||||
_companyName = [NSBundle stp_applicationName];
|
||||
_smsAutofillDisabled = NO;
|
||||
_shippingType = STPShippingTypeShipping;
|
||||
|
@ -51,6 +52,7 @@
|
|||
copy.additionalPaymentMethods = self.additionalPaymentMethods;
|
||||
copy.requiredBillingAddressFields = self.requiredBillingAddressFields;
|
||||
copy.requiredShippingAddressFields = self.requiredShippingAddressFields;
|
||||
copy.verifyPrefilledShippingAddress = self.verifyPrefilledShippingAddress;
|
||||
copy.shippingType = self.shippingType;
|
||||
copy.companyName = self.companyName;
|
||||
copy.appleMerchantIdentifier = self.appleMerchantIdentifier;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#import "PKPaymentAuthorizationViewController+Stripe_Blocks.h"
|
||||
#import "STPAddCardViewController+Private.h"
|
||||
#import "STPCardTuple.h"
|
||||
#import "STPCustomerContext+Private.h"
|
||||
#import "STPDispatchFunctions.h"
|
||||
#import "STPPaymentConfiguration+Private.h"
|
||||
#import "STPPaymentContext+Private.h"
|
||||
|
@ -65,7 +66,7 @@ typedef NS_ENUM(NSUInteger, STPPaymentContextState) {
|
|||
@property(nonatomic, assign) STPPaymentContextState state;
|
||||
|
||||
@property(nonatomic)STPPaymentContextAmountModel *paymentAmountModel;
|
||||
|
||||
@property(nonatomic)BOOL shippingAddressNeedsVerification;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -146,6 +147,10 @@ typedef NS_ENUM(NSUInteger, STPPaymentContextState) {
|
|||
[self.loadingPromise fail:error];
|
||||
return;
|
||||
}
|
||||
if (!self.shippingAddress && customer.shippingAddress) {
|
||||
self.shippingAddress = customer.shippingAddress;
|
||||
self.shippingAddressNeedsVerification = YES;
|
||||
}
|
||||
STPCard *selectedCard;
|
||||
NSMutableArray<STPCard *> *cards = [NSMutableArray array];
|
||||
for (id<STPSourceProtocol> source in customer.sources) {
|
||||
|
@ -196,6 +201,14 @@ typedef NS_ENUM(NSUInteger, STPPaymentContextState) {
|
|||
}];
|
||||
}
|
||||
|
||||
- (void)setPrefilledInformation:(STPUserInformation *)prefilledInformation {
|
||||
_prefilledInformation = prefilledInformation;
|
||||
if (prefilledInformation.shippingAddress && !self.shippingAddress) {
|
||||
self.shippingAddress = prefilledInformation.shippingAddress;
|
||||
self.shippingAddressNeedsVerification = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setPaymentMethods:(NSArray<id<STPPaymentMethod>> *)paymentMethods {
|
||||
_paymentMethods = [paymentMethods sortedArrayUsingComparator:^NSComparisonResult(id<STPPaymentMethod> obj1, id<STPPaymentMethod> obj2) {
|
||||
Class applePayKlass = [STPApplePayPaymentMethod class];
|
||||
|
@ -439,8 +452,13 @@ typedef NS_ENUM(NSUInteger, STPPaymentContextState) {
|
|||
didFinishWithAddress:(STPAddress *)address
|
||||
shippingMethod:(PKShippingMethod *)method {
|
||||
self.shippingAddress = address;
|
||||
self.shippingAddressNeedsVerification = NO;
|
||||
self.selectedShippingMethod = method;
|
||||
[self.delegate paymentContextDidChange:self];
|
||||
if ([self.apiAdapter isKindOfClass:[STPCustomerContext class]]) {
|
||||
STPCustomerContext *customerContext = (STPCustomerContext *)self.apiAdapter;
|
||||
[customerContext updateCustomerWithShippingAddress:self.shippingAddress completion:nil];
|
||||
}
|
||||
[self appropriatelyDismissViewController:addressViewController completion:^{
|
||||
if (self.state == STPPaymentContextStateRequestingPayment) {
|
||||
self.state = STPPaymentContextStateNone;
|
||||
|
@ -472,6 +490,14 @@ typedef NS_ENUM(NSUInteger, STPPaymentContextState) {
|
|||
|
||||
#pragma mark - Request Payment
|
||||
|
||||
- (BOOL)requestPaymentShouldPresentShippingViewController {
|
||||
BOOL shippingAddressRequired = self.configuration.requiredShippingAddressFields != STPBillingAddressFieldsNone;
|
||||
BOOL shippingAddressIncomplete = ![self.shippingAddress containsRequiredShippingAddressFields:self.configuration.requiredShippingAddressFields];
|
||||
BOOL shippingMethodRequired = ([self.delegate respondsToSelector:@selector(paymentContext:didUpdateShippingAddress:completion:)] && !self.selectedShippingMethod);
|
||||
BOOL verificationRequired = self.configuration.verifyPrefilledShippingAddress && self.shippingAddressNeedsVerification;
|
||||
return (shippingAddressRequired && (shippingAddressIncomplete || shippingMethodRequired || verificationRequired));
|
||||
}
|
||||
|
||||
- (void)requestPayment {
|
||||
FAUXPAS_IGNORED_IN_METHOD(APIAvailability);
|
||||
WEAK(self);
|
||||
|
@ -491,9 +517,7 @@ typedef NS_ENUM(NSUInteger, STPPaymentContextState) {
|
|||
if (!self.selectedPaymentMethod) {
|
||||
[self presentPaymentMethodsViewControllerWithNewState:STPPaymentContextStateRequestingPayment];
|
||||
}
|
||||
else if (self.configuration.requiredShippingAddressFields != STPBillingAddressFieldsNone &&
|
||||
!self.shippingAddress)
|
||||
{
|
||||
else if ([self requestPaymentShouldPresentShippingViewController]) {
|
||||
[self presentShippingViewControllerWithNewState:STPPaymentContextStateRequestingPayment];
|
||||
}
|
||||
else if ([self.selectedPaymentMethod isKindOfClass:[STPCard class]]) {
|
||||
|
@ -532,7 +556,12 @@ typedef NS_ENUM(NSUInteger, STPPaymentContextState) {
|
|||
STPPaymentAuthorizationBlock paymentHandler = ^(PKPayment *payment) {
|
||||
self.selectedShippingMethod = payment.shippingMethod;
|
||||
self.shippingAddress = [[STPAddress alloc] initWithABRecord:payment.shippingAddress];
|
||||
self.shippingAddressNeedsVerification = NO;
|
||||
[self.delegate paymentContextDidChange:self];
|
||||
if ([self.apiAdapter isKindOfClass:[STPCustomerContext class]]) {
|
||||
STPCustomerContext *customerContext = (STPCustomerContext *)self.apiAdapter;
|
||||
[customerContext updateCustomerWithShippingAddress:self.shippingAddress completion:nil];
|
||||
}
|
||||
};
|
||||
STPApplePayTokenHandlerBlock applePayTokenHandler = ^(STPToken *token, STPErrorBlock tokenCompletion) {
|
||||
[self.apiAdapter attachSourceToCustomer:token completion:^(NSError *tokenError) {
|
||||
|
|
|
@ -89,16 +89,8 @@
|
|||
if (shippingAddress != nil) {
|
||||
_addressViewModel.address = shippingAddress;
|
||||
}
|
||||
else if (prefilledInformation != nil) {
|
||||
STPAddress *prefilledAddress = [STPAddress new];
|
||||
prefilledAddress.country = _addressViewModel.address.country;
|
||||
if (self.configuration.requiredShippingAddressFields & PKAddressFieldEmail) {
|
||||
prefilledAddress.email = prefilledInformation.email;
|
||||
}
|
||||
if (self.configuration.requiredShippingAddressFields & PKAddressFieldPhone) {
|
||||
prefilledAddress.phone = prefilledInformation.phone;
|
||||
}
|
||||
_addressViewModel.address = prefilledAddress;
|
||||
else if (prefilledInformation.shippingAddress != nil) {
|
||||
_addressViewModel.address = prefilledInformation.shippingAddress;
|
||||
}
|
||||
self.title = [self titleForShippingType:self.configuration.shippingType];
|
||||
}
|
||||
|
|
|
@ -12,15 +12,10 @@
|
|||
|
||||
@implementation STPUserInformation
|
||||
|
||||
- (void)setPhone:(NSString *)phone {
|
||||
_phone = [STPCardValidator sanitizedNumericStringForString:phone];
|
||||
}
|
||||
|
||||
- (id)copyWithZone:(__unused NSZone *)zone {
|
||||
STPUserInformation *copy = [self.class new];
|
||||
copy.email = self.email;
|
||||
copy.phone = self.phone;
|
||||
copy.billingAddress = self.billingAddress;
|
||||
copy.shippingAddress = self.shippingAddress;
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
//
|
||||
// StripeError+Private.h
|
||||
// Stripe
|
||||
//
|
||||
// Created by Ben Guo on 5/22/17.
|
||||
// Copyright © 2017 Stripe, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NSError (StripePrivate)
|
||||
|
||||
+ (NSError *)stp_customerContextMissingKeyProviderError;
|
||||
|
||||
@end
|
||||
|
||||
void linkNSErrorPrivateCategory(void);
|
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// StripeError+Private.m
|
||||
// Stripe
|
||||
//
|
||||
// Created by Ben Guo on 6/22/17.
|
||||
// Copyright © 2017 Stripe, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#import "StripeError+Private.h"
|
||||
#import "StripeError.h"
|
||||
|
||||
@implementation NSError (StripePrivate)
|
||||
|
||||
+ (NSError *)stp_customerContextMissingKeyProviderError {
|
||||
NSDictionary *userInfo = @{
|
||||
NSLocalizedDescriptionKey: [self stp_unexpectedErrorMessage],
|
||||
STPErrorMessageKey: @"STPCustomerContext is missing a key provider. Did you forget to set the singleton instance's key provider?"
|
||||
};
|
||||
return [[self alloc] initWithDomain:StripeDomain code:STPCustomerContextMissingKeyProviderError userInfo:userInfo];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
void linkNSErrorPrivateCategory(void) {}
|
|
@ -11,6 +11,7 @@
|
|||
#import <PassKit/PassKit.h>
|
||||
#import <Contacts/Contacts.h>
|
||||
#import "STPAddress.h"
|
||||
#import "STPFixtures.h"
|
||||
|
||||
@interface STPAddressTests : XCTestCase
|
||||
|
||||
|
@ -431,4 +432,26 @@
|
|||
XCTAssertTrue([address containsRequiredShippingAddressFields:PKAddressFieldAll]);
|
||||
}
|
||||
|
||||
- (void)testShippingInfoForCharge {
|
||||
STPAddress *address = [STPFixtures address];
|
||||
PKShippingMethod *method = [[PKShippingMethod alloc] init];
|
||||
method.label = @"UPS Ground";
|
||||
NSDictionary *info = [STPAddress shippingInfoForChargeWithAddress:address
|
||||
shippingMethod:method];
|
||||
NSDictionary *expected = @{
|
||||
@"address": @{
|
||||
@"city": address.city,
|
||||
@"country": address.country,
|
||||
@"line1": address.line1,
|
||||
@"line2": address.line2,
|
||||
@"postal_code": address.postalCode,
|
||||
@"state": address.state
|
||||
},
|
||||
@"name": address.name,
|
||||
@"phone": address.phone,
|
||||
@"carrier": method.label,
|
||||
};
|
||||
XCTAssertEqualObjects(expected, info);
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#import <OCMock/OCMock.h>
|
||||
#import <Stripe/Stripe.h>
|
||||
#import "STPAPIClient+Private.h"
|
||||
#import "STPCustomerContext+Private.h"
|
||||
#import "STPEphemeralKeyManager.h"
|
||||
#import "STPFixtures.h"
|
||||
|
||||
|
@ -231,4 +232,43 @@
|
|||
[self waitForExpectationsWithTimeout:2 handler:nil];
|
||||
}
|
||||
|
||||
- (void)testSetCustomerShippingCallsAPIClientCorrectly {
|
||||
STPAddress *address = [STPFixtures address];
|
||||
STPEphemeralKey *customerKey = [STPFixtures ephemeralKey];
|
||||
id mockKeyManager = [self mockKeyManagerWithKey:customerKey];
|
||||
id mockAPIClient = OCMClassMock([STPAPIClient class]);
|
||||
XCTestExpectation *exp = [self expectationWithDescription:@"updateCustomer"];
|
||||
NSDictionary *expectedParams = @{
|
||||
@"shipping": @{
|
||||
@"address": @{
|
||||
@"city": address.city,
|
||||
@"country": address.country,
|
||||
@"line1": address.line1,
|
||||
@"line2": address.line2,
|
||||
@"postal_code": address.postalCode,
|
||||
@"state": address.state
|
||||
},
|
||||
@"name": address.name,
|
||||
@"phone": address.phone,
|
||||
}
|
||||
};
|
||||
OCMStub([mockAPIClient updateCustomerWithParameters:[OCMArg isEqual:expectedParams]
|
||||
usingKey:[OCMArg isEqual:customerKey]
|
||||
completion:[OCMArg any]])
|
||||
.andDo(^(NSInvocation *invocation) {
|
||||
STPCustomerCompletionBlock completion;
|
||||
[invocation getArgument:&completion atIndex:4];
|
||||
completion([STPFixtures customerWithSingleCardTokenSource], nil);
|
||||
[exp fulfill];
|
||||
});
|
||||
XCTestExpectation *exp2 = [self expectationWithDescription:@"updateCustomerWithShipping"];
|
||||
STPCustomerContext *sut = [[STPCustomerContext alloc] initWithKeyManager:mockKeyManager];
|
||||
[sut updateCustomerWithShippingAddress:address completion:^(NSError *error) {
|
||||
XCTAssertNil(error);
|
||||
[exp2 fulfill];
|
||||
}];
|
||||
|
||||
[self waitForExpectationsWithTimeout:2 handler:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#import <XCTest/XCTest.h>
|
||||
#import "STPCustomer.h"
|
||||
#import "StripeError.h"
|
||||
#import "STPAddress.h"
|
||||
#import "STPTestUtils.h"
|
||||
#import "STPSourceProtocol.h"
|
||||
|
||||
|
@ -54,6 +55,15 @@
|
|||
XCTAssertEqualObjects(sut.defaultSource.stripeID, card1[@"id"]);
|
||||
XCTAssertEqualObjects(sut.sources[2].stripeID, cardSource[@"id"]);
|
||||
XCTAssertEqualObjects(sut.sources[3].stripeID, threeDSSource[@"id"]);
|
||||
|
||||
XCTAssertEqualObjects(sut.shippingAddress.name, customer[@"shipping"][@"name"]);
|
||||
XCTAssertEqualObjects(sut.shippingAddress.phone, customer[@"shipping"][@"phone"]);
|
||||
XCTAssertEqualObjects(sut.shippingAddress.city, customer[@"shipping"][@"address"][@"city"]);
|
||||
XCTAssertEqualObjects(sut.shippingAddress.country, customer[@"shipping"][@"address"][@"country"]);
|
||||
XCTAssertEqualObjects(sut.shippingAddress.line1, customer[@"shipping"][@"address"][@"line1"]);
|
||||
XCTAssertEqualObjects(sut.shippingAddress.line2, customer[@"shipping"][@"address"][@"line2"]);
|
||||
XCTAssertEqualObjects(sut.shippingAddress.postalCode, customer[@"shipping"][@"address"][@"postal_code"]);
|
||||
XCTAssertEqualObjects(sut.shippingAddress.state, customer[@"shipping"][@"address"][@"state"]);
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -13,6 +13,11 @@
|
|||
|
||||
@interface STPFixtures : NSObject
|
||||
|
||||
/**
|
||||
An Address object with all fields filled.
|
||||
*/
|
||||
+ (STPAddress *)address;
|
||||
|
||||
/**
|
||||
A PKPaymentObject with test payment data.
|
||||
*/
|
||||
|
|
|
@ -12,6 +12,20 @@
|
|||
|
||||
@implementation STPFixtures
|
||||
|
||||
+ (STPAddress *)address {
|
||||
STPAddress *address = [STPAddress new];
|
||||
address.name = @"Jenny Rosen";
|
||||
address.phone = @"5555555555";
|
||||
address.email = @"jrosen@example.com";
|
||||
address.line1 = @"27 Smith St";
|
||||
address.line2 = @"Apt 2";
|
||||
address.postalCode = @"10001";
|
||||
address.city = @"New York";
|
||||
address.state = @"NY";
|
||||
address.country = @"US";
|
||||
return address;
|
||||
}
|
||||
|
||||
+ (STPBankAccountParams *)bankAccountParams {
|
||||
STPBankAccountParams *bankParams = [STPBankAccountParams new];
|
||||
// https://stripe.com/docs/testing#account-numbers
|
||||
|
|
Loading…
Reference in New Issue