├── .gitignore
├── phpcs.xml
├── composer.json
├── src
├── Adapters
│ ├── AdapterInterface.php
│ └── GuzzleAdapter.php
├── Calculo.php
└── Correios.php
├── phpunit.xml.dist
├── LICENSE.md
├── tests
├── CalculoTest.php
└── CorreiosTest.php
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | vendor/
2 | build/
3 | composer.lock
4 | composer.phar
5 | phpunit.xml
6 | php.ini
--------------------------------------------------------------------------------
/phpcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Ruleset personalizado
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "eberfreitas/correios",
3 | "description": "Um pacote para interagir com serviços dos Correios",
4 | "homepage": "https://github.com/eberfreitas/correios",
5 | "type": "library",
6 | "require": {
7 | "tburry/pquery": "1.*",
8 | "guzzlehttp/guzzle": "5.*"
9 | },
10 | "require-dev": {
11 | "phpunit/phpunit" : "4.*",
12 | "squizlabs/php_codesniffer": "*"
13 | },
14 | "license": "MIT",
15 | "authors": [
16 | {
17 | "name": "Éber Freitas Dias",
18 | "email": "eber.freitas@gmail.com"
19 | }
20 | ],
21 | "autoload": {
22 | "psr-4": {
23 | "Correios\\": "src"
24 | }
25 | },
26 | "autoload-dev": {
27 | "psr-4": {
28 | "Correios\\Test\\": "tests"
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/src/Adapters/AdapterInterface.php:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
14 | tests
15 |
16 |
17 |
18 |
19 | src/
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Éber F. Dias
4 |
5 | > Permission is hereby granted, free of charge, to any person obtaining a copy
6 | > of this software and associated documentation files (the "Software"), to deal
7 | > in the Software without restriction, including without limitation the rights
8 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | > copies of the Software, and to permit persons to whom the Software is
10 | > furnished to do so, subject to the following conditions:
11 | >
12 | > The above copyright notice and this permission notice shall be included in
13 | > all copies or substantial portions of the Software.
14 | >
15 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | > THE SOFTWARE.
--------------------------------------------------------------------------------
/tests/CalculoTest.php:
--------------------------------------------------------------------------------
1 | calculo = new Calculo($data);
28 | }
29 |
30 | public function tearDown()
31 | {
32 | $this->calculo = null;
33 | }
34 |
35 | public function testCalculaEntrega()
36 | {
37 | $date = new \DateTime('2015-05-07');
38 | $end = $this->calculo->calculaEntrega($date);
39 | $interval = $end->diff($date);
40 |
41 | $this->assertEquals('11', $interval->format('%a'));
42 | }
43 |
44 | public function testFormataValor()
45 | {
46 | $formated = $this->calculo->formataValor('valor');
47 | $this->assertEquals('R$ 15,50', $formated);
48 |
49 | $formated = $this->calculo->formataValor('valor', false);
50 | $this->assertEquals('15,50', $formated);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/Adapters/GuzzleAdapter.php:
--------------------------------------------------------------------------------
1 | $query];
26 | $options += $defaultOptions;
27 | $request = $client->get($url, $options);
28 | $response = (string)$request->getBody();
29 | return $response;
30 | }
31 |
32 | /**
33 | * Makes POST requests
34 | *
35 | * @param string $url O endereço da requisição.
36 | * @param array $body Array com as chaves e valores do corpo da requisição.
37 | * @param array $options Array com outras opções que possam ser usadas
38 | * pelo adapter na hora de realizar a requisição.
39 | *
40 | * @return string
41 | */
42 | public function post($url, array $body, array $options = [])
43 | {
44 | $client = new Client();
45 | $defaultOptions = ['body' => $body];
46 | $options += $defaultOptions;
47 | $request = $client->post($url, $options);
48 | $response = (string)$request->getBody();
49 | return $response;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/tests/CorreiosTest.php:
--------------------------------------------------------------------------------
1 | setAccessible(true);
16 | return $method->invokeArgs($obj, $args);
17 | }
18 |
19 | public function setUp()
20 | {
21 | $this->correios = new Correios();
22 | }
23 |
24 | public function tearDown()
25 | {
26 | $this->correios = null;
27 | }
28 |
29 | public function testConstructor()
30 | {
31 | $this->assertInstanceOf('\Correios\Correios', $this->correios);
32 | }
33 |
34 | public function testRastreamento()
35 | {
36 | $response = $this->correios->rastreamento('PE024442250BR');
37 |
38 | $this->assertNotEmpty($response);
39 | }
40 |
41 | /**
42 | * @expectedException InvalidArgumentException
43 | */
44 | public function testRastreamentoInvalido()
45 | {
46 | $response = $this->correios->rastreamento('HAHAHA');
47 | }
48 |
49 | /**
50 | * @expectedException RuntimeException
51 | */
52 | public function testRastreamentoInexistente()
53 | {
54 | $response = $this->correios->rastreamento('AA000000000AA');
55 | }
56 |
57 | public function testCalculaFrete()
58 | {
59 | $config = [
60 | 'usuario' => null,
61 | 'senha' => null,
62 | 'servicos' => [Correios::SEDEX, Correios::PAC],
63 | 'cep_origem' => '08820400',
64 | 'cep_destino' => '21832150',
65 | 'peso' => 0.3,
66 | 'formato' => Correios::CAIXA,
67 | 'comprimento' => 16,
68 | 'altura' => 2,
69 | 'largura' => 11,
70 | 'diametro' => 5,
71 | 'mao_propria' => false,
72 | 'valor_declarado' => 0,
73 | 'aviso_recebimento' => false
74 | ];
75 |
76 | $data = $this->correios->calculaFrete($config);
77 |
78 | $this->assertEquals(2, count($data));
79 | $this->assertEquals('SEDEX', $data[0]->servico_descricao);
80 | $this->assertEquals('40010', $data[0]['codigo']);
81 | }
82 |
83 | /**
84 | * @expectedException InvalidArgumentException
85 | */
86 | public function testEnderecoInvalido()
87 | {
88 | $data = $this->correios->endereco('nooooo');
89 | }
90 |
91 | /**
92 | * @expectedException RuntimeException
93 | */
94 | public function testEnderecoInexistente()
95 | {
96 | $data = $this->correios->endereco('00000000');
97 | }
98 |
99 | public function testEndereco()
100 | {
101 | $data = $this->correios->endereco('08820400');
102 | $this->assertNotEmpty($data);
103 | $this->assertEquals('Rua Nilo Garcia Alabarce', $data['logradouro']);
104 | $this->assertNull($data['logradouro_extra']);
105 |
106 | $data = $this->correios->endereco('28970000');
107 | $this->assertNotEmpty($data);
108 | $this->assertNull($data['logradouro']);
109 | $this->assertEquals('RJ', $data['uf']);
110 | $this->assertEquals('Araruama', $data['cidade']);
111 |
112 | $data = $this->correios->endereco('58030000');
113 | $this->assertNotEmpty($data);
114 | $this->assertNotNull($data['logradouro_extra']);
115 | $this->assertEquals('Avenida Presidente Epitácio Pessoa', $data['logradouro']);
116 | }
117 |
118 | public function testAjustaPacote()
119 | {
120 | $params = [
121 | 'nVlPeso' => 0.3,
122 | 'nCdFormato' => 1,
123 | 'nVlDiametro' => 0,
124 | 'nVlComprimento' => 16,
125 | 'nVlLargura' => 11,
126 | 'nVlAltura' => 2
127 | ];
128 |
129 | $result = $this->runProtectedMethod($this->correios, 'ajustaPacote', [$params]);
130 | $this->assertEquals($result, $params);
131 |
132 | $params = [
133 | 'nVlPeso' => 200,
134 | 'nCdFormato' => 1,
135 | 'nVlDiametro' => 200,
136 | 'nVlComprimento' => 200,
137 | 'nVlLargura' => 200,
138 | 'nVlAltura' => 200
139 | ];
140 |
141 | $result = $this->runProtectedMethod($this->correios, 'ajustaPacote', [$params]);
142 |
143 | $expected = [
144 | 'nVlPeso' => 30,
145 | 'nCdFormato' => 1,
146 | 'nVlDiametro' => 0,
147 | 'nVlComprimento' => 66,
148 | 'nVlLargura' => 66,
149 | 'nVlAltura' => 66
150 | ];
151 |
152 | $this->assertEquals($result, $expected);
153 |
154 | $params = [
155 | 'nVlPeso' => 1,
156 | 'nCdFormato' => 2,
157 | 'nVlDiametro' => 5,
158 | 'nVlComprimento' => 18,
159 | 'nVlLargura' => 0,
160 | 'nVlAltura' => 0
161 | ];
162 |
163 | $result = $this->runProtectedMethod($this->correios, 'ajustaPacote', [$params]);
164 | $this->assertEquals($result, $params);
165 |
166 | $params = [
167 | 'nVlPeso' => 0.150,
168 | 'nCdFormato' => 2,
169 | 'nVlDiametro' => 200,
170 | 'nVlComprimento' => 200,
171 | 'nVlLargura' => 200,
172 | 'nVlAltura' => 200
173 | ];
174 |
175 | $result = $this->runProtectedMethod($this->correios, 'ajustaPacote', [$params]);
176 |
177 | $expected = [
178 | 'nVlPeso' => 0.3,
179 | 'nCdFormato' => 2,
180 | 'nVlDiametro' => 62,
181 | 'nVlComprimento' => 76,
182 | 'nVlLargura' => 0,
183 | 'nVlAltura' => 0
184 | ];
185 |
186 | $this->assertEquals($result, $expected);
187 | }
188 | }
189 |
--------------------------------------------------------------------------------
/src/Calculo.php:
--------------------------------------------------------------------------------
1 | 'Aerograma',
18 | '10014' => 'Carta Registrada',
19 | '10030' => 'Carta Simples',
20 | '16012' => 'Cartão Postal',
21 | '81019' => 'e-SEDEX',
22 | '20010' => 'Impresso',
23 | '14036' => 'Mala Direta Postal Domiciliar',
24 | '14010' => 'Mala Direta Postal Não Urgente',
25 | '14028' => 'Mala Direta Postal Urgente',
26 | '44105' => 'Malote',
27 | '41106' => 'PAC',
28 | '41300' => 'PAC Grandes Formatos',
29 | '41262' => 'PAC Pagamento na Entrega',
30 | '43010' => 'Reembolso Postal',
31 | '40010' => 'SEDEX',
32 | '40215' => 'SEDEX 10',
33 | '40169' => 'SEDEX 12',
34 | '40290' => 'SEDEX HOJE',
35 | '40819' => 'SEDEX Pagamento na Entrega'
36 | ];
37 |
38 | /**
39 | * Construtor da classe.
40 | *
41 | * @param array $data Os dados referentes ao cálculo de frete.
42 | *
43 | * @throws \InvalidArgumentException Se não for fornecido um array válido.
44 | *
45 | * @return void
46 | */
47 | public function __construct(array $data = [])
48 | {
49 | if (empty($data)) {
50 | throw new \InvalidArgumentException('É necessário fornecer os dados de envio!');
51 | }
52 |
53 | $propertiesMap = [
54 | 'Codigo' => 'codigo',
55 | 'Valor' => 'valor',
56 | 'PrazoEntrega' => 'prazo_entrega',
57 | 'ValorSemAdicionais' => 'valor_sem_adicionais',
58 | 'ValorMaoPropria' => 'valor_mao_propria',
59 | 'ValorAvisoRecebimento' => 'valor_aviso_recebimento',
60 | 'ValorValorDeclarado' => 'valor_valor_declarado',
61 | 'EntregaDomiciliar' => 'entrega_domiciliar',
62 | 'EntregaSabado' => 'entrega_sabado',
63 | 'Erro' => 'erro',
64 | 'MsgErro' => 'msg_erro'
65 | ];
66 |
67 | $newSet = [];
68 |
69 | foreach ($propertiesMap as $old => $new) {
70 | $newSet[$new] = $data[$old];
71 | }
72 |
73 | $fixValue = function ($value) {
74 | $value = str_replace(',', '', $value);
75 | return (int)$value / 100;
76 | };
77 |
78 | $newSet['valor'] = $fixValue($newSet['valor']);
79 | $newSet['valor_sem_adicionais'] = $fixValue($newSet['valor_sem_adicionais']);
80 | $newSet['valor_mao_propria'] = $fixValue($newSet['valor_mao_propria']);
81 | $newSet['valor_aviso_recebimento'] = $fixValue($newSet['valor_aviso_recebimento']);
82 | $newSet['valor_valor_declarado'] = $fixValue($newSet['valor_valor_declarado']);
83 | $newSet['entrega_domiciliar'] = $newSet['entrega_domiciliar'] === 'S' ? true : false;
84 | $newSet['entrega_sabado'] = $newSet['entrega_sabado'] === 'S' ? true : false;
85 | $newSet['servico_descricao'] = $this->serviceMap[$newSet['codigo']];
86 |
87 | $this->raw = $newSet;
88 | }
89 |
90 | /**
91 | * Calcula a data de entrega baseado nos dados de cálculo e numa data
92 | * de envio específica.
93 | *
94 | * @param \DateTime $date Define a data de envio do pacote.
95 | *
96 | * @return \DateTime Objeto que representa a data de entrega estimada.
97 | */
98 | public function calculaEntrega(\DateTime $date)
99 | {
100 | $toSend = clone $date;
101 | $toSend->modify('+' . $this->raw['prazo_entrega'] . ' days');
102 | $weekDay = (int)$toSend->format('N');
103 |
104 | if ($weekDay === 6 && $this->raw['entrega_sabado'] === false) {
105 | $toSend->modify('+2 days');
106 | } elseif ($weekDay === 7) {
107 | $toSend->modify('+1 days');
108 | }
109 |
110 | return $toSend;
111 | }
112 |
113 | /**
114 | * Formata um valor calculado de acordo com a regra de formatação monetária.
115 | *
116 | * @param string $value Chave do valor a ser formatado.
117 | * @param boolean $prefix Coloca ou não o prefix `R$` na frente do valor
118 | * formatado.
119 | *
120 | * @throws \InvalidArgumentException Se o valor a ser formatado não existir.
121 | *
122 | * @return string Valor formatado.
123 | */
124 | public function formataValor($value, $prefix = true)
125 | {
126 | $whitelist = [
127 | 'valor',
128 | 'valor_sem_adicionais',
129 | 'valor_mao_propria',
130 | 'valor_aviso_recebimento',
131 | 'valor_valor_declarado'
132 | ];
133 |
134 | if (!in_array($value, $whitelist)) {
135 | throw new \InvalidArgumentException('Escolha uma chave de valor válida para formatar!');
136 | }
137 |
138 | $pf = $prefix === true ? 'R$ ' : '';
139 |
140 | return $pf . number_format($this->raw[$value], 2, ',', '.');
141 | }
142 |
143 | /**
144 | * Offset to set.
145 | *
146 | * @param mixed $offset Offset.
147 | * @param mixed $value Value.
148 | *
149 | * @return void
150 | */
151 | public function offsetSet($offset, $value)
152 | {
153 | if (is_null($offset)) {
154 | $this->raw[] = $value;
155 | } else {
156 | $this->raw[$offset] = $value;
157 | }
158 | }
159 |
160 | /**
161 | * Whether an offset exists.
162 | *
163 | * @param mixed $offset Offset.
164 | *
165 | * @return boolean
166 | */
167 | public function offsetExists($offset)
168 | {
169 | return isset($this->raw[$offset]);
170 | }
171 |
172 | /**
173 | * Offset to unset.
174 | *
175 | * @param mixed $offset Offset.
176 | *
177 | * @return void
178 | */
179 | public function offsetUnset($offset)
180 | {
181 | unset($this->raw[$offset]);
182 | }
183 |
184 | /**
185 | * Offset to retrieve.
186 | *
187 | * @param mixed $offset Offset.
188 | *
189 | * @return mixed
190 | */
191 | public function offsetGet($offset)
192 | {
193 | return isset($this->raw[$offset]) ? $this->raw[$offset] : null;
194 | }
195 |
196 | /**
197 | * Magic method pra pegar os atributos como um objeto.
198 | *
199 | * @param string $attr Nome do atributo.
200 | *
201 | * @return mixed
202 | */
203 | public function __get($attr)
204 | {
205 | return $this->raw[$attr];
206 | }
207 | }
208 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #Correios
2 |
3 | Um pacote para interagir com serviços dos Correios.
4 |
5 | ##Recursos
6 |
7 | * [Encontra endereço a partir de um CEP](#encontrando-um-endereço-via-cep);
8 | * [Pega dados de rastreio de pacotes](#rastreando-um-pacote);
9 | * [Calcula preços e prazos de entrega](#calculando-valor-de-frete-e-prazo-de-entrega).
10 |
11 | Acha que está faltando algo? [Abra um issue!](https://github.com/eberfreitas/correios/issues/new)
12 |
13 | ##Por quê?
14 |
15 | Já existem [diversos pacotes](https://packagist.org/search/?q=correios) que
16 | trabalham com os serviços dos Correios, mas sempre existia algo que me impedia
17 | de usar algum deles, seja porque ele havia sido feito especificamente para algum
18 | software ou framework, ou porque ele não tinha todos os recursos que eu
19 | precisava, etc. A ideia então foi tentar um novo pacote com os seguintes
20 | objetivos:
21 |
22 | * **Stand-alone**: para ser usado em qualquer projeto/framework com o mínimo de
23 | dependências extras possível;
24 | * **Feature complete**: tentar cobrir o máximo de recursos que os Correios
25 | oferecem através de APIs oficiais ou não;
26 | * **PSR compliant**: O autoload é compatível com PSR-4 e a formatação PSR-2;
27 | * **Testes**: Tentar testar a biblioteca o máximo possível.
28 |
29 | ##Instalação
30 |
31 | Pelo Composer:
32 |
33 | ``` bash
34 | $ composer require eberfreitas/correios
35 | ```
36 |
37 | ##Como usar
38 |
39 | Para usar a biblioteca, antes de tudo, você precisa criar uma instância:
40 |
41 | ``` php
42 | $correios = new Correios\Correios();
43 | ```
44 |
45 | Isto já deve ser suficiente para começar a utilizar a biblioteca. Opcionalmente
46 | você pode configurar a sua instância de forma diferente. O construtor da classe
47 | aceita um array com as seguintes chaves:
48 |
49 | Chave | Descrição
50 | ---------------|----------
51 | `usuario` | Se você tiver contrato com os Correios, pode informar seu nome de usuário aqui.
52 | `senha` | Sua senha, caso tenha um usuário com cadastro nos Correios.
53 | `http_adapter` | Aqui você pode passar um objeto que será responsável por realizar as requisições HTTP de consulta aos webservices dos Correios. Saiba mais sobre isto [aqui](#usando-um-http-adapter-diferente).
54 |
55 | Exemplo:
56 |
57 | ``` php
58 | $adaptador = new MinhaClasseHttp;
59 |
60 | $correios = new Correios\Correios([
61 | 'usuario' => 'joao',
62 | 'senha' => 'segredo',
63 | 'http_adapter' => $adaptador
64 | ]);
65 | ```
66 |
67 | Embora você tenha a opção de providenciar um adaptador, se você não indicar
68 | nenhum, a biblioteca irá utilizar o `Guzzle` por padrão.
69 |
70 | ###Encontrando um endereço via CEP
71 |
72 | Para encontrar um endereço a partir de um CEP, basta usar o método `endereco`:
73 |
74 | ``` php
75 | $endereco = $correios->endereco('70150900');
76 |
77 | print_r($endereco);
78 | ```
79 |
80 | Que resulta neste output:
81 |
82 | ```
83 | Array
84 | (
85 | [logradouro] => Praça dos Três Poderes
86 | [logradouro_extra] =>
87 | [bairro] => Zona Cívico-Administrativa
88 | [cidade] => Brasília
89 | [uf] => DF
90 | [cep] => 70150900
91 | )
92 | ```
93 |
94 | Chave | Valor
95 | -------------------|------
96 | `logradouro` | Aqui você encontra o nome da rua, avenida, praça, etc.
97 | `logradouro_extra` | Eventualmente algum CEP vai trazer informações extras com o lado (ímpar ou par) a que ele corresponde naquele logradouro ou qual a faixa de numeração (de 1001 a 2000).
98 | `bairro` | O bairro deste CEP.
99 | `cidade` | A cidade.
100 | `uf` | A sigla do estado.
101 | `cep` | A repetição do CEP consultado.
102 |
103 | No caso de falha na consulta serão emitidos exceptions. Fique atento para
104 | pegá-los quando necessário. Na dúvida, verifique o código-fonte. Ele é bem
105 | documentado e deve te ajudar a entender cada método corretamente.
106 |
107 | ###Rastreando um pacote
108 |
109 | Para rastrear um pacote basta utilizar o método `rastreamento`:
110 |
111 | ``` php
112 | $eventos = $correios->rastreamento('PE024442250BR');
113 |
114 | print_r($eventos);
115 | ```
116 |
117 | Que resulta neste output:
118 |
119 | ```
120 | Array
121 | (
122 | [0] => Array
123 | (
124 | [data] => DateTime Object
125 | (
126 | [date] => 2015-03-12 18:12:00
127 | [timezone_type] => 3
128 | [timezone] => UTC
129 | )
130 | [descricao] => Entrega Efetuada
131 | [local] => CEE JABOATAO DOS GUARARAPES
132 | [cidade] => Recife
133 | [uf] => PE
134 | )
135 | [1] => Array
136 | (
137 | [data] => DateTime Object
138 | (
139 | [date] => 2015-03-12 09:22:00
140 | [timezone_type] => 3
141 | [timezone] => UTC
142 | )
143 | [descricao] => Saiu para entrega ao destinatio
144 | [local] => CTE RECIFE
145 | [cidade] => Recife
146 | [uf] => PE
147 | )
148 | [2] => Array
149 | (
150 | [data] => DateTime Object
151 | (
152 | [date] => 2015-03-11 11:31:00
153 | [timezone_type] => 3
154 | [timezone] => UTC
155 | )
156 | [descricao] => Encaminhado
157 | [local] => CTE RECIFE
158 | [cidade] => Recife
159 | [uf] => PE
160 | )
161 | [3] => ...
162 | )
163 | ```
164 |
165 | Como você pode ver, temos um array associativo com diversos dados referentes a
166 | cada evento relativo ao pacote sendo consultado. Cada entrada diz respeito a um
167 | evento e possui as seguintes chaves:
168 |
169 | Chave | Valor
170 | ------------|------
171 | `data` | Um objeto do tipo [DateTime](http://php.net/DateTime) representando o horário em que o evento aconteceu.
172 | `descricao` | A descrição do evento em questão.
173 | `local` | O nome do estabeleciomento dos Correios onde este evento ocorreu.
174 | `cidade` | Cidade onde o evento ocorreu.
175 | `uf` | Sigla do estado onde o evento ocorreu.
176 |
177 | **Uma nota sobre a consulta de pacotes**: Os Correios fornecem um webservice
178 | específico para a consulta de pacotes, porém este webservice é reservado a
179 | clientes que possuem contrato. Sendo assim, a biblioteca realiza um
180 | processo de "web scraping" para extrair os dados de páginas comuns de consulta.
181 | Embora a página sendo utilizada já tenha demonstrado uma estabilidade de anos
182 | no que diz respeito à sua estrutura, qualquer alteração no HTML desta página
183 | pode fazer este método falhar.
184 |
185 | ###Calculando valor de frete e prazo de entrega
186 |
187 | Para calcular o valor de uma entrega e seu prazo, basta utilizar o método
188 | `calculaFrete`:
189 |
190 | ``` php
191 | $calculado = $correios->calculaFrete([
192 | 'usuario' => null,
193 | 'senha' => null,
194 | 'servicos' => [Correios\Correios::PAC],
195 | 'cep_origem' => '08820400',
196 | 'cep_destino' => '21832150',
197 | 'peso' => 0.3,
198 | 'formato' => Correios\Correios::CAIXA,
199 | 'comprimento' => 16,
200 | 'altura' => 2,
201 | 'largura' => 11,
202 | 'diametro' => 5,
203 | 'mao_propria' => false,
204 | 'valor_declarado' => 0,
205 | 'aviso_recebimento' => false
206 | ]);
207 |
208 | print_r($calculado);
209 | ```
210 |
211 | Diferente dos outros métodos, este método recebe um array com um bocado
212 | de opções para que o cálculo seja realizado. Vamos dar uma olhada no que eles
213 | são:
214 |
215 | Chave | Obrigatório? | Tipo | Valor
216 | --------------------|--------------|--------|------
217 | `usuario` | Não | string | Se você já preencheu o seu usuário na hora de criar a instância da biblioteca, não há necessidade de definir o usuário aqui novamente. Se você não tem um usuário também não é obrigado a definir um. O usuário e senha são necessários apenas para realizar o cálculo de envios especiais como e-Sedex, PAC com contrato, etc.
218 | `senha` | Não | string | Veja descrição acima.
219 | `servicos` | Sim | array | Aqui você pode fornecer os códigos de serviços que você deseja consultar num array. A biblioteca fornece constantes que podem te ajudar a escolher quais serviços você deseja consultar. Veja aqui a [tabela de serviços](#tabela-de-serviços). Você pode consultar por quantos serviços diferentes desejar.
220 | `cep_origem` | Sim | string | CEP de origem do envio.
221 | `cep_destino` | Sim | string | CEP de destino.
222 | `peso` | Sim | float | O peso do pacote em **kilos**, ou seja, para informar 500 gramas o valor deve ser `0.5` e assim por diante.
223 | `formato` | Sim | int | Qual o formato do pacote. Recebe um número de 1 a 3 onde 1 = caixa, 2 = rolo, 3 = envelope. A classe fornece algumas constantes para auxiliar na definição deste valor: `CAIXA`, `ROLO` e `ENVELOPE`.
224 | `comprimento` | Não | int | O comprimento do pacote.
225 | `altura` | Não | int | A altura do pacote.
226 | `largura` | Não | int | A largura do pacote.
227 | `diametro` | Não | int | O diametro do pacote.
228 | `mao_propria` | Não | bool | Define se o envio deve utilizar o serviço de [mão própria](http://www.correios.com.br/para-voce/correios-de-a-a-z/mao-propria-mp) ou não (altera o valor do envio).
229 | `valor_declarado` | Não | float | O valor daquilo que está sendo enviado para contratação de seguro (altera o valor do envio).
230 | `aviso_recebimento` | Não | bool | Define se o envio deve utilizar o serviço de [aviso de recebimento](http://www.correios.com.br/para-voce/correios-de-a-a-z/aviso-de-recebimento-ar) ou não (altera o valor do envio).
231 |
232 | Os valores não obrigatórios serão preenchidos por valores padrão minimamente
233 | sãos. Fique de olho para garantir que o valor calculado esteja de acordo com as
234 | reais condições de envio.
235 |
236 | A chamada acima vai produzir o seguinte output:
237 |
238 | ```
239 | Array
240 | (
241 | [0] => Correios\Calculo Object
242 | (
243 | [raw:protected] => Array
244 | (
245 | [codigo] => 41106
246 | [valor] => 15.5
247 | [prazo_entrega] => 11
248 | [valor_sem_adicionais] => 15.5
249 | [valor_mao_propria] => 0
250 | [valor_aviso_recebimento] => 0
251 | [valor_valor_declarado] => 0
252 | [entrega_domiciliar] => 1
253 | [entrega_sabado] =>
254 | [erro] => 010
255 | [msg_erro] => O CEP de destino está sujeito a condições especiais de entrega pela ECT e será realizada com o acréscimo de até 7 (sete) dias ao prazo regular.
256 | [servico_descricao] => PAC
257 | )
258 |
259 | [serviceMap:protected] => Array
260 | (
261 | //...
262 | )
263 | )
264 | )
265 | ```
266 |
267 | Veja que temos o retorno de um array cujos elementos são instâncias da classe
268 | `Correios\Calculo`. Esta é uma classe simples que de dá acesso aos dados do
269 | resultado da consulta como um array ou um objeto:
270 |
271 | ``` php
272 | echo $calculado[0]['codigo']; //41106
273 | echo $calculado[0]->valor; //15.5
274 | ```
275 |
276 | Os dados disponíveis são os seguintes:
277 |
278 | Chave | Tipo | Descrição
279 | --------------------------|--------|----------
280 | `codigo` | string | Código do serviço referente a esta consulta.
281 | `valor` | float | Valor total do envio.
282 | `prazo_entrega` | int | Número de dias para entrega.
283 | `valor_sem_adicionais` | float | Valor do envio sem os serviços adicionais.
284 | `valor_mao_propria` | float | Valor do serviço de mão própria.
285 | `valor_aviso_recebimento` | float | Valor do serviço de aviso de recebimento.
286 | `valor_valor_declarado` | float | Valor do seguro.
287 | `entrega_domiciliar` | bool | Informa se a localidade informada possui entrega domiciliária.
288 | `entrega_sabado` | bool | Informa se a localidade informada possui entrega domiciliária aos sábados.
289 | `erro` | string | Código de erro.
290 | `msg_erro` | string | Mensagem de erro.
291 | `servico_descricao` | string | Descrição do serviço.
292 |
293 | ####Calculando uma data de entrega
294 |
295 | Lembra que o resultado da consulta traz um objeto? Ele tem alguns métodos
296 | interessantes que podem te ajudar a manipular melhor os dados de retorno da
297 | consulta de preço e prazo. Um destes métodos é o `calculaEntrega`. Com ele a
298 | gente consegue ter uma data de estimativa de entrega. Veja:
299 |
300 | ``` php
301 | $entrega = $calculado[0]->calculaEntrega(new DateTime('now'));
302 |
303 | print_r($entrega);
304 | ```
305 |
306 | Que resulta neste output:
307 |
308 | ```
309 | DateTime Object
310 | (
311 | [date] => 2015-05-18 00:00:00
312 | [timezone_type] => 3
313 | [timezone] => UTC
314 | )
315 | ```
316 |
317 | Veja que o método recebe um objeto `DateTime` e retorna um objeto `DateTime`
318 | representando a data de entrega. O método vai levar em consideração se, a partir
319 | da data de envio, a soma do prazo cai em algum dia do fim de semana, e ajusta
320 | a data para o próximo dia útil seguinte, a não ser que a entrega caia num sábado
321 | e o endereço de entrega possua o valor da chave `entrega_sabado` como `true`.
322 |
323 | ####Formatando valores
324 |
325 | Você também pode retornar facilmente os valores de envio já formatados. Veja:
326 |
327 | ``` php
328 | echo $calculado[0]->formataValor('valor');
329 | ```
330 |
331 | Que resulta neste output:
332 |
333 | ```
334 | R$ 15,50
335 | ```
336 |
337 | O valor será formatado de acordo com o padrão monetário brasileiro. Se você
338 | quiser, pode omitir o prefixo "R$" passando `false` no segundo argumento:
339 |
340 | ``` php
341 | echo $calculado[0]->formataValor('valor', talse); //15,50
342 | ```
343 |
344 | Você pode realizar esta formatação para qualquer chave de valor suprida pela
345 | consulta.
346 |
347 | ####Ajuste inteligente de pacotes
348 |
349 | Nenhum dos valores de dimensões dos pacotes é obrigatório de ser preenchido.
350 | Desta forma a biblioteca usa padrões que fazem sentido pra maioria dos envios e
351 | deve retornar valores adequados. Se você quiser personalizar os valores das
352 | dimensões, a biblioteca automaticamente ajusta estes valores caso eles estejam
353 | fora dos padrões definidos pelos Correios. Existem diversas regras que definem
354 | quais são as dimensões permitidas, inclusive para cada tipo de formato
355 | diferente.
356 |
357 | Sendo assim, a biblioteca vai verificar qual o formato definido, as regras para
358 | este formato e vai tentar ajustar as dimensões para que o cálculo aconteça sem
359 | errors.
360 |
361 | Se você desejar que a biblioteca não faça este ajuste automaticamente, basta chamar
362 | o método da seguinte forma:
363 |
364 | ``` php
365 | $config = []; //a configuração de sua chamada aqui...
366 | $calculado = $correios->calculaFrete($config, false);
367 | ```
368 |
369 | ####Tabela de serviços
370 |
371 | Aqui estão alguns dos códigos e suas respectivas descrições para consulta:
372 |
373 | Código | Descrição
374 | -------|----------
375 | 85480 | Aerograma
376 | 10014 | Carta Registrada
377 | 10030 | Carta Simples
378 | 16012 | Cartão Postal
379 | 81019 | e-SEDEX
380 | 20010 | Impresso
381 | 14036 | Mala Direta Postal Domiciliar
382 | 14010 | Mala Direta Postal Não Urgente
383 | 14028 | Mala Direta Postal Urgente
384 | 44105 | Malote
385 | 41106 | PAC
386 | 41300 | PAC Grandes Formatos
387 | 41262 | PAC Pagamento na Entrega
388 | 43010 | Reembolso Postal
389 | 40010 | SEDEX
390 | 40215 | SEDEX 10
391 | 40169 | SEDEX 12
392 | 40290 | SEDEX HOJE
393 | 40819 | SEDEX Pagamento na Entrega
394 |
395 | ###Usando um http adapter diferente
396 |
397 | Por padrão a biblioteca irá usar o [Guzzle](https://packagist.org/packages/guzzlehttp/guzzle)
398 | para realizar as requisições http aos endpoints dos webservices e páginas usados
399 | pela biblioteca. Se você quiser, poderá utilizar outro pacote no lugar do
400 | `Guzzle` fornecendo um novo objeto na hora de instanciar a classe dos Correios.
401 |
402 | Para isto você deve criar uma classe intermediária que implemente a interface
403 | `Correios\Adapters\AdapterInterface` que possui apenas dois métodos: `get` e
404 | `post`.
405 |
406 | Ambos os métodos devem retornar uma `string` representando o corpo da resposta
407 | da requisição e qualquer erro no processo de requisição deve ser indicado
408 | através da utilização de exceptions.
409 |
410 | Veja uma implementação exemplo
411 | [aqui](https://github.com/eberfreitas/correios/blob/master/src/Adapters/GuzzleAdapter.php).
412 |
413 | ##Créditos
414 |
415 | * Criado por [Éber F. Dias](https://github.com/eberfreitas)
416 | * Com o auxilio de [Tiago Correa](https://github.com/tiagocorrea)
417 | * Patrocinado por [Tanlup](https://github.com/tanlup/)
--------------------------------------------------------------------------------
/src/Correios.php:
--------------------------------------------------------------------------------
1 | 'http://ws.correios.com.br/calculador/CalcPrecoPrazo.aspx',
35 | 'cep' => 'http://m.correios.com.br/movel/buscaCepConfirma.do',
36 | 'rastreamento' => 'http://websro.correios.com.br/sro_bin/txect01%24.QueryList'
37 | ];
38 |
39 | /**
40 | * Construtor da classe.
41 | *
42 | * @param array $options Aqui você pode injetar um objeto que será usando
43 | * como `$httpAdapter`, passar seu nome de usuário e senha. Para usar
44 | * outro adaptador para realizar as chamadas aos endpoints, veja a
45 | * documentação da lib.
46 | *
47 | * @throws \InvalidArgumentException Se o http_adapter não implementa a
48 | * interface corretamente.
49 | *
50 | * @return void
51 | */
52 | public function __construct(array $options = [])
53 | {
54 | $defaultOptions = [
55 | 'http_adapter' => null,
56 | 'usuario' => null,
57 | 'senha' => null
58 | ];
59 |
60 | $options += $defaultOptions;
61 |
62 | if (is_null($options['http_adapter'])) {
63 | $this->httpAdapter = new Adapters\GuzzleAdapter();
64 | } else {
65 | $this->httpAdapter = $options['http_adapter'];
66 | }
67 |
68 | $interfaces = class_implements($this->httpAdapter);
69 |
70 | if (!in_array('Correios\Adapters\AdapterInterface', $interfaces)) {
71 | throw new \InvalidArgumentException(
72 | 'O adaptador http precisa implementar a interface "Correios\Adapters\AdapterInterface"'
73 | );
74 | }
75 |
76 | $this->usuario = is_null($options['usuario']) ? null : $options['usuario'];
77 | $this->senha = is_null($options['senha']) ? null : $options['senha'];
78 | }
79 |
80 | /**
81 | * Retorna os dados de rastreio de um pacote.
82 | *
83 | * @param string $code Um código de rastreio válido.
84 | * @param array $options Possíveis opções que você queira passar ao
85 | * adapter que estiver sendo utilizado para realizar as requisições ao
86 | * webservice.
87 | *
88 | * @throws \InvalidArgumentException Se o CEP tiver valor inválido.
89 | * @throws \RuntimeException Se nenhum endereço for encontrado.
90 | *
91 | * @return array
92 | */
93 | public function rastreamento($code, array $options = [])
94 | {
95 | $code = strtoupper($code);
96 |
97 | if (preg_match('/^[A-Z]{2}[0-9]{9}[A-Z]{2}$/', $code) !== 1) {
98 | throw new \InvalidArgumentException('Use um código de rastreio válido!');
99 | }
100 |
101 | $body = [
102 | 'P_LINGUA' => '001',
103 | 'P_TIPO' => '001',
104 | 'P_COD_UNI' => $code
105 | ];
106 |
107 | $html = $this->httpAdapter->post($this->endpoints['rastreamento'], $body, $options);
108 | $tableStart = strpos($html, '') + 7; //mais o comprimento "/TABLE>"
115 | $tableLength = $tableEnd - $tableStart;
116 | $table = substr($html, $tableStart, $tableLength);
117 | $html = '' . $table . '';
118 | $html = \pQuery::parseStr($html);
119 | $tableCells = $html->query('table td');
120 | $cellContents = [];
121 |
122 | foreach ($tableCells as $cell) {
123 | $cellContents[] = $cell->getPlainText();
124 | }
125 |
126 | $cellContents = array_slice($cellContents, 3); // cabeçalhos, não precisamos deles...
127 | $raw = $data = [];
128 | $eventIndex = null;
129 | $i = 0;
130 |
131 | foreach ($cellContents as $content) {
132 | /**
133 | * Cada vez que encontramos uma data quer dizer que estamos em um
134 | * novo evento. Usamos o timestamp como chave pra separar os eventos
135 | * em um array e organizar os dados.
136 | */
137 | if (preg_match('#^[0-3]\d/[0-1]\d/(19|20)\d\d [0-2]\d:[0-5]\d$#', $content) != false) {
138 | $date = \DateTime::createFromFormat('d/m/Y H:i', $content);
139 | $eventIndex = $date->getTimestamp();
140 | $raw[$eventIndex] = [$date];
141 | } else {
142 | $raw[$eventIndex][] = $content;
143 | }
144 | }
145 |
146 | ksort($raw);
147 | $lastPlace = null;
148 |
149 | foreach ($raw as $info) {
150 | $parts = explode(' - ', $info[1]);
151 |
152 | if (count($parts) > 1) {
153 | $lastPlace = $parts[0];
154 | $address = $parts[1];
155 | } else {
156 | $address = $parts[0];
157 | }
158 |
159 | list($city, $uf) = explode('/', $address);
160 |
161 | $data[$i] = [];
162 | $data[$i]['data'] = $info[0];
163 | $data[$i]['descricao'] = $info[2];
164 | $data[$i]['local'] = trim($lastPlace);
165 | $data[$i]['cidade'] = trim($city);
166 | $data[$i]['uf'] = trim($uf);
167 |
168 | $i++;
169 | }
170 |
171 | return array_reverse($data);
172 | }
173 |
174 | /**
175 | * Pega o endereço a partir de um determinado CEP.
176 | *
177 | * @param string $cep Qualquer CEP válido.
178 | * @param array $options Possíveis opções que você queira passar ao
179 | * adapter que estiver sendo utilizado para realizar as requisições ao
180 | * webservice.
181 | *
182 | * @throws \InvalidArgumentException Se o CEP tiver valor inválido.
183 | * @throws \RuntimeException Se nenhum endereço for encontrado.
184 | *
185 | * @return array
186 | */
187 | public function endereco($cep, array $options = [])
188 | {
189 | $cep = str_replace('-', '', $cep);
190 |
191 | if (strlen($cep) !== 8 || !is_numeric($cep)) {
192 | throw new \InvalidArgumentException('Use um valor de CEP válido!');
193 | }
194 |
195 | $body = [
196 | 'cepEntrada' => $cep,
197 | 'tipoCep' => '',
198 | 'cepTemp' => '',
199 | 'metodo' => 'buscarCep'
200 | ];
201 |
202 | $html = $this->httpAdapter->post($this->endpoints['cep'], $body, $options);
203 | $html = \pQuery::parseStr($html);
204 | $parts = $html->query('span.respostadestaque');
205 | $addressParts = [];
206 | $address = [];
207 |
208 | foreach ($parts as $p) {
209 | $addressParts[] = $p->getPlainText();
210 | }
211 |
212 | if (empty($addressParts)) {
213 | throw new \RuntimeException('Nenhum endereço encontrado com este CEP!');
214 | }
215 |
216 | $partsCount = count($addressParts);
217 |
218 | switch ($partsCount) {
219 | case 2:
220 | list($cidade, $estado) = explode('/', $addressParts[0]);
221 |
222 | $address = [
223 | 'logradouro' => null,
224 | 'logradouro_extra' => null,
225 | 'bairro' => null,
226 | 'cidade' => utf8_encode(trim($cidade)),
227 | 'uf' => utf8_encode(trim($estado)),
228 | 'cep' => utf8_encode(trim($addressParts[1]))
229 | ];
230 |
231 | break;
232 | default:
233 | list($cidade, $estado) = explode('/', $addressParts[2]);
234 |
235 | $address = [
236 | 'logradouro' => utf8_encode(trim($addressParts[0])),
237 | 'logradouro_extra' => null,
238 | 'bairro' => utf8_encode(trim($addressParts[1])),
239 | 'cidade' => utf8_encode(trim($cidade)),
240 | 'uf' => utf8_encode(trim($estado)),
241 | 'cep' => utf8_encode(trim($addressParts[3]))
242 | ];
243 |
244 | if (strpos($address['logradouro'], ' - ') !== false) {
245 | $extra = explode(' - ', $address['logradouro']);
246 | $street = array_shift($extra);
247 | $extra = implode(' - ', $extra);
248 | $address['logradouro'] = trim($street);
249 | $address['logradouro_extra'] = trim($extra);
250 | }
251 |
252 | break;
253 | }
254 |
255 | return $address;
256 | }
257 |
258 | /**
259 | * Use este método para calcular o frete e prazo de entrega de um CEP para
260 | * outro CEP.
261 | *
262 | * @link http://bit.ly/1jwSH9i Documentação do webservice dos Correios.
263 | *
264 | * @param array $config Recebe um array com diversos valores que vão
265 | * definir como o frete será calculado. Consultar a variável
266 | * `$defaultConfig` para saber quais são as chaves que devem ser
267 | * preenchidas e que tipo de valor elas aceitam.
268 | * @param boolean $fix Se verdadeiro, este método irá corrigir qualquer
269 | * irregularidade referente a tamanhos de pacotes, peso, etc., fazendo
270 | * com que o valor do frete seja efetivamente calculado apesar da
271 | * informação de valores errados.
272 | * @param array $options Possíveis opções que você queira passar ao
273 | * adapter que estiver sendo utilizado para realizar as requisições ao
274 | * webservice.
275 | *
276 | * @return array
277 | */
278 | public function calculaFrete(array $config = [], $fix = true, array $options = [])
279 | {
280 | $defaultConfig = [
281 | 'usuario' => null,
282 | 'senha' => null,
283 | 'servicos' => [],
284 | 'cep_origem' => '',
285 | 'cep_destino' => '',
286 | 'peso' => null,
287 | 'formato' => null,
288 | 'comprimento' => 16,
289 | 'altura' => 2,
290 | 'largura' => 11,
291 | 'diametro' => 5,
292 | 'mao_propria' => false,
293 | 'valor_declarado' => 0,
294 | 'aviso_recebimento' => false
295 | ];
296 |
297 | $config += $defaultConfig;
298 | $params = $this->preparaParametrosCalculo($config);
299 |
300 | if ($fix) {
301 | $params = $this->ajustaPacote($params);
302 | }
303 |
304 | $xml = $this->httpAdapter->get($this->endpoints['calculo'], $params, $options);
305 | $data = $this->xmlToArray($xml);
306 | $return = [];
307 |
308 | if (empty($data['cServico'][0])) {
309 | $data['cServico'] = [$data['cServico']];
310 | }
311 |
312 | foreach ($data['cServico'] as $d) {
313 | $return[] = new Calculo($d);
314 | }
315 |
316 | return $return;
317 | }
318 |
319 | /**
320 | * Este método recebe as opções do método de cálculo de frete e os
321 | * transforma em parâmetros que poderão ser usados diretamente na chamada
322 | * http ao endpoint de consulta do frete.
323 | *
324 | * @param array $options As opções vindas do método de cálculo de frete.
325 | *
326 | * @return array Parâmetros devidamente formatados.
327 | */
328 | protected function preparaParametrosCalculo(array $options = [])
329 | {
330 | $paramsMap = [
331 | 'usuario' => 'nCdEmpresa',
332 | 'senha' => 'sDsSenha',
333 | 'servicos' => 'nCdServico',
334 | 'cep_origem' => 'sCepOrigem',
335 | 'cep_destino' => 'sCepDestino',
336 | 'peso' => 'nVlPeso',
337 | 'formato' => 'nCdFormato',
338 | 'comprimento' => 'nVlComprimento',
339 | 'altura' => 'nVlAltura',
340 | 'largura' => 'nVlLargura',
341 | 'diametro' => 'nVlDiametro',
342 | 'mao_propria' => 'sCdMaoPropria',
343 | 'valor_declarado' => 'nVlValorDeclarado',
344 | 'aviso_recebimento' => 'sCdAvisoRecebimento'
345 | ];
346 |
347 | $params = [];
348 |
349 | foreach ($paramsMap as $opt => $param) {
350 | $params[$param] = $options[$opt];
351 | }
352 |
353 | $params['sCdMaoPropria'] = $params['sCdMaoPropria'] === true ? 'S' : 'N';
354 | $params['sCdAvisoRecebimento'] = $params['sCdAvisoRecebimento'] === true ? 'S' : 'N';
355 |
356 | if (is_null($params['nCdEmpresa']) && !is_null($this->usuario)) {
357 | $params['nCdEmpresa'] = $this->usuario;
358 | }
359 |
360 | if (is_null($params['sDsSenha']) && !is_null($this->senha)) {
361 | $params['sDsSenha'] = $this->senha;
362 | }
363 |
364 | $params['nCdServico'] = implode(',', (array)$params['nCdServico']);
365 | $params['StrRetorno'] = 'xml';
366 | $params['nIndicaCalculo'] = 3; // preço e prazo
367 |
368 | return $params;
369 | }
370 |
371 | /**
372 | * Método que ajusta as dimensções de um determinado pacote para que o
373 | * cálculo aconteça corretamente.
374 | *
375 | * @link http://bit.ly/1JVa7Ls Especificações de tamanho.
376 | *
377 | * @param array $params Os parametros do cálculo do frete.
378 | *
379 | * @return array
380 | */
381 | protected function ajustaPacote(array $params = [])
382 | {
383 | if ($params['nVlPeso'] < 0.3) {
384 | $params['nVlPeso'] = 0.3;
385 | } elseif ($params['nVlPeso'] > 1 && $params['nCdFormato'] === self::ENVELOPE) {
386 | $params['nVlPeso'] = 1;
387 | } elseif ($params['nVlPeso'] > 30) {
388 | $params['nVlPeso'] = 30;
389 | }
390 |
391 | switch ($params['nCdFormato']) {
392 | case self::CAIXA:
393 | $params['nVlDiametro'] = 0;
394 |
395 | if ($params['nVlComprimento'] < 16) {
396 | $params['nVlComprimento'] = 16;
397 | return $this->ajustaPacote($params);
398 | } elseif ($params['nVlComprimento'] > 105) {
399 | $params['nVlComprimento'] = 105;
400 | return $this->ajustaPacote($params);
401 | }
402 |
403 | if ($params['nVlLargura'] < 11) {
404 | $params['nVlLargura'] = 11;
405 | return $this->ajustaPacote($params);
406 | } elseif ($params['nVlLargura'] > 105) {
407 | $params['nVlLargura'] = 105;
408 | return $this->ajustaPacote($params);
409 | }
410 |
411 | if ($params['nVlAltura'] < 2) {
412 | $params['nVlAltura'] = 2;
413 | return $this->ajustaPacote($params);
414 | } elseif ($params['nVlAltura'] > 105) {
415 | $params['nVlAltura'] = 105;
416 | return $this->ajustaPacote($params);
417 | }
418 |
419 | $sum = $params['nVlComprimento'] + $params['nVlLargura'] + $params['nVlAltura'];
420 |
421 | if ($sum > 200) {
422 | while ($sum > 200) {
423 | if ($params['nVlComprimento'] > 16) {
424 | $params['nVlComprimento']--;
425 | }
426 |
427 | if ($params['nVlLargura'] > 11) {
428 | $params['nVlLargura']--;
429 | }
430 |
431 | if ($params['nVlAltura'] > 2) {
432 | $params['nVlAltura']--;
433 | }
434 |
435 | $sum = $params['nVlComprimento'] + $params['nVlLargura'] + $params['nVlAltura'];
436 | }
437 |
438 | return $this->ajustaPacote($params);
439 | }
440 |
441 | break;
442 | case self::ROLO:
443 | $params['nVlAltura'] = 0;
444 | $params['nVlLargura'] = 0;
445 |
446 | if ($params['nVlComprimento'] < 18) {
447 | $params['nVlComprimento'] = 18;
448 | return $this->ajustaPacote($params);
449 | } elseif ($params['nVlComprimento'] > 105) {
450 | $params['nVlComprimento'] = 105;
451 | return $this->ajustaPacote($params);
452 | }
453 |
454 | if ($params['nVlDiametro'] < 5) {
455 | $params['nVlDiametro'] = 5;
456 | return $this->ajustaPacote($params);
457 | } elseif ($params['nVlDiametro'] > 91) {
458 | $params['nVlDiametro'] = 91;
459 | return $this->ajustaPacote($params);
460 | }
461 |
462 | $sum = $params['nVlComprimento'] + (2 * $params['nVlDiametro']);
463 |
464 | if ($sum > 200) {
465 | while ($sum > 200) {
466 | if ($params['nVlComprimento'] > 18) {
467 | $params['nVlComprimento']--;
468 | }
469 |
470 | if ($params['nVlDiametro'] > 5) {
471 | $params['nVlDiametro']--;
472 | }
473 |
474 | $sum = $params['nVlComprimento'] + (2 * $params['nVlDiametro']);
475 | }
476 |
477 | return $this->ajustaPacote($params);
478 | }
479 |
480 | break;
481 | case self::ENVELOPE:
482 | $params['nVlAltura'] = 0;
483 | $params['nVlDiametro'] = 0;
484 |
485 | if ($params['nVlComprimento'] < 16) {
486 | $params['nVlComprimento'] = 16;
487 | return $this->ajustaPacote($params);
488 | } elseif ($params['nVlComprimento'] > 60) {
489 | $params['nVlComprimento'] = 60;
490 | return $this->ajustaPacote($params);
491 | }
492 |
493 | if ($params['nVlLargura'] < 11) {
494 | $params['nVlLargura'] = 11;
495 | return $this->ajustaPacote($params);
496 | } elseif ($params['nVlLargura'] > 60) {
497 | $params['nVlLargura'] = 60;
498 | return $this->ajustaPacote($params);
499 | }
500 |
501 | break;
502 | }
503 |
504 | return $params;
505 | }
506 |
507 | /**
508 | * Método simples pra transformar um xml em array
509 | *
510 | * @param string $xml O string do XML sendo manipulado.
511 | *
512 | * @return array
513 | */
514 | protected function xmlToArray($xml)
515 | {
516 | $xml = simplexml_load_string($xml, null, LIBXML_NOCDATA);
517 | return json_decode(json_encode($xml), true);
518 | }
519 | }
520 |
--------------------------------------------------------------------------------