has_accounts 1.1.3 → 2.0.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/app/models/account.rb +33 -18
- data/app/models/booking.rb +80 -3
- data/app/models/booking_template.rb +18 -6
- data/config/locales/en.yml +1 -1
- data/db/migrate/20131021123821_change_bookings_amount_to_use_decimal_scope.rb +5 -0
- data/db/migrate/20131105212025_add_index_on_account_parent_id.rb +9 -0
- data/lib/has_accounts/railtie.rb +5 -0
- data/lib/has_accounts/version.rb +1 -1
- metadata +11 -35
- data/app/models/bank.rb +0 -12
- data/app/models/bank_account.rb +0 -6
- data/db/migrate/20111230121259_bank_now_inherits_from_person.rb +0 -28
data/app/models/account.rb
CHANGED
@@ -16,27 +16,40 @@ class Account < ActiveRecord::Base
|
|
16
16
|
"%s (%s)" % [title, code]
|
17
17
|
end
|
18
18
|
|
19
|
+
# Parent Account
|
20
|
+
# ==============
|
21
|
+
belongs_to :parent, :class_name => Account
|
22
|
+
attr_accessible :parent, :parent_id
|
23
|
+
|
19
24
|
# Account Type
|
20
25
|
# ============
|
21
26
|
belongs_to :account_type
|
22
27
|
attr_accessible :title, :code, :account_type_id, :account_type
|
23
28
|
validates_presence_of :account_type
|
24
29
|
|
25
|
-
def
|
30
|
+
def asset_account?
|
26
31
|
Account.by_type(['current_assets', 'capital_assets', 'costs']).exists?(self)
|
27
32
|
end
|
33
|
+
# Deprecated
|
34
|
+
alias_method :is_asset_account?, :asset_account?
|
28
35
|
|
29
|
-
def
|
30
|
-
!
|
36
|
+
def liability_account?
|
37
|
+
!asset_account?
|
31
38
|
end
|
39
|
+
# Deprecated
|
40
|
+
alias_method :is_liability_account?, :liability_account?
|
32
41
|
|
33
|
-
def
|
42
|
+
def balance_account?
|
34
43
|
Account.by_type(['current_assets', 'capital_assets', 'outside_capital', 'equity_capital']).exists?(self)
|
35
44
|
end
|
45
|
+
# Deprecated
|
46
|
+
alias_method :is_balance_account?, :balance_account?
|
36
47
|
|
37
|
-
def
|
38
|
-
!
|
48
|
+
def profit_account?
|
49
|
+
!balance_account?
|
39
50
|
end
|
51
|
+
# Deprecated
|
52
|
+
alias_method :is_profit_account?, :profit_account?
|
40
53
|
|
41
54
|
scope :by_type, lambda {|value| includes(:account_type).where('account_types.name' => value)} do
|
42
55
|
include AccountScopeExtension
|
@@ -44,15 +57,17 @@ class Account < ActiveRecord::Base
|
|
44
57
|
|
45
58
|
# Tagging
|
46
59
|
# =======
|
47
|
-
|
48
|
-
|
60
|
+
if defined?(ActsAsTaggableOn) && ActsAsTaggableOn::Tag.table_exists?
|
61
|
+
acts_as_taggable
|
62
|
+
attr_accessible :tag_list
|
49
63
|
|
50
|
-
|
51
|
-
|
52
|
-
|
64
|
+
def self.default_tags
|
65
|
+
['invoice:debit', 'invoice:earnings', 'invoice:credit', 'invoice:costs', 'vat:credit', 'vat:debit']
|
66
|
+
end
|
53
67
|
|
54
|
-
|
55
|
-
|
68
|
+
def self.tag_collection
|
69
|
+
(default_tags + Account.tag_counts.pluck(:name)).uniq
|
70
|
+
end
|
56
71
|
end
|
57
72
|
|
58
73
|
# Holder
|
@@ -68,10 +83,10 @@ class Account < ActiveRecord::Base
|
|
68
83
|
Booking.by_account(id)
|
69
84
|
end
|
70
85
|
|
71
|
-
#
|
72
|
-
|
73
|
-
|
74
|
-
|
86
|
+
# Balances grouped by references which have not 0
|
87
|
+
def unbalanced_references
|
88
|
+
bookings.unbalanced_by_grouped_reference(self.id)
|
89
|
+
end
|
75
90
|
|
76
91
|
# Helpers
|
77
92
|
# =======
|
@@ -129,7 +144,7 @@ class Account < ActiveRecord::Base
|
|
129
144
|
def saldo(selector = Date.today, inclusive = true)
|
130
145
|
credit_amount, debit_amount = turnover(selector, inclusive)
|
131
146
|
|
132
|
-
amount =
|
147
|
+
amount = debit_amount - credit_amount
|
133
148
|
|
134
149
|
return is_asset_account? ? amount : -amount
|
135
150
|
end
|
data/app/models/booking.rb
CHANGED
@@ -73,8 +73,11 @@ class Booking < ActiveRecord::Base
|
|
73
73
|
end
|
74
74
|
}
|
75
75
|
|
76
|
+
# Scope for all accounts assigned to account
|
77
|
+
#
|
78
|
+
# @param account_id [Integer]
|
76
79
|
scope :by_account, lambda {|account_id|
|
77
|
-
|
80
|
+
where("debit_account_id = :account_id OR credit_account_id = :account_id", :account_id => account_id)
|
78
81
|
} do
|
79
82
|
# Returns array of all booking titles.
|
80
83
|
def titles
|
@@ -89,6 +92,80 @@ class Booking < ActiveRecord::Base
|
|
89
92
|
end
|
90
93
|
end
|
91
94
|
|
95
|
+
# All involved accounts
|
96
|
+
#
|
97
|
+
# @returns all involved credit and debit accounts
|
98
|
+
def self.accounts
|
99
|
+
Account.where(:id => pluck(:debit_account_id).uniq + pluck(:credit_account_id).uniq)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Accounts with balances
|
103
|
+
#
|
104
|
+
# @returns [Hash] with involved accounts as keys and balances as values
|
105
|
+
def self.balances
|
106
|
+
account_balances = accounts.map do |account|
|
107
|
+
[account, balance_by(account)]
|
108
|
+
end
|
109
|
+
|
110
|
+
Hash[account_balances]
|
111
|
+
end
|
112
|
+
|
113
|
+
# Accounted bookings
|
114
|
+
# ==================
|
115
|
+
SELECT_ACCOUNTED_AMOUNT=
|
116
|
+
'CASE WHEN credit_account_id = debit_account_id THEN 0.0 WHEN credit_account_id = %{account_id} THEN -bookings.amount WHEN debit_account_id = %{account_id} THEN bookings.amount ELSE 0 END'
|
117
|
+
|
118
|
+
private
|
119
|
+
def self.get_account_id(account_or_id)
|
120
|
+
if account_or_id.is_a? Account
|
121
|
+
return account_or_id.id
|
122
|
+
elsif Account.exists?(account_or_id)
|
123
|
+
return account_or_id
|
124
|
+
else
|
125
|
+
raise "argument needs to be a record of type Account or an id for an existing Account record."
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
public
|
130
|
+
|
131
|
+
# Scope where booking amounts are signed according to debit or credit side
|
132
|
+
#
|
133
|
+
# @param account_or_id Account id or object
|
134
|
+
scope :accounted_by, lambda {|account_or_id|
|
135
|
+
select("bookings.*, #{SELECT_ACCOUNTED_AMOUNT % {:account_id => get_account_id(account_or_id)}} AS amount")
|
136
|
+
}
|
137
|
+
|
138
|
+
# Balance of bookings for the specified account
|
139
|
+
#
|
140
|
+
# @param account_or_id Account id or object
|
141
|
+
def self.balance_by(account_or_id)
|
142
|
+
BigDecimal.new(sum(SELECT_ACCOUNTED_AMOUNT % {:account_id => get_account_id(account_or_id)}), 2)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Balance of bookings for the specified account with 0 balance, grouped by reference
|
146
|
+
#
|
147
|
+
# @param account_or_id Account id or object
|
148
|
+
def self.unbalanced_by_grouped_reference(account_or_id)
|
149
|
+
# Do a manual sum using select() to be able to give it an alias we can use in having()
|
150
|
+
summs = group(:reference_type, :reference_id).having("balance != 0.0").select("sum(#{SELECT_ACCOUNTED_AMOUNT % {:account_id => get_account_id(account_or_id)}}) AS balance, reference_type, reference_id")
|
151
|
+
|
152
|
+
# Simulate Rails grouped summing result format
|
153
|
+
grouped = Hash[summs.map{ |group| [[group[:reference_type], group[:reference_id]], group[:balance]] }]
|
154
|
+
|
155
|
+
# Convert value to BigDecimal
|
156
|
+
Hash[grouped.map{|reference, value| [reference, BigDecimal.new(value, 2)] }]
|
157
|
+
end
|
158
|
+
|
159
|
+
# Balance of bookings for the specified account, grouped by reference
|
160
|
+
#
|
161
|
+
# @param account_or_id Account id or object
|
162
|
+
def self.balance_by_grouped_reference(account_or_id)
|
163
|
+
grouped = group(:reference_type, :reference_id).sum(SELECT_ACCOUNTED_AMOUNT % {:account_id => get_account_id(account_or_id)})
|
164
|
+
|
165
|
+
# Convert value to BigDecimal
|
166
|
+
Hash[grouped.map{|reference, value| [reference, BigDecimal.new(value, 2)] }]
|
167
|
+
end
|
168
|
+
|
92
169
|
scope :by_text, lambda {|value|
|
93
170
|
text = '%' + value + '%'
|
94
171
|
|
@@ -146,9 +223,9 @@ class Booking < ActiveRecord::Base
|
|
146
223
|
end
|
147
224
|
|
148
225
|
if account.is_asset_account?
|
149
|
-
return -(balance)
|
150
|
-
else
|
151
226
|
return balance
|
227
|
+
else
|
228
|
+
return -(balance)
|
152
229
|
end
|
153
230
|
end
|
154
231
|
|
@@ -47,8 +47,12 @@ class BookingTemplate < ActiveRecord::Base
|
|
47
47
|
|
48
48
|
# Tagging
|
49
49
|
# =======
|
50
|
-
|
51
|
-
|
50
|
+
if defined?(ActsAsTaggableOn) && ActsAsTaggableOn::Tag.table_exists?
|
51
|
+
acts_as_taggable
|
52
|
+
attr_accessible :tag_list
|
53
|
+
|
54
|
+
acts_as_taggable_on :include_in_saldo
|
55
|
+
end
|
52
56
|
|
53
57
|
def booking_parameters(params = {})
|
54
58
|
params = HashWithIndifferentAccess.new(params)
|
@@ -93,6 +97,7 @@ class BookingTemplate < ActiveRecord::Base
|
|
93
97
|
end
|
94
98
|
|
95
99
|
# Factory methods
|
100
|
+
# ===============
|
96
101
|
def build_booking(params = {})
|
97
102
|
Booking.new(booking_parameters(params))
|
98
103
|
end
|
@@ -101,8 +106,18 @@ class BookingTemplate < ActiveRecord::Base
|
|
101
106
|
Booking.create(booking_parameters(params))
|
102
107
|
end
|
103
108
|
|
109
|
+
# Build booking for template
|
110
|
+
#
|
111
|
+
# Raises an exception if template for given [code] cannot be found.
|
112
|
+
#
|
113
|
+
# @param code [String] to lookup template
|
114
|
+
# @param params [Hash] parameters to set on the Booking
|
115
|
+
# @return [Booking] unsaved Booking
|
104
116
|
def self.build_booking(code, params = {})
|
105
|
-
find_by_code(code)
|
117
|
+
template = find_by_code(code)
|
118
|
+
raise "BookingTemplate not found for '#{code}'" unless template
|
119
|
+
|
120
|
+
template.build_booking params
|
106
121
|
end
|
107
122
|
|
108
123
|
def self.create_booking(code, params = {})
|
@@ -148,9 +163,6 @@ class BookingTemplate < ActiveRecord::Base
|
|
148
163
|
line_item
|
149
164
|
end
|
150
165
|
|
151
|
-
# Tagging
|
152
|
-
acts_as_taggable_on :include_in_saldo
|
153
|
-
|
154
166
|
# Importer
|
155
167
|
# ========
|
156
168
|
attr_accessible :matcher
|
data/config/locales/en.yml
CHANGED
data/lib/has_accounts/railtie.rb
CHANGED
data/lib/has_accounts/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: has_accounts
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-02-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,32 +21,15 @@ dependencies:
|
|
21
21
|
version: '3.1'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
25
|
-
- !ruby/object:Gem::Dependency
|
26
|
-
name: has_vcards
|
27
|
-
requirement: &12391500 !ruby/object:Gem::Requirement
|
28
|
-
none: false
|
29
|
-
requirements:
|
30
|
-
- - ! '>='
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: '0'
|
33
|
-
type: :runtime
|
34
|
-
prerelease: false
|
35
|
-
version_requirements: *12391500
|
36
|
-
- !ruby/object:Gem::Dependency
|
37
|
-
name: acts-as-taggable-on
|
38
|
-
requirement: &12388840 !ruby/object:Gem::Requirement
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
39
25
|
none: false
|
40
26
|
requirements:
|
41
|
-
- -
|
27
|
+
- - ~>
|
42
28
|
- !ruby/object:Gem::Version
|
43
|
-
version: '
|
44
|
-
type: :runtime
|
45
|
-
prerelease: false
|
46
|
-
version_requirements: *12388840
|
29
|
+
version: '3.1'
|
47
30
|
- !ruby/object:Gem::Dependency
|
48
31
|
name: validates_timeliness
|
49
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
50
33
|
none: false
|
51
34
|
requirements:
|
52
35
|
- - ! '>='
|
@@ -54,18 +37,12 @@ dependencies:
|
|
54
37
|
version: '0'
|
55
38
|
type: :runtime
|
56
39
|
prerelease: false
|
57
|
-
version_requirements:
|
58
|
-
- !ruby/object:Gem::Dependency
|
59
|
-
name: inherited_resources
|
60
|
-
requirement: &12387640 !ruby/object:Gem::Requirement
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
61
41
|
none: false
|
62
42
|
requirements:
|
63
43
|
- - ! '>='
|
64
44
|
- !ruby/object:Gem::Version
|
65
45
|
version: '0'
|
66
|
-
type: :runtime
|
67
|
-
prerelease: false
|
68
|
-
version_requirements: *12387640
|
69
46
|
description: HasAccounts is a full featured Rails 3 gem providing models for financial
|
70
47
|
accounting.
|
71
48
|
email:
|
@@ -79,17 +56,16 @@ files:
|
|
79
56
|
- app/models/account.rb
|
80
57
|
- app/models/account_scope_extension.rb
|
81
58
|
- app/models/account_type.rb
|
82
|
-
- app/models/bank.rb
|
83
|
-
- app/models/bank_account.rb
|
84
59
|
- app/models/booking.rb
|
85
60
|
- app/models/booking_template.rb
|
86
61
|
- config/locales/de.yml
|
87
62
|
- config/locales/en.yml
|
88
63
|
- db/migrate/20111108000000_create_has_accounts_tables.rb
|
89
64
|
- db/migrate/20111109093857_use_string_for_account_number.rb
|
90
|
-
- db/migrate/20111230121259_bank_now_inherits_from_person.rb
|
91
65
|
- db/migrate/20111230222702_add_template_to_bookings.rb
|
92
66
|
- db/migrate/20130707121400_create_booking_templates.rb
|
67
|
+
- db/migrate/20131021123821_change_bookings_amount_to_use_decimal_scope.rb
|
68
|
+
- db/migrate/20131105212025_add_index_on_account_parent_id.rb
|
93
69
|
- lib/has_accounts.rb
|
94
70
|
- lib/has_accounts/class_methods.rb
|
95
71
|
- lib/has_accounts/core_ext/rounding.rb
|
@@ -119,7 +95,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
119
95
|
version: '0'
|
120
96
|
requirements: []
|
121
97
|
rubyforge_project:
|
122
|
-
rubygems_version: 1.8.
|
98
|
+
rubygems_version: 1.8.23
|
123
99
|
signing_key:
|
124
100
|
specification_version: 3
|
125
101
|
summary: HasAccounts provides models for financial accounting.
|
data/app/models/bank.rb
DELETED
data/app/models/bank_account.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
class LegacyBank < ActiveRecord::Base
|
2
|
-
set_table_name 'banks'
|
3
|
-
end
|
4
|
-
|
5
|
-
class BankNowInheritsFromPerson < ActiveRecord::Migration
|
6
|
-
def up
|
7
|
-
add_column :people, :swift, :string
|
8
|
-
add_column :people, :clearing, :string
|
9
|
-
|
10
|
-
for bank in LegacyBank.all
|
11
|
-
vcard = Vcard.where(:object_type => 'Bank', :object_id => bank.id).first
|
12
|
-
person = Bank.create!(
|
13
|
-
:vcard => vcard,
|
14
|
-
:swift => bank.swift,
|
15
|
-
:clearing => bank.clearing
|
16
|
-
)
|
17
|
-
|
18
|
-
if vcard
|
19
|
-
vcard.object = person
|
20
|
-
vcard.save!
|
21
|
-
else
|
22
|
-
person.build_vcard.save
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
drop_table :banks
|
27
|
-
end
|
28
|
-
end
|