bookkeeping 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/models/bookkeeping/account.rb +0 -7
- data/app/models/bookkeeping/credit_amount.rb +6 -0
- data/app/models/bookkeeping/entry.rb +18 -16
- data/lib/bookkeeping/dsl.rb +31 -18
- data/lib/bookkeeping/engine.rb +2 -0
- data/lib/bookkeeping/proxy.rb +25 -0
- data/lib/bookkeeping/version.rb +1 -1
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c80eee7c8cc61dde2184ffefa1c5c9cc241f82df
|
4
|
+
data.tar.gz: 37d0fede0812a012084e4b1fd30599f68360e009
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 58748ee0ad0b0411f736d4747ae0ee6f9bb9be2b1b8037ab43f7e31d0e547d9e1ecaf2407d30b3565d4c5bb5c50edbad8ea411432ae0fa5d57b24e17a1eb943d
|
7
|
+
data.tar.gz: f9c8cca3d4cb2fca1065dfe91a5bacd3a64b4a5f6a534898fb54a1f41e10fbd3978b996456d9034b9425d1b9c0ebe8976d45af2e7db7491e20803f9b2e870947
|
@@ -22,7 +22,6 @@ module Bookkeeping
|
|
22
22
|
|
23
23
|
# Validations
|
24
24
|
validates :name, presence: true
|
25
|
-
validate :prevent_overdraft, unless: :overdraft_enabled?
|
26
25
|
|
27
26
|
class NotFound < StandardError; end
|
28
27
|
class BadKind < StandardError; end
|
@@ -80,11 +79,5 @@ module Bookkeeping
|
|
80
79
|
def overdraft?
|
81
80
|
balance < 0
|
82
81
|
end
|
83
|
-
|
84
|
-
private
|
85
|
-
|
86
|
-
def prevent_overdraft
|
87
|
-
errors.add(:balance, :overdraft) if balance < 0
|
88
|
-
end
|
89
82
|
end
|
90
83
|
end
|
@@ -15,6 +15,7 @@ module Bookkeeping
|
|
15
15
|
class Entry < ActiveRecord::Base
|
16
16
|
|
17
17
|
belongs_to :transactionable, polymorphic: true
|
18
|
+
belongs_to :rollback_entry, class_name: 'Bookkeeping::Entry'
|
18
19
|
has_many :amounts, dependent: :destroy
|
19
20
|
has_many :debit_amounts, class_name: "Bookkeeping::DebitAmount"
|
20
21
|
has_many :credit_amounts, class_name: "Bookkeeping::CreditAmount"
|
@@ -22,42 +23,43 @@ module Bookkeeping
|
|
22
23
|
validates :transactionable, :description, presence: true
|
23
24
|
validate :has_credit_amounts?
|
24
25
|
validate :has_debit_amounts?
|
25
|
-
validate :
|
26
|
+
validate :amounts_equal?
|
26
27
|
|
27
28
|
def self.prepare(options = {}, &block)
|
28
|
-
new(options)
|
29
|
-
dsl = Bookkeeping::DSL.new(entry)
|
30
|
-
dsl.instance_eval &block
|
31
|
-
dsl.build
|
32
|
-
end
|
29
|
+
Bookkeeping::DSL.new(new(options), &block).build
|
33
30
|
end
|
34
31
|
|
35
|
-
# TODO: not work
|
36
|
-
def rollback
|
32
|
+
# TODO: not work
|
33
|
+
def rollback(ref = nil)
|
37
34
|
tran = self
|
38
|
-
|
35
|
+
inverse_entry = self.class.prepare do
|
39
36
|
tran.debit_amounts.each { |di| debit(di.account, -di.amount) }
|
40
37
|
tran.credit_amounts.each { |ci| credit(ci.account, -ci.amount) }
|
41
38
|
transactionable(ref || tran)
|
42
39
|
description("Rollback of #{tran.description}")
|
43
40
|
end
|
44
|
-
|
45
|
-
|
46
|
-
|
41
|
+
inverse_entry.save!
|
42
|
+
|
43
|
+
unless inverse_entry.new_record?
|
44
|
+
self.rollback_entry = inverse_entry
|
45
|
+
self.save!
|
46
|
+
end
|
47
|
+
|
48
|
+
inverse_entry
|
47
49
|
end
|
48
50
|
|
49
51
|
private
|
50
52
|
|
51
53
|
def has_credit_amounts?
|
52
|
-
errors[:
|
54
|
+
errors[:credit_amounts] << "Entry must have at least one credit amount" if self.credit_amounts.blank?
|
53
55
|
end
|
54
56
|
|
55
57
|
def has_debit_amounts?
|
56
|
-
errors[:
|
58
|
+
errors[:debit_amounts] << "Entry must have at least one debit amount" if self.debit_amounts.blank?
|
57
59
|
end
|
58
60
|
|
59
|
-
def
|
60
|
-
errors[:
|
61
|
+
def amounts_equal?
|
62
|
+
errors[:amounts_equality] << "The credit and debit amounts are not equal" if credit_amounts.to_a.sum(&:amount) != debit_amounts.to_a.sum(&:amount)
|
61
63
|
end
|
62
64
|
end
|
63
65
|
end
|
data/lib/bookkeeping/dsl.rb
CHANGED
@@ -1,45 +1,58 @@
|
|
1
1
|
module Bookkeeping
|
2
2
|
class DSL
|
3
|
-
attr_reader :
|
4
|
-
attr_accessor :entry
|
3
|
+
attr_reader :__debits, :__credits, :__description, :__reference
|
5
4
|
|
6
|
-
def initialize(entry)
|
7
|
-
@
|
8
|
-
@
|
9
|
-
|
5
|
+
def initialize(entry, &block)
|
6
|
+
@__debits = {}
|
7
|
+
@__credits = {}
|
8
|
+
|
9
|
+
self.extend Bookkeeping::Proxy
|
10
|
+
self.caller = block.binding.eval "self"
|
11
|
+
|
12
|
+
@__entry = entry
|
13
|
+
|
14
|
+
instance_eval &block
|
10
15
|
end
|
11
16
|
|
12
17
|
def debit(account, amount)
|
13
|
-
@
|
14
|
-
@
|
15
|
-
@debits[account] += amount
|
18
|
+
@__debits[account] ||= 0
|
19
|
+
@__debits[account] += amount
|
16
20
|
end
|
17
21
|
|
18
22
|
def credit(account, amount)
|
19
|
-
@
|
20
|
-
@
|
21
|
-
@credits[account] += amount
|
23
|
+
@__credits[account] ||= 0
|
24
|
+
@__credits[account] += amount
|
22
25
|
end
|
23
26
|
|
24
27
|
def description(description)
|
25
|
-
@
|
28
|
+
@__description = description
|
26
29
|
end
|
27
30
|
|
28
31
|
def transactionable(transactionable)
|
29
|
-
@
|
32
|
+
@__transactionable = transactionable
|
33
|
+
end
|
34
|
+
|
35
|
+
def entry
|
36
|
+
@__entry
|
37
|
+
end
|
38
|
+
|
39
|
+
def entry=(entry)
|
40
|
+
@__entry = entry
|
30
41
|
end
|
31
42
|
|
32
43
|
def build
|
33
|
-
entry.transactionable = @
|
34
|
-
entry.description = @
|
44
|
+
entry.transactionable = @__transactionable || entry.transactionable
|
45
|
+
entry.description = @__description || entry.description
|
35
46
|
|
36
|
-
|
47
|
+
__debits.each do |account, amount|
|
37
48
|
entry.debit_amounts.build(account: account, amount: amount)
|
38
49
|
end
|
39
50
|
|
40
|
-
|
51
|
+
__credits.each do |account, amount|
|
41
52
|
entry.credit_amounts.build(account: account, amount: amount)
|
42
53
|
end
|
54
|
+
|
55
|
+
entry
|
43
56
|
end
|
44
57
|
|
45
58
|
end
|
data/lib/bookkeeping/engine.rb
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Bookkeeping
|
2
|
+
module Proxy
|
3
|
+
def caller= context
|
4
|
+
@caller = context
|
5
|
+
exec_in_caller(context)
|
6
|
+
end
|
7
|
+
|
8
|
+
def method_missing(name, *args, &block)
|
9
|
+
@caller.send(name, *args, &block)
|
10
|
+
end
|
11
|
+
|
12
|
+
def respond_to?(name, include_private = false)
|
13
|
+
@caller.respond_to?(name) || super
|
14
|
+
end
|
15
|
+
|
16
|
+
def exec_in_caller(context)
|
17
|
+
return unless context
|
18
|
+
|
19
|
+
context.instance_variables.each do |ivar|
|
20
|
+
value_from_caller = context.instance_variable_get(ivar)
|
21
|
+
self.instance_variable_set(ivar, value_from_caller)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/bookkeeping/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bookkeeping
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Shlinchak
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-07-
|
11
|
+
date: 2015-07-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -108,6 +108,20 @@ dependencies:
|
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: shoulda-matchers
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
111
125
|
description: The goal of this gem is to build accounting (bookkeeping) system for
|
112
126
|
Rails projects using double entry theory.
|
113
127
|
email:
|
@@ -138,6 +152,7 @@ files:
|
|
138
152
|
- lib/bookkeeping.rb
|
139
153
|
- lib/bookkeeping/dsl.rb
|
140
154
|
- lib/bookkeeping/engine.rb
|
155
|
+
- lib/bookkeeping/proxy.rb
|
141
156
|
- lib/bookkeeping/version.rb
|
142
157
|
- lib/generators/bookkeeping/bookkeeping_generator.rb
|
143
158
|
- lib/generators/bookkeeping/templates/migration.rb
|