add shipping costs with live exchange rates and country detection

Shipping rates fetched from Printify during product sync, converted to
GBP at sync time using frankfurter.app ECB exchange rates with 5%
buffer. Cached in shipping_rates table per blueprint/provider/country.

Cart page shows shipping estimate with country selector (detected from
Accept-Language header, persisted in cookie). Stripe Checkout includes
shipping_options for UK domestic and international delivery. Order
shipping_cost extracted from Stripe on payment.

ScheduledSyncWorker runs every 6 hours via Oban cron to keep rates
and exchange rates fresh. REST_OF_THE_WORLD fallback covers unlisted
countries. 780 tests, 0 failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey
2026-02-14 10:48:00 +00:00
parent 44933acebb
commit 5c2f70ce44
26 changed files with 1707 additions and 38 deletions

View File

@@ -0,0 +1,30 @@
defmodule SimpleshopTheme.Repo.Migrations.CreateShippingRates do
use Ecto.Migration
def change do
create table(:shipping_rates, primary_key: false) do
add :id, :binary_id, primary_key: true
add :provider_connection_id,
references(:provider_connections, type: :binary_id, on_delete: :delete_all),
null: false
add :blueprint_id, :integer, null: false
add :print_provider_id, :integer, null: false
add :country_code, :string, null: false
add :first_item_cost, :integer, null: false
add :additional_item_cost, :integer, null: false
add :currency, :string, null: false, default: "USD"
add :handling_time_days, :integer
timestamps(type: :utc_datetime)
end
create unique_index(:shipping_rates, [
:provider_connection_id,
:blueprint_id,
:print_provider_id,
:country_code
])
end
end