current(); if (! $tenant) { throw new NotFoundHttpException('Tracking only available on tenant subdomain.'); } $wo = WorkOrder::with(['client', 'vehicle', 'master', 'media', 'works', 'parts']) ->where('tracking_token', $token) ->first(); if (! $wo) { throw new NotFoundHttpException('Fișa nu a fost găsită.'); } $pendingWorks = $wo->works->filter(fn ($w) => $w->isPendingApproval()); $pendingParts = $wo->parts->filter(fn ($p) => $p->isPendingApproval()); return view('tracking.show', [ 'wo' => $wo, 'tenant' => $tenant, 'photos' => $wo->getMedia('photos'), 'pendingWorks' => $pendingWorks, 'pendingParts' => $pendingParts, 'approvalStatus' => $request->session()->pull('approval_status'), ]); } /** * Client approves or declines a pending work/part line via the unique * approval_token. The line's approval_token IS the credential — anyone * with the URL can act (clients won't share it). */ public function approve(Request $request, string $token, string $kind, string $lineToken) { $tenant = app(TenantManager::class)->current(); if (! $tenant) throw new NotFoundHttpException(); $wo = WorkOrder::where('tracking_token', $token)->first(); if (! $wo) throw new NotFoundHttpException(); $decision = $request->input('decision', 'approve'); $line = match ($kind) { 'work' => WorkOrderWork::where('work_order_id', $wo->id)->where('approval_token', $lineToken)->first(), 'part' => WorkOrderPart::where('work_order_id', $wo->id)->where('approval_token', $lineToken)->first(), default => null, }; if (! $line || ! $line->isPendingApproval()) { $request->session()->flash('approval_status', ['kind' => 'error', 'message' => 'Linia nu mai necesită aprobare.']); return redirect()->route('tracking.show', ['token' => $token]); } if ($decision === 'approve') { $line->forceFill(['approved_at' => now()])->save(); $msg = '✅ Lucrarea „' . $line->name . '" a fost aprobată. Mulțumim!'; } else { $line->forceFill(['declined_at' => now()])->save(); $msg = '❌ Lucrarea „' . $line->name . '" a fost respinsă. Vă vom contacta.'; } $request->session()->flash('approval_status', ['kind' => 'success', 'message' => $msg]); return redirect()->route('tracking.show', ['token' => $token]); } public function qr(Request $request, string $token) { $tenant = app(TenantManager::class)->current(); if (! $tenant) { throw new NotFoundHttpException(); } $wo = WorkOrder::where('tracking_token', $token)->first(); if (! $wo) { throw new NotFoundHttpException(); } $options = new \chillerlan\QRCode\QROptions([ 'outputType' => \chillerlan\QRCode\QRCode::OUTPUT_MARKUP_SVG, 'eccLevel' => \chillerlan\QRCode\QRCode::ECC_M, 'scale' => 6, 'imageBase64' => false, 'svgViewBoxSize' => 200, 'addQuietzone' => true, ]); $svg = (new \chillerlan\QRCode\QRCode($options))->render($wo->trackingUrl()); return response($svg, 200, [ 'Content-Type' => 'image/svg+xml', 'Cache-Control' => 'public, max-age=3600', ]); } }