event_sourced_accounting 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.markdown +0 -3
- data/app/models/esa/account.rb +1 -1
- data/app/models/esa/context.rb +11 -3
- data/app/models/esa/ruleset.rb +2 -2
- data/app/models/esa/state.rb +11 -0
- data/app/models/esa/traits/accountable.rb +15 -0
- data/lib/esa/blocking_processor.rb +12 -0
- data/lib/esa/configuration.rb +2 -2
- data/lib/esa/context_providers/account_context_provider.rb +5 -1
- data/lib/esa/context_providers/date_context_provider.rb +7 -1
- data/lib/esa/version.rb +1 -1
- data/lib/esa.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 757034522657c82880626fda4bb8222b7e9702f3
|
4
|
+
data.tar.gz: b7fdfc9e21ec74f08a59040ab4e18b3eced0e006
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce61668ed87fa606d807ed3e0864fc16d1bff53dd86632a9089a4c251f86a26078cfe29a517aa22a9d29c1b33ec60b9e18d206cbd3e27d94d88dd0b622dc358a
|
7
|
+
data.tar.gz: 9b4a9e77495d407138511ce337132ad16e1c61742f7b6c82d5fd0d9c7e972547534e54ebd756d4cceb965a0a59f32503efb7186db1bce5609521540da320cfde
|
data/README.markdown
CHANGED
@@ -14,9 +14,6 @@ This plugin began life as a fork of the [Plutus](https://github.com/mbulat/plutu
|
|
14
14
|
many added features and refactored compontents. As the aims of the ESA plug-in have completely
|
15
15
|
changed compared to the original project, it warrants a release under its own name.
|
16
16
|
|
17
|
-
The API is not yet declared frozen and may change, as some refactoring is still due.
|
18
|
-
The documentation and test coverage is expected to be completed within April-May 2014.
|
19
|
-
|
20
17
|
|
21
18
|
Installation
|
22
19
|
============
|
data/app/models/esa/account.rb
CHANGED
@@ -35,7 +35,7 @@ module ESA
|
|
35
35
|
|
36
36
|
before_validation :update_normal_balance
|
37
37
|
validates_presence_of :type, :name, :chart, :normal_balance
|
38
|
-
validates_uniqueness_of :code, :scope => :chart_id
|
38
|
+
validates_uniqueness_of :code, :scope => :chart_id, :allow_nil => true
|
39
39
|
validates_uniqueness_of :name, :scope => :chart_id
|
40
40
|
|
41
41
|
# The balance of the account.
|
data/app/models/esa/context.rb
CHANGED
@@ -108,7 +108,7 @@ module ESA
|
|
108
108
|
end
|
109
109
|
|
110
110
|
def update!(options = {})
|
111
|
-
self.freshness =
|
111
|
+
self.freshness = self.next_freshness_timestamp
|
112
112
|
|
113
113
|
ESA.configuration.context_checkers.each do |checker|
|
114
114
|
if checker.respond_to? :check
|
@@ -121,10 +121,18 @@ module ESA
|
|
121
121
|
end
|
122
122
|
|
123
123
|
def update_freshness_timestamp!
|
124
|
-
self.freshness =
|
124
|
+
self.freshness = self.next_freshness_timestamp
|
125
125
|
self.save if self.can_be_persisted?
|
126
126
|
end
|
127
127
|
|
128
|
+
def next_freshness_timestamp
|
129
|
+
if self.parent.present?
|
130
|
+
[self.freshness, self.parent.try(:freshness)].compact.max
|
131
|
+
else
|
132
|
+
Time.zone.now
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
128
136
|
def subcontext_namespaces
|
129
137
|
self.subcontexts.pluck(:namespace).compact.uniq
|
130
138
|
end
|
@@ -225,7 +233,7 @@ module ESA
|
|
225
233
|
|
226
234
|
def parents_and_self
|
227
235
|
contexts = [self]
|
228
|
-
while contexts.last.parent_id.present? and
|
236
|
+
while contexts.last.parent_id.present? and
|
229
237
|
not contexts.last.parent_id.in? contexts.map(&:id) and
|
230
238
|
contexts.count < 16 do
|
231
239
|
# found a valid parent
|
data/app/models/esa/ruleset.rb
CHANGED
@@ -215,8 +215,8 @@ module ESA
|
|
215
215
|
|
216
216
|
def find_account(type, name)
|
217
217
|
if self.chart.present? and Account.valid_type?(type)
|
218
|
-
|
219
|
-
where(:
|
218
|
+
Account.namespaced_type(type).constantize.
|
219
|
+
where(:chart_id => self.chart, :name => name).
|
220
220
|
first_or_create
|
221
221
|
end
|
222
222
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module ESA
|
2
|
+
# Records the last known state of the given Accountable object
|
3
|
+
#
|
4
|
+
# @author Lenno Nagel
|
5
|
+
class State < ActiveRecord::Base
|
6
|
+
attr_accessible :accountable, :processed_at, :unprocessed
|
7
|
+
attr_readonly :accountable
|
8
|
+
|
9
|
+
belongs_to :accountable, :polymorphic => true
|
10
|
+
end
|
11
|
+
end
|
@@ -4,10 +4,25 @@ module ESA
|
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
6
|
included do
|
7
|
+
has_one :esa_state, :as => :accountable, :class_name => ESA::State, dependent: :destroy
|
7
8
|
has_many :esa_events, :as => :accountable, :class_name => ESA::Event.extension_name(self), :extend => ESA::Associations::EventsExtension
|
8
9
|
has_many :esa_flags, :as => :accountable, :class_name => ESA::Flag.extension_name(self), :extend => ESA::Associations::FlagsExtension
|
9
10
|
has_many :esa_transactions, :as => :accountable, :class_name => ESA::Transaction.extension_name(self), :extend => ESA::Associations::TransactionsExtension
|
10
11
|
|
12
|
+
scope :esa_processed_at, lambda { |timespec|
|
13
|
+
joins("INNER JOIN `esa_states` ON `esa_states`.`accountable_id` = `#{table_name}`.`#{primary_key}` AND `esa_states`.`accountable_type` = '#{self}'").
|
14
|
+
where(esa_states: {processed_at: timespec}).
|
15
|
+
readonly(false)
|
16
|
+
}
|
17
|
+
|
18
|
+
scope :esa_unprocessed, lambda {
|
19
|
+
joins("LEFT JOIN `esa_states` ON `esa_states`.`accountable_id` = `#{table_name}`.`#{primary_key}` AND `esa_states`.`accountable_type` = '#{self}'").
|
20
|
+
where("`esa_states`.`id` IS NULL").
|
21
|
+
readonly(false)
|
22
|
+
}
|
23
|
+
|
24
|
+
|
25
|
+
|
11
26
|
before_destroy :destroy_accountable
|
12
27
|
|
13
28
|
def esa_ruleset
|
@@ -7,6 +7,16 @@ module ESA
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.process_accountable(accountable)
|
10
|
+
processed = create_and_process_events(accountable)
|
11
|
+
|
12
|
+
state = ESA::State.where(accountable_id: accountable.id, accountable_type: accountable.class).first_or_create
|
13
|
+
state.processed_at = Time.now
|
14
|
+
state.unprocessed = processed ? 0 : accountable.esa_events.where(processed: false).count
|
15
|
+
|
16
|
+
state.save
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.create_and_process_events(accountable)
|
10
20
|
events_created = create_events(accountable)
|
11
21
|
|
12
22
|
if events_created
|
@@ -17,6 +27,8 @@ module ESA
|
|
17
27
|
# do not process later events if one fails
|
18
28
|
return false if not event.processed
|
19
29
|
end
|
30
|
+
|
31
|
+
true
|
20
32
|
else
|
21
33
|
false
|
22
34
|
end
|
data/lib/esa/configuration.rb
CHANGED
@@ -35,8 +35,8 @@ module ESA
|
|
35
35
|
'account' => ESA::ContextProviders::AccountContextProvider,
|
36
36
|
'accountable' => ESA::ContextProviders::AccountableContextProvider,
|
37
37
|
'accountable_type' => ESA::ContextProviders::AccountableTypeContextProvider,
|
38
|
-
'month' => [ESA::ContextProviders::DateContextProvider, {period: :month}],
|
39
|
-
'date' => [ESA::ContextProviders::DateContextProvider, {period: :date}],
|
38
|
+
'month' => [ESA::ContextProviders::DateContextProvider, {all: true, period: :month}],
|
39
|
+
'date' => [ESA::ContextProviders::DateContextProvider, {all: true, period: :date}],
|
40
40
|
}
|
41
41
|
|
42
42
|
@context_tree = {
|
@@ -10,7 +10,11 @@ module ESA
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.contained_ids(context, options = {})
|
13
|
-
|
13
|
+
if options[:all].present? and options[:all] == true
|
14
|
+
context.accounts.pluck(:id)
|
15
|
+
else
|
16
|
+
context.amounts.uniq.pluck(:account_id)
|
17
|
+
end
|
14
18
|
end
|
15
19
|
|
16
20
|
def self.instantiate(parent, namespace, id, options = {})
|
@@ -10,7 +10,13 @@ module ESA
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.contained_ids(context, options = {})
|
13
|
-
|
13
|
+
if options[:all].present? and options[:all] == true and
|
14
|
+
context.effective_start_date.present? and
|
15
|
+
context.effective_end_date.present?
|
16
|
+
dates = context.effective_start_date..context.effective_end_date
|
17
|
+
else
|
18
|
+
dates = context.transactions.uniq.pluck("date(esa_transactions.time)").sort
|
19
|
+
end
|
14
20
|
|
15
21
|
if options[:period].present? and options[:period] == :month
|
16
22
|
dates.group_by{|d| [d.year, d.month]}.keys.
|
data/lib/esa/version.rb
CHANGED
data/lib/esa.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: event_sourced_accounting
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lenno Nagel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-08-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -219,6 +219,7 @@ files:
|
|
219
219
|
- app/models/esa/event.rb
|
220
220
|
- app/models/esa/flag.rb
|
221
221
|
- app/models/esa/ruleset.rb
|
222
|
+
- app/models/esa/state.rb
|
222
223
|
- app/models/esa/traits/accountable.rb
|
223
224
|
- app/models/esa/traits/extendable.rb
|
224
225
|
- app/models/esa/traits/or_scope.rb
|