Skip to content

Commit

Permalink
bigcommerce: link existing customer (#154)
Browse files Browse the repository at this point in the history
  • Loading branch information
ah-s76 authored Nov 12, 2024
1 parent 285a7ef commit ea413f2
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lib/recognizer/accounts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ defmodule Recognizer.Accounts do

def maybe_create_big_commerce_customer({:ok, user}) do
if BigCommerce.enabled?() do
BigCommerce.create_customer(user)
BigCommerce.get_or_create_customer(user)
else
{:ok, user}
end
Expand Down
21 changes: 21 additions & 0 deletions lib/recognizer/bigcommerce.ex
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,27 @@ defmodule Recognizer.BigCommerce do
end
end

def get_or_create_customer(%{email: email, id: id} = user) do
case Client.get_customers(emails: [email]) do
{:ok, []} ->
create_customer(user)

{:ok, [customer_id]} ->
Logger.info("found existing customer for account create: #{inspect(email)}")
Repo.insert(%Customer{user_id: id, bc_id: customer_id})
{:ok, user}

e ->
Logger.error("error while getting or creating customer: #{inspect(e)}")
{:error, e}
end
end

def get_or_create_customer(e) do
Logger.error("unexpected customer #{e}")
{:error, "unexpected customer"}
end

def update_customer(user) do
case Client.update_customer(Repo.preload(user, :bigcommerce_user)) do
{:ok, _} ->
Expand Down
47 changes: 47 additions & 0 deletions lib/recognizer/bigcommerce/client.ex
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,53 @@ defmodule Recognizer.BigCommerce.Client do
end
end

def get_customers(queries \\ []) do
with params <- customer_queries_as_params(queries),
full_uri <- customers_uri(),
headers <- default_headers(),
:ok <- Logger.debug("GET bigcommerce customers by params: #{inspect(params)}"),
{:ok, %Response{body: response, status_code: 200}} <-
http_client().get(full_uri, headers, params: params),
{:ok, %{"data" => customers}} <- Jason.decode(response),
customer_ids <- Enum.map(customers, fn %{"id" => id} -> id end) do
{:ok, customer_ids}
else
{:ok, %Response{status_code: 429, headers: headers}} ->
sleep_for_rate_limit(headers)
get_customers(queries)

{:ok, %Response{status_code: 503}} ->
sleep_for_rate_limit(@default_retry_ms)
get_customers(queries)

{_, %Response{body: body, status_code: code}} ->
Logger.error("Unexpected http response #{inspect(code)}: #{inspect(body)}")
{:error, code}

e ->
Logger.error("cannot get customers with error: #{inspect(e)}")
{:error, e}
end
end

defp customer_queries_as_params(queries) do
[]
|> Keyword.merge(
case Keyword.get(queries, :emails) do
nil -> []
[] -> []
emails -> [{"email:in", Enum.join(emails, ",")}]
end
)
|> Keyword.merge(
case Keyword.get(queries, :ids) do
nil -> []
[] -> []
ids -> [{"id:in", Enum.join(ids, ",")}]
end
)
end

defp get_id(response) do
case Jason.decode(response) do
{:ok, %{"data" => [%{"id" => id}]}} -> {:ok, id}
Expand Down
5 changes: 5 additions & 0 deletions test/recognizer/accounts_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ defmodule Recognizer.AccountsTest do
end

describe "register_user/1" do
setup do
stub(HTTPoisonMock, :get, fn _, _, _ -> empty_bigcommerce_response() end)
:ok
end

test "requires email and password to be set" do
{:error, changeset} = Accounts.register_user(%{})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ defmodule RecognizerWeb.Api.UserRegistrationControllerTest do
setup :verify_on_exit!
setup :register_and_log_in_admin

setup do
stub(HTTPoisonMock, :get, fn _, _, _ -> empty_bigcommerce_response() end)
:ok
end

describe "POST /api/create-account" do
test "POST /api/create-account is limited to staff only", %{conn: conn} do
user = %{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ defmodule RecognizerWeb.Accounts.UserRegistrationControllerTest do
describe "POST /users/register" do
@tag :capture_log
test "creates account and prompts for verification", %{conn: conn} do
expect(HTTPoisonMock, :get, 1, fn _, _, _ -> empty_bigcommerce_response() end)
expect(HTTPoisonMock, :post, 1, fn _, _, _ -> ok_bigcommerce_response() end)

conn =
Expand All @@ -80,6 +81,19 @@ defmodule RecognizerWeb.Accounts.UserRegistrationControllerTest do
assert Repo.get_by(BCCustomerUser, bc_id: 1001)
end

test "creates account linked to existing bigcommerce account", %{conn: conn} do
expect(HTTPoisonMock, :get, 1, fn _, _, _ -> ok_bigcommerce_response() end)

conn =
post(conn, Routes.user_registration_path(conn, :create), %{
"user" => params_for(:user)
})

refute Recognizer.Guardian.Plug.current_resource(conn)
assert redirected_to(conn) =~ "/prompt/verification"
assert Repo.get_by(BCCustomerUser, bc_id: 1001)
end

test "render errors for invalid data", %{conn: conn} do
conn =
post(conn, Routes.user_registration_path(conn, :create), %{
Expand All @@ -95,6 +109,7 @@ defmodule RecognizerWeb.Accounts.UserRegistrationControllerTest do

@tag :capture_log
test "renders an error page for a bigcommerce failure", %{conn: conn} do
expect(HTTPoisonMock, :get, 1, fn _, _, _ -> empty_bigcommerce_response() end)
expect(HTTPoisonMock, :post, 1, fn _, _, _ -> bad_bigcommerce_response() end)

conn =
Expand All @@ -109,6 +124,7 @@ defmodule RecognizerWeb.Accounts.UserRegistrationControllerTest do
end

test "rate limits account creation", %{conn: conn} do
stub(HTTPoisonMock, :get, fn _, _, _ -> empty_bigcommerce_response() end)
stub(HTTPoisonMock, :post, fn _, _, _ -> ok_bigcommerce_response() end)

Enum.each(0..20, fn _ ->
Expand Down
6 changes: 6 additions & 0 deletions test/support/bigcommerce_test_helpers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ defmodule Recognizer.BigCommerceTestHelpers do
{:ok, %HTTPoison.Response{body: body, status_code: 200}}
end

def empty_bigcommerce_response() do
body = Jason.encode!(%{data: []})

{:ok, %HTTPoison.Response{body: body, status_code: 200}}
end

def bad_bigcommerce_response() do
body = Jason.encode!(%{errors: [%{failure: 1}]})

Expand Down

0 comments on commit ea413f2

Please sign in to comment.