Files
myep/tests/Service/BookingPricingAssemblerTest.php
T

257 lines
9.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
namespace App\Tests\Service;
use App\BusProNet\Model\Insurance;
use App\BusProNet\Model\Travel;
use App\Form\Model\BookingDto;
use App\Form\Model\ParticipantDto;
use App\Service\BookingPricingAssembler;
use App\Service\InsuranceManager;
use App\Service\ParticipantEligibilityChecker;
use App\Service\ParticipantPricingCalculator;
use App\Service\RoomPricingCalculator;
use PHPUnit\Framework\TestCase;
class BookingPricingAssemblerTest extends TestCase
{
private BookingPricingAssembler $assembler;
private ParticipantEligibilityChecker $eligibilityChecker;
protected function setUp(): void
{
$this->eligibilityChecker = $this->createMock(ParticipantEligibilityChecker::class);
$this->eligibilityChecker->method('isParticipantEligible')->willReturn(true);
$this->assembler = $this->createAssembler($this->eligibilityChecker);
}
public function testServicePricingWithoutBulkInsurance(): void
{
$travel = new Travel();
$travel->insurances = [];
$insurance1 = $this->createInsurance(1, 'Insurance A', 50.0);
$insurance2 = $this->createInsurance(2, 'Insurance B', 75.0);
$participant1 = new ParticipantDto();
$participant1->index = 0;
$participant1->insurance = $insurance1;
$participant1->bulkInsuranceBooking = false;
$participant2 = new ParticipantDto();
$participant2->index = 1;
$participant2->insurance = $insurance2;
$bookingDto = new BookingDto($travel, 2);
$bookingDto->participants = [$participant1, $participant2];
$result = $this->assembler->calculateServicePricing($bookingDto);
$this->assertNotEmpty($result);
$insuranceGroup = $this->findServiceGroup($result, 'Reiseversicherungen');
$this->assertNotNull($insuranceGroup, 'Insurance group should exist');
$this->assertCount(2, $insuranceGroup['services'], 'Should have 2 different insurance line items');
}
public function testServicePricingWithBulkInsuranceSamePriceTier(): void
{
$insurance = $this->createInsurance(1, 'Reise-Rücktritt', 50.0, 'RRV');
$insurance->travelPriceFrom = 0.0;
$insurance->travelPriceTo = 10000.0;
$travel = new Travel();
$travel->insurances = [$insurance];
$travel->dateFrom = new \DateTimeImmutable('2025-06-01');
$travel->dateTo = new \DateTimeImmutable('2025-06-08');
$participant1 = new ParticipantDto();
$participant1->index = 0;
$participant1->insurance = $insurance;
$participant1->bulkInsuranceBooking = true;
$participant2 = new ParticipantDto();
$participant2->index = 1;
$participant2->insurance = null;
$participant3 = new ParticipantDto();
$participant3->index = 2;
$participant3->insurance = null;
$bookingDto = new BookingDto($travel, 3);
$bookingDto->participants = [$participant1, $participant2, $participant3];
$result = $this->assembler->calculateServicePricing($bookingDto);
// 3× same insurance should aggregate into one line item
$insuranceGroup = $this->findServiceGroup($result, 'Reiseversicherungen');
$this->assertNotNull($insuranceGroup, 'Insurance group should exist');
$this->assertCount(1, $insuranceGroup['services'], 'Should have 1 insurance line item');
$this->assertEquals(3, $insuranceGroup['services'][0]['participantCount'], 'Should count all 3 participants');
$this->assertEquals(150.0, $insuranceGroup['services'][0]['totalPrice'], 'Total should be 3 × €50');
}
public function testServicePricingWithBulkInsuranceShowsPriceTierAdjustment(): void
{
$insuranceTier1 = $this->createInsurance(1, 'Reise-Rücktritt', 30.0, 'RRV');
$insuranceTier1->travelPriceFrom = 0.0;
$insuranceTier1->travelPriceTo = 500.0;
$insuranceTier2 = $this->createInsurance(2, 'Reise-Rücktritt', 50.0, 'RRV');
$insuranceTier2->travelPriceFrom = 501.0;
$insuranceTier2->travelPriceTo = 1000.0;
$travel = new Travel();
$travel->insurances = [$insuranceTier1, $insuranceTier2];
$travel->dateFrom = new \DateTimeImmutable('2025-06-01');
$travel->dateTo = new \DateTimeImmutable('2025-06-08');
$participant1 = new ParticipantDto();
$participant1->index = 0;
$participant1->insurance = $insuranceTier2;
$participant1->bulkInsuranceBooking = true;
$bookingDto = new BookingDto($travel, 1);
$bookingDto->participants = [$participant1];
$result = $this->assembler->calculateServicePricing($bookingDto);
$insuranceGroup = $this->findServiceGroup($result, 'Reiseversicherungen');
$this->assertNotNull($insuranceGroup, 'Insurance group should exist');
$this->assertEquals(1, $insuranceGroup['services'][0]['participantCount'], 'Should count applicant');
}
public function testServicePricingWithBulkInsuranceWhenNoBulkEnabled(): void
{
$insurance = $this->createInsurance(1, 'Reise-Rücktritt', 50.0, 'RRV');
$travel = new Travel();
$travel->insurances = [$insurance];
$participant1 = new ParticipantDto();
$participant1->index = 0;
$participant1->insurance = $insurance;
$participant1->bulkInsuranceBooking = false;
$participant2 = new ParticipantDto();
$participant2->index = 1;
$participant2->insurance = null;
$bookingDto = new BookingDto($travel, 2);
$bookingDto->participants = [$participant1, $participant2];
$result = $this->assembler->calculateServicePricing($bookingDto);
$insuranceGroup = $this->findServiceGroup($result, 'Reiseversicherungen');
$this->assertNotNull($insuranceGroup, 'Insurance group should exist');
$this->assertCount(1, $insuranceGroup['services'], 'Should have 1 insurance line item');
$this->assertEquals(1, $insuranceGroup['services'][0]['participantCount'], 'Should count only applicant');
$this->assertEquals(50.0, $insuranceGroup['services'][0]['totalPrice'], 'Total should be 1 × €50');
}
public function testServicePricingWithIneligibleParticipant(): void
{
$insurance = $this->createInsurance(1, 'Reise-Rücktritt', 50.0, 'RRV');
$travel = new Travel();
$travel->insurances = [$insurance];
$participant1 = new ParticipantDto();
$participant1->index = 0;
$participant1->insurance = $insurance;
$participant1->bulkInsuranceBooking = false;
$participant2 = new ParticipantDto();
$participant2->index = 1;
$participant2->insurance = null;
$bookingDto = new BookingDto($travel, 2);
$bookingDto->participants = [$participant1, $participant2];
$eligibilityChecker = $this->createMock(ParticipantEligibilityChecker::class);
$eligibilityChecker->method('isParticipantEligible')
->willReturnCallback(fn ($booking, int $index): bool => 0 === $index);
$result = $this->createAssembler($eligibilityChecker)->calculateServicePricing($bookingDto);
$insuranceGroup = $this->findServiceGroup($result, 'Reiseversicherungen');
$this->assertNotNull($insuranceGroup, 'Insurance group should exist');
$this->assertCount(1, $insuranceGroup['services'], 'Should have 1 insurance line item');
$this->assertEquals(1, $insuranceGroup['services'][0]['participantCount'], 'Should count only applicant');
}
public function testServicePricingWithBulkInsuranceCountsAllParticipants(): void
{
$insuranceA = $this->createInsurance(1, 'Reise-Rücktritt', 50.0, 'RRV');
$travel = new Travel();
$travel->insurances = [$insuranceA];
$travel->dateFrom = new \DateTimeImmutable('2025-06-01');
$travel->dateTo = new \DateTimeImmutable('2025-06-08');
$participant1 = new ParticipantDto();
$participant1->index = 0;
$participant1->insurance = $insuranceA;
$participant1->bulkInsuranceBooking = true;
$participant2 = new ParticipantDto();
$participant2->index = 1;
$participant2->insurance = null;
$participant3 = new ParticipantDto();
$participant3->index = 2;
$participant3->insurance = null;
$bookingDto = new BookingDto($travel, 3);
$bookingDto->participants = [$participant1, $participant2, $participant3];
$result = $this->assembler->calculateServicePricing($bookingDto);
$insuranceGroup = $this->findServiceGroup($result, 'Reiseversicherungen');
$this->assertNotNull($insuranceGroup, 'Insurance group should exist');
$totalParticipants = array_sum(array_column($insuranceGroup['services'], 'participantCount'));
$this->assertEquals(3, $totalParticipants, 'Should count all 3 participants across all tiers');
}
// Helpers
private function createAssembler(ParticipantEligibilityChecker $eligibilityChecker): BookingPricingAssembler
{
$roomPricingCalculator = new RoomPricingCalculator();
return new BookingPricingAssembler(
$roomPricingCalculator,
$eligibilityChecker,
new InsuranceManager(),
new ParticipantPricingCalculator($roomPricingCalculator),
);
}
private function createInsurance(int $id, string $label, float $price, string $subType = 'RRV'): Insurance
{
$insurance = new Insurance();
$insurance->id = (string) $id;
$insurance->label = $label;
$insurance->price = $price;
$insurance->subType = $subType;
$insurance->package = false;
$insurance->complementary = false;
return $insurance;
}
private function findServiceGroup(array $groups, string $groupName): ?array
{
foreach ($groups as $group) {
if ($group['groupName'] === $groupName) {
return $group;
}
}
return null;
}
}