Cart normalizer
The normalizeCart
function is used to map a SAP Cart into the unified SfCart
data model.
Parameters
Name | Type | Default value | Description |
---|---|---|---|
context | NormalizerContext | context needed for the normalizer. | |
cart | Cart | SAP 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 an expirationTime
field.
export const unifiedApiExtension = createUnifiedExtension({
normalizers: {
addCustomFields: [
{
normalizeCart: (context, cart) => ({
expirationTime: cart.expirationTime,
}),
},
],
},
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
import type { Address, Cart, Price } from "@vsf-enterprise/sapcc-types";
import type { Maybe, SfAddress, SfCart, SfMoney } from "@vue-storefront/unified-data-model";
import { defineNormalizer } from "../defineNormalizer";
import type { NormalizerContext } from "../types";
export const normalizeCart = defineNormalizer.normalizeCart((context, cart) => {
const { normalizeCartCoupon, normalizeCartLineItem, normalizeShippingMethod, normalizeMoney } =
context.normalizers;
const appliedCoupons = cart.appliedVouchers?.map((voucher) => normalizeCartCoupon(voucher)) ?? [];
const billingAddress = getAddress(context, cart.paymentInfo?.billingAddress);
const customerEmail = getCustomerEmail(cart);
const lineItems = cart.entries?.map((entry) => normalizeCartLineItem(entry)) ?? [];
const shippingAddress = getAddress(context, cart.deliveryAddress);
const shippingMethod = cart.deliveryMode ? normalizeShippingMethod(cart.deliveryMode) : null;
const subtotalDiscountedPrice = getSubtotalDiscountedPrice(context, cart);
const totalShippingPrice = cart.deliveryCost ? normalizeMoney(cart.deliveryCost) : null;
const id = (context.isAuthenthicated ? cart.code : cart.guid) as string;
return {
appliedCoupons,
billingAddress,
customerEmail,
id,
lineItems,
shippingAddress,
shippingMethod,
subtotalDiscountedPrice,
subtotalRegularPrice: getSubtotalRegularPrice(context, cart),
totalCouponDiscounts: normalizeMoney(cart.orderDiscounts as Price),
totalItems: cart.totalUnitCount as number,
totalPrice: normalizeMoney(cart.totalPriceWithTax as Price),
totalShippingPrice,
totalTax: normalizeMoney(cart.totalTax as Price),
};
});
function getAddress(context: NormalizerContext, address: Address | undefined): Maybe<SfAddress> {
return address ? context.normalizers.normalizeAddress(address) : null;
}
function getCustomerEmail(cart: Cart): SfCart["customerEmail"] {
// example uid: 42bc98b7-63ab-407b-9864-007acfa50888|email@example.com or just email
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const uidParts = cart.user?.uid?.split("|") ?? [];
return uidParts.find((element) => /^\S+@\S+\.\S+?$/.test(element)) ?? null;
}
/**
* Calculates cart subtotal price after item discounts are applied, before order discounts, shipping and tax.
*/
function getSubtotalDiscountedPrice(context: NormalizerContext, cart: Cart): SfMoney {
const productsPriceAfterDiscounts =
cart.entries?.reduce((acc, entry) => {
return acc + (entry.totalPrice?.value ?? 0);
}, 0) ?? 0;
return context.normalizers.normalizeMoney({
currencyIso: cart.totalPrice?.currencyIso,
value: productsPriceAfterDiscounts,
});
}
/**
* Calculates cart regular subtotal price before item discounts, order discounts, shipping and tax.
*
* Note: `subTotal` field in SAPCC represents the price **AFTER** item and order discounts are applied.
*/
function getSubtotalRegularPrice(context: NormalizerContext, cart: Cart): SfMoney {
const productsPriceBeforeDiscounts =
cart.entries?.reduce((acc, { quantity = 1, basePrice }) => {
return acc + (basePrice?.value ?? 0) * quantity;
}, 0) ?? 0;
return context.normalizers.normalizeMoney({
currencyIso: cart.totalPrice?.currencyIso,
value: productsPriceBeforeDiscounts,
});
}