boleto_bancario 0.0.1.beta → 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 +7 -0
- data/Changelog.markdown +58 -2
- data/README.markdown +679 -156
- data/lib/boleto_bancario/calculos/documento.rb +191 -0
- data/lib/boleto_bancario/calculos/fator_vencimento.rb +78 -31
- data/lib/boleto_bancario/calculos/modulo11_fator_de9a2.rb +65 -0
- data/lib/boleto_bancario/calculos/modulo11_fator_de9a2_resto_x.rb +5 -51
- data/lib/boleto_bancario/calculos/modulo_numero_de_controle.rb +117 -0
- data/lib/boleto_bancario/core/banco_brasil.rb +30 -5
- data/lib/boleto_bancario/core/banrisul.rb +182 -0
- data/lib/boleto_bancario/core/boleto.rb +97 -35
- data/lib/boleto_bancario/core/bradesco.rb +28 -16
- data/lib/boleto_bancario/core/c6_bank.rb +155 -0
- data/lib/boleto_bancario/core/caixa.rb +233 -0
- data/lib/boleto_bancario/core/inter.rb +155 -0
- data/lib/boleto_bancario/core/itau.rb +20 -10
- data/lib/boleto_bancario/core/nubank.rb +156 -0
- data/lib/boleto_bancario/core/santander.rb +19 -22
- data/lib/boleto_bancario/core/sicoob.rb +172 -0
- data/lib/boleto_bancario/core/sicredi.rb +290 -0
- data/lib/boleto_bancario/locales/pt-BR.yml +55 -0
- data/lib/boleto_bancario/renderers/base.rb +154 -0
- data/lib/boleto_bancario/renderers/html_renderer.rb +92 -0
- data/lib/boleto_bancario/renderers/pdf_renderer.rb +130 -0
- data/lib/boleto_bancario/renderers/png_renderer.rb +66 -0
- data/lib/boleto_bancario/templates/_barcode.html.erb +3 -0
- data/lib/boleto_bancario/templates/_cedente.html.erb +14 -0
- data/lib/boleto_bancario/templates/_header.html.erb +4 -0
- data/lib/boleto_bancario/templates/_instructions.html.erb +10 -0
- data/lib/boleto_bancario/templates/_payment.html.erb +36 -0
- data/lib/boleto_bancario/templates/_sacado.html.erb +10 -0
- data/lib/boleto_bancario/templates/boleto.html.erb +22 -0
- data/lib/boleto_bancario/templates/boleto_styles.css +18 -0
- data/lib/boleto_bancario/version.rb +3 -2
- data/lib/boleto_bancario.rb +48 -19
- data/lib/generators/boleto_bancario/views_generator.rb +47 -0
- metadata +140 -106
- data/.gitignore +0 -18
- data/.rspec +0 -1
- data/.rvmrc +0 -1
- data/Gemfile +0 -3
- data/Planning.markdown +0 -131
- data/Rakefile +0 -9
- data/TODO.markdown +0 -5
- data/boleto_bancario.gemspec +0 -25
- data/documentacoes_dos_boletos/Bradesco/Manual_BRADESCO.PDF +0 -0
- data/spec/boleto_bancario/calculos/digitos_spec.rb +0 -19
- data/spec/boleto_bancario/calculos/fator_vencimento_spec.rb +0 -59
- data/spec/boleto_bancario/calculos/fatores_de_multiplicacao_spec.rb +0 -69
- data/spec/boleto_bancario/calculos/linha_digitavel_spec.rb +0 -57
- data/spec/boleto_bancario/calculos/modulo10_spec.rb +0 -49
- data/spec/boleto_bancario/calculos/modulo11_fator_de2a7_spec.rb +0 -43
- data/spec/boleto_bancario/calculos/modulo11_fator_de2a9_resto_zero_spec.rb +0 -39
- data/spec/boleto_bancario/calculos/modulo11_fator_de2a9_spec.rb +0 -61
- data/spec/boleto_bancario/calculos/modulo11_fator_de9a2_resto_x_spec.rb +0 -37
- data/spec/boleto_bancario/calculos/modulo11_spec.rb +0 -19
- data/spec/boleto_bancario/core/banco_brasil_spec.rb +0 -383
- data/spec/boleto_bancario/core/boleto_spec.rb +0 -102
- data/spec/boleto_bancario/core/bradesco_spec.rb +0 -170
- data/spec/boleto_bancario/core/itau_spec.rb +0 -336
- data/spec/boleto_bancario/core/santander_spec.rb +0 -135
- data/spec/shared_examples/boleto_bancario_shared_example.rb +0 -164
- data/spec/spec_helper.rb +0 -14
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BoletoBancario
|
|
4
|
+
module Calculos
|
|
5
|
+
# Classe responsável pela validação e formatação de documentos (CPF e CNPJ).
|
|
6
|
+
#
|
|
7
|
+
# === Validação de CPF
|
|
8
|
+
#
|
|
9
|
+
# O CPF possui 11 dígitos e é validado através de dois dígitos verificadores
|
|
10
|
+
# calculados pelo módulo 11.
|
|
11
|
+
#
|
|
12
|
+
# === Validação de CNPJ
|
|
13
|
+
#
|
|
14
|
+
# O CNPJ possui 14 dígitos e é validado através de dois dígitos verificadores
|
|
15
|
+
# calculados pelo módulo 11.
|
|
16
|
+
#
|
|
17
|
+
# @example Validação
|
|
18
|
+
#
|
|
19
|
+
# Documento.valid?('111.444.777-35')
|
|
20
|
+
# #=> true
|
|
21
|
+
#
|
|
22
|
+
# Documento.valid?('11.222.333/0001-81')
|
|
23
|
+
# #=> true
|
|
24
|
+
#
|
|
25
|
+
# @example Formatação
|
|
26
|
+
#
|
|
27
|
+
# Documento.format('11144477735')
|
|
28
|
+
# #=> '111.444.777-35'
|
|
29
|
+
#
|
|
30
|
+
# Documento.format('11222333000181')
|
|
31
|
+
# #=> '11.222.333/0001-81'
|
|
32
|
+
#
|
|
33
|
+
class Documento
|
|
34
|
+
CPF_SIZE = 11
|
|
35
|
+
CNPJ_SIZE = 14
|
|
36
|
+
|
|
37
|
+
# CPF weights for first digit calculation
|
|
38
|
+
CPF_WEIGHTS_FIRST = [10, 9, 8, 7, 6, 5, 4, 3, 2].freeze
|
|
39
|
+
|
|
40
|
+
# CPF weights for second digit calculation
|
|
41
|
+
CPF_WEIGHTS_SECOND = [11, 10, 9, 8, 7, 6, 5, 4, 3, 2].freeze
|
|
42
|
+
|
|
43
|
+
# CNPJ weights for first digit calculation
|
|
44
|
+
CNPJ_WEIGHTS_FIRST = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2].freeze
|
|
45
|
+
|
|
46
|
+
# CNPJ weights for second digit calculation
|
|
47
|
+
CNPJ_WEIGHTS_SECOND = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2].freeze
|
|
48
|
+
|
|
49
|
+
class << self
|
|
50
|
+
# Valida se o documento é um CPF ou CNPJ válido.
|
|
51
|
+
#
|
|
52
|
+
# @param [String] documento O documento a ser validado
|
|
53
|
+
# @return [Boolean] true se válido, false caso contrário
|
|
54
|
+
#
|
|
55
|
+
def valid?(documento)
|
|
56
|
+
return false if documento.blank?
|
|
57
|
+
|
|
58
|
+
digits = only_digits(documento)
|
|
59
|
+
|
|
60
|
+
case digits.size
|
|
61
|
+
when CPF_SIZE
|
|
62
|
+
valid_cpf?(digits)
|
|
63
|
+
when CNPJ_SIZE
|
|
64
|
+
valid_cnpj?(digits)
|
|
65
|
+
else
|
|
66
|
+
false
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Formata o documento com pontuação.
|
|
71
|
+
#
|
|
72
|
+
# @param [String] documento O documento a ser formatado
|
|
73
|
+
# @return [String] O documento formatado
|
|
74
|
+
#
|
|
75
|
+
def format(documento)
|
|
76
|
+
return documento if documento.blank?
|
|
77
|
+
|
|
78
|
+
digits = only_digits(documento)
|
|
79
|
+
|
|
80
|
+
case digits.size
|
|
81
|
+
when CPF_SIZE
|
|
82
|
+
format_cpf(digits)
|
|
83
|
+
when CNPJ_SIZE
|
|
84
|
+
format_cnpj(digits)
|
|
85
|
+
else
|
|
86
|
+
documento.to_s
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Verifica se o documento é um CPF.
|
|
91
|
+
#
|
|
92
|
+
# @param [String] documento O documento a ser verificado
|
|
93
|
+
# @return [Boolean]
|
|
94
|
+
#
|
|
95
|
+
def cpf?(documento)
|
|
96
|
+
only_digits(documento).size == CPF_SIZE
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Verifica se o documento é um CNPJ.
|
|
100
|
+
#
|
|
101
|
+
# @param [String] documento O documento a ser verificado
|
|
102
|
+
# @return [Boolean]
|
|
103
|
+
#
|
|
104
|
+
def cnpj?(documento)
|
|
105
|
+
only_digits(documento).size == CNPJ_SIZE
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
# Remove caracteres não numéricos.
|
|
111
|
+
#
|
|
112
|
+
# @param [String] value
|
|
113
|
+
# @return [String]
|
|
114
|
+
#
|
|
115
|
+
def only_digits(value)
|
|
116
|
+
value.to_s.gsub(/\D/, '')
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Valida um CPF.
|
|
120
|
+
#
|
|
121
|
+
# @param [String] digits Os 11 dígitos do CPF
|
|
122
|
+
# @return [Boolean]
|
|
123
|
+
#
|
|
124
|
+
def valid_cpf?(digits)
|
|
125
|
+
return false if invalid_sequence?(digits)
|
|
126
|
+
|
|
127
|
+
first_digit = calculate_digit(digits[0, 9], CPF_WEIGHTS_FIRST)
|
|
128
|
+
second_digit = calculate_digit(digits[0, 10], CPF_WEIGHTS_SECOND)
|
|
129
|
+
|
|
130
|
+
digits[9].to_i == first_digit && digits[10].to_i == second_digit
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Valida um CNPJ.
|
|
134
|
+
#
|
|
135
|
+
# @param [String] digits Os 14 dígitos do CNPJ
|
|
136
|
+
# @return [Boolean]
|
|
137
|
+
#
|
|
138
|
+
def valid_cnpj?(digits)
|
|
139
|
+
return false if invalid_sequence?(digits)
|
|
140
|
+
|
|
141
|
+
first_digit = calculate_digit(digits[0, 12], CNPJ_WEIGHTS_FIRST)
|
|
142
|
+
second_digit = calculate_digit(digits[0, 13], CNPJ_WEIGHTS_SECOND)
|
|
143
|
+
|
|
144
|
+
digits[12].to_i == first_digit && digits[13].to_i == second_digit
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Verifica se todos os dígitos são iguais (sequência inválida).
|
|
148
|
+
#
|
|
149
|
+
# @param [String] digits
|
|
150
|
+
# @return [Boolean]
|
|
151
|
+
#
|
|
152
|
+
def invalid_sequence?(digits)
|
|
153
|
+
digits.chars.uniq.size == 1
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Calcula um dígito verificador usando módulo 11.
|
|
157
|
+
#
|
|
158
|
+
# @param [String] digits Os dígitos base
|
|
159
|
+
# @param [Array<Integer>] weights Os pesos para multiplicação
|
|
160
|
+
# @return [Integer] O dígito calculado
|
|
161
|
+
#
|
|
162
|
+
def calculate_digit(digits, weights)
|
|
163
|
+
sum = digits.chars.each_with_index.sum do |digit, index|
|
|
164
|
+
digit.to_i * weights[index]
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
remainder = sum % 11
|
|
168
|
+
remainder < 2 ? 0 : 11 - remainder
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Formata CPF com pontuação.
|
|
172
|
+
#
|
|
173
|
+
# @param [String] digits
|
|
174
|
+
# @return [String]
|
|
175
|
+
#
|
|
176
|
+
def format_cpf(digits)
|
|
177
|
+
"#{digits[0, 3]}.#{digits[3, 3]}.#{digits[6, 3]}-#{digits[9, 2]}"
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Formata CNPJ com pontuação.
|
|
181
|
+
#
|
|
182
|
+
# @param [String] digits
|
|
183
|
+
# @return [String]
|
|
184
|
+
#
|
|
185
|
+
def format_cnpj(digits)
|
|
186
|
+
"#{digits[0, 2]}.#{digits[2, 3]}.#{digits[5, 3]}/#{digits[8, 4]}-#{digits[12, 2]}"
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
@@ -1,33 +1,44 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
module BoletoBancario
|
|
3
4
|
module Calculos
|
|
4
5
|
# Classe responsável pelo cálculo de Fator de Vencimento do boleto bancário.
|
|
5
6
|
#
|
|
6
|
-
# ===
|
|
7
|
+
# === Descrição
|
|
7
8
|
#
|
|
8
9
|
# Conforme Carta-circular 002926 do Banco Central do Brasil, de 24/07/2000, recomenda-se a indicação do Fator de Vencimento no Código de Barras.
|
|
9
10
|
# A partir de 02/04/2001, o Banco acolhedor/recebedor não será mais responsável por eventuais diferenças de recebimento de BOLETOs fora do prazo,
|
|
10
11
|
# ou sem a indicação do fator de vencimento.
|
|
11
12
|
#
|
|
13
|
+
# === Atualização FEBRABAN 2025
|
|
14
|
+
#
|
|
15
|
+
# Em 22/02/2025, o fator de vencimento atingiu o limite de 9999 (baseado em 07/10/1997).
|
|
16
|
+
# A partir desta data, o cálculo utiliza uma nova data base (29/05/2022) e reinicia em 1000.
|
|
17
|
+
#
|
|
12
18
|
# === Forma para obtenção do Fator de Vencimento
|
|
13
19
|
#
|
|
14
|
-
# Calcula-se <b>o número de dias corridos</b> entre a data base
|
|
20
|
+
# Calcula-se <b>o número de dias corridos</b> entre a data base e a do vencimento desejado:
|
|
21
|
+
#
|
|
22
|
+
# Para datas anteriores a 22/02/2025:
|
|
23
|
+
# Data base: 07/10/1997
|
|
24
|
+
# Vencimento: 04/07/2000 => Fator: 1001
|
|
15
25
|
#
|
|
16
|
-
#
|
|
17
|
-
# Data base
|
|
18
|
-
#
|
|
26
|
+
# Para datas a partir de 22/02/2025:
|
|
27
|
+
# Data base: 29/05/2022
|
|
28
|
+
# Fator inicial: 1000
|
|
29
|
+
# Vencimento: 22/02/2025 => Fator: 1000
|
|
19
30
|
#
|
|
20
31
|
# === Atenção
|
|
21
32
|
#
|
|
22
|
-
# Caso ocorra divergência entre a data impressa no campo
|
|
33
|
+
# Caso ocorra divergência entre a data impressa no campo "data de vencimento" e a constante no código de barras,
|
|
23
34
|
# o recebimento se dará da seguinte forma:
|
|
24
35
|
#
|
|
25
|
-
# * Quando pago por sistemas eletrônicos (Home-Banking, Auto-Atendimento, Internet, SISPAG, telefone, etc.), prevalecerá à representada no
|
|
26
|
-
# * Quando quitado na rede de agências, diretamente no caixa, será considerada a data impressa no campo
|
|
36
|
+
# * Quando pago por sistemas eletrônicos (Home-Banking, Auto-Atendimento, Internet, SISPAG, telefone, etc.), prevalecerá à representada no "código de barras";
|
|
37
|
+
# * Quando quitado na rede de agências, diretamente no caixa, será considerada a data impressa no campo "vencimento" do BOLETO.
|
|
27
38
|
#
|
|
28
39
|
# @return [String] retorna o resultado do cálculo. <b>Deve conter 4 dígitos</b>.
|
|
29
40
|
#
|
|
30
|
-
# @example
|
|
41
|
+
# @example Datas anteriores à transição
|
|
31
42
|
#
|
|
32
43
|
# FatorVencimento.new(Date.parse("2012-12-02"))
|
|
33
44
|
# #=> "5535"
|
|
@@ -35,51 +46,87 @@ module BoletoBancario
|
|
|
35
46
|
# FatorVencimento.new(Date.parse("1997-10-08"))
|
|
36
47
|
# #=> "0001"
|
|
37
48
|
#
|
|
38
|
-
#
|
|
39
|
-
# #=> "5549"
|
|
49
|
+
# @example Datas após a transição FEBRABAN 2025
|
|
40
50
|
#
|
|
41
|
-
# FatorVencimento.new(Date.parse("
|
|
42
|
-
# #=> "
|
|
51
|
+
# FatorVencimento.new(Date.parse("2025-02-21"))
|
|
52
|
+
# #=> "9999"
|
|
53
|
+
#
|
|
54
|
+
# FatorVencimento.new(Date.parse("2025-02-22"))
|
|
55
|
+
# #=> "1000"
|
|
56
|
+
#
|
|
57
|
+
# FatorVencimento.new(Date.parse("2025-02-23"))
|
|
58
|
+
# #=> "1001"
|
|
43
59
|
#
|
|
44
60
|
class FatorVencimento < String
|
|
61
|
+
# Data base original utilizada até 21/02/2025
|
|
62
|
+
OLD_BASE_DATE = Date.new(1997, 10, 7).freeze
|
|
63
|
+
|
|
64
|
+
# Nova data base utilizada a partir de 22/02/2025
|
|
65
|
+
NEW_BASE_DATE = Date.new(2022, 5, 29).freeze
|
|
66
|
+
|
|
67
|
+
# Data de transição para o novo cálculo
|
|
68
|
+
TRANSITION_DATE = Date.new(2025, 2, 22).freeze
|
|
69
|
+
|
|
70
|
+
# Fator inicial para a nova data base
|
|
71
|
+
NEW_BASE_FACTOR = 1000
|
|
72
|
+
|
|
45
73
|
attr_reader :base_date
|
|
46
|
-
|
|
47
|
-
# @param [Date]
|
|
74
|
+
|
|
75
|
+
# @param [Date] expiration_date Data de vencimento do boleto
|
|
76
|
+
# @param [Date] base_date Data base para cálculo (opcional, determinado automaticamente)
|
|
48
77
|
# @return [String] retorna o resultado do cálculo. <b>Deve conter 4 dígitos</b>.
|
|
49
|
-
# @example
|
|
50
|
-
# FatorVencimento.new(Date.parse("2012-09-02"))
|
|
51
|
-
# #=> "5444"
|
|
52
|
-
#
|
|
53
|
-
# FatorVencimento.new(Date.parse("1999-10-01"))
|
|
54
|
-
# #=> "0724"
|
|
55
78
|
#
|
|
56
|
-
#
|
|
57
|
-
#
|
|
79
|
+
# @example
|
|
80
|
+
# FatorVencimento.new(Date.parse("2025-03-01"))
|
|
81
|
+
# #=> "1007"
|
|
58
82
|
#
|
|
59
|
-
def initialize(expiration_date, base_date =
|
|
60
|
-
@base_date = base_date
|
|
83
|
+
def initialize(expiration_date, base_date = nil)
|
|
61
84
|
@expiration_date = expiration_date
|
|
85
|
+
@base_date = base_date || determine_base_date
|
|
62
86
|
|
|
63
87
|
if @expiration_date.present?
|
|
64
88
|
super(calculate)
|
|
89
|
+
else
|
|
90
|
+
super()
|
|
65
91
|
end
|
|
66
92
|
end
|
|
67
93
|
|
|
68
94
|
# Cálculo da data de vencimento com a data base.
|
|
95
|
+
# Para ambos os períodos, o fator é simplesmente o número de dias desde a data base.
|
|
96
|
+
# A nova data base (29/05/2022) foi escolhida para que 22/02/2025 resulte em fator 1000.
|
|
69
97
|
#
|
|
70
98
|
# @return [String] exatamente 4 dígitos
|
|
71
99
|
#
|
|
72
100
|
def calculate
|
|
73
|
-
|
|
101
|
+
days_from_base.to_s.rjust(4, '0')
|
|
74
102
|
end
|
|
75
103
|
|
|
76
|
-
|
|
104
|
+
private
|
|
105
|
+
|
|
106
|
+
# Determina qual data base usar com base na data de vencimento
|
|
77
107
|
#
|
|
78
|
-
#
|
|
108
|
+
# @return [Date] a data base apropriada
|
|
109
|
+
#
|
|
110
|
+
def determine_base_date
|
|
111
|
+
return OLD_BASE_DATE unless @expiration_date
|
|
112
|
+
|
|
113
|
+
uses_new_calculation? ? NEW_BASE_DATE : OLD_BASE_DATE
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Verifica se deve usar o novo cálculo (pós-transição FEBRABAN)
|
|
117
|
+
#
|
|
118
|
+
# @return [Boolean]
|
|
119
|
+
#
|
|
120
|
+
def uses_new_calculation?
|
|
121
|
+
@expiration_date.is_a?(Date) && @expiration_date >= TRANSITION_DATE
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Calcula a diferença em dias entre a data de vencimento e a data base.
|
|
79
125
|
# Chamando #to_i para não retornar um Float.
|
|
80
|
-
# @return [Integer] diff between this two dates.
|
|
81
126
|
#
|
|
82
|
-
|
|
127
|
+
# @return [Integer] diferença em dias
|
|
128
|
+
#
|
|
129
|
+
def days_from_base
|
|
83
130
|
(@expiration_date - @base_date).to_i
|
|
84
131
|
end
|
|
85
132
|
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
module BoletoBancario
|
|
2
|
+
module Calculos
|
|
3
|
+
# === Módulo 11 Fator de 9 a 2
|
|
4
|
+
#
|
|
5
|
+
# === Passos
|
|
6
|
+
#
|
|
7
|
+
# 1) Tomando-se os algarismos multiplique-os, iniciando-se da direita para a esquerda,
|
|
8
|
+
# pela seqüência numérica de 9 a 2 (9, 8, 7, 6, 5, 4, 3, 2 ... e assim por diante).
|
|
9
|
+
#
|
|
10
|
+
# 2) Some o resultado de cada produto efetuado e determine o total como (N).
|
|
11
|
+
#
|
|
12
|
+
# 3) Divida o total (N) por 11 e determine o resto obtido da divisão como Mod 11(N).
|
|
13
|
+
#
|
|
14
|
+
# ==== Exemplo Normal
|
|
15
|
+
#
|
|
16
|
+
# Considerando o seguinte número: '89234560'.
|
|
17
|
+
#
|
|
18
|
+
# 1) Multiplicando a seqüência de multiplicadores:
|
|
19
|
+
#
|
|
20
|
+
# 8 9 2 3 4 5 6 0
|
|
21
|
+
# * * * * * * * *
|
|
22
|
+
# 2 3 4 5 6 7 8 9
|
|
23
|
+
#
|
|
24
|
+
# 2) Soma-se o resultado dos produtos obtidos no item “1” acima:
|
|
25
|
+
#
|
|
26
|
+
# 16 + 27 + 8 + 15 + 24 + 35 + 48 + 0
|
|
27
|
+
# # => 173
|
|
28
|
+
#
|
|
29
|
+
# 3) Determina-se o resto da Divisão:
|
|
30
|
+
#
|
|
31
|
+
# 173 % 11
|
|
32
|
+
# # => 8 =============> Resultado final retornado.
|
|
33
|
+
#
|
|
34
|
+
# @param [String]: Corresponde ao número a ser calculado o Módulo 11 no fator de 9 a 2.
|
|
35
|
+
# @return [String] Retorna o resultado do cálculo descrito acima.
|
|
36
|
+
#
|
|
37
|
+
# @example
|
|
38
|
+
#
|
|
39
|
+
# BoletoBancario::Calculos::Modulo11FatorDe9a2.new('12345')
|
|
40
|
+
# # => '5'
|
|
41
|
+
#
|
|
42
|
+
# BoletoBancario::Calculos::Modulo11FatorDe9a2.new('246')
|
|
43
|
+
# # => '1'
|
|
44
|
+
#
|
|
45
|
+
class Modulo11FatorDe9a2 < Modulo11
|
|
46
|
+
# Sequência numérica de 9 a 2 que será feito a multiplicação de cada dígito
|
|
47
|
+
# do número passado no #initialize.
|
|
48
|
+
#
|
|
49
|
+
# @return [Array] Sequência numérica
|
|
50
|
+
#
|
|
51
|
+
def fatores
|
|
52
|
+
[9, 8, 7, 6, 5, 4, 3, 2]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Calcula o número pelos fatores de multiplicação de 9 a 2.
|
|
56
|
+
# Depois calcula o resto da divisão por 11.
|
|
57
|
+
#
|
|
58
|
+
# @return [Fixnum]
|
|
59
|
+
#
|
|
60
|
+
def calculate
|
|
61
|
+
mod_division
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -1,37 +1,9 @@
|
|
|
1
1
|
module BoletoBancario
|
|
2
2
|
module Calculos
|
|
3
|
-
#
|
|
3
|
+
# === Módulo 11 Fator de 9 a 2 - Resto 10, sendo X
|
|
4
|
+
# <b>Essa classe difere da outra com Modulo11FatorDe9a2, no momento de verificar o resto da divisão por 11.</b>
|
|
4
5
|
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# 1) Tomando-se os algarismos multiplique-os, iniciando-se da direita para a esquerda,
|
|
8
|
-
# pela seqüência numérica de 9 a 2 (9, 8, 7, 6, 5, 4, 3, 2 ... e assim por diante).
|
|
9
|
-
#
|
|
10
|
-
# 2) Some o resultado de cada produto efetuado e determine o total como (N).
|
|
11
|
-
#
|
|
12
|
-
# 3) Divida o total (N) por 11 e determine o resto obtido da divisão como Mod 11(N).
|
|
13
|
-
#
|
|
14
|
-
# <b>OBS.:</b> Se o resultado desta expressão for igual a 10, considere DAC = X.
|
|
15
|
-
#
|
|
16
|
-
# ==== Exemplo Normal
|
|
17
|
-
#
|
|
18
|
-
# Considerando o seguinte número: '89234560'.
|
|
19
|
-
#
|
|
20
|
-
# 1) Multiplicando a seqüência de multiplicadores:
|
|
21
|
-
#
|
|
22
|
-
# 8 9 2 3 4 5 6 0
|
|
23
|
-
# * * * * * * * *
|
|
24
|
-
# 2 3 4 5 6 7 8 9
|
|
25
|
-
#
|
|
26
|
-
# 2) Soma-se o resultado dos produtos obtidos no item “1” acima:
|
|
27
|
-
#
|
|
28
|
-
# 16 + 27 + 8 + 15 + 24 + 35 + 48 + 0
|
|
29
|
-
# # => 173
|
|
30
|
-
#
|
|
31
|
-
# 3) Determina-se o resto da Divisão:
|
|
32
|
-
#
|
|
33
|
-
# 173 % 11
|
|
34
|
-
# # => 8 =============> Resultado final retornado.
|
|
6
|
+
# <b>Para mais detalhes veja a classe Modulo11FatorDe9a2.</b>
|
|
35
7
|
#
|
|
36
8
|
# ==== Exemplo 10 como resto da divisão
|
|
37
9
|
#
|
|
@@ -58,30 +30,12 @@ module BoletoBancario
|
|
|
58
30
|
# resultado == 10
|
|
59
31
|
# # => 'X' =============> Resultado final retornado.
|
|
60
32
|
#
|
|
61
|
-
# @param [String]: Corresponde ao número a ser calculado o Módulo 11 no fator de 9 a 2.
|
|
62
|
-
# @return [String] Retorna o resultado do cálculo descrito acima.
|
|
63
|
-
#
|
|
64
33
|
# @example
|
|
65
34
|
#
|
|
66
|
-
# BoletoBancario::Calculos::Modulo11FatorDe9a2RestoX.new('
|
|
67
|
-
# # => '5'
|
|
68
|
-
#
|
|
69
|
-
# BoletoBancario::Calculos::Modulo11FatorDe9a2RestoX.new('246')
|
|
70
|
-
# # => '1'
|
|
71
|
-
#
|
|
72
|
-
# BoletoBancario::Calculos::Modulo11FatorDe2a9.new('184122')
|
|
35
|
+
# BoletoBancario::Calculos::Modulo11FatorDe9a2RestoX.new('184122')
|
|
73
36
|
# # => 'X'
|
|
74
37
|
#
|
|
75
|
-
class Modulo11FatorDe9a2RestoX <
|
|
76
|
-
# Sequência numérica de 9 a 2 que será feito a multiplicação de cada dígito
|
|
77
|
-
# do número passado no #initialize.
|
|
78
|
-
#
|
|
79
|
-
# @return [Array] Sequência numérica
|
|
80
|
-
#
|
|
81
|
-
def fatores
|
|
82
|
-
[9, 8, 7, 6, 5, 4, 3, 2]
|
|
83
|
-
end
|
|
84
|
-
|
|
38
|
+
class Modulo11FatorDe9a2RestoX < Modulo11FatorDe9a2
|
|
85
39
|
# Calcula o número pelos fatores de multiplicação de 9 a 2.
|
|
86
40
|
# Depois calcula o resto da divisão por 11.
|
|
87
41
|
# Se o resultado desse cálculo for igual a 10, então o DAC = X.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
module BoletoBancario
|
|
2
|
+
module Calculos
|
|
3
|
+
# === Cálculo do Módulo do Número de Controle (2 dígitos)
|
|
4
|
+
#
|
|
5
|
+
# Tipo de cálculo usado pelo Banco Banrisul.
|
|
6
|
+
#
|
|
7
|
+
# === Cálculo do Primeiro Dígito
|
|
8
|
+
#
|
|
9
|
+
# 1) Multiplica-se cada algarismo do campo pela seqüência de multiplicadores <b>2, 1, 2, 1, 2, 1 ...</b>, posicionados da direita para a esquerda.
|
|
10
|
+
#
|
|
11
|
+
# 2) Some individualmente, os algarismos dos resultados dos produtos, obtendo-se o total (N).
|
|
12
|
+
#
|
|
13
|
+
# 3) Divida o total encontrado (N) por 10, e determine o resto da divisão como MOD 10 (N).
|
|
14
|
+
#
|
|
15
|
+
# 4) Encontre o DAC através da seguinte expressão:
|
|
16
|
+
#
|
|
17
|
+
# DAC = 10 - Mod 10 (n)
|
|
18
|
+
#
|
|
19
|
+
# === Cálculo do segundo dígito
|
|
20
|
+
#
|
|
21
|
+
# # 1) Tomando-se os algarismos multiplique-os, iniciando-se da direita para a esquerda,
|
|
22
|
+
# pela seqüência numérica de 2 a 7 (2, 3, 4, 5, 6, 7 ... e assim por diante).
|
|
23
|
+
#
|
|
24
|
+
# 2) Some o resultado de cada produto efetuado e determine o total como (N).
|
|
25
|
+
#
|
|
26
|
+
# 3) Divida o total (N) por 11 e determine o resto obtido da divisão como Mod 11(N).
|
|
27
|
+
#
|
|
28
|
+
# 4) Calcule o dígito verificador (DAC) através da expressão:
|
|
29
|
+
#
|
|
30
|
+
# DIGIT = 11 - Mod 11 (n)
|
|
31
|
+
#
|
|
32
|
+
# <b>Observações:</b>
|
|
33
|
+
#
|
|
34
|
+
# Caso o 'resto' obtido no cálculo do módulo '11' seja igual a '1', considera-se o DV inválido.
|
|
35
|
+
# Soma-se, então, "1" ao DV obtido do módulo "10" e refaz-se o cálculo do módulo “11”.
|
|
36
|
+
# Se o dígito obtido pelo módulo “10” era igual a "9", considera-se então (9+1=10) DV inválido.
|
|
37
|
+
# Neste caso, o DV do módulo "10" automaticamente será igual a "0" e procede-se assim
|
|
38
|
+
# novo cálculo pelo módulo "11".
|
|
39
|
+
#
|
|
40
|
+
# === Exemplo com Primeiro Dígito Inválido
|
|
41
|
+
#
|
|
42
|
+
# Dado o número '00009194':
|
|
43
|
+
#
|
|
44
|
+
# O somatório do primeiro cálculo é igual a '28' e o Resto é igual a '8'.
|
|
45
|
+
# Portanto, o primeiro DV é igual a 10 - 8 ou DV = 2.
|
|
46
|
+
#
|
|
47
|
+
# O somatório do segundo cálculo é igual a '111' e o Resto é, neste caso, igual a '1'.
|
|
48
|
+
# Portanto, o segundo DV é inválido (11 - 1 = 10).
|
|
49
|
+
#
|
|
50
|
+
# Neste caso, soma-se '1' ao DV obtido do primeiro cálculo:
|
|
51
|
+
#
|
|
52
|
+
# 2 + 1
|
|
53
|
+
# # ======> 3 # Primeiro dígito do número de controle
|
|
54
|
+
#
|
|
55
|
+
# Agora, efetua-se novo cálculo do módulo 11, agora com o novo número, ou seja, 000091943:
|
|
56
|
+
#
|
|
57
|
+
# A somatório do segundo cálculo é igual a '113' e o Resto igual a '3'.
|
|
58
|
+
# Portanto, o segundo DV é igual a:
|
|
59
|
+
#
|
|
60
|
+
# 11 - 3
|
|
61
|
+
# # ====> 8 # Segundo dígito do número de controle
|
|
62
|
+
#
|
|
63
|
+
# Neste exemplo, o número de controle será '38'.
|
|
64
|
+
#
|
|
65
|
+
class ModuloNumeroDeControle < String
|
|
66
|
+
attr_reader :number, :first_digit, :second_digit
|
|
67
|
+
|
|
68
|
+
def initialize(number)
|
|
69
|
+
@number = number
|
|
70
|
+
@first_digit = calculate_first_digit
|
|
71
|
+
@second_digit = calculate_second_digit
|
|
72
|
+
|
|
73
|
+
super(calculate)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Retorna 2 dígitos verificando o segundo dígito se é válido ou não.
|
|
77
|
+
#
|
|
78
|
+
# @return [String]
|
|
79
|
+
#
|
|
80
|
+
def calculate
|
|
81
|
+
if second_digit_result.equal?(10)
|
|
82
|
+
@first_digit = first_digit.to_i + 1
|
|
83
|
+
@first_digit = 0 if @first_digit.equal?(10)
|
|
84
|
+
@second_digit = calculate_second_digit
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
"#{first_digit}#{second_digit}"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Retorna a subtração de 11 pelo resto da divisão por 11 do segundo dígito.
|
|
91
|
+
#
|
|
92
|
+
# @return [Integer]
|
|
93
|
+
#
|
|
94
|
+
def second_digit_result
|
|
95
|
+
11 - @second_digit.mod_division
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Calcula o primeiro dígito pelo módulo 10.
|
|
99
|
+
# Para mais detalhes veja a classe Modulo10.
|
|
100
|
+
#
|
|
101
|
+
# @return [String]
|
|
102
|
+
#
|
|
103
|
+
def calculate_first_digit
|
|
104
|
+
Modulo10.new(number)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Calcula o segundo dígito pelo módulo 11 usando os fatores de 2 a 7.
|
|
108
|
+
# Para mais detalhes veja a classe Modulo11FatorDe2a7.
|
|
109
|
+
#
|
|
110
|
+
# @return [String]
|
|
111
|
+
#
|
|
112
|
+
def calculate_second_digit
|
|
113
|
+
Modulo11FatorDe2a7.new("#{number}#{first_digit}")
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
@@ -116,16 +116,25 @@ module BoletoBancario
|
|
|
116
116
|
17
|
|
117
117
|
end
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
# <b>Carteiras suportadas.</b>
|
|
120
|
+
#
|
|
121
|
+
# <b>Método criado para validar se a carteira informada é suportada.</b>
|
|
122
|
+
#
|
|
123
|
+
# @return [Array]
|
|
124
|
+
#
|
|
125
|
+
def self.carteiras_suportadas
|
|
126
|
+
%w[12 16 17 18]
|
|
127
|
+
end
|
|
120
128
|
|
|
121
|
-
validates :digito_agencia,
|
|
122
|
-
validates :digito_conta_corrente, length: { maximum: 1 }
|
|
129
|
+
validates :codigo_cedente, :agencia, :digito_agencia, :conta_corrente, :digito_conta_corrente, presence: true
|
|
123
130
|
|
|
124
|
-
# Validações de Agencia
|
|
131
|
+
# Validações de Agencia, Conta corrente e Carteira.
|
|
125
132
|
#
|
|
126
133
|
validates :agencia, length: { maximum: tamanho_maximo_agencia }, if: :deve_validar_agencia?
|
|
127
134
|
validates :conta_corrente, length: { maximum: tamanho_maximo_conta_corrente }, if: :deve_validar_conta_corrente?
|
|
128
135
|
|
|
136
|
+
validates :carteira, inclusion: { in: ->(object) { object.class.carteiras_suportadas } }, if: :deve_validar_carteira?
|
|
137
|
+
|
|
129
138
|
# Validações do número do documento.
|
|
130
139
|
#
|
|
131
140
|
# === Número do Documento e Código do Cedente.
|
|
@@ -182,7 +191,7 @@ module BoletoBancario
|
|
|
182
191
|
# @return [String]
|
|
183
192
|
#
|
|
184
193
|
def numero_documento
|
|
185
|
-
if @numero_documento.present?
|
|
194
|
+
if @numero_documento.present? and numero_documento_esperado[tamanho_codigo_cedente].present?
|
|
186
195
|
@numero_documento.to_s.rjust(numero_documento_esperado[tamanho_codigo_cedente], '0')
|
|
187
196
|
else
|
|
188
197
|
@numero_documento
|
|
@@ -214,6 +223,22 @@ module BoletoBancario
|
|
|
214
223
|
'9'
|
|
215
224
|
end
|
|
216
225
|
|
|
226
|
+
# Dígito do código da agência. Precisa mostrar esse dígito no boleto.
|
|
227
|
+
#
|
|
228
|
+
# @return [String] Dígito da agência calculado apartir do Modulo11FatorDe9a2RestoX.
|
|
229
|
+
#
|
|
230
|
+
def digito_agencia
|
|
231
|
+
Modulo11FatorDe9a2RestoX.new(agencia)
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# Dígito da conta corrente. Precisa mostrar esse dígito no boleto.
|
|
235
|
+
#
|
|
236
|
+
# @return [String] Dígito da conta corrente calculado apartir do Modulo11FatorDe9a2RestoX.
|
|
237
|
+
#
|
|
238
|
+
def digito_conta_corrente
|
|
239
|
+
Modulo11FatorDe9a2RestoX.new(conta_corrente)
|
|
240
|
+
end
|
|
241
|
+
|
|
217
242
|
# Campo Agencia / Código do Cedente
|
|
218
243
|
# Retorna formatado a agência, digito da agência, número da conta corrente e dígito da conta.
|
|
219
244
|
#
|