'unavailable', 'expires_at' => null, 'policy_pending' => true]; } $policy = is_array($operation) ? ($operation['validity_policies'][$key] ?? $operation['validity'] ?? null) : null; $pending = ! is_array($policy) || ($policy['days'] ?? null) === null; $result = ['state' => 'available', 'expires_at' => null, 'policy_pending' => $pending]; if ($operation !== null && ! is_array($operation)) { return [...$result, 'state' => 'unavailable']; } $state = $operation['status'] ?? 'available'; if (! is_int($operation['cycle'] ?? 0) || ($operation['cycle'] ?? 0) < 0) { return [...$result, 'state' => 'unavailable']; } if (! in_array($state, ['available', 'withdrawn', 'expired', 'revalidation'], true)) { return [...$result, 'state' => 'unavailable']; } if ($state !== 'available') { return [...$result, 'state' => $state]; } $days = $policy['days'] ?? null; if (($operation['cycle'] ?? 0) > 0 && ($publication['offer_cycle'] ?? null) !== $operation['cycle']) { return $result; } if ($days === null || ! is_array($publication) || ($publication['publication']['state'] ?? null) !== 'published') { return $result; } if (! is_int($days) || $days < 1 || $days > 36500) { return [...$result, 'state' => 'unavailable']; } try { $at = $publication['publication']['at'] ?? null; if (! is_string($at) || ! preg_match('/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,6})?(?:Z|[+-]\d{2}:\d{2})$/D', $at)) { return [...$result, 'state' => 'unavailable']; } $start = CarbonImmutable::parse($at); $end = $start->addDays($days)->utc(); } catch (\Throwable) { return [...$result, 'state' => 'unavailable']; } return [...$result, 'expires_at' => $end->toIso8601String(), 'state' => $end->lte(CarbonImmutable::now()) ? 'expired' : 'available']; } /** @return array{state:string,expires_at:?string,policy_pending:bool} */ public function record(Opportunity $record): array { return $this->view($record->workflow_context['offer_operation'] ?? null, $record->workflow_context['offer_publication'] ?? null); } public function publicAllowed(mixed $operation, mixed $publication): bool { if ($this->view($operation, $publication)['state'] !== 'available') { return false; } $cycle = $operation['cycle'] ?? 0; if (! is_int($cycle) || $cycle < 0) { return false; } // A new validation must never resurrect the previous public snapshot. return $cycle === 0 || (is_array($publication) && ($publication['offer_cycle'] ?? null) === $cycle && is_string($operation['activated_hash'] ?? null) && ($publication['editorial_hash'] ?? null) === $operation['activated_hash']); } }