Commit cce5f56f by Dima Bart

Abstract card vault token and apple pay token by generic protocol.

- add two classes conforming to BUYPaymentSessionProvider for internal use
- modify the API to only return payment tokens wrapped by protocol
- merge two `completePayment` methods into a single method
parent 8f4986f3
......@@ -68,6 +68,7 @@ FOUNDATION_EXPORT const unsigned char BuyVersionString[];
#import <Buy/BUYObserver.h>
#import <Buy/BUYShopifyErrorCodes.h>
#import <Buy/BUYPaymentSessionProvider.h>
#import <Buy/BUYPaymentButton.h>
#import <Buy/BUYProductViewController.h>
#import <Buy/BUYStoreViewController.h>
......
......@@ -40,6 +40,8 @@
@class BUYOrder;
@class BUYModelManager;
@protocol BUYPaymentSessionProvider;
/**
* The sort order for products in a collection
*/
......@@ -114,13 +116,13 @@ typedef NS_ENUM(NSUInteger, BUYStatus) {
};
/**
* Return block containing a BUYCheckout, Payment Session ID and/or an NSError
* Return block containing a BUYCheckout, id<BUYPaymentSessionProvider> and/or an NSError
*
* @param checkout The returned BUYCheckout
* @param paymentSessionId The Payment Session ID associated with a credit card transaction
* @param sessionProvider An opaque session provider type that wraps necessary credentials for payment
* @param error Optional NSError
*/
typedef void (^BUYDataCreditCardBlock)(BUYCheckout *checkout, NSString *paymentSessionId, NSError *error);
typedef void (^BUYDataCreditCardBlock)(BUYCheckout *checkout, id<BUYPaymentSessionProvider> sessionProvider, NSError *error);
/**
* Return block containing a BUYCheckout and/or an NSError
......@@ -444,7 +446,7 @@ typedef void (^BUYDataGiftCardBlock)(BUYGiftCard *giftCard, NSError *error);
- (NSURLSessionDataTask *)updateCheckout:(BUYCheckout *)checkout completion:(BUYDataCheckoutBlock)block;
/**
* Finalizes the BUYCheckout and charges the credit card.
* Finalizes the BUYCheckout and charges the payment provider (ex: Credi Card, Apple Pay, etc).
* This enqueues a completion job on Shopify and returns immediately.
* You must get the job's status by calling checkCompletionStatusOfCheckout:block
*
......@@ -456,25 +458,7 @@ typedef void (^BUYDataGiftCardBlock)(BUYGiftCard *giftCard, NSError *error);
*
* @return The associated NSURLSessionDataTask
*/
- (NSURLSessionDataTask *)completeCheckout:(BUYCheckout *)checkout completion:(BUYDataCheckoutBlock)block;
/**
*/
/**
* Finalizes the checkout and charges the credit card associated with the payment token from PassKit (Apple Pay).
* This only enqueues a completion job, and will return immediately.
* You must get the job's status by calling checkCompletionStatusOfCheckout:block
*
* Note: There's no guarantee that the BUYCheckout returned will be the same as the one that is passed in.
* We recommended using the BUYCheckout returned in the block.
*
* @param checkout The BUYCheckout to complete
* @param token The PKPaymentToken
* @param block (^BUYDataCheckoutBlock)(BUYCheckout *checkout, NSError *error);
*
* @return The associated NSURLSessionDataTask
*/
- (NSURLSessionDataTask *)completeCheckout:(BUYCheckout *)checkout withApplePayToken:(PKPaymentToken *)token completion:(BUYDataCheckoutBlock)block;
- (NSURLSessionDataTask*)completeCheckout:(BUYCheckout *)checkout sessionProvider:(id<BUYPaymentSessionProvider>)sessionProvider completion:(BUYDataCheckoutBlock)block;
/**
* Retrieve the status of a BUYCheckout. This checks the status of the current payment processing job for the provided checkout.
......
......@@ -30,12 +30,14 @@
#import "BUYCart.h"
#import "BUYCheckout.h"
#import "BUYCreditCard.h"
#import "BUYCreditCardSessionProvider.h"
#import "BUYCollection.h"
#import "BUYError.h"
#import "BUYGiftCard.h"
#import "BUYModelManager.h"
#import "BUYOrder.h"
#import "BUYProduct.h"
#import "BUYPaymentSessionProvider.h"
#import "BUYShippingRate.h"
#import "BUYShop.h"
#import "BUYShopifyErrorCodes.h"
......@@ -439,59 +441,30 @@ NSString *const BUYClientCustomerAccessToken = @"X-Shopify-Customer-Access-Token
return task;
}
- (NSURLSessionDataTask*)completeCheckout:(BUYCheckout *)checkout completion:(BUYDataCheckoutBlock)block
- (NSURLSessionDataTask*)completeCheckout:(BUYCheckout *)checkout sessionProvider:(id<BUYPaymentSessionProvider>)sessionProvider completion:(BUYDataCheckoutBlock)block
{
NSAssert(sessionProvider, @"Failed to complete checkout. BUYPaymentSessionProvider must not be nil.");
NSAssert(checkout, @"Failed to complete checkout. BUYCheckout must not be nil");
NSURLSessionDataTask *task = nil;
if ([checkout hasToken]) {
NSData *data = nil;
NSError *error = nil;
BOOL isFree = (checkout.paymentDue && checkout.paymentDue.floatValue == 0);
if (checkout.paymentSessionId.length > 0) {
NSDictionary *paymentJson = @{ @"payment_session_id" : checkout.paymentSessionId };
data = [NSJSONSerialization dataWithJSONObject:paymentJson options:0 error:&error];
NSData *data = nil;
if ([sessionProvider hasPaymentSessionID]) {
data = [NSJSONSerialization dataWithJSONObject:[sessionProvider jsonRepresentation] options:0 error:nil];
}
if ((data && !error) || (checkout.paymentDue && checkout.paymentDue.floatValue == 0)) {
if (data || isFree) {
task = [self checkoutCompletionRequestWithCheckout:checkout body:data completion:block];
}
}
else {
block(nil, [NSError errorWithDomain:kShopifyError code:BUYShopifyError_InvalidCheckoutObject userInfo:nil]);
}
return task;
}
- (NSURLSessionDataTask *)completeCheckout:(BUYCheckout *)checkout withApplePayToken:(PKPaymentToken *)token completion:(BUYDataCheckoutBlock)block
{
NSURLSessionDataTask *task = nil;
#if __has_include(<PassKit/PassKit.h>)
if ([checkout hasToken] == NO) {
block(nil, [NSError errorWithDomain:kShopifyError code:BUYShopifyError_InvalidCheckoutObject userInfo:nil]);
}
else if (!token) {
block(nil, [NSError errorWithDomain:kShopifyError code:BUYShopifyError_NoApplePayTokenSpecified userInfo:nil]);
}
else {
NSString *tokenString = [[NSString alloc] initWithData:token.paymentData encoding:NSUTF8StringEncoding];
NSDictionary *paymentJson = @{ @"payment_token" : @{ @"payment_data" : tokenString, @"type" : @"apple_pay" }};
NSError *error = nil;
NSData *data = [NSJSONSerialization dataWithJSONObject:paymentJson options:0 error:&error];
if (data && !error) {
task = [self checkoutCompletionRequestWithCheckout:checkout body:data completion:block];
}
else {
} else {
block(nil, [NSError errorWithDomain:kShopifyError code:BUYShopifyError_InvalidCheckoutObject userInfo:nil]);
}
}
#elif
block(nil, [NSError errorWithDomain:kShopifyError code:BUYShopifyError_NoApplePayTokenSpecified userInfo:nil]);
#endif
return task;
}
......@@ -574,17 +547,12 @@ NSString *const BUYClientCustomerAccessToken = @"X-Shopify-Customer-Access-Token
#pragma mark - Payments
- (NSURLSessionDataTask *)storeCreditCard:(BUYCreditCard *)creditCard checkout:(BUYCheckout *)checkout completion:(BUYDataCreditCardBlock)block
- (NSURLSessionDataTask *)storeCreditCard:(BUYCreditCard *)creditCard checkout:(BUYCheckout *)checkout completion:(BUYDataCreditCardBlock)completion
{
NSURLSessionDataTask *task = nil;
NSAssert(checkout, @"Failed to store credit card. No checkout provided.");
NSAssert(checkout.token, @"Failed to store credit card. No checkout token provided.");
NSAssert(creditCard, @"Failed to store credit card. No credit card provided.");
if ([checkout hasToken] == NO) {
block(nil, nil, [NSError errorWithDomain:kShopifyError code:BUYShopifyError_InvalidCheckoutObject userInfo:nil]);
}
else if (!creditCard) {
block(nil, nil, [NSError errorWithDomain:kShopifyError code:BUYShopifyError_NoCreditCardSpecified userInfo:nil]);
}
else {
NSMutableDictionary *json = [[NSMutableDictionary alloc] init];
json[@"token"] = checkout.token;
json[@"credit_card"] = [creditCard jsonDictionaryForCheckout];
......@@ -592,16 +560,17 @@ NSString *const BUYClientCustomerAccessToken = @"X-Shopify-Customer-Access-Token
json[@"billing_address"] = [checkout.billingAddress jsonDictionaryForCheckout];
}
NSError *error = nil;
NSData *data = [NSJSONSerialization dataWithJSONObject:@{ @"checkout" : json } options:0 error:&error];
if (data && !error) {
task = [self postPaymentRequestWithCheckout:checkout body:data completion:block];
}
else {
block(nil, nil, [NSError errorWithDomain:kShopifyError code:BUYShopifyError_InvalidCheckoutObject userInfo:nil]);
}
NSData *data = [NSJSONSerialization dataWithJSONObject:@{ @"checkout" : json } options:0 error:nil];
if (data) {
return [self postPaymentRequestWithCheckout:checkout body:data completion:^(BUYCheckout *checkout, NSString *paymentSessionId, NSError *error) {
id<BUYPaymentSessionProvider> provider = [[BUYCreditCardSessionProvider alloc] initWithPaymentSessionID:paymentSessionId];
completion(checkout, provider, error);
}];
} else {
completion(nil, nil, [NSError errorWithDomain:kShopifyError code:BUYShopifyError_InvalidCheckoutObject userInfo:nil]);
return nil;
}
return task;
}
- (NSURLSessionDataTask *)removeProductReservationsFromCheckout:(BUYCheckout *)checkout completion:(BUYDataCheckoutBlock)block
......@@ -703,7 +672,7 @@ NSString *const BUYClientCustomerAccessToken = @"X-Shopify-Customer-Access-Token
return task;
}
- (NSURLSessionDataTask *)postPaymentRequestWithCheckout:(BUYCheckout *)checkout body:(NSData *)body completion:(BUYDataCreditCardBlock)block
- (NSURLSessionDataTask *)postPaymentRequestWithCheckout:(BUYCheckout *)checkout body:(NSData *)body completion:(void (^)(BUYCheckout *checkout, NSString *paymentSessionId, NSError *error))block
{
return [self requestForURL:checkout.paymentURL method:kPOST body:body completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
NSString *paymentSessionId = nil;
......
//
// BUYApplePaySessionProvider.h
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import <Foundation/Foundation.h>
#import "BUYPaymentSessionProvider.h"
@class PKPaymentToken;
@interface BUYApplePaySessionProvider : NSObject <BUYPaymentSessionProvider>
@property (nonatomic, strong, readonly) PKPaymentToken *paymentToken;
- (instancetype)initWithPaymentToken:(PKPaymentToken *)paymentToken;
@end
//
// BUYApplePaySessionProvider.m
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#if __has_include(<PassKit/PassKit.h>)
#import <PassKit/PassKit.h>
#endif
#import "BUYApplePaySessionProvider.h"
@implementation BUYApplePaySessionProvider
#pragma mark - Init -
- (instancetype)initWithPaymentToken:(PKPaymentToken *)paymentToken
{
self = [super init];
if (self) {
_paymentToken = paymentToken;
}
return self;
}
- (NSString *)paymentTokenString {
return [[NSString alloc] initWithData:self.paymentToken.paymentData encoding:NSUTF8StringEncoding];
}
#pragma mark - BUYPaymentSessionProvider -
- (BOOL)hasPaymentSessionID
{
return self.paymentToken.paymentData.length > 0;
}
- (NSDictionary *)jsonRepresentation
{
return @{
@"payment_token" : @{
@"type" : @"apple_pay",
@"payment_data" : [self paymentTokenString],
},
};
}
@end
//
// BUYCreditCardSessionProvider.h
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import <Foundation/Foundation.h>
#import "BUYPaymentSessionProvider.h"
@interface BUYCreditCardSessionProvider : NSObject <BUYPaymentSessionProvider>
@property (nonatomic, strong, readonly) NSString *paymentSessionID;
- (instancetype)initWithPaymentSessionID:(NSString *)paymentSessionID;
@end
//
// BUYCreditCardSessionProvider.m
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
#import "BUYCreditCardSessionProvider.h"
@implementation BUYCreditCardSessionProvider
#pragma mark - Init -
- (instancetype)initWithPaymentSessionID:(NSString *)paymentSessionID
{
self = [super init];
if (self) {
_paymentSessionID = paymentSessionID;
}
return self;
}
#pragma mark - BUYPaymentSessionProvider -
- (BOOL)hasPaymentSessionID
{
return self.paymentSessionID.length > 0;
}
- (NSDictionary *)jsonRepresentation
{
return @{
@"payment_session_id" : self.paymentSessionID,
};
}
@end
//
// BUYPaymentSessionProvider.h
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2015 Shopify Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
@protocol BUYPaymentSessionProvider <NSObject>
- (BOOL)hasPaymentSessionID;
- (NSDictionary *)jsonRepresentation;
@end
......@@ -64,6 +64,7 @@
#import "BUYObserver.h"
#import "BUYShopifyErrorCodes.h"
#import "BUYPaymentSessionProvider.h"
#import "BUYPaymentButton.h"
#import "BUYProductViewController.h"
#import "BUYStoreViewController.h"
......
......@@ -33,6 +33,7 @@
#import "BUYModelManager.h"
#import "BUYShop.h"
#import "BUYShopifyErrorCodes.h"
#import "BUYApplePaySessionProvider.h"
const NSTimeInterval PollDelay = 0.5;
......@@ -113,8 +114,10 @@ const NSTimeInterval PollDelay = 0.5;
if (checkout && error == nil) {
self.checkout = checkout;
id<BUYPaymentSessionProvider> provider = [[BUYApplePaySessionProvider alloc] initWithPaymentToken:payment.token];
//Now that the checkout is up to date, call complete.
[self.client completeCheckout:checkout withApplePayToken:payment.token completion:^(BUYCheckout *checkout, NSError *error) {
[self.client completeCheckout:checkout sessionProvider:provider completion:^(BUYCheckout *checkout, NSError *error) {
if (checkout && error == nil) {
self.checkout = checkout;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment