# represents the purchase of a LessonPackage module JamRuby class LessonPackagePurchase < ActiveRecord::Base @@log = Logging.logger[LessonPackagePurchase] delegate :sent_billing_notices, :last_billing_attempt_at, :billing_attempts, :billing_should_retry, :billed, :billed_at, :billing_error_detail, :billing_error_reason, :is_card_declined?, :is_card_expired?, :last_billed_at_date, :sent_billing_notices, to: :lesson_payment_charge delegate :test_drive_count, to: :lesson_package_type # who purchased the lesson package? belongs_to :user, class_name: "JamRuby::User", :foreign_key => "user_id", inverse_of: :lesson_purchases belongs_to :lesson_package_type, class_name: "JamRuby::LessonPackageType" belongs_to :teacher, class_name: "JamRuby::User" belongs_to :lesson_booking, class_name: "JamRuby::LessonBooking" belongs_to :lesson_payment_charge, class_name: "JamRuby::LessonPaymentCharge", foreign_key: :charge_id belongs_to :posa_card, class_name: "JamRuby::PosaCard", foreign_key: :posa_card_id has_one :lesson_session, class_name: "JamRuby::LessonSession", dependent: :destroy has_many :teacher_distributions, class_name: "JamRuby::TeacherDistribution" has_one :sale_line_item, class_name: "JamRuby::SaleLineItem", dependent: :destroy validates :user, presence: true validates :lesson_package_type, presence: true validates :price, presence: true validate :validate_test_drive, on: :create after_create :add_test_drives after_create :create_charge def validate_test_drive if user # if this is a posa card purchase, we won't stop it from getting created if posa_card_id return end if lesson_package_type.is_test_drive? && !user.can_buy_test_drive? errors.add(:user, "can not buy test drive right now because you have already purchased it within the last year") end end end def create_charge if payment_if_school_on_school? && lesson_booking && lesson_booking.is_monthly_payment? self.lesson_payment_charge = LessonPaymentCharge.new lesson_payment_charge.user = user lesson_payment_charge.amount_in_cents = 0 lesson_payment_charge.fee_in_cents = 0 lesson_payment_charge.lesson_package_purchase = self lesson_payment_charge.save! end end def teacher_distribution teacher_distributions.where(education: false).first end def education_distribution teacher_distributions.where(education: true).first end def add_test_drives if posa_card_id #user.jamclass_credits incremented in posa_card.rb return end if self.lesson_package_type.is_test_drive? new_test_drives = user.remaining_test_drives + lesson_package_type.test_drive_count User.where(id: user.id).update_all(remaining_test_drives: new_test_drives) user.remaining_test_drives = new_test_drives end end def to_s "#{name}" end def name lesson_package_type.sale_display end def amount_charged lesson_payment_charge.amount_in_cents / 100.0 end def self.create(user, lesson_booking, lesson_package_type, year = nil, month = nil, posa_card = nil) purchase = LessonPackagePurchase.new purchase.user = user purchase.lesson_booking = lesson_booking purchase.teacher = lesson_booking.teacher if lesson_booking purchase.posa_card = posa_card if year purchase.year = year purchase.month = month purchase.recurring = true # this is for monthly if lesson_booking && lesson_booking.requires_teacher_distribution?(purchase) if lesson_booking.posa_card.nil? && lesson_booking.payment # if there is a payment object, it will describe how everything gets doled out payment = JSON.parse(lesson_booking.payment) teacher_split = payment["teacher"] retailer_split = payment["retailer"] retailer_rate = teacher.teacher.retailer.jamkazam_rate + APP_CONFIG.stripe[:charge_fee] # add 0.03 to account for stripe deduction if teacher_split && teacher_split > 0 teacher_dist = TeacherDistribution.create_for_lesson_package_purchase(purchase, false, (teacher_split / 100.0).round(2), retailer_rate) purchase.teacher_distributions << teacher_dist # price should always match the teacher_distribution, if there is one purchase.price = teacher_dist.amount_in_cents / 100 end if retailer_split && retailer_split > 0 teacher_dist = TeacherDistribution.create_for_lesson_package_purchase(purchase, false, (retailer_split / 100.0).round(2), retailer_rate) teacher_dist.retailer = teacher.teacher.retailer teacher_dist.save purchase.teacher_distributions << teacher_dist end else teacher_dist = TeacherDistribution.create_for_lesson_package_purchase(purchase, false) purchase.teacher_distributions << teacher_dist # price should always match the teacher_distribution, if there is one purchase.price = teacher_dist.amount_in_cents / 100 if lesson_booking.school_on_school_payment? && lesson_booking.school.education teacher_dist = TeacherDistribution.create_for_lesson_package_purchase(purchase, true) purchase.teacher_distributions << teacher_dist end end end else purchase.recurring = false end if lesson_booking purchase.lesson_package_type = lesson_package_type ? lesson_package_type : lesson_booking.lesson_package_type purchase.price = lesson_booking.booked_price if purchase.price.nil? else purchase.lesson_package_type = lesson_package_type purchase.price = lesson_package_type.price if purchase.price.nil? end purchase.save purchase end def price_in_cents (price * 100).to_i end def description(lesson_booking) lesson_package_type.description(lesson_booking) end def stripe_description(lesson_booking) description(lesson_booking) end def timed_description "Lessons for the month of #{self.month_name} with #{self.lesson_booking.student.name}" end def month_name if recurring Date.new(year, month, 1).strftime('%B') else 'non-monthly paid lesson' end end def student user end # test drive purchase doesn't have a tea def school_on_school? if teacher teacher.teacher.school && student.school && (teacher.teacher.school.id == student.school.id) else false end end def school_on_school_payment? #!!(school_on_school? && teacher.teacher.school.education) school_on_school? end def no_school_on_school_payment? !!(school_on_school? && !school_on_school_payment?) end # if this is school-on-school, is payment required? def payment_if_school_on_school? !!(!school_on_school? || school_on_school_payment?) end def bill_monthly(force = false) if !payment_if_school_on_school? puts "SCHOOL ON SCHOOL PAYMENT OH NO" raise "school-on-school: should not be here" else lesson_payment_charge.charge(force) success = lesson_payment_charge.billed end if success self.sent_notices = true self.sent_notices_at = Time.now self.post_processed = true self.post_processed_at = Time.now self.save(:validate => false) end 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 update_payment_url APP_CONFIG.external_root_url + "/client#/jamclass/update-payment" end end end