206 lines
6.2 KiB
PHP
206 lines
6.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\BusProNet\Model;
|
|
|
|
use Symfony\Component\Serializer\Attribute\Context;
|
|
use Symfony\Component\Serializer\Attribute\Groups;
|
|
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
|
|
|
|
/**
|
|
* Represents an insurance product or package with pricing, eligibility, and booking constraints.
|
|
*
|
|
* This class handles both individual insurance products and insurance packages,
|
|
* including pricing tiers, age restrictions, travel date validity, booking windows, and coverage details.
|
|
*/
|
|
class Insurance
|
|
{
|
|
/**
|
|
* Special ID for the synthetic "no insurance" option.
|
|
*
|
|
* This option is injected into the insurance selection list to force explicit user choice
|
|
* for legal compliance. When selected, it satisfies validation requirements but transmits
|
|
* no insurance data to the BPN API.
|
|
*/
|
|
public const NO_INSURANCE_ID = '0';
|
|
|
|
#[Groups(['api:single', 'api:list'])]
|
|
public ?string $id = null;
|
|
|
|
#[Groups(['api:single', 'api:list'])]
|
|
public ?string $code = null;
|
|
|
|
#[Groups(['api:single', 'api:list'])]
|
|
public ?string $label = null;
|
|
|
|
#[Groups(['api:single', 'api:list'])]
|
|
public ?string $subType = null;
|
|
|
|
#[Groups(['api:single', 'api:list'])]
|
|
public ?float $price = null;
|
|
|
|
#[Groups(['api:single', 'api:list'])]
|
|
public bool $familyInsurance = false;
|
|
|
|
#[Groups(['api:single', 'api:list'])]
|
|
public bool $package = false;
|
|
|
|
#[Groups(['api:single', 'api:list'])]
|
|
public bool $complementary = false;
|
|
|
|
#[Groups(['api:single', 'api:list'])]
|
|
#[Context([DateTimeNormalizer::FORMAT_KEY => 'Y-m-d'])]
|
|
public ?\DateTimeImmutable $travelDateFrom = null;
|
|
|
|
#[Groups(['api:single', 'api:list'])]
|
|
#[Context([DateTimeNormalizer::FORMAT_KEY => 'Y-m-d'])]
|
|
public ?\DateTimeImmutable $travelDateTo = null;
|
|
|
|
#[Groups(['api:single', 'api:list'])]
|
|
#[Context([DateTimeNormalizer::FORMAT_KEY => 'Y-m-d'])]
|
|
public ?\DateTimeImmutable $bookingDateFrom = null;
|
|
|
|
#[Groups(['api:single', 'api:list'])]
|
|
#[Context([DateTimeNormalizer::FORMAT_KEY => 'Y-m-d'])]
|
|
public ?\DateTimeImmutable $bookingDateTo = null;
|
|
|
|
#[Groups(['api:single', 'api:list'])]
|
|
public ?int $ageFrom = null;
|
|
|
|
#[Groups(['api:single', 'api:list'])]
|
|
public ?int $ageTo = null;
|
|
|
|
#[Groups(['api:single', 'api:list'])]
|
|
public ?float $travelPriceFrom = null;
|
|
|
|
#[Groups(['api:single', 'api:list'])]
|
|
public ?float $travelPriceTo = null;
|
|
|
|
#[Groups(['api:single', 'api:list'])]
|
|
public ?int $travelDurationFrom = null;
|
|
|
|
#[Groups(['api:single', 'api:list'])]
|
|
public ?int $travelDurationTo = null;
|
|
|
|
#[Groups(['api:single', 'api:list'])]
|
|
public ?string $urlInfo = null;
|
|
|
|
#[Groups(['api:single', 'api:list'])]
|
|
public ?string $urlProductInfo = null;
|
|
|
|
#[Groups(['api:single', 'api:list'])]
|
|
public ?string $urlTerms = null;
|
|
|
|
/**
|
|
* @var array<Insurance> Insurance products contained in this package (only for packages)
|
|
*/
|
|
#[Groups(['api:single', 'api:list'])]
|
|
public array $containedInsurances = [];
|
|
|
|
/**
|
|
* @var array<string|int> IDs of insurance products contained in this package (only for packages)
|
|
*/
|
|
#[Groups(['api:single', 'api:list'])]
|
|
public array $containedInsuranceIds = [];
|
|
|
|
/**
|
|
* @var array<int> Participant indices assigned to this insurance (booking data only)
|
|
*/
|
|
public array $mapping = [];
|
|
|
|
/**
|
|
* @var array<int, float> Individual prices per participant index (booking data only)
|
|
*/
|
|
public array $individualPrice = [];
|
|
|
|
/**
|
|
* Returns the subType, with virtual 'PKG' subType for insurance packages.
|
|
*
|
|
* @return string|null The subType (RRV, PAK, OHN, PKG) or null
|
|
*/
|
|
public function getSubType(): ?string
|
|
{
|
|
if (true === $this->package) {
|
|
return 'PKG'; // Virtual subType for all insurance packages
|
|
}
|
|
|
|
return $this->subType;
|
|
}
|
|
|
|
/**
|
|
* Returns all info URLs from this insurance or its contained insurances (for packages).
|
|
*
|
|
* @return array<string> Array of info URLs
|
|
*/
|
|
public function getAllUrlsInfo(): array
|
|
{
|
|
if (true === $this->package) {
|
|
return $this->collectUrlsFromContainedInsurances('urlInfo');
|
|
}
|
|
|
|
return null !== $this->urlInfo ? [$this->urlInfo] : [];
|
|
}
|
|
|
|
/**
|
|
* Returns all product info URLs from this insurance or its contained insurances (for packages).
|
|
*
|
|
* @return array<string> Array of product info URLs
|
|
*/
|
|
public function getAllUrlsProductInfo(): array
|
|
{
|
|
if (true === $this->package) {
|
|
return $this->collectUrlsFromContainedInsurances('urlProductInfo');
|
|
}
|
|
|
|
return null !== $this->urlProductInfo ? [$this->urlProductInfo] : [];
|
|
}
|
|
|
|
/**
|
|
* Returns all terms URLs from this insurance or its contained insurances (for packages).
|
|
*
|
|
* @return array<string> Array of terms URLs
|
|
*/
|
|
public function getAllUrlsTerms(): array
|
|
{
|
|
if (true === $this->package) {
|
|
return $this->collectUrlsFromContainedInsurances('urlTerms');
|
|
}
|
|
|
|
return null !== $this->urlTerms ? [$this->urlTerms] : [];
|
|
}
|
|
|
|
/**
|
|
* Collects URLs from contained insurances for a specific URL property.
|
|
*
|
|
* @param string $urlProperty The URL property name to collect (urlInfo, urlProductInfo, urlTerms)
|
|
*
|
|
* @return array<string> Array of non-null URLs from contained insurances
|
|
*/
|
|
private function collectUrlsFromContainedInsurances(string $urlProperty): array
|
|
{
|
|
$urls = [];
|
|
|
|
foreach ($this->containedInsurances as $containedInsurance) {
|
|
if (null !== $containedInsurance->{$urlProperty}) {
|
|
$urls[] = $containedInsurance->{$urlProperty};
|
|
}
|
|
}
|
|
|
|
return array_values(array_unique($urls));
|
|
}
|
|
|
|
/**
|
|
* Checks if this is the synthetic "no insurance" option.
|
|
*
|
|
* The "no insurance" option is a UI construct used to force explicit user choice.
|
|
* It should be excluded from BPN API transmission.
|
|
*
|
|
* @return bool True if this is the "no insurance" option
|
|
*/
|
|
public function isNoInsurance(): bool
|
|
{
|
|
return self::NO_INSURANCE_ID === $this->id;
|
|
}
|
|
}
|