offerings->findOneFor($resource, $item); $parentOffering = $parentService !== null && $parentService->getId() !== $item->getId() ? $this->offerings->findOneFor($resource, $parentService) : null; // ردیف غیرفعال یعنی «این منبع فعلاً این را نمی‌دهد»، نه «مقدارش را نمی‌دانم» — // پس اعدادش هم خوانده نمی‌شوند و زنجیره از رویش رد می‌شود. $optionOffering = $optionOffering?->isActive() === true ? $optionOffering : null; $parentOffering = $parentOffering?->isActive() === true ? $parentOffering : null; $branch = $this->branchOverrides->findOneBy(['item' => $item, 'address' => $address]); [$duration, $durationSource] = $this->first([ [$optionOffering?->getDurationMinutes(), ResolvedServiceSpec::SOURCE_RESOURCE_OPTION], [$parentOffering?->getDurationMinutes(), ResolvedServiceSpec::SOURCE_RESOURCE_SERVICE], [$branch?->getSoloDurationMinutes(), ResolvedServiceSpec::SOURCE_BRANCH], [$item->getSoloDurationMinutes(), ResolvedServiceSpec::SOURCE_SERVICE_DEFAULT], ]); [$price, $priceSource] = $this->first([ [$optionOffering?->getPriceRials(), ResolvedServiceSpec::SOURCE_RESOURCE_OPTION], [$parentOffering?->getPriceRials(), ResolvedServiceSpec::SOURCE_RESOURCE_SERVICE], [$branch?->getPriceRials(), ResolvedServiceSpec::SOURCE_BRANCH], [$item->getPriceRials(), ResolvedServiceSpec::SOURCE_SERVICE_DEFAULT], ]); return new ResolvedServiceSpec( durationMinutes: $duration, priceRials: (int) ($price ?? 0), durationSource: $duration === null ? null : $durationSource, priceSource: $priceSource ?? ResolvedServiceSpec::SOURCE_SERVICE_DEFAULT, ); } /** * اولین سطحی که مقدار دارد. `null` یعنی «حرفی برای گفتن ندارم» و رد می‌شود؛ * صفر یک مقدارِ واقعی است و **رد نمی‌شود** — سرویسِ رایگان قیمتش صفر است، نه ارث‌بر. * * @param list $levels * @return array{0: int|null, 1: string|null} */ private function first(array $levels): array { foreach ($levels as [$value, $source]) { if ($value !== null) { return [$value, $source]; } } return [null, null]; } }