2019-07-30 21:29:24 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2020-06-12 20:03:43 +00:00
|
|
|
# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later
|
|
|
|
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
|
2019-08-02 08:57:17 +00:00
|
|
|
require 'timespan'
|
2019-07-14 08:49:01 +00:00
|
|
|
|
2019-02-01 19:40:24 +00:00
|
|
|
class RecurringDonation < ApplicationRecord
|
2019-08-06 14:07:35 +00:00
|
|
|
# :amount, # int (cents)
|
|
|
|
# :active, # bool (whether this recurring donation should still be paid)
|
|
|
|
# :paydate, # int (fixed date of the month for monthly recurring donations)
|
|
|
|
# :interval, # int (interval of time, ie the '3' in '3 months')
|
|
|
|
# :time_unit, # str ('month', 'day', 'week', or 'year')
|
|
|
|
# :start_date, # date (when to start this recurring donation)
|
|
|
|
# :end_date, # date (when to deactivate this recurring donation)
|
|
|
|
# :n_failures, # int (how many times the charge has failed)
|
|
|
|
# :edit_token, # str / uuid to validate the editing page, linked from their email client
|
|
|
|
# :cancelled_by, # str email of user/supporter who made the cancellation
|
|
|
|
# :cancelled_at, # datetime of user/supporter who made the cancellation
|
|
|
|
# :donation_id, :donation,
|
|
|
|
# :nonprofit_id, :nonprofit,
|
|
|
|
# :supporter_id #used because things are messed up in the datamodel
|
2018-03-25 17:30:42 +00:00
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
scope :active, -> { where(active: true) }
|
|
|
|
scope :inactive, -> { where(active: [false, nil]) }
|
|
|
|
scope :monthly, -> { where(time_unit: 'month', interval: 1) }
|
|
|
|
scope :annual, -> { where(time_unit: 'year', interval: 1) }
|
2018-03-25 17:30:42 +00:00
|
|
|
|
|
|
|
belongs_to :donation
|
|
|
|
belongs_to :nonprofit
|
|
|
|
has_many :charges, through: :donation
|
|
|
|
has_one :card, through: :donation
|
|
|
|
has_one :supporter, through: :donation
|
|
|
|
|
2019-07-30 21:29:24 +00:00
|
|
|
validates :paydate, numericality: { less_than: 29 }, allow_blank: true
|
2018-03-25 17:30:42 +00:00
|
|
|
validates :donation_id, presence: true
|
|
|
|
validates :nonprofit_id, presence: true
|
|
|
|
validates :start_date, presence: true
|
2019-07-30 21:29:24 +00:00
|
|
|
validates :interval, presence: true, numericality: { greater_than: 0 }
|
|
|
|
validates :time_unit, presence: true, inclusion: { in: Timespan::Units }
|
2018-03-25 17:30:42 +00:00
|
|
|
validates_associated :donation
|
|
|
|
|
|
|
|
def most_recent_charge
|
2019-07-30 21:29:24 +00:00
|
|
|
charges&.max_by(&:created_at)
|
2018-03-25 17:30:42 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def most_recent_paid_charge
|
2019-07-30 21:29:24 +00:00
|
|
|
charges&.find_all(&:paid?)&.max_by(&:created_at)
|
2018-03-25 17:30:42 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def total_given
|
2019-07-30 21:29:24 +00:00
|
|
|
return charges.find_all(&:paid?).sum(&:amount) if charges
|
2018-03-25 17:30:42 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
# XXX let's make these monthly_totals a query
|
|
|
|
# Or just push it into the front-end
|
|
|
|
def self.monthly_total
|
2019-07-30 21:29:24 +00:00
|
|
|
all.map(&:monthly_total).sum
|
2018-03-25 17:30:42 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def monthly_total
|
|
|
|
multiple = {
|
|
|
|
'week' => 4,
|
|
|
|
'day' => 30,
|
|
|
|
'year' => 0.0833
|
2019-07-30 21:29:24 +00:00
|
|
|
}[interval] || 1
|
|
|
|
donation.amount * multiple
|
2018-03-25 17:30:42 +00:00
|
|
|
end
|
|
|
|
end
|