subledger 0.7.7
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +9 -0
- data/LICENSE.txt +12 -0
- data/README.md +136 -0
- data/Rakefile +5 -0
- data/bin/subledger +6 -0
- data/lib/subledger/actor.rb +32 -0
- data/lib/subledger/collection_name.rb +25 -0
- data/lib/subledger/domain/account.rb +168 -0
- data/lib/subledger/domain/balance.rb +102 -0
- data/lib/subledger/domain/book.rb +111 -0
- data/lib/subledger/domain/category.rb +157 -0
- data/lib/subledger/domain/control.rb +180 -0
- data/lib/subledger/domain/formatters.rb +31 -0
- data/lib/subledger/domain/identity.rb +159 -0
- data/lib/subledger/domain/journal_entry.rb +293 -0
- data/lib/subledger/domain/key.rb +113 -0
- data/lib/subledger/domain/line.rb +272 -0
- data/lib/subledger/domain/org.rb +110 -0
- data/lib/subledger/domain/report.rb +247 -0
- data/lib/subledger/domain/report_rendering.rb +233 -0
- data/lib/subledger/domain/roles/activatable.rb +11 -0
- data/lib/subledger/domain/roles/archivable.rb +11 -0
- data/lib/subledger/domain/roles/attributable.rb +14 -0
- data/lib/subledger/domain/roles/collectable.rb +175 -0
- data/lib/subledger/domain/roles/creatable.rb +58 -0
- data/lib/subledger/domain/roles/describable.rb +33 -0
- data/lib/subledger/domain/roles/describable_report_rendering.rb +50 -0
- data/lib/subledger/domain/roles/identifiable.rb +15 -0
- data/lib/subledger/domain/roles/postable.rb +54 -0
- data/lib/subledger/domain/roles/progressable.rb +11 -0
- data/lib/subledger/domain/roles/readable.rb +34 -0
- data/lib/subledger/domain/roles/restable.rb +69 -0
- data/lib/subledger/domain/roles/storable.rb +30 -0
- data/lib/subledger/domain/roles/timeable.rb +18 -0
- data/lib/subledger/domain/roles/updatable.rb +35 -0
- data/lib/subledger/domain/roles/versionable.rb +35 -0
- data/lib/subledger/domain/roles.rb +16 -0
- data/lib/subledger/domain/value/credit.rb +16 -0
- data/lib/subledger/domain/value/debit.rb +16 -0
- data/lib/subledger/domain/value/zero.rb +24 -0
- data/lib/subledger/domain/value.rb +111 -0
- data/lib/subledger/domain.rb +95 -0
- data/lib/subledger/exception_handler.rb +65 -0
- data/lib/subledger/interface/client.rb +295 -0
- data/lib/subledger/interface/dispatcher.rb +20 -0
- data/lib/subledger/interface.rb +2 -0
- data/lib/subledger/path.rb +106 -0
- data/lib/subledger/rest.rb +128 -0
- data/lib/subledger/server.rb +3 -0
- data/lib/subledger/store/api/errors.rb +95 -0
- data/lib/subledger/store/api/roles/activate.rb +21 -0
- data/lib/subledger/store/api/roles/archive.rb +21 -0
- data/lib/subledger/store/api/roles/balance.rb +39 -0
- data/lib/subledger/store/api/roles/categories.rb +51 -0
- data/lib/subledger/store/api/roles/collect.rb +58 -0
- data/lib/subledger/store/api/roles/create.rb +26 -0
- data/lib/subledger/store/api/roles/create_and_post.rb +35 -0
- data/lib/subledger/store/api/roles/create_identity.rb +39 -0
- data/lib/subledger/store/api/roles/create_line.rb +24 -0
- data/lib/subledger/store/api/roles/first_and_last_line.rb +31 -0
- data/lib/subledger/store/api/roles/post.rb +25 -0
- data/lib/subledger/store/api/roles/progress.rb +21 -0
- data/lib/subledger/store/api/roles/read.rb +19 -0
- data/lib/subledger/store/api/roles/reports.rb +77 -0
- data/lib/subledger/store/api/roles/update.rb +24 -0
- data/lib/subledger/store/api/store.rb +103 -0
- data/lib/subledger/store/api.rb +20 -0
- data/lib/subledger/store.rb +236 -0
- data/lib/subledger/supervisor.rb +21 -0
- data/lib/subledger/uuid.rb +52 -0
- data/lib/subledger/version.rb +4 -0
- data/lib/subledger.rb +234 -0
- data/spec/spec_helper.rb +77 -0
- data/spec/subledger_account_spec.rb +354 -0
- data/spec/subledger_book_spec.rb +130 -0
- data/spec/subledger_category_spec.rb +203 -0
- data/spec/subledger_control_spec.rb +43 -0
- data/spec/subledger_identity_spec.rb +47 -0
- data/spec/subledger_journal_entry_spec.rb +417 -0
- data/spec/subledger_key_spec.rb +43 -0
- data/spec/subledger_org_spec.rb +68 -0
- data/spec/subledger_report_spec.rb +295 -0
- data/spec/subledger_spec.rb +101 -0
- data/subledger.gemspec +52 -0
- metadata +205 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
module Subledger
|
2
|
+
module Domain
|
3
|
+
class Zero
|
4
|
+
|
5
|
+
include Value
|
6
|
+
|
7
|
+
def self.type
|
8
|
+
'zero'
|
9
|
+
end
|
10
|
+
|
11
|
+
def rest_hash
|
12
|
+
{ 'type' => 'zero', 'amount' => amount_to_s(@amount) }
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def validate_sign arg_amount
|
18
|
+
unless arg_amount.zero?
|
19
|
+
raise ValueError, 'Amount must be zero'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# additional requires at bottom
|
2
|
+
|
3
|
+
module Subledger
|
4
|
+
module Domain
|
5
|
+
class ValueError < Error; end
|
6
|
+
|
7
|
+
module Value
|
8
|
+
|
9
|
+
def self.included base
|
10
|
+
base.extend ValueClass
|
11
|
+
end
|
12
|
+
|
13
|
+
module ValueClass
|
14
|
+
def raise_unless_creatable args
|
15
|
+
value = args[:value]
|
16
|
+
|
17
|
+
if value.nil? or not value.kind_of? Value
|
18
|
+
raise ValueError, ':value is required and must be a Value'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :amount
|
24
|
+
|
25
|
+
def initialize arg_amount=0
|
26
|
+
if arg_amount.nil?
|
27
|
+
raise ValueError, 'amount may not be nil'
|
28
|
+
end
|
29
|
+
|
30
|
+
validate_amount(arg_amount) if arg_amount.respond_to?(:match)
|
31
|
+
|
32
|
+
big_amount = BigDecimal arg_amount
|
33
|
+
|
34
|
+
validate_sign big_amount
|
35
|
+
|
36
|
+
validate_amount( amount_to_s big_amount )
|
37
|
+
|
38
|
+
@amount = big_amount
|
39
|
+
end
|
40
|
+
|
41
|
+
def + other
|
42
|
+
(Balance.new + value + other.value).value
|
43
|
+
end
|
44
|
+
|
45
|
+
def == other
|
46
|
+
self.value.class == other.value.class and amount == other.amount
|
47
|
+
end
|
48
|
+
|
49
|
+
def value
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_s
|
54
|
+
"#{self.class.type}: #{amount_to_s @amount}"
|
55
|
+
end
|
56
|
+
|
57
|
+
alias :inspect :to_s
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def amount_to_s arg_amount
|
62
|
+
if arg_amount.zero?
|
63
|
+
'0'
|
64
|
+
else
|
65
|
+
arg_amount.to_s( 'F' ).chomp( '.0' ).sub( /^0+/, '' )
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def validate_sign arg_amount
|
70
|
+
unless arg_amount > 0
|
71
|
+
raise ValueError, 'amount must be positive'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
ERROR_TEXT = 'amount is limited to 15 whole digits and 12 fractional digits'
|
76
|
+
|
77
|
+
def validate_amount arg_amount
|
78
|
+
|
79
|
+
unless arg_amount.match /^\d*[.]?\d*$/
|
80
|
+
raise ValueError, "amount (#{arg_amount}) must be numeric"
|
81
|
+
end
|
82
|
+
|
83
|
+
return if BigDecimal(arg_amount).zero?
|
84
|
+
|
85
|
+
arg_amount.sub! /^0+/, ''
|
86
|
+
arg_amount.sub! /[.](\d)*0+$/, '.\\1'
|
87
|
+
|
88
|
+
if arg_amount.include? '.'
|
89
|
+
whole, fraction = arg_amount.split '.'
|
90
|
+
|
91
|
+
whole ||= ''
|
92
|
+
fraction ||= ''
|
93
|
+
|
94
|
+
if whole.length > 15 or fraction.length > 12
|
95
|
+
raise ValueError, ERROR_TEXT
|
96
|
+
end
|
97
|
+
else
|
98
|
+
if arg_amount.length > 15
|
99
|
+
raise ValueError, ERROR_TEXT
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
require 'subledger/domain/value/credit'
|
110
|
+
require 'subledger/domain/value/debit'
|
111
|
+
require 'subledger/domain/value/zero'
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'bcrypt'
|
2
|
+
require 'grape-entity'
|
3
|
+
|
4
|
+
# additional requires at bottom
|
5
|
+
|
6
|
+
module Subledger
|
7
|
+
module Domain
|
8
|
+
class ActivatableError < Error; end
|
9
|
+
class ArchivableError < Error; end
|
10
|
+
class AttributableError < Error; end
|
11
|
+
class CollectableError < Error; end
|
12
|
+
class CreatableError < Error; end
|
13
|
+
class DescribableError < Error; end
|
14
|
+
class DescribableReportRenderingError < Error; end
|
15
|
+
class IdentifiableError < Error; end
|
16
|
+
class PostableError < Error; end
|
17
|
+
class ProgressableError < Error; end
|
18
|
+
class ReadableError < Error; end
|
19
|
+
class RestableError < Error; end
|
20
|
+
class StorableError < Error; end
|
21
|
+
class TimeableError < Error; end
|
22
|
+
class UpdatableError < Error; end
|
23
|
+
class VersionableError < Error; end
|
24
|
+
|
25
|
+
def self.included base
|
26
|
+
base.extend DomainClass
|
27
|
+
end
|
28
|
+
|
29
|
+
module DomainClass
|
30
|
+
def keys
|
31
|
+
self::Entity.exposures.keys
|
32
|
+
end
|
33
|
+
|
34
|
+
def entity_name
|
35
|
+
self::Entity.instance_variable_get( :@root ).to_sym
|
36
|
+
end
|
37
|
+
|
38
|
+
def collection_name
|
39
|
+
self::Entity.instance_variable_get( :@collection_root ).to_sym
|
40
|
+
end
|
41
|
+
|
42
|
+
def raise_unless_creatable args
|
43
|
+
raise NoMethodError, 'subclasses must provide self.raise_unless_creatable'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def == other
|
48
|
+
if respond_to?( :id ) and
|
49
|
+
other.respond_to?( :id ) and
|
50
|
+
( ( not id.nil? ) and ( not other.id.nil? ) )
|
51
|
+
id == other.id
|
52
|
+
else
|
53
|
+
super
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def collection_name
|
58
|
+
self.class.collection_name
|
59
|
+
end
|
60
|
+
|
61
|
+
def entity_name
|
62
|
+
self.class.entity_name
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_s
|
66
|
+
"#{entity_name}: #{ MultiJson.dump serializable_hash }"
|
67
|
+
end
|
68
|
+
|
69
|
+
alias :inspect :to_s
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def short_klass_name
|
74
|
+
self.class.name.match( /[^:]+$/ )[0] + ': '
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
require 'subledger/domain/formatters'
|
80
|
+
require 'subledger/domain/roles'
|
81
|
+
|
82
|
+
require 'subledger/domain/value'
|
83
|
+
|
84
|
+
require 'subledger/domain/account'
|
85
|
+
require 'subledger/domain/balance'
|
86
|
+
require 'subledger/domain/book'
|
87
|
+
require 'subledger/domain/category'
|
88
|
+
require 'subledger/domain/control'
|
89
|
+
require 'subledger/domain/identity'
|
90
|
+
require 'subledger/domain/journal_entry'
|
91
|
+
require 'subledger/domain/key'
|
92
|
+
require 'subledger/domain/line'
|
93
|
+
require 'subledger/domain/org'
|
94
|
+
require 'subledger/domain/report'
|
95
|
+
require 'subledger/domain/report_rendering'
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Subledger
|
2
|
+
class ExceptionHandler
|
3
|
+
|
4
|
+
# attempts seconds
|
5
|
+
# 1 no point!
|
6
|
+
# 2 0.15+
|
7
|
+
# 3 0.35+
|
8
|
+
# 4 0.75+
|
9
|
+
# 5 1.55+
|
10
|
+
# 6 3.15+
|
11
|
+
# 7 6.35+
|
12
|
+
# 8 12.75+
|
13
|
+
# 9 25.55+ default max_attempts
|
14
|
+
# 10 51.15
|
15
|
+
#
|
16
|
+
# attempts 11 and up are 2 seconds apart
|
17
|
+
|
18
|
+
def initialize args
|
19
|
+
@name = args[:name]
|
20
|
+
@exception = args[:exception] || Exception
|
21
|
+
@max_attempts = args[:max_attempts] || 10
|
22
|
+
@initial_delay = args[:initial_delay] || 0
|
23
|
+
end
|
24
|
+
|
25
|
+
def with_retry
|
26
|
+
|
27
|
+
attempts = 1
|
28
|
+
total = 0
|
29
|
+
|
30
|
+
sleep @initial_delay
|
31
|
+
|
32
|
+
begin
|
33
|
+
yield
|
34
|
+
rescue @exception => e
|
35
|
+
if is_internal?( e ) or ( attempts >= @max_attempts )
|
36
|
+
raise e, "FAILURE: #{@name}, attempts: #{attempts}, total: #{total}, #{e}"
|
37
|
+
elsif attempts < @max_attempts
|
38
|
+
|
39
|
+
if attempts < 11
|
40
|
+
delay = 2 ** attempts * 0.05
|
41
|
+
else
|
42
|
+
delay += 2
|
43
|
+
end
|
44
|
+
|
45
|
+
if attempts > 8
|
46
|
+
LOG.warn "RETRY: #{@name}, attempts: #{attempts}, delay: #{delay}, #{e}"
|
47
|
+
end
|
48
|
+
|
49
|
+
sleep delay
|
50
|
+
|
51
|
+
total += delay
|
52
|
+
attempts += 1
|
53
|
+
|
54
|
+
retry
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def is_internal? e
|
62
|
+
e.class.name.to_s =~ /^Subledger::/
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,295 @@
|
|
1
|
+
module Subledger
|
2
|
+
module Interface
|
3
|
+
class ClientError < Error; end
|
4
|
+
|
5
|
+
class Client
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
attr_reader :client_args
|
10
|
+
|
11
|
+
COLLECTIONS = { :identity => { :klass => Domain::Identity,
|
12
|
+
:root_collection => :identities,
|
13
|
+
:state => :active },
|
14
|
+
:identities => { :klass => Domain::Identity,
|
15
|
+
:root_collection => :identities,
|
16
|
+
:state => :active },
|
17
|
+
:archived_identity => { :klass => Domain::ArchivedIdentity,
|
18
|
+
:root_collection => :identities,
|
19
|
+
:state => :archived },
|
20
|
+
:archived_identities => { :klass => Domain::ArchivedIdentity,
|
21
|
+
:root_collection => :identities,
|
22
|
+
:state => :archived },
|
23
|
+
:active_identity => { :klass => Domain::ActiveIdentity,
|
24
|
+
:root_collection => :identities,
|
25
|
+
:state => :active },
|
26
|
+
:active_identities => { :klass => Domain::ActiveIdentity,
|
27
|
+
:root_collection => :identities,
|
28
|
+
:state => :active },
|
29
|
+
:key => { :klass => Domain::Key,
|
30
|
+
:root_collection => :keys,
|
31
|
+
:state => :active },
|
32
|
+
:keys => { :klass => Domain::Key,
|
33
|
+
:root_collection => :keys,
|
34
|
+
:state => :active },
|
35
|
+
:archived_key => { :klass => Domain::ArchivedKey,
|
36
|
+
:root_collection => :keys,
|
37
|
+
:state => :archived },
|
38
|
+
:archived_keys => { :klass => Domain::ArchivedKey,
|
39
|
+
:root_collection => :keys,
|
40
|
+
:state => :archived },
|
41
|
+
:active_key => { :klass => Domain::ActiveKey,
|
42
|
+
:root_collection => :keys,
|
43
|
+
:state => :active },
|
44
|
+
:active_keys => { :klass => Domain::ActiveKey,
|
45
|
+
:root_collection => :keys,
|
46
|
+
:state => :active },
|
47
|
+
:control => { :klass => Domain::Control,
|
48
|
+
:root_collection => :controls,
|
49
|
+
:state => :active },
|
50
|
+
:controls => { :klass => Domain::Control,
|
51
|
+
:root_collection => :controls,
|
52
|
+
:state => :active },
|
53
|
+
:archived_control => { :klass => Domain::ArchivedControl,
|
54
|
+
:root_collection => :controls,
|
55
|
+
:state => :archived },
|
56
|
+
:archived_controls => { :klass => Domain::ArchivedControl,
|
57
|
+
:root_collection => :controls,
|
58
|
+
:state => :archived },
|
59
|
+
:active_control => { :klass => Domain::ActiveControl,
|
60
|
+
:root_collection => :controls,
|
61
|
+
:state => :active },
|
62
|
+
:active_controls => { :klass => Domain::ActiveControl,
|
63
|
+
:root_collection => :controls,
|
64
|
+
:state => :active },
|
65
|
+
:org => { :klass => Domain::Org,
|
66
|
+
:root_collection => :orgs,
|
67
|
+
:state => :active },
|
68
|
+
:orgs => { :klass => Domain::Org,
|
69
|
+
:root_collection => :orgs,
|
70
|
+
:state => :active },
|
71
|
+
:archived_org => { :klass => Domain::ArchivedOrg,
|
72
|
+
:root_collection => :orgs,
|
73
|
+
:state => :archived },
|
74
|
+
:archived_orgs => { :klass => Domain::ArchivedOrg,
|
75
|
+
:root_collection => :orgs,
|
76
|
+
:state => :archived },
|
77
|
+
:active_org => { :klass => Domain::ActiveOrg,
|
78
|
+
:root_collection => :orgs,
|
79
|
+
:state => :active },
|
80
|
+
:active_orgs => { :klass => Domain::ActiveOrg,
|
81
|
+
:root_collection => :orgs,
|
82
|
+
:state => :active },
|
83
|
+
:book => { :klass => Domain::Book,
|
84
|
+
:root_collection => :books,
|
85
|
+
:state => :active },
|
86
|
+
:books => { :klass => Domain::Book,
|
87
|
+
:root_collection => :books,
|
88
|
+
:state => :active },
|
89
|
+
:archived_book => { :klass => Domain::ArchivedBook,
|
90
|
+
:root_collection => :books,
|
91
|
+
:state => :archived },
|
92
|
+
:archived_books => { :klass => Domain::ArchivedBook,
|
93
|
+
:root_collection => :books,
|
94
|
+
:state => :archived },
|
95
|
+
:active_book => { :klass => Domain::ActiveBook,
|
96
|
+
:root_collection => :books,
|
97
|
+
:state => :active },
|
98
|
+
:active_books => { :klass => Domain::ActiveBook,
|
99
|
+
:root_collection => :books,
|
100
|
+
:state => :active },
|
101
|
+
:account => { :klass => Domain::Account,
|
102
|
+
:root_collection => :accounts,
|
103
|
+
:state => :active },
|
104
|
+
:accounts => { :klass => Domain::Account,
|
105
|
+
:root_collection => :accounts,
|
106
|
+
:state => :active },
|
107
|
+
:archived_account => { :klass => Domain::ArchivedAccount,
|
108
|
+
:root_collection => :accounts,
|
109
|
+
:state => :archived },
|
110
|
+
:archived_accounts => { :klass => Domain::ArchivedAccount,
|
111
|
+
:root_collection => :accounts,
|
112
|
+
:state => :archived },
|
113
|
+
:active_account => { :klass => Domain::ActiveAccount,
|
114
|
+
:root_collection => :accounts,
|
115
|
+
:state => :active },
|
116
|
+
:active_accounts => { :klass => Domain::ActiveAccount,
|
117
|
+
:root_collection => :accounts,
|
118
|
+
:state => :active },
|
119
|
+
:category_accounts => { :klass => Domain::Account,
|
120
|
+
:root_collection => :category_accounts,
|
121
|
+
:state => :nil },
|
122
|
+
:journal_entry => { :klass => Domain::JournalEntry,
|
123
|
+
:root_collection => :journal_entries,
|
124
|
+
:state => :active },
|
125
|
+
:journal_entries => { :klass => Domain::JournalEntry,
|
126
|
+
:root_collection => :journal_entries,
|
127
|
+
:state => :active },
|
128
|
+
:archived_journal_entry => { :klass => Domain::ArchivedJournalEntry,
|
129
|
+
:root_collection => :journal_entries,
|
130
|
+
:state => :archived },
|
131
|
+
:archived_journal_entries => { :klass => Domain::ArchivedJournalEntry,
|
132
|
+
:root_collection => :journal_entries,
|
133
|
+
:state => :archived },
|
134
|
+
:active_journal_entry => { :klass => Domain::ActiveJournalEntry,
|
135
|
+
:root_collection => :journal_entries,
|
136
|
+
:state => :active },
|
137
|
+
:active_journal_entries => { :klass => Domain::ActiveJournalEntry,
|
138
|
+
:root_collection => :journal_entries,
|
139
|
+
:state => :active },
|
140
|
+
:posting_journal_entry => { :klass => Domain::PostingJournalEntry,
|
141
|
+
:root_collection => :journal_entries,
|
142
|
+
:state => :posting },
|
143
|
+
:posting_journal_entries => { :klass => Domain::PostingJournalEntry,
|
144
|
+
:root_collection => :journal_entries,
|
145
|
+
:state => :posting },
|
146
|
+
:posted_journal_entry => { :klass => Domain::PostedJournalEntry,
|
147
|
+
:root_collection => :journal_entries,
|
148
|
+
:state => :posted },
|
149
|
+
:posted_journal_entries => { :klass => Domain::PostedJournalEntry,
|
150
|
+
:root_collection => :journal_entries,
|
151
|
+
:state => :posted },
|
152
|
+
:line => { :klass => Domain::Line,
|
153
|
+
:root_collection => :lines,
|
154
|
+
:state => :active },
|
155
|
+
:lines => { :klass => Domain::Line,
|
156
|
+
:root_collection => :lines,
|
157
|
+
:state => :active },
|
158
|
+
:archived_line => { :klass => Domain::ArchivedLine,
|
159
|
+
:root_collection => :lines,
|
160
|
+
:state => :archived },
|
161
|
+
:archived_lines => { :klass => Domain::ArchivedLine,
|
162
|
+
:root_collection => :lines,
|
163
|
+
:state => :archived },
|
164
|
+
:active_line => { :klass => Domain::ActiveLine,
|
165
|
+
:root_collection => :lines,
|
166
|
+
:state => :active },
|
167
|
+
:active_lines => { :klass => Domain::ActiveLine,
|
168
|
+
:root_collection => :lines,
|
169
|
+
:state => :active },
|
170
|
+
:posted_line => { :klass => Domain::PostedLine,
|
171
|
+
:root_collection => :lines,
|
172
|
+
:state => :posted },
|
173
|
+
:posted_lines => { :klass => Domain::PostedLine,
|
174
|
+
:root_collection => :lines,
|
175
|
+
:state => :posted },
|
176
|
+
:account_line => { :klass => Domain::PostedLine,
|
177
|
+
:root_collection => :account_lines,
|
178
|
+
:state => :nil },
|
179
|
+
:account_lines => { :klass => Domain::PostedLine,
|
180
|
+
:root_collection => :account_lines,
|
181
|
+
:state => :nil },
|
182
|
+
:category => { :klass => Domain::Category,
|
183
|
+
:root_collection => :categories,
|
184
|
+
:state => :active },
|
185
|
+
:categories => { :klass => Domain::Category,
|
186
|
+
:root_collection => :categories,
|
187
|
+
:state => :active },
|
188
|
+
:archived_category => { :klass => Domain::ArchivedCategory,
|
189
|
+
:root_collection => :categories,
|
190
|
+
:state => :archived },
|
191
|
+
:archived_categories => { :klass => Domain::ArchivedCategory,
|
192
|
+
:root_collection => :categories,
|
193
|
+
:state => :archived },
|
194
|
+
:active_category => { :klass => Domain::ActiveCategory,
|
195
|
+
:root_collection => :categories,
|
196
|
+
:state => :active },
|
197
|
+
:active_categories => { :klass => Domain::ActiveCategory,
|
198
|
+
:root_collection => :categories,
|
199
|
+
:state => :active },
|
200
|
+
:report_categories => { :klass => Domain::Category,
|
201
|
+
:root_collection => :report_categories,
|
202
|
+
:state => :nil },
|
203
|
+
:report => { :klass => Domain::Report,
|
204
|
+
:root_collection => :reports,
|
205
|
+
:state => :active },
|
206
|
+
:reports => { :klass => Domain::Report,
|
207
|
+
:root_collection => :reports,
|
208
|
+
:state => :active },
|
209
|
+
:archived_report => { :klass => Domain::ArchivedReport,
|
210
|
+
:root_collection => :reports,
|
211
|
+
:state => :archived },
|
212
|
+
:archived_reports => { :klass => Domain::ArchivedReport,
|
213
|
+
:root_collection => :reports,
|
214
|
+
:state => :archived },
|
215
|
+
:active_report => { :klass => Domain::ActiveReport,
|
216
|
+
:root_collection => :reports,
|
217
|
+
:state => :active },
|
218
|
+
:active_reports => { :klass => Domain::ActiveReport,
|
219
|
+
:root_collection => :reports,
|
220
|
+
:state => :active },
|
221
|
+
:report_rendering => { :klass => Domain::ReportRendering,
|
222
|
+
:root_collection => :report_renderings,
|
223
|
+
:state => :building },
|
224
|
+
:report_renderings => { :klass => Domain::ReportRendering,
|
225
|
+
:root_collection => :report_renderings,
|
226
|
+
:state => :building },
|
227
|
+
:building_report_rendering => { :klass => Domain::BuildingReportRendering,
|
228
|
+
:root_collection => :report_renderings,
|
229
|
+
:state => :building },
|
230
|
+
:building_report_renderings => { :klass => Domain::BuildingReportRendering,
|
231
|
+
:root_collection => :report_renderings,
|
232
|
+
:state => :building },
|
233
|
+
:completed_report_rendering => { :klass => Domain::CompletedReportRendering,
|
234
|
+
:root_collection => :report_renderings,
|
235
|
+
:state => :completed },
|
236
|
+
:completed_report_renderings => { :klass => Domain::CompletedReportRendering,
|
237
|
+
:root_collection => :report_renderings,
|
238
|
+
:state => :completed }
|
239
|
+
}
|
240
|
+
|
241
|
+
public
|
242
|
+
|
243
|
+
attr_reader :store
|
244
|
+
|
245
|
+
def initialize args
|
246
|
+
@client_args = args
|
247
|
+
|
248
|
+
# TODO client should not have @store and #store
|
249
|
+
|
250
|
+
@store = args[:store]
|
251
|
+
end
|
252
|
+
|
253
|
+
COLLECTIONS.each do |name, attributes|
|
254
|
+
klass = attributes[:klass]
|
255
|
+
state = attributes[:state] == :nil ? 'nil' : attributes[:state].inspect
|
256
|
+
root_collection = attributes[:root_collection]
|
257
|
+
|
258
|
+
method_text = <<-"EOM"
|
259
|
+
def #{name} *args
|
260
|
+
@#{name}_dispatcher ||= Dispatcher.new @client_args.
|
261
|
+
merge(
|
262
|
+
{ :klass => #{klass},
|
263
|
+
:client => self,
|
264
|
+
:state => #{state},
|
265
|
+
:root_collection => :#{root_collection} } )
|
266
|
+
|
267
|
+
if args.empty?
|
268
|
+
@#{name}_dispatcher
|
269
|
+
else
|
270
|
+
@#{name}_dispatcher.new args.first.dup
|
271
|
+
end
|
272
|
+
end
|
273
|
+
EOM
|
274
|
+
|
275
|
+
class_eval method_text
|
276
|
+
end
|
277
|
+
|
278
|
+
def debit *args
|
279
|
+
args.empty? ? Domain::Debit : Domain::Debit.new( *args )
|
280
|
+
end
|
281
|
+
|
282
|
+
def credit *args
|
283
|
+
args.empty? ? Domain::Credit : Domain::Credit.new( *args )
|
284
|
+
end
|
285
|
+
|
286
|
+
def zero *args
|
287
|
+
Domain::Zero.new
|
288
|
+
end
|
289
|
+
|
290
|
+
def balance *args
|
291
|
+
Domain::Balance.new *args
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Subledger
|
2
|
+
module Interface
|
3
|
+
class Dispatcher
|
4
|
+
def initialize args
|
5
|
+
@klass = args[:klass]
|
6
|
+
|
7
|
+
@dispatch_args = args
|
8
|
+
end
|
9
|
+
|
10
|
+
def method_missing method, args, &block
|
11
|
+
args.delete :store
|
12
|
+
args.delete :client
|
13
|
+
|
14
|
+
merged_args = @dispatch_args.merge args
|
15
|
+
|
16
|
+
@klass.send method, merged_args, &block
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|