# encoding: utf-8 module BoletoBancario module Core # @abstract Métodos { #codigo_banco, #digito_codigo_banco, #agencia_codigo_cedente, #nosso_numero, #codigo_de_barras_do_banco} # Métodos para serem escritos nas subclasses (exitem outros opcionais, conforme visto nessa documentação). # class Boleto include BoletoBancario::Calculos # Seguindo a interface do Active Model para: # * Validações; # * Internacionalização; # * Nomes das classes para serem manipuladas; # include ActiveModel::Model # Nome/Razão social que aparece no campo 'Cedente' no boleto. # attr_accessor :cedente # Código do Cedente é o código do cliente, fornecido pelo banco. # # Alguns bancos, dependendo do banco e da carteira, precisam desse campo preenchido. # Em compensação, outros bancos (a minoria) não fazem utilização desse campo. # attr_accessor :codigo_cedente # Documento do Cedente (CPF ou CNPJ). # OBS.: Esse campo não possui validação do campo. Caso você precise imeplemente na subclasse. # # Esse campo serve apenas para mostrar no boleto no campo "CPF/CNPJ". # attr_accessor :documento_cedente # Deve ser informado o endereço completo do Cedente. # Se o título possuir a figura de Sacador Avalista o endereço informado # deverá ser do Sacador Avalista, conforme Lei Federal 12.039 de 01/10/2009. # # Campo Obrigatório # attr_accessor :endereco_cedente # Data do vencimento do boleto. Campo auto explicativo. # # Campo Obrigatório # attr_accessor :data_vencimento # Número do documento que será mostrado no boleto. # Campo de resposabilidade do Cedente e cada banco possui um tamanho esperado. # attr_accessor :numero_documento # Valor total do documento. Campo auto explicativo. # # Campo Obrigatório. # attr_accessor :valor_documento # Uma carteira de cobrança define o modo como o boleto é tratado pelo banco. # Existem duas grandes divisões: carteiras não registradas e carteiras registradas. # # === Carteiras Não Registradas # # Significa que não há registro no banco sobre os boletos gerados, ou seja, você não precisa # notificar o banco a cada boleto gerado. # Neste caso a cobrança de taxa bancária é feita por boleto pago. # # === Carteiras Registradas # # Você precisa notificar o banco sobre todos os boletos gerados, em geral enviando um # arquivo chamado "arquivo de remessa". # Neste caso, normalmente existe uma taxa bancária por boleto gerado, independentemente de ele ser pago. # Nestas carteiras também se encaixam serviços bancários adicionais, como protesto em caso de não pagamento. # # Campo Obrigatório # attr_accessor :carteira # Número da agência. Campo auto explicativo. # attr_accessor :agencia # Número da Conta corrente. Campo auto explicativo. # attr_accessor :conta_corrente # Código da moeda. Campo auto explicativo. # Padrão '9' (Real). # attr_accessor :codigo_moeda # Essencial para identificação da moeda em que a operação foi efetuada. # # Padrão 'R$' (Real). # attr_accessor :especie # Normalmente se vê neste campo a informação "DM" que quer dizer duplicata mercantil, # mas existem inúmeros tipos de espécie, neste caso é aconselhável discutir com o banco # qual a espécie de documento será utilizada, a identificação incorreta da espécie do documento # não vai impedir que o boleto seja pago e nem que o credito seja efetuado na conta do cliente, # mas pode ocasionar na impossibilidade de se protestar o boleto caso venha a ser necessário. # # Segue a sigla e descrição do campo especie do documento: # # --------------------------------- # | Sigla | Descrição | # ---------------------------------- # | NP | Nota Promissória | # | NS | Nota de Seguro | # | CS | Cobrança Seriada | # | REC | Recibo | # | LC | Letras de Câmbio | # | ND | Notas de débito | # | DS | Duplicata de Serviços | # | DM | Duplicata Mercantil | # ---------------------------------| # # Padrão 'DM' (Duplicata Mercantil) # attr_accessor :especie_documento # Data em que o documento foi gerado. Campo auto explicativo. # attr_accessor :data_documento # Nome do sacado. # # O sacado é a pessoa para o qual o boleto está sendo emitido, podemos resumir dizendo # que o sacado é o cliente do Cedente, ou aquele para o qual uma determina mercadoria # foi vendida e o pagamento desta será efetuado por meio de boleto de cobrança. # # Campo Obrigatório. # attr_accessor :sacado # Documento do sacado. # # OBS.: Esse campo não possui validação do campo. Caso você precise imeplemente na subclasse. # # Esse campo serve apenas para mostrar no boleto no campo "CPF/CNPJ". # attr_accessor :documento_sacado # Endereço do sacado. # # OBS.: Esse campo não possui validação do campo. Caso você precise imeplemente na subclasse. # # Esse campo serve apenas para mostrar no boleto no campo "Sacado". # attr_accessor :endereco_sacado # Descrição do local do pagamento. # attr_accessor :local_pagamento # Aceitar após o vencimento. # Nessa gem utilizamos o campo aceite como Boolean. # Obviamente, true para 'S' e false/nil para 'N'. # attr_accessor :aceite # Campos de instruções. # São permitidas até seis linhas de instruções a serem mostradas no boleto attr_accessor :instrucoes1, :instrucoes2, :instrucoes3, :instrucoes4, :instrucoes5, :instrucoes6 # Caminho do logo do banco. # attr_accessor :logo # Tamanho maximo do valor do documento do boleto. # Acredito que não existirá valor de documento nesse valor, # porém a biblioteca precisa manter a consistência. # # No código de barras o valor do documento precisa # ter um tamanho de 8 caracteres para os reais (acrescentando zeros à esquerda), # e 2 caracteres nos centavos (acrescentando zeros à esquerda). # # @return [Float] 99999999.99 # def self.valor_documento_tamanho_maximo 99999999.99 end # Validações de todos os boletos # validates :carteira, :valor_documento, :numero_documento, :data_vencimento, presence: true validates :cedente, :endereco_cedente, presence: true validates :sacado, :documento_sacado, presence: true validates :valor_documento, numericality: { less_than_or_equal_to: ->(object) { object.class.valor_documento_tamanho_maximo } } validate :data_vencimento_deve_ser_uma_data # Passing the attributes as Hash or block # # @overload initialize(options = {}, &block) # @param [Hash] options Passing a hash accessing the attributes of the self. # @option options [String] :cedente # @option options [String] :codigo_cedente # @option options [String] :documento_cedente # @option options [String] :endereco_cedente # @option options [String] :conta_corrente # @option options [String] :agencia # @option options [Date] :data_vencimento # @option options [String] :numero_documento # @option options [Float] :valor_documento # @option options [String] :codigo_moeda # @option options [String] :especie # @option options [String] :especie_documento # @option options [String] :sacado # @option options [String] :documento_sacado # # @param [Proc] block Optional params. Passing a block accessing the attributes of the self. # # For the options, waiting for the ActiveModel 4 and the ActiveModel::Model. :) # # === Exemplos # # O recomendado é usar os boletos herdando de seu respectivo banco. Por exemplo: # # class Itau < BoletoBancario::Itau # end # # Agora você pode emitir um boleto usando a classe criada acima: # # Itau.new(conta_corrente: '89755', agencia: '0097', :carteira => '195') # # Você pode usar blocos se quiser: # # Itau.new do |boleto| # boleto.conta_corrente = '89755' # boleto.agencia = '0097' # boleto.carteira = '198' # boleto.numero_documento = '12345678' # boleto.codigo_cedente = '909014' # end # def initialize(options={}, &block) default_options.merge(options).each do |attribute, value| send("#{attribute}=", value) if respond_to?("#{attribute}=") end yield(self) if block_given? end # Opções default. # # Caso queira sobrescrever as opções, você pode simplesmente instanciar o objeto passando a opção desejada: # # class Bradesco < BoletoBancario::Bradesco # end # # Bradesco.new do |bradesco| # bradesco.codigo_moeda = 'outro_codigo_da_moeda' # bradesco.especie = 'outra_especie_que_nao_seja_em_reais' # bradesco.especie_documento = 'outra_especie_do_documento' # bradesco.data_documento = Date.tomorrow # bradesco.aceite = false # end # # @return [Hash] Código da Moeda sendo '9' (real). Espécie sendo 'R$' (real). # def default_options { :codigo_moeda => '9', :especie => 'R$', :especie_documento => 'DM', :local_pagamento => 'PAGÁVEL EM QUALQUER BANCO ATÉ O VENCIMENTO', :data_documento => Date.today, :aceite => true } end # Código do Banco. # Esse campo é específico para cada banco. # # @return [String] Corresponde ao código do banco. # # @raise [NotImplementedError] Precisa implementar nas subclasses. # def codigo_banco raise NotImplementedError.new("Not implemented #codigo_banco in #{self}.") end # Dígito do código do banco. # Esse campo é específico para cada banco. # # @return [String] Corresponde ao dígito do código do banco. # @raise [NotImplementedError] Precisa implementar nas subclasses. # def digito_codigo_banco raise NotImplementedError.new("Not implemented #digito_codigo_banco in #{self}.") end # Formata o código do banco com o dígito do código do banco. # Método usado para o campo de código do banco localizado no cabeçalho do boleto. # # @return [String] # def codigo_banco_formatado "#{codigo_banco}-#{digito_codigo_banco}" end # Agência, código do cedente ou nosso número. # Esse campo é específico para cada banco. # # @return [String] - Corresponde aos campos "Agencia / Codigo do Cedente". # @raise [NotImplementedError] Precisa implementar nas subclasses. # def agencia_codigo_cedente raise NotImplementedError.new("Not implemented #agencia_codigo_cedente in #{self}.") end # O Nosso Número é o número que identifica unicamente um boleto para uma conta. # O tamanho máximo do Nosso Número depende do banco e carteira. # # Para carteiras registradas, você deve solicitar ao seu banco um intervalo de números para utilização. # Quando estiver perto do fim do intervalo, deve solicitar um novo intervalo. # # Para carteiras não registradas o Nosso Número é livre. # Ao receber o retorno do banco, é através do Nosso Número que será possível identificar os boletos pagos. # # Esse campo é específico para cada banco. # # @return [String] Corresponde ao formato específico de cada banco. # @raise [NotImplementedError] Precisa implementar nas subclasses. # def nosso_numero raise NotImplementedError.new("Not implemented #nosso_numero in #{self}.") end # Formata o valor do documentado para ser mostrado no código de barras # e na linha digitável com 08 dígitos na casa dos Reais e 02 dígitos nas casas dos centavos. # # @example # # Bradesco.new(:valor_documento => 123.45).valor_formatado_para_codigo_de_barras # # => "0000012345" # # @return [String] Precisa retornar 10 dígitos para o código de barras (incluindo os centavos). # def valor_formatado_para_codigo_de_barras valor_documento_formatado = (Integer(valor_documento.to_f * 100) / Float(100)) real, centavos = valor_documento_formatado.to_s.split(/\./) "#{real.rjust(8, '0')}#{centavos.ljust(2, '0')}" end # Força a carteira a retornar o valor como string # # @return [String] # def carteira @carteira.to_s if @carteira.present? end # Embora o padrão seja mostrar o número da carteira no boleto, # alguns bancos requerem que seja mostrado um valor diferente na carteira. # Para essas exceções, sobrescreva esse método na subclasse. # # @return [String] retorna o número da carteira # def carteira_formatada carteira end # Se o aceite for 'true', retorna 'S'. # Retorna 'N', caso contrário. # # @return [String] # def aceite_formatado if @aceite.present? 'S' else 'N' end end # Fator de vencimento que é calculado a partir de uma data base. # Veja FatorVencimento para mais detalhes. # # @return [String] 4 caracteres. # def fator_de_vencimento FatorVencimento.new(data_vencimento) end # === Código de Barras # # O código de barras contêm exatamente 44 posições nessa sequência: # # ____________________________________________________________ # | Posição | Tamanho | Descrição | # |----------|---------|--------------------------------------| # | 01-03 | 03 | Código do banco | # | 04 | 01 | Código da moeda | # | 05 | 01 | Dígito do código de barras (DAC) | # | 06-09 | 04 | Fator de vencimento | # | 10-19 | 10 | Valor do documento | # | 20-44 | 25 | Critério de cada Banco (Campo livre) | # ------------------------------------------------------------- # # @return [String] Código de barras com 44 posições. # def codigo_de_barras "#{codigo_de_barras_padrao}#{codigo_de_barras_do_banco}".insert(4, digito_codigo_de_barras) end # Primeira parte do código de barras. # Essa parte do código de barras é padrão para todos os bancos.. # # @return [String] Primeiras 18 posições do código de barras (Não retorna o DAC do código de barras). # def codigo_de_barras_padrao "#{codigo_banco}#{codigo_moeda}#{fator_de_vencimento}#{valor_formatado_para_codigo_de_barras}" end # Segunda parte do código de barras. # Esse campo é específico para cada banco. # # @return [String] 25 últimas posições do código de barras. # @raise [NotImplementedError] Precisa implementar nas subclasses. # def codigo_de_barras_do_banco raise NotImplementedError.new("Not implemented #codigo_de_barras_do_banco in #{self}.") end # Dígito verificador do código de barras (DAC). # # Por definição da FEBRABAN e do Banco Central do Brasil, # na 5º posição do Código de Barras, deve ser indicado obrigatoriamente # o “dígito verificador” (DAC), calculado através do módulo 11. # # OBS.: Para mais detalhes deste cálculo, # veja a descrição em BoletoBancario::Calculos::Modulo11FatorDe2a9. # # @return [String] Dígito calculado do código de barras. # def digito_codigo_de_barras Modulo11FatorDe2a9.new("#{codigo_de_barras_padrao}#{codigo_de_barras_do_banco}") end # Representação numérica do código de barras, mais conhecida como linha digitável! :p # # A representação numérica do código de barras é composta, por cinco campos. # Sendo os três primeiros campos, amarrados por DAC's (dígitos verificadores), # todos calculados pelo módulo 10. # # OBS.: Para mais detalhes deste cálculo, veja a descrição em Modulo10. # # === Linha Digitável # # A linha digitável contêm exatamente 47 posições nessa sequência: # # _______________________________________________________________________________________________________ # |Campo | Posição | Tamanho | Descrição | # |------|----------|---------|--------------------------------------------------------------------------| # | 1º | 01-03 | 03 | Código do banco (posições 1 a 3 do código de barras) | # | | 04 | 01 | Código da moeda (posição 4 do código de barras) | # | | 05-09 | 5 | Cinco posições do campo livre (posições 20 a 24 do código de barras) | # | | 10 | 1 | Dígito verificador do primeiro campo (Módulo10) | # |------------------------------------------------------------------------------------------------------| # | 2º | 11-20 | 10 | 6º a 15º posições do campo livre (posições 25 a 34 do código de barras) | # | | 21 | 01 | Dígito verificador do segundo campo (Módulo10) | # |------------------------------------------------------------------------------------------------------| # | 3º | 22-31 | 10 | 16º a 25º posições do campo livre (posições 35 a 44 do código de barras) | # | | 32 | 01 | Dígito verificador do terceiro campo (Módulo10) | # |------------------------------------------------------------------------------------------------------| # | 4º | 33 | 01 | Dígito verificador do código de barras (posição 5 do código de barras) | # |------------------------------------------------------------------------------------------------------| # | 5ª | 34-37 | 04 | Fator de vencimento (posições 6 a 9 do código de barras) | # | | 38-47 | 10 | Valor nominal do documento (posições 10 a 19 do código de barras) | # -------------------------------------------------------------------------------------------------------| # # @return [String] Contêm a representação numérica do código de barras formatado com pontos e espaços. # def linha_digitavel LinhaDigitavel.new(codigo_de_barras) end # Returns a string that identifying the render path associated with the object. # # ActionPack uses this to find a suitable partial to represent the object. # # @return [String] # def to_partial_path "boleto_bancario/#{self.class.name.demodulize.underscore}" end # Seguindo a interface do Active Model. # # @return [False] # def persisted? false end # Método usado para verificar se deve realizar a validação de tamanho do campo 'agência'. # Sobrescreva esse método na subclasse, caso você mesmo queira fazer as validações. # # @return [True] # def deve_validar_agencia? true end # Método usado para verificar se deve realizar a validação de tamanho do campo 'conta_corrente'. # Sobrescreva esse método na subclasse, caso você mesmo queira fazer as validações. # # @return [True] # def deve_validar_conta_corrente? true end # Método usado para verificar se deve realizar a validação de tamanho do campo 'codigo_cedente'. # Sobrescreva esse método na subclasse, caso você mesmo queira fazer as validações. # # @return [True] # def deve_validar_codigo_cedente? true end # Método usado para verificar se deve realizar a validação de tamanho do campo 'numero_documento'. # Sobrescreva esse método na subclasse, caso você mesmo queira fazer as validações. # # @return [True] # def deve_validar_numero_documento? true end # Método usado para verificar se deve realizar a validação do campo 'carteira'. # Sobrescreva esse método na subclasse, caso você mesmo queira fazer as validações. # # @return [True] # def deve_validar_carteira? true end # Verifica e valida se a data do vencimento deve ser uma data válida. # Precisa ser uma data para o cálculo do fator do vencimento. # def data_vencimento_deve_ser_uma_data errors.add(:data_vencimento, :invalid) unless data_vencimento.kind_of?(Date) end end end end