houdini/lib/insert/insert_card.rb
Bradley M. Kuhn 6772312ea7 Relicense all .rb files under new project license.
The primary license of the project is changing to:
  AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later

with some specific files to be licensed under the one of two licenses:
   CC0-1.0
   LGPL-3.0-or-later

This commit is one of the many steps to relicense the entire codebase.

Documentation granting permission for this relicensing (from all past
contributors who hold copyrights) is on file with Software Freedom
Conservancy, Inc.
2018-03-25 15:10:40 -04:00

128 lines
5.8 KiB
Ruby

# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later
require 'hash'
module InsertCard
# Create a new card
# If a stripe_customer_id is present, then update that customer's primary source; otherwise create a new customer
# @param [ActiveSupport::HashWithIndifferentAccess] card_data card data
# @option card_data [Integer] holder_id the primary key of the card's holder
# @option card_data [String] holder_type the type of the card holder. Must be 'Nonprofit' or 'Supporter'
# @option card_data [String] stripe_card_token the card token from stripe
# @option card_data [String] stripe_card_id the card id from stripe
# @option card_data [String] name the card name
# @option card_data [String] cardholder_name (nil) the name of the cardholder
# @option card_data [String] stripe_customer_id (nil) the stripe customer id as provided by stripe
# @param [String] stripe_account_id not clear what this should do.
# @param [Integer] event_id id for events with when you want it associated with an event
# @param [User] current_user the user making the request. Used for validating that the current_user can make a long term token request
def self.with_stripe(card_data, stripe_account_id=nil, event_id=nil, current_user = nil)
begin
ParamValidation.new(card_data.merge({event_id: event_id}), {
holder_type: {required: true, included_in: ['Nonprofit', 'Supporter']},
holder_id: {required: true},
stripe_card_id: {not_blank: true, required: true},
stripe_card_token: {not_blank: true, required: true},
name: {not_blank: true, required: true},
event_id: {is_reference: true}
})
rescue ParamValidation::ValidationError => e
return {json: {error: "Validation error\n #{e.message}", errors: e.data}, status: :unprocessable_entity}
end
# validate that the user is with the correct nonprofit
card_data = card_data.keep_keys(:holder_type, :holder_id, :stripe_card_id, :stripe_card_token, :name )
holder_types = {'Nonprofit' => :nonprofit, 'Supporter' => :supporter}
holder_type = holder_types[card_data[:holder_type]]
holder = nil
begin
if holder_type == :nonprofit
holder = Nonprofit.select("id, email").includes(:cards).find(card_data[:holder_id])
elsif holder_type == :supporter
holder = Supporter.select("id, email, nonprofit_id").includes(:cards, :nonprofit).find(card_data[:holder_id])
end
rescue ActiveRecord::RecordNotFound
return {json: {error: "Sorry, you need to provide a nonprofit or supporter"}, status: :unprocessable_entity}
end
begin
if holder_type == :supporter && event_id
event = Event.where('id = ?', event_id).first
unless event
raise ParamValidation::ValidationError.new("#{event_id} is not a valid event", {key: :event_id})
end
if (holder.nonprofit != event.nonprofit )
raise ParamValidation::ValidationError.new("Event #{event_id} is not for the same nonprofit as supporter #{holder.id}", {key: :event_id})
end
unless QueryRoles.is_authorized_for_nonprofit?(current_user.id, holder.nonprofit.id)
raise AuthenticationError.new
end
end
rescue AuthenticationError
return {json: {error: "You're not authorized to perform that action"}, status: :unauthorized}
rescue => e
return {json: {error: "Oops! There was an error: #{e.message}"}, status: :unprocessable_entity}
end
stripe_account_hash = {} # stripe_account_id ? {stripe_account: stripe_account_id} : {}
begin
if card_data[:stripe_customer_id]
stripe_customer = Stripe::Customer.retrieve(card_data[:stripe_customer_id], stripe_account_hash)
else
stripe_customer = Stripe::Customer.create(customer_data(holder, card_data), stripe_account_hash)
end
stripe_customer.sources.create(source: card_data[:stripe_card_token])
card_data[:stripe_customer_id] = stripe_customer.id
rescue Stripe::CardError => e
return {json: {error: "Oops! #{e.json_body[:error][:message]}"}, status: :unprocessable_entity}
rescue Stripe::StripeError => e
return {json: {error: "Oops! There was an error processing your payment, and it did not complete. Please try again in a moment. Error: #{e}"}, status: :unprocessable_entity}
end
card = nil
source_token = nil
begin
Card.transaction {
if (holder_type == :nonprofit)
# @type [Nonprofit] holder
card = holder.create_active_card(card_data)
elsif (holder_type == :supporter)
# @type [Supporter] holder
card = holder.cards.create(card_data)
params = {}
if event
params[:event] = event
end
source_token = InsertSourceToken.create_record(card, params).token
end
card.save!
}
rescue ActiveRecord::ActiveRecordError => e
return {json: {error: "Oops! There was an error saving your card, and it did not complete. Please try again in a moment. Error: #{e}"}, status: :unprocessable_entity}
rescue e
Airbrake.notify(e)
return {json: {error: "Oops! There was an error saving your card, and it did not complete. Please try again in a moment. Error: #{e}"}, status: :unprocessable_entity}
rescue e
Airbrake.notify(e)
return {json: {error: "Oops! There was an error saving your card, and it did not complete. Please try again in a moment. Error: #{e}"}, status: :unprocessable_entity}
end
return { status: :ok, json: card.attributes.with_indifferent_access.merge(token: source_token) }
end
def self.customer_data(holder, card_data)
{ email: holder['email'], metadata: { cardholders_name: card_data[:cardholders_name], holder_id: card_data[:holder_id], holder_type: card_data[:holder_type] } }
end
end