valvat 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES.md CHANGED
@@ -1,10 +1,20 @@
1
1
  ### dev
2
2
 
3
- [full changelog](http://github.com/yolk/valvat/compare/v0.0.2...0.0.3)
3
+ [full changelog](http://github.com/yolk/valvat/compare/v0.1.0...master)
4
+
5
+ ### 0.1.0 / 2011-01-07
6
+
7
+ [full changelog](http://github.com/yolk/valvat/compare/v0.0.3...v0.1.0)
8
+
9
+ * ActiveModel validation: added optional lookup support
10
+ * ActiveModel validation: I18n support with country specific messages
11
+ * ActiveModel validation: I18n locales in english and german
12
+ * Fixed bug with wrong iso country code on greek vat number (EL != GR)
13
+ * Valvat::Util.split only returns countries from europe
4
14
 
5
15
  ### 0.0.3 / 2011-01-06
6
16
 
7
- [full changelog](http://github.com/yolk/valvat/compare/v0.0.1...v0.0.2)
17
+ [full changelog](http://github.com/yolk/valvat/compare/v0.0.2...v0.0.3)
8
18
 
9
19
  * Basic support for ActiveModel validation
10
20
 
data/lib/locale/de.yml ADDED
@@ -0,0 +1,34 @@
1
+ de:
2
+ errors:
3
+ messages:
4
+ invalid_vat: ist kein gültige %{country_adjective} UStId-Nr.
5
+ valvat:
6
+ country_adjectives:
7
+ eu: europäische
8
+ at: österreichische
9
+ be: belgische
10
+ bg: bulgarische
11
+ cy: zypriotische
12
+ cz: tschechische
13
+ de: deutsche
14
+ dk: dänische
15
+ ee: estnisch
16
+ es: spanisch
17
+ fi: finnische
18
+ fr: französische
19
+ gb: britische
20
+ gr: griechische
21
+ hu: ungarische
22
+ ie: irische
23
+ it: italienische
24
+ lt: litauisch
25
+ lu: luxemburgisch
26
+ lv: lettische
27
+ mt: malteser
28
+ nl: niederländische
29
+ pl: polnische
30
+ pt: portugiesische
31
+ ro: rumänische
32
+ se: schwedische
33
+ si: slowenische
34
+ sk: slowakische
data/lib/locale/en.yml ADDED
@@ -0,0 +1,34 @@
1
+ en:
2
+ errors:
3
+ messages:
4
+ invalid_vat: is not a valid %{country_adjective} vat number
5
+ valvat:
6
+ country_adjectives:
7
+ eu: european
8
+ at: austrian
9
+ be: belgian
10
+ bg: bulgarian
11
+ cy: cypriot
12
+ cz: czech
13
+ de: german
14
+ dk: danish
15
+ ee: estonian
16
+ es: spanish
17
+ fi: finnish
18
+ fr: french
19
+ gb: british
20
+ gr: greek
21
+ hu: hungarian
22
+ ie: irish
23
+ it: italian
24
+ lt: lithuanian
25
+ lu: luxembourg
26
+ lv: latvian
27
+ mt: maltese
28
+ nl: dutch
29
+ pl: polish
30
+ pt: portuguese
31
+ ro: rumanian
32
+ se: swedish
33
+ si: slovenian
34
+ sk: slovakian
@@ -1,7 +1,31 @@
1
- class ValvatValidator < ::ActiveModel::EachValidator
2
- def validate_each(record, attribute, value)
3
- unless Valvat::Syntax.validate(value)
4
- record.errors.add(attribute, options[:message])
1
+ require 'active_model'
2
+ require 'valvat/syntax'
3
+ require 'valvat/lookup'
4
+
5
+ module ActiveModel
6
+ module Validations
7
+ class ValvatValidator < ::ActiveModel::EachValidator
8
+
9
+ def validate_each(record, attribute, value)
10
+ is_valid = Valvat::Syntax.validate(value)
11
+
12
+ if is_valid && options[:lookup]
13
+ is_valid = Valvat::Lookup.validate(value)
14
+ is_valid.nil? && is_valid = (options[:lookup] != :fail_if_down)
15
+ end
16
+
17
+ unless is_valid
18
+ record.errors.add(attribute, :invalid_vat,
19
+ :message => options[:message],
20
+ :country_adjective => I18n.t(
21
+ :"valvat.country_adjectives.#{(Valvat::Utils.split(value)[0] || "eu").downcase}",
22
+ :default => [:"valvat.country_adjectives.eu", "european"]
23
+ )
24
+ )
25
+ end
26
+ end
5
27
  end
6
28
  end
7
- end
29
+ end
30
+
31
+ I18n.load_path << File.dirname(__FILE__) + '/../locale/en.yml'
data/lib/valvat/syntax.rb CHANGED
@@ -1,8 +1,6 @@
1
1
  require 'valvat/utils'
2
2
 
3
3
  module Valvat
4
- class InvalidSyntax < StandardError;end
5
-
6
4
  module Syntax
7
5
 
8
6
  VAT_PATTERNS = {
@@ -14,7 +12,7 @@ module Valvat
14
12
  'DE' => /\ADE[0-9]{9}\Z/, # Germany
15
13
  'DK' => /\ADK[0-9]{8}\Z/, # Denmark
16
14
  'EE' => /\AEE[0-9]{9}\Z/, # Estonia
17
- 'EL' => /\AEL[0-9]{9}\Z/, # Greece
15
+ 'GR' => /\AEL[0-9]{9}\Z/, # Greece
18
16
  'ES' => /\AES([A-Z][0-9]{8}|[0-9]{8}[A-Z]|[A-Z][0-9]{7}[A-Z])\Z/, # Spain
19
17
  'FI' => /\AFI[0-9]{8}\Z/, # Finland
20
18
  'FR' => /\AFR[A-Z0-9]{2}[0-9]{9}\Z/, # France
@@ -39,10 +37,6 @@ module Valvat
39
37
  pattern = VAT_PATTERNS[Valvat::Utils.split(vat)[0]]
40
38
  !!(pattern && pattern =~ vat)
41
39
  end
42
-
43
- def self.validate!(vat)
44
- validate(vat) || raise(Valvat::InvalidSyntax.new("#{vat.inspect} is an invalid vat number!"))
45
- end
46
40
  end
47
41
 
48
42
  end
data/lib/valvat/utils.rb CHANGED
@@ -1,11 +1,15 @@
1
1
  module Valvat
2
2
  module Utils
3
3
 
4
+ EU_COUNTRIES = %w(AT BE BG CY CZ DE DK EE ES FI FR GB GR HU IE IT LT LU LV MT NL PL PT RO SE SI SK)
4
5
  COUNTRY_PATTERN = /\A([A-Z]{2})(.+)\Z/
5
6
 
6
7
  def self.split(vat)
7
8
  COUNTRY_PATTERN =~ vat
8
- [$1, $2]
9
+ result = [$1, $2]
10
+ result[0] = "GR" if result[0] == "EL"
11
+ return [nil, nil] unless EU_COUNTRIES.include?(result[0])
12
+ result
9
13
  end
10
14
 
11
15
  def self.normalize(vat)
@@ -1,3 +1,3 @@
1
1
  module Valvat
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -4,6 +4,22 @@ class Invoice < ModelBase
4
4
  validates :vat_number, :valvat => true
5
5
  end
6
6
 
7
+ class InvoiceWithLookup < ModelBase
8
+ validates :vat_number, :valvat => {:lookup => true}
9
+ end
10
+
11
+ class InvoiceWithLookupAndFailIfDown < ModelBase
12
+ validates :vat_number, :valvat => {:lookup => :fail_if_down}
13
+ end
14
+
15
+ class InvoiceAllowBlank < ModelBase
16
+ validates :vat_number, :valvat => {:allow_blank => true}
17
+ end
18
+
19
+ class InvoiceAllowBlankOnAll < ModelBase
20
+ validates :vat_number, :valvat => true, :allow_blank => true
21
+ end
22
+
7
23
  describe Invoice do
8
24
  context "with valid vat number" do
9
25
  before do
@@ -11,7 +27,7 @@ describe Invoice do
11
27
  end
12
28
 
13
29
  it "should be valid" do
14
- Invoice.new(:vat_number => "DE345889003").should be_valid
30
+ Invoice.new(:vat_number => "DE123").should be_valid
15
31
  end
16
32
  end
17
33
 
@@ -20,8 +36,125 @@ describe Invoice do
20
36
  Valvat::Syntax.stub(:validate => false)
21
37
  end
22
38
 
39
+ it "should not be valid" do
40
+ Invoice.new(:vat_number => "DE123").should_not be_valid
41
+ end
42
+
43
+ it "should add default (country specific) error message" do
44
+ i = Invoice.new(:vat_number => "DE123")
45
+ i.valid?
46
+ i.errors[:vat_number].should eql(["is not a valid german vat number"])
47
+ end
48
+
49
+ context "with i18n translation in place" do
50
+ before do
51
+ I18n.backend.store_translations(:en, :activemodel => {
52
+ :errors => {:models => {:invoice => {:invalid_vat => "is ugly."}}}
53
+ })
54
+ end
55
+
56
+ after { I18n.reload! }
57
+
58
+ it "should use translation" do
59
+ i = Invoice.new(:vat_number => "DE123")
60
+ i.valid?
61
+ i.errors[:vat_number].should eql(["is ugly."])
62
+ end
63
+ end
64
+
65
+ context "with i18n translation with country adjective placeholder in place" do
66
+ before do
67
+ I18n.backend.store_translations(:en, :activemodel => {
68
+ :errors => {:models => {:invoice => {:invalid_vat => "is not a %{country_adjective} vat"}}}
69
+ })
70
+ end
71
+
72
+ after { I18n.reload! }
73
+
74
+ it "should replace country adjective placeholder" do
75
+ i = Invoice.new(:vat_number => "IE123")
76
+ i.valid?
77
+ i.errors[:vat_number].should eql(["is not a irish vat"])
78
+ end
79
+
80
+ it "should fall back to 'european' if country is missing" do
81
+ i = Invoice.new(:vat_number => "XX123")
82
+ i.valid?
83
+ i.errors[:vat_number].should eql(["is not a european vat"])
84
+ end
85
+ end
86
+ end
87
+
88
+ context "with blank vat number" do
89
+ it "should not be valid" do
90
+ Invoice.new(:vat_number => "").should_not be_valid
91
+ Invoice.new(:vat_number => nil).should_not be_valid
92
+ end
93
+ end
94
+ end
95
+
96
+ describe InvoiceWithLookup do
97
+ context "with valid but not existing vat number" do
98
+ before do
99
+ Valvat::Syntax.stub(:validate => true)
100
+ Valvat::Lookup.stub(:validate => false)
101
+ end
102
+
103
+ it "should not be valid" do
104
+ InvoiceWithLookup.new(:vat_number => "DE123").should_not be_valid
105
+ end
106
+ end
107
+
108
+ context "with valid and existing vat number" do
109
+ before do
110
+ Valvat::Syntax.stub(:validate => true)
111
+ Valvat::Lookup.stub(:validate => true)
112
+ end
113
+
114
+ it "should be valid" do
115
+ InvoiceWithLookup.new(:vat_number => "DE123").should be_valid
116
+ end
117
+ end
118
+
119
+ context "with valid vat number and VIES country service down" do
120
+ before do
121
+ Valvat::Syntax.stub(:validate => true)
122
+ Valvat::Lookup.stub(:validate => nil)
123
+ end
124
+
125
+ it "should be valid" do
126
+ InvoiceWithLookup.new(:vat_number => "DE123").should be_valid
127
+ end
128
+ end
129
+ end
130
+
131
+ describe InvoiceWithLookupAndFailIfDown do
132
+ context "with valid vat number and VIES country service down" do
133
+ before do
134
+ Valvat::Syntax.stub(:validate => true)
135
+ Valvat::Lookup.stub(:validate => nil)
136
+ end
137
+
138
+ it "should not be valid" do
139
+ InvoiceWithLookupAndFailIfDown.new(:vat_number => "DE123").should_not be_valid
140
+ end
141
+ end
142
+ end
143
+
144
+ describe InvoiceAllowBlank do
145
+ context "with blank vat number" do
146
+ it "should be valid" do
147
+ InvoiceAllowBlank.new(:vat_number => "").should be_valid
148
+ InvoiceAllowBlank.new(:vat_number => nil).should be_valid
149
+ end
150
+ end
151
+ end
152
+
153
+ describe InvoiceAllowBlankOnAll do
154
+ context "with blank vat number" do
23
155
  it "should be valid" do
24
- Invoice.new(:vat_number => "DE345889003").should_not be_valid
156
+ InvoiceAllowBlankOnAll.new(:vat_number => "").should be_valid
157
+ InvoiceAllowBlankOnAll.new(:vat_number => nil).should be_valid
25
158
  end
26
159
  end
27
160
  end
@@ -267,14 +267,4 @@ describe Valvat::Syntax do
267
267
  Valvat::Syntax.validate("BEFR").should eql(false)
268
268
  end
269
269
  end
270
-
271
- context "#validate!" do
272
- it "returns true on valid vat number" do
273
- Valvat::Syntax.validate!("DE345889003").should eql(true)
274
- end
275
-
276
- it "raises Valvat::InvalidSyntax on invalid vat number" do
277
- lambda { Valvat::Syntax.validate!("DE34588900") }.should raise_error(Valvat::InvalidSyntax)
278
- end
279
- end
280
270
  end
@@ -4,7 +4,12 @@ describe Valvat::Utils do
4
4
  context "#split" do
5
5
  it "returns country and rest on vat number as array" do
6
6
  Valvat::Utils.split("DE345889003").should eql(["DE", "345889003"])
7
- Valvat::Utils.split("XY345889003").should eql(["XY", "345889003"])
7
+ Valvat::Utils.split("ESX4588900X").should eql(["ES", "X4588900X"])
8
+ end
9
+
10
+ it "returns two nils on non-european iso codes as array" do
11
+ Valvat::Utils.split("US345889003").should eql([nil, nil])
12
+ Valvat::Utils.split("RUX4588900X").should eql([nil, nil])
8
13
  end
9
14
 
10
15
  it "returns two nils on non-sense input as array" do
@@ -14,6 +19,10 @@ describe Valvat::Utils do
14
19
  Valvat::Utils.split("1234").should eql([nil, nil])
15
20
  Valvat::Utils.split(" ").should eql([nil, nil])
16
21
  end
22
+
23
+ it "returns GR on greek vat" do
24
+ Valvat::Utils.split("EL999999999").should eql(["GR", "999999999"])
25
+ end
17
26
  end
18
27
 
19
28
  context "#normalize" do
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
+ - 1
7
8
  - 0
8
- - 3
9
- version: 0.0.3
9
+ version: 0.1.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Sebastian Munz
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-01-06 00:00:00 +01:00
17
+ date: 2011-01-07 00:00:00 +01:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -109,6 +109,8 @@ files:
109
109
  - MIT-LICENSE
110
110
  - README.md
111
111
  - Rakefile
112
+ - lib/locale/de.yml
113
+ - lib/locale/en.yml
112
114
  - lib/valvat.rb
113
115
  - lib/valvat/active_model.rb
114
116
  - lib/valvat/lookup.rb