
Frank K Hosaka
Membros-
Total de itens
1.590 -
Registro em
-
Última visita
Tudo que Frank K Hosaka postou
-
Pegando o nome de um arquivo zipado (Simples Nacional)
pergunta respondeu ao Frank K Hosaka de Frank K Hosaka em PHP
A seguir a listagem completa: arquivo app > Models > tbrendabruta.php <?php namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class tbrendabruta extends Model { use HasFactory; protected $table="tbrendabruta"; protected $fillable=['apuracao','renda']; const UPDATED_AT=null; const CREATED_AT=null; } ?> arquivo app > Livewire > Simples.php <?php namespace App\Livewire; use App\Models\tbrendabruta; use Carbon\Carbon; use DOMDocument; use Livewire\Attributes\Layout; use Livewire\Component; #[Layout('components.layouts.app',['titulo'=>'Estimativa do Simples'])] class Simples extends Component { protected $listeners=['verArquivo']; public $aliquota=7.3, $reducao=5940, $efetiva; // 2a. faixa da tabela do simples no comércio public $comST,$grupos,$modal, $notasFiscais = [],$nfCanceladas = []; public $notasCanceladas,$primeiraNota,$receitasAnteriores,$renda12; public $semST,$somaTotal,$totalDeNotas,$ultimaNota; public $CST,$SST,$TT; public $apuracao,$proxApuracao,$venda; function incluir() { tbrendabruta::create(['apuracao'=>$this->proxApuracao,'renda'=>$this->venda]); $this->modal=true; } function verArquivo($arquivo) { $this->modal=false; $this->apuracao=tbrendabruta::max('apuracao'); $previa=Carbon::createFromFormat('Ym',$this->apuracao); $this->proxApuracao=$previa->addMonth()->format('Ym'); $arquivo=substr($arquivo,0,-4); $diretorio="C:/Users/Frank/Downloads/".$arquivo; $contaArquivos=count(scandir($diretorio))-2; $nfces = scandir($diretorio); $this->notasCanceladas=0; $this->somaTotal=0; $this->comST=0; $this->semST=0; foreach($nfces as $nfce) { if($nfce !== '.' && $nfce !=='..' ) { if(strpos($nfce,'-can') !== false) { $this->nfCanceladas[] = intval(substr($nfce,28,6)); $this->notasCanceladas++; continue; } $numeroNota=intval(substr($nfce,28,6)); if(in_array($numeroNota,$this->nfCanceladas)) { continue; } $this->notasFiscais[]=$numeroNota; $dom = new DOMDocument(); $dom->load("$diretorio/$nfce"); $nfe=$dom->documentElement; if($nfe->getElementsByTagName('vNF')->item(0)) { $somaNF=$nfe->getElementsByTagName('vNF')->item(0)->nodeValue; $this->somaTotal+=$somaNF; $produtos=$nfe->getElementsByTagName('prod'); foreach($produtos as $p) { $cfop=$p->getElementsByTagName('CFOP')->item(0)->nodeValue; $vProd=$p->getElementsByTagName('vProd')->item(0)->nodeValue; $vDesc=0; if($p->getElementsByTagName('vDesc')->item(0)) { $vDesc=$p->getElementsByTagName('vDesc')->item(0)->nodeValue; } if($cfop==5405) { $this->comST += $vProd - $vDesc; } else { $this->semST += $vProd - $vDesc; } } } } } sort($this->notasFiscais); $this->primeiraNota=intval($this->notasFiscais[0]); $this->ultimaNota=intval($this->notasFiscais[$contaArquivos-1]); $this->totalDeNotas=count($this->notasFiscais); $this->receitasAnteriores = tbrendabruta::orderBy('id','desc') ->skip(1)->take(12)->get(); $this->renda12=array_reduce($this->receitasAnteriores->toArray(),function($total,$r) { return $total + $r['renda']; },0); $this->grupos=array_chunk($this->receitasAnteriores->toArray(),3); $this->efetiva=round((($this->renda12*$this->aliquota/100-$this->reducao)/$this->renda12)*100,4); $this->CST=round($this->comST*$this->efetiva/100*(1-34/100),2); $this->SST=round($this->semST*$this->efetiva/100,2); $this->TT=$this->CST+$this->SST; } function mount() { $this->modal=true; } } ?> arquivo resources > views > livewire > simples.blade.php <div> <div class="mt-5"></div> @if($modal) <flux:input type="file" wire:model="zip" label="Escolha um arquivo zipado da Bling já descompactado" onchange="arquivo=event.target.files[0].name; Livewire.dispatch('verArquivo',[arquivo])" /> @else <div class=font-semibold>Estimativa do Simples Nacional {{ $apuracao }}</div> <div class="flex items-center"> Próxima Apuração {{ $proxApuracao }} <div class="w-[200px] ml-2"> <flux:input wire:model="venda" wire:change="incluir" size=xs placeholder="valor da venda"/> </div> </div> <div class=flex> <div>Total de Notas</div> <div class="ml-2">{{$totalDeNotas}}</div> </div> <div class=flex> <div>Notas Canceladas</div> <div class="ml-2 text-right mr-2">{{$notasCanceladas.": ";}}</div> @foreach($nfCanceladas as $n) {{ $n." "}} @endforeach </div> <div class=flex> <div>Primeira Nota</div> <div class="text-right ml-2 font-semibold">{{$primeiraNota}}</div> <div class="ml-5">Última Nota</div> <div class="text-right ml-5 font-semibold">{{$ultimaNota}}</div> </div> @foreach($grupos as $grupo) <div class='flex'> @foreach($grupo as $r) <div class="w-[40px] font-semibold">{{$r['apuracao']}}</div> <div class="w-[100px] text-right mr-5">{{dec($r['renda'])}}</div> @endforeach </div> @endforeach <div class="flex"> <div class="mr-5">Renda 12 meses:</div> <div class="font-semibold">{{dec($renda12)}}</div> </div> <div class="flex"> <div class="w-[130px]">Alíquota Efetiva</div> <div class="w-[320px]">{{"(".dec($renda12)." x ".virgula($aliquota). " % - ".dec($reducao).") / ".dec($renda12)}}</div> <div class="w-[10px]">{{" = "}}</div> <div class="w-[80px] text-right font-semibold">{{ virgula($efetiva)." %" }} </div> </div> <div class=flex> <div class="w-[70px]">Com ST</div> <div class="w-[100px] text-right">{{dec($comST)}}</div> <div class="ml-1 w-[160px]">{{ " x ".virgula($efetiva)." % x (1 - 34%)"}}</div> <div class="w-[10px]">=</div> <div class="w-[100px] font-semibold text-right">{{ dec($CST) }}</div> </div> <div class=flex> <div class="w-[70px]">Sem ST</div> <div class="w-[100px] text-right">{{dec($semST)}}</div> <div class="ml-1 w-[160px]">{{ " x ".virgula($efetiva)." %"}}</div> <div class="w-[10px]">=</div> <div class="w-[100px] font-semibold text-right">{{ dec($SST) }}</div> </div> <div class=flex> <div class="w-[70px]">Total</div> <div class="w-[100px] text-right">{{dec($somaTotal)}}</div> <div class="ml-1 w-[160px]"></div> <div class="w-[10px]">{{ " " }}</div> <div class="w-[100px] font-semibold text-right text-red-700">{{ dec($TT) }}</div> </div> @endif </div> -
O tutorial do Livewire afirma que é fácil fazer upload, mas eu só recebi a mensagem de que o upload falhou, no caso do arquivo zipado. Mas eu vi que o <input type=file> pegou o nome do arquivo selecionado. Com a ajuda do Copilot, consegui pegar o nome do arquivo e mandar para o Livewire: arquivo app > Livewire > Simples.php <?php namespace App\Livewire; use Livewire\Component; class Simples extends Component { protected $listeners=['verArquivo']; public function verArquivo($arquivo) { dd($arquivo); } } arquivo resources > views > livewire > simples.blade.php <flux:input type="file" onchange="arquivo=event.target.files[0].name; Livewire.dispatch('verArquivo',[arquivo])" /> Apesar do código ser bem pequeno, isso é resultado de várias tentativas e erros. Foi muita sorte o código JavaScript funcionar, a lista do Copilot era bem maior. Já o Livewire.dispatch, esse deu muito trabalho, a ideia de colocar colchete em torno da variável que contém o nome do arquivo foi pura tentativa erro, não sei como usar o comando dispatch, mas nesse caso, deu certo. Claro que o nome do arquivo não ajuda muito, mas eu espero explorar o diretório que tem o mesmo nome do arquivo zipado. O PHP, o Laravel e o Livewire não gostam de arquivos zipados, mas para trabalhar com arquivo xml, eles não reclamam.
-
O orçamento é apenas uma equação do primeiro grau, onde orçamento = quantidade x preço. O PHP e o Laravel permitem pegar o valor do <input name=quantidade> e passar para a variável $quantidade através do recurso do <form>. Já o Livewire elimina o transtorno do <form> usando apenas <input wire:model=quantidade>. Isso é bem engenhoso. O problema é o preço. No PHP e no Laravel, eu tive que criar dois módulos, o orçamento e o produto. Para não perder as informações do orçamento eu usei a variável global session(['pedido'=>$pedido]), e assim eu pulava do módulo orçamento para o módulo produto. E no módulo produto, eu usei a variável global session(['codprod'=>$codprod]) e assim voltava para o módulo do orçamento para fazer o resto do serviço. A variável global é uma mão na roda, o problema são os outros módulos, e eu estou enfrentando um monte de problema de lógica. A minha ideia é acabar com a variável global, e usar o Livewire para carregar o orçamento e o produto ao mesmo tempo no navegador, a minha ideia é fazer do produto um modal do orçamento, e assim que o usuário selecionar o produto, ele usa o comando dispatch( ) para enviar o código do produto para o orçamento, e o orçamento usa o recurso do ouvinte ("listener") para pegar o código do produto para terminar a equação. Falar é fácil, codificar são outros quinhentos. Aqui só fiz o esboço.
-
O Livewire é a soma de três arquivos: o componente, o layout e o encaixe, os dois últimos usam o CSS Tailwind. Eu comecei a estudar o Laravel em 2022, mas em 2025 é que consegui dominar melhor porque eu consegui decorar um pouco a sintaxe do Tailwind. Só é possível mexer com o Tailwind com a ajuda do Copilot. Para contornar o problema do Tailwind é que inventaram o <flux>, ele é um componente do HTML que já vem pré-formatado, você não precisa do Copilot para desenhar um <input>. Mas para o Tailwind, o Livewire e o Flux funcionarem, o seu arquivo layout deve seguir essa diretriz: arquivo resources > views > components > teste.blade.php <!DOCTYPE html> <title>{{ $title }}</title> @vite(['resources/css/app.css', 'resources/js/app.js']) @livewireScripts @fluxAppearance <body> <flux:main> {{ $slot }} </flux:main> @fluxScripts </body> arquivo app > Livewire > Lteste.php <?php namespace App\Livewire; use Livewire\Attributes\Layout; use Livewire\Component; #[Layout('components.layouts.teste',['title'=>'Teste'])] class Lteste extends Component { } ?> arquivo resources > views > livewire > lteste.blade.php <div> <flux:modal.trigger name="edit-profile"> <flux:button>Edit profile</flux:button> </flux:modal.trigger> <flux:modal name="edit-profile" class="md:w-96"> <div class="space-y-6"> <div> <flux:heading size="lg">Update profile</flux:heading> <flux:text class="mt-2">Make changes to your personal details.</flux:text> </div> <flux:input label="Name" placeholder="Your name" /> <flux:input label="Date of birth" type="date" /> <div class="flex"> <flux:spacer /> <flux:button type="submit" variant="primary">Save changes</flux:button> </div> </div> </flux:modal> </div> arquivo routes > web.php <?php use App\Livewire\Lteste; Route::middleware(['auth','verified'])->group(function() { Route::get('lteste',Lteste::class)->name('lteste'); } ?>
-
Há muito tempo, eu consegui esse código para criar o arquivo csv no PHP e no Laravel <?php // listagem parcial class Orcamento extends Controller { function bling(Request $request) { // rotina para criar $dados $arquivo = fopen("$request->pBling.csv", "w"); fputcsv($arquivo, $dados[0]); foreach ($dados as $linha) { if ($linha != $dados[0]) { fputcsv($arquivo, $linha); } } fclose($arquivo); if (file_exists("$request->pBling.csv")) { header('Content-Description: File Transfer'); header('Content-Type: application/octet-stream'); header('Content-Disposition: attachment; filename=' . basename("$request->pBling.csv")); header('Content-Length: ' . filesize("$request->pBling.csv")); readfile("$request->pBling.csv"); unlink("$request->pBling.csv"); } } Mas esse código não funciona no Livewire. Depois de pesquisar o Livewire, o Laravel, o Copilot e um monte de tentativa e erro, cheguei nesse código: arquivo app > Livewire > Lorcamento.php <?php namespace App\Livewire; use App\Models\tbhistped; use App\Models\tbpedido; use App\Models\tbpessoa; use App\Models\tbprod; use Livewire\Attributes\Layout; use Livewire\Component; #[Layout('components.layouts.app',['titulo'=>'Orçamento'])] class Lorcamento extends Component { public $bling,$histped,$mensagem,$modal,$modal2; public $pedido,$pessoa,$procPed,$prod,$qt,$vendido,$vr=[]; // listagem parcial function gerarBling() { $this->modal = false; $this->modal2 = false; $pedido = $this->pedido; $pBling = $this->bling; tbpedido::where('ped',$pedido)->update(['bling'=>$pBling]); $contato="Consumidor Final"; $itens=tbhistped::where('ped',$pedido)->get(); $previa=tbhistped::where('ped',$pedido)->where('subtotal','<',0) ->sum('subtotal'); $desconto=$previa ? abs($previa) : 0; $total=tbpedido::where('ped',$pedido)->value('total'); $data=date('d/m/Y',strtotime(tbpedido::where('ped',$pedido)->value('dia'))); $dados = array( array("Número pedido","Nome Comprador","Data","CPF/CNPJ Comprador","Endereço Comprador", "Bairro Comprador","Número Comprador","Complemento Comprador","CEP Comprador","Cidade Comprador", "UF Comprador","Telefone Comprador","Celular Comprador","E-mail Comprador","Produto", "SKU","Un","Quantidade","Valor Unitário","Valor Total", "Total Pedido","Valor Frete Pedido","Valor Desconto Pedido","Outras despesas","Nome Entrega", "Endereço Entrega","Número Entrega","Complemento Entrega","Cidade Entrega","UF Entrega", "CEP Entrega","Bairro Entrega","Transportadora","Serviço","Tipo Frete", "Observações","Qtd Parcela","Data Prevista","Vendedor","Forma Pagamento", "ID Forma Pagamento")); foreach($itens as $item) { if($item->subtotal>0) { $dados[]=array($pBling,$contato,$data,null,null, null,null,null,null,null, null,null,null,null,null, $item->codprod,$item->un,$item->qt,$item->unitario,$item->subtotal, $total,null,$desconto,null,null, null,null,null,null,null, null,null,null,null,null, null,1,$data,null,1, 0); } } $path=storage_path(); $arquivo = fopen($path.$pBling.".csv", "w+"); fputcsv($arquivo, $dados[0]); foreach ($dados as $linha) { if ($linha != $dados[0]) { fputcsv($arquivo, $linha); } } fclose($arquivo); return response()->download($path.$pBling.".csv","$pBling.csv") ->deleteFileAfterSend(true); } } Esse código funciona tanto no Windows quanto no Hostinger. Mas dessa vez eu tive a curiosidade de saber onde exatamente o Laravel cria o arquivo csv. Do jeito que eu fiz, o Laravel cria o arquivo no diretório raíz, e eu chamei o arquivo de 1234.csv, já o Laravel muda o nome para storage1234.csv. Na hora de fazer o download, ele desce com o nome 1234.csv. Eu não sei se posso ou não usar o diretório raiz, mas é assim que estou trabalhando. Aqui no Windows, eu consegui criar o arquivo na pasta Storage, mas lá na Hostinger eu não tenho a menor ideia de como fazer isso.
-
Tudo indica que o Livewire é a versão PHP do Ajax. Eu não consegui trabalhar com o Ajax, mas eu estou conseguindo me entrosar com o Livewire. Em homenagem ao Livewire, eu criei um código PHP que tenta imitar a mágica que ele faz: arquivo teste.php <?php class Teste { public $mensagem, $renda, $view; function visao() { $this->view = " <div>$this->mensagem</div> <form method=post> <input name=renda onchange=submit() placeholder=$this->renda> </form> a sua renda é de $this->renda "; echo $this->view; } function __construct() { $this->renda=$_POST['renda'] ?? null; $this->mensagem="Qual a sua renda?"; $this->visao(); } } new Teste;
-
Finalmente, consegui um modal semi-transparente
pergunta respondeu ao Frank K Hosaka de Frank K Hosaka em PHP
Fiz um ajuste para o modal informar ou solicitar informação do usuário. Ele funciona no notebook, não ficou nada legal no celular e não tenho um tablet para testar: arquivo resources > views > livewire > lorcamento.blade.php <div> @if($modal) <div class="fixed inset-0 flex items-center justify-center" style="background-color: rgba(0, 0, 0, 0.5)"> <div class="bg-white p-6 rounded shadow-lg"> <h2 class="text-lg font-semibold">Mensagem</h2> <p class="mt-2 text-gray-700 text-xl whitespace-nowrap">{{$mensagem}}</p> @if($modal2) <flux:input wire:model="bling" wire:change="gerarBling" /> @endif <flux:button wire:click="fecharModal" class="mt-2"> Fechar </flux:button> </div> </div> @endif <!-- listagem parcial --> </div> arquivo app > Livewire > Lorcamento.php <?php namespace App\Livewire; use App\Models\tbhistped; use App\Models\tbpedido; use App\Models\tbpessoa; use App\Models\tbprod; use Livewire\Attributes\Layout; use Livewire\Component; #[Layout('components.layouts.app',['titulo'=>'Orçamento'])] class Lorcamento extends Component { public $bling,$histped,$mensagem,$modal,$modal2; public $pedido,$pessoa,$procPed,$prod,$qt,$vendido,$vr=[]; function apagarBling($pedido) { tbpedido::where('ped',$pedido)->update(['bling'=>null]); $this->montarPedido($pedido); } function blingar($vendido=null) { if(is_null($vendido)) { $this->mensagem="O pedido Bling só pode ser criado depois de registrar a venda"; $this->modal=true; } else { $this->mensagem="Número do pedido Bling"; $this->modal=true; $this->modal2=true; } } function blingProximo() { $numeros=tbpedido::whereNotNull('bling')->orderBy('bling')->get(); $intervalos=[]; $inicio=$fim=$numeros[0]->bling; foreach($numeros as $numero) { if($numero->bling == $fim || $numero->bling == $fim + 1) { $fim=$numero->bling; } else { $intervalos[]=($inicio==$fim) ? $inicio : "$inicio-$fim"; $inicio=$fim=$numero->bling; } } $intervalos[]=($inicio==$fim) ? $inicio : "$inicio-$fim"; $this->mensagem="Pedidos já utilizados: "; foreach($intervalos as $key => $i) { $this->mensagem .= $i; if($key===array_key_last($intervalos)) { $this->mensagem .= "."; } else { $this->mensagem .= ","; } } $this->modal=true; } function fecharModal() { $this->modal=false; $this->modal2=false; } // listagem parcial } -
Hoje eu reclamei com o Copilot que a classe "bg-opacity-50" do Tailwind não funciona comigo, assim ele sugeriu utilizar um CSS clássico com um style inline: arquivo resources > views > lorcamento.blade.php (listagem parcial) @if($modal) <div class="fixed inset-0 flex items-center justify-center" style="background-color: rgba(0, 0, 0, 0.5)"> <div class="bg-white p-6 rounded shadow-lg w-96"> <h2 class="text-lg font-semibold">Mensagem</h2> <p class="mt-2 text-gray-700 text-xl">{{$mensagem}}</p> <flux:button wire:click="fecharModal" class="mt-4"> Fechar </flux:button> </div> </div> @endif arquivo app > Livewire > Lorcamento.php (listagem parcial) <?php // ... function bling($pedido,$vendido=null) { if(is_null($vendido)) { $this->mensagem="O pedido Bling só pode ser criado depois de registrar a venda"; $this->modal=true; } } function fecharModal() { $this->modal=false; }
-
A Bling tem um serviço que pega os dados atuais do MySQL através de arquivos CSV e atualiza o cadastro de produtos. O problema é que isso acaba saindo caro porque cada atualização acaba aumentando o espaço ocupado no armazenamento de dados. A minha saída foi atualizar os produtos na Bling na unha. Ou seja, eu não mando um arquivo csv, eu pego o CSV da Bling e depois eu comparo com o MySQL. Quando são poucos registros para atualizar, é fácil selecionar, copiar e colar. Mas hoje eu tive que enfrentar um monte de atualização, e pedi socorro para o Copilot, perguntei se ele sabia se o JavaScript é capaz de transferir os dados que foram clicados para a área de transferência, isso reduziu 50% o meu serviço de edição: arquivo resources > views > lbling-diferenca.blade.php <div> <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 </div> arquivo app > Livewire > LblingDiferenca.php <?php namespace App\Livewire; use App\Models\tbprod; use App\Models\tbprodbling; use Illuminate\Support\Facades\DB; use Livewire\Attributes\Layout; use Livewire\Component; #[Layout('components.layouts.app',['titulo'=>'Diferença na Bling'])] class LblingDiferenca extends Component { public $contaProdBling, $contaProduto, $dif=[]; function mount() { DB::table('tbprodbling')->truncate(); $arquivos=$_FILES['arquivos']; foreach($arquivos['tmp_name'] as $arquivo) { $dados=file($arquivo); foreach($dados as $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])); tbprodbling::create(['codprod'=>$codprod,'un'=>$un, 'prod'=>$prod,'custo'=>$custo,'codbar'=>$codbar, 'cf'=>$cf,'venda'=>$venda]); } } } $produto=tbprod::where('loc','<>','a24')->get(); $prodBling=tbprodbling::all(); $this->contaProduto=count($produto); $this->contaProdBling=count($prodBling); if($this->contaProdBling>$this->contaProduto) { $prod=$produto->pluck('codprod'); $pBling=$prodBling->pluck('codprod'); $difs=$pBling->diff($prod); foreach($difs as $d) { echo "problema no codprod $d na Bling <br>"; } dd('parada total'); } foreach($produto as $key=>$pr) { $codprod=$pr->codprod; $previa=tbprodBling::where('codprod',$codprod)->get(); if(count($previa)==0) { $this->dif[$key][]=['Codigo'=>$codprod]; $this->dif[$key][]=['Incluir'=>$codprod,'Incluir2'=>'Incluir']; } else { $a=tbprodBling::where('codprod',$codprod)->first(); $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]; } } } } } }
-
Hoje eu vi que o meu irmão Jorge tentou alterar centenas de descrição de produtos na tentativa de tornar a leitura mais fácil para ele. Eu achei a ideia dele muito boa, e eu perguntei para o Copilot como eu faço para o HTML respeitar os espaços adicionais que o usuário tenta acrescentar na descrição do produto. O Copilot sugeriu eu usar caracteres invisíveis mas que não seja a barra de espaço. Eu fiquei bastante indignado, é muito difícil apertar a barra de espaço, imagine mexer com várias teclas ao mesmo tempo para incluir um caractere invisível. Mas eu lembrei do marcador <pre></pre>, eu uso bastante na hora de fazer depuração dos meus códigos. Pensei, o que me impede de usar esses marcadores no meu código? E assim eu testei: <?php foreach($produtos as $prod): ?> <pre class="font-sans"><?=$prod->prod?></pre> <?php endforeach; ?> E não é que deu certo! Agora, todos os espaços que o meu irmão colocou na descrição vão aparecer na tela da Web!
-
Código não traz os dados para alteração e exclusão
pergunta respondeu ao PaiDeLaura de Frank K Hosaka em VBA
Tem muito serviço por aqui, mas fiz o teste com a rotina cmdAlterar_Click( ), tentando fazer o comando funcionar, e ficou assim (simplifiquei bastante para testar a lógica): Acredito que o comando exit do está no lugar correto, assim sobrou dois comandos para verificar, o If not validated ... e o call cmdLimpar, mas isso é bastante serviço, e isso vai além do escopo de qualquer fórum. A minha sugestão é testar um código de cada vez, tipo Cell(1,1)="olá mundo", e vai acrescentando um novo recurso de cada vez. Private Sub cmdAlterar_Click() Dim linha As Long Dim encontrado As Boolean linha = 2 ' Começar da linha 2 With Sheets("AgendaEventos") Do While .Cells(linha, 1).Value <> "" If .Cells(linha, 1).Value = Me.txtNumOficio.Text Then .Cells(linha, 2).Value = Me.txtEvento.Text encontrado = True End If linha = linha + 1 Loop End With If encontrado Then MsgBox "Registro alterado com sucesso!", vbInformation Else MsgBox "Número de Ofício não encontrado para alteração!", vbExclamation End If End Sub -
Não consegui usar Livewire.dispatch( ) dentro do JavaScript [Resolvido]
pergunta respondeu ao Frank K Hosaka de Frank K Hosaka em PHP
Encontrei a resposta nessa mensagem: https://github.com/livewire/livewire/pull/8226 Adaptando ao meu código, ficou assim: arquivo app > Livewire > Lcontrolid.php <?php namespace App\Livewire; use App\Models\tbpedido; use Livewire\Attributes\Layout; use Livewire\Component; #[Layout('components.layouts.app',['titulo'=>'Imprimir Pedido'])] class Lcontrolid extends Component { public $itens,$modal,$ped; protected $listeners=['voltar'=>'voltar']; function mount($pedido) { $this->ped=$pedido; $this->itens=tbpedido::where('tbpedido.ped',$pedido) ->join('tbhistped','tbpedido.ped','=','tbhistped.ped') ->join('tbprod','tbprod.codprod','=','tbhistped.codprod')->get(); $num_rows=count($this->itens); if($num_rows==0) { $this->modal=true; } session(['ocultar'=>true]); } function voltar() { session()->forget('ocultar'); redirect("/lorcamento/$this->ped"); } } arquivo resources > views > livewire > lcontrolid.blade.php <div> @if($modal) Não há nada para imprimir @else <table> <tr class=fw-semibold><td colspan=7>Quitanda do Frank Corporation <tr class=fw-semibold><td colspan=7>Pedido {{$itens[0]->ped}} de {{dbr($itens[0]->dia)}} @foreach($itens as $item) <tr><td colspan=7>{{$item->prod}} <tr><td class=text-end>{{$item->qt}} <td class=text-end>{{$item->un}} <td class=px-2>x<td class=text-end>{{dec($item->unitario)}} <td class=px-2>=<td class=text-end>{{dec($item->subtotal)}} @endforeach <tr class=fw-semibold><td>Total<td><td><td><td><td class=text-end>{{dec($itens[0]->total)}} @endif @script <script> window.print() window.onafterprint = function() { setTimeout(()=>{$wire.$dispatch('voltar')}) // location.replace('/lorcamento/{{$ped}}') } </script> @endscript </div> -
O Livewire não consegue fazer o serviço de impressão. Quem faz isso é o bom e velho JavaScript. O problema é como o JavaScript vai devolver o comando para o Livewire. Há vários tutoriais na internet, recomendando a usar o Livewire.dispatch("voltar") dentro do JavaScript e um protected $listeners=["voltar"=>"voltar"] dentro do componente, mas isso não deu certo comigo, eu tive que apelar para a velha gambiarra, eu pedi para o JavaScript voltar para o orçamento. arquivo app > Livewire > Lcontrolid.php <?php namespace App\Livewire; use App\Models\tbpedido; use Livewire\Attributes\Layout; use Livewire\Component; #[Layout('components.layouts.app',['titulo'=>'Imprimir Pedido'])] class Lcontrolid extends Component { public $itens,$modal,$ped; function mount($pedido) { $this->ped=$pedido; $this->itens=tbpedido::where('tbpedido.ped',$pedido) ->join('tbhistped','tbpedido.ped','=','tbhistped.ped') ->join('tbprod','tbprod.codprod','=','tbhistped.codprod')->get(); $num_rows=count($this->itens); if($num_rows==0) { $this->modal=true; } session(['ocultar'=>true]); } } arquivo resources > views > livewire > lcontrolid.blade.php <div> @if($modal) Não há nada para imprimir @else <table> <tr class=fw-semibold><td colspan=7>Quitanda do Frank Corporation <tr class=fw-semibold><td colspan=7>Pedido {{$itens[0]->ped}} de {{dbr($itens[0]->dia)}} @foreach($itens as $item) <tr><td colspan=7>{{$item->prod}} <tr><td class=text-end>{{$item->qt}} <td class=text-end>{{$item->un}} <td class=px-2>x<td class=text-end>{{dec($item->unitario)}} <td>=<td class=text-end>{{dec($item->subtotal)}} @endforeach <tr class=fw-semibold><td>Total<td><td><td><td><td class=text-end>{{dec($itens[0]->total)}} @endif <script> window.print() window.onafterprint = function() { location.replace('/lorcamento/{{$ped}}') } </script> </div>
-
duvida por que meu codigo não esta recebendo os dados POST no controller
pergunta respondeu ao Braz Mendes de Frank K Hosaka em PHP
É porque você esqueceu de definir a rota do <form> através da propriedade action. A sintaxe correta é <form method=post action=controller.add> O problema é como o conteúdo do <input> vai chegar até aquela classe, isso vai depender do roteador. Eu tenho um código php que trabalha com a instancia de classe, e assim eu defino o action assim: <form method=post action=?controller.add>, ele força o navegador a jogar tudo para o arquivo index.php e de lá o roteador vai procurar a classe e o método correspondente. Enfim o roteador é um capítulo bem espinhoso que você precisa dominar antes de usar o <form> Mas essa fase já passou para mim. Eu não preciso mais usar o <form> para mandar o conteúdo do <input> para a variável $titulo, tem um rapaz que inventou o Livewire no Laravel, ele inventou o <input wire:model='titulo'>, assim que você dá o enter a variável $titulo já está definido. É uma mágica surpreendente! -
Lá em 2022 eu vi matéria de como o Laravel passa parâmetros de uma Blade para o Controller, só que eu não entendi nada, e improvisei assim <a href=orcamento?apagar=1>Orçamento</a> Isso deu certo até mesmo com o Livewire. Mas aqui em 2025, eu conto com o Copilot e com ele me aventurei a definir os parâmetros dentro do Route, agora com o paradigma do Livewire: Route::get('lorcamento/{pedido?}/{apagar?}',Lorcamento::class)->name('lorcamento'); Tentei mudar isso, mas o Copilot disse que não dá, essa é a sintaxe do Laravel. O que eu gostei é do ponto de interrogação, ele torna o parâmetro opcional. Eu defini o menu do orçamento, dentro do resources > views > components > layouts > app.blade.php <a class="block px-4 py-2 hover:bg-gray-200" href="{{ route('lorcamento',['apagar'=>1])}}"> Orçamento </a> E finalmente o componente ficou assim: function mount($pedido=null,$apagar=null) { $this->montarPedido($pedido,$apagar); } Note que o nome do parâmetro é exatamente igual ao que foi definido no Route, só que ele usa o prefixo $. O meu sonho é acabar com os parâmetros com a ajuda do Livewire, e definir o Route assim: Route::get('lorcamento',Lorcamento::class)->name('lorcamento'); Mas até esse dia chegar, preciso eliminar um monte de gambiarra que inventei na rotina do orçamento. Todos eles foram para o Liveware, só precisei adaptar aqui e ali. Foi isso que me fez gostar bastante do Liveware, ele é muito mais flexível que o Laravel.
-
Antes de conhecer o Livewire, eu usava o POST para atualizar a tela, o Livewire usa ouvintes ('listeners'), que executam tarefas para mudar as propriedades de um componente e assim mudam as informações que estão na tela, logo depois de ouvir a gritaria do dispatch( ). A seguir tenho um componente chamado razão que executa a mudança da apuração e a apuração aparece na forma de modal e assim que o usuário escolhe a nova apuração, a apuração grita "terminei!" e o razão faz o resto do serviço, e tudo isso sem usar o POST. Eu acredito que o listener é uma forma bem inteligente de executar um método dentro de uma classe. O clássico Laravel usava o Route para cada tarefa que você precisava executar dentro de uma classe, no Livewire o Route só serve para dizer aonde está a classe, ou, mais precisamente, o componente. arquivo resources > views > livewire > lrazao.blade.php <div> <div class="flex bg-gray-200"> <div class="w-[50px] text-right mr-2">Lcto</div> <div class="w-[200px]"> @livewire('lbalanceteApuracao') </div> <div class="w-[500px] -ml-3"> <a href="balanceteInicio" class="text-gray-500 font-semibold">{{$razao->conta}} {{$razao->descricao}}</a> </div> </div> <div class="flex font-semibold"> <div class="w-[240px] text-right mr-2">{{dec($razao->inicio)}}</div> <div>Saldo anterior</div> </div> @foreach($lctos as $lcto) @if($lcto->contad==$razao->conta) <div class="flex even:bg-gray-200"> <div class="w-[50px] text-right"> <a href="ldiarioLcto?docto={{$lcto->docto}}" class="text-gray-500 font-semibold">{{$lcto->lcto}}</a> </div> <div class="w-[40px] text-right">{{$lcto->contac}}</div> <div class="w-[50px] text-right"> <a href="balanceteDiario?dia='{{$lcto->dia}}'" class="text-gray-500 font-semibold"> {{date('d/m',strtotime($lcto->dia))}} </a> </div> <div class="w-[100px] text-right mr-2">{{dec($lcto->valor)}}</div> <div class="w-[350px] whitespace-nowrap overflow-auto">{{$lcto->hist}}</div> </div> @endif @if($lcto->contac==$razao->conta) <div class="flex even:bg-gray-200"> <div class="w-[50px] text-right"> <a href="ldiarioLcto?docto={{$lcto->docto}}" class="text-gray-500 font-semibold"> {{$lcto->lcto}} </a> </div> <div class="w-[40px] text-right text-red-500">{{$lcto->contad}}</div> <div class="w-[50px] text-right"> <a href="balanceteDiario?dia={{$lcto->dia}}" class="text-gray-500 font-semibold"> {{date('d/m',strtotime($lcto->dia))}} </a> </div> <div class="w-[100px] text-right text-red-500 mr-2">{{dec($lcto->valor)}}</div> <div class="w-[350px] whitespace-nowrap overflow-auto">{{$lcto->hist}}</div> </div> @endif @endforeach <div class="flex even:bg-gray-200 font-semibold"> <div class="w-[240px] text-right">{{dec($razao->fim)}}</div> <div class="ml-2"> Saldo atual {{dec($razao->debito)}} <span class="text-red-500">{{dec($razao->credito)}}</span> </div> </div> </div> arquivo resources > views > livewire > lbalancete-apuracao.blade.php <div> <div wire:click=alteraModal class="text-gray-500 font-semibold">{{ $apuracao }}</div> @if($modal) <div class="fixed inset-0 flex items-center justify-center"> <div class='bg-white p-6 rounded shadow-lg border-4 border-gray-500'> <div class="text-nowrap">Selecione o período de apuração</div> <select wire:model="ano"> @foreach($anos as $key => $ano) @if($key == 0) <option value="{{ $ano }}" selected>{{ $ano }}</option> @else <option value="{{ $ano }}">{{ $ano }}</option> @endif @endforeach </select> <div class="mt-3"> @foreach($meses as $posicao => $mes) <button class="ml-1 hover:bg-gray-200 text-gray-500 font-bold py-1 rounded" wire:click="apurada({{ $posicao + 1 }})">{{ $mes }}</button> @endforeach </div> </div> @endif </div> arquivo app > Livewire > Lrazao.php <?php namespace App\Livewire; use App\Models\tbdiario; use Livewire\Attributes\Layout; use Livewire\Component; #[Layout('components.layouts.app',['titulo'=>'Razão'])] class Lrazao extends Component { public $apuracao, $lctos, $razao; protected $listeners=['razaoAtualizar'=>'atualizar']; function atualizar() { $dia=session('apuracao') ?? date('Y-m-d'); $this->apuracao=apuracao($dia); $primeiroDia=$this->apuracao->primeiroDia; $ultimoDia=$this->apuracao->ultimoDia; $this->lctos=tbdiario::whereBetween('dia',[$primeiroDia,$ultimoDia])->get(); } function mount () { $conta=request()->input('conta') ? request()->input('conta') : session('razao'); $balancete=(new Lbalancete)->balancete()->balancete; $this->razao=array_column($balancete, null, 'conta')[$conta] ?? false; $this->atualizar(); } } ?> arquivo app > Livewire > LbalanceteApuracao.php <?php namespace App\Livewire; use App\Models\tbdiario; use Livewire\Component; class LbalanceteApuracao extends Component { public $ano, $anos=[],$apuracao,$mes,$modal; public $meses=['Jan','Fev','Mar','Abr','Mai','Jun','Jul','Ago','Set','Out','Nov','Dez']; public $depuracao; function apurada ($mes) { session(['apuracao'=>$this->ano."-".$mes."-01"]); $dia=session('apuracao'); $this->apuracao=apuracao($dia)->apuracao; $this->modal=false; $this->dispatch('razaoAtualizar'); } function alteraModal () { $this->modal = $this->modal ? false : true; } function mount() { $primeiroAno=substr(tbdiario::orderBy('dia')->value('dia'),0,4); $ultimoAno=substr(tbdiario::orderBy('dia','desc')->value('dia'),0,4); for($i=$ultimoAno;$i>=$primeiroAno;$i--) { $this->anos[]=$i; } $dia=session('apuracao'); $this->ano=date('Y',strtotime($dia)); $this->apuracao=apuracao($dia)->apuracao; } } ?>
-
O Copilot disse que o Livewire é baseado no Ajax, assim faz sentido quando você definir <input wire:model="pendencias.{{$index}}.vcto">. No começo achei bem estranho, pois eu estava acostumado com coisa do tipo <input value="{{ $pendencias[$index]->vcto }}">. É muito difícil entender o Livewire no começo, só o tempo é que você se familiarizar com a gramática do PHP e a gramática do Java Script Ajax que vem embutido no Livewire. Eu não tenho a menor ideia de como o Livewire conecta uma variável pública com um wire:model, mas na minha rotina de pendências eu precisei de um monte de wire:model para casar com um monte de pendência. Com a ajuda do Copilot, eu consegui isso: arquivo resources > views > livewire > lpgar.blade.php <div> <input wire:model="doc1" size="5" autocomplete="off" class="border-none rounded p-2 py-0"> <input wire:model="doc2" size="5" autocomplete="off" class="border-none rounded p-2 py-0"> <input type="submit" wire:click="ocultar" value="Ocultar Pendências"> <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> <div class="w-[346px] px-2 border">Pessoa</div> </div> @foreach($pendencias as $index => $pendencia) <div class="even:bg-gray-200"> <div class="flex"> <div class="w-[117px] ml-3 text-right"> <input type=date wire:model="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']}})" title="Lçto: {{ $pendencias[$index]['lcto'] }}" class="text-right"> {{ $pendencia['docto'] }} </div> </div> @if($pendencia['debito']) <div class="w-[110px] text-right"> <?=dec($pendencia['debito'])?> </div> @else <div class="w-[110px] text-right text-red-500"> <?=dec($pendencia['credito'])?> </div> @endif <div class="w-[346px] px-2 truncate"> <a class="text-gray-500 font-semibold hover:bg-gray-200" wire:click="selecionarPessoa({{$pendencia['docto']}})" title="Histórico: {!!$pendencia['hist']!!}"> <?=$pendencia['pessoa']?> </a> </div> </div> </div> @endforeach </div> Arquivo app > Livewire > Lpagar.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 Lpagar extends Component { public $doc1,$doc2,$pendencias=[]; function atualizaVcto($docto,$index) { $vcto=$this->pendencias[$index]['vcto']; tbcontacorrente::where('docto',$docto) ->update(['vcto'=>$vcto]); $this->montaPendencias(); } 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(); $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]; } } 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 selecionarDocto($docto) { if($this->doc1==null) { $this->doc1 = $docto; } else { if($this->doc2==null) { $this->doc2 = $docto; } } } function selecionarPessoa($docto) { session(['end'=>"lpagar?docto=$docto"]); redirect()->route("lpessoa"); } }
-
Nessa semana, eu consegui terminar de ver o tutorial gratuito no livewire.laravel.com, são vídeos rápidos falado em inglês. O tutorial gratuito mostra o básico, para recursos mais avançados o portal pede coisa da ordem de R$ 300,00, mesmo assim o tutorial gratuito fala do recurso de validação, confirmação, Alpine.js, e isso ainda não usei aqui. Eu já tinha visto o Livewire antes, mas eu não entendi o propósito dele. Nesse ano, o Laravel lançou a versão 12, o problema é que ele obriga a você escolher uma extensão: o Livewire, o Vue e o React. Eu escolhi o Livewire por achar que era o menos complicado. Eu tive que estudar o Livewire para adaptar o meu código escrito em Laravel. O problema é que eu não consegui adaptar coisa alguma. Assim eu peguei um tutorial e aos poucos fui migrando o meu código em Laravel para o Livewire, e acabei gostando. O Livewire acabou de vez com o mito MVC (modelo, visão e controle) e mostrou que é possível fazer a festa só trabalhando com a variável pública. No tempo do PHP e do Laravel, eu apanhei muito para pegar o valor do <input> para definir o valor da variável lá no Controller, usando uma complicada rotina de <form> e método POST. O Livewire acabou com esse pesadelo, basta você vincular o <input> com a variável através do recurso wire:model. Ele é fantástico! Agora, o Livewire mudou a linguagem, ao invés de Controle e Visão, agora é Componente e Visão; apesar deles serem visualmente diferentes (PHP e HTML), tudo indica que o Livewire conseguiu colocar tudo lá no navegador. O Livewire me deu muita coragem, e agora não tenho medo de mexer com o modal. O modal nada mais é que um código em HTML que você pode esconder e exibir, era necessário você dominar o JavaScript e o CSS para mexer com isso, eu gastei um monte de lenço de papel para fazer o modal funcionar. O Livewire me ensinou a usar um componente como modal, claro que o Copilot me ajudou bastante. O Liveware também me ensinou a fazer depuração. Quando um erro era encontrado no controle do Laravel, o Laravel parava tudo, e mostrava aquela mensagem "você está fazendo a coisa errada". Nem sempre o Liveware faz esse serviço, tudo é diferente. A primeira coisa que o Livewire faz é executar a função mount ( ), e se não tiver nada disso, ele mostra a visão. Se você aperta o botão, e nada acontece, basta usar o web console, e lá vai ter a mensagem 1 erro livewire.js. Eu aprendi que fiz um monte de erro de digitação na view. Mas se essa mensagem não aparece no web console, eu vou lá no componente e crio a variável pública $depuração, vou lá na visão e acrescento o comando {{ $depuração }} e finalmente vou no componente e uso a minha intuição e acrescento o código PHP $this->depuração="O problema pode estar aqui". Nem tudo dá para resolver no Livewire. Nessa semana eu pedi o balancete, mas o Livewire só mostrava o balancete de maio, quando precisava do balancete de abril. Isso é um erro de lógica. Para saber quem estava pedindo o balancete de maio eu usei o VS Code, pedi para ele listar todos os códigos onde havia o comando session(['apuracao'=> pelo comando Find in Files e assim eu cheguei no método tbw, onde ele pega a última data do diário contábil e monta o balancete. Foi fácil consertar, eu só pedi para apagar assim session( )->forget('apuracao') depois que o método conseguiu o que queria.
-
No mês passado, enfrentei o problema da diferença de um centavo entre o meu relatório e o da Bling, consegui resolver com a ajuda da função do PHP round( ) mais um epsilon de 0.0001. Hoje é Páscoa, e o coelhinho não trouxe o ovo, mas trouxe uma diferença de R$ 0,01 entre o meu relatório da previsão com o relatório da venda. Eu fiquei indignado. A minha saída foi entrar direto no MySQL e alterar o valor do pedido de 21.025 para 21.03, e assim consegui fazer o relatório da previsão bater com o relatório da venda. Foi aí que eu percebi que usei a função no lugar errado, ao invés de usar a função na consulta o certo é usar a função no momento do cálculo do item. O erro está aqui: $total = 0.15 x 3.50 = 0.525, o certo é $total=round(0.15 x 3.50,2)=0.53. O PHP é capaz de calcular com duas casas decimais. Três casas é pedir demais!
-
Eu estava reescrevendo o meu projeto Orçamento no formato Livewire na base da tentativa e erro, e até agora tem dado certo. Decidi estudar o Livewire de acordo com o tutorial. Logo na primeira página do livewire.laravel.com eu encontrei: <input wire:model.live="search"> Eu fiquei intrigado com o verbo "live", assim eu pedi ajuda para o Copilot para dar vida ao código, ele ficou assim: arquivo Lteste.php <?php namespace App\Livewire; use App\Models\tbprod; use Livewire\Attributes\Layout; use Livewire\Component; #[Layout('components.layouts.app',['titulo'=>'Teste'])] class Lteste extends Component { public $search; function render() { $results = $this->search ? tbprod::where('prod','like','%'.$this->search.'%')->get() : []; return view('livewire.lteste',compact('results')); } } arquivo lteste.blade.php <div> <flux:input wire:model.live="search" /> <ul> @foreach($results as $result) <li>{{ $result->prod }}</li> @endforeach </ul> </div> Ele é bacana, lembra o <datalist> do HTML, ele vai mostrando o resultado da busca na medida que você digita; mas o <datalist> precisa de todos os registros, já o Livewire vai buscar o resultado diretamente no MySQL. Eu escrevi "maçã", e o Livewire mostrou "maca" que eu cadastrei no MySQL. Fui no MySQL, eu mudei maca para maçã. Voltei no Livewire, escrevi maca e o Livewire mostrou maçã. Ele é bem melhor que o <datalist> que só retorna o que você digita, ele não suporta as variações da língua portuguesa. Se depender do Livewire dá para usar acentuações na descrição de produtos do MySQL, o problema é na hora de mandar a informação lá na Bling para ele emitir a NFCe, eu acredito que vai dar bode. Vou fazer o teste, e volto para dizer se é possível usar acentuação na descrição dos produtos.
-
Melhor que o atalho de teclado é o JavaScript. Hoje eu conheci o comando scrollIntoView( ), ele mostra o final da página, mas quando o <input> recebe o foco, o final da página some. Mas pelo menos o <input> fica sempre disponível no rodapé do navegador, principalmente quando a listagem é bem longa: arquivo lprevisao.blade.php (parcial) foreach($mercado as $m) <div class="flex odd:bg-gray-200 w-[350px]"> <div class="w-[100px] text-right">{{ dec($m->venda) }}</div> <div class="w-[100px] text-right">{{ dec($m->tarifa) }}</div> <div wire:click="excluir({{$m->id}})" class="w-[100px] text-right text-gray-500 font-semibold"> {{ dec($m->conta) }} </div> </div> @endforeach <div class=flex> <input id=venda wire:model="venda" class="w-[100px] text-right border border-gray-300 rounded-sm" autofocus> <input wire:model="tarifa" wire:change="incluir" onchange="venda.focus();ttarifa.scrollIntoView()" class="w-[100px] text-right border border-gray-300 rounded-sm"> </div> <div wire:click="registrar" class="flex odd:bg-gray-200 w-[350px] font-semibold"> <div class="w-[100px] text-right text-gray-500 font-semibold"> {{ dec($total->tvenda) }} </div> <div id=ttarifa class="w-[100px] text-right font-semibold">{{ dec($total->ttarifa) }}</div> <div class="w-[100px] text-right font-semibold">{{ dec($total->tconta) }}</div> </div>
-
HTML é uma linguagem que eu não domino, apesar de mexer com o PHP desde 2020. Hoje estou estudando o Livewire, mas tem uma rotina que eu chamei de previsão e queria dar um jeito de olhar o final da página. A maneira mais simples é a barra de rolagem no canto direito do navegador, mas o mouse está a vários quilômetros do destino e o pior é ter que fazer todo o caminho de volta. Assim, pensei em criar um atalho. Eu improvisei o seguinte código em PHP, não sei se vai funcionar lá no Livewire: <?php $mysqli = new mysqli("localhost", "root", "", "diario"); $produtos = $mysqli->query("SELECT * FROM tbprod LIMIT 30"); ?> <script src="https://cdn.tailwindcss.com"></script> <body class="min-h-screen flex flex-col justify-end"> <main class="flex flex-col gap-2"> <?php foreach($produtos as $index => $p): ?> <div class="px-2"><?=$p['prod']?></div> <?php if($index==10): ?> <a class="px-2 font-bold" href=#fimDaPagina>Ir para o final</a> <?php endif; endforeach; ?> </main> <div id="fimDaPagina"></div> </body> Esse é um péssimo exemplo de programação, o comando Ir para o final ficou bem no meio da listagem de produtos, o correto era colocar na barra de navegação, mas o meu conhecimento em HTML é precário, não sei como fixar a barra de navegação no topo da tela. A maneira mais fácil de chegar no fim de uma página é usando atalho de teclado. A maioria dos PCs usa CTRL + END. O meu é um notebook Galaxy Book S com Windows 11, usei Fn + flecha para baixo.
-
Antes do Laravel 12 eu usei o marcador <form><input></form>. O Livewire também tem o marcador <form>, mas eu ainda não sei como usá-lo, mas eu sei que o Livewire consegue trabalhar com o valor do <input wire:model="inputQt"> em conjunto com a variável pública $inputQt através do processo da "hidratação". O problema é que eu trabalho com o MySQL e tenho que mexer com vários registros e depois de muitas tentativas eu consegui casar o wire:model com os registros. Mas hoje estava brincando com o modal, e achei bem mais fácil trabalhar com um wire:model do que um monte deles: Esse é um trecho da view que chama a função wire:click="nfQt(...)" <!-- parte do blade --> @if($modal2) <div class="fixed inset-0 flex items-center justify-center"> <div class="bg-white p-6 rounded shadow-lg text-center border-8 border-gray-500"> <div>Qt anterior: {{ $qt }}</div> <div>Qt atual: </div> <input wire:model="inputQt" autofocus class=px-2> <button wire:click="nfQt({{$custoTotal}},{{$qt}},{{$codprod}},{{true}})" class="mt-4 bg-blue-500 text-white px-4 py-2 rounded"> Alterar </button> <button wire:click="$set('modal2', false)" class="mt-2 bg-red-500 text-white px-4 py-2 rounded"> Cancelar </button> </div> </div> @endif <!-- outra parte do mesmo blade --> @foreach($previa as $p) <div class="flex odd:bg-gray-200"> <div class="w-[80px] 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 wire:click="nfQt({{$p->custototal}},{{$p->qt}},{{$p->codprod}})" class="w-[50px] text-right"> {{ $p->qt }} </div> <div {!! $p->class !!} wire:click="atualizar({{$p->custoatual}},{{$p->custoanterior}},{{$p->codprod}})"> {{ dec($p->custoatual) }} </div> <div class="w-[70px] text-right">{{ dec($p->custototal) }}</div> </div> @endforeach Esse é o trecho do componente que executa o método nfQt(...), note que esse método serve tanto para chamar o modal bem como executar o resto do serviço, dependendo da escolha do usuário: <?php // ... function nfQt($custoTotal,$qt,$codprod,$executar = false) { if($executar) { $this->modal2=false; $novoCusto=round($custoTotal/$this->inputQt,2); $custoAnterior=tbprod::where('codprod',$codprod) ->value('custo'); if($novoCusto==$custoAnterior) { $class = "class='w-[70px] text-right'"; } else { $class = "class='w-[70px] text-right text-red-500'"; } tbnf::where('codprod',$codprod) ->update(['qt'=>$this->inputQt,'custoatual'=>$novoCusto, 'custoanterior'=>$custoAnterior,'class'=>$class]); $this->previa=tbnf::all(); } else { $this->custoTotal=$custoTotal; $this->qt=$qt; $this->codprod=$codprod; $this->modal2=true; } }
-
Não consegui usar a tecnologia Livewire com o marcador <details>, assim eu improvisei com um $modal. O seguinte código funciona no ambiente Hostinger: Lpessoas.php <?php namespace App\Livewire; use App\Models\tbpessoa; use Livewire\Attributes\Layout; use Livewire\Component; #[Layout('components.layouts.app',['titulo'=>'Pessoas'])] class Lpessoa extends Component { public $modal, $pessoas; function definirModal($i) { $this->modal=$i; } function mount() { $this->pessoas=tbpessoa::orderBy('pessoa') ->take(10)->get()->toArray(); } } ?> lpessoa.blade.php <div> @foreach($pessoas as $i => $pessoa) <div class="odd:bg-gray-200 flex"> <div class="w-[60px] text-right px-2">{{ $pessoas[$i]['codp'] }}</div> <div wire:click="definirModal({{$i}})"> @if($pessoa['vinculo']) <svg width="16" height="16" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><polygon points="50,75 25,25 75,25" style="fill:red;" /></svg> @else <svg width="16" height="16" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><polygon points="50,75 25,25 75,25" style="fill:black;" /></svg> @endif </div> <input wire:model="pessoas.{{$i}}.pessoa" class="px-2" /> </div> @if($modal===$i) // aqui usei o operador estritamente igual === para diferenciar o null de 0 <div class=flex> <div class=font-semibold>Endereço:</div> <input wire:model="pessoas.{{$i}}.end" class="px-2" /> </div> <div class=flex> <div class=font-semibold>CPF CNPJ:</div> <input wire:model="pessoas.{{$i}}.cnpj" class="px-2" /> </div> <div class=flex> <div class=font-semibold>Telefone:</div> <input wire:model="pessoas.{{$i}}.tel" class="px-2" /> </div> <div class=flex> <div class=font-semibold>Nota:</div> <input wire:model="pessoas.{{$i}}.nota" class="px-2" /> </div> <div class=flex> <div class=font-semibold>Vínculo:</div> <input wire:model="pessoas.{{$i}}.vinculo" class="px-2" /> </div> @endif @endforeach </div>
-
Finalmente, consegui trabalhar com o wire:model do Livewire com o MySQL. O Copilot me ajudou bastante a criar o código sem receber a mensagem "Livewire encountered corrupted data" no Hostinger: Lteste.php <?php namespace App\Livewire; use App\Models\tbprevisao; use Livewire\Component; class Lteste extends Component { public $previsao; function mount() { $this->previsao =tbprevisao::orderBy('conta') ->take(3)->get()->toArray(); } function updated($propertyName) { $parts=explode(".",$propertyName); $index=$parts[1]; $id=$this->previsao[$index]['id']; $valor=data_get($this,$propertyName); tbprevisao::where('id',$id) ->update(['valor'=>$valor]); } } lteste.blade.php <div class="w-[100px]"> <flux:input wire:model="previsao.0.valor" wire:change="$refresh" /> <flux:input wire:model="previsao.1.valor" wire:change="$refresh" /> <flux:input wire:model="previsao.2.valor" wire:change="$refresh" /> <pre>{{ print_r($previsao) }}</pre> </div>