Submit paid orders to Printify via provider API with idempotent guards, Stripe address mapping, and error handling. Track fulfilment status through submitted → processing → shipped → delivered via webhook-driven updates (primary) and Oban Cron polling fallback. - 9 fulfilment fields on orders (status, provider IDs, tracking, timestamps) - OrderSubmissionWorker with retry logic, auto-enqueued after Stripe payment - FulfilmentStatusWorker polls every 30 mins for missed webhook events - Printify order webhook handlers (sent-to-production, shipment, delivered) - Admin UI: fulfilment column in table, fulfilment card with tracking info, submit/retry and refresh buttons on order detail - Mox provider mocking for test isolation (Provider.for_type configurable) - 33 new tests (555 total), verified against real Printify API Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
111 lines
3.0 KiB
Elixir
111 lines
3.0 KiB
Elixir
defmodule SimpleshopTheme.OrdersFixtures do
|
|
@moduledoc """
|
|
Test helpers for creating orders.
|
|
"""
|
|
|
|
alias SimpleshopTheme.Orders
|
|
|
|
import SimpleshopTheme.ProductsFixtures
|
|
|
|
def order_fixture(attrs \\ %{}) do
|
|
attrs = Enum.into(attrs, %{})
|
|
|
|
items = [
|
|
%{
|
|
variant_id: Map.get(attrs, :variant_id, "var_#{System.unique_integer([:positive])}"),
|
|
name: Map.get(attrs, :product_name, "Test product"),
|
|
variant: Map.get(attrs, :variant_title, "Red / Large"),
|
|
price: Map.get(attrs, :unit_price, 1999),
|
|
quantity: Map.get(attrs, :quantity, 1)
|
|
}
|
|
]
|
|
|
|
order_attrs = %{
|
|
items: items,
|
|
customer_email: Map.get(attrs, :customer_email, "customer@example.com"),
|
|
currency: Map.get(attrs, :currency, "gbp")
|
|
}
|
|
|
|
{:ok, order} = Orders.create_order(order_attrs)
|
|
|
|
# Apply shipping address if provided
|
|
order =
|
|
case attrs[:shipping_address] do
|
|
nil ->
|
|
order
|
|
|
|
addr ->
|
|
{:ok, order} = Orders.update_order(order, %{shipping_address: addr})
|
|
order
|
|
end
|
|
|
|
case attrs[:payment_status] do
|
|
"paid" ->
|
|
{:ok, order} = Orders.mark_paid(order, "pi_test_#{System.unique_integer([:positive])}")
|
|
order
|
|
|
|
"failed" ->
|
|
{:ok, order} = Orders.mark_failed(order)
|
|
order
|
|
|
|
_ ->
|
|
order
|
|
end
|
|
end
|
|
|
|
@doc """
|
|
Creates a paid order with real product variants in the DB,
|
|
so enrich_items/1 can look up provider IDs. Also sets a shipping
|
|
address matching Stripe's format.
|
|
|
|
Returns `{order, variant, product, conn}`.
|
|
"""
|
|
def paid_order_with_products_fixture(attrs \\ %{}) do
|
|
attrs = Enum.into(attrs, %{})
|
|
conn = provider_connection_fixture(%{provider_type: "printify"})
|
|
product = product_fixture(%{provider_connection: conn})
|
|
variant = product_variant_fixture(%{product: product})
|
|
|
|
shipping =
|
|
Map.get(attrs, :shipping_address, %{
|
|
"name" => "Jane Doe",
|
|
"line1" => "42 Test Street",
|
|
"line2" => nil,
|
|
"city" => "London",
|
|
"postal_code" => "SW1A 1AA",
|
|
"state" => nil,
|
|
"country" => "GB"
|
|
})
|
|
|
|
order =
|
|
order_fixture(%{
|
|
variant_id: variant.id,
|
|
payment_status: "paid",
|
|
shipping_address: shipping,
|
|
customer_email: Map.get(attrs, :customer_email, "buyer@example.com")
|
|
})
|
|
|
|
{order, variant, product, conn}
|
|
end
|
|
|
|
@doc """
|
|
Creates a submitted order (has provider_order_id set).
|
|
Returns `{order, variant, product, conn}`.
|
|
"""
|
|
def submitted_order_fixture(attrs \\ %{}) do
|
|
{order, variant, product, conn} = paid_order_with_products_fixture(attrs)
|
|
|
|
attrs = Enum.into(attrs, %{})
|
|
|
|
{:ok, order} =
|
|
Orders.update_fulfilment(order, %{
|
|
fulfilment_status: "submitted",
|
|
provider_order_id:
|
|
Map.get(attrs, :provider_order_id, "printify_#{System.unique_integer([:positive])}"),
|
|
submitted_at: DateTime.utc_now() |> DateTime.truncate(:second)
|
|
})
|
|
|
|
{order, variant, product, conn}
|
|
end
|
|
end
|