Cart normalizer
The normalizeCart
function is used to map a Magento Cart into the unified SfCart
data model.
Parameters
Name | Type | Default value | Description |
---|---|---|---|
cart | Cart | Magento Cart | |
ctx | NormalizerContext | context needed for the normalizer |
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 defineNormalizers
function. The following example demonstrates how to extend SfCart
with a gift_message
field.
import { normalizers as normalizersMagento, defineNormalizers } from "@vsf-enterprise/unified-api-magento";
const normalizers = defineNormalizers<typeof normalizersMagento>()({
...normalizersMagento,
normalizeCart: (cart) => ({
...normalizersMagento.normalizeCart(cart),
giftMessage: cart.gift_message,
}),
});
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 "@shared/utils";
import { Cart } from "@vue-storefront/magento-types";
import type { SfCart } from "@vue-storefront/unified-data-model";
import { defineNormalizer } from "../defineNormalizer";
import { NormalizerContext } from "../types";
export const normalizeCart = defineNormalizer.normalizeCart((cart, ctx) => {
const { appliedCoupons } = normalizeDiscounts(cart, ctx);
const { lineItems, subtotalRegularPrice, subtotalDiscountedPrice } = normalizeLineItems(
cart,
ctx,
);
const { billingAddress, shippingAddress } = normalizeAddresses(cart, ctx);
const { shippingMethod, totalShippingPrice } = normalizeShipping(cart, ctx);
const { totalItems, totalPrice, totalTax, totalCouponDiscounts } = normalizeTotals(cart, ctx);
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(
cart: Cart,
ctx: NormalizerContext,
): Pick<SfCart, "lineItems" | "subtotalRegularPrice" | "subtotalDiscountedPrice"> {
const { normalizeMoney, normalizeCartLineItem } = ctx.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(
cart: Cart,
ctx: NormalizerContext,
): Pick<SfCart, "billingAddress" | "shippingAddress"> {
const { normalizeAddress } = ctx.normalizers;
return {
billingAddress: cart.billing_address ? normalizeAddress(cart.billing_address) : null,
shippingAddress: cart.shipping_addresses?.[0]
? normalizeAddress(cart.shipping_addresses?.[0])
: null,
};
}
function normalizeTotals(
cart: Cart,
ctx: NormalizerContext,
): Pick<SfCart, "totalPrice" | "totalItems" | "totalTax" | "totalCouponDiscounts"> {
const { normalizeMoney } = ctx.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(
cart: Cart,
ctx: NormalizerContext,
): Pick<SfCart, "shippingMethod" | "totalShippingPrice"> {
const { normalizeMoney, normalizeShippingMethod } = ctx.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),
};
}