valvat 0.9.1 → 1.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.gitignore +2 -1
- data/.travis.yml +30 -16
- data/CHANGES.md +13 -0
- data/Gemfile +2 -3
- data/README.md +90 -44
- data/gemfiles/activemodel-3-2 +3 -4
- data/gemfiles/activemodel-4 +3 -4
- data/gemfiles/activemodel-5 +4 -5
- data/gemfiles/activemodel-6 +7 -0
- data/gemfiles/before-ruby21/activemodel-3-2 +3 -4
- data/gemfiles/before-ruby21/activemodel-4 +3 -4
- data/gemfiles/before-ruby21/standalone +3 -4
- data/gemfiles/standalone +3 -5
- data/lib/active_model/validations/valvat_validator.rb +20 -5
- data/lib/valvat.rb +3 -1
- data/lib/valvat/checksum/gb.rb +30 -13
- data/lib/valvat/checksum/ie.rb +1 -1
- data/lib/valvat/error.rb +28 -0
- data/lib/valvat/locales/en.yml +1 -1
- data/lib/valvat/lookup.rb +11 -43
- data/lib/valvat/lookup/fault.rb +30 -0
- data/lib/valvat/lookup/request.rb +33 -12
- data/lib/valvat/lookup/response.rb +36 -0
- data/lib/valvat/version.rb +1 -1
- data/spec/active_model/validations/valvat_validator_spec.rb +66 -66
- data/spec/valvat/checksum/at_spec.rb +2 -2
- data/spec/valvat/checksum/be_spec.rb +2 -2
- data/spec/valvat/checksum/bg_spec.rb +2 -2
- data/spec/valvat/checksum/cy_spec.rb +2 -2
- data/spec/valvat/checksum/de_spec.rb +2 -2
- data/spec/valvat/checksum/dk_spec.rb +2 -2
- data/spec/valvat/checksum/ee_spec.rb +2 -2
- data/spec/valvat/checksum/es_spec.rb +2 -2
- data/spec/valvat/checksum/fi_spec.rb +2 -2
- data/spec/valvat/checksum/fr_spec.rb +2 -2
- data/spec/valvat/checksum/gb_spec.rb +5 -3
- data/spec/valvat/checksum/gr_spec.rb +2 -2
- data/spec/valvat/checksum/hr_spec.rb +2 -2
- data/spec/valvat/checksum/hu_spec.rb +2 -2
- data/spec/valvat/checksum/ie_spec.rb +8 -2
- data/spec/valvat/checksum/it_spec.rb +4 -4
- data/spec/valvat/checksum/lt_spec.rb +2 -2
- data/spec/valvat/checksum/lu_spec.rb +2 -2
- data/spec/valvat/checksum/mt_spec.rb +2 -2
- data/spec/valvat/checksum/nl_spec.rb +2 -2
- data/spec/valvat/checksum/pl_spec.rb +3 -3
- data/spec/valvat/checksum/pt_spec.rb +2 -2
- data/spec/valvat/checksum/ro_spec.rb +2 -2
- data/spec/valvat/checksum/se_spec.rb +3 -3
- data/spec/valvat/checksum/si_spec.rb +4 -4
- data/spec/valvat/checksum_spec.rb +2 -2
- data/spec/valvat/lockup/fault_spec.rb +32 -0
- data/spec/valvat/lockup/request_spec.rb +15 -0
- data/spec/valvat/lockup/response_spec.rb +27 -0
- data/spec/valvat/lookup_spec.rb +168 -35
- data/spec/valvat/syntax_spec.rb +29 -29
- data/spec/valvat/utils_spec.rb +6 -6
- data/spec/valvat_spec.rb +18 -18
- data/valvat.gemspec +1 -0
- metadata +29 -6
- metadata.gz.sig +0 -0
- data/lib/valvat/lookup/request_with_id.rb +0 -31
@@ -5,6 +5,20 @@ require 'valvat/lookup'
|
|
5
5
|
module ActiveModel
|
6
6
|
module Validations
|
7
7
|
class ValvatValidator < EachValidator
|
8
|
+
def initialize(options)
|
9
|
+
if options[:lookup]
|
10
|
+
options[:lookup] = if options[:lookup] == :fail_if_down
|
11
|
+
{fail_if_down: true}
|
12
|
+
elsif options[:lookup].is_a?(Hash)
|
13
|
+
options[:lookup]
|
14
|
+
else
|
15
|
+
{}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
super
|
20
|
+
end
|
21
|
+
|
8
22
|
def validate_each(record, attribute, value)
|
9
23
|
vat = Valvat(value)
|
10
24
|
iso_country_code = vat.iso_country_code
|
@@ -17,10 +31,10 @@ module ActiveModel
|
|
17
31
|
|
18
32
|
iso_country_code = "eu" if iso_country_code.blank?
|
19
33
|
record.errors.add(attribute, :invalid_vat,
|
20
|
-
:
|
21
|
-
:
|
34
|
+
message: options[:message],
|
35
|
+
country_adjective: I18n.t(
|
22
36
|
:"valvat.country_adjectives.#{iso_country_code.downcase}",
|
23
|
-
:
|
37
|
+
default: [:"valvat.country_adjectives.eu", "european"]
|
24
38
|
)
|
25
39
|
)
|
26
40
|
end
|
@@ -43,9 +57,10 @@ module ActiveModel
|
|
43
57
|
|
44
58
|
def vat_exists?(vat)
|
45
59
|
return true unless options[:lookup]
|
46
|
-
|
60
|
+
|
61
|
+
is_valid = vat.exists?(options[:lookup])
|
47
62
|
return is_valid unless is_valid.nil?
|
48
|
-
options[:lookup]
|
63
|
+
!options[:lookup][:fail_if_down]
|
49
64
|
end
|
50
65
|
end
|
51
66
|
end
|
data/lib/valvat.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
require 'valvat/error'
|
1
2
|
require 'valvat/local'
|
2
3
|
require 'valvat/lookup'
|
3
4
|
require 'valvat/lookup/request'
|
4
|
-
require 'valvat/lookup/
|
5
|
+
require 'valvat/lookup/response'
|
6
|
+
require 'valvat/lookup/fault'
|
5
7
|
require 'active_model/validations/valvat_validator' if defined?(ActiveModel)
|
6
8
|
|
7
9
|
class Valvat
|
data/lib/valvat/checksum/gb.rb
CHANGED
@@ -3,33 +3,50 @@ class Valvat
|
|
3
3
|
class GB < Base
|
4
4
|
OLD_FORMAT_FORBIDDEN_RANGES = [(100_000..999_999), (9_490_001..9_700_000), (9_990_001..9_999_999)]
|
5
5
|
NEW_FORMAT_FORBIDDEN_RANGES = [(1..100_000), (100_001..1_000_000)]
|
6
|
+
GOV_NUMBER = /\A(GD[0-4]{1}\d{2})\Z/
|
7
|
+
HEALTH_NUMBER = /\A(HA[5-9]{1}\d{2})\Z/
|
6
8
|
|
7
9
|
def validate
|
8
10
|
vat_number = vat.to_s_wo_country
|
9
|
-
check_sum = vat.to_s_wo_country[7..8].to_i
|
10
|
-
vat_base = vat_number[0..6]
|
11
11
|
|
12
12
|
# government departments and health authorities, so no checksum
|
13
|
-
return true if
|
14
|
-
return false if vat_number
|
13
|
+
return true if gov_or_health?(vat_number)
|
14
|
+
return false if all_zero?(vat_number)
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
inject(:+)
|
16
|
+
checksum = vat_number[7..8].to_i
|
17
|
+
vat_base = vat_number[0..6]
|
18
|
+
vat_base_int = vat_base.to_i
|
19
|
+
vat_base_sum = generate_vat_base_sum(vat_base)
|
21
20
|
|
22
|
-
old_format_remainder = (vat_base_sum +
|
23
|
-
new_format_remainder = (vat_base_sum + 55 +
|
21
|
+
old_format_remainder = (vat_base_sum + checksum).modulo(97)
|
22
|
+
new_format_remainder = (vat_base_sum + 55 + checksum).modulo(97)
|
24
23
|
|
25
24
|
return false if old_format_remainder == 0 &&
|
26
|
-
OLD_FORMAT_FORBIDDEN_RANGES.any? { |range| range.include?
|
25
|
+
OLD_FORMAT_FORBIDDEN_RANGES.any? { |range| range.include? vat_base_int }
|
27
26
|
|
28
27
|
return false if new_format_remainder == 0 &&
|
29
|
-
NEW_FORMAT_FORBIDDEN_RANGES.any? { |range| range.include?
|
28
|
+
NEW_FORMAT_FORBIDDEN_RANGES.any? { |range| range.include? vat_base_int }
|
30
29
|
|
31
30
|
old_format_remainder == 0 || new_format_remainder == 0
|
32
31
|
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def gov_or_health?(vat_number)
|
36
|
+
vat_number =~ GOV_NUMBER || vat_number =~ HEALTH_NUMBER
|
37
|
+
end
|
38
|
+
|
39
|
+
def all_zero?(vat_number)
|
40
|
+
vat_number =~ /\A0{9}\Z/ || vat_number =~ /\A0{12}\Z/
|
41
|
+
end
|
42
|
+
|
43
|
+
def generate_vat_base_sum(vat_base)
|
44
|
+
vat_base.split('').
|
45
|
+
map(&:to_i).
|
46
|
+
zip([8, 7, 6, 5, 4, 3, 2]).
|
47
|
+
map { |vat_number_digit, multiplier| vat_number_digit * multiplier }.
|
48
|
+
inject(:+)
|
49
|
+
end
|
33
50
|
end
|
34
51
|
end
|
35
52
|
end
|
data/lib/valvat/checksum/ie.rb
CHANGED
data/lib/valvat/error.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
class Valvat
|
2
|
+
Error = Class.new(RuntimeError)
|
3
|
+
|
4
|
+
class ViesError < Error
|
5
|
+
def initialize(faultstring='UNKOWN')
|
6
|
+
@faultstring = faultstring
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_s
|
10
|
+
"The VIES web service returned the error '#{@faultstring}'."
|
11
|
+
end
|
12
|
+
|
13
|
+
def eql?(other)
|
14
|
+
to_s.eql?(other.to_s)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
ViesMaintenanceError = Class.new(ViesError)
|
18
|
+
|
19
|
+
ServiceUnavailable = Class.new(ViesMaintenanceError)
|
20
|
+
MemberStateUnavailable = Class.new(ViesMaintenanceError)
|
21
|
+
|
22
|
+
Timeout = Class.new(ViesError)
|
23
|
+
InvalidRequester = Class.new(ViesError)
|
24
|
+
BlockedError = Class.new(ViesError)
|
25
|
+
RateLimitError = Class.new(ViesError)
|
26
|
+
|
27
|
+
UnknownViesError = Class.new(ViesError)
|
28
|
+
end
|
data/lib/valvat/locales/en.yml
CHANGED
data/lib/valvat/lookup.rb
CHANGED
@@ -1,36 +1,23 @@
|
|
1
|
-
require 'savon'
|
2
|
-
|
3
1
|
class Valvat
|
4
2
|
class Lookup
|
5
|
-
VIES_WSDL_URL = 'http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl'
|
6
|
-
REMOVE_KEYS = [:valid, :@xmlns]
|
7
|
-
|
8
|
-
attr_reader :vat, :options
|
9
3
|
|
10
4
|
def initialize(vat, options={})
|
11
5
|
@vat = Valvat(vat)
|
12
6
|
@options = options || {}
|
13
|
-
@options[:
|
7
|
+
@options[:requester] ||= @options[:requester_vat]
|
14
8
|
end
|
15
9
|
|
16
10
|
def validate
|
17
|
-
return false
|
11
|
+
return false if !@options[:skip_local_validation] && !@vat.valid?
|
12
|
+
return handle_vies_error(response[:error]) if response[:error]
|
18
13
|
|
19
|
-
valid
|
20
|
-
rescue => error
|
21
|
-
return false if invalid_input?(error)
|
22
|
-
raise error if options[:raise_error]
|
23
|
-
nil
|
14
|
+
response[:valid] && show_details? ? response.to_hash : response[:valid]
|
24
15
|
end
|
25
16
|
|
26
17
|
class << self
|
27
18
|
def validate(vat, options={})
|
28
19
|
new(vat, options).validate
|
29
20
|
end
|
30
|
-
|
31
|
-
def client
|
32
|
-
@client ||= Savon::Client.new(wsdl: VIES_WSDL_URL, log: false, follow_redirects: true)
|
33
|
-
end
|
34
21
|
end
|
35
22
|
|
36
23
|
private
|
@@ -40,37 +27,18 @@ class Valvat
|
|
40
27
|
end
|
41
28
|
|
42
29
|
def response
|
43
|
-
@response ||=
|
44
|
-
end
|
45
|
-
|
46
|
-
def request
|
47
|
-
if requester_vat
|
48
|
-
RequestWithId.new(vat, requester_vat)
|
49
|
-
else
|
50
|
-
Request.new(vat)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def requester_vat
|
55
|
-
options[:requester_vat]
|
56
|
-
end
|
57
|
-
|
58
|
-
def invalid_input?(err)
|
59
|
-
return if !err.respond_to?(:to_hash) || !err.to_hash[:fault]
|
60
|
-
(err.to_hash[:fault][:faultstring] || "").upcase =~ /INVALID_INPUT/
|
30
|
+
@response ||= Request.new(@vat, @options).perform
|
61
31
|
end
|
62
32
|
|
63
33
|
def show_details?
|
64
|
-
|
34
|
+
@options[:requester] || @options[:detail]
|
65
35
|
end
|
66
36
|
|
67
|
-
def
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
end
|
73
|
-
hash
|
37
|
+
def handle_vies_error(error)
|
38
|
+
if ViesMaintenanceError === error
|
39
|
+
raise error if @options[:raise_error]
|
40
|
+
else
|
41
|
+
raise error unless @options[:raise_error] == false
|
74
42
|
end
|
75
43
|
end
|
76
44
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Valvat
|
2
|
+
class Lookup
|
3
|
+
class Fault < Response
|
4
|
+
private
|
5
|
+
|
6
|
+
def self.cleanup(hash)
|
7
|
+
fault = hash[:fault][:faultstring]
|
8
|
+
return {valid: false} if fault == "INVALID_INPUT"
|
9
|
+
{error: fault_to_error(fault)}
|
10
|
+
end
|
11
|
+
|
12
|
+
FAULTS = {
|
13
|
+
"SERVICE_UNAVAILABLE" => ServiceUnavailable,
|
14
|
+
"MS_UNAVAILABLE" => MemberStateUnavailable,
|
15
|
+
"INVALID_REQUESTER_INFO" => InvalidRequester,
|
16
|
+
"TIMEOUT" => Timeout,
|
17
|
+
"VAT_BLOCKED" => BlockedError,
|
18
|
+
"IP_BLOCKED" => BlockedError,
|
19
|
+
"GLOBAL_MAX_CONCURRENT_REQ" => RateLimitError,
|
20
|
+
"GLOBAL_MAX_CONCURRENT_REQ_TIME" => RateLimitError,
|
21
|
+
"MS_MAX_CONCURRENT_REQ" => RateLimitError,
|
22
|
+
"MS_MAX_CONCURRENT_REQ_TIME" => RateLimitError
|
23
|
+
}
|
24
|
+
|
25
|
+
def self.fault_to_error(fault)
|
26
|
+
(FAULTS[fault] || UnknownViesError).new(fault)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -1,30 +1,51 @@
|
|
1
|
+
require 'savon'
|
2
|
+
|
1
3
|
class Valvat
|
2
4
|
class Lookup
|
3
5
|
class Request
|
4
|
-
|
5
|
-
|
6
|
+
VIES_WSDL_URL = 'https://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl'
|
7
|
+
|
8
|
+
def initialize(vat, options)
|
9
|
+
@vat = Valvat(vat)
|
10
|
+
@options = options || {}
|
11
|
+
@requester = @options[:requester] && Valvat(@options[:requester])
|
6
12
|
end
|
7
13
|
|
8
|
-
def perform
|
9
|
-
|
14
|
+
def perform
|
15
|
+
begin
|
16
|
+
Response.new(
|
17
|
+
client.call(action, message: message, message_tag: message_tag)
|
18
|
+
)
|
19
|
+
rescue Savon::SOAPFault => fault
|
20
|
+
Fault.new(fault)
|
21
|
+
end
|
10
22
|
end
|
11
23
|
|
12
24
|
private
|
13
25
|
|
14
|
-
def
|
15
|
-
{
|
26
|
+
def client
|
27
|
+
Savon::Client.new({
|
28
|
+
wsdl: VIES_WSDL_URL, log: false, follow_redirects: true
|
29
|
+
}.merge(@options[:savon] || {}))
|
16
30
|
end
|
17
31
|
|
18
|
-
def
|
19
|
-
|
32
|
+
def message
|
33
|
+
{
|
34
|
+
country_code: @vat.vat_country_code,
|
35
|
+
vat_number: @vat.to_s_wo_country
|
36
|
+
}.merge(@requester ? {
|
37
|
+
requester_country_code: @requester.vat_country_code,
|
38
|
+
requester_vat_number: @requester.to_s_wo_country
|
39
|
+
} : {}
|
40
|
+
)
|
20
41
|
end
|
21
42
|
|
22
|
-
def
|
23
|
-
:
|
43
|
+
def message_tag
|
44
|
+
@requester ? :checkVatApprox : :checkVat
|
24
45
|
end
|
25
46
|
|
26
|
-
def
|
27
|
-
:
|
47
|
+
def action
|
48
|
+
@requester ? :check_vat_approx : :check_vat
|
28
49
|
end
|
29
50
|
end
|
30
51
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class Valvat
|
2
|
+
class Lookup
|
3
|
+
class Response
|
4
|
+
def initialize(raw)
|
5
|
+
@raw = raw
|
6
|
+
end
|
7
|
+
|
8
|
+
def [](key)
|
9
|
+
to_hash[key]
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_hash
|
13
|
+
@hash ||= self.class.cleanup(@raw.to_hash)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def self.cleanup(hash)
|
19
|
+
(hash[:check_vat_approx_response] || hash[:check_vat_response] || {}).inject({}) do |hash, (key, value)|
|
20
|
+
hash[cleanup_key(key)] = cleanup_value(value) unless key == :"@xmlns"
|
21
|
+
hash
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
TRADER_PREFIX = /\Atrader_/
|
26
|
+
|
27
|
+
def self.cleanup_key(key)
|
28
|
+
key.to_s.sub(TRADER_PREFIX, "").to_sym
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.cleanup_value(value)
|
32
|
+
value == "---" ? nil : value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/valvat/version.rb
CHANGED
@@ -2,27 +2,27 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
if defined?(ActiveModel)
|
4
4
|
class Invoice < ModelBase
|
5
|
-
validates :vat_number, :
|
5
|
+
validates :vat_number, valvat: true
|
6
6
|
end
|
7
7
|
|
8
8
|
class InvoiceWithLookup < ModelBase
|
9
|
-
validates :vat_number, :
|
9
|
+
validates :vat_number, valvat: {lookup: true}
|
10
10
|
end
|
11
11
|
|
12
12
|
class InvoiceWithLookupAndFailIfDown < ModelBase
|
13
|
-
validates :vat_number, :
|
13
|
+
validates :vat_number, valvat: {lookup: :fail_if_down}
|
14
14
|
end
|
15
15
|
|
16
16
|
class InvoiceAllowBlank < ModelBase
|
17
|
-
validates :vat_number, :
|
17
|
+
validates :vat_number, valvat: {allow_blank: true}
|
18
18
|
end
|
19
19
|
|
20
20
|
class InvoiceAllowBlankOnAll < ModelBase
|
21
|
-
validates :vat_number, :
|
21
|
+
validates :vat_number, valvat: true, allow_blank: true
|
22
22
|
end
|
23
23
|
|
24
24
|
class InvoiceCheckCountry < ModelBase
|
25
|
-
validates :vat_number, :
|
25
|
+
validates :vat_number, valvat: {match_country: :country}
|
26
26
|
|
27
27
|
def country
|
28
28
|
@attributes[:country]
|
@@ -30,7 +30,7 @@ if defined?(ActiveModel)
|
|
30
30
|
end
|
31
31
|
|
32
32
|
class InvoiceCheckCountryWithLookup < ModelBase
|
33
|
-
validates :vat_number, :
|
33
|
+
validates :vat_number, valvat: {match_country: :country, lookup: true}
|
34
34
|
|
35
35
|
def country
|
36
36
|
@attributes[:country]
|
@@ -38,18 +38,18 @@ if defined?(ActiveModel)
|
|
38
38
|
end
|
39
39
|
|
40
40
|
class InvoiceWithChecksum < ModelBase
|
41
|
-
validates :vat_number, :
|
41
|
+
validates :vat_number, valvat: {checksum: true}
|
42
42
|
end
|
43
43
|
|
44
44
|
describe Invoice do
|
45
|
-
context "with valid
|
45
|
+
context "with valid VAT number" do
|
46
46
|
it "should be valid" do
|
47
|
-
expect(Invoice.new(:
|
47
|
+
expect(Invoice.new(vat_number: "DE259597697")).to be_valid
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
context "with invalid
|
52
|
-
let(:invoice) { Invoice.new(:
|
51
|
+
context "with invalid VAT number" do
|
52
|
+
let(:invoice) { Invoice.new(vat_number: "DE259597697123") }
|
53
53
|
|
54
54
|
it "should not be valid" do
|
55
55
|
expect(invoice).not_to be_valid
|
@@ -57,13 +57,13 @@ if defined?(ActiveModel)
|
|
57
57
|
|
58
58
|
it "should add default (country specific) error message" do
|
59
59
|
invoice.valid?
|
60
|
-
expect(invoice.errors[:vat_number]).to eql(["is not a valid German
|
60
|
+
expect(invoice.errors[:vat_number]).to eql(["is not a valid German VAT number"])
|
61
61
|
end
|
62
62
|
|
63
63
|
context "with i18n translation in place" do
|
64
64
|
before do
|
65
|
-
I18n.backend.store_translations(:en, :
|
66
|
-
:
|
65
|
+
I18n.backend.store_translations(:en, activemodel: {
|
66
|
+
errors: {models: {invoice: {invalid_vat: "is ugly."}}}
|
67
67
|
})
|
68
68
|
end
|
69
69
|
|
@@ -77,165 +77,165 @@ if defined?(ActiveModel)
|
|
77
77
|
|
78
78
|
context "with i18n translation with country adjective placeholder in place" do
|
79
79
|
before do
|
80
|
-
I18n.backend.store_translations(:en, :
|
81
|
-
:
|
80
|
+
I18n.backend.store_translations(:en, activemodel: {
|
81
|
+
errors: {models: {invoice: {invalid_vat: "is not a %{country_adjective} vat"}}}
|
82
82
|
})
|
83
83
|
end
|
84
84
|
|
85
85
|
after { I18n.reload! }
|
86
86
|
|
87
87
|
it "should replace country adjective placeholder" do
|
88
|
-
invoice = Invoice.new(:
|
88
|
+
invoice = Invoice.new(vat_number: "IE123")
|
89
89
|
invoice.valid?
|
90
90
|
expect(invoice.errors[:vat_number]).to eql(["is not a Irish vat"])
|
91
91
|
end
|
92
92
|
|
93
93
|
it "should fall back to 'European' if country is missing" do
|
94
|
-
invoice = Invoice.new(:
|
94
|
+
invoice = Invoice.new(vat_number: "XX123")
|
95
95
|
invoice.valid?
|
96
96
|
expect(invoice.errors[:vat_number]).to eql(["is not a European vat"])
|
97
97
|
end
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
|
-
context "with blank
|
101
|
+
context "with blank VAT number" do
|
102
102
|
it "should not be valid" do
|
103
|
-
expect(Invoice.new(:
|
104
|
-
expect(Invoice.new(:
|
103
|
+
expect(Invoice.new(vat_number: "")).not_to be_valid
|
104
|
+
expect(Invoice.new(vat_number: nil)).not_to be_valid
|
105
105
|
end
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
109
109
|
describe InvoiceWithLookup do
|
110
|
-
context "with valid but not existing
|
110
|
+
context "with valid but not existing VAT number" do
|
111
111
|
before do
|
112
|
-
allow(Valvat::Syntax).to receive_messages(:
|
113
|
-
allow(Valvat::Lookup).to receive_messages(:
|
112
|
+
allow(Valvat::Syntax).to receive_messages(validate: true)
|
113
|
+
allow(Valvat::Lookup).to receive_messages(validate: false)
|
114
114
|
end
|
115
115
|
|
116
116
|
it "should not be valid" do
|
117
|
-
expect(InvoiceWithLookup.new(:
|
117
|
+
expect(InvoiceWithLookup.new(vat_number: "DE123")).not_to be_valid
|
118
118
|
end
|
119
119
|
end
|
120
120
|
|
121
|
-
context "with valid and existing
|
121
|
+
context "with valid and existing VAT number" do
|
122
122
|
before do
|
123
|
-
allow(Valvat::Syntax).to receive_messages(:
|
124
|
-
allow(Valvat::Lookup).to receive_messages(:
|
123
|
+
allow(Valvat::Syntax).to receive_messages(validate: true)
|
124
|
+
allow(Valvat::Lookup).to receive_messages(validate: true)
|
125
125
|
end
|
126
126
|
|
127
127
|
it "should be valid" do
|
128
|
-
expect(InvoiceWithLookup.new(:
|
128
|
+
expect(InvoiceWithLookup.new(vat_number: "DE123")).to be_valid
|
129
129
|
end
|
130
130
|
end
|
131
131
|
|
132
|
-
context "with valid
|
132
|
+
context "with valid VAT number and VIES country service down" do
|
133
133
|
before do
|
134
|
-
allow(Valvat::Syntax).to receive_messages(:
|
135
|
-
allow(Valvat::Lookup).to receive_messages(:
|
134
|
+
allow(Valvat::Syntax).to receive_messages(validate: true)
|
135
|
+
allow(Valvat::Lookup).to receive_messages(validate: nil)
|
136
136
|
end
|
137
137
|
|
138
138
|
it "should be valid" do
|
139
|
-
expect(InvoiceWithLookup.new(:
|
139
|
+
expect(InvoiceWithLookup.new(vat_number: "DE123")).to be_valid
|
140
140
|
end
|
141
141
|
end
|
142
142
|
end
|
143
143
|
|
144
144
|
describe InvoiceWithLookupAndFailIfDown do
|
145
|
-
context "with valid
|
145
|
+
context "with valid VAT number and VIES country service down" do
|
146
146
|
before do
|
147
|
-
allow(Valvat::Syntax).to receive_messages(:
|
148
|
-
allow(Valvat::Lookup).to receive_messages(:
|
147
|
+
allow(Valvat::Syntax).to receive_messages(validate: true)
|
148
|
+
allow(Valvat::Lookup).to receive_messages(validate: nil)
|
149
149
|
end
|
150
150
|
|
151
151
|
it "should not be valid" do
|
152
|
-
expect(InvoiceWithLookupAndFailIfDown.new(:
|
152
|
+
expect(InvoiceWithLookupAndFailIfDown.new(vat_number: "DE123")).not_to be_valid
|
153
153
|
end
|
154
154
|
end
|
155
155
|
end
|
156
156
|
|
157
157
|
describe InvoiceAllowBlank do
|
158
|
-
context "with blank
|
158
|
+
context "with blank VAT number" do
|
159
159
|
it "should be valid" do
|
160
|
-
expect(InvoiceAllowBlank.new(:
|
161
|
-
expect(InvoiceAllowBlank.new(:
|
160
|
+
expect(InvoiceAllowBlank.new(vat_number: "")).to be_valid
|
161
|
+
expect(InvoiceAllowBlank.new(vat_number: nil)).to be_valid
|
162
162
|
end
|
163
163
|
end
|
164
164
|
end
|
165
165
|
|
166
166
|
describe InvoiceAllowBlankOnAll do
|
167
|
-
context "with blank
|
167
|
+
context "with blank VAT number" do
|
168
168
|
it "should be valid" do
|
169
|
-
expect(InvoiceAllowBlankOnAll.new(:
|
170
|
-
expect(InvoiceAllowBlankOnAll.new(:
|
169
|
+
expect(InvoiceAllowBlankOnAll.new(vat_number: "")).to be_valid
|
170
|
+
expect(InvoiceAllowBlankOnAll.new(vat_number: nil)).to be_valid
|
171
171
|
end
|
172
172
|
end
|
173
173
|
end
|
174
174
|
|
175
175
|
describe InvoiceCheckCountry do
|
176
176
|
it "should be not valid on blank country" do
|
177
|
-
expect(InvoiceCheckCountry.new(:
|
178
|
-
expect(InvoiceCheckCountry.new(:
|
177
|
+
expect(InvoiceCheckCountry.new(country: nil, vat_number: "DE259597697")).not_to be_valid
|
178
|
+
expect(InvoiceCheckCountry.new(country: "", vat_number: "DE259597697")).not_to be_valid
|
179
179
|
end
|
180
180
|
|
181
181
|
it "should be not valid on wired country" do
|
182
|
-
expect(InvoiceCheckCountry.new(:
|
183
|
-
expect(InvoiceCheckCountry.new(:
|
182
|
+
expect(InvoiceCheckCountry.new(country: "XAXXX", vat_number: "DE259597697")).not_to be_valid
|
183
|
+
expect(InvoiceCheckCountry.new(country: "ZO", vat_number: "DE259597697")).not_to be_valid
|
184
184
|
end
|
185
185
|
|
186
186
|
it "should be not valid on mismatching (eu) country" do
|
187
|
-
expect(InvoiceCheckCountry.new(:
|
188
|
-
expect(InvoiceCheckCountry.new(:
|
189
|
-
expect(InvoiceCheckCountry.new(:
|
187
|
+
expect(InvoiceCheckCountry.new(country: "FR", vat_number: "DE259597697")).not_to be_valid
|
188
|
+
expect(InvoiceCheckCountry.new(country: "AT", vat_number: "DE259597697")).not_to be_valid
|
189
|
+
expect(InvoiceCheckCountry.new(country: "DE", vat_number: "ATU65931334")).not_to be_valid
|
190
190
|
end
|
191
191
|
|
192
192
|
it "should be valid on matching country" do
|
193
|
-
expect(InvoiceCheckCountry.new(:
|
194
|
-
expect(InvoiceCheckCountry.new(:
|
193
|
+
expect(InvoiceCheckCountry.new(country: "DE", vat_number: "DE259597697")).to be_valid
|
194
|
+
expect(InvoiceCheckCountry.new(country: "AT", vat_number: "ATU65931334")).to be_valid
|
195
195
|
end
|
196
196
|
|
197
197
|
it "should give back error message with country from :country_match" do
|
198
|
-
invoice = InvoiceCheckCountry.new(:
|
198
|
+
invoice = InvoiceCheckCountry.new(country: "FR", vat_number: "DE259597697")
|
199
199
|
invoice.valid?
|
200
|
-
expect(invoice.errors[:vat_number]).to eql(["is not a valid French
|
200
|
+
expect(invoice.errors[:vat_number]).to eql(["is not a valid French VAT number"])
|
201
201
|
end
|
202
202
|
|
203
|
-
it "should give back error message with country from :country_match even on invalid
|
204
|
-
invoice = InvoiceCheckCountry.new(:
|
203
|
+
it "should give back error message with country from :country_match even on invalid VAT number" do
|
204
|
+
invoice = InvoiceCheckCountry.new(country: "FR", vat_number: "DE259597697123")
|
205
205
|
invoice.valid?
|
206
|
-
expect(invoice.errors[:vat_number]).to eql(["is not a valid French
|
206
|
+
expect(invoice.errors[:vat_number]).to eql(["is not a valid French VAT number"])
|
207
207
|
end
|
208
208
|
end
|
209
209
|
|
210
210
|
describe InvoiceCheckCountryWithLookup do
|
211
211
|
before do
|
212
|
-
allow(Valvat::Syntax).to receive_messages(:
|
213
|
-
allow(Valvat::Lookup).to receive_messages(:
|
212
|
+
allow(Valvat::Syntax).to receive_messages(validate: true)
|
213
|
+
allow(Valvat::Lookup).to receive_messages(validate: true)
|
214
214
|
end
|
215
215
|
|
216
216
|
it "avoids lookup or syntax check on failed because of mismatching country" do
|
217
217
|
expect(Valvat::Syntax).not_to receive(:validate)
|
218
218
|
expect(Valvat::Lookup).not_to receive(:validate)
|
219
|
-
InvoiceCheckCountryWithLookup.new(:
|
219
|
+
InvoiceCheckCountryWithLookup.new(country: "FR", vat_number: "DE259597697").valid?
|
220
220
|
end
|
221
221
|
|
222
222
|
it "check syntax and looup on matching country" do
|
223
223
|
expect(Valvat::Syntax).to receive(:validate).and_return(true)
|
224
224
|
expect(Valvat::Lookup).to receive(:validate).and_return(true)
|
225
|
-
InvoiceCheckCountryWithLookup.new(:
|
225
|
+
InvoiceCheckCountryWithLookup.new(country: "DE", vat_number: "DE259597697").valid?
|
226
226
|
end
|
227
227
|
end
|
228
228
|
|
229
229
|
describe InvoiceWithChecksum do
|
230
|
-
context "with valid
|
230
|
+
context "with valid VAT number" do
|
231
231
|
it "should be valid" do
|
232
|
-
expect(InvoiceWithChecksum.new(:
|
232
|
+
expect(InvoiceWithChecksum.new(vat_number: "DE259597697")).to be_valid
|
233
233
|
end
|
234
234
|
end
|
235
235
|
|
236
|
-
context "with invalid
|
236
|
+
context "with invalid VAT number" do
|
237
237
|
it "should not be valid" do
|
238
|
-
expect(InvoiceWithChecksum.new(:
|
238
|
+
expect(InvoiceWithChecksum.new(vat_number: "DE259597687")).not_to be_valid
|
239
239
|
end
|
240
240
|
end
|
241
241
|
end
|