File Coverage

blib/lib/Business/BR/CPF.pm
Criterion Covered Total %
statement 40 40 100.0
branch 14 16 87.5
condition 7 9 77.7
subroutine 10 10 100.0
pod 5 5 100.0
total 76 80 95.0


line stmt bran cond sub pod time code
1            
2             package Business::BR::CPF;
3            
4 6     6   101107 use 5;
  6         31  
5 6     6   29 use strict;
  6         10  
  6         151  
6 6     6   31 use warnings;
  6         9  
  6         1151  
7            
8             require Exporter;
9            
10             our @ISA = qw(Exporter);
11            
12             #our %EXPORT_TAGS = ( 'all' => [ qw() ] );
13             #our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
14             #our @EXPORT = qw();
15            
16             our @EXPORT_OK = qw( canon_cpf format_cpf parse_cpf random_cpf );
17             our @EXPORT = qw( test_cpf );
18            
19             our $VERSION = '0.00_16';
20            
21             #use Scalar::Util qw(looks_like_number);
22            
23 6     6   2616 use Business::BR::Ids::Common qw(_dot _canon_id);
  6         11  
  6         4901  
24            
25             sub canon_cpf {
26 233     233 1 422 return _canon_id(shift, size => 11);
27             }
28            
29            
30             # there is a subtle difference here between the return for
31             # for an input which is not 11 digits long (undef)
32             # and one that does not satisfy the check equations (0).
33             # Correct CPF numbers return 1.
34             sub test_cpf {
35 223     223 1 3695 my $cpf = canon_cpf shift;
36 223 100       393 return undef if length $cpf != 11;
37 220         536 my @cpf = split '', $cpf;
38 220         500 my $s1 = _dot([10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0], \@cpf) % 11;
39 220         612 my $s2 = _dot([0, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1], \@cpf) % 11;
40 220 100 100     472 unless ($s1==0 || $s1==1 && $cpf[9]==0) {
      66        
41 6         23 return 0;
42             }
43 214 100 66     1153 return ($s2==0 || $s2==1 && $cpf[10]==0) ? 1 : 0;
44             }
45            
46            
47             sub format_cpf {
48 4     4 1 15 my $cpf = canon_cpf shift;
49 4         34 $cpf =~ s/^(...)(...)(...)(..).*/$1.$2.$3-$4/;
50 4         15 return $cpf;
51             }
52            
53             sub parse_cpf {
54 2     2 1 1263 my $cpf = canon_cpf shift;
55 2         11 my ($base, $dv) = $cpf =~ /(\d{9})(\d{2})/;
56 2 100       7 if (wantarray) {
57 1         5 return ($base, $dv);
58             }
59 1         7 return { base => $base, dv => $dv };
60             }
61            
62             # my ($dv1, $dv2) = _dv_cpf('390.533.447-05') # => $dv1 = 0, $dv2 = 5
63             # my ($dv1, $dv2) = _dv_cpf('390.533.447-05', 0) # computes non-valid check digits
64             #
65             # computes the check digits of the candidate CPF number given as argument
66             # (only the first 9 digits enter the computation)
67             #
68             # In list context, it returns the check digits.
69             # In scalar context, it returns the complete CPF (base and check digits)
70             sub _dv_cpf {
71 200     200   171 my $base = shift; # expected to be canon'ed already ?!
72 200 50       242 my $valid = @_ ? shift : 1;
73 200 100       225 my $dev = $valid ? 0 : 2; # deviation (to make CPF invalid)
74 200         595 my @base = split '', substr($base, 0, 9);
75 200         733 my $dv1 = -_dot([10, 9, 8, 7, 6, 5, 4, 3, 2], \@base) % 11 % 10;
76 200         920 my $dv2 = (-_dot([0, 10, 9, 8, 7, 6, 5, 4, 3, 2], [ @base, $dv1 ]) + $dev) % 11 % 10;
77 200 50       455 return ($dv1, $dv2) if wantarray;
78 200         291 substr($base, 9, 2) = "$dv1$dv2";
79 200         476 return $base;
80             }
81            
82             # generates a random (correct or incorrect) CPF
83             # $cpf = rand_cpf();
84             # $cpf = rand_cpf($valid);
85             #
86             # if $valid==0, produces an invalid CPF.
87             sub random_cpf {
88 200 100   200 1 48500 my $valid = @_ ? shift : 1; # valid CPF by default
89 200         709 my $base = sprintf "%09s", int(rand(1E9)); # 9 dígitos
90 200         270 return scalar _dv_cpf($base, $valid);
91             }
92            
93             1;
94            
95             __END__