Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

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;
    }
}

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

Está lá em cima. Nas constantes. Solução, até onde pesquisei, nada simples.

Mas como não desisto fácil... bora continuar tentando :pensive:

Compartilhar este post


Link para o post
Compartilhar em outros 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.

Compartilhar este post


Link para o post
Compartilhar em outros 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:

Compartilhar este post


Link para o post
Compartilhar em outros 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?

Compartilhar este post


Link para o post
Compartilhar em outros 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.

Compartilhar este post


Link para o post
Compartilhar em outros 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

Compartilhar este post


Link para o post
Compartilhar em outros sites

  • Conteúdo Similar

    • Por Rafael_Ferreira
      Não consigo carregar a imagem do captcha do meu formulário. Foi testado com o xampp e easyphp. Também não carregou a imagem de outros captcha. 
       
       
    • Por luiz monteiro
      Olá, tudo bem?
       
      Estou melhorando meu conhecimento em php e mysql e, me deparei com o seguinte. A tabela da base de dados tem um campo do tipo varchar(8) o qual armazena números. Eu não posso alterar o tipo desse campo. O que preciso é fazer um select para retornar o números que contenham zeros a direita ou a esquerda.
      O que tentei até agora
       
      Ex1
      $busca = $conexao->prepare("select campo form tabela where (campo = :campo) ");
      $busca->bindParam('campo', $_REQUEST['campo_form']);
       
      Se a direita da string $_REQUEST['campo_form'] termina ou inicia com zero ou zeros, a busca retorna vazio.
      Inseri dados numéricos, da seguinte maneira para testar: 01234567;  12345670: 12345678: 12340000... entre outros nessa coluna. Todos os valores que não terminam ou não iniciam com zero ou zeros, o select funciona.
       
       
      Ex2
      $busca = $conexao->prepare("select campo form tabela where (campo = 0340000) ");
      Esse número está cadastrado, mas não retorna.
       
      Ex3
      $busca = $conexao->prepare("select campo form tabela where (campo = '02340001' ) ");
      Esse número está cadastrado, mas não retorna.
       
       
      Ex4
      $busca = $conexao->prepare("select campo form tabela where (campo like 2340000) ");
      Esse número está cadastrado, mas não retorna.
       
      Ex5
      $busca = $conexao->prepare("select campo form tabela where (campo like '12340000') ");
      Esse número está cadastrado, mas não retorna.
       
      Ex6
      $busca = $conexao->prepare("select campo form tabela where (campo like '"12340000"' ) ");
      Esse número está cadastrado, mas não retorna.
       
       
      Ex7
      $busca = $conexao->prepare("select campo form tabela where (campo like :campo) ");
      $busca->bindParam('campo', $_REQUEST['campo_form'])
      Não retorna dados.
       
      O  $_REQUEST['campo_form'] é envio via AJAX de um formulário. 
      Usei o gettype para verificar o post, e ele retorna string.
      Fiz uma busca com número 12345678 para verificar o que o select retorna, e também retrona como string.
       
      Esse tipo de varchar foi usado porque os números que serão gravados nesse campo,  terão zeros a direita ou na esquerda. Os tipos number do mysql não gravam zeros, então estou usando esse. O problema é a busca.
      Agradeço desde já.
       
       
    • Por daemon
      Boa tarde,
       
      Eu tenho uma rotina que faz uma leitura do arquivo .xml de vários sites.

      Eu consigo pegar o tópico e a descrição, e mostrar a imagem que esta na pagina do link.
      Para isso utilizo esta função:
      function getPreviewImage($url) { // Obter o conteúdo da página $html = file_get_contents($url); // Criar um novo objeto DOMDocument $doc = new DOMDocument(); @$doc->loadHTML($html); // Procurar pela tag meta og:image $tags = $doc->getElementsByTagName('meta'); foreach ($tags as $tag) { if ($tag->getAttribute('property') == 'og:image') { return $tag->getAttribute('content'); } } // Se não encontrar og:image, procurar pela primeira imagem na página $tags = $doc->getElementsByTagName('img'); if ($tags->length > 0) { return $tags->item(0)->getAttribute('src'); } // Se não encontrar nenhuma imagem, retornar null return null; } // Uso: $url = "https://example.com/article"; $imageUrl = getPreviewImage($url); if ($imageUrl) { echo "<img src='$imageUrl' alt='Preview'>"; } else { echo "Nenhuma imagem encontrada"; }  
      Mas estou com um problema, esta funcão funciona quando coloco em uma pagina de teste.php. Preciso mostrar em uma página inicial diversas fotos de todos os links. (No caso acima só funciona 1).
    • Por violin101
      Caros amigos, saudações.
       
      Por favor, me permita tirar uma dúvida com os amigos.

      Tenho um Formulário onde o Usuário digita todos os Dados necessários.

      Minha dúvida:
      --> como faço após o usuário digitar os dados e salvar, o Sistema chamar uma Modal ou mensagem perguntando se deseja imprimir agora ?

      Grato,
       
      Cesar
    • Por Carcleo
      Tenho uma abela de usuarios e uma tabela de administradores e clientes.
      Gostaria de uma ajuda para implementar um cadastro
       
      users -> name, login, passord (pronta) admins -> user_id, registratiom, etc.. client -> user_id, registratiom, etc...
      Queria ajuda para extender de user as classes Admin e Client
      Olhem como estáAdmin
      <?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class Admin extends User {     use HasFactory;            protected $fillable = [         'name',         'email',         'password',         'registration'     ];      private string $registration;     public function create(         string $name,          string $email,          string $password,         string $registration     )     {         //parent::create(['name'=>$name, 'email'=>$email, 'password'=>$password]);         parent::$name = $name;         parent::$email = $email;         parent::$password = $password;         $this->registration = $registration;     } } User
      <?php namespace App\Models; // use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Illuminate\Database\Eloquent\Relations\BelongsToMany; class User extends Authenticatable {     /** @use HasFactory<\Database\Factories\UserFactory> */     use HasFactory, Notifiable;     static string $name;     static string $email;     static string $password;     /**      * The attributes that are mass assignable.      *      * @var list<string>      */     protected $fillable = [         'name',         'email',         'password',     ];          /**      * The attributes that should be hidden for serialization.      *      * @var list<string>      */     protected $hidden = [         'remember_token',     ];     /**      * Get the attributes that should be cast.      *      * @return array<string, string>      */     protected function casts(): array     {         return [             'email_verified_at' => 'datetime',             'password' => 'hashed',         ];     }          public function roles() : BelongsToMany {         return $this->belongsToMany(Role::class);     }       public function hasHole(Array $roleName): bool     {                 foreach ($this->roles as $role) {             if ($role->name === $roleName) {                 return true;             }         }         return false;     }         public function hasHoles(Array $rolesName): bool     {                 foreach ($this->roles as $role) {             foreach ($rolesName as $rolee) {             if ($role->name === $rolee) {                 return true;             }          }         }         return false;     }         public function hasAbility(string $ability): bool     {         foreach ($this->roles as $role) {             if ($role->abilities->contains('name', $ability)) {                 return true;             }         }         return false;     }     } Como gravar um Admin na tabela admins sendo que ele é um User por extensão?
      Tentei assim mas é claro que está errado...
      public function store(Request $request, Admin $adminModel) {         $dados = $request->validate([             "name" => "required",             "email" => "required|email",             "password" => "required",             "registration" => "required"         ]);         $dados["password"] =  Hash::make($dados["password"]);                  $admin = Admin::where("registration",  $dados["registration"])->first();                  if ($admin)              return                    redirect()->route("admin.new")                             ->withErrors([                                 'fail' => 'Administrador já cadastrados<br>, favor verificar!'                   ]);                            $newAdmin = $adminModel->create(                                    $dados['name'],                                    $dados['email'],                                    $dados['password'],                                    $dados['registration']                                 );         dd($newAdmin);         $adminModel->save();         //$adminModel::create($admin);                  return redirect()->route("admin.new")->with("success",'Cadastrado com sucesso');     }  
×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.