brcobranca 12.0.0 → 13.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40b85b52a4ac810c6f1415906dd2099ca3f8ca623bcfc5f133a871e12ff1fa4d
4
- data.tar.gz: 593a1178adce41b5922e815436eb83e5db3f626711b2059b0b43cf7e08399642
3
+ metadata.gz: 6cb709eea03591dba80bcbd44a13db892cccf3631872d1ff612395b75efa7895
4
+ data.tar.gz: e71144ac7164a789303d3aa3fef7065c8ddbc46286c98b3f22a13aecd8c7a126
5
5
  SHA512:
6
- metadata.gz: 1f8b46f27016dc18170876394015e9c575fdb6c302ec9ed5698744421aa1fbd6b5226345f5ebf79af24a5fc82e14ac948bd058612050da7c582432496e6bc399
7
- data.tar.gz: 7968b70af83ef565021ba7f4666f7ffe35f64878ae2c6e9b36d454fb1cef8570012aa667c6de635eebe20c5587e4f5725f2738735d104105a07bd9d28068c309
6
+ metadata.gz: 0a7f6d6750e2a4ca483d72e1dc649b68e0da0c6252a806d82e4fe5a476ab4d96beee8cf2709c714f5f1d03b00f4e69bf995130592bdfc36e63ceecd6ad29f716
7
+ data.tar.gz: 2420142f69f9306c859c03c8c39f9f78072a6fe6fed30846b0cb25a4ad7bd9e85b7a2a13fd2139e3b4bafa3788b99ec5cd015879779dd411976a789e36bc3bfe
data/README.md CHANGED
@@ -53,7 +53,7 @@ Criado pelo pessoal da [Akretion](http://www.akretion.com) muito TOP \o/
53
53
  | Caixa | 240 | 240 |
54
54
  | Citibank | Não | 400 |
55
55
  | HSBC | Não | Não |
56
- | Itaú | 400 | 400 e 444 |
56
+ | Itaú | 400 e 240 | 400, 444 e 240 |
57
57
  | Santander | 400 e 240 | 400 e 240 |
58
58
  | Sicoob | 240 | 400 e 240 |
59
59
  | Sicredi | 240 | 240 |
@@ -28,6 +28,18 @@ module Brcobranca
28
28
  '341'
29
29
  end
30
30
 
31
+ # Agencia mantenedora da conta.
32
+ # @return [String] 4 caracteres numericos.
33
+ def agencia=(valor)
34
+ @agencia = valor.to_s.rjust(4, "0") if valor
35
+ end
36
+
37
+ # Numero da carteira no banco.
38
+ # @return [String] 3 caracteres numericos.
39
+ def carteira=(valor)
40
+ @carteira = valor.to_s.rjust(3, "0") if valor
41
+ end
42
+
31
43
  # Número do convênio/contrato do cliente junto ao banco.
32
44
  # @return [String] 5 caracteres numéricos.
33
45
  def convenio=(valor)
@@ -65,17 +77,18 @@ module Brcobranca
65
77
  #
66
78
  # @return [String] 1 caracteres numéricos.
67
79
  def nosso_numero_dv
68
- if %w[112 126 131 146 150 168].include?(carteira)
69
- "#{carteira}#{nosso_numero}".modulo10
70
- else
71
- "#{agencia}#{conta_corrente}#{carteira}#{nosso_numero}".modulo10
72
- end
80
+ Brcobranca::Util::Itau.nosso_numero_dv(
81
+ agencia, conta_corrente, carteira, nosso_numero
82
+ )
73
83
  end
74
84
 
75
- # Calcula o dígito verificador para conta corrente do Itau.
76
- # Retorna apenas o dígito verificador da conta ou nil caso seja impossível calcular.
85
+ # Calcula o digito verificador para conta corrente do Itau.
86
+ # Retorna apenas o digito verificador da conta, ou nil se nao for
87
+ # possivel calcular.
77
88
  def agencia_conta_corrente_dv
78
- "#{agencia}#{conta_corrente}".modulo10
89
+ Brcobranca::Util::Itau.agencia_conta_corrente_dv(
90
+ agencia, conta_corrente
91
+ )
79
92
  end
80
93
 
81
94
  # Nosso número para exibir no boleto.
@@ -0,0 +1,326 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brcobranca
4
+ module Remessa
5
+ module Cnab240
6
+ class Itau < Brcobranca::Remessa::Cnab240::Base
7
+ validates_length_of :agencia, maximum: 4,
8
+ message: "deve ter 4 dígitos."
9
+ validates_length_of :conta_corrente, maximum: 5,
10
+ message: "deve ter 5 dígitos."
11
+ validates_length_of :carteira, maximum: 3,
12
+ message: "deve ter 3 dígitos."
13
+
14
+ def initialize(campos = {})
15
+ # emissao_boleto/distribuicao_boleto/codigo_carteira/
16
+ # forma_cadastramento nao fazem parte do layout do Segmento P do
17
+ # Itau (ver #monta_segmento_p), mas precisam de um valor de 1
18
+ # digito para passar nas validacoes genericas de Cnab240::Base.
19
+ campos = { especie_titulo: "01",
20
+ emissao_boleto: "0",
21
+ distribuicao_boleto: "0" }.merge!(campos)
22
+ super
23
+ end
24
+
25
+ def agencia=(valor)
26
+ @agencia = valor.to_s.rjust(4, "0") if valor
27
+ end
28
+
29
+ def conta_corrente=(valor)
30
+ @conta_corrente = valor.to_s.rjust(5, "0") if valor
31
+ end
32
+
33
+ def carteira=(valor)
34
+ @carteira = valor.to_s.rjust(3, "0") if valor
35
+ end
36
+
37
+ def cod_banco
38
+ "341"
39
+ end
40
+
41
+ def nome_banco
42
+ "BANCO ITAU SA".ljust(30, " ")
43
+ end
44
+
45
+ def versao_layout_arquivo
46
+ "040"
47
+ end
48
+
49
+ def versao_layout_lote
50
+ "030"
51
+ end
52
+
53
+ def exclusivo_servico
54
+ "00"
55
+ end
56
+
57
+ # Digito verificador de agencia/conta corrente.
58
+ #
59
+ # @return [String]
60
+ def agencia_conta_corrente_dv
61
+ Brcobranca::Util::Itau.agencia_conta_corrente_dv(
62
+ agencia, conta_corrente
63
+ ).to_s
64
+ end
65
+
66
+ # Digito verificador do nosso numero.
67
+ #
68
+ # Calculado sobre o nosso numero ja com 8 posicoes (mesmo valor
69
+ # gravado no segmento P), e nao sobre o valor "cru" informado pelo
70
+ # usuario - ver #monta_segmento_p e #formata_nosso_numero.
71
+ #
72
+ # @return [String]
73
+ def nosso_numero_dv(pagamento)
74
+ Brcobranca::Util::Itau.nosso_numero_dv(
75
+ agencia, conta_corrente, carteira, formata_nosso_numero(pagamento)
76
+ ).to_s
77
+ end
78
+
79
+ # Nosso numero com exatamente 8 posicoes.
80
+ #
81
+ # O nosso numero pode vir do chamador (ex.: sequencia interna do
82
+ # Odoo) com mais de 8 digitos; nesse caso ficam os 8 ultimos
83
+ # digitos (o mesmo criterio usado para interpretar o nosso numero
84
+ # no arquivo de retorno), em vez de simplesmente preencher com
85
+ # zeros a esquerda sem cortar o excedente.
86
+ #
87
+ # @return [String]
88
+ def formata_nosso_numero(pagamento)
89
+ pagamento.nosso_numero.to_s.rjust(8, "0")[-8..-1]
90
+ end
91
+
92
+ # Informacoes da conta corrente do cedente no header de lote.
93
+ #
94
+ # CAMPO TAMANHO
95
+ # zeros 1
96
+ # agencia 4
97
+ # brancos 1
98
+ # zeros 7
99
+ # conta corrente 5
100
+ # brancos 1
101
+ # DAC ag/conta 1
102
+ #
103
+ # @return [String]
104
+ def info_conta
105
+ zeros = "".rjust(7, "0")
106
+ "0#{agencia} #{zeros}#{conta_corrente} #{agencia_conta_corrente_dv}"
107
+ end
108
+
109
+ # Sem uso de codigo de convenio pelo Itau neste layout (header arquivo)
110
+ #
111
+ # @return [String]
112
+ def codigo_convenio
113
+ "".rjust(20, " ")
114
+ end
115
+
116
+ # Sem uso de codigo de convenio pelo Itau neste layout (header lote)
117
+ #
118
+ # @return [String]
119
+ def convenio_lote
120
+ "".rjust(20, " ")
121
+ end
122
+
123
+ def uso_exclusivo_banco
124
+ "".rjust(20, " ")
125
+ end
126
+
127
+ def uso_exclusivo_empresa
128
+ "".rjust(20, " ")
129
+ end
130
+
131
+ # Complemento do header de arquivo
132
+ #
133
+ # @return [String]
134
+ def complemento_header
135
+ "#{''.rjust(14, ' ')}#{''.rjust(3, '0')}#{''.rjust(12, ' ')}"
136
+ end
137
+
138
+ # Complemento do trailer de lote
139
+ #
140
+ # @return [String]
141
+ def complemento_trailer
142
+ "".rjust(217, " ")
143
+ end
144
+
145
+ def dv_agencia_cobradora
146
+ "0"
147
+ end
148
+
149
+ # Prazo para baixa com exatamente 2 posicoes.
150
+ #
151
+ # O valor padrao herdado de Brcobranca::Remessa::Pagamento e "000"
152
+ # (3 digitos, dimensionado para o layout generico de outros bancos)
153
+ # e nao e truncado por um rjust simples, o que descasa o segmento P
154
+ # do Itau (campo de 2 digitos, posicoes 225-226) em 1 byte quando o
155
+ # chamador nao informa esse campo explicitamente.
156
+ #
157
+ # @return [String]
158
+ def dias_baixa(pagamento)
159
+ pagamento.dias_baixa.to_s.rjust(2, "0")[-2..-1]
160
+ end
161
+
162
+ # Monta o registro segmento P do arquivo.
163
+ #
164
+ # Layout especifico do Itau (manual "Cobranca FEBRABAN 240", item
165
+ # 3.1, Segmento P) - o campo "N. da carteira" (3 digitos, posicoes
166
+ # 038-040) nao corresponde ao hook generico `codigo_carteira` da
167
+ # classe base (1 digito), por isso o segmento e montado por inteiro.
168
+ #
169
+ # CAMPO POSICAO TAMANHO
170
+ # codigo banco 001-003 3
171
+ # lote de servico 004-007 4
172
+ # tipo de registro 008 1
173
+ # num. sequencial do registro no lote 009-013 5
174
+ # cod. segmento 014 1
175
+ # uso exclusivo 015 1
176
+ # cod. movimento remessa 016-017 2
177
+ # zeros 018 1
178
+ # agencia 019-022 4
179
+ # brancos 023 1
180
+ # zeros 024-030 7
181
+ # conta corrente 031-035 5
182
+ # brancos 036 1
183
+ # DAC agencia/conta 037 1
184
+ # numero da carteira 038-040 3
185
+ # nosso numero 041-048 8
186
+ # DAC nosso numero 049 1
187
+ # brancos 050-057 8
188
+ # zeros 058-062 5
189
+ # numero do documento 063-072 10
190
+ # brancos 073-077 5
191
+ # data de vencimento 078-085 8
192
+ # valor do titulo 086-100 15
193
+ # agencia cobradora 101-105 5
194
+ # DAC agencia cobradora 106 1
195
+ # especie do titulo 107-108 2
196
+ # aceite 109 1
197
+ # data de emissao do titulo 110-117 8
198
+ # zeros 118 1
199
+ # data base juros de mora 119-126 8
200
+ # valor de mora por dia de atraso 127-141 15
201
+ # zeros 142 1
202
+ # data limite do 1o desconto 143-150 8
203
+ # valor do 1o desconto 151-165 15
204
+ # valor do IOF 166-180 15
205
+ # valor do abatimento 181-195 15
206
+ # identificacao do titulo na empresa 196-220 25
207
+ # codigo para negativacao/protesto 221 1
208
+ # prazo para negativacao/protesto 222-223 2
209
+ # codigo para baixa 224 1
210
+ # prazo para baixa 225-226 2
211
+ # zeros 227-239 13
212
+ # brancos 240 1
213
+ #
214
+ # @return [String]
215
+ def monta_segmento_p(pagamento, nro_lote, sequencial)
216
+ segmento_p = ""
217
+ segmento_p += cod_banco
218
+ segmento_p << nro_lote.to_s.rjust(4, "0")
219
+ segmento_p << "3"
220
+ segmento_p << sequencial.to_s.rjust(5, "0")
221
+ segmento_p << "P"
222
+ segmento_p << " "
223
+ segmento_p << pagamento.identificacao_ocorrencia
224
+ segmento_p << "0"
225
+ segmento_p << agencia
226
+ segmento_p << " "
227
+ segmento_p << "".rjust(7, "0")
228
+ segmento_p << conta_corrente
229
+ segmento_p << " "
230
+ segmento_p << agencia_conta_corrente_dv
231
+ segmento_p << carteira
232
+ segmento_p << formata_nosso_numero(pagamento)
233
+ segmento_p << nosso_numero_dv(pagamento)
234
+ segmento_p << "".rjust(8, " ")
235
+ segmento_p << "".rjust(5, "0")
236
+ segmento_p << pagamento.formata_documento_ou_numero(10, " ")
237
+ segmento_p << "".rjust(5, " ")
238
+ segmento_p << pagamento.data_vencimento.strftime("%d%m%Y")
239
+ segmento_p << pagamento.formata_valor(15)
240
+ segmento_p << "".rjust(5, "0")
241
+ segmento_p << dv_agencia_cobradora
242
+ segmento_p << especie_titulo
243
+ segmento_p << aceite
244
+ segmento_p << pagamento.data_emissao.strftime("%d%m%Y")
245
+ segmento_p << "0"
246
+ segmento_p << data_mora(pagamento)
247
+ segmento_p << pagamento.formata_valor_mora(15)
248
+ segmento_p << "0"
249
+ segmento_p << pagamento.formata_data_desconto("%d%m%Y")
250
+ segmento_p << pagamento.formata_valor_desconto(15)
251
+ segmento_p << pagamento.formata_valor_iof(15)
252
+ segmento_p << pagamento.formata_valor_abatimento(15)
253
+ segmento_p << pagamento.formata_documento_ou_numero(25, " ")
254
+ segmento_p << pagamento.codigo_protesto
255
+ segmento_p << pagamento.dias_protesto.to_s.rjust(2, "0")
256
+ segmento_p << codigo_baixa(pagamento)
257
+ segmento_p << dias_baixa(pagamento)
258
+ segmento_p << "".rjust(13, "0")
259
+ segmento_p << " "
260
+ segmento_p
261
+ end
262
+
263
+ # Monta o registro segmento Q do arquivo.
264
+ #
265
+ # Layout especifico do Itau - o nome do pagador ocupa 30 posicoes
266
+ # (com 10 posicoes em branco a seguir) e o nome do sacador/avalista
267
+ # ocupa 30 posicoes, diferente do padrao generico de 40 posicoes sem
268
+ # espacamento usado pela classe base.
269
+ #
270
+ # CAMPO POSICAO TAMANHO
271
+ # codigo banco 001-003 3
272
+ # lote de servico 004-007 4
273
+ # tipo de registro 008 1
274
+ # num. sequencial do registro no lote 009-013 5
275
+ # cod. segmento 014 1
276
+ # brancos 015 1
277
+ # cod. movimento remessa 016-017 2
278
+ # tipo insc. pagador 018 1
279
+ # documento pagador 019-033 15
280
+ # nome pagador 034-063 30
281
+ # brancos 064-073 10
282
+ # logradouro 074-113 40
283
+ # bairro 114-128 15
284
+ # cep 129-133 5
285
+ # sufixo cep 134-136 3
286
+ # cidade 137-151 15
287
+ # uf 152-153 2
288
+ # tipo insc. sacador/avalista 154 1
289
+ # documento sacador/avalista 155-169 15
290
+ # nome sacador/avalista 170-199 30
291
+ # brancos 200-209 10
292
+ # zeros 210-212 3
293
+ # brancos 213-240 28
294
+ #
295
+ # @return [String]
296
+ def monta_segmento_q(pagamento, nro_lote, sequencial)
297
+ segmento_q = ""
298
+ segmento_q += cod_banco
299
+ segmento_q << nro_lote.to_s.rjust(4, "0")
300
+ segmento_q << "3"
301
+ segmento_q << sequencial.to_s.rjust(5, "0")
302
+ segmento_q << "Q"
303
+ segmento_q << " "
304
+ segmento_q << pagamento.identificacao_ocorrencia
305
+ segmento_q << pagamento.identificacao_sacado(false)
306
+ segmento_q << pagamento.documento_sacado.to_s.rjust(15, "0")
307
+ segmento_q << pagamento.nome_sacado.format_size(30)
308
+ segmento_q << "".rjust(10, " ")
309
+ segmento_q << pagamento.endereco_sacado.format_size(40)
310
+ segmento_q << pagamento.bairro_sacado.format_size(15)
311
+ segmento_q << pagamento.cep_sacado[0..4]
312
+ segmento_q << pagamento.cep_sacado[5..7]
313
+ segmento_q << pagamento.cidade_sacado.format_size(15)
314
+ segmento_q << pagamento.uf_sacado
315
+ segmento_q << pagamento.identificacao_avalista(false)
316
+ segmento_q << pagamento.documento_avalista.to_s.rjust(15, "0")
317
+ segmento_q << pagamento.nome_avalista.format_size(30)
318
+ segmento_q << "".rjust(10, " ")
319
+ segmento_q << "".rjust(3, "0")
320
+ segmento_q << "".rjust(28, " ")
321
+ segmento_q
322
+ end
323
+ end
324
+ end
325
+ end
326
+ end
@@ -151,16 +151,49 @@ module Brcobranca
151
151
  nosso_numero.somente_numeros.ljust(20, ' ')
152
152
  end
153
153
 
154
- def codigo_desconto(_pagamento)
155
- '1'
154
+ # Campo 30.3P - Codigo do desconto 1.
155
+ # Manual Sicredi: '0' - Sem desconto | '1' - Valor fixo ate a data
156
+ # informada | '2' - Percentual ate a data informada.
157
+ # Para o codigo '0' o valor e a data do desconto devem ser zerados.
158
+ # Deve respeitar o valor informado pelo beneficiario.
159
+ def codigo_desconto(pagamento)
160
+ if pagamento.cod_desconto == '0'
161
+ pagamento.data_desconto = nil
162
+ pagamento.valor_desconto = 0.0
163
+ end
164
+ pagamento.cod_desconto
156
165
  end
157
166
 
158
167
  def codigo_baixa(_pagamento)
159
168
  '1'
160
169
  end
161
170
 
171
+ # Campo 39.3P - No de dias para baixa/devolucao.
172
+ # Manual Sicredi: o Sicredi nao utiliza esse campo, preencher com zeros.
162
173
  def dias_baixa(_pagamento)
163
- '060'
174
+ '000'
175
+ end
176
+
177
+ # Campo 19.3P - Seu Numero (posicoes 63-77).
178
+ # Manual Sicredi: "Embora no layout constem 15 posicoes, o Sicredi
179
+ # apenas validara as 10 primeiras (campos 63-72), ou seja, da esquerda
180
+ # para a direita. Nao pode conter espaco."
181
+ # O numero deve entao ser alinhado a esquerda e o restante preenchido
182
+ # com zeros (o campo nao pode conter espaco).
183
+ def numero(pagamento)
184
+ pagamento.documento_ou_numero.to_s.gsub(/[^0-9A-Za-z]/, '').ljust(15, '0')[0...15]
185
+ end
186
+
187
+ # Campos 17.3Q, 18.3Q e 19.3Q - Beneficiario Final.
188
+ # Manual Sicredi: nao havendo Beneficiario Final o tipo deve ser "0"
189
+ # e o campo CPF/CNPJ (posicoes 155-169) deve ficar em branco.
190
+ # O BRCobranca preenche o CPF/CNPJ com zeros quando nao informado.
191
+ def monta_segmento_q(pagamento, nro_lote, sequencial)
192
+ segmento_q = super
193
+ return segmento_q unless pagamento.documento_avalista.to_s.strip.empty?
194
+
195
+ segmento_q[153, 16] = "0#{''.rjust(15, ' ')}"
196
+ segmento_q
164
197
  end
165
198
 
166
199
  def data_mora(pagamento)
@@ -3,7 +3,328 @@
3
3
  module Brcobranca
4
4
  module Remessa
5
5
  module Cnab240
6
- class Unicred < Brcobranca::Remessa::Cnab240::Sicredi
6
+ # Banco Unicred (136)
7
+ #
8
+ # Layout proprio do Unicred, baseado no manual "COBRANCA UNICRED -
9
+ # TROCA ELETRONICA CEDENTE CNAB 240 E 400" (item 6), disponivel em
10
+ # docs/unicred. Difere do padrao generico FEBRABAN principalmente no
11
+ # segmento P (posicao do nosso numero, carteira com 2 posicoes e
12
+ # diversos campos tratados como filler) e no segmento R, onde ficam as
13
+ # mensagens do titulo.
14
+ class Unicred < Brcobranca::Remessa::Cnab240::Base
15
+ # Parametro de movimento vinculado ao cedente no momento do
16
+ # cadastramento (campo 22 do header de arquivo - UN001).
17
+ attr_accessor :parametro_movimento
18
+
19
+ validates_presence_of :agencia, :conta_corrente, :digito_conta, :documento_cedente,
20
+ message: 'não pode estar em branco.'
21
+ validates_length_of :agencia, is: 4, message: 'deve ter 4 dígitos.'
22
+ validates_length_of :conta_corrente, maximum: 12, message: 'deve ter no máximo 12 dígitos.'
23
+ validates_length_of :digito_conta, is: 1, message: 'deve ter 1 dígito.'
24
+ validates_length_of :carteira, is: 2, message: 'deve ter 2 dígitos.'
25
+ validates_length_of :parametro_movimento, is: 3, message: 'deve ter 3 dígitos.'
26
+ validates_inclusion_of :carteira, in: %w[21], message: 'não existente para este banco.'
27
+
28
+ # Nova instancia do Unicred
29
+ def initialize(campos = {})
30
+ campos = {
31
+ carteira: '21',
32
+ parametro_movimento: '000',
33
+ emissao_boleto: '2',
34
+ distribuicao_boleto: '2',
35
+ especie_titulo: '02',
36
+ forma_cadastramento: '1',
37
+ tipo_documento: '1'
38
+ }.merge!(campos)
39
+ super(campos)
40
+ end
41
+
42
+ def agencia=(valor)
43
+ @agencia = valor.to_s.rjust(4, '0') if valor
44
+ end
45
+
46
+ def carteira=(valor)
47
+ @carteira = valor.to_s.rjust(2, '0') if valor
48
+ end
49
+
50
+ # Codigo do banco na camara de compensacao
51
+ # @return [String] 3 caracteres numericos.
52
+ def cod_banco
53
+ '136'
54
+ end
55
+
56
+ # Nome do banco
57
+ # @return [String] 30 caracteres.
58
+ def nome_banco
59
+ 'UNICRED'.ljust(30, ' ')
60
+ end
61
+
62
+ # Versao do layout do arquivo (campo 20 do header de arquivo)
63
+ def versao_layout_arquivo
64
+ '085'
65
+ end
66
+
67
+ # Versao do layout do lote (campo 7 do header de lote)
68
+ def versao_layout_lote
69
+ '044'
70
+ end
71
+
72
+ # Densidade de gravacao do arquivo: 1600 BPI
73
+ def densidade_gravacao
74
+ '01600'
75
+ end
76
+
77
+ # Digito verificador da agencia, calculado pelo modulo 11 com o mesmo
78
+ # criterio usado na remessa CNAB 400 do Unicred.
79
+ # @return [String] 1 caractere.
80
+ def digito_agencia
81
+ agencia.modulo11(mapeamento: { 10 => 'X' }).to_s
82
+ end
83
+
84
+ # Nosso numero com o digito verificador (campo 13 do segmento P).
85
+ # @return [String] 11 caracteres numericos.
86
+ def formata_nosso_numero(nosso_numero)
87
+ numero = nosso_numero.to_s.somente_numeros.rjust(10, '0')
88
+ "#{numero}#{numero.modulo11(mapeamento: { 10 => 0, 11 => 0 })}"
89
+ end
90
+
91
+ # O Unicred nao utiliza o codigo do convenio: campo 7 do header de
92
+ # arquivo e campo 11 do header de lote sao filler.
93
+ def codigo_convenio
94
+ ''.rjust(20, ' ')
95
+ end
96
+
97
+ alias convenio_lote codigo_convenio
98
+
99
+ # Informacoes da conta do cedente
100
+ # (header de arquivo 053-072 / header de lote 054-073)
101
+ #
102
+ # @return [String] 20 caracteres.
103
+ def info_conta
104
+ # CAMPO TAMANHO
105
+ # agencia 5
106
+ # dv agencia 1
107
+ # conta corrente 12
108
+ # dv conta 1
109
+ # filler 1
110
+ "#{agencia.rjust(5, '0')}#{digito_agencia}#{conta_corrente.to_s.rjust(12, '0')}#{digito_conta}0"
111
+ end
112
+
113
+ # Campos 22 e 23 do header de arquivo (posicoes 172 a 191):
114
+ # parametro de movimento seguido do campo reservado ao banco.
115
+ def uso_exclusivo_banco
116
+ "#{parametro_movimento}#{''.rjust(17, ' ')}"
117
+ end
118
+
119
+ # Campo 24 do header de arquivo (posicoes 192 a 211)
120
+ def uso_exclusivo_empresa
121
+ ''.rjust(20, ' ')
122
+ end
123
+
124
+ # Campo 25 do header de arquivo (posicoes 212 a 240)
125
+ def complemento_header
126
+ ''.rjust(29, ' ')
127
+ end
128
+
129
+ # Complemento do trailer de lote (posicoes 24 a 240)
130
+ #
131
+ # @return [String] 217 caracteres.
132
+ def complemento_trailer
133
+ # CAMPO TAMANHO
134
+ # qtde de titulos em cobranca simples 6
135
+ # valor total dos titulos em cobranca simples 17
136
+ # qtde/valor dos titulos em cobranca vinculada 23
137
+ # qtde/valor dos titulos em cobranca caucionada 23
138
+ # qtde/valor dos titulos em cobranca descontada 23
139
+ # numero do aviso de lancamento 8
140
+ # uso exclusivo FEBRABAN 117
141
+ cobranca_simples = "#{quantidade_titulos_cobranca}#{valor_titulos_carteira(17)}"
142
+ "#{cobranca_simples}#{''.rjust(69, '0')}#{''.rjust(125, ' ')}"
143
+ end
144
+
145
+ # Complemento do segmento R (posicoes 180 a 240)
146
+ #
147
+ # @return [String] 61 caracteres.
148
+ def complemento_r
149
+ # CAMPO TAMANHO
150
+ # uso exclusivo FEBRABAN 20
151
+ # filler 32
152
+ # uso exclusivo FEBRABAN 9
153
+ "#{''.rjust(20, ' ')}#{''.rjust(32, '0')}#{''.rjust(9, ' ')}"
154
+ end
155
+
156
+ # Monta o registro header do lote
157
+ #
158
+ # No layout do Unicred as duas mensagens do header de lote (posicoes
159
+ # 104 a 183) e a data do credito (posicoes 200 a 207) sao filler - as
160
+ # mensagens do titulo trafegam no segmento R.
161
+ #
162
+ # @return [String]
163
+ #
164
+ def monta_header_lote(nro_lote)
165
+ header_lote = super
166
+ header_lote[103, 80] = ''.rjust(80, ' ')
167
+ header_lote[199, 8] = ''.rjust(8, ' ')
168
+ header_lote
169
+ end
170
+
171
+ # Monta o registro segmento P do arquivo
172
+ #
173
+ # CAMPO POSICAO TAMANHO
174
+ # codigo banco 001-003 3
175
+ # lote de servico 004-007 4
176
+ # tipo de registro 008 1
177
+ # num. sequencial do registro no lote 009-013 5
178
+ # cod. segmento 014 1
179
+ # uso exclusivo FEBRABAN 015 1
180
+ # cod. movimento remessa 016-017 2
181
+ # agencia 018-022 5
182
+ # dv agencia 023 1
183
+ # conta corrente 024-035 12
184
+ # dv conta 036 1
185
+ # filler 037 1
186
+ # nosso numero (com dv) 038-048 11
187
+ # filler 049-056 8
188
+ # carteira 057-058 2
189
+ # filler 059-062 4
190
+ # numero do documento (seu numero) 063-077 15
191
+ # data de vencimento 078-085 8
192
+ # valor nominal do titulo 086-100 15
193
+ # agencia cobradora 101-105 5
194
+ # dv agencia cobradora 106 1
195
+ # filler 107-108 2
196
+ # aceite 109 1
197
+ # data de emissao do titulo 110-117 8
198
+ # codigo do juros de mora 118 1
199
+ # filler 119-126 8
200
+ # juros de mora por dia/taxa 127-141 15
201
+ # codigo do desconto 1 142 1
202
+ # data do desconto 1 143-150 8
203
+ # valor/percentual do desconto 1 151-165 15
204
+ # filler 166-180 15
205
+ # valor do abatimento 181-195 15
206
+ # identificacao do titulo na empresa 196-220 25
207
+ # codigo para protesto 221 1
208
+ # prazo para protesto 222-223 2
209
+ # filler 224-227 4
210
+ # codigo da moeda 228-229 2
211
+ # numero do contrato 230-239 10
212
+ # uso exclusivo FEBRABAN 240 1
213
+ #
214
+ # @return [String]
215
+ #
216
+ def monta_segmento_p(pagamento, nro_lote, sequencial)
217
+ segmento_p = ''
218
+ segmento_p += cod_banco
219
+ segmento_p << nro_lote.to_s.rjust(4, '0')
220
+ segmento_p << '3'
221
+ segmento_p << sequencial.to_s.rjust(5, '0')
222
+ segmento_p << 'P'
223
+ segmento_p << ' '
224
+ segmento_p << pagamento.identificacao_ocorrencia
225
+ segmento_p << agencia.rjust(5, '0')
226
+ segmento_p << digito_agencia
227
+ segmento_p << conta_corrente.to_s.rjust(12, '0')
228
+ segmento_p << digito_conta.to_s
229
+ segmento_p << '0'
230
+ segmento_p << formata_nosso_numero(pagamento.nosso_numero)
231
+ segmento_p << ''.rjust(8, ' ')
232
+ segmento_p << carteira
233
+ segmento_p << '0 0 '
234
+ segmento_p << numero(pagamento)
235
+ segmento_p << pagamento.data_vencimento.strftime('%d%m%Y')
236
+ segmento_p << pagamento.formata_valor(15)
237
+ segmento_p << ''.rjust(5, ' ')
238
+ segmento_p << ' '
239
+ segmento_p << ''.rjust(2, '0')
240
+ segmento_p << aceite
241
+ segmento_p << pagamento.data_emissao.strftime('%d%m%Y')
242
+ segmento_p << pagamento.tipo_mora
243
+ segmento_p << ''.rjust(8, '0')
244
+ segmento_p << pagamento.formata_valor_mora(15)
245
+ segmento_p << codigo_desconto(pagamento)
246
+ segmento_p << pagamento.formata_data_desconto('%d%m%Y')
247
+ segmento_p << pagamento.formata_valor_desconto(15)
248
+ segmento_p << ''.rjust(15, '0')
249
+ segmento_p << pagamento.formata_valor_abatimento(15)
250
+ segmento_p << identificacao_titulo_empresa(pagamento)
251
+ segmento_p << pagamento.codigo_protesto
252
+ segmento_p << pagamento.dias_protesto.to_s.rjust(2, '0')
253
+ segmento_p << '0'
254
+ segmento_p << ''.rjust(3, ' ')
255
+ segmento_p << '09'
256
+ segmento_p << ''.rjust(10, '0')
257
+ segmento_p << ' '
258
+ segmento_p
259
+ end
260
+
261
+ # Monta o registro segmento R do arquivo
262
+ #
263
+ # No layout do Unicred os campos de desconto 2/3 e de multa sao filler;
264
+ # o segmento carrega a informacao ao sacado e as duas mensagens.
265
+ #
266
+ # CAMPO POSICAO TAMANHO
267
+ # codigo banco 001-003 3
268
+ # lote de servico 004-007 4
269
+ # tipo de registro 008 1
270
+ # num. sequencial do registro no lote 009-013 5
271
+ # cod. segmento 014 1
272
+ # uso exclusivo FEBRABAN 015 1
273
+ # cod. movimento remessa 016-017 2
274
+ # filler (desconto 2 e desconto 3) 018-065 48
275
+ # filler 066 1
276
+ # filler (multa) 067-089 23
277
+ # informacao ao sacado 090-099 10
278
+ # mensagem 1 100-139 40
279
+ # mensagem 2 140-179 40
280
+ # complemento 180-240 61
281
+ #
282
+ # @return [String]
283
+ #
284
+ def monta_segmento_r(pagamento, nro_lote, sequencial)
285
+ segmento_r = ''
286
+ segmento_r += cod_banco
287
+ segmento_r << nro_lote.to_s.rjust(4, '0')
288
+ segmento_r << '3'
289
+ segmento_r << sequencial.to_s.rjust(5, '0')
290
+ segmento_r << 'R'
291
+ segmento_r << ' '
292
+ segmento_r << pagamento.identificacao_ocorrencia
293
+ segmento_r << ''.rjust(48, '0')
294
+ segmento_r << ' '
295
+ segmento_r << ''.rjust(23, '0')
296
+ segmento_r << ''.rjust(10, ' ')
297
+ segmento_r << mensagem_1.to_s.format_size(40)
298
+ segmento_r << mensagem_2.to_s.format_size(40)
299
+ segmento_r << complemento_r
300
+ segmento_r
301
+ end
302
+
303
+ # Monta o registro trailer do arquivo
304
+ #
305
+ # CAMPO POSICAO TAMANHO
306
+ # codigo banco 001-003 3
307
+ # lote de servico 004-007 4
308
+ # tipo de registro 008 1
309
+ # uso exclusivo FEBRABAN 009-017 9
310
+ # qtde de lotes do arquivo 018-023 6
311
+ # qtde de registros do arquivo 024-029 6
312
+ # qtde de contas para conciliacao 030-035 6
313
+ # uso exclusivo FEBRABAN 036-240 205
314
+ #
315
+ # @return [String]
316
+ #
317
+ def monta_trailer_arquivo(nro_lotes, sequencial)
318
+ trailer_arquivo = ''
319
+ trailer_arquivo += cod_banco
320
+ trailer_arquivo << '99999'
321
+ trailer_arquivo << ''.rjust(9, ' ')
322
+ trailer_arquivo << nro_lotes.to_s.rjust(6, '0')
323
+ trailer_arquivo << sequencial.to_s.rjust(6, '0')
324
+ trailer_arquivo << ''.rjust(6, '0')
325
+ trailer_arquivo << ''.rjust(205, ' ')
326
+ trailer_arquivo
327
+ end
7
328
  end
8
329
  end
9
330
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'parseline'
3
+ require "parseline"
4
4
 
5
5
  module Brcobranca
6
6
  module Retorno
@@ -13,13 +13,15 @@ module Brcobranca
13
13
  codigo_banco = codigo_banco_do_arquivo(file)
14
14
 
15
15
  case codigo_banco
16
- when '033'
16
+ when "033"
17
17
  Brcobranca::Retorno::Cnab240::Santander.load_lines(file, options)
18
- when '085'
18
+ when "341"
19
+ Brcobranca::Retorno::Cnab240::Itau.load_lines(file, options)
20
+ when "085"
19
21
  Brcobranca::Retorno::Cnab240::Ailos.load_lines(file, options)
20
- when '748'
22
+ when "748"
21
23
  Brcobranca::Retorno::Cnab240::Sicredi.load_lines(file, options)
22
- when '756'
24
+ when "756"
23
25
  Brcobranca::Retorno::Cnab240::Sicoob.load_lines(file, options)
24
26
  else
25
27
  Brcobranca::Retorno::RetornoCnab240.load_lines(file, options)
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brcobranca
4
+ module Retorno
5
+ module Cnab240
6
+ class Itau < Brcobranca::Retorno::Cnab240::Base
7
+ # Regex para remocao de headers/trailers e registros diferentes de T
8
+ # ou U.
9
+ REGEX_DE_EXCLUSAO_DE_REGISTROS_NAO_T_OU_U =
10
+ /^((?!^.{7}3.{5}[TU].*$).)*$/
11
+
12
+ def self.load_lines(file, options = {})
13
+ default_options = {
14
+ except: REGEX_DE_EXCLUSAO_DE_REGISTROS_NAO_T_OU_U
15
+ }
16
+ options = default_options.merge(options)
17
+
18
+ lines = Line.load_lines(file, options)
19
+ lines.each_slice(2).inject([]) do |retornos, cnab_lines|
20
+ validate_par_t_u!(cnab_lines)
21
+ retornos << generate_retorno_based_on_cnab_lines(cnab_lines)
22
+ end
23
+ end
24
+
25
+ # Garante que cada grupo de linhas T/U produzido por .load_lines
26
+ # esta completo e na ordem esperada antes de virar um retorno.
27
+ #
28
+ # Um arquivo corrompido ou truncado pode gerar um grupo com so a
29
+ # linha T (sem a U correspondente) ou fora de ordem; sem essa
30
+ # checagem, generate_retorno_based_on_cnab_lines trataria
31
+ # silenciosamente qualquer linha que nao seja T como se fosse U,
32
+ # produzindo um retorno com dados de liquidacao incorretos/parciais.
33
+ def self.validate_par_t_u!(cnab_lines)
34
+ return if cnab_lines.size == 2 &&
35
+ cnab_lines[0].tipo_registro == "T" &&
36
+ cnab_lines[1].tipo_registro == "U"
37
+
38
+ sequencial = cnab_lines.first&.sequencial
39
+ raise ArgumentError,
40
+ "Par de registros T/U invalido ou incompleto no retorno " \
41
+ "do Itau (sequencial: #{sequencial.inspect})"
42
+ end
43
+
44
+ def self.generate_retorno_based_on_cnab_lines(cnab_lines)
45
+ retorno = new
46
+ cnab_lines.each do |line|
47
+ if line.tipo_registro == "T"
48
+ Line::REGISTRO_T_FIELDS.each do |attr|
49
+ retorno.send(:"#{attr}=", line.send(attr))
50
+ end
51
+ else
52
+ Line::REGISTRO_U_FIELDS.each do |attr|
53
+ retorno.send(:"#{attr}=", line.send(attr))
54
+ end
55
+ end
56
+ end
57
+ retorno
58
+ end
59
+
60
+ # Linha de mapeamento do retorno do arquivo CNAB 240 do Itau.
61
+ #
62
+ # O registro CNAB 240 possui 2 tipos de registros que juntos geram
63
+ # um registro de retorno bancario. O primeiro e do tipo T que
64
+ # retorna os dados gerais sobre o titulo/pagador. O segundo e do
65
+ # tipo U que retorna os valores da liquidacao.
66
+ #
67
+ # Os nomes de campo reutilizam, sempre que fazem sentido, o
68
+ # vocabulario generico ja definido em Brcobranca::Retorno::Base (em
69
+ # vez de nomes especificos do Itau), pois e esse vocabulario que
70
+ # fica exposto para quem consome a classe via
71
+ # Brcobranca::Retorno::Cnab240::Base (ex.: a API HTTP do
72
+ # boleto_cnab_api so serializa os atributos ja conhecidos dessa
73
+ # lista generica).
74
+ #
75
+ # Posicoes conforme manual "Cobranca FEBRABAN 240" do Itau, item
76
+ # 3.2 (Arquivo Retorno), Segmentos T e U.
77
+ class Line < Base
78
+ extend ParseLine::FixedWidth # Extendendo parseline
79
+
80
+ REGISTRO_T_FIELDS = %w[
81
+ codigo_registro codigo_ocorrencia agencia_com_dv carteira
82
+ nosso_numero cedente_com_dv documento_numero data_vencimento
83
+ valor_titulo agencia_recebedora_com_dv valor_tarifa
84
+ motivo_ocorrencia sequencial
85
+ ].freeze
86
+ REGISTRO_U_FIELDS = %w[
87
+ juros_mora desconto_concedito valor_abatimento iof_desconto
88
+ valor_recebido outros_recebimento data_ocorrencia data_credito
89
+ ].freeze
90
+
91
+ attr_accessor :tipo_registro
92
+
93
+ fixed_width_layout do |parse|
94
+ # comuns aos registros T e U
95
+ parse.field :codigo_registro, 7..7
96
+ parse.field :sequencial, 8..12
97
+ parse.field :tipo_registro, 13..13
98
+ parse.field :codigo_ocorrencia, 15..16
99
+
100
+ # segmento T
101
+ parse.field :agencia_com_dv, 18..21
102
+ parse.field :cedente_com_dv, 30..36
103
+ parse.field :carteira, 37..39
104
+ parse.field :nosso_numero, 40..47
105
+ parse.field :documento_numero, 58..67
106
+ parse.field :data_vencimento, 73..80
107
+ parse.field :valor_titulo, 81..95
108
+ parse.field :agencia_recebedora_com_dv, 99..104
109
+ parse.field :valor_tarifa, 198..212
110
+ parse.field :motivo_ocorrencia, 213..220
111
+
112
+ # segmento U
113
+ parse.field :juros_mora, 17..31
114
+ parse.field :desconto_concedito, 32..46
115
+ parse.field :valor_abatimento, 47..61
116
+ parse.field :iof_desconto, 62..76
117
+ parse.field :valor_recebido, 77..91
118
+ parse.field :outros_recebimento, 92..106
119
+ parse.field :data_ocorrencia, 137..144
120
+ parse.field :data_credito, 145..152
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brcobranca
4
+ module Util
5
+ # Regras de calculo de digito verificador (DAC) compartilhadas entre as
6
+ # implementacoes de Boleto e Remessa/Retorno CNAB do Itau (341), para
7
+ # evitar duplicacao e manter as duas em sincronia.
8
+ module Itau
9
+ # Carteiras cujo DAC do nosso numero e calculado apenas com
10
+ # "carteira/nosso_numero", sem agencia/conta.
11
+ CARTEIRAS_SEM_AGENCIA_CONTA = %w[112 126 131 146 150 168].freeze
12
+
13
+ module_function
14
+
15
+ # Digito verificador (modulo 10) da agencia/conta corrente.
16
+ #
17
+ # @return [Integer]
18
+ def agencia_conta_corrente_dv(agencia, conta_corrente)
19
+ "#{agencia}#{conta_corrente}".modulo10
20
+ end
21
+
22
+ # Digito verificador (modulo 10) do nosso numero.
23
+ #
24
+ # Para a grande maioria das carteiras, e calculado sobre
25
+ # "agencia/conta_corrente/carteira/nosso_numero". Excecao: carteiras em
26
+ # CARTEIRAS_SEM_AGENCIA_CONTA, calculado apenas sobre
27
+ # "carteira/nosso_numero".
28
+ #
29
+ # @return [Integer]
30
+ def nosso_numero_dv(agencia, conta_corrente, carteira, nosso_numero)
31
+ if CARTEIRAS_SEM_AGENCIA_CONTA.include?(carteira.to_s)
32
+ "#{carteira}#{nosso_numero}".modulo10
33
+ else
34
+ "#{agencia}#{conta_corrente}#{carteira}#{nosso_numero}".modulo10
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Brcobranca
4
- VERSION = '12.0.0'
4
+ VERSION = '13.0.0'
5
5
  end
data/lib/brcobranca.rb CHANGED
@@ -148,6 +148,7 @@ module Brcobranca
148
148
 
149
149
  module Cnab240
150
150
  autoload :Base, 'brcobranca/retorno/cnab240/base'
151
+ autoload :Itau, "brcobranca/retorno/cnab240/itau"
151
152
  autoload :Santander, 'brcobranca/retorno/cnab240/santander'
152
153
  autoload :Sicredi, 'brcobranca/retorno/cnab240/sicredi'
153
154
  autoload :Sicoob, 'brcobranca/retorno/cnab240/sicoob'
@@ -186,6 +187,7 @@ module Brcobranca
186
187
  autoload :Base, 'brcobranca/remessa/cnab240/base'
187
188
  autoload :BaseCorrespondente, 'brcobranca/remessa/cnab240/base_correspondente'
188
189
  autoload :Caixa, 'brcobranca/remessa/cnab240/caixa'
190
+ autoload :Itau, "brcobranca/remessa/cnab240/itau"
189
191
  autoload :BancoBrasil, 'brcobranca/remessa/cnab240/banco_brasil'
190
192
  autoload :Santander, 'brcobranca/remessa/cnab240/santander'
191
193
  autoload :Sicoob, 'brcobranca/remessa/cnab240/sicoob'
@@ -200,5 +202,6 @@ module Brcobranca
200
202
  module Util
201
203
  autoload :Empresa, 'brcobranca/util/empresa'
202
204
  autoload :Errors, 'brcobranca/util/errors'
205
+ autoload :Itau, "brcobranca/util/itau"
203
206
  end
204
207
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: brcobranca
3
3
  version: !ruby/object:Gem::Version
4
- version: 12.0.0
4
+ version: 13.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kivanio Barbosa
@@ -150,6 +150,7 @@ files:
150
150
  - lib/brcobranca/remessa/cnab240/base.rb
151
151
  - lib/brcobranca/remessa/cnab240/base_correspondente.rb
152
152
  - lib/brcobranca/remessa/cnab240/caixa.rb
153
+ - lib/brcobranca/remessa/cnab240/itau.rb
153
154
  - lib/brcobranca/remessa/cnab240/santander.rb
154
155
  - lib/brcobranca/remessa/cnab240/sicoob.rb
155
156
  - lib/brcobranca/remessa/cnab240/sicoob_banco_brasil.rb
@@ -175,6 +176,7 @@ files:
175
176
  - lib/brcobranca/retorno/cnab240/ailos.rb
176
177
  - lib/brcobranca/retorno/cnab240/base.rb
177
178
  - lib/brcobranca/retorno/cnab240/caixa.rb
179
+ - lib/brcobranca/retorno/cnab240/itau.rb
178
180
  - lib/brcobranca/retorno/cnab240/santander.rb
179
181
  - lib/brcobranca/retorno/cnab240/sicoob.rb
180
182
  - lib/brcobranca/retorno/cnab240/sicredi.rb
@@ -194,6 +196,7 @@ files:
194
196
  - lib/brcobranca/util/date.rb
195
197
  - lib/brcobranca/util/empresa.rb
196
198
  - lib/brcobranca/util/errors.rb
199
+ - lib/brcobranca/util/itau.rb
197
200
  - lib/brcobranca/validations.rb
198
201
  - lib/brcobranca/version.rb
199
202
  homepage: https://github.com/kivanio/brcobranca
@@ -215,7 +218,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
215
218
  version: '0'
216
219
  requirements:
217
220
  - GhostScript > 9.0, para gerar PDF e código de Barras
218
- rubygems_version: 3.6.7
221
+ rubygems_version: 4.0.16
219
222
  specification_version: 4
220
223
  summary: Gem que permite trabalhar com boletos e CNABs para bancos brasileiros.
221
224
  test_files: []