Skip to content

Commit d5ab57f

Browse files
committed
Hook up connect with external account, change service so it associates the two on create
1 parent e753e3c commit d5ab57f

11 files changed

Lines changed: 94 additions & 12 deletions

lib/code_corps/stripe_service/adapters/stripe_external_account.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ defmodule CodeCorps.StripeService.Adapters.StripeExternalAccountAdapter do
77
:routing_number, :status
88
]
99

10-
def to_params(%Stripe.ExternalAccount{} = bank_account) do
10+
def to_params(%Stripe.ExternalAccount{} = bank_account, stripe_connect_account_id \\ nil) do
1111
params =
1212
bank_account
1313
|> Map.from_struct
1414
|> Map.take(@stripe_attributes)
1515
|> rename(:id, :id_from_stripe)
1616
|> rename(:account, :account_id_from_stripe)
17+
|> Map.put(:stripe_connect_account_id, stripe_connect_account_id)
1718

1819
{:ok, params}
1920
end
Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,24 @@
11
defmodule CodeCorps.StripeService.StripeConnectExternalAccountService do
2-
alias CodeCorps.{Repo, StripeExternalAccount}
2+
alias CodeCorps.{Repo, StripeConnectAccount, StripeExternalAccount}
33
alias CodeCorps.StripeService.Adapters.StripeExternalAccountAdapter
44

55
@api Application.get_env(:code_corps, :stripe)
66

77
def create(id_from_stripe, account_id_from_stripe) do
8-
with {:ok, %Stripe.ExternalAccount{} = bank_account} <- @api.ExternalAccount.retrieve(id_from_stripe, connect_account: account_id_from_stripe),
9-
{:ok, params} <- StripeExternalAccountAdapter.to_params(bank_account)
8+
with {:ok, %Stripe.ExternalAccount{} = external_account} <- @api.ExternalAccount.retrieve(id_from_stripe, connect_account: account_id_from_stripe),
9+
{:ok, %StripeConnectAccount{} = connect_account} <- get_connect_account(account_id_from_stripe),
10+
{:ok, params} <- StripeExternalAccountAdapter.to_params(external_account, connect_account.id)
1011
do
1112
%StripeExternalAccount{}
1213
|> StripeExternalAccount.changeset(params)
1314
|> Repo.insert
1415
end
1516
end
17+
18+
defp get_connect_account(account_id_from_stripe) do
19+
case Repo.get_by(StripeConnectAccount, id_from_stripe: account_id_from_stripe) do
20+
nil -> {:error, :not_found}
21+
record -> {:ok, record}
22+
end
23+
end
1624
end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
defmodule CodeCorps.Repo.Migrations.AddStripeConnectAccountReferenceToExternalAccounts do
2+
use Ecto.Migration
3+
4+
def change do
5+
alter table(:stripe_external_accounts) do
6+
add :stripe_connect_account_id, references(:stripe_connect_accounts)
7+
end
8+
end
9+
end

test/controllers/stripe_connect_events_controller_test.exs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ defmodule CodeCorps.StripeConnectEventsControllerTest do
147147
event = event_for(@bank_account, "account.external_account.created")
148148
path = stripe_connect_events_path(conn, :create)
149149

150+
# we expect the event to be associated with an account, so it must be created
151+
insert(:stripe_connect_account, id_from_stripe: @bank_account["account"])
152+
150153
assert conn |> post(path, event) |> response(200)
151154

152155
wait_for_supervisor
@@ -157,6 +160,20 @@ defmodule CodeCorps.StripeConnectEventsControllerTest do
157160
created_account = Repo.one(StripeExternalAccount)
158161
assert created_account
159162
end
163+
164+
test "errors out event if no associated connect account", %{conn: conn} do
165+
event = event_for(@bank_account, "account.external_account.created")
166+
path = stripe_connect_events_path(conn, :create)
167+
168+
assert conn |> post(path, event) |> response(200)
169+
170+
wait_for_supervisor
171+
172+
event = Repo.one(StripeEvent)
173+
assert event.status == "errored"
174+
175+
assert [] == Repo.all(StripeExternalAccount)
176+
end
160177
end
161178

162179
describe "any event" do

test/lib/code_corps/stripe_service/adapters/stripe_external_account_test.exs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ defmodule CodeCorps.StripeService.Adapters.StripeExternalAccountTestAdapter do
33

44
import CodeCorps.StripeService.Adapters.StripeExternalAccountAdapter, only: [to_params: 1]
55

