boleto_bancario 0.0.2 → 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.
Files changed (73) hide show
  1. checksums.yaml +5 -5
  2. data/Changelog.markdown +54 -2
  3. data/README.markdown +660 -189
  4. data/lib/boleto_bancario/calculos/documento.rb +191 -0
  5. data/lib/boleto_bancario/calculos/fator_vencimento.rb +78 -31
  6. data/lib/boleto_bancario/core/boleto.rb +30 -1
  7. data/lib/boleto_bancario/core/c6_bank.rb +155 -0
  8. data/lib/boleto_bancario/core/inter.rb +155 -0
  9. data/lib/boleto_bancario/core/nubank.rb +156 -0
  10. data/lib/boleto_bancario/locales/pt-BR.yml +55 -0
  11. data/lib/boleto_bancario/renderers/base.rb +154 -0
  12. data/lib/boleto_bancario/renderers/html_renderer.rb +92 -0
  13. data/lib/boleto_bancario/renderers/pdf_renderer.rb +130 -0
  14. data/lib/boleto_bancario/renderers/png_renderer.rb +66 -0
  15. data/lib/boleto_bancario/templates/_barcode.html.erb +3 -0
  16. data/lib/boleto_bancario/templates/_cedente.html.erb +14 -0
  17. data/lib/boleto_bancario/templates/_header.html.erb +4 -0
  18. data/lib/boleto_bancario/templates/_instructions.html.erb +10 -0
  19. data/lib/boleto_bancario/templates/_payment.html.erb +36 -0
  20. data/lib/boleto_bancario/templates/_sacado.html.erb +10 -0
  21. data/lib/boleto_bancario/templates/boleto.html.erb +22 -0
  22. data/lib/boleto_bancario/templates/boleto_styles.css +18 -0
  23. data/lib/boleto_bancario/version.rb +3 -1
  24. data/lib/boleto_bancario.rb +23 -6
  25. data/lib/generators/boleto_bancario/views_generator.rb +47 -0
  26. metadata +91 -129
  27. data/.gitignore +0 -19
  28. data/.rspec +0 -1
  29. data/.travis.yml +0 -10
  30. data/Gemfile +0 -3
  31. data/Planning.markdown +0 -63
  32. data/Rakefile +0 -15
  33. data/TODO.markdown +0 -19
  34. data/boleto_bancario.gemspec +0 -29
  35. data/documentacoes_dos_boletos/Bradesco/Manual_BRADESCO.PDF +0 -0
  36. data/lib/boleto_bancario/core/hsbc.rb +0 -170
  37. data/lib/boleto_bancario/core/real.rb +0 -177
  38. data/spec/boleto_bancario/calculos/digitos_spec.rb +0 -19
  39. data/spec/boleto_bancario/calculos/fator_vencimento_spec.rb +0 -59
  40. data/spec/boleto_bancario/calculos/fatores_de_multiplicacao_spec.rb +0 -69
  41. data/spec/boleto_bancario/calculos/linha_digitavel_spec.rb +0 -57
  42. data/spec/boleto_bancario/calculos/modulo10_spec.rb +0 -53
  43. data/spec/boleto_bancario/calculos/modulo11_fator_de2a7_spec.rb +0 -43
  44. data/spec/boleto_bancario/calculos/modulo11_fator_de2a9_resto_zero_spec.rb +0 -39
  45. data/spec/boleto_bancario/calculos/modulo11_fator_de2a9_spec.rb +0 -67
  46. data/spec/boleto_bancario/calculos/modulo11_fator_de9a2_resto_x_spec.rb +0 -37
  47. data/spec/boleto_bancario/calculos/modulo11_fator_de9a2_spec.rb +0 -31
  48. data/spec/boleto_bancario/calculos/modulo11_spec.rb +0 -19
  49. data/spec/boleto_bancario/calculos/modulo_numero_de_controle_spec.rb +0 -37
  50. data/spec/boleto_bancario/core/banco_brasil_spec.rb +0 -377
  51. data/spec/boleto_bancario/core/banrisul_spec.rb +0 -129
  52. data/spec/boleto_bancario/core/boleto_spec.rb +0 -218
  53. data/spec/boleto_bancario/core/bradesco_spec.rb +0 -163
  54. data/spec/boleto_bancario/core/caixa_spec.rb +0 -111
  55. data/spec/boleto_bancario/core/hsbc_spec.rb +0 -72
  56. data/spec/boleto_bancario/core/itau_spec.rb +0 -333
  57. data/spec/boleto_bancario/core/real_spec.rb +0 -104
  58. data/spec/boleto_bancario/core/santander_spec.rb +0 -137
  59. data/spec/boleto_bancario/core/sicoob_spec.rb +0 -111
  60. data/spec/boleto_bancario/core/sicredi_spec.rb +0 -149
  61. data/spec/inheritance/banco_brasil_spec.rb +0 -22
  62. data/spec/inheritance/banrisul_spec.rb +0 -22
  63. data/spec/inheritance/boleto_spec.rb +0 -15
  64. data/spec/inheritance/bradesco_spec.rb +0 -22
  65. data/spec/inheritance/caixa_spec.rb +0 -22
  66. data/spec/inheritance/hsbc_spec.rb +0 -22
  67. data/spec/inheritance/itau_spec.rb +0 -22
  68. data/spec/inheritance/real_spec.rb +0 -22
  69. data/spec/inheritance/santander_spec.rb +0 -22
  70. data/spec/inheritance/sicoob_spec.rb +0 -22
  71. data/spec/inheritance/sicredi_spec.rb +0 -22
  72. data/spec/shared_examples/boleto_bancario_shared_example.rb +0 -151
  73. data/spec/spec_helper.rb +0 -14
