From 1b0e479e498cfac533ef5e504ecd51cecdee4c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Sun, 5 Apr 2026 17:58:05 +0200 Subject: [PATCH] feat: refactor participant card DTOs and labels --- src/Form/Model/ParticipantCardDataDto.php | 43 +++++++++ src/Form/Model/ParticipantCardPriceDto.php | 17 ++++ .../ParticipantFieldOptionsProvider.php | 80 +++------------- src/Service/ParticipantCardDataService.php | 59 ++++++------ src/Service/ServiceLabelFormatter.php | 49 ++++++++++ templates/booking/_participant_card.html.twig | 8 +- ...articipantFieldOptionsProviderBabyTest.php | 3 + ...eldOptionsProviderMandatoryServiceTest.php | 25 +++++ .../ParticipantCardDataServiceTest.php | 91 +++++++++++-------- tests/Service/ServiceLabelFormatterTest.php | 63 +++++++++++++ 10 files changed, 299 insertions(+), 139 deletions(-) create mode 100644 src/Form/Model/ParticipantCardDataDto.php create mode 100644 src/Form/Model/ParticipantCardPriceDto.php create mode 100644 src/Service/ServiceLabelFormatter.php create mode 100644 tests/Service/ServiceLabelFormatterTest.php diff --git a/src/Form/Model/ParticipantCardDataDto.php b/src/Form/Model/ParticipantCardDataDto.php new file mode 100644 index 0000000..640e78c --- /dev/null +++ b/src/Form/Model/ParticipantCardDataDto.php @@ -0,0 +1,43 @@ + $errorMessages + */ + public function __construct( + public readonly string $name, + public readonly string $email, + public readonly string $roomName, + public readonly ParticipantCardPriceDto $price, + public readonly bool $isCanceled, + public readonly bool $isValid = true, + public readonly array $errorMessages = [], + ) { + } + + /** + * Returns a copy with validation state applied. + * + * @param array $errorMessages + */ + public function withValidation(bool $isValid, array $errorMessages): self + { + return new self( + name: $this->name, + email: $this->email, + roomName: $this->roomName, + price: $this->price, + isCanceled: $this->isCanceled, + isValid: $isValid, + errorMessages: $errorMessages, + ); + } +} diff --git a/src/Form/Model/ParticipantCardPriceDto.php b/src/Form/Model/ParticipantCardPriceDto.php new file mode 100644 index 0000000..ada3927 --- /dev/null +++ b/src/Form/Model/ParticipantCardPriceDto.php @@ -0,0 +1,17 @@ +price || 0.0 === $service->price) - ? 'inkl.' - : number_format($service->price, 2, ',', '.').' €'; - return $service->label.' ('.$priceLabel.')'; + return $this->serviceLabelFormatter->formatServiceLabel($service); }, 'choice_attr' => function (?Service $service) use ($bookingDto, $participantIndex) { if (null === $service) { @@ -405,7 +404,10 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider // Rental insurance field provider - provides rental insurance options when rental services are selected $this->fieldOptionProviders['rentalInsurance'] = fn (BookingDto $bookingDto, int $participantIndex, array $options = []) => [ - 'label' => $this->getRentalInsuranceCheckboxLabel($bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_RENTAL_INSURANCE, true)), + 'label' => $this->serviceLabelFormatter->formatServiceLabelForServices( + Constants::SERVICE_LABELS[Constants::TOKEN_RENTAL_INSURANCE], + $bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_RENTAL_INSURANCE, true) + ), 'required' => false, 'property_path' => 'rentalInsuranceSelected', 'help' => $this->getRentalInsuranceDescription($bookingDto->travel->getAdditionalServicesBySubTypes(Constants::TOKEN_RENTAL_INSURANCE, true)), @@ -645,7 +647,10 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider } return [ - 'label' => $this->getParkingCheckboxLabel($parkingServices), + 'label' => $this->serviceLabelFormatter->formatServiceLabelForServices( + Constants::SERVICE_LABELS[Constants::TOKEN_PARKING], + $parkingServices + ), 'required' => false, ]; }; @@ -833,56 +838,6 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider }); } - /** - * Formats service label with pricing information. - * - * @param Service|null $service The service to format - * - * @return string The formatted label - */ - private function formatServiceLabelWithPrice(?Service $service): string - { - if (null === $service) { - return ''; - } - - if (null === $service->price) { - return $service->label; - } - - if (0.0 === $service->price) { - return sprintf('%s (inkl.)', $service->label); - } - - if ($service->price < 0) { - // Negative prices are discounts - return sprintf('%s (-%s€ Rabatt)', $service->label, number_format(abs($service->price), 2, ',', '.')); - } - - return sprintf('%s (€%s)', $service->label, number_format($service->price, 2, ',', '.')); - } - - /** - * Gets the parking checkbox label with pricing information. - * - * Creates a checkbox label for the single parking service including pricing. - * Since there's only ever one parking type, we take the first available service. - * - * @param array $parkingServices Array of available parking services - * - * @return string The formatted checkbox label with pricing - */ - private function getParkingCheckboxLabel(array $parkingServices): string - { - if (empty($parkingServices)) { - return Constants::SERVICE_LABELS[Constants::TOKEN_PARKING]; - } - - $parkingService = reset($parkingServices); // Get the first (and only) parking service - - return $this->formatServiceLabelWithPrice($parkingService); - } - /** * Checks if a service should be rendered as read-only due to unavailability. * @@ -1154,19 +1109,6 @@ class ParticipantFieldOptionsProvider extends AbstractFieldOptionsProvider return ''; } - /** - * Generates label for rental insurance checkbox including pricing information. - */ - private function getRentalInsuranceCheckboxLabel(array $rentalInsuranceServices): string - { - if (empty($rentalInsuranceServices)) { - return Constants::SERVICE_LABELS[Constants::TOKEN_RENTAL_INSURANCE]; - } - $rentalInsuranceService = reset($rentalInsuranceServices); // Get the first (and only) rental insurance service - - return $this->formatServiceLabelWithPrice($rentalInsuranceService); - } - /** * Gets the rental insurance description for help text. */ diff --git a/src/Service/ParticipantCardDataService.php b/src/Service/ParticipantCardDataService.php index 904355c..c0ec7bf 100644 --- a/src/Service/ParticipantCardDataService.php +++ b/src/Service/ParticipantCardDataService.php @@ -5,6 +5,8 @@ declare(strict_types=1); namespace App\Service; use App\Form\Model\BookingDto; +use App\Form\Model\ParticipantCardDataDto; +use App\Form\Model\ParticipantCardPriceDto; use App\Form\Model\ParticipantEditDto; use Symfony\Component\Validator\Validator\ValidatorInterface; @@ -25,9 +27,9 @@ class ParticipantCardDataService /** * Get card data for a single participant. * - * @return array{name: string, email: string, roomName: string, price: string, isCanceled: bool} + * @return ParticipantCardDataDto */ - public function getCardData(BookingDto $bookingDto, int $index): array + public function getCardData(BookingDto $bookingDto, int $index): ParticipantCardDataDto { $participant = $bookingDto->participants[$index] ?? null; @@ -44,31 +46,31 @@ class ParticipantCardDataService // Extract room name $roomName = $this->getRoomName($bookingDto, $participant); - // Calculate and format individual price - $price = $this->getFormattedPrice($bookingDto, $index); + // Calculate pricing state for display + $priceData = $this->getPriceData($bookingDto, $index); // Check if participant is canceled $isCanceled = $participant->isCanceled(); - return [ - 'name' => $name, - 'email' => $email, - 'roomName' => $roomName, - 'price' => $price, - 'isCanceled' => $isCanceled, - ]; + return new ParticipantCardDataDto( + name: $name, + email: $email, + roomName: $roomName, + price: $priceData, + isCanceled: $isCanceled, + ); } /** * Get card data for all participants. * - * @return array + * @return array */ public function getAllCardsData(BookingDto $bookingDto): array { $cardsData = []; - foreach ($bookingDto->participants as $index => $participant) { + foreach ($bookingDto->participants as $index => $_participant) { $cardsData[$index] = $this->getCardData($bookingDto, $index); } @@ -118,12 +120,14 @@ class ParticipantCardDataService } /** - * Calculate and format individual participant price. + * Calculate individual participant price display state. * - * Returns a dash (-) when the price is zero and no room is assigned, + * Returns a dash marker when the price is zero and no room is assigned, * indicating incomplete configuration rather than a zero-cost booking. + * + * @return ParticipantCardPriceDto */ - private function getFormattedPrice(BookingDto $bookingDto, int $index): string + private function getPriceData(BookingDto $bookingDto, int $index): ParticipantCardPriceDto { // Check if canceled (only possible in edit mode when booking property is set) $isCanceled = ($bookingDto->booking?->participantsStatus[$index] ?? null) === 'S'; @@ -131,7 +135,7 @@ class ParticipantCardDataService if (true === $isCanceled) { // Calculate surcharge total for canceled participant if (null === $bookingDto->booking) { - return '-'; + return new ParticipantCardPriceDto(null, true); } $surcharges = $bookingDto->booking->getSurchargesForParticipant($index); @@ -143,10 +147,10 @@ class ParticipantCardDataService // Show nothing if no surcharges, otherwise show "x,xx € Stornokosten" if (0.0 === $surchargeTotal) { - return '-'; + return new ParticipantCardPriceDto(null, true); } - return number_format($surchargeTotal, 2, ',', '.').' € Stornokosten'; + return new ParticipantCardPriceDto($surchargeTotal, false); } // For active participants: existing price calculation logic @@ -157,18 +161,18 @@ class ParticipantCardDataService // Display dash when price is zero and no room assigned (incomplete configuration) $participant = $bookingDto->participants[$index] ?? null; if (0.0 === $price && (null === $participant || null === $participant->assignedRoomId)) { - return '-'; + return new ParticipantCardPriceDto(null, true); } - return number_format($price, 2, ',', '.').' €'; + return new ParticipantCardPriceDto($price, false); } /** * Get card data for a single participant with validation state. * - * @return array{name: string, email: string, roomName: string, price: string, isCanceled: bool, isValid: bool, errorMessages: array} + * @return ParticipantCardDataDto */ - public function getCardDataWithValidation(BookingDto $bookingDto, int $index): array + public function getCardDataWithValidation(BookingDto $bookingDto, int $index): ParticipantCardDataDto { $participant = $bookingDto->participants[$index] ?? null; @@ -199,22 +203,19 @@ class ParticipantCardDataService $errorMessages[] = $violation->getMessage(); } - return array_merge($cardData, [ - 'isValid' => $isValid, - 'errorMessages' => $errorMessages, - ]); + return $cardData->withValidation($isValid, $errorMessages); } /** * Get card data for all participants with validation state. * - * @return array}> + * @return array */ public function getAllCardsDataWithValidation(BookingDto $bookingDto): array { $cardsData = []; - foreach ($bookingDto->participants as $index => $participant) { + foreach ($bookingDto->participants as $index => $_participant) { $cardsData[$index] = $this->getCardDataWithValidation($bookingDto, $index); } diff --git a/src/Service/ServiceLabelFormatter.php b/src/Service/ServiceLabelFormatter.php new file mode 100644 index 0000000..2773e89 --- /dev/null +++ b/src/Service/ServiceLabelFormatter.php @@ -0,0 +1,49 @@ +label ?? ''; + + if (null === $service->price) { + return $label; + } + + if (0.0 === $service->price) { + return sprintf('%s (inkl.)', $label); + } + + if ($service->price < 0) { + return sprintf('%s (-%s€ Rabatt)', $label, number_format(abs($service->price), 2, ',', '.')); + } + + return sprintf('%s (€%s)', $label, number_format($service->price, 2, ',', '.')); + } + + /** + * @param array $services + */ + public function formatServiceLabelForServices(string $fallbackLabel, array $services): string + { + $service = reset($services); + if (false === $service) { + return $fallbackLabel; + } + + if (!($service instanceof Service)) { + return $fallbackLabel; + } + + return $this->formatServiceLabel($service); + } +} diff --git a/templates/booking/_participant_card.html.twig b/templates/booking/_participant_card.html.twig index 517d32c..74d0f28 100644 --- a/templates/booking/_participant_card.html.twig +++ b/templates/booking/_participant_card.html.twig @@ -48,7 +48,13 @@
{{ cardData.roomName }}
- {{ cardData.price }} + {% if cardData.price.showDash %} + - + {% elseif cardData.isCanceled %} + {{ cardData.price.amount|format_currency('EUR') }} Stornokosten + {% else %} + {{ cardData.price.amount|format_currency('EUR') }} + {% endif %}
{% endif %} diff --git a/tests/Form/Service/ParticipantFieldOptionsProviderBabyTest.php b/tests/Form/Service/ParticipantFieldOptionsProviderBabyTest.php index 1a947f8..a89589f 100644 --- a/tests/Form/Service/ParticipantFieldOptionsProviderBabyTest.php +++ b/tests/Form/Service/ParticipantFieldOptionsProviderBabyTest.php @@ -13,6 +13,7 @@ use App\Form\Model\ParticipantDto; use App\Form\Service\ParticipantFieldOptionsProvider; use App\Service\BookingPriceCalculatorService; use App\Service\InsuranceService; +use App\Service\ServiceLabelFormatter; use App\Service\ServiceAvailabilityCalculator; use PHPUnit\Framework\TestCase; use Symfony\Contracts\Translation\TranslatorInterface; @@ -27,12 +28,14 @@ class ParticipantFieldOptionsProviderBabyTest extends TestCase $this->serviceAvailabilityCalculator = $this->createMock(ServiceAvailabilityCalculator::class); $insuranceService = $this->createMock(InsuranceService::class); $priceCalculatorService = $this->createMock(BookingPriceCalculatorService::class); + $serviceLabelFormatter = new ServiceLabelFormatter(); $translator = $this->createMock(TranslatorInterface::class); $this->provider = new ParticipantFieldOptionsProvider( $this->serviceAvailabilityCalculator, $insuranceService, $priceCalculatorService, + $serviceLabelFormatter, $translator ); } diff --git a/tests/Form/Service/ParticipantFieldOptionsProviderMandatoryServiceTest.php b/tests/Form/Service/ParticipantFieldOptionsProviderMandatoryServiceTest.php index c5db354..4fc22f5 100644 --- a/tests/Form/Service/ParticipantFieldOptionsProviderMandatoryServiceTest.php +++ b/tests/Form/Service/ParticipantFieldOptionsProviderMandatoryServiceTest.php @@ -12,6 +12,7 @@ use App\Form\Model\ParticipantDto; use App\Form\Service\ParticipantFieldOptionsProvider; use App\Service\BookingPriceCalculatorService; use App\Service\InsuranceService; +use App\Service\ServiceLabelFormatter; use App\Service\ServiceAvailabilityCalculator; use PHPUnit\Framework\TestCase; use Symfony\Contracts\Translation\TranslatorInterface; @@ -30,12 +31,14 @@ class ParticipantFieldOptionsProviderMandatoryServiceTest extends TestCase $serviceAvailabilityCalculator = $this->createMock(ServiceAvailabilityCalculator::class); $insuranceService = $this->createMock(InsuranceService::class); $priceCalculatorService = $this->createMock(BookingPriceCalculatorService::class); + $serviceLabelFormatter = new ServiceLabelFormatter(); $translator = $this->createMock(TranslatorInterface::class); $this->provider = new ParticipantFieldOptionsProvider( $serviceAvailabilityCalculator, $insuranceService, $priceCalculatorService, + $serviceLabelFormatter, $translator ); } @@ -110,6 +113,28 @@ class ParticipantFieldOptionsProviderMandatoryServiceTest extends TestCase $this->assertArrayNotHasKey('checked', $attributes); } + public function testParkingLabelIncludesPrice(): void + { + $parkingService = new Service(); + $parkingService->id = 3; + $parkingService->label = 'Parkplatz'; + $parkingService->subType = Constants::TOKEN_PARKING; + $parkingService->available = 10; + $parkingService->price = 12.5; + + $travel = $this->createTravelWithAdditionalServices([$parkingService]); + $bookingDto = new BookingDto($travel, 1); + + $participant = new ParticipantDto(); + $participant->index = 0; + $participant->dateOfBirth = $travel->dateFrom->modify('-25 years'); + $bookingDto->participants[0] = $participant; + + $options = $this->provider->getFieldOptions('parking', $bookingDto, 0); + + $this->assertSame('Parkplatz (€12,50)', $options['label']); + } + public function testNullParticipantReturnsEmptyOptions(): void { $mandatoryService = $this->createMandatoryService(1, 'Ortstaxe'); diff --git a/tests/Service/ParticipantCardDataServiceTest.php b/tests/Service/ParticipantCardDataServiceTest.php index f3ce443..4054731 100644 --- a/tests/Service/ParticipantCardDataServiceTest.php +++ b/tests/Service/ParticipantCardDataServiceTest.php @@ -23,7 +23,10 @@ class ParticipantCardDataServiceTest extends TestCase { $this->priceCalculator = $this->createMock(BookingPriceCalculatorService::class); $this->validator = $this->createMock(ValidatorInterface::class); - $this->service = new ParticipantCardDataService($this->priceCalculator, $this->validator); + $this->service = new ParticipantCardDataService( + $this->priceCalculator, + $this->validator + ); } public function testGetCardDataWithFullParticipantData(): void @@ -55,9 +58,10 @@ class ParticipantCardDataServiceTest extends TestCase $result = $this->service->getCardData($bookingDto, 0); - $this->assertEquals('Max Mustermann', $result['name']); - $this->assertEquals('Doppelzimmer', $result['roomName']); - $this->assertEquals('450,50 €', $result['price']); + $this->assertSame('Max Mustermann', $result->name); + $this->assertSame('Doppelzimmer', $result->roomName); + $this->assertSame(450.50, $result->price->amount); + $this->assertFalse($result->price->showDash); } public function testGetCardDataWithPartialName(): void @@ -79,7 +83,7 @@ class ParticipantCardDataServiceTest extends TestCase $result = $this->service->getCardData($bookingDto, 0); - $this->assertEquals('Max', $result['name']); + $this->assertSame('Max', $result->name); } public function testGetCardDataWithNoName(): void @@ -101,7 +105,7 @@ class ParticipantCardDataServiceTest extends TestCase $result = $this->service->getCardData($bookingDto, 0); - $this->assertEquals('Anmelder:in', $result['name']); + $this->assertSame('Anmelder:in', $result->name); } public function testGetCardDataWithEmptyName(): void @@ -123,7 +127,7 @@ class ParticipantCardDataServiceTest extends TestCase $result = $this->service->getCardData($bookingDto, 0); - $this->assertEquals('Anmelder:in', $result['name']); + $this->assertSame('Anmelder:in', $result->name); } public function testGetCardDataWithNoRoomAssignment(): void @@ -145,7 +149,7 @@ class ParticipantCardDataServiceTest extends TestCase $result = $this->service->getCardData($bookingDto, 0); - $this->assertEquals('Kein Zimmer zugewiesen', $result['roomName']); + $this->assertSame('Kein Zimmer zugewiesen', $result->roomName); } public function testGetCardDataWithUnknownRoom(): void @@ -167,7 +171,7 @@ class ParticipantCardDataServiceTest extends TestCase $result = $this->service->getCardData($bookingDto, 0); - $this->assertEquals('Unbekanntes Zimmer', $result['roomName']); + $this->assertSame('Unbekanntes Zimmer', $result->roomName); } public function testGetCardDataWithZeroPriceAndNoRoom(): void @@ -190,7 +194,8 @@ class ParticipantCardDataServiceTest extends TestCase $result = $this->service->getCardData($bookingDto, 0); // When no room assigned and price is zero, display dash (incomplete configuration) - $this->assertEquals('-', $result['price']); + $this->assertNull($result->price->amount); + $this->assertTrue($result->price->showDash); } public function testGetCardDataWithZeroPriceButRoomAssigned(): void @@ -219,7 +224,8 @@ class ParticipantCardDataServiceTest extends TestCase $result = $this->service->getCardData($bookingDto, 0); // When room is assigned but price is zero, display formatted zero price - $this->assertEquals('0,00 €', $result['price']); + $this->assertSame(0.0, $result->price->amount); + $this->assertFalse($result->price->showDash); } public function testGetCardDataWithInvalidIndex(): void @@ -279,19 +285,22 @@ class ParticipantCardDataServiceTest extends TestCase $this->assertCount(3, $result); // First participant - $this->assertEquals('Max Mustermann', $result[0]['name']); - $this->assertEquals('Einzelzimmer', $result[0]['roomName']); - $this->assertEquals('450,00 €', $result[0]['price']); + $this->assertSame('Max Mustermann', $result[0]->name); + $this->assertSame('Einzelzimmer', $result[0]->roomName); + $this->assertSame(450.0, $result[0]->price->amount); + $this->assertFalse($result[0]->price->showDash); // Second participant - $this->assertEquals('Anna Schmidt', $result[1]['name']); - $this->assertEquals('Doppelzimmer', $result[1]['roomName']); - $this->assertEquals('500,00 €', $result[1]['price']); + $this->assertSame('Anna Schmidt', $result[1]->name); + $this->assertSame('Doppelzimmer', $result[1]->roomName); + $this->assertSame(500.0, $result[1]->price->amount); + $this->assertFalse($result[1]->price->showDash); // Third participant (no name) - $this->assertEquals('Teilnehmer:in', $result[2]['name']); - $this->assertEquals('Doppelzimmer', $result[2]['roomName']); - $this->assertEquals('480,00 €', $result[2]['price']); + $this->assertSame('Teilnehmer:in', $result[2]->name); + $this->assertSame('Doppelzimmer', $result[2]->roomName); + $this->assertSame(480.0, $result[2]->price->amount); + $this->assertFalse($result[2]->price->showDash); } public function testGetAllCardsDataWithEmptyParticipants(): void @@ -323,7 +332,8 @@ class ParticipantCardDataServiceTest extends TestCase $result = $this->service->getCardData($bookingDto, 0); - $this->assertEquals('1.234,56 €', $result['price']); + $this->assertSame(1234.56, $result->price->amount); + $this->assertFalse($result->price->showDash); } public function testFallbackNameIndexingIsOneBasedNotZeroBased(): void @@ -346,9 +356,9 @@ class ParticipantCardDataServiceTest extends TestCase $result2 = $this->service->getCardData($bookingDto, 1); $result3 = $this->service->getCardData($bookingDto, 2); - $this->assertEquals('Anmelder:in', $result1['name']); - $this->assertEquals('Teilnehmer:in', $result2['name']); - $this->assertEquals('Teilnehmer:in', $result3['name']); + $this->assertSame('Anmelder:in', $result1->name); + $this->assertSame('Teilnehmer:in', $result2->name); + $this->assertSame('Teilnehmer:in', $result3->name); } public function testGetCardDataWithValidationReturnsValidCard(): void @@ -384,13 +394,14 @@ class ParticipantCardDataServiceTest extends TestCase ->method('validate') ->willReturn($violations); - $result = $this->service->getCardDataWithValidation($bookingDto, 0, ['booking_create']); + $result = $this->service->getCardDataWithValidation($bookingDto, 0); - $this->assertEquals('Max Mustermann', $result['name']); - $this->assertEquals('Doppelzimmer', $result['roomName']); - $this->assertEquals('450,50 €', $result['price']); - $this->assertTrue($result['isValid']); - $this->assertEmpty($result['errorMessages']); + $this->assertSame('Max Mustermann', $result->name); + $this->assertSame('Doppelzimmer', $result->roomName); + $this->assertSame(450.50, $result->price->amount); + $this->assertFalse($result->price->showDash); + $this->assertTrue($result->isValid); + $this->assertEmpty($result->errorMessages); } public function testGetCardDataWithValidationReturnsInvalidCard(): void @@ -424,12 +435,12 @@ class ParticipantCardDataServiceTest extends TestCase ->method('validate') ->willReturn($violations); - $result = $this->service->getCardDataWithValidation($bookingDto, 0, ['booking_create']); + $result = $this->service->getCardDataWithValidation($bookingDto, 0); - $this->assertEquals('Max Mustermann', $result['name']); - $this->assertFalse($result['isValid']); - $this->assertCount(1, $result['errorMessages']); - $this->assertEquals('Diese E-Mail Adresse wird bereits von einem anderen Teilnehmer verwendet', $result['errorMessages'][0]); + $this->assertSame('Max Mustermann', $result->name); + $this->assertFalse($result->isValid); + $this->assertCount(1, $result->errorMessages); + $this->assertSame('Diese E-Mail Adresse wird bereits von einem anderen Teilnehmer verwendet', $result->errorMessages[0]); } public function testGetAllCardsDataWithValidationReturnsAllCards(): void @@ -472,12 +483,12 @@ class ParticipantCardDataServiceTest extends TestCase ->method('validate') ->willReturn($violations); - $result = $this->service->getAllCardsDataWithValidation($bookingDto, ['booking_create']); + $result = $this->service->getAllCardsDataWithValidation($bookingDto); $this->assertCount(2, $result); - $this->assertTrue($result[0]['isValid']); - $this->assertTrue($result[1]['isValid']); - $this->assertEquals('Max Mustermann', $result[0]['name']); - $this->assertEquals('Anna Schmidt', $result[1]['name']); + $this->assertTrue($result[0]->isValid); + $this->assertTrue($result[1]->isValid); + $this->assertSame('Max Mustermann', $result[0]->name); + $this->assertSame('Anna Schmidt', $result[1]->name); } } diff --git a/tests/Service/ServiceLabelFormatterTest.php b/tests/Service/ServiceLabelFormatterTest.php new file mode 100644 index 0000000..ca8afc3 --- /dev/null +++ b/tests/Service/ServiceLabelFormatterTest.php @@ -0,0 +1,63 @@ +formatter = new ServiceLabelFormatter(); + } + + public function testFormatServiceLabelReturnsLabelWithoutPrice(): void + { + $service = new Service(); + $service->label = 'Skipass'; + $service->price = null; + + $this->assertSame('Skipass', $this->formatter->formatServiceLabel($service)); + } + + public function testFormatServiceLabelFormatsIncludedService(): void + { + $service = new Service(); + $service->label = 'Ortstaxe'; + $service->price = 0.0; + + $this->assertSame('Ortstaxe (inkl.)', $this->formatter->formatServiceLabel($service)); + } + + public function testFormatServiceLabelFormatsPositivePrice(): void + { + $service = new Service(); + $service->label = 'Parkplatz'; + $service->price = 12.5; + + $this->assertSame('Parkplatz (€12,50)', $this->formatter->formatServiceLabel($service)); + } + + public function testFormatServiceLabelFormatsNegativePrice(): void + { + $service = new Service(); + $service->label = 'Rabatt'; + $service->price = -8.0; + + $this->assertSame('Rabatt (-8,00€ Rabatt)', $this->formatter->formatServiceLabel($service)); + } + + public function testFormatServiceLabelForServicesFallsBackWhenEmpty(): void + { + $this->assertSame( + 'Verpflegung', + $this->formatter->formatServiceLabelForServices('Verpflegung', []) + ); + } +}