where('business_id', $id) ->whereIn('action', ['created', 'updated', 'object_added', 'object_updated'])->max('version_no'); } /** @param array $input */ public function save(User $actor, string $id, array $input): ExistingBusiness { $data = Validator::make($input, [ 'version_no' => ['required', 'integer', 'min:1'], 'object_id' => ['nullable', 'uuid'], 'check' => ['required', 'in:'.implode(',', self::CHECKS)], 'outcome' => ['required', 'in:confirmed,rejected,inconclusive,revoked'], 'evidence_reference' => ['required', 'string', 'min:10', 'max:2000'], 'note' => ['required', 'string', 'min:10', 'max:2000'], 'valid_until' => ['required_if:outcome,confirmed', 'nullable', 'date_format:Y-m-d', 'after_or_equal:today'], ])->validate(); return DB::transaction(function () use ($actor, $id, $data) { $business = app(BusinessRepository::class)->find($id, true); Gate::forUser($actor)->authorize('review', $business); abort_unless($business->status === 'in_review' && $business->version_no === $data['version_no'], 409, 'Reabra a versão actual em revisão.'); if (! empty($data['object_id'])) { ExistingBusinessObject::where('business_id', $id)->whereKey($data['object_id'])->firstOrFail(); } $data['content_version'] = $this->contentVersion($id); $business->version_no++; $business->save(); app(ExistingBusinessDrafts::class)->snapshot($business, $actor, 'verification', $data['note'], $data); return $business; }); } /** Latest finding for each check/subject; complete evidence remains in immutable revisions. * @return array> */ public function findings(ExistingBusiness $business): array { $contentVersion = $this->contentVersion($business->id); $findings = []; foreach (DB::table('existing_business_revisions')->where('business_id', $business->id) ->where('action', 'verification')->orderByDesc('version_no')->cursor() as $revision) { $data = json_decode(Crypt::decryptString($revision->snapshot), true, 512, JSON_THROW_ON_ERROR)['context']; $key = ($data['object_id'] ?? 'business').':'.$data['check']; if (isset($findings[$key])) { continue; } $effective = $data['outcome']; if ($data['content_version'] !== $contentVersion) { $effective = 'stale'; } elseif (! empty($data['valid_until']) && $data['valid_until'] < today()->toDateString()) { $effective = 'expired'; } $findings[$key] = [...$data, 'effective_outcome' => $effective, 'version_no' => $revision->version_no, 'created_at' => $revision->created_at]; } return array_values($findings); } }