brcobranca 4.1.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -1
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +1 -1
  5. data/.travis.yml +2 -1
  6. data/Gemfile +4 -4
  7. data/Gemfile.lock +65 -53
  8. data/README.md +18 -5
  9. data/brcobranca.gemspec +8 -6
  10. data/lib/brcobranca/boleto/banco_brasil.rb +25 -27
  11. data/lib/brcobranca/boleto/base.rb +13 -6
  12. data/lib/brcobranca/boleto/bradesco.rb +4 -1
  13. data/lib/brcobranca/boleto/caixa.rb +14 -4
  14. data/lib/brcobranca/boleto/hsbc.rb +26 -26
  15. data/lib/brcobranca/boleto/santander.rb +6 -3
  16. data/lib/brcobranca/boleto/sicredi.rb +3 -5
  17. data/lib/brcobranca/boleto/template/rghost.rb +7 -5
  18. data/lib/brcobranca/boleto/template/rghost_carne.rb +1 -2
  19. data/lib/brcobranca/calculo.rb +19 -93
  20. data/lib/brcobranca/formatacao_string.rb +21 -0
  21. data/lib/brcobranca/remessa/base.rb +59 -0
  22. data/lib/brcobranca/remessa/cnab240/banco_brasil.rb +117 -0
  23. data/lib/brcobranca/remessa/cnab240/base.rb +379 -0
  24. data/lib/brcobranca/remessa/cnab240/caixa.rb +103 -0
  25. data/lib/brcobranca/remessa/cnab400/base.rb +112 -0
  26. data/lib/brcobranca/remessa/cnab400/bradesco.rb +128 -0
  27. data/lib/brcobranca/remessa/cnab400/itau.rb +149 -0
  28. data/lib/brcobranca/remessa/pagamento.rb +159 -0
  29. data/lib/brcobranca/retorno/base.rb +1 -0
  30. data/lib/brcobranca/retorno/retorno_cnab400.rb +0 -2
  31. data/lib/brcobranca/version.rb +1 -1
  32. data/lib/brcobranca.rb +33 -17
  33. data/spec/brcobranca/banco_bradesco_spec.rb +0 -2
  34. data/spec/brcobranca/banco_brasil_spec.rb +0 -2
  35. data/spec/brcobranca/banco_caixa_spec.rb +0 -2
  36. data/spec/brcobranca/banco_hsbc_spec.rb +0 -3
  37. data/spec/brcobranca/banco_itau_spec.rb +0 -1
  38. data/spec/brcobranca/banco_santander_spec.rb +14 -14
  39. data/spec/brcobranca/banco_sicredi_spec.rb +0 -2
  40. data/spec/brcobranca/base_spec.rb +11 -0
  41. data/spec/brcobranca/boletos_em_lote_spec.rb +0 -2
  42. data/spec/brcobranca/core_ext_spec.rb +104 -58
  43. data/spec/brcobranca/remessa/base_spec.rb +87 -0
  44. data/spec/brcobranca/remessa/cnab240/banco_brasil_spec.rb +200 -0
  45. data/spec/brcobranca/remessa/cnab240/base_spec.rb +88 -0
  46. data/spec/brcobranca/remessa/cnab240/caixa_spec.rb +137 -0
  47. data/spec/brcobranca/remessa/cnab400/base_spec.rb +51 -0
  48. data/spec/brcobranca/remessa/cnab400/bradesco_spec.rb +174 -0
  49. data/spec/brcobranca/remessa/cnab400/itau_spec.rb +160 -0
  50. data/spec/brcobranca/remessa/pagamento_spec.rb +197 -0
  51. data/spec/brcobranca/retorno_cbr643_spec.rb +0 -2
  52. data/spec/brcobranca/rghost_spec.rb +0 -2
  53. data/spec/shared_examples/cnab240.rb +206 -0
  54. data/spec/shared_examples/cnab400.rb +85 -0
  55. metadata +34 -4
@@ -102,7 +102,6 @@ module Brcobranca
102
102
  fail 'Não foi possível encontrar o template. Verifique o caminho' unless File.exist?(template_path)
