Commit 620cd3cb by Dima Bart

Merge pull request #137 from Shopify/feature/126-customer-api

Support for Customer API
parents 8cfe7c1a 5685355f
......@@ -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"
......
......@@ -45,6 +45,16 @@
"testCheckoutFlowUsingCreditCard_12":{"body":"","code":200,"message":"OK"},
"testCheckoutFlowUsingCreditCard_13":{"body":"{\"checkout\":{\"created_at\":\"2016-03-07T10:20:56-05:00\",\"currency\":\"CAD\",\"customer_id\":1137418883,\"email\":\"test@test.com\",\"location_id\":null,\"order_id\":2548686982,\"requires_shipping\":true,\"reservation_time\":300,\"source_name\":\"mobile_app\",\"source_identifier\":\"26915715\",\"source_url\":null,\"taxes_included\":false,\"token\":\"4bd92a3e9ab0b3adf790e0774db6c815\",\"updated_at\":\"2016-03-07T10:21:00-05:00\",\"payment_due\":\"2238.99\",\"payment_url\":\"https:\\/\\/elb.deposit.shopifycs.com\\/sessions\",\"reservation_time_left\":0,\"subtotal_price\":\"2230.99\",\"total_price\":\"2238.99\",\"total_tax\":\"0.00\",\"attributes\":[],\"note\":\"\",\"order\":{\"id\":2548686982,\"name\":\"#4269\",\"status_url\":\"https:\\/\\/checkout.shopify.com\\/9575792\\/checkouts\\/4bd92a3e9ab0b3adf790e0774db6c815\\/thank_you\"},\"order_status_url\":\"https:\\/\\/checkout.shopify.com\\/9575792\\/checkouts\\/4bd92a3e9ab0b3adf790e0774db6c815\\/thank_you\",\"privacy_policy_url\":null,\"refund_policy_url\":null,\"terms_of_service_url\":null,\"user_id\":null,\"web_url\":\"https:\\/\\/checkout.shopify.com\\/9575792\\/checkouts\\/4bd92a3e9ab0b3adf790e0774db6c815\",\"tax_lines\":[],\"line_items\":[{\"id\":\"cfdc9344bacf009e\",\"product_id\":2096063363,\"variant_id\":6030700419,\"sku\":\"\",\"vendor\":\"McCullough Group\",\"title\":\"Actinian Fur Hat\",\"variant_title\":\"Teal\",\"taxable\":false,\"requires_shipping\":true,\"price\":\"2230.99\",\"compare_at_price\":null,\"line_price\":\"2230.99\",\"properties\":{\"size\":\"large\",\"color\":\"red\"},\"quantity\":1,\"grams\":4000,\"fulfillment_service\":\"manual\",\"applied_discounts\":[]}],\"gift_cards\":[],\"shipping_rate\":{\"id\":\"shopify-Standard%20Shipping-8.00\",\"price\":\"8.00\",\"title\":\"Standard Shipping\"},\"shipping_address\":{\"id\":3479864454,\"first_name\":\"MobileBuy\",\"last_name\":\"TestBot\",\"phone\":\"1-555-555-5555\",\"company\":\"Shopify Inc.\",\"address1\":\"150 Elgin Street\",\"address2\":\"8th Floor\",\"city\":\"Ottawa\",\"province\":\"Ontario\",\"province_code\":\"ON\",\"country\":\"Canada\",\"country_code\":\"CA\",\"zip\":\"K1N5T5\"},\"credit_card\":{\"first_name\":\"John\",\"last_name\":\"Smith\",\"first_digits\":\"424242\",\"last_digits\":\"4242\",\"expiry_month\":5,\"expiry_year\":2020},\"billing_address\":{\"id\":3479864390,\"first_name\":\"MobileBuy\",\"last_name\":\"TestBot\",\"phone\":\"1-555-555-5555\",\"company\":\"Shopify Inc.\",\"address1\":\"150 Elgin Street\",\"address2\":\"8th Floor\",\"city\":\"Ottawa\",\"province\":\"Ontario\",\"province_code\":\"ON\",\"country\":\"Canada\",\"country_code\":\"CA\",\"zip\":\"K1N5T5\"},\"discount\":null}}","code":200,"message":"OK"},
"testCreateCheckoutWithExpiredDiscount_0":{"body":"{\"product_listings\":[{\"id\":2626498435,\"product_id\":2096063363,\"channel_id\":26915715,\"created_at\":\"2015-08-19T09:47:37-04:00\",\"updated_at\":\"2015-08-19T09:47:37-04:00\",\"body_html\":\"parsing the driver won't do anything, we need to calculate the online PNG program!\",\"handle\":\"actinian-fur-hat\",\"product_type\":\"enable bricks-and-clicks e-business\",\"title\":\"Actinian Fur Hat\",\"vendor\":\"McCullough Group\",\"published_at\":\"2015-08-19T09:47:37-04:00\",\"published\":true,\"available\":true,\"tags\":\"\",\"images\":[{\"id\":4277333187,\"created_at\":\"2015-08-13T14:12:44-04:00\",\"position\":1,\"updated_at\":\"2015-08-13T14:12:44-04:00\",\"product_id\":2096063363,\"src\":\"https:\\/\\/cdn.shopify.com\\/s\\/files\\/1\\/0957\\/5792\\/products\\/Kraepelin3.gif?v=1439489564\",\"variant_ids\":[]}],\"options\":[{\"id\":2524801731,\"name\":\"Color or something\",\"product_id\":2096063363,\"position\":1}],\"variants\":[{\"id\":6030700419,\"title\":\"Teal\",\"option_values\":[{\"option_id\":2524801731,\"name\":\"Color or something\",\"value\":\"Teal\"}],\"price\":\"2230.99\",\"compare_at_price\":null,\"grams\":4000,\"requires_shipping\":true,\"sku\":\"\",\"taxable\":false,\"position\":1,\"available\":true}]}]}","code":200,"message":"OK"},
"testCheckoutFlowUsingCreditCard_14": {
"body": "",
"code": 200,
"message": "OK"
},
"testCheckoutFlowUsingCreditCard_15": {
"body": "{\"checkout\":{\"created_at\":\"2015-10-08T13:34:30-04:00\",\"currency\":\"CAD\",\"customer_id\":1137418883,\"email\":\"test@test.com\",\"location_id\":null,\"order_id\":1432044675,\"requires_shipping\":true,\"reservation_time\":300,\"source_name\":\"mobile_app\",\"source_identifier\":\"26915715\",\"source_url\":null,\"taxes_included\":false,\"token\":\"89978073d2d3602c114fbd59becc5f96\",\"updated_at\":\"2015-10-08T13:34:33-04:00\",\"payment_due\":\"2238.99\",\"payment_url\":\"https:\\/\\/us-east-1-deposit.cs.shopify.com\\/sessions\",\"reservation_time_left\":0,\"subtotal_price\":\"2230.99\",\"total_price\":\"2238.99\",\"total_tax\":\"0.00\",\"order\":{\"id\":1432044675,\"name\":\"#1771\",\"status_url\":\"https:\\/\\/checkout.shopify.com\\/9575792\\/checkouts\\/89978073d2d3602c114fbd59becc5f96\\/thank_you\"},\"order_status_url\":\"https:\\/\\/checkout.shopify.com\\/9575792\\/checkouts\\/89978073d2d3602c114fbd59becc5f96\\/thank_you\",\"privacy_policy_url\":null,\"refund_policy_url\":null,\"terms_of_service_url\":null,\"user_id\":null,\"web_url\":\"https:\\/\\/checkout.shopify.com\\/9575792\\/checkouts\\/89978073d2d3602c114fbd59becc5f96\",\"tax_lines\":[],\"line_items\":[{\"id\":\"c7ec4b9bf3e6ddbd\",\"product_id\":2096063363,\"variant_id\":6030700419,\"sku\":\"\",\"vendor\":\"McCullough Group\",\"title\":\"Actinian Fur Hat\",\"variant_title\":\"Teal\",\"taxable\":false,\"requires_shipping\":true,\"price\":\"2230.99\",\"compare_at_price\":null,\"line_price\":\"2230.99\",\"properties\":{\"size\":\"large\",\"color\":\"red\"},\"quantity\":1,\"grams\":4000,\"fulfillment_service\":\"manual\"}],\"gift_cards\":[],\"shipping_rate\":{\"id\":\"shopify-Standard%20Shipping-8.00\",\"price\":\"8.00\",\"title\":\"Standard Shipping\"},\"shipping_address\":{\"first_name\":\"MobileBuy\",\"last_name\":\"TestBot\",\"phone\":\"1-555-555-5555\",\"company\":\"Shopify Inc.\",\"address1\":\"150 Elgin Street\",\"address2\":\"8th Floor\",\"city\":\"Ottawa\",\"province\":\"Ontario\",\"province_code\":\"ON\",\"country\":\"Canada\",\"country_code\":\"CA\",\"zip\":\"K1N5T5\"},\"credit_card\":{\"first_name\":\"John\",\"last_name\":\"Smith\",\"first_digits\":\"424242\",\"last_digits\":\"4242\",\"expiry_month\":5,\"expiry_year\":2020},\"billing_address\":{\"first_name\":\"MobileBuy\",\"last_name\":\"TestBot\",\"phone\":\"1-555-555-5555\",\"company\":\"Shopify Inc.\",\"address1\":\"150 Elgin Street\",\"address2\":\"8th Floor\",\"city\":\"Ottawa\",\"province\":\"Ontario\",\"province_code\":\"ON\",\"country\":\"Canada\",\"country_code\":\"CA\",\"zip\":\"K1N5T5\"},\"discount\":null}}",
"code": 200,
"message": "OK"
},
"testCreateCheckoutWithExpiredDiscount_1":{"body":"{\"errors\":{\"checkout\":{\"line_items\":[],\"source_name\":[],\"reservation_time\":[],\"discount\":{\"amount\":[{\"code\":\"greater_than\",\"message\":\"must be greater than 0\",\"options\":{\"value\":0.0,\"count\":0}}],\"code\":[{\"code\":\"discount_not_found\",\"message\":\"Unable to find a valid discount matching the code entered\",\"options\":{}}]}}}}","code":422,"message":"Unprocessable Entity"},
"testCreateCheckoutWithNonExistentDiscount_0":{"body":"{\"product_listings\":[{\"id\":2626498435,\"product_id\":2096063363,\"channel_id\":26915715,\"created_at\":\"2015-08-19T09:47:37-04:00\",\"updated_at\":\"2015-08-19T09:47:37-04:00\",\"body_html\":\"parsing the driver won't do anything, we need to calculate the online PNG program!\",\"handle\":\"actinian-fur-hat\",\"product_type\":\"enable bricks-and-clicks e-business\",\"title\":\"Actinian Fur Hat\",\"vendor\":\"McCullough Group\",\"published_at\":\"2015-08-19T09:47:37-04:00\",\"published\":true,\"available\":true,\"tags\":\"\",\"images\":[{\"id\":4277333187,\"created_at\":\"2015-08-13T14:12:44-04:00\",\"position\":1,\"updated_at\":\"2015-08-13T14:12:44-04:00\",\"product_id\":2096063363,\"src\":\"https:\\/\\/cdn.shopify.com\\/s\\/files\\/1\\/0957\\/5792\\/products\\/Kraepelin3.gif?v=1439489564\",\"variant_ids\":[]}],\"options\":[{\"id\":2524801731,\"name\":\"Color or something\",\"product_id\":2096063363,\"position\":1}],\"variants\":[{\"id\":6030700419,\"title\":\"Teal\",\"option_values\":[{\"option_id\":2524801731,\"name\":\"Color or something\",\"value\":\"Teal\"}],\"price\":\"2230.99\",\"compare_at_price\":null,\"grams\":4000,\"requires_shipping\":true,\"sku\":\"\",\"taxable\":false,\"position\":1,\"available\":true}]}]}","code":200,"message":"OK"},
"testCreateCheckoutWithNonExistentDiscount_1":{"body":"{\"errors\":{\"checkout\":{\"line_items\":[],\"source_name\":[],\"reservation_time\":[],\"discount\":{\"amount\":[{\"code\":\"greater_than\",\"message\":\"must be greater than 0\",\"options\":{\"value\":0.0,\"count\":0}}],\"code\":[{\"code\":\"discount_not_found\",\"message\":\"Unable to find a valid discount matching the code entered\",\"options\":{}}]}}}}","code":422,"message":"Unprocessable Entity"},
......@@ -109,4 +119,9 @@
"testGetProductsWithOneInvalidId_0":{"body":"{\"product_listings\":[{\"id\":2626498435,\"product_id\":2096063363,\"channel_id\":26915715,\"created_at\":\"2015-08-19T09:47:37-04:00\",\"updated_at\":\"2015-08-19T09:47:37-04:00\",\"body_html\":\"parsing the driver won't do anything, we need to calculate the online PNG program!\",\"handle\":\"actinian-fur-hat\",\"product_type\":\"enable bricks-and-clicks e-business\",\"title\":\"Actinian Fur Hat\",\"vendor\":\"McCullough Group\",\"published_at\":\"2015-08-19T09:47:37-04:00\",\"published\":true,\"available\":true,\"tags\":\"\",\"images\":[{\"id\":4277333187,\"created_at\":\"2015-08-13T14:12:44-04:00\",\"position\":1,\"updated_at\":\"2015-08-13T14:12:44-04:00\",\"product_id\":2096063363,\"src\":\"https:\\/\\/cdn.shopify.com\\/s\\/files\\/1\\/0957\\/5792\\/products\\/Kraepelin3.gif?v=1439489564\",\"variant_ids\":[]}],\"options\":[{\"id\":2524801731,\"name\":\"Color or something\",\"product_id\":2096063363,\"position\":1}],\"variants\":[{\"id\":6030700419,\"title\":\"Teal\",\"option_values\":[{\"option_id\":2524801731,\"name\":\"Color or something\",\"value\":\"Teal\"}],\"price\":\"2230.99\",\"compare_at_price\":null,\"grams\":4000,\"requires_shipping\":true,\"sku\":\"\",\"taxable\":false,\"position\":1,\"available\":true}]}]}","code":200,"message":"OK"},
"testGetShop_0":{"body":"{\"id\":9575792,\"name\":\"MobileBuySDKTestShop\",\"city\":\"Richmond Hill\",\"province\":\"Ontario\",\"country\":\"CA\",\"currency\":\"CAD\",\"domain\":\"mobilebuysdktestshop.myshopify.com\",\"url\":\"http:\\/\\/mobilebuysdktestshop.myshopify.com\",\"myshopify_domain\":\"mobilebuysdktestshop.myshopify.com\",\"description\":\"\",\"ships_to_countries\":[\"*\",\"CA\"],\"money_format\":\"${{amount}}\",\"published_collections_count\":1,\"published_products_count\":11}","code":200,"message":"OK"},
"testGetCollectionPage_0":{"body":"{\"collection_listings\":[{\"id\":171459075,\"collection_id\":109931075,\"channel_id\":26915715,\"created_at\":\"2015-08-19T09:47:00-04:00\",\"updated_at\":\"2015-08-19T15:43:26-04:00\",\"body_html\":\"\",\"handle\":\"frontpage\",\"image\":null,\"title\":\"Frontpage\",\"published_at\":\"2015-08-19T09:47:00-04:00\",\"published\":true}]}","code":200,"message":"OK"},
"testGetOutOfIndexCollectionPage_0":{"body":"{\"collection_listings\":[]}","code":200,"message":"OK"}}
\ No newline at end of file
"testGetOutOfIndexCollectionPage_0":{"body":"{\"collection_listings\":[]}","code":200,"message":"OK"},
"testOutOfStockVariant":{"body":"{\"errors\":{\"checkout\":{\"line_items\":[null,{\"quantity\":[{\"code\":\"not_enough_in_stock\",\"message\":\"Not enough items available. Only 0 left.\",\"options\":{\"remaining\":0}}]},{\"quantity\":[{\"code\":\"not_enough_in_stock\",\"message\":\"Not enough items available. Only 0 left.\",\"options\":{\"remaining\":0}}]}],\"source_name\":[],\"reservation_time\":[]}}}"},
"testCustomerDuplicateEmail":{"body":"{\"errors\":{\"customer\":{\"email\":[{\"code\":\"taken\",\"message\":\"has already been taken\",\"options\":{\"rescue_from_duplicate\":true,\"value\":\"asd@asd.com\"}}]}}}"},
"testCustomerInvalidEmailPassword":{"body":"{\"errors\":{\"customer\":{\"password\":[{\"code\":\"too_short\",\"message\":\"is too short (minimum is 5 characters)\",\"options\":{\"count\":5}}],\"password_confirmation\":[{\"code\":\"confirmation\",\"message\":\"doesn't match Password\",\"options\":{\"attribute\":\"Password\"}}],\"email\":[{\"code\":\"invalid\",\"message\":\"is invalid\",\"options\":{}}]}}}"},
"testCustomerLogin":{"body":"{\"customer\":{\"id\":2529265094,\"email\":\"asd@asd.com\",\"default_address\":{\"id\":2839567814,\"first_name\":\"Fast\",\"last_name\":\"Add\",\"company\":\"Adidas\",\"address1\":\"Sass\",\"address2\":\"12\",\"city\":\"Qsdasd\",\"province\":null,\"country\":\"Bouvet Island\",\"zip\":\"24124124\",\"phone\":\"123124124\",\"name\":\"Fast Add\",\"province_code\":null,\"country_code\":\"BV\",\"country_name\":\"Bouvet Island\",\"default\":true},\"verified_email\":true,\"accepts_marketing\":false,\"first_name\":\"Fast\",\"last_name\":\"Add\",\"orders_count\":9,\"total_spent\":\"375.00\",\"created_at\":\"2016-02-16T14:42:24-05:00\",\"updated_at\":\"2016-03-10T16:34:04-05:00\",\"state\":\"enabled\",\"last_order_id\":2566266118,\"last_order_name\":\"#1137\",\"addresses\":[{\"id\":2785988486,\"first_name\":\"AA\",\"last_name\":\"A\",\"phone\":\"\",\"company\":\"\",\"address1\":\"Assiniboine Road\",\"address2\":\"\",\"city\":\"Toronto\",\"province\":\"Ontario\",\"province_code\":\"ON\",\"country\":\"Canada\",\"country_code\":\"CA\",\"zip\":\"M3J1E1\"},{\"id\":2839567814,\"first_name\":\"Fast\",\"last_name\":\"Add\",\"phone\":\"123124124\",\"company\":\"Adidas\",\"address1\":\"Sass\",\"address2\":\"12\",\"city\":\"Qsdasd\",\"province\":null,\"province_code\":null,\"country\":\"Bouvet Island\",\"country_code\":\"BV\",\"zip\":\"24124124\"}],\"multipass_identifier\":null,\"tax_exempt\":false}}","code":200,"message":"OK"}
}
......@@ -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": {
......
......@@ -244,6 +244,26 @@
90F593091B0D5F4C0026B382 /* BUYClientTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 90F592FD1B0D5F4C0026B382 /* BUYClientTest.m */; };
90F5930A1B0D5F4C0026B382 /* BUYLineItemTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 90F592FE1B0D5F4C0026B382 /* BUYLineItemTest.m */; };
90F5930B1B0D5F4C0026B382 /* BUYObjectTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 90F592FF1B0D5F4C0026B382 /* BUYObjectTests.m */; };
9A3B2DC91CD27D5B00BFF49C /* BUYCustomer.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A3B2DC71CD27D5B00BFF49C /* BUYCustomer.h */; settings = {ATTRIBUTES = (Public, ); }; };
9A3B2DCA1CD27D5B00BFF49C /* BUYCustomer.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A3B2DC71CD27D5B00BFF49C /* BUYCustomer.h */; settings = {ATTRIBUTES = (Public, ); }; };
9A3B2DCB1CD27D5B00BFF49C /* BUYCustomer.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A3B2DC81CD27D5B00BFF49C /* BUYCustomer.m */; };
9A3B2DCC1CD27D5B00BFF49C /* BUYCustomer.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A3B2DC81CD27D5B00BFF49C /* BUYCustomer.m */; };
9A3B2DCF1CD2822F00BFF49C /* BUYClient+Customers.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A3B2DCD1CD2822F00BFF49C /* BUYClient+Customers.h */; settings = {ATTRIBUTES = (Public, ); }; };
9A3B2DD01CD2822F00BFF49C /* BUYClient+Customers.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A3B2DCD1CD2822F00BFF49C /* BUYClient+Customers.h */; settings = {ATTRIBUTES = (Public, ); }; };
9A3B2DD11CD2822F00BFF49C /* BUYClient+Customers.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A3B2DCE1CD2822F00BFF49C /* BUYClient+Customers.m */; };
9A3B2DD21CD2822F00BFF49C /* BUYClient+Customers.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A3B2DCE1CD2822F00BFF49C /* BUYClient+Customers.m */; };
9A3B2DD51CD2829900BFF49C /* BUYAccountCredentials.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A3B2DD31CD2829900BFF49C /* BUYAccountCredentials.h */; settings = {ATTRIBUTES = (Public, ); }; };
9A3B2DD61CD2829900BFF49C /* BUYAccountCredentials.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A3B2DD31CD2829900BFF49C /* BUYAccountCredentials.h */; settings = {ATTRIBUTES = (Public, ); }; };
9A3B2DD71CD2829900BFF49C /* BUYAccountCredentials.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A3B2DD41CD2829900BFF49C /* BUYAccountCredentials.m */; };
9A3B2DD81CD2829900BFF49C /* BUYAccountCredentials.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A3B2DD41CD2829900BFF49C /* BUYAccountCredentials.m */; };
9A3B2DDA1CD282DA00BFF49C /* BUYClient_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A3B2DD91CD282DA00BFF49C /* BUYClient_Internal.h */; };
9A3B2DDB1CD282DA00BFF49C /* BUYClient_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A3B2DD91CD282DA00BFF49C /* BUYClient_Internal.h */; };
9A3B2DDD1CD28D7300BFF49C /* BUYSerializable.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A3B2DDC1CD28D6F00BFF49C /* BUYSerializable.m */; };
9A3B2DDE1CD28D7300BFF49C /* BUYSerializable.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A3B2DDC1CD28D6F00BFF49C /* BUYSerializable.m */; };
9A3B2DE01CD28E9900BFF49C /* BUYShopifyErrorCodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A3B2DDF1CD28E9900BFF49C /* BUYShopifyErrorCodes.h */; };
9A3B2DE11CD28E9900BFF49C /* BUYShopifyErrorCodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A3B2DDF1CD28E9900BFF49C /* BUYShopifyErrorCodes.h */; };
9A9C03431CD9369400AE79BD /* BUYCheckout_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A9C03421CD9369400AE79BD /* BUYCheckout_Private.h */; };
9A9C03441CD9369600AE79BD /* BUYCheckout_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A9C03421CD9369400AE79BD /* BUYCheckout_Private.h */; };
BE1007951B6038150031CEE7 /* BUYProductVariant+Options.h in Headers */ = {isa = PBXBuildFile; fileRef = BE1007931B6038150031CEE7 /* BUYProductVariant+Options.h */; };
BE1007961B6038150031CEE7 /* BUYProductVariant+Options.m in Sources */ = {isa = PBXBuildFile; fileRef = BE1007941B6038150031CEE7 /* BUYProductVariant+Options.m */; };
BE10079B1B6165EC0031CEE7 /* BUYOptionValueCell.h in Headers */ = {isa = PBXBuildFile; fileRef = BE1007991B6165EC0031CEE7 /* BUYOptionValueCell.h */; };
......@@ -498,6 +518,18 @@
90F593001B0D5F4C0026B382 /* BUYTestConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BUYTestConstants.h; sourceTree = "<group>"; };
90FC31A61B50371600AFAB51 /* BUYProductViewHeaderBackgroundImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = BUYProductViewHeaderBackgroundImageView.h; path = "Product View/BUYProductViewHeaderBackgroundImageView.h"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
90FC31A71B50371600AFAB51 /* BUYProductViewHeaderBackgroundImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BUYProductViewHeaderBackgroundImageView.m; path = "Product View/BUYProductViewHeaderBackgroundImageView.m"; sourceTree = "<group>"; };
9A3B2DC71CD27D5B00BFF49C /* BUYCustomer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BUYCustomer.h; sourceTree = "<group>"; };
9A3B2DC81CD27D5B00BFF49C /* BUYCustomer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BUYCustomer.m; sourceTree = "<group>"; };
9A3B2DCD1CD2822F00BFF49C /* BUYClient+Customers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "BUYClient+Customers.h"; sourceTree = "<group>"; };
9A3B2DCE1CD2822F00BFF49C /* BUYClient+Customers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "BUYClient+Customers.m"; sourceTree = "<group>"; };
9A3B2DD31CD2829900BFF49C /* BUYAccountCredentials.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BUYAccountCredentials.h; sourceTree = "<group>"; };
9A3B2DD41CD2829900BFF49C /* BUYAccountCredentials.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BUYAccountCredentials.m; sourceTree = "<group>"; };
9A3B2DD91CD282DA00BFF49C /* BUYClient_Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BUYClient_Internal.h; sourceTree = "<group>"; };
9A3B2DDC1CD28D6F00BFF49C /* BUYSerializable.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BUYSerializable.m; sourceTree = "<group>"; };
9A3B2DDF1CD28E9900BFF49C /* BUYShopifyErrorCodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BUYShopifyErrorCodes.h; sourceTree = "<group>"; };
9A3B2DE81CD2990E00BFF49C /* BUYError+BUYAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "BUYError+BUYAdditions.h"; sourceTree = "<group>"; };
9A3B2DE91CD2990E00BFF49C /* BUYError+BUYAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "BUYError+BUYAdditions.m"; sourceTree = "<group>"; };
9A9C03421CD9369400AE79BD /* BUYCheckout_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BUYCheckout_Private.h; sourceTree = "<group>"; };
BE1007931B6038150031CEE7 /* BUYProductVariant+Options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "BUYProductVariant+Options.h"; sourceTree = "<group>"; };
BE1007941B6038150031CEE7 /* BUYProductVariant+Options.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "BUYProductVariant+Options.m"; sourceTree = "<group>"; };
BE1007991B6165EC0031CEE7 /* BUYOptionValueCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BUYOptionValueCell.h; sourceTree = "<group>"; };
......@@ -528,7 +560,6 @@
BE98DB5A1BB1F4D000C29564 /* OHHTTPStubsResponse+Helpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OHHTTPStubsResponse+Helpers.h"; sourceTree = "<group>"; };
BE98DB5B1BB1F4D000C29564 /* OHHTTPStubsResponse+Helpers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "OHHTTPStubsResponse+Helpers.m"; sourceTree = "<group>"; };
BE9A64281B503C2F0033E558 /* Buy.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Buy.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BEB74A1B1B5490140005A300 /* BUYCheckout_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BUYCheckout_Private.h; sourceTree = "<group>"; };
BEB74A1F1B554BF20005A300 /* BUYPresentationControllerForVariantSelection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BUYPresentationControllerForVariantSelection.h; path = "Mobile Buy SDK/Product View/Variant Selection/BUYPresentationControllerForVariantSelection.h"; sourceTree = SOURCE_ROOT; };
BEB74A201B554BF20005A300 /* BUYPresentationControllerForVariantSelection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BUYPresentationControllerForVariantSelection.m; path = "Mobile Buy SDK/Product View/Variant Selection/BUYPresentationControllerForVariantSelection.m"; sourceTree = SOURCE_ROOT; };
BEB74A251B554BFB0005A300 /* BUYOptionSelectionNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BUYOptionSelectionNavigationController.h; path = "Mobile Buy SDK/Product View/Variant Selection/BUYOptionSelectionNavigationController.h"; sourceTree = SOURCE_ROOT; };
......@@ -630,23 +661,23 @@
841ADE2A1CB6F31C000004B0 /* Transient */ = {
isa = PBXGroup;
children = (
90AFAA601B01390F00F21C23 /* BUYAddress.h */,
90AFAA611B01390F00F21C23 /* BUYAddress.m */,
BEB74A1B1B5490140005A300 /* BUYCheckout_Private.h */,
F773749419C77C260039681C /* BUYCheckout.h */,
F773749519C77C260039681C /* BUYCheckout.m */,
9032F2D81BE9457A00BB9EEF /* BUYCheckoutAttribute.h */,
9032F2D91BE9457A00BB9EEF /* BUYCheckoutAttribute.m */,
90AFAA681B0139DE00F21C23 /* BUYDiscount.h */,
90AFAA691B0139DE00F21C23 /* BUYDiscount.m */,
42488B321AB8761A005F21A9 /* BUYGiftCard.h */,
42488B331AB8761A005F21A9 /* BUYGiftCard.m */,
90AFAA681B0139DE00F21C23 /* BUYDiscount.h */,
90AFAA691B0139DE00F21C23 /* BUYDiscount.m */,
BE5DC3611B71022D00B2BC1E /* BUYMaskedCreditCard.h */,
BE5DC3621B71022D00B2BC1E /* BUYMaskedCreditCard.m */,
90AFAA641B01398A00F21C23 /* BUYShippingRate.h */,
90AFAA651B01398A00F21C23 /* BUYShippingRate.m */,
90AFAA5C1B011EA600F21C23 /* BUYTaxLine.h */,
90AFAA5D1B011EA600F21C23 /* BUYTaxLine.m */,
90AFAA601B01390F00F21C23 /* BUYAddress.h */,
90AFAA611B01390F00F21C23 /* BUYAddress.m */,
F773749419C77C260039681C /* BUYCheckout.h */,
F773749519C77C260039681C /* BUYCheckout.m */,
9A9C03421CD9369400AE79BD /* BUYCheckout_Private.h */,
9032F2D81BE9457A00BB9EEF /* BUYCheckoutAttribute.h */,
9032F2D91BE9457A00BB9EEF /* BUYCheckoutAttribute.m */,
);
path = Transient;
sourceTree = "<group>";
......@@ -654,12 +685,6 @@
841ADE2B1CB6F320000004B0 /* Persistent */ = {
isa = PBXGroup;
children = (
F773744719C77A210039681C /* BUYCart.h */,
F773744819C77A210039681C /* BUYCart.m */,
900396991B601DF400226B73 /* BUYCartLineItem.h */,
9003969A1B601DF400226B73 /* BUYCartLineItem.m */,
BEB74A8E1B55A3D00005A300 /* BUYCollection.h */,
9089CC5D1BB48D06009726D6 /* BUYCollection.m */,
2AF52A791A700B0A0087DB2C /* BUYImage.h */,
2AF52A7A1A700B0A0087DB2C /* BUYImage.m */,
F7FDA16C19C939FF00AF4E93 /* BUYLineItem.h */,
......@@ -676,6 +701,12 @@
2AF52A821A700B0A0087DB2C /* BUYProductVariant.m */,
2AF52A831A700B0A0087DB2C /* BUYShop.h */,
2AF52A841A700B0A0087DB2C /* BUYShop.m */,
F773744719C77A210039681C /* BUYCart.h */,
F773744819C77A210039681C /* BUYCart.m */,
900396991B601DF400226B73 /* BUYCartLineItem.h */,
9003969A1B601DF400226B73 /* BUYCartLineItem.m */,
BEB74A8E1B55A3D00005A300 /* BUYCollection.h */,
9089CC5D1BB48D06009726D6 /* BUYCollection.m */,
);
path = Persistent;
sourceTree = "<group>";
......@@ -871,13 +902,18 @@
children = (
841ADE2B1CB6F320000004B0 /* Persistent */,
841ADE2A1CB6F31C000004B0 /* Transient */,
9A3B2DD31CD2829900BFF49C /* BUYAccountCredentials.h */,
9A3B2DD41CD2829900BFF49C /* BUYAccountCredentials.m */,
F77374AA19C796BD0039681C /* BUYCreditCard.h */,
F77374AB19C796BD0039681C /* BUYCreditCard.m */,
9A3B2DC71CD27D5B00BFF49C /* BUYCustomer.h */,
9A3B2DC81CD27D5B00BFF49C /* BUYCustomer.m */,
BE47340D1B66C4EF00AA721A /* BUYError.h */,
BE47340E1B66C4EF00AA721A /* BUYError.m */,
2AF52A931A7010B20087DB2C /* BUYObject.h */,
2AF52A941A7010B20087DB2C /* BUYObject.mm */,
F76CFF1E19CB7C500079C703 /* BUYSerializable.h */,
9A3B2DDC1CD28D6F00BFF49C /* BUYSerializable.m */,
);
path = Models;
sourceTree = "<group>";
......@@ -885,6 +921,9 @@
F773744519C779C20039681C /* Utils */ = {
isa = PBXGroup;
children = (
9A3B2DDF1CD28E9900BFF49C /* BUYShopifyErrorCodes.h */,
9A3B2DE81CD2990E00BFF49C /* BUYError+BUYAdditions.h */,
9A3B2DE91CD2990E00BFF49C /* BUYError+BUYAdditions.m */,
BE33B4F91B177EC80067982B /* BUYAddress+Additions.h */,
BE33B4FA1B177EC80067982B /* BUYAddress+Additions.m */,
F70CE40D1A8BF1D90055BEB8 /* BUYApplePayAdditions.h */,
......@@ -939,6 +978,9 @@
children = (
F7FDA17019C93F6F00AF4E93 /* BUYClient.h */,
F7FDA17119C93F6F00AF4E93 /* BUYClient.m */,
9A3B2DD91CD282DA00BFF49C /* BUYClient_Internal.h */,
9A3B2DCD1CD2822F00BFF49C /* BUYClient+Customers.h */,
9A3B2DCE1CD2822F00BFF49C /* BUYClient+Customers.m */,
);
path = Data;
sourceTree = "<group>";
......@@ -956,6 +998,7 @@
901931271BC5B9BC00D1134E /* BUYAddress.h in Headers */,
901931281BC5B9BC00D1134E /* BUYApplePayHelpers.h in Headers */,
901931291BC5B9BC00D1134E /* BUYStoreViewController.h in Headers */,
9A3B2DDB1CD282DA00BFF49C /* BUYClient_Internal.h in Headers */,
9019312A1BC5B9BC00D1134E /* BUYCreditCard.h in Headers */,
9019312B1BC5B9BC00D1134E /* BUYOption.h in Headers */,
9019312C1BC5B9BC00D1134E /* BUYProductVariantCell.h in Headers */,
......@@ -972,8 +1015,10 @@
901931391BC5B9BC00D1134E /* BUYOptionValueCell.h in Headers */,
9019313A1BC5B9BC00D1134E /* BUYImage.h in Headers */,
9019313B1BC5B9BC00D1134E /* BUYOptionValue.h in Headers */,
9A9C03441CD9369600AE79BD /* BUYCheckout_Private.h in Headers */,
9019313C1BC5B9BC00D1134E /* BUYShop.h in Headers */,
9019313D1BC5B9BC00D1134E /* BUYShippingRate.h in Headers */,
9A3B2DE11CD28E9900BFF49C /* BUYShopifyErrorCodes.h in Headers */,
9019313E1BC5B9BC00D1134E /* BUYApplePayAdditions.h in Headers */,
901931401BC5B9BC00D1134E /* BUYTheme+Additions.h in Headers */,
901931411BC5B9BC00D1134E /* BUYVariantOptionView.h in Headers */,
......@@ -995,6 +1040,7 @@
841ADE181CB6C942000004B0 /* NSRegularExpression+BUYAdditions.h in Headers */,
841ADE0C1CB6C942000004B0 /* NSDecimalNumber+BUYAdditions.h in Headers */,
901931491BC5B9BC00D1134E /* BUYGiftCard.h in Headers */,
9A3B2DD61CD2829900BFF49C /* BUYAccountCredentials.h in Headers */,
9019314B1BC5B9BC00D1134E /* BUYNavigationController.h in Headers */,
9019314D1BC5B9BC00D1134E /* BUYVariantOptionBreadCrumbsView.h in Headers */,
9019314E1BC5B9BC00D1134E /* BUYProductViewFooter.h in Headers */,
......@@ -1016,7 +1062,9 @@
901931611BC5B9BC00D1134E /* BUYClient.h in Headers */,
901931631BC5B9BC00D1134E /* BUYGradientView.h in Headers */,
901931641BC5B9BC00D1134E /* BUYCartLineItem.h in Headers */,
9A3B2DCA1CD27D5B00BFF49C /* BUYCustomer.h in Headers */,
901931661BC5B9BC00D1134E /* BUYCheckout.h in Headers */,
9A3B2DD01CD2822F00BFF49C /* BUYClient+Customers.h in Headers */,
901931671BC5B9BC00D1134E /* BUYCart.h in Headers */,
901931681BC5B9BC00D1134E /* BUYProductViewController.h in Headers */,
901931691BC5B9BC00D1134E /* BUYProduct.h in Headers */,
......@@ -1035,6 +1083,7 @@
BE9A64531B503CBE0033E558 /* BUYAddress.h in Headers */,
BE9A64741B503D2E0033E558 /* BUYApplePayHelpers.h in Headers */,
BE9A647E1B503D930033E558 /* BUYStoreViewController.h in Headers */,
9A3B2DDA1CD282DA00BFF49C /* BUYClient_Internal.h in Headers */,
BE9A64551B503CC50033E558 /* BUYCreditCard.h in Headers */,
BE9A645F1B503CE90033E558 /* BUYOption.h in Headers */,
BEB74A6F1B5564260005A300 /* BUYProductVariantCell.h in Headers */,
......@@ -1053,6 +1102,8 @@
BE9A64661B503D010033E558 /* BUYShop.h in Headers */,
BE9A644D1B503CA20033E558 /* BUYShippingRate.h in Headers */,
BE9A646C1B503D180033E558 /* BUYApplePayAdditions.h in Headers */,
9A3B2DE01CD28E9900BFF49C /* BUYShopifyErrorCodes.h in Headers */,
BE9A646A1B503D100033E558 /* BUYProduct+Options.h in Headers */,
906EAE431B836DE000976165 /* BUYTheme+Additions.h in Headers */,
BEB74A7B1B5564810005A300 /* BUYVariantOptionView.h in Headers */,
BE5DC3631B71022D00B2BC1E /* BUYMaskedCreditCard.h in Headers */,
......@@ -1074,6 +1125,7 @@
841ADE171CB6C942000004B0 /* NSRegularExpression+BUYAdditions.h in Headers */,
841ADE0B1CB6C942000004B0 /* NSDecimalNumber+BUYAdditions.h in Headers */,
BE9A64571B503CCC0033E558 /* BUYGiftCard.h in Headers */,
9A3B2DD51CD2829900BFF49C /* BUYAccountCredentials.h in Headers */,
BEB74A671B55640C0005A300 /* BUYNavigationController.h in Headers */,
90DE92701B9897B6002EF4DA /* BUYVariantOptionBreadCrumbsView.h in Headers */,
BEB74A711B5564300005A300 /* BUYProductViewFooter.h in Headers */,
......@@ -1084,6 +1136,7 @@
BEB74A221B554BF20005A300 /* BUYPresentationControllerForVariantSelection.h in Headers */,
BE9A645D1B503CE30033E558 /* BUYObject.h in Headers */,
BE9A646E1B503D1E0033E558 /* BUYRuntime.h in Headers */,
9A9C03431CD9369400AE79BD /* BUYCheckout_Private.h in Headers */,
BEB74A901B55A3D00005A300 /* BUYCollection.h in Headers */,
904606AF1B6BC8D700754173 /* BUYProductImageCollectionViewCell.h in Headers */,
900E7C841B5DA553006F3C81 /* BUYImageKit.h in Headers */,
......@@ -1095,7 +1148,9 @@
BE9A64471B503C8B0033E558 /* BUYClient.h in Headers */,
BEB74A651B5563FF0005A300 /* BUYGradientView.h in Headers */,
9003969B1B601DF400226B73 /* BUYCartLineItem.h in Headers */,
9A3B2DC91CD27D5B00BFF49C /* BUYCustomer.h in Headers */,
BE9A644B1B503C9B0033E558 /* BUYCheckout.h in Headers */,
9A3B2DCF1CD2822F00BFF49C /* BUYClient+Customers.h in Headers */,
BE9A64491B503C940033E558 /* BUYCart.h in Headers */,
BEB74A2D1B554E870005A300 /* BUYProductViewController.h in Headers */,
BE9A64611B503CEF0033E558 /* BUYProduct.h in Headers */,
......@@ -1296,9 +1351,11 @@
901930FD1BC5B9BC00D1134E /* BUYTaxLine.m in Sources */,
901930FE1BC5B9BC00D1134E /* BUYCollection+Additions.m in Sources */,
901930FF1BC5B9BC00D1134E /* BUYVariantOptionBreadCrumbsView.m in Sources */,
9A3B2DCC1CD27D5B00BFF49C /* BUYCustomer.m in Sources */,
901931011BC5B9BC00D1134E /* BUYTheme+Additions.m in Sources */,
901931021BC5B9BC00D1134E /* BUYStoreViewController.m in Sources */,
901931031BC5B9BC00D1134E /* BUYOptionValue.m in Sources */,
9A3B2DDE1CD28D7300BFF49C /* BUYSerializable.m in Sources */,
901931041BC5B9BC00D1134E /* BUYApplePayAdditions.m in Sources */,
901931051BC5B9BC00D1134E /* BUYOptionSelectionNavigationController.m in Sources */,
901931061BC5B9BC00D1134E /* BUYDiscount.m in Sources */,
......@@ -1326,12 +1383,14 @@
901931161BC5B9BC00D1134E /* BUYShippingRate.m in Sources */,
841ADE061CB6C942000004B0 /* NSDate+BUYAdditions.m in Sources */,
901931181BC5B9BC00D1134E /* BUYGradientView.m in Sources */,
9A3B2DD21CD2822F00BFF49C /* BUYClient+Customers.m in Sources */,
901931191BC5B9BC00D1134E /* BUYViewController.m in Sources */,
9019311A1BC5B9BC00D1134E /* BUYImageKit.m in Sources */,
9019311B1BC5B9BC00D1134E /* BUYAddress.m in Sources */,
9019311C1BC5B9BC00D1134E /* BUYOption.m in Sources */,
9019311D1BC5B9BC00D1134E /* BUYClient.m in Sources */,
9019311E1BC5B9BC00D1134E /* UIFont+BUYAdditions.m in Sources */,
9A3B2DD81CD2829900BFF49C /* BUYAccountCredentials.m in Sources */,
9019311F1BC5B9BC00D1134E /* BUYProductView.m in Sources */,
901931201BC5B9BC00D1134E /* BUYCreditCard.m in Sources */,
901931211BC5B9BC00D1134E /* BUYProductImageCollectionViewCell.m in Sources */,
......@@ -1401,9 +1460,11 @@
BE9A64521B503CB80033E558 /* BUYTaxLine.m in Sources */,
900396F71B69563400226B73 /* BUYCollection+Additions.m in Sources */,
90DE92711B9897B6002EF4DA /* BUYVariantOptionBreadCrumbsView.m in Sources */,
9A3B2DCB1CD27D5B00BFF49C /* BUYCustomer.m in Sources */,
906EAE441B836DE000976165 /* BUYTheme+Additions.m in Sources */,
BE9A647F1B503D960033E558 /* BUYStoreViewController.m in Sources */,
BE9A64691B503D0C0033E558 /* BUYOptionValue.m in Sources */,
9A3B2DDD1CD28D7300BFF49C /* BUYSerializable.m in Sources */,
BE9A646D1B503D1C0033E558 /* BUYApplePayAdditions.m in Sources */,
BEB74A2A1B554BFB0005A300 /* BUYOptionSelectionNavigationController.m in Sources */,
BE9A64501B503CAD0033E558 /* BUYDiscount.m in Sources */,
......@@ -1431,12 +1492,14 @@
BE9A644E1B503CA60033E558 /* BUYShippingRate.m in Sources */,
841ADE051CB6C942000004B0 /* NSDate+BUYAdditions.m in Sources */,
BEB74A661B5564030005A300 /* BUYGradientView.m in Sources */,
9A3B2DD11CD2822F00BFF49C /* BUYClient+Customers.m in Sources */,
BE9A64811B503D9E0033E558 /* BUYViewController.m in Sources */,
900E7C851B5DA559006F3C81 /* BUYImageKit.m in Sources */,
BE9A64541B503CC30033E558 /* BUYAddress.m in Sources */,
BE9A64601B503CEC0033E558 /* BUYOption.m in Sources */,
BE9A64481B503C900033E558 /* BUYClient.m in Sources */,
9099444A1B71B76800C40A33 /* UIFont+BUYAdditions.m in Sources */,
9A3B2DD71CD2829900BFF49C /* BUYAccountCredentials.m in Sources */,
900396AD1B627CB900226B73 /* BUYProductView.m in Sources */,
BE9A64561B503CC90033E558 /* BUYCreditCard.m in Sources */,
904606B01B6BC8D700754173 /* BUYProductImageCollectionViewCell.m in Sources */,
......
......@@ -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
//
// BUYClient+Customers.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 "BUYClient+Customers.h"
#import "BUYClient_Internal.h"
#import "NSDateFormatter+BUYAdditions.h"
#import "BUYCustomer.h"
#import "BUYAccountCredentials.h"
#import "BUYOrder.h"
#import "BUYShopifyErrorCodes.h"
@interface BUYAuthenticatedResponse : NSObject
+ (BUYAuthenticatedResponse *)responseFromJSON:(NSDictionary *)json;
@property (nonatomic, copy) NSString *accessToken;
@property (nonatomic, copy) NSDate *expiry;
@property (nonatomic, copy) NSString *customerID;
@end
@implementation BUYAuthenticatedResponse
+ (BUYAuthenticatedResponse *)responseFromJSON:(NSDictionary *)json
{
BUYAuthenticatedResponse *response = [BUYAuthenticatedResponse new];
NSDictionary *access = json[@"customer_access_token"];
response.accessToken = access[@"access_token"];
NSDateFormatter *formatter = [NSDateFormatter dateFormatterForPublications];
response.expiry = [formatter dateFromString:access[@"expires_at"]];
response.customerID = [NSString stringWithFormat:@"%@", access[@"customer_id"]];
return response;
}
@end
@implementation BUYClient (Customers)
#pragma mark - Customer
- (NSURLSessionDataTask *)getCustomerWithID:(NSString *)customerID callback:(BUYDataCustomerBlock)block
{
NSURLComponents *components = [self URLComponentsForCustomerWithID:customerID];
return [self getRequestForURL:components.URL completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
block((json && !error ? [[BUYCustomer alloc] initWithDictionary:json[@"customer"]] : nil), error);
}];
}
- (NSURLSessionDataTask *)createCustomerWithCredentials:(BUYAccountCredentials *)credentials callback:(BUYDataCustomerTokenBlock)block
{
NSURLComponents *components = [self URLComponentsForCustomers];
return [self postRequestForURL:components.URL object:credentials.JSONRepresentation completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
if (json && !error) {
[self createTokenForCustomerWithCredentials:credentials customerJSON:json callback:block];
}
else {
block(nil, nil, error);
}
}];
}
- (NSURLSessionDataTask *)createTokenForCustomerWithCredentials:(BUYAccountCredentials *)credentials customerJSON:(NSDictionary *)customerJSON callback:(BUYDataCustomerTokenBlock)block
{
NSURLComponents *components = [self URLComponentsForCustomerLogin];
return [self postRequestForURL:components.URL object:credentials.JSONRepresentation completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
if (json && !error) {
BUYAuthenticatedResponse *authenticatedResponse = [BUYAuthenticatedResponse responseFromJSON:json];
self.customerToken = authenticatedResponse.accessToken;
if (!customerJSON) {
[self getCustomerWithID:authenticatedResponse.customerID callback:^(BUYCustomer *customer, NSError *error) {
block(customer, self.customerToken, error);
}];
}
else {
block([[BUYCustomer alloc] initWithDictionary:json[@"customer"]], self.customerToken, error);
}
}
else {
block(nil, nil, error);
}
}];
}
- (NSURLSessionDataTask *)loginCustomerWithCredentials:(BUYAccountCredentials *)credentials callback:(BUYDataCustomerTokenBlock)block
{
return [self createTokenForCustomerWithCredentials:credentials customerJSON:nil callback:block];
}
- (NSURLSessionDataTask *)recoverPasswordForCustomer:(NSString *)email callback:(BUYDataCheckoutStatusBlock)block
{
NSURLComponents *components = [self URLComponentsForPasswordReset];
return [self postRequestForURL:components.URL object:@{@"email": email} completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
if (!error) {
error = [self extractErrorFromResponse:response json:json];
}
block(statusCode, error);
}];
}
- (NSURLSessionDataTask *)renewCustomerTokenWithID:(NSString *)customerID callback:(BUYDataTokenBlock)block
{
if (self.customerToken) {
NSURLComponents *components = [self URLComponentsForTokenRenewalWithID:customerID];
return [self putRequestForURL:components.URL body:nil completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
NSString *accessToken = nil;
if (json && !error) {
BUYAuthenticatedResponse *authenticatedResponse = [BUYAuthenticatedResponse responseFromJSON:json];
accessToken = authenticatedResponse.accessToken;
}
if (!error) {
error = [self extractErrorFromResponse:response json:json];
}
block(accessToken, error);
}];
}
else {
block(nil, [NSError errorWithDomain:kShopifyError code:BUYShopifyError_InvalidCustomerToken userInfo:nil]);
return nil;
}
}
- (NSURLSessionDataTask *)activateCustomerWithCredentials:(BUYAccountCredentials *)credentials customerID:(NSString *)customerID customerToken:(NSString *)customerToken callback:(BUYDataCustomerTokenBlock)block
{
NSURLComponents *components = [self URLComponentsForCustomerActivationWithID:customerID customerToken:customerToken];
NSData *data = [NSJSONSerialization dataWithJSONObject:credentials.JSONRepresentation options:0 error:nil];
return [self putRequestForURL:components.URL body:data completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
if (json && !error) {
BUYAccountCredentialItem *emailItem = [BUYAccountCredentialItem itemWithKey:@"email" value:json[@"customer"][@"email"]];
credentials[@"email"] = emailItem;
[self loginCustomerWithCredentials:credentials callback:block];
}
else {
block(nil, nil, error);
}
}];
}
- (NSURLSessionDataTask *)resetPasswordWithCredentials:(BUYAccountCredentials *)credentials customerID:(NSString *)customerID customerToken:(NSString *)customerToken callback:(BUYDataCustomerTokenBlock)block
{
NSURLComponents *components = [self URLComponentsForCustomerPasswordResetWithCustomerID:customerID customerToken:customerToken];
NSData *data = [NSJSONSerialization dataWithJSONObject:credentials.JSONRepresentation options:0 error:nil];
return [self putRequestForURL:components.URL body:data completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
if (json && !error) {
BUYAccountCredentialItem *emailItem = [BUYAccountCredentialItem itemWithKey:@"email" value:json[@"customer"][@"email"]];
credentials[@"email"] = emailItem;
[self loginCustomerWithCredentials:credentials callback:block];
}
else {
block(nil, nil, error);
}
}];
}
- (NSURLSessionDataTask *)getOrdersForCustomerWithCallback:(BUYDataOrdersBlock)block
{
NSURLComponents *components = [self URLComponentsForCustomerOrders];
return [self getRequestForURL:components.URL completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
NSArray *ordersJSON = json[@"orders"];
if (ordersJSON && !error) {
NSMutableArray *container = [NSMutableArray new];
for (NSDictionary *orderJSON in ordersJSON) {
[container addObject:[[BUYOrder alloc] initWithDictionary:orderJSON]];
}
block([container copy], error);
} else {
block(nil, error);
}
}];
}
#pragma mark - URL Formatting
- (NSURLComponents *)URLComponentsForCustomers
{
return [self customerURLComponentsAppendingPath:nil];
}
- (NSURLComponents *)URLComponentsForCustomerWithID:(NSString *)customerID
{
return [self customerURLComponentsAppendingPath:customerID];
}
- (NSURLComponents *)URLComponentsForCustomerLogin
{
return [self customerURLComponentsAppendingPath:@"customer_token"];
}
- (NSURLComponents *)URLComponentsForCustomerActivationWithID:(NSString *)customerID customerToken:(NSString *)customerToken
{
NSDictionary *queryItems = @{ @"token": customerToken };
NSString *path = [NSString stringWithFormat:@"%@/activate", customerID];
return [self customerURLComponentsAppendingPath:path queryItems:queryItems];
}
- (NSURLComponents *)URLComponentsForCustomerPasswordResetWithCustomerID:(NSString *)customerID customerToken:(NSString *)customerToken
{
NSDictionary *queryItems = @{ @"token": customerToken };
NSString *path = [NSString stringWithFormat:@"%@/reset", customerID];
return [self customerURLComponentsAppendingPath:path queryItems:queryItems];
}
- (NSURLComponents *)URLComponentsForPasswordReset
{
return [self customerURLComponentsAppendingPath:@"recover" queryItems:nil];
}
- (NSURLComponents *)URLComponentsForTokenRenewalWithID:(NSString *)customerID
{
NSString *path = [NSString stringWithFormat:@"%@/customer_token/renew", customerID];
return [self customerURLComponentsAppendingPath:path queryItems:nil];
}
- (NSURLComponents *)URLComponentsForCustomerOrders
{
return [self customerURLComponentsAppendingPath:@"orders" queryItems:nil];
}
#pragma mark - Convenience methods
- (NSURLComponents *)customerURLComponentsAppendingPath:(NSString *)path
{
return [self customerURLComponentsAppendingPath:path queryItems:nil];
}
- (NSURLComponents *)customerURLComponentsAppendingPath:(NSString *)path queryItems:(NSDictionary *)queryItems
{
return [self URLComponentsForAPIPath:@"customers" appendingPath:path queryItems:queryItems];
}
- (NSString *)accessTokenFromHeaders:(NSDictionary *)headers
{
return [headers valueForKey:BUYClientCustomerAccessToken];
}
@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
......
......@@ -37,6 +37,7 @@
#import "BUYProduct.h"
#import "BUYShippingRate.h"
#import "BUYShop.h"
#import "BUYShopifyErrorCodes.h"
#import "NSDecimalNumber+BUYAdditions.h"
#import "NSURLComponents+BUYAdditions.h"
......@@ -47,6 +48,7 @@
#define kGET @"GET"
#define kPOST @"POST"
#define kPATCH @"PATCH"
#define kPUT @"PUT"
#define kDELETE @"DELETE"
#define kJSONType @"application/json"
......@@ -59,6 +61,8 @@ NSString * const BUYVersionString = @"1.2.6";
static NSString *const kBUYClientPathProductPublications = @"product_listings";
static NSString *const kBUYClientPathCollectionPublications = @"collection_listings";
NSString *const BUYClientCustomerAccessToken = @"X-Shopify-Customer-Access-Token";
@interface BUYClient () <NSURLSessionDelegate>
@property (nonatomic, strong) NSString *shopDomain;
......@@ -123,7 +127,7 @@ static NSString *const kBUYClientPathCollectionPublications = @"collection_listi
return [self getRequestForURL:shopComponents.URL completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
BUYShop *shop = nil;
if (json && error == nil) {
if (json && !error) {
shop = [[BUYShop alloc] initWithDictionary:json];
}
block(shop, error);
......@@ -139,7 +143,7 @@ static NSString *const kBUYClientPathCollectionPublications = @"collection_listi
return [self getRequestForURL:components.URL completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
NSArray *products = nil;
if (json && error == nil) {
if (json && !error) {
products = [BUYProduct convertJSONArray:json[kBUYClientPathProductPublications]];
}
block(products, page, [self hasReachedEndOfPage:products] || error, error);
......@@ -149,10 +153,10 @@ static NSString *const kBUYClientPathCollectionPublications = @"collection_listi
- (NSURLSessionDataTask *)getProductById:(NSString *)productId completion:(BUYDataProductBlock)block;
{
return [self getProductsByIds:@[productId] completion:^(NSArray *products, NSError *error) {
if ([products count]) {
if (products.count > 0) {
block(products[0], error);
} else {
if (error == nil && [products count] == 0) {
if (!error) {
error = [NSError errorWithDomain:kShopifyError code:BUYShopifyError_InvalidProductID userInfo:@{ NSLocalizedDescriptionKey : @"Product ID is not valid. Confirm the product ID on your shop's admin and also ensure that the visibility is on for the Mobile App channel." }];
}
block(nil, error);
......@@ -168,10 +172,10 @@ static NSString *const kBUYClientPathCollectionPublications = @"collection_listi
return [self getRequestForURL:components.URL completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
NSArray *products = nil;
if (json && error == nil) {
if (json && !error) {
products = [BUYProduct convertJSONArray:json[kBUYClientPathProductPublications]];
}
if (error == nil && [products count] == 0) {
if (!error && products.count == 0) {
error = [NSError errorWithDomain:kShopifyError code:BUYShopifyError_InvalidProductID userInfo:@{ NSLocalizedDescriptionKey : @"Product IDs are not valid. Confirm the product IDs on your shop's admin and also ensure that the visibility is on for the Mobile App channel." }];
}
block(products, error);
......@@ -193,7 +197,7 @@ static NSString *const kBUYClientPathCollectionPublications = @"collection_listi
return [self getRequestForURL:components.URL completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
NSArray *collections = nil;
if (json && error == nil) {
if (json && !error) {
collections = [BUYCollection convertJSONArray:json[kBUYClientPathCollectionPublications]];
}
block(collections, page, [self hasReachedEndOfPage:collections], error);
......@@ -218,7 +222,7 @@ static NSString *const kBUYClientPathCollectionPublications = @"collection_listi
task = [self getRequestForURL:components.URL completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
NSArray *products = nil;
if (json && error == nil) {
if (json && !error) {
products = [BUYProduct convertJSONArray:json[kBUYClientPathProductPublications]];
}
block(products, page, [self hasReachedEndOfPage:products] || error, error);
......@@ -290,7 +294,7 @@ static NSString *const kBUYClientPathCollectionPublications = @"collection_listi
- (void)handleCheckoutResponse:(NSDictionary *)json error:(NSError *)error block:(BUYDataCheckoutBlock)block
{
BUYCheckout *checkout = nil;
if (error == nil) {
if (!error) {
checkout = [[BUYCheckout alloc] initWithDictionary:json[@"checkout"]];
}
block(checkout, error);
......@@ -330,7 +334,7 @@ static NSString *const kBUYClientPathCollectionPublications = @"collection_listi
NSError *error = nil;
NSData *data = [NSJSONSerialization dataWithJSONObject:checkoutJSON options:0 error:&error];
if (data && error == nil) {
if (data && !error) {
NSURLComponents *components = [self URLComponentsForCheckoutsAppendingPath:nil checkoutToken:nil queryItems:nil];
task = [self postRequestForURL:components.URL body:data completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
......@@ -356,7 +360,7 @@ static NSString *const kBUYClientPathCollectionPublications = @"collection_listi
task = [self postRequestForURL:components.URL
object:giftCard
completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
if (error == nil) {
if (!error) {
[self updateCheckout:checkout withGiftCardDictionary:json[@"gift_card"] addingGiftCard:YES];
}
block(checkout, error);
......@@ -374,7 +378,7 @@ static NSString *const kBUYClientPathCollectionPublications = @"collection_listi
checkoutToken:checkout.token
queryItems:nil];
task = [self deleteRequestForURL:components.URL completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
if (error == nil) {
if (!error) {
[self updateCheckout:checkout withGiftCardDictionary:json[@"gift_card"] addingGiftCard:NO];
}
block(checkout, error);
......@@ -446,7 +450,7 @@ static NSString *const kBUYClientPathCollectionPublications = @"collection_listi
data = [NSJSONSerialization dataWithJSONObject:paymentJson options:0 error:&error];
}
if ((data && error == nil) || (checkout.paymentDue && checkout.paymentDue.floatValue == 0)) {
if ((data && !error) || (checkout.paymentDue && checkout.paymentDue.floatValue == 0)) {
task = [self checkoutCompletionRequestWithCheckout:checkout body:data completion:block];
}
}
......@@ -466,7 +470,7 @@ static NSString *const kBUYClientPathCollectionPublications = @"collection_listi
if ([checkout hasToken] == NO) {
block(nil, [NSError errorWithDomain:kShopifyError code:BUYShopifyError_InvalidCheckoutObject userInfo:nil]);
}
else if (token == nil) {
else if (!token) {
block(nil, [NSError errorWithDomain:kShopifyError code:BUYShopifyError_NoApplePayTokenSpecified userInfo:nil]);
}
else {
......@@ -474,7 +478,7 @@ static NSString *const kBUYClientPathCollectionPublications = @"collection_listi
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 == nil) {
if (data && !error) {
task = [self checkoutCompletionRequestWithCheckout:checkout body:data completion:block];
}
else {
......@@ -551,7 +555,7 @@ static NSString *const kBUYClientPathCollectionPublications = @"collection_listi
NSURLComponents *components = [self URLComponentsForCheckoutsAppendingPath:@"shipping_rates" checkoutToken:checkout.token queryItems:@{ @"checkout" : @"" }];
task = [self getRequestForURL:components.URL completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
NSArray *shippingRates = nil;
if (error == nil && json) {
if (json && !error) {
shippingRates = [BUYShippingRate convertJSONArray:json[@"shipping_rates"]];
}
......@@ -574,7 +578,7 @@ static NSString *const kBUYClientPathCollectionPublications = @"collection_listi
if ([checkout hasToken] == NO) {
block(nil, nil, [NSError errorWithDomain:kShopifyError code:BUYShopifyError_InvalidCheckoutObject userInfo:nil]);
}
else if (creditCard == nil) {
else if (!creditCard) {
block(nil, nil, [NSError errorWithDomain:kShopifyError code:BUYShopifyError_NoCreditCardSpecified userInfo:nil]);
}
else {
......@@ -587,7 +591,7 @@ static NSString *const kBUYClientPathCollectionPublications = @"collection_listi
NSError *error = nil;
NSData *data = [NSJSONSerialization dataWithJSONObject:@{ @"checkout" : json } options:0 error:&error];
if (data && error == nil) {
if (data && !error) {
task = [self postPaymentRequestWithCheckout:checkout body:data completion:block];
}
else {
......@@ -632,9 +636,9 @@ static NSString *const kBUYClientPathCollectionPublications = @"collection_listi
return status;
}
- (BUYError *)errorFromJSON:(NSDictionary *)errorDictionary statusCode:(NSInteger)statusCode
- (NSError *)errorFromJSON:(NSDictionary *)errorDictionary statusCode:(NSInteger)statusCode
{
return [[BUYError alloc] initWithDomain:kShopifyError code:statusCode userInfo:errorDictionary];
return [[NSError alloc] initWithDomain:kShopifyError code:statusCode userInfo:errorDictionary];
}
- (NSURLSessionDataTask *)requestForURL:(NSURL *)url method:(NSString *)method object:(id <BUYSerializable>)object completionHandler:(void (^)(NSDictionary *json, NSURLResponse *response, NSError *error))completionHandler
......@@ -643,7 +647,7 @@ static NSString *const kBUYClientPathCollectionPublications = @"collection_listi
NSError *error = nil;
NSData *data = [NSJSONSerialization dataWithJSONObject:json options:0 error:&error];
NSURLSessionDataTask *task = nil;
if (error == nil && data) {
if (data && !error) {
task = [self requestForURL:url method:method body:data completionHandler:completionHandler];
}
return task;
......@@ -663,6 +667,10 @@ static NSString *const kBUYClientPathCollectionPublications = @"collection_listi
[request addValue:kJSONType forHTTPHeaderField:@"Content-Type"];
[request addValue:kJSONType forHTTPHeaderField:@"Accept"];
if (self.customerToken) {
[request addValue:self.customerToken forHTTPHeaderField:BUYClientCustomerAccessToken];
}
request.HTTPMethod = method;
NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
......@@ -675,7 +683,7 @@ static NSString *const kBUYClientPathCollectionPublications = @"collection_listi
}
else {
//2 is the minimum amount of data {} for a JSON Object. Just ignore anything less.
if ((error == nil || failedValidation) && [data length] > 2) {
if ((!error || failedValidation) && [data length] > 2) {
id jsonData = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
json = [jsonData isKindOfClass:[NSDictionary class]] ? jsonData : nil;
}
......@@ -696,7 +704,7 @@ static NSString *const kBUYClientPathCollectionPublications = @"collection_listi
{
return [self requestForURL:checkout.paymentURL method:kPOST body:body completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
NSString *paymentSessionId = nil;
if (error == nil) {
if (!error) {
paymentSessionId = json[@"id"];
checkout.paymentSessionId = paymentSessionId;
}
......@@ -714,6 +722,11 @@ static NSString *const kBUYClientPathCollectionPublications = @"collection_listi
return [self requestForURL:url method:kPOST object:object completionHandler:completionHandler];
}
- (NSURLSessionDataTask *)putRequestForURL:(NSURL *)url body:(NSData *)body completionHandler:(void (^)(NSDictionary *json, NSURLResponse *response, NSError *error))completionHandler
{
return [self requestForURL:url method:kPUT body:body completionHandler:completionHandler];
}
- (NSURLSessionDataTask *)postRequestForURL:(NSURL *)url body:(NSData *)body completionHandler:(void (^)(NSDictionary *json, NSURLResponse *response, NSError *error))completionHandler
{
return [self requestForURL:url method:kPOST body:body completionHandler:completionHandler];
......
//
// 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
\ No newline at end of file
......@@ -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
......
......@@ -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