subledger 0.7.7

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.
Files changed (85) hide show
  1. data/.gitignore +9 -0
  2. data/LICENSE.txt +12 -0
  3. data/README.md +136 -0
  4. data/Rakefile +5 -0
  5. data/bin/subledger +6 -0
  6. data/lib/subledger/actor.rb +32 -0
  7. data/lib/subledger/collection_name.rb +25 -0
  8. data/lib/subledger/domain/account.rb +168 -0
  9. data/lib/subledger/domain/balance.rb +102 -0
  10. data/lib/subledger/domain/book.rb +111 -0
  11. data/lib/subledger/domain/category.rb +157 -0
  12. data/lib/subledger/domain/control.rb +180 -0
  13. data/lib/subledger/domain/formatters.rb +31 -0
  14. data/lib/subledger/domain/identity.rb +159 -0
  15. data/lib/subledger/domain/journal_entry.rb +293 -0
  16. data/lib/subledger/domain/key.rb +113 -0
  17. data/lib/subledger/domain/line.rb +272 -0
  18. data/lib/subledger/domain/org.rb +110 -0
  19. data/lib/subledger/domain/report.rb +247 -0
  20. data/lib/subledger/domain/report_rendering.rb +233 -0
  21. data/lib/subledger/domain/roles/activatable.rb +11 -0
  22. data/lib/subledger/domain/roles/archivable.rb +11 -0
  23. data/lib/subledger/domain/roles/attributable.rb +14 -0
  24. data/lib/subledger/domain/roles/collectable.rb +175 -0
  25. data/lib/subledger/domain/roles/creatable.rb +58 -0
  26. data/lib/subledger/domain/roles/describable.rb +33 -0
  27. data/lib/subledger/domain/roles/describable_report_rendering.rb +50 -0
  28. data/lib/subledger/domain/roles/identifiable.rb +15 -0
  29. data/lib/subledger/domain/roles/postable.rb +54 -0
  30. data/lib/subledger/domain/roles/progressable.rb +11 -0
  31. data/lib/subledger/domain/roles/readable.rb +34 -0
  32. data/lib/subledger/domain/roles/restable.rb +69 -0
  33. data/lib/subledger/domain/roles/storable.rb +30 -0
  34. data/lib/subledger/domain/roles/timeable.rb +18 -0
  35. data/lib/subledger/domain/roles/updatable.rb +35 -0
  36. data/lib/subledger/domain/roles/versionable.rb +35 -0
  37. data/lib/subledger/domain/roles.rb +16 -0
  38. data/lib/subledger/domain/value/credit.rb +16 -0
  39. data/lib/subledger/domain/value/debit.rb +16 -0
  40. data/lib/subledger/domain/value/zero.rb +24 -0
  41. data/lib/subledger/domain/value.rb +111 -0
  42. data/lib/subledger/domain.rb +95 -0
  43. data/lib/subledger/exception_handler.rb +65 -0
  44. data/lib/subledger/interface/client.rb +295 -0
  45. data/lib/subledger/interface/dispatcher.rb +20 -0
  46. data/lib/subledger/interface.rb +2 -0
  47. data/lib/subledger/path.rb +106 -0
  48. data/lib/subledger/rest.rb +128 -0
  49. data/lib/subledger/server.rb +3 -0
  50. data/lib/subledger/store/api/errors.rb +95 -0
  51. data/lib/subledger/store/api/roles/activate.rb +21 -0
  52. data/lib/subledger/store/api/roles/archive.rb +21 -0
  53. data/lib/subledger/store/api/roles/balance.rb +39 -0
  54. data/lib/subledger/store/api/roles/categories.rb +51 -0
  55. data/lib/subledger/store/api/roles/collect.rb +58 -0
  56. data/lib/subledger/store/api/roles/create.rb +26 -0
  57. data/lib/subledger/store/api/roles/create_and_post.rb +35 -0
  58. data/lib/subledger/store/api/roles/create_identity.rb +39 -0
  59. data/lib/subledger/store/api/roles/create_line.rb +24 -0
  60. data/lib/subledger/store/api/roles/first_and_last_line.rb +31 -0
  61. data/lib/subledger/store/api/roles/post.rb +25 -0
  62. data/lib/subledger/store/api/roles/progress.rb +21 -0
  63. data/lib/subledger/store/api/roles/read.rb +19 -0
  64. data/lib/subledger/store/api/roles/reports.rb +77 -0
  65. data/lib/subledger/store/api/roles/update.rb +24 -0
  66. data/lib/subledger/store/api/store.rb +103 -0
  67. data/lib/subledger/store/api.rb +20 -0
  68. data/lib/subledger/store.rb +236 -0
  69. data/lib/subledger/supervisor.rb +21 -0
  70. data/lib/subledger/uuid.rb +52 -0
  71. data/lib/subledger/version.rb +4 -0
  72. data/lib/subledger.rb +234 -0
  73. data/spec/spec_helper.rb +77 -0
  74. data/spec/subledger_account_spec.rb +354 -0
  75. data/spec/subledger_book_spec.rb +130 -0
  76. data/spec/subledger_category_spec.rb +203 -0
  77. data/spec/subledger_control_spec.rb +43 -0
  78. data/spec/subledger_identity_spec.rb +47 -0
  79. data/spec/subledger_journal_entry_spec.rb +417 -0
  80. data/spec/subledger_key_spec.rb +43 -0
  81. data/spec/subledger_org_spec.rb +68 -0
  82. data/spec/subledger_report_spec.rb +295 -0
  83. data/spec/subledger_spec.rb +101 -0
  84. data/subledger.gemspec +52 -0
  85. metadata +205 -0
