BTCardClient+UnionPay.m 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. #if __has_include(<Braintree/BraintreeUnionPay.h>) // CocoaPods
  2. #import <Braintree/BTCardClient+UnionPay.h>
  3. #import <Braintree/BTConfiguration+UnionPay.h>
  4. #import <Braintree/BTCardCapabilities.h>
  5. #import <Braintree/BTAPIClient_Internal.h>
  6. #import <Braintree/BTCardClient_Internal.h>
  7. #import <Braintree/BraintreeCore.h>
  8. #import <Braintree/BraintreeCard.h>
  9. #elif SWIFT_PACKAGE // SPM
  10. #import <BraintreeUnionPay/BTCardClient+UnionPay.h>
  11. #import <BraintreeUnionPay/BTConfiguration+UnionPay.h>
  12. #import <BraintreeUnionPay/BTCardCapabilities.h>
  13. #import "../BraintreeCore/BTAPIClient_Internal.h"
  14. #import "../BraintreeCard/BTCardClient_Internal.h"
  15. #import <BraintreeCore/BraintreeCore.h>
  16. #import <BraintreeCard/BraintreeCard.h>
  17. #else // Carthage
  18. #import <BraintreeUnionPay/BTCardClient+UnionPay.h>
  19. #import <BraintreeUnionPay/BTConfiguration+UnionPay.h>
  20. #import <BraintreeUnionPay/BTCardCapabilities.h>
  21. #import <BraintreeCore/BTAPIClient_Internal.h>
  22. #import <BraintreeCard/BTCardClient_Internal.h>
  23. #import <BraintreeCore/BraintreeCore.h>
  24. #import <BraintreeCard/BraintreeCard.h>
  25. #endif
  26. #pragma clang diagnostic push
  27. #pragma clang diagnostic ignored "-Weverything"
  28. @implementation BTCardClient (UnionPay)
  29. #pragma clang diagnostic pop
  30. #pragma mark - Public methods
  31. #pragma clang diagnostic push
  32. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  33. - (void)fetchCapabilities:(NSString *)cardNumber
  34. completion:(void (^)(BTCardCapabilities * _Nullable, NSError * _Nullable))completion {
  35. [self.apiClient fetchOrReturnRemoteConfiguration:^(BTConfiguration * _Nullable configuration, NSError * _Nullable error) {
  36. if (error) {
  37. completion(nil, error);
  38. return;
  39. }
  40. if (!configuration.isUnionPayEnabled) {
  41. NSError *error = [NSError errorWithDomain:BTCardClientErrorDomain code:BTCardClientErrorTypePaymentOptionNotEnabled userInfo:@{NSLocalizedDescriptionKey: @"UnionPay is not enabled for this merchant"}];
  42. completion(nil, error);
  43. return;
  44. }
  45. [self.apiClient GET:@"v1/payment_methods/credit_cards/capabilities"
  46. parameters:@{@"credit_card[number]" : cardNumber}
  47. completion:^(BTJSON * _Nullable body, __unused NSHTTPURLResponse * _Nullable response, NSError * _Nullable error)
  48. {
  49. if (error) {
  50. [self sendUnionPayEvent:@"capabilities-failed"];
  51. completion(nil, error);
  52. } else {
  53. [self sendUnionPayEvent:@"capabilities-received"];
  54. BTCardCapabilities *cardCapabilities = [[BTCardCapabilities alloc] init];
  55. cardCapabilities.isUnionPay = [body[@"isUnionPay"] isTrue];
  56. cardCapabilities.isDebit = [body[@"isDebit"] isTrue];
  57. cardCapabilities.supportsTwoStepAuthAndCapture = [body[@"unionPay"][@"supportsTwoStepAuthAndCapture"] isTrue];
  58. cardCapabilities.isSupported = [body[@"unionPay"][@"isSupported"] isTrue];
  59. completion(cardCapabilities, nil);
  60. }
  61. }];
  62. }];
  63. }
  64. #pragma clang diagnostic pop
  65. - (void)enrollCard:(BTCardRequest *)request
  66. completion:(nonnull void (^)(NSString * _Nullable, BOOL, NSError * _Nullable))completion {
  67. [self.apiClient fetchOrReturnRemoteConfiguration:^(BTConfiguration * _Nullable configuration, NSError * _Nullable error) {
  68. if (error) {
  69. [self invokeBlock:completion onMainThreadWithEnrollmentID:nil smsCodeRequired:NO error:error];
  70. return;
  71. }
  72. if (!configuration.isUnionPayEnabled) {
  73. NSError *error = [NSError errorWithDomain:BTCardClientErrorDomain code:BTCardClientErrorTypePaymentOptionNotEnabled userInfo:@{NSLocalizedDescriptionKey: @"UnionPay is not enabled for this merchant"}];
  74. [self invokeBlock:completion onMainThreadWithEnrollmentID:nil smsCodeRequired:NO error:error];
  75. return;
  76. }
  77. NSMutableDictionary *enrollmentParameters = [NSMutableDictionary dictionary];
  78. BTCard *card = request.card;
  79. if (card.number) {
  80. enrollmentParameters[@"number"] = card.number;
  81. }
  82. if (card.expirationMonth) {
  83. enrollmentParameters[@"expiration_month"] = card.expirationMonth;
  84. }
  85. if (card.expirationYear) {
  86. enrollmentParameters[@"expiration_year"] = card.expirationYear;
  87. }
  88. if (request.mobileCountryCode) {
  89. enrollmentParameters[@"mobile_country_code"] = request.mobileCountryCode;
  90. }
  91. if (request.mobilePhoneNumber) {
  92. enrollmentParameters[@"mobile_number"] = request.mobilePhoneNumber;
  93. }
  94. [self.apiClient POST:@"v1/union_pay_enrollments"
  95. parameters:@{ @"union_pay_enrollment": enrollmentParameters }
  96. completion:^(BTJSON * _Nullable body, __unused NSHTTPURLResponse * _Nullable response, NSError * _Nullable error)
  97. {
  98. if (error) {
  99. if (error.code == NETWORK_CONNECTION_LOST_CODE) {
  100. [self.apiClient sendAnalyticsEvent:@"ios.union-pay.network-connection.failure"];
  101. }
  102. [self sendUnionPayEvent:@"enrollment-failed"];
  103. NSError *callbackError = error;
  104. NSHTTPURLResponse *response = error.userInfo[BTHTTPURLResponseKey];
  105. if (response.statusCode == 422) {
  106. callbackError = [NSError errorWithDomain:BTCardClientErrorDomain
  107. code:BTCardClientErrorTypeCustomerInputInvalid
  108. userInfo:[self.class validationErrorUserInfo:error.userInfo]];
  109. }
  110. [self invokeBlock:completion onMainThreadWithEnrollmentID:nil smsCodeRequired:NO error:callbackError];
  111. return;
  112. }
  113. [self sendUnionPayEvent:@"enrollment-succeeded"];
  114. BOOL smsCodeRequired = ![body[@"smsCodeRequired"] isNull] && [body[@"smsCodeRequired"] isTrue];
  115. [self invokeBlock:completion onMainThreadWithEnrollmentID:[body[@"unionPayEnrollmentId"] asString] smsCodeRequired:smsCodeRequired error:nil];
  116. }];
  117. }];
  118. }
  119. #pragma mark - Helper methods
  120. - (void)invokeBlock:(nonnull void (^)(NSString * _Nullable, BOOL, NSError * _Nullable))completion onMainThreadWithEnrollmentID:(nullable NSString *)enrollmentID smsCodeRequired:(BOOL)smsCodeRequired error:(nullable NSError *)error {
  121. dispatch_async(dispatch_get_main_queue(), ^{
  122. completion(enrollmentID, smsCodeRequired, error);
  123. });
  124. }
  125. - (void)sendUnionPayEvent:(nonnull NSString *)event {
  126. NSString *fullEvent = [NSString stringWithFormat:@"ios.%@.unionpay.%@", self.apiClient.metadata.integrationString, event];
  127. [self.apiClient sendAnalyticsEvent:fullEvent];
  128. }
  129. @end