File Coverage

blib/lib/WWW/Correios/SRO.pm
Criterion Covered Total %
statement 54 77 70.1
branch 20 50 40.0
condition 33 103 32.0
subroutine 8 11 72.7
pod 5 5 100.0
total 120 246 48.7


line stmt bran cond sub pod time code
1             package WWW::Correios::SRO;
2              
3 3     3   54981 use strict;
  3         8  
  3         75  
4 3     3   13 use warnings;
  3         7  
  3         79  
5              
6 3     3   738 use parent 'Exporter';
  3         522  
  3         14  
7             our @EXPORT_OK = qw( sro sro_en sro_ok sro_sigla status_da_entrega );
8              
9             our $VERSION = '0.11';
10             my $AGENT = 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)';
11             my $TIMEOUT = 30;
12              
13             # Verificado em 22 de Maio de 2017
14             # http://www.correios.com.br/para-voce/precisa-de-ajuda/como-rastrear-um-objeto/siglas-utilizadas-no-rastreamento-de-objeto
15             #
16             #
17             # Sabemos que as seguintes siglas são usadas: DH
18             # Como não existem na tabela dos correios, nao se encontra na hash.
19             # Um código com esse prefixo funcionará ao usar a funcao sro sem
20             # passar o parametro verifica_prefixo. Porém, se passar este
21             # parametro, deve retornar undef como qualquer SRO
22             # cujo prefixo não está previsto na tabela dos Correios.
23             my %siglas = (
24             AL => 'AGENTES DE LEITURA',
25             AR => 'AVISO DE RECEBIMENTO',
26             AS => 'ENCOMENDA PAC – AÇÃO SOCIAL',
27             BE => 'REMESSA ECONÔMICA TALÃO/CARTÃO (SEM AR DIGITAL)',
28             CA => 'ENCOMENDA INTERNACIONAL - COLIS',
29             CB => 'ENCOMENDA INTERNACIONAL - COLIS',
30             CC => 'ENCOMENDA INTERNACIONAL - COLIS',
31             CD => 'ENCOMENDA INTERNACIONAL - COLIS',
32             CE => 'ENCOMENDA INTERNACIONAL - COLIS',
33             CF => 'ENCOMENDA INTERNACIONAL - COLIS',
34             CG => 'ENCOMENDA INTERNACIONAL - COLIS',
35             CH => 'ENCOMENDA INTERNACIONAL - COLIS',
36             CI => 'ENCOMENDA INTERNACIONAL - COLIS',
37             CJ => 'ENCOMENDA INTERNACIONAL - COLIS',
38             CK => 'ENCOMENDA INTERNACIONAL - COLIS',
39             CL => 'ENCOMENDA INTERNACIONAL - COLIS',
40             CM => 'ENCOMENDA INTERNACIONAL - COLIS',
41             CN => 'ENCOMENDA INTERNACIONAL - COLIS',
42             CO => 'ENCOMENDA INTERNACIONAL - COLIS',
43             CP => 'ENCOMENDA INTERNACIONAL - COLIS',
44             CQ => 'ENCOMENDA INTERNACIONAL - COLIS',
45             CR => 'CARTA REGISTRADA SEM VALOR DECLARADO',
46             CS => 'ENCOMENDA INTERNACIONAL - COLIS',
47             CT => 'ENCOMENDA INTERNACIONAL - COLIS',
48             CU => 'ENCOMENDA INTERNACIONAL - COLIS',
49             CV => 'ENCOMENDA INTERNACIONAL - COLIS',
50             CW => 'ENCOMENDA INTERNACIONAL - COLIS',
51             CX => 'ENCOMENDA INTERNACIONAL - COLIS OU SELO LACRE PARA CAIXETAS',
52             CY => 'ENCOMENDA INTERNACIONAL - COLIS',
53             CZ => 'ENCOMENDA INTERNACIONAL - COLIS',
54             DA => 'SEDEX OU REMESSA EXPRESSA COM AR DIGITAL',
55             DB => 'SEDEX OU REMESSA EXPRESSA COM AR DIGITAL (BRADESCO)',
56             DC => 'REMESSA EXPRESSA CRLV/CRV/CNH e NOTIFICAÇÕES',
57             DD => 'DEVOLUÇÃO DE DOCUMENTOS',
58             DE => 'REMESSA EXPRESSA TALÃO/CARTÃO COM AR',
59             DF => 'E-SEDEX',
60             DG => 'SEDEX',
61             DI => 'SEDEX OU REMESSA EXPRESSA COM AR DIGITAL (ITAU)',
62             DJ => 'SEDEX',
63             DK => 'PAC EXTRA GRANDE',
64             DL => 'SEDEX',
65             DM => 'E-SEDEX',
66             DN => 'SEDEX',
67             DO => 'SEDEX OU REMESSA EXPRESSA COM AR DIGITAL (ITAU)',
68             DP => 'SEDEX PAGAMENTO NA ENTREGA',
69             DQ => 'SEDEX OU REMESSA EXPRESSA COM AR DIGITAL (BRADESCO)',
70             DR => 'REMESSA EXPRESSA COM AR DIGITAL (SANTANDER)',
71             DS => 'SEDEX OU REMESSA EXPRESSA COM AR DIGITAL (SANTANDER)',
72             DT => 'REMESSA ECONÔMICA COM AR DIGITAL (DETRAN)',
73             DU => 'E-SEDEX',
74             DV => 'SEDEX COM AR DIGITAL',
75             DW => 'ENCOMENDA SEDEX (ETIQUETA LÓGICA)',
76             DX => 'SEDEX 10',
77             EA => 'ENCOMENDA INTERNACIONAL - EMS',
78             EB => 'ENCOMENDA INTERNACIONAL - EMS',
79             EC => 'PAC',
80             ED => 'PACKET EXPRESS',
81             EE => 'ENCOMENDA INTERNACIONAL - EMS',
82             EF => 'ENCOMENDA INTERNACIONAL - EMS',
83             EG => 'ENCOMENDA INTERNACIONAL - EMS',
84             EH => 'ENCOMENDA INTERNACIONAL - EMS OU ENCOMENDA COM AR DIGITAL',
85             EI => 'ENCOMENDA INTERNACIONAL - EMS',
86             EJ => 'ENCOMENDA INTERNACIONAL - EMS',
87             EK => 'ENCOMENDA INTERNACIONAL - EMS',
88             EL => 'ENCOMENDA INTERNACIONAL - EMS',
89             EM => 'ENCOMENDA INTERNACIONAL - SEDEX MUNDI OU EMS IMPORTAÇÃO',
90             EN => 'ENCOMENDA INTERNACIONAL - EMS',
91             EO => 'ENCOMENDA INTERNACIONAL - EMS',
92             EP => 'ENCOMENDA INTERNACIONAL - EMS',
93             EQ => 'ENCOMENDA DE SERVIÇO NÃO EXPRESSA (ECT)',
94             ER => 'OBJETO REGISTRADO',
95             ES => 'E-SEDEX OU EMS',
96             ET => 'ENCOMENDA INTERNACIONAL - EMS',
97             EU => 'ENCOMENDA INTERNACIONAL - EMS',
98             EV => 'ENCOMENDA INTERNACIONAL - EMS',
99             EW => 'ENCOMENDA INTERNACIONAL - EMS',
100             EX => 'ENCOMENDA INTERNACIONAL - EMS',
101             EY => 'ENCOMENDA INTERNACIONAL - EMS',
102             EZ => 'ENCOMENDA INTERNACIONAL - EMS',
103             FA => 'FAC REGISTRADO',
104             FE => 'ENCOMENDA FNDE',
105             FF => 'OBJETO REGISTRADO (DETRAN)',
106             FH => 'FAC REGISTRADO COM AR DIGITAL',
107             FM => 'FAC MONITORADO',
108             FR => 'FAC REGISTRADO',
109             IA => 'LOGÍSTICA INTEGRADA (AGENDADO/AVULSO)',
110             IC => 'LOGÍSTICA INTEGRADA (A COBRAR)',
111             ID => 'LOGÍSTICA INTEGRADA (DEVOLUCAO DE DOCUMENTO)',
112             IE => 'LOGÍSTICA INTEGRADA (ESPECIAL)',
113             IF => 'CPF',
114             II => 'LOGÍSTICA INTEGRADA (ECT)',
115             IK => 'LOGÍSTICA INTEGRADA COM COLETA SIMULTÂNEA',
116             IM => 'LOGÍSTICA INTEGRADA (MEDICAMENTOS)',
117             IN => 'CORRESPONDÊNCIA E EMS RECEBIDO DO EXTERIOR',
118             IP => 'LOGÍSTICA INTEGRADA (PROGRAMADA)',
119             IR => 'IMPRESSO REGISTRADO',
120             IS => 'LOGÍSTICA INTEGRADA STANDARD (MEDICAMENTOS)',
121             IT => 'REMESSA EXPRESSA MEDICAMENTOS / LOGÍSTICA INTEGRADA TERMOLÁBIL',
122             IU => 'LOGÍSTICA INTEGRADA (URGENTE)',
123             IX => 'EDEI EXPRESSO',
124             JA => 'REMESSA ECONOMICA COM AR DIGITAL',
125             JB => 'REMESSA ECONOMICA COM AR DIGITAL',
126             JC => 'REMESSA ECONOMICA COM AR DIGITAL',
127             JD => 'REMESSA ECONOMICA TALÃO/CARTÃO',
128             JE => 'REMESSA ECONÔMICA COM AR DIGITAL',
129             JF => 'REMESSA ECONÔMICA COM AR DIGITAL',
130             JG => 'OBJETO REGISTRADO URGENTE/PRIORITÁRIO',
131             JH => 'OBJETO REGISTRADO URGENTE/PRIORITÁRIO',
132             JI => 'REMESSA ECONÔMICA TALÃO/CARTÃO',
133             JJ => 'OBJETO REGISTRADO (JUSTIÇA)',
134             JK => 'REMESSA ECONÔMICA TALÃO/CARTÃO',
135             JL => 'OBJETO REGISTRADO',
136             JM => 'MALA DIRETA POSTAL ESPECIAL',
137             JN => 'OBJETO REGISTRADO ECONÔMICO',
138             JO => 'OBJETO REGISTRADO URGENTE',
139             JP => 'RECEITA FEDERAL',
140             JQ => 'REMESSA ECONÔMICA COM AR DIGITAL',
141             JR => 'OBJETO REGISTRADO URGENTE/PRIORITÁRIO',
142             JS => 'OBJETO REGISTRADO',
143             JT => 'OBJETO REGISTRADO URGENTE',
144             JV => 'REMESSA ECONÔMICA COM AR DIGITAL',
145             LA => 'SEDEX COM LOGÍSTICA REVERSA SIMULTÂNEA EM AGÊNCIA',
146             LB => 'E-SEDEX COM LOGÍSTICA REVERSA SIMULTÂNEA EM AGÊNCIA',
147             LC => 'OBJETO INTERNACIONAL (PRIME)',
148             LE => 'LOGÍSTICA REVERSA ECONOMICA',
149             LF => 'OBJETO INTERNACIONAL (PRIME)',
150             LI => 'OBJETO INTERNACIONAL (PRIME)',
151             LJ => 'OBJETO INTERNACIONAL (PRIME)',
152             LK => 'OBJETO INTERNACIONAL (PRIME)',
153             LM => 'OBJETO INTERNACIONAL (PRIME)',
154             LN => 'OBJETO INTERNACIONAL (PRIME)',
155             LP => 'PAC COM LOGÍSTICA REVERSA SIMULTÂNEA EM AGÊNCIA',
156             LS => 'SEDEX LOGISTICA REVERSA',
157             LV => 'LOGISTICA REVERSA EXPRESSA',
158             LX => 'PACKET STANDARD/ECONÔMICA',
159             LZ => 'OBJETO INTERNACIONAL (PRIME)',
160             MA => 'SERVIÇOS ADICIONAIS DO TELEGRAMA',
161             MB => 'TELEGRAMA (BALCÃO)',
162             MC => 'TELEGRAMA (FONADO)',
163             MD => 'SEDEX MUNDI (DOCUMENTO INTERNO)',
164             ME => 'TELEGRAMA',
165             MF => 'TELEGRAMA FONADO',
166             MK => 'TELEGRAMA (CORPORATIVO)',
167             ML => 'FECHA MALAS (RABICHO)',
168             MM => 'TELEGRAMA (GRANDES CLIENTES)',
169             MP => 'TELEGRAMA (PRÉ-PAGO)',
170             MR => 'AR DIGITAL',
171             MS => 'ENCOMENDA SAUDE',
172             MT => 'TELEGRAMA (TELEMAIL)',
173             MY => 'TELEGRAMA INTERNACIONAL (ENTRANTE)',
174             MZ => 'TELEGRAMA (CORREIOS ONLINE)',
175             NE => 'TELE SENA RESGATADA',
176             NX => 'EDEI ECONÔMICO (NÃO URGENTE)',
177             OA => 'ENCOMENDA SEDEX',
178             OB => 'ENCOMENDA E-SEDEX',
179             PA => 'PASSAPORTE',
180             PB => 'PAC',
181             PC => 'PAC A COBRAR',
182             PD => 'PAC',
183             PE => 'PAC',
184             PF => 'PASSAPORTE',
185             PG => 'PAC',
186             PH => 'PAC',
187             PI => 'PAC',
188             PJ => 'PAC',
189             PK => 'PAC EXTRA GRANDE',
190             PL => 'PAC',
191             PN => 'PAC',
192             PR => 'REEMBOLSO POSTAL',
193             QQ => 'OBJETO DE TESTE (SIGEP WEB)',
194             RA => 'OBJETO REGISTRADO/PRIORITÁRIO',
195             RB => 'CARTA REGISTRADA',
196             RC => 'CARTA REGISTRADA COM VALOR DECLARADO',
197             RD => 'REMESSA ECONOMICA OU OBJETO REGISTRADO (DETRAN)',
198             RE => 'OBJETO REGISTRADO ECONÔMICO',
199             RF => 'RECEITA FEDERAL',
200             RG => 'OBJETO REGISTRADO',
201             RH => 'OBJETO REGISTRADO COM AR DIGITAL',
202             RI => 'OBJETO REGISTRADO INTERNACIONAL PRIORITÁRIO',
203             RJ => 'OBJETO REGISTRADO',
204             RK => 'OBJETO REGISTRADO',
205             RL => 'OBJETO REGISTRADO',
206             RM => 'OBJETO REGISTRADO URGENTE',
207             RN => 'OBJETO REGISTRADO (SIGEPWEB OU AGÊNCIA)',
208             RO => 'OBJETO REGISTRADO',
209             RP => 'REEMBOLSO POSTAL',
210             RQ => 'OBJETO REGISTRADO',
211             RR => 'OBJETO REGISTRADO',
212             RS => 'OBJETO REGISTRADO',
213             RT => 'REMESSA ECONÔMICA TALÃO/CARTAO',
214             RU => 'OBJETO REGISTRADO (ECT)',
215             RV => 'REMESSA ECONÔMICA CRLV/CRV/CNH E NOTIFICAÇÕES COM AR DIGITAL',
216             RW => 'OBJETO INTERNACIONAL',
217             RX => 'OBJETO INTERNACIONAL',
218             RY => 'REMESSA ECONÔMICA TALÃO/CARTÃO COM AR DIGITAL',
219             RZ => 'OBJETO REGISTRADO',
220             SA => 'SEDEX',
221             SB => 'SEDEX 10',
222             SC => 'SEDEX A COBRAR',
223             SD => 'SEDEX OU REMESSA EXPRESSA (DETRAN)',
224             SE => 'SEDEX',
225             SF => 'SEDEX',
226             SG => 'SEDEX',
227             SH => 'SEDEX COM AR DIGITAL / SEDEX OU AR DIGITAL',
228             SI => 'SEDEX',
229             SJ => 'SEDEX HOJE',
230             SK => 'SEDEX',
231             SL => 'SEDEX',
232             SM => 'SEDEX 12',
233             SN => 'SEDEX',
234             SO => 'SEDEX',
235             SP => 'SEDEX PRÉ-FRANQUEADO',
236             SQ => 'SEDEX',
237             SR => 'SEDEX',
238             SS => 'SEDEX',
239             ST => 'REMESSA EXPRESSA TALÃO/CARTÃO',
240             SU => 'ENCOMENDA DE SERVIÇO EXPRESSA (ECT)',
241             SV => 'REMESSA EXPRESSA CRLV/CRV/CNH E NOTIFICAÇÕES COM AR DIGITAL',
242             SW => 'E-SEDEX',
243             SX => 'SEDEX 10',
244             SY => 'REMESSA EXPRESSA TALÃO/CARTÃO COM AR DIGITAL',
245             SZ => 'SEDEX',
246             TC => 'OBJETO PARA TREINAMENTO',
247             TE => 'OBJETO PARA TREINAMENTO',
248             TS => 'OBJETO PARA TREINAMENTO',
249             VA => 'ENCOMENDAS COM VALOR DECLARADO',
250             VC => 'ENCOMENDAS',
251             VD => 'ENCOMENDAS COM VALOR DECLARADO',
252             VE => 'ENCOMENDAS',
253             VF => 'ENCOMENDAS COM VALOR DECLARADO',
254             VV => 'OBJETO INTERNACIONAL',
255             XA => 'AVISO DE CHEGADA (INTERNACIONAL)',
256             XM => 'SEDEX MUNDI',
257             XR => 'ENCOMENDA SUR POSTAL EXPRESSO',
258             XX => 'ENCOMENDA SUR POSTAL 24 HORAS',
259             );
260              
261             # http://www.correios.com.br/para-sua-empresa/servicos-para-o-seu-contrato/guias/enderecamento/arquivos/guia_tecnico_encomendas.pdf/at_download/file
262             sub sro_ok {
263 19 100   19 1 1114 if ( $_[0] =~ m/^[A-Z|a-z]{2}([0-9]{8})([0-9])BR$/i ) {
264 11         41 my ( $numeros, $dv ) = ($1, $2);
265 11         42 my @numeros = split // => $numeros;
266 11         28 my @magica = ( 8, 6, 4, 2, 3, 5, 9, 7 );
267              
268 11         15 my $soma = 0;
269 11         24 foreach ( 0 .. 7 ) {
270 88         156 $soma += ( $numeros[$_] * $magica[$_] );
271             }
272              
273 11         19 my $resto = $soma % 11;
274 11 50       29 my $dv_check = $resto == 0 ? 5
    50          
275             : $resto == 1 ? 0
276             : 11 - $resto
277             ;
278 11         57 return $dv == $dv_check;
279             }
280             else {
281 8         31 return;
282             }
283             }
284              
285             sub sro_sigla {
286 8 100   8 1 1473 if ( sro_ok( @_ ) ) {
287 4         14 $_[0] =~ m/^([A-Z|a-z]{2}).*$/i;
288 4         9 my $prefixo = $1;
289 4         24 return $siglas{$prefixo};
290             } else {
291 4         17 return;
292             }
293             }
294              
295 0     0 1 0 sub sro { _sro('101', @_) }
296 0     0 1 0 sub sro_en { _sro('102', @_) }
297              
298             sub _sro {
299 0     0   0 my ($language, $code, $params) = @_;
300 0 0 0     0 return unless $code && sro_ok( $code );
301              
302 0 0       0 if ($params->{verifica_prefixo}) {
303 0         0 my $prefixo = sro_sigla( $code );
304 0 0       0 return unless defined $prefixo;
305             }
306              
307 0         0 my $agent = $params->{ua};
308 0 0       0 if (!$agent) {
309 0         0 require LWP::UserAgent;
310             $agent = LWP::UserAgent->new(
311             agent => $AGENT,
312 0 0       0 timeout => (exists $params->{timeout} ? $params->{timeout} : $TIMEOUT),
313             );
314             }
315              
316 0 0       0 my $results = wantarray ? 'T' : 'U';
317 0   0     0 my $user = $params->{username} || 'ECT';
318 0   0     0 my $pass = $params->{password} || 'SRO';
319              
320             # http://www.correios.com.br/para-voce/correios-de-a-a-z/pdf/rastreamento-de-objetos/manual_rastreamentoobjetosws.pdf
321 0         0 my $response = $agent->post(
322             'http://webservice.correios.com.br:80/service/rastro',
323             'Content-Type' => 'text/xml;charset=utf-8',
324             'SOAPAction' => 'buscaEventos',
325             'Content' => qq{
326             $user$passL$results$language$code}
327             );
328 0 0       0 return unless $response->is_success;
329              
330 0         0 my $data = _parse_response($response->content);
331 0 0       0 return $results eq 'T' ? @$data : $data->[0];
332             }
333              
334             sub _parse_response {
335 1     1   8 my ($content) = @_;
336 1 50       16 return unless $content =~ m{(.+)}si;
337              
338 1         2 my @events;
339 1         4 my $object = $1;
340 1         9 while ($object =~ m{(.+?)}gi) {
341 4         10 my $event = $1;
342 4         8 my $params = _parse_event($event);
343              
344 4         20 push @events, $params;
345             }
346 1         3 return \@events;
347             }
348              
349             sub _parse_event {
350 58     58   98 my ($event) = @_;
351              
352 58 100       311 return $event if index($event, '<') < 0;
353              
354 7         12 my %params;
355 7         30 while ($event =~ m{<\s*([^>]+)\s*>\s*(.+?)\s*<\s*/\s*\1\s*>}g) {
356 54         129 my ($key, $value) = ($1, $2);
357 54         94 $params{$key} = _parse_event($value);
358             }
359 7         18 return \%params;
360             }
361              
362             sub status_da_entrega {
363 5     5 1 1361 my ($data) = @_;
364 5 50 33     59 die 'entrega_concluida() takes a HASHREF or ARRAYREF'
      33        
      33        
365             unless $data && ref $data && (ref $data eq 'ARRAY' || ref $data eq 'HASH');
366              
367 5 50       15 my $last = ref $data eq 'ARRAY' ? $data->[0] : $data;
368 5 50       15 return unless $last;
369              
370             # objeto dos Correios tem as mesmas chaves, independente do idioma.
371 5 50 33     45 if (!ref $last || ref $last ne 'HASH' || !exists $last->{tipo} || !exists $last->{status}) {
      33        
      33        
372 0         0 warn "status_da_entrega() data looks invalid. Missing keys?";
373 0         0 return;
374             }
375 5         9 my $tipo = $last->{tipo};
376 5         11 my $status = $last->{status};
377 5 50 33     33 if ($tipo eq 'BDR' || $tipo eq 'BDE' || $tipo eq 'BDI') {
    0 33        
    0 0        
      0        
      0        
      0        
      0        
378             # estado final. entrega efetuada!
379 5 100       21 return 'entregue' if $status <= 1;
380              
381             # acionar correios (produto extraviado, etc).
382 4 50 66     64 return 'erro' if $status == 9 || $status == 12 || $status == 28
      66        
      33        
      33        
      33        
      33        
      33        
      33        
383             || $status == 37 || $status == 43 || $status == 50
384             || $status == 51 || $status == 52 || $status == 80
385             ;
386              
387             # pacote aguardando retirada pelo interessado.
388 3 100 66     17 return 'retirar' if $status == 54 || $status == 2;
389              
390             # entrega incompleta, pacote retornando.
391 2 50 33     36 return 'incompleto'
      66        
      66        
      66        
      33        
      33        
      33        
      33        
      33        
      33        
392             if ( ($status != 20 && $status != 7 && $status <= 21)
393             || $status == 26 || $status == 33 || $status == 36
394             || $status == 40 || $status == 42 || $status == 48
395             || $status == 49 || $status == 56
396             );
397              
398 1         4 return 'acompanhar';
399             }
400             elsif ($tipo eq 'FC' && $status == 1) {
401 0           return 'incompleto';
402             }
403             elsif (
404             # pacote aguardando retirada.
405             ($tipo eq 'LDI' && ($status <= 3 || $status == 14))
406             || ($tipo eq 'OEC' && $status == 0)
407             ) {
408 0           return 'retirar';
409             }
410             else {
411 0           return 'acompanhar';
412             }
413             }
414              
415              
416             42;
417             __END__