├── .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 | --------------------------------------------------------------------------------