brazilian_documents 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|