jam-cloud/ruby/lib/jam_ruby/models/charge.rb

155 lines
4.6 KiB
Ruby
Raw Permalink Normal View History

module JamRuby
2016-08-03 01:46:15 +00:00
class Charge < ActiveRecord::Base
attr_accessor :stripe_charge
belongs_to :user, class_name: "JamRuby::User"
validates :sent_billing_notices, inclusion: {in: [true, false]}
def max_retries
raise "not implemented"
end
def do_charge(force)
raise "not implemented"
end
def do_send_notices
raise "not implemented"
end
def do_send_unable_charge
raise "not implemented"
end
def charge_retry_hours
24
end
def charged_user
raise "not implemented"
end
def record_charge(stripe_charge)
self.stripe_charge_id = stripe_charge.id
self.billed = true
self.billed_at = Time.now
self.save(validate: false)
end
2018-03-13 02:53:24 +00:00
def admin_url
APP_CONFIG.admin_root_url + "/admin/charges/" + id
end
def charge(force = false)
@stripe_charge = nil
if !self.billed
# check if we can bill at the moment
if !force && last_billing_attempt_at && (charge_retry_hours.hours.ago < last_billing_attempt_at)
return false
end
if !force && !billing_should_retry
return false
end
# bill the user right now. if it fails, move on; will be tried again
self.billing_attempts = self.billing_attempts + 1
self.billing_should_retry = self.billing_attempts < max_retries
self.last_billing_attempt_at = Time.now
self.save(validate: false)
begin
stripe_charge = do_charge(force)
# record the charge in this context (meaning, in our transaction)
record_charge(@stripe_charge) if @stripe_charge
rescue Stripe::StripeError => e
stripe_handler(e)
subject = "Unable to charge user #{charged_user.email} for lesson #{self.id} (stripe)"
body = "user=#{charged_user.email}\n\nbilling_error_reason=#{billing_error_reason}\n\nbilling_error_detail = #{billing_error_detail}"
2016-08-03 01:46:15 +00:00
AdminMailer.alerts({subject: subject, body: body}).deliver_now
do_send_unable_charge
return false
rescue Exception => e
# record the charge even if there was an unhandled exception at some point
record_charge(@stripe_charge) if @stripe_charge
unhandled_handler(e)
subject = "Unable to charge user #{charged_user.email} for lesson #{self.id} (unhandled)"
body = "user=#{charged_user.email}\n\nbilling_error_reason=#{billing_error_reason}\n\nbilling_error_detail = #{billing_error_detail}"
2016-09-08 10:59:58 +00:00
AdminMailer.alerts({subject: subject, body: body}).deliver_now
return false
end
end
if !self.sent_billing_notices
# If the charge is successful, then we post the charge to the students payment history,
# and associate the charge with the lesson, so that everyone knows the student has paid, and we send an email
do_send_notices
self.sent_billing_notices = true
self.sent_billing_notices_at = Time.now
self.post_processed = true
self.post_processed_at = Time.now
self.save(validate: false)
end
return stripe_charge
end
def unhandled_handler(e)
self.billing_error_reason = e.to_s
if e.cause
self.billing_error_detail = e.cause.to_s + "\n" + e.cause.backtrace.join("\n\t") if e.cause.backtrace
self.billing_error_detail << "\n\n"
self.billing_error_detail << e.to_s + "\n" + e.backtrace.join("\n\t") if e.backtrace
else
self.billing_error_detail = e.to_s + "\n" + e.backtrace.join("\n\t") if e.backtrace
end
#puts "Charge: unhandled exception #{billing_error_reason}, #{billing_error_detail}"
self.save(validate: false)
end
def is_card_declined?
billed == false && billing_error_reason == 'card_declined'
end
def is_card_expired?
billed == false && billing_error_reason == 'card_expired'
end
def last_billed_at_date
last_billing_attempt_at.strftime("%B %d, %Y") if last_billing_attempt_at
end
def stripe_handler(e)
msg = e.to_s
if msg.include?('declined')
self.billing_error_reason = 'card_declined'
self.billing_error_detail = msg
elsif msg.include?('expired')
self.billing_error_reason = 'card_expired'
self.billing_error_detail = msg
elsif msg.include?('processing')
self.billing_error_reason = 'processing_error'
self.billing_error_detail = msg
else
self.billing_error_reason = 'stripe'
self.billing_error_detail = msg
end
self.save(validate: false)
end
end
end