*/ public function plan(StaffingRule $rule, Destination $destination): array { $roles = []; $guides = (int) $rule->getGuides(); if (true === $rule->isSplit()) { $combined = []; if (true === $rule->isSkiBeginner()) { $combined[] = StaffingRole::GUIDE_SKI_BEGINNER; } if (true === $rule->isSkiAdvanced()) { $combined[] = StaffingRole::GUIDE_SKI_ADVANCED; } // The matrix validation refuses more levels than guides; max() keeps a row that // slipped past it from planning a negative head count. $roles[] = [StaffingRole::GUIDE, max(0, $guides - count($combined))]; foreach ($combined as $role) { $roles[] = [$role, 1]; } } else { $roles[] = [StaffingRole::GUIDE, $guides]; if (true === $rule->isSkiBeginner()) { $roles[] = [StaffingRole::SKI_BEGINNER, 1]; } if (true === $rule->isSkiAdvanced()) { $roles[] = [StaffingRole::SKI_ADVANCED, 1]; } } $pickup = $this->firstPickup($destination); $planned = []; foreach ($roles as [$role, $places]) { if (0 === $places) { continue; } $fees = []; if (true === $role->isGuide() && true === $rule->isGuiding()) { $fees[] = StaffingFee::GUIDING; } if (true === $role->isCourse()) { $fees[] = StaffingFee::COURSE; } $planned[] = new PlannedAssignment( $role, $places, true === $role->isGuide() ? $pickup : null, $fees, ); if (true === $role->isGuide()) { $pickup = null; } } return $planned; } private function firstPickup(Destination $destination): ?int { return PickupOptions::inDepartureOrder($destination)[0]['busProId'] ?? null; } }