A basket is a collection of product variants.

There are two types of baskets:

  • Persistent Baskets: The contents of a PTKPersistentBasket are managed by the user and changes to the baskets are saved with the user profile.
  • Temporary Baskets: The contents of a PTKTemporaryBasket cannot be modified by the user and the basket is not saved with the user profile.

Manipulation of PersistentBaskets, such as adding or removing products and changing quantities is performed locally using the PTKBasketsManager.

A 'PTKTemporaryBasket' can only be retrieved from the PTKTemporaryBasketWorkflow and cannot be created or manipulated by the user -- the only action you can perform with a PTKTemporaryBasket is to create an invoice for the basket. After 60 minutes the tag associated with the basket will expire.


This page covers:


Managing Baskets


Obtaining the Baskets for a User

The SDK manages the creation and deletion of baskets based on whether there are any product variants added for a specific merchant.
A basket only exists for a merchant if it contains at least one product variant.

There are two situations that result in a basket being deleted:

  • All product variants are removed from the basket.
  • The user purchases the items in a basket.

If a null is returned when retrieving a basket it means that no product variants are currently added for the merchant. In this case just add a product variant using the PTKBasketsManager.

  1. Get the baskets for the current user using the BasketsManager:
PTKBasketsManager *basketsManager = [[PTKManagerFactory sharedManager] basketsManager];
PTKBaskets *baskets = basketsManager.currentBaskets;
// If there are no baskets, null is returned
if (baskets != nil) {
    for (PTKPersistentBasket *basket in baskets.baskets) {
        // Display baskets to user to select
    }
}

  1. Get the user's basket for a specific merchant:
PTKPersistentBasket *basket = [baskets basketWithMerchant:merchant];
// If there is no basket for the merchant null is returned
if (basket != nil) {
    // manage basket contents
}

Adding a Product Variant to a Basket

There is no need to create a basket for a merchant if one doesn't already exist. Simply follow the steps below and the SDK will create the basket for you.

  1. Add a product variant to the basket for the merchant:
PTKMerchant *merchant = workflow.merchant;
PTKProductVariant *variant = [workflow.product.variants firstObject];
[basketsManager addVariantWithMerchant:merchant productVariant:variant];

  1. Or you can add a specific quantity of the product variant to the basket:
[basketsManager addVariantWithMerchant:merchant productVariant:variant quantity:3];

Removing a Product Variant from a Basket

  1. You can remove a single quantity of a variant (this will return true if the quantity of the variant was decreased by 1), if the remaining quantity is 0 the item will be removed from the basket:
BOOL singleQuantityRemoved = [basketsManager removeVariantWithMerchant:merchant productVariant:variant];

  1. Or you can remove a specific quantity:
// The actualy quantity removed is returned
NSInteger quantityRemoved = [basketsManager removeVariantWithMerchant:workflow.merchant productVariant:variant quantity:2];

Changing the Quantity of a Product Variant

  1. Set the quantity of a variant:

This will override the existing quantity value.
if you set the quantity to 0 the basket item for that variant will be removed.

[basketsManager setVariantQuantityWithMerchant:workflow.merchant productVariant:variant quantity:3];

Basket Items

A basket is made up of multiple line items, one for each unique product variant. A BasketItem records the quantity of each variant (the quantity will always be >= 1):

for (PTKBasketItem *item in basket.items) {
	PTKProductVariant *variant = item.variant;
	NSUInteger quantity = item.quantity;
}

Saving a Basket to the Server

  1. To make Basket information available on other devices or between logins you need to update the Basket on the server using the BasketsManager:
[basketsManager updateBasketWithMerchant:merchant completion:^(PTKBasket *basket, NSError *error) {
	// Basket is now accessible from other devices
}];

Preparing The Basket For Checkout

Before creating an invoice you need to ensure the user's profile has all the information required by the merchant.


Obtaining Fulfillment Options

The merchant may offer multiple fulfillment options for the user's basket.

The two main fulfillment types are:

  • Delivery: The user selects an address where the order should be delivered.
  • Collection: The user selects one of the merchant's locations to collect the items from.

