Commit b3c7e09a by Brent Gulanowski

Merge branch 'integration/sdk-2.0' into task/json-serialization

parents ccec1776 620cd3cb
......@@ -33,6 +33,11 @@
#import "BUYClientTestBase.h"
#import "BUYCollection+Additions.h"
#import "NSURLComponents+BUYAdditions.h"
#import "BUYShopifyErrorCodes.h"
#import "BUYAccountCredentials.h"
#import "BUYClient+Customers.h"
NSString * const BUYFakeCustomerToken = @"dsfasdgafdg";
@interface BUYClient ()
......@@ -318,4 +323,121 @@
XCTAssertEqualObjects(requestQueryItems, queryItems);
}
#pragma mark - Customer Tests -
- (void)testCustomerCreationURL
{
BUYAccountCredentialItem *firstName = [BUYAccountCredentialItem itemWithKey:@"first_name" value:@"michael"];
BUYAccountCredentialItem *lastName = [BUYAccountCredentialItem itemWithKey:@"last_name" value:@"scott"];
BUYAccountCredentialItem *email = [BUYAccountCredentialItem itemWithKey:@"email" value:@"fake@example.com"];
BUYAccountCredentialItem *password = [BUYAccountCredentialItem itemWithKey:@"password" value:@"password"];
BUYAccountCredentialItem *passwordConfirmation = [BUYAccountCredentialItem itemWithKey:@"password_confirmation" value:@"password"];
BUYAccountCredentials *credentials = [BUYAccountCredentials credentialsWithItems:@[firstName, lastName, email, password, passwordConfirmation]];
NSURLSessionDataTask *task = [self.client createCustomerWithCredentials:credentials callback:nil];
XCTAssertEqualObjects(task.originalRequest.URL.scheme, @"https");
XCTAssertEqualObjects(task.originalRequest.URL.path, @"/api/customers.json");
XCTAssertEqualObjects(task.originalRequest.HTTPMethod, @"POST");
NSError *error = nil;
NSDictionary *payload = [NSJSONSerialization JSONObjectWithData:task.originalRequest.HTTPBody options:0 error:&error];
XCTAssertNil(error);
NSDictionary *dict = @{@"customer": @{
@"first_name": firstName.value,
@"last_name": lastName.value,
@"email": email.value,
@"password": password.value,
@"password_confirmation": passwordConfirmation.value}};
XCTAssertEqualObjects(payload, dict);
}
- (void)testLoginCustomerURL
{
BUYAccountCredentialItem *email = [BUYAccountCredentialItem itemWithKey:@"email" value:@"fake@example.com"];
BUYAccountCredentialItem *password = [BUYAccountCredentialItem itemWithKey:@"password" value:@"password"];
BUYAccountCredentials *credentials = [BUYAccountCredentials credentialsWithItems:@[email, password]];
NSURLSessionDataTask *task = [self.client loginCustomerWithCredentials:credentials callback:nil];
XCTAssertEqualObjects(task.originalRequest.URL.scheme, @"https");
XCTAssertEqualObjects(task.originalRequest.URL.path, @"/api/customers/customer_token.json");
XCTAssertEqualObjects(task.originalRequest.HTTPMethod, @"POST");
NSError *error = nil;
NSDictionary *payload = [NSJSONSerialization JSONObjectWithData:task.originalRequest.HTTPBody options:0 error:&error];
XCTAssertNil(error);
NSDictionary *dict = @{@"customer": @{@"email": email.value, @"password": password.value}};
XCTAssertEqualObjects(payload, dict);
}
- (void)testGetCustomerURL
{
NSURLSessionDataTask *task = [self.client getCustomerWithID:nil callback:nil];
XCTAssertEqualObjects(task.originalRequest.URL.scheme, @"https");
XCTAssertEqualObjects(task.originalRequest.URL.path, @"/api/customers.json");
XCTAssertEqualObjects(task.originalRequest.HTTPMethod, @"GET");
XCTAssertEqualObjects(self.client.customerToken, task.originalRequest.allHTTPHeaderFields[BUYClientCustomerAccessToken]);
}
- (void)testGetOrdersForCustomerURL
{
NSURLSessionDataTask *task = [self.client getOrdersForCustomerWithCallback:nil];
XCTAssertEqualObjects(task.originalRequest.URL.scheme, @"https");
XCTAssertEqualObjects(task.originalRequest.URL.path, @"/api/customers/orders.json");
XCTAssertEqualObjects(task.originalRequest.HTTPMethod, @"GET");
XCTAssertEqualObjects(self.client.customerToken, task.originalRequest.allHTTPHeaderFields[BUYClientCustomerAccessToken]);
}
- (void)testCustomerRecovery
{
NSString *email = @"fake@example.com";
NSURLSessionDataTask *task = [self.client recoverPasswordForCustomer:email callback:nil];
XCTAssertEqualObjects(task.originalRequest.URL.scheme, @"https");
XCTAssertEqualObjects(task.originalRequest.URL.path, @"/api/customers/recover.json");
XCTAssertEqualObjects(task.originalRequest.HTTPMethod, @"POST");
NSError *error = nil;
NSDictionary *payload = [NSJSONSerialization JSONObjectWithData:task.originalRequest.HTTPBody options:0 error:&error];
XCTAssertNil(error);
NSDictionary *dict = @{@"email": email};
XCTAssertEqualObjects(payload, dict);
}
- (void)testTokenRenewal
{
self.client.customerToken = nil;
NSURLSessionDataTask *task = [self.client renewCustomerTokenWithID:nil callback:^(NSString *token, NSError *error) {}];
XCTAssertNil(task); // task should be nil if no customer token was set on the client
self.client.customerToken = BUYFakeCustomerToken;
task = [self.client renewCustomerTokenWithID:@"1" callback:nil];
XCTAssertEqualObjects(task.originalRequest.URL.scheme, @"https");
XCTAssertEqualObjects(task.originalRequest.URL.path, @"/api/customers/1/customer_token/renew.json");
XCTAssertEqualObjects(task.originalRequest.HTTPMethod, @"PUT");
}
- (void)testCustomerActivation
{
BUYAccountCredentialItem *passwordItem = [BUYAccountCredentialItem itemWithKey:@"password" value:@"12345"];
BUYAccountCredentialItem *passwordConfItem = [BUYAccountCredentialItem itemWithKey:@"password_confirmation" value:@"12345"];
BUYAccountCredentials *credentials = [BUYAccountCredentials credentialsWithItems:@[passwordItem, passwordConfItem]];
NSString *customerID = @"12345";
NSString *customerToken = @"12345";
NSURLSessionDataTask *task = [self.client activateCustomerWithCredentials:credentials customerID:customerID customerToken:customerToken callback:nil];
XCTAssertEqualObjects(task.originalRequest.URL.scheme, @"https");
XCTAssertEqualObjects(task.originalRequest.URL.path, @"/api/customers/12345/activate.json");
XCTAssertEqualObjects(task.originalRequest.HTTPMethod, @"PUT");
}
@end
......@@ -30,6 +30,8 @@
extern NSString * const BUYShopDomain_Placeholder;
extern NSString * const BUYAPIKey_Placeholder;
extern NSString * const BUYAppId_Placeholder;
extern NSString * const BUYChannelId_Placeholder;
extern NSString * const BUYFakeCustomerToken;
@interface BUYClientTestBase : XCTestCase
......@@ -37,6 +39,8 @@ extern NSString * const BUYAppId_Placeholder;
@property (nonatomic, strong) NSString *apiKey;
@property (nonatomic, strong) NSString *appId;
@property (nonatomic, strong) NSString *merchantId;
@property (nonatomic, strong) NSString *customerEmail;
@property (nonatomic, strong) NSString *customerPassword;
@property (nonatomic, strong) NSString *giftCardCode;
@property (nonatomic, strong) NSString *giftCardCode2;
@property (nonatomic, strong) NSString *giftCardCode3;
......@@ -45,7 +49,11 @@ extern NSString * const BUYAppId_Placeholder;
@property (nonatomic, strong) NSString *giftCardCodeInvalid;
@property (nonatomic, strong) NSString *discountCodeValid;
@property (nonatomic, strong) NSString *discountCodeExpired;
@property (nonatomic, strong) NSArray *productIds;
@property (nonatomic, strong) NSNumber *variantUntrackedId;
@property (nonatomic, strong) NSNumber *variantInventory1Id;
@property (nonatomic, strong) NSNumber *variantSoldOutId;
@property (nonatomic, strong) BUYClient *client;
......
......@@ -53,6 +53,9 @@ NSString * const BUYAppId_Placeholder = @"app_id";
self.appId = environment[kBUYTestAppId] ?: jsonConfig[kBUYTestAppId];
self.merchantId = environment[kBUYTestMerchantId] ?: jsonConfig[kBUYTestMerchantId];
self.customerEmail = environment[kBUYTestEmail] ?: jsonConfig[kBUYTestEmail];
self.customerPassword = environment[kBUYTestPassword] ?: jsonConfig[kBUYTestPassword];
NSDictionary *giftCards = jsonConfig[@"gift_cards"];
self.giftCardCode = environment[kBUYTestGiftCardCode11] ?: giftCards[@"valid11"][@"code"];
......@@ -67,6 +70,10 @@ NSString * const BUYAppId_Placeholder = @"app_id";
NSString *productIdsString = [environment[kBUYTestProductIdsCommaSeparated] stringByReplacingOccurrencesOfString:@" " withString:@""];
self.productIds = [productIdsString componentsSeparatedByString:@","];
} else {
self.variantUntrackedId = jsonConfig[@"variants"][@"variant_untracked_id"];
self.variantInventory1Id = jsonConfig[@"variants"][@"variant_inventory1_id"];
self.variantSoldOutId = jsonConfig[@"variants"][@"variant_soldout_id"];
self.productIds = jsonConfig[@"product_ids"];
}
......
//
// BUYClientTest_Customer.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 XCTest;
#import "BUYClientTestBase.h"
#import "BUYClient+Customers.h"
#import "BUYAccountCredentials.h"
#import "BUYError+BUYAdditions.h"
#import <OHHTTPStubs/OHHTTPStubs.h>
#import "OHHTTPStubsResponse+Helpers.h"
// Remove this macro entirely when test shop has customer api enabled
//#define CUSTOMER_API_AVAILABLE
@interface BUYClientTest_Customer : BUYClientTestBase
@end
@implementation BUYClientTest_Customer
- (void)tearDown
{
[super tearDown];
[OHHTTPStubs removeAllStubs];
}
- (void)testCustomerDuplicateEmail
{
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest * _Nonnull request) {
return [self shouldUseMocks];
} withStubResponse:^OHHTTPStubsResponse * _Nonnull(NSURLRequest * _Nonnull request) {
return [OHHTTPStubsResponse responseWithKey:@"testCustomerDuplicateEmail"];
}];
XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)];
BUYAccountCredentialItem *emailItem = [BUYAccountCredentialItem itemWithKey:@"email" value:self.customerEmail];
BUYAccountCredentialItem *passwordItem = [BUYAccountCredentialItem itemWithKey:@"password" value:self.customerPassword];
BUYAccountCredentialItem *passwordConfItem = [BUYAccountCredentialItem itemWithKey:@"password_confirmation" value:self.customerPassword];
BUYAccountCredentials *credentials = [BUYAccountCredentials credentialsWithItems:@[emailItem, passwordItem, passwordConfItem]];
[self.client createCustomerWithCredentials:credentials callback:^(BUYCustomer *customer, NSString *token, NSError *error) {
XCTAssertNil(customer);
XCTAssertNotNil(error);
NSArray *errors = [BUYError errorsFromSignUpJSON:error.userInfo];
XCTAssertEqual(errors.count, 1);
BUYError *customerError = errors[0];
XCTAssertEqualObjects(customerError.code, @"taken");
XCTAssertEqualObjects(customerError.options[@"rescue_from_duplicate"], @YES);
XCTAssertEqualObjects(customerError.options[@"value"], self.customerEmail);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:10 handler:^(NSError * _Nullable error) {
XCTAssertNil(error);
}];
}
- (void)testCustomerInvalidEmailPassword
{
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest * _Nonnull request) {
return [self shouldUseMocks];
} withStubResponse:^OHHTTPStubsResponse * _Nonnull(NSURLRequest * _Nonnull request) {
return [OHHTTPStubsResponse responseWithKey:@"testCustomerInvalidEmailPassword"];
}];
XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)];
BUYAccountCredentialItem *emailItem = [BUYAccountCredentialItem itemWithKey:@"email" value:@"a"];
BUYAccountCredentialItem *passwordItem = [BUYAccountCredentialItem itemWithKey:@"password" value:@"b"];
BUYAccountCredentialItem *passwordConfItem = [BUYAccountCredentialItem itemWithKey:@"password_confirmation" value:@"c"];
BUYAccountCredentials *credentials = [BUYAccountCredentials credentialsWithItems:@[emailItem, passwordItem, passwordConfItem]];
[self.client createCustomerWithCredentials:credentials callback:^(BUYCustomer *customer, NSString *token, NSError *error) {
XCTAssertNil(customer);
XCTAssertNotNil(error);
NSArray<BUYError *> *errors = [BUYError errorsFromSignUpJSON:error.userInfo];
XCTAssertEqual(errors.count, 3);
BUYError *emailError = errors[0];
XCTAssertEqualObjects(emailError.code, @"invalid");
BUYError *passwordConfError = errors[1];
XCTAssertEqualObjects(passwordConfError.code, @"confirmation");
XCTAssertEqualObjects(passwordConfError.options[@"attribute"], @"Password");
BUYError *passwordError = errors[2];
XCTAssertEqualObjects(passwordError.code, @"too_short");
XCTAssertEqualObjects(passwordError.options[@"count"], @5);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:10 handler:^(NSError * _Nullable error) {
XCTAssertNil(error);
}];
}
- (void)testCustomerLogin
{
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest * _Nonnull request) {
return [self shouldUseMocks];
} withStubResponse:^OHHTTPStubsResponse * _Nonnull(NSURLRequest * _Nonnull request) {
return [OHHTTPStubsResponse responseWithKey:@"testCustomerLogin"];
}];
XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)];
BUYAccountCredentialItem *emailItem = [BUYAccountCredentialItem itemWithKey:@"email" value:self.customerEmail];
BUYAccountCredentialItem *passwordItem = [BUYAccountCredentialItem itemWithKey:@"password" value:self.customerPassword];
BUYAccountCredentials *credentials = [BUYAccountCredentials credentialsWithItems:@[emailItem, passwordItem]];
[self.client loginCustomerWithCredentials:credentials callback:^(BUYCustomer *customer, NSString *token, NSError *error) {
XCTAssertNil(error);
XCTAssertNotNil(customer);
XCTAssertEqualObjects(customer.email, self.customerEmail);
[expectation fulfill];
}];
[self waitForExpectationsWithTimeout:10 handler:^(NSError * _Nullable error) {
XCTAssertNil(error);
}];
}
@end
......@@ -33,6 +33,7 @@
#import "BUYClientTestBase.h"
#import <OHHTTPStubs/OHHTTPStubs.h>
#import "OHHTTPStubsResponse+Helpers.h"
#import "BUYShopifyErrorCodes.h"
@interface BUYClientTest_Storefront : BUYClientTestBase
@property (nonatomic, strong) BUYCollection *collection;
......
......@@ -32,6 +32,8 @@
#define kBUYTestAPIKey @"api_key"
#define kBUYTestAppId @"app_id"
#define kBUYTestMerchantId @"merchant_id"
#define kBUYTestEmail @"customer_email"
#define kBUYTestPassword @"customer_password"
#define kBUYTestGiftCardCode11 @"gift_card_code_11"
#define kBUYTestGiftCardCode25 @"gift_card_code_25"
#define kBUYTestGiftCardCode50 @"gift_card_code_50"
......
......@@ -5,10 +5,17 @@
"channel_id": "",
"app_id": "",
"merchant_id": "",
"customer_email": "",
"customer_password": "",
"product_ids": [
"",
""
],
"variants": {
"variant_untracked_id": "",
"variant_inventory1_id": "",
"variant_soldout_id": ""
},
"collection_id": "",
"gift_cards": {
"ValidGiftCard11": {
......
......@@ -28,7 +28,26 @@
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "90F592EB1B0D5EFE0026B382"
BuildableName = "Mobile Buy SDK Tests.xctest"
BlueprintName = "Mobile Buy SDK Tests"
ReferencedContainer = "container:Mobile Buy SDK.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "901930E11BC5B9BC00D1134E"
BuildableName = "Buy.framework"
BlueprintName = "Buy"
ReferencedContainer = "container:Mobile Buy SDK.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
......
......@@ -32,6 +32,7 @@ FOUNDATION_EXPORT double BuyVersionNumber;
//! Project version string for Buy.
FOUNDATION_EXPORT const unsigned char BuyVersionString[];
#import <Buy/BUYAccountCredentials.h>
#import <Buy/BUYAddress.h>
#import <Buy/BUYCart.h>
#import <Buy/BUYCartLineItem.h>
......@@ -39,10 +40,13 @@ FOUNDATION_EXPORT const unsigned char BuyVersionString[];
#import <Buy/BUYCheckoutAttribute.h>
#import <Buy/BUYCollection.h>
#import <Buy/BUYCreditCard.h>
#import <Buy/BUYCustomer.h>
#import <Buy/BUYDiscount.h>
#import <Buy/BUYGiftCard.h>
#import <Buy/BUYImage.h>
#import <Buy/BUYLineItem.h>
#import <Buy/BUYClient.h>
#import <Buy/BUYClient+Customers.h>
#import <Buy/BUYImage.h>
#import <Buy/BUYMaskedCreditCard.h>
#import <Buy/BUYOption.h>
#import <Buy/BUYOptionValue.h>
......@@ -55,7 +59,6 @@ FOUNDATION_EXPORT const unsigned char BuyVersionString[];
#import <Buy/BUYApplePayAdditions.h>
#import <Buy/BUYApplePayHelpers.h>
#import <Buy/BUYClient.h>
#import <Buy/BUYError.h>
#import <Buy/BUYPaymentButton.h>
......
//
// BUYClient+Customers.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 "BUYClient.h"
@class BUYCustomer;
@class BUYOrder;
@class BUYAccountCredentials;
/**
* Return block containing a BUYCustomer object for an existing customer of the shop
*
* @param customer A BUYCustomer
* @param error An optional NSError
*/
typedef void (^BUYDataCustomerBlock)(BUYCustomer *customer, NSError *error);
/**
* Return block containing a customer auth token
*
* @param customer A BUYCustomer
* @param token An authentication token to retrieve the customer later. Store this token securely on the device.
* @param error An optional NSError
*/
typedef void (^BUYDataCustomerTokenBlock)(BUYCustomer *customer, NSString *token, NSError *error);
/**
* Return block containing a customer auth token
*
* @param token An authentication token to retrieve the customer later. Store this token securely on the device.
* @param error An optional NSError
*/
typedef void (^BUYDataTokenBlock)(NSString *token, NSError *error);
/**
* Return block containing an array of BUYOrders
*
* @param orders An array of BUYOrders
* @param error An optional NSError
*/
typedef void (^BUYDataOrdersBlock)(NSArray <BUYOrder*> *orders, NSError *error);
@interface BUYClient (Customers)
/**
* GET /api/customers/:customer_id
* Gets an existing customer
*
* @param customerID A customer ID retrieved from either customer creation or login
* @param block (BUYCustomer *customer, NSError *error)
*
* @return The associated NSURLSessionDataTask
*/
- (NSURLSessionDataTask *)getCustomerWithID:(NSString *)customerID callback:(BUYDataCustomerBlock)block;
/**
* POST /api/customers
* Creates a new customer
* Expects first name, last name, email, password, and password confirmation
*
* @param credentials Credentials object containing items for required fields
* @param block (BUYCustomer *customer, NSString *token, NSError *error)
*
* @return The associated NSURLSessionDataTask
*
* @discussion The customer is automatically logged in using -loginCustomerWithCredentials:callback:
*/
- (NSURLSessionDataTask *)createCustomerWithCredentials:(BUYAccountCredentials *)credentials callback:(BUYDataCustomerTokenBlock)block;
/**
* POST /api/customers/customer_token
* Logs in an existing customer
* Expects email and password
*
* @param credentials Credentials object containing items for required fields
* @param block (BUYCustomer *customer, NSString *token, NSError *error)
*
* @return The associated NSURLSessionDataTask
*/
- (NSURLSessionDataTask *)loginCustomerWithCredentials:(BUYAccountCredentials *)credentials callback:(BUYDataCustomerTokenBlock)block;
/**
* POST /api/customers/recover
* Sends email for password recovery to an existing customer
*
* @param email Email to send the password reset to
* @param block (BUYStatus status, NSError *error)
*
* @return the associated NSURLSessionDataTask
*/
- (NSURLSessionDataTask *)recoverPasswordForCustomer:(NSString *)email callback:(BUYDataCheckoutStatusBlock)block;
/**
* PUT /api/customers/:customer_id/customer_token/renew
* Renews an existing customer's token
*
* @param customerID ID of customer renewing token
* @param block (NSString *token, NSError *error)
*
* @return the associated NSURLSessionDataTask
*/
- (NSURLSessionDataTask *)renewCustomerTokenWithID:(NSString *)customerID callback:(BUYDataTokenBlock)block;
/**
* PUT /api/customers/:customer_id/activate
* Activates an unactivated customer
*
* @param credentials Credentials containing a password and password confirmation
* @param customerID ID of customer being activated
* @param customerToken Token contained in activation URL
* @param block (BUYCustomer *customer, NSString *token, NSError *error)
*
* @return The associated NSURLSessionDataTask
*/
- (NSURLSessionDataTask *)activateCustomerWithCredentials:(BUYAccountCredentials *)credentials customerID:(NSString *)customerID customerToken:(NSString *)customerToken callback:(BUYDataCustomerTokenBlock)block;
/**
* PUT /api/customers/:customer_id/reset
* Resets an existing customer's password
*
* @param credentials Credentials containing a password and password confirmation
* @param customerID ID of customer resetting password
* @param customerToken Token contained in reset URL
* @param block (BUYCustomer *customer, NSString *token, NSError *error)
*
* @return The associated NSURLSessionDataTask
*/
- (NSURLSessionDataTask *)resetPasswordWithCredentials:(BUYAccountCredentials *)credentials customerID:(NSString *)customerID customerToken:(NSString *)customerToken callback:(BUYDataCustomerTokenBlock)block;
/**
* GET /api/customers/:customer_id/orders
* Gets orders for a given customer
*
* @param token An auth token retrieved from customer creation or customer login API
* @param block (NSArray <BUYOrder*> *orders, NSError *error)
*
* @return The associated NSURLSessionDataTask
*/
- (NSURLSessionDataTask *)getOrdersForCustomerWithCallback:(BUYDataOrdersBlock)block;
@end
......@@ -78,6 +78,8 @@ typedef NS_ENUM(NSUInteger, BUYCollectionSort) {
extern NSString * const BUYVersionString;
extern NSString * const BUYClientCustomerAccessToken;
/**
* A BUYStatus is associated with the completion of an enqueued job on Shopify.
* BUYStatus is equal is HTTP status codes returned from the server
......@@ -272,6 +274,12 @@ typedef void (^BUYDataGiftCardBlock)(BUYGiftCard *giftCard, NSError *error);
*/
@property (nonatomic, strong) NSString *urlScheme;
/**
* Allows the client to hold onto the customer token
*
* @param token The token received from the create and login callbacks
*/
@property (strong, nonatomic) NSString *customerToken;
#pragma mark - Storefront
......
//
// BUYClient_Internal.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 "BUYClient.h"
#import "BUYSerializable.h"
static NSString *const kShopifyError = @"shopify";
@interface BUYClient (Internal)
- (NSURLSessionDataTask *)postRequestForURL:(NSURL *)url object:(id <BUYSerializable>)object completionHandler:(void (^)(NSDictionary *json, NSURLResponse *response, NSError *error))completionHandler;
- (NSURLSessionDataTask *)putRequestForURL:(NSURL *)url body:(NSData *)body completionHandler:(void (^)(NSDictionary *json, NSURLResponse *response, NSError *error))completionHandler;
- (NSURLSessionDataTask *)getRequestForURL:(NSURL *)url completionHandler:(void (^)(NSDictionary *json, NSURLResponse *response, NSError *error))completionHandler;
- (NSURLSessionDataTask *)requestForURL:(NSURL *)url method:(NSString *)method body:(NSData *)body additionalHeaders:(NSDictionary *)headers completionHandler:(void (^)(NSDictionary *json, NSURLResponse *response, NSError *error))completionHandler;
- (NSURLComponents *)URLComponentsForAPIPath:(NSString *)apiPath appendingPath:(NSString *)appendingPath queryItems:(NSDictionary*)queryItems;
- (NSError *)extractErrorFromResponse:(NSURLResponse *)response json:(NSDictionary *)json;
@end
//
// BUYAccountCredentials.h
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2016 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>
/**
* Intended for storing a collection of credential items representing individual values
*/
@class BUYAccountCredentialItem;
@interface BUYAccountCredentials : NSObject
NS_ASSUME_NONNULL_BEGIN
+ (BUYAccountCredentials *)credentialsWithItems:(NSArray<BUYAccountCredentialItem *> *)items;
+ (BUYAccountCredentials *)credentialsWithItemKeys:(NSArray<NSString *> *)keys;
@property (readonly) NSDictionary *JSONRepresentation;
@property (nonatomic, readonly, getter=isValid) BOOL valid;
- (BUYAccountCredentialItem *)objectForKeyedSubscript:(NSString *)key;
- (void)setObject:(BUYAccountCredentialItem *)obj forKeyedSubscript:(NSString *)key;
@end
/**
* Represents a key and KVC-validatable value
*/
@interface BUYAccountCredentialItem : NSObject
+ (instancetype)itemWithKey:(NSString *)key value:(NSString *)value;
@property (nonatomic, getter=isValid) BOOL valid;
@property (nonatomic, strong) NSString *key;
@property (nonatomic, strong) NSString *value;
NS_ASSUME_NONNULL_END
@end
//
// BUYAccountCredentials.m
// Mobile Buy SDK
//
// Created by Shopify.
// Copyright (c) 2016 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 "BUYAccountCredentials.h"
@class BUYAccountCredentialItem;
@interface BUYAccountCredentials()
@property (strong, nonatomic) NSMutableDictionary<NSString *, BUYAccountCredentialItem *> *items;
@end
@implementation BUYAccountCredentials
+ (BUYAccountCredentials *)credentialsWithItems:(NSArray<BUYAccountCredentialItem *> *)items
{
BUYAccountCredentials *credentials = [BUYAccountCredentials new];
NSMutableDictionary *keyedItems = [NSMutableDictionary dictionary];
for (BUYAccountCredentialItem *item in items) {
keyedItems[item.key] = item;
}
credentials.items = keyedItems;
return credentials;
}
+ (BUYAccountCredentials *)credentialsWithItemKeys:(NSArray<NSString *> *)keys
{
NSMutableArray *items = [NSMutableArray array];
for (NSString *key in keys) {
BUYAccountCredentialItem *item = [BUYAccountCredentialItem itemWithKey:key value:@""];
[items addObject:item];
}
return [BUYAccountCredentials credentialsWithItems:items];
}
- (NSDictionary *)JSONRepresentation
{
__block NSMutableDictionary *customer = [NSMutableDictionary dictionary];
[self.items enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, BUYAccountCredentialItem * _Nonnull obj, BOOL * _Nonnull stop) {
customer[key] = obj.value;
}];
return @{ @"customer": customer };
}
- (BOOL)validateValue:(inout id _Nullable __autoreleasing *)ioValue forKey:(NSString *)inKey error:(out NSError * _Nullable __autoreleasing *)outError
{
return [self.items[inKey] validateValue:ioValue forKey:inKey error:outError];
}
- (BUYAccountCredentialItem *)objectForKeyedSubscript:(NSString *)key
{
return self.items[key];
}
- (void)setObject:(BUYAccountCredentialItem *)obj forKeyedSubscript:(NSString *)key
{
self.items[key] = obj;
}
- (BOOL)validationForKey:(NSString *)key
{
return [self.items[key] isValid];
}
- (BOOL)isValid
{
__block BOOL valid = YES;
[self.items enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, BUYAccountCredentialItem * _Nonnull obj, BOOL * _Nonnull stop) {
valid = valid && [obj isValid];
}];
return valid;
}
@end
@implementation BUYAccountCredentialItem
+ (instancetype)itemWithKey:(NSString *)key value:(NSString *)value
{
BUYAccountCredentialItem *item = [BUYAccountCredentialItem new];
item.key = key;
item.value = value;
return item;
}
- (NSString *)value
{
return _value ?: @"";
}
- (BOOL)validateValue:(inout id _Nullable __autoreleasing *)ioValue forKey:(NSString *)inKey error:(out NSError * _Nullable __autoreleasing *)outError
{
self.value = *ioValue;
self.valid = self.value.length > 0;
return [self isValid];
}
@end
//
// BUYCustomer.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 "BUYObject.h"
@class BUYAddress;
@interface BUYCustomer : BUYObject
/**
* Indicates whether the customer should be charged taxes when placing orders. Valid values are `true` and `false`
*/
@property (nonatomic, assign) BOOL taxExempt;
/**
* States whether or not the email address has been verified.
*/
@property (nonatomic, assign) BOOL verifiedEmail;
/**
* Indicates whether the customer has consented to be sent marketing material via email. Valid values are `true` and `false`
*/
@property (nonatomic, assign) BOOL acceptsMarketing;
/**
* The state of the customer in a shop. Customers start out as `disabled`. They are invited by email to setup an account with a shop. The customer can then:
*
* - `decline`: decline the invite to start an account that saves their customer settings.
* - `invited`: accept the invite to start an account that saves their customer settings. Customers then change from `disabled` to `enabled`.
*
* Shop owners also have the ability to disable a customer. This will cancel a customer's membership with a shop.
*/
@property (nonatomic, assign) BOOL customerState;
/**
* The email address of the customer.
*/
@property (nonatomic, strong) NSString *email;
/**
* The customer's first name.
*/
@property (nonatomic, strong) NSString *firstName;
/**
* The customer's last name.
*/
@property (nonatomic, strong) NSString *lastName;
/**
* The customer's combined first and last name.
*/
@property (nonatomic, strong, readonly) NSString *fullName;
/**
* The id of the customer's last order.
*/
@property (nonatomic, strong) NSNumber *lastOrderID;
/**
* The name of the customer's last order. This is directly related to the Order's name field.
*/
@property (nonatomic, strong) NSString *lastOrderName;
/**
* The customer's identifier used with Multipass login
*/
@property (nonatomic, strong) NSString *multipassIdentifier;
/**
* A note about the customer.
*/
@property (nonatomic, strong) NSString *note;
/**
* Tags are additional short descriptors formatted as a string of comma-separated values. For example, if a customer has three tags: `tag1, tag2, tag3`
*/
@property (nonatomic, strong) NSString *tags;
/**
* The number of orders associated with this customer.
*/
@property (nonatomic, strong) NSNumber *ordersCount;
/**
* The total amount of money that the customer has spent at the shop.
*/
@property (nonatomic, strong) NSDecimalNumber *totalSpent;
/**
* The date and time when the customer was created. The API returns this value in ISO 8601 format.
*/
@property (nonatomic, strong) NSDate *createdAt;
/**
* The date and time when the customer information was updated. The API returns this value in ISO 8601 format.
*/
@property (nonatomic, strong) NSDate *updatedAt;
/**
* An array of addresses for the customer.
*/
@property (nonatomic, strong) NSArray<BUYAddress *> *addresses;
/**
* The default address for the customer.
*/
@property (nonatomic, strong) BUYAddress *defaultAddress;
@end
//
// BUYCustomer.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 "BUYCustomer.h"
#import "BUYAddress.h"
@implementation BUYCustomer
- (NSString *)fullName
{
if (self.firstName.length > 0 || self.lastName.length > 0) {
return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
}
return @"";
}
- (void)updateWithDictionary:(NSDictionary *)dictionary
{
[super updateWithDictionary:dictionary];
_taxExempt = dictionary[@"tax_exempt"];
_verifiedEmail = dictionary[@"verified_email"];
_acceptsMarketing = dictionary[@"accepts_marketing"];
_customerState = dictionary[@"customer_state"];
_email = dictionary[@"email"];
_firstName = dictionary[@"first_name"];
_lastName = dictionary[@"last_name"];
_lastOrderID = dictionary[@"last_order_id"];
_lastOrderName = dictionary[@"last_order_name"];
_multipassIdentifier = dictionary[@"multipass_identifier"];
_note = dictionary[@"note"];
_tags = dictionary[@"tags"];
_ordersCount = dictionary[@"orders_count"];
_totalSpent = dictionary[@"total_spent"];
_createdAt = dictionary[@"created_at"];
_updatedAt = dictionary[@"updated_at"];
_addresses = [BUYAddress convertJSONArray:dictionary[@"addresses"]];
_defaultAddress = [BUYAddress convertObject:dictionary[@"default_address"]];
}
@end
......@@ -26,55 +26,14 @@
#import <Foundation/Foundation.h>
extern NSString * const BUYShopifyError;
@interface BUYError : NSObject
/**
* A collection of enums for error codes specific to the SDK
*/
typedef NS_ENUM(NSUInteger, BUYCheckoutError){
/**
* An error occurred retrieving the cart for an existing web checkout with BUYStoreViewController
*/
BUYShopifyError_CartFetchError,
/**
* No shipping rates are available for the selected address
*/
BUYShopifyError_NoShippingMethodsToAddress,
/**
* No product or product ID was provided when loading a product in BUYProductViewController
*/
BUYShopifyError_NoProductSpecified,
/**
* The product ID or IDs provided were invalid for the shop. Check that the product are made visible on the Mobile App channel on /admin.
*/
BUYShopifyError_InvalidProductID,
/**
* No collection ID was provided when loading a collection
*/
BUYShopifyError_NoCollectionIdSpecified,
/**
* No gift card code was provided when applying a gift card to a checkout
*/
BUYShopifyError_NoGiftCardSpecified,
/**
* No credit card was provided when calling `storeCreditCard:completion:`
*/
BUYShopifyError_NoCreditCardSpecified,
/**
* No Apple Pay token was provided when attempting to complete a checkout using Apple Pay
*/
BUYShopifyError_NoApplePayTokenSpecified,
/**
* The checkout is invalid and does not have a checkout token. This generally means the BUYCheckout object
* has not been synced with Shopify via `createCheckout:completion:` before making subsequent calls to update
* or complete the checkout
*/
BUYShopifyError_InvalidCheckoutObject,
};
@property (nonatomic, copy) NSString *key;
/**
* BUYError overrides `description` and provides a human-readable dictionary for the error
*/
@interface BUYError : NSError
- (instancetype)initWithKey:(NSString *)key json:(NSDictionary *)json;
@property (nonatomic, copy) NSString *code;
@property (nonatomic, copy) NSString *message;
@property (nonatomic, copy) NSDictionary<NSString *, NSString *> *options;
@end
......@@ -26,13 +26,21 @@
#import "BUYError.h"
NSString * const BUYShopifyError = @"BUYShopifyError";
@implementation BUYError
- (instancetype)initWithKey:(NSString *)key json:(NSDictionary *)json
{
self = [super init];
if (self) {
self.key = key;
[self setValuesForKeysWithDictionary:json];
}
return self;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"Error code %td: %@", self.code, [self userInfo]];
return [NSString stringWithFormat:@"%@ %@", self.key, self.message];
}
@end
......@@ -31,3 +31,7 @@
- (NSDictionary *)jsonDictionaryForCheckout;
@end
@interface NSDictionary (BUYSerializable) <BUYSerializable>
@end
\ No newline at end of file
//
// BUYSerializable.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 "BUYSerializable.h"
@implementation NSDictionary (BUYSerializable)
- (NSDictionary *)jsonDictionaryForCheckout {
return self;
}
@end
......@@ -32,19 +32,19 @@
- (void)updateWithDictionary:(NSDictionary *)dictionary
{
self.address1 = dictionary[@"address1"];
self.address2 = dictionary[@"address2"];
self.city = dictionary[@"city"];
self.company = dictionary[@"company"];
self.firstName = dictionary[@"first_name"];
self.lastName = dictionary[@"last_name"];
self.phone = dictionary[@"phone"];
self.address1 = [dictionary buy_objectForKey:@"address1"];
self.address2 = [dictionary buy_objectForKey:@"address2"];
self.city = [dictionary buy_objectForKey:@"city"];
self.company = [dictionary buy_objectForKey:@"company"];
self.firstName = [dictionary buy_objectForKey:@"first_name"];
self.lastName = [dictionary buy_objectForKey:@"last_name"];
self.phone = [dictionary buy_objectForKey:@"phone"];
self.country = dictionary[@"country"];
self.countryCode = dictionary[@"country_code"];
self.country = [dictionary buy_objectForKey:@"country"];
self.countryCode = [dictionary buy_objectForKey:@"country_code"];
self.province = [dictionary buy_objectForKey:@"province"];
self.provinceCode = [dictionary buy_objectForKey:@"province_code"];
self.zip = dictionary[@"zip"];
self.zip = [dictionary buy_objectForKey:@"zip"];
}
- (NSDictionary *)jsonDictionaryForCheckout
......
......@@ -227,7 +227,7 @@
/**
* Customer ID associated with the checkout
*/
@property (nonatomic, copy, readonly) NSString *customerId;
@property (nonatomic, copy, readonly) NSNumber *customerId;
/**
* An optional note attached to the order
......
......@@ -48,7 +48,7 @@
@property (nonatomic, copy) NSDate *updatedAtDate;
@property (nonatomic, strong) BUYMaskedCreditCard *creditCard;
@property (nonatomic, strong) BUYOrder *order;
@property (nonatomic, copy) NSString *customerId;
@property (nonatomic, copy) NSNumber *customerId;
@property (nonatomic, strong) NSURL *privacyPolicyURL;
@property (nonatomic, strong) NSURL *refundPolicyURL;
@property (nonatomic, strong) NSURL *termsOfServiceURL;
......
......@@ -44,6 +44,7 @@
#import "BUYVariantSelectionViewController.h"
#import "BUYError.h"
#import "BUYShop.h"
#import "BUYShopifyErrorCodes.h"
#import "BUYImage.h"
CGFloat const BUYMaxProductViewWidth = 414.0; // We max out to the width of the iPhone 6+
......
......@@ -28,13 +28,20 @@
* Umbrella header used for Cocoapods
*/
#import "BUYAccountCredentials.h"
#import "BUYApplePayAdditions.h"
#import "BUYApplePayHelpers.h"
#import "BUYAddress.h"
#import "BUYCart.h"
#import "BUYCartLineItem.h"
#import "BUYCheckout.h"
#import "BUYCheckoutAttribute.h"
#import "BUYClient+Test.h"
#import "BUYClient.h"
#import "BUYClient+Customers.h"
#import "BUYCollection.h"
#import "BUYCreditCard.h"
#import "BUYCustomer.h"
#import "BUYDiscount.h"
#import "BUYGiftCard.h"
#import "BUYImage.h"
......@@ -49,9 +56,6 @@
#import "BUYShop.h"
#import "BUYTaxLine.h"
#import "BUYApplePayAdditions.h"
#import "BUYApplePayHelpers.h"
#import "BUYClient.h"
#import "BUYError.h"
#import "BUYPaymentButton.h"
......
......@@ -31,6 +31,7 @@
#import "BUYError.h"
#import "BUYAddress+Additions.h"
#import "BUYShop.h"
#import "BUYShopifyErrorCodes.h"
const NSTimeInterval PollDelay = 0.5;
......
//
// BUYError+BUYAdditions.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 "BUYError.h"
@interface BUYError (Checkout)
+ (NSArray<BUYError *> *)errorsFromCheckoutJSON:(NSDictionary *)json;
@property (readonly) NSString *quantityRemainingMessage;
@end
@interface BUYError (Customer)
+ (NSArray<BUYError *> *)errorsFromSignUpJSON:(NSDictionary *)json;
@end
//
// BUYError+BUYAdditions.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 "BUYError+BUYAdditions.h"
@implementation BUYError (Checkout)
+ (NSArray<BUYError *> *)errorsFromCheckoutJSON:(NSDictionary *)json
{
NSArray *lineItems = json[@"errors"][@"checkout"][@"line_items"];
NSMutableArray *errors = [NSMutableArray array];
for (NSDictionary<NSString *, NSArray *> *lineItem in lineItems) {
if (lineItem == (id)[NSNull null]) {
[errors addObject:lineItem];
}
else {
for (NSString *key in lineItem.allKeys) {
NSDictionary *reason = [lineItem[key] firstObject];
[errors addObject:[[BUYError alloc] initWithKey:key json:reason]];
};
}
};
return errors;
}
- (NSString *)quantityRemainingMessage
{
NSNumber *remaining = (id)self.options[@"remaining"];
NSString *localizedString;
if ([remaining isEqualToNumber:@0]) {
localizedString = NSLocalizedString(@"Completely sold out", @"String describing a line item with zero stock available");
} else {
localizedString = NSLocalizedString(@"Only %1$@ left in stock, reduce the quantity and try again.", @"String describing an out of stock line item with first parameter representing amount remaining");
}
return [NSString localizedStringWithFormat:localizedString, remaining];
}
@end
@implementation BUYError (Customer)
+ (NSArray<BUYError *> *)errorsFromSignUpJSON:(NSDictionary *)json
{
NSDictionary *reasons = json[@"errors"][@"customer"];
__block NSMutableArray *errors = [NSMutableArray array];
[reasons enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSArray * _Nonnull obj, BOOL * _Nonnull stop) {
for (NSDictionary *reason in obj) {
[errors addObject:[[BUYError alloc] initWithKey:key json:reason]];
}
}];
return errors;
}
@end
//
// BUYShopifyErrorCodes.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.
//
#ifndef BUYShopifyErrorCodes_h
#define BUYShopifyErrorCodes_h
static NSString * const BUYShopifyError = @"BUYShopifyError";
/**
* A collection of enums for error codes specific to the SDK
*/
typedef NS_ENUM(NSUInteger, BUYCheckoutError){
/**
* An error occurred retrieving the cart for an existing web checkout with StoreViewController
*/
BUYShopifyError_CartFetchError,
/**
* No shipping rates are available for the selected address
*/
BUYShopifyError_NoShippingMethodsToAddress,
/**
* No product or product ID was provided when loading a product in BUYProductViewController
*/
BUYShopifyError_NoProductSpecified,
/**
* The product ID or IDs provided were invalid for the shop. Check that the product are made visible on the Mobile App channel on /admin.
*/
BUYShopifyError_InvalidProductID,
/**
* No collection ID was provided when loading a collection
*/
BUYShopifyError_NoCollectionIdSpecified,
/**
* No gift card code was provided when applying a gift card to a checkout
*/
BUYShopifyError_NoGiftCardSpecified,
/**
* No credit card was provided when calling `storeCreditCard:completion:`
*/
BUYShopifyError_NoCreditCardSpecified,
/**
* No Apple Pay token was provided when attempting to complete a checkout using Apple Pay
*/
BUYShopifyError_NoApplePayTokenSpecified,
/**
* The checkout is invalid and does not have a checkout token. This generally means the BUYCheckout object
* has not been synced with Shopify via `createCheckout:completion:` before making subsequent calls to update
* or complete the checkout
*/
BUYShopifyError_InvalidCheckoutObject,
/**
* A customer token has not been configured on the client
*/
BUYShopifyError_InvalidCustomerToken
};
#endif /* BUYShopifyErrorCodes_h */
......@@ -31,6 +31,7 @@
#import "BUYStoreViewController.h"
#import "BUYError.h"
#import "BUYOrder.h"
#import "BUYShopifyErrorCodes.h"
@interface BUYStoreViewController () <WKNavigationDelegate, WKScriptMessageHandler>
@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