feat: complete equipment handover workflow
This commit is contained in:
@@ -9,6 +9,7 @@ use Generator;
|
||||
use Illuminate\Http\Client\ConnectionException;
|
||||
use Illuminate\Http\Client\PendingRequest;
|
||||
use Illuminate\Http\Client\RequestException;
|
||||
use Illuminate\Http\Client\Response;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Str;
|
||||
use Throwable;
|
||||
@@ -20,6 +21,11 @@ final class SnipeItClient
|
||||
return filled(config('services.snipe_it.url')) && filled(config('services.snipe_it.read_token'));
|
||||
}
|
||||
|
||||
public function isOperationallyConfigured(): bool
|
||||
{
|
||||
return filled(config('services.snipe_it.url')) && filled(config('services.snipe_it.operational_token'));
|
||||
}
|
||||
|
||||
public function configuredUrl(): ?string
|
||||
{
|
||||
$url = trim((string) config('services.snipe_it.url'));
|
||||
@@ -32,7 +38,7 @@ final class SnipeItClient
|
||||
$pageSize = $limit ?? (int) config('services.snipe_it.page_size', 100);
|
||||
$pageSize = max(1, min(500, $pageSize));
|
||||
|
||||
$response = $this->request()->get('/hardware', [
|
||||
$response = $this->readRequest()->get('/hardware', [
|
||||
'limit' => $pageSize,
|
||||
'offset' => max(0, $offset),
|
||||
'sort' => 'id',
|
||||
@@ -92,7 +98,61 @@ final class SnipeItClient
|
||||
} while ($received > 0 && $offset < $page->total);
|
||||
}
|
||||
|
||||
private function request(): PendingRequest
|
||||
/** @return array<string, mixed> */
|
||||
public function checkoutHardware(
|
||||
int $hardwareId,
|
||||
int $statusId,
|
||||
int $assignedUserId,
|
||||
string $expectedCheckin,
|
||||
?string $note = null,
|
||||
): array {
|
||||
$this->assertPositiveIdentifiers($hardwareId, $statusId, $assignedUserId);
|
||||
|
||||
$payload = [
|
||||
'status_id' => $statusId,
|
||||
'checkout_to_type' => 'user',
|
||||
'assigned_user' => $assignedUserId,
|
||||
'expected_checkin' => $expectedCheckin,
|
||||
];
|
||||
|
||||
if (filled($note)) {
|
||||
$payload['note'] = $note;
|
||||
}
|
||||
|
||||
$response = $this->operationalRequest()->post("/hardware/{$hardwareId}/checkout", $payload);
|
||||
|
||||
return $this->operationPayload($response, 'entrega');
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public function checkinHardware(
|
||||
int $hardwareId,
|
||||
int $statusId,
|
||||
?int $locationId = null,
|
||||
?string $note = null,
|
||||
): array {
|
||||
$this->assertPositiveIdentifiers($hardwareId, $statusId);
|
||||
|
||||
if ($locationId !== null && $locationId < 1) {
|
||||
throw new SnipeItConfigurationException('O identificador da localização do Snipe-IT tem de ser positivo.');
|
||||
}
|
||||
|
||||
$payload = ['status_id' => $statusId];
|
||||
|
||||
if ($locationId !== null) {
|
||||
$payload['location_id'] = $locationId;
|
||||
}
|
||||
|
||||
if (filled($note)) {
|
||||
$payload['note'] = $note;
|
||||
}
|
||||
|
||||
$response = $this->operationalRequest()->post("/hardware/{$hardwareId}/checkin", $payload);
|
||||
|
||||
return $this->operationPayload($response, 'devolução');
|
||||
}
|
||||
|
||||
private function readRequest(): PendingRequest
|
||||
{
|
||||
if (! $this->isConfigured()) {
|
||||
throw new SnipeItConfigurationException('A URL e o token de leitura do Snipe-IT ainda não estão configurados.');
|
||||
@@ -116,6 +176,54 @@ final class SnipeItClient
|
||||
);
|
||||
}
|
||||
|
||||
private function operationalRequest(): PendingRequest
|
||||
{
|
||||
if (! $this->isOperationallyConfigured()) {
|
||||
throw new SnipeItConfigurationException('A URL e o token operacional do Snipe-IT ainda não estão configurados.');
|
||||
}
|
||||
|
||||
return Http::baseUrl($this->apiBaseUrl())
|
||||
->acceptJson()
|
||||
->asJson()
|
||||
->withToken((string) config('services.snipe_it.operational_token'))
|
||||
->withUserAgent(Str::slug((string) config('app.name')).'/inventory-operations')
|
||||
->connectTimeout(min(5, max(1, (int) config('services.snipe_it.timeout', 10))))
|
||||
->timeout(max(1, (int) config('services.snipe_it.timeout', 10)));
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
private function operationPayload(Response $response, string $operation): array
|
||||
{
|
||||
if (! $response->successful()) {
|
||||
throw new SnipeItApiException(
|
||||
"O Snipe-IT respondeu com HTTP {$response->status()} durante a {$operation}.",
|
||||
$response->status(),
|
||||
);
|
||||
}
|
||||
|
||||
$payload = $response->json();
|
||||
|
||||
if (! is_array($payload)) {
|
||||
throw new SnipeItApiException("O Snipe-IT devolveu uma resposta inválida durante a {$operation}.");
|
||||
}
|
||||
|
||||
if (($payload['status'] ?? null) !== 'success') {
|
||||
throw new SnipeItApiException("O Snipe-IT recusou a {$operation} apesar de responder com HTTP 200.");
|
||||
}
|
||||
|
||||
/** @var array<string, mixed> $payload */
|
||||
return $payload;
|
||||
}
|
||||
|
||||
private function assertPositiveIdentifiers(int ...$identifiers): void
|
||||
{
|
||||
foreach ($identifiers as $identifier) {
|
||||
if ($identifier < 1) {
|
||||
throw new SnipeItConfigurationException('Os identificadores do Snipe-IT têm de ser positivos.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function apiBaseUrl(): string
|
||||
{
|
||||
$baseUrl = $this->configuredUrl();
|
||||
|
||||
Reference in New Issue
Block a user