houdini/lib/insert/insert_recurring_donation.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

180 lines
6.7 KiB
Ruby

# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later
module InsertRecurringDonation
# Create a recurring_donation, donation, payment, charge, and activity
# See controllers/nonprofits/recurring_donations_controller#create for the data params to pass in
def self.with_stripe(data)
data = data.with_indifferent_access
ParamValidation.new(data, InsertDonation.common_param_validations
.merge(token: {required: true, format: UUID::Regex}))
unless data[:recurring_donation].nil?
ParamValidation.new(data[:recurring_donation], {
interval: {is_integer: true},
start_date: {can_be_date: true},
time_unit: {included_in: %w(month day week year)},
paydate: {is_integer:true, min: 1, max: 28}
})
else
data[:recurring_donation] = {}
end
source_token = QuerySourceToken.get_and_increment_source_token(data[:token], nil)
tokenizable = source_token.tokenizable
QuerySourceToken.validate_source_token_type(source_token)
entities = RetrieveActiveRecordItems.retrieve_from_keys(data, {Supporter => :supporter_id, Nonprofit => :nonprofit_id})
entities = entities.merge(RetrieveActiveRecordItems.retrieve_from_keys(data, {Campaign => :campaign_id, Event => :event_id, Profile => :profile_id}, true))
InsertDonation.validate_entities(entities)
## does the card belong to the supporter?
if tokenizable.holder != entities[:supporter_id]
raise ParamValidation::ValidationError.new("Supporter #{entities[:supporter_id].id} does not own card #{tokenizable.id}", key: :token)
end
data['card_id'] = tokenizable.id
result = {}
data[:date] = Time.now
data = data.merge(payment_provider: payment_provider(data))
data = data.except(:old_donation).except('old_donation')
# if start date is today, make initial charge first
test_start_date = get_test_start_date(data)
if test_start_date == nil || Time.current >= test_start_date
result = result.merge(InsertDonation.insert_charge(data))
if result['charge']['status'] == 'failed'
raise ChargeError.new(result['charge']['failure_message'])
end
end
# Create the donation record
result['donation'] = InsertDonation.insert_donation(data, entities)
entities[:donation_id] = result['donation']
# Create the recurring_donation record
result['recurring_donation'] = insert_recurring_donation(data,entities)
# Update charge foreign keys
if result['payment']
InsertDonation.update_donation_keys(result)
# Create the activity record
result['activity'] = InsertActivities.for_recurring_donations([result['payment'].id])
end
# Send receipts
EmailJobQueue.queue(JobTypes::NonprofitPaymentNotificationJob, result['donation'].id)
EmailJobQueue.queue(JobTypes::DonorPaymentNotificationJob, result['donation'].id, entities[:supporter_id].locale)
QueueDonations.delay.execute_for_donation(result['donation']['id'])
return result
end
def self.with_sepa(data)
data = set_defaults(data)
data = data.merge(payment_provider: payment_provider(data))
result = {}
if Time.current >= data[:recurring_donation][:start_date]
result = result.merge(InsertDonation.insert_charge(data))
end
result['donation'] = Psql.execute(Qexpr.new.insert(:donations, [
data.except(:recurring_donation)
]).returning('*')).first
result['recurring_donation'] = Psql.execute(Qexpr.new.insert(:recurring_donations, [
data[:recurring_donation].merge(donation_id: result['donation']['id'])
]).returning('*')).first
if result['payment']
InsertDonation.update_donation_keys(result)
end
DonationMailer.delay.nonprofit_payment_notification(result['donation']['id'])
DonationMailer.delay.donor_direct_debit_notification(result['donation']['id'], locale_for_supporter(result['donation']['supporter_id']))
QueueDonations.delay.execute_for_donation(result['donation']['id'])
{ status: 200, json: result }
end
# the data model here is brutal. This needs to get cleaned up.
def self.convert_donation_to_recurring_donation(donation_id)
ParamValidation.new({donation_id: donation_id}, {donation_id: {:required => true, :is_integer => true}})
don = Donation.where('id = ? ', donation_id).first
if !don
raise ParamValidation::ValidationError.new("#{donation_id} is not a valid donation", {:key => :donation_id, :val => donation_id})
end
rd = insert_recurring_donation({amount:don.amount, email: don.supporter.email, anonymous: don.anonymous, origin_url: don.origin_url, recurring_donation: { start_date: don.created_at, :paydate => convert_date_to_valid_paydate(don.created_at)}, date: don.created_at}, {supporter_id: don.supporter, nonprofit_id: don.nonprofit, donation_id: don})
don.recurring_donation = rd
don.recurring = true
don.payment.kind = "RecurringDonation"
don.payment.save!
rd.save!
don.save!
rd
end
def self.insert_recurring_donation(data, entities)
rd = RecurringDonation.new
rd.amount = data[:amount]
rd.nonprofit = entities[:nonprofit_id]
rd.donation = entities[:donation_id]
rd.supporter_id = entities[:supporter_id].id
rd.active = true
rd.edit_token = SecureRandom.uuid
rd.n_failures= 0
rd.email= entities[:supporter_id].email
rd.interval = data[:recurring_donation][:interval].blank? ? 1 : data[:recurring_donation][:interval]
rd.time_unit= data[:recurring_donation][:time_unit].blank? ? 'month' : data[:recurring_donation][:time_unit]
if data[:recurring_donation][:start_date].blank?
rd.start_date= Time.current.beginning_of_day
elsif data[:recurring_donation][:start_date].is_a? Time
rd.start_date = data[:recurring_donation][:start_date]
else
rd.start_date = Chronic.parse(data[:recurring_donation][:start_date])
end
if rd.time_unit == 'month' && rd.interval == 1 && data[:recurring_donation][:paydate].nil?
rd.paydate = convert_date_to_valid_paydate(rd.start_date)
else
rd.paydate = data[:recurring_donation][:paydate]
end
rd.save!
rd
end
def self.get_test_start_date(data)
unless data[:recurring_donation] && data[:recurring_donation][:start_date]
return nil
end
return Chronic.parse(data[:recurring_donation][:start_date])
end
def self.locale_for_supporter(supporter_id)
Psql.execute(
Qexpr.new.select(:locale).from(:supporters)
.where("id=$id", id: supporter_id)
).first['locale']
end
def self.payment_provider(data)
if data[:card_id]
:credit_card
elsif data[:direct_debit_detail_id]
:sepa
end
end
def self.convert_date_to_valid_paydate(date)
day = date.day
return day > 28 ? 28 : day
end
end