182 lines
8.3 KiB
Markdown
182 lines
8.3 KiB
Markdown
# Cart Service
|
|
In Medusa a cart is where a customer can add items that they intend to purchase
|
|
later. The Cart service is responsible for making the operations necessary for
|
|
handling items in the cart and completing a checkout.
|
|
|
|
## Creating carts
|
|
|
|
### When to create carts
|
|
You can create a cart when the user enters the site or when they first add
|
|
something to the cart.
|
|
|
|
If you decide to wait with cart creation until the
|
|
customer adds something to the cart you have to make sure that the customer sees
|
|
correct prices/products/etc. for the region they are shopping in. You will also
|
|
have to ensure that you make a `POST /cart` call before you call `POST
|
|
/cart/line-items`.
|
|
|
|
This can be circumvented by creating the cart as soon as the user enters your
|
|
site. You will then be able to keep the region data in the cart, which will be
|
|
ready for any `POST /cart/line-items`. This has the trade-off of creating many
|
|
unnecessary carts, but is easier to implement.
|
|
|
|
## Shopping
|
|
|
|
### Adding to the cart
|
|
The typical user journey is that a customer adds an item to her Cart this
|
|
usually happens with `POST /cart/line-items`. The endpoint takes a `variant_id`
|
|
and a `quantity`. The endpoint controller will then retrieve the variant and the
|
|
product it is associated with, compile a valid `LineItem` and use the
|
|
CartService function `addLineItem` to create the line item on the cart.
|
|
|
|
### Updating line items
|
|
Updating line items happens with `POST /cart/line-items/[line-id]`. The endpoint
|
|
takes `quantity` to update the line item's quantity. A quantity of 0 results in
|
|
a removal of the line item. The endpoint controller uses `updateLineItem` to
|
|
update the line item.
|
|
|
|
### Removing line items
|
|
Deleting line items happens with `DELETE /cart/line-items/[line-id]`. Endpoint
|
|
removes the line item with the given line id by calling `removeLineItem`.
|
|
|
|
> ### Custom add to cart
|
|
> It is possible to make custom endpoints to add to cart. For example if you are
|
|
> creating a gift card plugin you may want to create a custom endpoint that
|
|
> accepts values like `amount` which can be set by the customer. As long as the
|
|
> controller compiles a valid `LineItem` it can safely call `addLineItem`
|
|
|
|
## Checking out
|
|
|
|
### Initializing the checkout
|
|
When the customer is ready to check out they will reach your checkout page. At
|
|
this point you want to display which payment and shipping options are offered.
|
|
`POST /cart/payment-sessions` and `POST /cart/fulfillment-sessions` will
|
|
initialize payment sessions and shipping methods offered by fulfillment
|
|
providers. The payment sessions will typically have to be updated if any further
|
|
changes to the cart total happens (shipping fee, promo codes, user exits
|
|
checkout and adds more items to cart and returns to checkout). Medusa will make
|
|
sure to update any payment sessions that have already been initialized.
|
|
|
|
In cases where shipping rates can vary based on order size, shipping address
|
|
(with higher granularity than region) makes sense to call `POST
|
|
/cart/fulfillment-providers` multiple times, e.g. if the customer updates their
|
|
shipping address and new shipping rates have to be calculated. On each call the
|
|
endpoint will make sure to only return relevant shipping methods.
|
|
|
|
Note that `POST /cart/payment-providers` should not be used to fetch available
|
|
payment providers, only to initialize payment sessions. If you want to display
|
|
the available payment providers to the customer you can find an array of these
|
|
in `region.payment_providers`.
|
|
|
|
### Getting customer data
|
|
To complete a purchase the customer has to fill in her details. The endpoints to
|
|
do this are `POST /cart/email`, `POST /cart/shipping-address` and `POST /cart/
|
|
billing-address`. The endpoint controllers use the corresponding Cart service
|
|
methods (`updateEmail`, `updateShippingAddress`, `updateBillingAddress`) to
|
|
store the customer information in the cart.
|
|
|
|
### Handling payments and completing orders
|
|
Authorization of payments happen with the payment provider. As such the typical
|
|
payment flow will be:
|
|
|
|
1. the customer enters payment details
|
|
2. details are sent to the payment provider
|
|
3. the payment provider authorizes the payment
|
|
4. the payment method is store in the cart
|
|
5. the order is processed.
|
|
|
|
Steps 4. and 5. are handled with one API call in Medusa. Once the payment is
|
|
authorized you call `POST /order`. The endpoint takes `cart_id` and
|
|
`payment_provider_id` as data. The controller will call the Cart service
|
|
function `setPaymentMethod` which will fetch the cart, search the
|
|
`payment_sessions` array for the payment associated with `payment_provider` and
|
|
check that the payment session is authorized. When the authorization is verified
|
|
the payment method is set and the controller can safely call the Order service
|
|
function `create`.
|
|
|
|
|
|
### How do payment sessions work?
|
|
|
|
When the customer first enters the checkout page you should initialize payment
|
|
sessions for each of the possible payment providers. This is done with a single
|
|
call to `POST /cart/payment-sessions`. Calls to `POST /cart/payment-sessions`
|
|
will either create payment sessions for each payment provider or if the payment
|
|
sessions have already been initialized ensure that the sessions are up to date (
|
|
i.e. that the cart amount corresponds to the payment sessions' amounts). When
|
|
the customer reaches the payment part of the checkout (or alternatively when she
|
|
decides to use one of the payment providers as a checkout provider) the payment
|
|
method will be saved once authorized.
|
|
|
|
### How do fulfillment sessions work?
|
|
|
|
When the customer first enters the checkout page, fulfillment sessions should be
|
|
initialized. The fulfillment session is responsible for fetching shipping
|
|
options with a fulfillment provider. E.g. your store has an integration with
|
|
your 3PL as a fulfillment provider. The 3PL has 4 shipping options: standard,
|
|
express and fragile shipping as well as a parcel shop service where orders are
|
|
delivered to a local store.
|
|
|
|
The store operator will have set up which shipping options are available in the
|
|
customer's region. I.e. the store operator may have created a shipping option
|
|
called Free Shipping, which uses the "Standard Shipping" method from the 3PL
|
|
integration, and which is free when the order value is above 100 USD. The store
|
|
operator may have also created an Express Shipping option which uses the
|
|
"Express Shipping" method from the 3PL integration and which costs 20 USD.
|
|
The store operator has also created a Fragile Shipping option which uses the
|
|
"Fragile Shipping" method from the 3PL integration and which has variable
|
|
pricing depending on the size of the shipment. The variable pricing is
|
|
calculated by the integration depending on cart. Finally, the store operator has
|
|
defined a parcel shop option, which uses the 3PL's parcel shop shipping method.
|
|
The customer needs to provide the ID of the local store that she wants her order
|
|
delivered to and the shipping method therefore takes some additional input to be
|
|
a valid shipping method for an order.
|
|
|
|
When the customer enters the checkout page the `POST /cart/shipping-options`
|
|
call will fetch each of the shipping options that the store operator has set up.
|
|
Extending the above example, an array of shipping options would be stored in the
|
|
cart in the format:
|
|
|
|
```
|
|
[
|
|
{
|
|
_id: [some-id],
|
|
provider_id: "3pl_integration",
|
|
name: "Free Shipping",
|
|
price: 0,
|
|
data: {
|
|
// This will contain data specific to the shipping method, i.e. the
|
|
// id that the 3PL needs in order to process the order with this shipping
|
|
// method
|
|
}
|
|
},
|
|
{
|
|
_id: [some-id],
|
|
provider_id: "3pl_integration",
|
|
name: "Express Shipping",
|
|
price: 20,
|
|
data: {
|
|
// This will contain data specific to the shipping method, i.e. the
|
|
// id that the 3PL needs in order to process the order with this shipping
|
|
// method
|
|
}
|
|
},
|
|
{
|
|
_id: [some-id],
|
|
provider_id: "3pl_integration",
|
|
name: "Fragile Shipping",
|
|
price: 120, // Calculated from the cart
|
|
data: {
|
|
// This will contain data specific to the shipping method, i.e. the
|
|
// id that the 3PL needs in order to process the order with this shipping
|
|
// method
|
|
}
|
|
},
|
|
...
|
|
]
|
|
```
|
|
|
|
If the customer changes her cart, all shipping options will be recalculated. For
|
|
example, if the customer removes something from the cart so that they no longer
|
|
qualify for free shipping, the free shipping method will be removed at the same
|
|
time the fragile shipping method's price will be updated.
|