Ir para conteúdo
Fórum Script Brasil

Frank K Hosaka

Membros
  • Total de itens

    1.630
  • Registro em

  • Última visita

Tudo que Frank K Hosaka postou

  1. Essa é uma pergunta difícil de responder, o Livewire é dividido em duas partes, o Componente e o Blade. O Blade começa com um <div> e termina com um </div>, logo o único lugar para colocar um código JavaScript é dentro desse marcador. A minha intuição me disse que isso vai dar dor de cabeça, assim usei o método da tentativa e erro. Eu embuti o código JavaScript dentro do componente HTML, assim: arquivo resources > views > livewire > pagar.blade.php (parcial) <div class="w-[180px] truncate text-gray-500" onclick="this.classList.toggle('truncate')"> {{ $pendencia['lcto'].":".$pendencia['hist']}} </div> Tentei usar o comando wire:click, mas isso acabou expandindo todas as linhas, quando eu queria expandir apenas uma linha, a que foi clicado. Esse truque deu certo, e o DevTools do Chrome não apontou nenhum erro.
  2. O meu primeiro roteador só funcionava com um argumento, com a ajuda do Copilot mudei para ele suportar mais de um argumento. Mas quando um dos argumentos tinha um ponto no meio do caminho, o roteador separava o que era um valor em vários argumentos. O Copilot fez auditoria no meu roteador, e descobriu que usei o comando $_GET indevidamente, sem uma chave. O meu roteador é assim: <?php spl_autoload_register(fn ($class) => require str_replace('\\', DIRECTORY_SEPARATOR, strtolower($class)) . '.php'); $rota = 'login_login'; $parametros = []; if ($_GET) { $chaveCompleta = key($_GET); // Ex: Login_menu_param1_param2_param3 if (strpos($chaveCompleta, '_') === false) { exit; // proteção contra valores inválidos } $rota=$chaveCompleta; } $segmentos = explode('_', $rota); $nomeControle = $segmentos[0]; $metodo = $segmentos[1]; $parametros = array_slice($segmentos, 2); $controle = new $nomeControle(); call_user_func_array([$controle, $metodo], $parametros); e o Copilot disse que o correto é assim: <?php spl_autoload_register(fn ($class) => require str_replace('\\', DIRECTORY_SEPARATOR, strtolower($class)) . '.php'); $rota = $_GET['rota'] ?? 'login_login'; $segmentos = explode('_', $rota); $nomeControle = $segmentos[0]; $metodo = $segmentos[1]; $parametros = array_slice($segmentos, 2); $controle = new $nomeControle(); call_user_func_array([$controle, $metodo], $parametros); Ainda não testei a nova sugestão do Copilot, estou tentando me recompor. Que vergonha!
  3. Frank K Hosaka

    O roteador

    Eu estava me referindo a esse código: <?php spl_autoload_register(fn ($class) => require str_replace('\\', DIRECTORY_SEPARATOR, strtolower($class)) . '.php'); $rota = 'login_login'; $parametros = []; if ($_GET) { $chaveCompleta = key($_GET); // Ex: Login_menu_param1_param2_param3 if (strpos($chaveCompleta, '_') === false) { exit; // proteção contra valores inválidos } $rota=$chaveCompleta; } $segmentos = explode('_', $rota); $nomeControle = $segmentos[0]; $metodo = $segmentos[1]; $parametros = array_slice($segmentos, 2); $controle = new $nomeControle(); call_user_func_array([$controle, $metodo], $parametros); mas o Copilot disse que o código está equivocado, eu não posso usar diretamente a variável $_GET sem nenhuma chave.
  4. Eu ainda não tenho a menor noção sobre segurança na programação, o máximo que eu consegui foi criar a seguinte rotina no arquivo menuView.php que é invocado pelos outros arquivos: <?php if(!isset($_SESSION['id'])) {header('Location: ?Login_login');} ?> O Copilot comentou que ele parece confuso, ele esperava coisa do tipo <?php if(!isset($_SESSION['id'])) {header('Location: login.php');} ?> Eu comentei que isso não iria funcionar no meu caso. No meu caso, iria funcionar se fosse assim: <?php if(!isset($_SESSION['id'])) {header('Location: index.php');} ?> Mas eu acredito que o nível de segurança é o mesmo.
  5. <details> é uma excelente ferramenta para mostrar os detalhes de um item, desde que você não invente de colocar um monte de coisas dentro do <summary>, foi o que eu fiz, assim precisei abandonar essa ferramenta para criar a seguinte gambiarra: <script src="https://cdn.tailwindcss.com"></script> <script> function exibir(element) { const filhos=element.querySelectorAll("div") filhos.forEach(filho => { filho.classList.toggle("hidden"); }) } </script> <?php $historico="Detalhe da lista"; ?> <div class="w-[200px] m-0 m-auto" onclick="exibir(this)"> Lista <div class="hidden"><?=$historico?></div> <div class="hidden"><?=$historico?></div> </div> O Copilot é uma excelente ferramenta para fazer gambiarra.
  6. Faz muito tempo que tenho pensado no meu projeto orçamento dentro de um celular. O problema é que a tela do celular é bem pequena, mal dá para colocar duas colunas, no modo retrato. No Galaxy Note 10, eu consegui <div class="w-[630px]"></div> no modo paisagem e é baseado nesse limite é que estou fazendo o meu projeto. O problema é que não dá para exibir toda a informação numa só coluna, posso mostrar alguma coisa usando o CSS truncate do Tailwind. Mas e se o usuário quiser ver tudo? Desde 2020 é que estou quebrando a cabeça, só hoje é que surgiu essa ideia: <script src="https://cdn.tailwindcss.com"></script> <script> function expandir() { const descricao = document.getElementById("descricao"); descricao.classList.toggle("truncate"); } </script> <?php $historico="Vamos ver se isso funciona"; ?> <div class="w-[100px] m-0 m-auto"> <div class="w-[100px] odd:bg-gray-200">Teste</div> <div id="descricao" class="w-[100px] truncate" onclick="expandir()"><?=$historico?></div> <div class="w-[100px] odd:bg-gray-200">Teste</div> </div> / ==================== / A ideia é péssima, coloquei o código JavaScript no config.php, e em outro código tentei invocar a função expandir. Não deu certo. O código só funciona se existir apenas um único <div> com o id="descricao". Isso é bem constrangedor, o Copilot corrigiu o código: <script src="https://cdn.tailwindcss.com"></script> <script> function expandir(element) { element.classList.toggle("truncate"); } </script> <?php $historico="Vamos ver se isso funciona"; ?> <div class="w-[100px] m-0 m-auto"> <div class="w-[100px] odd:bg-gray-200">Teste</div> <div class="w-[100px] truncate" onclick="expandir(this)"><?=$historico?></div> <div class="w-[100px] odd:bg-gray-200">Teste</div> </div> /===== Outra ideia péssima, eu tive que tirar a função expandir( ) do JavaScript do config.php e colocar em cada código que precisava dessa função. Usar o config.php pareceu uma boa ideia, mas ele acabou aparecendo no cabeçalho de um arquivo csv e a Bling se recusou a receber por estar fora do layout esperado.
  7. Desde que o Copilot surgiu é que eu tento pintar a borda do <input> com Tailwind, e eu não consegui. Para pintar a borda, a solução é "border border-blue-700", o problema é na hora do <input> receber o foco, ele fica preto e grosso, e eu queria azul e grosso. O Copilot sempre repetiu a mesma solução que não resolvia "focus:border-2 focus:border-blue-700 focus:outline-none". Decidi abandonar o Copilot, e usar o velho método da tentativa e erro: <input class="border border-blue-700 focus:outline-blue-700"> O Copilot comentou que o meu código está incorreto, mas ele funciona! Eu estou usando <script src="https://cdn.tailwindcss.com"></script> ao invés do output.css no código que define a página de layout de todo projeto. O DevTools do Chrome reclama que eu não posso usar o cdn na produção, mas é o único jeito que eu encontrei para fazer o Tailwind funcionar no PHP.
  8. A grande maioria dos celulares não têm teclado físico e nem mouse, assim eu perguntei ao Copilot quantos eventos sobram para o programador trabalhar com o celular, e ele respondeu: [Eventos de toque] touchstart, touchmove, touchend e touchcancel. Há outros tipos de eventos, eu comecei a explorar o touchmove: <div class="w-[70px] text-right" title='<?=$grupo->pessoa?>' ontouchmove="alert('o cliente é o <?=$grupo->pessoa?>')" > <?=$grupo->codp?> </div>
  9. Não sei exatamente como o Laravel faz a rotina do login, mas hoje eu mudei a rotina no PHP de tal forma que conduz o usuário para as opções ao invés de fazer login novamente: <?php class Login { // listagem parcial function login() { if(isset($_SESSION['id']) && isset($_SESSION['nome'])) { return view('menuView'); } $mensagem=""; $email=""; return view('loginView',['mensagem'=>$mensagem,'email'=>$email]); } }
  10. <div class="text-green-700">Texto verde</a> tentei usar ./tailwindcss.exe -i input.css -o output.css --content "./*.php", mas não consegui o resultado desejado. Voltei a usar <script src="https://cdn.tailwindcss.com"></script> no <head> do arquivo que serve como layout para todas as páginas dependentes. O DevTools do Google Chrome reclama que não pode usar o CDN na produção, mas pelo menos ele funciona.
  11. Eu não manjo nada de Java Script, assim eu comecei o trabalho com o Copilot. Eu precisava mudar o foco para o topo da página no canto esquerdo, depois de usar o modal no celular. O Copilot deu dezenas de códigos e explicações, mas nenhuma funcionou. O Copilot usa o raciocínio lógico, ele pensa em HTML. Já o meu raciocínio é muito estreito, eu só penso no <div>, assim usei o Java Script na base da tentativa e erro: arquivo resources > views > livewire > diario-lcto.blade.php <div ondblclick="alert('olá mundo')"> etc etc </div> Depois de dezenas de tentativas, esse foi o único que deu certo. Acredito que o Livewire não quer ninguém usando o marcador <script></script> dentro do Blade, assim a minha ideia é esconder o Java Script dentro de um elemento HTML. Eu desisti de ir no topo da tela, então decidi pegar o primeiro controle perto do topo, <input wire:model="dia">, e aprendi com DevTools do Google Chrome que essa sintaxe está errada. Assim resolvi dois problemas de uma só vez assim: <input id="foco" wire:model="dia">. wire:model é um truque de mágica do Livewire, tudo o que você digitar nesse input, ele vai para a variável $dia, ou tudo o que fizer na variável $dia vai aparecer no <input id="foco" wire:model="dia">, sem precisar de nenhum <form>. E o código final ficou assim: <div ondblclick="document.getElementById('foco').focus()"> etc etc </div> O Copilot sugeriu turbinar o Laravel Livewire com Alpine, mas eu disse que sou contra. Se eu levei quatro horas para um código do Java Script funcionar, imagine quanto tempo vou levar para encontrar um erro num gigantesco framework cheio de extensões para todos os lados. É por isso que eu gosto do PHP, o Laravel é formidável mas tenho medo de mexer nele.
  12. Tentei usar o Copilot para localizar o arquivo que define a rota para o usuário que já está logado (ou seja, você fecha o navegador, depois você abre, chama o projeto e, ao invés de ir para o login você acaba no famoso painel do "dashboard"), mas o Copilot ficou preso numa função que verifica a sessão e isso eu não achei, até que ele chegou no web.php e sugeriu isso: <?php use Illuminate\Support\Facades\Auth; Route::get('/', function () { if (Auth::check()) { return Auth::id() == 1 ? redirect()->route('previsao') : redirect()->route('orcamento'); } return redirect()->route('login'); }); A sugestão do Copilot é brilhante, funcional, mas nada óbvio. Eu consegui redirecionar o usuário depois do login, eu só não sei como fazer isso depois que ele estiver logado. Até eu encontrar a sugestão do Copilot, eu fiz essa gambiarra: Route::get('outros/{opcao?}',Outros::class); Route::get('outrosTeste',function(){return redirect('outros/menu');})->name('dashboard'); Ou seja, criei uma rota fictícia, onde o usuário logado vai parar na tela do menu, mas eu queria mesmo uma página para o administrador e outra página para o resto da turma. A solução do Copilot é engenhosa, mas não faço a menor ideia de como ele funciona.
  13. 1. Baixar o arquivo tailwindcss-windows-x64.exe em https://github.com/tailwindlabs/tailwindcss/releases 2. Renomear o arquivo para tailwindcss.exe e mover para a pasta do projeto. 3. editar o arquivo index.php para teste: index.php <link rel="stylesheet" href="output.css"> <div class="text-red-500">Esse texto tem que aparecer em vermelho</div> <?php exit; // o código original é empurrado para baixo 4. criar o arquivo input.css @import "tailwindcss"; 5. executar no terminal o comando .\tailwindcss.exe -i input.css -o output.css --content "./*.php"
  14. Frank K Hosaka

    O roteador

    O meu projeto orçamento está codificado em Livewire e também no PHP puro. O Livewire é super bacana, mas tem muita coisa que ainda não domino: eu aperto o botão, e aparece o botão com uma imagem girando, girando e girando. Ainda não sei como consertar isso. No PHP puro eu uso as chamadas para as instâncias de classe, mas ao invés de usar as famosas pastas Models Views and Controllers, eu não uso nenhuma delas, tudo está no diretório raiz, eu vou navegando entre os arquivos com o controlador no index.php. Eu tive a sorte de encontrar o controlador aqui no fórum Script Brasil, mas ele só suportava um argumento. Pedi ajuda para o Copilot para o roteador suportar vários argumentos. Eu ainda não testei, mas achei o código bonito a beça: <?php require 'config.php'; $rota = 'login_login'; $parametros = []; if ($_GET) { $chaveCompleta = key($_GET); // Ex: Login_menu_param1_param2_param3 if (strpos($chaveCompleta, '_') === false) { exit; // proteção contra valores inválidos } $rota=$chaveCompleta; } $segmentos = explode('_', $rota); $nomeControle = $segmentos[0]; $metodo = $segmentos[1]; $parametros = array_slice($segmentos, 2); $controle = new $nomeControle(); call_user_func_array([$controle, $metodo], $parametros);
  15. Isso está um pouco fora do tópico do PHP, mas eu tenho um código que lê o arquivo xml da NF Eletrônica, e isso facilita na hora de dar entrada no estoque bem como atualizar custo e por tabela o preço de venda do produto. O problema é como obter o arquivo xml. Na maioria das vezes, eu uso a cópia da confirmação do pedido para dar entrada no produto, mas nesse caso tenho que digitar cada código, quantidade, valor, é um serviço chato e bem demorado. Muitas vezes eu perguntei ao Copilot se era possível obter as notas fiscais que foram emitidas contra a empresa no portal da Nota Fiscal Eletrônica, e ele disse sim várias e várias vezes, só que ele nunca me disse que precisa seguir a rota Serviços > Manifestação do Destinatário, e eu descobri hoje na base da tentativa e erro. Eu gostei desse serviço, ele entrega a lista de todas as notas fiscais que foram emitidas contra a empresa nos últimos quinze dias. Só basta ter o certificado digital.
  16. Eu tenho um código mais ou menos assim: blade @foreach($pendencias as $index => $pendencia) @if($pendencia['div1']==1) <div wire:click="mostrar({{$index}})">ola mundo</div> @else // o resto do código <div class="w-[110px] text-right" wire:click="mostrar({{$index}})"> {{ dec($pendencia['debito']) }} </div> // o resto do código @endif @endforeach component function mostrar($indicador) { if($this->pendencias[$indicador]['div1']==0) { return $this->pendencias[$indicador]['div1']=1; } else { return $this->pendencias[$indicador]['div1']=0; } } Esse é o clássico problema do modal. Eu tenho uma lista de pendência, onde aparece o valor da pendência e o nome de quem está me cobrando, só que eu precisava do número do lançamento contábil ou o número da nota fiscal ou qual a parcela que estou pagando, tudo isso dá para colocar num modal. Mas hoje eu pensei em colocar essa informação na mesma linha onde aparece as informações. E deu certo! Esse Livewire é fantástico! A seguir a listagem completa: arquivo resources > views > livewire > pagar.blade.php <div> @if(auth()->user()->id==1) <input wire:model.live="doc1" size="5" autocomplete="off" class="border-none rounded p-2 py-0"> <input wire:model.live="doc2" size="5" autocomplete="off" class="border-none rounded p-2 py-0"> <input type="submit" wire:click="ocultar" value="Ocultar Pendências"> @endif <div class="flex bg-gray-200 mt-2"> <div class="w-[117px] ml-3 text-center">Vencimento</div> <div class="w-[50px] text-right">Docto</div> <div class="w-[110px] text-right">Pendência</div> @if(auth()->user()->id==1) <div class="w-[10px] text-right px-2">R</div> @endif <div class="w-[336px] px-2 border">Pessoa</div> </div> @if(auth()->user()->id==1) @foreach($pendencias as $index => $pendencia) @if($pendencia['div1']==1) <div wire:click="mostrar({{$index}})" class="bg-red-200"> {{"Histórico: Lçto ".$pendencia['lcto']." ".$pendencia['hist']}} </div> @else <div class="even:bg-gray-200"> <div class="flex"> <div class="w-[117px] ml-3 text-right"> <input type=date wire:model.live="pendencias.{{$index}}.vcto" onclick=showPicker() wire:change="atualizaVcto({{$pendencia['docto']}},{{$index}})" class="w-[117px] bg-transparent text-gray-500 font-semibold rounded py-0 border-none"> </div> <div class="w-[50px] text-right"> <div wire:click="selecionarDocto({{$pendencia['docto']}})" class="text-right"> {{ $pendencia['docto'] }} </div> </div> @if($pendencia['debito']) <div class="w-[110px] text-right" wire:click="mostrar({{$index}})"> {{ dec($pendencia['debito']) }} </div> @else <div class="w-[110px] text-right text-red-500" wire:click="mostrar({{$index}})"> {{ dec($pendencia['credito']) }} </div> @endif <div class="w-[10px] px-2"> <input type=checkbox {{$pendencia['restrito']==1 ? 'checked' : ''}} wire:click="restritoDefinir({{$index}})"> </div> <div class="w-[336px] px-2 truncate"> <a class="text-gray-500 font-semibold hover:bg-gray-200" wire:click="selecionarPessoa({{$pendencia['docto']}})"> <?=$pendencia['pessoa']?> </a> </div> </div> </div> @endif @endforeach @endif @if(auth()->user()->id!==1) @foreach($pendencias as $index => $pendencia) @if($pendencia['restrito']==0 && $pendencia['div1']==1) <div wire:click="mostrar({{$index}})" class="bg-red-200"> {{"Histórico: Lçto ".$pendencia['lcto']." ".$pendencia['hist']}} </div> @endif @if($pendencia['restrito']==0 && $pendencia['div1']==0) <div class="even:bg-gray-200"> <div class="flex"> <div class="w-[117px] ml-3 text-right"> <input class="w-[117px] bg-transparent text-gray-500 font-semibold rounded py-0 border-none text-center" value='{{ dbr($pendencia['vcto']) }}'> </div> <div class="w-[50px] text-right"> <div class="text-right">{{ $pendencia['docto'] }}</div> </div> @if($pendencia['debito']) <div class="w-[110px] text-right" wire:click="mostrar({{$index}})"> {{ dec($pendencia['debito']) }} </div> @else <div class="w-[110px] text-right text-red-500" wire:click="mostrar({{$index}})"> {{ dec($pendencia['credito']) }} </div> @endif <div class="w-[346px] px-2 truncate"> <div class="text-gray-500 font-semibold hover:bg-gray-200"> <?=$pendencia['pessoa']?> </div> </div> </div> </div> @endif @endforeach @endif <div class="even:bg-gray-200"> <div class="w-[290px] text-right text-red-500 font-semibold">{{"JK ".dec($jk)}}</div> </div> </div> arquivo app > Livewire > Pagar.php <?php namespace App\Livewire; use App\Models\tbcontacorrente; use App\Models\tbdiario; use App\Models\tbpessoa; use Livewire\Attributes\Layout; use Livewire\Component; #[Layout('components.layouts.app',['titulo'=>'Pendências'])] class Pagar extends Component { public $doc1,$doc2,$histAtual,$jk,$lctoAtual,$modal=false,$pendencias=[]; function atualizaVcto($docto,$index) { $vcto=$this->pendencias[$index]['vcto']; tbcontacorrente::where('docto',$docto) ->update(['vcto'=>$vcto]); $this->montaPendencias(); } function fecharModal() { $this->modal=false; } function montaPendencias() { if(request()->input('docto')) { $docto=request()->input('docto'); $codp=session('codp'); tbcontacorrente::where('docto',$docto)->update(['codp'=>$codp]); } $this->pendencias=[]; $contas=tbcontacorrente::where('pgto',0)->orderBy('vcto')->get(); foreach($contas as $conta) { $doc=tbdiario::where('docto',$conta->docto)->first(); $restrito=$conta->restrito; $vcto=$conta->vcto; $docto=$conta->docto; $lcto=$doc->lcto; if($doc->contad==130 || $doc->contad==211) { $debito=$doc->valor; $credito=null; } else { $debito=null; $credito=$doc->valor; } $hist=dbr($doc->dia)." ".$doc->hist; if($conta->codp) { $pessoa=tbpessoa::where('codp',$conta->codp)->value('pessoa'); } else { $pessoa="Selecionar"; } $this->pendencias[]=['vcto'=>$vcto,'docto'=>$docto,'lcto'=>$lcto,'debito'=>$debito, 'credito'=>$credito,'hist'=>$hist,'pessoa'=>$pessoa,'restrito'=>$restrito,'div1'=>0]; } $this->jk=0; foreach ($this->pendencias as $item) { if (isset($item['restrito']) && $item['restrito'] == 0) { $this->jk += $item['credito']; } } } function mostrar($indicador) { if($this->pendencias[$indicador]['div1']==0) { return $this->pendencias[$indicador]['div1']=1; } else { return $this->pendencias[$indicador]['div1']=0; } } function mount() { $pendencias=tbcontacorrente::with('diario')->where('pgto',0)->get(); foreach($pendencias as $p) { $eliminar=($p->diario->contad!==130); $eliminar+=($p->diario->contad!==211); $eliminar+=($p->diario->contac!==130); $eliminar+=($p->diario->contac!==211); if($eliminar==4) { tbcontacorrente::where('docto',$p->docto)->delete(); } } $pendencias=tbcontacorrente::pluck('docto'); $doc1=tbdiario::where('dia','>','2023-12-31')->where('contad',130)->pluck('docto'); $doc2=tbdiario::where('dia','>','2023-12-31')->where('contac',130)->pluck('docto'); $doc3=tbdiario::where('dia','>','2023-12-31')->where('contad',211)->pluck('docto'); $doc4=tbdiario::where('dia','>','2023-12-31')->where('contac',211)->pluck('docto'); $documentos=$doc1->merge($doc2)->merge($doc3)->merge($doc4); $diferenca=$documentos->diff($pendencias); foreach($diferenca as $d) { $lcto=tbdiario::where('docto',$d)->value('lcto'); tbcontacorrente::create(['docto'=>$d,'lcto'=>$lcto,'pgto'=>0]); } $this->montaPendencias(); } function ocultar() { if($this->doc1 !== null) { tbcontacorrente::where('docto',$this->doc1) ->update(['pgto'=>1]); } if($this->doc2 !== null) { tbcontacorrente::where('docto',$this->doc2) ->update(['pgto'=>1]); } $this->doc1=$this->doc2=null; $this->montaPendencias(); } function restritoDefinir($indicador) { $docto=$this->pendencias[$indicador]['docto']; $restricao=$this->pendencias[$indicador]['restrito']; if($restricao==0) { $restricao=1; } else { $restricao=0; } tbcontacorrente::where('docto',$docto) ->update(['restrito'=>$restricao]); $this->montaPendencias(); } function selecionarDocto($docto) { if($this->doc1==null) { $this->doc1 = $docto; } else { if($this->doc2==null) { $this->doc2 = $docto; } } } function selecionarPessoa($docto) { session(['end'=>"pagar?docto=$docto"]); redirect("pessoa"); } }
  17. Frank K Hosaka

    Tofu

    Eu tentei copiar o código de barra de uma conta da Sabesp e colar no meu programa boleto, e apareceu um monte de tofus (retângulos pequenos). Pedi ajuda para o Copilot, ele me deu um monte de dicas para obter apenas os números, mas nenhum deu certo. Perguntei para o Adobe Acrobat quanto custa o serviço de inteligência artificial, e ele disse que o plano mais em conta é de R$ 333,00 por ano. Eu fiquei desesperado, nunca pensei que fosse tão caro copiar uma informação de um arquivo, se bem que o padre José me alertou que o fim dos tempos está cada vez mais próximo. Usei o botão direito do mouse no arquivo da conta da Sabesp, e lá encontrei "Pergunte ao Copilot" além do "Acrobat Reader", e o Copilot conseguiu ler o código de barra. Por enquanto, o Copilot é gratuito. A seguir o meu código Boleto em Livewire: arquivo resources > views > livewire > outros.blade.php (parcial) @if($modal2) <flux:input.group class="mt-5"> <flux:input.group.prefix>código de barra do boleto</flux:input.group.prefix> <flux:input wire:model="boleto" /> </flux:input.group> <flux:input.group class="mt-5"> <flux:input.group.prefix>código de barra do comprovante</flux:input.group.prefix> <flux:input wire:model="comprovante" /> </flux:input.group> <flux:button wire:click="boletos" class="mt-5">Verificar</flux:button> {!! $comparacao !!} <div>{{ $boleto1 }}</div> <div>{{ $comprovante1 }}</div> @endif arquivo app > Livewire > Outros.php (parcial) function boletos() { $this->boleto1=substr(preg_replace('/\D/', '', $this->boleto),0,48); $this->comprovante1=substr(preg_replace('/\D/', '', $this->comprovante),0,48); if($this->boleto1==$this->comprovante1) { $this->comparacao="<p></p>Os códigos de barra são iguais!</p>"; } else { $this->comparacao="<p class='text-red-500'>Os códigos de barra são diferentes</p>"; } }
  18. Desde 2020 sempre tive problema na hora de criar modal, não sabia como lidar com o JavaScript. Aqui em 2025 eu conheci o Livewire, e com ele percebi que era bem fácil criar o modal através do PHP. Nessa semana, eu criei cinco modais dentro de um HTML. É muito modal para um só HTML, mas para facilitar eu inventei um gerenciador de modal, assim: function modalDefinir($modais) { $this->modal=array_fill(0,5,false); foreach($modais as $indice) { $this->modal[$indice]=true; } } Para ativar a modal de índice 1, eu uso o comando $this->modalDefinir([1]). Para ativar outros modais, uso apenas uma vírgula para acrescentar outro índice. Outro truque bacana que eu aprendi foi passar toda a instância da classe para a view, assim: return view('nfView',['n'=>$this]); } Isso acabou com o pesadelo de passar um monte de parâmetros na hora de chamar o HTML, é bem mais fácil mandar toda a classe para ele. Para isso funcionar, eu usei um monte de variável pública. Mas o PHP não é Livewire, ele não tem o truque do "wire:model" e nem o "wire:click", o único recurso que sobre é a atualização do navegador, onde o HTML passa os dados obtidos do usuário, e o PHP monta um novo HTML baseado nas informações que recebeu, o problema é que tudo é perdido no meio do caminho. Para contornar esse problema, eu criei a função recuperarMemoria: function recuperarMemoria() { $this->nNF = $_SESSION['vetor']['nNF']; $this->xNome = $_SESSION['vetor']['xNome']; $this->previa = $_SESSION['vetor']['previa']; $this->codp = $_SESSION['vetor']['codp']; $this->vNF = $_SESSION['vetor']['vNF']; $this->difAliqICMS = $_SESSION['vetor']['difAliqICMS']; $this->soma = $_SESSION['vetor']['soma']; $this->inativos = $_SESSION['vetor']['inativos']; } Finalmente, um código exemplo de como usar tudo isso: arquivo nf.php <?php class NF { public $codp,$difAliqICMS,$inativos=[],$indicador,$modal=[],$nNF,$previa=[]; public $soma,$vNF,$xNome; function atualizar($indicador) { $this->indicador=$indicador; $this->recuperarMemoria(); $this->modalDefinir([0,2,3]); return view('nfView',['n'=>$this]); } function CFOP() { $this->recuperarMemoria(); $this->modalDefinir([2,4]); return view('nfView',['n'=>$this]); } function CFOPatualizar() { $cfop=$_POST['cfop']; $codprod = $_POST['codprod']; (new Conn)->update("tbprod set cfop='$cfop' where codprod = $codprod"); return ; } function custo() { $custoAtual = $_POST['custoAtual']; $codprod = $_POST['codprod']; $margem=(new Conn)->select("marg from tbprod where codprod=$codprod")[0]->marg; $venda=pvenda($custoAtual,$margem); $class=addslashes("class='w-[80px] text-right'"); (new Conn)->update("tbnf set custoanterior=$custoAtual, class='$class' where codprod=$codprod"); (new Conn)->update("tbprod set custo=$custoAtual, venda=$venda where codprod = $codprod"); } function incluir() { $lcto=$_POST['lcto']; $verifica=count((new Conn)->select("* from tbhistprod where lcto=$lcto")); if($verifica) { $mensagem="<h1>Nota já lançada. <a href=?NF.atualiza>Voltar</a></h1>"; return view('mensagemView',['mensagem'=>$mensagem]); } $dia=(new Conn)->select("dia from tbdiario where lcto=$lcto")[0]->dia; $matriz=(new Conn)->select("* from tbnf"); foreach($matriz as $vetor) { (new Conn)->insert("tbhistprod (codprod,dia,qt,custototal,codp,lcto) values ('$vetor->codprod','$dia',$vetor->qt,$vetor->custototal,$vetor->codp,$lcto)"); } return header("location:?Diario.inicio.$dia"); } function inicio() { $this->modalDefinir([1]); return view('nfView',['n'=>$this]); } function modalDefinir($modais) { $this->modal=array_fill(0,5,false); foreach($modais as $indice) { $this->modal[$indice]=true; } } function montarVetor() { $this->inativos=[]; // falta definir inativos $this->previa=[]; $nfe=simplexml_load_file($_FILES['arquivo']['tmp_name']); $itens=$nfe->NFe->infNFe->det; $this->difAliqICMS=0; $aliquotaInterna=0.18; foreach ($itens as $item) { if ((float)$item->prod->CFOP == 6102 || (float)$item->prod->CFOP ==6101) { $vBC = (float)$item->imposto->ICMS->ICMS10->vBC; $vBC = $vBC ? $vBC : (float)$item->imposto->ICMS->ICMS00->vBC; $vICMS = (float)$item->imposto->ICMS->ICMS10->vICMS; $vICMS = $vICMS ? $vICMS : (float)$item->imposto->ICMS->ICMS00->vICMS; $this->difAliqICMS += round(($vBC * $aliquotaInterna - $vICMS+0.00001),2); } } $this->vNF = (float)$nfe->NFe->infNFe->total->ICMSTot->vNF; $this->nNF = (float)$nfe->NFe->infNFe->ide->nNF; $this->xNome = (string)$nfe->NFe->infNFe->emit->xNome; $nome = explode(" ", $this->xNome)[0]; $this->codp = (new Conn)->select("codp from tbpessoa where pessoa like '%$nome%'")[0]->codp; $this->soma=0; foreach ($itens as $item){ // no campo codforn uso a primeira letra para identificar o fornecedor $codforn = (string)$item->prod->cProd; $criterio= strtolower($nome[0].$codforn); $consulta = (new Conn)->select("* from tbprod where codforn like '%$criterio%' "); $codprod = 'null'; $cfop = (string)$item->prod->CFOP; $ncm = (string)$item->prod->NCM; if (count($consulta) == 1) { $codprod = $consulta[0]->codprod; if(substr($consulta[0]->cfop,0,1)==0) { $this->inativos[]=$consulta[0]->codprod; } $fclass=($cfop == substr($consulta[0]->cfop,-4)) ? "w-[50px] text-right" : "w-[50px] text-red-500 text-right"; $nclass=($ncm == $consulta[0]->cf) ? "w-[100px] text-right" : "w-[100px] text-red-500 text-right"; } if (count($consulta) > 1) { $consulta2 = (new Conn)->select("* from tbprod where codforn like '$criterio'"); if(count($consulta2) == 1){ $codprod = $consulta2[0]->codprod; $consulta = $consulta2; } else { $codprod="mult"; } } if (count($consulta)==0) { $codprod = "none"; } $produto = substr((string)$item->prod->xProd,0,79); $quantidade = (float)$item->prod->qCom; if($cfop==6101 || $cfop==6102 || $cfop==5101) { $cfop=5102; } if($cfop==6401 || $cfop==6402 || $cfop==6403 || $cfop==5401 || $cfop==5403 || $cfop==5655) { $cfop=5405; } if (is_numeric($codprod)) { $produtox2 = [506, 507, 508, 509, 510, 519, 1768, 1770, 1772]; if (in_array($codprod, $produtox2)) { $quantidade = 2 * $quantidade; } $produtox5=[1798]; if (in_array($codprod,$produtox5 )) { $quantidade = 5 * $quantidade; } $produtox6 = [2652]; if (in_array($codprod,$produtox6 )) { $quantidade = 6 * $quantidade; } $produtox10 = [2192,1782,2456]; if (in_array($codprod, $produtox10)) { $quantidade = 10 * $quantidade; } $produtox12 = [2403,2406,2407,2408,2496,2497,2498,2499,2561,2653,2654]; if (in_array($codprod, $produtox12)) { $quantidade = 12 * $quantidade; } $produtox24 = [2493,2405,2494,2495,2409]; if (in_array($codprod, $produtox24)) { $quantidade = 24 * $quantidade; } $produtox36 = [2404]; if (in_array($codprod, $produtox36)) { $quantidade = 36 * $quantidade; } } $vICMSST1 = ((float)$item->imposto->ICMS->ICMS10->vICMSST) ? (float)$item->imposto->ICMS->ICMS10->vICMSST : null; $vICMSST2 = ((float)$item->imposto->ICMS->ICMSSN202->vICMSST) ? (float)$item->imposto->ICMS->ICMSSN202->vICMSST : null; $vICMSST = $vICMSST1 ? $vICMSST1 : $vICMSST2; $difAliq = 0; if ((float)$item->prod->CFOP == 6102 || (float)$item->prod->CFOP == 6101){ $vBC = (float)$item->imposto->ICMS->ICMS10->vBC; $vBC = $vBC ? $vBC : (float)$item->imposto->ICMS->ICMS00->vBC; $vICMS = (float)$item->imposto->ICMS->ICMS10->vICMS; $vICMS = $vICMS ? $vICMS : (float)$item->imposto->ICMS->ICMS00->vICMS; $difAliq = round(($vBC * $aliquotaInterna - $vICMS+0.00001),2); } $vIPI =(isset($item->imposto->IPI->IPITrib->vIPI) && (float)$item->imposto->IPI->IPITrib->vIPI) ? (float)$item->imposto->IPI->IPITrib->vIPI : 0; $vProd = (string)$item->prod->vProd; $valorTotal = $vProd + $vICMSST + $difAliq + $vIPI; $this->soma += $valorTotal; $custoAtual=0; $custoAnterior=0; $marg=0; $cclass="w-[80px] text-right"; $nclass="w-[100px] text-right"; $fclass="w-[50px] text-right"; if (is_numeric($codprod)) { $custoAtual = intval($valorTotal / $quantidade * 100) / 100; $consulta = (new Conn)->select("* from tbprod where codprod=$codprod"); $custoAnterior = $consulta[0]->custo; $marg=$consulta[0]->marg; if (abs($custoAnterior - $custoAtual) > 0.02) { $cclass = 'w-[80px] text-right text-red-500'; } if ($ncm !== $consulta[0]->cf) { $nclass = 'w-[100px] text-right text-red-500'; } if (trim($cfop) !== trim(substr($consulta[0]->cfop,-4))) { $fclass = 'w-[50px] text-right text-red-500'; } } $produto=str_replace("'","''",$produto); $this->previa[]=['codforn'=>$codforn,'codprod'=>$codprod,'prod'=>$produto, 'qt'=>$quantidade,'custoanterior'=>$custoAnterior,'custoatual'=>$custoAtual, 'custototal'=>$valorTotal, 'fclass'=>$fclass, 'cfop'=>$cfop,'codp'=>$this->codp,'ncm'=>$ncm,'nclass'=>$nclass,'cclass'=>$cclass, 'marg'=>$marg]; } $_SESSION['vetor']=['nNF' => $this->nNF,'xNome' => $this->xNome,'previa'=>$this->previa,'inativos'=>$this->inativos, 'codp' => $this->codp,'vNF' => $this->vNF,'difAliqICMS' => $this->difAliqICMS, 'soma'=>$this->soma]; $this->modalDefinir([2,3]); return view('nfView',['n'=>$this]); } function nfBasico() { $this->recuperarMemoria(); $this->modalDefinir([2,3]); return view('nfView',['n'=>$this]); } function qt() { $this->recuperarMemoria(); $qt=$_POST['qt']; $id=$_POST['id']; $novoClass=$this->previa[$id]['cclass']; $custoAtual=intval($this->previa[$id]['custototal']/$qt*100)/100; if($custoAtual!==$this->previa[$id]['custoanterior']) { $novoClass='w-[80px] text-red-700 text-right'; } else { $novoClass='w-[80px] text-right'; } $this->previa[$id]['cclass']=$novoClass; $this->previa[$id]['custoatual']=$custoAtual; $this->previa[$id]['qt']=$qt; $_SESSION['vetor']['previa']=$this->previa; $this->modalDefinir([2,3]); return view('nfView',['n'=>$this]); } function recuperarMemoria() { $this->nNF = $_SESSION['vetor']['nNF']; $this->xNome = $_SESSION['vetor']['xNome']; $this->previa = $_SESSION['vetor']['previa']; $this->codp = $_SESSION['vetor']['codp']; $this->vNF = $_SESSION['vetor']['vNF']; $this->difAliqICMS = $_SESSION['vetor']['difAliqICMS']; $this->soma = $_SESSION['vetor']['soma']; $this->inativos = $_SESSION['vetor']['inativos']; } } arquivo nfView.php <?php include('menuView.php'); ?> <script>btMenu.innerHTML='NF Fornecedor';document.title="NF Fornecedor"</script> <?php if($n->modal[0]): ?> <div class="fixed inset-0 flex items-center justify-center z-10" style="background-color: rgba(243,244,246,0.5)"> <div class="bg-white p-6 rounded shadow-lg"> <div class=w-[300px]> <div class="w-[300px] flex items-center border rounded overflow-hidden"> <label for=custoatual class="px-4 py-2 bg-gray-100 text-gray-700 text-sm whitespace-nowrap"> Custo Atual </label> <input class="flex-grow px-4 py-2 bg-white text-sm text-gray-900 placeholder-gray-400 focus:outline-none" id=custoatual value=<?=$n->previa[$n->indicador]['custoatual']?>> </div> <div class="w-[300px] mt-2 flex items-center border rounded overflow-hidden"> <label for=custoanterior class="px-4 py-2 bg-gray-100 text-gray-700 text-sm whitespace-nowrap"> Custo Anterior </label> <input class="flex-grow px-4 py-2 bg-white text-sm text-gray-900 placeholder-gray-400 focus:outline-none" id=custoatual value=<?=$n->previa[$n->indicador]['custoanterior']?>> </div> <div class="flex gap-4 mt-2"> <button class="px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700"> Alterar </button> <button class="px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700"> Cancelar </button> </div> </div> </div> </div> <?php endif; ?> <?php if($n->modal[1]): ?> <div class="mb-3 w-[530px]"> <form method=post enctype="multipart/form-data" action="?NF.montarVetor"> <label for=arquivo class=form-label>Escolha o arquivo XML</label> <input type=file name=arquivo class=form-control id=arquivo onchange=submit()> </form> </div> <?php endif; ?> <?php if($n->modal[2]): ?> <div class="flex"> <div class="w-[530px]">NF <?=$n->nNF." ".substr($n->xNome,0,10)." codp ".$n->codp?></div> <div class="w-[100px] text-right"><?=dec($n->vNF)?></div> <?php if(count($n->inativos)): print_r($n->inativos); endif;?> </div> <?php if($n->difAliqICMS!==0): ?> <div class="flex"> <div class="w-[530px] text-right">Diferença de Alíquota de ICMS</div> <div class="w-[100px] text-right"><?=dec($n->difAliqICMS)?></div> </div> <div class="flex"> <div class="w-[530px] text-right">Total a conferir</div> <div class="w-[100px] text-right"><?=dec($n->difAliqICMS+$n->vNF)?></div> </div> <?php endif; ?> <?php if($n->modal[3]): ?> <div class="flex bg-gray-200"> <div class="w-[50px]">Cforn</div> <div class="w-[50px] text-right">Cod</div> <div class="w-[318px] ml-1">Produto</div> <div class="w-[50px] text-right">Qt</div> <div class="w-[80px] text-right">Custo</div> <div class="w-[80px] text-right font-semibold" onclick="location.replace('?NF.CFOP')"> Total </div> </div> <?php foreach($n->previa as $index => $p): ?> <div class="flex odd:bg-gray-200"> <div class="w-[50px] truncate"><?=$p['codforn']?></div> <div class="w-[50px] text-right"><?=$p['codprod']?></div> <div class="w-[318px] ml-1 truncate"><?=$p['prod']?></div> <div class="w-[50px]"> <form method=post action=?NF.qt> <input name=qt value='<?=$p['qt']?>' class="w-[50px] text-right text-gray-500 font-semibold bg-transparent" size='1' onchange=submit()> <input type=hidden name=id value='<?=$index?>'> </form> </div> <div class="<?=$p['cclass']?>" onclick="location.replace('?NF.atualizar.<?=$index?>')"> <?=dec($p['custoatual'])?> </div> <div class="w-[80px] text-right"><?=dec($p['custototal'])?></div> </div> <?php endforeach; ?> <?php endif; ?> <?php if($n->modal[4]): ?> <div class="flex odd:bg-gray-200"> <div class="w-[50px] text-right">Cforn</div> <div class="w-[50px] text-right">Cod</div> <div class="w-[318px] ml-2">Produto</div> <div class="w-[50px] text-right">CFOP</div> <div class="w-[100px] text-right font-semibold" onclick="location.replace('?NF.nfBasico')">NCM</div> </div> <?php foreach($n->previa as $p): ?> <div class="flex odd:bg-gray-200"> <div class="w-[50px] text-right truncate"><?=$p['codforn']?></div> <div class="w-[50px] text-right"><?=$p['codprod']?></div> <div class="w-[318px] ml-2 truncate"><?=$p['prod']?></div> <div class="<?=$p['fclass']?>" onclick="atualizar(<?=$p['cfop']?>,<?=$p['codprod']?>)"> <?=$p['cfop']?> </div> <div class="<?=$p['nclass']?>"><?=$p['ncm']?></div> </div> <?php endforeach; ?> <?php endif; ?> <div class="odd:bg-gray-200 flex"> <div class="w-[530px] flex items-center border rounded overflow-hidden"> <label for=lcto class="px-4 py-2 bg-gray-100 text-gray-700 text-sm whitespace-nowrap">Enviar para </label> <input class="flex-grow px-4 py-2 bg-white text-sm text-gray-900 placeholder-gray-400 focus:outline-none" id=lcto placeholder="Lançamento" onchange="wire('incluir.'+this.value)"> </div> <div class="w-[100px] text-right"><?=dec($n->soma)?></div> </div> <?php endif; ?>
  19. O Livewire é muito engenhoso, ele coloca a classe e a view no mesmo ambiente. Pensei em fazer a mesma coisa com o PHP com a ajuda do Copilot, e hoje aprendi um truque novo: function inicio() { return view('contadorView',['contador'=>$this]); } Isso é bem engenhoso, eu jamais chegaria nesse código por conta própria. A seguir, a listagem que tenta imitar o tutorial do incremento que aparece na home page do Livewire: arquivo contador.php <?php session_start(); class Contador { function __construct() { if (!isset($_SESSION['contador'])) { $_SESSION['contador'] = 0; } } function handleAjax() { echo $this->incrementar(); exit; } function incrementar() { $_SESSION['contador']++; return $_SESSION['contador']; } function inicio() { return view('contadorView',['contador'=>$this]); } function valor() { return $_SESSION['contador']; } } arquivo contadorView.php <!DOCTYPE html> <html> <head> <title>Contador com Classe</title> </head> <body> <div id="contador">Contador: <strong><?= $contador->valor() ?></strong></div> <button onclick="incrementar()">Incrementar</button> <script> function incrementar() { fetch('?Contador.handleAjax') .then(response => response.text()) .then(novoValor => { document.getElementById('contador').innerHTML = `Contador: <strong>${novoValor}</strong>`; }); } </script> </body> </html> arquivo incrementa.php <?php session_start(); $_SESSION['contador'] = ($_SESSION['contador'] ?? 0) + 1; ?> <p>Contador: <strong><?= $_SESSION['contador'] ?></strong></p> <button onclick="incrementar()">Incrementar</button> arquivo index.php <?php function view($arquivo, $array = null) { if (!is_null($array)) { foreach ($array as $var => $value){ ${$var} = $value; } } ob_start(); include $arquivo . ".php"; ob_flush(); } spl_autoload_register(fn ($class) => require str_replace('\\', DIRECTORY_SEPARATOR, strtolower($class)) . '.php'); if($_GET) { $rota = key($_GET); $segmentos=explode('_',$rota); $nomeControle=$segmentos[0]; $metodo=$segmentos[1]; $parametro=$segmentos[2] ?? $controle=new $nomeControle(); $controle->$metodo($parametro); } else { header('location:?Contador.inicio'); } Esse código é bem difícil de entender e fazer manutenção. O Livewire é pura mágica, graças a ele eu consegui fazer um monte de "modal". Claro que dá para fazer modal no PHP com a ajuda do Copilot, o problema é que eu não sei como apurar um código feito em JavaScript, por mais que eu me esforce não consigo imaginar o que exatamente o comando "fetch( )" faz.
  20. arquivo app > Livewire > Cartao.php <?php namespace App\Livewire; use App\Models\tbdiario; use Livewire\Attributes\Layout; use Livewire\Component; #[Layout('components.layouts.app',['titulo'=>'Conferindo Cartão de Crédito'])] class Cartao extends Component { public $debito,$credito,$lctos=[]; function mount() { $doctos=tbdiario::where('lcto',16386)->get(); foreach($doctos as $d) { $this->lctos[]=['lcto'=>$d->lcto,'docto'=>$d->docto, 'contad'=>$d->contad,'contac'=>$d->contac, 'valor'=>$d->valor,'hist'=>$d->hist,'ticar'=>"flex even:bg-gray-300"]; } $this->debito = array_reduce($this->lctos, function($carry, $item) { if ($item['contad'] > 0) { $carry += $item['valor']; } return $carry; }, 0); $this->credito = array_reduce($this->lctos, function($carry, $item) { if ($item['contac'] > 0) { $carry += $item['valor']; } return $carry; }, 0); usort($this->lctos,function($a,$b) { return $b['valor'] <=> $a['valor']; }); } function ticar($indicador) { $this->lctos[$indicador]['ticar']="flex bg-red-200"; } } arquivo resources > views > livewire > cartao.blade.php <div> <div>Lançamento {{$lctos[0]['lcto']}}</div> <div class="flex bg-gray-300"> <div class=w-[60px]>Docto</div> <div class=w-[60px]>CtaD</div> <div class=w-[60px]>CtaC</div> <div class="w-[100px] text-right">Valor</div> <div class="w-[300px] px-2">Histórico</div> </div> @foreach($lctos as $key=>$l) <div class='{!! $l['ticar'] !!}' wire:click="ticar({{$key}})"> <div class=w-[60px]>{{$l['docto']}}</div> <div class=w-[60px]>{{$l['contad']}}</div> <div class=w-[60px]>{{$l['contac']}}</div> @if($l['contad']) <div class="w-[100px] text-right">{{dec($l['valor'])}}</div> @else <div class="w-[100px] text-right text-red-500">{{dec($l['valor'])}}</div> @endif <div class="W-[300px] px-2">{{$l['hist']}}</div> </div> @endforeach <div class=flex> <div class="w-[180px] text-right">{{dec($debito)}}</div> <div class="w-[100px] text-right text-red-500">{{dec($credito)}}</div> <div class="w-[100px] text-right">{{dec($debito-$credito)}}</div> </div> </div>
  21. Eu tenho um componente chamado Bling, e ele gastava 3 minutos para comparar 3.000 produtos do MySQL com o Bling. Eu usava o MySQL para gravar as informações obtidas do Bling. Ao invés de usar o MySQL, decidi usar um array, mas isso em nada ajudou a melhorar o tempo de resposta. Apresentei o meu código ao Copilot, ele mudou muita coisa, principalmente na hora de indexar um array e o tempo de resposta ficou bem melhor: arquivo app > Livewire > Bling.php <?php namespace App\Livewire; use App\Models\tbprod; use Livewire\Attributes\Layout; use Livewire\Component; use Livewire\WithFileUploads; #[Layout('components.layouts.app',['titulo'=>'Diferença na Bling'])] class Bling extends Component { use WithFileUploads; public $contaProdBling,$contaProduto,$dif=[],$files=[]; public $modal=true,$tbBling=[]; function updatedFiles() { $this->modal=false; foreach($this->files as $arquivo) { $dados=explode(PHP_EOL,$arquivo->get()); foreach($dados as $linha) { if($linha<>"") { $campos=explode(';',$linha); if(aspas($campos[1])!=="Código") { $codprod=intval(trim(aspas($campos[1]))); $un=aspas($campos[3]); $prod=aspas($campos[2]); $custo=deca(aspas($campos[11])); $codbar=trim(aspas($campos[19])); $cf=deca(aspas($campos[4])); $venda=deca(aspas($campos[6])); $this->tbBling[]=['codprod'=>$codprod,'un'=>$un, 'prod'=>$prod,'custo'=>$custo,'codbar'=>$codbar, 'cf'=>$cf,'venda'=>$venda]; } } } } // Criação do índice associativo por codprod $blingIndex = []; foreach ($this->tbBling as $item) { $blingIndex[$item['codprod']] = $item; } // Carrega os produtos do banco (opcionalmente como array) $produto = tbprod::where('loc','<>','a24')->get(); $this->contaProduto = count($produto); $this->contaProdBling = count($this->tbBling); // Verifica diferença de quantidade if ($this->contaProdBling > $this->contaProduto) { $prod = $produto->pluck('codprod'); $pBling = collect(array_column($this->tbBling, 'codprod')); $difs = $pBling->diff($prod); foreach ($difs as $d) { echo "problema no codprod $d na Bling <br>"; } dd('parada total'); // essa rotina não funciona no Laravel, precisa melhorar } // Compara os produtos foreach ($produto as $key => $pr) { $codprod = $pr->codprod; if (!isset($blingIndex[$codprod])) { $this->dif[$key][] = ['Codigo' => $codprod]; $this->dif[$key][] = ['Incluir' => $codprod, 'Incluir2' => 'Incluir']; } else { $a = $blingIndex[$codprod]; $un = ($pr->un == $a['un']) ? 1 : 0; $prod = ($pr->prod == $a['prod']) ? 1 : 0; $custo = ($pr->custo == $a['custo']) ? 1 : 0; $codbar = ($pr->codbar == $a['codbar']) ? 1 : 0; $cf = ($pr->cf == $a['cf']) ? 1 : 0; $venda = ($pr->venda == $a['venda']) ? 1 : 0; if ($un.$prod.$custo.$codbar.$cf.$venda !== '111111') { $this->dif[$key][] = ['Codigo' => $pr->codprod, 'Codigo2' => $a['codprod']]; if ($pr->prod !== $a['prod']) { $this->dif[$key][] = ['Descricao' => $pr->prod, 'Descricao2' => $a['prod']]; } if ($pr->custo !== $a['custo']) { if ($pr->custo || $a['custo'] != 0) { $this->dif[$key][] = ['Custo' => $pr->custo, 'Custo2' => $a['custo']]; } } if ($pr->codbar != $a['codbar']) { $this->dif[$key][] = ['Codigo de Barra' => $pr->codbar, 'Codigo de Barra2' => $a['codbar']]; } if ($pr->cf !== $a['cf']) { if ($pr->cf || $a['cf']) { $this->dif[$key][] = ['NCM' => $pr->cf, 'NCM2' => $a['cf']]; } } if ($pr->venda !== $a['venda']) { $this->dif[$key][] = ['Venda' => $pr->venda, 'Venda2' => $a['venda']]; } if ($pr->un !== $a['un']) { $this->dif[$key][] = ['Un' => $pr->un, 'Un2' => $a['un']]; } } } } } } arquivo resources > views > livewire > bling.blade.php <div> @if($modal) <div class="h-5"></div> <flux:input type="file" wire:model="files" multiple label="Selecione os arquivos de produtos da Bling" /> @else <script> function copiar(elemento) { conteudo=elemento.innerText || elemento.textContent navigator.clipboard.writeText(conteudo) elemento.parentElement.style.display="none" } </script> <div class="font-semibold flex"> <div class=w-[100px]>Código</div> <div class=w-[100px]>Campo</div> <div class=w-[100px]>MySQL</div> <div class=w-[100px]>Bling</div> </div> <div class=flex> <div class=w-[100px]></div> <div class=w-[100px]>Produtos</div> <div class=w-[100px]>{{ $contaProduto }}</div> <div class=w-[100px]>{{ $contaProdBling }}</div> </div> @foreach($dif as $d) @foreach($d as $v) @if(array_keys($v)[0]=="Codigo") @php $codigo=array_values($v)[0]; @endphp @else @if(array_keys($v)[0]!=="Descricao") <div class="flex"> <div class=w-[100px]>{{$codigo}}</div> <div class=w-[100px]>{{array_keys($v)[0]}}</div> <div class=w-[100px] onclick=copiar(this)> <pre class="font-sans"><?=array_values($v)[0]?></pre> </div> <div class=w-[100px]> <pre class="font-sans"><?=array_values($v)[1]?></pre> </div> </div> @else <div class=flex> <div class=w-[100px]>{{$codigo}}</div> <div class=w-[100px]>{{array_keys($v)[0]}}</div> <div class=w-[100px] onclick=copiar(this)> <pre class="font-sans"><?=array_values($v)[0]?></pre> </div> </div> <div class=flex> <div class=w-[200px]></div> <div class=w-[100px] onclick=copiar(this)> <pre class="font-sans"><?=array_values($v)[1]?></pre> </div> </div> @endif @endif @endforeach @endforeach @endif </div>
  22. Eu consigo acessar o gerenciador de arquivos com o <input type=file> através do Samsung Internet, mas não pelo navegador Google do Android.
  23. Dentro do componente Outros.php eu criei uma rotina chamada boletos, para comparar o código de barras do boleto com o código de barra que aparece no comprovante de pagamento. Eu pensei que seria fácil, mas não é. Eu precisei de muita ajuda do Copilot. Para pegar o código de barra no pdf do boleto, eu só selecionei e copiei e colei no meu projeto. Já o código de barra do pdf do comprovante não consegui selecionar e copiar, precisei da ajuda do IA que aparece no programa do Adobe Reader. O espaço que aparece no código de barra do boleto é pura maquiagem, ele não é um espaço de verdade. Já o código de barra do comprovante é bem maior do que você acredita que copiou. E assim, o meu componente Outros.php ficou assim: <?php namespace App\Livewire; use App\Models\tbdiario; use Livewire\Attributes\Layout; use Livewire\Component; #[Layout('components.layouts.app',['titulo'=>'Outros Comandos'])] class Outros extends Component { public $baixa,$boleto,$boleto1,$comparacao,$comprovante,$comprovante1,$diaAcerto,$mais,$menos,$modal,$modal2,$modal3=true; public $valorBaixa,$valorMais,$valorMenos,$vetor; function boletos() { $this->boleto1=substr(preg_replace('/\D/', '', $this->boleto),0,47); $this->comprovante1=substr(preg_replace('/\D/','',$this->comprovante),0,47); if($this->boleto1==$this->comprovante1) { $this->comparacao="<p>Os códigos de barra são iguais!</p>"; } else { $this->comparacao="<p class='text-red-500'>Os códigos de barra são diferentes</p>"; } } function mount($opcao=null) { if($opcao=="menu") {$this->modal3=false; return $this->modal=true;} if($opcao=="boleto"){$this->modal3=false; return $this->modal2=true;} // o resto do código } } E o Blade ficou assim: <div> @if($modal) @endif @if($modal2) <flux:input.group class="mt-5"> <flux:input.group.prefix>código de barra do boleto</flux:input.group.prefix> <flux:input wire:model="boleto" /> </flux:input.group> <flux:input.group class="mt-5"> <flux:input.group.prefix>código de barra do comprovante</flux:input.group.prefix> <flux:input wire:model="comprovante" /> </flux:input.group> <flux:button wire:click="boletos" class="mt-5">Verificar</flux:button> {!! $comparacao !!} <div>{{ $boleto }}</div> <div>{{ $comprovante }}</div> <div>{{ strcmp(trim(str_replace(".","",$boleto)),trim(str_replace(".","",$comprovante)))}}</div> <div>{{ $boleto1 }}</div> <div>{{ $comprovante1 }}</div> @endif @if($modal3) <!-- o resto do código --> @endif </div>
  24. Quando você abre o projeto do Laravel, ele vai direto na rotina do login. Mas se você já tiver logado uma vez, a sua chamada para o projeto vai mandar você para o dashboard.blade.php, o painel de controle que vem embutido no Laravel 12. No meu caso, eu defini a rota para o dashboard para o componente chamado menu, que simplesmente não faz nada, ele exibe apenas o layout que defini no arquivo resources > views > components > layouts > app.blade.php. Ao invés de usar um componente que não faz nada decidi usar um componente que faz alguma coisa. Peguei o componente outros.php, e o código do roteador ficou assim: Route::get('outros/{opcao?}',Outros::class); Route::get('outrosTeste',function(){return redirect('outros/menu');})->name('dashboard'); O componente Outros.php ficou assim: class Outros extends Component { public $modal; function mount($opcao=null) { if($opcao=="menu") {return $this->modal=true;} // o resto do código } } E finalmente o Blade: <div> @if($modal) @else <!-- o resto do código --> @endif </div>
  25. Fazer modal no PHP ou no Laravel foi bem difícil para mim, pois eu não tinha nenhuma familiaridade com o JavaScript. Já o Livewire trouxe um novo conceito, onde você divide o HTML em várias partes, e você vai exibindo de acordo com a necessidade. No meu caso, eu dividi o HTML em $modal, $modal2 e $modal3. Dentro do primeiro $modal existem dezenas de "submodais" que são controlados pela variável $comando. $modal2 mostra a nota do fornecedor onde tem quantidade e preço. O $modal3 mostra a mesma nota, mas com o CFOP e o NCM. arquivo app > Livewire > NotaFiscal.php <?php namespace App\Livewire; use App\Models\tbdiario; use App\Models\tbpessoa; use App\Models\tbhistprod; use App\Models\tbprod; use Illuminate\Support\Facades\DB; use Livewire\Attributes\Layout; use Livewire\Component; use Livewire\WithFileUploads; #[Layout('components.layouts.app',['titulo'=>'NF do Fornecedor'])] class NotaFiscal extends Component { use WithFileUploads; public $comando="pegar xml",$criterio,$difAliqICMS,$inativos=[],$indicador,$lcto; public $modal=true,$modal2,$modal3; public $nNF,$opcoes=[],$previa=[],$quant,$soma,$xNome,$XmlFile,$vNF; function updatedXmlFile() { $this->previa=[]; $xmlContent=file_get_contents($this->XmlFile->getRealPath()); $nfe=simplexml_load_string($xmlContent); $itens=$nfe->NFe->infNFe->det; $this->difAliqICMS=0; $aliquotaInterna=0.18; foreach ($itens as $item) { if ((float)$item->prod->CFOP == 6102 || (float)$item->prod->CFOP ==6101) { $vBC = (float)$item->imposto->ICMS->ICMS10->vBC; $vBC = $vBC ? $vBC : (float)$item->imposto->ICMS->ICMS00->vBC; $vICMS = (float)$item->imposto->ICMS->ICMS10->vICMS; $vICMS = $vICMS ? $vICMS : (float)$item->imposto->ICMS->ICMS00->vICMS; $this->difAliqICMS += round(($vBC * $aliquotaInterna - $vICMS+0.00001),2); } } $this->vNF = (float)$nfe->NFe->infNFe->total->ICMSTot->vNF; $this->nNF = (string)$nfe->NFe->infNFe->ide->nNF; $this->xNome = (string)$nfe->NFe->infNFe->emit->xNome; $nome = explode(" ", $this->xNome)[0]; $codp = tbpessoa::where('pessoa','like','%'.$nome.'%')->value('codp'); $this->soma=0; foreach ($itens as $item) { $codforn = (string)$item->prod->cProd; $criterio= strtolower($nome[0].$codforn); $consulta = tbprod::where('codforn','like','%'.$criterio.'%')->get(); $cfop = (string)$item->prod->CFOP; $ncm = (string)$item->prod->NCM; if (count($consulta) == 1) { $codprod = $consulta[0]->codprod; if(substr($consulta[0]->cfop,0,1)==0) { $this->inativos[]=$consulta[0]->codprod; } $class=($cfop == substr($consulta[0]->cfop,-4)) ? "w-[50px] text-right" : "w-[50px] text-red-500 text-right"; $class2=($ncm == $consulta[0]->cf) ? "w-[100px] text-right" : "w-[100px] text-red-500 text-right"; } if (count($consulta) > 1) { $consulta2 = tbprod::where('codforn','like','%'.$criterio)->get(); if(count($consulta2) == 1){ $codprod = $consulta2[0]->codprod; $consulta = $consulta2; } else { $codprod = "mult"; } } if (count($consulta)==0) { $codprod = "none"; } $produto = substr((string)$item->prod->xProd,0,79); $quantidade = (float)$item->prod->qCom; if($cfop==6101 || $cfop==6102 || $cfop==5101) { $cfop=5102; } if($cfop==6401 || $cfop==6402 || $cfop==6403 || $cfop==5401 || $cfop==5403 || $cfop==5655) { $cfop=5405; } if (is_numeric($codprod)) { $produtoDobrado = [506, 507, 508, 509, 510, 519, 1768, 1770, 1772]; if (in_array($codprod, $produtoDobrado)) { $quantidade = 2 * $quantidade; } $produtox5=[1798]; if (in_array($codprod,$produtox5 )) { $quantidade = 5 * $quantidade; } $produtoX10 = [2192,1782,2456]; if (in_array($codprod, $produtoX10)) { $quantidade = 10 * $quantidade; } $produtox12 = [2403,2406,2496,2497,2498,2499]; if (in_array($codprod, $produtox12)) { $quantidade = 12 * $quantidade; } $produtox24 = [2493,2405,2494,2495,2409]; if (in_array($codprod, $produtox24)) { $quantidade = 24 * $quantidade; } } $vICMSST1 = ((float)$item->imposto->ICMS->ICMS10->vICMSST) ? (float)$item->imposto->ICMS->ICMS10->vICMSST : null; $vICMSST2 = ((float)$item->imposto->ICMS->ICMSSN202->vICMSST) ? (float)$item->imposto->ICMS->ICMSSN202->vICMSST : null; $vICMSST = $vICMSST1 ? $vICMSST1 : $vICMSST2; $difAliq = 0; if ((float)$item->prod->CFOP == 6102 || (float)$item->prod->CFOP == 6101){ $vBC = (float)$item->imposto->ICMS->ICMS10->vBC; $vBC = $vBC ? $vBC : (float)$item->imposto->ICMS->ICMS00->vBC; $vICMS = (float)$item->imposto->ICMS->ICMS10->vICMS; $vICMS = $vICMS ? $vICMS : (float)$item->imposto->ICMS->ICMS00->vICMS; $difAliq = round(($vBC * $aliquotaInterna - $vICMS+0.00001),2); } $vIPI =(isset($item->imposto->IPI->IPITrib->vIPI) && (float)$item->imposto->IPI->IPITrib->vIPI) ? (float)$item->imposto->IPI->IPITrib->vIPI : 0; $vProd = (string)$item->prod->vProd; $valorTotal = $vProd + $vICMSST + $difAliq + $vIPI; $this->soma += $valorTotal; $custoAtual = intval($valorTotal / $quantidade * 100) / 100; $custoAnterior=0; $marg=0; $cclass="w-[70px] text-right"; $nclass="w-[100px] text-right"; $fclass="w-[50px] text-right"; if (is_numeric($codprod)) { $consulta = tbprod::where('codprod',$codprod)->first(); $custoAnterior = $consulta->custo; $marg=$consulta->marg; if (abs($custoAnterior - $custoAtual) > 0.02) { $cclass = 'w-[70px] text-right text-red-500'; } if ($ncm !== $consulta->cf) { $nclass = 'w-[100px] text-right text-red-500'; } if (trim($cfop) !== trim(substr($consulta->cfop,-4))) { $fclass = 'w-[50px] text-right text-red-500'; } } $this->previa[]=['codforn'=>$codforn,'codprod'=>$codprod,'prod'=>$produto, 'qt'=>$quantidade,'custoanterior'=>$custoAnterior,'custoatual'=>$custoAtual, 'custototal'=>$valorTotal, 'fclass'=>$fclass, 'cfop'=>$cfop,'codp'=>$codp,'ncm'=>$ncm,'nclass'=>$nclass,'cclass'=>$cclass, 'marg'=>$marg]; } $this->modal=false; $this->modal2=true; } function atualizarCfop($indicador) { $codprod=$this->previa[$indicador]['codprod']; $cfop=$this->previa[$indicador]['cfop']; DB::table('tbprod')->where('codprod',$codprod) ->update(['cfop' => DB::raw("CONCAT(LEFT(cfop, LENGTH(cfop) - 4), $cfop)")]); $this->previa[$indicador]['fclass']='w-[50px] text-right'; } function atualizarNcm($indicador) { $codprod=$this->previa[$indicador]['codprod']; $ncm=$this->previa[$indicador]['ncm']; tbprod::where('codprod',$codprod)->update(['cf'=>$ncm]); $this->previa[$indicador]['nclass']='w-[100px] text-right'; } function cancelar() { $this->modal=false; } function custo($indicador) { $this->indicador=$indicador; $this->comando="alterar custo"; $this->modal=true; } function custoConfirmado() { $custo=$this->previa[$this->indicador]['custoatual']; $codprod=$this->previa[$this->indicador]['codprod']; $this->previa[$this->indicador]['cclass']="w-[70px] text-right"; tbprod::where('codprod',$codprod)->update(['custo'=>$custo]); $this->modal=false; } function mostrarMais() { if($this->modal2) { $this->modal2=false; $this->modal3=true; } else { $this->modal2=true; $this->modal3=false; } } function multiplo($indicador) { $this->criterio=$this->previa[$indicador]['codforn']; $consulta=tbprod::where('codforn','like',"%$this->criterio")->get(); $this->opcoes=[]; foreach($consulta as $c) { $this->opcoes[]=['indicador'=>$indicador,'codprod'=>$c->codprod,'prod'=>$c->prod]; } $this->modal=true; } function qtDefinir($indicador) { $this->indicador=$indicador; $this->comando="qt"; $this->modal=true; } function qtDefinida() { $quant=$this->quant; $custo=round($this->previa[$this->indicador]['custototal']/$quant,2); $this->previa[$this->indicador]['qt']=$quant; $this->previa[$this->indicador]['custoatual']=$custo; $this->previa[$this->indicador]['cclass']="w-[50px] text-right text-red-500"; $this->modal=false; } function selecionado($chave) { $indicador=$this->opcoes[$chave]['indicador']; $codprod=$this->opcoes[$chave]['codprod']; $this->previa[$indicador]['codprod']=$codprod; $consulta=tbprod::where('codprod',$codprod)->first(); $this->previa[$indicador]['marg']=$consulta->marg; $this->previa[$indicador]['custoanterior']=$consulta->custo; if($this->previa[$indicador]['custoanterior'] !== $this->previa[$indicador]['custoatual']) { $previa[$indicador]['pclass']="w-[50px] text-right text-red-200"; } $this->modal=false; } function transferir() { if(count(tbhistprod::where('lcto',$this->lcto)->get())>0){ $this->comando="transferido"; $this->modal=true; } else { $dia=tbdiario::where('lcto',$this->lcto)->value('dia'); foreach($this->previa as $p) { tbhistprod::create(['codprod'=>$p['codprod'],'dia'=>$dia,'qt'=>$p['qt'], 'custototal'=>$p['custototal'],'codp'=>$p['codp'],'lcto'=>$this->lcto]); } return redirect('ldiario'); } } } arquivo resources > views > livewire > nota-fiscal.blade.php <div> @if($modal) <div class="fixed inset-0 flex items-center justify-center z-10" style="background-color: rgba(243,244,246,0.5)"> <div class="bg-white p-6 rounded shadow-lg"> @if($comando=="pegar xml") <flux:input type="file" wire:model="XmlFile" label="Pegar arquivo xml"/> @endif @if($comando=="escolher produto") @foreach($opcoes as $chave => $o) <flux:button wire:click="selecionado({{$chave}})">{{ $o['codprod']." ".$o['prod'] }} </flux:button> @endforeach <p>Existem muitos produtos com o critério {{$criterio}}. Escolha um.</p> @endif @if($comando=="alterar custo") <div class=w-[300px]> <flux:input.group> <flux:input.group.prefix>Custo Anterior</flux:input.group.prefix> <flux:input value="{{dec($previa[$indicador]['custoanterior'])}}" /> </flux:input.group> <flux:input.group> <flux:input.group.prefix>Custo Atual</flux:input.group.prefix> <flux:input value="{{ dec($previa[$indicador]['custoatual']) }}" /> </flux:input.group> <flux:button wire:click="custoConfirmado">Confirmar</flux:button> </div> @endif @if($comando=="qt") <div class=w-[300px]> <flux:input.group> <flux:input.group.prefix>Definir Quantidade</flux:input.group.prefix> <flux:input wire:model="quant" wire:change="qtDefinida" autofocus autocomplete="off" /> </flux:input.group> <flux:button wire:click="cancelar" class="mt-5">Cancelar</flux:button> </div> @endif @if($comando=="transferido") <div class="text-lg">Documento já transferido anteriormente</div> @endif </div> </div> @endif @if($modal2 || $modal3) @if(count($inativos)) <div class=mt-5>{{ "verificar ".print_r($inativos) }}</div> @endif <div class=flex> <div class=w-[530px]>NF {{ $nNF." ".$xNome }}</div> <div class="w-[100px] text-right">{{ dec($vNF) }}</div> </div> @if($difAliqICMS!==0) <div class="flex"> <div class="w-[530px] text-right">Diferença de Alíquota de ICMS</div> <div class="w-[100px] text-right"><?=dec($difAliqICMS)?></div> </div> <div class="flex"> <div class="w-[530px] text-right">Total a conferir</div> <div class="w-[100px] text-right"><?=dec($difAliqICMS+$vNF)?></div> </div> @endif @if($modal2) <div class="flex even:bg-gray-200"> <div class="w-[70px] text-right">Cforn</div> <div class="w-[50px] text-right">Cod</div> <div class="w-[288px] px-2">Produto</div> <div class="w-[50px] text-right">Mg</div> <div class="w-[50px] text-right">Qt</div> <div class="w-[70px] text-right">Preço</div> <div class="w-[100px] text-right font-semibold" wire:click=mostrarMais>Total</div> </div> @foreach($previa as $key => $p) <div class="flex even:bg-gray-200"> <div class="w-[70px] text-right truncate">{{$p['codforn']}}</div> @if($p['codprod']=="none") <div class="w-[50px] text-right text-red-500">{{$p['codprod']}}</div> @endif @if($p['codprod']=="mult") <div class="w-[50px] text-right text-red-500" wire:click="multiplo({{$key}})"> {{ $p['codprod']}} </div> @endif @if($p['codprod']!=="none" && $p['codprod']!=="mult") <div class="w-[50px] text-right">{{$p['codprod']}}</div> @endif <div class="w-[288px] px-2 truncate">{{$p['prod']}}</div> <div class="w-[50px] text-right">{{$p['marg']}}</div> <div class="w-[50px] text-right" wire:click="qtDefinir({{$key}})">{{$p['qt']}}</div> <div class="{{ $p['cclass']}}" wire:click="custo({{$key}})">{{dec($p['custoatual'])}}</div> <div class="w-[100px] text-right">{{dec($p['custototal'])}}</div> </div> @endforeach @endif @if($modal3) <div class="flex even:bg-gray-200"> <div class="w-[70px] text-right">Cforn</div> <div class="w-[50px] text-right">Cod</div> <div class="w-[358px] px-2">Produto</div> <div class="w-[50px] text-right">CFOP</div> <div class="w-[100px] text-right font-semibold" wire:click="mostrarMais">NCM</div> </div> @foreach($previa as $key => $p) <div class="flex even:bg-gray-200"> <div class="w-[70px] text-right truncate">{{$p['codforn']}}</div> @if($p['codprod']=="none") <div class="w-[50px] text-right text-red-500">{{$p['codprod']}}</div> @endif @if($p['codprod']=="mult") <div class="w-[50px] text-right text-red-500" wire:click="multiplo({{$key}})"> {{ $p['codprod']}} </div> @endif @if($p['codprod']!=="none" && $p['codprod']!=="mult") <div class="w-[50px] text-right">{{$p['codprod']}}</div> @endif <div class="w-[358px] px-2 truncate">{{$p['prod']}}</div> <div class="{{$p['fclass']}}" wire:click="atualizarCfop({{ $key }})"> {{$p['cfop']}} </div> <div class="{{$p['nclass']}}" wire:click="atualizarNcm({{ $key }})"> {{$p['ncm']}} </div> </div> @endforeach @endif <div class=flex> <div class="w-[300px]"> <flux:input.group> <flux:button>Enviar para Lançamento</flux:button> <flux:input wire:model="lcto" wire:change="transferir" /> </flux:input.group> </div> <div class="w-[330px] text-right">{{ dec($soma) }}</div> </div> @endif </div>
×
×
  • Criar Novo...