Skip to content

Commit c4d9876

Browse files
authored
Merge pull request #604 from code-corps/597-save-bank-account-last4-and-routing-number
Hook up stripe external account with connect account, expose bank_account info
2 parents e753e3c + 88a1bc6 commit c4d9876

12 files changed

Lines changed: 106 additions & 13 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

mix.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
"segment": {:hex, :segment, "0.1.1", "47bf9191590e7a533c105d1e21518e0d6da47c91e8d98ebb649c624db5dfc359", [:mix], [{:httpoison, "~> 0.8", [hex: :httpoison, optional: false]}, {:poison, "~> 1.3 or ~> 2.0", [hex: :poison, optional: false]}]},
5757
"sentry": {:hex, :sentry, "2.1.0", "51e7ca261b519294ac73b30763893c4a7ad2005205514aefa5bf37ccb83e44ea", [:mix], [{:hackney, "~> 1.6.1", [hex: :hackney, optional: false]}, {:plug, "~> 1.0", [hex: :plug, optional: true]}, {:poison, "~> 1.5 or ~> 2.0 or ~> 3.0", [hex: :poison, optional: false]}, {:uuid, "~> 1.0", [hex: :uuid, optional: false]}]},
5858
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.0", "edee20847c42e379bf91261db474ffbe373f8acb56e9079acb6038d4e0bf414f", [:make, :rebar], []},
59-
"stripity_stripe": {:git, "https://github.com/code-corps/stripity_stripe.git", "f325778c8fb2af3bc04c9d894daef0c47c1500de", [branch: "2.0"]},
59+
"stripity_stripe": {:git, "https://github.com/code-corps/stripity_stripe.git", "f6ddf082a86f558e23789f24aea581add3ca8821", [branch: "2.0"]},
6060
"sweet_xml": {:hex, :sweet_xml, "0.6.3", "814265792baeb163421811c546581c522dfdcb9d1767b1e59959c52906414e80", [:mix], []},
6161
"timber": {:hex, :timber, "0.4.7", "df3fcd79bcb4eb4b53874d906ef5f3a212937b4bc7b7c5b244745202cc389443", [:mix], [{:ecto, "~> 2.0", [hex: :ecto, optional: true]}, {:phoenix, "~> 1.2", [hex: :phoenix, optional: true]}, {:plug, "~> 1.2", [hex: :plug, optional: true]}, {:poison, "~> 2.0 or ~> 3.0", [hex: :poison, optional: false]}]},
6262
"timex": {:hex, :timex, "3.1.5", "413d6d8d6f0162a5d47080cb8ca520d790184ac43e097c95191c7563bf25b428", [:mix], [{:combine, "~> 0.7", [hex: :combine, optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5", [hex: :tzdata, optional: false]}]},
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: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,21 @@ defmodule CodeCorps.StripeConnectAccountViewTest do
1212
verification_disabled_reason: "fields_needed",
1313
verification_fields_needed: ["legal_entity.first_name", "legal_entity.last_name"]
1414
)
15+
insert(:stripe_external_account,
16+
stripe_connect_account: account,
17+
bank_name: "Wells Fargo",
18+
last4: "1234",
19+
routing_number: "123456789"
20+
)
1521

1622
rendered_json = render(CodeCorps.StripeConnectAccountView, "show.json-api", data: account)
1723

1824
expected_json = %{
1925
"data" => %{
2026
"attributes" => %{
27+
"bank-account-bank-name" => "Wells Fargo",
28+
"bank-account-last4" => "1234",
29+
"bank-account-routing-number" => "123456789",
2130
"bank-account-status" => "pending_requirement",
2231
"business-name" => account.business_name,
2332
"business-url" => account.business_url,
@@ -308,4 +317,16 @@ defmodule CodeCorps.StripeConnectAccountViewTest do
308317
assert rendered_json["data"]["attributes"]["bank-account-status"] == "verified"
309318
end
310319
end
320+
321+
describe "external account fields" do
322+
test "render if there is an associated external account" do
323+
account = insert(:stripe_connect_account)
324+
insert(:stripe_external_account, last4: "ABCD", routing_number: "123456", stripe_connect_account: account)
325+
326+
rendered_json = render(CodeCorps.StripeConnectAccountView, "show.json-api", data: account)
327+
328+
assert rendered_json["data"]["attributes"]["bank-account-last4"] == "ABCD"
329+
assert rendered_json["data"]["attributes"]["bank-account-routing-number"] == "123456"
330+
end
331+
end
311332
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

0 commit comments

Comments
 (0)