2026-02-07 08:30:17 +00:00
|
|
|
defmodule SimpleshopThemeWeb.CheckoutController do
|
|
|
|
|
use SimpleshopThemeWeb, :controller
|
|
|
|
|
|
|
|
|
|
alias SimpleshopTheme.Cart
|
|
|
|
|
alias SimpleshopTheme.Orders
|
|
|
|
|
|
|
|
|
|
require Logger
|
|
|
|
|
|
|
|
|
|
def create(conn, _params) do
|
|
|
|
|
cart_items = Cart.get_from_session(get_session(conn))
|
|
|
|
|
hydrated = Cart.hydrate(cart_items)
|
|
|
|
|
|
2026-02-08 15:19:42 +00:00
|
|
|
if hydrated == [] do
|
|
|
|
|
conn
|
|
|
|
|
|> put_flash(:error, "Your basket is empty")
|
|
|
|
|
|> redirect(to: ~p"/cart")
|
|
|
|
|
else
|
|
|
|
|
create_checkout(conn, hydrated)
|
2026-02-07 08:30:17 +00:00
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp create_checkout(conn, hydrated_items) do
|
|
|
|
|
# Create a pending order with price snapshots
|
|
|
|
|
case Orders.create_order(%{items: hydrated_items}) do
|
|
|
|
|
{:ok, order} ->
|
|
|
|
|
create_stripe_session(conn, order, hydrated_items)
|
|
|
|
|
|
|
|
|
|
{:error, _changeset} ->
|
|
|
|
|
Logger.error("Failed to create order")
|
|
|
|
|
|
|
|
|
|
conn
|
|
|
|
|
|> put_flash(:error, "Something went wrong. Please try again.")
|
|
|
|
|
|> redirect(to: ~p"/cart")
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp create_stripe_session(conn, order, hydrated_items) do
|
|
|
|
|
line_items =
|
|
|
|
|
Enum.map(hydrated_items, fn item ->
|
|
|
|
|
product_name =
|
|
|
|
|
if item.variant,
|
|
|
|
|
do: "#{item.name} — #{item.variant}",
|
|
|
|
|
else: item.name
|
|
|
|
|
|
|
|
|
|
%{
|
|
|
|
|
price_data: %{
|
|
|
|
|
currency: "gbp",
|
|
|
|
|
unit_amount: item.price,
|
|
|
|
|
product_data: %{name: product_name}
|
|
|
|
|
},
|
|
|
|
|
quantity: item.quantity
|
|
|
|
|
}
|
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
base_url = SimpleshopThemeWeb.Endpoint.url()
|
|
|
|
|
|
|
|
|
|
params = %{
|
|
|
|
|
mode: "payment",
|
|
|
|
|
line_items: line_items,
|
|
|
|
|
success_url: "#{base_url}/checkout/success?session_id={CHECKOUT_SESSION_ID}",
|
|
|
|
|
cancel_url: "#{base_url}/cart",
|
|
|
|
|
metadata: %{"order_id" => order.id},
|
|
|
|
|
shipping_address_collection: %{
|
|
|
|
|
allowed_countries: ["GB", "US", "CA", "AU", "DE", "FR", "NL", "IE", "AT", "BE"]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case Stripe.Checkout.Session.create(params) do
|
|
|
|
|
{:ok, session} ->
|
|
|
|
|
{:ok, _order} = Orders.set_stripe_session(order, session.id)
|
|
|
|
|
|
|
|
|
|
conn
|
|
|
|
|
|> redirect(external: session.url)
|
|
|
|
|
|
|
|
|
|
{:error, %Stripe.Error{message: message}} ->
|
|
|
|
|
Logger.error("Stripe session creation failed: #{message}")
|
|
|
|
|
Orders.mark_failed(order)
|
|
|
|
|
|
|
|
|
|
conn
|
|
|
|
|
|> put_flash(:error, "Payment setup failed. Please try again.")
|
|
|
|
|
|> redirect(to: ~p"/cart")
|
|
|
|
|
|
|
|
|
|
{:error, reason} ->
|
|
|
|
|
Logger.error("Stripe session creation failed: #{inspect(reason)}")
|
|
|
|
|
Orders.mark_failed(order)
|
|
|
|
|
|
|
|
|
|
conn
|
|
|
|
|
|> put_flash(:error, "Payment setup failed. Please try again.")
|
|
|
|
|
|> redirect(to: ~p"/cart")
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|