double_entry 0.3.1 → 0.4.0
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.
- data/README.md +46 -17
- data/lib/double_entry.rb +50 -15
- data/lib/double_entry/line.rb +3 -13
- data/lib/double_entry/reporting.rb +48 -31
- data/lib/double_entry/transfer.rb +4 -12
- data/lib/double_entry/version.rb +1 -1
- data/lib/generators/double_entry/install/templates/migration.rb +0 -1
- data/spec/double_entry/line_spec.rb +0 -24
- data/spec/double_entry_spec.rb +7 -21
- data/spec/support/schema.rb +0 -1
- metadata +2 -2
data/README.md
CHANGED
|
@@ -31,16 +31,27 @@ Rails Versions: Rails 3.2.x, 4.0.x, 4.1.x
|
|
|
31
31
|
|
|
32
32
|
In your application's `Gemfile`, add:
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
```ruby
|
|
35
|
+
gem 'double_entry'
|
|
36
|
+
```
|
|
35
37
|
|
|
36
|
-
|
|
38
|
+
Download and install the gem with Bundler:
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
```sh
|
|
41
|
+
bundle
|
|
42
|
+
```
|
|
40
43
|
|
|
41
|
-
|
|
44
|
+
Generate Rails schema migrations for the required tables:
|
|
42
45
|
|
|
43
|
-
|
|
46
|
+
```sh
|
|
47
|
+
rails generate double_entry:install
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Update the local database:
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
rake db:migrate
|
|
54
|
+
```
|
|
44
55
|
|
|
45
56
|
|
|
46
57
|
## Interface
|
|
@@ -91,7 +102,12 @@ will return the current balance for an account as a Money object.
|
|
|
91
102
|
To transfer money between accounts:
|
|
92
103
|
|
|
93
104
|
```ruby
|
|
94
|
-
DoubleEntry.transfer(
|
|
105
|
+
DoubleEntry.transfer(
|
|
106
|
+
20.dollars,
|
|
107
|
+
:from => one_account,
|
|
108
|
+
:to => another_account,
|
|
109
|
+
:code => :a_business_code_for_this_type_of_transfer,
|
|
110
|
+
)
|
|
95
111
|
```
|
|
96
112
|
|
|
97
113
|
The possible transfers, and their codes, should be defined in the configuration.
|
|
@@ -107,8 +123,9 @@ manually lock the accounts you're using:
|
|
|
107
123
|
|
|
108
124
|
```ruby
|
|
109
125
|
DoubleEntry.lock_accounts(account_a, account_b) do
|
|
110
|
-
#
|
|
126
|
+
# Perhaps transfer some money
|
|
111
127
|
DoubleEntry.transfer(20.dollars, :from => account_a, :to => account_b, :code => :purchase)
|
|
128
|
+
# Perform other tasks that should be commited atomically with the transfer of funds...
|
|
112
129
|
end
|
|
113
130
|
```
|
|
114
131
|
|
|
@@ -214,33 +231,45 @@ correct balances from the lines table.
|
|
|
214
231
|
|
|
215
232
|
## Future Direction
|
|
216
233
|
|
|
217
|
-
|
|
234
|
+
See the Github project [issues](https://github.com/envato/double_entry/issues).
|
|
218
235
|
|
|
219
236
|
## Development Environment Setup
|
|
220
237
|
|
|
221
238
|
1. Clone this repo.
|
|
222
239
|
|
|
223
|
-
|
|
240
|
+
```sh
|
|
241
|
+
git clone git@github.com:envato/double_entry.git && cd double_entry
|
|
242
|
+
```
|
|
224
243
|
|
|
225
244
|
2. Run the included setup script to install the gem dependencies.
|
|
226
245
|
|
|
227
|
-
|
|
246
|
+
```sh
|
|
247
|
+
./script/setup.sh
|
|
248
|
+
```
|
|
228
249
|
|
|
229
|
-
3. Install MySQL and PostgreSQL.
|
|
250
|
+
3. Install MySQL and PostgreSQL. We run tests against both databases.
|
|
230
251
|
4. Create a database in MySQL.
|
|
231
252
|
|
|
232
|
-
|
|
253
|
+
```sh
|
|
254
|
+
mysql -u root -e 'create database double_entry_test;'
|
|
255
|
+
```
|
|
233
256
|
|
|
234
257
|
5. Create a database in PostgreSQL.
|
|
235
258
|
|
|
236
|
-
|
|
259
|
+
```sh
|
|
260
|
+
psql -c 'create database double_entry_test;' -U postgres
|
|
261
|
+
```
|
|
237
262
|
|
|
238
263
|
6. Specify how the tests should connect to the database
|
|
239
264
|
|
|
240
|
-
|
|
241
|
-
|
|
265
|
+
```sh
|
|
266
|
+
cp spec/support/{database.example.yml,database.yml}
|
|
267
|
+
vim spec/support/database.yml
|
|
268
|
+
```
|
|
242
269
|
|
|
243
270
|
7. Run the tests
|
|
244
271
|
|
|
245
|
-
|
|
272
|
+
```sh
|
|
273
|
+
bundle exec rake
|
|
274
|
+
```
|
|
246
275
|
|
data/lib/double_entry.rb
CHANGED
|
@@ -31,7 +31,7 @@ module DoubleEntry
|
|
|
31
31
|
#
|
|
32
32
|
# @example Obtain the 'cash' account for a user
|
|
33
33
|
# DoubleEntry.account(:cash, scope: user)
|
|
34
|
-
# @param
|
|
34
|
+
# @param [Symbol] identifier The symbol identifying the desired account. As
|
|
35
35
|
# specified in the account configuration.
|
|
36
36
|
# @option options :scope Limit the account to the given scope. As specified
|
|
37
37
|
# in the account configuration.
|
|
@@ -56,12 +56,12 @@ module DoubleEntry
|
|
|
56
56
|
# checking_account = DoubleEntry.account(:checking, scope: user)
|
|
57
57
|
# savings_account = DoubleEntry.account(:savings, scope: user)
|
|
58
58
|
# DoubleEntry.transfer(
|
|
59
|
-
#
|
|
60
|
-
# from
|
|
61
|
-
# to
|
|
62
|
-
# code
|
|
59
|
+
# 20.dollars,
|
|
60
|
+
# :from => checking_account,
|
|
61
|
+
# :to => savings_account,
|
|
62
|
+
# :code => :save,
|
|
63
63
|
# )
|
|
64
|
-
# @param
|
|
64
|
+
# @param [Money] amount The quantity of money to transfer from one account
|
|
65
65
|
# to the other.
|
|
66
66
|
# @option options :from [DoubleEntry::Account::Instance] Transfer money out
|
|
67
67
|
# of this account.
|
|
@@ -69,7 +69,6 @@ module DoubleEntry
|
|
|
69
69
|
# this account.
|
|
70
70
|
# @option options :code [Symbol] The application specific code for this
|
|
71
71
|
# type of transfer. As specified in the transfer configuration.
|
|
72
|
-
# @option options :meta [String] Metadata to associate with this transfer.
|
|
73
72
|
# @option options :detail [ActiveRecord::Base] ActiveRecord model
|
|
74
73
|
# associated (via a polymorphic association) with the transfer.
|
|
75
74
|
# @raise [DoubleEntry::TransferIsNegative] The amount is less than zero.
|
|
@@ -82,14 +81,50 @@ module DoubleEntry
|
|
|
82
81
|
|
|
83
82
|
# Get the current or historic balance of an account.
|
|
84
83
|
#
|
|
85
|
-
# @
|
|
86
|
-
#
|
|
87
|
-
#
|
|
88
|
-
# @
|
|
89
|
-
#
|
|
90
|
-
# @
|
|
91
|
-
#
|
|
92
|
-
#
|
|
84
|
+
# @example Obtain the current balance of my checking account
|
|
85
|
+
# checking_account = DoubleEntry.account(:checking, :scope => user)
|
|
86
|
+
# DoubleEntry.balance(checking_account)
|
|
87
|
+
# @example Obtain the current balance of my checking account (without account or user model)
|
|
88
|
+
# DoubleEntry.balance(:checking, :scope => user_id)
|
|
89
|
+
# @example Obtain a historic balance of my checking account
|
|
90
|
+
# checking_account = DoubleEntry.account(:checking, :scope => user)
|
|
91
|
+
# DoubleEntry.balance(checking_account, :at => Time.new(2012, 1, 1))
|
|
92
|
+
# @example Obtain the net balance of my checking account during may
|
|
93
|
+
# checking_account = DoubleEntry.account(:checking, :scope => user)
|
|
94
|
+
# DoubleEntry.balance(
|
|
95
|
+
# checking_account,
|
|
96
|
+
# :from => Time.new(2012, 5, 1, 0, 0, 0),
|
|
97
|
+
# :to => Time.new(2012, 5, 31, 23, 59, 59),
|
|
98
|
+
# )
|
|
99
|
+
# @example Obtain the balance of salary deposits made to my checking account during may
|
|
100
|
+
# checking_account = DoubleEntry.account(:checking, :scope => user)
|
|
101
|
+
# DoubleEntry.balance(
|
|
102
|
+
# checking_account,
|
|
103
|
+
# :code => :salary,
|
|
104
|
+
# :from => Time.new(2012, 5, 1, 0, 0, 0),
|
|
105
|
+
# :to => Time.new(2012, 5, 31, 23, 59, 59),
|
|
106
|
+
# )
|
|
107
|
+
# @example Obtain the balance of salary & lottery deposits made to my checking account during may
|
|
108
|
+
# checking_account = DoubleEntry.account(:checking, :scope => user)
|
|
109
|
+
# DoubleEntry.balance(
|
|
110
|
+
# checking_account,
|
|
111
|
+
# :codes => [ :salary, :lottery ],
|
|
112
|
+
# :from => Time.new(2012, 5, 1, 0, 0, 0),
|
|
113
|
+
# :to => Time.new(2012, 5, 31, 23, 59, 59),
|
|
114
|
+
# )
|
|
115
|
+
# @param [DoubleEntry::Account:Instance, Symbol] account Find the balance
|
|
116
|
+
# for this account
|
|
117
|
+
# @option options :scope [Object] The scope identifier of the account (only
|
|
118
|
+
# needed if the provided account is a symbol).
|
|
119
|
+
# @option options :from [Time] used with :to, consider only the time
|
|
120
|
+
# between these dates
|
|
121
|
+
# @option options :to [Time] used with :from, consider only the time
|
|
122
|
+
# between these dates
|
|
123
|
+
# @option options :at [Time] obtain the account balance at this time
|
|
124
|
+
# @option options :code [Symbol] consider only the transfers with this code
|
|
125
|
+
# @option options :codes [Array<Symbol>] consider only the transfers with
|
|
126
|
+
# these codes
|
|
127
|
+
# @return [Money] The balance
|
|
93
128
|
def balance(account, options = {})
|
|
94
129
|
BalanceCalculator.calculate(account, options)
|
|
95
130
|
end
|
data/lib/double_entry/line.rb
CHANGED
|
@@ -72,16 +72,6 @@ module DoubleEntry
|
|
|
72
72
|
self[:code].try(:to_sym)
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
-
def meta=(meta)
|
|
76
|
-
self[:meta] = Marshal.dump(meta)
|
|
77
|
-
meta
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def meta
|
|
81
|
-
meta = self[:meta]
|
|
82
|
-
meta ? Marshal.load(meta) : {}
|
|
83
|
-
end
|
|
84
|
-
|
|
85
75
|
def account=(account)
|
|
86
76
|
self[:account] = account.identifier.to_s
|
|
87
77
|
self.scope = account.scope_identity
|
|
@@ -107,18 +97,18 @@ module DoubleEntry
|
|
|
107
97
|
end
|
|
108
98
|
|
|
109
99
|
def pair
|
|
110
|
-
if
|
|
100
|
+
if decrease?
|
|
111
101
|
[self, partner]
|
|
112
102
|
else
|
|
113
103
|
[partner, self]
|
|
114
104
|
end
|
|
115
105
|
end
|
|
116
106
|
|
|
117
|
-
def
|
|
107
|
+
def decrease?
|
|
118
108
|
amount < Money.empty
|
|
119
109
|
end
|
|
120
110
|
|
|
121
|
-
def
|
|
111
|
+
def increase?
|
|
122
112
|
amount > Money.empty
|
|
123
113
|
end
|
|
124
114
|
|
|
@@ -34,28 +34,36 @@ module DoubleEntry
|
|
|
34
34
|
# and provided custom filters.
|
|
35
35
|
#
|
|
36
36
|
# @example Find the sum for all $10 :save transfers in all :checking accounts in the current month (assume the date is January 30, 2014).
|
|
37
|
-
# time_range = DoubleEntry::TimeRange.make(2014, 1)
|
|
38
|
-
#
|
|
37
|
+
# time_range = DoubleEntry::Reporting::TimeRange.make(2014, 1)
|
|
38
|
+
#
|
|
39
|
+
# DoubleEntry::Line.class_eval do
|
|
39
40
|
# scope :ten_dollar_transfers, -> { where(:amount => 10_00) }
|
|
40
41
|
# end
|
|
41
|
-
#
|
|
42
|
-
#
|
|
42
|
+
#
|
|
43
|
+
# DoubleEntry::Reporting.aggregate(
|
|
44
|
+
# :sum,
|
|
45
|
+
# :checking,
|
|
46
|
+
# :save,
|
|
47
|
+
# :range => time_range,
|
|
48
|
+
# :filter => [ :ten_dollar_transfers ],
|
|
49
|
+
# )
|
|
50
|
+
# @param [Symbol] function The function to perform on the set of transfers.
|
|
43
51
|
# Valid functions are :sum, :count, and :average
|
|
44
|
-
# @param
|
|
52
|
+
# @param [Symbol] account The symbol identifying the account to perform
|
|
45
53
|
# the aggregate calculation on. As specified in the account configuration.
|
|
46
|
-
# @param
|
|
54
|
+
# @param [Symbol] code The application specific code for the type of
|
|
47
55
|
# transfer to perform an aggregate calculation on. As specified in the
|
|
48
56
|
# transfer configuration.
|
|
49
|
-
# @option options :range [DoubleEntry::TimeRange] Only include
|
|
50
|
-
# in the given time range in the calculation.
|
|
51
|
-
# @option options :filter [Array
|
|
57
|
+
# @option options :range [DoubleEntry::Reporting::TimeRange] Only include
|
|
58
|
+
# transfers in the given time range in the calculation.
|
|
59
|
+
# @option options :filter [Array<Symbol>, Array<Hash<Symbol, Object>>]
|
|
52
60
|
# A custom filter to apply before performing the aggregate calculation.
|
|
53
|
-
# Currently, filters must be monkey patched as scopes into the
|
|
54
|
-
# class in order to be used as filters, as the example
|
|
55
|
-
# If the filter requires a parameter, it must be given in a Hash,
|
|
56
|
-
# pass an array with the symbol names for the defined scopes.
|
|
57
|
-
# @return Returns a Money object for :sum and :average
|
|
58
|
-
# Fixnum for :count calculations.
|
|
61
|
+
# Currently, filters must be monkey patched as scopes into the
|
|
62
|
+
# DoubleEntry::Line class in order to be used as filters, as the example
|
|
63
|
+
# shows. If the filter requires a parameter, it must be given in a Hash,
|
|
64
|
+
# otherwise pass an array with the symbol names for the defined scopes.
|
|
65
|
+
# @return [Money, Fixnum] Returns a Money object for :sum and :average
|
|
66
|
+
# calculations, or a Fixnum for :count calculations.
|
|
59
67
|
# @raise [Reporting::AggregateFunctionNotSupported] The provided function
|
|
60
68
|
# is not supported.
|
|
61
69
|
#
|
|
@@ -70,20 +78,27 @@ module DoubleEntry
|
|
|
70
78
|
# and provided custom filters.
|
|
71
79
|
#
|
|
72
80
|
# @example Find the number of all $10 :save transfers in all :checking accounts per month for the entire year (Assume the year is 2014).
|
|
73
|
-
# DoubleEntry.aggregate_array(
|
|
74
|
-
#
|
|
81
|
+
# DoubleEntry::Reporting.aggregate_array(
|
|
82
|
+
# :sum,
|
|
83
|
+
# :checking,
|
|
84
|
+
# :save,
|
|
85
|
+
# :range_type => 'month',
|
|
86
|
+
# :start => '2014-01-01',
|
|
87
|
+
# :finish => '2014-12-31',
|
|
88
|
+
# )
|
|
89
|
+
# @param [Symbol] function The function to perform on the set of transfers.
|
|
75
90
|
# Valid functions are :sum, :count, and :average
|
|
76
|
-
# @param
|
|
91
|
+
# @param [Symbol] account The symbol identifying the account to perform
|
|
77
92
|
# the aggregate calculation on. As specified in the account configuration.
|
|
78
|
-
# @param
|
|
93
|
+
# @param [Symbol] code The application specific code for the type of
|
|
79
94
|
# transfer to perform an aggregate calculation on. As specified in the
|
|
80
95
|
# transfer configuration.
|
|
81
|
-
# @option options :filter [Array
|
|
96
|
+
# @option options :filter [Array<Symbol>, Array<Hash<Symbol, Object>>]
|
|
82
97
|
# A custom filter to apply before performing the aggregate calculation.
|
|
83
|
-
# Currently, filters must be monkey patched as scopes into the
|
|
84
|
-
# class in order to be used as filters, as the example
|
|
85
|
-
# If the filter requires a parameter, it must be given in a Hash,
|
|
86
|
-
# pass an array with the symbol names for the defined scopes.
|
|
98
|
+
# Currently, filters must be monkey patched as scopes into the
|
|
99
|
+
# DoubleEntry::Line class in order to be used as filters, as the example
|
|
100
|
+
# shows. If the filter requires a parameter, it must be given in a Hash,
|
|
101
|
+
# otherwise pass an array with the symbol names for the defined scopes.
|
|
87
102
|
# @option options :range_type [String] The type of time range to return data
|
|
88
103
|
# for. For example, specifying 'month' will return an array of the resulting
|
|
89
104
|
# aggregate calculation for each month.
|
|
@@ -95,7 +110,7 @@ module DoubleEntry
|
|
|
95
110
|
# @option options :finish [String] The finish (or end) date for the time range
|
|
96
111
|
# to perform calculations in. The default finish date is the current date.
|
|
97
112
|
# The format of the string must be as follows: 'YYYY-mm-dd'
|
|
98
|
-
# @return [Array
|
|
113
|
+
# @return [Array<Money, Fixnum>] Returns an array of Money objects for :sum
|
|
99
114
|
# and :average calculations, or an array of Fixnum for :count calculations.
|
|
100
115
|
# The array is indexed by the range_type. For example, if range_type is
|
|
101
116
|
# specified as 'month', each index in the array will represent a month.
|
|
@@ -110,14 +125,15 @@ module DoubleEntry
|
|
|
110
125
|
# the provided minimum balance.
|
|
111
126
|
#
|
|
112
127
|
# @example Find users with at least $1,000,000 in their savings accounts
|
|
113
|
-
# DoubleEntry.scopes_with_minimum_balance_for_account(
|
|
114
|
-
#
|
|
115
|
-
# :savings
|
|
116
|
-
# ) # might return user ids: [ 1423, 12232, 34729 ]
|
|
117
|
-
# @param
|
|
128
|
+
# DoubleEntry::Reporting.scopes_with_minimum_balance_for_account(
|
|
129
|
+
# 1_000_000.dollars,
|
|
130
|
+
# :savings,
|
|
131
|
+
# ) # might return the user ids: [ 1423, 12232, 34729 ]
|
|
132
|
+
# @param [Money] minimum_balance Minimum account balance a scope must have
|
|
118
133
|
# to be included in the result set.
|
|
119
|
-
# @param
|
|
134
|
+
# @param [Symbol] account_identifier
|
|
120
135
|
# @return [Array<Fixnum>] Scopes
|
|
136
|
+
#
|
|
121
137
|
def scopes_with_minimum_balance_for_account(minimum_balance, account_identifier)
|
|
122
138
|
select_values(sanitize_sql_array([<<-SQL, account_identifier, minimum_balance.cents])).map {|scope| scope.to_i }
|
|
123
139
|
SELECT scope
|
|
@@ -132,6 +148,7 @@ module DoubleEntry
|
|
|
132
148
|
# @api private
|
|
133
149
|
# @return [Boolean] true if all the amounts for an account add up to the final balance,
|
|
134
150
|
# which they always should.
|
|
151
|
+
#
|
|
135
152
|
def reconciled?(account)
|
|
136
153
|
scoped_lines = Line.where(:account => "#{account.identifier}", :scope => "#{account.scope}")
|
|
137
154
|
sum_of_amounts = scoped_lines.sum(:amount)
|
|
@@ -5,10 +5,10 @@ module DoubleEntry
|
|
|
5
5
|
# @api private
|
|
6
6
|
def self.transfer(defined_transfers, amount, options = {})
|
|
7
7
|
raise TransferIsNegative if amount < Money.empty
|
|
8
|
-
from, to, code,
|
|
8
|
+
from, to, code, detail = options[:from], options[:to], options[:code], options[:detail]
|
|
9
9
|
defined_transfers.
|
|
10
10
|
find!(from, to, code).
|
|
11
|
-
process
|
|
11
|
+
process(amount, from, to, code, detail)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
# @api private
|
|
@@ -44,24 +44,17 @@ module DoubleEntry
|
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
attr_accessor :code, :from, :to, :description
|
|
47
|
+
attr_accessor :code, :from, :to, :description
|
|
48
48
|
|
|
49
49
|
def initialize(attributes)
|
|
50
|
-
@meta_requirement = []
|
|
51
50
|
attributes.each { |name, value| send("#{name}=", value) }
|
|
52
51
|
end
|
|
53
52
|
|
|
54
|
-
def process
|
|
53
|
+
def process(amount, from, to, code, detail)
|
|
55
54
|
if from.scope_identity == to.scope_identity and from.identifier == to.identifier
|
|
56
55
|
raise TransferNotAllowed.new
|
|
57
56
|
end
|
|
58
57
|
|
|
59
|
-
meta_requirement.each do |key|
|
|
60
|
-
if meta[key].nil?
|
|
61
|
-
raise RequiredMetaMissing.new
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
58
|
Locking.lock_accounts(from, to) do
|
|
66
59
|
credit, debit = Line.new, Line.new
|
|
67
60
|
|
|
@@ -74,7 +67,6 @@ module DoubleEntry
|
|
|
74
67
|
credit.amount, debit.amount = -amount, amount
|
|
75
68
|
credit.account, debit.account = from, to
|
|
76
69
|
credit.code, debit.code = code, code
|
|
77
|
-
credit.meta, debit.meta = meta, meta
|
|
78
70
|
credit.detail, debit.detail = detail, detail
|
|
79
71
|
credit.balance, debit.balance = credit_balance.balance, debit_balance.balance
|
|
80
72
|
|
data/lib/double_entry/version.rb
CHANGED
|
@@ -10,13 +10,11 @@ describe DoubleEntry::Line do
|
|
|
10
10
|
:account => account,
|
|
11
11
|
:partner_account => partner_account,
|
|
12
12
|
:code => code,
|
|
13
|
-
:meta => meta,
|
|
14
13
|
)
|
|
15
14
|
}
|
|
16
15
|
let(:account) { DoubleEntry.account(:test, :scope => "17") }
|
|
17
16
|
let(:partner_account) { DoubleEntry.account(:test, :scope => "72") }
|
|
18
17
|
let(:code) { :test_code }
|
|
19
|
-
let(:meta) { "test meta" }
|
|
20
18
|
before { persisted_line.save! }
|
|
21
19
|
subject { DoubleEntry::Line.last }
|
|
22
20
|
|
|
@@ -41,28 +39,6 @@ describe DoubleEntry::Line do
|
|
|
41
39
|
its("partner_account.account.identifier") { should eq :test }
|
|
42
40
|
its("partner_account.scope") { should eq "91" }
|
|
43
41
|
end
|
|
44
|
-
|
|
45
|
-
context "given meta = 'the meta'" do
|
|
46
|
-
let(:meta) { "the meta" }
|
|
47
|
-
its(:meta) { should eq "the meta" }
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
context "given meta = nil" do
|
|
51
|
-
let(:meta) { nil }
|
|
52
|
-
its(:meta) { should eq nil }
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
context "given meta has not been persisted (NULL)" do
|
|
56
|
-
let(:persisted_line) {
|
|
57
|
-
DoubleEntry::Line.new(
|
|
58
|
-
:amount => Money.new(10_00),
|
|
59
|
-
:balance => Money.empty,
|
|
60
|
-
:account => DoubleEntry.account(:savings, :scope => User.make!),
|
|
61
|
-
:code => code,
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
its(:meta) { should eq Hash.new }
|
|
65
|
-
end
|
|
66
42
|
end
|
|
67
43
|
|
|
68
44
|
it "has a table name prefixed with double_entry_" do
|
data/spec/double_entry_spec.rb
CHANGED
|
@@ -100,7 +100,7 @@ describe DoubleEntry do
|
|
|
100
100
|
end
|
|
101
101
|
|
|
102
102
|
config.define_transfers do |transfers|
|
|
103
|
-
transfers.define(:from => :savings, :to => :cash, :code => :xfer
|
|
103
|
+
transfers.define(:from => :savings, :to => :cash, :code => :xfer)
|
|
104
104
|
end
|
|
105
105
|
end
|
|
106
106
|
end
|
|
@@ -115,7 +115,6 @@ describe DoubleEntry do
|
|
|
115
115
|
:from => savings,
|
|
116
116
|
:to => cash,
|
|
117
117
|
:code => :xfer,
|
|
118
|
-
:meta => { :ref => 'shopping!' },
|
|
119
118
|
)
|
|
120
119
|
end
|
|
121
120
|
|
|
@@ -137,7 +136,6 @@ describe DoubleEntry do
|
|
|
137
136
|
:from => savings,
|
|
138
137
|
:to => cash,
|
|
139
138
|
:code => :yfer,
|
|
140
|
-
:meta => { :ref => 'shopping!' },
|
|
141
139
|
)
|
|
142
140
|
}.to raise_error DoubleEntry::TransferNotAllowed
|
|
143
141
|
end
|
|
@@ -151,18 +149,6 @@ describe DoubleEntry do
|
|
|
151
149
|
)
|
|
152
150
|
}.to raise_error DoubleEntry::TransferNotAllowed
|
|
153
151
|
end
|
|
154
|
-
|
|
155
|
-
it 'raises an exception when required meta data is omitted' do
|
|
156
|
-
expect {
|
|
157
|
-
DoubleEntry.transfer(
|
|
158
|
-
Money.new(100_00),
|
|
159
|
-
:from => savings,
|
|
160
|
-
:to => cash,
|
|
161
|
-
:code => :xfer,
|
|
162
|
-
:meta => {},
|
|
163
|
-
)
|
|
164
|
-
}.to raise_error DoubleEntry::RequiredMetaMissing
|
|
165
|
-
end
|
|
166
152
|
end
|
|
167
153
|
|
|
168
154
|
describe 'lines' do
|
|
@@ -173,7 +159,7 @@ describe DoubleEntry do
|
|
|
173
159
|
accounts.define(:identifier => :b)
|
|
174
160
|
end
|
|
175
161
|
|
|
176
|
-
description = ->(line) { "Money goes #{line.
|
|
162
|
+
description = ->(line) { "Money goes #{line.decrease? ? 'out' : 'in'}: #{line.amount.format}" }
|
|
177
163
|
config.define_transfers do |transfers|
|
|
178
164
|
transfers.define(:code => :xfer, :from => :a, :to => :b, :description => description)
|
|
179
165
|
end
|
|
@@ -208,11 +194,11 @@ describe DoubleEntry do
|
|
|
208
194
|
expect(credit_line.partner_account).to eq debit_line.account
|
|
209
195
|
end
|
|
210
196
|
|
|
211
|
-
it 'knows if it is
|
|
212
|
-
expect(credit_line).to
|
|
213
|
-
expect(debit_line).to
|
|
214
|
-
expect(credit_line).to_not
|
|
215
|
-
expect(debit_line).to_not
|
|
197
|
+
it 'knows if it is an increase or decrease' do
|
|
198
|
+
expect(credit_line).to be_decrease
|
|
199
|
+
expect(debit_line).to be_increase
|
|
200
|
+
expect(credit_line).to_not be_increase
|
|
201
|
+
expect(debit_line).to_not be_decrease
|
|
216
202
|
end
|
|
217
203
|
|
|
218
204
|
it 'can reference its partner' do
|
data/spec/support/schema.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: double_entry
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -16,7 +16,7 @@ authors:
|
|
|
16
16
|
autorequire:
|
|
17
17
|
bindir: bin
|
|
18
18
|
cert_chain: []
|
|
19
|
-
date: 2014-07-
|
|
19
|
+
date: 2014-07-17 00:00:00.000000000 Z
|
|
20
20
|
dependencies:
|
|
21
21
|
- !ruby/object:Gem::Dependency
|
|
22
22
|
name: money
|