Jump to content
Nerdmonkey

Organização de itens em caixas para cálculo de frete nos Correios

Recommended Posts

A quanto tempo não posto aqui. As novidades do fórum estão bem bacanas... já volto com uma bomba rs

 

Estou adaptando um classe para arranjar os produtos do carrinho de um e-comerce em caixas para calcular o frete juntos aos correios.

Gostaria de sugestões dos colegas para implementar, sempre que um caixa atingir o limite, gerar uma nova caixa... a parte da comunicação com a API do correios está bem tranquilo.

O que tá pegando mesmo é essa parte da organização dos itens em várias caixas.

Vou deixar aqui o código completo que estou testando...

 

/

config.php

<?php

define("MIN_LARGURA", 11);
define("MAX_LARGURA", 105);
define("MIN_ALTURA", 2);
define("MAX_ALTURA", 105);
define("MIN_COMPRIMENTO", 16);
define("MAX_COMPRIMENTO", 105);
define("MIN_SOMA_CLA", 29);
define("MAX_SOMA_CLA", 200);

function dd($data) {
    echo '<pre>';
    var_dump($data);
    echo '</pre>';
}

index.php

<?php

require_once 'config.php';
require_once 'Boxes.php';

$cart = [
    [
        'title' => 'Book - The art of war',
        'A' => 25, 
        'L' => 70, 
        'C' => 90,
    ],
    [
        'title' => 'Book - The art of war',
        'A' => 25, 
        'L' => 70, 
        'C' => 90,
    ],
    [
        'title' => 'Book - The art of war',
        'A' => 25, 
        'L' => 70, 
        'C' => 90,
    ],
];

$boxes = new Boxes($cart);
dd($boxes->createBoxes());

Boxes.php

<?php

class Boxes {
    
    private $cart = [];
    
    private $box = [];
    
    private $box_properties = [];
    
    /**
     * __construct
     * 
     * @param array $cart
     */
    public function __construct($cart = []) 
    {
        $this->cart = $cart;
        $this->box_properties = [
            'altura' => 0,
            'largura' => 0,
            'comprimento' => 0,
            'qtd_itens' => 0,
            'message' => null,
            'volume' => 0,
            'volume_itens' => 0,
            'volume_vazio' => 0,
            'comprimento_remanescente' => 0,
            'largura_remanescente' => 0,
            'altura_remanescente' => 0
        ];
    }
    
    /**
     * Order items inside the box
     * 
     * @return array
     */
    public function orderBox()
    {
        foreach ($this->cart as $k => $item):
            $new_height = min($item['A'], $item['L'], $item['C']);
            $new_length = max($item['A'], $item['L'], $item['C']);
            $width = [$item['A'], $item['L'], $item['C']];
            
            sort($width) ;
            array_shift($width);
            array_pop($width);

            $item['L'] = isset($width[0]) ? $width[0] : $new_height;
            $item['A'] = $new_height ;
            $item['C'] = $new_length ;
            $item['LC'] = $item['L'] * $item['C'] ;
            $this->cart[$k] = $item;
        endforeach;
        
        usort($this->cart, function($a, $b){
            return $a['LC'] < $b['LC'];
        });

        return $this->cart ;
    }
    
    /**
     * Create and put items inside the box
     * 
     * @return array
     */
    public function createBoxes()
    {
        $this->cart = $this->orderBox();
        $this->box = json_decode(json_encode($this->box_properties,FALSE));
        $this->organizeItems();
        $this->box->volume = ($this->box->altura * $this->box->largura * $this->box->comprimento);
	$this->box->volume_vazio = $this->box->volume - $this->box->volume_itens;
        $this->minSpecifications();
        $this->errors();
        
        return $this->box;
    }

    private function organizeItems()
    {
        foreach ($this->cart as $item):
            $this->box->qtd_itens++;
            $this->box->volume_itens += ($item['A'] * $item['L'] * $item['C']);
            $this->allocateItems($item);      
            $this->box->altura += $item['A'];
            
            if($item['L'] > $this->box->largura):
                $this->box->largura = $item['L'];
            endif;

            if ($item['C'] > $this->box->comprimento):
                $this->box->comprimento = $item['C'];
            endif;

            $this->box->comprimento_remanescente = $this->box->comprimento;
            $this->box->largura_remanescente = $this->box->largura - $item['L'];
            $this->box->altura_remanescente = $item['A'];
        endforeach;
    }

