0

I am making an e-commerce app and trying to deal with the backend stuff so the shop owner can see what a user ordered. I am going to use Stripe + Parse for this.

In my Payment View Controller I use fast enumeration to go through my array and get the items in the shopping cart. The items in my array can only be one of two custom objects (Bike or Accessory).

Then I put the objects I get back into a NSDictionary, which is required to use my Stripe token and Parse together. Then the items in my NSDictionary should come out listed in my Parse log.

My issue is that this only works if I have one Bike and/or one Accessory. If I add a second Bike or Accessory to my cart, it just replaces the old info with my new Bike or Accessory.

I can kinda see in my code why this happens but I don't really know how to find a solution (still a newbie to programming).

Would appreciate your help! Code below:

Cart *cartObject = [Cart sharedManager];
for (id object in cartObject.cartArray)
{
    if ([object isKindOfClass:[ChosenBike class]])
    {
        ChosenBike *bikeObject = (ChosenBike *)object;
        self.bikeName = bikeObject.chosenName;
        self.bikeSize = bikeObject.chosenSize;
        self.bicycleHasRearBrake = bikeObject.bicycleHasRearBrake;
        self.bikeWheelSetColor = bikeObject.chosenWheelSetColor;
        self.bikeExtraWheelset = bikeObject.extraSeriesWheelset;
        self.bikeQty = bikeObject.chosenQuantity;

    }
    else if ([object isKindOfClass:[ChosenAccessory class]])
    {
        ChosenAccessory *accessoryObject = (ChosenAccessory *)object;
        self.accessoryName = accessoryObject.chosenName;
        self.accessoryQty = accessoryObject.chosenQuantity;
        self.accessoryColor = accessoryObject.color;
        self.accessorySize = accessoryObject.chosenSize;

    }
}

NSDictionary *chargeParams = @{
                               @"token": token.tokenId,
                               @"currency": @"usd",
                               @"amount": result, // this is in cents (i.e. 1000 = $10)
                               @"bikeName": self.bikeName,
                               @"bikeSize": self.bikeSize,
                               @"bikeHasRearBrake": [NSNumber numberWithBool:self.bicycleHasRearBrake],
                               @"bikeColor": self.bikeWheelSetColor,
                               @"bikeExtraWheelset": self.bikeExtraWheelset,
                               @"bikeQty": [self.bikeQty stringValue],
                               @"accessoryName": self.accessoryName,
                               @"accessoryQty": [self.accessoryQty stringValue],
                               @"accessoryColor": self.accessoryColor,
                               @"accessorySize": self.accessorySize,
                               };


// This passes the token off to our payment backend, which will then actually complete charging the card using your account's
[PFCloud callFunctionInBackground:@"charge"
                   withParameters:chargeParams
                            block:^(id object, NSError *error) {
                                [MBProgressHUD hideHUDForView:self.view animated:YES];
                                if (error) {
                                    [self hasError:error];
                                    return;
                                }
                                [self.presentingViewController dismissViewControllerAnimated:YES
                                                                                  completion:^{
                                                                                      [[[UIAlertView alloc] initWithTitle:@"Payment Succeeded"
                                                                                                                  message:nil
                                                                                                                 delegate:nil
                                                                                                        cancelButtonTitle:nil
                                                                                                        otherButtonTitles:@"OK", nil] show];
                                                                                  }];
                            }];

}

May Yang
  • 523
  • 1
  • 5
  • 18

1 Answers1

1

If you need to support more than one instance of each type of product, then you should probably restructure your charge params dictionary to support arrays. It's common in commerce systems to have the concept of a "line items", which would be a set of items in the order. For each of the line items, you could have a line_item_type, and a dictionary of type_attributes which would differ based on the line_item_type. This way, you can capture the specific attributes of your accessories and bikes, but in a generic line_item structure.

A structure that resembles something like below should work for what you're after. This example has 2 bike items and 1 accessory.

