death_and_taxes 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/config/ca.yml +33 -0
- data/lib/death_and_taxes/country.rb +37 -0
- data/lib/death_and_taxes/state.rb +37 -0
- data/lib/death_and_taxes/tax.rb +7 -0
- data/lib/death_and_taxes/tax_info.rb +27 -0
- data/lib/death_and_taxes/tax_version.rb +17 -0
- data/lib/death_and_taxes/taxable.rb +6 -1
- data/lib/death_and_taxes/version.rb +1 -1
- data/lib/death_and_taxes.rb +18 -4
- metadata +67 -38
data/config/ca.yml
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
taxes:
|
2
|
+
GST:
|
3
|
+
versions:
|
4
|
+
- starts: 2011-01-01
|
5
|
+
ends: 2011-12-31
|
6
|
+
percentage: 5
|
7
|
+
|
8
|
+
states:
|
9
|
+
qc:
|
10
|
+
rules:
|
11
|
+
same_state: [GST, QST]
|
12
|
+
same_country: GST
|
13
|
+
taxes:
|
14
|
+
QST:
|
15
|
+
apply_on: GST
|
16
|
+
versions:
|
17
|
+
- starts: 2011-01-01
|
18
|
+
ends: 2011-12-31
|
19
|
+
percentage: 8.5
|
20
|
+
|
21
|
+
- starts: 2012-01-01
|
22
|
+
ends: 2012-12-31
|
23
|
+
percentage: 9.5
|
24
|
+
|
25
|
+
on:
|
26
|
+
rules:
|
27
|
+
same_country: HST
|
28
|
+
taxes:
|
29
|
+
HST:
|
30
|
+
versions:
|
31
|
+
- starts: 2011-01-01
|
32
|
+
ends: 2012-12-31
|
33
|
+
percentage: 5
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module DeathAndTaxes
|
2
|
+
class Country
|
3
|
+
|
4
|
+
def initialize code, yml = nil
|
5
|
+
@taxes = {}
|
6
|
+
@states = {}
|
7
|
+
@code = code
|
8
|
+
parse yml if yml
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse yml
|
12
|
+
yml['taxes'].each do |tax_name, infos|
|
13
|
+
@taxes[tax_name] = TaxInfo.new(tax_name, infos)
|
14
|
+
end
|
15
|
+
|
16
|
+
yml['states'].each do |state_code, state_yml|
|
17
|
+
@states[state_code] = State.new(state_code, state_yml)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def applicable_taxes from, to, date
|
22
|
+
if from[:country] == to[:country] && to[:country] == @code
|
23
|
+
@states[from[:state]].applicable_taxes to[:state], date
|
24
|
+
else
|
25
|
+
[]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def applies_taxes? from, to, date
|
30
|
+
applicable_taxes(from, to, date).any?
|
31
|
+
end
|
32
|
+
|
33
|
+
def build_tax tax, date
|
34
|
+
@taxes[tax].try(:build, date) || @states.map{|t, s| s.build_tax(tax, date)}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module DeathAndTaxes
|
2
|
+
class State
|
3
|
+
|
4
|
+
def initialize code, yml = nil
|
5
|
+
@taxes = {}
|
6
|
+
@code = code
|
7
|
+
parse yml if yml
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse yml
|
11
|
+
##
|
12
|
+
# Builds a tax list for each taxes defined in this state
|
13
|
+
yml['taxes'].each do |tax_name, infos|
|
14
|
+
@taxes[tax_name] = TaxInfo.new(tax_name, infos)
|
15
|
+
end
|
16
|
+
|
17
|
+
@rules = yml['rules']
|
18
|
+
end
|
19
|
+
|
20
|
+
def applicable_taxes to_state, date
|
21
|
+
taxes = if to_state == @code && @rules['same_state']
|
22
|
+
@rules['same_state']
|
23
|
+
elsif @rules['same_country']
|
24
|
+
@rules['same_country']
|
25
|
+
else
|
26
|
+
[]
|
27
|
+
end
|
28
|
+
[taxes].flatten
|
29
|
+
end
|
30
|
+
|
31
|
+
def build_tax tax, date
|
32
|
+
if i = @taxes[tax] && i.cover?(date)
|
33
|
+
i.build(date)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/death_and_taxes/tax.rb
CHANGED
@@ -3,6 +3,9 @@ module DeathAndTaxes
|
|
3
3
|
belongs_to :taxer, :polymorphic => true
|
4
4
|
belongs_to :tax, :foreign_key => :apply_on_tax
|
5
5
|
|
6
|
+
validates :percentage, :numericality => {:greater_than => 0.01, :less_than => 100}, :format => /^\d+??(?:\.\d*)?$/, :presence => true
|
7
|
+
validates_presence_of :name
|
8
|
+
|
6
9
|
def apply amount
|
7
10
|
amount * multiplier
|
8
11
|
end
|
@@ -10,5 +13,9 @@ module DeathAndTaxes
|
|
10
13
|
def multiplier
|
11
14
|
(percentage / 100) * (1 + tax.try(:multiplier).to_f)
|
12
15
|
end
|
16
|
+
|
17
|
+
def blank?
|
18
|
+
percentage.blank? && name.blank? && account_number.blank?
|
19
|
+
end
|
13
20
|
end
|
14
21
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module DeathAndTaxes
|
2
|
+
class TaxInfo
|
3
|
+
def initialize name, yml = nil
|
4
|
+
@name = name
|
5
|
+
parse yml if yml
|
6
|
+
end
|
7
|
+
|
8
|
+
def parse yml
|
9
|
+
@apply_on = yml['apply_on']
|
10
|
+
@versions = yml['versions'].collect do |version|
|
11
|
+
TaxVersion.new(version)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def cover? date
|
16
|
+
@versions.any?{ |version| v.cover? date }
|
17
|
+
end
|
18
|
+
|
19
|
+
def build date
|
20
|
+
if v = @versions.detect{ |v| v.cover?(date) }
|
21
|
+
t = Tax.new :name => @name, :percentage => v['percentage']
|
22
|
+
t.tax = DeathAndTaxes.build_tax(@apply_on, date) if @apply_on
|
23
|
+
t
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -22,6 +22,11 @@ module DeathAndTaxes
|
|
22
22
|
|
23
23
|
include DeathAndTaxes::Taxable::InstanceMethods
|
24
24
|
end
|
25
|
+
|
26
|
+
def calculate_rate taxes
|
27
|
+
taxes.reduce(1) { |rate, tax| rate + tax.apply(1) }
|
28
|
+
end
|
29
|
+
|
25
30
|
end
|
26
31
|
|
27
32
|
module InstanceMethods
|
@@ -29,7 +34,7 @@ module DeathAndTaxes
|
|
29
34
|
taxes = [taxes] unless taxes.is_a? Array
|
30
35
|
|
31
36
|
self.taxations = taxes.collect do |tax|
|
32
|
-
Taxation.new :amount => tax.apply(amount), :percentage => tax.
|
37
|
+
Taxation.new :amount => tax.apply(amount), :percentage => tax.percentage, :name => tax.name, :account_number => tax.account_number
|
33
38
|
end
|
34
39
|
end
|
35
40
|
end
|
data/lib/death_and_taxes.rb
CHANGED
@@ -3,11 +3,25 @@ require 'active_record/version'
|
|
3
3
|
|
4
4
|
require 'active_support/core_ext'
|
5
5
|
|
6
|
-
|
7
|
-
require File.join(File.dirname(__FILE__), 'death_and_taxes/railtie')
|
6
|
+
require File.join(File.dirname(__FILE__), 'death_and_taxes', 'railtie')
|
8
7
|
|
9
8
|
module DeathAndTaxes
|
10
|
-
%w( Tax Taxable Taxation Taxer ).each do |class_name|
|
11
|
-
autoload class_name.to_sym, File.join(File.dirname(__FILE__), "death_and_taxes/#{class_name.
|
9
|
+
%w( Country State Tax Taxable Taxation Taxer TaxInfo TaxVersion ).each do |class_name|
|
10
|
+
autoload class_name.to_sym, File.join(File.dirname(__FILE__), "death_and_taxes/#{class_name.underscore}")
|
11
|
+
end
|
12
|
+
|
13
|
+
Dir[File.join(File.dirname(__FILE__), '..', 'config', '*.yml')].each do |filename|
|
14
|
+
country_code = filename.match(/\W(?<country_code>[a-z]+)\.yml/)[:country_code]
|
15
|
+
@countries = {}
|
16
|
+
@countries[country_code] = Country.new( country_code, YAML::load_file(filename) )
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.applicable_taxes from, to, date = nil
|
20
|
+
date ||= Date.today
|
21
|
+
@countries.map{ |code, country| country.applicable_taxes(from, to, date)}.flatten.compact
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.build tax, date
|
25
|
+
@countries.detect {|code, country| country.build_tax(tax, date)}
|
12
26
|
end
|
13
27
|
end
|
metadata
CHANGED
@@ -1,45 +1,60 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: death_and_taxes
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
6
11
|
platform: ruby
|
7
|
-
authors:
|
12
|
+
authors:
|
8
13
|
- Guillaume Malette
|
9
14
|
autorequire:
|
10
15
|
bindir: bin
|
11
16
|
cert_chain: []
|
12
|
-
|
17
|
+
|
18
|
+
date: 2011-08-09 00:00:00 -04:00
|
13
19
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
- !ruby/object:Gem::Dependency
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
16
22
|
name: rails
|
17
|
-
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
18
25
|
none: false
|
19
|
-
requirements:
|
20
|
-
- -
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
23
33
|
type: :runtime
|
24
|
-
|
25
|
-
|
26
|
-
- !ruby/object:Gem::Dependency
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
27
36
|
name: sqlite3
|
28
|
-
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
29
39
|
none: false
|
30
|
-
requirements:
|
31
|
-
- -
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
34
47
|
type: :development
|
35
|
-
|
36
|
-
version_requirements: *2152141280
|
48
|
+
version_requirements: *id002
|
37
49
|
description: Death and Taxes allows to 'easily' calculate taxes on a model
|
38
50
|
email: gmalette@gmail.com
|
39
51
|
executables: []
|
52
|
+
|
40
53
|
extensions: []
|
54
|
+
|
41
55
|
extra_rdoc_files: []
|
42
|
-
|
56
|
+
|
57
|
+
files:
|
43
58
|
- .document
|
44
59
|
- .gitignore
|
45
60
|
- Gemfile
|
@@ -47,10 +62,15 @@ files:
|
|
47
62
|
- LICENSE.txt
|
48
63
|
- README.rdoc
|
49
64
|
- Rakefile
|
65
|
+
- config/ca.yml
|
50
66
|
- death_and_taxes.gemspec
|
51
67
|
- lib/death_and_taxes.rb
|
68
|
+
- lib/death_and_taxes/country.rb
|
52
69
|
- lib/death_and_taxes/railtie.rb
|
70
|
+
- lib/death_and_taxes/state.rb
|
53
71
|
- lib/death_and_taxes/tax.rb
|
72
|
+
- lib/death_and_taxes/tax_info.rb
|
73
|
+
- lib/death_and_taxes/tax_version.rb
|
54
74
|
- lib/death_and_taxes/taxable.rb
|
55
75
|
- lib/death_and_taxes/taxation.rb
|
56
76
|
- lib/death_and_taxes/taxer.rb
|
@@ -60,30 +80,39 @@ files:
|
|
60
80
|
- test/helper.rb
|
61
81
|
- test/test_death_and_taxes.rb
|
62
82
|
has_rdoc: true
|
63
|
-
homepage:
|
83
|
+
homepage: ""
|
64
84
|
licenses: []
|
85
|
+
|
65
86
|
post_install_message:
|
66
87
|
rdoc_options: []
|
67
|
-
|
88
|
+
|
89
|
+
require_paths:
|
68
90
|
- lib
|
69
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
92
|
none: false
|
71
|
-
requirements:
|
72
|
-
- -
|
73
|
-
- !ruby/object:Gem::Version
|
74
|
-
|
75
|
-
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
hash: 3
|
97
|
+
segments:
|
98
|
+
- 0
|
99
|
+
version: "0"
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
101
|
none: false
|
77
|
-
requirements:
|
78
|
-
- -
|
79
|
-
- !ruby/object:Gem::Version
|
80
|
-
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
hash: 3
|
106
|
+
segments:
|
107
|
+
- 0
|
108
|
+
version: "0"
|
81
109
|
requirements: []
|
110
|
+
|
82
111
|
rubyforge_project:
|
83
|
-
rubygems_version: 1.
|
112
|
+
rubygems_version: 1.3.7
|
84
113
|
signing_key:
|
85
114
|
specification_version: 3
|
86
115
|
summary: Tax calculations
|
87
|
-
test_files:
|
116
|
+
test_files:
|
88
117
|
- test/helper.rb
|
89
118
|
- test/test_death_and_taxes.rb
|