diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..e69de29 diff --git a/README.md b/README.md new file mode 100644 index 0000000..f725ae7 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# Correios para Bagisto + +Módulo desenvolvido para adicionar o método de entrega dos Correios na ferramenta de e-Commerce Bagisto + +## Instalação + +@todo + +## Configurações + + diff --git a/composer.json b/composer.json new file mode 100755 index 0000000..b313216 --- /dev/null +++ b/composer.json @@ -0,0 +1,28 @@ +{ + "name": "cagartner/bagisto-correios", + "description": "Shipping Method for Correios", + "license": "MIT", + "authors": [ + { + "name": "Carlos Gartner", + "email": "contato@carlosgartner.com.br" + } + ], + "require": { + "cagartner/phpquery": "0.9.10" + }, + "autoload": { + "psr-4": { + "Cagartner\\Correios\\": "src/" + } + }, + "extra": { + "laravel": { + "providers": [ + "Cagartner\\Correios\\Providers\\CorreiosServiceProvider" + ], + "aliases": {} + } + }, + "minimum-stability": "dev" +} diff --git a/src/Carriers/Correios.php b/src/Carriers/Correios.php new file mode 100755 index 0000000..608e5b2 --- /dev/null +++ b/src/Carriers/Correios.php @@ -0,0 +1,114 @@ + + */ +class Correios extends AbstractShipping +{ + /** + * Correios methods map + */ + const METHODS_TITLE = [ + 'sedex' => 'Sedex', + 'sedex_a_cobrar' => 'Sedex a Cobrar', + 'sedex_10' => 'Sedex 10', + 'sedex_hoje' => 'Sedex Hoje', + 'pac' => 'PAC', + 'pac_contrato' => 'PAC', + 'sedex_contrato' => 'Sedex', + 'esedex' => 'e-Sedex', + ]; + + /** + * Payment method code + * + * @var string + */ + protected $code = 'cagartner_correios'; + + /** + * Returns rate for correios + * + * @return array + */ + public function calculate() + { + if (!$this->isAvailable()) + return false; + + /** @var \Webkul\Checkout\Models\Cart $cart */ + $cart = Cart::getCart(); + $total_weight = $cart->items->sum('total_weight'); + + $data = [ + 'tipo' => $this->getConfigData('methods'), + 'formato' => $this->getConfigData('package_type'), // opções: `caixa`, `rolo`, `envelope` + 'cep_destino' => $cart->shipping_address->postcode, + 'cep_origem' => core()->getConfigData('sales.shipping.origin.zipcode'), + 'peso' => $total_weight, // Peso em kilos + 'comprimento' => $this->getConfigData('package_length'), // Em centímetros + 'altura' => $this->getConfigData('package_height'), // Em centímetros + 'largura' => $this->getConfigData('package_width'), // Em centímetros + 'diametro' => $this->getConfigData('roll_diameter'), // Em centímetros, no caso de rolo + ]; + + if ($this->getConfigData('cod_company') && $this->getConfigData('password')) { + $data['empresa'] = $this->getConfigData('cod_company'); + $data['senha'] = $this->getConfigData('password'); + } + + $consult = new Consult(); + /** @var Collection $result */ + $result = $consult->carriers($data); + $rates = []; + $tax_handling = (int)core()->convertPrice($this->getConfigData('tax_handling')) ?: 0; + + foreach ($result as $item) { + $object = new CartShippingRate; + $object->carrier = 'correios'; + $object->carrier_title = $this->getConfigData('title'); + $object->method = 'cagartner_correios_' . Consult::getTipoIndex($item['codigo']); + $object->method_title = $this->getMethodTitle($item['codigo']); + $object->method_description = $this->getMethodDescription($item['prazo']); + $object->price = core()->convertPrice($item['valor']) + $tax_handling; + $object->base_price = core()->convertPrice($item['valor']) + $tax_handling; + array_push($rates, $object); + } + return $rates; + } + + /** + * @param $code + * @return mixed + */ + protected function getMethodTitle($code) + { + $method = Consult::getTipoIndex($code); + return self::METHODS_TITLE[$method]; + } + + /** + * @param $deadline + * @return mixed + */ + protected function getMethodDescription($deadline) + { + $template = $this->getConfigData('method_template'); + $extra_time = (int)core()->convertPrice($this->getConfigData('extra_time')) ?: 0; + if (strpos($template, ':dia')) { + $template = str_replace(':dia', ($deadline + $extra_time), $template); + } + return $template; + } +} \ No newline at end of file diff --git a/src/Config/carriers.php b/src/Config/carriers.php new file mode 100755 index 0000000..7d2d7aa --- /dev/null +++ b/src/Config/carriers.php @@ -0,0 +1,20 @@ + [ + 'code' => 'correios', + 'title' => 'Correios', + 'description' => 'Correios', + 'active' => true, + 'class' => \Cagartner\Correios\Carriers\Correios::class, + 'methods' => 'sedex,pac', + 'tax_handling' => 0, + 'extra_time' => 1, + 'method_template' => 'Entrega em até :dia dia úteis(s)', + 'package_type' => 'caixa', + 'package_length' => 16, + 'package_height' => 11, + 'package_width' => 11, + 'roll_diameter' => 0 + ], +]; \ No newline at end of file diff --git a/src/Config/system.php b/src/Config/system.php new file mode 100755 index 0000000..9860ccd --- /dev/null +++ b/src/Config/system.php @@ -0,0 +1,165 @@ + 'sales.carriers.cagartner_correios', + 'name' => 'Correios', + 'sort' => 1, + 'fields' => [ + [ + 'name' => 'title', + 'title' => 'Title', + 'type' => 'text', + 'validation' => 'required', + 'channel_based' => false, + 'locale_based' => true + ], [ + 'name' => 'description', + 'title' => 'Description', + 'type' => 'textarea', + 'channel_based' => false, + 'locale_based' => true + ], [ + 'name' => 'tax_handling', + 'title' => 'Taxa de Manuseio', + 'type' => 'text', + 'channel_based' => false, + 'locale_based' => true, + 'validation' => 'required', + ], [ + 'name' => 'methods', + 'title' => 'Methods', + 'type' => 'multiselect', + 'options' => [ + [ + 'title' => 'Sedex', + 'value' => 'sedex' + ], [ + 'title' => 'Sedex a Cobrar', + 'value' => 'sedex_a_cobrar' + ], [ + 'title' => 'Sedex 10', + 'value' => 'sedex_10' + ], [ + 'title' => 'Sedex Hoje', + 'value' => 'sedex_hoje' + ], [ + 'title' => 'PAC', + 'value' => 'pac' + ], [ + 'title' => 'PAC Contrato', + 'value' => 'pac_contrato' + ], [ + 'title' => 'Sedex Contrato', + 'value' => 'sedex_contrato' + ], [ + 'title' => 'e-Sedex', + 'value' => 'esedex' + ] + ], + 'validation' => 'required' + ], [ + 'name' => 'extra_time', + 'title' => 'Dias Extras ao Prazo de Entrega', + 'type' => 'text', + 'channel_based' => false, + 'locale_based' => true, + 'validation' => 'required', + ], [ + 'name' => 'method_template', + 'title' => 'Template do Retorno', + 'type' => 'text', + 'channel_based' => false, + 'locale_based' => true, + 'validation' => 'required', + 'info' => 'A variável :dia será substituído pelo retorno dos Correios + os Dias Extras ao Prazo de Entrega definido' + ], + [ + 'name' => 'package_type', + 'title' => 'Formato do Pacote', + 'type' => 'select', + 'options' => [ + [ + 'title' => 'Caixa', + 'value' => 'caixa' + ], [ + 'title' => 'Rolo', + 'value' => 'rolo' + ], [ + 'title' => 'Envelope', + 'value' => 'envelope' + ] + ], + 'channel_based' => false, + 'locale_based' => true, + 'validation' => 'required' + ], + [ + 'name' => 'package_length', + 'title' => 'Comprimento do Pacote', + 'type' => 'text', + 'channel_based' => false, + 'locale_based' => true, + 'info' => 'Válido apenas para Formato Caixa', + 'validation' => 'required', + ], + [ + 'name' => 'package_height', + 'title' => 'Altura do Pacote', + 'type' => 'text', + 'channel_based' => false, + 'locale_based' => true, + 'validation' => 'required', + 'info' => 'Válido apenas para Formato Caixa' + ], + [ + 'name' => 'package_width', + 'title' => 'Largura do Pacote', + 'type' => 'text', + 'channel_based' => false, + 'locale_based' => true, + 'info' => 'Válido apenas para Formato Caixa', + 'validation' => 'required', + ], + [ + 'name' => 'roll_diameter', + 'title' => 'Diâmetro do Rôlo', + 'type' => 'text', + 'channel_based' => false, + 'locale_based' => true, + 'info' => 'Válido apenas para Formato Rolo, Manter 0 se não aplicável.', + 'validation' => 'required', + ], + [ + 'name' => 'cod_company', + 'title' => 'Código Da Empresa', + 'type' => 'text', + 'channel_based' => false, + 'locale_based' => true, + 'info' => 'Código da Empresa junto aos Correios' + ], + [ + 'name' => 'password', + 'title' => 'Senha', + 'type' => 'text', + 'channel_based' => false, + 'locale_based' => true, + 'info' => 'Senha da Empresa junto aos Correios' + ], + [ + 'name' => 'active', + 'title' => 'Status', + 'type' => 'select', + 'options' => [ + [ + 'title' => 'Active', + 'value' => true + ], [ + 'title' => 'Inactive', + 'value' => false + ] + ], + 'validation' => 'required' + ] + ] + ] +]; \ No newline at end of file diff --git a/src/Helpers/Consult.php b/src/Helpers/Consult.php new file mode 100644 index 0000000..79245ff --- /dev/null +++ b/src/Helpers/Consult.php @@ -0,0 +1,217 @@ + '04014', + 'sedex_a_cobrar' => '40045', + 'sedex_10' => '40215', + 'sedex_hoje' => '40290', + 'pac' => '04510', + 'pac_contrato' => '04669', + 'sedex_contrato' => '04162', + 'esedex' => '81019', + ); + + public static function getMethods() + { + return self::$methods; + } + + /** + * Verifica se e uma solicitacao de varios $tipos + * + * @param $valor string + * @return boolean + */ + public static function getTipoIsArray($valor) + { + return count(explode(",", $valor)) > 1 ?: false; + } + + /** + * @param $valor string + * @return string + */ + public static function getTipoIndex($valor) + { + return array_search($valor, self::getMethods()); + } + + /** + * Retorna todos os codigos em uma linha + * + * @param $valor string + * @return string + */ + public static function getTipoInline($valor) + { + $explode = explode(",", $valor); + $tipos = array(); + foreach ($explode as $value) { + $tipos[] = self::$methods[$value]; + } + return implode(",", $tipos); + } + + /** + * @param $data + * @param array $options + * @return array|mixed + */ + public function carriers($data, $options = array()) + { + $endpoint = self::FRETE_URL; + $tipos = self::getTipoInline($data['tipo']); + + $formatos = array( + 'caixa' => 1, + 'rolo' => 2, + 'envelope' => 3, + ); + + $data['tipo'] = $tipos; + $data['formato'] = $formatos[$data['formato']]; + + $data['cep_destino'] = preg_replace("/[^0-9]/", '', $data['cep_destino']); + $data['cep_origem'] = preg_replace("/[^0-9]/", '', $data['cep_origem']); + + $options = array_merge(array( + 'trace' => true, + 'exceptions' => true, + 'compression' => SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP, + 'connection_timeout' => 1000 + ), $options); + + $soap = new \SoapClient($endpoint, $options); + $params = array( + 'nCdEmpresa' => (isset($data['empresa']) ? $data['empresa'] : ''), + 'sDsSenha' => (isset($data['senha']) ? $data['senha'] : ''), + 'nCdServico' => $data['tipo'], + 'sCepOrigem' => $data['cep_origem'], + 'sCepDestino' => $data['cep_destino'], + 'nVlPeso' => $data['peso'], + 'nCdFormato' => $data['formato'], + 'nVlComprimento' => $data['comprimento'], + 'nVlAltura' => $data['altura'], + 'nVlLargura' => $data['largura'], + 'nVlDiametro' => $data['diametro'], + 'sCdMaoPropria' => (isset($data['mao_propria']) && $data['mao_propria'] ? 'S' : 'N'), + 'nVlValorDeclarado' => (isset($data['valor_declarado']) ? $data['valor_declarado'] : 0), + 'sCdAvisoRecebimento' => (isset($data['aviso_recebimento']) && $data['aviso_recebimento'] ? 'S' : 'N'), + 'sDtCalculo' => date('d/m/Y'), + ); + + $CalcPrecoPrazoData = $soap->CalcPrecoPrazoData($params); + $resultado = $CalcPrecoPrazoData->CalcPrecoPrazoDataResult->Servicos->cServico; + if (!is_array($resultado)) + $resultado = array($resultado); + $data = array(); + foreach ($resultado as $consulta) { + $consulta = (array)$consulta; + $data[] = array( + 'codigo' => $consulta['Codigo'], + 'valor' => (float)str_replace(',', '.', $consulta['Valor']), + 'prazo' => (int)str_replace(',', '.', $consulta['PrazoEntrega']), + 'mao_propria' => (float)str_replace(',', '.', $consulta['ValorMaoPropria']), + 'aviso_recebimento' => (float)str_replace(',', '.', $consulta['ValorAvisoRecebimento']), + 'valor_declarado' => (float)str_replace(',', '.', $consulta['ValorValorDeclarado']), + 'entrega_domiciliar' => ($consulta['EntregaDomiciliar'] === 'S' ? true : false), + 'entrega_sabado' => ($consulta['EntregaSabado'] === 'S' ? true : false), + 'erro' => array('codigo' => (real)$consulta['Erro'], 'mensagem' => $consulta['MsgErro']), + ); + } + return collect($data); + } + + /** + * @param $postcode + * @return array + * @throws \Exception + */ + public function postcode($postcode) + { + $query = array( + 'relaxation' => $postcode, + 'tipoCEP' => 'ALL', + 'semelhante' => 'N', + ); + $curl = new Curl; + $html = $curl->simple(self::CEP_URL, $query); + phpQuery::newDocumentHTML($html, $charset = 'ISO-8859-1'); + $pq_form = phpQuery::pq(''); + + $result = []; + if (phpQuery::pq('.tmptabela')) { + $line = 0; + foreach (phpQuery::pq('.tmptabela tr') as $pq_div) { + if ($line) { + $item = array(); + foreach (phpQuery::pq('td', $pq_div) as $pq_td) { + $children = $pq_td->childNodes; + $innerHTML = ''; + foreach ($children as $child) { + $innerHTML .= $child->ownerDocument->saveXML($child); + } + $item[] = trim(preg_replace("/&#?[a-z0-9]+;/i", "", $innerHTML)); + } + $data = []; + $data['address'] = trim($item[0], " \t\n\r\0\x0B\xc2\xa0"); + $data['neighbourhood'] = trim($item[1], " \t\n\r\0\x0B\xc2\xa0"); + $data['postcode'] = trim($item[3], " \t\n\r\0\x0B\xc2\xa0"); + $citystate = explode('/', trim($item[2], " \t\n\r\0\x0B\xc2\xa0")); + $data['city'] = trim($citystate[0], " \t\n\r\0\x0B\xc2\xa0"); + $data['state'] = trim($citystate[1], " \t\n\r\0\x0B\xc2\xa0"); + $result = $data; + } + $line++; + } + } + return $result; + } + + /** + * @param $code + * @return bool|\Illuminate\Support\Collection + * @throws \Exception + */ + public function tracking($code) + { + $curl = new Curl; + $html = $curl->simple(self::RASTREIO_URL, array( + "Objetos" => $code + )); + + phpQuery::newDocumentHTML($html, $charset = 'utf-8'); + $tracking = array(); + $c = 0; + foreach (phpQuery::pq('tr') as $tr) { + $c++; + if (count(phpQuery::pq($tr)->find('td')) == 2) { + list($date, $hour, $place) = explode("
", phpQuery::pq($tr)->find('td:eq(0)')->html()); + list($status, $forwarded) = explode("
", phpQuery::pq($tr)->find('td:eq(1)')->html()); + $tracking[] = array('date' => trim($date) . " " . trim($hour), 'local' => trim($place), 'status' => trim(strip_tags($status))); + if (trim($forwarded)) { + $tracking[count($tracking) - 1]['encaminhado'] = trim($encaminhado); + } + } + } + + if (!count($tracking)) + return false; + + return collect($tracking); + } +} \ No newline at end of file diff --git a/src/Helpers/Curl.php b/src/Helpers/Curl.php new file mode 100644 index 0000000..2082da6 --- /dev/null +++ b/src/Helpers/Curl.php @@ -0,0 +1,71 @@ + 0) + curl_setopt($conn, CURLOPT_POSTFIELDS, json_encode($parameters)); + else + curl_setopt($conn, CURLOPT_POSTFIELDS, null); + $data = null; + $response = curl_exec($conn); + if ($response !== false) { + $data = json_decode($response, true); + if (!$data) { + $data = array('error' => $response, "code" => curl_getinfo($conn, CURLINFO_HTTP_CODE)); + } + } + curl_close($conn); + if(isset($data['error'])) + { + throw new \Exception($data['error']); + } + if(empty($data)) + { + throw new \Exception("curl Could not reach the server: $path"); + } + return $data; + } + /** + * Added Class for consult + * @link https://github.com/feliperoberto/correios-cep/blob/master/correios.class.php + * + * @param string $url $url da busca + * @param array $post Dados via POST + * @param array $get Dados via GET + * @return string + */ + public function simple($url, $post=array(), $get=array()) + { + $url = explode('?', $url, 2); + + if(count($url)===2){ + $tmp = []; + parse_str($url[1], $tmp); + $get = array_merge($get, $tmp); + } + + $ch = curl_init($url[0]."?".http_build_query($get)); + curl_setopt ($ch, CURLOPT_POST, 1); + curl_setopt ($ch, CURLOPT_POSTFIELDS, http_build_query($post)); + curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, 1); + curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true); + $response = curl_exec ($ch); + curl_close($ch); + return $response; + } +} \ No newline at end of file diff --git a/src/Providers/CorreiosServiceProvider.php b/src/Providers/CorreiosServiceProvider.php new file mode 100755 index 0000000..6ea8741 --- /dev/null +++ b/src/Providers/CorreiosServiceProvider.php @@ -0,0 +1,44 @@ +registerConfig(); + } + + /** + * Register package config. + * + * @return void + */ + protected function registerConfig() + { + $this->mergeConfigFrom( + dirname(__DIR__) . '/Config/carriers.php', 'carriers' + ); + + $this->mergeConfigFrom( + dirname(__DIR__) . '/Config/system.php', 'core' + ); + } +} diff --git a/src/Resources/views/autocomplete.blade.php b/src/Resources/views/autocomplete.blade.php new file mode 100644 index 0000000..85009ad --- /dev/null +++ b/src/Resources/views/autocomplete.blade.php @@ -0,0 +1,29 @@ +@push('scripts') + +@endpush \ No newline at end of file