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 k9studio
      Olá Amigos,
      se alguem puder dar um help fico muito grato
      seguinte:
      estou criando um sistema de login com cookie
      todas as paginas fica no patch
      www/htdocs/script/
      quando logar no dominio.com.br liberar o acesso no  cliente.dominio.com.br tambem
      acesso:dominio.com.br
      ou
      quando logar no cliente.dominio.com.br liberar o acesso no dominio.com.br tambem
      acesso:cliente.dominio.com.br
      e guando deslogar quebrar conxao com os dois
      existe uma maneira de fazer isso?
       
    • By Kefatif
      Prezados boa tarde.
       
      Preciso bloquear a edição de um date input de forma que só seja possível selecionar a data através do calendário.
       
      Alguém pode me ajudar?
       
      Utilizo php, html e js.
       
      <input type="date" value="<?php echo $data ?>" name="datacoleta" class="form-control" required style="width:100%;">  
      Agradeço desde já.
    • By Kefatif
      Prezados boa tarde.
       
      Preciso bloquear a edição de um date input de forma que só seja possível selecionar a data através do calendário.
       
      Alguém pode me ajudar?
       
      Utilizo php, html e js.
       
      <input type="date" value="<?php echo $data ?>" name="datacoleta" class="form-control" required style="width:100%;">  
      Agradeço desde já.
    • By Thiago Duarte
      Eu tenho uma página que abri um alert ao clicar no link , só que nao cadastra e nem funciona o login.
       
       <div class="btn-box">          <a class="btn btn-color venobox vbox-item" data-toggle="modal" href="javascript:void(0)" onclick="openRegisterModal();">Start now Free </a>             <img src="images/seta.png"> </div>  
      <div class="modal-body">                               <div class="box">                                  <div class="content">                                     <!-- Login Form -->                                     <div class="loginBox">                                        <form id="login-modal" role="form"  method="post" action="#">                                           <input type="hidden" name="param" value="logar" />                                           <!-- Success/Alert Notification -->                                           <p class="lm-success"><i class="icon icon_check_alt2"></i> <strong>Congratulation! Login modal validation is working. Implement your code.</strong></p>                                           <p class="lm-failed"><i class="icon icon_close_alt2"></i><strong> Something went wrong! Insert correct value.</strong></p>                                           <!-- Input Fields -->                                           <input id="lm-email" class="form-control input-lg" type="text" placeholder="Email" name="email" required="">                                           <input id="lm-password" class="form-control input-lg" type="password" placeholder="Password" name="senha" required="">                                           <!-- Login Button -->                                           <input type="submit" class="btn btn-color" value="Login">                                           <!-- <button class="btn btn-color">Login</button> -->                                        </form>                                     </div>                                     <!-- /End Login Form -->                                  </div>                               </div>                               <!-- /End Login Form Box -->                               <div class="box">                                  <!-- Signup Form -->                                  <div class="content registerBox" style="display:none;">                                     <form id="signup-modal" role="form" method="post" action="?go=cadastrar">                                        <!-- Success/Alert Notification -->                                        <p class="sm-success"><i class="icon icon_check_alt2"></i> <strong>Congratulation! Signup modal validation is working. Implement your code.</strong></p>                                        <p class="sm-failed"><i class="icon icon_close_alt2"></i><strong> Something went wrong! Insert correct value.</strong></p>                                        <!-- Input Fields -->                                        <input id="sm-email" class="form-control input-lg" type="text" placeholder="Email" name="email" required="">                                        <input id="sm-password" class="form-control input-lg" type="password" placeholder="password" name="password">                                        <input id="sm-confirm" class="form-control input-lg" type="password" placeholder="Repeat password" name="senha-confirm">                                        <!-- Signup Button -->                                        <!--  <button class="btn btn-color">Create an account</button> -->                                        <input type="submit" class="btn btn-color" value="Create an account">                                     </form>                                  </div>                                  <!-- /End Signup Form -->                               </div>                               <!-- /End Signup Form Box -->                            </div>  
      e em baixo do </html> coloquei
        <?php           $param = (empty($_POST['param'])) ? 'error' : $_POST['param'];           if($param == 'logar'){       //if($_POST['param'] == 'logar'){             $email = $_POST['email'];             $password = $_POST['password'];             $query1 = mysql_num_rows(mysql_query("SELECT * FROM usuario WHERE email = '$email' AND password = '$password'")) or die(mysql_error());             if($query1 == 1){           // print "<script>alert('logou');</script>";              print "<script>window.location.replace('dashboard/index.php');</script>";           }else{              echo "<script>alert('User and password do not match.'); history.back();</script>";           }        }        if(@$_GET['go'] == 'cadastrar'){           // $dominio_gratis = $_POST['dominio_gratis'];          $email = $_POST['email'];          $password = $_POST['password'];          $date_register = date("m-d-Y");                // if(empty($dominio_gratis)){           //     echo "<script>alert('Preencha todos os campos para se cadastrar.'); history.back();</script>";           // }else          if(empty($email)){           echo "<script>alert('Fill in all the fields to register.'); history.back();</script>";            }elseif(empty($password)){           echo "<script>alert('Fill in all the fields to register.'); history.back();</script>";        }else{           $query1 = mysql_num_rows(mysql_query("SELECT * FROM usuario WHERE email = '$email'"));           if($query1 == 1){            echo "<script>alert('User already exists.'); history.back();</script>";          }else{            mysql_query("insert into usuario (email, password, date_register, plan) values ('$email','$password','$date_register', '0')");            header("Location: dashboard/dashboard.php");         }      }   }   ?>  
      Alguem pode ajudar?
    • By ricardocelso
      Pessoal boa tarde,  tenho um pc com windows 10, oque preciso instalar para programar em php desde ja muito obrigado.
×

Important Information

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