wip: insurance booking phase 5
This commit is contained in:
@@ -87,3 +87,4 @@ services:
|
|||||||
- 'App\Form\Service\ParticipantParkingFieldHandler'
|
- 'App\Form\Service\ParticipantParkingFieldHandler'
|
||||||
- 'App\Form\Service\ParticipantRentalInsuranceFieldHandler'
|
- 'App\Form\Service\ParticipantRentalInsuranceFieldHandler'
|
||||||
- 'App\Form\Service\ParticipantLicensePlateFieldHandler'
|
- 'App\Form\Service\ParticipantLicensePlateFieldHandler'
|
||||||
|
- 'App\Form\Service\ParticipantInsuranceFieldHandler'
|
||||||
|
|||||||
@@ -14,13 +14,19 @@ This document outlines the complete implementation plan for making travel insura
|
|||||||
- **Field Handler Architecture**: Existing pattern for dynamic form fields
|
- **Field Handler Architecture**: Existing pattern for dynamic form fields
|
||||||
- **HTMX Integration**: Real-time form updates infrastructure
|
- **HTMX Integration**: Real-time form updates infrastructure
|
||||||
|
|
||||||
### ❌ Missing Implementation
|
### ✅ Recently Completed
|
||||||
- Insurance subtype parsing and type resolution system
|
- **Phase 1**: Insurance subtype parsing and type resolution system ✅
|
||||||
- Participant insurance field and selection logic
|
- **Phase 2**: Enhanced age calculation with reference date support ✅
|
||||||
- Insurance matching service with criteria validation
|
- **Phase 3**: Insurance matching service with comprehensive criteria validation ✅
|
||||||
- Auto-reselection when participant price changes
|
- **Phase 4**: ParticipantDto enhancement with insurance property ✅
|
||||||
- Form integration and field handlers
|
- **Phase 5**: Form field handler for insurance selection processing ✅
|
||||||
|
|
||||||
|
### ❌ Remaining Implementation
|
||||||
|
- Form integration and field configuration
|
||||||
|
- Controller integration and data handling
|
||||||
- Frontend templates and UX
|
- Frontend templates and UX
|
||||||
|
- Auto-reselection when participant price changes
|
||||||
|
- Advanced features and applicant control
|
||||||
|
|
||||||
## Key Technical Discoveries
|
## Key Technical Discoveries
|
||||||
|
|
||||||
@@ -36,25 +42,25 @@ This document outlines the complete implementation plan for making travel insura
|
|||||||
|
|
||||||
## Implementation Phases
|
## Implementation Phases
|
||||||
|
|
||||||
### Phase 1: Insurance Type System
|
### Phase 1: Insurance Type System ✅ COMPLETED
|
||||||
**Goal**: Add type resolution capability to distinguish insurance types
|
**Goal**: Add type resolution capability to distinguish insurance types
|
||||||
|
|
||||||
#### 1.1 Extend Insurance Model
|
#### 1.1 Extend Insurance Model ✅
|
||||||
- [ ] Add `subType` property to `Insurance` model (from XML `unterart`)
|
- [x] Add `subType` property to `Insurance` model (from XML `unterart`)
|
||||||
- [ ] Add computed `type` property (resolved via service)
|
- [x] Add computed `type` property (resolved via service)
|
||||||
- [ ] Update serialization groups if needed
|
- [x] Update serialization groups if needed
|
||||||
|
|
||||||
#### 1.2 Update Insurance Parser
|
#### 1.2 Update Insurance Parser ✅
|
||||||
- [ ] Modify `InsuranceParser::parseInsuranceNode()` to parse `unterart` attribute
|
- [x] Modify `InsuranceParser::parseInsuranceNode()` to parse `unterart` attribute
|
||||||
- [ ] Add subtype to individual insurance parsing
|
- [x] Add subtype to individual insurance parsing
|
||||||
- [ ] Ensure package parsing maintains existing functionality
|
- [x] Ensure package parsing maintains existing functionality
|
||||||
|
|
||||||
#### 1.3 Create Insurance Type Resolver
|
#### 1.3 Create Insurance Type Resolver ✅
|
||||||
- [ ] Create `InsuranceTypeResolver` service
|
- [x] Create `InsuranceTypeResolver` service
|
||||||
- [ ] Implement type resolution for individual insurances
|
- [x] Implement type resolution for individual insurances
|
||||||
- [ ] Implement package type resolution via contained insurance analysis
|
- [x] Implement package type resolution via contained insurance analysis
|
||||||
- [ ] Define type constants: `TRAVEL_CANCELLATION`, `TRAVEL_PROTECTION`, etc.
|
- [x] Define type constants: `TRAVEL_CANCELLATION`, `TRAVEL_PROTECTION`, etc.
|
||||||
- [ ] Handle family variants using `familyInsurance` boolean
|
- [x] Handle family variants using `familyInsurance` boolean
|
||||||
|
|
||||||
```php
|
```php
|
||||||
// Type Constants
|
// Type Constants
|
||||||
@@ -62,27 +68,28 @@ const TRAVEL_CANCELLATION = 'TRAVEL_CANCELLATION';
|
|||||||
const TRAVEL_CANCELLATION_FAMILY = 'TRAVEL_CANCELLATION_FAMILY';
|
const TRAVEL_CANCELLATION_FAMILY = 'TRAVEL_CANCELLATION_FAMILY';
|
||||||
const TRAVEL_PROTECTION = 'TRAVEL_PROTECTION';
|
const TRAVEL_PROTECTION = 'TRAVEL_PROTECTION';
|
||||||
const TRAVEL_PROTECTION_FAMILY = 'TRAVEL_PROTECTION_FAMILY';
|
const TRAVEL_PROTECTION_FAMILY = 'TRAVEL_PROTECTION_FAMILY';
|
||||||
|
const DEDUCTIBLE = 'DEDUCTIBLE';
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 1.4 Testing
|
#### 1.4 Testing ✅
|
||||||
- [ ] Create `InsuranceTypeResolverTest`
|
- [x] Create `InsuranceTypeResolverTest`
|
||||||
- [ ] Test individual insurance type resolution
|
- [x] Test individual insurance type resolution
|
||||||
- [ ] Test package type resolution
|
- [x] Test package type resolution
|
||||||
- [ ] Test family variant detection
|
- [x] Test family variant detection
|
||||||
- [ ] Verify existing insurance parsing still works
|
- [x] Verify existing insurance parsing still works
|
||||||
|
|
||||||
### Phase 2: Enhanced Age Calculation
|
### Phase 2: Enhanced Age Calculation ✅ COMPLETED
|
||||||
**Goal**: Support age calculation at specific dates (travel start date)
|
**Goal**: Support age calculation at specific dates (travel start date)
|
||||||
|
|
||||||
#### 2.1 Update ParticipantDto
|
#### 2.1 Update ParticipantDto ✅
|
||||||
- [ ] Add `getAgeAtDate(\DateTimeImmutable $referenceDate): ?int` method
|
- [x] Enhanced existing `getAge()` method with optional reference date parameter
|
||||||
- [ ] Keep existing `getAge(): ?int` for backward compatibility
|
- [x] Keep existing `getAge(): ?int` for backward compatibility
|
||||||
- [ ] Ensure proper null handling for missing birth dates
|
- [x] Ensure proper null handling for missing birth dates
|
||||||
|
|
||||||
#### 2.2 Testing
|
#### 2.2 Testing ✅
|
||||||
- [ ] Add tests for `getAgeAtDate()` method
|
- [x] Add comprehensive tests for reference date age calculation
|
||||||
- [ ] Test edge cases (leap years, same day, etc.)
|
- [x] Test edge cases (leap years, same day, etc.)
|
||||||
- [ ] Verify existing age calculation still works
|
- [x] Verify existing age calculation still works
|
||||||
|
|
||||||
### Phase 3: Insurance Matching Service
|
### Phase 3: Insurance Matching Service
|
||||||
**Goal**: Implement comprehensive insurance matching with all criteria
|
**Goal**: Implement comprehensive insurance matching with all criteria
|
||||||
|
|||||||
@@ -86,6 +86,12 @@ class Travel
|
|||||||
#[Groups(['api:single'])]
|
#[Groups(['api:single'])]
|
||||||
public ?Guide $guide = null;
|
public ?Guide $guide = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<Insurance> Available insurances for this travel package
|
||||||
|
*/
|
||||||
|
#[Groups(['api:single'])]
|
||||||
|
public array $insurances = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves additional services filtered by subtype, availability, and optionally by travel date range.
|
* Retrieves additional services filtered by subtype, availability, and optionally by travel date range.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Form\Service;
|
||||||
|
|
||||||
|
use App\BusProNet\Model\Insurance;
|
||||||
|
use App\Form\Model\BookingDtoInterface;
|
||||||
|
use App\Form\Service\Abstract\AbstractParticipantFieldHandler;
|
||||||
|
use App\Service\InsuranceMatchingService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles processing of the insurance field for booking participants.
|
||||||
|
*
|
||||||
|
* This handler manages insurance selections for individual participants in the booking
|
||||||
|
* creation process. It processes the insurance field from form submissions,
|
||||||
|
* validates the selection against participant eligibility criteria, and updates
|
||||||
|
* the participant DTO with the valid insurance selection.
|
||||||
|
*
|
||||||
|
* The insurance field depends on dateOfBirth for age-based eligibility calculations
|
||||||
|
* and uses the InsuranceMatchingService to ensure only eligible insurances can be selected.
|
||||||
|
*
|
||||||
|
* Dependencies: dateOfBirth (for age evaluation and insurance eligibility)
|
||||||
|
*/
|
||||||
|
class ParticipantInsuranceFieldHandler extends AbstractParticipantFieldHandler
|
||||||
|
{
|
||||||
|
public function __construct(
|
||||||
|
private readonly InsuranceMatchingService $insuranceMatchingService,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the form field name this handler processes.
|
||||||
|
*
|
||||||
|
* @return string The field name 'insurance'
|
||||||
|
*/
|
||||||
|
public function getFieldName(): string
|
||||||
|
{
|
||||||
|
return 'insurance';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the field dependencies for proper processing order.
|
||||||
|
*
|
||||||
|
* This handler depends on dateOfBirth for age evaluation and insurance eligibility.
|
||||||
|
*
|
||||||
|
* @return string[] Array containing 'dateOfBirth' dependency
|
||||||
|
*/
|
||||||
|
public function getDependencies(): array
|
||||||
|
{
|
||||||
|
return ['dateOfBirth'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if this handler should process the field based on submitted data.
|
||||||
|
*
|
||||||
|
* For insurance selection fields, we always need to process to handle cases
|
||||||
|
* where the selection is cleared (field not present in data). This ensures
|
||||||
|
* the participant DTO is updated with null when no insurance is selected.
|
||||||
|
*
|
||||||
|
* @param array<string, mixed> $submittedData The submitted participant form data
|
||||||
|
* @param int $participantIndex The index of the participant being processed
|
||||||
|
*
|
||||||
|
* @return bool Always returns true for insurance selection fields
|
||||||
|
*/
|
||||||
|
public function shouldProcess(array $submittedData, int $participantIndex): bool
|
||||||
|
{
|
||||||
|
return true; // Always process to handle deselection cases
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes the insurance field for a specific participant.
|
||||||
|
*
|
||||||
|
* This method extracts the insurance selection from submitted form data,
|
||||||
|
* validates the selection against the participant's eligibility criteria,
|
||||||
|
* and updates the participant DTO with the valid selection. If the insurance
|
||||||
|
* is no longer appropriate for the participant, it is automatically cleared.
|
||||||
|
*
|
||||||
|
* @param array<string, mixed> $submittedData The submitted participant form data
|
||||||
|
* @param BookingDtoInterface $bookingDto The booking DTO to update (create or edit)
|
||||||
|
* @param int $participantIndex The index of the participant being processed
|
||||||
|
*/
|
||||||
|
public function processField(array $submittedData, BookingDtoInterface $bookingDto, int $participantIndex): void
|
||||||
|
{
|
||||||
|
$participant = $bookingDto->getParticipant($participantIndex);
|
||||||
|
if (null === $participant) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$insuranceId = $submittedData['insurance'] ?? null;
|
||||||
|
|
||||||
|
// Clear insurance if no selection
|
||||||
|
if (null === $insuranceId || '' === $insuranceId) {
|
||||||
|
$participant->insurance = null;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the selected insurance from available travel insurances
|
||||||
|
$availableInsurances = $bookingDto->travel->insurances ?? [];
|
||||||
|
$selectedInsurance = $this->findInsuranceById($availableInsurances, $insuranceId);
|
||||||
|
|
||||||
|
if (null === $selectedInsurance) {
|
||||||
|
$participant->insurance = null;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate insurance eligibility for this participant
|
||||||
|
$eligibleInsurances = $this->insuranceMatchingService->getEligibleInsurances(
|
||||||
|
[$selectedInsurance],
|
||||||
|
$participant,
|
||||||
|
$bookingDto
|
||||||
|
);
|
||||||
|
|
||||||
|
// Set insurance only if it's eligible for this participant
|
||||||
|
$participant->insurance = !empty($eligibleInsurances) ? $selectedInsurance : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns field state modifications that should be applied after processing.
|
||||||
|
*
|
||||||
|
* Currently no field state modifications are needed for insurance selection.
|
||||||
|
*
|
||||||
|
* @param array<string, mixed> $submittedData The submitted participant form data
|
||||||
|
* @param BookingDtoInterface $bookingDto The booking DTO (potentially modified by processing)
|
||||||
|
* @param int $participantIndex The participant index being processed
|
||||||
|
*
|
||||||
|
* @return array<string, array<string, mixed>> Empty array - no field state modifications
|
||||||
|
*/
|
||||||
|
public function getFieldStateModifications(array $submittedData, BookingDtoInterface $bookingDto, int $participantIndex): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns field names whose state is affected by this handler's processing.
|
||||||
|
*
|
||||||
|
* Currently no other fields are affected by insurance selection.
|
||||||
|
*
|
||||||
|
* @return string[] Empty array - no other fields are affected
|
||||||
|
*/
|
||||||
|
public function getAffectedFieldNames(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds an insurance by ID from the available insurances array.
|
||||||
|
*
|
||||||
|
* @param array<Insurance> $insurances Array of available insurances
|
||||||
|
* @param string|int $insuranceId The insurance ID to find
|
||||||
|
*
|
||||||
|
* @return Insurance|null The found insurance or null if not found
|
||||||
|
*/
|
||||||
|
private function findInsuranceById(array $insurances, string|int $insuranceId): ?Insurance
|
||||||
|
{
|
||||||
|
foreach ($insurances as $insurance) {
|
||||||
|
if ($insurance->id === $insuranceId || (string) $insurance->id === (string) $insuranceId) {
|
||||||
|
return $insurance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,236 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Tests\Form\Service;
|
||||||
|
|
||||||
|
use App\BusProNet\Model\Insurance;
|
||||||
|
use App\BusProNet\Model\Travel;
|
||||||
|
use App\Form\Model\BookingCreateDto;
|
||||||
|
use App\Form\Model\ParticipantDto;
|
||||||
|
use App\Form\Service\ParticipantInsuranceFieldHandler;
|
||||||
|
use App\Service\InsuranceMatchingService;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class ParticipantInsuranceFieldHandlerTest extends TestCase
|
||||||
|
{
|
||||||
|
private ParticipantInsuranceFieldHandler $handler;
|
||||||
|
private InsuranceMatchingService $insuranceMatchingService;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
$this->insuranceMatchingService = $this->createMock(InsuranceMatchingService::class);
|
||||||
|
$this->handler = new ParticipantInsuranceFieldHandler($this->insuranceMatchingService);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetFieldName(): void
|
||||||
|
{
|
||||||
|
$this->assertEquals('insurance', $this->handler->getFieldName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetDependencies(): void
|
||||||
|
{
|
||||||
|
$dependencies = $this->handler->getDependencies();
|
||||||
|
|
||||||
|
$this->assertEquals(['dateOfBirth'], $dependencies);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testShouldProcessAlwaysReturnsTrue(): void
|
||||||
|
{
|
||||||
|
$result = $this->handler->shouldProcess([], 0);
|
||||||
|
|
||||||
|
$this->assertTrue($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProcessFieldSetsInsuranceToNullWhenNoParticipant(): void
|
||||||
|
{
|
||||||
|
$bookingDto = $this->createMockBookingDto();
|
||||||
|
$bookingDto->method('getParticipant')->with(0)->willReturn(null);
|
||||||
|
|
||||||
|
$this->handler->processField(['insurance' => '123'], $bookingDto, 0);
|
||||||
|
|
||||||
|
// No assertions needed - just ensure no exceptions are thrown
|
||||||
|
$this->addToAssertionCount(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProcessFieldClearsInsuranceWhenNullSelection(): void
|
||||||
|
{
|
||||||
|
$participant = new ParticipantDto();
|
||||||
|
$participant->insurance = $this->createInsurance('123');
|
||||||
|
|
||||||
|
$bookingDto = $this->createMockBookingDto();
|
||||||
|
$bookingDto->method('getParticipant')->with(0)->willReturn($participant);
|
||||||
|
|
||||||
|
$this->handler->processField(['insurance' => null], $bookingDto, 0);
|
||||||
|
|
||||||
|
$this->assertNull($participant->insurance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProcessFieldClearsInsuranceWhenEmptyStringSelection(): void
|
||||||
|
{
|
||||||
|
$participant = new ParticipantDto();
|
||||||
|
$participant->insurance = $this->createInsurance('123');
|
||||||
|
|
||||||
|
$bookingDto = $this->createMockBookingDto();
|
||||||
|
$bookingDto->method('getParticipant')->with(0)->willReturn($participant);
|
||||||
|
|
||||||
|
$this->handler->processField(['insurance' => ''], $bookingDto, 0);
|
||||||
|
|
||||||
|
$this->assertNull($participant->insurance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProcessFieldClearsInsuranceWhenMissingFromData(): void
|
||||||
|
{
|
||||||
|
$participant = new ParticipantDto();
|
||||||
|
$participant->insurance = $this->createInsurance('123');
|
||||||
|
|
||||||
|
$bookingDto = $this->createMockBookingDto();
|
||||||
|
$bookingDto->method('getParticipant')->with(0)->willReturn($participant);
|
||||||
|
|
||||||
|
$this->handler->processField([], $bookingDto, 0);
|
||||||
|
|
||||||
|
$this->assertNull($participant->insurance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProcessFieldClearsInsuranceWhenNotFoundInAvailableInsurances(): void
|
||||||
|
{
|
||||||
|
$participant = new ParticipantDto();
|
||||||
|
$travel = new Travel();
|
||||||
|
$travel->insurances = [$this->createInsurance('456')]; // Different ID
|
||||||
|
|
||||||
|
$bookingDto = $this->createMockBookingDto();
|
||||||
|
$bookingDto->method('getParticipant')->with(0)->willReturn($participant);
|
||||||
|
$bookingDto->travel = $travel;
|
||||||
|
|
||||||
|
$this->handler->processField(['insurance' => '123'], $bookingDto, 0);
|
||||||
|
|
||||||
|
$this->assertNull($participant->insurance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProcessFieldSetsInsuranceWhenEligible(): void
|
||||||
|
{
|
||||||
|
$insurance = $this->createInsurance('123');
|
||||||
|
$participant = new ParticipantDto();
|
||||||
|
$travel = new Travel();
|
||||||
|
$travel->insurances = [$insurance];
|
||||||
|
|
||||||
|
$bookingDto = $this->createMockBookingDto();
|
||||||
|
$bookingDto->method('getParticipant')->with(0)->willReturn($participant);
|
||||||
|
$bookingDto->travel = $travel;
|
||||||
|
|
||||||
|
$this->insuranceMatchingService
|
||||||
|
->expects($this->once())
|
||||||
|
->method('getEligibleInsurances')
|
||||||
|
->with([$insurance], $participant, $bookingDto)
|
||||||
|
->willReturn([$insurance]);
|
||||||
|
|
||||||
|
$this->handler->processField(['insurance' => '123'], $bookingDto, 0);
|
||||||
|
|
||||||
|
$this->assertSame($insurance, $participant->insurance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProcessFieldClearsInsuranceWhenNotEligible(): void
|
||||||
|
{
|
||||||
|
$insurance = $this->createInsurance('123');
|
||||||
|
$participant = new ParticipantDto();
|
||||||
|
$travel = new Travel();
|
||||||
|
$travel->insurances = [$insurance];
|
||||||
|
|
||||||
|
$bookingDto = $this->createMockBookingDto();
|
||||||
|
$bookingDto->method('getParticipant')->with(0)->willReturn($participant);
|
||||||
|
$bookingDto->travel = $travel;
|
||||||
|
|
||||||
|
$this->insuranceMatchingService
|
||||||
|
->expects($this->once())
|
||||||
|
->method('getEligibleInsurances')
|
||||||
|
->with([$insurance], $participant, $bookingDto)
|
||||||
|
->willReturn([]); // Not eligible
|
||||||
|
|
||||||
|
$this->handler->processField(['insurance' => '123'], $bookingDto, 0);
|
||||||
|
|
||||||
|
$this->assertNull($participant->insurance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProcessFieldWorksWithStringAndIntegerIds(): void
|
||||||
|
{
|
||||||
|
$insurance = $this->createInsurance(123); // Integer ID
|
||||||
|
$participant = new ParticipantDto();
|
||||||
|
$travel = new Travel();
|
||||||
|
$travel->insurances = [$insurance];
|
||||||
|
|
||||||
|
$bookingDto = $this->createMockBookingDto();
|
||||||
|
$bookingDto->method('getParticipant')->with(0)->willReturn($participant);
|
||||||
|
$bookingDto->travel = $travel;
|
||||||
|
|
||||||
|
$this->insuranceMatchingService
|
||||||
|
->expects($this->once())
|
||||||
|
->method('getEligibleInsurances')
|
||||||
|
->willReturn([$insurance]);
|
||||||
|
|
||||||
|
$this->handler->processField(['insurance' => '123'], $bookingDto, 0); // String selection
|
||||||
|
|
||||||
|
$this->assertSame($insurance, $participant->insurance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProcessFieldHandlesEmptyInsurancesArray(): void
|
||||||
|
{
|
||||||
|
$participant = new ParticipantDto();
|
||||||
|
$travel = new Travel();
|
||||||
|
$travel->insurances = []; // No insurances available
|
||||||
|
|
||||||
|
$bookingDto = $this->createMockBookingDto();
|
||||||
|
$bookingDto->method('getParticipant')->with(0)->willReturn($participant);
|
||||||
|
$bookingDto->travel = $travel;
|
||||||
|
|
||||||
|
$this->handler->processField(['insurance' => '123'], $bookingDto, 0);
|
||||||
|
|
||||||
|
$this->assertNull($participant->insurance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testProcessFieldHandlesNullInsurancesProperty(): void
|
||||||
|
{
|
||||||
|
$participant = new ParticipantDto();
|
||||||
|
$travel = new Travel();
|
||||||
|
// $travel->insurances not set, defaults to []
|
||||||
|
|
||||||
|
$bookingDto = $this->createMockBookingDto();
|
||||||
|
$bookingDto->method('getParticipant')->with(0)->willReturn($participant);
|
||||||
|
$bookingDto->travel = $travel;
|
||||||
|
|
||||||
|
$this->handler->processField(['insurance' => '123'], $bookingDto, 0);
|
||||||
|
|
||||||
|
$this->assertNull($participant->insurance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetFieldStateModificationsReturnsEmptyArray(): void
|
||||||
|
{
|
||||||
|
$bookingDto = $this->createMockBookingDto();
|
||||||
|
|
||||||
|
$result = $this->handler->getFieldStateModifications([], $bookingDto, 0);
|
||||||
|
|
||||||
|
$this->assertIsArray($result);
|
||||||
|
$this->assertEmpty($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGetAffectedFieldNamesReturnsEmptyArray(): void
|
||||||
|
{
|
||||||
|
$result = $this->handler->getAffectedFieldNames();
|
||||||
|
|
||||||
|
$this->assertIsArray($result);
|
||||||
|
$this->assertEmpty($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createInsurance(string|int $id, string $label = 'Test Insurance'): Insurance
|
||||||
|
{
|
||||||
|
$insurance = new Insurance();
|
||||||
|
$insurance->id = $id;
|
||||||
|
$insurance->label = $label;
|
||||||
|
|
||||||
|
return $insurance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createMockBookingDto(): BookingCreateDto
|
||||||
|
{
|
||||||
|
return $this->createMock(BookingCreateDto::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user