Skip to content

Instantly share code, notes, and snippets.

@nicolkill
Last active March 17, 2023 16:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nicolkill/508f4446ee801e50b6f0f01c14c58802 to your computer and use it in GitHub Desktop.
Save nicolkill/508f4446ee801e50b6f0f01c14c58802 to your computer and use it in GitHub Desktop.
defmodule Nicolkill.Cache do
@moduledoc """
Cache wrapper for store key: value in ETS
"""
@cache_table :cache
defp init_table() do
if :ets.info(@cache_table) == :undefined do
:ets.new(@cache_table, [:set, :public, :named_table])
end
end
def save_value(key, value) do
init_table()
:ets.insert(@cache_table, {key, value})
end
def get_value(key) do
init_table()
case :ets.lookup(@cache_table, key) do
[{_, value}] -> value
_ -> nil
end
end
end
defmodule Nicolkill.PaypalClient do
@moduledoc """
Api wrapper for the paypal api
"""
use Tesla
alias Nicolkill.Cache
@paypal_config Application.get_env(:pl_connect, :paypal_config)
plug Tesla.Middleware.BaseUrl, @paypal_config[:url]
plug Tesla.Middleware.Headers, [{"accept", "application/json"}]
plug Tesla.Middleware.JSON
defp request_token() do
basic_auth = Base.encode64("#{@paypal_config[:client]}:#{@paypal_config[:secret]}")
headers = [{"authorization", "Basic #{basic_auth}"}]
%{
"token_type" => token_type,
"access_token" => access_token,
"expires_in" => expires_in
} = post!("/v1/oauth2/token/", "grant_type=client_credentials", headers: headers)
|> (&(&1.body)).()
expire_date = Timex.now()
|> Timex.shift(seconds: expires_in)
{token_type, access_token, expire_date}
end
defp get_and_save_token() do
{token_type, access_token, expire_date} = request_token()
Cache.save_value(:paypal_token, {token_type, access_token, expire_date})
{token_type, access_token}
end
@doc """
"""
@spec get_token() :: {String.t(), String.t()}
def get_token() do
case Cache.get_value(paypal_token) do
{token_type, access_token, expire_date} ->
if Timex.before?(Timex.now(), expire_date) do
{token_type, access_token}
else
get_and_save_token()
end
_ ->
get_and_save_token()
end
end
@spec complete_transaction!(String.t(), String.t()) :: number()
def complete_transaction!(order_id, authorization_id) do
{type, access_token} = get_token()
headers = [{"authorization", "#{type} #{access_token}"}]
%{"purchase_units" => [%{"amount" => %{"value" => amount}}]} =
get!("/v2/checkout/orders/#{order_id}", headers: headers)
|> (&(&1.body)).()
amount = Float.parse(amount) |> elem(0)
%{"id" => capture_id} = post!("/v2/payments/authorizations/#{authorization_id}/capture", %{}, headers: headers)
|> (&(&1.body)).()
{:ok, capture_id, amount}
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment