tapajos/brazilian-rails

View on GitHub
brcpfcnpj/lib/brcpfcnpj/cpf_cnpj.rb

Summary

Maintainability
A
35 mins
Test Coverage
# -*- encoding : utf-8 -*-
module CpfCnpj
  attr_reader :numero

  def initialize(numero)
    @numero = numero
    @match = self.instance_of?(Cpf) ? @numero =~ CPF_REGEX : @numero =~ CNPJ_REGEX
    @numero_puro = $1
    @para_verificacao = $2
    @numero = (@match ? format_number! : nil)
  end

  def to_s
    @numero || ""
  end

  def ==(outro_doc)
    self.numero == outro_doc.numero
  end

  # Verifica se o numero possui o formato correto e se
  # constitui um numero de documento valido, dependendo do seu
  # tipo (Cpf ou Cnpj).
  def valido?
    return false unless @match
    verifica_numero
  end

  private
  DIVISOR = 11

  CPF_LENGTH = 11
  CPF_REGEX = /^(\d{3}\.?\d{3}\.?\d{3})-?(\d{2})$/
  CPF_ALGS_1 = [10, 9, 8, 7, 6, 5, 4, 3, 2]
  CPF_ALGS_2 = [11, 10, 9, 8, 7, 6, 5, 4, 3, 2]

  CNPJ_LENGTH = 14
  CNPJ_REGEX = /^(\d{2}\.?\d{3}\.?\d{3}\/?\d{4})-?(\d{2})$/ # <= 11.222.333/0001-XX
  CNPJ_ALGS_1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]
  CNPJ_ALGS_2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]


  def verifica_numero
    limpo = @numero.gsub(/[\.\/-]/, "")
    if self.instance_of? Cpf
      return false if limpo.length != 11
    elsif self.instance_of? Cnpj
      return false if limpo.length != 14
    end
    return false if limpo.scan(/\d/).uniq.length == 1
    primeiro_verificador = primeiro_digito_verificador
    segundo_verificador = segundo_digito_verificador(primeiro_verificador)
    verif = primeiro_verificador + segundo_verificador
    verif == @para_verificacao
  end

  def multiplica_e_soma(algs, numero_str)
    multiplicados = []
    numero_str.scan(/\d{1}/).each_with_index { |e, i| multiplicados[i] = e.to_i * algs[i] }
    multiplicados.inject { |s,e| s + e }
  end

  def digito_verificador(resto)
    resto < 2 ? 0 : DIVISOR - resto
  end

  def primeiro_digito_verificador
    array = self.instance_of?(Cpf) ? CPF_ALGS_1 : CNPJ_ALGS_1
    soma = multiplica_e_soma(array, @numero_puro)
    digito_verificador(soma%DIVISOR).to_s
  end

  def segundo_digito_verificador(primeiro_verificador)
    array = self.instance_of?(Cpf) ? CPF_ALGS_2 : CNPJ_ALGS_2
    soma = multiplica_e_soma(array, @numero_puro + primeiro_verificador)
    digito_verificador(soma%DIVISOR).to_s
  end

  def format_number!
    if self.instance_of? Cpf
      @numero =~ /(\d{3})\.?(\d{3})\.?(\d{3})-?(\d{2})/
      @numero = "#{$1}.#{$2}.#{$3}-#{$4}"
    else
      @numero =~ /(\d{2})\.?(\d{3})\.?(\d{3})\/?(\d{4})-?(\d{2})/
      @numero = "#{$1}.#{$2}.#{$3}/#{$4}-#{$5}"
    end
  end

end