feat: consolidate micro-services and unify draft merge logic
This commit is contained in:
@@ -8,15 +8,13 @@ use App\BusProNet\Model\Room;
|
||||
use App\BusProNet\Model\Travel;
|
||||
use App\Form\Model\BookingCreateContext;
|
||||
use App\Form\Model\BookingDto;
|
||||
use App\Form\Model\RoomGroupsDto;
|
||||
use App\Form\Model\ParticipantCardDataDto;
|
||||
use App\Form\Model\ParticipantCardPriceDto;
|
||||
use App\Form\Model\BookingSummaryDto;
|
||||
use App\Service\BookingCreateContextFactory;
|
||||
use App\Service\BookingRoomSelectionService;
|
||||
use App\Service\ParticipantCardDataService;
|
||||
use App\Service\BookingSummaryDataService;
|
||||
use App\Service\BookingPriceCalculatorService;
|
||||
use App\Service\ParticipantCardAssembler;
|
||||
use App\Service\BookingSummaryAssembler;
|
||||
use App\Service\BookingPriceCalculator;
|
||||
use App\Service\RoomPricingCalculator;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
@@ -47,7 +45,7 @@ class BookingCreateContextFactoryTest extends TestCase
|
||||
$bookingDto = new BookingDto($travel, 157047);
|
||||
$summaryData = $this->createMock(BookingSummaryDto::class);
|
||||
|
||||
$summaryDataService = $this->createMock(BookingSummaryDataService::class);
|
||||
$summaryDataService = $this->createMock(BookingSummaryAssembler::class);
|
||||
$summaryDataService->expects($this->once())
|
||||
->method('getSummaryData')
|
||||
->with(
|
||||
@@ -56,26 +54,15 @@ class BookingCreateContextFactoryTest extends TestCase
|
||||
)
|
||||
->willReturn($summaryData);
|
||||
|
||||
$roomSelectionService = $this->createMock(BookingRoomSelectionService::class);
|
||||
$groupedRooms = new RoomGroupsDto(
|
||||
byPax: [$roomByPax->id => $roomByPax],
|
||||
byRoom: [$roomByRoom->id => $roomByRoom],
|
||||
);
|
||||
$roomSelectionService->expects($this->once())
|
||||
->method('groupRoomsBySelectionType')
|
||||
->with([$roomByRoom->id => $roomByRoom, $roomByPax->id => $roomByPax])
|
||||
->willReturn($groupedRooms);
|
||||
|
||||
$participantCardDataService = $this->createMock(ParticipantCardDataService::class);
|
||||
$participantCardDataService = $this->createMock(ParticipantCardAssembler::class);
|
||||
$participantCardDataService->expects($this->never())
|
||||
->method('getAllCardsDataWithValidation');
|
||||
|
||||
$priceCalculator = $this->createMock(BookingPriceCalculatorService::class);
|
||||
$priceCalculator = $this->createMock(BookingPriceCalculator::class);
|
||||
$priceCalculator->expects($this->never())
|
||||
->method('calculateAllParticipantIndividualPrices');
|
||||
|
||||
$service = new BookingCreateContextFactory(
|
||||
$roomSelectionService,
|
||||
$participantCardDataService,
|
||||
$summaryDataService,
|
||||
$priceCalculator,
|
||||
@@ -86,9 +73,10 @@ class BookingCreateContextFactoryTest extends TestCase
|
||||
$this->assertInstanceOf(BookingCreateContext::class, $context);
|
||||
$this->assertSame($bookingDto, $context->bookingDto);
|
||||
$this->assertSame($summaryData, $context->summaryData);
|
||||
$this->assertSame(null, $context->cardsData);
|
||||
$this->assertNull($context->cardsData);
|
||||
$this->assertFalse($context->isSubmitted);
|
||||
$this->assertSame($groupedRooms, $context->groupedRooms);
|
||||
$this->assertSame([11 => $roomByPax], $context->groupedRooms->byPax);
|
||||
$this->assertSame([10 => $roomByRoom], $context->groupedRooms->byRoom);
|
||||
}
|
||||
|
||||
public function testCreateWithParticipantCardsBuildsStep2Context(): void
|
||||
@@ -116,34 +104,23 @@ class BookingCreateContextFactoryTest extends TestCase
|
||||
isCanceled: false,
|
||||
);
|
||||
|
||||
$summaryDataService = $this->createMock(BookingSummaryDataService::class);
|
||||
$summaryDataService = $this->createMock(BookingSummaryAssembler::class);
|
||||
$summaryDataService->expects($this->once())
|
||||
->method('getSummaryData')
|
||||
->with($bookingDto, RoomPricingCalculator::PRICING_MODE_SELECTION)
|
||||
->willReturn($summaryData);
|
||||
|
||||
$roomSelectionService = $this->createMock(BookingRoomSelectionService::class);
|
||||
$groupedRooms = new RoomGroupsDto(
|
||||
byPax: [],
|
||||
byRoom: [$room->id => $room],
|
||||
);
|
||||
$roomSelectionService->expects($this->once())
|
||||
->method('groupRoomsBySelectionType')
|
||||
->with([$room->id => $room])
|
||||
->willReturn($groupedRooms);
|
||||
|
||||
$participantCardDataService = $this->createMock(ParticipantCardDataService::class);
|
||||
$participantCardDataService = $this->createMock(ParticipantCardAssembler::class);
|
||||
$participantCardDataService->expects($this->once())
|
||||
->method('getAllCardsDataWithValidation')
|
||||
->with($bookingDto)
|
||||
->willReturn([$cardData]);
|
||||
|
||||
$priceCalculator = $this->createMock(BookingPriceCalculatorService::class);
|
||||
$priceCalculator = $this->createMock(BookingPriceCalculator::class);
|
||||
$priceCalculator->expects($this->never())
|
||||
->method('calculateAllParticipantIndividualPrices');
|
||||
|
||||
$service = new BookingCreateContextFactory(
|
||||
$roomSelectionService,
|
||||
$participantCardDataService,
|
||||
$summaryDataService,
|
||||
$priceCalculator,
|
||||
@@ -154,6 +131,8 @@ class BookingCreateContextFactoryTest extends TestCase
|
||||
$this->assertInstanceOf(BookingCreateContext::class, $context);
|
||||
$this->assertSame([$cardData], $context->cardsData);
|
||||
$this->assertTrue($context->isSubmitted);
|
||||
$this->assertSame([], $context->groupedRooms->byPax);
|
||||
$this->assertSame([10 => $room], $context->groupedRooms->byRoom);
|
||||
}
|
||||
|
||||
public function testCreateWithParticipantPricesBuildsStep4Context(): void
|
||||
@@ -174,34 +153,23 @@ class BookingCreateContextFactoryTest extends TestCase
|
||||
$bookingDto = new BookingDto($travel, 157047);
|
||||
$summaryData = $this->createMock(BookingSummaryDto::class);
|
||||
|
||||
$summaryDataService = $this->createMock(BookingSummaryDataService::class);
|
||||
$summaryDataService = $this->createMock(BookingSummaryAssembler::class);
|
||||
$summaryDataService->expects($this->once())
|
||||
->method('getSummaryData')
|
||||
->with($bookingDto, RoomPricingCalculator::PRICING_MODE_ASSIGNMENT)
|
||||
->willReturn($summaryData);
|
||||
|
||||
$roomSelectionService = $this->createMock(BookingRoomSelectionService::class);
|
||||
$groupedRooms = new RoomGroupsDto(
|
||||
byPax: [],
|
||||
byRoom: [$room->id => $room],
|
||||
);
|
||||
$roomSelectionService->expects($this->once())
|
||||
->method('groupRoomsBySelectionType')
|
||||
->with([$room->id => $room])
|
||||
->willReturn($groupedRooms);
|
||||
|
||||
$participantCardDataService = $this->createMock(ParticipantCardDataService::class);
|
||||
$participantCardDataService = $this->createMock(ParticipantCardAssembler::class);
|
||||
$participantCardDataService->expects($this->never())
|
||||
->method('getAllCardsDataWithValidation');
|
||||
|
||||
$priceCalculator = $this->createMock(BookingPriceCalculatorService::class);
|
||||
$priceCalculator = $this->createMock(BookingPriceCalculator::class);
|
||||
$priceCalculator->expects($this->once())
|
||||
->method('calculateAllParticipantIndividualPrices')
|
||||
->with($bookingDto)
|
||||
->willReturn([123.45]);
|
||||
|
||||
$service = new BookingCreateContextFactory(
|
||||
$roomSelectionService,
|
||||
$participantCardDataService,
|
||||
$summaryDataService,
|
||||
$priceCalculator,
|
||||
@@ -212,5 +180,6 @@ class BookingCreateContextFactoryTest extends TestCase
|
||||
$this->assertInstanceOf(BookingCreateContext::class, $context);
|
||||
$this->assertSame([123.45], $context->participantPrices);
|
||||
$this->assertNull($context->cardsData);
|
||||
$this->assertSame([10 => $room], $context->groupedRooms->byRoom);
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -13,9 +13,9 @@ use App\Entity\User;
|
||||
use App\Form\Model\BookingDto;
|
||||
use App\Form\Model\ParticipantDto;
|
||||
use App\Repository\BookingEditDraftRepository;
|
||||
use App\Service\BookingEditDraftService;
|
||||
use App\Service\BookingEditDraftParticipantApplier;
|
||||
use App\Service\BookingFingerprintService;
|
||||
use App\Service\BookingEditDraftManager;
|
||||
use App\Service\BookingEditDraftMerger;
|
||||
use App\Service\BookingChangeTracker;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\NullLogger;
|
||||
@@ -27,17 +27,17 @@ use Psr\Log\NullLogger;
|
||||
* service selections on the DTO. This prevents stale draft data from causing
|
||||
* BusPro API rejections when submitting booking updates.
|
||||
*/
|
||||
class BookingEditDraftServiceMutabilityTest extends TestCase
|
||||
class BookingEditDraftManagerMutabilityTest extends TestCase
|
||||
{
|
||||
private BookingEditDraftService $service;
|
||||
private BookingEditDraftManager $service;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->service = new BookingEditDraftService(
|
||||
$this->service = new BookingEditDraftManager(
|
||||
$this->createMock(BookingEditDraftRepository::class),
|
||||
$this->createMock(EntityManagerInterface::class),
|
||||
$this->createMock(BookingFingerprintService::class),
|
||||
new BookingEditDraftParticipantApplier(),
|
||||
$this->createMock(BookingChangeTracker::class),
|
||||
new BookingEditDraftMerger(),
|
||||
new NullLogger(),
|
||||
);
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Service;
|
||||
|
||||
use App\BusProNet\Model\Room;
|
||||
use App\BusProNet\Model\Travel;
|
||||
use App\BusProNet\Constants;
|
||||
use App\Form\Model\BookingDto;
|
||||
use App\Form\Model\ParticipantDto;
|
||||
use App\Form\Model\RoomSelectionDto;
|
||||
use App\Service\BookingParticipantCountService;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class BookingParticipantCountServiceTest extends TestCase
|
||||
{
|
||||
private BookingParticipantCountService $service;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->service = new BookingParticipantCountService();
|
||||
}
|
||||
|
||||
public function testEnsureCorrectNumberOfParticipantsExpandsToCalculatedCount(): void
|
||||
{
|
||||
$travel = $this->createTravel([
|
||||
1 => 2,
|
||||
2 => 3,
|
||||
]);
|
||||
|
||||
$bookingDto = new BookingDto($travel, 123);
|
||||
$bookingDto->roomSelections = [
|
||||
$this->createRoomSelection(1, 1),
|
||||
$this->createRoomSelection(2, 2),
|
||||
];
|
||||
$bookingDto->participants = [new ParticipantDto()];
|
||||
|
||||
$this->service->ensureCorrectNumberOfParticipants($bookingDto);
|
||||
|
||||
$this->assertCount(8, $bookingDto->participants);
|
||||
$this->assertSame(0, $bookingDto->participants[0]->index);
|
||||
$this->assertSame(7, $bookingDto->participants[7]->index);
|
||||
}
|
||||
|
||||
private function createTravel(array $roomCapacities): Travel
|
||||
{
|
||||
$travel = new Travel();
|
||||
$travel->dateFrom = new \DateTimeImmutable('2030-01-01');
|
||||
$travel->dateTo = new \DateTimeImmutable('2030-01-06');
|
||||
|
||||
$rooms = [];
|
||||
foreach ($roomCapacities as $id => $minPax) {
|
||||
$room = new Room();
|
||||
$room->id = $id;
|
||||
$room->label = 'Room '.$id;
|
||||
$room->minPax = $minPax;
|
||||
$room->maxPax = $minPax + 1;
|
||||
$room->available = 5;
|
||||
$room->status = Constants::STATUS_AVAILABLE;
|
||||
$rooms[$id] = $room;
|
||||
}
|
||||
|
||||
$travel->rooms = $rooms;
|
||||
|
||||
return $travel;
|
||||
}
|
||||
|
||||
private function createRoomSelection(int $id, int $quantity): RoomSelectionDto
|
||||
{
|
||||
$selection = new RoomSelectionDto();
|
||||
$selection->id = $id;
|
||||
$selection->quantity = $quantity;
|
||||
|
||||
return $selection;
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Service;
|
||||
|
||||
use App\BusProNet\Model\Room;
|
||||
use App\Form\Model\RoomGroupsDto;
|
||||
use App\Service\BookingRoomSelectionService;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class BookingRoomSelectionServiceTest extends TestCase
|
||||
{
|
||||
private BookingRoomSelectionService $service;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->service = new BookingRoomSelectionService();
|
||||
}
|
||||
|
||||
public function testGroupRoomsBySelectionTypeSplitsAndSortsRooms(): void
|
||||
{
|
||||
$rooms = [
|
||||
10 => $this->createRoom(10, '2 Bett Zimmer', 4),
|
||||
11 => $this->createRoom(11, 'Suite', 2),
|
||||
12 => $this->createRoom(12, '3 Bett Zimmer', 6),
|
||||
];
|
||||
|
||||
$groups = $this->service->groupRoomsBySelectionType($rooms);
|
||||
|
||||
$this->assertInstanceOf(RoomGroupsDto::class, $groups);
|
||||
$this->assertSame([10, 12], array_keys($groups->byPax));
|
||||
$this->assertSame([11], array_keys($groups->byRoom));
|
||||
}
|
||||
|
||||
private function createRoom(int $id, string $label, int $maxPax): Room
|
||||
{
|
||||
$room = new Room();
|
||||
$room->id = $id;
|
||||
$room->label = $label;
|
||||
$room->maxPax = $maxPax;
|
||||
|
||||
return $room;
|
||||
}
|
||||
}
|
||||
+45
-9
@@ -4,19 +4,27 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Service;
|
||||
|
||||
use App\BusProNet\Model\Booking;
|
||||
use App\BusProNet\Model\Room;
|
||||
use App\BusProNet\Model\Travel;
|
||||
use App\Form\Model\BookingDto;
|
||||
use App\Form\Model\BookingSummaryDto;
|
||||
use App\Form\Model\ParticipantDto;
|
||||
use App\Form\Model\RoomSelectionDto;
|
||||
use App\Service\BookingSummaryParticipantCountService;
|
||||
use App\Service\BookingPriceCalculator;
|
||||
use App\Service\BookingSummaryAssembler;
|
||||
use App\Service\CmsDataProvider;
|
||||
use App\BusProNet\DataProvider\CountryDataProvider;
|
||||
use App\BusProNet\XmlLoader\HotelLoader;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\NullLogger;
|
||||
use Symfony\Contracts\Cache\CacheInterface;
|
||||
|
||||
class BookingSummaryParticipantCountServiceTest extends TestCase
|
||||
class BookingSummaryAssemblerTest extends TestCase
|
||||
{
|
||||
public function testCreateStep1UsesExpectedParticipantCountFromSelectedRooms(): void
|
||||
{
|
||||
$service = new BookingSummaryParticipantCountService();
|
||||
$service = $this->createService();
|
||||
$bookingDto = $this->createBookingDto();
|
||||
$bookingDto->currentStep = 1;
|
||||
$bookingDto->roomSelections = [
|
||||
@@ -24,12 +32,15 @@ class BookingSummaryParticipantCountServiceTest extends TestCase
|
||||
$this->createRoomSelection(11, 2),
|
||||
];
|
||||
|
||||
self::assertSame(8, $service->calculate($bookingDto));
|
||||
$summary = $service->getSummaryData($bookingDto);
|
||||
|
||||
$this->assertInstanceOf(BookingSummaryDto::class, $summary);
|
||||
$this->assertSame(8, $summary->participantCount); // 1×2 + 2×3 = 8
|
||||
}
|
||||
|
||||
public function testLaterCreateStepsUseActualParticipantCount(): void
|
||||
{
|
||||
$service = new BookingSummaryParticipantCountService();
|
||||
$service = $this->createService();
|
||||
$bookingDto = $this->createBookingDto();
|
||||
$bookingDto->currentStep = 2;
|
||||
$bookingDto->participants = [
|
||||
@@ -38,20 +49,45 @@ class BookingSummaryParticipantCountServiceTest extends TestCase
|
||||
new ParticipantDto(),
|
||||
];
|
||||
|
||||
self::assertSame(3, $service->calculate($bookingDto));
|
||||
$summary = $service->getSummaryData($bookingDto);
|
||||
|
||||
$this->assertSame(3, $summary->participantCount);
|
||||
}
|
||||
|
||||
public function testEditModeUsesActualParticipantCount(): void
|
||||
{
|
||||
$service = new BookingSummaryParticipantCountService();
|
||||
$service = $this->createService();
|
||||
$bookingDto = $this->createBookingDto();
|
||||
$bookingDto->booking = new \App\BusProNet\Model\Booking();
|
||||
$bookingDto->booking = new Booking();
|
||||
$bookingDto->participants = [
|
||||
new ParticipantDto(),
|
||||
new ParticipantDto(),
|
||||
];
|
||||
|
||||
self::assertSame(2, $service->calculate($bookingDto));
|
||||
$summary = $service->getSummaryData($bookingDto);
|
||||
|
||||
$this->assertSame(2, $summary->participantCount);
|
||||
}
|
||||
|
||||
private function createService(): BookingSummaryAssembler
|
||||
{
|
||||
$priceCalculator = $this->createMock(BookingPriceCalculator::class);
|
||||
$priceCalculator->method('calculateAllParticipantIndividualPrices')->willReturn([]);
|
||||
$priceCalculator->method('getPricingBreakdown')->willReturn([
|
||||
'rooms' => [],
|
||||
'services' => [],
|
||||
'surcharges' => null,
|
||||
'grandTotal' => 0.0,
|
||||
]);
|
||||
|
||||
return new BookingSummaryAssembler(
|
||||
$priceCalculator,
|
||||
$this->createMock(CmsDataProvider::class),
|
||||
$this->createMock(HotelLoader::class),
|
||||
$this->createMock(CountryDataProvider::class),
|
||||
$this->createMock(CacheInterface::class),
|
||||
new NullLogger(),
|
||||
);
|
||||
}
|
||||
|
||||
private function createBookingDto(): BookingDto
|
||||
@@ -1,87 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Service;
|
||||
|
||||
use App\BusProNet\Model\Booking;
|
||||
use App\Form\Model\BookingDto;
|
||||
use App\Form\Model\BookingSummaryDto;
|
||||
use App\Service\BookingPriceCalculatorService;
|
||||
use App\Service\BookingSummaryDataService;
|
||||
use App\Service\BookingSummaryParticipantCountService;
|
||||
use App\Service\CmsDataService;
|
||||
use App\BusProNet\DataProvider\CountryDataProvider;
|
||||
use App\BusProNet\XmlLoader\HotelLoader;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\NullLogger;
|
||||
use Symfony\Contracts\Cache\CacheInterface;
|
||||
|
||||
class BookingSummaryDataServiceTest extends TestCase
|
||||
{
|
||||
public function testCreateStep1UsesExpectedParticipantCountFromSelectedRooms(): void
|
||||
{
|
||||
$service = $this->createService(8);
|
||||
$bookingDto = $this->createBookingDto();
|
||||
|
||||
$summary = $service->getSummaryData($bookingDto);
|
||||
|
||||
$this->assertInstanceOf(BookingSummaryDto::class, $summary);
|
||||
$this->assertSame(8, $summary->participantCount);
|
||||
}
|
||||
|
||||
public function testLaterCreateStepsUseActualParticipantCount(): void
|
||||
{
|
||||
$service = $this->createService(3);
|
||||
$bookingDto = $this->createBookingDto();
|
||||
$bookingDto->currentStep = 2;
|
||||
|
||||
$summary = $service->getSummaryData($bookingDto);
|
||||
|
||||
$this->assertSame(3, $summary->participantCount);
|
||||
}
|
||||
|
||||
public function testEditModeUsesActualParticipantCount(): void
|
||||
{
|
||||
$service = $this->createService(2);
|
||||
$bookingDto = $this->createBookingDto();
|
||||
$bookingDto->booking = new Booking();
|
||||
|
||||
$summary = $service->getSummaryData($bookingDto);
|
||||
|
||||
$this->assertSame(2, $summary->participantCount);
|
||||
}
|
||||
|
||||
private function createService(int $participantCount): BookingSummaryDataService
|
||||
{
|
||||
$priceCalculator = $this->createMock(BookingPriceCalculatorService::class);
|
||||
$priceCalculator->method('calculateAllParticipantIndividualPrices')->willReturn([]);
|
||||
$priceCalculator->method('getPricingBreakdown')->willReturn([
|
||||
'rooms' => [],
|
||||
'services' => [],
|
||||
'surcharges' => null,
|
||||
'grandTotal' => 0.0,
|
||||
]);
|
||||
|
||||
$participantCountService = $this->createMock(BookingSummaryParticipantCountService::class);
|
||||
$participantCountService->method('calculate')
|
||||
->willReturn($participantCount);
|
||||
|
||||
return new BookingSummaryDataService(
|
||||
$priceCalculator,
|
||||
$participantCountService,
|
||||
$this->createMock(CmsDataService::class),
|
||||
$this->createMock(HotelLoader::class),
|
||||
$this->createMock(CountryDataProvider::class),
|
||||
$this->createMock(CacheInterface::class),
|
||||
new NullLogger(),
|
||||
);
|
||||
}
|
||||
|
||||
private function createBookingDto(): BookingDto
|
||||
{
|
||||
$bookingDto = new BookingDto(new \App\BusProNet\Model\Travel(), 157047);
|
||||
|
||||
return $bookingDto;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user