has_accounts 0.2.1 → 0.2.2
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 +9 -9
- data/app/models/account.rb +11 -3
- data/app/models/account.rb~ +113 -0
- metadata +4 -5
- data/lib/booking.rb~ +0 -92
- data/lib/has_accounts.rb~ +0 -3
data/README.md
CHANGED
@@ -9,7 +9,7 @@ Install
|
|
9
9
|
|
10
10
|
In Rails 3 simply add
|
11
11
|
|
12
|
-
|
12
|
+
gem 'has_accounts'
|
13
13
|
|
14
14
|
|
15
15
|
Example
|
@@ -17,24 +17,24 @@ Example
|
|
17
17
|
|
18
18
|
A few models are available:
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
class Booking
|
21
|
+
class Account
|
22
|
+
class AccountType
|
23
23
|
|
24
24
|
There's also a ready to use module available to attach accountable
|
25
25
|
functionality to existing models.
|
26
26
|
|
27
27
|
To use it, simply add the following to your Model:
|
28
28
|
|
29
|
-
|
29
|
+
include HasAccounts::Model
|
30
30
|
|
31
31
|
|
32
32
|
License
|
33
33
|
=======
|
34
34
|
|
35
|
-
Copyright (c) 2008 Agrabah <http://www.agrabah.ch>
|
36
|
-
Copyright (c) 2008-2011 Simon Hürlimann <simon.huerlimann@cyt.ch>
|
37
|
-
Copyright (c) 2010-2011 CyT <http://www.cyt.ch>
|
38
|
-
Copyright (c) 2008-2010 ZytoLabor <http://www.zyto-labor.com>
|
35
|
+
* Copyright (c) 2008 Agrabah <http://www.agrabah.ch>
|
36
|
+
* Copyright (c) 2008-2011 Simon Hürlimann <simon.huerlimann@cyt.ch>
|
37
|
+
* Copyright (c) 2010-2011 CyT <http://www.cyt.ch>
|
38
|
+
* Copyright (c) 2008-2010 ZytoLabor <http://www.zyto-labor.com>
|
39
39
|
|
40
40
|
Released under the MIT license.
|
data/app/models/account.rb
CHANGED
@@ -83,8 +83,16 @@ class Account < ActiveRecord::Base
|
|
83
83
|
}]
|
84
84
|
end
|
85
85
|
elsif
|
86
|
-
|
87
|
-
|
86
|
+
if selector.first == selector.last
|
87
|
+
condition = ["date(value_date) = :value_date", {
|
88
|
+
:value_date => selector.first
|
89
|
+
}]
|
90
|
+
else
|
91
|
+
condition = ["date(value_date) BETWEEN :first_value_date AND :latest_value_date", {
|
92
|
+
:first_value_date => selector.first,
|
93
|
+
:latest_value_date => selector.last
|
94
|
+
}]
|
95
|
+
end
|
88
96
|
end
|
89
97
|
else
|
90
98
|
if selector.is_a? Booking
|
@@ -93,7 +101,7 @@ class Account < ActiveRecord::Base
|
|
93
101
|
condition = ["(value_date < :value_date) OR (date(value_date) = :value_date AND id <#{equality} :id)", {:value_date => selector.value_date, :id => selector.id}]
|
94
102
|
else
|
95
103
|
equality = "=" if inclusive
|
96
|
-
condition = ["value_date <#{equality} ?", selector]
|
104
|
+
condition = ["date(value_date) <#{equality} ?", selector]
|
97
105
|
end
|
98
106
|
end
|
99
107
|
|
@@ -0,0 +1,113 @@
|
|
1
|
+
class Account < ActiveRecord::Base
|
2
|
+
# Scopes
|
3
|
+
default_scope :order => 'code'
|
4
|
+
|
5
|
+
# Dummy scope to make scoped_by happy
|
6
|
+
scope :by_value_period, scoped
|
7
|
+
|
8
|
+
# Validation
|
9
|
+
validates_presence_of :code, :title
|
10
|
+
|
11
|
+
# String
|
12
|
+
def to_s(format = :default)
|
13
|
+
"%s (%s)" % [title, code]
|
14
|
+
end
|
15
|
+
|
16
|
+
# Account Type
|
17
|
+
# ============
|
18
|
+
belongs_to :account_type
|
19
|
+
|
20
|
+
def is_asset_account?
|
21
|
+
[1, 2, 5].include? account_type_id
|
22
|
+
end
|
23
|
+
|
24
|
+
def is_liability_account?
|
25
|
+
[3, 4, 6].include? account_type_id
|
26
|
+
end
|
27
|
+
|
28
|
+
scope :current_assets, where('account_type_id = 1') do
|
29
|
+
include AccountScopeExtension
|
30
|
+
end
|
31
|
+
scope :capital_assets, where('account_type_id = 2') do
|
32
|
+
include AccountScopeExtension
|
33
|
+
end
|
34
|
+
scope :outside_capital, where('account_type_id = 3') do
|
35
|
+
include AccountScopeExtension
|
36
|
+
end
|
37
|
+
scope :equity_capital, where('account_type_id = 4') do
|
38
|
+
include AccountScopeExtension
|
39
|
+
end
|
40
|
+
scope :expenses, where('account_type_id = 5') do
|
41
|
+
include AccountScopeExtension
|
42
|
+
end
|
43
|
+
scope :earnings, where('account_type_id = 6') do
|
44
|
+
include AccountScopeExtension
|
45
|
+
end
|
46
|
+
|
47
|
+
# Holder
|
48
|
+
# ======
|
49
|
+
belongs_to :holder, :polymorphic => true
|
50
|
+
|
51
|
+
# Bookings
|
52
|
+
# ========
|
53
|
+
has_many :credit_bookings, :class_name => "Booking", :foreign_key => "credit_account_id"
|
54
|
+
has_many :debit_bookings, :class_name => "Booking", :foreign_key => "debit_account_id"
|
55
|
+
|
56
|
+
def bookings
|
57
|
+
Booking.by_account(id)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Helpers
|
61
|
+
# =======
|
62
|
+
def self.overview(value_range = Date.today, format = :default)
|
63
|
+
Account.all.map{|a| a.to_s(value_range, format)}
|
64
|
+
end
|
65
|
+
|
66
|
+
# Calculations
|
67
|
+
def turnover(selector = Date.today, inclusive = true)
|
68
|
+
if selector.is_a? Range or selector.is_a? Array
|
69
|
+
if selector.first.is_a? Booking
|
70
|
+
equality = "=" if inclusive
|
71
|
+
if selector.first.value_date == selector.last.value_date
|
72
|
+
condition = ["date(value_date) = :value_date AND id >#{equality} :first_id AND id <#{equality} :last_id", {
|
73
|
+
:value_date => selector.first.value_date,
|
74
|
+
:first_id => selector.first.id,
|
75
|
+
:last_id => selector.last.id
|
76
|
+
}]
|
77
|
+
else
|
78
|
+
condition = ["(value_date > :first_value_date AND value_date < :latest_value_date) OR (date(value_date) = :first_value_date AND id >#{equality} :first_id) OR (date(value_date) = :latest_value_date AND id <#{equality} :last_id)", {
|
79
|
+
:first_value_date => selector.first.value_date,
|
80
|
+
:latest_value_date => selector.last.value_date,
|
81
|
+
:first_id => selector.first.id,
|
82
|
+
:last_id => selector.last.id
|
83
|
+
}]
|
84
|
+
end
|
85
|
+
elsif
|
86
|
+
# TODO support inclusive param
|
87
|
+
condition = {:value_date => selector}
|
88
|
+
end
|
89
|
+
else
|
90
|
+
if selector.is_a? Booking
|
91
|
+
equality = "=" if inclusive
|
92
|
+
# date(value_date) is needed on sqlite!
|
93
|
+
condition = ["(value_date < :value_date) OR (date(value_date) = :value_date AND id <#{equality} :id)", {:value_date => selector.value_date, :id => selector.id}]
|
94
|
+
else
|
95
|
+
equality = "=" if inclusive
|
96
|
+
condition = ["value_date <#{equality} ?", selector]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
credit_amount = credit_bookings.where(condition).sum(:amount)
|
101
|
+
debit_amount = debit_bookings.where(condition).sum(:amount)
|
102
|
+
|
103
|
+
[credit_amount || 0.0, debit_amount || 0.0]
|
104
|
+
end
|
105
|
+
|
106
|
+
def saldo(selector = Date.today, inclusive = true)
|
107
|
+
credit_amount, debit_amount = turnover(selector, inclusive)
|
108
|
+
|
109
|
+
amount = credit_amount - debit_amount
|
110
|
+
|
111
|
+
return is_asset_account? ? amount : -amount
|
112
|
+
end
|
113
|
+
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 2
|
8
|
-
-
|
9
|
-
version: 0.2.
|
8
|
+
- 2
|
9
|
+
version: 0.2.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- "Simon H\xC3\xBCrlimann (CyT)"
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-04-
|
17
|
+
date: 2011-04-12 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|
@@ -28,15 +28,14 @@ extensions: []
|
|
28
28
|
extra_rdoc_files: []
|
29
29
|
|
30
30
|
files:
|
31
|
+
- app/models/account.rb~
|
31
32
|
- app/models/account_scope_extension.rb
|
32
33
|
- app/models/bank.rb
|
33
34
|
- app/models/account.rb
|
34
35
|
- app/models/booking.rb
|
35
36
|
- app/models/account_type.rb
|
36
37
|
- app/models/bank_account.rb
|
37
|
-
- lib/has_accounts.rb~
|
38
38
|
- lib/has_accounts.rb
|
39
|
-
- lib/booking.rb~
|
40
39
|
- lib/has_accounts/class_methods.rb
|
41
40
|
- lib/has_accounts/railtie.rb~
|
42
41
|
- lib/has_accounts/core_ext/rounding.rb~
|
data/lib/booking.rb~
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
class Booking < ActiveRecord::Base
|
2
|
-
# Validation
|
3
|
-
validates_presence_of :debit_account, :credit_account, :title, :amount, :value_date
|
4
|
-
validates_time :value_date
|
5
|
-
|
6
|
-
belongs_to :debit_account, :foreign_key => 'debit_account_id', :class_name => "Account"
|
7
|
-
belongs_to :credit_account, :foreign_key => 'credit_account_id', :class_name => "Account"
|
8
|
-
|
9
|
-
# Scoping
|
10
|
-
named_scope :by_value_date, lambda {|value_date| { :conditions => { :value_date => value_date } } }
|
11
|
-
named_scope :by_value_period, lambda {|from, to| { :conditions => { :value_date => from..to } } }
|
12
|
-
|
13
|
-
named_scope :by_account, lambda {|account_id|
|
14
|
-
{ :conditions => ["debit_account_id = :account_id OR credit_account_id = :account_id", {:account_id => account_id}] }
|
15
|
-
} do
|
16
|
-
# Returns array of all booking titles.
|
17
|
-
def titles
|
18
|
-
find(:all, :group => :title).map{|booking| booking.title}
|
19
|
-
end
|
20
|
-
|
21
|
-
# Statistics per booking title.
|
22
|
-
#
|
23
|
-
# The statistics are an array of hashes with keys title, count, sum, average.
|
24
|
-
def statistics
|
25
|
-
find(:all, :select => "title, count(*) AS count, sum(amount) AS sum, avg(amount) AS avg", :group => :title).map{|stat| stat.attributes}
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
# Returns array of all years we have bookings for
|
30
|
-
def self.fiscal_years
|
31
|
-
with_exclusive_scope do
|
32
|
-
find(:all, :select => "year(value_date) AS year", :group => "year(value_date)").map{|booking| booking.year}
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def self.scope_by_value_date(value_date)
|
37
|
-
scoping = self.default_scoping - [@by_value_scope]
|
38
|
-
|
39
|
-
@by_value_scope = {:find => {:conditions => {:value_date => value_date}}}
|
40
|
-
scoping << @by_value_scope
|
41
|
-
|
42
|
-
Thread.current["#{self}_scoped_methods"] = nil
|
43
|
-
self.default_scoping = scoping
|
44
|
-
end
|
45
|
-
|
46
|
-
def self.filter(controller, &block)
|
47
|
-
if controller.value_date_scope
|
48
|
-
with_scope(:find => {:conditions => {:value_date => controller.value_date_scope}}, &block)
|
49
|
-
else
|
50
|
-
block.call
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
# Standard methods
|
55
|
-
def to_s(format = :default)
|
56
|
-
case format
|
57
|
-
when :short
|
58
|
-
"#{value_date.strftime('%d.%m.%Y')}: #{credit_account.code} / #{debit_account.code} CHF #{amount_as_string} "
|
59
|
-
else
|
60
|
-
"#{value_date.strftime('%d.%m.%Y')}: #{credit_account.title} (#{credit_account.code}) an #{debit_account.title} (#{debit_account.code}) CHF #{amount_as_string}, #{title} " +
|
61
|
-
(comments.blank? ? "" :"(#{comments})")
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
# Helpers
|
66
|
-
def accounted_amount(account)
|
67
|
-
if credit_account == account
|
68
|
-
return amount
|
69
|
-
elsif debit_account == account
|
70
|
-
return -(amount)
|
71
|
-
else
|
72
|
-
return 0.0
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def amount_as_string
|
77
|
-
'%0.2f' % amount
|
78
|
-
end
|
79
|
-
|
80
|
-
def amount_as_string=(value)
|
81
|
-
self.amount = value
|
82
|
-
end
|
83
|
-
|
84
|
-
# Reference
|
85
|
-
belongs_to :reference, :polymorphic => true
|
86
|
-
after_save :notify_references
|
87
|
-
|
88
|
-
private
|
89
|
-
def notify_references
|
90
|
-
reference.booking_saved(self) if reference.respond_to?(:booking_saved)
|
91
|
-
end
|
92
|
-
end
|
data/lib/has_accounts.rb~
DELETED