payment) { return $this->price; } return $this->price - $this->payment; } /** * Retrieves additional services filtered by group. * * Filters the additional services array based on the provided group(s). * Supports both single group strings and arrays of groups. * * @param mixed $group The service group(s) to filter by * * @return array The filtered services array */ public function getAdditionalServicesByGroup(mixed $group): array { $group = (array) $group; return array_filter($this->additionalServices, function (Service $service) use ($group) { return in_array($service->subType, $group); }); } /** * Retrieves additional services for a specific participant by group. * * Filters additional services by group and participant index mapping. * Returns services that are assigned to the specified participant. * * @param int $participantIndex The participant index to filter by * @param mixed $group The service group(s) to filter by * * @return array The filtered services for the participant */ public function getAdditionalServicesForParticipantByGroup(int $participantIndex, mixed $group): array { $selectedServices = $this->getAdditionalServicesByGroup($group); return array_filter($selectedServices, function (Service $service) use ($participantIndex) { return in_array($participantIndex, $service->mapping); }); } /** * Retrieves transportation service for a specific participant and direction. * * Finds the transportation service that matches the participant index * and travel direction (e.g., 'H' for outbound, 'R' for inbound). * * @param int $participantIndex The participant index to search for * @param string $direction The travel direction ('H' or 'R') * * @return Service|null The matching transportation service or null if not found */ public function getTransportationServiceForParticipantAndDirection( int $participantIndex, string $direction, ): ?Service { foreach ($this->transportationServices as $service) { if ($service->direction !== $direction) { continue; } if (in_array($participantIndex, $service->mapping)) { return $service; } } return null; } /** * Retrieves pickup service for a specific participant. * * Finds the pickup service assigned to the specified participant * from the pickup services. * * @param int $participantIndex The participant index to search for * * @return Pickup|null The matching pickup service or null if not found */ public function getPickupForParticipant(int $participantIndex): ?Pickup { foreach ($this->pickups as $pickup) { if (in_array($participantIndex, $pickup->mapping)) { return $pickup; } } return null; } /** * Retrieves drop-off service for a specific participant. * * Finds the drop-off service assigned to the specified participant * from the drop-off services (inbound/return direction). * * @param int $participantIndex The participant index to search for * * @return Pickup|null The matching drop-off service or null if not found */ public function getDropOffForParticipant(int $participantIndex): ?Pickup { foreach ($this->dropOffs as $dropOff) { if (in_array($participantIndex, $dropOff->mapping)) { return $dropOff; } } return null; } /** * Gets the insurance assigned to a specific participant. * * @param int $participantIndex The participant index (0-based) * * @return Insurance|null The assigned insurance or null if none assigned */ public function getInsuranceForParticipant(int $participantIndex): ?Insurance { foreach ($this->insurances as $insurance) { if (in_array($participantIndex, $insurance->mapping ?? [], true)) { return $insurance; } } return null; } /** * Retrieves ski pass for a specific participant. * * Since each participant can only have one ski pass, this method returns * the single ski pass assigned to the participant or null if none is assigned. * * @param int $participantIndex The participant index to search for * * @return Service|null The participant's ski pass or null if not found */ public function getSkiPassForParticipant(int $participantIndex): ?Service { $skiPasses = $this->getAdditionalServicesByGroup('SPA'); foreach ($skiPasses as $service) { if (in_array($participantIndex, $service->mapping)) { return $service; } } return null; } /** * Retrieves rental insurance for a specific participant. */ public function getRentalInsuranceForParticipant(int $participantIndex): ?Service { $rentalInsurances = $this->getAdditionalServicesByGroup(Constants::TOKEN_RENTAL_INSURANCE); foreach ($rentalInsurances as $service) { if (in_array($participantIndex, $service->mapping)) { return $service; } } return null; } /** * Retrieves room assignment for a specific participant. * * Finds the room assigned to the specified participant * based on the room mapping configuration. * * @param int $participantIndex The participant index to search for * * @return Room|null The matching room or null if not found */ public function getRoomForParticipant(int $participantIndex): ?Room { foreach ($this->rooms as $room) { if (in_array($participantIndex, $room->mapping)) { return $room; } } return null; } /** * Calculates the total price for a specific participant. * * Sums up all services, surcharges, and room costs assigned to the participant. * Includes mandatory services that apply to all participants. * * @param int $participantIndex The participant index to calculate for * * @return float The total price for the participant */ public function getPriceForParticipant(int $participantIndex): float { $price = 0.0; // Sum up all services foreach ([...$this->transportationServices, ...$this->additionalServices] as $service) { if ((in_array($participantIndex, $service->mapping) || true === $service->mandatory) && isset($service->individualPrice[$participantIndex])) { $price += $service->individualPrice[$participantIndex] ?? 0; } } // Sum up all surcharges foreach ($this->surcharges as $surcharge) { if (in_array($participantIndex, $surcharge->mapping) && isset($surcharge->individualPrice[$participantIndex])) { $price += $surcharge->individualPrice[$participantIndex] ?? 0; } } $room = $this->getRoomForParticipant($participantIndex); if (null !== $room && isset($room->individualPrice[$participantIndex])) { $price += $room->individualPrice[$participantIndex] ?? 0; } return $price; } /** * Retrieves surcharges for a specific participant. * * Filters surcharges based on participant index mapping. * * @param int $participantIndex The participant index to filter by * * @return array The surcharges assigned to the participant */ public function getSurchargesForParticipant(int $participantIndex): array { return array_filter($this->surcharges, function (Surcharge $surcharge) use ($participantIndex) { return in_array($participantIndex, $surcharge->mapping); }); } /** * Calculates the total price for all participants. * * Sums up the individual prices for all participants in the booking. * * @return float The calculated total price for all participants */ public function getCalculatedTotalPrice(): float { $totalPrice = 0.0; foreach ($this->participants as $index => $participant) { $totalPrice += $this->getPriceForParticipant($index); } return $totalPrice; } /** * Determines if the booking is editable. * * A booking is editable if the travel date is in the future and * the status is not cancelled ('S') or unknown ('U'). * * @return bool True if the booking can be edited, false otherwise */ public function isEditable(): bool { return $this->travelDate > new \DateTimeImmutable() && false === in_array($this->status, ['S', 'U']); } }