double_entry 2.0.0.beta4 → 2.0.0.beta5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -2
- data/README.md +64 -35
- data/lib/active_record/locking_extensions.rb +3 -3
- data/lib/double_entry.rb +18 -18
- data/lib/double_entry/account.rb +2 -2
- data/lib/double_entry/account_balance.rb +3 -3
- data/lib/double_entry/balance_calculator.rb +5 -5
- data/lib/double_entry/configuration.rb +2 -2
- data/lib/double_entry/line.rb +6 -6
- data/lib/double_entry/locking.rb +2 -2
- data/lib/double_entry/transfer.rb +2 -2
- data/lib/double_entry/validation/line_check.rb +3 -3
- data/lib/double_entry/version.rb +1 -1
- data/lib/generators/double_entry/install/templates/initializer.rb +4 -4
- data/lib/generators/double_entry/install/templates/migration.rb +26 -26
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3fac339d10077ee1c807e16d37f4aa6bd7ad4d6179f8f94b4ad114085e83b83a
|
4
|
+
data.tar.gz: 5f50033972098dfada8195c0bd17923005f2e0601ed1a694cf25c43080d2f939
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2fb0041f4cf1af34416a5af798d1b7b32675565f39f9f0abec80d40d1ad30159dc1fe716427a41a43c1c608f9b1cd8ff63c998ee2c974895a28c873ba0e7250e
|
7
|
+
data.tar.gz: 66be7ef0d59ca846b5c9c588d68dd72be1577c2ef03069fc93d148ec7bc821aaf265b66ae75ad1cece6649d1605412f41f3e81284ba2d29c513804f6484af368
|
data/CHANGELOG.md
CHANGED
@@ -7,7 +7,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
-
[
|
10
|
+
## [2.0.0.beta5] - 2020-01-25
|
11
|
+
|
12
|
+
### Changed
|
13
|
+
|
14
|
+
- Use the Ruby 1.9 hash syntax ([#182]).
|
15
|
+
- Make the Line detail association optional ([#184]).
|
16
|
+
- Support Ruby 3 ([#196]).
|
17
|
+
|
18
|
+
[#182]: https://github.com/envato/double_entry/pull/182
|
19
|
+
[#184]: https://github.com/envato/double_entry/pull/184
|
20
|
+
[#196]: https://github.com/envato/double_entry/pull/196
|
11
21
|
|
12
22
|
## [2.0.0.beta4] - 2020-01-25
|
13
23
|
|
@@ -25,7 +35,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
25
35
|
|
26
36
|
- Prevent using Ruby 2.2 via restrictions in Gemfile and Gemspec ([#175]).
|
27
37
|
|
28
|
-
[2.0.0.beta4]: https://github.com/envato/double_entry/compare/v2.0.0.beta3...v2.0.0.beta4
|
29
38
|
[#175]: https://github.com/envato/double_entry/pull/175
|
30
39
|
[#176]: https://github.com/envato/double_entry/pull/176
|
31
40
|
[#178]: https://github.com/envato/double_entry/pull/178
|
@@ -462,6 +471,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
462
471
|
|
463
472
|
- Library released as Open Source!
|
464
473
|
|
474
|
+
[Unreleased]: https://github.com/envato/double_entry/compare/v2.0.0.beta5...HEAD
|
475
|
+
[2.0.0.beta5]: https://github.com/envato/double_entry/compare/v2.0.0.beta4...v2.0.0.beta5
|
476
|
+
[2.0.0.beta4]: https://github.com/envato/double_entry/compare/v2.0.0.beta3...v2.0.0.beta4
|
465
477
|
[2.0.0.beta3]: https://github.com/envato/double_entry/compare/v2.0.0.beta2...v2.0.0.beta3
|
466
478
|
[2.0.0.beta2]: https://github.com/envato/double_entry/compare/v2.0.0.beta1...v2.0.0.beta2
|
467
479
|
[2.0.0.beta1]: https://github.com/envato/double_entry/compare/v1.0.1...v2.0.0.beta1
|
data/README.md
CHANGED
@@ -72,7 +72,7 @@ rake db:migrate
|
|
72
72
|
## Interface
|
73
73
|
|
74
74
|
The entire API for recording financial transactions is available through a few
|
75
|
-
methods in the
|
75
|
+
methods in the [DoubleEntry](lib/double_entry.rb) module. For full details on
|
76
76
|
what the API provides, please view the documentation on these methods.
|
77
77
|
|
78
78
|
A configuration file should be used to define a set of accounts, and potential
|
@@ -93,12 +93,12 @@ than scoped accounts due to lock contention.
|
|
93
93
|
To get a particular account:
|
94
94
|
|
95
95
|
```ruby
|
96
|
-
account = DoubleEntry.account(:spending, :
|
96
|
+
account = DoubleEntry.account(:spending, scope: user)
|
97
97
|
```
|
98
98
|
|
99
99
|
(This actually returns an Account::Instance object.)
|
100
100
|
|
101
|
-
See
|
101
|
+
See [DoubleEntry::Account](lib/double_entry/account.rb) for more info.
|
102
102
|
|
103
103
|
|
104
104
|
### Balances
|
@@ -119,15 +119,15 @@ To transfer money between accounts:
|
|
119
119
|
```ruby
|
120
120
|
DoubleEntry.transfer(
|
121
121
|
Money.new(20_00),
|
122
|
-
:
|
123
|
-
:
|
124
|
-
:
|
122
|
+
from: one_account,
|
123
|
+
to: another_account,
|
124
|
+
code: :a_business_code_for_this_type_of_transfer,
|
125
125
|
)
|
126
126
|
```
|
127
127
|
|
128
128
|
The possible transfers, and their codes, should be defined in the configuration.
|
129
129
|
|
130
|
-
See
|
130
|
+
See [DoubleEntry::Transfer](lib/double_entry/transfer.rb) for more info.
|
131
131
|
|
132
132
|
### Metadata
|
133
133
|
|
@@ -136,10 +136,10 @@ You may associate arbitrary metadata with transfers, for example:
|
|
136
136
|
```ruby
|
137
137
|
DoubleEntry.transfer(
|
138
138
|
Money.new(20_00),
|
139
|
-
:
|
140
|
-
:
|
141
|
-
:
|
142
|
-
:
|
139
|
+
from: one_account,
|
140
|
+
to: another_account,
|
141
|
+
code: :a_business_code_for_this_type_of_transfer,
|
142
|
+
metadata: {key1: ['value 1', 'value 2'], key2: 'value 3'},
|
143
143
|
)
|
144
144
|
```
|
145
145
|
|
@@ -152,7 +152,7 @@ manually lock the accounts you're using:
|
|
152
152
|
```ruby
|
153
153
|
DoubleEntry.lock_accounts(account_a, account_b) do
|
154
154
|
# Perhaps transfer some money
|
155
|
-
DoubleEntry.transfer(Money.new(20_00), :
|
155
|
+
DoubleEntry.transfer(Money.new(20_00), from: account_a, to: account_b, code: :purchase)
|
156
156
|
# Perform other tasks that should be commited atomically with the transfer of funds...
|
157
157
|
end
|
158
158
|
```
|
@@ -160,8 +160,23 @@ end
|
|
160
160
|
The lock_accounts call generates a database transaction, which must be the
|
161
161
|
outermost transaction.
|
162
162
|
|
163
|
-
See
|
163
|
+
See [DoubleEntry::Locking](lib/double_entry/locking.rb) for more info.
|
164
164
|
|
165
|
+
### Account Checker/Fixer
|
166
|
+
|
167
|
+
Although it's unlikely, DoubleEntry has tools for checking accounts to make sure they tie out, and optionally fixing them if there is a discrepancy. It's recommended to run this in a scheduled job, somewhere on the order of hourly to daily, depending on transaction volume. Keep in mind that this process locks accounts as it inspects their balances, so it will have an prevent new transactions from being written for a short time.
|
168
|
+
|
169
|
+
Here are examples that could go in your scheduled job, depending on your needs:
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
# Check all accounts & write the results to the double_entry_line_checks table
|
173
|
+
DoubleEntry::Validation::LineCheck.perform!
|
174
|
+
|
175
|
+
# Check & fix accounts (results will also be written to the table)
|
176
|
+
DoubleEntry::Validation::LineCheck.perform!(fixer: DoubleEntry::Validation::AccountFixer.new)
|
177
|
+
```
|
178
|
+
|
179
|
+
See [DoubleEntry::Validation](lib/double_entry/validation) for more info.
|
165
180
|
|
166
181
|
## Implementation
|
167
182
|
|
@@ -173,7 +188,7 @@ Lines table entries also store the running balance for the account. To retrieve
|
|
173
188
|
the current balance for an account, we find the most recent lines table entry
|
174
189
|
for it.
|
175
190
|
|
176
|
-
See
|
191
|
+
See [DoubleEntry::Line](lib/double_entry/line.rb) for more info.
|
177
192
|
|
178
193
|
AccountBalance records cache the current balance for each Account, and are used
|
179
194
|
to perform database level locking.
|
@@ -206,13 +221,13 @@ DoubleEntry.configure do |config|
|
|
206
221
|
raise 'not a User' unless user.class.name == 'User'
|
207
222
|
user.id
|
208
223
|
end
|
209
|
-
accounts.define(:
|
210
|
-
accounts.define(:
|
224
|
+
accounts.define(identifier: :savings, scope_identifier: user_scope, positive_only: true)
|
225
|
+
accounts.define(identifier: :checking, scope_identifier: user_scope)
|
211
226
|
end
|
212
227
|
|
213
228
|
config.define_transfers do |transfers|
|
214
|
-
transfers.define(:
|
215
|
-
transfers.define(:
|
229
|
+
transfers.define(from: :checking, to: :savings, code: :deposit)
|
230
|
+
transfers.define(from: :savings, to: :checking, code: :withdraw)
|
216
231
|
end
|
217
232
|
end
|
218
233
|
```
|
@@ -225,7 +240,7 @@ Transfers between accounts of different currencies are not allowed.
|
|
225
240
|
```ruby
|
226
241
|
DoubleEntry.configure do |config|
|
227
242
|
config.define_accounts do |accounts|
|
228
|
-
accounts.define(:
|
243
|
+
accounts.define(identifier: :savings, scope_identifier: user_scope, currency: 'AUD')
|
229
244
|
end
|
230
245
|
end
|
231
246
|
```
|
@@ -277,42 +292,56 @@ See the Github project [issues](https://github.com/envato/double_entry/issues).
|
|
277
292
|
|
278
293
|
## Development Environment Setup
|
279
294
|
|
280
|
-
|
295
|
+
We're using Docker to provide a convenient and consistent environment for
|
296
|
+
executing tests during development. This allows engineers to quickly set up
|
297
|
+
a productive development environment.
|
281
298
|
|
282
|
-
|
283
|
-
|
284
|
-
|
299
|
+
Note: Most development files are mounted in the Docker container. This
|
300
|
+
enables engineers to edit files in their favourite editor (on the host
|
301
|
+
OS) and have the changes immediately available in the Docker container
|
302
|
+
to be exercised.
|
303
|
+
|
304
|
+
One exception to this is the RSpec configuration. Changes to these files will
|
305
|
+
require a rebuild of the Docker image (step 2).
|
285
306
|
|
286
|
-
|
307
|
+
Prerequisites:
|
308
|
+
|
309
|
+
* Docker
|
310
|
+
* Docker Compose
|
311
|
+
* Git
|
312
|
+
|
313
|
+
1. Clone this repo.
|
287
314
|
|
288
315
|
```sh
|
289
|
-
|
316
|
+
git clone git@github.com:envato/double_entry.git && cd double_entry
|
290
317
|
```
|
291
318
|
|
292
|
-
|
293
|
-
4. Create a database in MySQL.
|
319
|
+
2. Build the Docker image we'll use to run tests
|
294
320
|
|
295
321
|
```sh
|
296
|
-
|
322
|
+
docker-compose build --pull double_entry
|
297
323
|
```
|
298
324
|
|
299
|
-
|
325
|
+
3. Startup a container and attach a terminal. This will also start up a
|
326
|
+
MySQL and Postgres database.
|
300
327
|
|
301
328
|
```sh
|
302
|
-
|
329
|
+
docker-compose run --rm double_entry ash
|
303
330
|
```
|
304
331
|
|
305
|
-
|
332
|
+
4. Run the tests
|
306
333
|
|
307
334
|
```sh
|
308
|
-
|
309
|
-
|
335
|
+
DB=mysql bundle exec rspec
|
336
|
+
DB=postgres bundle exec rspec
|
337
|
+
DB=sqlite bundle exec rspec
|
310
338
|
```
|
311
339
|
|
312
|
-
|
340
|
+
5. When finished, exit the container terminal and shut down the databases.
|
313
341
|
|
314
342
|
```sh
|
315
|
-
|
343
|
+
exit
|
344
|
+
docker-compose down
|
316
345
|
```
|
317
346
|
|
318
347
|
## Contributors
|
@@ -18,7 +18,7 @@ module ActiveRecord
|
|
18
18
|
yield
|
19
19
|
rescue ActiveRecord::StatementInvalid => exception
|
20
20
|
if exception.message =~ /deadlock/i || exception.message =~ /database is locked/i
|
21
|
-
ActiveSupport::Notifications.publish('deadlock_restart.double_entry', :
|
21
|
+
ActiveSupport::Notifications.publish('deadlock_restart.double_entry', exception: exception)
|
22
22
|
|
23
23
|
raise ActiveRecord::RestartTransaction
|
24
24
|
else
|
@@ -46,7 +46,7 @@ module ActiveRecord
|
|
46
46
|
yield
|
47
47
|
rescue ActiveRecord::StatementInvalid, ActiveRecord::RecordNotUnique => exception
|
48
48
|
if exception.message =~ /duplicate/i || exception.message =~ /ConstraintException/
|
49
|
-
ActiveSupport::Notifications.publish('duplicate_ignore.double_entry', :
|
49
|
+
ActiveSupport::Notifications.publish('duplicate_ignore.double_entry', exception: exception)
|
50
50
|
|
51
51
|
# Just ignore it...someone else has already created the record.
|
52
52
|
else
|
@@ -63,7 +63,7 @@ module ActiveRecord
|
|
63
63
|
if exception.message =~ /deadlock/i || exception.message =~ /database is locked/i
|
64
64
|
# Somebody else is in the midst of creating the record. We'd better
|
65
65
|
# retry, so we ensure they're done before we move on.
|
66
|
-
ActiveSupport::Notifications.publish('deadlock_retry.double_entry', :
|
66
|
+
ActiveSupport::Notifications.publish('deadlock_retry.double_entry', exception: exception)
|
67
67
|
|
68
68
|
retry
|
69
69
|
else
|
data/lib/double_entry.rb
CHANGED
@@ -66,9 +66,9 @@ module DoubleEntry
|
|
66
66
|
# savings_account = DoubleEntry.account(:savings, scope: user)
|
67
67
|
# DoubleEntry.transfer(
|
68
68
|
# 20.dollars,
|
69
|
-
# :
|
70
|
-
# :
|
71
|
-
# :
|
69
|
+
# from: checking_account,
|
70
|
+
# to: savings_account,
|
71
|
+
# code: :save,
|
72
72
|
# )
|
73
73
|
# @param [Money] amount The quantity of money to transfer from one account
|
74
74
|
# to the other.
|
@@ -91,35 +91,35 @@ module DoubleEntry
|
|
91
91
|
# Get the current or historic balance of an account.
|
92
92
|
#
|
93
93
|
# @example Obtain the current balance of my checking account
|
94
|
-
# checking_account = DoubleEntry.account(:checking, :
|
94
|
+
# checking_account = DoubleEntry.account(:checking, scope: user)
|
95
95
|
# DoubleEntry.balance(checking_account)
|
96
96
|
# @example Obtain the current balance of my checking account (without account or user model)
|
97
|
-
# DoubleEntry.balance(:checking, :
|
97
|
+
# DoubleEntry.balance(:checking, scope: user_id)
|
98
98
|
# @example Obtain a historic balance of my checking account
|
99
|
-
# checking_account = DoubleEntry.account(:checking, :
|
100
|
-
# DoubleEntry.balance(checking_account, :
|
99
|
+
# checking_account = DoubleEntry.account(:checking, scope: user)
|
100
|
+
# DoubleEntry.balance(checking_account, at: Time.new(2012, 1, 1))
|
101
101
|
# @example Obtain the net balance of my checking account during may
|
102
|
-
# checking_account = DoubleEntry.account(:checking, :
|
102
|
+
# checking_account = DoubleEntry.account(:checking, scope: user)
|
103
103
|
# DoubleEntry.balance(
|
104
104
|
# checking_account,
|
105
|
-
# :
|
106
|
-
# :
|
105
|
+
# from: Time.new(2012, 5, 1, 0, 0, 0),
|
106
|
+
# to: Time.new(2012, 5, 31, 23, 59, 59),
|
107
107
|
# )
|
108
108
|
# @example Obtain the balance of salary deposits made to my checking account during may
|
109
|
-
# checking_account = DoubleEntry.account(:checking, :
|
109
|
+
# checking_account = DoubleEntry.account(:checking, scope: user)
|
110
110
|
# DoubleEntry.balance(
|
111
111
|
# checking_account,
|
112
|
-
# :
|
113
|
-
# :
|
114
|
-
# :
|
112
|
+
# code: :salary,
|
113
|
+
# from: Time.new(2012, 5, 1, 0, 0, 0),
|
114
|
+
# to: Time.new(2012, 5, 31, 23, 59, 59),
|
115
115
|
# )
|
116
116
|
# @example Obtain the balance of salary & lottery deposits made to my checking account during may
|
117
|
-
# checking_account = DoubleEntry.account(:checking, :
|
117
|
+
# checking_account = DoubleEntry.account(:checking, scope: user)
|
118
118
|
# DoubleEntry.balance(
|
119
119
|
# checking_account,
|
120
|
-
# :
|
121
|
-
# :
|
122
|
-
# :
|
120
|
+
# codes: [ :salary, :lottery ],
|
121
|
+
# from: Time.new(2012, 5, 1, 0, 0, 0),
|
122
|
+
# to: Time.new(2012, 5, 31, 23, 59, 59),
|
123
123
|
# )
|
124
124
|
# @param [DoubleEntry::Account:Instance, Symbol] account Find the balance
|
125
125
|
# for this account
|
data/lib/double_entry/account.rb
CHANGED
@@ -15,7 +15,7 @@ module DoubleEntry
|
|
15
15
|
# @api private
|
16
16
|
def account(identifier, options = {})
|
17
17
|
account = accounts.find(identifier, (options[:scope].present? || options[:scope_identity].present?))
|
18
|
-
Instance.new(:
|
18
|
+
Instance.new(account: account, scope: options[:scope], scope_identity: options[:scope_identity])
|
19
19
|
end
|
20
20
|
|
21
21
|
# @api private
|
@@ -67,7 +67,7 @@ module DoubleEntry
|
|
67
67
|
|
68
68
|
class Instance
|
69
69
|
attr_reader :account, :scope
|
70
|
-
delegate :identifier, :scope_identifier, :scoped?, :positive_only, :negative_only, :currency, :
|
70
|
+
delegate :identifier, :scope_identifier, :scoped?, :positive_only, :negative_only, :currency, to: :account
|
71
71
|
|
72
72
|
def initialize(args)
|
73
73
|
@account = args[:account]
|
@@ -8,7 +8,7 @@ module DoubleEntry
|
|
8
8
|
#
|
9
9
|
# Account balances are created on demand when transfers occur.
|
10
10
|
class AccountBalance < ActiveRecord::Base
|
11
|
-
delegate :currency, :
|
11
|
+
delegate :currency, to: :account
|
12
12
|
|
13
13
|
def balance
|
14
14
|
self[:balance] && Money.new(self[:balance], currency)
|
@@ -25,11 +25,11 @@ module DoubleEntry
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def account
|
28
|
-
DoubleEntry.account(self[:account].to_sym, :
|
28
|
+
DoubleEntry.account(self[:account].to_sym, scope_identity: self[:scope])
|
29
29
|
end
|
30
30
|
|
31
31
|
def self.find_by_account(account, options = {})
|
32
|
-
scope = where(:
|
32
|
+
scope = where(scope: account.scope_identity, account: account.identifier.to_s)
|
33
33
|
scope = scope.lock(true) if options[:lock]
|
34
34
|
scope.first
|
35
35
|
end
|
@@ -79,18 +79,18 @@ module DoubleEntry
|
|
79
79
|
# @api private
|
80
80
|
class RelationBuilder
|
81
81
|
attr_reader :options
|
82
|
-
delegate :account, :scope, :scope?, :from, :to, :between?, :at, :at?, :codes, :code?, :
|
82
|
+
delegate :account, :scope, :scope?, :from, :to, :between?, :at, :at?, :codes, :code?, to: :options
|
83
83
|
|
84
84
|
def initialize(options)
|
85
85
|
@options = options
|
86
86
|
end
|
87
87
|
|
88
88
|
def build
|
89
|
-
lines = Line.where(:
|
89
|
+
lines = Line.where(account: account)
|
90
90
|
lines = lines.where('created_at <= ?', at) if at?
|
91
|
-
lines = lines.where(:
|
92
|
-
lines = lines.where(:
|
93
|
-
lines = lines.where(:
|
91
|
+
lines = lines.where(created_at: from..to) if between?
|
92
|
+
lines = lines.where(code: codes) if code?
|
93
|
+
lines = lines.where(scope: scope) if scope?
|
94
94
|
lines
|
95
95
|
end
|
96
96
|
end
|
@@ -16,7 +16,7 @@ module DoubleEntry
|
|
16
16
|
:scope_identifier_max_length=,
|
17
17
|
:account_identifier_max_length,
|
18
18
|
:account_identifier_max_length=,
|
19
|
-
:
|
19
|
+
to: 'DoubleEntry::Account',
|
20
20
|
)
|
21
21
|
|
22
22
|
delegate(
|
@@ -24,7 +24,7 @@ module DoubleEntry
|
|
24
24
|
:transfers=,
|
25
25
|
:code_max_length,
|
26
26
|
:code_max_length=,
|
27
|
-
:
|
27
|
+
to: 'DoubleEntry::Transfer',
|
28
28
|
)
|
29
29
|
|
30
30
|
def define_accounts
|
data/lib/double_entry/line.rb
CHANGED
@@ -55,8 +55,8 @@ module DoubleEntry
|
|
55
55
|
# by account, or account and code, over a particular period.
|
56
56
|
#
|
57
57
|
class Line < ActiveRecord::Base
|
58
|
-
belongs_to :detail, :
|
59
|
-
has_many :metadata, :
|
58
|
+
belongs_to :detail, polymorphic: true, required: false
|
59
|
+
has_many :metadata, class_name: 'DoubleEntry::LineMetadata' unless -> { DoubleEntry.config.json_metadata }
|
60
60
|
scope :with_id_greater_than, ->(id) { where('id > ?', id) }
|
61
61
|
|
62
62
|
def amount
|
@@ -75,12 +75,12 @@ module DoubleEntry
|
|
75
75
|
self[:balance] = (money && money.fractional)
|
76
76
|
end
|
77
77
|
|
78
|
-
def save(
|
78
|
+
def save(**)
|
79
79
|
check_balance_will_remain_valid
|
80
80
|
super
|
81
81
|
end
|
82
82
|
|
83
|
-
def save!(
|
83
|
+
def save!(**)
|
84
84
|
check_balance_will_remain_valid
|
85
85
|
super
|
86
86
|
end
|
@@ -102,7 +102,7 @@ module DoubleEntry
|
|
102
102
|
end
|
103
103
|
|
104
104
|
def account
|
105
|
-
DoubleEntry.account(self[:account].to_sym, :
|
105
|
+
DoubleEntry.account(self[:account].to_sym, scope_identity: scope)
|
106
106
|
end
|
107
107
|
|
108
108
|
def currency
|
@@ -117,7 +117,7 @@ module DoubleEntry
|
|
117
117
|
end
|
118
118
|
|
119
119
|
def partner_account
|
120
|
-
DoubleEntry.account(self[:partner_account].to_sym, :
|
120
|
+
DoubleEntry.account(self[:partner_account].to_sym, scope_identity: partner_scope)
|
121
121
|
end
|
122
122
|
|
123
123
|
def partner
|
data/lib/double_entry/locking.rb
CHANGED
@@ -149,7 +149,7 @@ module DoubleEntry
|
|
149
149
|
# If one or more account balance records don't exist, set
|
150
150
|
# accounts_with_balances to the corresponding accounts, and return false.
|
151
151
|
def grab_locks
|
152
|
-
account_balances = @accounts.map { |account| AccountBalance.find_by_account(account, :
|
152
|
+
account_balances = @accounts.map { |account| AccountBalance.find_by_account(account, lock: true) }
|
153
153
|
|
154
154
|
if account_balances.any?(&:nil?)
|
155
155
|
@accounts_without_balances = @accounts.zip(account_balances).
|
@@ -168,7 +168,7 @@ module DoubleEntry
|
|
168
168
|
# Get the initial balance from the lines table.
|
169
169
|
balance = account.balance
|
170
170
|
# Try to create the balance record, but ignore it if someone else has done it in the meantime.
|
171
|
-
AccountBalance.create_ignoring_duplicates!(:
|
171
|
+
AccountBalance.create_ignoring_duplicates!(account: account, balance: balance)
|
172
172
|
end
|
173
173
|
end
|
174
174
|
end
|
@@ -121,8 +121,8 @@ module DoubleEntry
|
|
121
121
|
def create_line_metadata(credit, debit, metadata)
|
122
122
|
metadata.each_pair do |key, value|
|
123
123
|
Array(value).each do |each_value|
|
124
|
-
LineMetadata.create!(:
|
125
|
-
LineMetadata.create!(:
|
124
|
+
LineMetadata.create!(line: credit, key: key, value: each_value)
|
125
|
+
LineMetadata.create!(line: debit, key: key, value: each_value)
|
126
126
|
end
|
127
127
|
end
|
128
128
|
end
|
@@ -34,9 +34,9 @@ module DoubleEntry
|
|
34
34
|
|
35
35
|
unless active_accounts.empty?
|
36
36
|
LineCheck.create!(
|
37
|
-
:
|
38
|
-
:
|
39
|
-
:
|
37
|
+
errors_found: incorrect_accounts.any?,
|
38
|
+
last_line_id: current_line_id,
|
39
|
+
log: log,
|
40
40
|
)
|
41
41
|
end
|
42
42
|
end
|
data/lib/double_entry/version.rb
CHANGED
@@ -9,12 +9,12 @@ DoubleEntry.configure do |config|
|
|
9
9
|
# raise 'not a User' unless user.class.name == 'User'
|
10
10
|
# user.id
|
11
11
|
# end
|
12
|
-
# accounts.define(:
|
13
|
-
# accounts.define(:
|
12
|
+
# accounts.define(identifier: :savings, scope_identifier: user_scope, positive_only: true)
|
13
|
+
# accounts.define(identifier: :checking, scope_identifier: user_scope)
|
14
14
|
# end
|
15
15
|
#
|
16
16
|
# config.define_transfers do |transfers|
|
17
|
-
# transfers.define(:
|
18
|
-
# transfers.define(:
|
17
|
+
# transfers.define(from: :checking, to: :savings, code: :deposit)
|
18
|
+
# transfers.define(from: :savings, to: :checking, code: :withdraw)
|
19
19
|
# end
|
20
20
|
end
|
@@ -1,25 +1,25 @@
|
|
1
1
|
class CreateDoubleEntryTables < ActiveRecord::Migration<%= migration_version %>
|
2
2
|
def self.up
|
3
3
|
create_table "double_entry_account_balances" do |t|
|
4
|
-
t.string "account", :
|
4
|
+
t.string "account", null: false
|
5
5
|
t.string "scope"
|
6
|
-
t.bigint "balance", :
|
7
|
-
t.timestamps :
|
6
|
+
t.bigint "balance", null: false
|
7
|
+
t.timestamps null: false
|
8
8
|
end
|
9
9
|
|
10
|
-
add_index "double_entry_account_balances", ["account"], :
|
11
|
-
add_index "double_entry_account_balances", ["scope", "account"], :
|
10
|
+
add_index "double_entry_account_balances", ["account"], name: "index_account_balances_on_account"
|
11
|
+
add_index "double_entry_account_balances", ["scope", "account"], name: "index_account_balances_on_scope_and_account", unique: true
|
12
12
|
|
13
13
|
create_table "double_entry_lines" do |t|
|
14
|
-
t.string "account", :
|
14
|
+
t.string "account", null: false
|
15
15
|
t.string "scope"
|
16
|
-
t.string "code", :
|
17
|
-
t.bigint "amount", :
|
18
|
-
t.bigint "balance", :
|
19
|
-
t.references "partner", :
|
20
|
-
t.string "partner_account", :
|
16
|
+
t.string "code", null: false
|
17
|
+
t.bigint "amount", null: false
|
18
|
+
t.bigint "balance", null: false
|
19
|
+
t.references "partner", index: false
|
20
|
+
t.string "partner_account", null: false
|
21
21
|
t.string "partner_scope"
|
22
|
-
t.references "detail", :
|
22
|
+
t.references "detail", index: false, polymorphic: true
|
23
23
|
<%- if json_metadata -%>
|
24
24
|
if ActiveRecord::Base.connection.adapter_name == "PostgreSQL"
|
25
25
|
t.jsonb "metadata"
|
@@ -27,32 +27,32 @@ class CreateDoubleEntryTables < ActiveRecord::Migration<%= migration_version %>
|
|
27
27
|
t.json "metadata"
|
28
28
|
end
|
29
29
|
<%- end -%>
|
30
|
-
t.timestamps :
|
30
|
+
t.timestamps null: false
|
31
31
|
end
|
32
32
|
|
33
|
-
add_index "double_entry_lines", ["account", "code", "created_at"], :
|
34
|
-
add_index "double_entry_lines", ["account", "created_at"], :
|
35
|
-
add_index "double_entry_lines", ["scope", "account", "created_at"], :
|
36
|
-
add_index "double_entry_lines", ["scope", "account", "id"], :
|
33
|
+
add_index "double_entry_lines", ["account", "code", "created_at"], name: "lines_account_code_created_at_idx"
|
34
|
+
add_index "double_entry_lines", ["account", "created_at"], name: "lines_account_created_at_idx"
|
35
|
+
add_index "double_entry_lines", ["scope", "account", "created_at"], name: "lines_scope_account_created_at_idx"
|
36
|
+
add_index "double_entry_lines", ["scope", "account", "id"], name: "lines_scope_account_id_idx"
|
37
37
|
|
38
38
|
create_table "double_entry_line_checks" do |t|
|
39
|
-
t.references "last_line", :
|
40
|
-
t.boolean "errors_found", :
|
39
|
+
t.references "last_line", null: false, index: false
|
40
|
+
t.boolean "errors_found", null: false
|
41
41
|
t.text "log"
|
42
|
-
t.timestamps :
|
42
|
+
t.timestamps null: false
|
43
43
|
end
|
44
44
|
|
45
|
-
add_index "double_entry_line_checks", ["created_at", "last_line_id"], :
|
45
|
+
add_index "double_entry_line_checks", ["created_at", "last_line_id"], name: "line_checks_created_at_last_line_id_idx"
|
46
46
|
<%- unless json_metadata -%>
|
47
47
|
|
48
48
|
create_table "double_entry_line_metadata" do |t|
|
49
|
-
t.references "line", :
|
50
|
-
t.string "key", :
|
51
|
-
t.string "value", :
|
52
|
-
t.timestamps :
|
49
|
+
t.references "line", null: false, index: false
|
50
|
+
t.string "key", null: false
|
51
|
+
t.string "value", null: false
|
52
|
+
t.timestamps null: false
|
53
53
|
end
|
54
54
|
|
55
|
-
add_index "double_entry_line_metadata", ["line_id", "key", "value"], :
|
55
|
+
add_index "double_entry_line_metadata", ["line_id", "key", "value"], name: "lines_meta_line_id_key_value_idx"
|
56
56
|
<%- end -%>
|
57
57
|
end
|
58
58
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: double_entry
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.
|
4
|
+
version: 2.0.0.beta5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Envato
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -256,9 +256,9 @@ licenses:
|
|
256
256
|
- MIT
|
257
257
|
metadata:
|
258
258
|
bug_tracker_uri: https://github.com/envato/double_entry/issues
|
259
|
-
changelog_uri: https://github.com/envato/double_entry/blob/v2.0.0.
|
260
|
-
documentation_uri: https://www.rubydoc.info/gems/double_entry/2.0.0.
|
261
|
-
source_code_uri: https://github.com/envato/double_entry/tree/v2.0.0.
|
259
|
+
changelog_uri: https://github.com/envato/double_entry/blob/v2.0.0.beta5/CHANGELOG.md
|
260
|
+
documentation_uri: https://www.rubydoc.info/gems/double_entry/2.0.0.beta5
|
261
|
+
source_code_uri: https://github.com/envato/double_entry/tree/v2.0.0.beta5
|
262
262
|
post_install_message:
|
263
263
|
rdoc_options: []
|
264
264
|
require_paths:
|
@@ -274,7 +274,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
274
274
|
- !ruby/object:Gem::Version
|
275
275
|
version: 1.3.1
|
276
276
|
requirements: []
|
277
|
-
|
277
|
+
rubyforge_project:
|
278
|
+
rubygems_version: 2.7.3
|
278
279
|
signing_key:
|
279
280
|
specification_version: 4
|
280
281
|
summary: Tools to build your double entry financial ledger
|