131 lines
4.1 KiB
Ruby
131 lines
4.1 KiB
Ruby
module JamRuby
|
||
class Charge
|
||
validates :sent_notices, inclusion: {in: [true, false]}
|
||
|
||
def max_retries
|
||
raise "not implemented"
|
||
end
|
||
def do_charge
|
||
raise "not implemented"
|
||
end
|
||
|
||
def bill_lesson
|
||
|
||
if !self.billed
|
||
|
||
# check if we can bill at the moment
|
||
if last_billing_attempt_at && (24.hours.ago < last_billing_attempt_at)
|
||
return
|
||
end
|
||
|
||
if !billing_should_retry
|
||
return
|
||
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
|
||
|
||
do_charge
|
||
|
||
if sale.errors.any?
|
||
self.billing_error_reason = 'sale_error'
|
||
self.billing_error_detail = sale.errors.inspect
|
||
line_item = sale.sale_line_items[0]
|
||
if line_item && line_item.errors.any?
|
||
self.billing_error_detail = "#{self.billing_error_detail}\n\n#{line_item.errors.inspect}"
|
||
end
|
||
self.save(validate: false)
|
||
return false
|
||
else
|
||
self.billed = true
|
||
self.billed_at = Time.now
|
||
self.save(validate: false)
|
||
end
|
||
rescue Stripe::StripeError => e
|
||
|
||
stripe_handler(e)
|
||
|
||
subject = "Unable to charge user #{student.email} for lesson #{self.id} (stripe)"
|
||
body = "teacher=#{teacher.email}\n\nbilling_error_reason=#{billing_error_reason}\n\nbilling_error_detail = #{billing_error_detail}"
|
||
AdminMailer.alerts({subject: subject, body: body})
|
||
UserMailer.student_unable_charge(self)
|
||
return false
|
||
rescue Exception => e
|
||
subject = "Unable to charge user #{student.email} for lesson #{self.id} (unhandled)"
|
||
body = "teacher=#{teacher.email}\n\nbilling_error_reason=#{billing_error_reason}\n\nbilling_error_detail = #{billing_error_detail}"
|
||
AdminMailer.alerts({subject: subject, body: body})
|
||
unhandled_handler(e)
|
||
return false
|
||
end
|
||
|
||
end
|
||
|
||
if !self.sent_billing_notices
|
||
# If the charge is successful, then we post the charge to the student’s payment history,
|
||
# and associate the charge with the lesson, so that everyone knows the student has paid, and we send an email
|
||
|
||
UserMailer.student_lesson_normal_done(self).deliver
|
||
UserMailer.teacher_lesson_normal_done(self).deliver
|
||
|
||
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 true
|
||
end
|
||
|
||
def unhandled_handler(e, reason = 'unhandled_exception')
|
||
self.billing_error_reason = reason
|
||
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
|
||
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 |