Commit 8bae5f42 by Brent Gulanowski

Update Advanced Sample to use shipping rate and checkout auto-polling conveniences.

parent 7c8da3a2
......@@ -26,20 +26,19 @@
#import <Buy/Buy.h>
#import "CheckoutViewController.h"
#import "GetCompletionStatusOperation.h"
#import "SummaryItemsTableViewCell.h"
#import "UIButton+PaymentButton.h"
NSString * const CheckoutCallbackNotification = @"CheckoutCallbackNotification";
NSString * const MerchantId = @"";
@interface CheckoutViewController () <GetCompletionStatusOperationDelegate, SFSafariViewControllerDelegate, PKPaymentAuthorizationViewControllerDelegate>
@interface CheckoutViewController () <SFSafariViewControllerDelegate, PKPaymentAuthorizationViewControllerDelegate>
@property (nonatomic, strong) BUYCheckout *checkout;
@property (nonatomic, strong) BUYClient *client;
@property (nonatomic, strong) BUYShop *shop;
@property (nonatomic, strong) NSArray *summaryItems;
@property (nonatomic, strong) BUYApplePayHelpers *applePayHelper;
@property (nonatomic, strong) BUYApplePayAuthorizationDelegate *applePayHelper;
@end
......@@ -141,20 +140,19 @@ NSString * const MerchantId = @"";
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[self.client storeCreditCard:[self creditCard] checkout:self.checkout completion:^(BUYCheckout *checkout, id<BUYPaymentToken> token, NSError *error) {
[self.client storeCreditCard:[self creditCard] checkout:self.checkout completion:^(id<BUYPaymentToken> token, NSError *error) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
if (error == nil && checkout) {
if (error == nil && token) {
NSLog(@"Successfully added credit card to checkout");
self.checkout = checkout;
}
else {
NSLog(@"Error applying credit card: %@", error);
}
callback(error == nil && checkout, token);
callback(error == nil && token, token);
}];
}
......@@ -224,8 +222,16 @@ NSString * const MerchantId = @"";
NSLog(@"Successfully completed checkout");
welf.checkout = checkout;
GetCompletionStatusOperation *completionOperation = [[GetCompletionStatusOperation alloc] initWithClient:welf.client withCheckout:welf.checkout];
completionOperation.delegate = welf;
NSOperation *completionOperation = [welf.client getCompletionStatusOfCheckout:checkout completion:^(BUYStatus status, NSError * _Nullable error) {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
if (error) {
NSLog(@"Error getting completion status: %@", error);
}
else {
NSLog(@"Successfully got completion status: %lu", (unsigned long)status);
[welf getCompletedCheckout:NULL];
}
}];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[[NSOperationQueue mainQueue] addOperation:completionOperation];
......@@ -239,22 +245,6 @@ NSString * const MerchantId = @"";
}];
}
- (void)operation:(GetCompletionStatusOperation *)operation didReceiveCompletionStatus:(BUYStatus)completionStatus
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(@"Successfully got completion status: %lu", (unsigned long)completionStatus);
[self getCompletedCheckout:NULL];
}
- (void)operation:(GetCompletionStatusOperation *)operation failedToReceiveCompletionStatus:(NSError *)error
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
NSLog(@"Error getting completion status: %@", error);
}
#pragma mark - Apple Pay Checkout
- (void)checkoutWithApplePay
......@@ -263,7 +253,7 @@ NSString * const MerchantId = @"";
PKPaymentAuthorizationViewController *paymentController = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest:request];
self.applePayHelper = [[BUYApplePayHelpers alloc] initWithClient:self.client checkout:self.checkout shop:self.shop];
self.applePayHelper = [[BUYApplePayAuthorizationDelegate alloc] initWithClient:self.client checkout:self.checkout shopName:self.shop.name];
paymentController.delegate = self;
/**
......
//
// GetCompletionStatusOperation.h
// Mobile Buy SDK Advanced Sample
//
// 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 Buy;
@class GetCompletionStatusOperation;
@protocol GetCompletionStatusOperationDelegate <NSObject>
- (void)operation:(GetCompletionStatusOperation *)operation didReceiveCompletionStatus:(BUYStatus)completionStatus;
- (void)operation:(GetCompletionStatusOperation *)operation failedToReceiveCompletionStatus:(NSError *)error;
@end
@interface GetCompletionStatusOperation : NSOperation
- (instancetype)initWithClient:(BUYClient *)client withCheckout:(BUYCheckout *)checkout;
@property (nonatomic, weak) id <GetCompletionStatusOperationDelegate> delegate;
@property (nonatomic, readonly) BUYStatus completionStatus;
@end
//
// GetCompletionStatusOperation.m
// Mobile Buy SDK Advanced Sample
//
// 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 "GetCompletionStatusOperation.h"
@interface GetCompletionStatusOperation ()
@property (nonatomic, strong) BUYCheckout *checkout;
@property (nonatomic, strong) BUYClient *client;
@property (nonatomic, assign) BOOL done;
@property (nonatomic, strong) NSURLSessionDataTask *task;
@property (nonatomic) BUYStatus completionStatus;
@end
@implementation GetCompletionStatusOperation
- (instancetype)initWithClient:(BUYClient *)client withCheckout:(BUYCheckout *)checkout;
{
NSParameterAssert(client);
NSParameterAssert(checkout);
self = [super init];
if (self) {
self.checkout = checkout;
self.client = client;
}
return self;
}
- (BOOL)isFinished
{
return [super isFinished] && self.done;
}
- (void)cancel
{
[self.task cancel];
[super cancel];
}
- (void)main
{
[self pollForCompletionStatus];
}
- (void)pollForCompletionStatus
{
__block BUYStatus completionStatus = BUYStatusUnknown;
if (self.isCancelled) {
return;
}
self.task = [self.client getCompletionStatusOfCheckout:self.checkout completion:^(BUYStatus status, NSError *error) {
completionStatus = status;
if (status == BUYStatusProcessing) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self pollForCompletionStatus];
});
}
else {
self.completionStatus = status;
[self willChangeValueForKey:@"isFinished"];
self.done = YES;
[self didChangeValueForKey:@"isFinished"];
if (error) {
[self.delegate operation:self failedToReceiveCompletionStatus:error];
}
else {
[self.delegate operation:self didReceiveCompletionStatus:status];
}
}
}];
}
@end
//
// GetShippingRatesOperations.h
// Mobile Buy SDK Advanced Sample
//
// 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>
@class BUYCheckout;
@class BUYClient;
@class GetShippingRatesOperation;
@protocol GetShippingRatesOperationDelegate <NSObject>
- (void)operation:(GetShippingRatesOperation *)operation didReceiveShippingRates:(NSArray *)shippingRates;
- (void)operation:(GetShippingRatesOperation *)operation failedToReceiveShippingRates:(NSError *)error;
@end
@interface GetShippingRatesOperation : NSOperation
- (instancetype)initWithClient:(BUYClient *)client withCheckout:(BUYCheckout *)checkout;
@property (nonatomic, weak) id <GetShippingRatesOperationDelegate> delegate;
@property (nonatomic, strong, readonly) BUYCheckout *checkout;
@property (nonatomic, strong, readonly) NSArray *shippingRates;
@end
//
// GetShippingRatesOperations.m
// Mobile Buy SDK Advanced Sample
//
// 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 "GetShippingRatesOperation.h"
@import Buy;
@interface GetShippingRatesOperation ()
@property (nonatomic, strong) BUYCheckout *checkout;
@property (nonatomic, strong) BUYClient *client;
@property (nonatomic, assign) BOOL done;
@property (nonatomic, strong) NSURLSessionDataTask *task;
@property (nonatomic, strong) NSArray *shippingRates;
@end
@implementation GetShippingRatesOperation
- (instancetype)initWithClient:(BUYClient *)client withCheckout:(BUYCheckout *)checkout;
{
NSParameterAssert(client);
NSParameterAssert(checkout);
self = [super init];
if (self) {
self.checkout = checkout;
self.client = client;
}
return self;
}
- (BOOL)isFinished
{
return [super isFinished] && self.done;
}
- (void)cancel
{
[self.task cancel];
[super cancel];
}
- (void)main
{
// We're now fetching the rates from Shopify. This will will calculate shipping rates very similarly to how our web checkout.
// We then turn our BUYShippingRate objects into PKShippingMethods for Apple to present to the user.
if ([self.checkout requiresShipping] == NO) {
[self willChangeValueForKey:@"isFinished"];
self.done = YES;
[self didChangeValueForKey:@"isFinished"];
[self.delegate operation:self didReceiveShippingRates:nil];
}
else {
[self pollForShippingRates];
}
}
- (void)pollForShippingRates
{
__block BUYStatus shippingStatus = BUYStatusUnknown;
self.task = [self.client getShippingRatesForCheckout:self.checkout completion:^(NSArray *shippingRates, BUYStatus status, NSError *error) {
shippingStatus = status;
if (error) {
[self willChangeValueForKey:@"isFinished"];
self.done = YES;
[self didChangeValueForKey:@"isFinished"];
[self.delegate operation:self failedToReceiveShippingRates:error];
}
else if (shippingStatus == BUYStatusComplete) {
self.shippingRates = shippingRates;
[self willChangeValueForKey:@"isFinished"];
self.done = YES;
[self didChangeValueForKey:@"isFinished"];
[self.delegate operation:self didReceiveShippingRates:self.shippingRates];
}
else if (shippingStatus == BUYStatusProcessing) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self pollForShippingRates];
});
}
}];
}
@end
//
// GetShopOperation.h
// Mobile Buy SDK Advanced Sample
//
// 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;
@import Buy;
@class GetShopOperation;
@protocol GetShopOperationDelegate <NSObject>
- (void)operation:(GetShopOperation *)operation didReceiveShop:(BUYShop*)shop;
- (void)operation:(GetShopOperation *)operation failedToReceiveShop:(NSError *)error;
@end
@interface GetShopOperation : NSOperation
- (instancetype)initWithClient:(BUYClient *)client;
@property (nonatomic, weak) id <GetShopOperationDelegate> delegate;
@end
//
// GetShopOperation.h
// Mobile Buy SDK Advanced Sample
//
// 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 "GetShopOperation.h"
@interface GetShopOperation ()
@property (nonatomic, strong) BUYClient *client;
@property (nonatomic, assign) BOOL done;
@property (nonatomic, strong) NSURLSessionDataTask *task;
@end
@implementation GetShopOperation
- (instancetype)initWithClient:(BUYClient *)client
{
NSParameterAssert(client);
self = [super init];
if (self) {
self.client = client;
}
return self;
}
- (BOOL)isFinished
{
return [super isFinished] && self.done;
}
- (void)cancel
{
[self.task cancel];
[super cancel];
}
- (void)main
{
if (self.isCancelled) {
return;
}
self.task = [self.client getShop:^(BUYShop *shop, NSError *error) {
[self willChangeValueForKey:@"isFinished"];
self.done = YES;
[self didChangeValueForKey:@"isFinished"];
if (error) {
[self.delegate operation:self failedToReceiveShop:error];
}
else {
[self.delegate operation:self didReceiveShop:shop ];
}
}];
}
@end
......@@ -25,14 +25,12 @@
//
#import "ShippingRatesTableViewController.h"
#import "GetShippingRatesOperation.h"
#import "PreCheckoutViewController.h"
#import "GetShopOperation.h"
#import "ShippingRateTableViewCell.h"
@import Buy;
@interface ShippingRatesTableViewController () <GetShippingRatesOperationDelegate, GetShopOperationDelegate>
@interface ShippingRatesTableViewController ()
@property (nonatomic, strong) BUYCheckout *checkout;
@property (nonatomic, strong) BUYClient *client;
@property (nonatomic, strong) NSNumberFormatter *currencyFormatter;
......@@ -64,27 +62,47 @@
[self.tableView registerClass:[ShippingRateTableViewCell class] forCellReuseIdentifier:@"Cell"];
// Setup both operations to run
GetShopOperation *shopOperation = [[GetShopOperation alloc] initWithClient:self.client];
shopOperation.delegate = self;
[[NSOperationQueue mainQueue] addOperation:shopOperation];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[self getShopAndShippingRates];
}
GetShippingRatesOperation *shippingOperation = [[GetShippingRatesOperation alloc] initWithClient:self.client withCheckout:self.checkout];
shippingOperation.delegate = self;
[[NSOperationQueue mainQueue] addOperation:shippingOperation];
- (void)getShopAndShippingRates
{
[self.client getShop:^(BUYShop *shop, NSError *error) {
if (shop && !error) {
[self didGetShop:shop];
[self getShippingRates];
}
else {
NSLog(@"Failed to retrieve shop: %@", error);
}
}];
}
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
- (void)didGetShop:(BUYShop *)shop
{
self.currencyFormatter = [[NSNumberFormatter alloc] init];
self.currencyFormatter.numberStyle = NSNumberFormatterCurrencyStyle;
self.currencyFormatter.currencyCode = shop.currency;
}
// Ensure both operations are completed before we reload the table view
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
- (void)getShippingRates
{
[self.client getShippingRatesForCheckout:self.checkout completion:^(NSArray *shippingRates, BUYStatus status, NSError *error) {
if ([shippingRates count] > 0 && !error) {
[self didGetShippingRates:shippingRates];
}
else {
NSLog(@"Failed to retrieve shipping rates: %@", error);
}
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
[self.tableView reloadData];
}];
[blockOperation addDependency:shopOperation];
[blockOperation addDependency:shippingOperation];
[[NSOperationQueue mainQueue] addOperation:blockOperation];
}
self.allOperations = @[blockOperation, shopOperation, shippingOperation];
- (void)didGetShippingRates:(NSArray *)shippingRates
{
self.shippingRates = shippingRates;
[self.tableView reloadData];
}
- (void)dealloc
......@@ -128,30 +146,4 @@
}];
}
#pragma mark - Shop delegate methods
-(void)operation:(GetShopOperation *)operation didReceiveShop:(BUYShop *)shop
{
self.currencyFormatter = [[NSNumberFormatter alloc] init];
self.currencyFormatter.numberStyle = NSNumberFormatterCurrencyStyle;
self.currencyFormatter.currencyCode = shop.currency;
}
-(void)operation:(GetShopOperation *)operation failedToReceiveShop:(NSError *)error
{
NSLog(@"Failed to retrieve shop: %@", error);
}
#pragma mark - Shipping Rates delegate methods
-(void)operation:(GetShippingRatesOperation *)operation didReceiveShippingRates:(NSArray *)shippingRates
{
self.shippingRates = shippingRates;
}
-(void)operation:(GetShippingRatesOperation *)operation failedToReceiveShippingRates:(NSError *)error
{
NSLog(@"Failed to retrieve shipping rates: %@", error);
}
@end
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