From 4e19d4c4a96fee3a032ddcb6546087fae2ca4631 Mon Sep 17 00:00:00 2001 From: jamey Date: Mon, 16 Feb 2026 00:11:18 +0000 Subject: [PATCH] fetch catalog color hex codes during Printful sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- lib/simpleshop_theme/providers/printful.ex | 56 ++++++++++++++++++---- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/lib/simpleshop_theme/providers/printful.ex b/lib/simpleshop_theme/providers/printful.ex index 338675f..b938470 100644 --- a/lib/simpleshop_theme/providers/printful.ex +++ b/lib/simpleshop_theme/providers/printful.ex @@ -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 =