149 lines
5.5 KiB
PHP
149 lines
5.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Service;
|
|
|
|
use App\BusProNet\ApiClient;
|
|
use App\BusProNet\Model\Address;
|
|
use App\BusProNet\Model\Notification;
|
|
use App\Entity\User;
|
|
use App\Form\Model\BookingDto;
|
|
use App\Form\Model\ParticipantDto;
|
|
use App\Security\Crypt;
|
|
use Carbon\CarbonImmutable;
|
|
use Psr\Log\LoggerInterface;
|
|
|
|
/**
|
|
* Service for prepopulating participant data from authenticated user's personal data.
|
|
*
|
|
* Fetches personal data from BPN API and maps it to a ParticipantDto to streamline
|
|
* the booking process for authenticated users. All errors are handled gracefully
|
|
* to ensure the booking flow is never interrupted.
|
|
*/
|
|
class ParticipantDataPrefiller
|
|
{
|
|
public const TOKEN = '#KUN#';
|
|
|
|
public function __construct(
|
|
private readonly ApiClient $apiClient,
|
|
private readonly Crypt $crypt,
|
|
private readonly LoggerInterface $logger,
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* Prepopulates applicant data from authenticated user's personal data.
|
|
*
|
|
* Fetches PersonalData from BPN API using the user's credentials and maps
|
|
* the data to the provided ParticipantDto. If the API call fails or returns
|
|
* incomplete data, the method logs the error and returns the unpopulated
|
|
* participant without throwing exceptions.
|
|
*
|
|
* @param User $user The authenticated user
|
|
* @param ParticipantDto $applicant The applicant DTO to prepopulate
|
|
*
|
|
* @return ParticipantDto The prepopulated participant (or unchanged if API fails)
|
|
*/
|
|
public function prefillApplicantFromUser(User $user, ParticipantDto $applicant): ParticipantDto
|
|
{
|
|
try {
|
|
// Decrypt user password for API authentication
|
|
$password = $this->crypt->decrypt($user->getPassword());
|
|
$email = $user->getEmail();
|
|
|
|
// Fetch personal data from API
|
|
$result = $this->apiClient->getPersonalData($email, $password);
|
|
|
|
// Handle API error response
|
|
if ($result instanceof Notification) {
|
|
$this->logger->warning('Failed to fetch personal data for prepopulation', [
|
|
'email' => $email,
|
|
'code' => $result->code,
|
|
'message' => $result->message,
|
|
]);
|
|
|
|
return $applicant;
|
|
}
|
|
|
|
// Create a temporary participant from personal data
|
|
$prepopulated = ParticipantDto::fromPersonalData($result);
|
|
|
|
// Copy personal data fields to the existing applicant
|
|
// Preserve booking-specific fields (roomId, services, etc.)
|
|
$applicant->addressId = $prepopulated->addressId;
|
|
$applicant->personId = $prepopulated->personId;
|
|
$applicant->firstName = $prepopulated->firstName;
|
|
$applicant->lastName = $prepopulated->lastName;
|
|
$applicant->title = $prepopulated->title;
|
|
$applicant->gender = $prepopulated->gender;
|
|
$applicant->nationality = $prepopulated->nationality;
|
|
$applicant->dateOfBirth = $prepopulated->dateOfBirth;
|
|
$applicant->email = $prepopulated->email;
|
|
$applicant->mobile = $prepopulated->mobile;
|
|
$applicant->address = $prepopulated->address;
|
|
$applicant->height = $prepopulated->height;
|
|
$applicant->weight = $prepopulated->weight;
|
|
$applicant->shoeSize = $prepopulated->shoeSize;
|
|
$applicant->remarksRoom = $prepopulated->remarksRoom;
|
|
$applicant->licensePlate = $prepopulated->licensePlate;
|
|
|
|
return $applicant;
|
|
} catch (\Exception $e) {
|
|
// Catch any unexpected exceptions (decryption failure, API errors, etc.)
|
|
$this->logger->error('Exception during applicant prepopulation', [
|
|
'error' => $e->getMessage(),
|
|
'email' => $user->getEmail(),
|
|
]);
|
|
|
|
return $applicant;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Determines whether the applicant should be prepopulated.
|
|
*
|
|
* Only prepopulates if the participant is fresh.
|
|
*/
|
|
public function shouldPrefillApplicant(ParticipantDto $applicant): bool
|
|
{
|
|
return null === $applicant->firstName || '' === $applicant->firstName;
|
|
}
|
|
|
|
/**
|
|
* Checks if the participant's last name triggers dummy data fill.
|
|
*
|
|
* Only matches in create mode to avoid accidental triggering during edits.
|
|
*/
|
|
public function isDummyDataFillRequested(ParticipantDto $participant, string $mode): bool
|
|
{
|
|
if (BookingDto::MODE_CREATE !== $mode) {
|
|
return false;
|
|
}
|
|
|
|
return self::TOKEN === $participant->lastName;
|
|
}
|
|
|
|
/**
|
|
* Fills the participant DTO with generated dummy personal data.
|
|
*/
|
|
public function fillDummyParticipant(ParticipantDto $participant, int $participantIndex): void
|
|
{
|
|
$participantNumber = $participantIndex + 1;
|
|
$now = CarbonImmutable::now();
|
|
|
|
$participant->firstName = sprintf('Vorname %d', $participantNumber);
|
|
$participant->lastName = sprintf('Muster %d %s', $participantNumber, $now->format('H:i'));
|
|
$participant->mobile = '0171/111111';
|
|
$participant->email = sprintf('teilnehmer.in%[email protected]', $participantNumber);
|
|
$participant->dateOfBirth = $now->subYears(20)->toImmutable();
|
|
|
|
$address = new Address();
|
|
$address->street = 'Musterstr. 123';
|
|
$address->postCode = '99999';
|
|
$address->city = 'MusterOrt';
|
|
$address->country = 'Deutschland';
|
|
$participant->address = $address;
|
|
}
|
|
}
|