Current section

Files

Jump to
shopifex lib shopifex_web controllers payment_controller.ex
Raw

lib/shopifex_web/controllers/payment_controller.ex

defmodule ShopifexWeb.PaymentController do
@moduledoc """
You can use this module inside of another controller to handle initial iFrame load and shop installation
Example:
mix phx.gen.html Shops Plan plans name:string price:string features:array grants:array test:boolean
mix phx.gen.html Shops Grant grants shop:references:shops charge_id:integer grants:array
```elixir
defmodule MyAppWeb.PaymentController do
use MyAppWeb, :controller
use ShopifexWeb.PaymentController
# Thats it! You can now configure your purchasable products :)
end
```
"""
@doc """
An optional callback called after a payment is completed. By default, this function
redirects the user to the app index within their Shopify admin panel.
## Example
def after_payment(conn, shop, plan, grant) do
# send yourself an e-mail about payment
# follow default behaviour.
super(conn, shop, plan, grant)
end
"""
@callback after_payment(
Plug.Conn.t(),
Ecto.Schema.t(),
Ecto.Schema.t(),
Ecto.Schema.t()
) ::
Plug.Conn.t()
@optional_callbacks after_payment: 4
defmacro __using__(_opts) do
quote do
@behaviour ShopifexWeb.PaymentController
require Logger
@doc """
Displays a list of available plans with which the user can access
the guarded feature
"""
def show_plans(conn, %{"guard" => guard, "redirect_after" => redirect_after}) do
plans = Shopifex.Shops.list_plans_granting_guard(guard)
conn
|> put_view(ShopifexWeb.PaymentView)
|> put_layout({ShopifexWeb.LayoutView, "app.html"})
|> render("show-plans.html",
plans: plans,
guard: guard,
redirect_after: redirect_after,
shop_url: conn.private.shop_url
)
end
def select_plan(conn, %{"plan_id" => plan_id, "redirect_after" => redirect_after}) do
plan = Shopifex.Shops.get_plan!(plan_id)
shop = conn.private.shop
{:ok, charge} = create_charge(shop, plan)
Shopifex.RedirectAfterAgent.set(charge["id"], redirect_after)
send_resp(conn, 200, Jason.encode!(charge))
end
defp create_charge(shop, plan = %{type: "recurring_application_charge"}) do
redirect_uri = Application.get_env(:shopifex, :payment_redirect_uri)
body =
Jason.encode!(%{
recurring_application_charge: %{
name: plan.name,
price: plan.price,
test: plan.test,
return_url: "#{redirect_uri}?plan_id=#{plan.id}"
}
})
case HTTPoison.post(
"https://#{shop.url}/admin/api/2021-01/recurring_application_charges.json",
body,
"X-Shopify-Access-Token": shop.access_token,
"Content-Type": "application/json"
) do
{:ok, resp} ->
{:ok, Jason.decode!(resp.body)["recurring_application_charge"]}
end
end
defp create_charge(shop, plan = %{type: "application_charge"}) do
redirect_uri = Application.get_env(:shopifex, :payment_redirect_uri)
body =
Jason.encode!(%{
application_charge: %{
name: plan.name,
price: plan.price,
test: plan.test,
return_url: "#{redirect_uri}?plan_id=#{plan.id}"
}
})
case HTTPoison.post(
"https://#{shop.url}/admin/api/2021-01/application_charges.json",
body,
"X-Shopify-Access-Token": shop.access_token,
"Content-Type": "application/json"
) do
{:ok, resp} ->
{:ok, Jason.decode!(resp.body)["application_charge"]}
end
end
def complete_payment(conn, %{
"charge_id" => charge_id,
"plan_id" => plan_id
}) do
plan = Shopifex.Shops.get_plan!(plan_id)
shop = conn.private.shop
{:ok, grant} =
Shopifex.Shops.create_grant(%{
shop: shop,
charge_id: charge_id,
grants: plan.grants,
remaining_usages: plan.usages
})
after_payment(conn, shop, plan, grant)
end
@impl ShopifexWeb.PaymentController
def after_payment(conn, shop, plan, grant) do
redirect_after = Shopifex.RedirectAfterAgent.get(grant.charge_id)
api_key = Application.get_env(:shopifex, :api_key)
redirect(conn, external: "https://#{shop.url}/admin/apps/#{api_key}#{redirect_after}")
end
defoverridable after_payment: 4
end
end
end