Obtaining Delivery Options

If the user has selected to ship the items to an address.

Use the calculateShippingCostsForBasket method to obtain a list of shipping costs for each address in the user's profile.
Each PTKShippingCost contains a list of fulfillment options available for a single address.
Each PTKFulfillmentOption has a name, description and price that can be shown to the user.

[basketsManager calculateShippingCostsForBasket:basket completion:^(NSArray <PTKShippingCost *> *shippingCosts, NSError *error) {
    for (PTKShippingCost *shippingCost in shippingCosts) {
        if (selectAddress == shippingCost.address) {
            NSArray *fulfillmentOptions = shippingCost.fulfillmentOptions;
            // Display fulfillment options for selected address to user for selection
            [self displayInitialFulfillmentOptions:fulfillmentOptions];
        }
    }
}];

Obtaining Collection Options

Not all merchants allow in-store collection so always check before offering this option to a user.

  1. Determine if in-store collection is available and display fulfillment options:
NSArray<PTKFulfillmentOption *> *fulfillmentOptions = basket.merchant.fulfillmentOptions;
for (PTKFulfillmentOption *fulfillmentOption in fulfillmentOptions) {
    if (fulfillmentOption.type == PTKDeliveryTypeCollection) {
        // The merchant offers in-store collection
        // Add to collection to display to user for selection.
        [collectionFulfillmentOptions addObject:fulfillmentOption];
    } else {
        // Do not offer in-store collection to user
    }
}

  1. Obtain pickup locations for the merchant:
PTKMerchantLocation *selectedLocation;
PTKMerchantManager *merchantManager = [[PTKManagerFactory sharedManager] merchantManager];
[merchantManager getMerchantPickupLocations:merchant page:page withCompletion:^(NSArray <PTKMerchantLocation *> *merchantLocation, NSError *error) {
    // Display the merchant locations to the user for selction
}];

For a detailed examples please refer to the sample app in the ConfirmationController.


Creating an Invoice for a Basket

  1. Select a Payment Instrument from the Profile that is accepted by the Merchant:
PTKProfileManager *profileManager = [[PTKManagerFactory sharedManager] profileManager];
NSArray *acceptedPaymentInstruments = [profileManager acceptedPaymentInstrumentsForMerchant:merchant];
PTKPaymentInstrument *paymentInstrument = acceptedPaymentInstruments[0];

  1. Redeem coupons

Use the CouponPicker to help the user select an available discount for this purchase. (see Coupons)

NSArray <PTKCoupon *> *selectedCoupons = nil;
// Obtain the discount the user has selected.
PTKDiscount *discount = couponPicker.selectedDiscount;
if (discount != nil) {
    selectedCoupons = discount.appliedCoupons;
}

  1. Create the Payment Invoice Details:

Create the PTKPaymentInvoiceDetails using one of the two constructors depending on the fullfilment type.

PTKPaymentInvoiceDetails *paymentInvoiceDetails;
if (userSelectedDeliveryOption) {
    // Use the shipping address selected by the user
    paymentInvoiceDetails = [PTKPaymentInvoiceDetails paymentInvoiceDetailsWithPaymentInstrument:selectedPaymentInstrument
                                                                                 shippingAddress:selectedShippingAddress
                                                                               fulfillmentOption:selectedFulfillmentOption];
} else {
    // Use the merchant location selected by the user
    paymentInvoiceDetails = [PTKPaymentInvoiceDetails paymentInvoiceDetailsWithPaymentInstrument:selectedPaymentInstrument
                                                                                  pickUpLocation:selectedLocation
                                                                               fulfillmentOption:selectedFulfillmentOption];
}

  1. Use the PTKBasketsManager to create the invoice for the basket:
[basketsManager createInvoiceWithBasket:basket coupons:selectedCoupons  paymentInvoiceDetails:paymentInvoiceDetails completion:^(PTKPaymentInvoice *invoice, NSError *error) {
    if (invoice) {
        PTKCost *cost = invoice.cost;
    }
}];

Paying for a Payment Invoice

Now that you have an invoice for the basket, the next step is to process the payment.