    private function allocateItems($item)
    {
        if($this->box->comprimento_remanescente >= $item['C'] && $this->box->largura_remanescente >= $item['L']):
            if($item['A'] > $this->box->altura_remanescente):
                $this->box->altura += $item['A'] - $this->box->altura_remanescente ;
            endif;

            if($item['C'] > $this->box->comprimento):
                $this->box->comprimento = $item['C'];
            endif;

            $this->box->comprimento_remanescente = $this->box->comprimento - $item['C'];
            $this->box->largura_remanescente = $this->box->largura_remanescente - $item['L'] ;
            $this->box->altura_remanescente = $item['A'] > $this->box->altura_remanescente ? $item['A'] : $this->box->altura_remanescente ;
        endif;
    }
    
    private function minSpecifications()
    {
        if($this->box->altura > 0 && $this->box->altura < MIN_ALTURA):
            $this->box->altura = MIN_ALTURA ;
        endif;
        
        if($this->box->largura > 0 && $this->box->largura < MIN_LARGURA):
            $this->box->largura = MIN_LARGURA ;
        endif;
        
        if($this->box->comprimento > 0 && $this->box->comprimento < MIN_COMPRIMENTO):
            $this->box->comprimento = MIN_COMPRIMENTO ;
        endif;
    }
    
    private function errors() 
    {
        if($this->box->altura > MAX_ALTURA):
            $this->box->message = "Erro: Altura maior que o permitido.";
        endif;
        
	if($this->box->largura > MAX_LARGURA ):
            $this->box->message = "Erro: Largura maior que o permitido.";
        endif;
        
	if($this->box->comprimento > MAX_COMPRIMENTO ):
            $this->box->message = "Erro: Comprimento maior que o permitido.";
        endif;
        
	if(($this->box->comprimento + $this->box->comprimento + $this->box->comprimento) < MIN_SOMA_CLA):
            $this->box->message = "Erro: Soma dos valores C+L+A menor que o permitido.";
        endif;
		
	if(($this->box->comprimento + $this->box->comprimento + $this->box->comprimento) > MAX_SOMA_CLA):
            $this->box->message = "Erro: Soma dos valores C+L+A maior que o permitido.";
        endif;
    }
}

 

Share this post


Link to post
Share on other sites

A ideia talvez seria aplicar um método quase no mesmo estilo que você fez no método errors(), só que ao invés de disparar um erro, você abriria uma nova caixa caso o cliente fosse adicionando mais itens no carrinho.

Qual ideia você teve que não é simples? De repente se você colocar ela aqui a galera pode ajudar a simplificar ou dar novas ideias.

Share this post


Link to post
Share on other sites

A justificativa do meu argumento de não ser tão simples de resolver esse problema https://pt.wikipedia.org/wiki/Problema_da_mochila. Fora o fato de que ninguém, pelo menos que eu conheça, como programador, tenha feito parecido ou consiga palpitar sobre um caminha por onde seguir. Mas já imaginava que não seria fácil antes mesmo de começar. Dinamismo, de certa forma, na minha opinião,  torna o código reutilizável, e de certa forma, aumenta sua complexabilidade de desenvolvimento, para soluções bem elaboradas.

 

A sua ideia é boa, estou realmente trabalhando em cima disso atualmente. A lógica é verificar quando uma caixa atingiu seu limite > fechar esta caixa, tendo seus parâmetros para medir a cubagem definidos(A * C * L) > abrir uma nova caixa e começar a alocar os itens que não foram alocados na caixa anterior, pois excederiam os limites especificados pelos Correios.

 

Isso me daria margem para definir o valor do frete com base na cubagem de cada caixa. Posso ter 'n' caixas, cada uma com 'm' volume e peso distintos. Bem complexo, pelo menos pra mim, no momento. Mas acredito que não é impossível. :sweat_smile:

Share this post


Link to post
Share on other sites
8 horas atrás, Nerdmonkey disse:

A sua ideia é boa, estou realmente trabalhando em cima disso atualmente. A lógica é verificar quando uma caixa atingiu seu limite > fechar esta caixa, tendo seus parâmetros para medir a cubagem definidos(A * C * L) > abrir uma nova caixa e começar a alocar os itens que não foram alocados na caixa anterior, pois excederiam os limites especificados pelos Correios.

 

Isso me daria margem para definir o valor do frete com base na cubagem de cada caixa. Posso ter 'n' caixas, cada uma com 'm' volume e peso distintos. Bem complexo, pelo menos pra mim, no momento. Mas acredito que não é impossível.

 

Perfeito, a lógica ta bacana, vai verificando cada produto que entra, e eu acho que aquele método errors() que você fez é quase que meio caminho andado, pq pelo o que eu entendi ele verifica o tamanho das caixas e dispara os erros informando que tal largura/altura/comprimento da caixa foi excedido, só que, caso o cliente já esteja com a caixa cheia ou quase cheia e queira continuar comprando e o produto que ele adicionar não caber na caixa atual, chama um método tipo "newBox()", bota a caixa que já está cheia em um array nesse método e guarda ele, deixa o cliente continuar comprando e abrindo novas caixas se necessário.

