File Coverage

blib/lib/Business/BR/IE.pm
Criterion Covered Total %
statement 319 360 88.6
branch 137 194 70.6
condition 40 66 60.6
subroutine 73 92 79.3
pod 0 76 0.0
total 569 788 72.2


line stmt bran cond sub pod time code
1            
2             package Business::BR::IE;
3            
4 6     6   73968 use 5;
  6         15  
5 6     6   25 use strict;
  6         6  
  6         121  
6 6     6   19 use warnings;
  6         7  
  6         585  
7            
8             require Exporter;
9            
10             our @ISA = qw(Exporter);
11            
12             our @EXPORT_OK = qw( canon_ie format_ie parse_ie random_ie );
13             our @EXPORT = qw( test_ie );
14            
15             our $VERSION = '0.00_20';
16             $VERSION = eval $VERSION;
17            
18 6     6   1848 use Business::BR::Ids::Common qw( _dot _dot_10 _canon_id );
  6         12  
  6         30963  
19            
20             ### AC ###
21            
22             # http://www.sintegra.gov.br/Cad_Estados/cad_AC.html
23            
24             sub canon_ie_ac {
25 207     207 0 338 return _canon_id(shift, size => 13);
26             }
27             sub test_ie_ac {
28 203     203 0 223 my $ie = canon_ie_ac shift;
29 203 50       291 return undef if length $ie != 13;
30 203 50       599 return 0 unless $ie =~ /^01/;
31 203         452 my @ie = split '', $ie;
32 203         487 my $s1 = _dot([4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0], \@ie) % 11;
33 203 100 66     395 unless ($s1==0 || $s1==1 && $ie[11]==0) {
      66        
34 1         5 return 0;
35             }
36 202         436 my $s2 = _dot([5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2, 1], \@ie) % 11;
37 202 100 66     1180 return ($s2==0 || $s2==1 && $ie[12]==0) ? 1 : 0;
38            
39             }
40             sub format_ie_ac {
41 1     1 0 3 my $ie = canon_ie_ac shift;
42 1         12 $ie =~ s|^(..)(...)(...)(...)(..).*|$1.$2.$3/$4-$5|; # 01.004.823/001-12
43 1         7 return $ie;
44             }
45             sub _dv_ie_ac {
46 200     200   150 my $base = shift; # expected to be canon'ed already ?!
47 200 50       230 my $valid = @_ ? shift : 1;
48 200 100       199 my $dev = $valid ? 0 : 2; # deviation (to make IE-PR invalid)
49 200         589 my @base = split '', substr($base, 0, 11);
50 200         565 my $dv1 = -_dot([4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2], \@base) % 11 % 10;
51 200         1004 my $dv2 = (-_dot([5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2], [ @base, $dv1 ]) + $dev) % 11 % 10;
52 200 50       442 return ($dv1, $dv2) if wantarray;
53 200         344 substr($base, 11, 2) = "$dv1$dv2";
54 200         455 return $base;
55             }
56             sub random_ie_ac {
57 200 100   200 0 256 my $valid = @_ ? shift : 1; # valid IE-SP by default
58 200         640 my $base = sprintf "01%09s", int(rand(1E9)); # '01' and 9 digits
59 200         220 return scalar _dv_ie_ac($base, $valid);
60             }
61             sub parse_ie_ac {
62 2     2 0 7 my $ie = canon_ie_ac shift;
63 2         14 my ($base, $dv) = $ie =~ /(\d{11})(\d{2})/;
64 2 100       10 if (wantarray) {
65 1         4 return ($base, $dv);
66             }
67 1         26 return { base => $base, dv => $dv };
68             }
69            
70             ### AL ###
71            
72             # http://www.sefaz.al.gov.br/sintegra/cad_AL.asp
73             # http://www.sintegra.gov.br/Cad_Estados/cad_AL.html
74            
75             my %AL_TYPES = (
76             0 => "normal",
77             1 => "normal",
78             3 => "produtor rural",
79             5 => "substituta",
80             6 => "empresa pequeno porte",
81             7 => "micro empresa ambulante",
82             8 => "micro empresa",
83             9 => "especial"
84             );
85             my @AL_TYPES = keys %AL_TYPES;
86            
87             sub canon_ie_al {
88 204     204 0 398 return _canon_id(shift, size => 9);
89             }
90             sub test_ie_al {
91 201     201 0 217 my $ie = canon_ie_al shift;
92 201 50       351 return undef if length $ie != 9;
93 201 50       706 return 0 unless $ie =~ /^24/;
94 201         512 my @ie = split '', $ie;
95 201 50       454 return 0 unless $AL_TYPES{$ie[2]};
96 201         574 my $s1 = _dot([90, 80, 70, 60, 50, 40, 30, 20, -1], \@ie) % 11;
97             #print "ie: $ie, s1: $s1\n";
98 201 100 66     1442 return ($s1==0 || $s1==10 && $ie[8]==0) ? 1 : 0;
99            
100             }
101             sub format_ie_al {
102 1     1 0 22 my $ie = canon_ie_al shift;
103 1         9 $ie =~ s|^(..)(...)(...)(.).*|$1.$2.$3-$4|; # 24.000.004-8
104 1         4 return $ie;
105             }
106             sub _dv_ie_al {
107 200     200   186 my $base = shift; # expected to be canon'ed already ?!
108 200 50       264 my $valid = @_ ? shift : 1;
109 200 100       251 my $dev = $valid ? 0 : 2; # deviation (to make IE-AL invalid)
110 200         623 my @base = split '', $base;
111 200         673 my $dv1 = (_dot([90, 80, 70, 60, 50, 40, 30, 20], \@base) + $dev) % 11 % 10;
112 200 50       424 return ($dv1) if wantarray;
113 200         269 substr($base, 8, 1) = $dv1;
114 200         642 return $base;
115             }
116             sub random_ie_al {
117 200 100   200 0 309 my $valid = @_ ? shift : 1; # valid IE-AL by default
118 200         950 my $base = sprintf "24%1s%05s",
119             $AL_TYPES[int(rand(@AL_TYPES))],
120             int(rand(1E5)); # '24', type and 5 digits
121 200         274 return scalar _dv_ie_al($base, $valid);
122             }
123             sub parse_ie_al {
124 1     1 0 5 my $ie = canon_ie_al shift;
125 1         6 my ($base, $dv) = $ie =~ /(\d{8})(\d{1})/;
126 1 50       4 if (wantarray) {
127 0         0 return ($base, $dv);
128             }
129 1         4 my $type = substr($ie, 2, 1);
130             return {
131             base => $base,
132             dv => $dv,
133             type => $type,
134 1         8 t_name => $AL_TYPES{$type}
135            
136             };
137             }
138            
139             ### AP ###
140            
141             #***
142            
143             sub canon_ie_ap {
144 214     214 0 351 return _canon_id(shift, size => 9);
145             }
146             sub test_ie_ap {
147 211     211 0 248 my $ie = canon_ie_ap shift;
148 211 50       347 return undef if length $ie != 9;
149 211 100       637 return 0 unless $ie =~ /^03/;
150            
151 210         221 my $nr_empresa = substr($ie, 2, -1);
152 210 100 66     988 my ($p, $d) = ($nr_empresa >= 1) && ($nr_empresa <= 17000) ? (5, 0) : # 1st class, 03.000.001-x up to 03.017.000-x
    100 66        
153             ($nr_empresa >= 17001) && ($nr_empresa <= 19022) ? (9, 1) : # 2nd class, 03.017.001-x up to 03.019.022-x
154             (0, 0); # 3rd class, from 03.019.023-x and on
155             # print "(p, d) = ($p, $d)\n";
156            
157 210         455 my @ie = split '', $ie;
158 210         485 my $sum = -($p + _dot([9, 8, 7, 6, 5, 4, 3, 2, 1], \@ie)) % 11;
159            
160             # print "# ie: $ie, sum: $sum\n"; # ***
161 210 100 66     1258 return ($sum==0 || $sum==10 && $ie[8]==0) ? 1 : 0;
162            
163             } # FIXME: this is not QUITE RIGHT !!!!!!!!!
164             sub format_ie_ap {
165 1     1 0 4 my $ie = canon_ie_ap shift;
166 1         10 $ie =~ s|^(..)(...)(...)(.).*|$1.$2.$3-$4|; # 03.012.245-9
167 1         4 return $ie;
168             }
169             sub _dv_ie_ap {
170 200     200   151 my $base = shift; # expected to be canon'ed already ?!
171 200 50       226 my $valid = @_ ? shift : 1;
172 200 100       219 my $dev = $valid ? 0 : 3; # deviation (to make IE-AP invalid)
173 200         554 my @base = split '', $base;
174            
175 200         239 my $nr_empresa = substr($base, 2, -1);
176 200 50 66     1145 my ($p, $d) = ($nr_empresa >= 1) && ($nr_empresa <= 17000) ? (5, 0) : # 1st class, 03.000.001-x up to 03.017.000-x
    100 33        
177             ($nr_empresa >= 17001) && ($nr_empresa <= 19022) ? (9, 1) : # 2nd class, 03.017.001-x up to 03.019.022-x
178             (0, 0); # 3rd class, from 03.019.023-x and on
179            
180 200         695 my $dv1 = -($p + _dot([9, 8, 7, 6, 5, 4, 3, 2, 0], \@base) + $dev) % 11 % 10;
181 200 50       356 return ($dv1) if wantarray;
182 200         289 substr($base, 8, 1) = $dv1;
183 200         487 return $base;
184             }
185             sub random_ie_ap {
186 200 100   200 0 294 my $valid = @_ ? shift : 1; # valid IE-AP by default
187 200         658 my $base = sprintf "03%06d*",
188             int(rand(1E6)); # '03', 6 digits, dv
189 200         242 return scalar _dv_ie_ap($base, $valid);
190             }
191             sub parse_ie_ap {
192 0     0 0 0 my $ie = canon_ie_ap shift;
193 0         0 my ($base, $dv) = $ie =~ /(\d{8})(\d{1})/;
194 0 0       0 if (wantarray) {
195 0         0 return ($base, $dv);
196             }
197             return {
198 0         0 base => $base,
199             dv => $dv,
200             range => '?'
201             };
202            
203             }
204            
205            
206            
207             ### AM ###
208            
209             # http://www.sintegra.gov.br/Cad_Estados/cad_AM.html
210            
211             sub canon_ie_am {
212 203     203 0 361 return _canon_id( shift, size => 9 );
213             }
214             sub test_ie_am {
215 201     201 0 211 my $ie = canon_ie_am(shift);
216 201 50       327 return undef if length $ie != 9;
217            
218 201         388 my @ie = split '', $ie;
219 201         420 my $s1 = _dot( [ 9, 8, 7, 6, 5, 4, 3, 2, 1 ], \@ie ) % 11;
220 201 100 66     1233 return ( $s1==0 || $s1==1 && $ie[8]==0 ) ? 1 : 0;
221             }
222             sub format_ie_am {
223 1     1 0 4 my $ie = canon_ie_am(shift);
224 1         9 $ie =~ s|^(..)(...)(...)(.).*|$1.$2.$3-$4|; # 11.111.111-0
225 1         4 return $ie;
226             }
227             sub parse_ie_am {
228 1     1 0 5 my $ie = canon_ie_am(shift);
229 1         6 my ($base, $dv) = $ie =~ /(\d{8})(\d{1})/;
230 1 50       4 if (wantarray) {
231 0         0 return ($base, $dv);
232             }
233             return {
234 1         6 base => $base,
235             dv => $dv,
236             };
237             }
238             sub _dv_ie_am {
239 200     200   149 my $base = shift; # expected to be canon'ed already ?!
240 200 50       236 my $valid = @_ ? shift : 1;
241 200 100       222 my $dev = $valid ? 0 : 2; # deviation (to make IE/AM invalid)
242 200         583 my @base = split '', substr($base, 0, 8);
243 200         533 my $dv1 = (-_dot([9, 8, 7, 6, 5, 4, 3, 2], \@base)+$dev) % 11 % 10;
244 200 50       351 return ($dv1) if wantarray;
245 200         214 substr($base, 8, 1) = $dv1;
246 200         465 return $base;
247             }
248             sub random_ie_am {
249 200 100   200 0 319 my $valid = @_ ? shift : 1; # valid IE-SP by default
250 200         615 my $base = sprintf "%08s", int(rand(1E8)); # 8 digits # XXX IE/AM begins with '04'?
251 200         251 return scalar _dv_ie_am($base, $valid);
252             }
253            
254             ### BA ###
255            
256             # http://www.sintegra.gov.br/Cad_Estados/cad_BA.html
257            
258             sub canon_ie_ba {
259 205     205 0 421 return _canon_id(shift, size => 8);
260             }
261             sub test_ie_ba {
262 202     202 0 258 my $ie = canon_ie_ba(shift);
263 202 50       416 return undef if length $ie != 8;
264            
265 202         613 my @ie = split '', $ie;
266 202 100       655 if ( $ie =~ /^[0123458]/ ) { # calculo pelo modulo 10
267            
268 145         518 my $s2 = _dot( [ 7, 6, 5, 4, 3, 2, undef, 1 ], \@ie ) % 10;
269 145 50       408 unless ( $s2==0 ) {
270 0         0 return 0;
271             }
272 145         448 my $s1 = _dot( [ 8, 7, 6, 5, 4, 3, 1, 2 ], \@ie ) % 10;
273 145 100       1156 return ( $s1==0 ) ? 1 : 0;
274            
275             } else { # $ie =~ /^[679]/ # calculo pelo modulo 11
276            
277 57         208 my $s2 = _dot( [ 7, 6, 5, 4, 3, 2, undef, 1 ], \@ie ) % 11;
278 57 50 33     198 unless ( $s2==0 || $s2==1 && $ie[7]==0 ) {
      66        
279 0         0 return 0;
280             }
281 57         212 my $s1 = _dot( [ 8, 7, 6, 5, 4, 3, 1, 2 ], \@ie ) % 11;
282 57 100 66     699 return ( $s1==0 || $s1==1 && $ie[6]==0 ) ? 1 : 0;
283            
284             }
285             }
286             sub format_ie_ba {
287 1     1 0 4 my $ie = canon_ie_ba(shift);
288 1         8 $ie =~ s|^(......)(..).*|$1-$2|; # 123456-63
289 1         4 return $ie;
290             }
291             sub parse_ie_ba {
292 1     1 0 4 my $ie = canon_ie_ba(shift);
293 1         6 my ($base, $dv) = $ie =~ /^(\d{6})(\d{2})/;
294 1 50       4 if (wantarray) {
295 0         0 return ($base, $dv);
296             }
297             return {
298 1         8 base => $base,
299             dv => $dv,
300             };
301             }
302             # ???
303             sub _dv_ie_ba {
304 200     200   184 my $base = shift; # expected to be canon'ed already ?!
305 200 50       270 my $valid = @_ ? shift : 1;
306 200 100       272 my $dev = $valid ? 0 : 2; # deviation (to make IE/BA invalid)
307 200         718 my @base = split '', substr($base, 0, 6);
308            
309 200 100       649 if ( $base =~ /^[0123458]/ ) { # calculo pelo modulo 10)
310            
311 144         504 my $dv2 = -_dot( [ 7, 6, 5, 4, 3, 2 ], \@base) % 10;
312 144         880 my $dv1 = (-_dot( [ 8, 7, 6, 5, 4, 3, 2 ], [ @base, $dv2 ])+$dev) % 10;
313 144 50       444 return ($dv1, $dv2) if wantarray;
314 144         331 substr($base, 6, 2) = "$dv1$dv2";
315 144         605 return $base;
316            
317             } else { # =~ /^[679]/ # calculo pelo modulo 11
318            
319 56         222 my $dv2 = -_dot( [ 7, 6, 5, 4, 3, 2 ], \@base) % 11 % 10;
320 56         356 my $dv1 = (-_dot( [ 8, 7, 6, 5, 4, 3, 2 ], [ @base, $dv2 ])+$dev) % 11 % 10;
321 56 50       192 return ($dv1, $dv2) if wantarray;
322 56         131 substr($base, 6, 2) = "$dv1$dv2";
323 56         254 return $base;
324            
325             }
326             }
327             sub random_ie_ba {
328 200 100   200 0 427 my $valid = @_ ? shift : 1; # valid IE/BA by default
329 200         865 my $base = sprintf "%06s", int(rand(1E6)); # 6 digits
330 200         313 return scalar _dv_ie_ba($base, $valid);
331             }
332            
333            
334             ### CE ###
335            
336             sub canon_ie_ce {
337 0     0 0 0 return _canon_id(shift, size => 9);
338             }
339            
340             ### DF ###
341            
342             sub canon_ie_df {
343 0     0 0 0 return _canon_id(shift, size => 13);
344             }
345            
346             ### ES ###
347            
348             sub canon_ie_es {
349 0     0 0 0 return _canon_id(shift, size => 9);
350             }
351            
352             ### GO ###
353            
354             sub canon_ie_go {
355 0     0 0 0 return _canon_id(shift, size => 9);
356             }
357            
358             ### MA ###
359            
360             # http://www.sintegra.gov.br/Cad_Estados/cad_MA.html
361            
362             sub canon_ie_ma {
363 204     204 0 422 return _canon_id(shift, size => 9);
364             }
365             sub test_ie_ma {
366 201     201 0 245 my $ie = canon_ie_ma shift;
367 201 50       446 return undef if length $ie != 9;
368 201 50       838 return 0 unless $ie =~ /^12/;
369 201         599 my @ie = split '', $ie;
370 201         800 my $s1 = _dot([9, 8, 7, 6, 5, 4, 3, 2, 1], \@ie) % 11;
371 201 100 66     1794 return ($s1==0 || $s1==1 && $ie[8]==0) ? 1 : 0;
372            
373             }
374             sub format_ie_ma {
375 1     1 0 4 my $ie = canon_ie_ma shift;
376 1         11 $ie =~ s|^(..)(...)(...)(.).*|$1.$2.$3-$4|; # 12.000.038-5
377 1         4 return $ie;
378             }
379             sub _dv_ie_ma {
380 200     200   211 my $base = shift; # expected to be canon'ed already ?!
381 200 50       271 my $valid = @_ ? shift : 1;
382 200 100       297 my $dev = $valid ? 0 : 2; # deviation (to make IE-MA invalid)
383 200         785 my @base = split '', substr($base, 0, 8);
384 200         776 my $dv1 = (-_dot([9, 8, 7, 6, 5, 4, 3, 2], \@base)+$dev) % 11 % 10;
385 200 50       518 return ($dv1) if wantarray;
386 200         300 substr($base, 8, 1) = $dv1;
387 200         771 return $base;
388             }
389             sub random_ie_ma {
390 200 100   200 0 373 my $valid = @_ ? shift : 1; # valid IE-SP by default
391 200         834 my $base = sprintf "12%06s", int(rand(1E6)); # '12' and 6 digits
392 200         289 return scalar _dv_ie_ma($base, $valid);
393             }
394             sub parse_ie_ma {
395 1     1 0 4 my $ie = canon_ie_ma shift;
396 1         7 my ($base, $dv) = $ie =~ /(\d{8})(\d{1})/;
397 1 50       4 if (wantarray) {
398 0         0 return ($base, $dv);
399             }
400 1         6 return { base => $base, dv => $dv };
401             }
402            
403             ### MT ###
404            
405             sub canon_ie_mt {
406 0     0 0 0 return _canon_id(shift, size => 11);
407             }
408            
409             ### MS ###
410            
411             sub canon_ie_ms {
412 0     0 0 0 return _canon_id(shift, size => 9);
413             }
414            
415             ### MG ###
416            
417             # http://www.sintegra.gov.br/Cad_Estados/cad_MG.html
418            
419             sub canon_ie_mg {
420 204     204 0 326 return _canon_id( shift, size => 13 );
421             }
422            
423             sub test_ie_mg {
424 201     201 0 209 my $ie = canon_ie_mg( shift );
425 201 50       292 return undef if length $ie != 13;
426 201         434 my @ie = split '', $ie;
427            
428 201         449 my $c1 = - _dot_10( [1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, undef, undef], \@ie ) % 10;
429 201 50       405 unless ( $ie[11] eq $c1 ) {
430 0         0 return 0;
431             }
432            
433 201         432 my $s2 = _dot( [ 3, 2, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 ], \@ie ) % 11;
434 201 100 66     1232 return ( $s2==0 || $s2==1 && $ie[12]==0 ) ? 1 : 0;
435             }
436            
437             sub format_ie_mg {
438 1     1 0 4 my $ie = canon_ie_mg shift;
439 1         9 $ie =~ s|^(...)(...)(...)(..)(..).*|$1.$2.$3/$4$5|; # 062.307.904/0081
440 1         4 return $ie;
441             }
442            
443             sub parse_ie_mg {
444 1     1 0 5 my $ie = canon_ie_mg shift;
445 1         7 my ($municipio, $inscricao, $ordem, $dv) = $ie =~ /(\d{3})(\d{6})(\d{2})(\d{2})/;
446 1 50       5 if (wantarray) {
447 0         0 return ($municipio, $inscricao, $ordem, $dv);
448             }
449             return {
450 1         17 municipio => $municipio,
451             inscricao => $inscricao,
452             ordem => $ordem,
453             dv => $dv,
454             };
455             }
456            
457             sub _dv_ie_mg {
458 200     200   144 my $base = shift; # expected to be canon'ed already ?!
459 200 50       218 my $valid = @_ ? shift : 1;
460 200 100       211 my $dev = $valid ? 0 : 2; # deviation (to make IE/MG invalid)
461 200         547 my @base = split '', substr($base, 0, 11);
462 200         603 my $dv1 = -_dot_10([ 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2 ], \@base) % 10;
463 200         957 my $dv2 = (-_dot([ 3, 2, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2 ], [ @base, $dv1 ]) + $dev) % 11 % 10;
464 200 50       414 return ($dv1, $dv2) if wantarray;
465 200         353 substr($base, 11, 2) = "$dv1$dv2";
466 200         449 return $base;
467             }
468             sub random_ie_mg {
469 200 100   200 0 275 my $valid = @_ ? shift : 1; # valid IE/MG by default
470 200         639 my $base = sprintf "%011s", int(rand(1E11)); # 11 digits
471 200         228 return scalar _dv_ie_mg($base, $valid);
472             }
473            
474            
475             ### PA ###
476            
477             sub canon_ie_pa {
478 0     0 0 0 return _canon_id(shift, size => 9);
479             }
480            
481             ### PB ###
482            
483             sub canon_ie_pb {
484 0     0 0 0 return _canon_id(shift, size => 9);
485             }
486            
487             ### PR ###
488            
489             #PR - http://www.fazenda.pr.gov.br/icms/calc_dgv.asp
490             # Formato da Inscrição: NNN NNN NN-DD (10 dígitos)
491             # Cálculo do Primeiro Dígito: Módulo 11 com pesos de 2 a 7, aplicados da direita para esquerda, sobre as 8 primeiras posições.
492             # Cálculo do Segundo Dígito: Módulo 11 com pesos de 2 a 7, aplicados da direita para esquerda, sobre as 9 primeiras posições (inclui o primeiro dígito).
493             # Exemplo: CAD 123.45678-50
494            
495             #PR - http://www.sintegra.gov.br/Cad_Estados/cad_PR.html
496             # Formato da Inscrição NNN.NNNNN-DD (1o dígitos) [ NNN NNN NN-DD ]
497             # Exemplo: 123.45678-50
498            
499            
500             sub canon_ie_pr {
501 204     204 0 415 return _canon_id(shift, size => 10);
502             }
503             sub test_ie_pr {
504 202     202 0 256 my $ie = canon_ie_pr shift;
505 202 50       404 return undef if length $ie != 10;
506 202         637 my @ie = split '', $ie;
507 202         609 my $s1 = _dot([3, 2, 7, 6, 5, 4, 3, 2, 1, 0], \@ie) % 11;
508 202         747 my $s2 = _dot([4, 3, 2, 7, 6, 5, 4, 3, 2, 1], \@ie) % 11;
509 202 50 33     625 unless ($s1==0 || $s1==1 && $ie[8]==0) {
      66        
510 0         0 return 0;
511             }
512 202 100 66     1719 return ($s2==0 || $s2==1 && $ie[9]==0) ? 1 : 0;
513            
514             }
515             sub format_ie_pr {
516 0     0 0 0 my $ie = canon_ie_pr shift;
517 0         0 $ie =~ s|^(...)(.....)(..).*|$1.$2-$3|;
518 0         0 return $ie;
519             }
520             sub _dv_ie_pr {
521 200     200   208 my $base = shift; # expected to be canon'ed already ?!
522 200 50       315 my $valid = @_ ? shift : 1;
523 200 100       280 my $dev = $valid ? 0 : 2; # deviation (to make IE-PR invalid)
524 200         736 my @base = split '', substr($base, 0, 8);
525 200         750 my $dv1 = -_dot([3, 2, 7, 6, 5, 4, 3, 2], \@base) % 11 % 10;
526 200         1230 my $dv2 = (-_dot([4, 3, 2, 7, 6, 5, 4, 3, 2], [ @base, $dv1 ]) + $dev) % 11 % 10;
527 200 50       576 return ($dv1, $dv2) if wantarray;
528 200         355 substr($base, 8, 2) = "$dv1$dv2";
529 200         751 return $base;
530             }
531             sub random_ie_pr {
532 200 100   200 0 362 my $valid = @_ ? shift : 1; # valid IE-SP by default
533 200         771 my $base = sprintf "%08s", int(rand(1E8)); # 8 dígitos
534 200         315 return scalar _dv_ie_pr($base, $valid);
535             }
536             sub parse_ie_pr {
537 2     2 0 7 my $ie = canon_ie_pr shift;
538 2         11 my ($base, $dv) = $ie =~ /(\d{8})(\d{2})/;
539 2 100       6 if (wantarray) {
540 1         5 return ($base, $dv);
541             }
542 1         6 return { base => $base, dv => $dv };
543             }
544            
545             ### PE ###
546            
547             sub canon_ie_pe {
548 0     0 0 0 return _canon_id(shift, size => 14);
549             }
550            
551             ### PI ###
552            
553             sub canon_ie_pi {
554 0     0 0 0 return _canon_id(shift, size => 9);
555             }
556            
557             ### RJ ###
558            
559             sub canon_ie_rj {
560 0     0 0 0 return _canon_id(shift, size => 9);
561             }
562            
563             ### RN ###
564            
565             sub canon_ie_rn {
566 0     0 0 0 return _canon_id(shift, size => 9);
567             }
568            
569             ### RS ###
570            
571             sub canon_ie_rs {
572 0     0 0 0 return _canon_id(shift, size => 10);
573             }
574            
575             ### RO ###
576            
577             # http://www.sintegra.gov.br/Cad_Estados/cad_RO.html
578            
579             sub canon_ie_ro {
580 206     206 0 363 return _canon_id(shift, size => 14);
581             }
582             sub test_ie_ro {
583 203     203 0 251 my $ie = canon_ie_ro shift;
584 203 50       346 return undef if length $ie != 14;
585 203         638 my @ie = split '', $ie;
586 203         549 my $s1 = _dot([6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2, 1], \@ie) % 11;
587 203   66     1629 return $s1==0 || $ie[13]==0 && $s1==1;
588             }
589             sub format_ie_ro {
590 1     1 0 3 my $ie = canon_ie_ro shift;
591 1         8 $ie =~ s|^(.............)(.).*|$1-$2|;
592 1         4 return $ie;
593             }
594             sub _dv_ie_ro {
595 200     200   207 my $base = shift; # expected to be canon'ed already ?!
596 200 50       253 my $valid = @_ ? shift : 1;
597 200 100       226 my $dev = $valid ? 0 : 2; # deviation (to make IE-RO invalid)
598 200         802 my @base = split '', substr($base, 0, 13);
599 200         767 my $dv = (-_dot([6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2], \@base)+$dev) % 11 % 10;
600 200 50       712 return ($dv) if wantarray;
601 200         250 substr($base, 13, 1) = $dv;
602 200         649 return $base;
603             }
604             sub random_ie_ro {
605 200 100   200 0 323 my $valid = @_ ? shift : 1; # valid IE-RO by default
606 200         734 my $base = sprintf "%013s", int(rand(1E13)); # 13 dígitos # devia ter maior probabilidade para 000 00000 AAAAA D
607 200         272 return scalar _dv_ie_ro($base, $valid);
608             }
609             sub parse_ie_ro {
610 1     1 0 5 my $ie = canon_ie_ro shift;
611 1         8 my ($base, $dv) = $ie =~ /(\d{13})(\d{1})/;
612 1 50       4 if (wantarray) {
613 0         0 return ($base, $dv);
614             }
615 1         6 return { base => $base, dv => $dv };
616             }
617            
618             ### RR ###
619            
620             # http://www.sintegra.gov.br/Cad_Estados/cad_RR.html
621            
622             sub canon_ie_rr {
623 213     213 0 402 return _canon_id(shift, size => 9);
624             }
625             sub test_ie_rr {
626 210     210 0 244 my $ie = canon_ie_rr shift;
627 210 50       347 return undef if length $ie != 9;
628 210 50       713 return 0 unless $ie =~ /^24/;
629 210         494 my @ie = split '', $ie;
630 210         551 my $s1 = _dot([1, 2, 3, 4, 5, 6, 7, 8, -1], \@ie) % 9;
631 210 100       1123 return $s1==0 ? 1 : 0;
632            
633             }
634             sub format_ie_rr {
635 1     1 0 4 my $ie = canon_ie_rr shift;
636 1         8 $ie =~ s|^(..)(...)(...)(.).*|$1.$2.$3-$4|; # 24.006.628-1
637 1         4 return $ie;
638             }
639             sub _dv_ie_rr {
640 200     200   154 my $base = shift; # expected to be canon'ed already ?!
641 200 50       259 my $valid = @_ ? shift : 1;
642 200 100       251 my $dev = $valid ? 0 : 2; # deviation (to make IE-PR invalid)
643 200         628 my @base = split '', substr($base, 0, 8);
644 200         629 my $dv1 = (_dot([1, 2, 3, 4, 5, 6, 7, 8], \@base)+$dev) % 9;
645 200 50       415 return ($dv1) if wantarray;
646 200         244 substr($base, 8, 1) = $dv1;
647 200         548 return $base;
648             }
649             sub random_ie_rr {
650 200 100   200 0 303 my $valid = @_ ? shift : 1; # valid IE-SP by default
651 200         654 my $base = sprintf "24%06s", int(rand(1E6)); # '24' and 6 digits
652 200         238 return scalar _dv_ie_rr($base, $valid);
653             }
654             sub parse_ie_rr {
655 1     1 0 5 my $ie = canon_ie_rr shift;
656 1         7 my ($base, $dv) = $ie =~ /(\d{8})(\d{1})/;
657 1 50       4 if (wantarray) {
658 0         0 return ($base, $dv);
659             }
660 1         6 return { base => $base, dv => $dv };
661             }
662            
663             ### SC ###
664            
665             sub canon_ie_sc {
666 0     0 0 0 return _canon_id(shift, size => 9);
667             }
668            
669             ### SP ###
670            
671             sub canon_ie_sp {
672 220     220 0 402 return _canon_id(shift, size => 12);
673             }
674            
675             #SP - http://www.csharpbr.com.br/arquivos/csharp_mostra_materias.asp?escolha=0021
676             # Exemplo: Inscrição Estadual 110.042.490.114
677             # 12 dígitos, 9o. e 12o. são DVs
678             # dv[1] = (1, 3, 4, 5, 6, 7, 8, 10) .* (c[1] c[2] c[3] c[4] c[5] c[6] c[7] c[8]) (mod 11)
679             # dv[2] = (3 2 10 9 8 7 6 5 4 3 2 1) .* (c[1] ... c[11]) (mod 11)
680            
681             sub test_ie_sp {
682 211     211 0 260 my $ie = canon_ie_sp shift;
683 211 50       364 return undef if length $ie != 12;
684 211         589 my @ie = split '', $ie;
685 211         551 my $s1 = _dot([1, 3, 4, 5, 6, 7, 8, 10, -1, 0, 0, 0], \@ie) % 11;
686 211 50 33     613 unless ($s1==0 || $s1==10 && $ie[8]==0) {
      66        
687 0         0 return 0;
688             }
689 211         552 my $s2 = _dot([3, 2, 10, 9, 8, 7, 6, 5, 4, 3, 2, -1], \@ie) % 11;
690 211 100 66     1606 return ($s2==0 || $s2==10 && $ie[11]==0) ? 1 : 0;
691            
692             }
693            
694             sub format_ie_sp {
695 4     4 0 8 my $ie = canon_ie_sp shift;
696 4         27 $ie =~ s|^(...)(...)(...)(...).*|$1.$2.$3.$4|;
697 4         16 return $ie;
698             }
699            
700             # my ($dv1, $dv2) = _dv_ie_sp('') # => $dv1 = ?, $dv2 = ?
701             # my ($dv1, $dv2) = _dv_ie_sp('', 0) # computes non-valid check digits
702             #
703             # computes the check digits of the candidate IE-SP number given as argument
704             # (only the first 12 digits enter the computation) (9th and 12nd are ignored)
705             #
706             # In list context, it returns the check digits.
707             # In scalar context, it returns the complete IE-SP (base and check digits)
708             sub _dv_ie_sp {
709 200     200   171 my $base = shift; # expected to be canon'ed already ?!
710 200 50       243 my $valid = @_ ? shift : 1;
711 200 100       221 my $dev = $valid ? 0 : 2; # deviation (to make IE-SP invalid)
712 200         771 my @base = split '', substr($base, 0, 12);
713 200         688 my $dv1 = _dot([1, 3, 4, 5, 6, 7, 8, 10, 0, 0, 0, 0], \@base) % 11 % 10;
714 200         676 my $dv2 = (_dot([3, 2, 10, 9, 8, 7, 6, 5, 0, 3, 2, 0], \@base) + 4*$dv1 + $dev) % 11 % 10;
715 200 50       444 return ($dv1, $dv2) if wantarray;
716 200         323 substr($base, 8, 1) = $dv1;
717 200         183 substr($base, 11, 1) = $dv2;
718 200         665 return $base
719             }
720            
721             # generates a random (correct or incorrect) IE-SP
722             # $ie = rand_ie_sp();
723             # $ie = rand_ie_sp($valid);
724             #
725             # if $valid==0, produces an invalid IE-SP
726             sub random_ie_sp {
727 200 100   200 0 345 my $valid = @_ ? shift : 1; # correct IE-SP by default
728 200         789 my $ie = sprintf "%08s0%02s0", int(rand(1E8)), int(rand(1E2)); # 10 dígitos aleatórios
729 200         254 return scalar _dv_ie_sp($ie, $valid);
730             }
731            
732             sub parse_ie_sp {
733 0     0 0 0 my $ie = canon_ie_sp shift;
734 0         0 my ($base, $dv) = $ie =~ /(\d{8})(\d{2})/;
735 0 0       0 if (wantarray) {
736 0         0 return ($base, $dv);
737             }
738 0         0 return { base => $base, dv => $dv };
739             }
740            
741             ### SE ###
742            
743             sub canon_ie_se {
744 0     0 0 0 return _canon_id(shift, size => 9);
745             }
746            
747             ### TO ###
748            
749             sub canon_ie_to {
750 0     0 0 0 return _canon_id(shift, size => 11);
751             }
752            
753             # a dispatch table is used here, because we know beforehand
754             # the list of Brazilian states. I am not sure it is
755             # better than using symbolic references.
756            
757             my %dispatch_table = (
758             # AC
759             test_ie_ac => \&test_ie_ac,
760             canon_ie_ac => \&canon_ie_ac,
761             format_ie_ac => \&format_ie_ac,
762             random_ie_ac => \&random_ie_ac,
763             parse_ie_ac => \&parse_ie_ac,
764            
765             # AL
766             test_ie_al => \&test_ie_al,
767             canon_ie_al => \&canon_ie_al,
768             format_ie_al => \&format_ie_al,
769             random_ie_al => \&random_ie_al,
770             parse_ie_al => \&parse_ie_al,
771            
772             # AM
773             test_ie_am => \&test_ie_am,
774             canon_ie_am => \&canon_ie_am,
775             format_ie_am => \&format_ie_am,
776             random_ie_am => \&random_ie_am,
777             parse_ie_am => \&parse_ie_am,
778            
779             # AP
780             test_ie_ap => \&test_ie_ap,
781             canon_ie_ap => \&canon_ie_ap,
782             format_ie_ap => \&format_ie_ap,
783             random_ie_ap => \&random_ie_ap,
784             parse_ie_ap => \&parse_ie_ap,
785            
786             # BA
787             test_ie_ba => \&test_ie_ba,
788             canon_ie_ba => \&canon_ie_ba,
789             format_ie_ba => \&format_ie_ba,
790             random_ie_ba => \&random_ie_ba,
791             parse_ie_ba => \&parse_ie_ba,
792            
793             # CE
794             canon_ie_ce => \&canon_ie_ce,
795            
796             # DF
797             canon_ie_df => \&canon_ie_df,
798            
799             # ES
800             canon_ie_es => \&canon_ie_es,
801            
802             # GO
803             canon_ie_go => \&canon_ie_go,
804            
805             # MA
806             test_ie_ma => \&test_ie_ma,
807             canon_ie_ma => \&canon_ie_ma,
808             format_ie_ma => \&format_ie_ma,
809             random_ie_ma => \&random_ie_ma,
810             parse_ie_ma => \&parse_ie_ma,
811            
812             # MG
813             test_ie_mg => \&test_ie_mg,
814             canon_ie_mg => \&canon_ie_mg,
815             format_ie_mg => \&format_ie_mg,
816             random_ie_mg => \&random_ie_mg,
817             parse_ie_mg => \&parse_ie_mg,
818            
819             # MT
820             canon_ie_mt => \&canon_ie_mt,
821            
822             # MS
823             canon_ie_ms => \&canon_ie_ms,
824            
825             # PE
826             canon_ie_pe => \&canon_ie_pe,
827            
828             # PA
829             canon_ie_pa => \&canon_ie_pa,
830            
831             # PB
832             canon_ie_pb => \&canon_ie_pb,
833            
834             # PI
835             canon_ie_pi => \&canon_ie_pi,
836            
837             # PR
838             test_ie_pr => \&test_ie_pr,
839             canon_ie_pr => \&canon_ie_pr,
840             format_ie_pr => \&format_ie_pr,
841             random_ie_pr => \&random_ie_pr,
842             parse_ie_pr => \&parse_ie_pr,
843            
844             # RJ
845             canon_ie_rj => \&canon_ie_rj,
846            
847             # RN
848             canon_ie_rn => \&canon_ie_rn,
849            
850             # RO
851             test_ie_ro => \&test_ie_ro,
852             canon_ie_ro => \&canon_ie_ro,
853             format_ie_ro => \&format_ie_ro,
854             random_ie_ro => \&random_ie_ro,
855             parse_ie_ro => \&parse_ie_ro,
856             # RR
857             test_ie_rr => \&test_ie_rr,
858             canon_ie_rr => \&canon_ie_rr,
859             format_ie_rr => \&format_ie_rr,
860             random_ie_rr => \&random_ie_rr,
861             parse_ie_rr => \&parse_ie_rr,
862             # RS
863             canon_ie_rs => \&canon_ie_rs,
864             # SC
865             canon_ie_sc => \&canon_ie_sc,
866             # SE
867             canon_ie_se => \&canon_ie_se,
868             # SP
869             test_ie_sp => \&test_ie_sp,
870             canon_ie_sp => \&canon_ie_sp,
871             format_ie_sp => \&format_ie_sp,
872             random_ie_sp => \&random_ie_sp,
873             #parse_ie_sp
874             # TO
875             canon_ie_to => \&canon_ie_to,
876            
877             );
878            
879             sub _invoke {
880 4484     4484   3786 my $subname = shift;
881 4484         5059 my $sub = $dispatch_table{$subname};
882 4484 50       7326 die "$subname not implemented" unless $sub;
883 4484         6526 return &$sub(@_);
884             }
885            
886             sub test_ie {
887 2246     2246 0 8452 my $uf = lc shift;
888 2246         4279 return _invoke("test_ie_$uf", @_);
889             }
890             sub canon_ie {
891 14     14 0 27 my $uf = lc shift;
892 14         32 return _invoke("canon_ie_$uf", @_);
893             }
894             sub format_ie {
895 13     13 0 27 my $uf = lc shift;
896 13         32 return _invoke("format_ie_$uf", @_);
897             }
898             sub random_ie {
899 2200     2200 0 688449 my $uf = lc shift;
900 2200         6269 return _invoke("random_ie_$uf", @_);
901             }
902            
903             sub parse_ie {
904 11     11 0 7255 my $uf = lc shift;
905 11         39 return _invoke("parse_ie_$uf", @_);
906             }
907            
908            
909            
910             1;
911            
912             __END__