@@ -0,0 +1,106 @@
1
+ module Subledger
2
+ module Path
3
+ def self.for_collection args
4
+ "/#{ API_VERSION }#{ path args }"
5
+ end
6
+
7
+ def self.for_entity args
8
+ "#{ for_collection args }/#{ args[ :anchor ].id }"
9
+ end
10
+
11
+ def self.for_entity_without_api_version args
12
+ "#{ path args }/#{ args[ :anchor ].id }"
13
+ end
14
+
15
+ def self.for_collect args
16
+ action = args[:action]
17
+ state = args[:state]
18
+ limit = args[:limit]
19
+ collection_name = args[:collection_name]
20
+
21
+ key = key_for args
22
+ value = URI.escape value_for( args ).to_s
23
+
24
+ path = for_collection( args ) + '?'
25
+
26
+ query_params = []
27
+
28
+ query_params << "state=#{ state }" unless collection_name == :account_lines
29
+ query_params << "action=#{ action }"
30
+ query_params << "#{ key }=#{ value }" unless value.respond_to?( :length ) and value.length.zero?
31
+ query_params << "limit=#{ limit }" unless limit.nil?
32
+
33
+ path + query_params.join('&')
34
+ end
35
+
36
+ private
37
+
38
+ COLLECTION_PATHS = {
39
+ :identities => lambda { |anchor| 'identities' },
40
+ :keys => lambda { |anchor| "identities/#{anchor.identity.id}/keys" },
41
+ :controls => lambda { |anchor| "identities/#{anchor.identity.id}/controls" },
42
+ :orgs => lambda { |anchor| 'orgs' },
43
+ :books => lambda { |anchor| "orgs/#{anchor.org.id}/books" },
44
+ :accounts => lambda { |anchor| "orgs/#{anchor.book.org.id}/books/#{anchor.book.id}/accounts" },
45
+ :journal_entries => lambda { |anchor| "orgs/#{anchor.book.org.id}/books/#{anchor.book.id}/journal_entries" },
46
+ :lines => lambda { |anchor| "orgs/#{anchor.journal_entry.book.org.id}/books/#{anchor.journal_entry.book.id}/journal_entries/#{anchor.journal_entry.id}/lines" },
47
+ :account_lines => lambda { |anchor| "orgs/#{anchor.account.book.org.id}/books/#{anchor.account.book.id}/accounts/#{anchor.account.id}/lines" },
48
+ :reports => lambda { |anchor| "orgs/#{anchor.book.org.id}/books/#{anchor.book.id}/reports" },
49
+ :categories => lambda { |anchor| "orgs/#{anchor.book.org.id}/books/#{anchor.book.id}/categories" },
50
+ :report_renderings => lambda { |anchor| "orgs/#{anchor.book.org.id}/books/#{anchor.book.id}/report_renderings" }
51
+ }
52
+
53
+ def self.path args
54
+ anchor = args[:anchor]
55
+
56
+ collection_name = CollectionName.without_state args
57
+
58
+ path = COLLECTION_PATHS[collection_name].call anchor
59
+
60
+ "/#{path}"
61
+ end
62
+
63
+ KEY_FOR = { :books => 'description',
64
+ :accounts => 'description',
65
+ :journal_entries => 'effective_at',
66
+ :lines => 'order',
67
+ :account_lines => 'effective_at',
68
+ :reports => 'description',
69
+ :categories => 'description',
70
+ :report_renderings => 'rendered_at'
71
+ }
72
+
73
+ def self.key_for args
74
+ action = args[:action]
75
+
76
+ if [ :preceding, :following ].include? action
77
+ 'id'
78
+ else
79
+ KEY_FOR[ CollectionName.without_state args ]
80
+ end
81
+ end
82
+
83
+ VALUE_FOR = { :books => lambda { |anchor| anchor.description },
84
+ :accounts => lambda { |anchor| anchor.description },
85
+ :journal_entries => lambda { |anchor| anchor.effective_at.iso8601(3) },
86
+ :lines => lambda { |anchor| anchor.order },
87
+ :account_lines => lambda { |anchor| anchor.effective_at.iso8601(3) },
88
+ :reports => lambda { |anchor| anchor.description },
89
+ :categories => lambda { |anchor| anchor.description },
90
+ :report_renderings => lambda { |anchor| anchor.rendered_at.iso8601(3) }
91
+ }
92
+
93
+ def self.value_for args
94
+ action = args[:action]
95
+ anchor = args[:anchor]
96
+
97
+ if [ :preceding, :following ].include? action
98
+ anchor.id
99
+ else
100
+ collection_name = CollectionName.without_state args
101
+
102
+ VALUE_FOR[collection_name].call anchor
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,128 @@
1
+ module Subledger
2
+ module Rest
3
+ def self.to_args rest_args, client
4
+ args = { }
5
+
6
+ rest_args.each do |key, value|
7
+ key_symbol = key.to_sym
8
+
9
+ unless value.nil?
10
+ code = LAMBDAS[key]
11
+
12
+ args[key_symbol] = if code.nil? or value.kind_of? Domain
13
+ value
14
+ else
15
+ code.call client, args, key, value
16
+ end
17
+ end
18
+ end
19
+
20
+ args
21
+ end
22
+
23
+ def self.to_balance rest_args, client
24
+ to_args( rest_args, client )[:balance]
25
+ end
26
+
27
+ def self.present_entity entity
28
+ { entity.entity_name => entity.serializable_hash }
29
+ end
30
+
31
+ def self.present_collection entity_name, collection
32
+ entities = collection.collect { |entity| entity.serializable_hash }
33
+
34
+ { entity_name => entities }
35
+ end
36
+
37
+ private
38
+
39
+ ACCOUNT = lambda do |client, args, key, value|
40
+ client.account :id => value
41
+ end
42
+
43
+ # TODO eliminate if condition in BALANCE LAMBDA
44
+
45
+ BALANCE = lambda do |client, args, key, value|
46
+ if value.has_key? :debit_value
47
+ client.balance :debit_value => debit_value( client, value[:debit_value ]['amount'] ),
48
+ :credit_value => credit_value( client, value[:credit_value]['amount'] )
49
+ else
50
+ client.balance :debit_value => debit_value( client, value['debit_value' ]['amount'] ),
51
+ :credit_value => credit_value( client, value['credit_value']['amount'] )
52
+ end
53
+ end
54
+
55
+ BOOK = lambda do |client, args, key, value|
56
+ client.book :id => value
57
+ end
58
+
59
+ CATEGORIES = lambda do |client, args, key, value|
60
+ args[:categories] = MultiJson.dump value
61
+ end
62
+
63
+ IDENTITY = lambda do |client, args, key, value|
64
+ client.identity :id => value
65
+ end
66
+
67
+ JOURNAL_ENTRY = lambda do |client, args, key, value|
68
+ client.journal_entry :id => value
69
+ end
70
+
71
+ MODE = lambda do |client, args, key, value|
72
+ value.to_sym
73
+ end
74
+
75
+ NB = lambda do | client, args, key, value |
76
+ client.send value
77
+ end
78
+
79
+ ORG = lambda do |client, args, key, value|
80
+ client.org :id => value
81
+ end
82
+
83
+ TIME = lambda do |client, args, key, value|
84
+ Subledger.parse_time key, value
85
+ end
86
+
87
+ VALUE = lambda do |client, args, key, value|
88
+ client.send value['type'], value['amount']
89
+ end
90
+
91
+ VERSION = lambda do |client, args, key, value|
92
+ value.to_i
93
+ end
94
+
95
+ REPORT = lambda do |client, args, key, value|
96
+ client.report :id => value
97
+ end
98
+
99
+ LAMBDAS = {
100
+ 'account' => ACCOUNT,
101
+ 'balance' => BALANCE,
102
+ 'book' => BOOK,
103
+ 'categories' => CATEGORIES,
104
+ 'completed_at' => TIME,
105
+ 'credit_value' => VALUE,
106
+ 'debit_value' => VALUE,
107
+ 'effective_at' => TIME,
108
+ 'identity' => IDENTITY,
109
+ 'journal_entry' => JOURNAL_ENTRY,
110
+ 'mode' => MODE,
111
+ 'normal_balance' => NB,
112
+ 'org' => ORG,
113
+ 'posted_at' => TIME,
114
+ 'rendered_at' => TIME,
115
+ 'report' => REPORT,
116
+ 'value' => VALUE,
117
+ 'version' => VERSION
118
+ }
119
+
120
+ def self.debit_value client, amount
121
+ BigDecimal( amount ) == 0 ? client.zero : client.debit( amount )
122
+ end
123
+
124
+ def self.credit_value client, amount
125
+ BigDecimal( amount ) == 0 ? client.zero : client.credit( amount )
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,3 @@
1
+ require 'bundler/setup'
2
+
3
+ require 'subledger/server/v1'
@@ -0,0 +1,95 @@
1
+ module Subledger
2
+ module Store
3
+ module Api
4
+ module Errors
5
+ # Raised when the Subledger API returns a 400 status code
6
+ class BadRequest < Error; end
7
+
8
+ # Raised when the Subledger API returns a 401 status code
9
+ class Unauthorized < Error; end
10
+
11
+ # Raised when the Subledger API returns a 403 status code
12
+ class Forbidden < Error; end
13
+
14
+ # Raised when the Subledger API returns a 404 status code
15
+ class NotFound < Error; end
16
+
17
+ # Raised when the Subledger API returns a 406 status code
18
+ class NotAcceptable < Error; end
19
+
20
+ # Raised when the Subledger API returns a 409 status code
21
+ class Conflict < Error; end
22
+
23
+ # Raised when the Subledger API returns a 422 status code
24
+ class UnprocessableEntity < Error; end
25
+
26
+ # Raised when the Subledger API returns a 500 status code
27
+ class InternalServerError < Error; end
28
+
29
+ # Raised when the Subledger API returns a 501 status code
30
+ class NotImplemented < Error; end
31
+
32
+ # Raised when the Subledger API returns a 502 status code
33
+ class BadGateway < Error; end
34
+
35
+ # Raised when the Subledger API returns a 503 status code
36
+ class ServiceUnavailable < Error; end
37
+
38
+ # Raise when the Subledger API returns any other status code
39
+ class HttpError < Error; end
40
+
41
+ class ServerNotAvailable < Error
42
+ def initialize wrapped
43
+ @wrapped = wrapped
44
+ end
45
+
46
+ def message
47
+ "#{super} was not avaiable. Please check your configuration. (#{@wrapped.message})"
48
+ end
49
+ end
50
+
51
+ class ResponseError < Faraday::Response::Middleware
52
+
53
+ EXCEPTIONS = {
54
+ 400 => BadRequest,
55
+ 401 => Unauthorized,
56
+ 403 => Forbidden,
57
+ 404 => NotFound,
58
+ 406 => NotAcceptable,
59
+ 409 => Store::UpdateConflictError,
60
+ 422 => UnprocessableEntity,
61
+ 500 => InternalServerError,
62
+ 501 => NotImplemented,
63
+ 502 => BadGateway,
64
+ 503 => ServiceUnavailable
65
+ }
66
+
67
+ def call env
68
+ @app.call(env).on_complete do
69
+ status = env[:status].to_i
70
+
71
+ if ( 400..600 ).include? status
72
+ raise exception_for( status ), response_for( env )
73
+ end
74
+ end
75
+ end
76
+
77
+ def exception_for status
78
+ EXCEPTIONS[status] || HttpError
79
+ end
80
+
81
+ def response_for env
82
+ { :status => env[:status],
83
+ :url => url_for( env ),
84
+ :headers => env[:response_headers],
85
+ :body => env[:body] }
86
+ end
87
+
88
+ def url_for env
89
+ env[:url].to_s
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,21 @@
1
+ module Subledger
2
+ module Store
3
+ module Api
4
+ module Activate
5
+ def activate activatable
6
+ path = Path.for_entity( :anchor => activatable ) + '/activate'
7
+
8
+ begin
9
+ json_body = http.post do |req|
10
+ req.url path
11
+ end.body
12
+ rescue Exception => e
13
+ raise ActivateError, "Cannot activate #{activatable}: #{e}"
14
+ end
15
+
16
+ new_or_initialize json_body, activatable
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ module Subledger
2
+ module Store
3
+ module Api
4
+ module Archive
5
+ def archive archivable
6
+ path = Path.for_entity( :anchor => archivable ) + '/archive'
7
+
8
+ begin
9
+ json_body = http.post do |req|
10
+ req.url path
11
+ end.body
12
+ rescue Exception => e
13
+ raise ArchiveError, "Cannot archive #{archivable}: #{e}"
14
+ end
15
+
16
+ new_or_initialize json_body, archivable
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,39 @@
1
+ module Subledger
2
+ module Store
3
+ module Api
4
+ module Balance
5
+ def account_balance args
6
+ client = args[:client]
7
+ account = args[:account]
8
+ at = args[:at].iso8601(3)
9
+
10
+ path = Path.for_entity( :anchor => account ) + '/balance?at=' + at
11
+
12
+ begin
13
+ response_hash = parse_json(
14
+ http.get( path ).body )
15
+ rescue Exception => e
16
+ raise BalanceError, "Cannot balance #{account}: #{e}"
17
+ end
18
+
19
+ Rest.to_balance response_hash, client
20
+ end
21
+
22
+ def journal_entry_balance args
23
+ client = args[:client]
24
+ journal_entry = args[:journal_entry]
25
+
26
+ path = Path.for_entity( :anchor => journal_entry ) + '/balance'
27
+
28
+ begin
29
+ response_hash = parse_json( http.get( path ).body )
30
+ rescue Exception => e
31
+ raise BalanceError, "Cannot balance #{journal_entry}: #{e}"
32
+ end
33
+
34
+ Rest.to_balance response_hash, client
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,51 @@
1
+ module Subledger
2
+ module Store
3
+ module Api
4
+ module Categories
5
+ def attach_account_to_category args
6
+ category = args[:category]
7
+ account = args[:account]
8
+
9
+ path = Path.for_entity( :anchor => category ) + '/attach'
10
+
11
+ attach_post_hash = { 'account' => account.id }
12
+
13
+ begin
14
+ json_body = http.post do |req|
15
+ req.url path
16
+ req.body = attach_post_hash
17
+ end.body
18
+ rescue Exception => e
19
+ raise AttachError, "Cannot attach #{account}: #{e}"
20
+ end
21
+
22
+ account
23
+ end
24
+
25
+ def detach_account_from_category args
26
+ category = args[:category]
27
+ account = args[:account]
28
+
29
+ path = Path.for_entity( :anchor => category ) + '/detach'
30
+
31
+ detach_post_hash = { 'account' => account.id }
32
+
33
+ begin
34
+ json_body = http.post do |req|
35
+ req.url path
36
+ req.body = detach_post_hash
37
+ end.body
38
+ rescue Exception => e
39
+ raise DetachError, "Cannot detach #{account}: #{e}"
40
+ end
41
+
42
+ account
43
+ end
44
+
45
+ def collect_accounts_for_category category
46
+ raise CategoryError, 'category#accounts is not yet implemented'
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,58 @@
1
+ module Subledger
2
+ module Store
3
+ module Api
4
+ module Collect
5
+
6
+ private
7
+
8
+ def before args
9
+ collect_with args
10
+ end
11
+
12
+ def ending args
13
+ collect_with args
14
+ end
15
+
16
+ def starting args
17
+ collect_with args
18
+ end
19
+
20
+ def after args
21
+ collect_with args
22
+ end
23
+
24
+ def preceding args
25
+ collect_with args
26
+ end
27
+
28
+ def following args
29
+ collect_with args
30
+ end
31
+
32
+ def collect_with args
33
+ path = Path.for_collect args
34
+
35
+ anchor = args[:anchor]
36
+
37
+ klass = anchor.class
38
+
39
+ begin
40
+ collection = parse_json http.get( path ).body
41
+ rescue Exception => e
42
+ raise CollectError, "Cannot collect: #{e}"
43
+ end
44
+
45
+ client = anchor.client
46
+
47
+ key = collection.keys.first
48
+
49
+ collection[key].collect do |response_hash|
50
+ args = Rest.to_args response_hash, client
51
+
52
+ client.send key, args
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,26 @@
1
+ module Subledger
2
+ module Store
3
+ module Api
4
+ module Create
5
+ def create creatable
6
+ unless creatable.id.nil?
7
+ raise CreateError, 'cannot create an object with an :id'
8
+ end
9
+
10
+ path = Path.for_collection :anchor => creatable
11
+
12
+ begin
13
+ json_body = http.post do |req|
14
+ req.url path
15
+ req.body = creatable.post_hash
16
+ end.body
17
+ rescue Exception => e
18
+ raise CreateError, "Cannot create #{creatable}: #{e}"
19
+ end
20
+
21
+ new_or_initialize json_body, creatable
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,35 @@
1
+ module Subledger
2
+ module Store
3
+ module Api
4
+ module CreateAndPost
5
+ def create_and_post args
6
+ dje = args[:active_journal_entry]
7
+ dje_lines = args[:active_lines]
8
+ pje = args[:posting_journal_entry]
9
+
10
+ path = Path.for_collection( :anchor => dje ) + '/create_and_post'
11
+
12
+ json_body = http.post do |req|
13
+ req.url path
14
+
15
+ unless dje.post_delay.zero?
16
+ req.headers['X-Subledger-Post-Slowly'] = 'true'
17
+ end
18
+
19
+ req.body = create_and_post_hash( dje, dje_lines )
20
+ end.body
21
+
22
+ new_or_initialize json_body, pje
23
+ end
24
+
25
+ private
26
+
27
+ def create_and_post_hash dje, dje_lines
28
+ lines = dje_lines.collect { |line| line.post_hash }
29
+
30
+ dje.post_hash.merge :lines => lines
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,39 @@
1
+ module Subledger
2
+ module Store
3
+ module Api
4
+ module CreateIdentity
5
+ ACTIVE_IDENTITY = 'active_identity'
6
+ ACTIVE_KEY = 'active_key'
7
+
8
+ def create_identity identity
9
+ client = identity.client
10
+
11
+ path = Path.for_collection :anchor => identity
12
+
13
+ begin
14
+ json_body = http.post do |req|
15
+ req.url path
16
+ req.body = identity.post_hash
17
+ end.body
18
+ rescue Exception => e
19
+ raise CreateError, "Cannot create #{identity.class}: #{e}"
20
+ end
21
+
22
+ response_hash = parse_json json_body
23
+
24
+ identity_hash = { 'active_identity' => response_hash[ACTIVE_IDENTITY] }
25
+ identity_json = MultiJson.dump identity_hash
26
+
27
+ new_identity = new_or_initialize identity_json, identity
28
+
29
+ identity.send :initialize, new_identity.attributes
30
+
31
+ key_args = Rest.to_args response_hash[ACTIVE_KEY], client
32
+ key = client.active_keys key_args
33
+
34
+ return identity, key
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,24 @@
1
+ module Subledger
2
+ module Store
3
+ module Api
4
+ module CreateLine
5
+ def create_line args
6
+ begin
7
+ line = args[:line]
8
+
9
+ path = Path.for_entity( :anchor => line.journal_entry ) + '/create_line'
10
+
11
+ json_body = http.post do |req|
12
+ req.url path
13
+ req.body = line.post_hash
14
+ end.body
15
+ rescue Exception => e
16
+ raise CreateLineError, "Cannot create #{line}: #{e}"
17
+ end
18
+
19
+ new_or_initialize json_body, line
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,31 @@
1
+ module Subledger
2
+ module Store
3
+ module Api
4
+ module FirstAndLastLine
5
+
6
+ def first_and_last_line args
7
+ anchor = args[:account]
8
+ client = anchor.client
9
+
10
+ path = Path.for_entity( :anchor => anchor ) + '/first_and_last_line'
11
+
12
+ klass = anchor.class
13
+
14
+ begin
15
+ collection = parse_json http.get( path ).body
16
+ rescue Exception => e
17
+ raise FirstAndLastLineError, "Cannot get first and last line: #{e}"
18
+ end
19
+
20
+ key = collection.keys.first
21
+
22
+ collection[key].collect do |response_hash|
23
+ args = Rest.to_args response_hash, client
24
+
25
+ client.send key, args
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end