Eu só não consigo te ajudar mais precisamente pq, sinceramente, eu não manjo muito do cálculo que é feito pra definir o tamanho/volume de uma caixa, pq pelo o que você falou você ta multiplicando todos eles, A*C*L, que no caso daria 157500 (25*70*90), como você extrai o valor final das caixas com esse resultado?

Share this post


Link to post
Share on other sites
Citar

Perfeito, a lógica ta bacana, vai verificando cada produto que entra, e eu acho que aquele método errors() que você fez é quase que meio caminho andado...

 

Estou trabalhando nisso. A lógica aqui é verificar quando a caixa exceder altura, largura ou comprimento. Normalmente, vai exceder em altura, porque os produtos são pequenos, ai na organização, consigo ir colocado os maiores por baixo e ir ajustando os demais no espaço remanescente. 

 

Citar

como você extrai o valor final das caixas com esse resultado?

 

É nessa questão mesmo que estou testando uma possível solução. Mas o conceito você pegou bem. É gerar a caixa, quando bater no limite, eu fecho a caixa e começo uma nova. Estou testando algumas formas de aplicar isso na classe. O trabalhoso está sendo armazenas os itens que cabem na caixa. Guardá-los e fechar a caixa. Pegar somente o que passa e ir colocando em novas caixas conforme a quantidade.

Share this post


Link to post
Share on other sites

Pensei em uma solução bem elegante e que se aproximaria bem do tamanho da embalagem necessária para trasnportar os produtos.

 

