Vue Storefront is now Alokai! Learn More
Order normalizer

Order normalizer

  • normalizeOrder: This function is used to map Commercetools Order into SfOrder, which includes order details data.
  • normalizeOrderListItem: This function maps Commercetools OrderHistory into Unified SfOrderListItem which includes only basic order details, used to display an data in an order list.

Parameters

normalizeOrder

NameTypeDefault valueDescription
inputOrderCommercetools Order
ctxNormalizerContextContext needed for the normalizer

normalizeOrderListItem

NameTypeDefault valueDescription
orderOrderCommercetools Order
ctxNormalizerContextContext needed for the normalizer

normalizeOrderLineItem

NameTypeDefault valueDescription
lineItemLineItemCommercetools Line Item
ctxNormalizerContextContext needed for the normalizer

Extending

The SfOrder is returned from the GetOrders Method. If the SfOrder 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 SfOrder with a cartRef field.

import { normalizers as normalizersCT, defineNormalizers } from "@vsf-enterprise/unified-api-commercetools";

const normalizers = defineNormalizers<typeof normalizersCT>()({
  ...normalizersCT,
  normalizeOrder: (order, context) => ({
    ...normalizersCT.normalizeOrder(order, context),
    cartRef: order.cartRef,
  }),
});

You can override the normalizeOrder, but it's also available to override the smaller normalizers such as normalizeAddress, normalizeShippingMethod.

Source

order.ts
/* eslint-disable complexity */
import type { BaseMoney, TaxedPrice } from "@vsf-enterprise/commercetools-types";
import { defineNormalizer } from "../defineNormalizer";

export const normalizeOrder = defineNormalizer.normalizeOrder((input, ctx) => {
  const {
    id,
    createdAt,
    orderState,
    lineItems,
    totalPrice,
    taxedPrice,
    shippingAddress,
    shippingInfo,
    billingAddress,
  } = input;

  if (
    !id ||
    !createdAt ||
    !totalPrice ||
    !taxedPrice ||
    !lineItems ||
    lineItems.length === 0 ||
    !shippingAddress ||
    !shippingInfo ||
    !shippingInfo.shippingMethod ||
    !shippingInfo.price
  ) {
    throw new Error("Missing required order fields");
  }

  const { normalizeMoney, normalizeAddress, normalizeOrderLineItem, normalizeShippingMethod } =
    ctx.normalizers;

  const shippingMethod = normalizeShippingMethod({
    ...shippingInfo.shippingMethod,
    totalPrice: totalPrice,
  });

  const totalTax = calculateTotalTax(taxedPrice);
  const subTotal = {
    ...totalPrice,
    centAmount: totalPrice.centAmount - shippingInfo.price.centAmount - totalTax.centAmount,
  };

  return {
    id,
    orderDate: new Date(createdAt).toISOString(),
    status: orderState ?? "UNKNOWN",
    lineItems: lineItems.map((entry) => normalizeOrderLineItem(entry)),
    subtotalPrice: normalizeMoney(subTotal),
    totalShippingPrice: normalizeMoney(shippingInfo.price),
    totalTax: normalizeMoney(totalTax),
    totalPrice: normalizeMoney(totalPrice),
    shippingAddress: normalizeAddress(shippingAddress),
    billingAddress: billingAddress ? normalizeAddress(billingAddress) : null,
    shippingMethod: shippingMethod!,
    paymentMethod: "CARD",
  };
});

function calculateTotalTax(taxedPrice: TaxedPrice) {
  const { totalNet, totalGross } = taxedPrice;
  const totalTax = totalGross.centAmount - totalNet.centAmount;

  return {
    type: totalGross.type,
    centAmount: totalTax,
    currencyCode: totalGross.currencyCode,
    fractionDigits: totalGross.fractionDigits,
  } satisfies BaseMoney;
}