user('web'); abort_unless($actor instanceof User, 403); return $actor; } public function page(Request $r, WarehouseReturns $flow): Response { $flow->authorize($this->actor($r), 'read'); $d = $r->validate(['request_id' => 'sometimes|integer|min:1']); $actor = $this->actor($r); $source = isset($d['request_id']) ? $flow->availableDeliveries($actor, (int) $d['request_id'], 1) : null; $response = Inertia::render('stock/returns', ['requestId' => isset($d['request_id']) ? (int) $d['request_id'] : null, 'canPrepare' => $source['can_prepare'] ?? false, 'canWithdraw' => $flow->allows($actor, 'prepare'), 'canConfirm' => $flow->allows($actor, 'confirm'), 'actorId' => $actor->id])->toResponse($r); $response->headers->set('Cache-Control', 'private, no-store, max-age=0'); return $response; } public function sources(Request $r, WarehouseReturns $flow): JsonResponse { $d = $r->validate(['request_id' => 'required|integer|min:1', 'source_page' => 'sometimes|integer|min:1|max:100000']); abort_if(array_diff(array_keys($r->query()), array_keys($d)) !== [], 422); return $this->response(fn () => $flow->availableDeliveries($this->actor($r), (int) $d['request_id'], (int) ($d['source_page'] ?? 1)), true); } /** @param callable():array $run */ private function response(callable $run,bool $readOnly=false): JsonResponse { try { $result=$readOnly?DB::transaction(function()use($run){if(DB::getDriverName()==='pgsql'&&DB::transactionLevel()===1)DB::statement('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ READ ONLY');return $run();}):$run(); return response()->json($result)->header('Cache-Control', 'no-store'); } catch (QueryException $e) { if (($e->errorInfo[0] ?? null) === '55P03') { return response()->json(['code'=>'warehouse_return_busy','message' => 'Devolução ocupada. Aguarde e repita manualmente a conferência.'], 423)->header('Cache-Control', 'no-store'); } throw $e; } } public function index(Request $r, WarehouseReturns $flow): JsonResponse { $d = $r->validate(['page' => 'sometimes|integer|min:1|max:100000', 'state' => 'sometimes|in:all,prepared,confirmed,withdrawn,rejected']); abort_if(array_diff(array_keys($r->query()), array_keys($d)) !== [], 422); return $this->response(fn () => $flow->listing($this->actor($r), (int) ($d['page'] ?? 1), $d['state'] ?? 'all'), true); } public function prepare(Request $r, WarehouseReturns $flow): JsonResponse { $d = $r->validate(['operation_key' => 'required|uuid', 'delivery_event_id' => 'required|integer|min:1', 'line_index' => 'required|integer|min:0|max:49', 'quantity' => 'required|string|regex:/^[0-9]{1,6}(\.[0-9]{1,3})?$/D', 'declared_unused' => 'required|accepted', 'evidence' => 'required|string|min:10|max:1000', 'reason' => 'required|string|min:10|max:1000']); abort_if(array_diff(array_keys($r->all()), array_keys($d)) !== [], 422); $d['quantity_milli'] = ReceiptWorkflow::milli($d['quantity']); $d['line_index'] = (int) $d['line_index']; $d['delivery_event_id'] = (int) $d['delivery_event_id']; $d['declared_unused'] = true; return $this->response(fn () => $flow->prepare($this->actor($r), $d)); } public function confirm(Request $r, int $id, WarehouseReturns $flow): JsonResponse { $d = $r->validate(['version' => 'required|integer|min:1', 'received_in_warehouse' => 'required|accepted', 'reason' => 'required|string|min:10|max:1000']); abort_if(array_diff(array_keys($r->all()), array_keys($d)) !== [], 422); $d['version'] = (int) $d['version']; $d['received_in_warehouse'] = true; return $this->response(fn () => $flow->confirm($this->actor($r),$id,$d)); } public function withdraw(Request $r,int $id,WarehouseReturns $flow): JsonResponse {return $this->close($r,$id,$flow,'withdrawn');} public function reject(Request $r,int $id,WarehouseReturns $flow): JsonResponse {return $this->close($r,$id,$flow,'rejected');} private function close(Request $r,int $id,WarehouseReturns $flow,string $state): JsonResponse { $d=$r->validate(['version'=>'required|integer|min:1','reason'=>'required|string|min:10|max:1000']);abort_if(array_diff(array_keys($r->all()),array_keys($d))!==[],422);$d['version']=(int)$d['version'];return $this->response(fn()=>$flow->close($this->actor($r),$id,$d,$state)); } }