{ "token": token.tokenId,
  "currency": "usd",
  "amount": result,
  "line_items": [
    { "line_item_type": "bike",
      "line_item_attributes": {
        "bikeName": self.bikeName,
        "bikeSize": self.bikeSize,
        "bikeHasRearBrake": [NSNumber numberWithBool:self.bicycleHasRearBrake],
        "bikeColor": self.bikeWheelSetColor,
        "bikeExtraWheelset": self.bikeExtraWheelset,
        "bikeQty": [self.bikeQty stringValue]
      }
    },
    { "line_item_type": "bike",
      "line_item_attributes": {
        "bikeName": self.bikeName,
        "bikeSize": self.bikeSize,
        "bikeHasRearBrake": [NSNumber numberWithBool:self.bicycleHasRearBrake],
        "bikeColor": self.bikeWheelSetColor,
        "bikeExtraWheelset": self.bikeExtraWheelset,
        "bikeQty": [self.bikeQty stringValue]
      }
    },
    { "line_item_type": "accessory",
      "line_item_attributes": {
        "accessoryName": self.accessoryName,
        "accessoryQty": [self.accessoryQty stringValue],
        "accessoryColor": self.accessoryColor,
        "accessorySize": self.accessorySize
      }
    }]
}

--- Update with example of adding a dictionary to an array ---

NSMutableArray *lineItems = [NSMutableArray new];
Cart *cartObject = [Cart sharedManager];
for (id object in cartObject.cartArray) {
  if ([object isKindOfClass:[ChosenBike class]]) {
    ChosenBike *bikeObject = (ChosenBike *)object;
    NSDictionary *attributes = @{@"bikeName": bikeObject.chosenName, 
                                 @"bikeSize": bikeObject.chosenSize, 
                                 @"bikeHasRearBrake": @(bikeObject.bicycleHasRearBrake), 
                                 @"bikeColor": bikeObject.chosenWheelSetColor, 
                                 @"bikeExtraWheelset": bikeObject.extraSeriesWheelset, 
                                 @"bikeQty": [bikeObject.extraSeriesWheelset stringValue]};
    NSDictionary *lineItem = @{@"line_item_type": @"bike",
                               @"line_item_attributes": attributes};
    [lineItems addObject:lineItem];
  } else if ([object isKindOfClass:[ChosenAccessory class]]) {
    ChosenAccessory *accessoryObject = (ChosenAccessory *)object;
    NSDictionary *attributes = @{@"accessoryName": accessoryObject.chosenName, 
                                 @"accessoryQty": [accessoryObject.chosenQuantity stringValue], 
                                 @"accessoryColor": accessoryObject.color, 
                                 @"accessorySize": accessoryObject.chosenSize};
    NSDictionary *lineItem = @{@"line_item_type": @"accessory",
                               @"line_item_attributes": attributes};
    [lineItems addObject:lineItem];
  }
}

NSDictionary *chargeParams = @{@"token": token.tokenId,
                               @"currency": @"usd",
                               @"amount": result, 
                               @"line_items": lineItems};
rickerbh
  • 9,731
  • 1
  • 31
  • 35
  • Thanks, I'll give this a try later tonight. – May Yang Dec 30 '14 at 23:53
  • I am unable to get this to work, Xcode keeps giving me an "Expected expression" error. – May Yang Dec 31 '14 at 01:36
  • The block I provided above is not code... It's a structure. You'll need to create the dictionary and arrays yourself in a similar structure that meets your needs. – rickerbh Dec 31 '14 at 04:14
  • Your answer helps me see the big picture, but I guess the problem I am facing is I am not sure then how to create the NSDictionaries to reflect 2 instances of the same kind of class. I created a NSDictionary but say I add 2 different Accessories... the NSDictionary I made still just picks up one of the objects. – May Yang Dec 31 '14 at 04:48
  • 1
    Yeah, that's because you're storing the attributes in the class, and then constructing your charge params from this. If you iterate through your collection and build out the structure, you should be able to support multiple item. Check my edit above for an example on how to do this. – rickerbh Dec 31 '14 at 05:44