defmodule SimpleshopTheme.OrdersTest do use SimpleshopTheme.DataCase, async: false import Mox import SimpleshopTheme.OrdersFixtures alias SimpleshopTheme.Orders alias SimpleshopTheme.Providers.MockProvider setup :verify_on_exit! describe "list_orders/1" do test "returns all orders" do order1 = order_fixture() order2 = order_fixture() orders = Orders.list_orders() order_ids = Enum.map(orders, & &1.id) assert order1.id in order_ids assert order2.id in order_ids assert length(orders) == 2 end test "filters by payment status" do _pending = order_fixture() paid = order_fixture(payment_status: "paid") _failed = order_fixture(payment_status: "failed") orders = Orders.list_orders(status: "paid") assert length(orders) == 1 assert hd(orders).id == paid.id end test "returns all when status is 'all'" do order_fixture() order_fixture(payment_status: "paid") orders = Orders.list_orders(status: "all") assert length(orders) == 2 end test "preloads items" do order_fixture() [order] = Orders.list_orders() assert Ecto.assoc_loaded?(order.items) assert length(order.items) == 1 end end describe "count_orders_by_status/0" do test "returns empty map when no orders" do assert Orders.count_orders_by_status() == %{} end test "counts orders by status" do order_fixture() order_fixture() order_fixture(payment_status: "paid") order_fixture(payment_status: "failed") counts = Orders.count_orders_by_status() assert counts["pending"] == 2 assert counts["paid"] == 1 assert counts["failed"] == 1 end end describe "submit_to_provider/1" do setup do Application.put_env(:simpleshop_theme, :provider_modules, %{ "printify" => MockProvider }) on_exit(fn -> Application.delete_env(:simpleshop_theme, :provider_modules) end) :ok end test "submits order and sets fulfilment status" do {order, _variant, _product, _conn} = paid_order_with_products_fixture() expect(MockProvider, :submit_order, fn _conn, order_data -> assert order_data.order_number == order.order_number assert is_list(order_data.line_items) assert hd(order_data.line_items).quantity == 1 {:ok, %{provider_order_id: "pfy_123"}} end) assert {:ok, updated} = Orders.submit_to_provider(order) assert updated.fulfilment_status == "submitted" assert updated.provider_order_id == "pfy_123" assert updated.submitted_at != nil assert updated.fulfilment_error == nil end test "is idempotent when already submitted" do {order, _variant, _product, _conn} = submitted_order_fixture() # No mock expectations — provider should not be called assert {:ok, ^order} = Orders.submit_to_provider(order) end test "sets failed status on provider error" do {order, _variant, _product, _conn} = paid_order_with_products_fixture() expect(MockProvider, :submit_order, fn _conn, _data -> {:error, {500, %{"message" => "Server error"}}} end) assert {:error, {500, _}} = Orders.submit_to_provider(order) updated = Orders.get_order(order.id) assert updated.fulfilment_status == "failed" assert updated.fulfilment_error =~ "Provider API error (500)" end end describe "refresh_fulfilment_status/1" do setup do Application.put_env(:simpleshop_theme, :provider_modules, %{ "printify" => MockProvider }) on_exit(fn -> Application.delete_env(:simpleshop_theme, :provider_modules) end) :ok end test "updates tracking info from provider" do {order, _variant, _product, _conn} = submitted_order_fixture() expect(MockProvider, :get_order_status, fn _conn, pid -> assert pid == order.provider_order_id {:ok, %{ status: "shipped", provider_status: "shipped", tracking_number: "TRACK123", tracking_url: "https://track.example.com/TRACK123" }} end) assert {:ok, updated} = Orders.refresh_fulfilment_status(order) assert updated.fulfilment_status == "shipped" assert updated.tracking_number == "TRACK123" assert updated.tracking_url == "https://track.example.com/TRACK123" assert updated.shipped_at != nil end test "no-op when no provider_order_id" do order = order_fixture(payment_status: "paid") assert is_nil(order.provider_order_id) assert {:ok, ^order} = Orders.refresh_fulfilment_status(order) end end describe "update_fulfilment/2" do test "updates fulfilment fields" do order = order_fixture() assert {:ok, updated} = Orders.update_fulfilment(order, %{ fulfilment_status: "submitted", provider_order_id: "test_123" }) assert updated.fulfilment_status == "submitted" assert updated.provider_order_id == "test_123" end test "validates fulfilment status inclusion" do order = order_fixture() assert {:error, changeset} = Orders.update_fulfilment(order, %{fulfilment_status: "bogus"}) assert errors_on(changeset).fulfilment_status != [] end end describe "list_submitted_orders/0" do test "returns orders with submitted or processing status" do {submitted, _v, _p, _c} = submitted_order_fixture() {processing, _v2, _p2, _c2} = submitted_order_fixture() {:ok, processing} = Orders.update_fulfilment(processing, %{fulfilment_status: "processing"}) _unfulfilled = order_fixture(payment_status: "paid") orders = Orders.list_submitted_orders() ids = Enum.map(orders, & &1.id) assert submitted.id in ids assert processing.id in ids assert length(orders) == 2 end test "returns empty list when no submitted orders" do order_fixture() assert Orders.list_submitted_orders() == [] end end describe "get_order_by_number/1" do test "finds order by order number" do order = order_fixture() found = Orders.get_order_by_number(order.order_number) assert found.id == order.id end test "returns nil for unknown order number" do assert is_nil(Orders.get_order_by_number("SS-000000-XXXX")) end end end