103
103
 
104
104
  boletos.each_with_index do |boleto, index|
105
-
106
105
  modelo_generico_template(doc, boleto, template_path)
107
106
  modelo_generico_cabecalho(doc, boleto)
108
107
  modelo_generico_rodape(doc, boleto)
@@ -111,7 +110,6 @@ module Brcobranca
111
110
  doc.barcode_interleaved2of5(boleto.codigo_barras, width: '10.3 cm', height: '1.3 cm', x: '0.7 cm', y: '5.8 cm') if boleto.codigo_barras
112
111
  # Cria nova página se não for o último boleto
113
112
  doc.next_page unless index == boletos.length - 1
114
-
115
113
  end
116
114
  # Gerando stream
117
115
  formato = (options.delete(:formato) || Brcobranca.configuration.formato)
@@ -177,10 +175,14 @@ module Brcobranca
177
175
  doc.show boleto.local_pagamento
178
176
  doc.moveto x: '16.5 cm', y: '16 cm'
179
177
  doc.show boleto.data_vencimento.to_s_br if boleto.data_vencimento
180
- doc.moveto x: '1.9 cm', y: '15.5 cm'
181
- doc.show boleto.cedente
182
178
  doc.moveto x: '0.7 cm', y: '15.2 cm'
183
- doc.show boleto.cedente_endereco
179
+ if boleto.cedente_endereco
180
+ doc.show boleto.cedente_endereco
181
+ doc.moveto x: '1.9 cm', y: '15.5 cm'
182
+ doc.show boleto.cedente
183
+ else
184
+ doc.show boleto.cedente
185
+ end
184
186
  doc.moveto x: '16.5 cm', y: '15.2 cm'
185
187
  doc.show boleto.agencia_conta_boleto
186
188
  doc.moveto x: '0.7 cm', y: '14.4 cm'
@@ -104,7 +104,7 @@ module Brcobranca
104
104
  modelo_carne_define_tags(doc)
105
105
 
106
106
  boletos.each_with_index do |boleto, index|
107
- curr_page_position = curr_page_position + 1
107
+ curr_page_position += 1
108
108
 
109
109
  margin_bottom = initial_margin_bottom + (heigth_template * (max_per_page - curr_page_position)) # onde o boleto sera impresso na pagina A4
110
110
 
@@ -122,7 +122,6 @@ module Brcobranca
122
122
 
123
123
  curr_page_position = 0 # reinicia contador por página
124
124
  end
125
-
126
125
  end
127
126
 
128
127
  # Gerando stream
@@ -22,91 +22,21 @@ module Brcobranca
22
22
  valor == 10 ? 0 : valor
23
23
  end
24
24
 
25
- # Calcula módulo 11 com multiplicaroes de 9 a 2 segundo a BACEN.
25
+ # Calcula o módulo 11 segundo a BACEN
26
26
  #
27
27
  # @return [Integer]
