subledger 0.7.7

Sign up to get free protection for your applications and to get access to all the features.
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