valvat 0.0.3 → 0.1.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/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