28
- def modulo11_9to2
29
- total = multiplicador([9, 8, 7, 6, 5, 4, 3, 2])
30
-
31
- (total % 11)
32
- end
33
-
34
- # Calcula módulo 11 com multiplicaroes de 2 a 9 segundo a BACEN.
35
- #
36
- # @return [Integer]
37
- def modulo11_2to9
38
- total = multiplicador([2, 3, 4, 5, 6, 7, 8, 9])
39
-
40
- valor = (11 - (total % 11))
41
- [0, 10, 11].include?(valor) ? 1 : valor
42
- end
43
-
44
- # Calcula módulo 11 com multiplicadores de 2 a 9 e 2 a 5 (Utilizado pelo Santander).
45
- #
46
- # @return [Integer]
47
- def modulo11_santander
48
- return 0 if self.to_i == 0
49
-
50
- somatorio = 0
51
- multiplicadores = [2, 3, 4, 5, 6, 7, 8, 9, 2, 3, 4, 5]
52
- base = "#{self.rjust(12, '0')}".reverse
53
- index = 0
54
-
55
- base.each_char do |char|
56
- somatorio += base[index].to_i * multiplicadores[index].to_i
57
- index += 1
58
- end
59
-
60
- resto = somatorio % 11
61
- return 1 if resto == 10
62
- return 0 if resto == 1 || resto == 0
63
- return 11 - resto
64
- end
65
-
66
- # Calcula módulo 11 com multiplicadores de 2, 7 a 2, e 7 a 2 (Utilizado pelo Bradesco).
67
- #
68
- # @return [Integer, String] Caso o resto seja 1, retorna P
69
-
70
- def modulo11_bradesco
71
- somatorio = 0
72
- multiplicadores = [2, 7, 6, 5, 4, 3, 2, 7, 6, 5, 4, 3, 2]
73
- index = 0
74
-
75
- self.each_char do |char|
76
- somatorio += self[index].to_i * multiplicadores[index]
77
- index += 1
78
- end
79
-
80
- resto = somatorio % 11
81
- return 0 if resto == 0
82
- return 'P' if resto == 1
83
- return 11 - resto
84
- end
85
-
86
- # Calcula módulo 11 com multiplicaroes de 2 a 9 (Utilizado pela CAIXA - boletos SIGCB).
87
- #
88
- # @return [Integer]
89
- def modulo11_2to9_caixa
90
- total = multiplicador([2, 3, 4, 5, 6, 7, 8, 9])
91
- total = (total % 11) unless total < 11
92
- valor = (11 - total)
93
- valor > 9 ? 0 : valor
94
- end
28
+ # @raise [ArgumentError] Caso não seja um número inteiro.
29
+ # @param [Hash] options Opções para o cálculo do módulo
30
+ # @option options [Hash] :mapeamento Mapeamento do valor final. Ex: { 10 => "X" }. Padrão: {}
31
+ # @option options [Array] :multiplicador Números a serem utilizados na multiplicação da direita para a esquerda. Padrão: [9 até 2]
32
+ def modulo11(options = {}, &_block)
33
+ options[:mapeamento] ||= {}
34
+ options[:multiplicador] ||= [9, 8, 7, 6, 5, 4, 3, 2]
95
35
 
96
- # Calcula módulo 11 com multiplicaroes de 9 a 2 trocando retorno <b>10 por X</b>.
97
- #
98
- # @return [Integer, String] Caso resultado for 10, retorna X.
99
- def modulo11_9to2_10_como_x
100
- valor = modulo11_9to2
101
- valor == 10 ? 'X' : valor
102
- end
36
+ total = multiplicador(options[:multiplicador])
37
+ valor = block_given? ? yield(total) : (total % 11)
103
38
 
104
- # Calcula módulo 11 com multiplicaroes de 9 a 2 trocando retorno <b>10 por 0</b>.
105
- #
106
- # @return [Integer]
107
- def modulo11_9to2_10_como_zero
108
- valor = modulo11_9to2
109
- valor == 10 ? 0 : valor
39
+ options[:mapeamento][valor] || valor
110
40
  end
111
41
 
112
42
  # Verifica se String só contem caracteres numéricos.
@@ -125,13 +55,13 @@ module Brcobranca
125
55
  # 13 (1+3) #=> 4
126
56
  def soma_digitos
127
57
  total = case to_i
128
- when (0..9)
129
- self
130
- else
131
- numero = to_s
132
- total = 0
133
- 0.upto(numero.size - 1) { |digito| total += numero[digito, 1].to_i }
134
- total
58
+ when (0..9)
59
+ self
60
+ else
61
+ numero = to_s
62
+ total = 0
63
+ 0.upto(numero.size - 1) { |digito| total += numero[digito, 1].to_i }
64
+ total
135
65
  end
136
66
  total.to_i
137
67
  end
@@ -149,11 +79,7 @@ module Brcobranca
149
79
 
