Cart normalizer
The normalizeCart
function is used to map a Magento Cart into the unified SfCart
data model.
Parameters
Name | Type | Default value | Description |
---|---|---|---|
context | NormalizerContext | context needed for the normalizer | |
cart | Cart | Magento Cart |
Extending
The SfCart
structure is returned from all Unified Cart Methods such as GetCart
, AddCartLineItem
, and UpdateCartLineItem
. If the SfCart
structure doesn't contain the information you need for your Storefront, you can extend its logic using the addCustomFields
API. The following example demonstrates how to extend SfCart
with a gift_message
field.
export const unifiedApiExtension = createUnifiedExtension({
normalizers: {
addCustomFields: [
{
normalizeCart: (context, cart) => ({
giftMessage: cart.gift_message,
}),
},
],
},
config: {
...
},
});
You can override the normalizeCart
, but it's also available to override the smaller normalizers such as normalizeCartCoupon
, normalizeShippingMethod
, normalizeCartLineItem
.
Source
The normalizeCart
function consists of several smaller normalizers such as normalizeCartCoupon
, normalizeShippingMethod
, and more.
cart.ts
/* eslint-disable complexity */
import { maybe } from "@/helpers";
import type { Cart } from "@/ecommerceTypes";
import type { SfCart } from "@vue-storefront/unified-data-model";
import { defineNormalizer } from "../defineNormalizer";
import type { NormalizerContext } from "../types";
export const normalizeCart = defineNormalizer.normalizeCart((context, cart) => {
const { appliedCoupons } = normalizeDiscounts(cart, context);
const { lineItems, subtotalRegularPrice, subtotalDiscountedPrice } = normalizeLineItems(
context,
cart,
);
const { billingAddress, shippingAddress } = normalizeAddresses(context, cart);
const { shippingMethod, totalShippingPrice } = normalizeShipping(context, cart);
const { totalItems, totalPrice, totalTax, totalCouponDiscounts } = normalizeTotals(context, cart);
return {
id: cart.id!,
customerEmail: maybe(cart.email),
appliedCoupons,
lineItems,
billingAddress,
shippingAddress,
totalItems,
totalPrice,
totalTax,
subtotalDiscountedPrice,
totalCouponDiscounts,
shippingMethod,
totalShippingPrice,
subtotalRegularPrice,
};
});
function normalizeDiscounts(cart: Cart, ctx: NormalizerContext): Pick<SfCart, "appliedCoupons"> {
const appliedCoupons = (cart.applied_coupons ?? [])
.filter(Boolean)
.map((coupon) => ctx.normalizers.normalizeCartCoupon(coupon));
return { appliedCoupons };
}
function normalizeLineItems(
context: NormalizerContext,
cart: Cart,
): Pick<SfCart, "lineItems" | "subtotalRegularPrice" | "subtotalDiscountedPrice"> {
const { normalizeMoney, normalizeCartLineItem } = context.normalizers;
const lineItems = (cart.items ?? [])
.filter(Boolean)
.map((lineItem) => normalizeCartLineItem(lineItem));
const lineItemsSubtotalRegular = lineItems.reduce((prev, curr) => {
return prev + (curr.unitPrice?.regularPrice.amount ?? 0) * curr.quantity;
}, 0);
const lineItemsSubtotalDiscounted = lineItems.reduce((prev, curr) => {
return prev + (curr.unitPrice?.value.amount ?? 0) * curr.quantity;
}, 0);
return {
lineItems,
subtotalRegularPrice: normalizeMoney({
value: +lineItemsSubtotalRegular.toFixed(2),
currency: cart.prices?.grand_total?.currency,
}),
subtotalDiscountedPrice: normalizeMoney({
value: +lineItemsSubtotalDiscounted.toFixed(2),
currency: cart.prices?.grand_total?.currency,
}),
};
}
function normalizeAddresses(
context: NormalizerContext,
cart: Cart,
): Pick<SfCart, "billingAddress" | "shippingAddress"> {
const { normalizeAddress } = context.normalizers;
return {
billingAddress: cart.billing_address ? normalizeAddress(cart.billing_address) : null,
shippingAddress: cart.shipping_addresses?.[0]
? normalizeAddress(cart.shipping_addresses?.[0])
: null,
};
}
function normalizeTotals(
context: NormalizerContext,
cart: Cart,
): Pick<SfCart, "totalPrice" | "totalItems" | "totalTax" | "totalCouponDiscounts"> {
const { normalizeMoney } = context.normalizers;
const totalPrice = normalizeMoney(cart.prices?.grand_total ?? {});
const totalItems = cart.total_quantity ?? 0;
const totalTax = normalizeMoney({
currency: cart.prices?.subtotal_including_tax?.currency,
value:
(cart.prices?.subtotal_including_tax?.value ?? 0) -
(cart.prices?.subtotal_excluding_tax?.value ?? 0),
});
const totalCouponDiscounts = normalizeMoney({
value: cart.prices?.discounts?.reduce((prev, curr) => prev + (curr?.amount.value ?? 0), 0) ?? 0,
currency: cart.prices?.grand_total?.currency,
});
return {
totalPrice,
totalItems,
totalTax,
totalCouponDiscounts,
};
}
function normalizeShipping(
context: NormalizerContext,
cart: Cart,
): Pick<SfCart, "shippingMethod" | "totalShippingPrice"> {
const { normalizeMoney, normalizeShippingMethod } = context.normalizers;
const selectedShippingMethod = cart.shipping_addresses?.[0]?.selected_shipping_method;
const totalShippingPrice = selectedShippingMethod?.amount
? normalizeMoney(selectedShippingMethod?.amount)
: null;
const shippingMethod = selectedShippingMethod
? normalizeShippingMethod(selectedShippingMethod)
: null;
return {
shippingMethod: maybe(shippingMethod),
totalShippingPrice: maybe(totalShippingPrice),
};
}