fetch catalog color hex codes during Printful sync

Printful sync variants don't include color_code — hex values are only
available from the catalog product endpoint. Fetch catalog colors per
unique product type during sync (cached in process dictionary to avoid
duplicate calls) and store as "colors" array in option values, matching
the Printify format that Product.option_types expects.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey 2026-02-16 00:11:18 +00:00
parent daa6d3de71
commit 4e19d4c4a9

View File

@ -76,7 +76,9 @@ defmodule SimpleshopTheme.Providers.Printful do
case Client.get_sync_product(product["id"]) do
{:ok, detail} ->
normalize_product(detail["sync_product"], detail["sync_variants"] || [])
sync_variants = detail["sync_variants"] || []
catalog_colors = fetch_catalog_colors(sync_variants)
normalize_product(detail["sync_product"], sync_variants, catalog_colors)
{:error, reason} ->
Logger.warning(
@ -106,6 +108,42 @@ defmodule SimpleshopTheme.Providers.Printful do
end
end
# Fetch catalog color hex codes for a product's catalog type.
# Caches per catalog_product_id in the process dictionary to avoid duplicate calls.
defp fetch_catalog_colors(sync_variants) do
catalog_product_id = extract_catalog_product_id_from_variants(sync_variants)
cache_key = {:catalog_colors, catalog_product_id}
case Process.get(cache_key) do
nil ->
colors = do_fetch_catalog_colors(catalog_product_id)
Process.put(cache_key, colors)
colors
cached ->
cached
end
end
defp do_fetch_catalog_colors(0), do: %{}
defp do_fetch_catalog_colors(catalog_product_id) do
Process.sleep(100)
case Client.get_catalog_product(catalog_product_id) do
{:ok, catalog} ->
(catalog["colors"] || [])
|> Map.new(fn c -> {c["name"], c["value"]} end)
{:error, reason} ->
Logger.warning(
"Failed to fetch catalog colors for product #{catalog_product_id}: #{inspect(reason)}"
)
%{}
end
end
# =============================================================================
# Orders
# =============================================================================
@ -295,7 +333,7 @@ defmodule SimpleshopTheme.Providers.Printful do
# Data Normalization
# =============================================================================
defp normalize_product(sync_product, sync_variants) do
defp normalize_product(sync_product, sync_variants, catalog_colors) do
images = extract_preview_images(sync_variants)
catalog_product_id = extract_catalog_product_id_from_variants(sync_variants)
catalog_variant_ids = Enum.map(sync_variants, & &1["variant_id"]) |> Enum.reject(&is_nil/1)
@ -322,7 +360,7 @@ defmodule SimpleshopTheme.Providers.Printful do
print_provider_id: 0,
thumbnail_url: sync_product["thumbnail_url"],
artwork_url: extract_artwork_url(sync_variants),
options: build_option_types(sync_variants),
options: build_option_types(sync_variants, catalog_colors),
raw: %{sync_product: sync_product}
}
}
@ -395,16 +433,18 @@ defmodule SimpleshopTheme.Providers.Printful do
end) || 0
end
# Build option types from variants for frontend display
defp build_option_types(sync_variants) do
# Build colour values with hex codes from sync variant data
# Build option types from variants for frontend display.
# catalog_colors is a %{"Black" => "#0b0b0b", ...} map from the catalog API.
defp build_option_types(sync_variants, catalog_colors) do
colors =
sync_variants
|> Enum.reject(fn sv -> is_nil(sv["color"]) end)
|> Enum.uniq_by(fn sv -> sv["color"] end)
|> Enum.map(fn sv ->
base = %{"title" => normalize_text(sv["color"])}
if sv["color_code"], do: Map.put(base, "hex", sv["color_code"]), else: base
title = normalize_text(sv["color"])
base = %{"title" => title}
hex = Map.get(catalog_colors, sv["color"])
if hex, do: Map.put(base, "colors", [hex]), else: base
end)
sizes =