diff --git a/lib/code_corps/stripe_service/adapters/stripe_connect_account.ex b/lib/code_corps/stripe_service/adapters/stripe_connect_account.ex index f329fa598..1a47f511a 100644 --- a/lib/code_corps/stripe_service/adapters/stripe_connect_account.ex +++ b/lib/code_corps/stripe_service/adapters/stripe_connect_account.ex @@ -7,6 +7,7 @@ defmodule CodeCorps.StripeService.Adapters.StripeConnectAccountAdapter do ] def to_params(%Stripe.Account{} = stripe_account, %{} = attributes) do + result = stripe_account |> Map.from_struct @@ -18,6 +19,100 @@ defmodule CodeCorps.StripeService.Adapters.StripeConnectAccountAdapter do {:ok, result} end + def to_managed_params(%Stripe.Account{} = stripe_account, %{} = attributes) do + params = %{ + email: stripe_account.email, + managed: stripe_account.managed, + # TODO: A stripe response will not return the business_ein. instead, + # it will return business_tax_id_provided, which is a boolean. we should probably store that, + # not this + business_ein: attributes |> Map.get("business_ein"), + business_name: stripe_account.legal_entity.business_name, # or stripe_account.business_name + + # as far as I can tell, stripe does not store this. might wanna remove it from the whole process. + # added it due to looking at kickstarter form + business_type: attributes |> Map.get("business_type"), + + first_name: stripe_account.legal_entity.first_name, + last_name: stripe_account.legal_entity.last_name, + # TODO: A stripe response will not return the ssn_last4. instead, + # it will return ssn_last4_provided, which is a boolean. we should probably store that, + # not this + ssn_last4: attributes |> Map.get("ssn_last4"), + recipient_type: stripe_account.legal_entity.type, + + # TODO: decide on getting legal_entity.address or legal_entity.personal_address + address1: stripe_account.legal_entity.address.line1, + address2: stripe_account.legal_entity.address.line2, + city: stripe_account.legal_entity.address.city, + country: stripe_account.legal_entity.address.country, + state: stripe_account.legal_entity.address.state, + # we maybe wanna rename this one + zip: stripe_account.legal_entity.address.postal_code, + + dob_day: stripe_account.legal_entity.dob.day, + dob_month: stripe_account.legal_entity.dob.month, + dob_year: stripe_account.legal_entity.dob.year, + + id_from_stripe: stripe_account.id, + charges_enabled: stripe_account.charges_enabled, + transfers_enabled: stripe_account.transfers_enabled, + + organization_id: attributes |> Map.get("organization_id"), + } + + IO.inspect(params) + {:ok, params} + end + + def to_stripe_params(%{ + "country" => country, + "email" => email + } = attributes) do + with legal_entity <- build_legal_entity(attributes) + do + params = %{ country: country, email: email, managed: true, legal_entity: legal_entity} + {:ok, params} + end + end + def to_stripe_managed_params(attributes) do + {:error, :fields_missing} + end + + defp build_legal_entity(%{ + "business_ein" => business_ein, "business_name" => business_name, "business_type" => _, + "first_name" => first_name, "last_name" => last_name, "ssn_last4" => ssn_last4, + "recipient_type" => recipient_type + } = attributes) do + with address <- build_address(attributes), + dob <- build_dob(attributes) + do + %{ + business_name: business_name, + business_tax_id: business_ein, + dob: dob, + first_name: first_name, + last_name: last_name, + ssn_last_4: ssn_last4, + type: recipient_type, + # TODO: Decide which address to set + address: address, + personal_address: address + } + end + end + + defp build_dob(%{"dob_day" => dob_day, "dob_month" => dob_month, "dob_year" => dob_year}) do + %{day: dob_day, month: dob_month, year: dob_year} + end + + defp build_address(%{ + "address1" => address1, "address2" => address2, "city" => city, + "country" => country, "state" => state,"zip" => zip + }) do + %{city: city, country: country, line1: address1, line2: address2, postal_code: zip, state: state} + end + @non_stripe_attributes ["organization_id"] defp add_non_stripe_attributes(%{} = params, %{} = attributes) do diff --git a/lib/code_corps/stripe_service/stripe_connect_account.ex b/lib/code_corps/stripe_service/stripe_connect_account.ex index db16ee8d5..8139ca5d9 100644 --- a/lib/code_corps/stripe_service/stripe_connect_account.ex +++ b/lib/code_corps/stripe_service/stripe_connect_account.ex @@ -4,13 +4,13 @@ defmodule CodeCorps.StripeService.StripeConnectAccountService do @api Application.get_env(:code_corps, :stripe) - def create(%{"access_code" => code, "organization_id" => _organization_id} = attributes) do - with {:ok, %TokenResponse{stripe_user_id: account_id}} <- @api.Connect.OAuth.token(code), - {:ok, account} <- @api.Account.retrieve(account_id), - {:ok, params} <- StripeConnectAccountAdapter.to_params(account, attributes) + def create(%{} = attributes) do + with {:ok, stripe_params} <- StripeConnectAccountAdapter.to_stripe_params(attributes), + {:ok, %Stripe.Account{} = stripe_account} <- @api.Account.create(stripe_params), + {:ok, params} <- StripeConnectAccountAdapter.to_managed_params(stripe_account, attributes) do %CodeCorps.StripeConnectAccount{} - |> CodeCorps.StripeConnectAccount.create_changeset(params) + |> CodeCorps.StripeConnectAccount.managed_create_changeset(params) |> CodeCorps.Repo.insert end end diff --git a/mix.lock b/mix.lock index b39cf1524..db0df1805 100644 --- a/mix.lock +++ b/mix.lock @@ -56,6 +56,7 @@ "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], []}, "stripe_eventex": {:hex, :stripe_eventex, "1.0.0", "782016598b751c0fdb5489038c92c30a5aab034636d0d9d3a486f75a01fbf0b6", [:mix], [{:cowboy, "~> 1.0.0", [hex: :cowboy, optional: false]}, {:plug, "~> 1.0", [hex: :plug, optional: false]}, {:poison, "~> 2.0", [hex: :poison, optional: false]}]}, "stripity_stripe": {:hex, :stripity_stripe, "2.0.0-alpha.5", "ba6d4ffc6251029135c76e9c6e2dd77580713f5c6833fb82da708336023bbfa2", [:mix], [{:hackney, "~> 1.6", [hex: :hackney, optional: false]}, {:poison, "~> 2.0 or ~> 3.0", [hex: :poison, optional: false]}]}, + "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]}]}, "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]}]}, "timex_ecto": {:hex, :timex_ecto, "3.0.5", "3ec6c25e10d2c0020958e5df64d2b5e690e441faa2c2259da8bc6bd3d7f39256", [:mix], [{:ecto, "~> 2.0", [hex: :ecto, optional: false]}, {:timex, "~> 3.0", [hex: :timex, optional: false]}]}, "tzdata": {:hex, :tzdata, "0.5.9", "575be217b039057a47e133b72838cbe104fb5329b19906ea4e66857001c37edb", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, optional: false]}]}, diff --git a/priv/repo/managed_account_spike.exs b/priv/repo/managed_account_spike.exs new file mode 100644 index 000000000..7ea72b31c --- /dev/null +++ b/priv/repo/managed_account_spike.exs @@ -0,0 +1,31 @@ +alias CodeCorps.Repo +alias CodeCorps.Organization +alias CodeCorps.Project +alias CodeCorps.User +alias CodeCorps.OrganizationMembership + +{:ok, owner } = + %User{} + |> User.registration_changeset(%{username: "owner", email: "owner@managed.org", password: "password"}) + |> Repo.insert + +{:ok, organization } = + %Organization{} + |> Organization.create_changeset(%{name: "Managed", description: "A managed organization"}) + |> Repo.insert + +{:ok, _} = + %OrganizationMembership{member_id: owner.id, organization_id: organization.id, role: "owner"} + |> Repo.insert + +{:ok, _project} = + %Project{} + |> Project.create_changeset(%{title: "Managed project", description: "A project created for a managed organization", organization_id: organization.id}) + |> Repo.insert + +{:ok, _donor} = + %User{} + |> User.registration_changeset(%{username: "donor", email: "donor@test.org", password: "password"}) + |> Repo.insert + + diff --git a/web/models/stripe_connect_account.ex b/web/models/stripe_connect_account.ex index e967b46ee..9c7003acb 100644 --- a/web/models/stripe_connect_account.ex +++ b/web/models/stripe_connect_account.ex @@ -6,28 +6,67 @@ defmodule CodeCorps.StripeConnectAccount do use CodeCorps.Web, :model schema "stripe_connect_accounts" do - field :business_name, :string + # these might not be needed by managed accounts, + # but we have them defined at DB level + field :business_url, :string - field :charges_enabled, :boolean - field :country, :string field :default_currency, :string field :details_submitted, :boolean field :display_name, :string - field :email, :string - field :id_from_stripe, :string, null: false - field :managed, :boolean field :support_email, :string field :support_phone, :string field :support_url, :string - field :transfers_enabled, :boolean + # this was needed for connect field :access_code, :string, virtual: true + # these fields are filled out and sent by the client + + field :address1, :string, virtual: true + field :address2, :string, virtual: true + field :business_ein, :string, virtual: true + field :business_name, :string + field :business_type, :string, virtual: true + field :city, :string, virtual: true + field :country, :string + field :dob_day, :integer, virtual: true + field :dob_month, :integer, virtual: true + field :dob_year, :integer, virtual: true + field :email, :string + field :first_name, :string, virtual: true + field :last_name, :string, virtual: true + field :recipient_type, :string, virtual: true + field :ssn_last4, :string, virtual: true + field :state, :string, virtual: true + field :zip, :string, virtual: true + belongs_to :organization, CodeCorps.Organization + # these fields are set automatically + field :managed, :boolean + + # these fields are set from stripe + field :id_from_stripe, :string, null: false + field :charges_enabled, :boolean + field :transfers_enabled, :boolean timestamps() end + @managed_create_fields [ + :address1, :address2, :business_ein, :business_name, :business_type, + :city, :country, :dob_day, :dob_month, :dob_year, :email, + :first_name, :last_name, :recipient_type, :ssn_last4, + :state, :zip, :organization_id, + :managed, :id_from_stripe, :charges_enabled, :transfers_enabled + ] + + def managed_create_changeset(struct, params) do + struct + |> cast(params, @managed_create_fields) + |> validate_required(@managed_create_fields) + |> assoc_constraint(:organization) + end + @insert_params [ :business_name, :business_url, :charges_enabled, :country, :default_currency, :details_submitted, :email, :id_from_stripe, :managed, :organization_id,