# encoding: utf-8 module BoletoBancario module Core # Implementação de emissão de boleto bancário pelo Banco do Brasil. # # === Documentação Implementada # # A documentação na qual essa implementação foi baseada está localizada na pasta # 'documentacoes_dos_boletos/banco_brasil' dentro dessa biblioteca. # # === Experimental # # O Boleto do Banco do Brasil ainda está categorizado como experimental. POr favor ajude a validar e homologar # esse banco para as carteiras suportadas conforme descrito abaixo. # # === Contrato das classes de emissão de boletos # # Para ver o "contrato" da Emissão de Boletos (geração de código de barras, linha digitável, etc) veja # a classe BoletoBancario::Core::Boleto. # # === Carteiras suportadas # # Segue abaixo as carteiras suportadas do Banco do Brasil seguindo a documentação: # # ________________________________________________________________________________________________________ # | Carteira | Descrição | Testada/Homologada no banco | # | 12 | Código do cedente de 6 dígitos | Esperando Contribuição | # | 16 | Código do cedente de 6 dígitos e nosso numero com 17 dígitos | Esperando Contribuição | # | 16 | Código do cedente de 4 dígitos | Esperando Contribuição | # | 16 | Código do cedente de 6 dígitos | Esperando Contribuição | # | 17 | Código do cedente de 7 dígitos | Esperando Contribuição | # | 17 | Código do cedente de 8 dígitos | Esperando Contribuição | # | 18 | Código do cedente de 4 dígitos | Esperando Contribuição | # | 18 | Código do cedente de 6 dígitos | Esperando Contribuição | # | 18 | Código do cedente de 6 dígitos e nosso numero com 17 dígitos | Esperando Contribuição | # | 18 | Código do cedente de 7 dígitos | Esperando Contribuição | # | 18 | Código do cedente de 8 dígitos | Esperando Contribuição | # --------------------------------------------------------------------------------------------------------- # # # OBS.: Seja um contribuidor dessa gem. Contribua para homologar os boletos e as # devidas carteiras junto ao banco Bradesco. # class BancoBrasil < Boleto # Tamanho máximo de uma agência no Banco do Brasil. # Método criado justamente para ficar documentado o tamanho máximo aceito até a data corrente. # # @return [Fixnum] 4 # def self.tamanho_maximo_agencia 4 end # Tamanho máximo de uma conta corrente no Banco do Brasil. # Método criado justamente para ficar documentado o tamanho máximo aceito até a data corrente. # # @return [Fixnum] 8 # def self.tamanho_maximo_conta_corrente 8 end # Tamanho máximo do número do documento emitido no Boleto, quando o código do cedente tiver 4 dígitos. # # Método criado justamente para ficar documentado o tamanho máximo aceito até a data corrente. # # @return [Fixnum] 7 # def self.tamanho_maximo_numero_documento_com_codigo_cedente_quatro_digitos 7 end # Tamanho máximo do número do documento emitido no Boleto, quando o código do cedente tiver 6 dígitos. # # === Convenção # # Sempre que você for usar o número do documento com 17 dígitos nas carteiras 16 ou 18 com # código cedente de 6 dígitos, fica a seu cargo colocar os 17 dígitos do número do documento. # # Método criado justamente para ficar documentado o tamanho máximo aceito até a data corrente. # # @return [Fixnum] 17 ou 5 # # def self.tamanho_maximo_numero_documento_com_codigo_cedente_seis_digitos 5 end # Tamanho máximo do número do documento emitido no Boleto, quando o código do cedente tiver 7 dígitos. # # Método criado justamente para ficar documentado o tamanho máximo aceito até a data corrente. # # @return [Fixnum] 10 # def self.tamanho_maximo_numero_documento_com_codigo_cedente_sete_digitos 10 end # Tamanho máximo do número do documento emitido no Boleto, quando o código do cedente tiver 8 dígitos. # # Método criado justamente para ficar documentado o tamanho máximo aceito até a data corrente. # # @return [Fixnum] 9 # def self.tamanho_maximo_numero_documento_com_codigo_cedente_oito_digitos 9 end # Tamanho máximo do número do documento emitido no Boleto, quando o código do cedente tiver 6 dígitos, # ser carteira 16 ou 18 e ter o nosso número com 17 dígitos. # # Método criado justamente para ficar documentado o tamanho máximo aceito até a data corrente. # # @return [Fixnum] 9 # def self.tamanho_maximo_numero_documento_dezessete_digitos 17 end # Carteiras suportadas. # # Método criado para validar se a carteira informada é suportada. # # @return [Array] # def self.carteiras_suportadas %w[12 16 17 18] end validates :codigo_cedente, :agencia, :digito_agencia, :conta_corrente, :digito_conta_corrente, presence: true # Validações de Agencia, Conta corrente e Carteira. # validates :agencia, length: { maximum: tamanho_maximo_agencia }, if: :deve_validar_agencia? validates :conta_corrente, length: { maximum: tamanho_maximo_conta_corrente }, if: :deve_validar_conta_corrente? validates :carteira, inclusion: { in: ->(object) { object.class.carteiras_suportadas } }, if: :deve_validar_carteira? # Validações do número do documento. # # === Número do Documento e Código do Cedente. # # A validação do número do documento, varia, dependendo da quantidade de dígitos do código do cedente. # # Para mais detalhes, veja o método #numero_documento, para entender essas validações. # validates :numero_documento, length: { maximum: tamanho_maximo_numero_documento_com_codigo_cedente_quatro_digitos }, if: :deve_validar_com_codigo_cedente_quatro_digitos? validates :numero_documento, length: { maximum: tamanho_maximo_numero_documento_com_codigo_cedente_sete_digitos }, if: :deve_validar_com_codigo_cedente_sete_digitos? validates :numero_documento, length: { maximum: tamanho_maximo_numero_documento_com_codigo_cedente_oito_digitos }, if: :deve_validar_com_codigo_cedente_oito_digitos? # Possui 2 tipos de validações de código do cedente com 6 dígitos: # # 1) Quando for nosso número com onze posições (6 do código cedente + 5 do número do documento). # 2) Quando for nosso número com dezessete posições (17 do número do documento). # # validates :numero_documento, length: { maximum: tamanho_maximo_numero_documento_com_codigo_cedente_seis_digitos }, if: :deve_validar_com_codigo_cedente_seis_digitos? validates :numero_documento, length: { maximum: tamanho_maximo_numero_documento_dezessete_digitos }, if: :deve_validar_com_nosso_numero_dezessete_digitos? validate :validacao_tamanho_de_digitos_codigo_cedente, if: :deve_validar_codigo_cedente? # @return [String] 4 caracteres # def agencia @agencia.to_s.rjust(4, '0') if @agencia.present? end # @return [String] 8 caracteres # def conta_corrente @conta_corrente.to_s.rjust(8, '0') if @conta_corrente.present? end # === Número do Documento VS. Código do Cedente # # No caso do Banco do Brasil, o tamanho do código do cedente ditará o tamanho do número do documento. # Ou seja, quando o código do cedente for X, o tamanho do número do documento deverá ser Y. # Segue abaixo: # # ______________________________________________________________ # | Tamanho do Código Cedente | Tamanho do Número do documento | # |----------------------------|--------------------------------| # | 04 | 07 | # | 06 | 05 | # | 07 | 10 | # | 08 | 09 | # --------------------------------------------------------------- # # OBS.: Quando o tamanho do código do cedente for 6, o número do documento # pode ter 17 dígitos, se for usado com a carteira 16 ou 18. # # @return [String] # def numero_documento if @numero_documento.present? and numero_documento_esperado[tamanho_codigo_cedente].present? @numero_documento.to_s.rjust(numero_documento_esperado[tamanho_codigo_cedente], '0') else @numero_documento end end # Para ficar documentado preferi criar um método onde retorna o tamanho esperado # do número do documento dependendo do tamanho do código do cedente. # # Para mais detalhes veja o método #numero_documento dessa classe. # # @return [Hash] As chaves significam o tamanho do código cedente e o valor o tamanho esperado do número do documento. # def numero_documento_esperado { 0 => 0, 4 => 7, 6 => 5, 7 => 10, 8 => 9 } end # @return [String] Código do Banco descrito na documentação. # def codigo_banco '001' end # Dígito do código do banco. Precisa mostrar esse dígito no boleto. # # @return [String] Dígito do código do banco descrito na documentação. # def digito_codigo_banco '9' end # Dígito do código da agência. Precisa mostrar esse dígito no boleto. # # @return [String] Dígito da agência calculado apartir do Modulo11FatorDe9a2RestoX. # def digito_agencia Modulo11FatorDe9a2RestoX.new(agencia) end # Dígito da conta corrente. Precisa mostrar esse dígito no boleto. # # @return [String] Dígito da conta corrente calculado apartir do Modulo11FatorDe9a2RestoX. # def digito_conta_corrente Modulo11FatorDe9a2RestoX.new(conta_corrente) end # Campo Agencia / Código do Cedente # Retorna formatado a agência, digito da agência, número da conta corrente e dígito da conta. # # @return [String] # def agencia_codigo_cedente "#{agencia}-#{digito_agencia} / #{conta_corrente}-#{digito_conta_corrente}" end # === Composição do nosso número # # ==== Código do Cedente de 4 dígitos # # ___________________________________________________________ # | Posição | Tamanho | Descrição | # |----------|---------|-------------------------------------| # | 01-04 | 04 | Código do cedente de 4 dígitos | # | 05-11 | 07 | Nosso número livre do cliente | # | 12 | 01 | Dígito Verificador do Nosso número | # ------------------------------------------------------------ # # ==== Código do Cedente de 6 dígitos # # ___________________________________________________________ # | Posição | Tamanho | Descrição | # |----------|---------|-------------------------------------| # | 01-06 | 06 | Código do cedente de 6 dígitos | # | 07-11 | 05 | Nosso número livre do cliente | # | 12 | 01 | Dígito Verificador do Nosso número | # ------------------------------------------------------------ # # ==== Código do Cedente de 7 dígitos # # ___________________________________________________________ # | Posição | Tamanho | Descrição | # |----------|---------|-------------------------------------| # | 01-07 | 07 | Código do cedente de 7 dígitos | # | 08-17 | 10 | Nosso número livre do cliente | # ------------------------------------------------------------ # # Obs.: Não existe Dígito Verificador na composição do nosso-número para convênios # de sete posições. # # ==== Código do Cedente de 8 dígitos # # ___________________________________________________________ # | Posição | Tamanho | Descrição | # |----------|---------|-------------------------------------| # | 01-08 | 08 | Código do cedente de 7 dígitos | # | 09-17 | 09 | Nosso número livre do cliente | # ------------------------------------------------------------ # # Obs.: Não existe Dígito Verificador na composição do nosso-número para convênios # de oito posições. # # @return [String] Nosso número que será mostrado no boleto # def nosso_numero if codigo_cedente_oito_digitos? or codigo_cedente_sete_digitos? "#{codigo_cedente}#{numero_documento}" else "#{codigo_cedente}#{numero_documento}-#{digito_nosso_numero}" end end # Para o cálculo do dígito, será necessário acrescentar o código do cedente e # Nosso Número (número do documento), e aplicar o módulo 11, com fatores de 9 a 2 # verificando o resto da divisão. # # Para mais detalhes de como o cálculo é feito veja a classe Modulo11FatorDe9a2RestoX. # # @return [String] Retorno do cálculo do módulo 11 com os fatores (9,8,7,6,5,4,3,2). # def digito_nosso_numero Modulo11FatorDe9a2RestoX.new("#{codigo_cedente}#{numero_documento}") end # === Código do cedente com 4 dígitos # # Quando o código do cedente possui 4 dígitos o formato do código de barras deve ficar assim: # # __________________________________________________________________________ # | Posição | Tamanho | Descrição | # |----------|---------|----------------------------------------------------| # | 20-30 | 11 | Nosso-Número, sem dígito verificador | # | 20-23 | Código do cedente fornecido pelo Banco (4 dígitos) | # | 24-30 | Nosso-Número, sem dígito verificador (7 dígitos) | # | 31-34 | 04 | Agência (sem o dígito) | # | 35-42 | 08 | Conta corrente (sem o dígito) | # | 43-44 | 02 | Carteira | # --------------------------------------------------------------------------- # # === Código do cedente com 6 dígitos # # Quando o código do cedente possui 6 dígitos o formato do código de barras deve ficar assim: # # __________________________________________________________________________ # | Posição | Tamanho | Descrição | # |----------|---------|----------------------------------------------------| # | 20-30 | 11 | Nosso-Número, sem dígito verificador | # | 20-25 | Código do cedente fornecido pelo Banco (6 dígitos) | # | 26-30 | Nosso-Número, sem dígito verificador (5 dígitos) | # | 31-34 | 04 | Agência (sem o dígito) | # | 35-42 | 08 | Conta corrente (sem o dígito) | # | 43-44 | 02 | Carteira | # --------------------------------------------------------------------------- # # === Código do cedente com 7 dígitos # # Quando o código do cedente possui 7 dígitos o formato do código de barras deve ficar assim: # # __________________________________________________________________________ # | Posição | Tamanho | Descrição | # |----------|---------|----------------------------------------------------| # | 20-30 | 17 | Nosso-Número, sem dígito verificador | # | 20-32 | Código do cedente fornecido pelo Banco (7 dígitos) | # | 33-42 | Nosso-Número, sem dígito verificador (10 dígitos) | # | 43-44 | 02 | Carteira | # --------------------------------------------------------------------------- # # === Código do cedente com 8 dígitos # # Quando o código do cedente possui 8 dígitos o formato do código de barras deve ficar assim: # # __________________________________________________________________________ # | Posição | Tamanho | Descrição | # |----------|---------|----------------------------------------------------| # | 20-30 | 17 | Nosso-Número, sem dígito verificador | # | 20-33 | Código do cedente fornecido pelo Banco (8 dígitos) | # | 34-42 | Nosso-Número, sem dígito verificador (9 dígitos) | # | 43-44 | 02 | Carteira | # --------------------------------------------------------------------------- # # === Carteiras 16 e 18, código do cedente de 6 posições, nosso número com 17 dígitos. # # Código do cedente possui 6 dígitos, nosso número com 17 dígitos e a carteira for 16 ou 18, # o formato do código de barras deve ficar assim: # # ___________________________________________________________ # | Posição | Tamanho | Descrição | # |----------|---------|-------------------------------------| # | 20-25 | 6 | Código do cedente de 6 dígitos | # | 26-42 | 17 | Nosso número livre do cliente | # | 43-44 | 02 | "21" Tipo da modalidade de cobranca | # ------------------------------------------------------------ # def codigo_de_barras_do_banco if nosso_numero_dezessete_posicoes? return codigo_de_barras_codigo_cedente_seis_posicoes_nosso_numero_dezessete_posicoes end if codigo_cedente_quatro_digitos? or codigo_cedente_seis_digitos? return codigo_de_barras_codigo_cedente_quatro_ou_seis_digitos end if codigo_cedente_sete_digitos? or codigo_cedente_oito_digitos? codigo_de_barras_codigo_cedente_sete_ou_oito_digitos end end # Retorna o código de barras do campo livre para emissão de boletos com: # # Nosso número de 11 posições - EXCLUSIVO PARA CONVÊNIOS DE SEIS POSIÇÕES. # # @return [String] # def codigo_de_barras_codigo_cedente_quatro_ou_seis_digitos "#{codigo_cedente}#{numero_documento}#{agencia}#{conta_corrente}#{carteira}" end # Retorna o código de barras do campo livre para emissão de boletos com: # # Carteira 17 e 18 - VINCULADOS À CONVÊNIOS COM NUMERAÇÃO SUPERIOR A 1.000.000 (um milhão). # # @return [String] # def codigo_de_barras_codigo_cedente_sete_ou_oito_digitos "000000#{codigo_cedente}#{numero_documento}#{carteira}" end # Retorna o código de barras do campo livre para emissão de bloquetos com: # # Nosso número de 17 posições - EXCLUSIVO PARA AS CARTEIRAS 16 E 18, VINCULADAS À CONVÊNIOS COM SEIS POSIÇÕES. # # @return [String] # def codigo_de_barras_codigo_cedente_seis_posicoes_nosso_numero_dezessete_posicoes "#{codigo_cedente}#{numero_documento}#{modalidade_de_cobranca}" end # Modalidade de cobranca definida pelo Banco do Brasil para ser mostrado no código de barras # com código de cedente de seis posições e nosso número de 17 posições, carteira 16 e 18. # # @return [String] 21 # def modalidade_de_cobranca "21" end # Verifica se o código do cedente possui 4 dígitos. # # @return [true, false] # def codigo_cedente_quatro_digitos? tamanho_codigo_cedente == 4 end # Verifica se o código do cedente possui 6 dígitos. # # @return [true, false] # def codigo_cedente_seis_digitos? tamanho_codigo_cedente == 6 end # Verifica se o código do cedente possui 7 dígitos. # # @return [true, false] # def codigo_cedente_sete_digitos? tamanho_codigo_cedente == 7 end # Verifica se o código do cedente possui 8 dígitos. # # @return [true, false] # def codigo_cedente_oito_digitos? tamanho_codigo_cedente == 8 end # Retorna o tamanho do campo código do cedente. # Super importante para o número do documento e e para o código de barras # # @return [Fixnum] Tamanho do campo código do cedente. # def tamanho_codigo_cedente codigo_cedente.to_s.size end # Verifica se: # # * Número do documento possui 17 dígitos # * Carteira está habilitada para usar 17 dígitos do número documento. # * Código do Cedente está habilitado para usar 17 dígitos do número documento (se tiver 6 dígitos). # # @return [true, false] # def nosso_numero_dezessete_posicoes? codigo_cedente_seis_digitos? and carteira.to_s.in?(carteiras_nosso_numero_dezessete_posicoes) and numero_documento.to_s.size == 17 end # Retorna as carteiras que aceitam nosso número com 17 posições. # # @return [Array] # def carteiras_nosso_numero_dezessete_posicoes %w(16 18) end # Verifica se o campo código do cedente tem o tamanho suportado pelo Banco do Brasil. # def validacao_tamanho_de_digitos_codigo_cedente errors.add(:codigo_cedente, :invalid) unless tamanho_codigo_cedente.in?(tamanhos_codigo_cedente_suportado) end # Retorna os tamanhos do código do cedente suportados pelo Banco do Brasil. # # @return [Array] # def tamanhos_codigo_cedente_suportado [4, 6, 7, 8] end # Método que pode ser sobrescrito na subclasse se você não quiser que essa validação ocorra. # # Lembre-se que fica a seu critério, mudar as validações da gem. # def deve_validar_com_codigo_cedente_quatro_digitos? deve_validar_codigo_cedente? and codigo_cedente_quatro_digitos? end # Método que pode ser sobrescrito na subclasse se você não quiser que essa validação ocorra. # # Lembre-se que fica a seu critério, mudar as validações da gem. # def deve_validar_com_codigo_cedente_seis_digitos? deve_validar_codigo_cedente? and codigo_cedente_seis_digitos? and not nosso_numero_dezessete_posicoes? end # Método que pode ser sobrescrito na subclasse se você não quiser que essa validação ocorra. # # Lembre-se que fica a seu critério, mudar as validações da gem. # def deve_validar_com_nosso_numero_dezessete_digitos? deve_validar_codigo_cedente? and codigo_cedente_seis_digitos? and nosso_numero_dezessete_posicoes? end # Método que pode ser sobrescrito na subclasse se você não quiser que essa validação ocorra. # # Lembre-se que fica a seu critério, mudar as validações da gem. # def deve_validar_com_codigo_cedente_sete_digitos? deve_validar_codigo_cedente? and codigo_cedente_sete_digitos? end # Método que pode ser sobrescrito na subclasse se você não quiser que essa validação ocorra. # # Lembre-se que fica a seu critério, mudar as validações da gem. # def deve_validar_com_codigo_cedente_oito_digitos? deve_validar_codigo_cedente? and codigo_cedente_oito_digitos? end end end end