Skip to content

Instantly share code, notes, and snippets.

@ewilliam
Created April 20, 2016 22:09
Show Gist options
  • Save ewilliam/caf20f5117331b4c1c02d5130be1e85a to your computer and use it in GitHub Desktop.
Save ewilliam/caf20f5117331b4c1c02d5130be1e85a to your computer and use it in GitHub Desktop.
class BankAccountForm
include Virtus.model
include ActiveModel::Model
attribute :country, String
attribute :routing_number, String
attribute :account_number, String
attribute :first_name, String
attribute :last_name, String
attribute :dob, Hash[String => String]
attribute :ssn_last4, String
attribute :personal_id_number, String
attribute :identity_document
attribute :line1, String
attribute :line2, String
attribute :locality, String
attribute :region, String
attribute :postcode, String
attribute :stripe_token, String
attribute :wallet_id, Integer
attr_reader :bank_account
validates_presence_of :first_name, :last_name, :line1, :dob,
:locality, :region, :postcode
def save
if valid?
persist!
update_stripe_account
end
end
def wallet
@wallet ||= Wallet.find(wallet_id)
end
private
def persist!
return true if account.external_accounts.empty?
ActiveRecord::Base.transaction do
@bank_account = BankAccount.find_or_create_by(
payment_entity_id: account.external_accounts.first.id
)
@bank_account.update_attributes(
first_name: first_name,
last_name: last_name,
last4: account.external_accounts.first.last4,
brand: account.external_accounts.first.bank_name,
wallet_id: wallet.id,
)
address = Address.find_or_create_by(
addressable_id: @bank_account.id,
addressable_type: @bank_account.class.name
)
address.update_attributes(
line1: line1,
line2: line2,
locality: locality,
region: region,
postcode: postcode,
country: "US"
)
end
end
def update_stripe_account
StripeManagedService.new(wallet).update_account!(params: {
legal_entity: {
first_name: first_name,
last_name: last_name,
dob: dob,
ssn_last_4: ssn_last4,
personal_id_number: personal_id_number,
verification: {
document: identity_document,
},
address: {
line1: line1,
line2: line2,
city: locality,
state: region,
postal_code: postcode
}
},
stripe_token: stripe_token
})
end
def account
@account ||= Stripe::Account.retrieve(wallet.payment_entity_id)
end
end
class BankAccountsController < ApplicationController
before_action :authenticate_user!
before_action :set_bank_account, only: [:edit, :update]
before_action :set_wallet, only: [:new, :create, :edit, :update]
def new
if current_user.merchant_account.bank_account.blank?
@bank_account_form = BankAccountForm.new
else
redirect_to "/settings/wallet", alert: "You already have a bank account."
end
end
def create
params[:bank_account_form][:stripe_token] = params[:stripe_token]
@bank_account_form = BankAccountForm.new(bank_account_form_params)
if @bank_account_form.save
return redirect_to "/settings/wallet", notice: "Bank account added."
end
render :new
end
def edit
authorize @bank_account
@bank_account_form = BankAccountForm.new
end
def update
authorize @bank_account
@bank_account_form = BankAccountForm.new(bank_account_form_params)
if @bank_account_form.save
return redirect_to "/settings/wallet/", notice: "Bank account updated."
end
flash.now.alert = @bank_account_form.wallet.errors.full_messages
render :edit
end
private
def bank_account_form_params
params.require(:bank_account_form).permit(
:country,
:routing_number,
:account_number,
:first_name,
:last_name,
:ssn_last4,
:personal_id_number,
:identity_document,
:line1,
:line2,
:locality,
:region,
:postcode,
:stripe_token,
:wallet_id,
dob: ["dob(1i)", "dob(2i)", "dob(3i)"]
)
end
def set_bank_account
@bank_account = BankAccount.find(params[:id])
end
def set_wallet
@wallet = current_user.merchant_account
end
end
class StripeManagedService < Struct.new(:wallet)
ALLOWED = ['US', 'CA'] # public beta
COUNTRIES = [
{ name: 'United States', code: 'US' },
{ name: 'Canada', code: 'CA' },
{ name: 'Australia', code: 'AU' },
{ name: 'United Kingdom', code: 'GB' },
{ name: 'Ireland', code: 'IE' }
]
def create_account!(country, tos_accepted, ip)
return nil unless tos_accepted
return nil unless country.in?(COUNTRIES.map { |c| c[:code] })
unless wallet.user.merchant_account.nil?
Rails.logger.error "Account Error: User attempted to create extra merchant account."
wallet.errors.add :base, "You already have a seller account."
return false
end
begin
@account = Stripe::Account.create(
managed: true,
country: country,
email: wallet.user.email,
tos_acceptance: {
ip: ip,
date: Time.now.to_i
},
legal_entity: {
type: 'individual',
}
)
rescue => e
Rails.logger.error "Error: " + e.message
wallet.errors.add :base, "Something went wrong. Please try again!"
return false
end
if @account
wallet.update_attributes(
currency: @account.default_currency,
wallet_type_id: 2,
payment_entity_id: @account.id,
payment_service_id: 1,
# secret_key: @account.keys.secret,
# publishable_key: @account.keys.publishable,
account_status: account_status
)
end
@account
end
def update_account!(params: nil)
if params
if params[:stripe_token]
account.bank_account = params[:stripe_token]
account.save
end
if params[:legal_entity]
# clean up dob fields
params[:legal_entity][:dob] = {
year: params[:legal_entity][:dob].delete('dob(1i)'),
month: params[:legal_entity][:dob].delete('dob(2i)'),
day: params[:legal_entity][:dob].delete('dob(3i)')
}
if params[:legal_entity][:verification][:document]
# upload file to Stripe for a token
id_doc = Stripe::FileUpload.create(
purpose: "identity_document",
file: params[:legal_entity][:verification][:document]
)
# attach file id to account
params[:legal_entity][:verification][:document] = id_doc.id
end
# update legal_entity hash from the params
params[:legal_entity].entries.each do |key, value|
if [ :address, :dob, :verification ].include? key.to_sym
value.entries.each do |akey, avalue|
next if avalue.blank?
# Rails.logger.error "#{akey} - #{avalue.inspect}"
account.legal_entity[key] ||= {}
account.legal_entity[key][akey] = avalue
end
else
next if value.blank?
# Rails.logger.error "#{key} - #{value.inspect}"
account.legal_entity[key] = value
end
end
# copy 'address' as 'personal_address'
pa = account.legal_entity['address'].dup.to_h
account.legal_entity['personal_address'] = pa
account.save
end
end
wallet.update_attributes(
account_status: account_status
)
rescue => e
Rails.logger.error "Error: " + e.message
wallet.errors.add :base, "Something went wrong. Please try again!"
return false
end
def legal_entity
account.legal_entity
end
def needs?(field)
wallet.account_status['fields_needed'].grep( Regexp.new( /#{field}/i ) ).any?
end
def supported_bank_account_countries
country_codes = case account.country
when 'US' then %w{ US }
when 'CA' then %w{ US CA }
when 'IE', 'UK' then %w{ IE UK US }
when 'AU' then %w{ AU }
end
COUNTRIES.select do |country|
country[:code].in? country_codes
end
end
protected
def account_status
{
details_submitted: account.details_submitted,
charges_enabled: account.charges_enabled,
transfers_enabled: account.transfers_enabled,
fields_needed: account.verification.fields_needed,
due_by: account.verification.due_by
}
end
def account
@account ||= Stripe::Account.retrieve(wallet.payment_entity_id)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment