unpack brazilian-rails

This commit is contained in:
2013-07-14 11:09:25 -04:00
parent 7d287fe530
commit e563725dc5
131 changed files with 5496 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
# -*- encoding : utf-8 -*-
$:.unshift(File.dirname(__FILE__)) unless
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
%w(cpf_cnpj cnpj cpf cpf_cnpj_activerecord cnpj_validator cpf_validator).each {|req| require File.dirname(__FILE__) + "/brcpfcnpj/#{req}"}
%w(rubygems active_record active_support).each {|req| require req }
ActiveRecord::Base.send :include, CpfCnpjActiveRecord
module BrCpfCnpj
end

View File

@@ -0,0 +1,46 @@
# -*- encoding : utf-8 -*-
# Representa um numero de CNPJ. Objetos da classe Cnpj recebem strings representando numeros de cnpj e verificam a validade destes numeros usando dois criterios:
# 1. O formato da string, que deve seguir o padrao xx.xxx.xxx/xxxx-xx, onde 'x' pode ser qualquer digito de 0 a 9 e os tracos (-), barra (/) e pontos (.) *sao opcionais*.
# 2. O conteudo numerico desta string, que eh validado atraves do calculo do 'modulo 11' dos digitos que compoe a string.
#
# Caso o conteudo da string obedeca ao formato especificado acima, o mesmo sera formatado para obedecer ao padrao xx.xxx.xxx/xxxx-xx
#
# Eh importante observar que caso voce associe um valor de cnpj invalido ao seu model, o mesmo passara automaticamente a ser invalido, o que impede que valores de cpf incorretos sejam salvos no banco de dados.
#
# Como usar a classe Cnpj no seu ActiveRecord:
#
# Suponha que temos um model Empresa, com um atributo 'cnpj'
# que voce quer usar como um numero de documento para cnpj. Basta usar o
# metodo <tt>usar_como_cnpj</tt>, assim:
#
# class Empresa < ActiveRecord::Base
# usar_como_cnpj :cnpj
# end
#
# Agora voce pode usar o atributo para cnpj da seguinte forma:
#
# e = Empresa.new
# e.cnpj = "69103604000160"
# puts e.cnpj # ==> 69.103.604/0001-60
# e.cnpj.valido? # ==> true
# e.cnpj_valido? # ==> true
#
# e = Empresa.new(:cnpj => "69.103.604/0001-60")
# puts e.cnpj # ==> 69.103.604/0001-60
#
# e = Empresa.new
# e.cnpj = Cnpj.new("691036040001-60")
# puts e.cnpj # ==> 69.103.604/0001-60
#
# e = Empresa.new
# e.cnpj = "12343" # ==> um cnpj invalido
# puts e.valid? # ==> false
# e.save # ==> false
# e.errors.on(:cnpj) # ==> 'não é válido' # de acordo com a I18n
#
# c = Cnpj.new("69103604000160")
# e.cnpj = "69.103.604/0001-60"
# c == e.cnpj # ==> true
class Cnpj
include CpfCnpj
end

View File

@@ -0,0 +1,6 @@
class CnpjValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return if value.nil?
record.errors.add attribute, :invalid unless Cnpj.new(value).valido?
end
end

View File

