module Brcobranca # Métodos auxiliares de formatação module Formatacao # Formata como CPF def to_br_cpf (self.kind_of?(String) ? self : self.to_s).gsub(/^(.{3})(.{3})(.{3})(.{2})$/,'\1.\2.\3-\4') end # Formata como CEP def to_br_cep (self.kind_of?(String) ? self : self.to_s).gsub(/^(.{5})(.{3})$/,'\1-\2') end # Formata como CNPJ def to_br_cnpj (self.kind_of?(String) ? self : self.to_s).gsub(/^(.{2})(.{3})(.{3})(.{4})(.{2})$/,'\1.\2.\3/\4-\5') end # Gera formatação automatica do documento baseado no tamanho do campo. def formata_documento case (self.kind_of?(String) ? self : self.to_s).size when 8 then self.to_br_cep when 11 then self.to_br_cpf when 14 then self.to_br_cnpj else self end end # Remove caracteres que não sejam numéricos do tipo MOEDA def limpa_valor_moeda return self unless self.kind_of?(String) && self.moeda? self.somente_numeros end # Remove caracteres que não sejam numéricos def somente_numeros return self unless self.kind_of?(String) self.gsub(/\D/,'') end # Completa zeros a esquerda. # Ex. numero="123" :tamanho=>3 | numero="123" # Ex. numero="123" :tamanho=>4 | numero="0123" # Ex. numero="123" :tamanho=>5 | numero="00123" def zeros_esquerda(options={}) valor_inicial = self.kind_of?(String) ? self : self.to_s return valor_inicial if (valor_inicial !~ /\S/) digitos = options[:tamanho] || valor_inicial.size diferenca = (digitos - valor_inicial.size) return valor_inicial if (diferenca <= 0) return (("0" * diferenca) + valor_inicial ) end # Monta a linha digitável padrão para todos os bancos segundo a BACEN. # Retorna + nil + para Codigo de Barras em branco, # Codigo de Barras com tamanho diferente de 44 dígitos e # Codigo de Barras que não tenham somente caracteres numéricos. # A linha digitável será composta por cinco campos: # 1º campo # Composto pelo código de Banco, código da moeda, as cinco primeiras posições do campo livre # e o dígito verificador deste campo; # 2º campo # Composto pelas posições 6ª a 15ª do campo livre e o dígito verificador deste campo; # 3º campo # Composto pelas posições 16ª a 25ª do campo livre e o dígito verificador deste campo; # 4º campo # Composto pelo dígito verificador do código de barras, ou seja, a 5ª posição do código de # barras; # 5º campo # Composto pelo fator de vencimento com 4(quatro) caracteres e o valor do documento com # 10(dez) caracteres, sem separadores e sem edição. # Entre cada campo deverá haver espaço equivalente a 2 (duas) posições, sendo a 1ª # interpretada por um ponto (.) e a 2ª por um espaço em branco. def linha_digitavel valor_inicial = self.kind_of?(String) ? self : self.to_s return nil if (valor_inicial !~ /\S/) || valor_inicial.size != 44 || (!valor_inicial.scan(/\D/).empty?) dv_1 = ("#{valor_inicial[0..3]}#{valor_inicial[19..23]}").modulo10 campo_1_dv = "#{valor_inicial[0..3]}#{valor_inicial[19..23]}#{dv_1}" campo_linha_1 = "#{campo_1_dv[0..4]}.#{campo_1_dv[5..9]}" dv_2 = "#{valor_inicial[24..33]}".modulo10 campo_2_dv = "#{valor_inicial[24..33]}#{dv_2}" campo_linha_2 = "#{campo_2_dv[0..4]}.#{campo_2_dv[5..10]}" dv_3 = "#{valor_inicial[34..43]}".modulo10 campo_3_dv = "#{valor_inicial[34..43]}#{dv_3}" campo_linha_3 = "#{campo_3_dv[0..4]}.#{campo_3_dv[5..10]}" campo_linha_4 = "#{valor_inicial[4..4]}" campo_linha_5 = "#{valor_inicial[5..18]}" "#{campo_linha_1} #{campo_linha_2} #{campo_linha_3} #{campo_linha_4} #{campo_linha_5}" end end # métodos auxiliares de cálculos module Calculo # Método padrão para cálculo de módulo 10 segundo a BACEN. def modulo10 valor_inicial = self.kind_of?(String) ? self : self.to_s return nil if (valor_inicial !~ /\S/) total = 0 multiplicador = 2 valor_inicial.split(//).reverse!.each do |caracter| total += (caracter.to_i * multiplicador).soma_digitos multiplicador = multiplicador == 2 ? 1 : 2 end valor = (10 - (total % 10)) valor == 10 ? 0 : valor end # Método padrão para cálculo de módulo 11 com multiplicaroes de 9 a 2 segundo a BACEN. # Usado no DV do Nosso Numero, Agência e Cedente. # Retorna + nil + para todos os parametros que nao forem String # Retorna + nil + para String em branco def modulo11_9to2 valor_inicial = self.kind_of?(String) ? self : self.to_s return nil if (valor_inicial !~ /\S/) multiplicadores = [9,8,7,6,5,4,3,2] total = 0 multiplicador_posicao = 0 valor_inicial.split(//).reverse!.each do |caracter| multiplicador_posicao = 0 if (multiplicador_posicao == 8) total += (caracter.to_i * multiplicadores[multiplicador_posicao]) multiplicador_posicao += 1 end return (total % 11 ) end # Método padrão para cálculo de módulo 11 com multiplicaroes de 2 a 9 segundo a BACEN. # Usado no DV do Código de Barras. # Retorna + nil + para todos os parametros que não forem String # Retorna + nil + para String em branco def modulo11_2to9 valor_inicial = self.kind_of?(String) ? self : self.to_s return nil if (valor_inicial !~ /\S/) multiplicadores = [2,3,4,5,6,7,8,9] total = 0 multiplicador_posicao = 0 valor_inicial.split(//).reverse!.each do |caracter| multiplicador_posicao = 0 if (multiplicador_posicao == 8) total += (caracter.to_i * multiplicadores[multiplicador_posicao]) multiplicador_posicao += 1 end valor = (11 - (total % 11)) return [0,10,11].include?(valor) ? 1 : valor end # Retorna o dígito verificador de modulo 11(9-2) trocando retorno 10 por X. # Usado por alguns bancos. def modulo11_9to2_10_como_x valor = self.modulo11_9to2 valor == 10 ? "X" : valor end # Retorna o dígito verificador de modulo 11(9-2) trocando retorno 10 por 0. # Usado por alguns bancos. def modulo11_9to2_10_como_zero valor = self.modulo11_9to2 valor == 10 ? 0 : valor end # Soma números inteiros positivos com 2 dígitos ou mais # Retorna 0(zero) caso seja impossível. # Ex. 1 = 1 # Ex. 11 = (1+1) = 2 # Ex. 13 = (1+3) = 4 def soma_digitos valor_inicial = self.kind_of?(Fixnum) ? self : self.to_i return 0 if valor_inicial == 0 return valor_inicial if valor_inicial <= 9 valor_inicial = valor_inicial.to_s total = 0 0.upto(valor_inicial.size-1) {|digito| total += valor_inicial[digito,1].to_i } return total end end # Métodos auxiliares de verificação e validação. module Validacao # Verifica se o valor é moeda. # Ex. +1.232.33 # Ex. -1.232.33 # Ex. 1.232.33 def moeda? return false unless self.kind_of?(String) self =~ /^(\+|-)?\d+((\.|,)\d{3}*)*((\.|,)\d{2}*)$/ ? true : false end end # Métodos auxiliares de limpeza. module Limpeza # Retorna uma String contendo exatamente o valor FLOAT def limpa_valor_moeda return self unless self.kind_of?(Float) valor_inicial = self.to_s (valor_inicial + ("0" * (2 - valor_inicial.split(/\./).last.size ))).somente_numeros end end # Métodos auxiliares de cálculos envolvendo Datas. module CalculoData # Calcula o número de dias corridos entre a data base ("Fixada" em 07.10.1997) e a data de vencimento desejado: # VENCIMENTO 04/07/2000 # DATA BASE - 07/10/1997 # FATOR DE VENCIMENTO 1001 def fator_vencimento data_base = Date.parse "1997-10-07" (self - data_base).to_i end # Mostra a data em formato dia/mês/ano def to_s_br self.strftime('%d/%m/%Y') end # Retorna string contendo número de dias julianos: # O cálculo é feito subtraindo-se a data atual, pelo último dia válido do ano anterior, # acrescentando-se o último algarismo do ano atual na quarta posição. # Deve retornar string com 4 digitos. # Ex. Data atual = 11/02/2009 # Data válida ano anterior = 31/12/2008 # (Data atual - Data válida ano anterior) = 42 # último algarismo do ano atual = 9 # String atual 42+9 = 429 # Completa zero esquerda para formar 4 digitos = "0429" def to_juliano ultima_data = Date.parse("#{self.year - 1}-12-31") ultimo_digito_ano = self.to_s[3..3] dias = (self - ultima_data) (dias.to_s + ultimo_digito_ano).zeros_esquerda(:tamanho => 4) end end end class String #:nodoc:[all] include Brcobranca::Formatacao include Brcobranca::Validacao include Brcobranca::Calculo end class Integer #:nodoc:[all] include Brcobranca::Formatacao include Brcobranca::Calculo end class Float #:nodoc:[all] include Brcobranca::Limpeza end class Date #:nodoc:[all] include Brcobranca::CalculoData end