Class: Spiff
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- Spiff
- Includes:
- Models::Auditable, Models::LiquidMethods
- Defined in:
- app/models/spiff.rb
Overview
== Schema Information
Table name: spiffs
Database name: primary
id :integer not null, primary key
begin_date :date
buying_group_ids :integer is an Array
catalog_ids :integer is an Array
enrollment_period :integer
expire_date :date
max_enrollments :integer
name :string(255)
survey_url :string(255)
created_at :datetime
updated_at :datetime
Constant Summary
Constants included from Models::Auditable
Models::Auditable::ALWAYS_IGNORED
Constants included from Schedulable
Schedulable::SIMPLE_FORM_OPTIONS
Instance Attribute Summary collapse
- #begin_date ⇒ Object readonly
- #expire_date ⇒ Object readonly
- #name ⇒ Object readonly
Has many collapse
- #contacts ⇒ ActiveRecord::Relation<Contact>
- #orders ⇒ ActiveRecord::Relation<Order>
- #spiff_enrollments ⇒ ActiveRecord::Relation<SpiffEnrollment>
- #spiff_rewards ⇒ ActiveRecord::Relation<SpiffReward>
Class Method Summary collapse
-
.active ⇒ ActiveRecord::Relation<Spiff>
A relation of Spiffs that are active.
-
.active_or_recent ⇒ ActiveRecord::Relation<Spiff>
A relation of Spiffs that are active or recent.
-
.active_spiff_select(buying_group_id) ⇒ Array<Array(String, Integer)>
[name, id]pairs of currently-active SPIFFs whosebuying_group_idsarray containsbuying_group_id. -
.enrollment_period_options ⇒ Array<Array(String, Integer)>
Allowed enrollment-window lengths for the SPIFF form (
enrollment_periodfield, in days). -
.for_buying_group_id ⇒ ActiveRecord::Relation<Spiff>
A relation of Spiffs that are for buying group id.
-
.for_catalog_id ⇒ ActiveRecord::Relation<Spiff>
A relation of Spiffs that are for catalog id.
-
.in_use ⇒ ActiveRecord::Relation<Spiff>
A relation of Spiffs that are in use.
-
.not_buying_group_specific ⇒ ActiveRecord::Relation<Spiff>
A relation of Spiffs that are not buying group specific.
-
.not_catalog_specific ⇒ ActiveRecord::Relation<Spiff>
A relation of Spiffs that are not catalog specific.
-
.not_expired ⇒ ActiveRecord::Relation<Spiff>
A relation of Spiffs that are not expired.
-
.recently_ended ⇒ ActiveRecord::Relation<Spiff>
A relation of Spiffs that are recently ended.
-
.select_options ⇒ Array<Array(String, Integer)>
[label, id]pairs of every SPIFF, ordered by name and annotated with the date range, for the SPIFF picker. -
.select_options_for_contact(contact, include_spiff_id) ⇒ Array<Array(String, Integer)>
[name_with_period, id]pairs of SPIFFs valid for the contact, optionally pinning an extra SPIFF (used to keep the currently-selected option visible even after it expires). -
.valid_for_contact(contact) ⇒ ActiveRecord::Relation<Spiff>
SPIFFs valid for the contact's parent Customer.
-
.valid_for_customer(customer) ⇒ ActiveRecord::Relation<Spiff>
SPIFFs that the Customer is eligible for: not yet expired, restricted to the customer's catalog and (if any) buying group.
Instance Method Summary collapse
-
#eligible_reward(itemizable) ⇒ BigDecimal
Total reward earned by
itemizable(an Order or LineItem) — sum of every linked SpiffReward's computed amount. -
#eligible_rewards(itemizable) ⇒ Hash{String=>BigDecimal}
Same as #eligible_reward but broken out by reward name —
{ "Tier 1" => 25.00, "Bonus" => 5.00 }— for showing the rep how the payout was constructed. - #expired? ⇒ Boolean
-
#get_bg_short_name ⇒ String?
7-character abbreviation of the first associated buying-group name (with spaces stripped) — used as a slug in #invoice_number.
-
#invoice_number(order) ⇒ String
Synthetic invoice number for the rep-payout invoice that writes off a SPIFF earning.
-
#is_active? ⇒ Boolean
Whether the SPIFF is past its expiration date.
-
#name_with_period ⇒ String
SPIFF name annotated with its enrollment-period length (when set) and an
(expired)tag for past-end-date rows. - #to_s ⇒ String
-
#total_revenue(spiff_state = %w[awaiting_payment paid])) ⇒ BigDecimal
Total Order revenue (gross total) attached to this SPIFF in one of the given states.
-
#total_rewards(spiff_state = %w[awaiting_payment paid])) ⇒ BigDecimal
Total payout the SPIFF would owe across orders in the given state(s) — sums SpiffReward#eligible_reward per order.
Methods included from Models::Auditable
#all_skipped_columns, #audit_reference_data, #creator, #should_not_save_version, #stamp_record, #updater
Methods inherited from ApplicationRecord
ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation
Methods included from Schedulable
Methods included from Models::AfterCommittable
Methods included from Models::EventPublishable
Instance Attribute Details
#begin_date ⇒ Object (readonly)
23 |
# File 'app/models/spiff.rb', line 23 validates :name, :begin_date, :expire_date, presence: true |
#expire_date ⇒ Object (readonly)
23 |
# File 'app/models/spiff.rb', line 23 validates :name, :begin_date, :expire_date, presence: true |
#name ⇒ Object (readonly)
23 |
# File 'app/models/spiff.rb', line 23 validates :name, :begin_date, :expire_date, presence: true |
Class Method Details
.active ⇒ ActiveRecord::Relation<Spiff>
A relation of Spiffs that are active. Active Record Scope
31 |
# File 'app/models/spiff.rb', line 31 scope :active, -> { where("spiffs.begin_date <= '#{Date.current}' and spiffs.expire_date >= '#{Date.current}'") } |
.active_or_recent ⇒ ActiveRecord::Relation<Spiff>
A relation of Spiffs that are active or recent. Active Record Scope
30 |
# File 'app/models/spiff.rb', line 30 scope :active_or_recent, -> { where("spiffs.expire_date >= '#{Date.current - 1.month}'") } |
.active_spiff_select(buying_group_id) ⇒ Array<Array(String, Integer)>
[name, id] pairs of currently-active SPIFFs whose
buying_group_ids array contains buying_group_id.
91 92 93 |
# File 'app/models/spiff.rb', line 91 def self.active_spiff_select() Spiff.active.where("buying_group_ids like '%#{}%'").map { |n| [n.name, n.id] } end |
.enrollment_period_options ⇒ Array<Array(String, Integer)>
Allowed enrollment-window lengths for the SPIFF form
(enrollment_period field, in days).
66 67 68 |
# File 'app/models/spiff.rb', line 66 def self. [['30 days', 30], ['60 days', 60], ['90 days', 90]] end |
.for_buying_group_id ⇒ ActiveRecord::Relation<Spiff>
A relation of Spiffs that are for buying group id. Active Record Scope
39 |
# File 'app/models/spiff.rb', line 39 scope :for_buying_group_id, ->() { where.overlap(buying_group_ids: ).or(where('cardinality(buying_group_ids) = 0')) } |
.for_catalog_id ⇒ ActiveRecord::Relation<Spiff>
A relation of Spiffs that are for catalog id. Active Record Scope
40 |
# File 'app/models/spiff.rb', line 40 scope :for_catalog_id, ->(catalog_id) { where.overlap(catalog_ids: catalog_id).or(where('cardinality(catalog_ids) = 0')) } |
.in_use ⇒ ActiveRecord::Relation<Spiff>
A relation of Spiffs that are in use. Active Record Scope
33 |
# File 'app/models/spiff.rb', line 33 scope :in_use, -> { where('id in (select distinct(p.spiff_id) from parties p where p.spiff_id is not null)') } |
.not_buying_group_specific ⇒ ActiveRecord::Relation<Spiff>
A relation of Spiffs that are not buying group specific. Active Record Scope
37 |
# File 'app/models/spiff.rb', line 37 scope :not_buying_group_specific, -> { where(buying_group_ids: []) } |
.not_catalog_specific ⇒ ActiveRecord::Relation<Spiff>
A relation of Spiffs that are not catalog specific. Active Record Scope
38 |
# File 'app/models/spiff.rb', line 38 scope :not_catalog_specific, -> { where(catalog_ids: []) } |
.not_expired ⇒ ActiveRecord::Relation<Spiff>
A relation of Spiffs that are not expired. Active Record Scope
32 |
# File 'app/models/spiff.rb', line 32 scope :not_expired, -> { where("spiffs.expire_date >= '#{Date.current}'") } |
.recently_ended ⇒ ActiveRecord::Relation<Spiff>
A relation of Spiffs that are recently ended. Active Record Scope
34 35 36 |
# File 'app/models/spiff.rb', line 34 scope :recently_ended, -> { where("spiffs.expire_date <= '#{Date.current}' and spiffs.expire_date >= '#{(Date.current - 1.month).at_beginning_of_month}'") } |
.select_options ⇒ Array<Array(String, Integer)>
[label, id] pairs of every SPIFF, ordered by name and
annotated with the date range, for the SPIFF picker.
82 83 84 |
# File 'app/models/spiff.rb', line 82 def self. Spiff.order(:name).map { |n| ["#{n.name} (#{n.begin_date.to_fs(:crm_date_only)} - #{n.expire_date.to_fs(:crm_date_only)})", n.id] } end |
.select_options_for_contact(contact, include_spiff_id) ⇒ Array<Array(String, Integer)>
[name_with_period, id] pairs of SPIFFs valid for the
contact, optionally pinning an extra SPIFF (used to keep the
currently-selected option visible even after it expires).
102 103 104 105 106 |
# File 'app/models/spiff.rb', line 102 def self.(contact, include_spiff_id) scope = valid_for_contact(contact).to_a scope << Spiff.find(include_spiff_id) if include_spiff_id scope.uniq.sort.map { |s| [s.name_with_period, s.id] } end |
.valid_for_contact(contact) ⇒ ActiveRecord::Relation<Spiff>
SPIFFs valid for the contact's parent Customer. Sales reps
use this when enrolling individual contacts (installers).
74 75 76 77 |
# File 'app/models/spiff.rb', line 74 def self.valid_for_contact(contact) customer = contact.customer valid_for_customer(customer) end |
.valid_for_customer(customer) ⇒ ActiveRecord::Relation<Spiff>
SPIFFs that the Customer is eligible for: not yet expired,
restricted to the customer's catalog and (if any) buying
group. Both filters fall through when the SPIFF is "open"
(no catalog / buying-group restriction).
57 58 59 60 61 |
# File 'app/models/spiff.rb', line 57 def self.valid_for_customer(customer) spiffs = not_expired.for_catalog_id(customer.catalog_id) spiffs = spiffs.(customer.) if customer. spiffs end |
Instance Method Details
#contacts ⇒ ActiveRecord::Relation<Contact>
25 |
# File 'app/models/spiff.rb', line 25 has_many :contacts |
#eligible_reward(itemizable) ⇒ BigDecimal
Total reward earned by itemizable (an Order or
LineItem) — sum of every linked SpiffReward's computed
amount. Used by Liquid templates exposed to enrollees.
158 159 160 161 162 163 164 |
# File 'app/models/spiff.rb', line 158 def eligible_reward(itemizable) reward = BigDecimal('0') spiff_rewards.each do |r| reward += r.eligible_reward(itemizable) end reward end |
#eligible_rewards(itemizable) ⇒ Hash{String=>BigDecimal}
Same as #eligible_reward but broken out by reward name —
{ "Tier 1" => 25.00, "Bonus" => 5.00 } — for showing the
rep how the payout was constructed.
172 173 174 175 176 177 178 |
# File 'app/models/spiff.rb', line 172 def eligible_rewards(itemizable) rewards = {} spiff_rewards.each do |r| rewards[r.name] = r.eligible_reward(itemizable) if r.eligible_reward(itemizable) > 0 end rewards end |
#expired? ⇒ Boolean
131 132 133 |
# File 'app/models/spiff.rb', line 131 def expired? expire_date && expire_date <= Date.current end |
#get_bg_short_name ⇒ String?
7-character abbreviation of the first associated buying-group
name (with spaces stripped) — used as a slug in
#invoice_number. Returns nil for SPIFFs that aren't tied
to a buying group.
202 203 204 205 206 207 208 |
# File 'app/models/spiff.rb', line 202 def get_bg_short_name return nil if .blank? bg = BuyingGroup.find(.first) y = Object.new.extend(ActionView::Helpers::TextHelper) y.truncate(bg.name.delete(' '), length: 7, omission: '') end |
#invoice_number(order) ⇒ String
Synthetic invoice number for the rep-payout invoice that
writes off a SPIFF earning. Format:
SPIFF-<BG-SHORT>-<MMYY>-<ORDER#>.
186 187 188 |
# File 'app/models/spiff.rb', line 186 def invoice_number(order) ['SPIFF', get_bg_short_name, begin_date.strftime('%m%y'), order.reference_number].compact.join('-') end |
#is_active? ⇒ Boolean
Whether the SPIFF is past its expiration date.
192 193 194 |
# File 'app/models/spiff.rb', line 192 def is_active? expire_date >= Date.current end |
#name_with_period ⇒ String
SPIFF name annotated with its enrollment-period length
(when set) and an (expired) tag for past-end-date rows.
Used in dropdowns shared between active and historical SPIFFs.
145 146 147 148 149 150 |
# File 'app/models/spiff.rb', line 145 def name_with_period res = name res << " (#{enrollment_period} day period)" if enrollment_period.present? res << ' (expired)' if expired? res end |
#orders ⇒ ActiveRecord::Relation<Order>
28 |
# File 'app/models/spiff.rb', line 28 has_many :orders, through: :spiff_enrollments |
#spiff_enrollments ⇒ ActiveRecord::Relation<SpiffEnrollment>
27 |
# File 'app/models/spiff.rb', line 27 has_many :spiff_enrollments |
#spiff_rewards ⇒ ActiveRecord::Relation<SpiffReward>
26 |
# File 'app/models/spiff.rb', line 26 has_many :spiff_rewards, dependent: :destroy |
#to_s ⇒ String
136 137 138 |
# File 'app/models/spiff.rb', line 136 def to_s "#{name} [#{id}]" end |
#total_revenue(spiff_state = %w[awaiting_payment paid])) ⇒ BigDecimal
Total Order revenue (gross total) attached to this SPIFF in
one of the given states. Defaults to "earned but not yet
paid out" totals.
114 115 116 117 |
# File 'app/models/spiff.rb', line 114 def total_revenue(spiff_state = %w[awaiting_payment paid]) spiff_enrollment_ids = spiff_enrollments.map(&:id) Order.where(spiff_enrollment_id: spiff_enrollment_ids, spiff_state: spiff_state).sum(:total) end |
#total_rewards(spiff_state = %w[awaiting_payment paid])) ⇒ BigDecimal
Total payout the SPIFF would owe across orders in the given
state(s) — sums SpiffReward#eligible_reward per order.
124 125 126 127 128 |
# File 'app/models/spiff.rb', line 124 def total_rewards(spiff_state = %w[awaiting_payment paid]) spiff_enrollment_ids = spiff_enrollments.map(&:id) orders = Order.where(spiff_enrollment_id: spiff_enrollment_ids, spiff_state: spiff_state) orders.to_a.sum { |o| o.spiff_enrollment.spiff.eligible_reward(o) } end |