164 lines
5.7 KiB
Ruby
164 lines
5.7 KiB
Ruby
# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later
|
|
require 'query/query_recurring_donations'
|
|
require 'insert/insert_supporter_notes'
|
|
require 'format/date'
|
|
require 'format/currency'
|
|
|
|
module UpdateRecurringDonations
|
|
|
|
# Update the card id and name for a given recurring donation (provide rd['donation_id'])
|
|
def self.update_card_id(rd, token)
|
|
rd = rd&.with_indifferent_access
|
|
ParamValidation.new({rd: rd, token: token},
|
|
{
|
|
rd: {is_hash: true, required: true},
|
|
token: {format: UUID::Regex, required: true}
|
|
})
|
|
|
|
ParamValidation.new(rd,
|
|
{
|
|
id: {is_reference: true, required: true}
|
|
})
|
|
|
|
source_token = QuerySourceToken.get_and_increment_source_token(token, nil)
|
|
tokenizable = source_token.tokenizable
|
|
|
|
|
|
entities = RetrieveActiveRecordItems.retrieve_from_keys(rd, RecurringDonation => :id )
|
|
|
|
validate_entities(entities[:id], tokenizable)
|
|
|
|
Qx.transaction do
|
|
rec_don = entities[:id]
|
|
donation = rec_don.donation
|
|
#TODO This is stupid but the two are used together inconsistently. We should scrap one or the other.
|
|
donation.card = tokenizable
|
|
rec_don.card_id = tokenizable
|
|
|
|
rec_don.n_failures = 0
|
|
rec_don.save!
|
|
donation.save!
|
|
InsertSupporterNotes.create([{content: "This supporter updated their card for their recurring donation with ID #{rec_don.id}", supporter_id: rec_don.supporter.id, user_id: 540}])
|
|
end
|
|
return QueryRecurringDonations.fetch_for_edit(rd[:id])['recurring_donation']
|
|
end
|
|
|
|
# Update the paydate for a given recurring donation (provide rd['id'])
|
|
def self.update_paydate(rd, paydate)
|
|
return ValidationError.new(['Invalid paydate']) unless (1..28).include?(paydate.to_i)
|
|
Psql.execute(Qexpr.new.update(:recurring_donations, paydate: paydate).where("id=$id", id: rd['id']))
|
|
rd['paydate'] = paydate
|
|
return rd
|
|
end
|
|
|
|
# @param [RecurringDonation] rd
|
|
# @param [String] token
|
|
# @param [Integer] amount
|
|
def self.update_amount(rd, token, amount)
|
|
ParamValidation.new({amount: amount, rd: rd, token: token},
|
|
{amount: {is_integer: true, min: 50, required:true},
|
|
rd: {required:true, is_a: RecurringDonation},
|
|
token: {required:true, format: UUID::Regex}
|
|
})
|
|
source_token = QuerySourceToken.get_and_increment_source_token(token, nil)
|
|
tokenizable = source_token.tokenizable
|
|
|
|
validate_entities(rd, tokenizable)
|
|
|
|
previous_amount = rd.amount
|
|
donation = rd.donation
|
|
Qx.transaction do
|
|
#TODO This is stupid but the two are used together inconsistently. We should scrap one or the other.
|
|
rd.card = tokenizable
|
|
rd.amount = amount
|
|
rd.n_failures= 0
|
|
donation.card = tokenizable
|
|
donation.amount = amount
|
|
rd.save!
|
|
donation.save!
|
|
end
|
|
EmailJobQueue.queue(JobTypes::NonprofitRecurringDonationChangeAmountJob, rd.id, previous_amount)
|
|
EmailJobQueue.queue(JobTypes::DonorRecurringDonationChangeAmountJob,rd.id, previous_amount)
|
|
rd
|
|
end
|
|
|
|
|
|
def self.update_from_start_dates
|
|
RecurringDonation.inactive.where("start_date >= ?", Date.today).update_all(active: true)
|
|
end
|
|
|
|
|
|
def self.update_from_end_dates
|
|
RecurringDonation.active.where("end_date < ?", Date.today).update_all(active: false)
|
|
end
|
|
|
|
|
|
# Cancel a recurring donation (set active='f') and record the supporter/user email who did it
|
|
def self.cancel(rd_id, email, dont_notify_nonprofit=false)
|
|
Psql.execute(
|
|
Qexpr.new.update(:recurring_donations, {
|
|
active: false,
|
|
cancelled_by: email,
|
|
cancelled_at: Time.current
|
|
})
|
|
.where("id=$id", id: rd_id.to_i)
|
|
)
|
|
rd = QueryRecurringDonations.fetch_for_edit(rd_id)['recurring_donation']
|
|
InsertSupporterNotes.create([{supporter_id: rd['supporter_id'], content: "This supporter's recurring donation for $#{Format::Currency.cents_to_dollars(rd['amount'])} was cancelled by #{rd['cancelled_by']} on #{Format::Date.simple(rd['cancelled_at'])}", user_id: 540}])
|
|
if (!dont_notify_nonprofit)
|
|
DonationMailer.delay.nonprofit_recurring_donation_cancellation(rd['donation_id'])
|
|
end
|
|
return rd
|
|
end
|
|
|
|
|
|
def self.update(rd, params)
|
|
params = set_defaults(params)
|
|
if params[:donation]
|
|
rd.donation.update_attributes(params[:donation])
|
|
return rd.donation unless rd.donation.valid?
|
|
params = params.except(:donation)
|
|
end
|
|
|
|
rd.update_attributes(params)
|
|
return rd
|
|
end
|
|
|
|
|
|
def self.set_defaults(params)
|
|
if params[:donation] && params[:donation][:dollars]
|
|
params[:donation][:amount] = Format::Currency.dollars_to_cents(params[:donation][:dollars])
|
|
params[:donation] = params[:donation].except(:dollars)
|
|
params[:amount] = params[:donation][:amount]
|
|
end
|
|
|
|
if params[:end_date_str]
|
|
if params[:end_date_str].blank? || params[:end_date_str] == 'None'
|
|
params[:end_date] = nil
|
|
else
|
|
params[:end_date] = Chronic.parse(params[:end_date_str])
|
|
end
|
|
params = params.except(:end_date_str)
|
|
end
|
|
|
|
return params
|
|
end
|
|
|
|
# @param [RecurringDonation] rd
|
|
# @param [Card] tokenizable
|
|
def self.validate_entities(rd, tokenizable)
|
|
if (rd.cancelled_at)
|
|
raise ParamValidation::ValidationError.new("Recurring Donation #{rd.id} is already cancelled.", key: :id)
|
|
end
|
|
|
|
if (tokenizable.deleted)
|
|
raise ParamValidation::ValidationError.new("Tokenized card #{tokenizable.id} is not valid.", key: :token)
|
|
end
|
|
|
|
if tokenizable.holder != rd.supporter
|
|
raise ParamValidation::ValidationError.new("Supporter #{rd.supporter.id} does not own card #{tokenizable.id}", key: :token)
|
|
end
|
|
end
|
|
|
|
end
|
|
|