6-
@stripe_connect_account %Stripe.ExternalAccount{
6+
@stripe_external_account %Stripe.ExternalAccount{
77
id: "ba_19SSZG2eZvKYlo2CXnmzYU5H",
88
object: "bank_account",
99
account: "acct_1032D82eZvKYlo2C",
@@ -32,12 +32,13 @@ defmodule CodeCorps.StripeService.Adapters.StripeExternalAccountTestAdapter do
3232
fingerprint: "1JWtPxqbdX5Gamtc",
3333
last4: "6789",
3434
routing_number: "110000000",
35-
status: "new"
35+
status: "new",
36+
stripe_connect_account_id: nil
3637
}
3738

3839
describe "to_params/2" do
3940
test "converts from stripe map to local properly" do
40-
{:ok, result} = to_params(@stripe_connect_account)
41+
{:ok, result} = to_params(@stripe_external_account)
4142
assert result == @local_map
4243
end
4344
end

test/lib/code_corps/stripe_service/stripe_connect_external_account_service_test.exs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,20 @@ defmodule CodeCorps.StripeService.StripeConnectExternalAccountServiceTest do
1010
id_from_stripe = "ba_testing123"
1111
account_id_from_stripe = "acct_123"
1212

13-
{:ok, %CodeCorps.StripeExternalAccount{} = bank_account} =
13+
connect_account = insert(:stripe_connect_account, id_from_stripe: account_id_from_stripe)
14+
15+
{:ok, %CodeCorps.StripeExternalAccount{} = external_account} =
1416
StripeConnectExternalAccountService.create(id_from_stripe, account_id_from_stripe)
1517

16-
assert bank_account.id_from_stripe == id_from_stripe
18+
assert external_account.id_from_stripe == id_from_stripe
19+
assert external_account.stripe_connect_account_id == connect_account.id
20+
end
21+
22+
test "returns {:error, :not_found} if there's no associated stripe connect account" do
23+
id_from_stripe = "ba_testing123"
24+
account_id_from_stripe = "acct_123"
25+
26+
assert {:error, :not_found} == StripeConnectExternalAccountService.create(id_from_stripe, account_id_from_stripe)
1727
end
1828
end
1929
end

test/support/factories.ex

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,13 +153,20 @@ defmodule CodeCorps.Factories do
153153

154154
def stripe_event_factory do
155155
%CodeCorps.StripeEvent{
156-
endpoint: sequence(:endpoint, fn(_) -> Enum.random(~w{ connect platform }) end),
156+
endpoint: sequence(:endpoint, fn(_) -> Enum.random(~w{ connect platform }) end),
157157
id_from_stripe: sequence(:id_from_stripe, &"stripe_id_#{&1}"),
158158
status: sequence(:status, fn(_) -> Enum.random(~w{ unprocessed processed errored }) end),
159159
type: "test.type"
160160
}
161161
end
162162

163+
def stripe_external_account_factory do
164+
%CodeCorps.StripeExternalAccount{
165+
account_id_from_stripe: sequence(:id_from_stripe, &"stripe_id_#{&1}"),
166+
id_from_stripe: sequence(:id_from_stripe, &"stripe_id_#{&1}")
167+
}
168+
end
169+
163170
def stripe_file_upload_factory do
164171
%CodeCorps.StripeFileUpload{
165172
id_from_stripe: sequence(:id_from_stripe, &"stripe_id_#{&1}"),

test/views/stripe_connect_account_view_test.exs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ defmodule CodeCorps.StripeConnectAccountViewTest do
1919
"data" => %{
2020
"attributes" => %{
2121
"bank-account-status" => "pending_requirement",
22+
"bank-account-last4" => nil,
23+
"bank-account-routing-number" => nil,
2224
"business-name" => account.business_name,
2325
"business-url" => account.business_url,
2426
"can-accept-donations" => true,
@@ -308,4 +310,16 @@ defmodule CodeCorps.StripeConnectAccountViewTest do
308310
assert rendered_json["data"]["attributes"]["bank-account-status"] == "verified"
309311
end
310312
end
313+
314+
describe "external account fields" do
315+
test "render if there is an associated external account" do
316+
account = insert(:stripe_connect_account)
317+
insert(:stripe_external_account, last4: "ABCD", routing_number: "123456", stripe_connect_account: account)
318+
319+
rendered_json = render(CodeCorps.StripeConnectAccountView, "show.json-api", data: account)
320+
321+
assert rendered_json["data"]["attributes"]["bank-account-last4"] == "ABCD"
322+
assert rendered_json["data"]["attributes"]["bank-account-routing-number"] == "123456"
323+
end
324+
end
311325
end

web/models/stripe_connect_account.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ defmodule CodeCorps.StripeConnectAccount do
7171
field :verification_fields_needed, {:array, :string}, default: []
7272

7373
belongs_to :organization, CodeCorps.Organization
74+
has_one :stripe_external_account, CodeCorps.StripeExternalAccount
7475

7576
timestamps()
7677
end

web/models/stripe_external_account.ex

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,15 @@ defmodule CodeCorps.StripeExternalAccount do
1515
field :routing_number, :string
1616
field :status, :string
1717

18+
belongs_to :stripe_connect_account, CodeCorps.StripeConnectAccount
19+
1820
timestamps()
1921
end
2022

2123
@create_params [
2224
:id_from_stripe, :account_id_from_stripe, :account_holder_name, :account_holder_type, :bank_name,
23-
:country, :currency, :default_for_currency, :fingerprint, :last4, :routing_number, :status
25+
:country, :currency, :default_for_currency, :fingerprint, :last4, :routing_number, :status,
26+
:stripe_connect_account_id
2427
]
2528

2629
@required_create_params [:id_from_stripe, :account_id_from_stripe]
@@ -32,5 +35,6 @@ defmodule CodeCorps.StripeExternalAccount do
3235
struct
3336
|> cast(params, @create_params)
3437
|> validate_required(@required_create_params)
38+
|> assoc_constraint(:stripe_connect_account)
3539
end
3640
end

0 commit comments

Comments
 (0)