diff --git a/Stripe.xcodeproj/project.pbxproj b/Stripe.xcodeproj/project.pbxproj index 5514f3e2a32..40c6a78fc90 100644 --- a/Stripe.xcodeproj/project.pbxproj +++ b/Stripe.xcodeproj/project.pbxproj @@ -349,9 +349,20 @@ 8BD87B931EFB1C1E00269C2B /* STPSourceVerification+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 8BD87B911EFB1C1E00269C2B /* STPSourceVerification+Private.h */; }; 8BD87B951EFB1CB100269C2B /* STPSourceVerificationTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD87B941EFB1CB100269C2B /* STPSourceVerificationTest.m */; }; 8BE5AE8B1EF8905B0081A33C /* STPCardParamsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BE5AE8A1EF8905B0081A33C /* STPCardParamsTest.m */; }; + B3302F462006FBA7005DDBE9 /* STPConnectAccountParamsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B3302F452006FBA7005DDBE9 /* STPConnectAccountParamsTest.m */; }; + B3302F4C200700AB005DDBE9 /* STPLegalEntityParamsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B3302F4B200700AB005DDBE9 /* STPLegalEntityParamsTest.m */; }; B347DD481FE35423006B3BAC /* STPValidatedTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = B347DD461FE35423006B3BAC /* STPValidatedTextField.h */; }; B347DD491FE35423006B3BAC /* STPValidatedTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = B347DD471FE35423006B3BAC /* STPValidatedTextField.m */; }; B382D6611FE8BEA0009B56AB /* STPValidatedTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = B347DD471FE35423006B3BAC /* STPValidatedTextField.m */; }; + B3A241391FFEB57400A2F00D /* STPConnectAccountParams.h in Headers */ = {isa = PBXBuildFile; fileRef = B3A241371FFEB57400A2F00D /* STPConnectAccountParams.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B3A2413A1FFEB57400A2F00D /* STPConnectAccountParams.h in Headers */ = {isa = PBXBuildFile; fileRef = B3A241371FFEB57400A2F00D /* STPConnectAccountParams.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B3A2413B1FFEB57400A2F00D /* STPConnectAccountParams.m in Sources */ = {isa = PBXBuildFile; fileRef = B3A241381FFEB57400A2F00D /* STPConnectAccountParams.m */; }; + B3A2413C1FFEB57400A2F00D /* STPConnectAccountParams.m in Sources */ = {isa = PBXBuildFile; fileRef = B3A241381FFEB57400A2F00D /* STPConnectAccountParams.m */; }; + B3A99BC31FEAF2CA003F6ED3 /* STPLegalEntityParams.h in Headers */ = {isa = PBXBuildFile; fileRef = B3A99BC11FEAF2CA003F6ED3 /* STPLegalEntityParams.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B3A99BC41FEAF2CA003F6ED3 /* STPLegalEntityParams.h in Headers */ = {isa = PBXBuildFile; fileRef = B3A99BC11FEAF2CA003F6ED3 /* STPLegalEntityParams.h */; settings = {ATTRIBUTES = (Public, ); }; }; + B3A99BC51FEAF2CA003F6ED3 /* STPLegalEntityParams.m in Sources */ = {isa = PBXBuildFile; fileRef = B3A99BC21FEAF2CA003F6ED3 /* STPLegalEntityParams.m */; }; + B3A99BC61FEAF2CA003F6ED3 /* STPLegalEntityParams.m in Sources */ = {isa = PBXBuildFile; fileRef = B3A99BC21FEAF2CA003F6ED3 /* STPLegalEntityParams.m */; }; + B3C9CF2D2004595A005502ED /* STPConnectAccountFunctionalTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B3C9CF2C2004595A005502ED /* STPConnectAccountFunctionalTest.m */; }; C1054F911FE197AE0033C87E /* STPPaymentContextSnapshotTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C1054F901FE197AE0033C87E /* STPPaymentContextSnapshotTests.m */; }; C1080F491CBECF7B007B2D89 /* STPAddress.h in Headers */ = {isa = PBXBuildFile; fileRef = C1080F471CBECF7B007B2D89 /* STPAddress.h */; settings = {ATTRIBUTES = (Public, ); }; }; C1080F4A1CBECF7B007B2D89 /* STPAddress.m in Sources */ = {isa = PBXBuildFile; fileRef = C1080F481CBECF7B007B2D89 /* STPAddress.m */; }; @@ -999,8 +1010,15 @@ 8BD87B911EFB1C1E00269C2B /* STPSourceVerification+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "STPSourceVerification+Private.h"; sourceTree = ""; }; 8BD87B941EFB1CB100269C2B /* STPSourceVerificationTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPSourceVerificationTest.m; sourceTree = ""; }; 8BE5AE8A1EF8905B0081A33C /* STPCardParamsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPCardParamsTest.m; sourceTree = ""; }; + B3302F452006FBA7005DDBE9 /* STPConnectAccountParamsTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPConnectAccountParamsTest.m; sourceTree = ""; }; + B3302F4B200700AB005DDBE9 /* STPLegalEntityParamsTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPLegalEntityParamsTest.m; sourceTree = ""; }; B347DD461FE35423006B3BAC /* STPValidatedTextField.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = STPValidatedTextField.h; sourceTree = ""; }; B347DD471FE35423006B3BAC /* STPValidatedTextField.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPValidatedTextField.m; sourceTree = ""; }; + B3A241371FFEB57400A2F00D /* STPConnectAccountParams.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = STPConnectAccountParams.h; path = PublicHeaders/STPConnectAccountParams.h; sourceTree = ""; }; + B3A241381FFEB57400A2F00D /* STPConnectAccountParams.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPConnectAccountParams.m; sourceTree = ""; }; + B3A99BC11FEAF2CA003F6ED3 /* STPLegalEntityParams.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = STPLegalEntityParams.h; path = PublicHeaders/STPLegalEntityParams.h; sourceTree = ""; }; + B3A99BC21FEAF2CA003F6ED3 /* STPLegalEntityParams.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPLegalEntityParams.m; sourceTree = ""; }; + B3C9CF2C2004595A005502ED /* STPConnectAccountFunctionalTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPConnectAccountFunctionalTest.m; sourceTree = ""; }; C1054F901FE197AE0033C87E /* STPPaymentContextSnapshotTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = STPPaymentContextSnapshotTests.m; sourceTree = ""; }; C1080F471CBECF7B007B2D89 /* STPAddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = STPAddress.h; path = PublicHeaders/STPAddress.h; sourceTree = ""; }; C1080F481CBECF7B007B2D89 /* STPAddress.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STPAddress.m; sourceTree = ""; }; @@ -1506,6 +1524,7 @@ 04CDB5211A5F3A9300B854EE /* STPApplePayFunctionalTest.m */, 04CDB5221A5F3A9300B854EE /* STPBankAccountFunctionalTest.m */, 04CDB5241A5F3A9300B854EE /* STPCardFunctionalTest.m */, + B3C9CF2C2004595A005502ED /* STPConnectAccountFunctionalTest.m */, C1CFCB6F1ED5E11500BE45DF /* STPFileFunctionalTest.m */, C1CFCB711ED5E11500BE45DF /* STPPIIFunctionalTest.m */, C1D7B5241E36C70D002181F5 /* STPSourceFunctionalTest.m */, @@ -1537,7 +1556,9 @@ 04CDB5251A5F3A9300B854EE /* STPCardTest.m */, 0438EF4A1B741B0100D506CC /* STPCardValidatorTest.m */, 04CDB5261A5F3A9300B854EE /* STPCertTest.m */, + B3302F452006FBA7005DDBE9 /* STPConnectAccountParamsTest.m */, C1E4F8051EBBEB0F00E611F5 /* STPCustomerContextTest.m */, + F1303E1A1F90000700E670AE /* STPCustomerSourceTupleTest.m */, C1D23FAC1D37F81F002FD83C /* STPCustomerTest.m */, C1EEDCC51CA2126000A54582 /* STPDelegateProxyTest.m */, 04A488351CA34DC600506E53 /* STPEmailAddressValidatorTest.m */, @@ -1547,6 +1568,7 @@ 04CDB51F1A5F3A9300B854EE /* STPFormEncoderTest.m */, C16F66AA1CA21BAC006A21B5 /* STPFormTextFieldTest.m */, 04827D171D257A6C002DB3E8 /* STPImageLibraryTest.m */, + B3302F4B200700AB005DDBE9 /* STPLegalEntityParamsTest.m */, 045A62AA1B8E7259000165CE /* STPPaymentCardTextFieldTest.m */, 0438EF4B1B741B0100D506CC /* STPPaymentCardTextFieldViewModelTest.m */, 8B013C881F1E784A00DD831B /* STPPaymentConfigurationTest.m */, @@ -1570,7 +1592,6 @@ C15B02721EA176090026E606 /* StripeErrorTest.m */, F1D3A25E1EB015B30095BFA9 /* UIImage+StripeTests.m */, F1122A7D1DFB84E000A8B1AF /* UINavigationBar+StripeTest.m */, - F1303E1A1F90000700E670AE /* STPCustomerSourceTupleTest.m */, ); name = Unit; sourceTree = ""; @@ -1876,11 +1897,15 @@ 04CDE5BB1BC1F21500548833 /* STPCardParams.h */, 04CDE5B41BC1F1F100548833 /* STPCardParams.m */, 04EBC7511B7533C300A0E6AE /* STPCardValidationState.h */, + B3A241371FFEB57400A2F00D /* STPConnectAccountParams.h */, + B3A241381FFEB57400A2F00D /* STPConnectAccountParams.m */, 04B31DD21D08E6E200EF1631 /* STPCustomer.h */, 04B31DD31D08E6E200EF1631 /* STPCustomer.m */, F1D3A2501EB0120F0095BFA9 /* STPFile.h */, F1D3A2461EB012010095BFA9 /* STPFile.m */, 04F213301BCEAB61001D6F22 /* STPFormEncodable.h */, + B3A99BC11FEAF2CA003F6ED3 /* STPLegalEntityParams.h */, + B3A99BC21FEAF2CA003F6ED3 /* STPLegalEntityParams.m */, C1D7B51E1E36C32F002181F5 /* STPSource.h */, C1D7B51F1E36C32F002181F5 /* STPSource.m */, F19491DD1E5F6B8C001E1FC2 /* STPSourceCardDetails.h */, @@ -2016,6 +2041,7 @@ 04EBC75A1B7533C300A0E6AE /* STPCardValidator.h in Headers */, C159933D1D8808970047950D /* STPShippingMethodsViewController.h in Headers */, F15232251EA9303800D65C67 /* STPURLCallbackHandler.h in Headers */, + B3A2413A1FFEB57400A2F00D /* STPConnectAccountParams.h in Headers */, F1D3A2561EB012350095BFA9 /* STPMultipartFormDataPart.h in Headers */, 04F94DCD1D22A22F004FC826 /* UIViewController+Stripe_KeyboardAvoiding.h in Headers */, C1BD9B3A1E39416700CEE925 /* STPSourceOwner.h in Headers */, @@ -2098,6 +2124,7 @@ C15608DE1FE08F2E0032AE66 /* UIView+Stripe_SafeAreaBounds.h in Headers */, 049E84EC1A605EF0000B66CD /* StripeError.h in Headers */, 046FE9A31CE5608000DA6A7B /* STPPaymentActivityIndicatorView.h in Headers */, + B3A99BC41FEAF2CA003F6ED3 /* STPLegalEntityParams.h in Headers */, F1DEB88B1E2047CA0066B8E8 /* STPCoreTableViewController.h in Headers */, F1FA6F931E258F6800EB444D /* STPCoreViewController+Private.h in Headers */, 04793F571D1D9C0200B3C551 /* STPSourceProtocol.h in Headers */, @@ -2153,6 +2180,7 @@ F1D3A24E1EB012010095BFA9 /* STPMultipartFormDataPart.h in Headers */, C11810A71CC6EE840022FB55 /* STPBackendAPIAdapter.h in Headers */, F12C8DC01D63DE9F00ADA0D7 /* STPPaymentContextAmountModel.h in Headers */, + B3A241391FFEB57400A2F00D /* STPConnectAccountParams.h in Headers */, F19491DE1E5F6B8C001E1FC2 /* STPSourceCardDetails.h in Headers */, 0439B9871C454F97005A1ED5 /* STPPaymentMethodsViewController.h in Headers */, 04B31DF91D11AC6400EF1631 /* STPUserInformation.h in Headers */, @@ -2235,6 +2263,7 @@ C15608DD1FE08F2E0032AE66 /* UIView+Stripe_SafeAreaBounds.h in Headers */, F1852F931D80B6EC00367C86 /* STPStringUtils.h in Headers */, 049A3FAE1CC9AA9900F57DE7 /* STPAddressViewModel.h in Headers */, + B3A99BC31FEAF2CA003F6ED3 /* STPLegalEntityParams.h in Headers */, C175B7941FE834A3009F5A0E /* STPCustomer+Private.h in Headers */, F1D3A2651EBA5BAE0095BFA9 /* STPPaymentCardTextField+Private.h in Headers */, 0426B96E1CEADC98006AC8DD /* STPColorUtils.h in Headers */, @@ -2667,6 +2696,7 @@ C127110A1DBA7E490087840D /* STPAddressViewModelTest.m in Sources */, C17D24EE1E37DBAC005CB188 /* STPSourceTest.m in Sources */, C1E4F8061EBBEB0F00E611F5 /* STPCustomerContextTest.m in Sources */, + B3302F4C200700AB005DDBE9 /* STPLegalEntityParamsTest.m in Sources */, F14C872F1D4FCDBA00C7CC6A /* STPPaymentContextApplePayTest.m in Sources */, C1BD9B1F1E390A2700CEE925 /* STPSourceParamsTest.m in Sources */, C1D7B5251E36C70D002181F5 /* STPSourceFunctionalTest.m in Sources */, @@ -2678,6 +2708,7 @@ C1FEE5991CBFF24000A7632B /* STPPostalCodeValidatorTest.m in Sources */, 8BD87B8B1EFB136F00269C2B /* STPSourceCardDetailsTest.m in Sources */, C13538081D2C2186003F6157 /* STPAddCardViewControllerTest.m in Sources */, + B3302F462006FBA7005DDBE9 /* STPConnectAccountParamsTest.m in Sources */, 04415C671A6605B5001225ED /* STPAPIClientTest.m in Sources */, 045D71311CF514BB00F6CD65 /* STPBinRangeTest.m in Sources */, C15B02731EA176090026E606 /* StripeErrorTest.m in Sources */, @@ -2714,6 +2745,7 @@ 04415C6F1A6605B5001225ED /* STPCertTest.m in Sources */, 04415C701A6605B5001225ED /* STPTokenTest.m in Sources */, 8B8DDBB31EF887A4004B141F /* STPBankAccountParamsTest.m in Sources */, + B3C9CF2D2004595A005502ED /* STPConnectAccountFunctionalTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2773,8 +2805,10 @@ C159933A1D8808880047950D /* STPShippingAddressViewController.m in Sources */, 04F94DA41D229F1C004FC826 /* STPAddressViewModel.m in Sources */, 049880FF1CED5A2300EA4FFD /* STPPaymentConfiguration.m in Sources */, + B3A99BC61FEAF2CA003F6ED3 /* STPLegalEntityParams.m in Sources */, C180211D1E3A58710089D712 /* STPSourcePoller.m in Sources */, 04F94DB91D229F86004FC826 /* STPApplePayPaymentMethod.m in Sources */, + B3A2413C1FFEB57400A2F00D /* STPConnectAccountParams.m in Sources */, C1BD9B2B1E39406C00CEE925 /* STPSourceOwner.m in Sources */, C1BD9B311E3940A200CEE925 /* STPSourceRedirect.m in Sources */, 04B31DE91D09D25F00EF1631 /* STPPaymentMethodsInternalViewController.m in Sources */, @@ -2877,12 +2911,14 @@ C1BD9B241E393FFE00CEE925 /* STPSourceReceiver.m in Sources */, 04B31DD61D08E6E200EF1631 /* STPCustomer.m in Sources */, 0438EF351B7416BB00D506CC /* STPPaymentCardTextField.m in Sources */, + B3A2413B1FFEB57400A2F00D /* STPConnectAccountParams.m in Sources */, F1D3A24F1EB012010095BFA9 /* STPMultipartFormDataPart.m in Sources */, 04827D121D2575C6002DB3E8 /* STPImageLibrary.m in Sources */, 04CDB5041A5F30A700B854EE /* STPFormEncoder.m in Sources */, 0426B96F1CEADC98006AC8DD /* STPColorUtils.m in Sources */, C1D7B51C1E36B8B9002181F5 /* STPSourceParams.m in Sources */, 049880FE1CED5A2300EA4FFD /* STPPaymentConfiguration.m in Sources */, + B3A99BC51FEAF2CA003F6ED3 /* STPLegalEntityParams.m in Sources */, 046FE9A21CE55D1D00DA6A7B /* STPPaymentActivityIndicatorView.m in Sources */, 045D71221CEFA57000F6CD65 /* UIViewController+Stripe_Promises.m in Sources */, C124A1721CCA968B007D42EE /* STPAnalyticsClient.m in Sources */, diff --git a/Stripe/PublicHeaders/STPAPIClient.h b/Stripe/PublicHeaders/STPAPIClient.h index 18f1ce92155..af9ba9aadf6 100644 --- a/Stripe/PublicHeaders/STPAPIClient.h +++ b/Stripe/PublicHeaders/STPAPIClient.h @@ -20,7 +20,7 @@ NS_ASSUME_NONNULL_BEGIN */ static NSString *const STPSDKVersion = @"11.5.0"; -@class STPBankAccount, STPBankAccountParams, STPCard, STPCardParams, STPSourceParams, STPToken, STPPaymentConfiguration; +@class STPBankAccount, STPBankAccountParams, STPCard, STPCardParams, STPConnectAccountParams, STPSourceParams, STPToken, STPPaymentConfiguration; /** A top-level class that imports the rest of the Stripe SDK. @@ -127,6 +127,28 @@ static NSString *const STPSDKVersion = @"11.5.0"; @end +#pragma mark Connect Accounts + +/** + Stripe extensions for working with Connect Accounts + */ +@interface STPAPIClient (ConnectAccounts) + + +/** + Converts an `STPConnectAccountParams` object into a Stripe token using the Stripe API. + + This allows the connected account to accept the Terms of Service, and/or send Legal Entity information. + + @param account The Connect Account parameters. Cannot be nil. + @param completion The callback to run with the returned Stripe token (and any errors that may have occurred). + */ +- (void)createTokenWithConnectAccount:(STPConnectAccountParams *)account completion:(__nullable STPTokenCompletionBlock)completion; + +@end + +#pragma mark Upload + /** STPAPIClient extensions to upload files. */ diff --git a/Stripe/PublicHeaders/STPAddress.h b/Stripe/PublicHeaders/STPAddress.h index b3302d9aa7f..9863fea38c4 100644 --- a/Stripe/PublicHeaders/STPAddress.h +++ b/Stripe/PublicHeaders/STPAddress.h @@ -8,7 +8,9 @@ #import #import + #import "STPAPIResponseDecodable.h" +#import "STPFormEncodable.h" @class CNContact; @@ -64,7 +66,7 @@ extern STPContactField const STPContactFieldName; /** STPAddress Contains an address as represented by the Stripe API. */ -@interface STPAddress : NSObject +@interface STPAddress : NSObject /** The user's full name (e.g. "Jane Doe") diff --git a/Stripe/PublicHeaders/STPConnectAccountParams.h b/Stripe/PublicHeaders/STPConnectAccountParams.h new file mode 100644 index 00000000000..92e0bc4c53d --- /dev/null +++ b/Stripe/PublicHeaders/STPConnectAccountParams.h @@ -0,0 +1,72 @@ +// +// STPConnectAccountParams.h +// Stripe +// +// Created by Daniel Jackson on 1/4/18. +// Copyright © 2018 Stripe, Inc. All rights reserved. +// + +#import + +#import "STPFormEncodable.h" + +@class STPLegalEntityParams; + +NS_ASSUME_NONNULL_BEGIN + +/** + Parameters for creating a Connect Account token. + */ +@interface STPConnectAccountParams : NSObject + +/** + Optional boolean indicating that the Terms Of Service were shown to the user & + the user accepted them. + */ +@property (nonatomic, nullable, readonly) NSNumber *tosShownAndAccepted; + +/** + Required property with information about the legal entity for this account. + + At least one field in the legalEntity must have a value, otherwise the create token + call will fail. + */ +@property (nonatomic, readonly) STPLegalEntityParams *legalEntity; + +/** + `STPConnectAccountParams` cannot be directly instantiated, use `initWithTosShownAndAccepted:legalEntity:` + or `initWithLegalEntity:` + */ +- (instancetype)init __attribute__((unavailable("Cannot be directly instantiated"))); + +/** + Initialize `STPConnectAccountParams` with tosShownAndAccepted = YES + + This method cannot be called with `wasAccepted == NO`, guarded by a `NSParameterAssert()`. + + Use this init method if you want to set the `tosShownAndAccepted` parameter. If you + don't, use the `initWithLegalEntity:` version instead. + + @param wasAccepted Must be YES, but only if the user was shown & accepted the ToS + @param legalEntity data about the legal entity + */ +- (instancetype)initWithTosShownAndAccepted:(BOOL)wasAccepted + legalEntity:(STPLegalEntityParams *)legalEntity; + +/** + Initialize `STPConnectAccountParams` with the `STPLegalEntityParams` provided. + + This init method cannot change the `tosShownAndAccepted` parameter. Use + `initWithTosShownAndAccepted:legalEntity:` instead if you need to do that. + + These two init methods exist to avoid the (slightly awkward) NSNumber box that would + be needed around `tosShownAndAccepted` if it was optional/nullable, and to enforce + that it is either nil or YES. + + @param legalEntity data to send to Stripe about the legal entity + */ +- (instancetype)initWithLegalEntity:(STPLegalEntityParams *)legalEntity; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Stripe/PublicHeaders/STPLegalEntityParams.h b/Stripe/PublicHeaders/STPLegalEntityParams.h new file mode 100644 index 00000000000..0bf71ea51e3 --- /dev/null +++ b/Stripe/PublicHeaders/STPLegalEntityParams.h @@ -0,0 +1,141 @@ +// +// STPLegalEntityParams.h +// Stripe +// +// Created by Daniel Jackson on 12/20/17. +// Copyright © 2017 Stripe, Inc. All rights reserved. +// + +#import +#import "STPFormEncodable.h" + +@class STPAddress, STPVerificationParams; + +NS_ASSUME_NONNULL_BEGIN + +/** + Stripe API parameters to define a Person. Things like their name, address, etc. + + All of the fields are optional. + */ +@interface STPPersonParams: NSObject + +/** + The first name of this person. + */ +@property (nonatomic, copy, nullable) NSString *firstName; + +/** + The last name of this person. + */ +@property (nonatomic, copy, nullable) NSString *lastName; + +/** + The maiden name of this person. + */ +@property (nonatomic, copy, nullable) NSString *maidenName; + +/** + The address parameter. For `STPPersonParams`, this is the address of the person. + For the `STPLegalEntityParams` subclass, see also `personalAddress`. + */ +@property (nonatomic, strong, nullable) STPAddress *address; + +/** + The date of birth (dob) of this person. + + Must include `day`, `month`, and `year`, and only those fields are used. + */ +@property (nonatomic, copy, nullable) NSDateComponents *dateOfBirth; + +/** + Verification document for this person. + */ +@property (nonatomic, strong, nullable) STPVerificationParams *verification; + +@end + + +/** + Stripe API parameters to define a Legal Entity. This extends `STPPersonParams` + and adds some more fields. + + Legal entities can be either an individual or a company. + */ +@interface STPLegalEntityParams : STPPersonParams + +/** + Additional owners of the legal entity. + */ +@property (nonatomic, copy, nullable) NSArray *additionalOwners; + +/** + The business name + */ +@property (nonatomic, copy, nullable) NSString *businessName; + +/** + The business Tax Id + */ +@property (nonatomic, copy, nullable) NSString *businessTaxId; + +/** + The business VAT Id + */ +@property (nonatomic, copy, nullable) NSString *businessVATId; + +/** + The gender of the individual, as a string. + + Currently either `male` or `female` are supported values. + */ +@property (nonatomic, copy, nullable) NSString *genderString; + +/** + The personal address field. + */ +@property (nonatomic, strong, nullable) STPAddress *personalAddress; + +/** + The Personal Id number + */ +@property (nonatomic, copy, nullable) NSString *personalIdNumber; + +/** + The phone number of the entity. + */ +@property (nonatomic, copy, nullable) NSString *phoneNumber; + +/** + The last four digits of the SSN of the individual. + */ +@property (nonatomic, copy, nullable) NSString *ssnLast4; + +/** + The Tax Id Registrar + */ +@property (nonatomic, copy, nullable) NSString *taxIdRegistrar; + +/** + The type of this legal entity, as a string. + + Currently `individual` or `company` are supported values. + */ +@property (nonatomic, copy, nullable) NSString *entityTypeString; + +@end + + +/** + Parameters for supported types of verification. + */ +@interface STPVerificationParams: NSObject + +/** + The file id for the uploaded verification document. + */ +@property (nonatomic, copy, nullable) NSString *document; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Stripe/PublicHeaders/Stripe.h b/Stripe/PublicHeaders/Stripe.h index df39ac3ff72..7e2a1a5ffb9 100644 --- a/Stripe/PublicHeaders/Stripe.h +++ b/Stripe/PublicHeaders/Stripe.h @@ -22,6 +22,7 @@ #import "STPCardParams.h" #import "STPCardValidationState.h" #import "STPCardValidator.h" +#import "STPConnectAccountParams.h" #import "STPCoreScrollViewController.h" #import "STPCoreTableViewController.h" #import "STPCoreViewController.h" @@ -31,6 +32,7 @@ #import "STPFile.h" #import "STPFormEncodable.h" #import "STPImageLibrary.h" +#import "STPLegalEntityParams.h" #import "STPPaymentActivityIndicatorView.h" #import "STPPaymentCardTextField.h" #import "STPPaymentConfiguration.h" diff --git a/Stripe/STPAPIClient.m b/Stripe/STPAPIClient.m index 7d13dd1810e..980f32604fa 100644 --- a/Stripe/STPAPIClient.m +++ b/Stripe/STPAPIClient.m @@ -288,6 +288,19 @@ - (void)createTokenWithPersonalIDNumber:(NSString *)pii completion:(__nullable S @end +#pragma mark - Connect Accounts + +@implementation STPAPIClient (ConnectAccounts) + +- (void)createTokenWithConnectAccount:(STPConnectAccountParams *)account completion:(__nullable STPTokenCompletionBlock)completion { + NSMutableDictionary *params = [[STPFormEncoder dictionaryForObject:account] mutableCopy]; + [[STPTelemetryClient sharedInstance] addTelemetryFieldsToParams:params]; + [self createTokenWithParameters:params completion:completion]; + [[STPTelemetryClient sharedInstance] sendTelemetryData]; +} + +@end + #pragma mark - Upload @implementation STPAPIClient (Upload) diff --git a/Stripe/STPAddress.m b/Stripe/STPAddress.m index 4b53c65a512..7ef71a7c2a2 100644 --- a/Stripe/STPAddress.m +++ b/Stripe/STPAddress.m @@ -13,6 +13,7 @@ #import "NSDictionary+Stripe.h" #import "STPCardValidator.h" #import "STPEmailAddressValidator.h" +#import "STPFormEncoder.h" #import "STPPhoneNumberValidator.h" #import "STPPostalCodeValidator.h" @@ -32,6 +33,7 @@ @interface STPAddress () @end @implementation STPAddress +@synthesize additionalAPIParameters; + (NSDictionary *)shippingInfoForChargeWithAddress:(nullable STPAddress *)address shippingMethod:(nullable PKShippingMethod *)method { @@ -42,14 +44,8 @@ + (NSDictionary *)shippingInfoForChargeWithAddress:(nullable STPAddress *)addres 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]; + // Re-use STPFormEncoder + params[@"address"] = [STPFormEncoder dictionaryForObject:address]; return [params copy]; } @@ -311,8 +307,29 @@ + (instancetype)decodedObjectFromAPIResponse:(NSDictionary *)response { return address; } +#pragma mark STPFormEncodable + ++ (nullable NSString *)rootObjectName { + return nil; +} + ++ (NSDictionary *)propertyNamesToFormFieldNamesMapping { + // Paralleling `decodedObjectFromAPIResponse:`, *only* the 6 address fields are encoded + // If this changes, shippingInfoForChargeWithAddress:shippingMethod: might break + return @{ + NSStringFromSelector(@selector(line1)): @"line1", + NSStringFromSelector(@selector(line2)): @"line2", + NSStringFromSelector(@selector(city)): @"city", + NSStringFromSelector(@selector(state)): @"state", + NSStringFromSelector(@selector(postalCode)): @"postal_code", + NSStringFromSelector(@selector(country)): @"country", + }; +} + @end +#pragma mark - + NSString *stringIfHasContentsElseNil(NSString *string) { if (string.length > 0) { return string; diff --git a/Stripe/STPAnalyticsClient.m b/Stripe/STPAnalyticsClient.m index 633fddc7b12..79c0ff35b6f 100644 --- a/Stripe/STPAnalyticsClient.m +++ b/Stripe/STPAnalyticsClient.m @@ -117,7 +117,7 @@ + (BOOL)shouldCollectAnalytics { + (NSString *)tokenTypeFromParameters:(NSDictionary *)parameters { if ([parameters.allKeys count] == 1) { - NSArray *validTypes = @[@"bank_account", @"card", @"pii"]; + NSArray *validTypes = @[@"account", @"bank_account", @"card", @"pii"]; NSString *type = [parameters.allKeys firstObject]; if ([validTypes containsObject:type]) { return type; diff --git a/Stripe/STPConnectAccountParams.m b/Stripe/STPConnectAccountParams.m new file mode 100644 index 00000000000..d3075fae009 --- /dev/null +++ b/Stripe/STPConnectAccountParams.m @@ -0,0 +1,69 @@ +// +// STPConnectAccountParams.m +// Stripe +// +// Created by Daniel Jackson on 1/4/18. +// Copyright © 2018 Stripe, Inc. All rights reserved. +// + +#import "STPConnectAccountParams.h" + +#import "STPLegalEntityParams.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation STPConnectAccountParams + +@synthesize additionalAPIParameters; + +- (instancetype)initWithTosShownAndAccepted:(BOOL)wasAccepted + legalEntity:(STPLegalEntityParams *)legalEntity { + // It is an error to call this method with wasAccepted == NO + NSParameterAssert(wasAccepted == YES); + self = [super init]; + if (self) { + _tosShownAndAccepted = @(wasAccepted); + _legalEntity = legalEntity; + } + return self; +} + +- (instancetype)initWithLegalEntity:(STPLegalEntityParams *)legalEntity { + self = [super init]; + if (self) { + _tosShownAndAccepted = nil; + _legalEntity = legalEntity; + } + return self; +} + +#pragma mark - description + +- (NSString *)description { + NSArray *props = @[ + [NSString stringWithFormat:@"%@: %p", NSStringFromClass([self class]), self], + // We use NSParameterAssert to block this being NO: + [NSString stringWithFormat:@"tosShownAndAccepted = %@", + self.tosShownAndAccepted != nil ? @"YES" : @""], + [NSString stringWithFormat:@"legalEntity = %@", self.legalEntity.description], + ]; + + return [NSString stringWithFormat:@"<%@>", [props componentsJoinedByString:@"; "]]; +} + +#pragma mark - STPFormEncodable + ++ (nullable NSString *)rootObjectName { + return @"account"; +} + ++ (nonnull NSDictionary *)propertyNamesToFormFieldNamesMapping { + return @{ + NSStringFromSelector(@selector(tosShownAndAccepted)): @"tos_shown_and_accepted", + NSStringFromSelector(@selector(legalEntity)): @"legal_entity", + }; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Stripe/STPFormEncoder.h b/Stripe/STPFormEncoder.h index 9e9157eea09..f36f05d1cba 100644 --- a/Stripe/STPFormEncoder.h +++ b/Stripe/STPFormEncoder.h @@ -8,7 +8,6 @@ #import -@class STPCardParams, STPBankAccountParams; @protocol STPFormEncodable; @interface STPFormEncoder : NSObject diff --git a/Stripe/STPFormEncoder.m b/Stripe/STPFormEncoder.m index 1299a861d97..cac5516d11c 100644 --- a/Stripe/STPFormEncoder.m +++ b/Stripe/STPFormEncoder.m @@ -8,8 +8,7 @@ #import "STPFormEncoder.h" -#import "STPBankAccountParams.h" -#import "STPCardParams.h" +#import "STPFormEncodable.h" FOUNDATION_EXPORT NSString * STPPercentEscapedStringFromString(NSString *string); FOUNDATION_EXPORT NSString * STPQueryStringFromParameters(NSDictionary *parameters); diff --git a/Stripe/STPLegalEntityParams.m b/Stripe/STPLegalEntityParams.m new file mode 100644 index 00000000000..11dc6a93c24 --- /dev/null +++ b/Stripe/STPLegalEntityParams.m @@ -0,0 +1,165 @@ +// +// STPLegalEntityParams.m +// Stripe +// +// Created by Daniel Jackson on 12/20/17. +// Copyright © 2017 Stripe, Inc. All rights reserved. +// + +#import "STPLegalEntityParams.h" +#import "FauxPasAnnotations.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation STPVerificationParams +@synthesize additionalAPIParameters; + +- (NSString *)description { + NSArray *props = @[ + [NSString stringWithFormat:@"%@: %p", NSStringFromClass([self class]), self], + [NSString stringWithFormat:@"document = %@", self.document], + ]; + + return [NSString stringWithFormat:@"<%@>", [props componentsJoinedByString:@"; "]]; +} + ++ (nullable NSString *)rootObjectName { + return @"verification"; +} + ++ (nonnull NSDictionary *)propertyNamesToFormFieldNamesMapping { + return @{ + NSStringFromSelector(@selector(document)): @"document", + }; +} + +@end + +@implementation STPPersonParams +@synthesize additionalAPIParameters; + +- (NSString *)description { + NSArray *props = @[ + [NSString stringWithFormat:@"%@: %p", NSStringFromClass([self class]), self], + + [NSString stringWithFormat:@"firstName = %@", self.firstName], + [NSString stringWithFormat:@"lastName = %@", self.lastName], + [NSString stringWithFormat:@"maidenName = %@", self.maidenName], + [NSString stringWithFormat:@"address = <%@>", self.address], + [NSString stringWithFormat:@"dateOfBirth = <%@>", self.dateOfBirth], + [NSString stringWithFormat:@"verification = %@", self.verification], + ]; + + return [NSString stringWithFormat:@"<%@>", [props componentsJoinedByString:@"; "]]; +} + ++ (nullable NSString *)rootObjectName { + // STPPersonParams is never a named root object. It's either inherited by STPLegalEntityParams + // or an element in the STPLegalEntityParams.additionalOwners array + return nil; +} + ++ (nonnull NSDictionary *)propertyNamesToFormFieldNamesMapping { + return @{ + NSStringFromSelector(@selector(firstName)): @"first_name", + NSStringFromSelector(@selector(lastName)): @"last_name", + NSStringFromSelector(@selector(maidenName)): @"maiden_name", + NSStringFromSelector(@selector(address)): @"address", + NSStringFromSelector(@selector(dateOfBirth)): @"dob", + NSStringFromSelector(@selector(verification)): @"verification", + }; +} + +@end + +@implementation STPLegalEntityParams + +- (NSString *)description { + + NSArray *props = @[ + // Object + [NSString stringWithFormat:@"%@: %p", NSStringFromClass([self class]), self], + [NSString stringWithFormat:@"super = %@", [super description]], + + [NSString stringWithFormat:@"additionalOwners = %@", self.additionalOwners], + [NSString stringWithFormat:@"businessName = %@", self.businessName], + [NSString stringWithFormat:@"businessTaxId = %@", self.businessTaxId], + [NSString stringWithFormat:@"businessVATId = %@", self.businessVATId], + [NSString stringWithFormat:@"genderString = %@", self.genderString], + [NSString stringWithFormat:@"personalAddress = %@", self.personalAddress], + [NSString stringWithFormat:@"personalIdNumber = %@", self.personalIdNumber], + [NSString stringWithFormat:@"phoneNumber = %@", self.phoneNumber], + [NSString stringWithFormat:@"ssnLast4 = %@", self.ssnLast4], + [NSString stringWithFormat:@"taxIdRegistrar = %@", self.taxIdRegistrar], + [NSString stringWithFormat:@"entityTypeString = %@", self.entityTypeString], + ]; + + return [NSString stringWithFormat:@"<%@>", [props componentsJoinedByString:@"; "]]; +} + ++ (nullable NSString *)rootObjectName { + return @"legal_entity"; +} + ++ (nonnull NSDictionary *)propertyNamesToFormFieldNamesMapping { + NSMutableDictionary *props = [@{ + NSStringFromSelector(@selector(additionalOwners)): @"additional_owners", + NSStringFromSelector(@selector(businessName)): @"business_name", + NSStringFromSelector(@selector(businessTaxId)): @"business_tax_id", + NSStringFromSelector(@selector(businessVATId)): @"business_vat_id", + NSStringFromSelector(@selector(genderString)): @"gender", + NSStringFromSelector(@selector(personalAddress)): @"personal_address", + NSStringFromSelector(@selector(personalIdNumber)): @"personal_id_number", + NSStringFromSelector(@selector(phoneNumber)): @"phone_number", + NSStringFromSelector(@selector(ssnLast4)): @"ssn_last_4", + NSStringFromSelector(@selector(taxIdRegistrar)): @"tax_id_registrar", + NSStringFromSelector(@selector(entityTypeString)): @"type", + } mutableCopy]; + + [props addEntriesFromDictionary:[super propertyNamesToFormFieldNamesMapping]]; + + return [props copy]; +} + +@end + + +/* + Add STPFormEncodable conformance for `STPPersonParams.dateOfBirth`. + + Faux Pas (correctly) points out this is dangerous. Probably a better thing to do + is either prefix all of these methods in the protocol, or add custom support for + `NSDateComponents` in `+[STPFormEncoder formEncodableValueForObject:]`. + + For now, I think this is safe enough. + */ +@interface NSDateComponents (STPFormEncodable) @end +@implementation NSDateComponents (STPFormEncodable) + +- (NSDictionary *)additionalAPIParameters { + FAUXPAS_IGNORED_IN_METHOD(UnprefixedCategoryMethod) + return @{}; +} + +- (void)setAdditionalAPIParameters:(__unused NSDictionary *)additionalAPIParameters { + FAUXPAS_IGNORED_IN_METHOD(UnprefixedCategoryMethod) + [self doesNotRecognizeSelector:_cmd]; +} + ++ (nullable NSString *)rootObjectName { + FAUXPAS_IGNORED_IN_METHOD(UnprefixedCategoryMethod) + return nil; +} + ++ (nonnull NSDictionary *)propertyNamesToFormFieldNamesMapping { + FAUXPAS_IGNORED_IN_METHOD(UnprefixedCategoryMethod) + return @{ + NSStringFromSelector(@selector(day)): @"day", + NSStringFromSelector(@selector(month)): @"month", + NSStringFromSelector(@selector(year)): @"year", + }; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Tests/Tests/STPAddressTests.m b/Tests/Tests/STPAddressTests.m index 31164078aef..7b7fb1ec949 100644 --- a/Tests/Tests/STPAddressTests.m +++ b/Tests/Tests/STPAddressTests.m @@ -447,4 +447,28 @@ - (void)testShippingInfoForCharge { XCTAssertEqualObjects(expected, info); } +#pragma mark STPFormEncodable Tests + +- (void)testRootObjectName { + XCTAssertNil([STPAddress rootObjectName]); +} + +- (void)testPropertyNamesToFormFieldNamesMapping { + STPAddress *address = [STPAddress new]; + + NSDictionary *mapping = [STPAddress propertyNamesToFormFieldNamesMapping]; + + for (NSString *propertyName in [mapping allKeys]) { + XCTAssertFalse([propertyName containsString:@":"]); + XCTAssert([address respondsToSelector:NSSelectorFromString(propertyName)]); + } + + for (NSString *formFieldName in [mapping allValues]) { + XCTAssert([formFieldName isKindOfClass:[NSString class]]); + XCTAssert([formFieldName length] > 0); + } + + XCTAssertEqual([[mapping allValues] count], [[NSSet setWithArray:[mapping allValues]] count]); +} + @end diff --git a/Tests/Tests/STPAnalyticsClientTest.m b/Tests/Tests/STPAnalyticsClientTest.m index 0b6a16ddff5..b2c6545231a 100644 --- a/Tests/Tests/STPAnalyticsClientTest.m +++ b/Tests/Tests/STPAnalyticsClientTest.m @@ -34,6 +34,10 @@ - (void)testTokenTypeFromParameters { NSDictionary *cardDict = [STPFormEncoder dictionaryForObject:card]; XCTAssertEqualObjects([STPAnalyticsClient tokenTypeFromParameters:cardDict], @"card"); + STPConnectAccountParams *account = [STPFixtures accountParams]; + NSDictionary *accountDict = [STPFormEncoder dictionaryForObject:account]; + XCTAssertEqualObjects([STPAnalyticsClient tokenTypeFromParameters:accountDict], @"account"); + STPBankAccountParams *bank = [STPFixtures bankAccountParams]; NSDictionary *bankDict = [STPFormEncoder dictionaryForObject:bank]; XCTAssertEqualObjects([STPAnalyticsClient tokenTypeFromParameters:bankDict], @"bank_account"); diff --git a/Tests/Tests/STPConnectAccountFunctionalTest.m b/Tests/Tests/STPConnectAccountFunctionalTest.m new file mode 100644 index 00000000000..98067e76fd0 --- /dev/null +++ b/Tests/Tests/STPConnectAccountFunctionalTest.m @@ -0,0 +1,78 @@ +// +// STPConnectAccountFunctionalTest.m +// StripeiOS Tests +// +// Created by Daniel Jackson on 1/8/18. +// Copyright © 2018 Stripe, Inc. All rights reserved. +// + +#import + +#import "STPAPIClient.h" +#import "STPConnectAccountParams.h" + +#import "STPFixtures.h" + +@interface STPConnectAccountFunctionalTest : XCTestCase + +/// Client with test publishable key +@property (nonatomic, strong, nonnull) STPAPIClient *client; + +@end + +@implementation STPConnectAccountFunctionalTest + +- (void)setUp { + [super setUp]; + + self.client = [[STPAPIClient alloc] initWithPublishableKey:@"pk_test_vOo1umqsYxSrP5UXfOeL3ecm"]; +} + +- (void)testTokenCreation_terms_throws { + XCTAssertThrows([[STPConnectAccountParams alloc] initWithTosShownAndAccepted:NO + legalEntity:[STPFixtures legalEntityParams]], + @"NSParameterAssert to prevent trying to call this with `NO`"); +} + +- (void)testTokenCreation_fullySpecified { + [self createToken:[STPFixtures accountParams] + shouldSucceed:YES]; +} + +- (void)testTokenCreation_legalEntityOnly { + STPLegalEntityParams *entity = [[STPLegalEntityParams alloc] init]; + entity.firstName = @"Legal"; + entity.lastName = @"Eagle"; + + [self createToken:[[STPConnectAccountParams alloc] initWithLegalEntity:entity] + shouldSucceed:YES]; +} + +- (void)testTokenCreation_legalEntity_emptyFails { + [self createToken:[[STPConnectAccountParams alloc] initWithLegalEntity:[STPLegalEntityParams new]] + shouldSucceed:NO]; +} + +#pragma mark - + +- (void)createToken:(STPConnectAccountParams *)params shouldSucceed:(BOOL)shouldSucceed { + XCTestExpectation *expectation = [self expectationWithDescription:@"Connect Account Token"]; + + [self.client createTokenWithConnectAccount:params completion:^(STPToken * _Nullable token, NSError * _Nullable error) { + [expectation fulfill]; + + if (shouldSucceed) { + XCTAssertNil(error); + XCTAssertNotNil(token); + XCTAssertNotNil(token.tokenId); + } + else { + XCTAssertNil(token); + XCTAssertNotNil(error); + } + }]; + + [self waitForExpectationsWithTimeout:5.0 handler:nil]; +} + +@end diff --git a/Tests/Tests/STPConnectAccountParamsTest.m b/Tests/Tests/STPConnectAccountParamsTest.m new file mode 100644 index 00000000000..e4077d12002 --- /dev/null +++ b/Tests/Tests/STPConnectAccountParamsTest.m @@ -0,0 +1,43 @@ +// +// STPConnectAccountParamsTest.m +// StripeiOS Tests +// +// Created by Daniel Jackson on 1/10/18. +// Copyright © 2018 Stripe, Inc. All rights reserved. +// + +#import + +#import "STPConnectAccountParams.h" +#import "STPLegalEntityParams.h" + +@interface STPConnectAccountParamsTest : XCTestCase +@end + +@implementation STPConnectAccountParamsTest + +#pragma mark - STPFormEncodable Tests + +- (void)testRootObjectName { + XCTAssertEqualObjects([STPConnectAccountParams rootObjectName], @"account"); +} + +- (void)testPropertyNamesToFormFieldNamesMapping { + STPConnectAccountParams *accountParams = [[STPConnectAccountParams alloc] initWithLegalEntity:[STPLegalEntityParams new]]; + + NSDictionary *mapping = [STPConnectAccountParams propertyNamesToFormFieldNamesMapping]; + + for (NSString *propertyName in [mapping allKeys]) { + XCTAssertFalse([propertyName containsString:@":"]); + XCTAssert([accountParams respondsToSelector:NSSelectorFromString(propertyName)]); + } + + for (NSString *formFieldName in [mapping allValues]) { + XCTAssert([formFieldName isKindOfClass:[NSString class]]); + XCTAssert([formFieldName length] > 0); + } + + XCTAssertEqual([[mapping allValues] count], [[NSSet setWithArray:[mapping allValues]] count]); +} + +@end diff --git a/Tests/Tests/STPFixtures.h b/Tests/Tests/STPFixtures.h index e9bb27beb9f..4445d063f72 100644 --- a/Tests/Tests/STPFixtures.h +++ b/Tests/Tests/STPFixtures.h @@ -24,6 +24,12 @@ extern NSString *const STPTestJSONSourceSEPADebit; @interface STPFixtures : NSObject +/** + An STPConnectAccountParams object with all of the fields filled in, and + ToS accepted. + */ ++ (STPConnectAccountParams *)accountParams; + /** An Address object with all fields filled. */ @@ -133,6 +139,11 @@ extern NSString *const STPTestJSONSourceSEPADebit; */ + (STPEphemeralKey *)expiringEphemeralKey; +/** + A fully specified STPLegalEntityParams + */ ++ (STPLegalEntityParams *)legalEntityParams; + @end @interface STPJsonSources : NSObject diff --git a/Tests/Tests/STPFixtures.m b/Tests/Tests/STPFixtures.m index ce0b28d14f9..1e8c4f2e900 100644 --- a/Tests/Tests/STPFixtures.m +++ b/Tests/Tests/STPFixtures.m @@ -23,6 +23,11 @@ @implementation STPFixtures ++ (STPConnectAccountParams *)accountParams { + return [[STPConnectAccountParams alloc] initWithTosShownAndAccepted:YES + legalEntity:[self legalEntityParams]]; +} + + (STPAddress *)address { STPAddress *address = [STPAddress new]; address.name = @"Jenny Rosen"; @@ -248,4 +253,59 @@ + (PKPayment *)applePayPayment { return payment; } ++ (STPLegalEntityParams *)legalEntityParams { + STPLegalEntityParams *legalEntity = [STPLegalEntityParams new]; + + legalEntity.firstName = @"Jessica"; + legalEntity.lastName = @"Jones"; + legalEntity.maidenName = @"Smith"; + legalEntity.address = [self address]; + + legalEntity.dateOfBirth = [NSDateComponents new]; + legalEntity.dateOfBirth.year = 1980; + legalEntity.dateOfBirth.month = 7; + legalEntity.dateOfBirth.day = 4; + + legalEntity.verification = [STPVerificationParams new]; + legalEntity.verification.document = @"file_abc"; + + STPPersonParams *jenny = [self personParams], *jacob = [self personParams]; + jenny.firstName = @"Jenny"; + jacob.firstName = @"Jacob"; + legalEntity.additionalOwners = @[jenny, jacob]; + + legalEntity.businessName = @"Internet Business"; + legalEntity.businessTaxId = @"123"; + legalEntity.businessVATId = @"456"; + legalEntity.genderString = @"female"; + legalEntity.personalAddress = [self address]; + legalEntity.personalAddress.state = @"CA"; + legalEntity.personalIdNumber = @"000000000"; + legalEntity.phoneNumber = @"555-1234"; + legalEntity.ssnLast4 = @"0000"; + legalEntity.taxIdRegistrar = @"321"; + legalEntity.entityTypeString = @"individual"; + + return legalEntity; +} + ++ (STPPersonParams *)personParams { + STPPersonParams *person = [STPPersonParams new]; + + person.firstName = @"James"; + person.lastName = @"Smith"; + person.maidenName = @"Jones"; + person.address = [self address]; + + person.dateOfBirth = [NSDateComponents new]; + person.dateOfBirth.year = 1980; + person.dateOfBirth.month = 7; + person.dateOfBirth.day = 4; + + person.verification = [STPVerificationParams new]; + person.verification.document = @"file_abc"; + + return person; +} + @end diff --git a/Tests/Tests/STPLegalEntityParamsTest.m b/Tests/Tests/STPLegalEntityParamsTest.m new file mode 100644 index 00000000000..4f97071db86 --- /dev/null +++ b/Tests/Tests/STPLegalEntityParamsTest.m @@ -0,0 +1,144 @@ +// +// STPLegalEntityParamsTest.m +// StripeiOS Tests +// +// Created by Daniel Jackson on 1/10/18. +// Copyright © 2018 Stripe, Inc. All rights reserved. +// + +#import + +#import "STPLegalEntityParams.h" + +@interface STPLegalEntityParamsTest : XCTestCase +@end + +@implementation STPLegalEntityParamsTest + +#pragma mark STPFormEncodable Tests + +- (void)testRootObjectName { + XCTAssertEqualObjects([STPLegalEntityParams rootObjectName], @"legal_entity"); +} + +- (void)testPropertyNamesToFormFieldNamesMapping { + STPLegalEntityParams *entityParams = [STPLegalEntityParams new]; + + NSDictionary *mapping = [STPLegalEntityParams propertyNamesToFormFieldNamesMapping]; + + for (NSString *propertyName in [mapping allKeys]) { + XCTAssertFalse([propertyName containsString:@":"]); + XCTAssert([entityParams respondsToSelector:NSSelectorFromString(propertyName)]); + } + + for (NSString *formFieldName in [mapping allValues]) { + XCTAssert([formFieldName isKindOfClass:[NSString class]]); + XCTAssert([formFieldName length] > 0); + } + + XCTAssertEqual([[mapping allValues] count], [[NSSet setWithArray:[mapping allValues]] count]); +} + +@end + + +@interface STPPersonParamsTest : XCTestCase +@end + +@implementation STPPersonParamsTest + +#pragma mark STPFormEncodable Tests + +- (void)testRootObjectName { + XCTAssertNil([STPPersonParams rootObjectName]); +} + +- (void)testPropertyNamesToFormFieldNamesMapping { + STPPersonParams *personParams = [STPPersonParams new]; + + NSDictionary *mapping = [STPPersonParams propertyNamesToFormFieldNamesMapping]; + + for (NSString *propertyName in [mapping allKeys]) { + XCTAssertFalse([propertyName containsString:@":"]); + XCTAssert([personParams respondsToSelector:NSSelectorFromString(propertyName)]); + } + + for (NSString *formFieldName in [mapping allValues]) { + XCTAssert([formFieldName isKindOfClass:[NSString class]]); + XCTAssert([formFieldName length] > 0); + } + + XCTAssertEqual([[mapping allValues] count], [[NSSet setWithArray:[mapping allValues]] count]); +} + +@end + + +@interface STPVerificationParamsTest : XCTestCase +@end + +@implementation STPVerificationParamsTest + +#pragma mark STPFormEncodable Tests + +- (void)testRootObjectName { + XCTAssertEqualObjects([STPVerificationParams rootObjectName], @"verification"); +} + +- (void)testPropertyNamesToFormFieldNamesMapping { + STPVerificationParams *verificationParams = [STPVerificationParams new]; + + NSDictionary *mapping = [STPVerificationParams propertyNamesToFormFieldNamesMapping]; + + for (NSString *propertyName in [mapping allKeys]) { + XCTAssertFalse([propertyName containsString:@":"]); + XCTAssert([verificationParams respondsToSelector:NSSelectorFromString(propertyName)]); + } + + for (NSString *formFieldName in [mapping allValues]) { + XCTAssert([formFieldName isKindOfClass:[NSString class]]); + XCTAssert([formFieldName length] > 0); + } + + XCTAssertEqual([[mapping allValues] count], [[NSSet setWithArray:[mapping allValues]] count]); +} + +@end + +// this was declared privately in STPLegalEntityParams.m +@interface NSDateComponents (STPFormEncodable) @end + +@interface STPDateComponentsFormEncodableTest : XCTestCase +@end + +@implementation STPDateComponentsFormEncodableTest + +#pragma mark STPFormEncodable Tests + +- (void)testIsFormEncodable { + XCTAssertTrue([[NSDateComponents class] conformsToProtocol:@protocol(STPFormEncodable)]); +} + +- (void)testRootObjectName { + XCTAssertNil([NSDateComponents rootObjectName]); +} + +- (void)testPropertyNamesToFormFieldNamesMapping { + NSDateComponents *components = [NSDateComponents new]; + + NSDictionary *mapping = [NSDateComponents propertyNamesToFormFieldNamesMapping]; + + for (NSString *propertyName in [mapping allKeys]) { + XCTAssertFalse([propertyName containsString:@":"]); + XCTAssert([components respondsToSelector:NSSelectorFromString(propertyName)]); + } + + for (NSString *formFieldName in [mapping allValues]) { + XCTAssert([formFieldName isKindOfClass:[NSString class]]); + XCTAssert([formFieldName length] > 0); + } + + XCTAssertEqual([[mapping allValues] count], [[NSSet setWithArray:[mapping allValues]] count]); +} + +@end