Commit f3321e31 by Brent Gulanowski

Merge pull request #131 from Shopify/task/generated-models

Convert to automatically generated models
parents 4f189e2a c45ff37d
......@@ -28,11 +28,8 @@
@import PassKit;
@import UIKit;
@import XCTest;
#import <Buy/Buy.h>
#import "BUYAddress+Additions.h"
#import "BUYCheckout_Private.h"
#import "NSDecimalNumber+BUYAdditions.h"
#import "NSDateFormatter+BUYAdditions.h"
#import "BUYPKContact.h"
#import "BUYNSPersonNameComponents.h"
......@@ -44,13 +41,20 @@
@implementation BUYApplePayAdditionsTest {
BUYCheckout *_checkout;
BUYModelManager *_modelManager;
}
- (void)setUp
{
_modelManager = [BUYModelManager modelManager];
_checkout = [[BUYCheckout alloc] initWithCart:nil];
}
- (void)tearDown
{
_modelManager = nil;
}
#pragma mark - BUYCheckout Apple Pay additions
- (void)testSummaryItemsWithEmptyCheckout
......@@ -67,7 +71,7 @@
- (void)testFullSummaryItems
{
_checkout.subtotalPrice = [NSDecimalNumber one];
_checkout.shippingRate = [[BUYShippingRate alloc] initWithDictionary:@{ @"price" : @"2.00" }];
_checkout.shippingRate = [[BUYShippingRate alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"price" : @"2.00" }];
_checkout.totalTax = [NSDecimalNumber decimalNumberWithString:@"1.00"];
_checkout.paymentDue = [NSDecimalNumber decimalNumberWithString:@"4.00"];
......@@ -87,7 +91,7 @@
- (void)testSummaryItemsWithShippingRate
{
_checkout.subtotalPrice = [NSDecimalNumber one];
_checkout.shippingRate = [[BUYShippingRate alloc] initWithDictionary:@{ @"price" : @"2.00" }];
_checkout.shippingRate = [[BUYShippingRate alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"price" : @"2.00" }];
_checkout.paymentDue = [NSDecimalNumber decimalNumberWithString:@"3.00"];
NSArray *summaryItems = [_checkout buy_summaryItems];
......@@ -104,7 +108,7 @@
- (void)testSummaryItemsWithFreeShippingAndTaxesShouldNotShowShippingOrTaxes
{
_checkout.subtotalPrice = [NSDecimalNumber one];
_checkout.shippingRate = [[BUYShippingRate alloc] initWithDictionary:@{ @"price" : @"0.00" }];
_checkout.shippingRate = [[BUYShippingRate alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"price" : @"0.00" }];
_checkout.totalTax = [NSDecimalNumber zero];
_checkout.paymentDue = [NSDecimalNumber decimalNumberWithString:@"3.00"];
......@@ -120,13 +124,12 @@
- (void)testSummaryItemsWithZeroDiscount
{
_checkout.subtotalPrice = [NSDecimalNumber one];
_checkout.shippingRate = [[BUYShippingRate alloc] initWithDictionary:@{ @"price" : @"0.00" }];
_checkout.shippingRate = [[BUYShippingRate alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"price" : @"0.00" }];
_checkout.totalTax = [NSDecimalNumber zero];
_checkout.paymentDue = [NSDecimalNumber decimalNumberWithString:@"3.00"];
BUYDiscount *discount = [[BUYDiscount alloc] init];
discount.code = @"BANANA";
BUYDiscount *discount = [_modelManager discountWithCode:@"BANANA"];
discount.amount = [NSDecimalNumber zero];
discount.applicable = YES;
discount.applicableValue = YES;
_checkout.discount = discount;
NSArray *summaryItems = [_checkout buy_summaryItems];
......@@ -141,13 +144,12 @@
- (void)testSummaryItemsWithNonZeroDiscount
{
_checkout.subtotalPrice = [NSDecimalNumber one];
_checkout.shippingRate = [[BUYShippingRate alloc] initWithDictionary:@{ @"price" : @"0.00" }];
_checkout.shippingRate = [[BUYShippingRate alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"price" : @"0.00" }];
_checkout.totalTax = [NSDecimalNumber zero];
_checkout.paymentDue = [NSDecimalNumber decimalNumberWithString:@"2.00"];
BUYDiscount *discount = [[BUYDiscount alloc] init];
discount.code = @"BANANA";
BUYDiscount *discount = [_modelManager discountWithCode:@"BANANA"];
discount.amount = [NSDecimalNumber one];
discount.applicable = YES;
discount.applicableValue = YES;
_checkout.discount = discount;
NSArray *summaryItems = [_checkout buy_summaryItems];
......@@ -165,13 +167,12 @@
- (void)testSummaryItemsWithNonZeroCodelessDiscount
{
_checkout.subtotalPrice = [NSDecimalNumber one];
_checkout.shippingRate = [[BUYShippingRate alloc] initWithDictionary:@{ @"price" : @"0.00" }];
_checkout.shippingRate = [[BUYShippingRate alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"price" : @"0.00" }];
_checkout.totalTax = [NSDecimalNumber zero];
_checkout.paymentDue = [NSDecimalNumber decimalNumberWithString:@"2.00"];
BUYDiscount *discount = [[BUYDiscount alloc] init];
discount.code = @"";
BUYDiscount *discount = [_modelManager discountWithCode:@""];
discount.amount = [NSDecimalNumber one];
discount.applicable = YES;
discount.applicableValue = YES;
_checkout.discount = discount;
NSArray *summaryItems = [_checkout buy_summaryItems];
......@@ -189,17 +190,16 @@
- (void)testSummaryItemsWithGiftCard
{
_checkout.subtotalPrice = [NSDecimalNumber decimalNumberWithString:@"12.00"];
_checkout.shippingRate = [[BUYShippingRate alloc] initWithDictionary:@{ @"price" : @"0.00" }];
_checkout.shippingRate = [[BUYShippingRate alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"price" : @"0.00" }];
_checkout.totalTax = [NSDecimalNumber zero];
_checkout.paymentDue = [NSDecimalNumber decimalNumberWithString:@"2.00"];
BUYDiscount *discount = [[BUYDiscount alloc] init];
discount.code = @"";
BUYDiscount *discount = [_modelManager discountWithCode:@""];
discount.amount = [NSDecimalNumber one];
discount.applicable = YES;
discount.applicableValue = YES;
_checkout.discount = discount;
BUYGiftCard *giftCard = [[BUYGiftCard alloc] initWithDictionary:@{ @"amount_used" : [NSDecimalNumber decimalNumberWithString:@"10.00"], @"balance" : [NSDecimalNumber decimalNumberWithString:@"10.00"], @"last_characters" : @"1234" }];
_checkout.giftCards = @[giftCard];
BUYGiftCard *giftCard = [[BUYGiftCard alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"amount_used" : [NSDecimalNumber decimalNumberWithString:@"10.00"], @"balance" : [NSDecimalNumber decimalNumberWithString:@"10.00"], @"last_characters" : @"1234" }];
[[_checkout giftCardsSet] addObject:giftCard];
NSArray *summaryItems = [_checkout buy_summaryItems];
XCTAssertEqual(5, [summaryItems count]);
......@@ -227,15 +227,15 @@
NSDate *lastDate = [self dateWithoutTime:[NSDate dateWithTimeIntervalSinceNow:day]];
NSDateFormatter *dateFormatter = [NSDateFormatter dateFormatterForShippingRates];
BUYShippingRate *rate1 = [[BUYShippingRate alloc] initWithDictionary:@{@"price" : @"5.00", @"id" : @"1234", @"title" : @"Banana", @"delivery_range" : @[[dateFormatter stringFromDate:firstDate], [dateFormatter stringFromDate:lastDate]]}];
BUYShippingRate *rate1 = [[BUYShippingRate alloc] initWithModelManager:_modelManager JSONDictionary:@{@"price" : @"5.00", @"id" : @"1234", @"title" : @"Banana", @"delivery_range" : @[[dateFormatter stringFromDate:firstDate], [dateFormatter stringFromDate:lastDate]]}];
firstDate = [self dateWithoutTime:[NSDate dateWithTimeIntervalSinceNow:day * 3]];
lastDate = [self dateWithoutTime:[NSDate dateWithTimeIntervalSinceNow:day * 5]];
BUYShippingRate *rate2 = [[BUYShippingRate alloc] initWithDictionary:@{@"price" : @"3.00", @"id" : @"5678", @"title" : @"Dinosaur", @"delivery_range" : @[[dateFormatter stringFromDate:firstDate], [dateFormatter stringFromDate:lastDate]]}];
BUYShippingRate *rate2 = [[BUYShippingRate alloc] initWithModelManager:_modelManager JSONDictionary:@{@"price" : @"3.00", @"id" : @"5678", @"title" : @"Dinosaur", @"delivery_range" : @[[dateFormatter stringFromDate:firstDate], [dateFormatter stringFromDate:lastDate]]}];
firstDate = [self dateWithoutTime:[NSDate dateWithTimeIntervalSinceNow:day * 10]];
lastDate = [self dateWithoutTime:[NSDate dateWithTimeIntervalSinceNow:day * 12]];
BUYShippingRate *rate3 = [[BUYShippingRate alloc] initWithDictionary:@{@"price" : @"19.00", @"id" : @"1357", @"title" : @"Bulldozer", @"delivery_range" : @[[dateFormatter stringFromDate:firstDate], [dateFormatter stringFromDate:lastDate]]}];
BUYShippingRate *rate3 = [[BUYShippingRate alloc] initWithModelManager:_modelManager JSONDictionary:@{@"price" : @"19.00", @"id" : @"1357", @"title" : @"Bulldozer", @"delivery_range" : @[[dateFormatter stringFromDate:firstDate], [dateFormatter stringFromDate:lastDate]]}];
NSArray *shippingMethods = [BUYShippingRate buy_convertShippingRatesToShippingMethods:@[rate1, rate2, rate3]];
XCTAssertEqual(3, [shippingMethods count]);
......@@ -353,7 +353,7 @@
ABRecordSetValue(person, kABPersonAddressProperty, addresses, &error);
CFRelease(addresses);
BUYAddress *newAddress = [BUYAddress buy_addressFromRecord:person];
BUYAddress *newAddress = [_modelManager buyAddressWithABRecord:person];
CFRelease(person);
......@@ -410,7 +410,7 @@
[postalAddress setISOCountryCode:@"CA"];
[contact setPostalAddress:postalAddress];
return [BUYAddress buy_addressFromContact:contact];
return [_modelManager buyAddressWithContact:contact];
}
- (void)testCompareAddressWithContactWithNameOrStreetOrPhone
......
......@@ -33,33 +33,32 @@
@implementation BUYCartTest {
BUYCart *_cart;
BUYModelManager *_modelManager;
}
- (void)setUp
{
[super setUp];
_cart = [[BUYCart alloc] init];
_modelManager = [BUYModelManager modelManager];
_cart = [_modelManager insertCartWithJSONDictionary:nil];
}
#pragma mark - Serialization Tests
- (void)testJsonDictionaryShouldBeEmptyWhenNothingIsSet
- (void)tearDown
{
NSDictionary *json = [_cart jsonDictionaryForCheckout];
XCTAssertNotNil(json);
XCTAssertEqual(0, [json count]);
_cart = nil;
_modelManager = nil;
}
#pragma mark - Serialization Tests
- (void)testCartShouldBeInvalidWhenEmpty
{
BUYCart *cart = [[BUYCart alloc] init];
XCTAssertFalse([cart isValid]);
XCTAssertFalse([_cart isValid]);
}
- (void)testAddVariantWillAddALineItem
{
BUYProductVariant *variant = [[BUYProductVariant alloc] initWithDictionary:@{ @"id" : @1 }];
BUYProductVariant *variant = [[BUYProductVariant alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"id" : @1 }];
[_cart addVariant:variant];
XCTAssertEqual([[_cart lineItems] count], 1);
XCTAssertEqualObjects([[_cart lineItems][0] variantId], variant.identifier);
......@@ -67,10 +66,10 @@
- (void)testAddingTwoDifferentVariantsWillAddDifferentLineItems
{
BUYProductVariant *variant = [[BUYProductVariant alloc] initWithDictionary:@{ @"id" : @1 }];
BUYProductVariant *variant = [[BUYProductVariant alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"id" : @1 }];
[_cart addVariant:variant];
BUYProductVariant *variant2 = [[BUYProductVariant alloc] initWithDictionary:@{ @"id" : @2 }];
BUYProductVariant *variant2 = [[BUYProductVariant alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"id" : @2 }];
[_cart addVariant:variant2];
XCTAssertEqual([[_cart lineItems] count], 2);
......@@ -78,7 +77,7 @@
- (void)testAddingAVariantOfTheSameTypeWillNotAddAnotherLineItem
{
BUYProductVariant *variant = [[BUYProductVariant alloc] initWithDictionary:@{ @"id" : @1 }];
BUYProductVariant *variant = [[BUYProductVariant alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"id" : @1 }];
[_cart addVariant:variant];
[_cart addVariant:variant];
XCTAssertEqual([[_cart lineItems] count], 1);
......@@ -88,7 +87,7 @@
- (void)testRemovingAVariantDecrementsQuantity
{
BUYProductVariant *variant = [[BUYProductVariant alloc] initWithDictionary:@{ @"id" : @1 }];
BUYProductVariant *variant = [[BUYProductVariant alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"id" : @1 }];
[_cart addVariant:variant];
[_cart addVariant:variant];
[_cart removeVariant:variant];
......@@ -97,7 +96,7 @@
- (void)testRemovingAllVariantsOfASingleTypeRemovesItsLineItem
{
BUYProductVariant *variant = [[BUYProductVariant alloc] initWithDictionary:@{ @"id" : @1 }];
BUYProductVariant *variant = [[BUYProductVariant alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"id" : @1 }];
[_cart addVariant:variant];
[_cart removeVariant:variant];
XCTAssertEqual([[_cart lineItems] count], 0);
......@@ -105,8 +104,8 @@
- (void)testSetVariantWithQuantity
{
BUYProductVariant *variant = [[BUYProductVariant alloc] initWithDictionary:@{ @"id" : @1 }];
BUYProductVariant *variantTwo = [[BUYProductVariant alloc] initWithDictionary:@{ @"id" : @2 }];
BUYProductVariant *variant = [[BUYProductVariant alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"id" : @1 }];
BUYProductVariant *variantTwo = [[BUYProductVariant alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"id" : @2 }];
[_cart setVariant:variant withTotalQuantity:2];
XCTAssertEqual([[_cart lineItems] count], 1);
......
......@@ -26,12 +26,15 @@
@import UIKit;
@import XCTest;
#import <Buy/Buy.h>
#import "BUYCheckout_Private.h"
#import "BUYCheckout.h"
@interface BUYCheckoutTest : XCTestCase
@end
@implementation BUYCheckoutTest {
BUYModelManager *_modelManager;
BUYCheckout *_checkout;
BUYCart *_cart;
BUYProductVariant *_variant;
......@@ -41,27 +44,28 @@
- (void)setUp
{
[super setUp];
_cart = [[BUYCart alloc] init];
_checkout = [[BUYCheckout alloc] initWithCart:_cart];
_variant = [[BUYProductVariant alloc] initWithDictionary:@{ @"id" : @1 }];
_modelManager = [BUYModelManager modelManager];
_cart = [_modelManager insertCartWithJSONDictionary:nil];
_checkout = [_modelManager checkoutWithCart:_cart];
_variant = [[BUYProductVariant alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"id" : @1 }];
_discountDictionary = @{ @"code" : @"abcd1234", @"amount" : @"5.00", @"applicable" : @true };
}
- (void)testOrderStatusDeserializationWithInvalidURL
{
BUYCheckout *checkout = [[BUYCheckout alloc] initWithDictionary:@{ @"order" : @{ @"status_url" : @"NOT REAL" } }];
BUYCheckout *checkout = [[BUYCheckout alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"order" : @{ @"status_url" : @"NOT REAL" } }];
XCTAssertNil(checkout.order.statusURL);
}
- (void)testOrderStatusDeserializationWithValidURL
{
BUYCheckout *checkout = [[BUYCheckout alloc] initWithDictionary:@{ @"order" : @{ @"status_url" : @"http://www.shopify.com/" } }];
BUYCheckout *checkout = [[BUYCheckout alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"order" : @{ @"status_url" : @"http://www.shopify.com/" } }];
XCTAssertNotNil(checkout.order.statusURL);
}
- (void)testOrderStatusDeserializationWithNoURL
{
BUYCheckout *checkout = [[BUYCheckout alloc] initWithDictionary:@{}];
BUYCheckout *checkout = [[BUYCheckout alloc] initWithModelManager:_modelManager JSONDictionary:@{}];
XCTAssertNil(checkout.order.statusURL);
}
......@@ -73,25 +77,47 @@
XCTAssertTrue([checkout isDirty]);
}
- (void)testCheckoutWithVariant
{
BUYCheckout *checkout = [_modelManager checkoutWithVariant:_variant];
XCTAssertNotNil(checkout);
XCTAssertGreaterThanOrEqual([checkout.lineItems count], 1);
BUYLineItem *lineItem = checkout.lineItems[0];
XCTAssertEqual(_variant.identifier, lineItem.variantId);
}
- (void)testSettingAShippingRateMarksShippingRateIdAsDirty
{
BUYShippingRate *shippingRate = [[BUYShippingRate alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"id" : @"banana" }];
XCTAssertNil(_checkout.shippingRate);
XCTAssertNil(_checkout.shippingRateId);
_checkout.shippingRate = shippingRate;
XCTAssertEqualObjects(@"banana", _checkout.shippingRateId);
XCTAssertTrue([[_checkout dirtyProperties] containsObject:@"shippingRateId"]);
}
- (void)testDirtyPropertiesAreReturnedInJSON
{
BUYShippingRate *shippingRate = [[BUYShippingRate alloc] initWithDictionary:@{ @"id" : @"banana" }];
BUYShippingRate *shippingRate = [[BUYShippingRate alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"id" : @"banana" }];
[_checkout markAsClean];
_checkout.shippingRate = shippingRate;
_checkout.currency = @"BANANA";
NSSet *dirtyProperties = [_checkout dirtyProperties];
XCTAssertTrue([dirtyProperties containsObject:@"currency"]);
XCTAssertTrue([dirtyProperties containsObject:@"shippingRateId"]);
XCTAssertTrue([dirtyProperties containsObject:@"shippingRate"]);
NSDictionary *json = [_checkout jsonDictionaryForCheckout];
XCTAssertEqualObjects(json[@"checkout"][@"currency"], @"BANANA");
XCTAssertEqualObjects(json[@"checkout"][@"shipping_rate_id"], @"banana");
}
- (void)testRequiresShippingAndIncludesTaxesSerialization
{
_checkout.requiresShipping = YES;
_checkout.taxesIncluded = YES;
_checkout.requiresShippingValue = YES;
_checkout.includesTaxesValue = YES;
NSDictionary *jsonDictionary = [_checkout jsonDictionaryForCheckout][@"checkout"];
XCTAssertEqualObjects(@YES, jsonDictionary[@"requires_shipping"]);
XCTAssertEqualObjects(@YES, jsonDictionary[@"taxes_included"]);
......@@ -99,16 +125,16 @@
- (void)testDiscountDeserialization
{
BUYDiscount *discount = [[BUYDiscount alloc] initWithDictionary: _discountDictionary];
BUYDiscount *discount = [[BUYDiscount alloc] initWithModelManager:_modelManager JSONDictionary: _discountDictionary];
XCTAssertEqualObjects(@"abcd1234", discount.code);
XCTAssertEqualObjects(@5.00, discount.amount);
XCTAssertEqual(true, discount.applicable);
XCTAssertEqual(true, discount.applicableValue);
}
- (void)testDiscountSerialization
{
NSDictionary *jsonDict = @{ @"code": @"abcd1234" };
BUYDiscount *discount = [[BUYDiscount alloc] initWithDictionary:_discountDictionary];
BUYDiscount *discount = [[BUYDiscount alloc] initWithModelManager:_modelManager JSONDictionary:_discountDictionary];
XCTAssertEqualObjects(jsonDict, [discount jsonDictionaryForCheckout]);
}
......@@ -125,21 +151,21 @@
- (void)testEmptyCheckoutsDoNotRequireShipping
{
_checkout = [[BUYCheckout alloc] initWithDictionary:@{}];
_checkout = [[BUYCheckout alloc] initWithModelManager:_modelManager JSONDictionary:@{}];
XCTAssertFalse([_checkout requiresShipping]);
}
- (void)testCheckoutsWithoutItemsThatRequireShipping
{
_checkout = [[BUYCheckout alloc] initWithDictionary:@{ @"requires_shipping" : @1 }];
_checkout = [[BUYCheckout alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"requires_shipping" : @1 }];
XCTAssertTrue([_checkout requiresShipping]);
}
- (void)testTaxLineDeserialization
{
BUYTaxLine *taxLine = [[BUYTaxLine alloc] initWithDictionary:@{@"price": @"0.29",
@"rate": @"0.13",
@"title": @"HST"}];
BUYTaxLine *taxLine = [[BUYTaxLine alloc] initWithModelManager:_modelManager JSONDictionary:@{@"price": @"0.29",
@"rate": @"0.13",
@"title": @"HST"}];
XCTAssertEqualObjects(@0.29, taxLine.price);
XCTAssertEqualObjects(@0.13, taxLine.rate);
XCTAssertEqualObjects(@"HST", taxLine.title);
......
......@@ -29,9 +29,7 @@
#import <Buy/Buy.h>
#import "BUYTestConstants.h"
#import "BUYAddress+Additions.h"
#import "BUYClientTestBase.h"
#import "BUYCollection+Additions.h"
#import "NSURLComponents+BUYAdditions.h"
#import "BUYShopifyErrorCodes.h"
#import "BUYAccountCredentials.h"
......@@ -74,7 +72,7 @@ NSString * const BUYFakeCustomerToken = @"dsfasdgafdg";
- (NSData *)dataForCartFromClient:(BUYClient *)client
{
BUYCart *cart = [[BUYCart alloc] init];
BUYCart *cart = [self cart];
BUYCheckout *checkout = [[BUYCheckout alloc] initWithCart:cart];
NSURLSessionDataTask *task = [self.client createCheckout:checkout completion:nil];
XCTAssertNotNil(task);
......@@ -103,10 +101,10 @@ NSString * const BUYFakeCustomerToken = @"dsfasdgafdg";
- (void)testPartialAddressesFlag
{
BUYCart *cart = [[BUYCart alloc] init];
BUYCart *cart = [self cart];
BUYCheckout *checkout = [[BUYCheckout alloc] initWithCart:cart];
XCTAssertThrows([checkout setPartialAddresses:NO]);
XCTAssertThrows([checkout setPartialAddressesValue:NO]);
NSURLSessionDataTask *task = [self.client createCheckout:checkout completion:nil];
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:task.originalRequest.HTTPBody options:0 error:nil];
......@@ -114,11 +112,11 @@ NSString * const BUYFakeCustomerToken = @"dsfasdgafdg";
checkout = [[BUYCheckout alloc] initWithCart:cart];
BUYAddress *partialAddress = [[BUYAddress alloc] init];
BUYAddress *partialAddress = [self.client.modelManager insertAddressWithJSONDictionary:nil];
partialAddress.address1 = nil;
if ([partialAddress isPartialAddress]) {
checkout.partialAddresses = YES;
checkout.partialAddressesValue = YES;
}
checkout.shippingAddress = partialAddress;
......@@ -130,7 +128,7 @@ NSString * const BUYFakeCustomerToken = @"dsfasdgafdg";
- (void)testCheckoutPaymentWithOnlyGiftCard
{
BUYCheckout *checkout = [[BUYCheckout alloc] initWithDictionary:@{@"token": @"abcdef", @"payment_due": @0}];
BUYCheckout *checkout = [[BUYCheckout alloc] initWithModelManager:self.client.modelManager JSONDictionary:@{@"token": @"abcdef", @"payment_due": @0}];
NSURLSessionDataTask *task = [self.client completeCheckout:checkout completion:nil];
XCTAssertNotNil(task);
......@@ -205,7 +203,7 @@ NSString * const BUYFakeCustomerToken = @"dsfasdgafdg";
XCTAssertEqual(error.code, BUYShopifyError_InvalidCheckoutObject);
}];
BUYCheckout *checkout = [[BUYCheckout alloc] initWithDictionary:@{@"token": @"abcdef", @"payment_due": @0}];
BUYCheckout *checkout = [[BUYCheckout alloc] initWithModelManager:self.client.modelManager JSONDictionary:@{@"token": @"abcdef", @"payment_due": @0}];
[self.client completeCheckout:checkout withApplePayToken:nil completion:^(BUYCheckout *checkout, NSError *error) {
callbackCount++;
......@@ -323,6 +321,11 @@ NSString * const BUYFakeCustomerToken = @"dsfasdgafdg";
XCTAssertEqualObjects(requestQueryItems, queryItems);
}
- (BUYCart *)cart
{
return [self.client.modelManager insertCartWithJSONDictionary:nil];
}
#pragma mark - Customer Tests -
- (void)testCustomerCreationURL
......
......@@ -56,9 +56,9 @@
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];
BUYAccountCredentialItem *emailItem = [BUYAccountCredentialItem itemWithEmail:self.customerEmail];
BUYAccountCredentialItem *passwordItem = [BUYAccountCredentialItem itemWithPassword:self.customerPassword];
BUYAccountCredentialItem *passwordConfItem = [BUYAccountCredentialItem itemWithPasswordConfirmation:self.customerPassword];
BUYAccountCredentials *credentials = [BUYAccountCredentials credentialsWithItems:@[emailItem, passwordItem, passwordConfItem]];
[self.client createCustomerWithCredentials:credentials callback:^(BUYCustomer *customer, NSString *token, NSError *error) {
......@@ -93,9 +93,9 @@
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"];
BUYAccountCredentialItem *emailItem = [BUYAccountCredentialItem itemWithEmail:@"a"];
BUYAccountCredentialItem *passwordItem = [BUYAccountCredentialItem itemWithPassword:@"b"];
BUYAccountCredentialItem *passwordConfItem = [BUYAccountCredentialItem itemWithPasswordConfirmation:@"c"];
BUYAccountCredentials *credentials = [BUYAccountCredentials credentialsWithItems:@[emailItem, passwordItem, passwordConfItem]];
[self.client createCustomerWithCredentials:credentials callback:^(BUYCustomer *customer, NSString *token, NSError *error) {
......@@ -135,8 +135,8 @@
XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)];
BUYAccountCredentialItem *emailItem = [BUYAccountCredentialItem itemWithKey:@"email" value:self.customerEmail];
BUYAccountCredentialItem *passwordItem = [BUYAccountCredentialItem itemWithKey:@"password" value:self.customerPassword];
BUYAccountCredentialItem *emailItem = [BUYAccountCredentialItem itemWithEmail:self.customerEmail];
BUYAccountCredentialItem *passwordItem = [BUYAccountCredentialItem itemWithPassword:self.customerPassword];
BUYAccountCredentials *credentials = [BUYAccountCredentials credentialsWithItems:@[emailItem, passwordItem]];
[self.client loginCustomerWithCredentials:credentials callback:^(BUYCustomer *customer, NSString *token, NSError *error) {
......
......@@ -29,7 +29,6 @@
#import <Buy/Buy.h>
#import "BUYTestConstants.h"
#import "BUYCollection.h"
#import "NSDateFormatter+BUYAdditions.h"
#import "BUYClientTestBase.h"
#import <OHHTTPStubs/OHHTTPStubs.h>
#import "OHHTTPStubsResponse+Helpers.h"
......
//
// BUYCollection+Additions.m
// BUYCollectionTests.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,30 +24,23 @@
// THE SOFTWARE.
//
#import "BUYCollection+Additions.h"
#import <XCTest/XCTest.h>
#import "BUYCollection.h"
#import "BUYModelManager.h"
@implementation BUYCollection (Additions)
@interface BUYCollectionTests : XCTestCase
@end
@implementation BUYCollectionTests
+(NSString *)sortOrderParameterForCollectionSort:(BUYCollectionSort)sort
- (void)testStringDescriptionGetsCreated
{
switch (sort) {
case BUYCollectionSortBestSelling:
return @"best-selling";
case BUYCollectionSortCreatedAscending:
return @"created-ascending";
case BUYCollectionSortCreatedDescending:
return @"created-descending";
case BUYCollectionSortPriceAscending:
return @"price-ascending";
case BUYCollectionSortPriceDescending:
return @"price-descending";
case BUYCollectionSortTitleAscending:
return @"title-ascending";
case BUYCollectionSortTitleDescending:
return @"title-descending";
default:
return @"collection-default";
}
BUYModelManager *modelManager = [BUYModelManager modelManager];
BUYCollection *collection = [modelManager insertCollectionWithJSONDictionary:nil];
XCTAssertNil(collection.stringDescription);
collection.JSONDictionary = @{ @"html_description" : @"<meta>super</meta> duper <b>collection</b>" };
XCTAssertEqualObjects(collection.stringDescription, @"super duper collection");
}
@end
......@@ -42,7 +42,7 @@ static NSString * const ResearchEntity = @"Researcher";
static NSString * const RootEntity = @"Root";
@interface NSIndexSet (BUYTestAdditions)
+ (instancetype)indexSetWithIndexes:(NSArray *)indexes;
+ (instancetype)buy_indexSetWithIndexes:(NSArray *)indexes;
@end
@interface BUYCoreDataModelAdditionsTests : XCTestCase
......@@ -264,7 +264,7 @@ static NSString * const RootEntity = @"Root";
dispatch_once(&onceToken, ^{
tags = @[@"one", @"two", @"three", @"hot", @"urgent", @"important", @"red", @"green", @"blue", @"animal", @"vegetable", @"mineral", @"fungus"];
});
return [NSSet setWithArray:[tags objectsAtIndexes:[NSIndexSet indexSetWithIndexes:indexes]]];
return [NSSet setWithArray:[tags objectsAtIndexes:[NSIndexSet buy_indexSetWithIndexes:indexes]]];
}
- (NSDate *)dateWithComponents:(NSDateComponents *)components
......@@ -304,7 +304,7 @@ static NSString * const RootEntity = @"Root";
@implementation NSIndexSet (BUYTestAdditions)
+ (instancetype)indexSetWithIndexes:(NSArray *)indexes
+ (instancetype)buy_indexSetWithIndexes:(NSArray *)indexes
{
NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
for (NSNumber *index in indexes) {
......
//
// BUYProductVariant+Options.m
// BUYCustomerTests.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,32 +24,41 @@
// THE SOFTWARE.
//
#import "BUYProductVariant+Options.h"
@implementation BUYProductVariant (Options)
#import <XCTest/XCTest.h>
#import "BUYCustomer.h"
- (BUYOptionValue *)optionValueForName:(NSString *)optionName
@interface BUYCustomerTests : XCTestCase
@end
@implementation BUYCustomerTests
- (BUYCustomer *)createTestCustomer
{
for (BUYOptionValue *value in self.options) {
if ([value.name isEqualToString:optionName]) {
return value;
}
}
return nil;
BUYCustomer *customer = [BUYCustomer new];
customer.firstName = @"Brent";
customer.lastName = @"Gulanowski";
return customer;
}
+ (NSArray *)filterProductVariants:(NSArray *)productVariants forOptionValue:(BUYOptionValue *)optionValue
- (void)testFullName
{
NSMutableArray *filteredArray = [NSMutableArray new];
for (BUYProductVariant *variant in productVariants) {
for (BUYOptionValue *opValue in variant.options) {
if ([opValue isEqual:optionValue]) {
[filteredArray addObject:variant];
}
}
}
return [filteredArray copy];
BUYCustomer *customer = [self createTestCustomer];
XCTAssertEqualObjects(customer.fullName, @"Brent Gulanowski");
}
- (void)testJSONRepresentation
{
BUYModelManager *modelManager = [BUYModelManager modelManager];
NSDictionary *JSON = @{ @"customer": @{
@"first_name": @"Brent",
@"last_name": @"Gulanowski"
}};
BUYCustomer *jsonCustomer = [modelManager customerWithJSONDictionary:JSON];
NSDictionary *actualJSON = jsonCustomer.JSONDictionary;
XCTAssertEqualObjects(JSON[@"customer"], actualJSON);
}
@end
......@@ -29,8 +29,7 @@
#import <Buy/Buy.h>
#import "BUYTestConstants.h"
#import "BUYAddress+Additions.h"
#import "BUYCheckout_Private.h"
#import "BUYCheckout.h"
#import "BUYClientTestBase.h"
#import <OHHTTPStubs/OHHTTPStubs.h>
#import "OHHTTPStubsResponse+Helpers.h"
......@@ -40,6 +39,8 @@
@implementation BUYIntegrationTest {
BUYModelManager *_modelManager;
NSMutableArray *_products;
BUYCart *_cart;
......@@ -52,6 +53,7 @@
{
[super setUp];
_modelManager = [BUYModelManager modelManager];
_products = [[NSMutableArray alloc] init];
[self fetchProducts];
......@@ -87,12 +89,12 @@
XCTAssertNil(error);
}];
NSLog(@"Fetched products (count: %ld", _products.count);
NSLog(@"Fetched products (count: %tu", _products.count);
}
- (void)createCart
{
_cart = [[BUYCart alloc] init];
_cart = [_modelManager insertCartWithJSONDictionary:nil];
for (BUYProduct *product in _products) {
[_cart addVariant:product.variants[0]];
}
......@@ -132,20 +134,22 @@
return [OHHTTPStubsResponse responseWithKey:@"testCheckoutFlowUsingCreditCard_1"];
}];
[self createCart];
_checkout = [[BUYCheckout alloc] initWithCart:_cart];
NSString *note = @"Order note";
_checkout.note = note;
NSArray *attributes = @[ [[BUYCheckoutAttribute alloc] initWithDictionary:@{ @"name" : @"attribute1", @"value" : @"value1" }], [[BUYCheckoutAttribute alloc] initWithDictionary:@{ @"name" : @"attribute2", @"value" : @"value2" }] ];
_checkout.attributes = attributes;
NSArray *attributes = @[ [[BUYCheckoutAttribute alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"name" : @"attribute1", @"value" : @"value1" }],
[[BUYCheckoutAttribute alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"name" : @"attribute2", @"value" : @"value2" }] ];
_checkout.attributes = [NSSet setWithArray:attributes];
XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)];
[self.client createCheckout:_checkout completion:^(BUYCheckout *returnedCheckout, NSError *error) {
XCTAssertNil(error);
XCTAssertNotNil(returnedCheckout);
XCTAssertEqualObjects(returnedCheckout.note, note);
XCTAssertEqualObjects(returnedCheckout.attributes, attributes);
XCTAssertEqualObjects(returnedCheckout.attributes, _checkout.attributes);
_checkout = returnedCheckout;
[expectation fulfill];
......@@ -509,7 +513,7 @@
return [OHHTTPStubsResponse responseWithKey:@"testRemovingInvalidGiftCardFromCheckout_2"];
}];
BUYGiftCard *giftCard = [[BUYGiftCard alloc] initWithDictionary:@{ @"id" : @"000" }];
BUYGiftCard *giftCard = [[BUYGiftCard alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"id" : @"000" }];
XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)];
[self.client removeGiftCard:giftCard fromCheckout:_checkout completion:^(BUYCheckout *checkout, NSError *error) {
XCTAssertNotNil(error);
......@@ -537,7 +541,7 @@
return [OHHTTPStubsResponse responseWithKey:@"testRemovingExpiredGiftCardFromCheckout_2"];
}];
BUYGiftCard *giftCard = [[BUYGiftCard alloc] initWithDictionary:@{ @"id" : self.giftCardIdExpired }];
BUYGiftCard *giftCard = [[BUYGiftCard alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"id" : self.giftCardIdExpired }];
XCTestExpectation *expectation = [self expectationWithDescription:NSStringFromSelector(_cmd)];
[self.client removeGiftCard:giftCard fromCheckout:_checkout completion:^(BUYCheckout *checkout, NSError *error) {
XCTAssertNotNil(error);
......@@ -998,7 +1002,7 @@
_checkout.shippingAddress = [self partialShippingAddress];
if ([_checkout.shippingAddress isPartialAddress]) {
_checkout.partialAddresses = YES;
_checkout.partialAddressesValue = YES;
}
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest * _Nonnull request) {
......@@ -1181,7 +1185,7 @@
- (BUYAddress *)billingAddress
{
BUYAddress *address = [[BUYAddress alloc] init];
BUYAddress *address = [_modelManager insertAddressWithJSONDictionary:nil];
address.address1 = @"150 Elgin Street";
address.address2 = @"8th Floor";
address.city = @"Ottawa";
......@@ -1197,7 +1201,7 @@
- (BUYAddress *)shippingAddress
{
BUYAddress *address = [[BUYAddress alloc] init];
BUYAddress *address = [_modelManager insertAddressWithJSONDictionary:nil];
address.address1 = @"150 Elgin Street";
address.address2 = @"8th Floor";
address.city = @"Ottawa";
......@@ -1213,7 +1217,7 @@
- (BUYAddress *)partialShippingAddress
{
BUYAddress *address = [[BUYAddress alloc] init];
BUYAddress *address = [_modelManager insertAddressWithJSONDictionary:nil];
address.address1 = nil;
address.city = @"Ottawa";
address.firstName = nil;
......@@ -1227,20 +1231,17 @@
- (BUYDiscount *)applicableDiscount
{
BUYDiscount *discount = [[BUYDiscount alloc] initWithCode:self.discountCodeValid];
return discount;
return [_modelManager discountWithCode:self.discountCodeValid];
}
- (BUYDiscount *)inapplicableDiscount
{
BUYDiscount *discount = [[BUYDiscount alloc] initWithCode:self.discountCodeExpired];
return discount;
return [_modelManager discountWithCode:self.discountCodeExpired];
}
- (BUYDiscount *)nonExistentDiscount
{
BUYDiscount *discount = [[BUYDiscount alloc] initWithCode:@"asdfasdfasdfasdf"];
return discount;
return [_modelManager discountWithCode:@"asdfasdfasdfasdf"];
}
- (void)testExpiringCheckout
......@@ -1248,6 +1249,8 @@
[self createCart];
[self createCheckout];
XCTAssertGreaterThanOrEqual([_checkout.lineItems count], 1);
XCTAssertNotNil(_checkout.reservationTime);
XCTAssertTrue([_checkout.reservationTime isKindOfClass:[NSNumber class]]);
XCTAssertEqual(300, _checkout.reservationTime.intValue);
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest * _Nonnull request) {
......
......@@ -32,25 +32,30 @@
@end
@implementation BUYLineItemTest {
BUYProductVariant *_variant;
BUYLineItem *_lineItem;
BUYModelManager *_modelManager;
}
- (void)setUp
{
[super setUp];
_lineItem = [[BUYLineItem alloc] init];
_modelManager = [BUYModelManager modelManager];
_variant = [[BUYProductVariant alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"id" : @1, @"requires_shipping" : @YES }];
_lineItem = [[BUYLineItem alloc] initWithVariant:_variant];
}
- (void)tearDown
{
_modelManager = nil;
}
- (void)testInitRespectsVariantShippingFlag
{
XCTAssertFalse([[_lineItem requiresShipping] boolValue]);
BUYProductVariant *variant = [[BUYProductVariant alloc] initWithDictionary:@{ @"id" : @1, @"requires_shipping" : @YES }];
_lineItem = [[BUYLineItem alloc] initWithVariant:variant];
XCTAssertTrue([[_lineItem requiresShipping] boolValue]);
BUYLineItem *newLineItem = [[BUYLineItem alloc] initWithVariant:variant];
XCTAssertTrue([[newLineItem requiresShipping] boolValue]);
_variant.requiresShipping = @NO;
XCTAssertTrue([[_lineItem requiresShipping] boolValue]);
}
#pragma mark - Serialization Tests
......@@ -59,13 +64,13 @@
{
NSDictionary *json = [_lineItem jsonDictionaryForCheckout];
XCTAssertNotNil(json);
XCTAssertEqualObjects([NSDecimalNumber zero], json[@"price"]);
XCTAssertEqualObjects([NSDecimalNumber zero], json[@"quantity"]);
XCTAssertEqualObjects(@"0", json[@"price"]);
XCTAssertEqualObjects(@"1", json[@"quantity"]);
}
- (void)testJsonDictionaryDoesntIncludeVariantsWithoutIds
{
_lineItem = [[BUYLineItem alloc] initWithVariant:nil];
_lineItem = [_modelManager lineItemWithVariant:nil];
NSDictionary *json = [_lineItem jsonDictionaryForCheckout];
XCTAssertNotNil(json);
XCTAssertNil(json[@"variant_id"]);
......@@ -73,7 +78,7 @@
- (void)testJsonDictionaryShouldShowAllProperties
{
BUYProductVariant *variant = [[BUYProductVariant alloc] initWithDictionary:@{ @"id" : @5 }];
BUYProductVariant *variant = [[BUYProductVariant alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"id" : @5 }];
_lineItem = [[BUYLineItem alloc] initWithVariant:variant];
_lineItem.quantity = [NSDecimalNumber decimalNumberWithString:@"3"];
_lineItem.price = [NSDecimalNumber decimalNumberWithString:@"5.55"];
......@@ -81,17 +86,15 @@
NSDictionary *json = [_lineItem jsonDictionaryForCheckout];
XCTAssertEqualObjects(@5, json[@"variant_id"]);
XCTAssertEqualObjects([NSDecimalNumber decimalNumberWithString:@"3"], json[@"quantity"]);
XCTAssertEqualObjects([NSDecimalNumber decimalNumberWithString:@"5.55"], json[@"price"]);
XCTAssertEqualObjects(@"3", json[@"quantity"]);
XCTAssertEqualObjects(@"5.55", json[@"price"]);
XCTAssertEqualObjects(@"banana", json[@"title"]);
}
- (void)testUpdatingFromJsonShouldUpdateAllValues
{
XCTAssertFalse([[_lineItem requiresShipping] boolValue]);
BUYLineItem *lineItem = [[BUYLineItem alloc] initWithDictionary:@{ @"id" : @5, @"price" : @"5.99", @"quantity" : @5, @"requires_shipping" : @YES, @"title" : @"banana" }];
XCTAssertEqualObjects(@5, lineItem.lineItemIdentifier);
BUYLineItem *lineItem = [[BUYLineItem alloc] initWithModelManager:_modelManager JSONDictionary:@{ @"id" : @"5", @"price" : @"5.99", @"quantity" : @5, @"requires_shipping" : @YES, @"title" : @"banana" }];
XCTAssertEqualObjects(@"5", lineItem.identifier);
XCTAssertEqualObjects([NSDecimalNumber decimalNumberWithString:@"5.99"], lineItem.price);
XCTAssertEqualObjects([NSDecimalNumber decimalNumberWithString:@"5"], lineItem.quantity);
XCTAssertEqualObjects(@"banana", lineItem.title);
......
//
// buymodel_tests.m
// buymodel tests
//
// 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 "BUYManagedObject.h"
#import "BUYCollection.h"
//#import "BUYCustomer.h"
#import "BUYProduct.h"
#import "BUYProductVariant.h"
#import "BUYShop.h"
#import "BUYAddress.h"
#import "BUYCheckout.h"
#import "BUYLineItem.h"
#import "BUYModelManager.h"
#import <CoreData/CoreData.h>
@interface BUYModelManager (buymodel_tests)
- (BUYCollection *)newTestCollection;
- (BUYCollection *)newTestCollectionWithProducts:(NSArray *)products;
- (BUYProduct *)newTestProduct;
- (BUYProduct *)newTestProductWithVariants:(NSArray *)variants;
- (BUYProductVariant *)newTestVariant;
@end
@interface NSJSONSerialization (buymodel_tests)
+ (NSDictionary *)JSONDictionaryWithData:(NSData *)data;
+ (NSDictionary *)JSONDictionaryWithString:(NSString *)string;
@end
@interface BUYModelManagerTests : XCTestCase {
BUYModelManager *_modelManager;
}
@end
static NSDictionary *sampleJSON;
@implementation BUYModelManagerTests
+ (void)initialize
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSURL *jsonURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"mocked_responses" withExtension:@"json"];
NSData *jsonData = [NSData dataWithContentsOfURL:jsonURL];
sampleJSON = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:NULL];
});
}
- (NSManagedObjectModel *)buyModel
{
NSBundle *bundle = [NSBundle bundleForClass:[BUYObject class]];
XCTAssertNotNil(bundle, @"Cannot find bundle for BUYManagedObject");
NSURL *url = [bundle URLForResource:@"Mobile Buy SDK" withExtension:@"momd"];
XCTAssertNotNil(url);
return [[NSManagedObjectModel alloc] initWithContentsOfURL:url];
}
- (void)setUp
{
[super setUp];
_modelManager = [[BUYModelManager alloc] initWithManagedObjectModel:[self buyModel]];
}
- (void)tearDown
{
_modelManager = nil;
}
- (void)testCoreDataModelDefinitions
{
NSManagedObjectModel *model = _modelManager.model;
NSDictionary *entities = [model entitiesByName];
XCTAssertGreaterThan(entities.count, 0, @"No entities found in model %@", model);
NSArray *persistentEntities = [model entitiesForConfiguration:@"persistent"];
NSArray *transientEntities = [model entitiesForConfiguration:@"transient"];
XCTAssertEqual((persistentEntities.count + transientEntities.count), entities.count, @"Some entities in model not included in configurations");
}
- (void)testConvertJSON
{
NSString *JSONString = sampleJSON[@"testGetShop_0"][@"body"];
NSDictionary *expected = [NSJSONSerialization JSONDictionaryWithString:JSONString];
id<BUYObject> object = [_modelManager buy_objectWithEntityName:@"Shop" JSONDictionary:expected];
NSDictionary *actual = object.JSONDictionary;
XCTAssertEqualObjects(actual, expected, @"generated dictionary was incorrect");
}
#if 0
- (void)testTransformFromJSONTransient
{
}
- (void)testTransformFromJSONPersistent
{
}
- (void)testTransformFromJSONPersistentUnique
{
}
- (void)testTransformtoJSONTransient
{
}
- (void)testTransformToJSONPersistent
{
}
#endif
- (BUYCheckout *)newTestCheckout
{
return [self newTestCheckoutWithLineItems:@[[self newTestLineItem], [self newTestLineItem], [self newTestLineItem]]];
}
- (BUYCheckout *)newTestCheckoutWithLineItems:(NSArray *)lineItems
{
static NSUInteger checkoutId = 0;
++checkoutId;
NSDictionary *props = @{
@"identifier" : @(checkoutId),
};
BUYCheckout *checkout = [[BUYCheckout alloc] initWithModelManager:_modelManager JSONDictionary:props];
checkout.lineItems = [NSOrderedSet orderedSetWithArray:lineItems];
return checkout;
}
- (BUYLineItem *)newTestLineItem
{
return [self newTestLineItemWithVariant:[_modelManager newTestVariant]];
}
- (BUYLineItem *)newTestLineItemWithVariant:(BUYProductVariant *)variant
{
static NSUInteger lineItemId = 0;
++lineItemId;
NSDictionary *props = @{
@"identifier" : @(lineItemId),
};
BUYLineItem *lineItem = [[BUYLineItem alloc] initWithModelManager:_modelManager JSONDictionary:props];
lineItem.variantId = variant.identifier;
return lineItem;
}
@end
@implementation BUYModelManager (buymodel_tests)
- (BUYCollection *)newTestCollection
{
return [self newTestCollectionWithProducts:@[[self newTestProduct], [self newTestProduct]]];
}
- (BUYCollection *)newTestCollectionWithProducts:(NSArray *)products
{
static NSUInteger collectionId = 0;
++collectionId;
NSDictionary *props = @{
BUYCollectionAttributes.identifier : @(collectionId),
BUYCollectionAttributes.title : [NSString stringWithFormat:@"Collection-%tu", collectionId],
};
BUYCollection *collection = [self insertCollectionWithJSONDictionary:props];
collection.products = [NSOrderedSet orderedSetWithArray:products];
return collection;
}
- (BUYProduct *)newTestProduct
{
return [self newTestProductWithVariants:@[[self newTestVariant], [self newTestVariant]]];
}
- (BUYProduct *)newTestProductWithVariants:(NSArray *)variants
{
static NSUInteger productId = 0;
++productId;
int32_t order = 0;
for (BUYProductVariant *variant in variants) {
variant.positionValue = order++;
}
NSDictionary *props = @{
BUYProductAttributes.identifier : @(productId),
BUYProductAttributes.title : [NSString stringWithFormat:@"Product-%tu", productId],
};
BUYProduct *product = [self insertProductWithJSONDictionary:props];
product.variants = [NSOrderedSet orderedSetWithArray:variants];
return product;
}
- (BUYProductVariant *)newTestVariant
{
static NSUInteger variantId = 0;
++variantId;
NSDictionary *props = @{
BUYProductVariantAttributes.identifier : @(variantId),
BUYProductVariantAttributes.available : @YES,
BUYProductVariantAttributes.requiresShipping : @YES,
BUYProductVariantAttributes.title : [NSString stringWithFormat:@"Variant-%tu", variantId],
BUYProductVariantAttributes.price : [NSDecimalNumber decimalNumberWithString:@"9.95"]
};
return [self insertProductVariantWithJSONDictionary:props];
}
@end
@implementation NSJSONSerialization (buymodel_tests)
+ (NSDictionary *)JSONDictionaryWithData:(NSData *)data
{
NSError *error = nil;
NSDictionary *dictionary = [self JSONObjectWithData:data options:0 error:&error];
if (nil == dictionary) {
NSLog(@"Failed to decode %tu bytes of data; error: %@", data.length, error);
}
return dictionary;
}
+ (NSDictionary *)JSONDictionaryWithString:(NSString *)string
{
return [self JSONDictionaryWithData:[string dataUsingEncoding:NSUTF8StringEncoding]];
}
@end
......@@ -50,77 +50,33 @@
@property (nonatomic, readonly) NSArray *array;
@property (nonatomic, readonly) NSMutableArray *mutableArray;
- (NSArray *)propertyNames;
@end
@interface BUYObjectSubclass : BUYObject
@property (nonatomic, strong) NSNumber *identifier;
@end
@interface BUYObjectTests : XCTestCase
@property (nonatomic, strong) BUYModelManager *modelManager;
@end
@implementation BUYObjectTests
- (void)testInitWithDictionaryParsesIdentifier
{
BUYObject *object = [[BUYObject alloc] initWithDictionary:@{ @"id" : @5 }];
XCTAssert([object isDirty] == NO);
XCTAssertEqual(@5, [object identifier]);
}
- (void)testInitWithDictionaryWithoutIdentifier
{
BUYObject *object = [[BUYObject alloc] initWithDictionary:@{}];
XCTAssertNil([object identifier]);
}
- (void)testConvertObject
{
BUYObject *object = [BUYObject convertObject:@{ @"id" : @10 }];
XCTAssertNotNil(object);
XCTAssertEqual(@10, [object identifier]);
}
- (void)testConvertObjectWorksWithSubclasses
{
BUYObject *object = [BUYObjectSubclass convertObject:@{ @"id" : @10 }];
XCTAssertNotNil(object);
XCTAssertTrue([object isKindOfClass:[BUYObjectSubclass class]]);
XCTAssertEqual(@10, [object identifier]);
}
- (void)testConvertJSONArrayWithEmptyArray
{
NSArray *json = @[];
XCTAssertEqual(0, [[BUYObject convertJSONArray:json] count]);
}
@interface BUYModelManager (BUYDirtyTracked)
+ (BUYModelManager *)testModelManager;
@end
- (void)testConvertJSONArrayCreatesObjectOfClass
{
NSArray *json = @[@{ @"id" : @5 }, @{ @"id" : @7 }];
NSArray *convertedArray = [BUYObject convertJSONArray:json];
XCTAssertEqual(2, [convertedArray count]);
XCTAssertTrue([convertedArray[0] isKindOfClass:[BUYObject class]]);
XCTAssertTrue([convertedArray[1] isKindOfClass:[BUYObject class]]);
XCTAssertEqualObjects(@5, [convertedArray[0] identifier]);
XCTAssertEqualObjects(@7, [convertedArray[1] identifier]);
}
@implementation BUYObjectTests
- (void)testConvertJSONArrayWithCreatedBlock
- (void)setUp
{
NSArray *json = @[@{ @"id" : @5 }, @{ @"id" : @6 }, @{ @"id" : @7 }];
__block NSUInteger numberOfInvokes = 0;
NSArray *convertedArray = [BUYObject convertJSONArray:json block:^(id obj) {
XCTAssertTrue([obj isKindOfClass:[BUYObject class]]);
++numberOfInvokes;
}];
XCTAssertNotNil(convertedArray);
XCTAssertEqual([json count], [convertedArray count]);
XCTAssertEqual([json count], numberOfInvokes);
[super setUp];
self.modelManager = [BUYModelManager testModelManager];
}
- (void)testDirtyTracking
{
BUYDirtyTracked *object = [[BUYDirtyTracked alloc] init];
BUYDirtyTracked *object = [self dirtyTrackedObject];
object.s = @"short property name test";
object.dirtyObjectValue = @"Banana";
object.dirtyBooleanValue = true;
......@@ -136,19 +92,14 @@
object.dirtyUnsignedLongLongValue = 1234123412341234;
object.dirtyFloatValue = 0.5f;
object.dirtyDoubleValue = 0.5;
NSSet *expected = [NSSet setWithArray:@[@"s", @"dirtyObjectValue", @"dirtyBooleanValue", @"dirtyCharacterValue",
@"dirtyUnsignedCharValue", @"dirtyIntegerValue", @"dirtyUnsignedIntegerValue",
@"dirtyShortValue", @"dirtyUnsignedShortValue", @"dirtyLongValue",
@"dirtyUnsignedLongValue", @"dirtyLongLongValue", @"dirtyUnsignedLongLongValue",
@"dirtyFloatValue", @"dirtyDoubleValue"]];
NSSet *expected = [NSSet setWithArray:[object propertyNames]];
NSSet *actual = [object dirtyProperties];
XCTAssert([expected isEqual:actual]);
XCTAssertEqual([actual count], [expected count]);
XCTAssertEqualObjects(actual, expected);
}
- (void)testIsDirtyReturnsFalseWhenClean
{
BUYDirtyTracked *object = [[BUYDirtyTracked alloc] init];
BUYDirtyTracked *object = [self dirtyTrackedObject];
XCTAssert([object isDirty] == NO);
object.dirtyObjectValue = @"Banana";
[object markAsClean];
......@@ -157,18 +108,23 @@
- (void)testIsDirtyReturnsTrueWhenDirty
{
BUYDirtyTracked *object = [[BUYDirtyTracked alloc] init];
BUYDirtyTracked *object = [self dirtyTrackedObject];
object.dirtyObjectValue = @"Banana";
XCTAssert([object isDirty]);
}
- (void)testMarkAsClean
{
BUYDirtyTracked *object = [[BUYDirtyTracked alloc] init];
BUYDirtyTracked *object = [self dirtyTrackedObject];
object.dirtyObjectValue = @"Banana";
XCTAssert([object dirtyProperties]);
}
- (BUYDirtyTracked *)dirtyTrackedObject
{
return [[BUYDirtyTracked alloc] initWithModelManager:nil JSONDictionary:nil];
}
@end
#pragma mark - Helper Impls
......@@ -180,7 +136,44 @@
return YES;
}
+ (NSString *)entityName
{
return nil;
}
// Overriding private BUYObject class method to avoid need for entity
- (NSArray *)propertyNames
{
return @[@"s", @"dirtyObjectValue", @"dirtyBooleanValue", @"dirtyCharacterValue",
@"dirtyUnsignedCharValue", @"dirtyIntegerValue", @"dirtyUnsignedIntegerValue",
@"dirtyShortValue", @"dirtyUnsignedShortValue", @"dirtyLongValue",
@"dirtyUnsignedLongValue", @"dirtyLongLongValue", @"dirtyUnsignedLongLongValue",
@"dirtyFloatValue", @"dirtyDoubleValue"];
}
@end
@implementation BUYObjectSubclass
+ (NSString *)entityName
{
return @"ObjectSubclass";
}
@end
@implementation BUYModelManager (BUYDirtyTracked)
+ (BUYModelManager *)testModelManager
{
static dispatch_once_t onceToken;
static BUYModelManager *modelManager;
dispatch_once(&onceToken, ^{
NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:@[[NSBundle bundleForClass:self]]];
modelManager = [[BUYModelManager alloc] initWithManagedObjectModel:model];
});
return modelManager;
}
@end
......@@ -31,15 +31,25 @@
@end
@implementation BUYOptionValueTests
@implementation BUYOptionValueTests {
BUYModelManager *_modelManager;
}
- (instancetype)initWithInvocation:(NSInvocation *)invocation
{
self = [super initWithInvocation:invocation];
if (self) {
_modelManager = [BUYModelManager modelManager];
}
return self;
}
- (void)testInitWithValidData
{
NSDictionary *json = [self jsonWithID:@84935 optionID:@749];
BUYOptionValue *value = [[BUYOptionValue alloc] initWithDictionary:json];
NSDictionary *json = [self jsonWithOptionID:@749];
BUYOptionValue *value = [self optionValueWithOptionID:@749];
XCTAssertNotNil(value);
XCTAssertEqualObjects(value.identifier, json[@"id"]);
XCTAssertEqualObjects(value.name, json[@"name"]);
XCTAssertEqualObjects(value.value, json[@"value"]);
XCTAssertEqualObjects(value.optionId, json[@"option_id"]);
......@@ -47,8 +57,8 @@
- (void)testEqualOptions
{
BUYOptionValue *value1 = [self optionValueWithID:@123 optionID:@321];
BUYOptionValue *value2 = [self optionValueWithID:@123 optionID:@321];
BUYOptionValue *value1 = [self optionValueWithOptionID:@321];
BUYOptionValue *value2 = [self optionValueWithOptionID:@321];
XCTAssertNotEqual(value1, value2); // Pointer comparison, different objects
XCTAssertEqualObjects(value1, value2);
......@@ -57,7 +67,7 @@
- (void)testIdenticalOptions
{
BUYOptionValue *value1 = [self optionValueWithID:@123 optionID:@321];
BUYOptionValue *value1 = [self optionValueWithOptionID:@321];
BUYOptionValue *value2 = value1;
XCTAssertEqual(value1, value2);
......@@ -66,15 +76,14 @@
#pragma mark - Convenience -
- (BUYOptionValue *)optionValueWithID:(NSNumber *)identifier optionID:(NSNumber *)optionID
- (BUYOptionValue *)optionValueWithOptionID:(NSNumber *)optionID
{
return [[BUYOptionValue alloc] initWithDictionary:[self jsonWithID:identifier optionID:optionID]];
return [_modelManager buy_objectWithEntityName:[BUYOptionValue entityName] JSONDictionary:[self jsonWithOptionID:optionID]];
}
- (NSDictionary *)jsonWithID:(NSNumber *)identifier optionID:(NSNumber *)optionID
- (NSDictionary *)jsonWithOptionID:(NSNumber *)optionID
{
return @{
@"id" : @19483,
@"name" : @"option1",
@"value" : @"value1",
@"option_id" : @543,
......
//
// BUYOrderTests.m
// Mobile Buy SDK
//
// Created by Gabriel O'Flaherty-Chan on 2016-02-17.
// Copyright © 2016 Shopify Inc. All rights reserved.
//
#import <XCTest/XCTest.h>
#import "BUYOrder.h"
@interface BUYOrderTests : XCTestCase
@property (nonatomic, readonly) NSArray<BUYOrder *> *orders;
@property (nonatomic, readonly) NSDictionary *ordersJSON;
@end
@implementation BUYOrderTests
- (NSArray<BUYOrder *> *)orders
{
return [[BUYModelManager modelManager] buy_objectsWithEntityName:[BUYOrder entityName] JSONArray:self.JSON[@"orders"]];
}
- (NSDictionary *)JSON
{
NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"orders" ofType:@"json"];
NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:path];
return dictionary;
}
- (void)testLineItems
{
NSArray *ordersJSON = self.JSON[@"orders"];
XCTAssertNotNil(ordersJSON);
[ordersJSON enumerateObjectsUsingBlock:^(NSDictionary *orderJSON, NSUInteger idx, BOOL * _Nonnull stop) {
NSArray *unfulfilledLineItems = orderJSON[@"unfulfilled_line_items"];
NSArray *fulfilledLineItems = orderJSON[@"fulfilled_line_items"];
NSInteger lineItemCount = unfulfilledLineItems.count + fulfilledLineItems.count;
BUYOrder *order = self.orders[idx];
XCTAssertEqual(order.lineItems.count, lineItemCount);
}];
}
@end
......@@ -75,6 +75,11 @@
return self;
}
- (NSDictionary *)jsonDictionaryForCheckout
{
return self.JSONDictionary;
}
- (NSDictionary *)JSONDictionary
{
return [self.entity buy_JSONForObject:self];
......
{
orders = (
{
"billing_address" = "<null>";
"cancel_reason" = "<null>";
cancelled = 0;
"cancelled_at" = "<null>";
"customer_url" = "http://greats-clone.myshopify.com/account/orders/1695e53d1444e62f1d454e8113f76a4a";
"discounts_savings" = "<null>";
"financial_status" = paid;
"fulfilled_line_items" = (
);
"fulfillment_aborted" = 0;
"fulfillment_status" = unfulfilled;
id = 2457117894;
name = "#1048";
"order_number" = 1048;
"order_status_url" = "<null>";
"payment_details" = "<null>";
"payment_methods" = (
{
amount = "49.00";
authorization = "<null>";
"created_at" = "2016-02-17T14:02:21-05:00";
currency = CAD;
"device_id" = "<null>";
"error_code" = "<null>";
gateway = "Cash on Delivery (COD)";
id = 2626153222;
kind = sale;
"location_id" = "<null>";
message = "Marked the Cash on Delivery (COD) payment as received";
"order_id" = 2457117894;
"parent_id" = "<null>";
receipt = {
};
"source_name" = "shopify_draft_order";
status = success;
test = 0;
"user_id" = "<null>";
}
);
"processed_at" = "2016-02-17T14:02:21-05:00";
refunds = (
);
"shipping_address" = "<null>";
"shipping_methods" = (
);
"unfulfilled_line_items" = (
{
"applied_discounts" = (
);
"compare_at_price" = "<null>";
"fulfillment_service" = manual;
grams = 907;
id = 4286111430;
"line_price" = "49.00";
price = "49.00";
"product_id" = 3329986435;
properties = {
};
quantity = 1;
"requires_shipping" = 1;
sku = BLBJ420;
taxable = 1;
title = "Bab Low - Blue Jay // White Sole -FB";
"variant_id" = 9687610627;
"variant_title" = 9;
vendor = Greats;
}
);
},
{
"billing_address" = "<null>";
"cancel_reason" = "<null>";
cancelled = 0;
"cancelled_at" = "<null>";
"customer_url" = "http://greats-clone.myshopify.com/account/orders/1eab1c363d5450b560dcd096df9abc2c";
"discounts_savings" = "<null>";
"financial_status" = paid;
"fulfilled_line_items" = (
);
"fulfillment_aborted" = 0;
"fulfillment_status" = unfulfilled;
id = 2456988806;
name = "#1047";
"order_number" = 1047;
"order_status_url" = "<null>";
"payment_details" = "<null>";
"payment_methods" = (
{
amount = "326.00";
authorization = "<null>";
"created_at" = "2016-02-17T13:31:38-05:00";
currency = CAD;
"device_id" = "<null>";
"error_code" = "<null>";
gateway = "Cash on Delivery (COD)";
id = 2625993094;
kind = sale;
"location_id" = "<null>";
message = "Marked the Cash on Delivery (COD) payment as received";
"order_id" = 2456988806;
"parent_id" = "<null>";
receipt = {
};
"source_name" = "shopify_draft_order";
status = success;
test = 0;
"user_id" = "<null>";
}
);
"processed_at" = "2016-02-17T13:31:38-05:00";
refunds = (
);
"shipping_address" = "<null>";
"shipping_methods" = (
);
"unfulfilled_line_items" = (
{
"applied_discounts" = (
);
"compare_at_price" = "<null>";
"fulfillment_service" = manual;
grams = 907;
id = 4285887686;
"line_price" = "78.00";
price = "39.00";
"product_id" = 3330051395;
properties = {
};
quantity = 2;
"requires_shipping" = 1;
sku = BLBJ430;
taxable = 1;
title = "Bab Low - Blue Jay // White Sole";
"variant_id" = 9687849283;
"variant_title" = 10;
vendor = Greats;
},
{
"applied_discounts" = (
);
"compare_at_price" = "<null>";
"fulfillment_service" = manual;
grams = 907;
id = 4285887750;
"line_price" = "49.00";
price = "49.00";
"product_id" = 3330049347;
properties = {
};
quantity = 1;
"requires_shipping" = 1;
sku = BLCW440;
taxable = 1;
title = "Bab Low - Clay // White Sole";
"variant_id" = 9687834243;
"variant_title" = "11 / Clay";
vendor = Greats;
},
{
"applied_discounts" = (
);
"compare_at_price" = "<null>";
"fulfillment_service" = manual;
grams = 907;
id = 4285887814;
"line_price" = "199.00";
price = "199.00";
"product_id" = 3329903235;
properties = {
};
quantity = 1;
"requires_shipping" = 1;
sku = PRCM430;
taxable = 1;
title = "The Pronto - Camo";
"variant_id" = 9687361283;
"variant_title" = 10;
vendor = Greats;
}
);
}
);
}
{
"application_name": "MobileBuyTest",
<<<<<<< Updated upstream
"shop_domain": "",
"api_key": "",
"channel_id": "",
......@@ -7,51 +8,64 @@
"merchant_id": "",
"customer_email": "",
"customer_password": "",
=======
"shop_domain": "mobilebuysdktestshop.myshopify.com",
"api_key": "fccaa7eceb7d210a6e5366e676d4edff",
"channel_id": "26915715",
"app_id": "8",
"merchant_id": "merchant.com.shopify.applepay",
>>>>>>> Stashed changes
"product_ids": [
"",
""
"2096060931",
"2096063363",
"2096062275",
"2096057987"
],
<<<<<<< Updated upstream
"variants": {
"variant_untracked_id": "",
"variant_inventory1_id": "",
"variant_soldout_id": ""
},
"collection_id": "",
=======
"collection_id": "109931075",
>>>>>>> Stashed changes
"gift_cards": {
"ValidGiftCard11": {
"id": "",
"code": "",
"valid11": {
"id": "8366979",
"code": "ValidGiftCard11",
"value": 11
},
"ValidGiftCard25": {
"id": "",
"code": "",
"valid25": {
"id": "7441155",
"code": "ValidGiftCard25",
"value": 25
},
"ValidGiftCard50": {
"id": "",
"code": "",
"valid50": {
"id": "7438659",
"code": "ValidGiftCard50",
"value": 50
},
"expired": {
"id": "",
"code": "",
"value": 0
"id": "7438723",
"code": "ExpiredGiftCard25",
"value": 25
},
"invalid": {
"id": "",
"code": "",
"value": 0
"id": "42424242",
"code": "InvalidGiftCard42",
"value": 42
}
},
"discounts": {
"expired": {
"code": "",
"value": 0
"code": "expired_discount",
"value": 1
},
"valid": {
"code": "",
"value": 0
"code": "12_dollar_discount",
"value": 12
}
}
}
\ No newline at end of file
}
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -39,7 +39,6 @@ extern NSString * const BUYJSONPropertyKeyUserInfoKey; // = @"JSONPropertyK
* The name of a value transformer used to convert to JSON values and back.
* Uses the value specified in the property's user info dictionary under the "JSONValueTransformer" key.
*
* Currently only two transformers are supported: "BUYPublicationsDate" and "BUYShippingRateDate".
* Currently, only attributes (instances of NSAttributeDescription) use value transformers.
*/
@property (nonatomic, readonly, getter=buy_JSONValueTransformerName) NSString *JSONValueTransformerName;
......
......@@ -46,6 +46,8 @@ NSString * const BUYJSONPropertyKeyUserInfoKey = @"JSONPropertyKey";
// This is defined by mogenerator
static NSString * const BUYAttributeValueClassNameKey = @"attributeValueClassName";
static NSString * const BUYDateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
#pragma mark -
@interface NSObject (BUYValueTransforming)
......
......@@ -60,14 +60,29 @@ FOUNDATION_EXPORT const unsigned char BuyVersionString[];
#import <Buy/BUYClient.h>
#import <Buy/BUYClient+Customers.h>
#import <Buy/BUYError.h>
#import <Buy/BUYError+BUYAdditions.h>
#import <Buy/BUYManagedObject.h>
#import <Buy/BUYModelManager.h>
#import <Buy/BUYModelManagerProtocol.h>
#import <Buy/BUYObjectProtocol.h>
#import <Buy/BUYObserver.h>
#import <Buy/BUYShopifyErrorCodes.h>
#import <Buy/BUYPaymentButton.h>
#import <Buy/BUYProductViewController.h>
#import <Buy/BUYStoreViewController.h>
#import <Buy/BUYTheme.h>
#import <Buy/BUYViewController.h>
#import <Buy/NSArray+BUYAdditions.h>
#import <Buy/NSDateFormatter+BUYAdditions.h>
#import <Buy/NSDecimalNumber+BUYAdditions.h>
#import <Buy/NSDictionary+BUYAdditions.h>
#import <Buy/NSDictionary+BUYAdditions.h>
#import <Buy/NSEntityDescription+BUYAdditions.h>
#import <Buy/NSException+BUYAdditions.h>
#import <Buy/NSPropertyDescription+BUYAdditions.h>
#import <Buy/NSRegularExpression+BUYAdditions.h>
#import <Buy/NSString+BUYAdditions.h>
#import <Buy/NSURL+BUYAdditions.h>
#import <Buy/NSURLComponents+BUYAdditions.h>
......@@ -62,7 +62,11 @@
{
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);
BUYCustomer *customer = nil;
if (json && !error) {
customer = [self.modelManager customerWithJSONDictionary:json];
}
block(customer, error);
}];
}
......@@ -93,7 +97,8 @@
}];
}
else {
block([[BUYCustomer alloc] initWithDictionary:json[@"customer"]], self.customerToken, error);
BUYCustomer *customer = [self.modelManager customerWithJSONDictionary:json[@"customer"]];
block(customer, self.customerToken, error);
}
}
else {
......@@ -186,15 +191,9 @@
{
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);
if (json && !error) {
NSArray *orders = [self.modelManager ordersWithJSONDictionary:json];
block(orders, error);
} else {
block(nil, error);
}
......
......@@ -25,10 +25,10 @@
//
@import Foundation;
#import "BUYSerializable.h"
@class PKPaymentToken;
@class BUYAccountCredentials;
@class BUYCart;
@class BUYCheckout;
@class BUYCreditCard;
......@@ -37,6 +37,8 @@
@class BUYProductVariant;
@class BUYShop;
@class BUYCollection;
@class BUYOrder;
@class BUYModelManager;
/**
* The sort order for products in a collection
......@@ -178,12 +180,10 @@ typedef void (^BUYDataProductBlock)(BUYProduct *product, NSError *error);
typedef void (^BUYDataProductsBlock)(NSArray<BUYProduct *> *products, NSError *error);
/**
* Return block containing a list of BUYCollection objects
* Return block containing list of collections
*
* @param collections An array of BUYCollection objects
* @param page Index of the page requested
* @param reachedEnd Boolean indicating whether additional pages exist
* @param error An optional NSError
* @param error Optional NSError
*/
typedef void (^BUYDataCollectionsListBlock)(NSArray<BUYCollection *> *collections, NSUInteger page, BOOL reachedEnd, NSError *error);
......@@ -234,6 +234,11 @@ typedef void (^BUYDataGiftCardBlock)(BUYGiftCard *giftCard, NSError *error);
- (instancetype)initWithShopDomain:(NSString *)shopDomain apiKey:(NSString *)apiKey appId:(NSString *)appId NS_DESIGNATED_INITIALIZER;
/**
*
*/
@property (nonatomic, strong) BUYModelManager *modelManager;
/**
* Queue where callbacks will be called
* defaults to main queue
*/
......@@ -262,7 +267,7 @@ typedef void (^BUYDataGiftCardBlock)(BUYGiftCard *giftCard, NSError *error);
/**
* The Merchant ID is used for Apple Pay and set using `enableApplePayWithMerchantId:`
*/
@property (nonatomic, strong, readonly) NSString *merchantId DEPRECATED_MSG_ATTRIBUTE("Set the `merchantId` on a BUYViewController subclass");
@property (nonatomic, strong, readonly) NSString *merchantId NS_DEPRECATED_IOS(8_0, 9_0, "Set the `merchantId` on a BUYViewController subclass instead");
/**
* Application name to attribute orders to. Defaults to app bundle name (CFBundleName)
......@@ -523,7 +528,7 @@ typedef void (^BUYDataGiftCardBlock)(BUYGiftCard *giftCard, NSError *error);
*
* @return The associated NSURLSessionDataTask
*/
- (NSURLSessionDataTask *)storeCreditCard:(id <BUYSerializable>)creditCard checkout:(BUYCheckout *)checkout completion:(BUYDataCreditCardBlock)block;
- (NSURLSessionDataTask *)storeCreditCard:(BUYCreditCard *)creditCard checkout:(BUYCheckout *)checkout completion:(BUYDataCreditCardBlock)block;
/**
* Convenience method to release all product inventory reservations by setting its
......@@ -544,6 +549,6 @@ typedef void (^BUYDataGiftCardBlock)(BUYGiftCard *giftCard, NSError *error);
*
* @param merchantId The Merchant ID generated on Shopify Admin
*/
- (void)enableApplePayWithMerchantId:(NSString *)merchantId DEPRECATED_MSG_ATTRIBUTE("Set the merchantId on a BUYViewController subclass instead");
- (void)enableApplePayWithMerchantId:(NSString *)merchantId NS_DEPRECATED_IOS(8_0, 9_0, "Set the merchantId on a `BUYViewController` subclass instead");
@end
......@@ -24,21 +24,23 @@
// THE SOFTWARE.
//
#import "BUYClient_Internal.h"
#import "BUYAddress.h"
#import "BUYCart.h"
#import "BUYCheckout.h"
#import "BUYCheckout_Private.h"
#import "BUYCreditCard.h"
#import "BUYClient.h"
#import "BUYCollection.h"
#import "BUYCollection+Additions.h"
#import "BUYError.h"
#import "BUYGiftCard.h"
#import "BUYModelManager.h"
#import "BUYOrder.h"
#import "BUYProduct.h"
#import "BUYShippingRate.h"
#import "BUYShop.h"
#import "BUYShopifyErrorCodes.h"
#import "NSDecimalNumber+BUYAdditions.h"
#import "NSDictionary+BUYAdditions.h"
#import "NSURLComponents+BUYAdditions.h"
#if __has_include(<PassKit/PassKit.h>)
......@@ -52,11 +54,12 @@
#define kDELETE @"DELETE"
#define kJSONType @"application/json"
#define kShopifyError @"shopify"
#define kMinSuccessfulStatusCode 200
#define kMaxSuccessfulStatusCode 299
NSString * const BUYVersionString = @"1.2.6";
NSString * const BUYVersionString = @"1.3";
NSString *const kShopifyError = @"shopify";
static NSString *const kBUYClientPathProductPublications = @"product_listings";
static NSString *const kBUYClientPathCollectionPublications = @"collection_listings";
......@@ -87,18 +90,19 @@ NSString *const BUYClientCustomerAccessToken = @"X-Shopify-Customer-Access-Token
self = [super init];
if (self) {
self.modelManager = [BUYModelManager modelManager];
self.shopDomain = shopDomain;
self.apiKey = apiKey;
self.appId = appId;
self.applicationName = [[NSBundle mainBundle] infoDictionary][@"CFBundleName"] ?: @"";
self.queue = dispatch_get_main_queue();
self.session = [self createUrlSession];
self.session = [self urlSession];
self.pageSize = 25;
}
return self;
}
- (NSURLSession *)createUrlSession
- (NSURLSession *)urlSession
{
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
......@@ -128,7 +132,7 @@ NSString *const BUYClientCustomerAccessToken = @"X-Shopify-Customer-Access-Token
return [self getRequestForURL:shopComponents.URL completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
BUYShop *shop = nil;
if (json && !error) {
shop = [[BUYShop alloc] initWithDictionary:json];
shop = [self.modelManager insertShopWithJSONDictionary:json];
}
block(shop, error);
}];
......@@ -144,7 +148,7 @@ NSString *const BUYClientCustomerAccessToken = @"X-Shopify-Customer-Access-Token
NSArray *products = nil;
if (json && !error) {
products = [BUYProduct convertJSONArray:json[kBUYClientPathProductPublications]];
products = [self.modelManager insertProductsWithJSONArray:json[kBUYClientPathProductPublications]];
}
block(products, page, [self hasReachedEndOfPage:products] || error, error);
}];
......@@ -173,7 +177,7 @@ NSString *const BUYClientCustomerAccessToken = @"X-Shopify-Customer-Access-Token
NSArray *products = nil;
if (json && !error) {
products = [BUYProduct convertJSONArray:json[kBUYClientPathProductPublications]];
products = [self.modelManager insertProductsWithJSONArray:json[kBUYClientPathProductPublications]];
}
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." }];
......@@ -198,7 +202,7 @@ NSString *const BUYClientCustomerAccessToken = @"X-Shopify-Customer-Access-Token
NSArray *collections = nil;
if (json && !error) {
collections = [BUYCollection convertJSONArray:json[kBUYClientPathCollectionPublications]];
collections = [self.modelManager buy_objectsWithEntityName:[BUYCollection entityName] JSONArray:json[kBUYClientPathCollectionPublications]];
}
block(collections, page, [self hasReachedEndOfPage:collections], error);
}];
......@@ -223,7 +227,7 @@ NSString *const BUYClientCustomerAccessToken = @"X-Shopify-Customer-Access-Token
NSArray *products = nil;
if (json && !error) {
products = [BUYProduct convertJSONArray:json[kBUYClientPathProductPublications]];
products = [self.modelManager buy_objectsWithEntityName:[BUYProduct entityName] JSONArray:json[kBUYClientPathProductPublications]];
}
block(products, page, [self hasReachedEndOfPage:products] || error, error);
}];
......@@ -295,7 +299,7 @@ NSString *const BUYClientCustomerAccessToken = @"X-Shopify-Customer-Access-Token
{
BUYCheckout *checkout = nil;
if (!error) {
checkout = [[BUYCheckout alloc] initWithDictionary:json[@"checkout"]];
checkout = [self.modelManager insertCheckoutWithJSONDictionary:json[@"checkout"]];
}
block(checkout, error);
}
......@@ -305,7 +309,7 @@ NSString *const BUYClientCustomerAccessToken = @"X-Shopify-Customer-Access-Token
checkout.marketingAttribution = @{@"medium": @"iOS", @"source": self.applicationName};
checkout.sourceName = @"mobile_app";
if (self.urlScheme || checkout.webReturnToURL) {
checkout.webReturnToURL = checkout.webReturnToURL ?: self.urlScheme;
checkout.webReturnToURL = checkout.webReturnToURL ?: [NSURL URLWithString:self.urlScheme];
checkout.webReturnToLabel = checkout.webReturnToLabel ?: [@"Return to " stringByAppendingString:self.applicationName];
}
}
......@@ -321,7 +325,7 @@ NSString *const BUYClientCustomerAccessToken = @"X-Shopify-Customer-Access-Token
- (NSURLSessionDataTask *)createCheckoutWithCartToken:(NSString *)cartToken completion:(BUYDataCheckoutBlock)block
{
BUYCheckout *checkout = [[BUYCheckout alloc] initWithCartToken:cartToken];
BUYCheckout *checkout = [self.modelManager checkoutwithCartToken:cartToken];
[self configureCheckout:checkout];
NSDictionary *json = [checkout jsonDictionaryForCheckout];
......@@ -352,7 +356,7 @@ NSString *const BUYClientCustomerAccessToken = @"X-Shopify-Customer-Access-Token
block(nil, [NSError errorWithDomain:kShopifyError code:BUYShopifyError_NoGiftCardSpecified userInfo:nil]);
}
else {
BUYGiftCard *giftCard = [[BUYGiftCard alloc] initWithDictionary:@{ @"code" : giftCardCode }];
BUYGiftCard *giftCard = [self.modelManager giftCardWithCode:giftCardCode];
NSURLComponents *components = [self URLComponentsForCheckoutsAppendingPath:@"gift_cards"
checkoutToken:checkout.token
queryItems:nil];
......@@ -393,14 +397,13 @@ NSString *const BUYClientCustomerAccessToken = @"X-Shopify-Customer-Access-Token
- (void)updateCheckout:(BUYCheckout *)checkout withGiftCardDictionary:(NSDictionary *)giftCardDictionary addingGiftCard:(BOOL)addingGiftCard
{
NSMutableArray *giftCardArray = [NSMutableArray arrayWithArray:checkout.giftCards];
BUYGiftCard *giftCard = [[BUYGiftCard alloc] initWithDictionary:giftCardDictionary];
if (addingGiftCard) {
[giftCardArray addObject:giftCard];
BUYGiftCard *giftCard = [self.modelManager insertGiftCardWithJSONDictionary:giftCardDictionary];
[checkout.giftCardsSet addObject:giftCard];
} else {
[giftCardArray removeObject:giftCard];
[checkout removeGiftCardWithIdentifier:giftCardDictionary[@"id"]];
}
checkout.giftCards = [giftCardArray copy];
checkout.paymentDue = [NSDecimalNumber buy_decimalNumberFromJSON:giftCardDictionary[@"checkout"][@"payment_due"]];
// Marking the checkout as clean. The properties we have updated above we don't need to re-sync with Shopify.
......@@ -556,7 +559,7 @@ NSString *const BUYClientCustomerAccessToken = @"X-Shopify-Customer-Access-Token
task = [self getRequestForURL:components.URL completionHandler:^(NSDictionary *json, NSURLResponse *response, NSError *error) {
NSArray *shippingRates = nil;
if (json && !error) {
shippingRates = [BUYShippingRate convertJSONArray:json[@"shipping_rates"]];
shippingRates = [self.modelManager insertShippingRatesWithJSONArray:json[@"shipping_rates"]];
}
NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
......@@ -571,7 +574,7 @@ NSString *const BUYClientCustomerAccessToken = @"X-Shopify-Customer-Access-Token
#pragma mark - Payments
- (NSURLSessionDataTask *)storeCreditCard:(id <BUYSerializable>)creditCard checkout:(BUYCheckout *)checkout completion:(BUYDataCreditCardBlock)block
- (NSURLSessionDataTask *)storeCreditCard:(BUYCreditCard *)creditCard checkout:(BUYCheckout *)checkout completion:(BUYDataCreditCardBlock)block
{
NSURLSessionDataTask *task = nil;
......
......@@ -27,7 +27,7 @@
#import "BUYClient.h"
#import "BUYSerializable.h"
static NSString *const kShopifyError = @"shopify";
extern NSString *const kShopifyError;
@interface BUYClient (Internal)
......
//
// 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
......@@ -34,16 +34,11 @@
#import "NSEntityDescription+BUYAdditions.h"
#import "NSPropertyDescription+BUYAdditions.h"
// Custom value transformer names
NSString * const BUYPublicationsDateTransformerName = @"BUYPublicationsDate";
// Structured value transformer names
NSString * const BUYDeliveryRangeTransformerName = @"BUYDeliveryRange";
NSString * const BUYFlatArrayTransformerName = @"BUYFlatArray";
NSString * const BUYProductTagsTransformerName = @"BUYProductTags";
NSString * const BUYPublicationsDateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
@interface BUYModelManager ()
@property (nonatomic, strong) NSManagedObjectModel *model;
@end
......@@ -54,10 +49,6 @@ NSString * const BUYPublicationsDateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// specialty type transformers
[NSValueTransformer setValueTransformer:[BUYDateTransformer dateTransformerWithFormat:BUYPublicationsDateFormat] forName:BUYPublicationsDateTransformerName];
// specialty collection transformers
[NSValueTransformer setValueTransformer:[[BUYDeliveryRangeTransformer alloc] init] forName:BUYDeliveryRangeTransformerName];
[NSValueTransformer setValueTransformer:[BUYFlatCollectionTransformer arrayTransformer] forName:BUYFlatArrayTransformerName];
[NSValueTransformer setValueTransformer:[BUYFlatCollectionTransformer setTransformerWithSeparator:@", "] forName:BUYProductTagsTransformerName];
......
......@@ -27,37 +27,16 @@
#import <Foundation/Foundation.h>
#import <Buy/BUYObjectProtocol.h>
#import <Buy/BUYModelManagerProtocol.h>
/**
* This is the base class for all Shopify model objects.
* This class takes care of convertion .json responses into
* the associated subclass.
*
* You will generally not need to interact with this class directly.
*/
@interface BUYObject : NSObject<BUYObject>
/**
* The identifier of any Shopify model object.
*/
@property (nonatomic, strong, readonly) NSNumber *identifier;
/**
* Objects marked as "dirty" are unsynced with Shopify and will
* sync on any calls to Shopify when updating a checkout.
*/
@property (nonatomic, readonly, getter=isDirty) BOOL dirty;
- (instancetype)initWithDictionary:(NSDictionary *)dictionary;
- (void)updateWithDictionary:(NSDictionary *)dictionary;
+ (NSArray *)convertJSONArray:(NSArray *)json block:(void (^)(id obj))createdBlock;
+ (NSArray *)convertJSONArray:(NSArray *)json;
+ (instancetype)convertObject:(id)object;
#pragma mark - Dirty Property Tracking
- (NSSet *)dirtyProperties;
- (void)markPropertyAsDirty:(NSString *)property;
- (void)markAsClean;
......
......@@ -39,45 +39,6 @@
@implementation BUYObject
#pragma mark - Deprecated
- (instancetype)init
{
return [self initWithDictionary:nil];
}
- (instancetype)initWithDictionary:(NSDictionary *)dictionary
{
return [self initWithModelManager:nil JSONDictionary:dictionary];
}
+ (NSArray *)convertJSONArray:(NSArray*)json block:(void (^)(id obj))createdBlock
{
NSMutableArray *objects = [[NSMutableArray alloc] init];
for (NSDictionary *jsonObject in json) {
BUYObject *obj = [[self alloc] initWithDictionary:jsonObject];
[objects addObject:obj];
if (createdBlock) {
createdBlock(obj);
}
}
return objects;
}
+ (NSArray *)convertJSONArray:(NSArray*)json
{
return [self convertJSONArray:json block:nil];
}
+ (instancetype)convertObject:(id)object
{
BUYObject *convertedObject = nil;
if (!(object == nil || [object isKindOfClass:[NSNull class]])) {
convertedObject = [[self alloc] initWithDictionary:object];
}
return convertedObject;
}
#pragma mark - Dirty Property Tracking
- (BOOL)isDirty
......@@ -100,23 +61,6 @@
[self.dirtyObserver reset];
}
- (BOOL)isEqual:(id)object
{
if (self == object) return YES;
if (![object isKindOfClass:self.class]) return NO;
BOOL same = ([self.identifier isEqual:((BUYObject*)object).identifier]);
return same;
}
- (NSUInteger)hash
{
NSUInteger hash = [self.identifier hash];
return hash;
}
- (void)trackDirtyProperties:(NSArray *)properties
{
self.dirtyObserver = [BUYObserver observeProperties:properties ofObject:self];
......@@ -124,29 +68,14 @@
#pragma mark - Dynamic JSON Serialization
+ (NSArray *)propertyNames
{
static NSMutableDictionary *namesCache;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
namesCache = [NSMutableDictionary dictionary];
});
NSString *className = NSStringFromClass(self);
NSArray *names = namesCache[className];
if (names == nil) {
NSMutableSet *allNames = [class_getBUYProperties(self) mutableCopy];
[allNames removeObject:NSStringFromSelector(@selector(dirtyObserver))];
names = [allNames allObjects];
namesCache[className] = names;
}
return names;
- (NSArray *)propertyNames
{
return [self.entity.JSONEncodedProperties allKeys];
}
+ (NSEntityDescription *)entity
- (NSEntityDescription *)entity
{
@throw BUYAbstractMethod();
return [self.modelManager buy_entityWithName:[[self class] entityName]];
}
+ (NSString *)entityName
......@@ -161,23 +90,17 @@
- (instancetype)initWithModelManager:(id<BUYModelManager>)modelManager JSONDictionary:(NSDictionary *)dictionary
{
self = [super init];
self = [self init];
if (self) {
self.modelManager = modelManager;
[self updateWithDictionary:dictionary];
self.JSONDictionary = dictionary;
if ([[self class] tracksDirtyProperties]) {
[self trackDirtyProperties:[[self class] propertyNames]];
[self trackDirtyProperties:[self propertyNames]];
}
}
return self;
}
- (void)updateWithDictionary:(NSDictionary *)dictionary
{
_identifier = dictionary[@"id"];
[self markAsClean];
}
- (NSDictionary *)jsonDictionaryForCheckout
{
return self.JSONDictionary;
......@@ -198,11 +121,6 @@
return NO;
}
- (NSEntityDescription *)entity
{
return [self.modelManager buy_entityWithName:[[self class] entityName]];
}
- (NSDictionary *)JSONDictionary
{
// JSON generation starts in `-buy_JSONForObject`.
......
......@@ -25,6 +25,7 @@
//
#import <Foundation/Foundation.h>
#import <Buy/BUYSerializable.h>
@class NSEntityDescription;
......@@ -34,7 +35,7 @@
* The BUYObject protocol is adopted by the common superclasses of both persistent and transient model classes.
*
*/
@protocol BUYObject <NSObject>
@protocol BUYObject <BUYSerializable>
@property (nonatomic, readonly, weak) id<BUYModelManager> modelManager;
......
//
// BUYAddress+Additions.h
// _BUYAddress.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,14 +24,13 @@
// THE SOFTWARE.
//
@import Foundation;
#import "BUYAddress.h"
#import <Buy/_BUYAddress.h>
@interface BUYAddress (Additions)
@interface BUYAddress : _BUYAddress {}
/**
* Check if the address does not include first and last name
* and address1 field. This is used to determine whether a
* Check if the address does not include first and last name
* and address1 field. This is used to determine whether a
* placeholder was set for shipping rates calculations in Apple Pay.
*
* @return True if first name, last name or address1 contain placeholders
......@@ -42,7 +41,7 @@
* Local validation to check that the minimum set of properties required
* to calculate shipping rates are available.
*
* @return True if city, zip/postal code, province/state and country or
* @return True if city, zip/postal code, province/state and country or
* country code are set.
*/
- (BOOL)isValidAddressForShippingRates;
......
//
// BUYAddress+Additions.m
// BUYAddress.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,10 +24,14 @@
// THE SOFTWARE.
//
#import "BUYAddress+Additions.h"
#import "BUYAddress.h"
@implementation BUYAddress
@implementation BUYAddress (Additions)
-(NSString *)countryCode
{
return [[super countryCode] uppercaseString];
}
- (BOOL)isPartialAddress
{
......@@ -38,19 +42,20 @@
}
return NO;
}
}
- (BOOL)isValidAddressForShippingRates
{
BOOL valid = NO;
if (self.city.length > 0 &&
self.zip.length > 0 &&
self.province.length > 0 &&
(self.country.length > 0 || self.countryCode.length == 2)) {
valid = YES;
}
return valid;
}
......
//
// BUYCart.h
// _BUYCart.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,25 +24,11 @@
// THE SOFTWARE.
//
@import Foundation;
#import "BUYSerializable.h"
#import "_BUYCart.h"
@class BUYLineItem;
@class BUYCartLineItem;
@class BUYProductVariant;
/**
* The BUYCart is the starting point for the Checkout API. You are responsible for building a cart, then transforming it
* into a BUYCheckout using the BUYDataClient.
*/
@interface BUYCart : NSObject <BUYSerializable>
/**
* Array of BUYCartLineItem objects in the cart
* Note: These are different from BUYLineItem objects in that
* the line item objects do include the BUYProductVariant.
*/
@property (nonatomic, strong, readonly, nonnull) NSArray<BUYCartLineItem *> *lineItems;
@interface BUYCart : _BUYCart {}
/**
* Returns true if the cart is acceptable to send to Shopify.
......
//
// BUYCart.m
// _BUYCart.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,94 +25,91 @@
//
#import "BUYCart.h"
#import "BUYCartLineItem.h"
#import "BUYProductVariant.h"
@interface BUYCart ()
@property (nonatomic, strong, nonnull) NSMutableSet<BUYCartLineItem *> *lineItemsSet;
@end
#import "./BUYCartLineItem.h"
#import "BUYModelManager.h"
@implementation BUYCart
#if !defined CORE_DATA_PERSISTENCE
- (instancetype)init
{
self = [super init];
if (self) {
self.lineItemsSet = [[NSMutableSet alloc] init];
self.lineItems = [NSOrderedSet orderedSet];
}
return self;
}
- (nonnull NSArray<BUYCartLineItem *> *)lineItems
{
return [self.lineItemsSet allObjects];
}
#endif
- (BOOL)isValid
{
return [self.lineItemsSet count] > 0;
return [self.lineItems count] > 0;
}
- (void)clearCart
{
[self.lineItemsSet removeAllObjects];
self.lineItems = [NSOrderedSet orderedSet];
}
#pragma mark - Simple Cart Editing
- (void)addVariant:(nonnull BUYProductVariant *)variant
- (void)addVariant:(BUYProductVariant *)variant
{
BUYCartLineItem *lineItem = [[BUYCartLineItem alloc] initWithVariant:variant];
BUYCartLineItem *existingLineItem = [self.lineItemsSet member:lineItem];
if (existingLineItem) {
existingLineItem.quantity = [existingLineItem.quantity decimalNumberByAdding:[NSDecimalNumber one]];
} else {
[self.lineItemsSet addObject:lineItem];
[self willChangeValueForKey:BUYCartRelationships.lineItems];
BUYCartLineItem *lineItem = [self linetItemForVariant:variant];
if (lineItem) {
[lineItem incrementQuantity];
}
else {
// quantity is 1 by default
[self.lineItemsSet addObject:[self newCartLineItemWithVariant:variant]];
}
[self didChangeValueForKey:BUYCartRelationships.lineItems];
}
- (void)removeVariant:(nonnull BUYProductVariant *)variant
- (void)removeVariant:(BUYProductVariant *)variant
{
BUYCartLineItem *lineItem = [[BUYCartLineItem alloc] initWithVariant:variant];
BUYCartLineItem *existingLineItem = [self.lineItemsSet member:lineItem];
if (existingLineItem) {
existingLineItem.quantity = [existingLineItem.quantity decimalNumberBySubtracting:[NSDecimalNumber one]];
if ([[existingLineItem quantity] isEqual:[NSDecimalNumber zero]]) {
[self.lineItemsSet removeObject:existingLineItem];
}
[self willChangeValueForKey:BUYCartRelationships.lineItems];
BUYCartLineItem *lineItem = [self linetItemForVariant:variant];
if (lineItem && [lineItem decrementQuantity].integerValue <= 0) {
[self.lineItemsSet removeObject:lineItem];
}
[self didChangeValueForKey:BUYCartRelationships.lineItems];
}
- (void)setVariant:(nonnull BUYProductVariant *)variant withTotalQuantity:(NSInteger)quantity
- (void)setVariant:(BUYProductVariant *)variant withTotalQuantity:(NSInteger)quantity
{
BUYCartLineItem *lineItem = [[BUYCartLineItem alloc] initWithVariant:variant];
BUYCartLineItem *existingLineItem = [self.lineItemsSet member:lineItem];
if (existingLineItem && quantity > 0) {
existingLineItem.quantity = (NSDecimalNumber*)[NSDecimalNumber numberWithInteger:quantity];
} else if (existingLineItem && quantity == 0) {
[self.lineItemsSet removeObject:existingLineItem];
} else {
lineItem.quantity = (NSDecimalNumber*)[NSDecimalNumber numberWithInteger:quantity];
[self.lineItemsSet addObject:lineItem];
[self willChangeValueForKey:BUYCartRelationships.lineItems];
BUYCartLineItem *lineItem = [self linetItemForVariant:variant];
if (quantity == 0 && lineItem != nil) {
[self.lineItemsSet removeObject:lineItem];
}
else if (quantity > 0) {
if (lineItem == nil) {
lineItem = [self newCartLineItemWithVariant:variant];
[self.lineItemsSet addObject:lineItem];
}
lineItem.quantity = [NSDecimalNumber decimalNumberWithMantissa:quantity exponent:0 isNegative:NO];
}
[self didChangeValueForKey:BUYCartRelationships.lineItems];
}
#pragma mark - Helpers
- (BUYCartLineItem *)newCartLineItemWithVariant:(BUYProductVariant *)variant
{
BUYCartLineItem *lineItem = [self.modelManager buy_objectWithEntityName:[BUYCartLineItem entityName] JSONDictionary:nil];
lineItem.variant = variant;
return lineItem;
}
- (NSDictionary *)jsonDictionaryForCheckout
- (BUYCartLineItem *)linetItemForVariant:(BUYProductVariant *)variant
{
NSMutableDictionary *cart = [[NSMutableDictionary alloc] init];
NSArray *lineItems = [self lineItems];
if ([lineItems count] > 0) {
NSMutableArray *lineItemsJson = [[NSMutableArray alloc] init];
for (BUYCartLineItem *lineItem in lineItems) {
[lineItemsJson addObject:[lineItem jsonDictionaryForCheckout]];
}
cart[@"line_items"] = lineItemsJson;
}
return cart;
return [[self.lineItems filteredOrderedSetUsingPredicate:[NSPredicate predicateWithFormat:@"variant = %@", variant]] lastObject];
}
@end
//
// BUYCartLineItem.h
// _BUYCartLineItem.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,23 +24,48 @@
// THE SOFTWARE.
//
#import "BUYLineItem.h"
#import <Buy/_BUYCartLineItem.h>
/**
* BUYCartLineItem is a subclass of BUYLineItem that extends the object
* by exposing the BUYProductVariant that the line item was initialized with
* using `initWithVariant:`.
*
* Note that this object is only used for a BUYCart and line item objects on
* BUYCheckout are represented by BUYLineItem objects that only contain the
* variant ID (if created from a BUYProductVariant).
* Newly inserted `CartLineItem`s have an initial quantity of 1.
*/
@interface BUYCartLineItem : BUYLineItem
@interface BUYCartLineItem : _BUYCartLineItem {}
/**
* Convenience method for access the identifier of the underlying variant.
*/
- (NSNumber *)variantId;
/**
* The variant price times the quantity.
*/
@property (nonatomic, readonly) NSDecimalNumber *linePrice;
/**
* Add the amount to the current quantity.
*/
- (NSDecimalNumber *)addQuantity:(NSDecimalNumber *)amount;
/**
* The BUYProductVariant object associated with the line item
* when created using the preferred `initWithVariant:` initializer.
* Subtract the amount from the current quantity.
*/
@property (nonatomic, strong, readonly) BUYProductVariant *variant;
- (NSDecimalNumber *)subtractQuantity:(NSDecimalNumber *)amount;
/**
* Add 1 to the existing quantity;
*/
- (NSDecimalNumber *)incrementQuantity;
/**
* Subtract 1 from the existing quantity.
*/
- (NSDecimalNumber *)decrementQuantity;
@end
@interface BUYModelManager (BUYCartLineItemCreation)
- (BUYCartLineItem *)cartLineItemWithVariant:(BUYProductVariant *)variant;
@end
\ No newline at end of file
//
// BUYCartLineItem.m
// _BUYCartLineItem.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -26,39 +26,81 @@
#import "BUYCartLineItem.h"
#import "BUYProductVariant.h"
@interface BUYCartLineItem ()
@property (nonatomic, strong) BUYProductVariant *variant;
@end
#import "BUYModelManager.h"
@implementation BUYCartLineItem
- (instancetype)initWithVariant:(BUYProductVariant *)variant
#if defined CORE_DATA_PERSISTENCE
- (void)awakeFromInsert
{
self = [super initWithVariant:variant];
self.quantity = [NSDecimalNumber one];
}
#else
- (instancetype)init
{
self = [super init];
if (self) {
self.variant = variant;
self.quantity = [NSDecimalNumber one];
}
return self;
}
#endif
+ (NSSet *)keyPathsForValuesAffectingLinePrice
{
NSString *variantPriceKeyPath = [@[BUYCartLineItemRelationships.variant, BUYProductVariantAttributes.price] componentsJoinedByString:@"."];
return [NSSet setWithObjects:BUYCartLineItemAttributes.quantity, variantPriceKeyPath, nil];
}
- (NSNumber *)variantId
{
return self.variant.identifier;
}
- (NSDecimalNumber *)linePrice
{
return [self.quantity decimalNumberByMultiplyingBy:self.variant.price];
}
- (NSDecimalNumber *)addQuantity:(NSDecimalNumber *)amount
{
NSDecimalNumber *quantity = [self.quantity decimalNumberByAdding:amount];
self.quantity = quantity;
return quantity;
}
- (NSDecimalNumber *)subtractQuantity:(NSDecimalNumber *)amount
{
NSDecimalNumber *quantity = self.quantity ?: [NSDecimalNumber zero];
if ([quantity compare:amount] == NSOrderedDescending) {
quantity = [quantity decimalNumberBySubtracting:amount];
}
else {
quantity = [NSDecimalNumber zero];
}
self.quantity = quantity;
return quantity;
}
- (BOOL)isEqual:(id)object
- (NSDecimalNumber *)incrementQuantity
{
if (self == object) return YES;
if (![object isKindOfClass:self.class]) return NO;
BOOL same = ([self.identifier isEqual:((BUYObject*)object).identifier]) || [self.variantId isEqual:((BUYCartLineItem*)object).variant.identifier];
return [self addQuantity:[NSDecimalNumber one]];
}
return same;
- (NSDecimalNumber *)decrementQuantity
{
return [self subtractQuantity:[NSDecimalNumber one]];
}
- (NSUInteger)hash
@end
@implementation BUYModelManager (BUYCartLineItemCreation)
- (BUYCartLineItem *)cartLineItemWithVariant:(BUYProductVariant *)variant
{
NSUInteger hash = [self.identifier hash];
return hash;
BUYCartLineItem *lineItem = [self insertCartLineItemWithJSONDictionary:nil];
lineItem.variant = variant;
return lineItem;
}
@end
//
// BUYCollection.h
// _BUYCollection.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,57 +24,26 @@
// THE SOFTWARE.
//
@import Foundation;
#import "BUYObject.h"
#import <Buy/_BUYCollection.h>
#import "BUYClient.h"
/**
* Represents a collection of products on the shop
*/
@interface BUYCollection : BUYObject
/**
* The title of the collection
*/
@property (nonatomic, strong, readonly) NSString *title;
/**
* The unique collection ID
*/
@property (nonatomic, strong, readonly) NSNumber *collectionId;
@interface BUYCollection : _BUYCollection {}
/**
* The html description
*/
@property (nonatomic, strong, readonly) NSString *htmlDescription;
@property (nonatomic, readonly) NSDate *createdAtDate NS_DEPRECATED_IOS(8_0, 9_0);
@property (nonatomic, readonly) NSDate *updatedAtDate NS_DEPRECATED_IOS(8_0, 9_0);
@property (nonatomic, readonly) NSDate *publishedAtDate NS_DEPRECATED_IOS(8_0, 9_0);
/**
* The collection's image URL
*/
@property (nonatomic, strong, readonly) NSURL *imageURL;
@property (nonatomic, readonly) NSURL *imageURL NS_DEPRECATED_IOS(8_0, 9_0);
/**
* The handle of the collection
*/
@property (nonatomic, strong, readonly) NSString *handle;
/**
* The state of whether the collection is currently published or not
*/
@property (nonatomic, assign, readonly) BOOL published;
/**
* The creation date for the collection
*/
@property (nonatomic, readonly, copy) NSDate *createdAtDate;
/**
* The updated date for the collection
*/
@property (nonatomic, readonly, copy) NSDate *updatedAtDate;
@property (nonatomic, readonly) NSString *stringDescription;
/**
* The publish date for the collection
* Converts the BUYCollectionSort enum to an API-compatible string for the collection sort parameter
*
* @param sort BUYCollectionSort enum
*
* @return API-compatible string for the collection sort parameter
*/
@property (nonatomic, readonly, copy) NSDate *publishedAtDate;
+ (NSString *)sortOrderParameterForCollectionSort:(BUYCollectionSort)sort;
@end
//
// BUYCollection.m
// _BUYCollection.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,35 +25,64 @@
//
#import "BUYCollection.h"
#import "NSDateFormatter+BUYAdditions.h"
#import "NSURL+BUYAdditions.h"
#import "NSDictionary+BUYAdditions.h"
@interface BUYCollection ()
@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) NSString *htmlDescription;
@property (nonatomic, strong) NSString *handle;
@property (nonatomic, assign) BOOL published;
@property (nonatomic, strong) NSNumber *collectionId;
@end
#import "BUYImageLink.h"
#import "NSString+BUYAdditions.h"
@implementation BUYCollection
@synthesize stringDescription=_stringDescription;
- (NSDate *)createdAtDate
{
return self.createdAt;
}
- (NSDate *)updatedAtDate
{
return self.updatedAt;
}
- (NSDate *)publishedAtDate
{
return self.publishedAt;
}
- (NSURL *)imageURL
{
return self.image.sourceURL;
}
- (void)updateStringDescription
{
// Force early cache of this value to prevent spooky behaviour
_stringDescription = [[self.htmlDescription buy_stringByStrippingHTML] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
- (void)setJSONDictionary:(NSDictionary *)JSONDictionary
{
[super setJSONDictionary:JSONDictionary];
[self updateStringDescription];
}
- (void)updateWithDictionary:(NSDictionary *)dictionary
+ (NSString *)sortOrderParameterForCollectionSort:(BUYCollectionSort)sort
{
[super updateWithDictionary:dictionary];
_title = dictionary[@"title"];
_htmlDescription = dictionary[@"body_html"];
_imageURL = [NSURL buy_urlWithString:[dictionary buy_objectForKey:@"image"][@"src"]];
_handle = dictionary[@"handle"];
_published = [dictionary[@"published"] boolValue];
_collectionId = dictionary[@"collection_id"];
NSDateFormatter *dateFormatter = [NSDateFormatter dateFormatterForPublications];
_createdAtDate = [dateFormatter dateFromString:dictionary[@"created_at"]];
_updatedAtDate = [dateFormatter dateFromString:dictionary[@"updated_at"]];
_publishedAtDate = [dateFormatter dateFromString:dictionary[@"published_at"]];
switch (sort) {
case BUYCollectionSortBestSelling:
return @"best-selling";
case BUYCollectionSortCreatedAscending:
return @"created-ascending";
case BUYCollectionSortCreatedDescending:
return @"created-descending";
case BUYCollectionSortPriceAscending:
return @"price-ascending";
case BUYCollectionSortPriceDescending:
return @"price-descending";
case BUYCollectionSortTitleAscending:
return @"title-ascending";
case BUYCollectionSortTitleDescending:
return @"title-descending";
default:
return @"collection-default";
}
}
@end
//
// BUYCollection+Additions.h
// _BUYCustomer.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,18 +24,16 @@
// THE SOFTWARE.
//
#import "BUYCollection.h"
#import "BUYClient.h"
#import <Buy/_BUYCustomer.h>
@interface BUYCollection (Additions)
@interface BUYCustomer : _BUYCustomer {}
/**
* Converts the BUYCollectionSort enum to an API-compatible string for the collection sort parameter
*
* @param sort BUYCollectionSort enum
*
* @return API-compatible string for the collection sort parameter
*/
+(NSString *)sortOrderParameterForCollectionSort:(BUYCollectionSort)sort;
@property (readonly) NSString *fullName;
@end
@interface BUYModelManager (BUYCustomer)
- (BUYCustomer *)customerWithJSONDictionary:(NSDictionary *)json;
@end
//
// BUYCustomer.m
// _BUYCustomer.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,11 +25,11 @@
//
#import "BUYCustomer.h"
#import "BUYAddress.h"
#import "NSDateFormatter+BUYAdditions.h"
@implementation BUYCustomer
@synthesize addresses=_addresses;
- (NSString *)fullName
{
if (self.firstName.length > 0 || self.lastName.length > 0) {
......@@ -38,30 +38,13 @@
return @"";
}
- (void)updateWithDictionary:(NSDictionary *)dictionary
@end
@implementation BUYModelManager (BUYCustomer)
- (BUYCustomer *)customerWithJSONDictionary:(NSDictionary *)json
{
[super updateWithDictionary:dictionary];
NSDateFormatter *formatter = [NSDateFormatter dateFormatterForPublications];
_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 = [formatter dateFromString:dictionary[@"created_at"]];
_updatedAt = [formatter dateFromString:dictionary[@"updated_at"]];
_addresses = [BUYAddress convertJSONArray:dictionary[@"addresses"]];
_defaultAddress = [BUYAddress convertObject:dictionary[@"default_address"]];
NSDictionary *customerDictionary = [json objectForKey:@"customer"];
return (id)[self buy_objectWithEntityName:[BUYCustomer entityName] JSONDictionary:customerDictionary];
}
@end
//
// BUYImageLink.h
// _BUYImageLink.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,41 +24,64 @@
// THE SOFTWARE.
//
#import "BUYObject.h"
#import <Buy/_BUYImageLink.h>
/**
* Products are easier to sell if customers can see pictures of them, which is why there are product images.
*/
@interface BUYImageLink : BUYObject
@import UIKit;
/**
* Specifies the location of the product image.
*/
@property (nonatomic, readonly, copy) NSString *src;
// Defines for common maximum image sizes
typedef NS_ENUM(NSUInteger, BUYImageURLSize) {
BUYImageURLSize100x100,
BUYImageURLSize160x160,
BUYImageURLSize240x240,
BUYImageURLSize480x480,
BUYImageURLSize600x600,
BUYImageURLSize1024x1024,
BUYImageURLSize2048x2048
};
/**
* An array of variant ids associated with the image.
*/
@property (nonatomic, readonly, copy) NSArray<NSNumber *> *variantIds;
@interface BUYImageLink : _BUYImageLink {}
/**
* Creation date of the image
*/
@property (nonatomic, readonly, copy) NSDate *createdAtDate;
@property (nonatomic, readonly, copy) NSDate *updatedAtDate;
@property (nonatomic, readonly) NSString *src NS_DEPRECATED_IOS(8_0, 9_0);
@end
@interface BUYImageLink (BUYImageSizing)
/**
* The date the image was last updated
* Generates a link to the image with the specified size
*
* @param size desired maximum size of the image
*
* @return NSURL to the image resourse
*/
@property (nonatomic, readonly, copy) NSDate *updatedAtDate;
- (NSURL *)imageURLWithSize:(BUYImageURLSize)size;
@end
@interface NSURL (BUYImageSizing)
/**
* The position of the image for the product
* Generates a link to the image with the specified size
*
* @param size desired maximum size of the image
*
* @return NSURL to the image resourse
*/
@property (nonatomic, readonly, copy) NSNumber *position;
- (instancetype)buy_imageURLWithSize:(BUYImageURLSize)size;
@end
@interface UIView (BUYImageSizing)
/**
* The associated product ID for the image
* Determines the optimal size for the image for the given view
*
* @return the size enum value
*/
@property (nonatomic, readonly, copy) NSNumber *productId;
- (BUYImageURLSize)buy_imageSize;
@end
//
// BUYImageLink.m
// _BUYImageLink.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,22 +25,104 @@
//
#import "BUYImageLink.h"
#import "NSDateFormatter+BUYAdditions.h"
#import "NSString+BUYAdditions.h"
#import "NSURL+BUYAdditions.h"
@implementation BUYImageLink
- (void)updateWithDictionary:(NSDictionary *)dictionary
- (NSDate *)createdAtDate
{
[super updateWithDictionary:dictionary];
return self.createdAt;
}
- (NSDate *)updatedAtDate
{
return self.updatedAt;
}
- (NSString *)src
{
return self.sourceURL.absoluteString;
}
@end
@implementation BUYImageLink (BUYImageSizing)
- (NSURL *)imageURLWithSize:(BUYImageURLSize)size
{
return [self.sourceURL buy_imageURLWithSize:size];
}
+ (NSString *)keyForImageSize:(BUYImageURLSize)size
{
NSString *sizeKey = nil;
switch (size) {
case BUYImageURLSize100x100:
sizeKey = @"_small";
break;
case BUYImageURLSize160x160:
sizeKey = @"_compact";
break;
case BUYImageURLSize240x240:
sizeKey = @"_medium";
break;
case BUYImageURLSize480x480:
sizeKey = @"_large";
break;
case BUYImageURLSize600x600:
sizeKey = @"_grande";
break;
case BUYImageURLSize1024x1024:
sizeKey = @"_1024x1024";
break;
case BUYImageURLSize2048x2048:
sizeKey = @"_2048x2048";
break;
}
return sizeKey;
}
@end
#pragma mark -
@implementation NSURL (BUYImageSizing)
- (instancetype)buy_imageURLWithSize:(BUYImageURLSize)size
{
return [self buy_URLByAppendingFileBaseNameSuffix:[BUYImageLink keyForImageSize:size]];
}
@end
#pragma mark -
@implementation UIView (BUYImageSizing)
- (BUYImageURLSize)buy_imageSize
{
CGFloat scale = [[UIScreen mainScreen] scale];
CGFloat maxDimension = MAX(CGRectGetHeight(self.bounds), CGRectGetWidth(self.bounds));
CGFloat pixelSize = scale * maxDimension;
_src = [dictionary[@"src"] copy];
_variantIds = [dictionary[@"variant_ids"] copy];
_productId = [dictionary[@"product_id"] copy];
_position = [dictionary[@"position"] copy];
if (pixelSize <= 100.0) return BUYImageURLSize100x100;
if (pixelSize <= 160.0) return BUYImageURLSize160x160;
if (pixelSize <= 240.0) return BUYImageURLSize240x240;
if (pixelSize <= 480.0) return BUYImageURLSize480x480;
if (pixelSize <= 600.0) return BUYImageURLSize600x600;
if (pixelSize <= 1024.0) return BUYImageURLSize1024x1024;
NSDateFormatter *dateFormatter = [NSDateFormatter dateFormatterForPublications];
_createdAtDate = [dateFormatter dateFromString:dictionary[@"created_at"]];
_updatedAtDate = [dateFormatter dateFromString:dictionary[@"updated_at"]];
return BUYImageURLSize2048x2048;
}
@end
//
// BUYLineItem.h
// _BUYLineItem.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,104 +24,25 @@
// THE SOFTWARE.
//
#import "BUYSerializable.h"
#import "BUYObject.h"
#import <Buy/_BUYLineItem.h>
#import <Buy/BUYModelManager.h>
@class BUYProductVariant;
@class BUYCartLineItem, BUYProductVariant;
/**
* This represents a BUYLineItem on a BUYCart or on a BUYCheckout.
*/
@interface BUYLineItem : BUYObject <BUYSerializable>
@interface BUYLineItem : _BUYLineItem {}
/**
* The unique line item identifier
*/
@property (nonatomic, strong, readonly) NSString *lineItemIdentifier;
- (instancetype)initWithVariant:(BUYProductVariant *)variant NS_DEPRECATED_IOS(8_0, 9_0, "Use `BUYModelManager` to create new instances of model objects instead");
- (instancetype)initWithCartLineItem:(BUYCartLineItem *)cartLineItem NS_DEPRECATED_IOS(8_0, 9_0, "Use `BUYModelManager` to create new instances of model objects instead");
/**
* BUYProductVariant identifer. Keep a reference to a cart or products if you wish to
* display information for product variants in a BUYCheckout
*/
@property (nonatomic, strong, readonly) NSNumber *variantId;
@property (readonly) NSString *lineItemIdentifier NS_DEPRECATED_IOS(8_0, 9_0);
/**
* The `BUYProduct` product ID for the product in the line item
*/
@property (nonatomic, strong, readonly) NSNumber *productId;
/**
* The quantity of the BUYLineItem.
*/
@property (nonatomic, strong) NSDecimalNumber *quantity;
/**
* The weight of the BUYProductVariant in grams.
*/
@property (nonatomic, readonly, strong) NSDecimalNumber *grams;
/**
* The price of the BUYLineItem.
* Note: This price does not need to match the product variant.
*/
@property (nonatomic, strong) NSDecimalNumber *price;
/**
* The line price of the item (price * quantity)
*/
@property (nonatomic, strong) NSDecimalNumber *linePrice;
/**
* The competitor's prices for the same item.
*/
@property (nonatomic, readonly, strong) NSDecimalNumber *compareAtPrice;
/**
* The title of the BUYLineItem.
* Note: The title does not need to match the product variant.
*/
@property (nonatomic, copy) NSString *title;
/**
* The title for the variant in the line item
*/
@property (nonatomic, copy) NSString *variantTitle;
/**
* YES if this BUYLineItem requires shipping.
* Note: This needs to match the product variant.
*/
@property (nonatomic, strong) NSNumber *requiresShipping;
/**
* The unique SKU for the line item
*/
@property (nonatomic, readonly, copy) NSString *sku;
/**
* If the line item is taxable
*/
@property (nonatomic, readonly, assign) BOOL taxable;
@end
/**
* Custom properties set on the line item
*/
@property (nonatomic, copy) NSDictionary *properties;
@class BUYCartLineItem;
/**
* Service provider who is doing the fulfillment
*/
@property (nonatomic, readonly, copy) NSString *fulfillmentService;
@interface BUYModelManager (BUYLineItemCreation)
/**
* Initialize a BUYLineItem with an optional variant.
* Note: We recommend setting up a BUYCart and using `addVariant:`, which handles incrementing
* existing variants for line items in a cart
*
* @param variant A BUYProductVariant to initialize the BUYLineItem with
*
* @return Returns an instance of BUYLineItem
*/
- (instancetype)initWithVariant:(BUYProductVariant *)variant;
- (BUYLineItem *)lineItemWithVariant:(BUYProductVariant *)variant;
- (BUYLineItem *)lineItemWithCartLineItem:(BUYCartLineItem *)cartLineItem;
@end
//
// BUYLineItem.m
// _BUYLineItem.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -20,96 +20,75 @@
// 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 "BUYLineItem.h"
#import "BUYCartLineItem.h"
#import "BUYProductVariant.h"
#import "NSDecimalNumber+BUYAdditions.h"
#import "NSString+BUYAdditions.h"
#import "BUYProduct.h"
@interface BUYLineItem ()
@implementation BUYLineItem
@property (nonatomic, strong) NSString *lineItemIdentifier;
@property (nonatomic, strong) NSNumber *variantId;
@property (nonatomic, strong) NSNumber *productId;
@property (nonatomic, copy) NSString *sku;
@property (nonatomic, readwrite) BOOL taxable;
@property (nonatomic, strong) NSDecimalNumber *compareAtPrice;
@property (nonatomic, strong) NSDecimalNumber *grams;
@property (nonatomic, copy) NSString *fulfillmentService;
/**
* Have model manager responsible for instantiation, and allow deprecated
* initializers for backwards compatability
*/
- (instancetype)initWithCartLineItem:(BUYCartLineItem *)cartLineItem
{
BUYLineItem *lineItem = [[BUYLineItem alloc] initWithModelManager:cartLineItem.modelManager JSONDictionary:nil];
[lineItem updateWithLineItem:cartLineItem];
return lineItem;
}
@end
- (instancetype)initWithVariant:(BUYProductVariant *)variant
{
BUYLineItem *lineItem = [[BUYLineItem alloc] initWithModelManager:variant.modelManager JSONDictionary:nil];
[lineItem updateWithVariant:variant];
return lineItem;
}
@implementation BUYLineItem
- (void)updateWithVariant:(BUYProductVariant *)variant
{
self.variantId = variant.identifier;
self.quantity = variant ? [NSDecimalNumber one] : [NSDecimalNumber zero];
self.price = variant.price ?: [NSDecimalNumber zero];
self.title = variant.title ?: @"";
self.requiresShipping = variant.requiresShipping;
self.compareAtPrice = variant.compareAtPrice;
self.grams = variant.grams;
}
- (instancetype)init
- (void)updateWithLineItem:(BUYCartLineItem *)lineItem
{
return [self initWithVariant:nil];
[self updateWithVariant:lineItem.variant];
self.quantity = lineItem.quantity;
}
- (instancetype)initWithVariant:(BUYProductVariant *)variant
- (NSString *)lineItemIdentifier
{
self = [super init];
if (self) {
self.variantId = variant.identifier;
self.productId = variant.product.productId;
self.quantity = variant ? [NSDecimalNumber one] : [NSDecimalNumber zero];
self.price = variant ? [variant price] : [NSDecimalNumber zero];
self.title = variant ? [variant title] : @"";
self.requiresShipping = variant.requiresShipping;
self.compareAtPrice = variant.compareAtPrice;
self.grams = variant.grams;
}
return self;
return self.identifier;
}
- (void)updateWithDictionary:(NSDictionary *)dictionary
@end
@implementation BUYModelManager (BUYLineItemCreation)
- (BUYLineItem *)lineItemWithVariant:(BUYProductVariant *)variant
{
self.lineItemIdentifier = dictionary[@"id"];
self.variantId = dictionary[@"variant_id"];
self.productId = dictionary[@"product_id"];
self.title = dictionary[@"title"];
self.variantTitle = dictionary[@"variant_title"];
self.quantity = [NSDecimalNumber buy_decimalNumberFromJSON:dictionary[@"quantity"]];
self.price = [NSDecimalNumber buy_decimalNumberFromJSON:dictionary[@"price"]];
self.linePrice = [NSDecimalNumber buy_decimalNumberFromJSON:dictionary[@"line_price"]];
self.compareAtPrice = [NSDecimalNumber buy_decimalNumberFromJSON:dictionary[@"compare_at_price"]];
self.requiresShipping = dictionary[@"requires_shipping"];
self.sku = dictionary[@"sku"];
self.taxable = [dictionary[@"taxable"] boolValue];
self.properties = dictionary[@"properties"];
self.grams = [NSDecimalNumber buy_decimalNumberFromJSON:dictionary[@"grams"]];
self.fulfillmentService = [dictionary[@"fulfillment_service"] copy];
BUYLineItem *lineItem = [self insertLineItemWithJSONDictionary:nil];
[lineItem updateWithVariant:variant];
return lineItem;
}
- (NSDictionary *)jsonDictionaryForCheckout
- (BUYLineItem *)lineItemWithCartLineItem:(BUYCartLineItem *)cartLineItem
{
NSMutableDictionary *lineItem = [[NSMutableDictionary alloc] init];
if (self.variantId) {
lineItem[@"variant_id"] = self.variantId;
}
if ([self.title length] > 0) {
lineItem[@"title"] = [self.title buy_trim];
}
if (self.quantity) {
lineItem[@"quantity"] = self.quantity;
}
if (self.price) {
lineItem[@"price"] = self.price;
}
if (self.properties) {
lineItem[@"properties"] = self.properties;
}
lineItem[@"requires_shipping"] = self.requiresShipping ?: @NO;
BUYLineItem *lineItem = [self insertLineItemWithJSONDictionary:nil];
[lineItem updateWithLineItem:cartLineItem];
return lineItem;
}
......
//
// BUYOption.h
// _BUYOption.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,27 +24,8 @@
// THE SOFTWARE.
//
#import "BUYObject.h"
#import <Buy/_BUYOption.h>
/**
* This represent a BUYOption on a BUYProduct
*/
@interface BUYOption : BUYObject
/**
* Custom product property names like "Size", "Color", and "Material".
* 255 characters limit each.
*/
@property (nonatomic, readonly, copy) NSString *name;
/**
* The order in which the option should optionally appear
*/
@property (nonatomic, readonly, strong) NSNumber *position;
/**
* The associated product ID for this option
*/
@property (nonatomic, readonly, copy) NSNumber *productId;
@interface BUYOption : _BUYOption {}
@end
//
// BUYOption.m
// _BUYOption.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -28,13 +28,4 @@
@implementation BUYOption
- (void)updateWithDictionary:(NSDictionary *)dictionary
{
[super updateWithDictionary:dictionary];
_name = [dictionary[@"name"] copy];
_position = dictionary[@"position"];
_productId = [dictionary[@"product_id"] copy];
}
@end
//
// BUYOptionValue.h
// _BUYOptionValue.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,24 +24,10 @@
// THE SOFTWARE.
//
#import "BUYObject.h"
#import <Buy/_BUYOptionValue.h>
@interface BUYOptionValue : BUYObject
@interface BUYOptionValue : _BUYOptionValue {}
/**
* Custom product property names like "Size", "Color", and "Material".
* 255 characters limit each.
*/
@property (nonatomic, readonly, copy) NSString *name;
/**
* The value of the option
*/
@property (nonatomic, readonly, strong) NSString *value;
/**
* the option identifier
*/
@property (nonatomic, readonly, strong) NSNumber *optionId;
- (BOOL)isEqualToOptionValue:(BUYOptionValue *)other;
@end
//
// BUYOptionValue.m
// _BUYOptionValue.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -28,37 +28,22 @@
@implementation BUYOptionValue
- (void)updateWithDictionary:(NSDictionary *)dictionary
- (BOOL)isEqualToOptionValue:(BUYOptionValue *)other
{
[super updateWithDictionary:dictionary];
_name = [dictionary[@"name"] copy];
_value = [dictionary[@"value"] copy];
_optionId = [dictionary[@"option_id"] copy];
return [other isKindOfClass:[self class]] && [self.name isEqual:other.name] && [self.optionId isEqual:other.optionId];
}
#if !defined CORE_DATA_PERSISTENCE
- (BOOL)isEqual:(id)object
{
BOOL same = NO;
if (self == object) {
same = YES;
}
else if ([object isKindOfClass:self.class]) {
BUYOptionValue *optionValue = (BUYOptionValue *)object;
same = ([self.optionId isEqualToNumber:optionValue.optionId] &&
[self.value isEqualToString:optionValue.value]);
}
return same;
return [super isEqual:object] || [self isEqualToOptionValue:object];
}
- (NSUInteger)hash
{
NSUInteger hash = [self.value hash];
hash ^= [self.optionId hash];
return hash;
NSUInteger hash = self.name.hash;
return ((hash << 5) + hash) + self.optionId.hash;
}
#endif
@end
......@@ -24,137 +24,15 @@
// THE SOFTWARE.
//
#import "BUYObject.h"
#import <Buy/_BUYOrder.h>
@class BUYAddress;
@class BUYLineItem;
@class BUYShippingRate;
@class BUYLineItem;
@interface BUYOrder : _BUYOrder {}
@interface BUYOrder : BUYObject
/**
* Whether the order was cancelled or not.
*/
@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.
*/
@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;
@end
/**
* An array of fulfilled line item objects.
*/
@property (nonatomic, strong, readonly) NSArray<BUYLineItem *> *fulfilledLineItems;
@interface BUYModelManager (BUYOrder)
/**
* An array of unfulfilled line item objects.
*/
@property (nonatomic, strong, readonly) NSArray<BUYLineItem *> *unfulfilledLineItems;
- (NSArray<BUYOrder *> *)ordersWithJSONDictionary:(NSDictionary *)json;
@end
//
// BUYOrder.m
// _BUYOrder.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,48 +25,53 @@
//
#import "BUYOrder.h"
#import "BUYAddress.h"
#import "BUYLineItem.h"
#import "BUYShippingRate.h"
#import "NSURL+BUYAdditions.h"
#import "NSDictionary+BUYAdditions.h"
#import "NSDateFormatter+BUYAdditions.h"
#import "NSDecimalNumber+BUYAdditions.h"
@implementation BUYOrder
- (void)updateWithDictionary:(NSDictionary *)dictionary
- (NSArray *)formatIDsForLineItemsJSON:(NSArray<NSDictionary *> *)lineItems
{
[super updateWithDictionary:dictionary];
NSDateFormatter *formatter = [NSDateFormatter dateFormatterForPublications];
_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"];
__block NSMutableArray<NSDictionary *> *mutableLineItems = [NSMutableArray array];
[lineItems enumerateObjectsUsingBlock:^(NSDictionary * _Nonnull lineItem, NSUInteger idx, BOOL * _Nonnull stop) {
NSNumber *identifier = lineItem[@"id"];
NSMutableDictionary *mutableLineItem = [lineItem mutableCopy];
if ([identifier isKindOfClass:[NSNumber class]]) {
mutableLineItem[@"id"] = identifier.stringValue;
}
[mutableLineItems addObject:mutableLineItem];
}];
return mutableLineItems;
}
- (void)setJSONDictionary:(NSDictionary *)JSONDictionary
{
// TODO: Have API return string IDs for line items instead of numbers
NSArray *fulfilledLineItemsJSON = [self formatIDsForLineItemsJSON:JSONDictionary[@"fulfilled_line_items"]];
NSArray *unFulfilledLineItemsJSON = [self formatIDsForLineItemsJSON:JSONDictionary[@"unfulfilled_line_items"]];
_statusURL = [NSURL buy_urlWithString:dictionary[@"status_url"]];
_customerURL = [NSURL buy_urlWithString:dictionary[@"customer_url"]];
_orderStatusURL = [NSURL buy_urlWithString:dictionary[@"order_status_url"]];
[super setJSONDictionary:JSONDictionary];
_cancelledAt = [formatter dateFromString:[dictionary buy_objectForKey:@"cancelled_at"]];
_processedAt = [formatter dateFromString:[dictionary buy_objectForKey:@"processed_at"]];
// Required if core data is not being used
if (!self.lineItems) {
self.lineItems = [NSOrderedSet orderedSet];
}
_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"]];
NSArray *fulfilledLineItems = [self.modelManager buy_objectsWithEntityName:[BUYLineItem entityName] JSONArray:fulfilledLineItemsJSON];
[fulfilledLineItems makeObjectsPerformSelector:@selector(setFulfilled:) withObject:@YES];
NSArray *unfulfilledLineItems = [self.modelManager buy_objectsWithEntityName:[BUYLineItem entityName] JSONArray:unFulfilledLineItemsJSON];
_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"]];
[self.lineItemsSet addObjectsFromArray:fulfilledLineItems];
[self.lineItemsSet addObjectsFromArray:unfulfilledLineItems];
}
@end
@implementation BUYModelManager (BUYOrder)
- (NSArray<BUYOrder *> *)ordersWithJSONDictionary:(NSDictionary *)json
{
NSArray *orders = [json objectForKey:@"orders"];
return (id)[self buy_objectsWithEntityName:[BUYOrder entityName] JSONArray:orders];
}
@end
......@@ -24,94 +24,42 @@
// THE SOFTWARE.
//
#import "BUYObject.h"
#import <Buy/_BUYProduct.h>
@class BUYProductVariant;
@class BUYImageLink;
@class BUYOption;
@interface BUYProduct : _BUYProduct {}
/**
* A BUYProduct is an individual item for sale in a Shopify shop.
*/
@interface BUYProduct : BUYObject
/**
* The product ID
*/
@property (nonatomic, readonly, copy) NSNumber *productId;
/**
* The name of the product. In a shop's catalog, clicking on a product's title takes you to that product's page.
* On a product's page, the product's title typically appears in a large font.
*/
@property (nonatomic, readonly, copy) NSString *title;
/**
* The handle of the product. Can be used to construct links to the web page for the product
*/
@property (nonatomic, readonly, copy) NSString *handle;
/**
* The name of the vendor of the product.
*/
@property (nonatomic, readonly, copy) NSString *vendor;
/**
* A categorization that a product can be tagged with, commonly used for filtering and searching.
*/
@property (nonatomic, readonly, copy) NSString *productType;
/**
* A list of BUYProductVariant objects, each one representing a slightly different version of the product.
*/
@property (nonatomic, readonly, copy) NSArray<BUYProductVariant *> *variants;
/**
* A list of BUYImageLink objects, each one representing an image associated with the product.
*/
@property (nonatomic, readonly, copy) NSArray<BUYImageLink *> *images;
/**
* Custom product property names like "Size", "Color", and "Material".
* Products are based on permutations of these options.
* A product may have a maximum of 3 options. 255 characters limit each.
*/
@property (nonatomic, readonly, copy) NSArray<BUYOption *> *options;
/**
* The description of the product, complete with HTML formatting.
*/
@property (nonatomic, readonly, copy) NSString *htmlDescription;
/**
* If the product is in stock (see each variant for their specific availability)
*/
@property (nonatomic, readonly, assign) BOOL available;
@property (nonatomic, readonly, copy) NSDate *createdAtDate;
@property (nonatomic, readonly, copy) NSDate *updatedAtDate;
@property (nonatomic, readonly, copy) NSDate *publishedAtDate;
@property (nonatomic, readonly, copy) NSString *stringDescription;
/**
* A categorization that a product can be tagged with, commonly used for filtering and searching.
* Each tag has a character limit of 255.
*/
@property (nonatomic, readonly, copy) NSSet<NSString *> *tags;
@end
/**
* The product is published on the current sales channel
*/
@property (nonatomic, readonly, assign) BOOL published;
@interface BUYProduct (Options)
/**
* The creation date for a product
* Get the option values available for the given option
*
* @param option the option
*
* @return array of BUYOptionValues
*/
@property (nonatomic, readonly, copy) NSDate *createdAtDate;
- (NSArray *)valuesForOption:(BUYOption *)option variants:(NSArray *)variants;
/**
* The updated date for a product
* Determine the variant given an array of options
*
* @param options array of option values
*
* @return the product variant matching the set of options
*/
@property (nonatomic, readonly, copy) NSDate *updatedAtDate;
- (BUYProductVariant *)variantWithOptions:(NSArray *)options;
/**
* The publish date for a product
* Determine if the variant is a default variant automatically created by Shopify
*
* @return YES if its a default variant
*/
@property (nonatomic, readonly, copy) NSDate *publishedAtDate;
- (BOOL)isDefaultVariant;
@end
//
// BUYProduct.m
// _BUYProduct.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,39 +24,94 @@
// THE SOFTWARE.
//
#import "BUYImageLink.h"
#import "BUYOption.h"
#import "BUYProduct.h"
#import "BUYModelManager.h"
#import "BUYOption.h"
#import "BUYOptionValue.h"
#import "BUYProductVariant.h"
#import "NSDateFormatter+BUYAdditions.h"
#import "NSDictionary+BUYAdditions.h"
#import "NSString+BUYAdditions.h"
@implementation BUYProduct
- (void)updateWithDictionary:(NSDictionary *)dictionary
@synthesize stringDescription=_stringDescription;
- (NSDate *)createdAtDate
{
return self.createdAt;
}
- (NSDate *)updatedAtDate
{
return self.updatedAt;
}
- (NSDate *)publishedAtDate
{
[super updateWithDictionary:dictionary];
return self.publishedAt;
}
- (NSString *)stringDescription
{
if (nil == _stringDescription) {
_stringDescription = [self.htmlDescription buy_stringByStrippingHTML];
}
return _stringDescription;
}
@end
@implementation BUYProduct (Options)
- (NSArray *)valuesForOption:(BUYOption *)option variants:(NSArray *)variants
{
NSMutableOrderedSet *set = [NSMutableOrderedSet new];
_title = [dictionary[@"title"] copy];
_handle = [dictionary[@"handle"] copy];
_productId = [dictionary[@"product_id"] copy];
_vendor = [dictionary[@"vendor"] copy];
_productType = [dictionary[@"product_type"] copy];
_variants = [BUYProductVariant convertJSONArray:dictionary[@"variants"] block:^(BUYProductVariant *variant) {
variant.product = self;
}];
_images = [BUYImageLink convertJSONArray:dictionary[@"images"]];
_options = [BUYOption convertJSONArray:dictionary[@"options"]];
_htmlDescription = [dictionary buy_objectForKey:@"body_html"];
_available = [dictionary[@"available"] boolValue];
_published = [dictionary[@"published"] boolValue];
NSDateFormatter *dateFormatter = [NSDateFormatter dateFormatterForPublications];
_createdAtDate = [dateFormatter dateFromString:dictionary[@"created_at"]];
_updatedAtDate = [dateFormatter dateFromString:dictionary[@"updated_at"]];
_publishedAtDate = [dateFormatter dateFromString:dictionary[@"published_at"]];
NSArray *tagsArray = [dictionary[@"tags"] componentsSeparatedByString:@", "];
NSSet *tagsSet = [NSSet setWithArray:tagsArray];
_tags = [tagsSet copy];
for (BUYProductVariant *variant in variants) {
BUYOptionValue *optionValue = [variant optionValueForName:option.name];
[set addObject:optionValue];
}
return [set array];
}
- (BUYProductVariant *)variantWithOptions:(NSArray *)options
{
BUYProductVariant *variant = nil;
for (BUYProductVariant *aVariant in self.variants) {
BOOL match = YES;
for (BUYOptionValue *value in options) {
BUYOptionValue *optionValue = [aVariant optionValueForName:value.name];
if (![optionValue isEqual:value]) {
match = NO;
break;
}
}
if (match) {
variant = aVariant;
}
}
return variant;
}
- (BOOL)isDefaultVariant
{
if ([self.variants count] == 1) {
BUYProductVariant *productVariant = [self.variants firstObject];
BUYOptionValue *optionValue = [productVariant.options anyObject];
NSString *defaultTitleString = @"Default Title";
NSString *defaultString = @"Default";
if ([productVariant.title isEqualToString:defaultTitleString] &&
([optionValue.value isEqualToString:defaultTitleString] || [optionValue.value isEqualToString:defaultString])) {
return YES;
}
}
return NO;
}
@end
//
// BUYProductVariant.h
// _BUYProductVariant.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,72 +24,29 @@
// THE SOFTWARE.
//
#import "BUYObject.h"
#import <Buy/_BUYProductVariant.h>
@class BUYProduct;
@class BUYOptionValue;
/**
* A BUYProductVariant is a different version of a product, such as differing sizes or differing colours.
*/
@interface BUYProductVariant : BUYObject
/**
* The BUYProduct associated this BUYProductVariant
*/
@property (nonatomic, strong) BUYProduct *product;
/**
* The title of the BUYProductVariant.
*/
@property (nonatomic, readonly, copy) NSString *title;
/**
* Custom properties that a shop owner can use to define BUYProductVariants.
*/
@property (nonatomic, readonly, copy) NSArray<BUYOptionValue *> *options;
/**
* The price of the BUYProductVariant.
*/
@property (nonatomic, readonly, strong) NSDecimalNumber *price;
/**
* The competitor's prices for the same item.
*/
@property (nonatomic, readonly, strong) NSDecimalNumber *compareAtPrice;
/**
* The weight of the BUYProductVariant in grams.
*/
@property (nonatomic, readonly, strong) NSDecimalNumber *grams;
/**
* Specifies whether or not a customer needs to provide a shipping address when placing an order for this BUYProductVariant.
* Valid values are:
* true: Customer needs to supply a shipping address.
* false: Customer does not need to supply a shipping address.
*/
@property (nonatomic, readonly, strong) NSNumber *requiresShipping;
/**
* A unique identifier for the product in the shop.
*/
@property (nonatomic, readonly, strong) NSString *sku;
/**
* Specifies whether or not a tax is charged when the BUYProductVariant is sold.
*/
@property (nonatomic, readonly, strong) NSNumber *taxable;
@interface BUYProductVariant : _BUYProductVariant {}
/**
* The order of the BUYProductVariant in the list of product variants. 1 is the first position.
* Returns the option value for the given name
*
* @param optionName name of the option
*
* @return the option value
*/
@property (nonatomic, readonly, strong) NSNumber *position;
- (BUYOptionValue *)optionValueForName:(NSString *)optionName;
/**
* If the variant is in stock
* Filters array of product variants filtered based on a selected option value
*
* @param productVariants BUYProductVariant objects to filter
* @param optionValue The option value to filter with
*
* @return A filtered copy of the original array
*/
@property (nonatomic, readonly, assign) BOOL available;
+ (NSArray *)filterProductVariants:(NSArray *)productVariants forOptionValue:(BUYOptionValue *)optionValue;
@end
//
// BUYProductVariant.m
// _BUYProductVariant.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -25,29 +25,32 @@
//
#import "BUYProductVariant.h"
#import "NSDecimalNumber+BUYAdditions.h"
#import "BUYOptionValue.h"
@implementation BUYProductVariant
- (void)updateWithDictionary:(NSDictionary *)dictionary
- (BUYOptionValue *)optionValueForName:(NSString *)optionName
{
[super updateWithDictionary:dictionary];
for (BUYOptionValue *value in self.options) {
if ([value.name isEqualToString:optionName]) {
return value;
}
}
_title = [dictionary[@"title"] copy];
_options = [BUYOptionValue convertJSONArray:dictionary[@"option_values"]];
_price = [NSDecimalNumber buy_decimalNumberFromJSON:dictionary[@"price"]];
_compareAtPrice = [NSDecimalNumber buy_decimalNumberFromJSON:dictionary[@"compare_at_price"]];
_grams = [NSDecimalNumber buy_decimalNumberFromJSON:dictionary[@"grams"]];
_requiresShipping = dictionary[@"requires_shipping"];
_sku = dictionary[@"sku"];
_taxable = dictionary[@"taxable"];
_position = dictionary[@"position"];
_available = [dictionary[@"available"] boolValue];
return nil;
}
+ (NSArray *)filterProductVariants:(NSArray *)productVariants forOptionValue:(BUYOptionValue *)optionValue
{
NSMutableArray *filteredArray = [NSMutableArray new];
for (BUYProductVariant *variant in productVariants) {
for (BUYOptionValue *opValue in variant.options) {
if ([opValue isEqual:optionValue]) {
[filteredArray addObject:variant];
}
}
}
return [filteredArray copy];
}
@end
//
// BUYShop.h
// _BUYShop.h
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -24,66 +24,8 @@
// THE SOFTWARE.
//
#import "BUYObject.h"
#import <Buy/_BUYShop.h>
/**
* The BUYShop object is a collection of the general settings and information about the shop.
*/
@interface BUYShop : BUYObject
/**
* The name of the shop.
*/
@property (nonatomic, readonly, copy) NSString *name;
/**
* The city in which the shop is located.
*/
@property (nonatomic, readonly, copy) NSString *city;
/**
* The shop's normalized province or state name.
*/
@property (nonatomic, readonly, copy) NSString *province;
/**
* The country in which the shop is located
*/
@property (nonatomic, readonly, copy) NSString *country;
/**
* The three-letter code for the currency that the shop accepts.
*/
@property (nonatomic, readonly, copy) NSString *currency;
/**
* A string representing the way currency is formatted when the currency isn't specified.
*/
@property (nonatomic, readonly, copy) NSString *moneyFormat;
/**
* The shop's domain.
*/
@property (nonatomic, readonly, copy) NSString *domain;
/**
* The shop's description.
*/
@property (nonatomic, readonly, copy) NSString *shopDescription;
/**
* A list of two-letter country codes identifying the countries that the shop ships to.
*/
@property (nonatomic, readonly, copy) NSArray<NSString *> *shipsToCountries;
/**
* The URL for the web storefront
*/
@property (nonatomic, readonly) NSURL *shopURL;
/**
* The shop's 'myshopify.com' domain.
*/
@property (nonatomic, readonly) NSURL *myShopifyURL;
@interface BUYShop : _BUYShop {}
@end
//
// BUYShop.m
// _BUYShop.m
// Mobile Buy SDK
//
// Created by Shopify.
......@@ -28,21 +28,4 @@
@implementation BUYShop
- (void)updateWithDictionary:(NSDictionary *)dictionary
{
[super updateWithDictionary:dictionary];
_name = [dictionary[@"name"] copy];
_city = [dictionary[@"city"] copy];
_country = [dictionary[@"country"] copy];
_province = [dictionary[@"province"] copy];
_currency = [dictionary[@"currency"] copy];
_moneyFormat = [dictionary[@"money_format"] copy];
_domain = [dictionary[@"domain"] copy];
_shopDescription = [dictionary[@"description"] copy];
_shipsToCountries = [dictionary[@"ships_to_countries"] copy];
_shopURL = [NSURL URLWithString:dictionary[@"url"]];
_myShopifyURL = [NSURL URLWithString:dictionary[@"myshopify_domain"]];
}
@end
//
// _BUYAddress.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.
//
// DO NOT EDIT. This file is machine-generated and constantly overwritten.
// Make changes to BUYAddress.h instead.
#import <Buy/BUYManagedObject.h>
#import "BUYModelManager.h"
extern const struct BUYAddressAttributes {
__unsafe_unretained NSString *address1;
__unsafe_unretained NSString *address2;
__unsafe_unretained NSString *city;
__unsafe_unretained NSString *company;
__unsafe_unretained NSString *country;
__unsafe_unretained NSString *countryCode;
__unsafe_unretained NSString *firstName;
__unsafe_unretained NSString *lastName;
__unsafe_unretained NSString *phone;
__unsafe_unretained NSString *province;
__unsafe_unretained NSString *provinceCode;
__unsafe_unretained NSString *zip;
} BUYAddressAttributes;
extern const struct BUYAddressRelationships {
__unsafe_unretained NSString *customer;
} BUYAddressRelationships;
extern const struct BUYAddressUserInfo {
__unsafe_unretained NSString *documentation;
} BUYAddressUserInfo;
@class BUYCustomer;
@class BUYAddress;
@interface BUYModelManager (BUYAddressInserting)
- (NSArray<BUYAddress *> *)allAddressObjects;
- (BUYAddress *)fetchAddressWithIdentifierValue:(int64_t)identifier;
- (BUYAddress *)insertAddressWithJSONDictionary:(NSDictionary *)dictionary;
- (NSArray<BUYAddress *> *)insertAddresssWithJSONArray:(NSArray <NSDictionary *> *)array;
@end
/**
* A BUYAddress represents a shipping or billing address on an order. This will be associated with the customer upon completion.
*/
@interface _BUYAddress : BUYCachedObject
+ (NSString *)entityName;
/**
* The street address of the address.
*/
@property (nonatomic, strong) NSString* address1;
/**
* An optional additional field for the street address of the address.
*/
@property (nonatomic, strong) NSString* address2;
/**
* The city of the address.
*/
@property (nonatomic, strong) NSString* city;
/**
* The company of the person associated with the address (optional).
*/
@property (nonatomic, strong) NSString* company;
/**
* The name of the country of the address.
*/
@property (nonatomic, strong) NSString* country;
/**
* The two-letter code (ISO 3166-1 alpha-2 two-letter country code) for the country of the address.
*/
@property (nonatomic, strong) NSString* countryCode;
/**
* The first name of the person associated with the payment method.
*/
@property (nonatomic, strong) NSString* firstName;
/**
* The last name of the person associated with the payment method.
*/
@property (nonatomic, strong) NSString* lastName;
/**
* The phone number at the address.
*/
@property (nonatomic, strong) NSString* phone;
/**
* The name of the state or province of the address
*/
@property (nonatomic, strong) NSString* province;
/**
* The two-letter abbreviation of the state or province of the address.
*/
@property (nonatomic, strong) NSString* provinceCode;
/**
* The zip or postal code of the address.
*/
@property (nonatomic, strong) NSString* zip;
@property (nonatomic, strong) BUYCustomer *customer;
@end
@interface _BUYAddress (CoreDataGeneratedPrimitiveAccessors)
- (NSString*)primitiveAddress1;
- (void)setPrimitiveAddress1:(NSString*)value;
- (NSString*)primitiveAddress2;
- (void)setPrimitiveAddress2:(NSString*)value;
- (NSString*)primitiveCity;
- (void)setPrimitiveCity:(NSString*)value;
- (NSString*)primitiveCompany;
- (void)setPrimitiveCompany:(NSString*)value;
- (NSString*)primitiveCountry;
- (void)setPrimitiveCountry:(NSString*)value;
- (NSString*)primitiveCountryCode;
- (void)setPrimitiveCountryCode:(NSString*)value;
- (NSString*)primitiveFirstName;
- (void)setPrimitiveFirstName:(NSString*)value;
- (NSString*)primitiveLastName;
- (void)setPrimitiveLastName:(NSString*)value;
- (NSString*)primitivePhone;
- (void)setPrimitivePhone:(NSString*)value;
- (NSString*)primitiveProvince;
- (void)setPrimitiveProvince:(NSString*)value;
- (NSString*)primitiveProvinceCode;
- (void)setPrimitiveProvinceCode:(NSString*)value;
- (NSString*)primitiveZip;
- (void)setPrimitiveZip:(NSString*)value;
- (BUYCustomer *)primitiveCustomer;
- (void)setPrimitiveCustomer:(BUYCustomer *)value;
@end
//
// _BUYAddress.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.
//
// DO NOT EDIT. This file is machine-generated and constantly overwritten.
// Make changes to BUYAddress.m instead.
#import "_BUYAddress.h"
const struct BUYAddressAttributes BUYAddressAttributes = {
.address1 = @"address1",
.address2 = @"address2",
.city = @"city",
.company = @"company",
.country = @"country",
.countryCode = @"countryCode",
.firstName = @"firstName",
.lastName = @"lastName",
.phone = @"phone",
.province = @"province",
.provinceCode = @"provinceCode",
.zip = @"zip",
};
const struct BUYAddressRelationships BUYAddressRelationships = {
.customer = @"customer",
};
const struct BUYAddressUserInfo BUYAddressUserInfo = {
.documentation = @"A BUYAddress represents a shipping or billing address on an order. This will be associated with the customer upon completion.",
};
@implementation _BUYAddress
+ (NSString *)entityName {
return @"Address";
}
+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {
NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
return keyPaths;
}
#if defined CORE_DATA_PERSISTENCE
- (NSString*)address1 {
[self willAccessValueForKey:@"address1"];
id value = [self primitiveValueForKey:@"address1"];
[self didAccessValueForKey:@"address1"];
return value;
}
- (void)setAddress1:(NSString*)value_ {
[self willChangeValueForKey:@"address1"];
[self setPrimitiveValue:value_ forKey:@"address1"];
[self didChangeValueForKey:@"address1"];
}
- (NSString*)address2 {
[self willAccessValueForKey:@"address2"];
id value = [self primitiveValueForKey:@"address2"];
[self didAccessValueForKey:@"address2"];
return value;
}
- (void)setAddress2:(NSString*)value_ {
[self willChangeValueForKey:@"address2"];
[self setPrimitiveValue:value_ forKey:@"address2"];
[self didChangeValueForKey:@"address2"];
}
- (NSString*)city {
[self willAccessValueForKey:@"city"];
id value = [self primitiveValueForKey:@"city"];
[self didAccessValueForKey:@"city"];
return value;
}
- (void)setCity:(NSString*)value_ {
[self willChangeValueForKey:@"city"];
[self setPrimitiveValue:value_ forKey:@"city"];
[self didChangeValueForKey:@"city"];
}
- (NSString*)company {
[self willAccessValueForKey:@"company"];
id value = [self primitiveValueForKey:@"company"];
[self didAccessValueForKey:@"company"];
return value;
}
- (void)setCompany:(NSString*)value_ {
[self willChangeValueForKey:@"company"];
[self setPrimitiveValue:value_ forKey:@"company"];
[self didChangeValueForKey:@"company"];
}
- (NSString*)country {
[self willAccessValueForKey:@"country"];
id value = [self primitiveValueForKey:@"country"];
[self didAccessValueForKey:@"country"];
return value;
}
- (void)setCountry:(NSString*)value_ {
[self willChangeValueForKey:@"country"];
[self setPrimitiveValue:value_ forKey:@"country"];
[self didChangeValueForKey:@"country"];
}
- (NSString*)countryCode {
[self willAccessValueForKey:@"countryCode"];
id value = [self primitiveValueForKey:@"countryCode"];
[self didAccessValueForKey:@"countryCode"];
return value;
}
- (void)setCountryCode:(NSString*)value_ {
[self willChangeValueForKey:@"countryCode"];
[self setPrimitiveValue:value_ forKey:@"countryCode"];
[self didChangeValueForKey:@"countryCode"];
}
- (NSString*)firstName {
[self willAccessValueForKey:@"firstName"];
id value = [self primitiveValueForKey:@"firstName"];
[self didAccessValueForKey:@"firstName"];
return value;
}
- (void)setFirstName:(NSString*)value_ {
[self willChangeValueForKey:@"firstName"];
[self setPrimitiveValue:value_ forKey:@"firstName"];
[self didChangeValueForKey:@"firstName"];
}
- (NSString*)lastName {
[self willAccessValueForKey:@"lastName"];
id value = [self primitiveValueForKey:@"lastName"];
[self didAccessValueForKey:@"lastName"];
return value;
}
- (void)setLastName:(NSString*)value_ {
[self willChangeValueForKey:@"lastName"];
[self setPrimitiveValue:value_ forKey:@"lastName"];
[self didChangeValueForKey:@"lastName"];
}
- (NSString*)phone {
[self willAccessValueForKey:@"phone"];
id value = [self primitiveValueForKey:@"phone"];
[self didAccessValueForKey:@"phone"];
return value;
}
- (void)setPhone:(NSString*)value_ {
[self willChangeValueForKey:@"phone"];
[self setPrimitiveValue:value_ forKey:@"phone"];
[self didChangeValueForKey:@"phone"];
}
- (NSString*)province {
[self willAccessValueForKey:@"province"];
id value = [self primitiveValueForKey:@"province"];
[self didAccessValueForKey:@"province"];
return value;
}
- (void)setProvince:(NSString*)value_ {
[self willChangeValueForKey:@"province"];
[self setPrimitiveValue:value_ forKey:@"province"];
[self didChangeValueForKey:@"province"];
}
- (NSString*)provinceCode {
[self willAccessValueForKey:@"provinceCode"];
id value = [self primitiveValueForKey:@"provinceCode"];
[self didAccessValueForKey:@"provinceCode"];
return value;
}
- (void)setProvinceCode:(NSString*)value_ {
[self willChangeValueForKey:@"provinceCode"];
[self setPrimitiveValue:value_ forKey:@"provinceCode"];
[self didChangeValueForKey:@"provinceCode"];
}
- (NSString*)zip {
[self willAccessValueForKey:@"zip"];
id value = [self primitiveValueForKey:@"zip"];
[self didAccessValueForKey:@"zip"];
return value;
}
- (void)setZip:(NSString*)value_ {
[self willChangeValueForKey:@"zip"];
[self setPrimitiveValue:value_ forKey:@"zip"];
[self didChangeValueForKey:@"zip"];
}
#endif
#if defined CORE_DATA_PERSISTENCE
@dynamic customer;
#endif
@end
#pragma mark -
@implementation BUYModelManager (BUYAddressInserting)
- (BUYAddress *)insertAddressWithJSONDictionary:(NSDictionary *)dictionary
{
return (BUYAddress *)[self buy_objectWithEntityName:@"Address" JSONDictionary:dictionary];
}
- (NSArray<BUYAddress *> *)insertAddresssWithJSONArray:(NSArray <NSDictionary *> *)array
{
return (NSArray<BUYAddress *> *)[self buy_objectsWithEntityName:@"Address" JSONArray:array];
}
- (NSArray<BUYAddress *> *)allAddressObjects
{
return (NSArray<BUYAddress *> *)[self buy_objectsWithEntityName:@"Address" identifiers:nil];
}
- (BUYAddress *)fetchAddressWithIdentifierValue:(int64_t)identifier
{
return (BUYAddress *)[self buy_objectWithEntityName:@"Address" identifier:@(identifier)];
}
@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