341421d2a0
The match statement wasn't returning the actions array, causing no actions to display on inspection orders. Changed to directly return the match result.
235 lines
7.2 KiB
PHP
235 lines
7.2 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\Order;
|
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class OpsController extends Controller
|
|
{
|
|
/**
|
|
* Display order details via QR token (state-machine driven UI)
|
|
*
|
|
* GET /ops/orders/{token}
|
|
*/
|
|
public function showOrder(Request $request, $token)
|
|
{
|
|
// Find order by QR token
|
|
$order = Order::where('qr_token', $token)->first();
|
|
|
|
if (! $order) {
|
|
Log::warning('QR token not found', ['token' => substr($token, 0, 8) . '...']);
|
|
|
|
return response()->view('ops.order-not-found', [], 404);
|
|
}
|
|
|
|
// Check user authorization - must be logged in ops user
|
|
// TODO: Add middleware to enforce this
|
|
if (! auth()->check() || ! auth()->user()->can('access-ops')) {
|
|
Log::warning('Unauthorized QR access attempt', [
|
|
'order_uuid' => $order->uuid,
|
|
'user_id' => auth()->id(),
|
|
]);
|
|
|
|
return response()->view('ops.unauthorized', [], 403);
|
|
}
|
|
|
|
Log::info('QR order accessed', [
|
|
'order_uuid' => $order->uuid,
|
|
'status' => $order->status,
|
|
'user_id' => auth()->id(),
|
|
]);
|
|
|
|
// Determine available actions based on order status
|
|
$availableActions = $this->getAvailableActions($order);
|
|
|
|
return view('ops.order-detail', [
|
|
'order' => $order,
|
|
'availableActions' => $availableActions,
|
|
'qrUrl' => route('ops.order.show', ['token' => $order->qr_token]),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Confirm packing via QR form
|
|
*
|
|
* POST /ops/orders/{id}/pack
|
|
*/
|
|
public function confirmPacking(Request $request, Order $order)
|
|
{
|
|
// Validate input
|
|
$validated = $request->validate([
|
|
'weight' => ['required', 'numeric', 'min:0.1'],
|
|
'width' => ['required', 'numeric', 'min:1'],
|
|
'length' => ['required', 'numeric', 'min:1'],
|
|
'height' => ['required', 'numeric', 'min:1'],
|
|
]);
|
|
|
|
// Ensure order is in packing state
|
|
if ($order->status !== 'packing' && $order->status !== 'inspection') {
|
|
return response()->json([
|
|
'error' => 'Order cannot be packed in current state',
|
|
'current_status' => $order->status,
|
|
], 409);
|
|
}
|
|
|
|
// Save packing dimensions
|
|
$order->update([
|
|
'packing_width' => $validated['width'],
|
|
'packing_length' => $validated['length'],
|
|
'packing_weight' => $validated['weight'],
|
|
'packing_completed_at' => now(),
|
|
'packed_by' => auth()->id(),
|
|
'status' => 'packing',
|
|
]);
|
|
|
|
Log::info('Order packed via QR', [
|
|
'order_uuid' => $order->uuid,
|
|
'packed_by' => auth()->user()->name,
|
|
'dimensions' => "{$validated['width']}x{$validated['length']}cm, {$validated['weight']}kg",
|
|
]);
|
|
|
|
// Emit event to trigger Slack notification and Trello update
|
|
\App\Events\OrderPacked::dispatch($order);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Order packed successfully',
|
|
'order' => [
|
|
'uuid' => $order->uuid,
|
|
'number' => $order->order_number,
|
|
'status' => $order->status,
|
|
],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Mark inspection passed via QR
|
|
*
|
|
* POST /ops/orders/{id}/inspection-passed
|
|
*/
|
|
public function markInspectionPassed(Request $request, Order $order)
|
|
{
|
|
if ($order->status !== 'inspection') {
|
|
return response()->json([
|
|
'error' => 'Order is not in inspection state',
|
|
'current_status' => $order->status,
|
|
], 409);
|
|
}
|
|
|
|
// Update status and emit event
|
|
$order->update(['status' => 'packing']);
|
|
|
|
Log::info('Inspection passed via QR', [
|
|
'order_uuid' => $order->uuid,
|
|
'marked_by' => auth()->user()->name,
|
|
]);
|
|
|
|
// Emit event for listeners to handle Slack/Trello updates
|
|
// TODO: Create InspectionPassed event
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Inspection passed',
|
|
'order' => ['uuid' => $order->uuid, 'status' => $order->status],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Flag inspection issue via QR
|
|
*
|
|
* POST /ops/orders/{id}/inspection-failed
|
|
*/
|
|
public function flagInspectionIssue(Request $request, Order $order)
|
|
{
|
|
$validated = $request->validate([
|
|
'issue_description' => ['required', 'string', 'max:500'],
|
|
]);
|
|
|
|
if ($order->status !== 'inspection') {
|
|
return response()->json([
|
|
'error' => 'Order is not in inspection state',
|
|
'current_status' => $order->status,
|
|
], 409);
|
|
}
|
|
|
|
// Update status and store issue
|
|
$order->update([
|
|
'status' => 'review_required',
|
|
'notes' => $validated['issue_description'],
|
|
]);
|
|
|
|
Log::warning('Inspection issue flagged via QR', [
|
|
'order_uuid' => $order->uuid,
|
|
'flagged_by' => auth()->user()->name,
|
|
'issue' => $validated['issue_description'],
|
|
]);
|
|
|
|
// Emit event for listeners to alert ops
|
|
// TODO: Create InspectionFailed event
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Issue flagged - order moved to review',
|
|
'order' => ['uuid' => $order->uuid, 'status' => $order->status],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Determine which actions are available based on order status
|
|
*/
|
|
private function getAvailableActions(Order $order): array
|
|
{
|
|
return match ($order->status) {
|
|
'inspection' => [
|
|
'markInspectionPassed' => true,
|
|
'flagInspectionIssue' => true,
|
|
],
|
|
'packing' => [
|
|
'confirmPacking' => true,
|
|
],
|
|
'ready_to_ship', 'awaiting_collection', 'in_transit' => [
|
|
'readOnly' => true,
|
|
],
|
|
default => []
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Download QR sticker PDF for printing
|
|
*
|
|
* GET /ops/orders/{id}/sticker/download
|
|
*/
|
|
public function downloadSticker(Order $order)
|
|
{
|
|
// Authorize
|
|
if (! auth()->user()->can('access-ops')) {
|
|
abort(403, 'Unauthorized to access ops interface');
|
|
}
|
|
|
|
$stickerPath = "qr-stickers/{$order->uuid}.pdf";
|
|
|
|
if (! \Illuminate\Support\Facades\Storage::disk('public')->exists($stickerPath)) {
|
|
Log::warning('QR sticker PDF not found', [
|
|
'order_uuid' => $order->uuid,
|
|
'path' => $stickerPath,
|
|
]);
|
|
|
|
abort(404, 'QR sticker not found');
|
|
}
|
|
|
|
Log::info('QR sticker downloaded', [
|
|
'order_uuid' => $order->uuid,
|
|
'user_id' => auth()->id(),
|
|
'user_name' => auth()->user()->name,
|
|
]);
|
|
|
|
return \Illuminate\Support\Facades\Storage::disk('public')->download(
|
|
$stickerPath,
|
|
"QR-{$order->order_number}.pdf"
|
|
);
|
|
}
|
|
}
|