@@ -0,0 +1,156 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BoletoBancario
4
+ module Core
5
+ # Implementação de emissão de boleto bancário pelo Nubank.
6
+ #
7
+ # === Documentação Implementada
8
+ #
9
+ # A documentação na qual essa implementação foi baseada está localizada na pasta
10
+ # 'documentacoes_dos_boletos/nubank' dentro dessa biblioteca.
11
+ #
12
+ # === Contrato das classes de emissão de boletos
13
+ #
14
+ # Para ver o "<b>contrato</b>" da Emissão de Boletos veja a classe BoletoBancario::Core::Boleto.
15
+ #
16
+ # === Carteiras suportadas
17
+ #
18
+ # O Nubank trabalha com carteira única de cobrança registrada.
19
+ #
20
+ # ___________________________________________________________________________
21
+ # | Carteira | Descrição | Testada/Homologada |
22
+ # | 1 | Cobrança Registrada | Esperando Contribuição |
23
+ # ----------------------------------------------------------------------------
24
+ #
25
+ class Nubank < Boleto
26
+ # Tamanho máximo de uma conta corrente no Nubank.
27
+ #
28
+ # @return [Integer] 10
29
+ #
30
+ def self.tamanho_maximo_conta_corrente
31
+ 10
32
+ end
33
+
34
+ # Tamanho máximo de uma agência no Nubank.
35
+ # Nubank utiliza agência fixa 0001.
36
+ #
37
+ # @return [Integer] 4
38
+ #
39
+ def self.tamanho_maximo_agencia
40
+ 4
41
+ end
42
+
43
+ # Tamanho máximo do número do documento.
44
+ #
45
+ # @return [Integer] 11
46
+ #
47
+ def self.tamanho_maximo_numero_documento
48
+ 11
49
+ end
50
+
51
+ # Tamanho máximo do código do cedente.
52
+ #
53
+ # @return [Integer] 10
54
+ #
55
+ def self.tamanho_maximo_codigo_cedente
56
+ 10
57
+ end
58
+
59
+ # Carteiras suportadas pelo Nubank.
60
+ #
61
+ # @return [Array]
62
+ #
63
+ def self.carteiras_suportadas
64
+ %w[1]
65
+ end
66
+
67
+ validates :agencia, :conta_corrente, presence: true
68
+ validates :numero_documento, length: { maximum: tamanho_maximo_numero_documento }, if: :deve_validar_numero_documento?
69
+ validates :conta_corrente, length: { maximum: tamanho_maximo_conta_corrente }, if: :deve_validar_conta_corrente?
70
+ validates :agencia, length: { maximum: tamanho_maximo_agencia }, if: :deve_validar_agencia?
71
+ validates :carteira, inclusion: { in: ->(object) { object.class.carteiras_suportadas } }, if: :deve_validar_carteira?
72
+
73
+ # @return [String] Número do documento com 11 dígitos.
74
+ #
75
+ def numero_documento
76
+ @numero_documento.to_s.rjust(11, '0') if @numero_documento.present?
77
+ end
78
+
79
+ # @return [String] Agência com 4 dígitos.
80
+ #
81
+ def agencia
82
+ @agencia.to_s.rjust(4, '0') if @agencia.present?
83
+ end
84
+
85
+ # @return [String] Conta corrente com 10 dígitos.
86
+ #
87
+ def conta_corrente
88
+ @conta_corrente.to_s.rjust(10, '0') if @conta_corrente.present?
89
+ end
90
+
91
+ # @return [String] Código do cedente com 10 dígitos.
92
+ #
93
+ def codigo_cedente
94
+ @codigo_cedente.to_s.rjust(10, '0') if @codigo_cedente.present?
95
+ end
96
+
97
+ # Código do Banco Nubank.
98
+ #
99
+ # @return [String] '260'
100
+ #
101
+ def codigo_banco
102
+ '260'
103
+ end
104
+
105
+ # Dígito do código do banco.
106
+ #
107
+ # @return [String] '0'
108
+ #
109
+ def digito_codigo_banco
110
+ '0'
111
+ end
112
+
113
+ # Dígito verificador da conta corrente.
114
+ #
115
+ # @return [String]
116
+ #
117
+ def digito_conta_corrente
118
+ Modulo10.new(conta_corrente.to_s)
119
+ end
120
+
121
+ # Agência e código do cedente formatados.
122
+ #
123
+ # @return [String]
124
+ #
125
+ def agencia_codigo_cedente
126
+ "#{agencia} / #{conta_corrente}-#{digito_conta_corrente}"
127
+ end
128
+
129
+ # Nosso Número formatado.
130
+ #
131
+ # @return [String]
132
+ #
133
+ def nosso_numero
134
+ "#{carteira}/#{numero_documento}-#{digito_nosso_numero}"
135
+ end
136
+
137
+ # Dígito verificador do nosso número.
138
+ #
139
+ # @return [String]
140
+ #
141
+ def digito_nosso_numero
142
+ Modulo10.new("#{carteira}#{numero_documento}")
143
+ end
144
+
145
+ # Segunda parte do código de barras (campo livre).
146
+ # 25 posições específicas do Nubank.
147
+ #
148
+ # @return [String]
149
+ #
150
+ def codigo_de_barras_do_banco
151
+ codigo = "#{carteira.to_s.rjust(1, '0')}#{numero_documento}#{agencia}#{conta_corrente.to_s[0, 9]}"
152
+ "#{codigo.ljust(25, '0')}"
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,55 @@
1
+ pt-BR:
2
+ boleto_bancario:
3
+ labels:
4
+ cedente: "Cedente"
5
+ sacado: "Sacado"
6
+ nosso_numero: "Nosso Número"
7
+ numero_documento: "Número do Documento"
8
+ data_vencimento: "Data de Vencimento"
9
+ valor_documento: "Valor do Documento"
10
+ agencia_cedente: "Agência/Código Cedente"
11
+ especie: "Espécie"
12
+ especie_documento: "Espécie Doc."
13
+ aceite: "Aceite"
14
+ data_documento: "Data do Documento"
15
+ carteira: "Carteira"
16
+ instrucoes: "Instruções"
17
+ local_pagamento: "Local de Pagamento"
18
+ linha_digitavel: "Linha Digitável"
19
+ codigo_banco: "Código do Banco"
20
+ documento_cedente: "CPF/CNPJ Cedente"
21
+ documento_sacado: "CPF/CNPJ Sacado"
22
+ endereco_cedente: "Endereço Cedente"
23
+ endereco_sacado: "Endereço Sacado"
24
+ conta_corrente: "Conta Corrente"
25
+ agencia: "Agência"
26
+ codigo_cedente: "Código do Cedente"
27
+
28
+ errors:
29
+ messages:
30
+ carteira_invalida: "carteira inválida"
31
+ agencia_invalida: "agência inválida"
32
+ conta_corrente_invalida: "conta corrente inválida"
33
+ valor_documento_invalido: "valor do documento inválido"
34
+ numero_documento_invalido: "número do documento inválido"
35
+ codigo_cedente_invalido: "código do cedente inválido"
36
+ documento_invalido: "documento inválido (CPF/CNPJ)"
37
+ data_vencimento_invalida: "data de vencimento inválida"
38
+
39
+ banks:
40
+ banco_brasil: "Banco do Brasil"
41
+ bradesco: "Bradesco"
42
+ itau: "Itaú"
43
+ santander: "Santander"
44
+ caixa: "Caixa Econômica Federal"
45
+ banrisul: "Banrisul"
46
+ sicoob: "Sicoob"
47
+ sicredi: "Sicredi"
48
+ nubank: "Nubank"
49
+ inter: "Banco Inter"
50
+ c6_bank: "C6 Bank"
51
+
52
+ defaults:
53
+ local_pagamento: "PAGÁVEL EM QUALQUER BANCO ATÉ O VENCIMENTO"
54
+ especie_documento: "DM"
55
+ especie: "R$"
@@ -0,0 +1,154 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'erb'
4
+
5
+ module BoletoBancario
6
+ module Renderers
7
+ # Classe base para renderizadores de boletos.
8
+ #
9
+ # Esta classe fornece a interface comum para todos os renderizadores
10
+ # (PDF, HTML, PNG).
11
+ #
12
+ # @abstract Subclasses devem implementar o método #render
13
+ #
14
+ class Base
15
+ attr_reader :boleto
16
+
17
+ class << self
18
+ # Caminho customizado para templates ERB.
19
+ # Se não definido, usa o caminho padrão dos templates bundled.
20
+ #
21
+ # @return [String, nil]
22
+ #
23
+ attr_accessor :template_path
24
+ end
25
+
26
+ # Inicializa o renderizador com um boleto.
27
+ #
28
+ # @param [BoletoBancario::Core::Boleto] boleto O boleto a ser renderizado
29
+ # @raise [ArgumentError] Se o boleto não for válido
30
+ #
31
+ def initialize(boleto)
32
+ raise ArgumentError, 'Boleto deve ser válido' unless boleto.valid?
33
+
34
+ @boleto = boleto
35
+ end
36
+
37
+ # Renderiza o boleto.
38
+ #
39
+ # @abstract Subclasses devem implementar este método
40
+ # @raise [NotImplementedError]
41
+ #
42
+ def render
43
+ raise NotImplementedError, "#{self.class} deve implementar #render"
44
+ end
45
+
46
+ # Retorna o partial path para integração com Rails.
47
+ #
48
+ # @return [String]
49
+ #
50
+ def to_partial_path
51
+ boleto.to_partial_path
52
+ end
53
+
54
+ protected
55
+
56
+ # Retorna o caminho para os templates.
57
+ # Usa o template_path da classe se definido, caso contrário usa o padrão.
58
+ #
59
+ # @return [String]
60
+ #
61
+ def template_path
62
+ self.class.template_path || default_template_path
63
+ end
64
+
65
+ # Retorna o caminho padrão para os templates bundled.
66
+ #
67
+ # @return [String]
68
+ #
69
+ def default_template_path
70
+ File.expand_path('../templates', __dir__)
71
+ end
72
+
73
+ # Renderiza um template ERB.
74
+ #
75
+ # @param [String] template_name Nome do arquivo de template (ex: 'boleto.html.erb')
76
+ # @return [String] Conteúdo renderizado
77
+ #
78
+ def render_template(template_name)
79
+ template_file = File.join(template_path, template_name)
80
+ template_content = File.read(template_file)
81
+ erb = ERB.new(template_content, trim_mode: '-')
82
+ erb.result(binding)
83
+ end
84
+
85
+ # Renderiza um partial ERB.
86
+ #
87
+ # @param [String] partial_name Nome do partial (sem underscore, ex: 'header')
88
+ # @return [String] Conteúdo renderizado
89
+ #
90
+ def render_partial(partial_name)
91
+ render_template("_#{partial_name}.html.erb")
92
+ end
93
+
94
+ # Retorna as variáveis locais disponíveis nos templates.
95
+ #
96
+ # @return [Hash]
97
+ #
98
+ def locals
99
+ {
100
+ boleto: boleto,
101
+ renderer: self
102
+ }
103
+ end
104
+
105
+ # Retorna o código de barras do boleto.
106
+ #
107
+ # @return [String]
108
+ #
109
+ def codigo_de_barras
110
+ boleto.codigo_de_barras
111
+ end
112
+
113
+ # Retorna a linha digitável do boleto.
114
+ #
115
+ # @return [String]
116
+ #
117
+ def linha_digitavel
118
+ boleto.linha_digitavel
119
+ end
120
+
121
+ # Retorna o nosso número formatado.
122
+ #
123
+ # @return [String]
124
+ #
125
+ def nosso_numero
126
+ boleto.nosso_numero
127
+ end
128
+
129
+ # Retorna o valor formatado.
130
+ #
131
+ # @return [String]
132
+ #
133
+ def valor_formatado
134
+ format('%.2f', boleto.valor_documento).tr('.', ',')
135
+ end
136
+
137
+ # Retorna a data de vencimento formatada.
138
+ #
139
+ # @return [String]
140
+ #
141
+ def data_vencimento_formatada
142
+ boleto.data_vencimento.strftime('%d/%m/%Y')
143
+ end
144
+
145
+ # Retorna a data do documento formatada.
146
+ #
147
+ # @return [String]
148
+ #
149
+ def data_documento_formatada
150
+ boleto.data_documento&.strftime('%d/%m/%Y')
151
+ end
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BoletoBancario
4
+ module Renderers
5
+ # Renderizador de boletos em formato HTML usando templates ERB.
6
+ #
7
+ # @example Gerando HTML com template padrão
8
+ #
9
+ # boleto = BoletoBancario::Itau.new(...)
10
+ # html_content = BoletoBancario::Renderers::HtmlRenderer.new(boleto).render
11
+ #
12
+ # @example Customizando o caminho dos templates
13
+ #
14
+ # class MyHtmlRenderer < BoletoBancario::Renderers::HtmlRenderer
15
+ # self.template_path = 'path/to/my/templates'
16
+ # end
17
+ #
18
+ # renderer = MyHtmlRenderer.new(boleto)
19
+ # html = renderer.render
20
+ #
21
+ class HtmlRenderer < Base
22
+ # Renderiza o boleto em HTML usando template ERB.
23
+ #
24
+ # @return [String] O conteúdo HTML do boleto
25
+ #
26
+ def render
27
+ render_template('boleto.html.erb')
28
+ end
29
+
30
+ # Retorna os estilos CSS para o boleto.
31
+ # Pode ser sobrescrito em subclasses para customização.
32
+ #
33
+ # @return [String]
34
+ #
35
+ def css_styles
36
+ css_file = File.join(template_path, 'boleto_styles.css')
37
+ if File.exist?(css_file)
38
+ File.read(css_file)
39
+ else
40
+ default_css_styles
41
+ end
42
+ end
43
+
44
+ # Retorna a lista de instruções não vazias.
45
+ #
46
+ # @return [Array<String>]
47
+ #
48
+ def instructions
49
+ [
50
+ boleto.instrucoes1,
51
+ boleto.instrucoes2,
52
+ boleto.instrucoes3,
53
+ boleto.instrucoes4,
54
+ boleto.instrucoes5,
55
+ boleto.instrucoes6
56
+ ].compact.reject(&:empty?)
57
+ end
58
+
59
+ # Retorna o nome do banco formatado.
60
+ #
61
+ # @return [String]
62
+ #
63
+ def bank_name
64
+ boleto.class.name.split('::').last
65
+ end
66
+
67
+ private
68
+
69
+ def default_css_styles
70
+ <<~CSS
71
+ * { margin: 0; padding: 0; box-sizing: border-box; }
72
+ body { font-family: Arial, sans-serif; font-size: 12px; }
73
+ .boleto { max-width: 800px; margin: 20px auto; border: 1px solid #000; padding: 15px; }
74
+ .header { display: flex; justify-content: space-between; border-bottom: 2px solid #000; padding-bottom: 10px; margin-bottom: 10px; }
75
+ .bank-name { font-size: 18px; font-weight: bold; }
76
+ .bank-code { font-size: 16px; font-weight: bold; }
77
+ .linha-digitavel { text-align: center; font-size: 14px; font-weight: bold; margin: 15px 0; letter-spacing: 1px; }
78
+ .info-row { display: flex; border-bottom: 1px solid #ccc; }
79
+ .info-cell { flex: 1; padding: 5px; border-right: 1px solid #ccc; }
80
+ .info-cell:last-child { border-right: none; }
81
+ .info-cell label { font-size: 10px; color: #666; display: block; }
82
+ .info-cell span { font-weight: bold; }
83
+ .instructions { margin: 15px 0; padding: 10px; background: #f9f9f9; }
84
+ .instructions h4 { margin-bottom: 5px; }
85
+ .instructions ul { margin-left: 20px; }
86
+ .barcode { text-align: center; margin: 20px 0; font-family: 'Libre Barcode 128', monospace; font-size: 48px; }
87
+ .barcode-text { font-size: 10px; margin-top: 5px; }
88
+ CSS
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'prawn'
4
+ require 'prawn/table'
5
+ require 'barby'
6
+ require 'barby/barcode/code_25_interleaved'
7
+ require 'barby/outputter/prawn_outputter'
8
+
9
+ module BoletoBancario
10
+ module Renderers
11
+ # Renderizador de boletos em formato PDF usando Prawn.
12
+ #
13
+ # @example Gerando um PDF
14
+ #
15
+ # boleto = BoletoBancario::Itau.new(...)
16
+ # pdf_content = BoletoBancario::Renderers::PdfRenderer.new(boleto).render
17
+ # File.write('boleto.pdf', pdf_content)
18
+ #
19
+ class PdfRenderer < Base
20
+ # Configurações padrão do documento PDF.
21
+ DEFAULT_OPTIONS = {
22
+ page_size: 'A4',
23
+ margin: [20, 20, 20, 20]
24
+ }.freeze
25
+
26
+ # Renderiza o boleto em PDF.
27
+ #
28
+ # @return [String] O conteúdo binário do PDF
29
+ #
30
+ def render
31
+ Prawn::Document.new(**DEFAULT_OPTIONS) do |pdf|
32
+ render_header(pdf)
33
+ render_bank_info(pdf)
34
+ pdf.move_down 10
35
+ render_recipient_info(pdf)
36
+ pdf.move_down 10
37
+ render_payment_info(pdf)
38
+ pdf.move_down 10
39
+ render_barcode(pdf)
40
+ pdf.move_down 20
41
+ render_instructions(pdf)
42
+ pdf.move_down 30
43
+ render_tear_line(pdf)
44
+ pdf.move_down 10
45
+ render_stub(pdf)
46
+ end.render
47
+ end
48
+
49
+ private
50
+
51
+ def render_header(pdf)
52
+ pdf.text boleto.class.name.demodulize, size: 14, style: :bold
53
+ pdf.text "Código do Banco: #{boleto.codigo_banco_formatado}", size: 10
54
+ end
55
+
56
+ def render_bank_info(pdf)
57
+ pdf.move_down 10
58
+ pdf.text linha_digitavel, size: 12, style: :bold, align: :center
59
+ end
60
+
61
+ def render_recipient_info(pdf)
62
+ data = [
63
+ ['Cedente', boleto.cedente],
64
+ ['CPF/CNPJ', boleto.documento_cedente],
65
+ ['Endereço', boleto.endereco_cedente],
66
+ ['Agência/Código Cedente', boleto.agencia_codigo_cedente]
67
+ ]
68
+
69
+ pdf.table(data, width: pdf.bounds.width) do |t|
70
+ t.cells.borders = [:bottom]
71
+ t.cells.padding = [2, 5]
72
+ t.column(0).font_style = :bold
73
+ t.column(0).width = 150
74
+ end
75
+ end
76
+
77
+ def render_payment_info(pdf)
78
+ data = [
79
+ ['Data Vencimento', data_vencimento_formatada, 'Valor', "R$ #{valor_formatado}"],
80
+ ['Nosso Número', nosso_numero, 'Nº Documento', boleto.numero_documento],
81
+ ['Carteira', boleto.carteira_formatada, 'Espécie', boleto.especie_documento],
82
+ ['Sacado', boleto.sacado, 'CPF/CNPJ', boleto.documento_sacado]
83
+ ]
84
+
85
+ pdf.table(data, width: pdf.bounds.width) do |t|
86
+ t.cells.borders = [:bottom]
87
+ t.cells.padding = [2, 5]
88
+ t.columns([0, 2]).font_style = :bold
89
+ t.columns([0, 2]).width = 100
90
+ end
91
+ end
92
+
93
+ def render_barcode(pdf)
94
+ barcode = Barby::Code25Interleaved.new(codigo_de_barras)
95
+ outputter = Barby::PrawnOutputter.new(barcode)
96
+ outputter.annotate_pdf(pdf, height: 40, x: 0)
97
+ end
98
+
99
+ def render_instructions(pdf)
100
+ pdf.text 'Instruções:', style: :bold
101
+ [
102
+ boleto.instrucoes1,
103
+ boleto.instrucoes2,
104
+ boleto.instrucoes3,
105
+ boleto.instrucoes4,
106
+ boleto.instrucoes5,
107
+ boleto.instrucoes6
108
+ ].compact.each do |instrucao|
109
+ pdf.text "• #{instrucao}", size: 9
110
+ end
111
+ end
112
+
113
+ def render_tear_line(pdf)
114
+ pdf.stroke_horizontal_rule
115
+ pdf.text 'Corte aqui', size: 8, align: :center
116
+ pdf.stroke_horizontal_rule
117
+ end
118
+
119
+ def render_stub(pdf)
120
+ pdf.text 'RECIBO DO SACADO', size: 10, style: :bold
121
+ pdf.move_down 5
122
+ pdf.text "Cedente: #{boleto.cedente}", size: 9
123
+ pdf.text "Sacado: #{boleto.sacado}", size: 9
124
+ pdf.text "Valor: R$ #{valor_formatado}", size: 9
125
+ pdf.text "Vencimento: #{data_vencimento_formatada}", size: 9
126
+ pdf.text "Nosso Número: #{nosso_numero}", size: 9
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'barby'
4
+ require 'barby/barcode/code_25_interleaved'
5
+ require 'barby/outputter/png_outputter'
6
+
7
+ module BoletoBancario
8
+ module Renderers
9
+ # Renderizador de código de barras em formato PNG.
10
+ #
11
+ # Este renderizador gera apenas a imagem do código de barras,
12
+ # não o boleto completo.
13
+ #
14
+ # @example Gerando um PNG do código de barras
15
+ #
16
+ # boleto = BoletoBancario::Itau.new(...)
17
+ # png_content = BoletoBancario::Renderers::PngRenderer.new(boleto).render
18
+ # File.binwrite('barcode.png', png_content)
19
+ #
20
+ class PngRenderer < Base
21
+ # Configurações padrão para o PNG.
22
+ DEFAULT_OPTIONS = {
23
+ height: 50,
24
+ xdim: 2,
25
+ margin: 10
26
+ }.freeze
27
+
28
+ attr_reader :options
29
+
30
+ # Inicializa o renderizador com opções.
31
+ #
32
+ # @param [BoletoBancario::Core::Boleto] boleto O boleto
33
+ # @param [Hash] options Opções para o PNG
34
+ # @option options [Integer] :height Altura da barra (padrão: 50)
35
+ # @option options [Integer] :xdim Largura de cada módulo (padrão: 2)
36
+ # @option options [Integer] :margin Margem ao redor (padrão: 10)
37
+ #
38
+ def initialize(boleto, options = {})
39
+ super(boleto)
40
+ @options = DEFAULT_OPTIONS.merge(options)
41
+ end
42
+
43
+ # Renderiza o código de barras em PNG.
44
+ #
45
+ # @return [String] O conteúdo binário do PNG
46
+ #
47
+ def render
48
+ barcode = Barby::Code25Interleaved.new(codigo_de_barras)
49
+ outputter = Barby::PngOutputter.new(barcode)
50
+ outputter.height = options[:height]
51
+ outputter.xdim = options[:xdim]
52
+ outputter.margin = options[:margin]
53
+ outputter.to_png
54
+ end
55
+
56
+ # Renderiza e salva o código de barras em um arquivo.
57
+ #
58
+ # @param [String] filepath Caminho do arquivo
59
+ # @return [Integer] Número de bytes escritos
60
+ #
61
+ def render_to_file(filepath)
62
+ File.binwrite(filepath, render)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,3 @@
1
+ <div class="barcode">
2
+ <div class="barcode-text"><%= codigo_de_barras %></div>
3
+ </div>
@@ -0,0 +1,14 @@
1
+ <div class="info-row">
2
+ <div class="info-cell flex-2">
3
+ <label>Cedente</label>
4
+ <span><%= boleto.cedente %></span>
5
+ </div>
6
+ <div class="info-cell">
7
+ <label>CPF/CNPJ</label>
8
+ <span><%= boleto.documento_cedente %></span>
9
+ </div>
10
+ <div class="info-cell">
11
+ <label>Agencia/Codigo Cedente</label>
12
+ <span><%= boleto.agencia_codigo_cedente %></span>
13
+ </div>
14
+ </div>
@@ -0,0 +1,4 @@
1
+ <div class="header">
2
+ <div class="bank-name"><%= bank_name %></div>
3
+ <div class="bank-code"><%= boleto.codigo_banco_formatado %></div>
4
+ </div>
@@ -0,0 +1,10 @@
1
+ <%- if instructions.any? -%>
2
+ <div class="instructions">
3
+ <h4>Instrucoes</h4>
4
+ <ul>
5
+ <%- instructions.each do |instruction| -%>
6
+ <li><%= instruction %></li>
7
+ <%- end -%>
8
+ </ul>
9
+ </div>
10
+ <%- end -%>