Files
compras/app/Http/Controllers/WarehouseReturnController.php
2026-11-02 20:27:11 +02:00

95 lines
5.0 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\User;
use App\Services\ReceiptWorkflow;
use App\Services\WarehouseReturns;
use Illuminate\Database\QueryException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
use Symfony\Component\HttpFoundation\Response;
final class WarehouseReturnController extends Controller
{
private function actor(Request $r): User
{
$actor = $r->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<string,mixed> $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));
}
}