ReferenceBigCommerceNormalizers
Order normalizer
normalizeOrder: This function is used to map BigCommerceOrderByCartResponseintoSfOrder, which includes order details data.normalizeOrderListItem: This function maps BigCommerceOrderinto UnifiedSfOrderListItemwhich includes only basic order details, used to display data in an order list.
Parameters
normalizeOrder
| Name | Type | Default value | Description |
|---|---|---|---|
context | NormalizerContext | Context which contains e.g. currency | |
input | OrderByCartResponse | BigCommerce OrderByCartResponse |
normalizeOrderListItem
| Name | Type | Default value | Description |
|---|---|---|---|
context | NormalizerContext | Context which contains e.g. currency | |
order | Order | BigCommerce Order |
normalizeOrderLineItem
| Name | Type | Default value | Description |
|---|---|---|---|
context | NormalizerContext | Context which contains e.g. currency | |
lineItem | OrderItem | BigCommerce Order Item |
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 addCustomFields API. The following example demonstrates how to extend SfOrder with a staffNotes field.
export const unifiedApiExtension = createUnifiedExtension({
normalizers: {
addCustomFields: [
{
normalizeOrder: (context, order) => ({
staffNotes: order.staff_notes,
}),
},
],
},
config: {
...
},
});You can override the normalizeOrder, but it's also available to override the smaller normalizers such as normalizeAddress, normalizeShippingMethod.
Source
import { z } from "zod";
import { defineNormalizer } from "../defineNormalizer";
const orderSchema = z.object({
billing_address: z.looseObject({}),
date_created: z.string().min(1, "Order date is required"),
id: z.number(),
products: z.array(z.looseObject({})).min(1, "At least one product is required"),
shipping_addresses: z.tuple([
z.looseObject({
shipping_method: z.string().min(1, "Shipping method is required"),
}),
]),
shipping_cost_inc_tax: z.string(),
status: z.string().optional(),
subtotal_ex_tax: z.string(),
total_inc_tax: z.string(),
total_tax: z.string(),
});
export const normalizeOrder = defineNormalizer.normalizeOrder((context, input) => {
let validated;
try {
validated = orderSchema.parse(input);
} catch (error) {
throw new Error("Missing required order fields", { cause: error });
}
const lineItems = validated.products.map((entry) =>
context.normalizers.normalizeOrderLineItem(entry),
);
return {
billingAddress: context.normalizers.normalizeAddress(validated.billing_address),
id: validated.id.toString(),
lineItems,
orderDate: new Date(validated.date_created).toISOString(),
paymentMethod: "CARD",
shippingAddress: context.normalizers.normalizeAddress(validated.shipping_addresses[0]),
shippingMethod: context.normalizers.normalizeShippingMethod({
name: validated.shipping_addresses[0].shipping_method,
price: validated.shipping_cost_inc_tax,
}),
status: validated.status ?? "UNKNOWN",
subtotalPrice: context.normalizers.normalizeMoney(Number.parseFloat(validated.subtotal_ex_tax)),
totalPrice: context.normalizers.normalizeMoney(Number.parseFloat(validated.total_inc_tax)),
totalShippingPrice: context.normalizers.normalizeMoney(
Number.parseFloat(validated.shipping_cost_inc_tax),
),
totalTax: context.normalizers.normalizeMoney(Number.parseFloat(validated.total_tax)),
};
});import { z } from "zod";
import { defineNormalizer } from "../defineNormalizer";
const orderListItemSchema = z.object({
date_created: z.string().min(1, "Order date is required"),
id: z.number(),
status: z.string().optional(),
total_inc_tax: z.string().min(1, "Total price is required"),
});
export const normalizeOrderListItem = defineNormalizer.normalizeOrderListItem((context, input) => {
let validated;
try {
validated = orderListItemSchema.parse(input);
} catch (error) {
throw new Error("Order is missing required fields", { cause: error });
}
return {
id: validated.id.toString(),
orderDate: new Date(validated.date_created).toISOString(),
status: validated.status ?? "UNKNOWN",
totalPrice: context.normalizers.normalizeMoney(Number.parseFloat(validated.total_inc_tax)),
};
});import type { SfAttribute, SfImage } from "@alokai/connect";
import type { OrderItem } from "@vsf-enterprise/bigcommerce-api";
import { z } from "zod";
import { maybe } from "@vsf-enterprise/unified-api-bigcommerce";
import type { NormalizerContext } from "@vsf-enterprise/unified-api-bigcommerce";
import { defineNormalizer } from "../defineNormalizer";
const orderLineItemSchema = z.object({
id: z.number().positive("Order item id is required"),
name: z.string().min(1, "Product name is required"),
price_inc_tax: z.string().min(1, "Price is required"),
product_id: z.number().positive("Product id is required"),
product_options: z.array(z.looseObject({})).optional(),
total_inc_tax: z.string().min(1, "Total price is required"),
});
export const normalizeOrderLineItem = defineNormalizer.normalizeOrderLineItem((context, input) => {
let validated;
try {
validated = orderLineItemSchema.parse(input);
} catch (error) {
throw new Error("OrderItem is missing required fields", { cause: error });
}
return {
attributes: normalizeAttributes(validated.product_options),
id: validated.id.toString(),
image: normalizeImage(validated.product_id, context),
productId: validated.product_id.toString(),
productName: validated.name,
quantity: input.quantity ?? 1,
sku: maybe(input.sku),
totalPrice: context.normalizers.normalizeMoney(Number.parseFloat(validated.total_inc_tax)),
unitPrice: context.normalizers.normalizeMoney(Number.parseFloat(validated.price_inc_tax)),
};
});
function normalizeAttributes(productOptions: OrderItem["product_options"]) {
return productOptions
? productOptions
.map((option) => {
const { display_name, display_value, name, value } = option;
if (!(name && value && display_name && display_value)) {
return null;
}
return {
label: display_name,
name: name,
value: value,
valueLabel: display_value,
} satisfies SfAttribute;
})
.filter(Boolean)
: [];
}
function normalizeImage(product_id: number, ctx: NormalizerContext) {
if (!ctx.imageGetter) {
return null;
}
const imageSource = ctx.imageGetter(product_id);
if (!imageSource) {
return null;
}
return {
alt: maybe(imageSource.description),
url: imageSource.image_url!,
} satisfies SfImage;
}