2018-03-25 16:15:39 +00:00
# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later
2018-03-25 17:30:42 +00:00
require 'insert/insert_donation'
require 'insert/insert_supporter_notes'
require 'timespan'
require 'delayed_job_helper'
module PayRecurringDonation
# Pay ALL recurring donations that are currently due; each payment gets a queued delayed_job
# Returns the number of queued jobs
def self . pay_all_due_with_stripe
# Bulk insert the delayed jobs with a single expression
ids = Psql . execute_vectors (
QueryRecurringDonations . _all_that_are_due
) [ 1 .. - 1 ] . flatten
jobs = ids . map do | id |
{ handler : DelayedJobHelper . create_handler ( PayRecurringDonation , :with_stripe , [ id ] ) }
end
Psql . execute ( Qexpr . new . insert ( :delayed_jobs , jobs , {
common_data : {
run_at : Time . current ,
attempts : 0 ,
failed_at : nil ,
last_error : nil ,
locked_at : nil ,
locked_by : nil ,
priority : 0 ,
queue : " rec-don-payments "
}
} ) )
return ids
end
# run the payrecurring_donation in development so I can make sure we have the expected failures
# def self._____test_do_not_use_pay_all_due_with_stripe
# # Bulk insert the delayed jobs with a single expression
# ids = Psql.execute_vectors(
# QueryRecurringDonations._all_that_are_due
# )[1..-1].flatten
#
# output = ids.map{|id|
# begin
# i = PayRecurringDonation.with_stripe(id)
# result = {is_error:false, value: i}
# rescue => e
# result = {is_error: true, error_type: e.class.to_s, message: e.message, backtrace: e.backtrace}
# end
#
# result
# }
#
#
#
# return output
# end
# Charge an existing donation via stripe, only if it is due
# Pass in an instance of an existing RecurringDonation
def self . with_stripe ( rd_id )
ParamValidation . new ( { :rd_id = > rd_id } , {
:rd_id = > {
:required = > true ,
:is_integer = > true
}
} )
rd = RecurringDonation . where ( 'id = ?' , rd_id ) . first
unless rd
raise ParamValidation :: ValidationError . new ( " #{ rd_id } is not a valid recurring donation " , { :key = > :rd_id } )
end
return false if ! QueryRecurringDonations . is_due? ( rd_id )
donation = Donation . where ( 'id = ?' , rd [ 'donation_id' ] ) . first
unless donation
raise ParamValidation :: ValidationError . new ( " #{ rd [ 'donation_id' ] } is not a valid donation " , { } )
end
result = { }
result = result . merge ( InsertDonation . insert_charge ( {
'card_id' = > donation [ 'card_id' ] ,
'recurring_donation' = > true ,
'designation' = > donation [ 'designation' ] ,
'amount' = > donation [ 'amount' ] ,
'nonprofit_id' = > donation [ 'nonprofit_id' ] ,
'donation_id' = > donation [ 'id' ] ,
'supporter_id' = > donation [ 'supporter_id' ] ,
'old_donation' = > true
} ) )
if result [ 'charge' ] [ 'status' ] != 'failed'
result [ 'recurring_donation' ] = Psql . execute (
Qexpr . new . update ( :recurring_donations , { n_failures : 0 } )
. where ( " id=$id " , id : rd_id ) . returning ( '*' )
) . first
Delayed :: Job . enqueue JobTypes :: DonorPaymentNotificationJob . new ( rd [ 'donation_id' ] )
Delayed :: Job . enqueue JobTypes :: NonprofitPaymentNotificationJob . new ( rd [ 'donation_id' ] )
InsertActivities . for_recurring_donations ( [ result [ 'payment' ] [ 'id' ] ] )
else
result [ 'recurring_donation' ] = Psql . execute (
Qexpr . new . update ( :recurring_donations , { n_failures : rd [ 'n_failures' ] + 1 } )
. where ( " id=$id " , id : rd_id ) . returning ( '*' )
) . first
DonationMailer . delay . donor_failed_recurring_donation ( rd [ 'donation_id' ] )
if rd [ 'n_failures' ] > = 3
DonationMailer . delay . nonprofit_failed_recurring_donation ( rd [ 'donation_id' ] )
end
InsertSupporterNotes . create ( [ { content : " This supporter had a payment failure for their recurring donation with ID #{ rd_id } " , supporter_id : donation [ 'supporter_id' ] , user_id : 540 } ] )
end
return result
end
def self . fail_a_recurring_donation ( rd , donation , notify_nonprofit = false )
recurring_donation = Psql . execute (
Qexpr . new . update ( :recurring_donations , { n_failures : 3 } )
. where ( " id=$id " , id : rd [ 'id' ] ) . returning ( '*' )
) . first
DonationMailer . delay . donor_failed_recurring_donation ( rd [ 'donation_id' ] )
if notify_nonprofit
DonationMailer . delay . nonprofit_failed_recurring_donation ( rd [ 'donation_id' ] )
end
InsertSupporterNotes . create ( [ { content : " This supporter had a payment failure for their recurring donation with ID #{ rd [ 'id' ] } " , supporter_id : donation [ 'supporter_id' ] , user_id : 540 } ] )
return recurring_donation
end
# Charge an existing donation via stripe, NO MATTER WHAT
# Pass in an instance of an existing RecurringDonation
def self . with_stripe_BUT_NO_MATTER_WHAT ( rd_id , enter_todays_date , run_this = false , set_this_true = false , this_one_needs_to_be_false = true , is_this_run_dangerously = " no " )
if ( PayRecurringDonation :: ULTIMATE_VERIFICATION ( enter_todays_date , run_this , set_this_true , this_one_needs_to_be_false , is_this_run_dangerously ) )
rd = Psql . execute ( " SELECT * FROM recurring_donations WHERE id= #{ rd_id } " ) . first
donation = Psql . execute ( " SELECT * FROM donations WHERE id= #{ rd [ 'donation_id' ] } " ) . first
result = { }
result = result . merge ( InsertDonation . insert_charge ( {
'card_id' = > donation [ 'card_id' ] ,
'recurring_donation' = > true ,
'designation' = > donation [ 'designation' ] ,
'amount' = > donation [ 'amount' ] ,
'nonprofit_id' = > donation [ 'nonprofit_id' ] ,
'donation_id' = > donation [ 'id' ] ,
'supporter_id' = > donation [ 'supporter_id' ]
} ) )
if result [ 'charge' ] [ 'status' ] != 'failed'
result [ 'recurring_donation' ] = Psql . execute (
Qexpr . new . update ( :recurring_donations , { n_failures : 0 } )
. where ( " id=$id " , id : rd_id ) . returning ( '*' )
) . first
Delayed :: Job . enqueue JobTypes :: DonorPaymentNotificationJob . new ( rd [ 'donation_id' ] )
Delayed :: Job . enqueue JobTypes :: NonprofitPaymentNotificationJob . new ( rd [ 'donation_id' ] )
InsertActivities . for_recurring_donations ( [ result [ 'payment' ] [ 'id' ] ] )
else
result [ 'recurring_donation' ] = Psql . execute (
Qexpr . new . update ( :recurring_donations , { n_failures : rd [ 'n_failures' ] + 1 } )
. where ( " id=$id " , id : rd_id ) . returning ( '*' )
) . first
DonationMailer . delay . donor_failed_recurring_donation ( rd [ 'donation_id' ] )
if rd [ 'n_failures' ] > = 3
DonationMailer . delay . nonprofit_failed_recurring_donation ( rd [ 'donation_id' ] )
end
InsertSupporterNotes . create ( [ { content : " This supporter had a payment failure for their recurring donation with ID #{ rd_id } " , supporter_id : donation [ 'supporter_id' ] , user_id : 540 } ] )
end
return result
end
return false
end
def self . ULTIMATE_VERIFICATION ( enter_todays_date , run_this = false , set_this_true = false , this_one_needs_to_be_false = true , is_this_run_dangerously = " no " )
return ( Date . parse ( enter_todays_date ) == Date . today ( ) && run_this && set_this_true && ! this_one_needs_to_be_false && is_this_run_dangerously == " run dangerously " )
end
end