150
80
  to_s.split(//).reverse!.each do |caracter|
151
81
  fator = fatores[multiplicador_posicao]
152
- total += if block_given?
153
- yield(caracter, fator)
154
- else
155
- (caracter.to_i * fator)
156
- end
82
+ total += block_given? ? yield(caracter, fator) : (caracter.to_i * fator)
157
83
  multiplicador_posicao = (multiplicador_posicao < (fatores.size - 1)) ? (multiplicador_posicao + 1) : 0
158
84
  end
159
85
  total
@@ -0,0 +1,21 @@
1
+ module Brcobranca
2
+ # Métodos auxiliares de formatação de strings
3
+ module FormatacaoString
4
+ # Formata o tamanho da string
5
+ # para o tamanho passado
6
+ # se a string for menor, adiciona espacos a direita
7
+ # se a string for maior, trunca para o num. de caracteres
8
+ #
9
+ def format_size(size)
10
+ if self.size > size
11
+ return truncate(size, omission: '')
12
+ else
13
+ return ljust(size, ' ')
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ [String].each do |klass|
20
+ klass.class_eval { include Brcobranca::FormatacaoString }
21
+ end
@@ -0,0 +1,59 @@
1
+ # -*- encoding: utf-8 -*-
2
+ module Brcobranca
3
+ module Remessa
4
+ class Base
5
+ # pagamentos da remessa (cada pagamento representa um registro detalhe no arquivo)
6
+ attr_accessor :pagamentos
7
+ # empresa mae (razao social)
8
+ attr_accessor :empresa_mae
9
+ # agencia (sem digito verificador)
10
+ attr_accessor :agencia
11
+ # numero da conta corrente
12
+ attr_accessor :conta_corrente
13
+ # digito verificador da conta corrente
14
+ attr_accessor :digito_conta
15
+ # carteira do cedente
16
+ attr_accessor :carteira
17
+ # sequencial remessa (num. sequencial que nao pode ser repetido nem zerado)
18
+ attr_accessor :sequencial_remessa
19
+ # aceite (A = ACEITO/N = NAO ACEITO)
20
+ attr_accessor :aceite
21
+
22
+ # Validações do Rails 3
23
+ include ActiveModel::Validations
24
+
25
+ validates_presence_of :pagamentos, :empresa_mae, :agencia, :conta_corrente, message: 'não pode estar em branco.'
26
+ validates_length_of :empresa_mae, maximum: 30, message: 'deve ser menor ou igual a 30 caracteres.'
27
+
28
+ validates_each :pagamentos do |record, attr, value|
29
+ if value.is_a? Array
30
+ record.errors.add(attr, 'não pode estar vazio.') if value.empty?
31
+ value.each do |pagamento|
32
+ if pagamento.is_a? Brcobranca::Remessa::Pagamento
33
+ if pagamento.invalid?
34
+ pagamento.errors.full_messages.each { |msg| record.errors.add(attr, msg) }
35
+ end
36
+ else
37
+ record.errors.add(attr, 'cada item deve ser um objeto Pagamento.')
38
+ end
39
+ end
40
+ else
41
+ record.errors.add(attr, 'deve ser uma coleção (Array).')
42
+ end
43
+ end
44
+
45
+ # Nova instancia da classe
46
+ #
47
+ # @param campos [Hash]
48
+ #
49
+ def initialize(campos = {})
50
+ campos = { aceite: 'N' }.merge!(campos)
51
+ campos.each do |campo, valor|
52
+ send "#{campo}=", valor
53
+ end
54
+
55
+ yield self if block_given?
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,117 @@
1
+ # -*- encoding: utf-8 -*-
2
+ module Brcobranca
3
+ module Remessa
4
+ module Cnab240
5
+ class BancoBrasil < Brcobranca::Remessa::Cnab240::Base
6
+ # variacao da carteira
7
+ attr_accessor :variacao
8
+ # identificacao da emissao do boleto (attr na classe base)
9
+ # campo nao tratado pelo sistema do Banco do Brasil
10
+ # identificacao da distribuicao do boleto (attr na classe base)
11
+ # campo nao tratado pelo sistema do Banco do Brasil
12
+
13
+ validates_presence_of :carteira, :variacao, message: 'não pode estar em branco.'
14
+ validates_length_of :conta_corrente, is: 5, message: 'deve ter 5 dígitos.'
15
+ validates_length_of :agencia, is: 4, message: 'deve ter 4 dígitos.'
16
+ validates_length_of :carteira, is: 2, message: 'deve ter 2 dígitos.'
17
+ validates_length_of :variacao, is: 3, message: 'deve ter 3 dígitos.'
18
+ validates_length_of :convenio, in: 4..7, message: 'não existente para este banco.'
19
+
20
+ def initialize(campos = {})
21
+ campos = { emissao_boleto: '0',
22
+ distribuicao_boleto: '0',
23
+ especie_titulo: '02' }.merge!(campos)
24
+ super(campos)
25
+ end
26
+
27
+ def cod_banco
28
+ '001'
29
+ end
30
+
31
+ def nome_banco
32
+ 'BANCO DO BRASIL S.A.'.ljust(30, ' ')
33
+ end
34
+
35
+ def versao_layout
36
+ '000'
37
+ end
38
+
39
+ def digito_agencia
40
+ # utilizando a agencia com 4 digitos
41
+ # para calcular o digito
42
+ agencia.modulo11(mapeamento: { 10 => 'X' }).to_s
43
+ end
44
+
45
+ def digito_conta
46
+ # utilizando a conta corrente com 5 digitos
47
+ # para calcular o digito
48
+ conta_corrente.modulo11(mapeamento: { 10 => 'X' }).to_s
49
+ end
50
+
51
+ def codigo_convenio
52
+ # CAMPO TAMANHO
53
+ # num. convenio 9
54
+ # cobranca cedente 4
55
+ # carteira 2
56
+ # variacao carteira 3
57
+ # campo reservado 2
58
+ "#{convenio.rjust(9, '0')}0014#{carteira}#{variacao} "
59
+ end
60
+ alias_method :convenio_lote, :codigo_convenio
61
+
62
+ def info_conta
63
+ # CAMPO TAMANHO
64
+ # agencia 5
65
+ # digito agencia 1
66
+ # conta corrente 12
67
+ # digito conta 1
68
+ # digito agencia/conta 1
69
+ "#{agencia.rjust(5, '0')}#{digito_agencia}#{conta_corrente.rjust(12, '0')}#{digito_conta} "
70
+ end
71
+
72
+ def complemento_header
73
+ ''.rjust(29, ' ')
74
+ end
75
+
76
+ def complemento_trailer
77
+ ''.rjust(217, ' ')
78
+ end
79
+
80
+ def complemento_p(pagamento)
81
+ # CAMPO TAMANHO
82
+ # conta corrente 12
83
+ # digito conta 1
84
+ # digito agencia/conta 1
85
+ # ident. titulo no banco 20
86
+ "#{conta_corrente.rjust(12, '0')}#{digito_conta} #{identificador_titulo(pagamento.nosso_numero)}"
87
+ end
88
+
89
+ # Retorna o nosso numero mais o digito verificador
90
+ #
91
+ # @return [String]
92
+ #
93
+ def formata_nosso_numero(nosso_numero)
94
+ quantidade = case convenio.to_s.size
95
+ # convenio de 4 posicoes com nosso numero de 7
96
+ when 4 then 7
97
+ # convenio de 6 posicoes com nosso numero de 5
98
+ when 6 then 5
99
+ # convenio de 7 posicoes com nosso numero de 10
100
+ when 7 then 10
101
+ else
102
+ fail Brcobranca::NaoImplementado.new('Tipo de convênio não implementado.')
103
+ end
104
+ nosso_numero = nosso_numero.to_s.rjust(quantidade, '0')
105
+
106
+ # calcula o digito do nosso numero (menos para quando nosso numero tiver 10 posicoes)
107
+ digito = "#{convenio}#{nosso_numero}".modulo11(mapeamento: { 10 => 'X' }) unless quantidade == 10
108
+ "#{nosso_numero}#{digito}"
109
+ end
110
+
111
+ def identificador_titulo(nosso_numero)
112
+ "#{convenio}#{formata_nosso_numero(nosso_numero)}".ljust(20, ' ')
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end