brazilian_documents 0.1.1 → 0.1.2
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
- data/Gemfile +2 -0
- data/README.md +263 -15
- data/br_documents.gemspec +5 -5
- data/lib/br_documents.rb +3 -0
- data/lib/br_documents/documents/cnpj.rb +7 -10
- data/lib/br_documents/documents/cpf.rb +7 -10
- data/lib/br_documents/documents/ie.rb +43 -0
- data/lib/br_documents/documents/ie/ac.rb +15 -0
- data/lib/br_documents/documents/ie/al.rb +50 -0
- data/lib/br_documents/documents/ie/am.rb +12 -0
- data/lib/br_documents/documents/ie/ap.rb +61 -0
- data/lib/br_documents/documents/ie/ba.rb +84 -0
- data/lib/br_documents/documents/ie/ba/base.rb +37 -0
- data/lib/br_documents/documents/ie/ba/digits8/modulo_10.rb +12 -0
- data/lib/br_documents/documents/ie/ba/digits8/modulo_11.rb +12 -0
- data/lib/br_documents/documents/ie/ba/digits9/modulo_10.rb +19 -0
- data/lib/br_documents/documents/ie/ba/digits9/modulo_11.rb +20 -0
- data/lib/br_documents/documents/ie/ba/modulo_10.rb +19 -0
- data/lib/br_documents/documents/ie/ba/modulo_11.rb +18 -0
- data/lib/br_documents/documents/ie/base.rb +79 -0
- data/lib/br_documents/documents/ie/ce.rb +14 -0
- data/lib/br_documents/documents/ie/df.rb +16 -0
- data/lib/br_documents/documents/ie/es.rb +12 -0
- data/lib/br_documents/documents/ie/go.rb +14 -0
- data/lib/br_documents/documents/ie/ma.rb +14 -0
- data/lib/br_documents/documents/ie/mg.rb +66 -0
- data/lib/br_documents/documents/ie/ms.rb +14 -0
- data/lib/br_documents/documents/ie/mt.rb +14 -0
- data/lib/br_documents/documents/ie/pa.rb +14 -0
- data/lib/br_documents/documents/ie/pb.rb +14 -0
- data/lib/br_documents/documents/ie/pe.rb +38 -0
- data/lib/br_documents/documents/ie/pe/current.rb +13 -0
- data/lib/br_documents/documents/ie/pe/legacy.rb +12 -0
- data/lib/br_documents/documents/ie/pi.rb +14 -0
- data/lib/br_documents/documents/ie/pr.rb +13 -0
- data/lib/br_documents/documents/ie/rj.rb +25 -0
- data/lib/br_documents/documents/ie/rn.rb +14 -0
- data/lib/br_documents/documents/ie/ro.rb +44 -0
- data/lib/br_documents/documents/ie/ro/current.rb +24 -0
- data/lib/br_documents/documents/ie/ro/legacy.rb +13 -0
- data/lib/br_documents/documents/ie/rr.rb +19 -0
- data/lib/br_documents/documents/ie/rs.rb +12 -0
- data/lib/br_documents/documents/ie/sc.rb +12 -0
- data/lib/br_documents/documents/ie/se.rb +14 -0
- data/lib/br_documents/documents/ie/sp.rb +38 -0
- data/lib/br_documents/documents/ie/sp/industry.rb +22 -0
- data/lib/br_documents/documents/ie/sp/rural.rb +21 -0
- data/lib/br_documents/documents/ie/to.rb +14 -0
- data/lib/br_documents/version.rb +1 -1
- metadata +47 -5
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative 'ie/base'
|
2
|
+
|
3
|
+
Dir[File.expand_path("ie/{**/**,**}.rb", File.dirname(__FILE__))].each {|file| require file }
|
4
|
+
|
5
|
+
module BRDocuments
|
6
|
+
module IE
|
7
|
+
|
8
|
+
AVAILABLE_STATES = [
|
9
|
+
'AC',
|
10
|
+
'AL',
|
11
|
+
'AM',
|
12
|
+
'AP',
|
13
|
+
'BA',
|
14
|
+
'CE',
|
15
|
+
'DF',
|
16
|
+
'ES',
|
17
|
+
'GO',
|
18
|
+
'MA',
|
19
|
+
'MG',
|
20
|
+
'MS',
|
21
|
+
'MT',
|
22
|
+
'PA',
|
23
|
+
'PB',
|
24
|
+
'PE',
|
25
|
+
'PI',
|
26
|
+
'PR',
|
27
|
+
'RJ',
|
28
|
+
'RN',
|
29
|
+
'RO',
|
30
|
+
'RR',
|
31
|
+
'RS',
|
32
|
+
'SE',
|
33
|
+
'SP',
|
34
|
+
'TO'
|
35
|
+
]
|
36
|
+
|
37
|
+
|
38
|
+
def self.available_states
|
39
|
+
AVAILABLE_STATES
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# http://www.sintegra.gov.br/Cad_Estados/cad_AC.html
|
2
|
+
module BRDocuments
|
3
|
+
class IE::AC < IE::Base
|
4
|
+
|
5
|
+
set_verify_digits_weights first: %w(4 3 2 9 8 7 6 5 4 3 2),
|
6
|
+
last: %w(5 4 3 2 9 8 7 6 5 4 3 2)
|
7
|
+
|
8
|
+
set_format_regexp %r{^(01)[-.]?(\d{3})[-.]?(\d{3})[\/-]?(\d{3})[-.]?(\d{2})}
|
9
|
+
|
10
|
+
set_pretty_format_mask %(%s.%s.%s/%s-%s)
|
11
|
+
|
12
|
+
set_fixed_digits [0, 1]
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# http://www.sintegra.gov.br/Cad_Estados/cad_AL.html
|
2
|
+
module BRDocuments
|
3
|
+
class IE::AL < IE::Base
|
4
|
+
|
5
|
+
set_verify_digits_weights first: %w(9 8 7 6 5 4 3 2)
|
6
|
+
|
7
|
+
set_format_regexp %r{^(24)[-.]?(\d{3})[-.]?(\d{3})[-.]?(\d{1})}
|
8
|
+
|
9
|
+
set_pretty_format_mask %(%s.%s.%s-%s)
|
10
|
+
|
11
|
+
set_fixed_digits [2, 4]
|
12
|
+
|
13
|
+
COMPANIES_TYPES = {
|
14
|
+
"0": "Normal",
|
15
|
+
"3": "Produtor Rural",
|
16
|
+
"5": "Substituta",
|
17
|
+
"7": "Micro-Empresa Ambulante",
|
18
|
+
"8": "Micro-Empresa"
|
19
|
+
}
|
20
|
+
|
21
|
+
class << self
|
22
|
+
def companies_types_labels
|
23
|
+
COMPANIES_TYPES.values
|
24
|
+
end
|
25
|
+
|
26
|
+
def sample_company_type_digit
|
27
|
+
COMPANIES_TYPES.keys.sample.to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
def generate_root_numbers
|
31
|
+
numbers = super
|
32
|
+
# force digit
|
33
|
+
numbers[2] = sample_company_type_digit.to_i
|
34
|
+
|
35
|
+
numbers
|
36
|
+
end
|
37
|
+
|
38
|
+
def company_type(number)
|
39
|
+
# .to_s.to_sym to avoid nil.to_sym
|
40
|
+
COMPANIES_TYPES[company_type_digit(number).to_s.to_sym]
|
41
|
+
end
|
42
|
+
|
43
|
+
def company_type_digit(number)
|
44
|
+
number = new(number).strip
|
45
|
+
|
46
|
+
number.match(/^\d{2}(\d{1})/) && $1
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# http://www.sintegra.gov.br/Cad_Estados/cad_AM.html
|
2
|
+
module BRDocuments
|
3
|
+
class IE::AM < IE::Base
|
4
|
+
|
5
|
+
set_verify_digits_weights first: %w(9 8 7 6 5 4 3 2)
|
6
|
+
|
7
|
+
set_format_regexp %r{^(\d{2})[-.]?(\d{3})[-.]?(\d{3})[-.]?(\d{1})}
|
8
|
+
|
9
|
+
set_pretty_format_mask %(%s.%s.%s-%s)
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# http://www.sintegra.gov.br/Cad_Estados/cad_AP.html
|
2
|
+
module BRDocuments
|
3
|
+
class IE::AP < IE::Base
|
4
|
+
|
5
|
+
set_verify_digits_weights first: %w(9 8 7 6 5 4 3 2)
|
6
|
+
|
7
|
+
set_format_regexp %r{^(03)[-.]?(\d{6})[-.]?(\d{1})}
|
8
|
+
|
9
|
+
set_pretty_format_mask %(%s.%s-%s)
|
10
|
+
|
11
|
+
set_fixed_digits [0, 3]
|
12
|
+
|
13
|
+
# In RANGE_VALUES we remove the first '0' character so
|
14
|
+
# numbers are't treated as octal numberss
|
15
|
+
# see: :obtain_range_aux_value method
|
16
|
+
RANGE_VALUES = {
|
17
|
+
3000001..3017000 => [5, 0],
|
18
|
+
3017001..3019022 => [9, 1]
|
19
|
+
}.freeze
|
20
|
+
|
21
|
+
DEFAULT_RANGE_CONF = [0, 0]
|
22
|
+
|
23
|
+
def range_aux_values_hash
|
24
|
+
range_conf = obtain_range_aux_value(@number.dup)
|
25
|
+
|
26
|
+
{
|
27
|
+
:p => range_conf[0],
|
28
|
+
:d => range_conf[1]
|
29
|
+
} # equivalent to Hash[[:p, :d].zip(range_conf)]
|
30
|
+
end
|
31
|
+
|
32
|
+
def reduce_digits_weights(number, weights)
|
33
|
+
range_aux_values_hash[:p] + super(number, weights)
|
34
|
+
end
|
35
|
+
|
36
|
+
def calc_verify_digit(quotient_rest)
|
37
|
+
if ([11].member?(get_division_modulo - quotient_rest))
|
38
|
+
return range_aux_values_hash[:d]
|
39
|
+
end
|
40
|
+
|
41
|
+
super
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def obtain_range_aux_value(number)
|
46
|
+
remove_verify_digits(number)
|
47
|
+
|
48
|
+
# remove first '0' digit so number is not a octal
|
49
|
+
number = (stripped(number)[1..-1]).to_i
|
50
|
+
|
51
|
+
# We try to check if `number` is include in one of the pre defined range
|
52
|
+
range_conf = RANGE_VALUES.map do |range, aux_values|
|
53
|
+
range.include?(number) ? aux_values : nil
|
54
|
+
end.compact
|
55
|
+
|
56
|
+
# One of the configured values or the default
|
57
|
+
range_conf.shift || DEFAULT_RANGE_CONF
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# This class is a wrapper/interface to glue all Bahia IE generators and validators
|
2
|
+
module BRDocuments
|
3
|
+
module IE::BA
|
4
|
+
class << self
|
5
|
+
|
6
|
+
DIGITS_MOD_10 = [0,1,2,3,4,5,8]
|
7
|
+
DIGITS_MOD_11 = [6,7,9]
|
8
|
+
|
9
|
+
# Delegate all methods to specific class
|
10
|
+
def method_missing(method, *args)
|
11
|
+
class_for_number(args[0]).public_send(method, *args)
|
12
|
+
end
|
13
|
+
|
14
|
+
def generate(formatted = true, digits_count = 9, modulo = 10)
|
15
|
+
generator_class(digits_count, modulo).generate(formatted)
|
16
|
+
end
|
17
|
+
|
18
|
+
def generate_root_numbers(digits_count = 9, modulo = 10)
|
19
|
+
generator_class(digits_count, modulo).generate_root_numbers
|
20
|
+
end
|
21
|
+
|
22
|
+
def class_for_number(number)
|
23
|
+
class_name = class_name_for_number(number)
|
24
|
+
IE::BA.const_get(class_name)
|
25
|
+
end
|
26
|
+
|
27
|
+
def rand_generate(formatted = true)
|
28
|
+
generate(formatted, rand_digits_count, rand_modulo)
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
def generator_class(digits_count = 9, modulo = 10)
|
33
|
+
IE::BA.const_get("Digits#{digits_count}::Modulo#{modulo}")
|
34
|
+
end
|
35
|
+
|
36
|
+
def class_name_for_number(number)
|
37
|
+
[
|
38
|
+
digits_module_for(number),
|
39
|
+
modulo_class_for(number)
|
40
|
+
].join("::")
|
41
|
+
end
|
42
|
+
|
43
|
+
def digits_module_for(number)
|
44
|
+
eight_digits?(number) ? "Digits8" : "Digits9"
|
45
|
+
end
|
46
|
+
|
47
|
+
def modulo_class_for(number)
|
48
|
+
number = normalize_number(number)
|
49
|
+
|
50
|
+
# for eigth numbers documents, the first digit is cheched
|
51
|
+
# otherwhise the second digit is checked
|
52
|
+
check_position = eight_digits?(number) ? 0 : 1
|
53
|
+
check_digit = number.slice(check_position, 1).to_i
|
54
|
+
|
55
|
+
DIGITS_MOD_11.member?(check_digit) ? 'Modulo11' : 'Modulo10'
|
56
|
+
end
|
57
|
+
|
58
|
+
def eight_digits?(number)
|
59
|
+
normalize_number(number).size == 8
|
60
|
+
end
|
61
|
+
|
62
|
+
def nine_digits?(number)
|
63
|
+
normalize_number(number).size == 9
|
64
|
+
end
|
65
|
+
|
66
|
+
def normalize_number(number)
|
67
|
+
number.to_s.gsub(/[^\d+]/, '')
|
68
|
+
end
|
69
|
+
|
70
|
+
def rand_digits_count
|
71
|
+
rand_boolean ? 9 : 8
|
72
|
+
end
|
73
|
+
|
74
|
+
def rand_modulo
|
75
|
+
(rand_boolean ? 10 : 11)
|
76
|
+
end
|
77
|
+
|
78
|
+
def rand_boolean
|
79
|
+
# 50%/50% of chance
|
80
|
+
rand(2) > 0
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# http://www.sintegra.gov.br/Cad_Estados/cad_BA.html
|
2
|
+
module BRDocuments
|
3
|
+
module IE
|
4
|
+
module BA
|
5
|
+
class Base < IE::Base
|
6
|
+
|
7
|
+
set_format_regexp %r{(\d{3})[-.]?(\d{3})[-.]?(\d{2,3})}
|
8
|
+
|
9
|
+
set_pretty_format_mask %(%s.%s.%s)
|
10
|
+
|
11
|
+
# I don't know why in Bahia they calculate the LAST digit FIRST and
|
12
|
+
# the FIRST digit LAST, wtf
|
13
|
+
def calculate_verify_digits
|
14
|
+
super.reverse
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.valid_fixed_digits?(number)
|
18
|
+
number = new(number).normalize
|
19
|
+
fixed_numbers = self.const_get('FIXED_INITIAL_NUMBERS')
|
20
|
+
|
21
|
+
fixed_numbers.member?(number[fixed_digits_positions].to_s)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.fixed_digits
|
25
|
+
[super.sample.to_i]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module BRDocuments::IE::BA
|
33
|
+
module Digits8
|
34
|
+
end
|
35
|
+
module Digits9
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative '../modulo_10'
|
2
|
+
|
3
|
+
module BRDocuments
|
4
|
+
module IE
|
5
|
+
class BA::Digits9::Modulo10 < IE::BA::Modulo10
|
6
|
+
|
7
|
+
set_verify_digits_weights first: %w(8 7 6 5 4 3 2),
|
8
|
+
last: %w(9 8 7 6 5 4 3 2)
|
9
|
+
|
10
|
+
|
11
|
+
# 9 digits IE from bahia have FIXED NUMBER in the second position
|
12
|
+
INITIAL_FIX_NUMBERS_POSITION = 1
|
13
|
+
|
14
|
+
def fixed_digits_positions
|
15
|
+
self.const_get('INITIAL_FIX_NUMBERS_POSITION')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative '../modulo_11'
|
2
|
+
|
3
|
+
module BRDocuments
|
4
|
+
module IE
|
5
|
+
class BA::Digits9::Modulo11 < IE::BA::Modulo11
|
6
|
+
|
7
|
+
set_verify_digits_weights first: %w(8 7 6 5 4 3 2),
|
8
|
+
last: %w(9 8 7 6 5 4 3 2)
|
9
|
+
|
10
|
+
|
11
|
+
# 9 digits IE from bahia have FIXED NUMBER in the second position
|
12
|
+
INITIAL_FIX_NUMBERS_POSITION = 1
|
13
|
+
|
14
|
+
def fixed_digits_positions
|
15
|
+
self.const_get('INITIAL_FIX_NUMBERS_POSITION')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
# http://www.sintegra.gov.br/Cad_Estados/cad_BA.html
|
4
|
+
module BRDocuments
|
5
|
+
module IE
|
6
|
+
module BA
|
7
|
+
class Modulo10 < IE::BA::Base
|
8
|
+
|
9
|
+
# All documents generated through modulo 11 may start
|
10
|
+
# with one of theses values
|
11
|
+
FIXED_INITIAL_NUMBERS = %w(0 1 2 3 4 5 8)
|
12
|
+
|
13
|
+
# Force modulo 10
|
14
|
+
set_division_modulo 10
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
# http://www.sintegra.gov.br/Cad_Estados/cad_BA.html
|
4
|
+
module BRDocuments
|
5
|
+
module IE
|
6
|
+
module BA
|
7
|
+
class Modulo11 < IE::BA::Base
|
8
|
+
|
9
|
+
# All documents generated through modulo 11 may start
|
10
|
+
# with one of theses values
|
11
|
+
FIXED_INITIAL_NUMBERS = %w(6 7 9)
|
12
|
+
|
13
|
+
# Force modulo 11
|
14
|
+
set_division_modulo 11
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# http://www.sintegra.gov.br/insc_est.html
|
2
|
+
module BRDocuments
|
3
|
+
module IE
|
4
|
+
class Base < ::DigitChecksum::BaseDocument
|
5
|
+
# MOD 11
|
6
|
+
set_division_modulo 11
|
7
|
+
|
8
|
+
# remove any non digit from document number
|
9
|
+
set_clear_number_regexp %r{[^(\d+)]}
|
10
|
+
|
11
|
+
# numbers sampled to generate new document numbers
|
12
|
+
set_generator_numbers (0..9).to_a
|
13
|
+
|
14
|
+
# Start from first position
|
15
|
+
INITIAL_FIX_NUMBERS_POSITION = 0
|
16
|
+
# No one
|
17
|
+
FIXED_INITIAL_NUMBERS = []
|
18
|
+
|
19
|
+
def valid?
|
20
|
+
return false unless valid_fixed_digits?
|
21
|
+
|
22
|
+
return super
|
23
|
+
end
|
24
|
+
|
25
|
+
def valid_fixed_digits?
|
26
|
+
return true unless validate_fixed_digits?
|
27
|
+
|
28
|
+
self.class.valid_fixed_digits?(self.number)
|
29
|
+
end
|
30
|
+
|
31
|
+
def validate_fixed_digits?
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
class << self
|
36
|
+
def valid_fixed_digits?(number)
|
37
|
+
number = new(number).normalize
|
38
|
+
|
39
|
+
initial_pos = fixed_digits_positions
|
40
|
+
fixed_numbers = fixed_digits
|
41
|
+
|
42
|
+
return (number.slice(initial_pos, fixed_numbers.size) == fixed_numbers)
|
43
|
+
end
|
44
|
+
|
45
|
+
def generate_root_numbers
|
46
|
+
numbers = (root_digits_count - fixed_digits.size).times.map {
|
47
|
+
get_generator_numbers.sample.to_i
|
48
|
+
}
|
49
|
+
|
50
|
+
append_fixed_digits(numbers)
|
51
|
+
|
52
|
+
numbers
|
53
|
+
end
|
54
|
+
|
55
|
+
def fixed_digits_positions
|
56
|
+
self.const_get('INITIAL_FIX_NUMBERS_POSITION')
|
57
|
+
end
|
58
|
+
|
59
|
+
def fixed_digits
|
60
|
+
self.const_get('FIXED_INITIAL_NUMBERS')
|
61
|
+
end
|
62
|
+
|
63
|
+
def set_fixed_digits(initial_numbers)
|
64
|
+
self.const_set('FIXED_INITIAL_NUMBERS', initial_numbers).freeze
|
65
|
+
end
|
66
|
+
|
67
|
+
protected
|
68
|
+
def append_fixed_digits(numbers)
|
69
|
+
fixed_digits.each_with_index {|number, index|
|
70
|
+
numbers.insert(fixed_digits_positions + index, number)
|
71
|
+
}
|
72
|
+
|
73
|
+
numbers
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|