Frank K Hosaka
Membros-
Total de itens
1.678 -
Registro em
-
Última visita
Tudo que Frank K Hosaka postou
-
O Livewire é basicamente um par de componente e seu Blade correspondente. O Copilot disse que não é possível acessar um método do Livewire pelo roteador, ele disse que o correto é eu invocar o método desejado através do Blade. Eu não gostei da resposta do Copilot, mas com a ajuda dele eu fiz a seguinte gambiarra: arquivo routes > web.php (parcial) <?php use App\Livewire\Lbalancete; Route::middleware(['auth','verified'])->group(function() { Route::get('lbalancete/{opcao?}',Lbalancete::class)->name('lbalancete'); } arquivo resources > views > livewire > loutros.blade.php (parcial) <a href="lbalancete/1" class="text-gray-500 font-semibold">Criar TBW</a> arquivo app > Livewire > Lbalancete.php (parcial) class Lbalancete extends Component { function mount($opcao = null) { if($opcao==1) { $this->tbw() ;} $this->atualizar(); } function tbw() { $ultimoDia=tbdiario::orderBy('dia','desc')->value('dia'); session(['apuracao'=>$ultimoDia]); $balancete=$this->balancete()->balancete; DB::table('tbw')->truncate(); foreach($balancete as $conta) { $inicio=$conta->inicio ?? 'null' ; $debito=$conta->debito ?? 'null '; $credito=$conta->credito ?? 'null'; $fim=$conta->fim ?? 'null'; tbw::create(['conta'=>$conta->conta,'descricao'=>$conta->descricao, 'inicio'=>$inicio,'debito'=>$debito,'credito'=>$credito,'fim'=>$fim]); } session()->forget('apuracao'); return redirect()->to("https://123.456.78.900:8443/phpmyadmin/index.php"); } }
-
Foi em 1999 é que eu inventei o estoque como a última compra. Coloquei essa ideia no MS Access, em 2020 no PHP e agora cheguei no Livewire, eu chamei a rotina de baixa de estoque. A ideia é bem simples, o problema é como adaptar num programa de computador. Ou seja, eu fiz tudo na base da improvisação, a maior prova é que eu sempre encontro divergência na hora de rodar a rotina. Hoje eu aprendi um novo método no Eloquent chamado keyBy. Ao invés de ajuntar duas tabelas, eu fiz uma consulta numa tabela e outra consulta em outra tabela, e em seguida ajuntei o resultado, tendo como denominador o campo lançamento. A primeira diferença que eu encontrei foi lá em 2023. Naquela época, o fornecedor trocou uma mercadoria por outra. Ao invés de fazer um lançamento para a mercadoria que entrou e outro lançamento para a mercadoria que saiu, eu fiz tudo num só lançamento, e agora eu amargo o problema da inconsistência contábil no estoque. Naquela época, eu achei a ideia ótima, mas hoje eu volto a aprender que a gambiarra não compensa. app > Livewire > EstoqueDiferenca.php <?php namespace App\Livewire; use App\Models\tbdiario; use App\Models\tbhistprod; use Illuminate\Support\Facades\DB; use Livewire\Attributes\Layout; use Livewire\Component; #[Layout('components.layouts.app',['titulo'=>'Teste'])] class Teste extends Component { public $entrada,$saida; function mount() { $contabil = tbdiario::where('contac',123)->orderBy('lcto')->get()->keyBy('lcto'); $estoque = tbhistprod::select('lcto', DB::raw('SUM(custototal) as saida')) ->groupBy('lcto')->orderBy('lcto')->get()->keyBy('lcto'); $this->saida=collect(); foreach($contabil as $lcto => $conta) { $saiu=$estoque[$lcto]->saida ?? 0; $this->saida->push(['lcto'=>$lcto,'valor'=>$conta->valor,'saida'=>$saiu]); } $contabil = tbdiario::where('contad',123)->orderBy('lcto')->get()->keyBy('lcto'); $this->entrada=collect(); foreach($contabil as $lcto => $conta) { $entrou=$estoque[$lcto]->saida ?? 0; $this->entrada->push(['lcto'=>$lcto,'valor'=>$conta->valor,'entrada'=>$entrou]); } } } resources > views > estoque-diferenca.blade.php <div> <div class=flex> <div class="w-[100px] text-right">Lcto</div> <div class="w-[100px] text-right">Contábil</div> <div class="w-[100px] text-right">Estoque</div> <div class="w-[100px] text-right">Divergência</div> </div> <div class="w-[300px] ml-40">Diferença na Saída do Estoque</div> @foreach($saida as $a) @if($a['valor']+$a['saida']) <div class="flex odd:bg-gray-200"> <div class="w-[100px] text-right">{{$a['lcto']}}</div> <div class="w-[100px] text-right">{{dec($a['valor'])}}</div> <div class="w-[100px] text-right">{{dec($a['saida'])}}</div> <div class="w-[100px] text-right">{{dec($a['valor']+$a['saida'])}}</div> </div> @endif @endforeach <div class="w-[300px] ml-40">Diferença na Entrada do Estoque</div> @foreach($entrada as $a) @if($a['valor']-$a['entrada']) <div class="flex odd:bg-gray-200"> <div class="w-[100px] text-right">{{$a['lcto']}}</div> <div class="w-[100px] text-right">{{dec($a['valor'])}}</div> <div class="w-[100px] text-right">{{dec($a['entrada'])}}</div> <div class="w-[100px] text-right">{{dec($a['valor']-$a['entrada'])}}</div> </div> @endif @endforeach </div>
-
O marcador <flux:checkbox> desenha uma caixa de opção um pouco mais bonita do que o <input type="checkbox"> e só vale a pena utilizar, se você precisar de uma resposta do usuário. O meu caso é diferente, eu preciso mostrar ao usuário qual foi a opção que ele escolheu. Um coisa é pegar a informação e guardar no banco de dados, e outra bem diferente é fazer o caminho inverso. No caso do Livewire temos no componente public $teste e no blade <input type="checkbox" wire:model="teste">, aqui o usuário define a caixa ou a variável $teste define a caixa (mas a variável só pode usar os valores true ou false na versão Livewire 3.0). Já o marcador <flux:checkbox wire:model="teste"> só é útil para pegar a opção do usuário, já o caminho inverso não dá, o Livewire não é capaz de mudar o <flux:checkbox wire:model="teste"> para <flex:checkbox wire:model="teste" checked> quando o $teste está definido para true.
-
No tempo do PHP e Laravel, eu usei o <form> para fazer uma ponte entre o view e o controller, mas no Livewire acredito que o <form> só serve para usar as regras de validação. Em vários tutoriais do Livewire você vai encontrar coisa do tipo unique:user, ou seja, o Livewire vai procurar a informação na tabela user. No meu caso, o nome da minha tabela é tbusuarios. Mesmo que eu tenho colocado a tabela no model User, o código no Livewire só vai funcionar se eu usar unique:tbusuarios. <?php // Teste.php namespace App\Livewire; use Livewire\Component; class Teste extends Component { public $email; function register() { $data=$this->validate(['email'=>'required|email|unique:tbusuarios']); dd("creating a user with email $this->email"); } } ?> <form wire:submit.prevent="register" class="w-25"> <!-- teste.blade.php --> <div class="h-5"></div> <flux:input wire:model="email" /> <div class="h-5"></div> <flux:button type=submit>Register</flux:button> <div class="h-5"></div> @error('email'){{ $message }}@enderror </form>
-
Eu tentei testar o código que aparece logo no portal do livewire.laravel.com, ao invés de usar a tabela user, eu usei a tabela de produtos, mas o VS Code disse que encontrou um erro por eu não ter definido a propriedade produto no componente. O VS Code tem razão, o portal do Livewire apresenta um péssimo exemplo de programação, aonde deveria ser @foreach($users as $user), o rapaz escreveu $this->users.
-
Hoje eu estudei o <wire:loading>, mas nenhum dos exemplos do tutorial funcionou comigo. O único que deu certo foi um que muda a cor de uma opção que foi selecionada: <div wire:click="multiploAtualiza" wire:loading.class="text-red-500" class="text-gray-500 font-semibold"> Atualizar Produtos Vinculados </div>
-
A minha sugestão é usar o comando print_r ao invés do echo: $result=[['CDSCR'=>'RACCORD ASPIRAÇÃO']]; foreach($result as $r) { print_r($r); }
-
================= // ================= Finalmente eu achei o portal do heroicons.com, e lá achei o ícone da verificação ("check"), e coloquei no Blade assim: <div class="flex mt-2"> <div class=w-[310px]> <input id="codforn" wire:model="codforn" size="3" autofocus placeholder="codforn" onchange="qt.focus()" class="px-2 border-2 rounded py-0" autocomplete="off"> </div> <div class="w-[210px]"> <input id="qt" wire:model="qt" size="2" placeholder="qt" onchange="total.focus()" class="border-2 rounded py-0 text-center" autocomplete="off"> </div> <div class="text-right"> <input id="total" wire:model="total" size="2" placeholder="total" class="border-2 rounded py-0 text-center" autocomplete="off" wire:change="item" onchange="codforn.focus()"> </div> <flux:icon.check wire:click="item" class="ml-4" /> </div> O meu grande problema é que eu não encontrava espaço suficiente para colocar um botão, tentando simular um <button type=submit>, mas tem espaço para colocar um ícone. Graças ao ícone, eu não preciso mais das variáveis $codforn2, $qt2 e $total2, eu simplesmente só vou esvaziar as variáveis $codforn, $qt e $total só depois que elas forem usadas no cadastro do histórico do produto, ou seja, se o usuário ver a mensagem de que o produto não existe, tudo o que ele digitou vai permanecer no painel de entrada de produtos, e depois dele acertar o cadastro de produto, ele só vai ter que apertar o ícone da confirmação mais uma vez.
-
Apesar do Livewire ser uma extensão do Laravel, aqui eu já considero como um novo recurso do PHP, principalmente para um programador eventual como eu que não conseguiu dominar o JavaScript e principalmente o Ajax. Eu tenho uma rotina que dá entrada no estoque, usando o serviço da digitação. Acredito que a grande maioria dos programadores utiliza o serviço de importação do xml para dar entrada no estoque, mas eu não tenho paciência de esperar e assim eu uso uma cópia da confirmação do pedido do fornecedor. No view, eu tenho três entradas: <input wire:model="codfornec">, <input wire:model="qt"> e <input wire:model="total">. Depois que o usuário fornece os dados, o componente procura na tabela de produtos o registro que contém o codfornec que foi digitado, e se encontrar, ele dá a entrada na tabela histórico do produto. O problema é se o componente não conseguir encontrar, aí o componente solta a mensagem "eu não achei" e fica por isso mesmo. O usuário pode abrir uma nova guia e acertar a tabela de produtos, atualizando ou criando um novo registro. Depois ele volta na guia da entrada de produto, e digita tudo de novo. A lei do menor esforço obriga o usuário a reclamar com o programador que não faz sentido digitar tudo de novo, coisa que já foi digitado antes. E ele tem razão. Eu não sei como resolver isso de maneira lógica, mas improvisei essa gambiarra: Eu criei três variáveis públicas: public $codfornec2, $qt2, $total2, e eles foram definidos quando o componente não encontrar o produto, assim: <?php // ... function item() { // ... $aux=tbprod::where('codforn','like',"%$codforn%")->get(); if (count($aux) == 0) { $this->codforn2=$codforn; $this->qt2=$qt; $this->total2=$total; $this->mensagem="Não existe produto com codforn $codforn"; $this->modal=true; return; } A rotina que fecha o modal anula o conteúdo de $codforn, $qt e $total, e assim o usuário vai ver três caixas vazias que ele não quer digitar. Eu mudei a primeira caixa de entrada: <input wire:model="codforn" wire:click="item">, e o método item no componente ficou assim: <?php // ... function item() { if($this->codforn2) { $codforn=$this->codforn2; $qt=$this->qt2; $total=$this->total2; $this->codforn2=$this->qt2=$this->total2=null; } else { if(is_null($this->codforn)) { return; } $codforn = $this->codforn; $qt = $this->qt; $total = deca($this->total); } Essa gambiarra funciona, o problema é como lembrar o usuário de que é possível recuperar a última digitação só com um clique na primeira caixa.
-
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; } } ?>