UNPKG

43.9 kBPlain TextView Raw
1//
2// TPSStripeManager.m
3// TPSStripe
4//
5// Created by Anton Petrov on 28.10.16.
6// Copyright © 2016 Tipsi. All rights reserved.
7//
8
9#import <EXPaymentsStripe/EXTPSStripeManager.h>
10#import <EXPaymentsStripe/EXTPSError.h>
11
12NSString * const kErrorKeyCode = @"errorCode";
13NSString * const kErrorKeyDescription = @"description";
14NSString * const kErrorKeyBusy = @"busy";
15NSString * const kErrorKeyApi = @"api";
16NSString * const kErrorKeyRedirectSpecific = @"redirectSpecific";
17NSString * const kErrorKeyCancelled = @"cancelled";
18NSString * const kErrorKeySourceStatusCanceled = @"sourceStatusCanceled";
19NSString * const kErrorKeySourceStatusPending = @"sourceStatusPending";
20NSString * const kErrorKeySourceStatusFailed = @"sourceStatusFailed";
21NSString * const kErrorKeySourceStatusUnknown = @"sourceStatusUnknown";
22NSString * const kErrorKeyDeviceNotSupportsNativePay = @"deviceNotSupportsNativePay";
23NSString * const kErrorKeyNoPaymentRequest = @"noPaymentRequest";
24NSString * const kErrorKeyNoMerchantIdentifier = @"noMerchantIdentifier";
25NSString * const kErrorKeyNoAmount = @"noAmount";
26
27@interface EXTPSStripeManager ()
28
29@property (nonatomic, weak) UMModuleRegistry *moduleRegistry;
30
31@end
32
33NSString * const TPSPaymentNetworkAmex = @"american_express";
34NSString * const TPSPaymentNetworkDiscover = @"discover";
35NSString * const TPSPaymentNetworkMasterCard = @"master_card";
36NSString * const TPSPaymentNetworkVisa = @"visa";
37
38@implementation EXTPSStripeManager
39{
40 NSString *publishableKey;
41 NSString *merchantId;
42 NSDictionary *errorCodes;
43
44 UMPromiseResolveBlock promiseResolver;
45 UMPromiseRejectBlock promiseRejector;
46
47 BOOL requestIsCompleted;
48
49 void (^applePayCompletion)(PKPaymentAuthorizationStatus);
50 NSError *applePayStripeError;
51}
52
53- (instancetype)init {
54 if ((self = [super init])) {
55 requestIsCompleted = YES;
56 }
57 return self;
58}
59
60- (dispatch_queue_t)methodQueue {
61 return dispatch_get_main_queue();
62}
63
64- (NSDictionary *)constantsToExport
65{
66 return @{
67 @"TPSErrorDomain": TPSErrorDomain,
68 @"TPSErrorCodeApplePayNotConfigured": [@(TPSErrorCodeApplePayNotConfigured) stringValue],
69 @"TPSErrorCodePreviousRequestNotCompleted": [@(TPSErrorCodePreviousRequestNotCompleted) stringValue],
70 @"TPSErrorCodeUserCancel": [@(TPSErrorCodeUserCancel) stringValue],
71 };
72}
73
74UM_REGISTER_MODULE();
75
76+ (const NSString *)exportedModuleName
77{
78 return @"StripeModule";
79}
80
81UM_EXPORT_METHOD_AS(init, init:(NSDictionary *)options
82 errorCodes:(NSDictionary *)errors
83 resolver:(UMPromiseResolveBlock)resolve
84 rejecter:(UMPromiseRejectBlock)reject) {
85 publishableKey = options[@"publishableKey"];
86 merchantId = options[@"merchantId"];
87 errorCodes = errors;
88 [Stripe setDefaultPublishableKey:publishableKey];
89 resolve(@(YES));
90}
91
92UM_EXPORT_METHOD_AS(deviceSupportsApplePay, deviceSupportsApplePay:(UMPromiseResolveBlock)resolve
93 rejecter:(UMPromiseRejectBlock)reject) {
94 resolve(@([PKPaymentAuthorizationViewController canMakePayments]));
95}
96
97UM_EXPORT_METHOD_AS(canMakeApplePayPayments, canMakeApplePayPayments:(NSDictionary *)options
98 resolver:(UMPromiseResolveBlock)resolve
99 rejecter:(UMPromiseRejectBlock)reject) {
100 NSArray <NSString *> *paymentNetworksStrings =
101 options[@"networks"] ?: [EXTPSStripeManager supportedPaymentNetworksStrings];
102
103 NSArray <PKPaymentNetwork> *networks = [self paymentNetworks:paymentNetworksStrings];
104 resolve(@([PKPaymentAuthorizationViewController canMakePaymentsUsingNetworks:networks]));
105}
106
107UM_EXPORT_METHOD_AS(completeApplePayRequest, completeApplePayRequest:(UMPromiseResolveBlock)resolve
108 rejecter:(UMPromiseRejectBlock)reject) {
109 if (applePayCompletion) {
110 promiseResolver = resolve;
111 [self resolveApplePayCompletion:PKPaymentAuthorizationStatusSuccess];
112 } else {
113 resolve(nil);
114 }
115}
116
117UM_EXPORT_METHOD_AS(cancelApplePayRequest, cancelApplePayRequest:(UMPromiseResolveBlock)resolve
118 rejecter:(UMPromiseRejectBlock)reject) {
119 if (applePayCompletion) {
120 promiseResolver = resolve;
121 [self resolveApplePayCompletion:PKPaymentAuthorizationStatusFailure];
122 } else {
123 resolve(nil);
124 }
125}
126
127UM_EXPORT_METHOD_AS(createTokenWithCard, createTokenWithCard:(NSDictionary *)params
128 resolver:(UMPromiseResolveBlock)resolve
129 rejecter:(UMPromiseRejectBlock)reject) {
130 if(!requestIsCompleted) {
131 NSDictionary *error = [errorCodes valueForKey:kErrorKeyBusy];
132 reject(error[kErrorKeyCode], error[kErrorKeyDescription], nil);
133 return;
134 }
135
136 requestIsCompleted = NO;
137
138 STPCardParams *cardParams = [[STPCardParams alloc] init];
139
140 [cardParams setNumber: params[@"number"]];
141 [cardParams setExpMonth: [params[@"expMonth"] integerValue]];
142 [cardParams setExpYear: [params[@"expYear"] integerValue]];
143 [cardParams setCvc: params[@"cvc"]];
144
145 [cardParams setCurrency: params[@"currency"]];
146 [cardParams setName: params[@"name"]];
147 [cardParams setAddressLine1: params[@"addressLine1"]];
148 [cardParams setAddressLine2: params[@"addressLine2"]];
149 [cardParams setAddressCity: params[@"addressCity"]];
150 [cardParams setAddressState: params[@"addressState"]];
151 [cardParams setAddressCountry: params[@"addressCountry"]];
152 [cardParams setAddressZip: params[@"addressZip"]];
153
154 STPAPIClient *stripeAPIClient = [self newAPIClient];
155
156 [stripeAPIClient createTokenWithCard:cardParams completion:^(STPToken *token, NSError *error) {
157 requestIsCompleted = YES;
158
159 if (error) {
160 NSDictionary *jsError = [errorCodes valueForKey:kErrorKeyApi];
161 [self rejectPromiseWithCode:jsError[kErrorKeyCode] message:error.localizedDescription];
162 } else {
163 resolve([self convertTokenObject:token]);
164 }
165 }];
166}
167
168UM_EXPORT_METHOD_AS(createTokenWithBankAccount, createTokenWithBankAccount:(NSDictionary *)params
169 resolver:(UMPromiseResolveBlock)resolve
170 rejecter:(UMPromiseRejectBlock)reject) {
171 if(!requestIsCompleted) {
172 NSDictionary *error = [errorCodes valueForKey:kErrorKeyBusy];
173 reject(error[kErrorKeyCode], error[kErrorKeyDescription], nil);
174 return;
175 }
176
177 requestIsCompleted = NO;
178
179 STPBankAccountParams *bankAccount = [[STPBankAccountParams alloc] init];
180
181 [bankAccount setAccountNumber: params[@"accountNumber"]];
182 [bankAccount setCountry: params[@"countryCode"]];
183 [bankAccount setCurrency: params[@"currency"]];
184 [bankAccount setRoutingNumber: params[@"routingNumber"]];
185 [bankAccount setAccountHolderName: params[@"accountHolderName"]];
186 STPBankAccountHolderType accountHolderType =
187 [EXTPSConvert holderType:params[@"accountHolderType"]];
188 [bankAccount setAccountHolderType: accountHolderType];
189
190 STPAPIClient *stripeAPIClient = [self newAPIClient];
191
192 [stripeAPIClient createTokenWithBankAccount:bankAccount completion:^(STPToken *token, NSError *error) {
193 requestIsCompleted = YES;
194
195 if (error) {
196 NSDictionary *jsError = [errorCodes valueForKey:kErrorKeyApi];
197 [self rejectPromiseWithCode:jsError[kErrorKeyCode] message:error.localizedDescription];
198 } else {
199 resolve([self convertTokenObject:token]);
200 }
201 }];
202}
203
204UM_EXPORT_METHOD_AS(createSourceWithParams, createSourceWithParams:(NSDictionary *)params
205 resolver:(UMPromiseResolveBlock)resolve
206 rejecter:(UMPromiseRejectBlock)reject) {
207 if(!requestIsCompleted) {
208 NSDictionary *error = [errorCodes valueForKey:kErrorKeyBusy];
209 reject(error[kErrorKeyCode], error[kErrorKeyDescription], nil);
210 return;
211 }
212
213 requestIsCompleted = NO;
214
215 NSString *sourceType = params[@"type"];
216 STPSourceParams *sourceParams;
217 if ([sourceType isEqualToString:@"bancontact"]) {
218 sourceParams = [STPSourceParams bancontactParamsWithAmount:[[params objectForKey:@"amount"] unsignedIntegerValue] name:params[@"name"] returnURL:params[@"returnURL"] statementDescriptor:params[@"statementDescriptor"]];
219 }
220 if ([sourceType isEqualToString:@"giropay"]) {
221 sourceParams = [STPSourceParams giropayParamsWithAmount:[[params objectForKey:@"amount"] unsignedIntegerValue] name:params[@"name"] returnURL:params[@"returnURL"] statementDescriptor:params[@"statementDescriptor"]];
222 }
223 if ([sourceType isEqualToString:@"ideal"]) {
224 sourceParams = [STPSourceParams idealParamsWithAmount:[[params objectForKey:@"amount"] unsignedIntegerValue] name:params[@"name"] returnURL:params[@"returnURL"] statementDescriptor:params[@"statementDescriptor"] bank:params[@"bank"]];
225 }
226 if ([sourceType isEqualToString:@"sepaDebit"]) {
227 sourceParams = [STPSourceParams sepaDebitParamsWithName:params[@"name"] iban:params[@"iban"] addressLine1:params[@"addressLine1"] city:params[@"city"] postalCode:params[@"postalCode"] country:params[@"country"]];
228 }
229 if ([sourceType isEqualToString:@"sofort"]) {
230 sourceParams = [STPSourceParams sofortParamsWithAmount:[[params objectForKey:@"amount"] unsignedIntegerValue] returnURL:params[@"returnURL"] country:params[@"country"] statementDescriptor:params[@"statementDescriptor"]];
231 }
232 if ([sourceType isEqualToString:@"threeDSecure"]) {
233 sourceParams = [STPSourceParams threeDSecureParamsWithAmount:[[params objectForKey:@"amount"] unsignedIntegerValue] currency:params[@"currency"] returnURL:params[@"returnURL"] card:params[@"card"]];
234 }
235 if ([sourceType isEqualToString:@"alipay"]) {
236 sourceParams = [STPSourceParams alipayParamsWithAmount:[[params objectForKey:@"amount"] unsignedIntegerValue] currency:params[@"currency"] returnURL:params[@"returnURL"]];
237 }
238
239 [[STPAPIClient sharedClient] createSourceWithParams:sourceParams completion:^(STPSource *source, NSError *error) {
240 requestIsCompleted = YES;
241
242 if (error) {
243 reject(nil, nil, error);
244 } else {
245 if (source.redirect) {
246 self.redirectContext = [[STPRedirectContext alloc] initWithSource:source completion:^(NSString *sourceID, NSString *clientSecret, NSError *error) {
247 if (error) {
248 NSDictionary *jsError = [errorCodes valueForKey:kErrorKeyRedirectSpecific];
249 reject(jsError[kErrorKeyCode], error.localizedDescription, nil);
250 } else {
251 [[STPAPIClient sharedClient] startPollingSourceWithId:sourceID clientSecret:clientSecret timeout:10 completion:^(STPSource *source, NSError *error) {
252 if (error) {
253 NSDictionary *jsError = [errorCodes valueForKey:kErrorKeyApi];
254 reject(jsError[kErrorKeyCode], error.localizedDescription, nil);
255 } else {
256 switch (source.status) {
257 case STPSourceStatusChargeable:
258 case STPSourceStatusConsumed:
259 resolve([self convertSourceObject:source]);
260 break;
261 case STPSourceStatusCanceled: {
262 NSDictionary *error = [errorCodes valueForKey:kErrorKeySourceStatusCanceled];
263 reject(error[kErrorKeyCode], error[kErrorKeyDescription], nil);
264 }
265 break;
266 case STPSourceStatusPending: {
267 NSDictionary *error = [errorCodes valueForKey:kErrorKeySourceStatusPending];
268 reject(error[kErrorKeyCode], error[kErrorKeyDescription], nil);
269 }
270 break;
271 case STPSourceStatusFailed: {
272 NSDictionary *error = [errorCodes valueForKey:kErrorKeySourceStatusFailed];
273 reject(error[kErrorKeyCode], error[kErrorKeyDescription], nil);
274 }
275 break;
276 case STPSourceStatusUnknown: {
277 NSDictionary *error = [errorCodes valueForKey:kErrorKeySourceStatusUnknown];
278 reject(error[kErrorKeyCode], error[kErrorKeyDescription], nil);
279 }
280 break;
281 }
282 }
283 }];
284 }
285 }];
286 [self.redirectContext startSafariAppRedirectFlow];
287 } else {
288 resolve([self convertSourceObject:source]);
289 }
290 }
291 }];
292}
293
294UM_EXPORT_METHOD_AS(paymentRequestWithCardForm, paymentRequestWithCardForm:(NSDictionary *)options
295 resolver:(UMPromiseResolveBlock)resolve
296 rejecter:(UMPromiseRejectBlock)reject) {
297 if(!requestIsCompleted) {
298 NSDictionary *error = [errorCodes valueForKey:kErrorKeyBusy];
299 reject(error[kErrorKeyCode], error[kErrorKeyDescription], nil);
300 return;
301 }
302
303 requestIsCompleted = NO;
304 // Save promise handlers to use in `paymentAuthorizationViewController`
305 promiseResolver = resolve;
306 promiseRejector = reject;
307
308 NSUInteger requiredBillingAddressFields = [self billingType:options[@"requiredBillingAddressFields"]];
309 NSString *companyName = options[@"companyName"] ? options[@"companyName"] : @"";
310 STPUserInformation *prefilledInformation = [self userInformation:options[@"prefilledInformation"]];
311 NSString *managedAccountCurrency = options[@"managedAccountCurrency"];
312 NSString *nextPublishableKey = options[@"publishableKey"] ? options[@"publishableKey"] : publishableKey;
313 UIModalPresentationStyle formPresentation = [self formPresentation:options[@"presentation"]];
314 STPTheme *theme = [self formTheme:options[@"theme"]];
315
316 STPPaymentConfiguration *configuration = [[STPPaymentConfiguration alloc] init];
317 [configuration setRequiredBillingAddressFields:requiredBillingAddressFields];
318 [configuration setCompanyName:companyName];
319 [configuration setPublishableKey:nextPublishableKey];
320
321 [configuration setCreateCardSources:[options[@"createCardSource"] boolValue]];
322
323
324 STPAddCardViewController *addCardViewController = [[STPAddCardViewController alloc] initWithConfiguration:configuration theme:theme];
325 [addCardViewController setDelegate:self];
326 [addCardViewController setPrefilledInformation:prefilledInformation];
327 [addCardViewController setManagedAccountCurrency:managedAccountCurrency];
328 // STPAddCardViewController must be shown inside a UINavigationController.
329 UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:addCardViewController];
330 [navigationController setModalPresentationStyle:formPresentation];
331 navigationController.navigationBar.stp_theme = theme;
332 [[self getViewController] presentViewController:navigationController animated:YES completion:nil];
333}
334
335UM_EXPORT_METHOD_AS(paymentRequestWithApplePay, paymentRequestWithApplePay:(NSArray *)items
336 withOptions:(NSDictionary *)options
337 resolver:(UMPromiseResolveBlock)resolve
338 rejecter:(UMPromiseRejectBlock)reject) {
339 if(!requestIsCompleted) {
340 NSDictionary *error = [errorCodes valueForKey:kErrorKeyBusy];
341 reject(error[kErrorKeyCode], error[kErrorKeyDescription], nil);
342 return;
343 }
344
345 requestIsCompleted = NO;
346 // Save promise handlers to use in `paymentAuthorizationViewController`
347 promiseResolver = resolve;
348 promiseRejector = reject;
349
350 NSUInteger requiredShippingAddressFields = [self applePayAddressFields:options[@"requiredShippingAddressFields"]];
351 NSUInteger requiredBillingAddressFields = [self applePayAddressFields:options[@"requiredBillingAddressFields"]];
352 PKShippingType shippingType = [self applePayShippingType:options[@"shippingType"]];
353 NSMutableArray *shippingMethodsItems = options[@"shippingMethods"] ? options[@"shippingMethods"] : [NSMutableArray array];
354 NSString* currencyCode = options[@"currencyCode"] ? options[@"currencyCode"] : @"USD";
355 NSString* countryCode = options[@"countryCode"] ? options[@"countryCode"] : @"US";
356
357 NSMutableArray *shippingMethods = [NSMutableArray array];
358
359 for (NSDictionary *item in shippingMethodsItems) {
360 PKShippingMethod *shippingItem = [[PKShippingMethod alloc] init];
361 shippingItem.label = item[@"label"];
362 shippingItem.detail = item[@"detail"];
363 shippingItem.amount = [NSDecimalNumber decimalNumberWithString:item[@"amount"]];
364 shippingItem.identifier = item[@"id"];
365 [shippingMethods addObject:shippingItem];
366 }
367
368 NSMutableArray *summaryItems = [NSMutableArray array];
369
370 for (NSDictionary *item in items) {
371 PKPaymentSummaryItem *summaryItem = [[PKPaymentSummaryItem alloc] init];
372 summaryItem.label = item[@"label"];
373 summaryItem.amount = [NSDecimalNumber decimalNumberWithString:item[@"amount"]];
374 summaryItem.type = [@"pending" isEqualToString:item[@"type"]] ? PKPaymentSummaryItemTypePending : PKPaymentSummaryItemTypeFinal;
375 [summaryItems addObject:summaryItem];
376 }
377
378 PKPaymentRequest *paymentRequest = [Stripe paymentRequestWithMerchantIdentifier:merchantId country:countryCode currency:currencyCode];
379
380 [paymentRequest setRequiredShippingAddressFields:requiredShippingAddressFields];
381 [paymentRequest setRequiredBillingAddressFields:requiredBillingAddressFields];
382 [paymentRequest setPaymentSummaryItems:summaryItems];
383 [paymentRequest setShippingMethods:shippingMethods];
384 [paymentRequest setShippingType:shippingType];
385
386 if ([self canSubmitPaymentRequest:paymentRequest rejecter:reject]) {
387 PKPaymentAuthorizationViewController *paymentAuthorizationVC = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest:paymentRequest];
388 paymentAuthorizationVC.delegate = self;
389 [[self getViewController] presentViewController:paymentAuthorizationVC animated:YES completion:nil];
390 } else {
391 // There is a problem with your Apple Pay configuration.
392 [self resetPromiseCallbacks];
393 requestIsCompleted = YES;
394 }
395}
396
397UM_EXPORT_METHOD_AS(openApplePaySetup, openApplePaySetup:(UMPromiseResolveBlock)resolve
398 rejecter:(UMPromiseRejectBlock)reject) {
399 PKPassLibrary *library = [[PKPassLibrary alloc] init];
400
401 // Here we should check, if openPaymentSetup selector exist
402 if ([library respondsToSelector:NSSelectorFromString(@"openPaymentSetup")]) {
403 [library openPaymentSetup];
404 }
405}
406
407#pragma mark - Private
408
409-(UIViewController*) getViewController {
410 return [[_moduleRegistry getModuleImplementingProtocol:@protocol(UMUtilitiesInterface)] currentViewController];
411}
412
413- (void)resolvePromise:(id)result {
414 if (promiseResolver) {
415 promiseResolver(result);
416 }
417 [self resetPromiseCallbacks];
418}
419
420- (void)rejectPromiseWithCode:(NSString *)code message:(NSString *)message {
421 if (promiseRejector) {
422 promiseRejector(code, message, nil);
423 }
424 [self resetPromiseCallbacks];
425}
426
427- (void)resetPromiseCallbacks {
428 promiseResolver = nil;
429 promiseRejector = nil;
430}
431
432- (void)resolveApplePayCompletion:(PKPaymentAuthorizationStatus)status {
433 if (applePayCompletion) {
434 applePayCompletion(status);
435 }
436 [self resetApplePayCallback];
437}
438
439- (void)resetApplePayCallback {
440 applePayCompletion = nil;
441}
442
443- (BOOL)canSubmitPaymentRequest:(PKPaymentRequest *)paymentRequest rejecter:(UMPromiseRejectBlock)reject {
444 if (![Stripe deviceSupportsApplePay]) {
445 NSDictionary *error = [errorCodes valueForKey:kErrorKeyDeviceNotSupportsNativePay];
446 reject(error[kErrorKeyCode], error[kErrorKeyDescription], nil);
447 return NO;
448 }
449 if (paymentRequest == nil) {
450 NSDictionary *error = [errorCodes valueForKey:kErrorKeyNoPaymentRequest];
451 reject(error[kErrorKeyCode], error[kErrorKeyDescription], nil);
452 return NO;
453 }
454 if (paymentRequest.merchantIdentifier == nil) {
455 NSDictionary *error = [errorCodes valueForKey:kErrorKeyNoMerchantIdentifier];
456 reject(error[kErrorKeyCode], error[kErrorKeyDescription], nil);
457 return NO;
458 }
459 if ([[[paymentRequest.paymentSummaryItems lastObject] amount] floatValue] == 0) {
460 NSDictionary *error = [errorCodes valueForKey:kErrorKeyNoAmount];
461 reject(error[kErrorKeyCode], error[kErrorKeyDescription], nil);
462 return NO;
463 }
464 return YES;
465}
466
467#pragma mark - STPAddCardViewControllerDelegate
468
469- (void)addCardViewController:(STPAddCardViewController *)controller
470 didCreateToken:(STPToken *)token
471 completion:(STPErrorBlock)completion {
472 [[self getViewController] dismissViewControllerAnimated:YES completion:nil];
473
474 requestIsCompleted = YES;
475 completion(nil);
476 [self resolvePromise:[self convertTokenObject:token]];
477}
478
479- (void)addCardViewController:(STPAddCardViewController *)controller
480 didCreateSource:(STPSource *)source
481 completion:(STPErrorBlock)completion {
482 [[self getViewController] dismissViewControllerAnimated:YES completion:nil];
483
484 requestIsCompleted = YES;
485 completion(nil);
486 [self resolvePromise:[self convertSourceObject:source]];
487}
488
489- (void)addCardViewControllerDidCancel:(STPAddCardViewController *)addCardViewController {
490 [[self getViewController] dismissViewControllerAnimated:YES completion:nil];
491
492 if (!requestIsCompleted) {
493 requestIsCompleted = YES;
494 NSDictionary *error = [errorCodes valueForKey:kErrorKeyCancelled];
495 [self rejectPromiseWithCode:error[kErrorKeyCode] message:error[kErrorKeyDescription]];
496 }
497
498}
499
500#pragma mark PKPaymentAuthorizationViewControllerDelegate
501
502- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
503 didAuthorizePayment:(PKPayment *)payment
504 completion:(void (^)(PKPaymentAuthorizationStatus))completion {
505 // Save for deffered call
506 applePayCompletion = completion;
507
508 STPAPIClient *stripeAPIClient = [self newAPIClient];
509
510 [stripeAPIClient createTokenWithPayment:payment completion:^(STPToken * _Nullable token, NSError * _Nullable error) {
511 requestIsCompleted = YES;
512
513 if (error) {
514 // Save for deffered use
515 applePayStripeError = error;
516 [self resolveApplePayCompletion:PKPaymentAuthorizationStatusFailure];
517 } else {
518 NSDictionary *result = [self convertTokenObject:token];
519 NSDictionary *extra = @{
520 @"billingContact": [self contactDetails:payment.billingContact] ?: [NSNull null],
521 @"shippingContact": [self contactDetails:payment.shippingContact] ?: [NSNull null],
522 @"shippingMethod": [self shippingDetails:payment.shippingMethod] ?: [NSNull null]
523 };
524
525 [result setValue:extra forKey:@"extra"];
526
527 [self resolvePromise:result];
528 }
529 }];
530}
531
532
533- (void)paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller {
534 [self resetApplePayCallback];
535
536 void(^completion)() = ^{
537 if (!requestIsCompleted) {
538 requestIsCompleted = YES;
539
540 NSDictionary *error = [errorCodes valueForKey:kErrorKeyCancelled];
541 [self rejectPromiseWithCode:error[kErrorKeyCode] message:error[kErrorKeyDescription]];
542 } else {
543 if (applePayStripeError) {
544 NSDictionary *error = [errorCodes valueForKey:kErrorKeyApi];
545 [self rejectPromiseWithCode:error[kErrorKeyCode] message:applePayStripeError.localizedDescription];
546 applePayStripeError = nil;
547 } else {
548 [self resolvePromise:nil];
549 }
550 }
551 };
552
553 [[self getViewController] dismissViewControllerAnimated:YES completion:completion];
554}
555
556- (STPAPIClient *)newAPIClient {
557 return [[STPAPIClient alloc] initWithPublishableKey:[Stripe defaultPublishableKey]];
558}
559
560- (NSDictionary *)convertTokenObject:(STPToken*)token {
561 NSMutableDictionary *result = [@{} mutableCopy];
562
563 // Token
564 [result setValue:token.tokenId forKey:@"tokenId"];
565 [result setValue:@([token.created timeIntervalSince1970]) forKey:@"created"];
566 [result setValue:@(token.livemode) forKey:@"livemode"];
567
568 // Card
569 if (token.card) {
570 NSMutableDictionary *card = [@{} mutableCopy];
571 [result setValue:card forKey:@"card"];
572
573 [card setValue:token.card.stripeID forKey:@"cardId"];
574
575 [card setValue:[self cardBrand:token.card.brand] forKey:@"brand"];
576 [card setValue:[self cardFunding:token.card.funding] forKey:@"funding"];
577 [card setValue:token.card.last4 forKey:@"last4"];
578 [card setValue:token.card.dynamicLast4 forKey:@"dynamicLast4"];
579 [card setValue:@(token.card.isApplePayCard) forKey:@"isApplePayCard"];
580 [card setValue:@(token.card.expMonth) forKey:@"expMonth"];
581 [card setValue:@(token.card.expYear) forKey:@"expYear"];
582 [card setValue:token.card.country forKey:@"country"];
583 [card setValue:token.card.currency forKey:@"currency"];
584
585 [card setValue:token.card.name forKey:@"name"];
586 [card setValue:token.card.address.line1 forKey:@"addressLine1"];
587 [card setValue:token.card.address.line2 forKey:@"addressLine2"];
588 [card setValue:token.card.address.city forKey:@"addressCity"];
589 [card setValue:token.card.address.state forKey:@"addressState"];
590 [card setValue:token.card.address.country forKey:@"addressCountry"];
591 [card setValue:token.card.address.postalCode forKey:@"addressZip"];
592 }
593
594 // Bank Account
595 if (token.bankAccount) {
596 NSMutableDictionary *bankAccount = [@{} mutableCopy];
597 [result setValue:bankAccount forKey:@"bankAccount"];
598
599 NSString *bankAccountStatusString =
600 [EXTPSConvert STPBankAccountStatusToString:token.bankAccount.status];
601 [bankAccount setValue:bankAccountStatusString forKey:@"status"];
602 [bankAccount setValue:token.bankAccount.country forKey:@"countryCode"];
603 [bankAccount setValue:token.bankAccount.currency forKey:@"currency"];
604 [bankAccount setValue:token.bankAccount.stripeID forKey:@"bankAccountId"];
605 [bankAccount setValue:token.bankAccount.bankName forKey:@"bankName"];
606 [bankAccount setValue:token.bankAccount.last4 forKey:@"last4"];
607 [bankAccount setValue:token.bankAccount.accountHolderName forKey:@"accountHolderName"];
608 NSString *bankAccountHolderTypeString =
609 [EXTPSConvert STPBankAccountHolderTypeToString:token.bankAccount.accountHolderType];
610 [bankAccount setValue:bankAccountHolderTypeString forKey:@"accountHolderType"];
611 }
612
613 return result;
614}
615
616- (NSDictionary *)convertSourceObject:(STPSource*)source {
617 NSMutableDictionary *result = [@{} mutableCopy];
618
619 // Source
620 [result setValue:source.clientSecret forKey:@"clientSecret"];
621 [result setValue:@([source.created timeIntervalSince1970]) forKey:@"created"];
622 [result setValue:source.currency forKey:@"currency"];
623 [result setValue:@(source.livemode) forKey:@"livemode"];
624 [result setValue:source.amount forKey:@"amount"];
625 [result setValue:source.stripeID forKey:@"sourceId"];
626
627 // Flow
628 [result setValue:[self sourceFlow:source.flow] forKey:@"flow"];
629
630 // Metadata
631 if (source.metadata) {
632 [result setValue:source.metadata forKey:@"metadata"];
633 }
634
635 // Owner
636 if (source.owner) {
637 NSMutableDictionary *owner = [@{} mutableCopy];
638 [result setValue:owner forKey:@"owner"];
639
640 if (source.owner.address) {
641 [owner setObject:source.owner.address forKey:@"address"];
642 }
643 [owner setValue:source.owner.email forKey:@"email"];
644 [owner setValue:source.owner.name forKey:@"name"];
645 [owner setValue:source.owner.phone forKey:@"phone"];
646 if (source.owner.verifiedAddress) {
647 [owner setObject:source.owner.verifiedAddress forKey:@"verifiedAddress"];
648 }
649 [owner setValue:source.owner.verifiedEmail forKey:@"verifiedEmail"];
650 [owner setValue:source.owner.verifiedName forKey:@"verifiedName"];
651 [owner setValue:source.owner.verifiedPhone forKey:@"verifiedPhone"];
652 }
653
654 // Details
655 if (source.details) {
656 [result setValue:source.details forKey:@"details"];
657 }
658
659 // Receiver
660 if (source.receiver) {
661 NSMutableDictionary *receiver = [@{} mutableCopy];
662 [result setValue:receiver forKey:@"receiver"];
663
664 [receiver setValue:source.receiver.address forKey:@"address"];
665 [receiver setValue:source.receiver.amountCharged forKey:@"amountCharged"];
666 [receiver setValue:source.receiver.amountReceived forKey:@"amountReceived"];
667 [receiver setValue:source.receiver.amountReturned forKey:@"amountReturned"];
668 }
669
670 // Redirect
671 if (source.redirect) {
672 NSMutableDictionary *redirect = [@{} mutableCopy];
673 [result setValue:redirect forKey:@"redirect"];
674 NSString *returnURL = source.redirect.returnURL.absoluteString;
675 [redirect setValue:returnURL forKey:@"returnURL"];
676 NSString *url = source.redirect.url.absoluteString;
677 [redirect setValue:url forKey:@"url"];
678 [redirect setValue:[self sourceRedirectStatus:source.redirect.status] forKey:@"status"];
679 }
680
681 // Verification
682 if (source.verification) {
683 NSMutableDictionary *verification = [@{} mutableCopy];
684 [result setValue:verification forKey:@"verification"];
685
686 [verification setValue:source.verification.attemptsRemaining forKey:@"attemptsRemaining"];
687 [verification setValue:[self sourceVerificationStatus:source.verification.status] forKey:@"status"];
688 }
689
690 // Status
691 [result setValue:[self sourceStatus:source.status] forKey:@"status"];
692
693 // Type
694 [result setValue:[self sourceType:source.type] forKey:@"type"];
695
696 // Usage
697 [result setValue:[self sourceUsage:source.usage] forKey:@"usage"];
698
699 // CardDetails
700 if (source.cardDetails) {
701 NSMutableDictionary *cardDetails = [@{} mutableCopy];
702 [result setValue:cardDetails forKey:@"cardDetails"];
703
704 [cardDetails setValue:source.cardDetails.last4 forKey:@"last4"];
705 [cardDetails setValue:@(source.cardDetails.expMonth) forKey:@"expMonth"];
706 [cardDetails setValue:@(source.cardDetails.expYear) forKey:@"expYear"];
707 [cardDetails setValue:[self cardBrand:source.cardDetails.brand] forKey:@"brand"];
708 [cardDetails setValue:[self cardFunding:source.cardDetails.funding] forKey:@"funding"];
709 [cardDetails setValue:source.cardDetails.country forKey:@"country"];
710 [cardDetails setValue:[self card3DSecureStatus:source.cardDetails.threeDSecure] forKey:@"threeDSecure"];
711 }
712
713 // SepaDebitDetails
714 if (source.sepaDebitDetails) {
715 NSMutableDictionary *sepaDebitDetails = [@{} mutableCopy];
716 [result setValue:sepaDebitDetails forKey:@"sepaDebitDetails"];
717
718 [sepaDebitDetails setValue:source.sepaDebitDetails.last4 forKey:@"last4"];
719 [sepaDebitDetails setValue:source.sepaDebitDetails.bankCode forKey:@"bankCode"];
720 [sepaDebitDetails setValue:source.sepaDebitDetails.country forKey:@"country"];
721 [sepaDebitDetails setValue:source.sepaDebitDetails.fingerprint forKey:@"fingerprint"];
722 [sepaDebitDetails setValue:source.sepaDebitDetails.mandateReference forKey:@"mandateReference"];
723 NSString *mandateURL = source.sepaDebitDetails.mandateURL.absoluteString;
724 [sepaDebitDetails setValue:mandateURL forKey:@"mandateURL"];
725 }
726
727 return result;
728}
729
730- (NSString *)cardBrand:(STPCardBrand)inputBrand {
731 switch (inputBrand) {
732 case STPCardBrandJCB:
733 return @"JCB";
734 case STPCardBrandAmex:
735 return @"American Express";
736 case STPCardBrandVisa:
737 return @"Visa";
738 case STPCardBrandDiscover:
739 return @"Discover";
740 case STPCardBrandDinersClub:
741 return @"Diners Club";
742 case STPCardBrandMasterCard:
743 return @"MasterCard";
744 default:
745 return @"Unknown";
746 }
747}
748
749- (NSString *)cardFunding:(STPCardFundingType)inputFunding {
750 switch (inputFunding) {
751 case STPCardFundingTypeDebit:
752 return @"debit";
753 case STPCardFundingTypeCredit:
754 return @"credit";
755 case STPCardFundingTypePrepaid:
756 return @"prepaid";
757 case STPCardFundingTypeOther:
758 default:
759 return @"unknown";
760 }
761}
762
763- (NSString *)card3DSecureStatus:(STPSourceCard3DSecureStatus)inputStatus {
764 switch (inputStatus) {
765 case STPSourceCard3DSecureStatusRequired:
766 return @"required";
767 case STPSourceCard3DSecureStatusOptional:
768 return @"optional";
769 case STPSourceCard3DSecureStatusNotSupported:
770 return @"notSupported";
771 case STPSourceCard3DSecureStatusUnknown:
772 default:
773 return @"unknown";
774 }
775}
776
777- (NSString *)sourceFlow:(STPSourceFlow)inputFlow {
778 switch (inputFlow) {
779 case STPSourceFlowNone:
780 return @"none";
781 case STPSourceFlowRedirect:
782 return @"redirect";
783 case STPSourceFlowCodeVerification:
784 return @"codeVerification";
785 case STPSourceFlowReceiver:
786 return @"receiver";
787 case STPSourceFlowUnknown:
788 default:
789 return @"unknown";
790 }
791}
792
793- (NSString *)sourceRedirectStatus:(STPSourceRedirectStatus)inputStatus {
794 switch (inputStatus) {
795 case STPSourceRedirectStatusPending:
796 return @"pending";
797 case STPSourceRedirectStatusSucceeded:
798 return @"succeeded";
799 case STPSourceRedirectStatusFailed:
800 return @"failed";
801 case STPSourceRedirectStatusUnknown:
802 default:
803 return @"unknown";
804 }
805}
806
807- (NSString *)sourceVerificationStatus:(STPSourceVerificationStatus)inputStatus {
808 switch (inputStatus) {
809 case STPSourceVerificationStatusPending:
810 return @"pending";
811 case STPSourceVerificationStatusSucceeded:
812 return @"succeeded";
813 case STPSourceVerificationStatusFailed:
814 return @"failed";
815 case STPSourceVerificationStatusUnknown:
816 default:
817 return @"unknown";
818 }
819}
820
821- (NSString *)sourceStatus:(STPSourceStatus)inputStatus {
822 switch (inputStatus) {
823 case STPSourceStatusPending:
824 return @"pending";
825 case STPSourceStatusChargeable:
826 return @"chargable";
827 case STPSourceStatusConsumed:
828 return @"consumed";
829 case STPSourceStatusCanceled:
830 return @"canceled";
831 case STPSourceStatusFailed:
832 return @"failed";
833 case STPSourceStatusUnknown:
834 default:
835 return @"unknown";
836 }
837}
838
839- (NSString *)sourceType:(STPSourceType)inputType {
840 switch (inputType) {
841 case STPSourceTypeBancontact:
842 return @"bancontact";
843 case STPSourceTypeGiropay:
844 return @"giropay";
845 case STPSourceTypeIDEAL:
846 return @"ideal";
847 case STPSourceTypeSEPADebit:
848 return @"sepaDebit";
849 case STPSourceTypeSofort:
850 return @"sofort";
851 case STPSourceTypeThreeDSecure:
852 return @"threeDSecure";
853 case STPSourceTypeAlipay:
854 return @"alipay";
855 case STPSourceTypeUnknown:
856 default:
857 return @"unknown";
858 }
859}
860
861- (NSString *)sourceUsage:(STPSourceUsage)inputUsage {
862 switch (inputUsage) {
863 case STPSourceUsageReusable:
864 return @"reusable";
865 case STPSourceUsageSingleUse:
866 return @"singleUse";
867 case STPSourceUsageUnknown:
868 default:
869 return @"unknown";
870 }
871}
872
873- (NSDictionary *)contactDetails:(PKContact*)inputContact {
874 NSMutableDictionary *contactDetails = [[NSMutableDictionary alloc] init];
875
876 if (inputContact.name) {
877 [contactDetails setValue:[NSPersonNameComponentsFormatter localizedStringFromPersonNameComponents:inputContact.name style:NSPersonNameComponentsFormatterStyleDefault options:0] forKey:@"name"];
878 }
879
880 if (inputContact.phoneNumber) {
881 [contactDetails setValue:[inputContact.phoneNumber stringValue] forKey:@"phoneNumber"];
882 }
883
884 if (inputContact.emailAddress) {
885 [contactDetails setValue:inputContact.emailAddress forKey:@"emailAddress"];
886 }
887
888 if (inputContact.supplementarySubLocality) {
889 [contactDetails setValue:inputContact.supplementarySubLocality forKey:@"supplementarySubLocality"];
890 }
891
892 for (NSString *elem in @[@"street", @"city", @"state", @"country", @"ISOCountryCode", @"postalCode"]) {
893 if ([inputContact.postalAddress respondsToSelector:NSSelectorFromString(elem)]) {
894 [contactDetails setValue:[inputContact.postalAddress valueForKey:elem] forKey:elem];
895 }
896 }
897 if ([contactDetails count] == 0) {
898 return nil;
899 }
900
901 return contactDetails;
902}
903
904- (NSDictionary *)shippingDetails:(PKShippingMethod*)inputShipping {
905 NSMutableDictionary *shippingDetails = [[NSMutableDictionary alloc] init];
906
907 if (inputShipping.label) {
908 [shippingDetails setValue:inputShipping.label forKey:@"label"];
909 }
910
911 if (inputShipping.amount) {
912 [shippingDetails setValue:[[self numberFormatter] stringFromNumber: inputShipping.amount] forKey:@"amount"];
913 }
914
915 if (inputShipping.detail) {
916 [shippingDetails setValue:inputShipping.detail forKey:@"detail"];
917 }
918
919 if (inputShipping.identifier) {
920 [shippingDetails setValue:inputShipping.identifier forKey:@"id"];
921 }
922
923 if ([shippingDetails count] == 0) {
924 return nil;
925 }
926
927 return shippingDetails;
928}
929
930- (PKAddressField)applePayAddressFields:(NSArray <NSString *> *)addressFieldStrings {
931 PKAddressField addressField = PKAddressFieldNone;
932
933 for (NSString *addressFieldString in addressFieldStrings) {
934 addressField |= [self applePayAddressField:addressFieldString];
935 }
936
937 return addressField;
938}
939
940- (PKAddressField)applePayAddressField:(NSString *)addressFieldString {
941 PKAddressField addressField = PKAddressFieldNone;
942 if ([addressFieldString isEqualToString:@"postal_address"]) {
943 addressField = PKAddressFieldPostalAddress;
944 }
945 if ([addressFieldString isEqualToString:@"phone"]) {
946 addressField = PKAddressFieldPhone;
947 }
948 if ([addressFieldString isEqualToString:@"email"]) {
949 addressField = PKAddressFieldEmail;
950 }
951 if ([addressFieldString isEqualToString:@"name"]) {
952 addressField = PKAddressFieldName;
953 }
954 if ([addressFieldString isEqualToString:@"all"]) {
955 addressField = PKAddressFieldAll;
956 }
957 return addressField;
958}
959
960- (PKShippingType)applePayShippingType:(NSString*)inputType {
961 PKShippingType shippingType = PKShippingTypeShipping;
962 if ([inputType isEqualToString:@"delivery"]) {
963 shippingType = PKShippingTypeDelivery;
964 }
965 if ([inputType isEqualToString:@"store_pickup"]) {
966 shippingType = PKShippingTypeStorePickup;
967 }
968 if ([inputType isEqualToString:@"service_pickup"]) {
969 shippingType = PKShippingTypeServicePickup;
970 }
971
972 return shippingType;
973}
974
975- (STPBillingAddressFields)billingType:(NSString*)inputType {
976 if ([inputType isEqualToString:@"zip"]) {
977 return STPBillingAddressFieldsZip;
978 }
979 if ([inputType isEqualToString:@"full"]) {
980 return STPBillingAddressFieldsFull;
981 }
982 return STPBillingAddressFieldsNone;
983}
984
985- (STPUserInformation *)userInformation:(NSDictionary*)inputInformation {
986 STPUserInformation *userInformation = [[STPUserInformation alloc] init];
987
988 [userInformation setBillingAddress: [self address:inputInformation[@"billingAddress"]]];
989 [userInformation setShippingAddress: [self address:inputInformation[@"shippingAddress"]]];
990
991 return userInformation;
992}
993
994- (STPAddress *)address:(NSDictionary*)inputAddress {
995 STPAddress *address = [[STPAddress alloc] init];
996
997 [address setName:inputAddress[@"name"]];
998 [address setLine1:inputAddress[@"line1"]];
999 [address setLine2:inputAddress[@"line2"]];
1000 [address setCity:inputAddress[@"city"]];
1001 [address setState:inputAddress[@"state"]];
1002 [address setPostalCode:inputAddress[@"postalCode"]];
1003 [address setCountry:inputAddress[@"country"]];
1004 [address setPhone:inputAddress[@"phone"]];
1005 [address setEmail:inputAddress[@"email"]];
1006
1007 return address;
1008}
1009
1010- (STPTheme *)formTheme:(NSDictionary*)options {
1011 STPTheme *theme = [[STPTheme alloc] init];
1012
1013 [theme setPrimaryBackgroundColor:[EXTPSConvert UIColor:options[@"primaryBackgroundColor"]]];
1014 [theme setSecondaryBackgroundColor:[EXTPSConvert UIColor:options[@"secondaryBackgroundColor"]]];
1015 [theme setPrimaryForegroundColor:[EXTPSConvert UIColor:options[@"primaryForegroundColor"]]];
1016 [theme setSecondaryForegroundColor:[EXTPSConvert UIColor:options[@"secondaryForegroundColor"]]];
1017 [theme setAccentColor:[EXTPSConvert UIColor:options[@"accentColor"]]];
1018 [theme setErrorColor:[EXTPSConvert UIColor:options[@"errorColor"]]];
1019 [theme setErrorColor:[EXTPSConvert UIColor:options[@"errorColor"]]];
1020 // TODO: process font vars
1021
1022 return theme;
1023}
1024
1025- (UIModalPresentationStyle)formPresentation:(NSString*)inputType {
1026 if ([inputType isEqualToString:@"pageSheet"])
1027 return UIModalPresentationPageSheet;
1028 if ([inputType isEqualToString:@"formSheet"])
1029 return UIModalPresentationFormSheet;
1030
1031 return UIModalPresentationFullScreen;
1032}
1033
1034+ (NSArray <NSString *> *)supportedPaymentNetworksStrings {
1035 return @[
1036 TPSPaymentNetworkAmex,
1037 TPSPaymentNetworkDiscover,
1038 TPSPaymentNetworkMasterCard,
1039 TPSPaymentNetworkVisa,
1040 ];
1041}
1042
1043- (NSArray <PKPaymentNetwork> *)paymentNetworks:(NSArray <NSString *> *)paymentNetworkStrings {
1044 NSMutableArray <PKPaymentNetwork> *results = [@[] mutableCopy];
1045
1046 for (NSString *paymentNetworkString in paymentNetworkStrings) {
1047 PKPaymentNetwork paymentNetwork = [self paymentNetwork:paymentNetworkString];
1048 if (paymentNetwork) {
1049 [results addObject:paymentNetwork];
1050 }
1051 }
1052
1053 return [results copy];
1054}
1055
1056- (PKPaymentNetwork)paymentNetwork:(NSString *)paymentNetworkString {
1057 static NSDictionary *paymentNetworksMap;
1058 static dispatch_once_t onceToken;
1059 dispatch_once(&onceToken, ^{
1060 NSMutableDictionary *mutableMap = [@{} mutableCopy];
1061
1062 if ((&PKPaymentNetworkAmex) != NULL) {
1063 mutableMap[TPSPaymentNetworkAmex] = PKPaymentNetworkAmex;
1064 }
1065
1066 if ((&PKPaymentNetworkDiscover) != NULL) {
1067 mutableMap[TPSPaymentNetworkDiscover] = PKPaymentNetworkDiscover;
1068 }
1069
1070 if ((&PKPaymentNetworkMasterCard) != NULL) {
1071 mutableMap[TPSPaymentNetworkMasterCard] = PKPaymentNetworkMasterCard;
1072 }
1073
1074 if ((&PKPaymentNetworkVisa) != NULL) {
1075 mutableMap[TPSPaymentNetworkVisa] = PKPaymentNetworkVisa;
1076 }
1077
1078 paymentNetworksMap = [mutableMap copy];
1079 });
1080
1081 return paymentNetworksMap[paymentNetworkString];
1082}
1083
1084- (NSNumberFormatter *)numberFormatter {
1085 static NSNumberFormatter *kSharedFormatter;
1086 static dispatch_once_t onceToken;
1087 dispatch_once(&onceToken, ^{
1088 kSharedFormatter = [[NSNumberFormatter alloc] init];
1089 [kSharedFormatter setPositiveFormat:@"$0.00"];
1090 });
1091 return kSharedFormatter;
1092}
1093
1094+ (BOOL)requiresMainQueueSetup
1095{
1096 return YES;
1097}
1098
1099- (void)setModuleRegistry:(UMModuleRegistry *)moduleRegistry
1100{
1101 _moduleRegistry = moduleRegistry;
1102}
1103
1104@end