Files
myep/src/Form/Model/VoucherPurchaseDto.php
T

152 lines
5.4 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Form\Model;
use App\BusProNet\Model\Address;
use App\BusProNet\Model\PersonalData;
use App\BusProNet\Model\VoucherPaymentMethod;
use App\BusProNet\Model\VoucherTemplate;
use App\Validator\Constraints as AppAssert;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Session state of the voucher purchase flow (/gutschein).
*
* The fields are exactly what the BusProNet voucher shop collects, with its mandatory flags rather
* than those of ADRESSFELDERGUTSCHEIN (which would also demand a phone number and a gender). There
* is no Zusatztext: GUTSCHEINBUCHUNG is sent an empty <text/>, as the live shop does.
*
* Step 2 is validated with the groups ['voucher_step_2', 'personal_data']: the buyer address reuses
* the Address model, whose constraints live in the personal_data group.
*/
class VoucherPurchaseDto
{
public const string SALUTATION_MR = 'Herr';
public const string SALUTATION_MS = 'Frau';
public int $currentStep = 1;
// BusPro's bounds from GUTSCHEINVORLAGEN at the start of the flow. BusPro re-checks them on
// every GUTSCHEINBUCHUNG (607/608), so a change in between still surfaces as a step 1 error.
public int $minAmount = 0;
public int $maxAmount = 0;
// Fixed at the start of the flow from GUTSCHEINZAHLUNGSARTEN; transfer is the only one offered.
public ?VoucherPaymentMethod $paymentMethod = null;
// Step 1: voucher
#[Assert\NotNull(message: 'Bitte wähle ein Motiv', groups: ['voucher_step_1'])]
public ?VoucherTemplate $template = null;
#[Assert\NotBlank(message: 'Bitte angeben', groups: ['voucher_step_1'])]
public ?string $from = null;
#[Assert\NotBlank(message: 'Bitte angeben', groups: ['voucher_step_1'])]
public ?string $to = null;
#[Assert\NotNull(message: 'Bitte gib einen Gutscheinwert an', groups: ['voucher_step_1'])]
#[Assert\Range(
notInRangeMessage: 'Der Gutscheinwert muss zwischen {{ min }} und {{ max }} Euro liegen',
minPropertyPath: 'minAmount',
maxPropertyPath: 'maxAmount',
groups: ['voucher_step_1'],
)]
public ?int $amount = null;
// Step 2: buyer (rechnungsempfänger)
#[Assert\Choice(choices: [self::SALUTATION_MR, self::SALUTATION_MS], groups: ['voucher_step_2'])]
public ?string $salutation = null;
public ?string $title = null;
#[Assert\NotBlank(message: 'Bitte angeben', groups: ['voucher_step_2'])]
public ?string $lastName = null;
#[Assert\NotBlank(message: 'Bitte angeben', groups: ['voucher_step_2'])]
public ?string $firstName = null;
#[Assert\Valid]
public Address $address;
#[Assert\When(
expression: 'this.isPhoneNewlyEntered()',
constraints: [new AppAssert\PhoneNumber()],
groups: ['voucher_step_2'],
)]
public ?string $phone = null;
#[Assert\When(
expression: 'this.isMobileNewlyEntered()',
constraints: [new AppAssert\PhoneNumber()],
groups: ['voucher_step_2'],
)]
public ?string $mobile = null;
// The numbers prefilled from BusPro, which are exempt from PhoneNumber.
public ?string $loadedPhone = null;
public ?string $loadedMobile = null;
#[Assert\NotBlank(message: 'Bitte angeben', groups: ['voucher_step_2'])]
#[Assert\Email(message: 'Bitte eine gültige Adresse angeben', mode: 'strict', groups: ['voucher_step_2'])]
public ?string $email = null;
// Step 3: confirmation, reset on every visit so a stale tick never carries over
#[Assert\IsTrue(message: 'Bitte bestätige', groups: ['voucher_step_3'])]
public bool $termsAccepted = false;
#[Assert\IsTrue(message: 'Bitte bestätige', groups: ['voucher_step_3'])]
public bool $purchaseConfirmed = false;
public function __construct()
{
$this->address = new Address();
$this->address->country = 'D';
}
public function isPhoneNewlyEntered(): bool
{
return AppAssert\PhoneNumber::isNewlyEntered($this->phone, $this->loadedPhone);
}
public function isMobileNewlyEntered(): bool
{
return AppAssert\PhoneNumber::isNewlyEntered($this->mobile, $this->loadedMobile);
}
public function getBuyerFullName(): string
{
return trim(sprintf('%s %s', $this->firstName ?? '', $this->lastName ?? ''));
}
public function hasBuyerData(): bool
{
return null !== $this->lastName && '' !== $this->lastName;
}
/**
* Copies the buyer fields from the signed-in account's BusPro record.
*
* The e-mail is the one the account signed in with, not the record's communication address:
* a BusPro address can carry several e-mails for different persons.
*/
public function prefillBuyer(PersonalData $personalData, ?string $loginEmail): void
{
$this->salutation = \in_array($personalData->salutation, [self::SALUTATION_MR, self::SALUTATION_MS], true)
? $personalData->salutation
: null;
$this->title = $personalData->title;
$this->lastName = $personalData->name;
$this->firstName = $personalData->firstName;
$this->address = clone $personalData->address;
$this->address->normalize();
$this->address->country ??= 'D';
$this->phone = $personalData->communication->phone;
$this->mobile = $personalData->communication->mobile;
$this->loadedPhone = $this->phone;
$this->loadedMobile = $this->mobile;
$this->email = $loginEmail;
}
}