-
-
Notifications
You must be signed in to change notification settings - Fork 573
Expand file tree
/
Copy pathdonation.rb
More file actions
147 lines (122 loc) · 4.66 KB
/
donation.rb
File metadata and controls
147 lines (122 loc) · 4.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# == Schema Information
#
# Table name: donations
#
# id :integer not null, primary key
# comment :text
# issued_at :datetime
# money_raised :integer
# source :string
# created_at :datetime not null
# updated_at :datetime not null
# donation_site_id :integer
# manufacturer_id :bigint
# organization_id :integer
# product_drive_id :bigint
# product_drive_participant_id :integer
# storage_location_id :integer
#
class Donation < ApplicationRecord
has_paper_trail
SOURCES = { product_drive: "Product Drive",
manufacturer: "Manufacturer",
donation_site: "Donation Site",
misc: "Misc. Donation" }.freeze
SOURCES.values.map(&:freeze)
belongs_to :organization
belongs_to :donation_site, optional: true # Validation is conditionally handled below.
belongs_to :product_drive_participant, optional: proc { |d| d.from_product_drive? } # Validation is conditionally handled below.
belongs_to :product_drive, optional: true
belongs_to :manufacturer, optional: proc { |d| d.from_manufacturer? } # Validation is conditionally handled below.
belongs_to :storage_location
include Itemizable
include Exportable
include Filterable
include IssuedAt
scope :at_storage_location, ->(storage_location_id) {
where(storage_location_id: storage_location_id)
}
scope :from_donation_site, ->(donation_site_id) { where(donation_site_id: donation_site_id) }
scope :by_product_drive, ->(product_drive_id) {
where(product_drive_id: product_drive_id)
}
scope :by_product_drive_participant, ->(product_drive_participant_id) {
where(product_drive_participant_id: product_drive_participant_id)
}
scope :from_manufacturer, ->(manufacturer_id) {
where(manufacturer_id: manufacturer_id)
}
scope :by_item_id, ->(item_id) { joins(:items).where(items: { id: item_id }).distinct }
scope :by_category, ->(item_category) {
joins(line_items: {item: :item_category}).where("item_categories.name ILIKE ?", item_category)
}
before_create :combine_duplicates
validates :donation_site, presence:
{ message: "must be specified since you chose '#{SOURCES[:donation_site]}'" }, if: :from_donation_site?
validates :product_drive, presence:
{ message: "must be specified since you chose '#{SOURCES[:product_drive]}'" }, if: :from_product_drive?
validates :manufacturer, presence:
{ message: "must be specified since you chose '#{SOURCES[:manufacturer]}'" }, if: :from_manufacturer?
validates :source, presence: true, inclusion: { in: SOURCES.values, message: "Must be a valid source." }
validates :money_raised, numericality: { greater_than_or_equal_to: 0 }, allow_nil: true
validate :line_items_quantity_is_positive
before_destroy :check_no_intervening_snapshot
# TODO: move this to Organization.donations as an extension
scope :during, ->(range) { where(donations: { issued_at: range }) }
scope :by_source, ->(source) {
return where(source: source) unless source.is_a?(Symbol)
includes(source).where(source: SOURCES[source])
}
scope :recent, ->(count = 3) { order(issued_at: :desc).limit(count) }
scope :active, -> { joins(:line_items).joins(:items).where(items: { active: true }) }
def from_product_drive?
source == SOURCES[:product_drive]
end
def from_manufacturer?
source == SOURCES[:manufacturer]
end
def from_donation_site?
source == SOURCES[:donation_site]
end
def source_view
return source unless from_product_drive?
product_drive_participant&.donation_source_view || product_drive.donation_source_view
end
def details
case source
when SOURCES[:product_drive]
product_drive.name
when SOURCES[:manufacturer]
manufacturer.name
when SOURCES[:donation_site]
donation_site.name
when SOURCES[:misc]
comment&.truncate(25, separator: /\s/)
end
end
def money_raised_in_dollars
money_raised.to_d / 100
end
def donation_site_view
donation_site.nil? ? "N/A" : donation_site.name
end
def storage_view
storage_location.nil? ? "N/A" : storage_location.name
end
def in_kind_value_money
Money.new(value_per_itemizable).to_f
end
private
def combine_duplicates
line_items.combine!
end
def line_items_quantity_is_positive
line_items_quantity_is_at_least(1)
end
def check_no_intervening_snapshot
intervening = SnapshotEvent.intervening(self)
if intervening
raise "We can't delete donations entered before #{intervening.event_time.to_date}."
end
end
end