Skip to content

Commit

Permalink
add aggregate inventory data to product api
Browse files Browse the repository at this point in the history
  • Loading branch information
bv-armstrong committed Dec 6, 2024
1 parent f90d994 commit 085a4c3
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 129 deletions.
77 changes: 70 additions & 7 deletions server/src/shopify/product.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,52 @@
import { ShopifyGraphQLClient } from './shopify-client'
import { logger } from '../util/logger'
import { ProductSchema, Product, PageInfo, PageInfoSchema } from 'shared'
import {ProductSchema, Product, PageInfo, PageInfoSchema, Inventory} from 'shared'
import { isValid } from '../util/validate'
import {getVariantInventory, internalVariantQuery} from "./productVariant";

const MAX_VARIANTS_COUNT = 10;
const MAX_LOCATIONS_COUNT = 5;

export const internalVariantQuery = /* GraphQL */ `
id
title
image {
id
url
}
sku
displayName
image {
url
id
}
contextualPricing(context: {}) {
price {
amount
currencyCode
}
}
inventoryQuantity
inventoryItem {
inventoryLevels(first: ${MAX_LOCATIONS_COUNT}) {
nodes {
id
location {
id
name
}
quantities(names: ["available", "committed"]) {
name
quantity
}
}
}
}
`

const internalProductQuery = /* GraphQL */ `
id
handle
variants(first: 100) {
variants(first: ${MAX_VARIANTS_COUNT}) {
nodes {
${internalVariantQuery}
}
Expand Down Expand Up @@ -49,10 +88,34 @@ const getProductsQuery = /* GraphQL */ `
}
`

async function parseProduct(product: any, client: ShopifyGraphQLClient): Promise<Product> {
function parseProduct(product: any): Product {
let productInventory: Inventory = {
totalInventory: product.totalInventory,
totalAvailableInventory: 0,
totalCommittedInventory: 0
}

for (const variant of product.variants.nodes) {
variant.inventory = await getVariantInventory(client, variant.id, variant.inventoryItem.locationsCount.count) // TODO: Reduce API calls
let variantInventory: Inventory = {
totalInventory: variant.inventoryQuantity,
totalAvailableInventory: 0,
totalCommittedInventory: 0
}

for (const inventoryLevel of variant.inventoryItem.inventoryLevels.nodes) {
for (const quantity of inventoryLevel.quantities) {
if (quantity.name == "available") {
variantInventory.totalAvailableInventory += quantity.quantity;
productInventory.totalAvailableInventory += quantity.quantity;
} else if (quantity.name == "committed") {
variantInventory.totalCommittedInventory += quantity.quantity;
productInventory.totalCommittedInventory += quantity.quantity;
}
}
}
variant.inventory = variantInventory;
}
product.inventory = productInventory;
if (!isValid<Product>(ProductSchema, product, 'product')) {
throw new Error('Error mapping product')
}
Expand All @@ -77,7 +140,7 @@ export async function getProductById (
return null
}

return await parseProduct(data.product, client)
return parseProduct(data.product)
}

export async function getProducts (
Expand All @@ -104,7 +167,7 @@ export async function getProducts (

const products: Product[] = []
for (const edge of data.products.edges) {
products.push(await parseProduct(edge.node, client))
products.push(await parseProduct(edge.node))
}
const pageInfo = data.products.pageInfo
if (!isValid<PageInfo>(PageInfoSchema, pageInfo, 'page info')) {
Expand Down
112 changes: 0 additions & 112 deletions server/src/shopify/productVariant.ts

This file was deleted.

9 changes: 3 additions & 6 deletions shared/src/model/inventory.model.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import {Static, Type} from "@fastify/type-provider-typebox";

export const VariantInventorySchema = Type.Object({
export const InventorySchema = Type.Object({
totalInventory: Type.Integer(),
totalCommittedInventory: Type.Integer(),
totalAvailableInventory: Type.Integer(),
inventoryItem: Type.Object({
inventoryLevels: Type.Null() // TODO
})
totalAvailableInventory: Type.Integer()
})
export type VariantInventory = Static<typeof VariantInventorySchema>
export type Inventory = Static<typeof InventorySchema>
4 changes: 3 additions & 1 deletion shared/src/model/product.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Static, Type } from '@fastify/type-provider-typebox'
import { ImageObjSchema } from './image.model'
import { VariantSchema } from './variant.model'
import { PageInfoSchema } from './response.model'
import {InventorySchema} from "./inventory.model";

export const ProductSchema = Type.Object({
id: Type.String(),
Expand All @@ -13,7 +14,8 @@ export const ProductSchema = Type.Object({
variants: Type.Object({
nodes: Type.Array(VariantSchema)
}),
totalInventory: Type.Integer()
totalInventory: Type.Integer(),
inventory: InventorySchema
})
export type Product = Static<typeof ProductSchema>

Expand Down
6 changes: 3 additions & 3 deletions shared/src/model/variant.model.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { Static, Type } from '@fastify/type-provider-typebox'
import { ImageObjSchema } from './image.model'
import { Nullable } from './misc'
import {VariantInventorySchema} from "./inventory.model";
import {InventorySchema} from "./inventory.model";

export const VariantSchema = Type.Object({
id: Type.String(),
title: Type.String(),
image: Nullable(ImageObjSchema), // TODO: Should this be optional?
image: Nullable(ImageObjSchema),
contextualPricing: Type.Object({
price: Type.Object({
amount: Type.String(),
currencyCode: Type.String()
})
}),
sku: Nullable(Type.String()),
inventory: VariantInventorySchema
inventory: InventorySchema
})
export type Variant = Static<typeof VariantSchema>

0 comments on commit 085a4c3

Please sign in to comment.