Você precisa inicialmente calcular o  cm³ (centimetro cúbico = multiplicar a altura, com a largura, com o comprimento) encontrando o volume que o produto ocupa. Apos fazer isso com cada produto, você soma os volumes e depois calcula a raiz cúbica desse valor, o resultado dessa raiz cúbica será cada uma das medidas da sua embalagem (altura, comprimento e largura) sempre gerará uma embalagem quadrada, mas não importa,  pois isso irá aproximar bem o valor do frete real. Caso ultrapasse a medida máxima permitida pelos correios, basta dividir em mais caixas e somar os fretes

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Similar Content

    • By marceloDiegues
      Olá, amigos.
      Por favor,  me ajude com a seguintes perguntas.
       
      Qual a complexidade de um projeto desse?
      Qual o preçp de um projeto desse tipo?
       
      Quero contratar algum profissional para criar um site que tenha as seguintes funcionabilidades:
       
      1- Cadastro de usuário;
      2- Login e senha;
      3- O site seria muito parecido com o www.qconcursos.com, o usuário resolveria questões online.
      Contudo, haveria a possibilidade de criar salas tipo aqueles bate-papo da &nbsp;UOL.
      Então, o usuário criaria salas de estudos, em que , resolveria questões e conseguiria se comunicar por chat com usuários que estejam na mesma sala.
       
      Exemplo em anexo:
       
       
       
       

    • By rvamecca
      Eu tenho um servidor que roda os PHP da versão 5.6 até a 8.0 com vários sites. Utilizo a versão FPM só que pesquisei na internet inteira e não consegui fazer rodar os arquivos customizados php.ini/.user.ini nos diretórios dos domínios. Chequei via phpinfo() e não carrega o arquivo customizado de configuração.
       
      Alguém pode me dar um help?
       
      Servidor Ubuntu 18.04 com Apache e as versões PHP 5.6, 7.0, 7.2, 7.4, 8.0 em FPM
    • By violin101
      Caros amigos, saudações...
       
      Fiz várias pesquisa, mas não consegui entender como devo fazer corretamente.
       
      Tenho um Cadastro de Produto/Clientes/etc.
       
      Gostaria de após clicar no Button ADICIONAR ou GRAVAR, quero mostrar na tela a seguinte mensagem:
      msg:
      Aguarde Processando...
       
      obs.: em alguns sistema até parece uma MODAL, com barra de progresso.
       
      Para impedir que o usuário fica Clicando nos Buttons.
       
      Alguém poderia me auxiliar de como devo fazer isso ?
       
      Grato,
       
      Cesar
    • By alysson122010
      Galera estou começando a trabalhar com datatables porem tenho uma dificuldade pq tipo até 200 registros por pagina é aceitavel mas penso quando tiver 2000 registro carregar tudo numa pagina so da errado pq é muitos dados e pode travar tudo.
      Como posso fazer para listar com limite por pagina ou alguma maneira para poder colocar varios dados sem travar.
       
      estou usando assim:
      <script type="text/javascript">        $(document).ready(function() {             $('#example').DataTable({         "order": [[ 0, "desc" ]],         "language": {             "url": "//cdn.datatables.net/plug-ins/1.10.21/i18n/Portuguese-Brasil.json"         }     });         } );        </script> <table id="example" class="table table-striped table-bordered" style="width:100%">         <thead>             <tr>                 <th>Name</th>                 <th>Position</th>                 <th>Office</th>                 <th>Age</th>                 <th>Start date</th>                 <th>Salary</th>             </tr>         </thead>         <tbody>             <tr>                 <td>Tiger Nixon</td>                 <td>System Architect</td>                 <td>Edinburgh</td>                 <td>61</td>                 <td>2011/04/25</td>                 <td>$320,800</td>             </tr>             <tr>                 <td>Garrett Winters</td>                 <td>Accountant</td>                 <td>Tokyo</td>                 <td>63</td>                 <td>2011/07/25</td>                 <td>$170,750</td>             </tr>             <tr>                 <td>Ashton Cox</td>                 <td>Junior Technical Author</td>                 <td>San Francisco</td>                 <td>66</td>                 <td>2009/01/12</td>                 <td>$86,000</td>             </tr>             <tr>                 <td>Cedric Kelly</td>                 <td>Senior Javascript Developer</td>                 <td>Edinburgh</td>                 <td>22</td>                 <td>2012/03/29</td>                 <td>$433,060</td>             </tr>             <tr>                 <td>Airi Satou</td>                 <td>Accountant</td>                 <td>Tokyo</td>                 <td>33</td>                 <td>2008/11/28</td>                 <td>$162,700</td>             </tr>             <tr>                 <td>Brielle Williamson</td>                 <td>Integration Specialist</td>                 <td>New York</td>                 <td>61</td>                 <td>2012/12/02</td>                 <td>$372,000</td>             </tr>             <tr>                 <td>Herrod Chandler</td>                 <td>Sales Assistant</td>                 <td>San Francisco</td>                 <td>59</td>                 <td>2012/08/06</td>                 <td>$137,500</td>             </tr>             <tr>                 <td>Rhona Davidson</td>                 <td>Integration Specialist</td>                 <td>Tokyo</td>                 <td>55</td>                 <td>2010/10/14</td>                 <td>$327,900</td>             </tr>             <tr>                 <td>Colleen Hurst</td>                 <td>Javascript Developer</td>                 <td>San Francisco</td>                 <td>39</td>                 <td>2009/09/15</td>                 <td>$205,500</td>             </tr>         </tbody>         <tfoot>             <tr>                 <th>Name</th>                 <th>Position</th>                 <th>Office</th>                 <th>Age</th>                 <th>Start date</th>                 <th>Salary</th>             </tr>         </tfoot>     </table> <script type="text/javascript" language="javascript" src="https://cdn.datatables.net/1.10.22/js/jquery.dataTables.min.js"></script> <script type="text/javascript" language="javascript" src="https://cdn.datatables.net/1.10.22/js/dataTables.bootstrap4.min.js"></script>  
    • By AlexandrePrezzi
      Seguinte
      Tenho uma página chamada  "teste.php" nessa página tem um formulário com vários campos que o usuário usa para fazer um filtro dos campos a serem pesquisado...
       
      Ao clicar no Pesquisar (submit) ... o action da página faz a seguinte ação
       
      script type="text/javascript"> $(function($){ $('#meuFormulario').submit(function(){ var dados = jQuery(this).serialize(); jQuery.ajax({ type: "POST", url: "src/controller/request_teste.php", data: dados, cache: false, beforeSend: function() { $('#resultPesq').html("Carregando..."); }, success: function(e) { //window.alert(e); $('#resultPesq').html(e); }, error: function() { $('#resultPesq').html('Não foi encontrado dados!'); } }); return false; }); }); </script> O arquivo "request_teste.php", é quem recebe os dados do POST e faz o  tratamento desses dados....
       
      Ao final desse arquivo tem um  require_once 'result_teste.php' que vem a ser o arquivo onde irá mostrar o resultado da pesquisa.
       
      Nesse arquivo eu fiz uma páginação ao final do resultado.
       
      Entao primeiramente o link que estou acessando é 
       
      principal.php?link=teste.php  (abre a pagina com o formulário)
      ao clicar em pesquisar o link nao muda
       
      quando clico em página 2, é feito um refresh e a url fica principal.php?link=teste.php&pag=2
       
      O que acontece é que como a página faz um refresh eu perco todos dados do meu POST e tambem preciso clicar no botão pesquisar pra carregar os dado da página 2.
       
      Alguem sabe como ajustar isso ?

      Se precisarem de mais informações me avisem
       
       
       
×

Important Information

Ao usar o fórum, você concorda com nossos Terms of Use.