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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/README.md +263 -15
  4. data/br_documents.gemspec +5 -5
  5. data/lib/br_documents.rb +3 -0
  6. data/lib/br_documents/documents/cnpj.rb +7 -10
  7. data/lib/br_documents/documents/cpf.rb +7 -10
  8. data/lib/br_documents/documents/ie.rb +43 -0
  9. data/lib/br_documents/documents/ie/ac.rb +15 -0
  10. data/lib/br_documents/documents/ie/al.rb +50 -0
  11. data/lib/br_documents/documents/ie/am.rb +12 -0
  12. data/lib/br_documents/documents/ie/ap.rb +61 -0
  13. data/lib/br_documents/documents/ie/ba.rb +84 -0
  14. data/lib/br_documents/documents/ie/ba/base.rb +37 -0
  15. data/lib/br_documents/documents/ie/ba/digits8/modulo_10.rb +12 -0
  16. data/lib/br_documents/documents/ie/ba/digits8/modulo_11.rb +12 -0
  17. data/lib/br_documents/documents/ie/ba/digits9/modulo_10.rb +19 -0
  18. data/lib/br_documents/documents/ie/ba/digits9/modulo_11.rb +20 -0
  19. data/lib/br_documents/documents/ie/ba/modulo_10.rb +19 -0
  20. data/lib/br_documents/documents/ie/ba/modulo_11.rb +18 -0
  21. data/lib/br_documents/documents/ie/base.rb +79 -0
  22. data/lib/br_documents/documents/ie/ce.rb +14 -0
  23. data/lib/br_documents/documents/ie/df.rb +16 -0
  24. data/lib/br_documents/documents/ie/es.rb +12 -0
  25. data/lib/br_documents/documents/ie/go.rb +14 -0
  26. data/lib/br_documents/documents/ie/ma.rb +14 -0
  27. data/lib/br_documents/documents/ie/mg.rb +66 -0
  28. data/lib/br_documents/documents/ie/ms.rb +14 -0
  29. data/lib/br_documents/documents/ie/mt.rb +14 -0
  30. data/lib/br_documents/documents/ie/pa.rb +14 -0
  31. data/lib/br_documents/documents/ie/pb.rb +14 -0
  32. data/lib/br_documents/documents/ie/pe.rb +38 -0
  33. data/lib/br_documents/documents/ie/pe/current.rb +13 -0
  34. data/lib/br_documents/documents/ie/pe/legacy.rb +12 -0
  35. data/lib/br_documents/documents/ie/pi.rb +14 -0
  36. data/lib/br_documents/documents/ie/pr.rb +13 -0
  37. data/lib/br_documents/documents/ie/rj.rb +25 -0
  38. data/lib/br_documents/documents/ie/rn.rb +14 -0
  39. data/lib/br_documents/documents/ie/ro.rb +44 -0
  40. data/lib/br_documents/documents/ie/ro/current.rb +24 -0
  41. data/lib/br_documents/documents/ie/ro/legacy.rb +13 -0
  42. data/lib/br_documents/documents/ie/rr.rb +19 -0
  43. data/lib/br_documents/documents/ie/rs.rb +12 -0
  44. data/lib/br_documents/documents/ie/sc.rb +12 -0
  45. data/lib/br_documents/documents/ie/se.rb +14 -0
  46. data/lib/br_documents/documents/ie/sp.rb +38 -0
  47. data/lib/br_documents/documents/ie/sp/industry.rb +22 -0
  48. data/lib/br_documents/documents/ie/sp/rural.rb +21 -0
  49. data/lib/br_documents/documents/ie/to.rb +14 -0
  50. data/lib/br_documents/version.rb +1 -1
  51. 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,12 @@
1
+ require_relative '../modulo_10'
2
+
3
+ module BRDocuments
4
+ module IE
5
+ class BA::Digits8::Modulo10 < IE::BA::Modulo10
6
+
7
+ set_verify_digits_weights first: %w(7 6 5 4 3 2),
8
+ last: %w(8 7 6 5 4 3 2)
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ require_relative '../modulo_11'
2
+
3
+ module BRDocuments
4
+ module IE
5
+ class BA::Digits8::Modulo11 < IE::BA::Modulo11
6
+ set_verify_digits_weights first: %w(7 6 5 4 3 2),
7
+ last: %w(8 7 6 5 4 3 2)
8
+
9
+ end
10
+ end
11
+ end
12
+
@@ -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