add Printful mockup generator and post-sync angle enrichment
New PrintfulGenerator module creates demo products in Printful with multi-variant support (multiple colours/sizes per product type). Mix task gets --provider flag to choose between Printify and Printful. After syncing Printful products, MockupEnricher Oban worker calls the legacy mockup generator API to produce extra angle images (back, left, right) and appends them as product images. Jobs are staggered 45s apart with snooze-based 429 handling. Flat products (canvas, poster) get no extras — apparel and 3D products get 1-5 extra angles each. Also fixes: - cross-provider slug uniqueness (appends -2, -3 suffix) - category mapping order (Accessories before Canvas Prints) - image dedup by URL instead of colour (fixes canvas variants) - artwork URL stored in provider_data for enricher access Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -314,6 +314,7 @@ defmodule SimpleshopTheme.Providers.Printful do
|
||||
blueprint_id: catalog_product_id,
|
||||
print_provider_id: 0,
|
||||
thumbnail_url: sync_product["thumbnail_url"],
|
||||
artwork_url: extract_artwork_url(sync_variants),
|
||||
options: build_option_types(sync_variants),
|
||||
raw: %{sync_product: sync_product}
|
||||
}
|
||||
@@ -345,7 +346,7 @@ defmodule SimpleshopTheme.Providers.Printful do
|
||||
opts
|
||||
end
|
||||
|
||||
# Extract unique preview images from sync variants (one per unique colour)
|
||||
# Extract unique preview images from sync variants (one per unique image URL)
|
||||
defp extract_preview_images(sync_variants) do
|
||||
sync_variants
|
||||
|> Enum.flat_map(fn sv ->
|
||||
@@ -354,18 +355,28 @@ defmodule SimpleshopTheme.Providers.Printful do
|
||||
|> Enum.map(fn file ->
|
||||
%{
|
||||
src: file["preview_url"] || file["thumbnail_url"],
|
||||
color: sv["color"]
|
||||
color: sv["color"],
|
||||
name: sv["name"]
|
||||
}
|
||||
end)
|
||||
end)
|
||||
|> Enum.uniq_by(& &1.color)
|
||||
|> Enum.uniq_by(& &1.src)
|
||||
|> Enum.with_index()
|
||||
|> Enum.map(fn {img, index} ->
|
||||
%{
|
||||
src: img.src,
|
||||
position: index,
|
||||
alt: img.color
|
||||
}
|
||||
alt = if img.color not in [nil, ""], do: img.color, else: img.name
|
||||
%{src: img.src, position: index, alt: alt}
|
||||
end)
|
||||
end
|
||||
|
||||
# Find the artwork (design file) URL from the first variant's "default" file
|
||||
defp extract_artwork_url(sync_variants) do
|
||||
sync_variants
|
||||
|> Enum.find_value(fn sv ->
|
||||
(sv["files"] || [])
|
||||
|> Enum.find_value(fn
|
||||
%{"type" => "default", "url" => url} when is_binary(url) -> url
|
||||
_ -> nil
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
@@ -423,10 +434,10 @@ defmodule SimpleshopTheme.Providers.Printful do
|
||||
|
||||
cond do
|
||||
has_keyword?(name_lower, ~w[t-shirt tshirt shirt hoodie sweatshirt jogger]) -> "Apparel"
|
||||
has_keyword?(name_lower, ~w[bag tote hat cap sleeve phone case]) -> "Accessories"
|
||||
has_keyword?(name_lower, ~w[mug cup blanket pillow cushion throw]) -> "Homewares"
|
||||
has_keyword?(name_lower, ~w[canvas poster print frame]) -> "Canvas Prints"
|
||||
has_keyword?(name_lower, ~w[mug cup blanket pillow cushion]) -> "Homewares"
|
||||
has_keyword?(name_lower, ~w[notebook journal]) -> "Stationery"
|
||||
has_keyword?(name_lower, ~w[phone case bag tote hat cap]) -> "Accessories"
|
||||
true -> "Apparel"
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user