Class: ESA::Ruleset
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- ESA::Ruleset
- Includes:
- Traits::Extendable
- Defined in:
- app/models/esa/ruleset.rb
Overview
The Ruleset class contains the business logic and rules of accounting.
Instance Method Summary collapse
-
#accountables_updated_at(timespec) ⇒ Object
accountable.
- #addable_unrecorded_events_as_attributes(accountable) ⇒ Object
- #ensure_positive_amounts(attrs) ⇒ Object
- #event_flags_as_attributes(event) ⇒ Object
-
#event_nature_flags ⇒ Object
flags.
-
#event_times(accountable) ⇒ Object
events.
- #find_account(type, name) ⇒ Object
- #flag_transactions(flag) ⇒ Object
- #flag_transactions_as_attributes(flag) ⇒ Object
- #flag_transactions_match_specs?(flag) ⇒ Boolean
-
#flag_transactions_spec(accountable, flag_nature) ⇒ Object
transactions.
- #flag_transactions_when_adjusted(flag) ⇒ Object
- #flag_transactions_when_set(flag) ⇒ Object
- #flag_transactions_when_unset(flag) ⇒ Object
- #flags_needing_adjustment(accountable) ⇒ Object
- #inverted(amounts) ⇒ Object
- #is_adjustment_event_needed?(accountable) ⇒ Boolean
- #stateful_events(accountable) ⇒ Object
- #stateful_events_as_attributes(accountable) ⇒ Object
- #unrecorded_events_as_attributes(accountable) ⇒ Object
Instance Method Details
#accountables_updated_at(timespec) ⇒ Object
accountable
22 23 24 |
# File 'app/models/esa/ruleset.rb', line 22 def accountables_updated_at(timespec) [] end |
#addable_unrecorded_events_as_attributes(accountable) ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'app/models/esa/ruleset.rb', line 69 def addable_unrecorded_events_as_attributes(accountable) flag_times_max = accountable.esa_flags.group(:nature).maximum(:time) unrecorded_events_as_attributes(accountable).select do |event| event_flags = event_nature_flags[event[:nature]] || {} flag_times = flag_times_max.slice(*event_flags.keys.map(&:to_s)) # allow when the event flags have not been used before or # when all the currently used flag times are before the new event flag_times.values.none? || flag_times.values.max <= event[:time] end end |
#ensure_positive_amounts(attrs) ⇒ Object
198 199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'app/models/esa/ruleset.rb', line 198 def ensure_positive_amounts(attrs) amounts = attrs[:debits] + attrs[:credits] nonpositives = amounts.map{|a| a[:amount] <= BigDecimal(0)} if nonpositives.all? attrs.merge({ debits: inverted(attrs[:credits]), credits: inverted(attrs[:debits]), }) else attrs end end |
#event_flags_as_attributes(event) ⇒ Object
92 93 94 95 96 97 98 99 100 101 102 |
# File 'app/models/esa/ruleset.rb', line 92 def event_flags_as_attributes(event) flags = self.event_nature_flags[event.nature.to_sym] || {} flags.map do |nature,state| { :accountable => event.accountable, :nature => nature, :state => state, :event => event, } end end |
#event_nature_flags ⇒ Object
flags
88 89 90 |
# File 'app/models/esa/ruleset.rb', line 88 def event_nature_flags {} end |
#event_times(accountable) ⇒ Object
events
28 29 30 |
# File 'app/models/esa/ruleset.rb', line 28 def event_times(accountable) {} end |
#find_account(type, name) ⇒ Object
216 217 218 219 220 221 222 |
# File 'app/models/esa/ruleset.rb', line 216 def find_account(type, name) if self.chart.present? and Account.valid_type?(type) Account.namespaced_type(type).constantize. where(:chart_id => self.chart, :name => name). first_or_create end end |
#flag_transactions(flag) ⇒ Object
169 170 171 172 173 174 175 176 177 178 179 |
# File 'app/models/esa/ruleset.rb', line 169 def flag_transactions(flag) if flag.adjusted? flag_transactions_when_adjusted(flag) elsif flag.is_set? and (flag.became_set? or (flag.event.present? and flag.event.nature.adjustment?)) flag_transactions_when_set(flag) elsif flag.became_unset? flag_transactions_when_unset(flag) else [] end end |
#flag_transactions_as_attributes(flag) ⇒ Object
181 182 183 184 185 186 187 188 189 190 191 |
# File 'app/models/esa/ruleset.rb', line 181 def flag_transactions_as_attributes(flag) defaults = { time: flag.time, accountable: flag.accountable, flag: flag, } flag_transactions(flag).map do |tx| attrs = defaults.merge(tx) ensure_positive_amounts(attrs) end end |
#flag_transactions_match_specs?(flag) ⇒ Boolean
193 194 195 196 |
# File 'app/models/esa/ruleset.rb', line 193 def flag_transactions_match_specs?(flag) specs = flag_transactions_as_attributes(flag) flag.transactions_match_specs?(specs) end |
#flag_transactions_spec(accountable, flag_nature) ⇒ Object
transactions
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'app/models/esa/ruleset.rb', line 118 def flag_transactions_spec(accountable, flag_nature) function_name = "flag_#{flag_nature}_transactions" if self.respond_to? function_name transactions = self.send(function_name, accountable) if transactions.is_a? Hash [transactions] elsif transactions.is_a? Array transactions else [] end else [] end end |
#flag_transactions_when_adjusted(flag) ⇒ Object
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'app/models/esa/ruleset.rb', line 150 def flag_transactions_when_adjusted(flag) flag.transactions.map do |tx| if tx.valid? spec = tx.spec [ # original transaction, which must be kept spec, # adjustment transaction, which must be added spec.merge({ :time => flag.adjustment_time, :description => "#{tx.description} / adjusted", :debits => spec[:credits], # swap :credits => spec[:debits], # swap }) ] end end.compact.flatten end |
#flag_transactions_when_set(flag) ⇒ Object
136 137 138 |
# File 'app/models/esa/ruleset.rb', line 136 def flag_transactions_when_set(flag) flag_transactions_spec(flag.accountable, flag.nature) end |
#flag_transactions_when_unset(flag) ⇒ Object
140 141 142 143 144 145 146 147 148 |
# File 'app/models/esa/ruleset.rb', line 140 def flag_transactions_when_unset(flag) self.flag_transactions_when_set(flag).map do |tx| tx.merge({ description: "#{tx[:description]} / reversed", debits: tx[:credits], credits: tx[:debits] }) end end |
#flags_needing_adjustment(accountable) ⇒ Object
104 105 106 107 108 109 110 111 112 113 114 |
# File 'app/models/esa/ruleset.rb', line 104 def flags_needing_adjustment(accountable) natures = accountable.esa_flags.pluck(:nature).uniq.map{|nature| nature.to_sym} most_recent_flags = natures.map do |nature| accountable.esa_flags.transitioning.most_recent(nature) end.compact most_recent_flags.select do |flag| flag.is_set? and not flag_transactions_match_specs?(flag) end end |
#inverted(amounts) ⇒ Object
212 213 214 |
# File 'app/models/esa/ruleset.rb', line 212 def inverted(amounts) amounts.map{|a| a.dup.merge({amount: BigDecimal(0) - a[:amount]}) } end |
#is_adjustment_event_needed?(accountable) ⇒ Boolean
82 83 84 |
# File 'app/models/esa/ruleset.rb', line 82 def is_adjustment_event_needed?(accountable) flags_needing_adjustment(accountable).count > 0 end |
#stateful_events(accountable) ⇒ Object
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'app/models/esa/ruleset.rb', line 32 def stateful_events(accountable) self.event_times(accountable).map do |nature,times| if times.present? and times.is_a? Time {nature: nature, time: times} elsif times.present? and times.respond_to? :each times.map do |t| if t.is_a? Time {nature: nature, time: t} else nil end end.compact else nil end end.flatten.compact end |
#stateful_events_as_attributes(accountable) ⇒ Object
50 51 52 53 54 55 56 57 58 |
# File 'app/models/esa/ruleset.rb', line 50 def stateful_events_as_attributes(accountable) defaults = { accountable: accountable, ruleset: self, } stateful_events(accountable).map do |event| defaults.merge(event) end end |
#unrecorded_events_as_attributes(accountable) ⇒ Object
60 61 62 63 64 65 66 67 |
# File 'app/models/esa/ruleset.rb', line 60 def unrecorded_events_as_attributes(accountable) stateful = stateful_events_as_attributes(accountable) recorded = accountable.esa_events.pluck([:nature, :time]). map{|nature,time| [nature, time.to_i]} stateful.reject{|s| [s[:nature].to_s, s[:time].to_i].in? recorded} end |