54 lines
2.2 KiB
PHP
54 lines
2.2 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\SupplyRecord;
|
|
use App\Models\User;
|
|
use Closure;
|
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
|
use Illuminate\Validation\ValidationException;
|
|
|
|
/** Shared participation in physical dispositions/reversals; source and stock checks remain in their commands. */
|
|
class InventoryReviewParticipation
|
|
{
|
|
/** @param Closure(array<string,mixed>):array<string,mixed> $basis */
|
|
public function executionSourceCurrent(SupplyRecord $record, Closure $basis): bool
|
|
{
|
|
if ($record->state !== 'approved' || ! isset($record->snapshot['source'])) {
|
|
return false;
|
|
}
|
|
try {
|
|
return $basis($record->data)['source'] === $record->snapshot['source'];
|
|
} catch (ValidationException|ModelNotFoundException) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public function independentReviewer(User $actor, SupplyRecord $record): bool
|
|
{
|
|
return ! in_array($actor->id, $record->snapshot['contributors'], true);
|
|
}
|
|
|
|
public function independentExecutor(User $actor, SupplyRecord $record): bool
|
|
{
|
|
return isset($record->snapshot['reviewed_by']) && $actor->id !== $record->snapshot['reviewed_by'];
|
|
}
|
|
|
|
/** @param Closure(string):bool $allows */
|
|
public function canAct(User $actor, SupplyRecord $record, string $kind, string $action, Closure $allows): bool
|
|
{
|
|
if (! in_array($kind, ['stock_event', 'stock_reversal'], true) || $record->kind !== $kind || $record->tenant_id !== $actor->tenant_id
|
|
|| ! in_array($action, ['approve', 'return', 'execute'], true) || ! $allows($action === 'execute' ? 'execute' : 'review')) {
|
|
return false;
|
|
}
|
|
$latest = app(SupplyPlanning::class)->latest($kind)->where('record_key', $record->record_key)->first();
|
|
if ($latest?->id !== $record->id) {
|
|
return false;
|
|
}
|
|
|
|
return $action === 'execute'
|
|
? $record->state === 'approved' && $this->independentExecutor($actor, $record)
|
|
: $this->independentReviewer($actor, $record) && in_array($record->state, $action === 'return' ? ['draft', 'returned', 'approved'] : ['draft', 'returned'], true);
|
|
}
|
|
}
|