Commit 01b76023 by Dima Bart

Merge pull request #140 from Shopify/feature/138-improve-credentials-api

Improve BUYAccountCredentials API
parents 93460a07 229e559e
//
// BUYAccountCredentialsTests.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 <XCTest/XCTest.h>
#import <Buy/Buy.h>
@interface BUYAccountCredentialsTests : XCTestCase
@end
@implementation BUYAccountCredentialsTests
#pragma mark - Init -
- (void)testInitWithoutItems {
BUYAccountCredentials *credentials = [BUYAccountCredentials credentialsWithItems:@[]];
XCTAssertNotNil(credentials);
XCTAssertEqual(credentials.count, 0);
}
- (void)testInitWithItems {
BUYAccountCredentials *credentials = [BUYAccountCredentials credentialsWithItems:[self sampleWithValidItems]];
XCTAssertNotNil(credentials);
XCTAssertEqual(credentials.count, 2);
}
#pragma mark - Validation -
- (void)testValidationWithValidItems {
BUYAccountCredentials *credentials = [BUYAccountCredentials credentialsWithItems:[self sampleWithValidItems]];
XCTAssertEqual(credentials.count, 2);
XCTAssertTrue(credentials.isValid);
}
- (void)testValidationWithInvalidItems {
BUYAccountCredentials *credentials = [BUYAccountCredentials credentialsWithItems:[self sampleWithInvalidItems]];
XCTAssertEqual(credentials.count, 3);
XCTAssertFalse(credentials.isValid);
}
#pragma mark - Mutation -
- (void)testExtendingCredentials {
BUYAccountCredentials *credentials = [BUYAccountCredentials credentialsWithItems:[self sampleWithValidItems]];
XCTAssertEqual(credentials.count, 2);
credentials = [credentials credentialsByAddingItems:@[
[BUYAccountCredentialItem itemWithFirstName:@"John"],
[BUYAccountCredentialItem itemWithLastName:@"Doe"],
]];
XCTAssertEqual(credentials.count, 4);
}
#pragma mark - Serialization -
- (void)testJSONSerialization {
BUYAccountCredentials *credentials = [BUYAccountCredentials credentialsWithItems:@[
[BUYAccountCredentialItem itemWithEmail:@"john@doe.com"],
[BUYAccountCredentialItem itemWithFirstName:@"John"],
[BUYAccountCredentialItem itemWithLastName:@"Doe"],
[BUYAccountCredentialItem itemWithPassword:@"pass"],
[BUYAccountCredentialItem itemWithPasswordConfirmation:@"pass"],
]];
NSDictionary *json = [credentials JSONRepresentation];
NSDictionary *customer = json[@"customer"];
XCTAssertNotNil(json);
XCTAssertEqual(json.count, 1);
XCTAssertNotNil(customer);
XCTAssertEqual(customer[@"email"], @"john@doe.com");
XCTAssertEqual(customer[@"first_name"], @"John");
XCTAssertEqual(customer[@"last_name"], @"Doe");
XCTAssertEqual(customer[@"password"], @"pass");
XCTAssertEqual(customer[@"password_confirmation"], @"pass");
}
#pragma mark - Utilities -
- (BUYAccountCredentialItem *)emailItem
{
return [BUYAccountCredentialItem itemWithEmail:@"john@smith.com"];
}
- (BUYAccountCredentialItem *)passwordItem
{
return [BUYAccountCredentialItem itemWithPassword:@"password"];
}
- (BUYAccountCredentialItem *)passwordConfirmationItem
{
return [BUYAccountCredentialItem itemWithPasswordConfirmation:@"password"];
}
- (NSArray *)sampleWithValidItems {
NSMutableArray *items = [NSMutableArray new];
[items addObject:[self emailItem]];
[items addObject:[self passwordItem]];
return items;
}
- (NSArray *)sampleWithInvalidItems {
NSMutableArray *items = [NSMutableArray new];
[items addObject:[self emailItem]];
[items addObject:[BUYAccountCredentialItem itemWithPassword:@""]];
[items addObject:[BUYAccountCredentialItem itemWithPasswordConfirmation:@""]];
return items;
}
@end
...@@ -327,14 +327,18 @@ NSString * const BUYFakeCustomerToken = @"dsfasdgafdg"; ...@@ -327,14 +327,18 @@ NSString * const BUYFakeCustomerToken = @"dsfasdgafdg";
- (void)testCustomerCreationURL - (void)testCustomerCreationURL
{ {
BUYAccountCredentialItem *firstName = [BUYAccountCredentialItem itemWithKey:@"first_name" value:@"michael"]; NSArray *items = @[
BUYAccountCredentialItem *lastName = [BUYAccountCredentialItem itemWithKey:@"last_name" value:@"scott"]; [BUYAccountCredentialItem itemWithFirstName:@"michael"],
BUYAccountCredentialItem *email = [BUYAccountCredentialItem itemWithKey:@"email" value:@"fake@example.com"]; [BUYAccountCredentialItem itemWithLastName:@"scott"],
BUYAccountCredentialItem *password = [BUYAccountCredentialItem itemWithKey:@"password" value:@"password"]; [BUYAccountCredentialItem itemWithEmail:@"fake@example.com"],
BUYAccountCredentialItem *passwordConfirmation = [BUYAccountCredentialItem itemWithKey:@"password_confirmation" value:@"password"]; [BUYAccountCredentialItem itemWithPassword:@"password"],
BUYAccountCredentials *credentials = [BUYAccountCredentials credentialsWithItems:@[firstName, lastName, email, password, passwordConfirmation]]; [BUYAccountCredentialItem itemWithPasswordConfirmation:@"password"],
];
BUYAccountCredentials *credentials = [BUYAccountCredentials credentialsWithItems:items];
NSURLSessionDataTask *task = [self.client createCustomerWithCredentials:credentials callback:nil]; NSURLSessionDataTask *task = [self.client createCustomerWithCredentials:credentials callback:^(BUYCustomer *customer, NSString *token, NSError *error) {
}];
XCTAssertEqualObjects(task.originalRequest.URL.scheme, @"https"); XCTAssertEqualObjects(task.originalRequest.URL.scheme, @"https");
XCTAssertEqualObjects(task.originalRequest.URL.path, @"/api/customers.json"); XCTAssertEqualObjects(task.originalRequest.URL.path, @"/api/customers.json");
...@@ -345,20 +349,25 @@ NSString * const BUYFakeCustomerToken = @"dsfasdgafdg"; ...@@ -345,20 +349,25 @@ NSString * const BUYFakeCustomerToken = @"dsfasdgafdg";
XCTAssertNil(error); XCTAssertNil(error);
NSDictionary *dict = @{@"customer": @{ NSDictionary *dict = @{@"customer": @{
@"first_name": firstName.value, @"first_name": @"michael",
@"last_name": lastName.value, @"last_name": @"scott",
@"email": email.value, @"email": @"fake@example.com",
@"password": password.value, @"password": @"password",
@"password_confirmation": passwordConfirmation.value}}; @"password_confirmation": @"password"
}};
XCTAssertEqualObjects(payload, dict); XCTAssertEqualObjects(payload, dict);
} }
- (void)testLoginCustomerURL - (void)testLoginCustomerURL
{ {
BUYAccountCredentialItem *email = [BUYAccountCredentialItem itemWithKey:@"email" value:@"fake@example.com"]; NSArray *items = @[
BUYAccountCredentialItem *password = [BUYAccountCredentialItem itemWithKey:@"password" value:@"password"]; [BUYAccountCredentialItem itemWithEmail:@"fake@example.com"],
BUYAccountCredentials *credentials = [BUYAccountCredentials credentialsWithItems:@[email, password]]; [BUYAccountCredentialItem itemWithPassword:@"password"],
NSURLSessionDataTask *task = [self.client loginCustomerWithCredentials:credentials callback:nil]; ];
BUYAccountCredentials *credentials = [BUYAccountCredentials credentialsWithItems:items];
NSURLSessionDataTask *task = [self.client loginCustomerWithCredentials:credentials callback:^(BUYCustomer *customer, NSString *token, NSError *error) {
}];
XCTAssertEqualObjects(task.originalRequest.URL.scheme, @"https"); XCTAssertEqualObjects(task.originalRequest.URL.scheme, @"https");
XCTAssertEqualObjects(task.originalRequest.URL.path, @"/api/customers/customer_token.json"); XCTAssertEqualObjects(task.originalRequest.URL.path, @"/api/customers/customer_token.json");
...@@ -368,13 +377,18 @@ NSString * const BUYFakeCustomerToken = @"dsfasdgafdg"; ...@@ -368,13 +377,18 @@ NSString * const BUYFakeCustomerToken = @"dsfasdgafdg";
NSDictionary *payload = [NSJSONSerialization JSONObjectWithData:task.originalRequest.HTTPBody options:0 error:&error]; NSDictionary *payload = [NSJSONSerialization JSONObjectWithData:task.originalRequest.HTTPBody options:0 error:&error];
XCTAssertNil(error); XCTAssertNil(error);
NSDictionary *dict = @{@"customer": @{@"email": email.value, @"password": password.value}}; NSDictionary *dict = @{@"customer": @{
@"email": @"fake@example.com",
@"password": @"password",
}};
XCTAssertEqualObjects(payload, dict); XCTAssertEqualObjects(payload, dict);
} }
- (void)testGetCustomerURL - (void)testGetCustomerURL
{ {
NSURLSessionDataTask *task = [self.client getCustomerWithID:nil callback:nil]; NSURLSessionDataTask *task = [self.client getCustomerWithID:@"" callback:^(BUYCustomer *customer, NSError *error) {
}];
XCTAssertEqualObjects(task.originalRequest.URL.scheme, @"https"); XCTAssertEqualObjects(task.originalRequest.URL.scheme, @"https");
XCTAssertEqualObjects(task.originalRequest.URL.path, @"/api/customers.json"); XCTAssertEqualObjects(task.originalRequest.URL.path, @"/api/customers.json");
...@@ -385,7 +399,9 @@ NSString * const BUYFakeCustomerToken = @"dsfasdgafdg"; ...@@ -385,7 +399,9 @@ NSString * const BUYFakeCustomerToken = @"dsfasdgafdg";
- (void)testGetOrdersForCustomerURL - (void)testGetOrdersForCustomerURL
{ {
NSURLSessionDataTask *task = [self.client getOrdersForCustomerWithCallback:nil]; NSURLSessionDataTask *task = [self.client getOrdersForCustomerWithCallback:^(NSArray<BUYOrder *> *orders, NSError *error) {
}];
XCTAssertEqualObjects(task.originalRequest.URL.scheme, @"https"); XCTAssertEqualObjects(task.originalRequest.URL.scheme, @"https");
XCTAssertEqualObjects(task.originalRequest.URL.path, @"/api/customers/orders.json"); XCTAssertEqualObjects(task.originalRequest.URL.path, @"/api/customers/orders.json");
...@@ -397,7 +413,9 @@ NSString * const BUYFakeCustomerToken = @"dsfasdgafdg"; ...@@ -397,7 +413,9 @@ NSString * const BUYFakeCustomerToken = @"dsfasdgafdg";
- (void)testCustomerRecovery - (void)testCustomerRecovery
{ {
NSString *email = @"fake@example.com"; NSString *email = @"fake@example.com";
NSURLSessionDataTask *task = [self.client recoverPasswordForCustomer:email callback:nil]; NSURLSessionDataTask *task = [self.client recoverPasswordForCustomer:email callback:^(BUYStatus status, NSError *error) {
}];
XCTAssertEqualObjects(task.originalRequest.URL.scheme, @"https"); XCTAssertEqualObjects(task.originalRequest.URL.scheme, @"https");
XCTAssertEqualObjects(task.originalRequest.URL.path, @"/api/customers/recover.json"); XCTAssertEqualObjects(task.originalRequest.URL.path, @"/api/customers/recover.json");
...@@ -415,11 +433,13 @@ NSString * const BUYFakeCustomerToken = @"dsfasdgafdg"; ...@@ -415,11 +433,13 @@ NSString * const BUYFakeCustomerToken = @"dsfasdgafdg";
{ {
self.client.customerToken = nil; self.client.customerToken = nil;
NSURLSessionDataTask *task = [self.client renewCustomerTokenWithID:nil callback:^(NSString *token, NSError *error) {}]; NSURLSessionDataTask *task = [self.client renewCustomerTokenWithID:@"" callback:^(NSString *token, NSError *error) {}];
XCTAssertNil(task); // task should be nil if no customer token was set on the client XCTAssertNil(task); // task should be nil if no customer token was set on the client
self.client.customerToken = BUYFakeCustomerToken; self.client.customerToken = BUYFakeCustomerToken;
task = [self.client renewCustomerTokenWithID:@"1" callback:nil]; task = [self.client renewCustomerTokenWithID:@"1" callback:^(NSString *token, NSError *error) {
}];
XCTAssertEqualObjects(task.originalRequest.URL.scheme, @"https"); XCTAssertEqualObjects(task.originalRequest.URL.scheme, @"https");
XCTAssertEqualObjects(task.originalRequest.URL.path, @"/api/customers/1/customer_token/renew.json"); XCTAssertEqualObjects(task.originalRequest.URL.path, @"/api/customers/1/customer_token/renew.json");
...@@ -428,12 +448,16 @@ NSString * const BUYFakeCustomerToken = @"dsfasdgafdg"; ...@@ -428,12 +448,16 @@ NSString * const BUYFakeCustomerToken = @"dsfasdgafdg";
- (void)testCustomerActivation - (void)testCustomerActivation
{ {
BUYAccountCredentialItem *passwordItem = [BUYAccountCredentialItem itemWithKey:@"password" value:@"12345"]; NSArray *items = @[
BUYAccountCredentialItem *passwordConfItem = [BUYAccountCredentialItem itemWithKey:@"password_confirmation" value:@"12345"]; [BUYAccountCredentialItem itemWithPassword:@"12345"],
BUYAccountCredentials *credentials = [BUYAccountCredentials credentialsWithItems:@[passwordItem, passwordConfItem]]; [BUYAccountCredentialItem itemWithPasswordConfirmation:@"12345"],
];
BUYAccountCredentials *credentials = [BUYAccountCredentials credentialsWithItems:items];
NSString *customerID = @"12345"; NSString *customerID = @"12345";
NSString *customerToken = @"12345"; NSString *customerToken = @"12345";
NSURLSessionDataTask *task = [self.client activateCustomerWithCredentials:credentials customerID:customerID customerToken:customerToken callback:nil]; NSURLSessionDataTask *task = [self.client activateCustomerWithCredentials:credentials customerID:customerID customerToken:customerToken callback:^(BUYCustomer *customer, NSString *token, NSError *error) {
}];
XCTAssertEqualObjects(task.originalRequest.URL.scheme, @"https"); XCTAssertEqualObjects(task.originalRequest.URL.scheme, @"https");
XCTAssertEqualObjects(task.originalRequest.URL.path, @"/api/customers/12345/activate.json"); XCTAssertEqualObjects(task.originalRequest.URL.path, @"/api/customers/12345/activate.json");
......
...@@ -314,6 +314,7 @@ ...@@ -314,6 +314,7 @@
9A3B2DDE1CD28D7300BFF49C /* 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 */; }; 9A3B2DE01CD28E9900BFF49C /* BUYShopifyErrorCodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A3B2DDF1CD28E9900BFF49C /* BUYShopifyErrorCodes.h */; };
9A3B2DE11CD28E9900BFF49C /* BUYShopifyErrorCodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A3B2DDF1CD28E9900BFF49C /* BUYShopifyErrorCodes.h */; }; 9A3B2DE11CD28E9900BFF49C /* BUYShopifyErrorCodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A3B2DDF1CD28E9900BFF49C /* BUYShopifyErrorCodes.h */; };
9A6B03791CDA5D4F0054C26E /* BUYAccountCredentialsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A6B03781CDA5D4F0054C26E /* BUYAccountCredentialsTests.m */; };
9A9C03431CD9369400AE79BD /* BUYCheckout_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A9C03421CD9369400AE79BD /* BUYCheckout_Private.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 */; }; 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 */; }; BE1007951B6038150031CEE7 /* BUYProductVariant+Options.h in Headers */ = {isa = PBXBuildFile; fileRef = BE1007931B6038150031CEE7 /* BUYProductVariant+Options.h */; };
...@@ -610,6 +611,7 @@ ...@@ -610,6 +611,7 @@
9A3B2DDF1CD28E9900BFF49C /* BUYShopifyErrorCodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BUYShopifyErrorCodes.h; 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>"; }; 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>"; }; 9A3B2DE91CD2990E00BFF49C /* BUYError+BUYAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "BUYError+BUYAdditions.m"; sourceTree = "<group>"; };
9A6B03781CDA5D4F0054C26E /* BUYAccountCredentialsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BUYAccountCredentialsTests.m; sourceTree = "<group>"; };
9A9C03421CD9369400AE79BD /* BUYCheckout_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BUYCheckout_Private.h; 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>"; }; 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>"; }; BE1007941B6038150031CEE7 /* BUYProductVariant+Options.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "BUYProductVariant+Options.m"; sourceTree = "<group>"; };
...@@ -851,6 +853,7 @@ ...@@ -851,6 +853,7 @@
84CA59BA1CD1378100B2A956 /* BUYTestModel.xcdatamodeld */, 84CA59BA1CD1378100B2A956 /* BUYTestModel.xcdatamodeld */,
90F592F91B0D5F4C0026B382 /* BUYApplePayAdditionsTest.m */, 90F592F91B0D5F4C0026B382 /* BUYApplePayAdditionsTest.m */,
8491102E1CCE708900E53B93 /* BUYArrayAdditionsTests.m */, 8491102E1CCE708900E53B93 /* BUYArrayAdditionsTests.m */,
9A6B03781CDA5D4F0054C26E /* BUYAccountCredentialsTests.m */,
90F592FA1B0D5F4C0026B382 /* BUYCartTest.m */, 90F592FA1B0D5F4C0026B382 /* BUYCartTest.m */,
90F592FB1B0D5F4C0026B382 /* BUYCheckoutTest.m */, 90F592FB1B0D5F4C0026B382 /* BUYCheckoutTest.m */,
90F592FC1B0D5F4C0026B382 /* BUYClientTest_Storefront.m */, 90F592FC1B0D5F4C0026B382 /* BUYClientTest_Storefront.m */,
...@@ -1586,6 +1589,7 @@ ...@@ -1586,6 +1589,7 @@
849110331CCE708900E53B93 /* BUYStringAdditionsTests.m in Sources */, 849110331CCE708900E53B93 /* BUYStringAdditionsTests.m in Sources */,
906CF1B11B8B66AE001F7D5B /* BUYCNPostalAddress.m in Sources */, 906CF1B11B8B66AE001F7D5B /* BUYCNPostalAddress.m in Sources */,
84CA59BC1CD1378100B2A956 /* BUYTestModel.xcdatamodeld in Sources */, 84CA59BC1CD1378100B2A956 /* BUYTestModel.xcdatamodeld in Sources */,
9A6B03791CDA5D4F0054C26E /* BUYAccountCredentialsTests.m in Sources */,
8491103C1CCE731900E53B93 /* BUYURLAdditionsTests.m in Sources */, 8491103C1CCE731900E53B93 /* BUYURLAdditionsTests.m in Sources */,
8491104A1CCEA85C00E53B93 /* BUYObserverTests.m in Sources */, 8491104A1CCEA85C00E53B93 /* BUYObserverTests.m in Sources */,
84CA59C01CD1609400B2A956 /* TestModel.m in Sources */, 84CA59C01CD1609400B2A956 /* TestModel.m in Sources */,
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
// //
#import "BUYClient.h" #import "BUYClient.h"
NS_ASSUME_NONNULL_BEGIN
@class BUYCustomer; @class BUYCustomer;
@class BUYOrder; @class BUYOrder;
...@@ -36,7 +37,7 @@ ...@@ -36,7 +37,7 @@
* @param customer A BUYCustomer * @param customer A BUYCustomer
* @param error An optional NSError * @param error An optional NSError
*/ */
typedef void (^BUYDataCustomerBlock)(BUYCustomer *customer, NSError *error); typedef void (^BUYDataCustomerBlock)(BUYCustomer * _Nullable customer, NSError * _Nullable error);
/** /**
* Return block containing a customer auth token * Return block containing a customer auth token
...@@ -45,7 +46,7 @@ typedef void (^BUYDataCustomerBlock)(BUYCustomer *customer, NSError *error); ...@@ -45,7 +46,7 @@ typedef void (^BUYDataCustomerBlock)(BUYCustomer *customer, NSError *error);
* @param token An authentication token to retrieve the customer later. Store this token securely on the device. * @param token An authentication token to retrieve the customer later. Store this token securely on the device.
* @param error An optional NSError * @param error An optional NSError
*/ */
typedef void (^BUYDataCustomerTokenBlock)(BUYCustomer *customer, NSString *token, NSError *error); typedef void (^BUYDataCustomerTokenBlock)(BUYCustomer * _Nullable customer, NSString * _Nullable token, NSError * _Nullable error);
/** /**
* Return block containing a customer auth token * Return block containing a customer auth token
...@@ -53,7 +54,7 @@ typedef void (^BUYDataCustomerTokenBlock)(BUYCustomer *customer, NSString *token ...@@ -53,7 +54,7 @@ typedef void (^BUYDataCustomerTokenBlock)(BUYCustomer *customer, NSString *token
* @param token An authentication token to retrieve the customer later. Store this token securely on the device. * @param token An authentication token to retrieve the customer later. Store this token securely on the device.
* @param error An optional NSError * @param error An optional NSError
*/ */
typedef void (^BUYDataTokenBlock)(NSString *token, NSError *error); typedef void (^BUYDataTokenBlock)(NSString * _Nullable token, NSError * _Nullable error);
/** /**
* Return block containing an array of BUYOrders * Return block containing an array of BUYOrders
...@@ -61,7 +62,7 @@ typedef void (^BUYDataTokenBlock)(NSString *token, NSError *error); ...@@ -61,7 +62,7 @@ typedef void (^BUYDataTokenBlock)(NSString *token, NSError *error);
* @param orders An array of BUYOrders * @param orders An array of BUYOrders
* @param error An optional NSError * @param error An optional NSError
*/ */
typedef void (^BUYDataOrdersBlock)(NSArray <BUYOrder*> *orders, NSError *error); typedef void (^BUYDataOrdersBlock)(NSArray <BUYOrder*> * _Nullable orders, NSError * _Nullable error);
@interface BUYClient (Customers) @interface BUYClient (Customers)
...@@ -163,3 +164,5 @@ typedef void (^BUYDataOrdersBlock)(NSArray <BUYOrder*> *orders, NSError *error); ...@@ -163,3 +164,5 @@ typedef void (^BUYDataOrdersBlock)(NSArray <BUYOrder*> *orders, NSError *error);
- (NSURLSessionDataTask *)getOrdersForCustomerWithCallback:(BUYDataOrdersBlock)block; - (NSURLSessionDataTask *)getOrdersForCustomerWithCallback:(BUYDataOrdersBlock)block;
@end @end
NS_ASSUME_NONNULL_END
...@@ -154,10 +154,10 @@ ...@@ -154,10 +154,10 @@
NSData *data = [NSJSONSerialization dataWithJSONObject:credentials.JSONRepresentation options:0 error:nil]; NSData *data = [NSJSONSerialization dataWithJSONObject:credentials.JSONRepresentation options:0 error:nil];
return [self putRequestForURL:components.URL body:data completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) { return [self putRequestForURL:components.URL body:data completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
if (json && !error) { NSString *email = json[@"customer"][@"email"];
BUYAccountCredentialItem *emailItem = [BUYAccountCredentialItem itemWithKey:@"email" value:json[@"customer"][@"email"]]; if (email && !error) {
credentials[@"email"] = emailItem; BUYAccountCredentialItem *emailItem = [BUYAccountCredentialItem itemWithEmail:email];
[self loginCustomerWithCredentials:credentials callback:block]; [self loginCustomerWithCredentials:[credentials credentialsByAddingItems:@[emailItem]] callback:block];
} }
else { else {
block(nil, nil, error); block(nil, nil, error);
...@@ -171,10 +171,10 @@ ...@@ -171,10 +171,10 @@
NSData *data = [NSJSONSerialization dataWithJSONObject:credentials.JSONRepresentation options:0 error:nil]; NSData *data = [NSJSONSerialization dataWithJSONObject:credentials.JSONRepresentation options:0 error:nil];
return [self putRequestForURL:components.URL body:data completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) { return [self putRequestForURL:components.URL body:data completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
if (json && !error) { NSString *email = json[@"customer"][@"email"];
BUYAccountCredentialItem *emailItem = [BUYAccountCredentialItem itemWithKey:@"email" value:json[@"customer"][@"email"]]; if (email && !error) {
credentials[@"email"] = emailItem; BUYAccountCredentialItem *emailItem = [BUYAccountCredentialItem itemWithEmail:email];
[self loginCustomerWithCredentials:credentials callback:block]; [self loginCustomerWithCredentials:[credentials credentialsByAddingItems:@[emailItem]] callback:block];
} }
else { else {
block(nil, nil, error); block(nil, nil, error);
......
...@@ -25,40 +25,46 @@ ...@@ -25,40 +25,46 @@
// //
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class BUYAccountCredentialItem;
/** /**
* Intended for storing a collection of credential items representing individual values * Encapsulates user's credentials represented by BUYAccountCredentialItem
* objects.
*/ */
@class BUYAccountCredentialItem;
@interface BUYAccountCredentials : NSObject @interface BUYAccountCredentials : NSObject
NS_ASSUME_NONNULL_BEGIN @property (nonatomic, strong, readonly) NSArray<BUYAccountCredentialItem *> *items;
+ (BUYAccountCredentials *)credentialsWithItems:(NSArray<BUYAccountCredentialItem *> *)items; @property (nonatomic, assign, readonly) NSUInteger count;
+ (BUYAccountCredentials *)credentialsWithItemKeys:(NSArray<NSString *> *)keys; @property (nonatomic, assign, readonly, getter=isValid) BOOL valid;
@property (nonatomic, strong, readonly) NSDictionary *JSONRepresentation;
@property (readonly) NSDictionary *JSONRepresentation; + (BUYAccountCredentials *)credentialsWithItems:(NSArray<BUYAccountCredentialItem *> *)items;
@property (nonatomic, readonly, getter=isValid) BOOL valid; - (instancetype)initWithItems:(NSArray<BUYAccountCredentialItem *> *)items;
- (BUYAccountCredentialItem *)objectForKeyedSubscript:(NSString *)key; - (BUYAccountCredentials *)credentialsByAddingItems:(NSArray<BUYAccountCredentialItem *> *)items;
- (void)setObject:(BUYAccountCredentialItem *)obj forKeyedSubscript:(NSString *)key;
@end @end
/** /**
* Represents a key and KVC-validatable value * Represents a single for user's credentials such as
* email or password.
*/ */
@interface BUYAccountCredentialItem : NSObject @interface BUYAccountCredentialItem : NSObject
+ (instancetype)itemWithKey:(NSString *)key value:(NSString *)value; @property (nonatomic, assign, readonly, getter=isValid) BOOL valid;
@property (nonatomic, strong, readonly) NSString *key;
@property (nonatomic, getter=isValid) BOOL valid; @property (nonatomic, strong, readonly) NSString *value;
@property (nonatomic, strong) NSString *key;
@property (nonatomic, strong) NSString *value;
NS_ASSUME_NONNULL_END + (instancetype)itemWithEmail:(NSString *)value;
+ (instancetype)itemWithFirstName:(NSString *)value;
+ (instancetype)itemWithLastName:(NSString *)value;
+ (instancetype)itemWithPassword:(NSString *)value;
+ (instancetype)itemWithPasswordConfirmation:(NSString *)value;
@end @end
NS_ASSUME_NONNULL_END
\ No newline at end of file
...@@ -26,94 +26,129 @@ ...@@ -26,94 +26,129 @@
#import "BUYAccountCredentials.h" #import "BUYAccountCredentials.h"
@class BUYAccountCredentialItem; static NSString * const BUYAccountFirstNameKey = @"first_name";
static NSString * const BUYAccountLastNameKey = @"last_name";
static NSString * const BUYAccountEmailKey = @"email";
static NSString * const BUYAccountPasswordKey = @"password";
static NSString * const BUYAccountPasswordConfirmationKey = @"password_confirmation";
#pragma mark - BUYAccountCredentials -
@interface BUYAccountCredentials() @interface BUYAccountCredentials()
@property (strong, nonatomic) NSMutableDictionary<NSString *, BUYAccountCredentialItem *> *items;
@property (strong, nonatomic) NSDictionary<NSString *, BUYAccountCredentialItem *> *credentialItems;
@end @end
@implementation BUYAccountCredentials @implementation BUYAccountCredentials
#pragma mark - Init -
+ (BUYAccountCredentials *)credentialsWithItems:(NSArray<BUYAccountCredentialItem *> *)items + (BUYAccountCredentials *)credentialsWithItems:(NSArray<BUYAccountCredentialItem *> *)items
{ {
BUYAccountCredentials *credentials = [BUYAccountCredentials new]; return [[BUYAccountCredentials alloc] initWithItems:items];
NSMutableDictionary *keyedItems = [NSMutableDictionary dictionary]; }
- (instancetype)initWithItems:(NSArray<BUYAccountCredentialItem *> *)items
{
self = [super init];
if (self) {
NSMutableDictionary *container = [NSMutableDictionary new];
for (BUYAccountCredentialItem *item in items) { for (BUYAccountCredentialItem *item in items) {
keyedItems[item.key] = item; container[item.key] = item;
} }
credentials.items = keyedItems; _credentialItems = [container copy];
return credentials; }
return self;
}
#pragma mark - Adding Items -
- (BUYAccountCredentials *)credentialsByAddingItems:(NSArray<BUYAccountCredentialItem *> *)items
{
NSMutableArray *container = [self.items mutableCopy];
[container addObjectsFromArray:items];
return [BUYAccountCredentials credentialsWithItems:container];
}
#pragma mark - Accessors -
- (NSArray<BUYAccountCredentialItem *> *)items
{
return self.credentialItems.allValues;
} }
+ (BUYAccountCredentials *)credentialsWithItemKeys:(NSArray<NSString *> *)keys - (NSUInteger)count
{
return self.credentialItems.count;
}
- (BOOL)isValid
{ {
NSMutableArray *items = [NSMutableArray array]; __block BOOL valid = YES;
for (NSString *key in keys) { [self.credentialItems enumerateKeysAndObjectsUsingBlock:^(NSString *key, BUYAccountCredentialItem *item, BOOL * _Nonnull stop) {
BUYAccountCredentialItem *item = [BUYAccountCredentialItem itemWithKey:key value:@""]; if (!item.isValid) {
[items addObject:item]; valid = NO;
*stop = YES;
} }
return [BUYAccountCredentials credentialsWithItems:items]; }];
return valid;
} }
#pragma mark - Serialization -
- (NSDictionary *)JSONRepresentation - (NSDictionary *)JSONRepresentation
{ {
__block NSMutableDictionary *customer = [NSMutableDictionary dictionary]; __block NSMutableDictionary *customer = [NSMutableDictionary dictionary];
[self.items enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, BUYAccountCredentialItem * _Nonnull obj, BOOL * _Nonnull stop) { [self.credentialItems enumerateKeysAndObjectsUsingBlock:^(NSString *key, BUYAccountCredentialItem *obj, BOOL *stop) {
customer[key] = obj.value; customer[key] = obj.value;
}]; }];
return @{ @"customer": customer }; return @{ @"customer": customer };
} }
- (BOOL)validateValue:(inout id _Nullable __autoreleasing *)ioValue forKey:(NSString *)inKey error:(out NSError * _Nullable __autoreleasing *)outError @end
#pragma mark - BUYAccountCredentialItem -
@implementation BUYAccountCredentialItem
#pragma mark - Init -
+ (instancetype)itemWithEmail:(NSString *)value
{ {
return [self.items[inKey] validateValue:ioValue forKey:inKey error:outError]; return [BUYAccountCredentialItem itemWithKey:BUYAccountEmailKey value:value];
} }
- (BUYAccountCredentialItem *)objectForKeyedSubscript:(NSString *)key + (instancetype)itemWithFirstName:(NSString *)value
{ {
return self.items[key]; return [BUYAccountCredentialItem itemWithKey:BUYAccountFirstNameKey value:value];
} }
- (void)setObject:(BUYAccountCredentialItem *)obj forKeyedSubscript:(NSString *)key + (instancetype)itemWithLastName:(NSString *)value
{ {
self.items[key] = obj; return [BUYAccountCredentialItem itemWithKey:BUYAccountLastNameKey value:value];
} }
- (BOOL)validationForKey:(NSString *)key + (instancetype)itemWithPassword:(NSString *)value
{ {
return [self.items[key] isValid]; return [BUYAccountCredentialItem itemWithKey:BUYAccountPasswordKey value:value];
} }
- (BOOL)isValid + (instancetype)itemWithPasswordConfirmation:(NSString *)value
{ {
__block BOOL valid = YES; return [BUYAccountCredentialItem itemWithKey:BUYAccountPasswordConfirmationKey value:value];
[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 + (instancetype)itemWithKey:(NSString *)key value:(NSString *)value
{ {
BUYAccountCredentialItem *item = [BUYAccountCredentialItem new]; return [[BUYAccountCredentialItem alloc] initWithKey:key value:value];
item.key = key;
item.value = value;
return item;
} }
- (NSString *)value - (instancetype)initWithKey:(NSString *)key value:(NSString *)value
{ {
return _value ?: @""; self = [super init];
} if (self) {
NSAssert(value, @"Cannot initialize BUYAccountCredentialItem with nil value.");
- (BOOL)validateValue:(inout id _Nullable __autoreleasing *)ioValue forKey:(NSString *)inKey error:(out NSError * _Nullable __autoreleasing *)outError _key = key;
{ _value = value;
self.value = *ioValue; _valid = value.length > 0;
self.valid = self.value.length > 0; }
return [self isValid]; return self;
} }
@end @end
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#import "BUYCustomer.h" #import "BUYCustomer.h"
#import "BUYAddress.h" #import "BUYAddress.h"
#import "NSDateFormatter+BUYAdditions.h"
@implementation BUYCustomer @implementation BUYCustomer
...@@ -41,6 +42,8 @@ ...@@ -41,6 +42,8 @@
{ {
[super updateWithDictionary:dictionary]; [super updateWithDictionary:dictionary];
NSDateFormatter *formatter = [NSDateFormatter dateFormatterForPublications];
_taxExempt = dictionary[@"tax_exempt"]; _taxExempt = dictionary[@"tax_exempt"];
_verifiedEmail = dictionary[@"verified_email"]; _verifiedEmail = dictionary[@"verified_email"];
_acceptsMarketing = dictionary[@"accepts_marketing"]; _acceptsMarketing = dictionary[@"accepts_marketing"];
...@@ -55,8 +58,8 @@ ...@@ -55,8 +58,8 @@
_tags = dictionary[@"tags"]; _tags = dictionary[@"tags"];
_ordersCount = dictionary[@"orders_count"]; _ordersCount = dictionary[@"orders_count"];
_totalSpent = dictionary[@"total_spent"]; _totalSpent = dictionary[@"total_spent"];
_createdAt = dictionary[@"created_at"]; _createdAt = [formatter dateFromString:dictionary[@"created_at"]];
_updatedAt = dictionary[@"updated_at"]; _updatedAt = [formatter dateFromString:dictionary[@"updated_at"]];
_addresses = [BUYAddress convertJSONArray:dictionary[@"addresses"]]; _addresses = [BUYAddress convertJSONArray:dictionary[@"addresses"]];
_defaultAddress = [BUYAddress convertObject:dictionary[@"default_address"]]; _defaultAddress = [BUYAddress convertObject:dictionary[@"default_address"]];
} }
......
...@@ -26,16 +26,135 @@ ...@@ -26,16 +26,135 @@
#import "BUYObject.h" #import "BUYObject.h"
@class BUYAddress;
@class BUYLineItem;
@class BUYShippingRate;
@class BUYLineItem;
@interface BUYOrder : BUYObject @interface BUYOrder : BUYObject
/** /**
* URL for the website showing the order status * Whether the order was cancelled or not.
*/ */
@property (nonatomic, strong, readonly) NSURL *statusURL; @property (nonatomic, assign, readonly) BOOL cancelled;
/**
* Whether the fulfillment was aborted or not.
*/
@property (nonatomic, assign, readonly) BOOL fulfillmentAborted;
/**
* The amount of discounts applied to the price of the order.
*/
@property (nonatomic, strong, readonly) NSDecimalNumber *discountSavings;
/**
* Price of the order before shipping and taxes
*/
@property (nonatomic, strong, readonly) NSDecimalNumber *subtotalPrice;
/**
* The sum of all the prices of all the items in the order, taxes and discounts included.
*/
@property (nonatomic, strong, readonly) NSDecimalNumber *totalPrice;
/** /**
* The customer's order name as represented by a number. * The customer's order name as represented by a number.
*/ */
@property (nonatomic, strong, readonly) NSString *name; @property (nonatomic, strong, readonly) NSString *name;
/**
* The reason why the order was cancelled. If the order was not cancelled, this value is "null." If the order was cancelled, the value will be one of the following:
*
* customer: The customer changed or cancelled the order.
* fraud: The order was fraudulent.
* inventory: Items in the order were not in inventory.
* other: The order was cancelled for a reason not in the list above.
*/
@property (nonatomic, strong, readonly) NSString *cancelReason;
/**
* The three letter code (ISO 4217) for the currency used for the payment.
*/
@property (nonatomic, strong, readonly) NSString *currency;
/**
* The state of finances. Value will be one of the following:
*
* pending: The finances are pending.
* authorized: The finances have been authorized.
* partially_paid: The finances have been partially paid.
* paid: The finances have been paid. (This is the default value.)
* partially_refunded: The finances have been partially refunded.
* refunded: The finances have been refunded.
* voided: The finances have been voided.
*/
@property (nonatomic, strong, readonly) NSString *financialStatus;
/**
* The status of the fulfillment. Value will be one of the following:
*
* nil: None of the line items in the order have been fulfilled.
* partial: At least one line item in the order has been fulfilled.
* fulfilled: Every line item in the order has been fulfilled.
*/
@property (nonatomic, strong, readonly) NSString *fulfillmentStatus;
/**
* A unique numeric identifier for the order. This one is used by the shop owner and customer.
* This is different from the id property, which is also a unique numeric identifier for the order,
* but used for API purposes.
*/
@property (nonatomic, strong, readonly) NSNumber *orderNumber;
/**
* The URL for the customer.
*/
@property (nonatomic, strong, readonly) NSURL *customerURL;
/**
* The URL pointing to the order status web page. The URL will be null unless the order was created from a checkout.
*/
@property (nonatomic, strong, readonly) NSURL *orderStatusURL;
/**
* URL for the website showing the order status
*/
@property (nonatomic, strong, readonly) NSURL *statusURL;
/**
* The date and time when the order was imported, in ISO 8601 format.
*/
@property (nonatomic, strong, readonly) NSDate *processedAt;
/**
* The date and time when the order was cancelled, in ISO 8601 format. Nil if the order was not cancelled.
*/
@property (nonatomic, strong, readonly) NSDate *cancelledAt;
/**
* The mailing address to where the order will be shipped. This address is optional and will not be available on orders that do not require one.
*/
@property (nonatomic, strong, readonly) BUYAddress *shippingAddress;
/**
* The mailing address associated with the payment method. This address is an optional field that will not be available on orders that do not require one.
*/
@property (nonatomic, strong, readonly) BUYAddress *billingAddress;
/**
* An array of shipping rate objects.
*/
@property (nonatomic, strong, readonly) NSArray<BUYShippingRate *> *shippingRates;
/**
* An array of fulfilled line item objects.
*/
@property (nonatomic, strong, readonly) NSArray<BUYLineItem *> *fulfilledLineItems;
/**
* An array of unfulfilled line item objects.
*/
@property (nonatomic, strong, readonly) NSArray<BUYLineItem *> *unfulfilledLineItems;
@end @end
...@@ -25,24 +25,48 @@ ...@@ -25,24 +25,48 @@
// //
#import "BUYOrder.h" #import "BUYOrder.h"
#import "BUYAddress.h"
#import "BUYLineItem.h"
#import "BUYShippingRate.h"
#import "NSURL+BUYAdditions.h" #import "NSURL+BUYAdditions.h"
#import "NSDictionary+BUYAdditions.h" #import "NSDictionary+BUYAdditions.h"
#import "NSDateFormatter+BUYAdditions.h"
@interface BUYOrder () #import "NSDecimalNumber+BUYAdditions.h"
@property (nonatomic, strong) NSURL *statusURL;
@property (nonatomic, strong) NSString *name;
@end
@implementation BUYOrder @implementation BUYOrder
- (void)updateWithDictionary:(NSDictionary *)dictionary - (void)updateWithDictionary:(NSDictionary *)dictionary
{ {
[super updateWithDictionary:dictionary]; [super updateWithDictionary:dictionary];
NSString *statusURLString = dictionary[@"status_url"];
self.statusURL = [NSURL buy_urlWithString:statusURLString]; NSDateFormatter *formatter = [NSDateFormatter dateFormatterForPublications];
self.name = [dictionary buy_objectForKey:@"name"];
_cancelled = [[dictionary buy_objectForKey:@"cancelled"] boolValue];
_fulfillmentAborted = [[dictionary buy_objectForKey:@"fulfillment_aborted"] boolValue];
_name = [dictionary buy_objectForKey:@"name"];
_cancelReason = [dictionary buy_objectForKey:@"cancel_reason"];
_currency = [dictionary buy_objectForKey:@"currency"];
_financialStatus = [dictionary buy_objectForKey:@"financial_status"];
_fulfillmentStatus = [dictionary buy_objectForKey:@"fulfillment_status"];
_orderNumber = [dictionary buy_objectForKey:@"order_number"];
_statusURL = [NSURL buy_urlWithString:dictionary[@"status_url"]];
_customerURL = [NSURL buy_urlWithString:dictionary[@"customer_url"]];
_orderStatusURL = [NSURL buy_urlWithString:dictionary[@"order_status_url"]];
_cancelledAt = [formatter dateFromString:[dictionary buy_objectForKey:@"cancelled_at"]];
_processedAt = [formatter dateFromString:[dictionary buy_objectForKey:@"processed_at"]];
_billingAddress = [BUYAddress convertObject:[dictionary buy_objectForKey:@"billing_address"]];
_shippingAddress = [BUYAddress convertObject:[dictionary buy_objectForKey:@"shipping_address"]];
_shippingRates = [BUYShippingRate convertJSONArray:[dictionary buy_objectForKey:@"shipping_methods"]];
_fulfilledLineItems = [BUYLineItem convertJSONArray:dictionary[@"fulfilled_line_items"]];
_unfulfilledLineItems = [BUYLineItem convertJSONArray:dictionary[@"unfulfilled_line_items"]];
_discountSavings = [NSDecimalNumber buy_decimalNumberFromJSON:[dictionary buy_objectForKey:@"discount_savings"]];
_subtotalPrice = [NSDecimalNumber buy_decimalNumberFromJSON:[dictionary buy_objectForKey:@"subtotal_price"]];
_totalPrice = [NSDecimalNumber buy_decimalNumberFromJSON:[dictionary buy_objectForKey:@"total_price"]];
} }
@end @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