feat: exclusion groups for additional services
This commit is contained in:
@@ -4,20 +4,21 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Form;
|
||||
|
||||
use App\Entity\Groups\AdditionalService;
|
||||
use App\Form\AccommodationStep2Type;
|
||||
use App\Form\Model\AccommodationBookingDto;
|
||||
use App\Service\AdditionalServiceExclusionResolver;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\Form\Forms;
|
||||
|
||||
class AccommodationStep2TypeTest extends TestCase
|
||||
{
|
||||
public function testChildrenLabelIsBuiltFromMaxAdolescentAgeOption(): void
|
||||
{
|
||||
$form = Forms::createFormFactoryBuilder()
|
||||
->getFormFactory()
|
||||
->create(AccommodationStep2Type::class, new AccommodationBookingDto(), [
|
||||
'max_adolescent_age' => 15,
|
||||
]);
|
||||
$form = $this->createForm(new AccommodationBookingDto(), [
|
||||
'max_adolescent_age' => 15,
|
||||
]);
|
||||
|
||||
self::assertSame(
|
||||
'davon Kinder (4–15 Jahre)',
|
||||
@@ -28,9 +29,7 @@ class AccommodationStep2TypeTest extends TestCase
|
||||
public function testBlankOptionalChildCountersAreNormalizedToZero(): void
|
||||
{
|
||||
$dto = new AccommodationBookingDto();
|
||||
$form = Forms::createFormFactoryBuilder()
|
||||
->getFormFactory()
|
||||
->create(AccommodationStep2Type::class, $dto);
|
||||
$form = $this->createForm($dto);
|
||||
|
||||
$form->submit([
|
||||
'paxCount' => '2',
|
||||
@@ -48,14 +47,12 @@ class AccommodationStep2TypeTest extends TestCase
|
||||
public function testGroupedAdditionalServiceValuesCanSubmitUnderSelectionGroupKeys(): void
|
||||
{
|
||||
$dto = new AccommodationBookingDto();
|
||||
$form = Forms::createFormFactoryBuilder()
|
||||
->getFormFactory()
|
||||
->create(AccommodationStep2Type::class, $dto, [
|
||||
'additional_service_choices' => [
|
||||
'Ski service' => 101,
|
||||
'Board service' => 202,
|
||||
],
|
||||
]);
|
||||
$form = $this->createForm($dto, [
|
||||
'additional_service_choices' => [
|
||||
'Ski service' => 101,
|
||||
'Board service' => 202,
|
||||
],
|
||||
]);
|
||||
|
||||
$form->submit([
|
||||
'paxCount' => '2',
|
||||
@@ -71,4 +68,87 @@ class AccommodationStep2TypeTest extends TestCase
|
||||
self::assertTrue($form->isSynchronized());
|
||||
self::assertSame([101, 202], array_values($dto->selectedAdditionalServiceIds));
|
||||
}
|
||||
|
||||
public function testNewlySelectedExclusiveServiceClearsItsConflicts(): void
|
||||
{
|
||||
$dto = new AccommodationBookingDto();
|
||||
$dto->selectedAdditionalServiceIds = [11, 12];
|
||||
|
||||
$form = $this->createForm($dto, [
|
||||
'additional_service_choices' => [
|
||||
'Keller' => 11,
|
||||
'1. OG' => 12,
|
||||
'Komplett' => 13,
|
||||
],
|
||||
'additional_services' => [
|
||||
$this->service(11, 'Reinigung', false),
|
||||
$this->service(12, 'Reinigung', false),
|
||||
$this->service(13, 'Reinigung', true),
|
||||
],
|
||||
]);
|
||||
|
||||
$form->submit([
|
||||
'paxCount' => '2',
|
||||
'minorsCount' => '0',
|
||||
'childrenCount' => '0',
|
||||
'selectedBoardServiceId' => '',
|
||||
'selectedAdditionalServiceIds' => ['11', '12', '13'],
|
||||
]);
|
||||
|
||||
self::assertTrue($form->isSynchronized());
|
||||
self::assertSame([13], array_values($dto->selectedAdditionalServiceIds));
|
||||
}
|
||||
|
||||
public function testNewlySelectedRegularServiceClearsTheExclusiveOne(): void
|
||||
{
|
||||
$dto = new AccommodationBookingDto();
|
||||
$dto->selectedAdditionalServiceIds = [13];
|
||||
|
||||
$form = $this->createForm($dto, [
|
||||
'additional_service_choices' => [
|
||||
'Keller' => 11,
|
||||
'Komplett' => 13,
|
||||
],
|
||||
'additional_services' => [
|
||||
$this->service(11, 'Reinigung', false),
|
||||
$this->service(13, 'Reinigung', true),
|
||||
],
|
||||
]);
|
||||
|
||||
$form->submit([
|
||||
'paxCount' => '2',
|
||||
'minorsCount' => '0',
|
||||
'childrenCount' => '0',
|
||||
'selectedBoardServiceId' => '',
|
||||
'selectedAdditionalServiceIds' => ['13', '11'],
|
||||
]);
|
||||
|
||||
self::assertTrue($form->isSynchronized());
|
||||
self::assertSame([11], array_values($dto->selectedAdditionalServiceIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $options
|
||||
*
|
||||
* @return FormInterface<AccommodationBookingDto>
|
||||
*/
|
||||
private function createForm(AccommodationBookingDto $dto, array $options = []): FormInterface
|
||||
{
|
||||
return Forms::createFormFactoryBuilder()
|
||||
->addType(new AccommodationStep2Type(new AdditionalServiceExclusionResolver()))
|
||||
->getFormFactory()
|
||||
->create(AccommodationStep2Type::class, $dto, $options);
|
||||
}
|
||||
|
||||
private function service(int $id, ?string $exclusionGroup, bool $isExclusive): AdditionalService
|
||||
{
|
||||
$service = new AdditionalService();
|
||||
$service->setExclusionGroup($exclusionGroup);
|
||||
$service->setIsExclusive($isExclusive);
|
||||
|
||||
$property = new \ReflectionProperty(AdditionalService::class, 'id');
|
||||
$property->setValue($service, $id);
|
||||
|
||||
return $service;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Service;
|
||||
|
||||
use App\Entity\Groups\AdditionalService;
|
||||
use App\Service\AdditionalServiceExclusionResolver;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class AdditionalServiceExclusionResolverTest extends TestCase
|
||||
{
|
||||
private const int BASEMENT = 1;
|
||||
private const int FIRST_FLOOR = 2;
|
||||
private const int SECOND_FLOOR = 3;
|
||||
private const int FULL = 4;
|
||||
private const int BREAKFAST = 5;
|
||||
|
||||
public function testSelectingTheExclusiveServiceClearsTheOtherGroupMembers(): void
|
||||
{
|
||||
$resolved = $this->resolve(
|
||||
[self::BASEMENT, self::FIRST_FLOOR, self::FULL],
|
||||
[self::BASEMENT, self::FIRST_FLOOR],
|
||||
);
|
||||
|
||||
self::assertSame([self::FULL], array_values($resolved));
|
||||
}
|
||||
|
||||
public function testSelectingANonExclusiveServiceClearsOnlyTheExclusiveOne(): void
|
||||
{
|
||||
$resolved = $this->resolve(
|
||||
[self::FULL, self::BASEMENT],
|
||||
[self::FULL],
|
||||
);
|
||||
|
||||
self::assertSame([self::BASEMENT], array_values($resolved));
|
||||
}
|
||||
|
||||
public function testNonExclusiveGroupMembersCanBeCombined(): void
|
||||
{
|
||||
$resolved = $this->resolve(
|
||||
[self::BASEMENT, self::FIRST_FLOOR, self::SECOND_FLOOR],
|
||||
[self::BASEMENT],
|
||||
);
|
||||
|
||||
self::assertSame(
|
||||
[self::BASEMENT, self::FIRST_FLOOR, self::SECOND_FLOOR],
|
||||
array_values($resolved),
|
||||
);
|
||||
}
|
||||
|
||||
public function testServicesWithoutAnExclusionGroupAreNeverCleared(): void
|
||||
{
|
||||
$resolved = $this->resolve(
|
||||
[self::BREAKFAST, self::BASEMENT, self::FULL],
|
||||
[self::BREAKFAST, self::BASEMENT],
|
||||
);
|
||||
|
||||
self::assertSame([self::BREAKFAST, self::FULL], array_values($resolved));
|
||||
}
|
||||
|
||||
public function testUnchangedSelectionIsLeftAlone(): void
|
||||
{
|
||||
$resolved = $this->resolve(
|
||||
[self::BASEMENT, self::FULL],
|
||||
[self::BASEMENT, self::FULL],
|
||||
);
|
||||
|
||||
self::assertSame([self::BASEMENT, self::FULL], array_values($resolved));
|
||||
}
|
||||
|
||||
public function testSubmittedArrayKeysArePreserved(): void
|
||||
{
|
||||
$resolver = new AdditionalServiceExclusionResolver();
|
||||
|
||||
$resolved = $resolver->resolve(
|
||||
$this->services(),
|
||||
['Reinigung' => self::FULL, 'Verpflegung' => self::BREAKFAST, 0 => self::BASEMENT],
|
||||
[self::BASEMENT],
|
||||
);
|
||||
|
||||
self::assertSame(
|
||||
['Reinigung' => self::FULL, 'Verpflegung' => self::BREAKFAST],
|
||||
$resolved,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<int> $submittedIds
|
||||
* @param list<int> $previousIds
|
||||
*
|
||||
* @return array<array-key, int>
|
||||
*/
|
||||
private function resolve(array $submittedIds, array $previousIds): array
|
||||
{
|
||||
return (new AdditionalServiceExclusionResolver())->resolve(
|
||||
$this->services(),
|
||||
$submittedIds,
|
||||
$previousIds,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AdditionalService[]
|
||||
*/
|
||||
private function services(): array
|
||||
{
|
||||
return [
|
||||
$this->service(self::BASEMENT, 'Reinigung', false),
|
||||
$this->service(self::FIRST_FLOOR, 'Reinigung', false),
|
||||
$this->service(self::SECOND_FLOOR, 'Reinigung', false),
|
||||
$this->service(self::FULL, 'Reinigung', true),
|
||||
$this->service(self::BREAKFAST, null, false),
|
||||
];
|
||||
}
|
||||
|
||||
private function service(int $id, ?string $exclusionGroup, bool $isExclusive): AdditionalService
|
||||
{
|
||||
$service = new AdditionalService();
|
||||
$service->setExclusionGroup($exclusionGroup);
|
||||
$service->setIsExclusive($isExclusive);
|
||||
|
||||
$property = new \ReflectionProperty(AdditionalService::class, 'id');
|
||||
$property->setValue($service, $id);
|
||||
|
||||
return $service;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user