# -*- encoding: utf-8 -*-
# @author Kivanio Barbosa
module Brcobranca
# Métodos auxiliares de cálculos
module Calculo
# Calcula módulo 10 segundo a BACEN.
#
# @return [Integer]
# @raise [ArgumentError] Caso não seja um número inteiro.
def modulo10
fail ArgumentError, 'Número inválido' unless self.is_number?
total = 0
multiplicador = 2
to_s.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
# Calcula módulo 11 com multiplicaroes de 9 a 2 segundo a BACEN.
#
# @return [Integer]
def modulo11_9to2
total = multiplicador([9, 8, 7, 6, 5, 4, 3, 2])
(total % 11)
end
# Calcula módulo 11 com multiplicaroes de 2 a 9 segundo a BACEN.
#
# @return [Integer]
def modulo11_2to9
total = multiplicador([2, 3, 4, 5, 6, 7, 8, 9])
valor = (11 - (total % 11))
[0, 10, 11].include?(valor) ? 1 : valor
end
# Calcula módulo 11 com multiplicadores de 2 a 9 e 2 a 5 (Utilizado pelo Santander).
#
# @return [Integer]
def modulo11_santander
return 0 if self.to_i == 0
somatorio = 0
multiplicadores = [2, 3, 4, 5, 6, 7, 8, 9, 2, 3, 4, 5]
base = "#{self.rjust(12, '0')}".reverse
index = 0
base.each_char do |char|
somatorio += base[index].to_i * multiplicadores[index].to_i
index += 1
end
resto = somatorio % 11
return 1 if resto == 10
return 0 if resto == 1 || resto == 0
return 11 - resto
end
# Calcula módulo 11 com multiplicadores de 2, 7 a 2, e 7 a 2 (Utilizado pelo Bradesco).
#
# @return [Integer, String] Caso o resto seja 1, retorna P
def modulo11_bradesco
somatorio = 0
multiplicadores = [2, 7, 6, 5, 4, 3, 2, 7, 6, 5, 4, 3, 2]
index = 0
self.each_char do |char|
somatorio += self[index].to_i * multiplicadores[index]
index += 1
end
resto = somatorio % 11
return 0 if resto == 0
return 'P' if resto == 1
return 11 - resto
end
# Calcula módulo 11 com multiplicaroes de 2 a 9 (Utilizado pela CAIXA - boletos SIGCB).
#
# @return [Integer]
def modulo11_2to9_caixa
total = multiplicador([2, 3, 4, 5, 6, 7, 8, 9])
total = (total % 11) unless total < 11
valor = (11 - total)
valor > 9 ? 0 : valor
end
# Calcula módulo 11 com multiplicaroes de 9 a 2 trocando retorno 10 por X.
#
# @return [Integer, String] Caso resultado for 10, retorna X.
def modulo11_9to2_10_como_x
valor = modulo11_9to2
valor == 10 ? 'X' : valor
end
# Calcula módulo 11 com multiplicaroes de 9 a 2 trocando retorno 10 por 0.
#
# @return [Integer]
def modulo11_9to2_10_como_zero
valor = modulo11_9to2
valor == 10 ? 0 : valor
end
# Verifica se String só contem caracteres numéricos.
#
# @return [Boolean]
def is_number?
to_s.empty? ? false : (to_s =~ (/\D/)).nil?
end
# Soma dígitos de números inteiros positivos com 2 dígitos ou mais.
#
# @return [Integer]
# @example
# 1 #=> 1
# 11 (1+1) #=> 2
# 13 (1+3) #=> 4
def soma_digitos
total = case to_i
when (0..9)
self
else
numero = to_s
total = 0
0.upto(numero.size - 1) { |digito| total += numero[digito, 1].to_i }
total
end
total.to_i
end
# Faz a multiplicação de um número pelos fatores passados como parâmetro.
#
# @param [Array]
# @return [Integer]
# @raise [ArgumentError] Caso não seja um número inteiro.
def multiplicador(fatores, &_block)
fail ArgumentError, 'Número inválido' unless self.is_number?
total = 0
multiplicador_posicao = 0
to_s.split(//).reverse!.each do |caracter|
fator = fatores[multiplicador_posicao]
total += if block_given?
yield(caracter, fator)
else
(caracter.to_i * fator)
end
multiplicador_posicao = (multiplicador_posicao < (fatores.size - 1)) ? (multiplicador_posicao + 1) : 0
end
total
end
end
end
[String, Numeric].each do |klass|
klass.class_eval { include Brcobranca::Calculo }
end