brazil-validator 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.
- checksums.yaml +7 -0
- data/README.md +77 -0
- data/lib/br_validator/cep.rb +44 -0
- data/lib/br_validator/cnpj.rb +78 -0
- data/lib/br_validator/cpf.rb +63 -0
- data/lib/br_validator/email.rb +48 -0
- data/lib/br_validator/ie/ac.rb +48 -0
- data/lib/br_validator/ie/al.rb +46 -0
- data/lib/br_validator/ie/am.rb +52 -0
- data/lib/br_validator/ie/ap.rb +64 -0
- data/lib/br_validator/ie/ba.rb +76 -0
- data/lib/br_validator/ie/ce.rb +42 -0
- data/lib/br_validator/ie/df.rb +58 -0
- data/lib/br_validator/ie/es.rb +39 -0
- data/lib/br_validator/ie/go.rb +49 -0
- data/lib/br_validator/ie/ma.rb +41 -0
- data/lib/br_validator/ie/mg.rb +93 -0
- data/lib/br_validator/ie/mod11.rb +48 -0
- data/lib/br_validator/ie/ms.rb +45 -0
- data/lib/br_validator/ie/mt.rb +42 -0
- data/lib/br_validator/ie/pa.rb +44 -0
- data/lib/br_validator/ie/pb.rb +42 -0
- data/lib/br_validator/ie/pe.rb +52 -0
- data/lib/br_validator/ie/pi.rb +38 -0
- data/lib/br_validator/ie/pr.rb +53 -0
- data/lib/br_validator/ie/rj.rb +53 -0
- data/lib/br_validator/ie/rn.rb +58 -0
- data/lib/br_validator/ie/ro.rb +58 -0
- data/lib/br_validator/ie/rr.rb +47 -0
- data/lib/br_validator/ie/rs.rb +42 -0
- data/lib/br_validator/ie/sc.rb +42 -0
- data/lib/br_validator/ie/se.rb +42 -0
- data/lib/br_validator/ie/sp.rb +121 -0
- data/lib/br_validator/ie/to.rb +49 -0
- data/lib/br_validator/ie.rb +112 -0
- data/lib/br_validator/phone.rb +59 -0
- data/lib/br_validator/pix.rb +134 -0
- data/lib/br_validator/shared.rb +31 -0
- data/lib/br_validator/version.rb +5 -0
- data/lib/br_validator.rb +13 -0
- metadata +84 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../shared"
|
|
4
|
+
require_relative "mod11"
|
|
5
|
+
|
|
6
|
+
module BrValidator
|
|
7
|
+
module Ie
|
|
8
|
+
# DF: SEFAZ-DF's own Sintegra "Roteiro de Crítica" page
|
|
9
|
+
# (sintegra.gov.br/Cad_Estados/cad_DF.html) is empty, so this was
|
|
10
|
+
# instead cross-verified against two independent secondary sources
|
|
11
|
+
# that agree with each other (cadcobol.com.br's fully worked example,
|
|
12
|
+
# arithmetic re-checked by hand, and mestredocalculo.com.br
|
|
13
|
+
# independently citing the same valid example "07.300.001.001-09").
|
|
14
|
+
# The algorithm is structurally identical to AC's officially-confirmed
|
|
15
|
+
# one (same weight sequences), differing only in the fixed "07" prefix
|
|
16
|
+
# -- strong evidence both derive from the same original SEFAZ
|
|
17
|
+
# documentation.
|
|
18
|
+
#
|
|
19
|
+
# Format: "07" (fixed) + 6 sequence digits + 3 "ordem do
|
|
20
|
+
# estabelecimento" digits (001 = matriz) + 2 check digits = 13 digits
|
|
21
|
+
# total.
|
|
22
|
+
module Df
|
|
23
|
+
module_function
|
|
24
|
+
|
|
25
|
+
ALLOWED_CHARS = %r{\A[\d./\-\s]+\z}.freeze
|
|
26
|
+
FIRST_DIGIT_WEIGHTS = [4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2].freeze
|
|
27
|
+
SECOND_DIGIT_WEIGHTS = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2].freeze
|
|
28
|
+
private_constant :ALLOWED_CHARS, :FIRST_DIGIT_WEIGHTS, :SECOND_DIGIT_WEIGHTS
|
|
29
|
+
|
|
30
|
+
def normalize(value)
|
|
31
|
+
Shared.remove_non_digits(value)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def is_valid?(value)
|
|
35
|
+
return false unless value.match?(ALLOWED_CHARS)
|
|
36
|
+
|
|
37
|
+
v = normalize(value)
|
|
38
|
+
|
|
39
|
+
return false unless v.length == 13 && v.start_with?("07")
|
|
40
|
+
|
|
41
|
+
first_digit = Mod11.mod11_check_digit(Mod11.weighted_sum(v, FIRST_DIGIT_WEIGHTS))
|
|
42
|
+
return false unless first_digit == v[11].to_i
|
|
43
|
+
|
|
44
|
+
second_digit = Mod11.mod11_check_digit(Mod11.weighted_sum(v, SECOND_DIGIT_WEIGHTS))
|
|
45
|
+
|
|
46
|
+
second_digit == v[12].to_i
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def format(value)
|
|
50
|
+
v = normalize(value)
|
|
51
|
+
|
|
52
|
+
return value unless v.length == 13
|
|
53
|
+
|
|
54
|
+
"#{v[0...2]}.#{v[2...5]}.#{v[5...8]}.#{v[8...11]}-#{v[11...13]}"
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../shared"
|
|
4
|
+
require_relative "mod11"
|
|
5
|
+
|
|
6
|
+
module BrValidator
|
|
7
|
+
module Ie
|
|
8
|
+
# ES: verified against the official SEFAZ-ES "Roteiro de Crítica da
|
|
9
|
+
# Inscrição Estadual" (sintegra.gov.br/Cad_Estados/cad_ES.html),
|
|
10
|
+
# including its worked example (all-9s base -> sum 396). Format: 8
|
|
11
|
+
# digits + 1 check digit. No official punctuation mask is published,
|
|
12
|
+
# so format returns plain digits.
|
|
13
|
+
module Es
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
ALLOWED_CHARS = /\A[\d\s]+\z/.freeze
|
|
17
|
+
WEIGHTS = [9, 8, 7, 6, 5, 4, 3, 2].freeze
|
|
18
|
+
private_constant :ALLOWED_CHARS, :WEIGHTS
|
|
19
|
+
|
|
20
|
+
def normalize(value)
|
|
21
|
+
Shared.remove_non_digits(value)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def is_valid?(value)
|
|
25
|
+
return false unless value.match?(ALLOWED_CHARS)
|
|
26
|
+
|
|
27
|
+
v = normalize(value)
|
|
28
|
+
|
|
29
|
+
return false unless v.length == 9
|
|
30
|
+
|
|
31
|
+
Mod11.mod11_check_digit(Mod11.weighted_sum(v, WEIGHTS)) == v[8].to_i
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def format(value)
|
|
35
|
+
normalize(value)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../shared"
|
|
4
|
+
require_relative "mod11"
|
|
5
|
+
|
|
6
|
+
module BrValidator
|
|
7
|
+
module Ie
|
|
8
|
+
# GO: verified against the official SEFAZ-GO "Roteiro de Crítica da
|
|
9
|
+
# Inscrição Estadual" (sintegra.gov.br/Cad_Estados/cad_GO.html),
|
|
10
|
+
# including its worked example (10.987.654-7). Format: AB.CDE.FGH-I,
|
|
11
|
+
# where AB must be 10, 11, or 20-29.
|
|
12
|
+
module Go
|
|
13
|
+
module_function
|
|
14
|
+
|
|
15
|
+
ALLOWED_CHARS = /\A[\d.\-\s]+\z/.freeze
|
|
16
|
+
WEIGHTS = [9, 8, 7, 6, 5, 4, 3, 2].freeze
|
|
17
|
+
private_constant :ALLOWED_CHARS, :WEIGHTS
|
|
18
|
+
|
|
19
|
+
def normalize(value)
|
|
20
|
+
Shared.remove_non_digits(value)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def valid_prefix?(v)
|
|
24
|
+
prefix = v[0...2].to_i
|
|
25
|
+
|
|
26
|
+
prefix == 10 || prefix == 11 || (20..29).cover?(prefix)
|
|
27
|
+
end
|
|
28
|
+
private_class_method :valid_prefix?
|
|
29
|
+
|
|
30
|
+
def is_valid?(value)
|
|
31
|
+
return false unless value.match?(ALLOWED_CHARS)
|
|
32
|
+
|
|
33
|
+
v = normalize(value)
|
|
34
|
+
|
|
35
|
+
return false unless v.length == 9 && valid_prefix?(v)
|
|
36
|
+
|
|
37
|
+
Mod11.mod11_check_digit(Mod11.weighted_sum(v, WEIGHTS)) == v[8].to_i
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def format(value)
|
|
41
|
+
v = normalize(value)
|
|
42
|
+
|
|
43
|
+
return value unless v.length == 9
|
|
44
|
+
|
|
45
|
+
"#{v[0...2]}.#{v[2...5]}.#{v[5...8]}-#{v[8...9]}"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../shared"
|
|
4
|
+
require_relative "mod11"
|
|
5
|
+
|
|
6
|
+
module BrValidator
|
|
7
|
+
module Ie
|
|
8
|
+
# MA: verified against the official SEFAZ-MA "Roteiro de Crítica da
|
|
9
|
+
# Inscrição Estadual" (sintegra.gov.br/Cad_Estados/cad_MA.html),
|
|
10
|
+
# including its worked example (120000385).
|
|
11
|
+
#
|
|
12
|
+
# Format: "12" (fixed) + 6 sequence digits + 1 check digit = 9 digits
|
|
13
|
+
# total. No official punctuation mask is published, so format returns
|
|
14
|
+
# plain digits.
|
|
15
|
+
module Ma
|
|
16
|
+
module_function
|
|
17
|
+
|
|
18
|
+
ALLOWED_CHARS = /\A[\d\s]+\z/.freeze
|
|
19
|
+
WEIGHTS = [9, 8, 7, 6, 5, 4, 3, 2].freeze
|
|
20
|
+
private_constant :ALLOWED_CHARS, :WEIGHTS
|
|
21
|
+
|
|
22
|
+
def normalize(value)
|
|
23
|
+
Shared.remove_non_digits(value)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def is_valid?(value)
|
|
27
|
+
return false unless value.match?(ALLOWED_CHARS)
|
|
28
|
+
|
|
29
|
+
v = normalize(value)
|
|
30
|
+
|
|
31
|
+
return false unless v.length == 9 && v.start_with?("12")
|
|
32
|
+
|
|
33
|
+
Mod11.mod11_check_digit(Mod11.weighted_sum(v, WEIGHTS)) == v[8].to_i
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def format(value)
|
|
37
|
+
normalize(value)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../shared"
|
|
4
|
+
require_relative "mod11"
|
|
5
|
+
|
|
6
|
+
module BrValidator
|
|
7
|
+
module Ie
|
|
8
|
+
# MG: verified against the official SEFAZ-MG "Roteiro de Crítica da
|
|
9
|
+
# Inscrição Estadual" (mirrored at
|
|
10
|
+
# sintegra.gov.br/Cad_Estados/cad_MG.html), including its fully worked
|
|
11
|
+
# example (062.307.904/0081).
|
|
12
|
+
#
|
|
13
|
+
# Format: A1A2A3 B1B2B3B4B5B6 C1C2 D1D2 (13 digits), where A =
|
|
14
|
+
# município code, B = registration number, C = establishment order, D
|
|
15
|
+
# = check digits.
|
|
16
|
+
module Mg
|
|
17
|
+
module_function
|
|
18
|
+
|
|
19
|
+
ALLOWED_CHARS = %r{\A[\d./\s]+\z}.freeze
|
|
20
|
+
FIRST_DIGIT_WEIGHTS = [1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2].freeze
|
|
21
|
+
SECOND_DIGIT_WEIGHTS = [3, 2, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2].freeze
|
|
22
|
+
private_constant :ALLOWED_CHARS, :FIRST_DIGIT_WEIGHTS, :SECOND_DIGIT_WEIGHTS
|
|
23
|
+
|
|
24
|
+
def normalize(value)
|
|
25
|
+
Shared.remove_non_digits(value)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def sum_of_digits(value)
|
|
29
|
+
value.digits.sum
|
|
30
|
+
end
|
|
31
|
+
private_class_method :sum_of_digits
|
|
32
|
+
|
|
33
|
+
# D1 equalizes the field widths by inserting a "0" right after the
|
|
34
|
+
# município code, then sums the *digits* of each weighted product
|
|
35
|
+
# (not the products themselves) before completing to the next
|
|
36
|
+
# multiple of ten.
|
|
37
|
+
def calculate_first_digit(base)
|
|
38
|
+
with_inserted_zero = "#{base[0...3]}0#{base[3..]}"
|
|
39
|
+
|
|
40
|
+
digit_sum = FIRST_DIGIT_WEIGHTS.each_with_index.sum do |weight, i|
|
|
41
|
+
sum_of_digits(with_inserted_zero[i].to_i * weight)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
remainder = digit_sum % 10
|
|
45
|
+
|
|
46
|
+
return 0 if remainder.zero?
|
|
47
|
+
|
|
48
|
+
10 - remainder
|
|
49
|
+
end
|
|
50
|
+
private_class_method :calculate_first_digit
|
|
51
|
+
|
|
52
|
+
# D2 uses the original (un-padded) base plus D1, and sums the
|
|
53
|
+
# weighted products directly, following the general módulo 11
|
|
54
|
+
# remainder rule.
|
|
55
|
+
def calculate_second_digit(base, first_digit)
|
|
56
|
+
with_first_digit = "#{base}#{first_digit}"
|
|
57
|
+
|
|
58
|
+
sum = Mod11.weighted_sum(with_first_digit, SECOND_DIGIT_WEIGHTS)
|
|
59
|
+
remainder = sum % 11
|
|
60
|
+
|
|
61
|
+
return 0 if remainder <= 1
|
|
62
|
+
|
|
63
|
+
11 - remainder
|
|
64
|
+
end
|
|
65
|
+
private_class_method :calculate_second_digit
|
|
66
|
+
|
|
67
|
+
def is_valid?(value)
|
|
68
|
+
return false unless value.match?(ALLOWED_CHARS)
|
|
69
|
+
|
|
70
|
+
v = normalize(value)
|
|
71
|
+
|
|
72
|
+
return false unless v.length == 13
|
|
73
|
+
|
|
74
|
+
base = v[0...11]
|
|
75
|
+
first_digit = calculate_first_digit(base)
|
|
76
|
+
|
|
77
|
+
return false unless first_digit == v[11].to_i
|
|
78
|
+
|
|
79
|
+
second_digit = calculate_second_digit(base, first_digit)
|
|
80
|
+
|
|
81
|
+
second_digit == v[12].to_i
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def format(value)
|
|
85
|
+
v = normalize(value)
|
|
86
|
+
|
|
87
|
+
return value unless v.length == 13
|
|
88
|
+
|
|
89
|
+
"#{v[0...3]}.#{v[3...6]}.#{v[6...9]}/#{v[9...13]}"
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BrValidator
|
|
4
|
+
module Ie
|
|
5
|
+
# Shared by most Inscrição Estadual algorithms (SEFAZ "Roteiro de
|
|
6
|
+
# Crítica" documents): weight each digit, sum the products, then
|
|
7
|
+
# reduce modulo 11.
|
|
8
|
+
#
|
|
9
|
+
# Not part of the public API of brazil-validator.
|
|
10
|
+
module Mod11
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
def weighted_sum(digits, weights)
|
|
14
|
+
weights.each_with_index.sum { |weight, i| digits[i].to_i * weight }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# The most common check-digit rule across states: remainder 0 or 1
|
|
18
|
+
# maps to digit 0, otherwise the digit is 11 minus the remainder.
|
|
19
|
+
def mod11_check_digit(sum)
|
|
20
|
+
remainder = sum % 11
|
|
21
|
+
|
|
22
|
+
return 0 if remainder <= 1
|
|
23
|
+
|
|
24
|
+
11 - remainder
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Used by Bahia's módulo-10 branch: remainder 0 maps to digit 0,
|
|
28
|
+
# otherwise the digit is 10 minus the remainder.
|
|
29
|
+
def mod10_check_digit(sum)
|
|
30
|
+
remainder = sum % 10
|
|
31
|
+
|
|
32
|
+
return 0 if remainder.zero?
|
|
33
|
+
|
|
34
|
+
10 - remainder
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Used by Alagoas and Rio Grande do Norte: the sum is multiplied by
|
|
38
|
+
# 10 before reducing modulo 11, and the remainder *is* the digit
|
|
39
|
+
# directly (a remainder of 10 wraps to 0). Mirrors CPF's check-digit
|
|
40
|
+
# formula.
|
|
41
|
+
def mod11_times_ten_check_digit(sum)
|
|
42
|
+
remainder = (sum * 10) % 11
|
|
43
|
+
|
|
44
|
+
remainder == 10 ? 0 : remainder
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../shared"
|
|
4
|
+
require_relative "mod11"
|
|
5
|
+
|
|
6
|
+
module BrValidator
|
|
7
|
+
module Ie
|
|
8
|
+
# MS: verified against the official SEFAZ-MS "Roteiro de Crítica da
|
|
9
|
+
# Inscrição Estadual" (sintegra.gov.br/Cad_Estados/cad_MS.html) for the
|
|
10
|
+
# algorithm (which the page does not accompany with a worked numeric
|
|
11
|
+
# example), plus an independently hand-computed regression vector
|
|
12
|
+
# (281234566). Format: 8 digits (always starting with "28" or "50") +
|
|
13
|
+
# 1 check digit.
|
|
14
|
+
module Ms
|
|
15
|
+
module_function
|
|
16
|
+
|
|
17
|
+
ALLOWED_CHARS = /\A[\d\s]+\z/.freeze
|
|
18
|
+
WEIGHTS = [9, 8, 7, 6, 5, 4, 3, 2].freeze
|
|
19
|
+
private_constant :ALLOWED_CHARS, :WEIGHTS
|
|
20
|
+
|
|
21
|
+
def normalize(value)
|
|
22
|
+
Shared.remove_non_digits(value)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def valid_prefix?(v)
|
|
26
|
+
%w[28 50].include?(v[0...2])
|
|
27
|
+
end
|
|
28
|
+
private_class_method :valid_prefix?
|
|
29
|
+
|
|
30
|
+
def is_valid?(value)
|
|
31
|
+
return false unless value.match?(ALLOWED_CHARS)
|
|
32
|
+
|
|
33
|
+
v = normalize(value)
|
|
34
|
+
|
|
35
|
+
return false unless v.length == 9 && valid_prefix?(v)
|
|
36
|
+
|
|
37
|
+
Mod11.mod11_check_digit(Mod11.weighted_sum(v, WEIGHTS)) == v[8].to_i
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def format(value)
|
|
41
|
+
normalize(value)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../shared"
|
|
4
|
+
require_relative "mod11"
|
|
5
|
+
|
|
6
|
+
module BrValidator
|
|
7
|
+
module Ie
|
|
8
|
+
# MT: verified against the official SEFAZ-MT "Roteiro de Crítica da
|
|
9
|
+
# Inscrição Estadual" (sintegra.gov.br/Cad_Estados/cad_MT.html),
|
|
10
|
+
# including its worked example (0013000001-9). Format: 10 digits + 1
|
|
11
|
+
# check digit.
|
|
12
|
+
module Mt
|
|
13
|
+
module_function
|
|
14
|
+
|
|
15
|
+
ALLOWED_CHARS = /\A[\d\-\s]+\z/.freeze
|
|
16
|
+
WEIGHTS = [3, 2, 9, 8, 7, 6, 5, 4, 3, 2].freeze
|
|
17
|
+
private_constant :ALLOWED_CHARS, :WEIGHTS
|
|
18
|
+
|
|
19
|
+
def normalize(value)
|
|
20
|
+
Shared.remove_non_digits(value)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def is_valid?(value)
|
|
24
|
+
return false unless value.match?(ALLOWED_CHARS)
|
|
25
|
+
|
|
26
|
+
v = normalize(value)
|
|
27
|
+
|
|
28
|
+
return false unless v.length == 11
|
|
29
|
+
|
|
30
|
+
Mod11.mod11_check_digit(Mod11.weighted_sum(v, WEIGHTS)) == v[10].to_i
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def format(value)
|
|
34
|
+
v = normalize(value)
|
|
35
|
+
|
|
36
|
+
return value unless v.length == 11
|
|
37
|
+
|
|
38
|
+
"#{v[0...10]}-#{v[10...11]}"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../shared"
|
|
4
|
+
require_relative "mod11"
|
|
5
|
+
|
|
6
|
+
module BrValidator
|
|
7
|
+
module Ie
|
|
8
|
+
# PA: verified against the official SEFAZ-PA "Roteiro de Crítica da
|
|
9
|
+
# Inscrição Estadual" (sintegra.gov.br/Cad_Estados/cad_PA.html),
|
|
10
|
+
# including its two worked examples (15999999-5, 75000002-3). Format:
|
|
11
|
+
# 8 digits (always starting with 15, 75, 76, 77, 78 or 79) + 1 check
|
|
12
|
+
# digit.
|
|
13
|
+
module Pa
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
ALLOWED_CHARS = /\A[\d\-\s]+\z/.freeze
|
|
17
|
+
WEIGHTS = [9, 8, 7, 6, 5, 4, 3, 2].freeze
|
|
18
|
+
VALID_PREFIXES = %w[15 75 76 77 78 79].freeze
|
|
19
|
+
private_constant :ALLOWED_CHARS, :WEIGHTS, :VALID_PREFIXES
|
|
20
|
+
|
|
21
|
+
def normalize(value)
|
|
22
|
+
Shared.remove_non_digits(value)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def is_valid?(value)
|
|
26
|
+
return false unless value.match?(ALLOWED_CHARS)
|
|
27
|
+
|
|
28
|
+
v = normalize(value)
|
|
29
|
+
|
|
30
|
+
return false unless v.length == 9 && VALID_PREFIXES.include?(v[0...2])
|
|
31
|
+
|
|
32
|
+
Mod11.mod11_check_digit(Mod11.weighted_sum(v, WEIGHTS)) == v[8].to_i
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def format(value)
|
|
36
|
+
v = normalize(value)
|
|
37
|
+
|
|
38
|
+
return value unless v.length == 9
|
|
39
|
+
|
|
40
|
+
"#{v[0...8]}-#{v[8...9]}"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../shared"
|
|
4
|
+
require_relative "mod11"
|
|
5
|
+
|
|
6
|
+
module BrValidator
|
|
7
|
+
module Ie
|
|
8
|
+
# PB: verified against the official SEFAZ-PB "Roteiro de Crítica da
|
|
9
|
+
# Inscrição Estadual" (sintegra.gov.br/Cad_Estados/cad_PB.html),
|
|
10
|
+
# including its worked example (06000001-5). Format: 8 digits + 1
|
|
11
|
+
# check digit.
|
|
12
|
+
module Pb
|
|
13
|
+
module_function
|
|
14
|
+
|
|
15
|
+
ALLOWED_CHARS = /\A[\d\-\s]+\z/.freeze
|
|
16
|
+
WEIGHTS = [9, 8, 7, 6, 5, 4, 3, 2].freeze
|
|
17
|
+
private_constant :ALLOWED_CHARS, :WEIGHTS
|
|
18
|
+
|
|
19
|
+
def normalize(value)
|
|
20
|
+
Shared.remove_non_digits(value)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def is_valid?(value)
|
|
24
|
+
return false unless value.match?(ALLOWED_CHARS)
|
|
25
|
+
|
|
26
|
+
v = normalize(value)
|
|
27
|
+
|
|
28
|
+
return false unless v.length == 9
|
|
29
|
+
|
|
30
|
+
Mod11.mod11_check_digit(Mod11.weighted_sum(v, WEIGHTS)) == v[8].to_i
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def format(value)
|
|
34
|
+
v = normalize(value)
|
|
35
|
+
|
|
36
|
+
return value unless v.length == 9
|
|
37
|
+
|
|
38
|
+
"#{v[0...8]}-#{v[8...9]}"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../shared"
|
|
4
|
+
require_relative "mod11"
|
|
5
|
+
|
|
6
|
+
module BrValidator
|
|
7
|
+
module Ie
|
|
8
|
+
# PE: verified against the official SEFAZ-PE "Roteiro de Crítica da
|
|
9
|
+
# Inscrição Estadual" for the e-Fisco system
|
|
10
|
+
# (sintegra.gov.br/Cad_Estados/cad_PE.html), including its fully
|
|
11
|
+
# worked example (0321418-40). Format: 7 digits + 2 check digits.
|
|
12
|
+
module Pe
|
|
13
|
+
module_function
|
|
14
|
+
|
|
15
|
+
ALLOWED_CHARS = /\A[\d\-\s]+\z/.freeze
|
|
16
|
+
FIRST_DIGIT_WEIGHTS = [8, 7, 6, 5, 4, 3, 2].freeze
|
|
17
|
+
SECOND_DIGIT_WEIGHTS = [9, 8, 7, 6, 5, 4, 3, 2].freeze
|
|
18
|
+
private_constant :ALLOWED_CHARS, :FIRST_DIGIT_WEIGHTS, :SECOND_DIGIT_WEIGHTS
|
|
19
|
+
|
|
20
|
+
def normalize(value)
|
|
21
|
+
Shared.remove_non_digits(value)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def is_valid?(value)
|
|
25
|
+
return false unless value.match?(ALLOWED_CHARS)
|
|
26
|
+
|
|
27
|
+
v = normalize(value)
|
|
28
|
+
|
|
29
|
+
return false unless v.length == 9
|
|
30
|
+
|
|
31
|
+
base = v[0...7]
|
|
32
|
+
first_digit = Mod11.mod11_check_digit(Mod11.weighted_sum(base, FIRST_DIGIT_WEIGHTS))
|
|
33
|
+
|
|
34
|
+
return false unless first_digit == v[7].to_i
|
|
35
|
+
|
|
36
|
+
second_digit = Mod11.mod11_check_digit(
|
|
37
|
+
Mod11.weighted_sum(base + first_digit.to_s, SECOND_DIGIT_WEIGHTS)
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
second_digit == v[8].to_i
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def format(value)
|
|
44
|
+
v = normalize(value)
|
|
45
|
+
|
|
46
|
+
return value unless v.length == 9
|
|
47
|
+
|
|
48
|
+
"#{v[0...7]}-#{v[7...9]}"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../shared"
|
|
4
|
+
require_relative "mod11"
|
|
5
|
+
|
|
6
|
+
module BrValidator
|
|
7
|
+
module Ie
|
|
8
|
+
# PI: verified against the official SEFAZ-PI "Roteiro de Crítica da
|
|
9
|
+
# Inscrição Estadual" (sintegra.gov.br/Cad_Estados/cad_PI.html),
|
|
10
|
+
# including its worked example (012345679). Format: 8 digits + 1 check
|
|
11
|
+
# digit.
|
|
12
|
+
module Pi
|
|
13
|
+
module_function
|
|
14
|
+
|
|
15
|
+
ALLOWED_CHARS = /\A[\d\s]+\z/.freeze
|
|
16
|
+
WEIGHTS = [9, 8, 7, 6, 5, 4, 3, 2].freeze
|
|
17
|
+
private_constant :ALLOWED_CHARS, :WEIGHTS
|
|
18
|
+
|
|
19
|
+
def normalize(value)
|
|
20
|
+
Shared.remove_non_digits(value)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def is_valid?(value)
|
|
24
|
+
return false unless value.match?(ALLOWED_CHARS)
|
|
25
|
+
|
|
26
|
+
v = normalize(value)
|
|
27
|
+
|
|
28
|
+
return false unless v.length == 9
|
|
29
|
+
|
|
30
|
+
Mod11.mod11_check_digit(Mod11.weighted_sum(v, WEIGHTS)) == v[8].to_i
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def format(value)
|
|
34
|
+
normalize(value)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../shared"
|
|
4
|
+
require_relative "mod11"
|
|
5
|
+
|
|
6
|
+
module BrValidator
|
|
7
|
+
module Ie
|
|
8
|
+
# PR: verified against the official SEFAZ-PR "Roteiro de Crítica da
|
|
9
|
+
# Inscrição Estadual" (sintegra.gov.br/Cad_Estados/cad_PR.html),
|
|
10
|
+
# including its fully worked example (123.45678-50), and cross-checked
|
|
11
|
+
# against the reference Visual Basic routine published on the same
|
|
12
|
+
# page. Format: 8 digits + 2 check digits.
|
|
13
|
+
module Pr
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
ALLOWED_CHARS = /\A[\d.\-\s]+\z/.freeze
|
|
17
|
+
FIRST_DIGIT_WEIGHTS = [3, 2, 7, 6, 5, 4, 3, 2].freeze
|
|
18
|
+
SECOND_DIGIT_WEIGHTS = [4, 3, 2, 7, 6, 5, 4, 3, 2].freeze
|
|
19
|
+
private_constant :ALLOWED_CHARS, :FIRST_DIGIT_WEIGHTS, :SECOND_DIGIT_WEIGHTS
|
|
20
|
+
|
|
21
|
+
def normalize(value)
|
|
22
|
+
Shared.remove_non_digits(value)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def is_valid?(value)
|
|
26
|
+
return false unless value.match?(ALLOWED_CHARS)
|
|
27
|
+
|
|
28
|
+
v = normalize(value)
|
|
29
|
+
|
|
30
|
+
return false unless v.length == 10
|
|
31
|
+
|
|
32
|
+
base = v[0...8]
|
|
33
|
+
first_digit = Mod11.mod11_check_digit(Mod11.weighted_sum(base, FIRST_DIGIT_WEIGHTS))
|
|
34
|
+
|
|
35
|
+
return false unless first_digit == v[8].to_i
|
|
36
|
+
|
|
37
|
+
second_digit = Mod11.mod11_check_digit(
|
|
38
|
+
Mod11.weighted_sum(base + first_digit.to_s, SECOND_DIGIT_WEIGHTS)
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
second_digit == v[9].to_i
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def format(value)
|
|
45
|
+
v = normalize(value)
|
|
46
|
+
|
|
47
|
+
return value unless v.length == 10
|
|
48
|
+
|
|
49
|
+
"#{v[0...3]}.#{v[3...8]}-#{v[8...10]}"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|