6772312ea7
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.
128 lines
5.8 KiB
Ruby
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
|