event_sourced_accounting 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|