178 lines
6.7 KiB
PHP
178 lines
6.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Form\Service;
|
|
|
|
use App\BusProNet\Constants;
|
|
use App\BusProNet\Model\Service;
|
|
use App\BusProNet\Model\Travel;
|
|
use App\Form\Model\BookingDto;
|
|
use App\Form\Model\ParticipantDto;
|
|
use App\Form\Service\ParticipantFieldOptionsProvider;
|
|
use App\Service\BookingPriceCalculator;
|
|
use App\Service\InsuranceManager;
|
|
use App\Service\ServiceLabelFormatter;
|
|
use App\Service\ServiceAvailabilityCalculator;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
|
|
|
/**
|
|
* Tests that mandatory services in choice_attr are only locked (readonly)
|
|
* when actually selected in the participant's DTO, preventing incorrect
|
|
* force-locking after age-related service changes.
|
|
*/
|
|
class ParticipantFieldOptionsProviderMandatoryServiceTest extends TestCase
|
|
{
|
|
private ParticipantFieldOptionsProvider $provider;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$serviceAvailabilityCalculator = $this->createMock(ServiceAvailabilityCalculator::class);
|
|
$insuranceService = $this->createMock(InsuranceManager::class);
|
|
$priceCalculatorService = $this->createMock(BookingPriceCalculator::class);
|
|
$serviceLabelFormatter = new ServiceLabelFormatter();
|
|
$translator = $this->createMock(TranslatorInterface::class);
|
|
|
|
$this->provider = new ParticipantFieldOptionsProvider(
|
|
$serviceAvailabilityCalculator,
|
|
$insuranceService,
|
|
$priceCalculatorService,
|
|
$serviceLabelFormatter,
|
|
$translator
|
|
);
|
|
}
|
|
|
|
public function testMandatoryServiceSelectedHasReadonlyAndTooltip(): void
|
|
{
|
|
$mandatoryService = $this->createMandatoryService(1, 'Ortstaxe');
|
|
$travel = $this->createTravelWithAdditionalServices([$mandatoryService]);
|
|
$bookingDto = new BookingDto($travel, 1);
|
|
|
|
$participant = new ParticipantDto();
|
|
$participant->index = 0;
|
|
$participant->dateOfBirth = $travel->dateFrom->modify('-25 years');
|
|
$participant->additionalServices = [$mandatoryService];
|
|
$bookingDto->participants[0] = $participant;
|
|
|
|
$options = $this->provider->getFieldOptions('additionalServices', $bookingDto, 0);
|
|
$choiceAttr = $options['choice_attr'];
|
|
$attributes = $choiceAttr($mandatoryService);
|
|
|
|
$this->assertTrue($attributes['readonly']);
|
|
$this->assertSame('Diese Leistung ist nicht abwählbar', $attributes['data-tooltip']);
|
|
$this->assertArrayNotHasKey('checked', $attributes);
|
|
}
|
|
|
|
public function testMandatoryServiceNotSelectedHasNoReadonlyOrChecked(): void
|
|
{
|
|
$mandatoryService = $this->createMandatoryService(1, 'Ortstaxe');
|
|
$travel = $this->createTravelWithAdditionalServices([$mandatoryService]);
|
|
$bookingDto = new BookingDto($travel, 1);
|
|
|
|
$participant = new ParticipantDto();
|
|
$participant->index = 0;
|
|
$participant->dateOfBirth = $travel->dateFrom->modify('-25 years');
|
|
$participant->additionalServices = [];
|
|
$bookingDto->participants[0] = $participant;
|
|
|
|
$options = $this->provider->getFieldOptions('additionalServices', $bookingDto, 0);
|
|
$choiceAttr = $options['choice_attr'];
|
|
$attributes = $choiceAttr($mandatoryService);
|
|
|
|
$this->assertArrayNotHasKey('readonly', $attributes);
|
|
$this->assertArrayNotHasKey('checked', $attributes);
|
|
$this->assertArrayNotHasKey('data-tooltip', $attributes);
|
|
}
|
|
|
|
public function testNonMandatoryServiceUnaffected(): void
|
|
{
|
|
$nonMandatoryService = new Service();
|
|
$nonMandatoryService->id = 2;
|
|
$nonMandatoryService->label = 'Keycard-Pfand';
|
|
$nonMandatoryService->subType = Constants::TOKEN_ADDITIONAL;
|
|
$nonMandatoryService->available = 10;
|
|
$nonMandatoryService->price = 10.0;
|
|
$nonMandatoryService->mandatory = false;
|
|
$nonMandatoryService->autoBook = true;
|
|
|
|
$travel = $this->createTravelWithAdditionalServices([$nonMandatoryService]);
|
|
$bookingDto = new BookingDto($travel, 1);
|
|
|
|
$participant = new ParticipantDto();
|
|
$participant->index = 0;
|
|
$participant->dateOfBirth = $travel->dateFrom->modify('-25 years');
|
|
$participant->additionalServices = [$nonMandatoryService];
|
|
$bookingDto->participants[0] = $participant;
|
|
|
|
$options = $this->provider->getFieldOptions('additionalServices', $bookingDto, 0);
|
|
$choiceAttr = $options['choice_attr'];
|
|
$attributes = $choiceAttr($nonMandatoryService);
|
|
|
|
$this->assertArrayNotHasKey('readonly', $attributes);
|
|
$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');
|
|
$travel = $this->createTravelWithAdditionalServices([$mandatoryService]);
|
|
$bookingDto = new BookingDto($travel, 1);
|
|
|
|
// Do not set participant — age filtering cannot determine choices, returns empty
|
|
$options = $this->provider->getFieldOptions('additionalServices', $bookingDto, 0);
|
|
|
|
$this->assertEmpty($options);
|
|
}
|
|
|
|
private function createMandatoryService(int $id, string $label): Service
|
|
{
|
|
$service = new Service();
|
|
$service->id = $id;
|
|
$service->label = $label;
|
|
$service->subType = Constants::TOKEN_ADDITIONAL;
|
|
$service->available = 10;
|
|
$service->price = 5.0;
|
|
$service->mandatory = true;
|
|
|
|
return $service;
|
|
}
|
|
|
|
private function createTravelWithAdditionalServices(array $services): Travel
|
|
{
|
|
$travel = new Travel();
|
|
$travel->dateFrom = new \DateTimeImmutable('+30 days');
|
|
$travel->dateTo = new \DateTimeImmutable('+37 days');
|
|
|
|
$indexed = [];
|
|
foreach ($services as $service) {
|
|
$indexed[$service->id] = $service;
|
|
}
|
|
$travel->additionalServices = $indexed;
|
|
|
|
return $travel;
|
|
}
|
|
}
|