@@ -0,0 +1,52 @@
# -*- encoding : utf-8 -*-
# Representa um numero de CPF. Objetos da classe Cpf recebem strings representando
# numeros de cpf e verificam a validade destes numeros usando dois criterios:
# 1. O formato da string, que deve seguir o padrao xxx.xxx.xxx-xx, onde 'x' pode ser qualquer digito de 0 a 9 e os tracos (-) e pontos (.) *sao opcionais*.
# 2. O conteudo numerico desta string, que eh validado atraves do calculo do 'modulo 11' dos digitos que compoe a string.
#
# Caso o conteudo da string obedeca ao formato especificado acima, o mesmo sera formatado para obedecer ao padrao xxx.xxx.xxx-xx
#
# Eh importante observar que caso voce associe um valor de cpf invalido ao seu model, o mesmo passara automaticamente a ser invalido, o que impede que valores de cpf incorretos sejam salvos no banco de dados.
#
# Como usar a classe Cpf no seu ActiveRecord:
#
# Suponha que temos um model Pessoa, com um atributo 'cpf'
# que voce quer usar como um numero de documento para cpf. Basta usar o
# metodo <tt>usar_como_cpf</tt>, assim:
#
# class Pessoa < ActiveRecord::Base
# usar_como_cpf :cpf
# end
#
# O atributo que sera usado como cpf pode ter qualquer nome e nao apenas 'cpf'
#
# Agora voce pode usar o atributo para cpf da seguinte forma:
#
# p = Pessoa.new
# p.cpf = "11144477735"
# puts p.cpf # ==> 111.444.777-35
# p.cpf.valido? # ==> true
# p.cpf_valido? # ==> true
#
# p = Pessoa.new(:cpf => "111.444.777-35")
# puts p.cpf # ==> 111.444.777-35
#
# p = Pessoa.new
# p.cpf = Cpf.new("111444777-35")
# puts p.cpf # ==> 111.444.777-35
#
# p = Pessoa.new
# p.cpf = "12345" # ==> um cpf invalido
# puts p.valid? # ==> false
# p.save # ==> false
# p.errors.on(:cpf) # ==> 'não é válido' # de acordo com o I18n
#
# c = Cpf.new("11144477735")
# p.cpf = "111.444.777-35"
# c == p.cpf # ==> true
#
class Cpf
include CpfCnpj
end

View File

@@ -0,0 +1,90 @@
# -*- 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

View File

@@ -0,0 +1,61 @@
# -*- encoding : utf-8 -*-
module CpfCnpjActiveRecord #:nodoc:
def self.included(base) #:nodoc:
base.extend ClassMethods
end
module ClassMethods #:nodoc:
def usar_como_cpf(*args) #:nodoc:
init(args, 'Cpf')
end
def usar_como_cnpj(*args) #:nodoc:
init(args, 'Cnpj')
end
def init(args, klass)
unless args.size.zero?
args.each do |name|
add_composed_class(name, klass)
module_eval create_code(name.to_s, klass)
end
end
end
def add_composed_class(name, klass)
options = {:class_name => klass, :mapping => [name.to_s, "numero"], :allow_nil => true}
constructor = Proc.new { |numero| eval(klass).new(numero) }
converter = Proc.new { |value| eval(klass).new(value) }
begin
composed_of name, options.merge( { :constructor => constructor, :converter => converter } )
rescue Exception
composed_of name, options { eval(klass).new(name[:numero]) }
end
end
def create_code(name, klass)
str = <<-CODE
validate :#{name}_valido?
def #{name}_valido?
value = read_attribute('#{name}')
if !value.nil? && value.strip != '' && !#{name}.nil? && !#{name}.valido?
self.errors.add('#{name}', :invalid)
end
end
def #{name}=(value)
if value.blank?
write_attribute('#{name}', nil)
elsif value.kind_of?(#{eval(klass)})
write_attribute('#{name}', value.numero)
else
begin
c = #{eval(klass)}.new(value)
c.valido? ? write_attribute('#{name}', c.numero) : write_attribute('#{name}', value)
rescue
@#{name} = value
end
end
end
CODE
end
end
end

View File

@@ -0,0 +1,6 @@
class CpfValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return if value.nil?
record.errors.add attribute, :invalid unless Cpf.new(value).valido?
end
end

View File

@@ -0,0 +1,10 @@
module BrCpfCnpj
module VERSION #:nodoc:
MAJOR = 3
MINOR = 3
TINY = 0
STRING = "#{MAJOR}.#{MINOR}.#{TINY}"
end
end