plutus 0.10.1 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.markdown +115 -68
- data/app/models/plutus/amount.rb +20 -1
- data/app/models/plutus/amounts_extension.rb +1 -1
- data/app/models/plutus/entry.rb +14 -24
- data/lib/plutus/version.rb +1 -1
- data/spec/models/account_spec.rb +8 -8
- data/spec/models/debit_amount_spec.rb +1 -1
- data/spec/models/entry_spec.rb +124 -17
- data/spec/spec_helper.rb +3 -0
- data/spec/support/amount_shared_examples.rb +3 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 800c3e46c1d9b6590ede005950a962326ba72f62
|
4
|
+
data.tar.gz: 0264281c8d603c01e045ec91fe1ecb0137be1e6f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d363104d103fc0d409b55d435c215299b2ca74e72f431fc49c83ff9fbf2a405c50c2a9ed767189739247b8ea4705539bd20216b4570ff33d8154861ee1e2785f
|
7
|
+
data.tar.gz: c5ade1d75490927b5926e175a7e8180a7f9cdd2bc33c90e351f438d0e2e8eca44eddae8c7ae24662634a05822caa9471138c6993cb0c7e9aac3cb9d6d87bf32e
|
data/README.markdown
CHANGED
@@ -45,18 +45,21 @@ The Account class represents accounts in the system. The Account table uses sing
|
|
45
45
|
|
46
46
|
Your Book of Accounts needs to be created prior to recording any entries. The simplest method is to have a number of `create` methods in your db/seeds.rb file like so:
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
48
|
+
```ruby
|
49
|
+
Plutus::Asset.create(:name => "Accounts Receivable")
|
50
|
+
Plutus::Asset.create(:name => "Cash")
|
51
|
+
Plutus::Revenue.create(:name => "Sales Revenue")
|
52
|
+
Plutus::Liability.create(:name => "Unearned Revenue")
|
53
|
+
Plutus::Liability.create(:name => "Sales Tax Payable")
|
54
|
+
```
|
54
55
|
|
55
56
|
Then simply run `rake db:seed`
|
56
57
|
|
57
58
|
Each account can also be marked as a "Contra Account". A contra account will have its normal balance swapped. For example, to remove equity, a "Drawing" account may be created as a contra equity account as follows:
|
58
59
|
|
59
|
-
|
60
|
+
```ruby
|
61
|
+
Plutus::Equity.create(:name => "Drawing", :contra => true)
|
62
|
+
```
|
60
63
|
|
61
64
|
At all times the balance of all accounts should conform to the [Accounting
|
62
65
|
Equation](http://en.wikipedia.org/wiki/Accounting_equation)
|
@@ -75,23 +78,27 @@ Recording an Entry
|
|
75
78
|
|
76
79
|
Let's assume we're accounting on an [Accrual basis](http://en.wikipedia.org/wiki/Accounting_methods#Accrual_basis). We've just taken a customer's order for some widgets, which we've also billed him for. At this point we've actually added a liability to the company until we deliver the goods. To record this entry we'd need two accounts:
|
77
80
|
|
78
|
-
|
79
|
-
|
81
|
+
```ruby
|
82
|
+
>> Plutus::Asset.create(:name => "Cash")
|
83
|
+
>> Plutus::Liability.create(:name => "Unearned Revenue")
|
84
|
+
```
|
80
85
|
|
81
|
-
Next we'll build the entry we want to record. Plutus
|
86
|
+
Next we'll build the entry we want to record. Plutus uses ActiveRecord conventions to build the transaction and its associated amounts.
|
82
87
|
|
83
|
-
entry = Plutus::Entry.
|
88
|
+
entry = Plutus::Entry.new(
|
84
89
|
:description => "Order placed for widgets",
|
85
90
|
:debits => [
|
86
|
-
{:
|
91
|
+
{:account_name => "Cash", :amount => 100.00}],
|
87
92
|
:credits => [
|
88
|
-
{:
|
93
|
+
{:account_name => "Unearned Revenue", :amount => 100.00}])
|
89
94
|
|
90
|
-
|
95
|
+
Entries must specify a description, as well as at least one credit and debit amount. `Amount`s must specify an amount value as well as an account, either by providing a `Plutus::Account` to `account` or by passing in an `account_name` string.
|
91
96
|
|
92
97
|
Finally, save the entry.
|
93
98
|
|
94
|
-
|
99
|
+
```ruby
|
100
|
+
>> entry.save
|
101
|
+
```
|
95
102
|
|
96
103
|
If there are any issues with your credit and debit amounts, the save will fail and return false. You can inspect the errors via `entry.errors`. Because we are doing double-entry accounting, your credit and debit amounts must always cancel out to keep the accounts in balance.
|
97
104
|
|
@@ -100,20 +107,24 @@ Recording an Entry with multiple accounts
|
|
100
107
|
|
101
108
|
Often times a single entry requires more than one type of account. A classic example would be a entry in which a tax is charged. We'll assume that we have not yet received payment for the order, so we'll need an "Accounts Receivable" Asset:
|
102
109
|
|
103
|
-
|
104
|
-
|
105
|
-
|
110
|
+
```ruby
|
111
|
+
>> Plutus::Asset.create(:name => "Accounts Receivable")
|
112
|
+
>> Plutus::Revenue.create(:name => "Sales Revenue")
|
113
|
+
>> Plutus::Liability.create(:name => "Sales Tax Payable")
|
114
|
+
```
|
106
115
|
|
107
116
|
And here's the entry:
|
108
117
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
118
|
+
```ruby
|
119
|
+
entry = Plutus::Entry.build(
|
120
|
+
:description => "Sold some widgets",
|
121
|
+
:debits => [
|
122
|
+
{:account => "Accounts Receivable", :amount => 50}],
|
123
|
+
:credits => [
|
124
|
+
{:account => "Sales Revenue", :amount => 45},
|
125
|
+
{:account => "Sales Tax Payable", :amount => 5}])
|
126
|
+
entry.save
|
127
|
+
```
|
117
128
|
|
118
129
|
Associating Documents
|
119
130
|
---------------------
|
@@ -122,19 +133,23 @@ Although Plutus does not provide a mechanism for generating invoices or orders,
|
|
122
133
|
|
123
134
|
Suppose we pull up our latest invoice in order to generate a entry for plutus (we'll assume you already have an Invoice model):
|
124
135
|
|
125
|
-
|
136
|
+
```ruby
|
137
|
+
>> invoice = Invoice.last
|
138
|
+
```
|
126
139
|
|
127
140
|
Let's assume we're using the same entry from the last example
|
128
141
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
142
|
+
```ruby
|
143
|
+
entry = Plutus::Entry.new(
|
144
|
+
:description => "Sold some widgets",
|
145
|
+
:commercial_document => invoice,
|
146
|
+
:debits => [
|
147
|
+
{:account_name => "Accounts Receivable", :amount => invoice.total_amount}],
|
148
|
+
:credits => [
|
149
|
+
{:account_name => "Sales Revenue", :amount => invoice.sales_amount},
|
150
|
+
{:account_name => "Sales Tax Payable", :amount => invoice.tax_amount}])
|
151
|
+
entry.save
|
152
|
+
```
|
138
153
|
|
139
154
|
The commercial document attribute on the entry is a polymorphic association allowing you to associate any record from your models with a entry (i.e. Bills, Invoices, Receipts, Returns, etc.)
|
140
155
|
|
@@ -143,9 +158,11 @@ Checking the Balance of an Individual Account
|
|
143
158
|
|
144
159
|
Each account can report on its own balance. This number should normally be positive. If the number is negative, you may have a problem.
|
145
160
|
|
146
|
-
|
147
|
-
|
148
|
-
|
161
|
+
```ruby
|
162
|
+
>> cash = Plutus::Asset.find_by_name("Cash")
|
163
|
+
>> cash.balance
|
164
|
+
=> #<BigDecimal:103259bb8,'0.2E4',4(12)>
|
165
|
+
```
|
149
166
|
|
150
167
|
|
151
168
|
Checking the Balance of an Account Type
|
@@ -153,16 +170,20 @@ Checking the Balance of an Account Type
|
|
153
170
|
|
154
171
|
Each subclass of accounts can report on the total balance of all the accounts of that type. This number should normally be positive. If the number is negative, you may have a problem.
|
155
172
|
|
156
|
-
|
157
|
-
|
173
|
+
```ruby
|
174
|
+
>> Plutus::Asset.balance
|
175
|
+
=> #<BigDecimal:103259bb8,'0.2E4',4(12)>
|
176
|
+
```
|
158
177
|
|
159
178
|
Calculating the Trial Balance
|
160
179
|
-----------------------------
|
161
180
|
|
162
181
|
The [Trial Balance](http://en.wikipedia.org/wiki/Trial_balance) for all accounts on the system can be found through the abstract Account class. This value should be 0 unless there is an error in the system.
|
163
182
|
|
164
|
-
|
165
|
-
|
183
|
+
```ruby
|
184
|
+
>> Plutus::Account.trial_balance
|
185
|
+
=> #<BigDecimal:1031c0d28,'0.0',4(12)>
|
186
|
+
```
|
166
187
|
|
167
188
|
Contra Accounts and Complex Entries
|
168
189
|
-----------------------------------
|
@@ -173,37 +194,61 @@ For complex entries, you should always ensure that you are balancing your accoun
|
|
173
194
|
|
174
195
|
For example, let's assume the owner of a business wants to withdraw cash. First we'll assume that we have an asset account for "Cash" which the funds will be drawn from. We'll then need an Equity account to record where the funds are going, however, in this case, we can't simply create a regular Equity account. The "Cash" account must be credited for the decrease in its balance since it's an Asset. Likewise, Equity accounts are typically credited when there is an increase in their balance. Equity is considered an owner's rights to Assets in the business. In this case however, we are not simply increasing the owner's rights to assets within the business; we are actually removing capital from the business altogether. Hence both sides of our accounting equation will see a decrease. In order to accomplish this, we need to create a Contra-Equity account we'll call "Drawings". Since Equity accounts normally have credit balances, a Contra-Equity account will have a debit balance, which is what we need for our entry.
|
175
196
|
|
176
|
-
|
177
|
-
|
197
|
+
```ruby
|
198
|
+
>> Plutus::Equity.create(:name => "Drawing", :contra => true)
|
199
|
+
>> Plutus::Asset.create(:name => "Cash")
|
200
|
+
```
|
178
201
|
|
179
202
|
We would then create the following entry:
|
180
203
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
204
|
+
```ruby
|
205
|
+
entry = Plutus::Entry.new(
|
206
|
+
:description => "Owner withdrawing cash",
|
207
|
+
:debits => [
|
208
|
+
{:account_name => "Drawing", :amount => 1000}],
|
209
|
+
:credits => [
|
210
|
+
{:account_name => "Cash", :amount => 1000}])
|
211
|
+
entry.save
|
212
|
+
```
|
188
213
|
|
189
214
|
To make the example clearer, imagine instead that the owner decides to invest his money into the business in exchange for some type of equity security. In this case we might have the following accounts:
|
190
215
|
|
191
|
-
|
192
|
-
|
216
|
+
```ruby
|
217
|
+
>> Plutus::Equity.create(:name => "Common Stock")
|
218
|
+
>> Plutus::Asset.create(:name => "Cash")
|
219
|
+
```
|
193
220
|
|
194
221
|
And out entry would be:
|
195
222
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
223
|
+
```ruby
|
224
|
+
entry = Plutus::Entry.new(
|
225
|
+
:description => "Owner investing cash",
|
226
|
+
:debits => [
|
227
|
+
{:account_name => "Cash", :amount => 1000}],
|
228
|
+
:credits => [
|
229
|
+
{:account_name => "Common Stock", :amount => 1000}])
|
230
|
+
entry.save
|
231
|
+
```
|
203
232
|
|
204
233
|
In this case, we've increase our cash Asset, and simultaneously increased the other side of our accounting equation in
|
205
234
|
Equity, keeping everything balanced.
|
206
235
|
|
236
|
+
Money & Currency Support
|
237
|
+
========================
|
238
|
+
|
239
|
+
Plutus aims to be agnostic about the values used for amounts. All fields are maintained as BigDecimal values, with `:precision => 20, :scale => 10`, which means that any currency can be safely stored in the tables.
|
240
|
+
|
241
|
+
Plutus is also compatible with the [Money](https://github.com/RubyMoney/money) gem. With Money versions greater than 6.0, the `money.amount` will returns a BigDecimal which you can use with plutus as follows:
|
242
|
+
|
243
|
+
```ruby
|
244
|
+
entry = Plutus::Entry.build(
|
245
|
+
:description => "Order placed for widgets",
|
246
|
+
:debits => [
|
247
|
+
{:account => "Cash", :amount => money.amount}],
|
248
|
+
:credits => [
|
249
|
+
{:account => "Unearned Revenue", :amount => money.amount}])
|
250
|
+
```
|
251
|
+
|
207
252
|
Multitenancy Support
|
208
253
|
=====================
|
209
254
|
|
@@ -212,22 +257,22 @@ Plutus supports multitenant applications. Multitenancy is acheived by associatin
|
|
212
257
|
- Generate the migration which will add `tenant_id` to the plutus accounts table
|
213
258
|
|
214
259
|
```sh
|
215
|
-
|
260
|
+
bundle exec rails g plutus:tenancy
|
216
261
|
```
|
217
262
|
|
218
263
|
- Run the migration
|
219
264
|
|
220
265
|
```sh
|
221
|
-
|
266
|
+
rake db:migrate
|
222
267
|
```
|
223
268
|
|
224
269
|
- Add an initializer to your Rails application, i.e. `config/initializers/plutus.rb`
|
225
270
|
|
226
271
|
```ruby
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
272
|
+
Plutus.config do |config|
|
273
|
+
config.enable_tenancy = true
|
274
|
+
config.tenant_class = 'Tenant'
|
275
|
+
end
|
231
276
|
```
|
232
277
|
|
233
278
|
Access & Security
|
@@ -239,7 +284,9 @@ These controllers are read-only for reporting purposes. It is assumed entry crea
|
|
239
284
|
|
240
285
|
Routing is supplied via an engine mount point. Plutus can be mounted on a subpath in your existing Rails 3 app by adding the following to your routes.rb:
|
241
286
|
|
242
|
-
|
287
|
+
```ruby
|
288
|
+
mount Plutus::Engine => "/plutus", :as => "plutus"
|
289
|
+
```
|
243
290
|
|
244
291
|
*NOTE: If you enable routing, you should ensure that your ApplicationController enforces its own authentication and authorization, which this controller will inherit.*
|
245
292
|
|
data/app/models/plutus/amount.rb
CHANGED
@@ -2,7 +2,7 @@ module Plutus
|
|
2
2
|
# The Amount class represents debit and credit amounts in the system.
|
3
3
|
#
|
4
4
|
# @abstract
|
5
|
-
# An amount must be a subclass as either a debit or a credit to be saved to the database.
|
5
|
+
# An amount must be a subclass as either a debit or a credit to be saved to the database.
|
6
6
|
#
|
7
7
|
# @author Michael Bulat
|
8
8
|
class Amount < ActiveRecord::Base
|
@@ -10,5 +10,24 @@ module Plutus
|
|
10
10
|
belongs_to :account, :class_name => 'Plutus::Account'
|
11
11
|
|
12
12
|
validates_presence_of :type, :amount, :entry, :account
|
13
|
+
# attr_accessible :account, :account_name, :amount, :entry
|
14
|
+
|
15
|
+
# Assign an account by name
|
16
|
+
def account_name=(name)
|
17
|
+
self.account = Account.find_by_name!(name)
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
# Support constructing amounts with account = "name" syntax
|
23
|
+
def account_with_name_lookup=(v)
|
24
|
+
if v.kind_of?(String)
|
25
|
+
ActiveSupport::Deprecation.warn('Plutus was given an :account String (use account_name instead)', caller)
|
26
|
+
self.account_name = v
|
27
|
+
else
|
28
|
+
self.account_without_name_lookup = v
|
29
|
+
end
|
30
|
+
end
|
31
|
+
alias_method_chain :account=, :name_lookup
|
13
32
|
end
|
14
33
|
end
|
data/app/models/plutus/entry.rb
CHANGED
@@ -23,8 +23,8 @@ module Plutus
|
|
23
23
|
# @author Michael Bulat
|
24
24
|
class Entry < ActiveRecord::Base
|
25
25
|
belongs_to :commercial_document, :polymorphic => true
|
26
|
-
has_many :credit_amounts, :extend => AmountsExtension, :class_name => 'Plutus::CreditAmount'
|
27
|
-
has_many :debit_amounts, :extend => AmountsExtension, :class_name => 'Plutus::DebitAmount'
|
26
|
+
has_many :credit_amounts, :extend => AmountsExtension, :class_name => 'Plutus::CreditAmount', :inverse_of => :entry
|
27
|
+
has_many :debit_amounts, :extend => AmountsExtension, :class_name => 'Plutus::DebitAmount', :inverse_of => :entry
|
28
28
|
has_many :credit_accounts, :through => :credit_amounts, :source => :account, :class_name => 'Plutus::Account'
|
29
29
|
has_many :debit_accounts, :through => :debit_amounts, :source => :account, :class_name => 'Plutus::Account'
|
30
30
|
|
@@ -33,30 +33,20 @@ module Plutus
|
|
33
33
|
validate :has_debit_amounts?
|
34
34
|
validate :amounts_cancel?
|
35
35
|
|
36
|
+
# Support construction using 'credits' and 'debits' keys
|
37
|
+
accepts_nested_attributes_for :credit_amounts, :debit_amounts
|
38
|
+
alias_method :credits=, :credit_amounts_attributes=
|
39
|
+
alias_method :debits=, :debit_amounts_attributes=
|
40
|
+
# attr_accessible :credits, :debits
|
36
41
|
|
37
|
-
#
|
38
|
-
#
|
39
|
-
# @example
|
40
|
-
# entry = Plutus::Entry.build(
|
41
|
-
# description: "Sold some widgets",
|
42
|
-
# debits: [
|
43
|
-
# {account: "Accounts Receivable", amount: 50}],
|
44
|
-
# credits: [
|
45
|
-
# {account: "Sales Revenue", amount: 45},
|
46
|
-
# {account: "Sales Tax Payable", amount: 5}])
|
47
|
-
#
|
48
|
-
# @return [Plutus::Entry] A Entry with built credit and debit objects ready for saving
|
42
|
+
# Support the deprecated .build method
|
49
43
|
def self.build(hash)
|
50
|
-
|
51
|
-
hash
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
a = Plutus::Account.find_by_name(credit[:account])
|
57
|
-
entry.credit_amounts << Plutus::CreditAmount.new(:account => a, :amount => credit[:amount], :entry => entry)
|
58
|
-
end
|
59
|
-
entry
|
44
|
+
ActiveSupport::Deprecation.warn('Plutus::Transaction.build() is deprecated (use new instead)', caller)
|
45
|
+
new(hash)
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize(*args)
|
49
|
+
super
|
60
50
|
end
|
61
51
|
|
62
52
|
private
|
data/lib/plutus/version.rb
CHANGED
data/spec/models/account_spec.rb
CHANGED
@@ -4,30 +4,30 @@ module Plutus
|
|
4
4
|
describe Account do
|
5
5
|
let(:account) { FactoryGirl.build(:account) }
|
6
6
|
subject { account }
|
7
|
-
|
7
|
+
|
8
8
|
it { should_not be_valid } # must construct a child type instead
|
9
9
|
|
10
10
|
describe "when using a child type" do
|
11
11
|
let(:account) { FactoryGirl.create(:account, type: "Finance::Asset") }
|
12
12
|
it { should be_valid }
|
13
|
-
|
13
|
+
|
14
14
|
it "should be unique per name" do
|
15
15
|
conflict = FactoryGirl.build(:account, name: account.name, type: account.type)
|
16
16
|
conflict.should_not be_valid
|
17
17
|
conflict.errors[:name].should == ["has already been taken"]
|
18
18
|
end
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
it { should_not respond_to(:balance) }
|
22
|
-
|
22
|
+
|
23
23
|
describe ".trial_balance" do
|
24
24
|
subject { Account.trial_balance }
|
25
25
|
it { should be_kind_of BigDecimal }
|
26
|
-
|
26
|
+
|
27
27
|
context "when given no entries" do
|
28
28
|
it { should == 0 }
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
context "when given correct entries" do
|
32
32
|
before {
|
33
33
|
# credit accounts
|
@@ -57,12 +57,12 @@ module Plutus
|
|
57
57
|
da5 = FactoryGirl.build(:debit_amount, :account => contra_revenue, :amount => 333)
|
58
58
|
|
59
59
|
FactoryGirl.create(:entry, :credit_amounts => [ca1], :debit_amounts => [da1])
|
60
|
-
FactoryGirl.create(:entry, :credit_amounts => [ca2], :debit_amounts => [da2])
|
60
|
+
FactoryGirl.create(:entry, :credit_amounts => [ca2], :debit_amounts => [da2])
|
61
61
|
FactoryGirl.create(:entry, :credit_amounts => [ca3], :debit_amounts => [da3])
|
62
62
|
FactoryGirl.create(:entry, :credit_amounts => [ca4], :debit_amounts => [da4])
|
63
63
|
FactoryGirl.create(:entry, :credit_amounts => [ca5], :debit_amounts => [da5])
|
64
64
|
}
|
65
|
-
|
65
|
+
|
66
66
|
it { should == 0 }
|
67
67
|
end
|
68
68
|
end
|
data/spec/models/entry_spec.rb
CHANGED
@@ -10,7 +10,7 @@ module Plutus
|
|
10
10
|
context "with credit and debit" do
|
11
11
|
let(:entry) { FactoryGirl.build(:entry_with_credit_and_debit) }
|
12
12
|
it { should be_valid }
|
13
|
-
|
13
|
+
|
14
14
|
it "should require a description" do
|
15
15
|
entry.description = nil
|
16
16
|
entry.should_not be_valid
|
@@ -68,23 +68,130 @@ module Plutus
|
|
68
68
|
saved_entry.commercial_document.should == mock_document
|
69
69
|
end
|
70
70
|
|
71
|
-
|
72
|
-
FactoryGirl.create(:asset
|
73
|
-
FactoryGirl.create(:
|
74
|
-
FactoryGirl.create(:
|
75
|
-
|
76
|
-
entry = Entry.build(
|
77
|
-
description: "Sold some widgets",
|
78
|
-
commercial_document: mock_document,
|
79
|
-
debits: [
|
80
|
-
{account: "Accounts Receivable", amount: 50}],
|
81
|
-
credits: [
|
82
|
-
{account: "Sales Revenue", amount: 45},
|
83
|
-
{account: "Sales Tax Payable", amount: 5}])
|
84
|
-
entry.save!
|
71
|
+
context "given a set of accounts" do
|
72
|
+
let(:mock_document) { FactoryGirl.create(:asset) }
|
73
|
+
let!(:accounts_receivable) { FactoryGirl.create(:asset, name: "Accounts Receivable") }
|
74
|
+
let!(:sales_revenue) { FactoryGirl.create(:revenue, name: "Sales Revenue") }
|
75
|
+
let!(:sales_tax_payable) { FactoryGirl.create(:liability, name: "Sales Tax Payable") }
|
85
76
|
|
86
|
-
|
87
|
-
|
77
|
+
shared_examples_for 'a built-from-hash Plutus::Entry' do
|
78
|
+
its(:credit_amounts) { should_not be_empty }
|
79
|
+
its(:debit_amounts) { should_not be_empty }
|
80
|
+
it { should be_valid }
|
81
|
+
|
82
|
+
context "when saved" do
|
83
|
+
before { entry.save! }
|
84
|
+
its(:id) { should_not be_nil }
|
85
|
+
|
86
|
+
context "when reloaded" do
|
87
|
+
let(:saved_transaction) { Entry.find(entry.id) }
|
88
|
+
subject { saved_transaction }
|
89
|
+
it("should have the correct commercial document") {
|
90
|
+
saved_transaction.commercial_document == mock_document
|
91
|
+
}
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe ".new" do
|
97
|
+
let(:entry) { Entry.new(hash) }
|
98
|
+
subject { entry }
|
99
|
+
|
100
|
+
context "when given a credit/debits hash with :account => Account" do
|
101
|
+
let(:hash) {
|
102
|
+
{
|
103
|
+
description: "Sold some widgets",
|
104
|
+
commercial_document: mock_document,
|
105
|
+
debits: [{account: accounts_receivable, amount: 50}],
|
106
|
+
credits: [
|
107
|
+
{account: sales_revenue, amount: 45},
|
108
|
+
{account: sales_tax_payable, amount: 5}
|
109
|
+
]
|
110
|
+
}
|
111
|
+
}
|
112
|
+
include_examples 'a built-from-hash Plutus::Entry'
|
113
|
+
end
|
114
|
+
|
115
|
+
context "when given a credit/debits hash with :account_name => String" do
|
116
|
+
let(:hash) {
|
117
|
+
{
|
118
|
+
description: "Sold some widgets",
|
119
|
+
commercial_document: mock_document,
|
120
|
+
debits: [{account_name: accounts_receivable.name, amount: 50}],
|
121
|
+
credits: [
|
122
|
+
{account_name: sales_revenue.name, amount: 45},
|
123
|
+
{account_name: sales_tax_payable.name, amount: 5}
|
124
|
+
]
|
125
|
+
}
|
126
|
+
}
|
127
|
+
include_examples 'a built-from-hash Plutus::Entry'
|
128
|
+
end
|
129
|
+
|
130
|
+
context "when given a credit/debits hash with :account => String" do
|
131
|
+
let(:hash) {
|
132
|
+
{
|
133
|
+
description: "Sold some widgets",
|
134
|
+
commercial_document: mock_document,
|
135
|
+
debits: [{account: accounts_receivable.name, amount: 50}],
|
136
|
+
credits: [
|
137
|
+
{account: sales_revenue.name, amount: 45},
|
138
|
+
{account: sales_tax_payable.name, amount: 5}
|
139
|
+
]
|
140
|
+
}
|
141
|
+
}
|
142
|
+
|
143
|
+
before { ::ActiveSupport::Deprecation.silenced = true }
|
144
|
+
after { ::ActiveSupport::Deprecation.silenced = false }
|
145
|
+
|
146
|
+
it("should be deprecated") {
|
147
|
+
# one deprecation per account looked up
|
148
|
+
::ActiveSupport::Deprecation.should_receive(:warn).exactly(3).times
|
149
|
+
entry
|
150
|
+
}
|
151
|
+
|
152
|
+
include_examples 'a built-from-hash Plutus::Entry'
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
describe ".build" do
|
157
|
+
let(:entry) { Entry.build(hash) }
|
158
|
+
subject { entry }
|
159
|
+
|
160
|
+
before { ::ActiveSupport::Deprecation.silenced = true }
|
161
|
+
after { ::ActiveSupport::Deprecation.silenced = false }
|
162
|
+
|
163
|
+
context "when used at all" do
|
164
|
+
let(:hash) { Hash.new }
|
165
|
+
|
166
|
+
it("should be deprecated") {
|
167
|
+
# .build is the only thing deprecated
|
168
|
+
::ActiveSupport::Deprecation.should_receive(:warn).once
|
169
|
+
entry
|
170
|
+
}
|
171
|
+
end
|
172
|
+
|
173
|
+
context "when given a credit/debits hash with :account => String" do
|
174
|
+
let(:hash) {
|
175
|
+
{
|
176
|
+
description: "Sold some widgets",
|
177
|
+
commercial_document: mock_document,
|
178
|
+
debits: [{account: accounts_receivable.name, amount: 50}],
|
179
|
+
credits: [
|
180
|
+
{account: sales_revenue.name, amount: 45},
|
181
|
+
{account: sales_tax_payable.name, amount: 5}
|
182
|
+
]
|
183
|
+
}
|
184
|
+
}
|
185
|
+
|
186
|
+
it("should be deprecated") {
|
187
|
+
# one deprecation for build, plus three for accounts as strings
|
188
|
+
::ActiveSupport::Deprecation.should_receive(:warn).exactly(4).times
|
189
|
+
entry
|
190
|
+
}
|
191
|
+
|
192
|
+
include_examples 'a built-from-hash Plutus::Entry'
|
193
|
+
end
|
194
|
+
end
|
88
195
|
end
|
89
196
|
|
90
197
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
shared_examples_for 'a Plutus::Amount subtype' do |elements|
|
2
2
|
let(:amount) { FactoryGirl.build(elements[:kind]) }
|
3
3
|
subject { amount }
|
4
|
-
|
4
|
+
|
5
5
|
it { should be_valid }
|
6
|
-
|
6
|
+
|
7
7
|
it "should require an amount" do
|
8
8
|
amount.amount = nil
|
9
9
|
amount.should_not be_valid
|
@@ -13,7 +13,7 @@ shared_examples_for 'a Plutus::Amount subtype' do |elements|
|
|
13
13
|
amount.entry = nil
|
14
14
|
amount.should_not be_valid
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
it "should require an account" do
|
18
18
|
amount.account = nil
|
19
19
|
amount.should_not be_valid
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: plutus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Bulat
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|