wip: initial commit

This commit is contained in:
Björn Fromme
2024-11-20 18:32:09 +01:00
parent ae964198e9
commit d4c4e69d09
91 changed files with 32685 additions and 144 deletions
+23
View File
@@ -0,0 +1,23 @@
<?php
namespace App\BusProNet\Model;
class Address
{
public ?string $street = null;
public ?string $postCode = null;
public ?string $city = null;
public ?string $district = null;
public ?string $country = null;
public function toPayload(): array
{
return [
'strasse' => $this->street,
'plz' => $this->postCode,
'ort' => $this->city,
'ortsteil' => $this->district,
'land' => $this->country,
];
}
}
+11
View File
@@ -0,0 +1,11 @@
<?php
namespace App\BusProNet\Model;
class Availability
{
public ?int $serviceId = null;
public ?string $status = null;
public ?int $available = null;
public ?float $price = null;
}
+14
View File
@@ -0,0 +1,14 @@
<?php
namespace App\BusProNet\Model;
class BaseData
{
public function __construct(private readonly array $items)
{}
public function getItems(): array
{
return $this->items;
}
}
+180
View File
@@ -0,0 +1,180 @@
<?php
namespace App\BusProNet\Model;
use App\Form\Model\BookingData;
class Booking
{
public ?int $id = null;
public ?int $bookingNumber = null;
public ?Travel $travelData = null;
public ?string $status = null;
public ?PersonalData $applicant = null;
public ?int $participantCount = null;
public ?float $price = null;
public ?\DateTimeImmutable $bookingDate = null;
public ?string $travel = null;
public ?int $travelId = null;
public ?string $travelCode = null;
public ?\DateTimeImmutable $travelDate = null;
public ?int $hotelId = null;
public ?string $hotelName = null;
public ?bool $document = null;
public ?float $payment = null;
public array $participantsStatus = [];
public array $participants = [];
public array $transportationServices = [];
public array $additionalServices = [];
public array $rooms = [];
public ?int $invoiceNumber = null;
public ?float $totalPrice = null;
public function getBalance(): float
{
if (null === $this->payment) {
return $this->price;
}
return $this->price - $this->payment;
}
public function getAdditionalServicesByGroup(mixed $group): array
{
$group = (array) $group;
return array_filter($this->additionalServices, function (Service $service) use ($group) {
return in_array($service->subType, $group);
});
}
public function getAdditionalServicesForParticipantByGroup(int $participantIndex, mixed $group): array
{
$services = $this->getAdditionalServicesByGroup($group);
return array_filter($services, function (Service $service) use ($participantIndex) {
return in_array($participantIndex, $service->mapping);
});
}
public function getTransportationServiceForParticipantAndDirection(int $participantIndex, string $direction): ?Service
{
foreach ($this->transportationServices as $service) {
if ($service->direction !== $direction) {
continue;
}
if (in_array($participantIndex, $service->mapping)) {
return $service;
}
}
return null;
}
public function getRoomForParticipant(int $participantIndex): ?Room
{
foreach ($this->rooms as $room) {
if (in_array($participantIndex, $room->mapping)) {
return $room;
}
return null;
}
}
public function getPriceForParticipant(int $participantIndex): float
{
$price = 0.0;
foreach ([...$this->transportationServices, ...$this->additionalServices] as $service) {
if (in_array($participantIndex, $service->mapping) && isset($service->individualPrice[$participantIndex])) {
$price += $service->individualPrice[$participantIndex];
} elseif ($service->price) {
$price += $service->price;
}
}
$room = $this->getRoomForParticipant($participantIndex);
if (isset($room->individualPrice[$participantIndex])) {
$price += $room->individualPrice[$participantIndex];
} elseif ($room->price) {
$price += $room->price;
}
return $price;
}
public function isEditable(): bool
{
return $this->travelDate > new \DateTimeImmutable() && false === in_array($this->status, ['S', 'U']);
}
public function toPayload(?BookingData $formData): array
{
// Reset services to participants mappings
foreach ([...$this->additionalServices, ...$this->transportationServices] as $service) {
$service->mapping = [];
}
// Update mappings and add previously unselected services
foreach ($formData->participants as $participant) {
$servicesToMap = [
...$participant->courses,
...$participant->additionalServices,
...$participant->skiPass,
...$participant->board,
...$participant->rentals,
];
foreach ($servicesToMap as $service) {
if (false === isset($this->additionalServices[$service->id])) {
$serviceToAdd = $this->travelData->additionalServices[$service->id];
$this->additionalServices[$service->id] = $serviceToAdd;
$this->additionalServices[$service->id]->individualPrice[$participant->index] = $serviceToAdd->price;
}
$this->additionalServices[$service->id]->mapping[] = $participant->index;
}
foreach ([$participant->transportationServiceTo, $participant->transportationServiceFro] as $service) {
if (false === isset($this->transportationServices[$service->id])) {
$serviceToAdd = $this->travelData->transportationServices[$service->id];
$this->transportationServices[$service->id] = $serviceToAdd;
$this->transportationServices[$service->id]->individualPrice[$participant->index] = $serviceToAdd->price;
}
$this->transportationServices[$service->id]->mapping[] = $participant->index;
}
}
// Remove services with empty mappings
foreach ($this->additionalServices as $service) {
if (0 === count($service->mapping)) {
unset($this->additionalServices[$service->id]);
}
}
foreach ($this->transportationServices as $service) {
if (0 === count($service->mapping)) {
unset($this->transportationServices[$service->id]);
}
}
// Update participants' personal data
foreach ($formData->participants as $participant) {
$this->participants[$participant->index]->firstName = $participant->firstName;
$this->participants[$participant->index]->lastName = $participant->lastName;
$this->participants[$participant->index]->dateOfBirth = $participant->dateOfBirth;
$this->participants[$participant->index]->gender = $participant->gender;
$this->participants[$participant->index]->nationality = $participant->nationality;
$this->participants[$participant->index]->height = $participant->height;
$this->participants[$participant->index]->weight = $participant->weight;
$this->participants[$participant->index]->shoeSize = $participant->shoeSize;
$this->participants[$participant->index]->communication->email = $participant->email;
$this->participants[$participant->index]->communication->mobile = $participant->mobile;
}
return [
'status' => $this->status,
'idreise' => $this->travelId,
'anmelder' => $this->applicant->toPayload(),
'teilnehmerliste' => [],
'beförderungen' => [],
'unterbringungen' => [],
'zusatzleistungen' => [],
'zustiege' => [],
];
}
}
+19
View File
@@ -0,0 +1,19 @@
<?php
namespace App\BusProNet\Model;
class Communication
{
public ?string $phone = null;
public ?string $mobile = null;
public ?string $email = null;
public function toPayload(): array
{
return [
'email' => $this->email,
'telefonmobil' => $this->mobile,
'telefonprivat' => $this->phone,
];
}
}
+11
View File
@@ -0,0 +1,11 @@
<?php
namespace App\BusProNet\Model;
class Country
{
public ?int $id = null;
public ?string $name = null;
public ?string $token = null;
public ?string $nationality = null;
}
+10
View File
@@ -0,0 +1,10 @@
<?php
namespace App\BusProNet\Model;
class CrmAttribute
{
public ?int $id = null;
public ?string $label = null;
public bool $selected = false;
}
+10
View File
@@ -0,0 +1,10 @@
<?php
namespace App\BusProNet\Model;
class CrmAttributeGroup
{
public ?int $id = null;
public ?string $label = null;
public ?array $attributes = null;
}
+34
View File
@@ -0,0 +1,34 @@
<?php
namespace App\BusProNet\Model;
class CrmAttributes
{
public ?array $attributeGroups = null;
public bool $admin = false;
public bool $manager = false;
public bool $houseManager = false;
public bool $teamer = false;
public ?string $hotelCode = null;
public function toArray(): array
{
$crmSelections = [];
foreach ($this->attributeGroups as $group) {
/** @var CrmAttributeGroup $group */
if (false === isset($crmSelections[$group->label])) {
$crmSelections[$group->label] = [];
}
foreach ($group->attributes as $attribute) {
/** @var CrmAttribute $attribute */
if (false === $attribute->selected) {
continue;
}
$crmSelections[$group->label][] = $attribute->label;
}
}
return $crmSelections;
}
}
+103
View File
@@ -0,0 +1,103 @@
<?php
namespace App\BusProNet\Model;
class Error
{
private static array $errors = [
100 => 'Anfrageknoten fehlt',
101 => 'Satzknoten fehlt in Anfrageknoten',
102 => 'Ungültiger Satztyp [#1#]',
103 => 'User fehlt',
104 => 'User fehlerhaft',
105 => 'Key fehlt',
106 => 'Key fehlerhaft',
200 => 'Keine Einträge vorhanden',
201 => 'Keine Partner zur Auswahl gefunden',
202 => 'Keinen Partner mit der ID [#1#] gefunden',
203 => 'Ungültiger Termin',
300 => 'IDReise fehlt',
301 => 'Reise nicht gefunden',
302 => 'IDLeistung (Hin & Rück) fehlt',
303 => 'IDLeistung passt nicht zu IDReise',
304 => 'Es konnte nicht für alle Teilnehmer ein Sitzplatz ermittelt werden',
305 => 'Anzahl Personen fehlt',
306 => 'Leistungen mit ID #1# nicht gefunden',
307 => 'Leistungen mit ID #1# passen nicht zur Reise mit ID #2#',
308 => 'Keine Zahlungsarten gefunden',
400 => 'IDPartner fehlt',
401 => 'Partner nicht gefunden',
402 => 'Bis-Termin fehlt',
403 => 'Keine Unterbringungsleistungen gefunden',
500 => 'Art fehlt',
501 => 'Reise- und Buchungszeitraum fehlen',
502 => 'Keine Kunden gefunden',
600 => 'Keine Gutscheine gefunden',
601 => 'Gutschein-IDs fehlen',
602 => 'Gutscheine mit ID #1# nicht gefunden',
610 => 'Buchungsart fehlt',
611 => 'Buchungsart falsch',
612 => 'Gutscheinart fehlt',
613 => 'Gutscheinart falsch',
614 => 'Gutscheinstamm-ID fehlt',
615 => 'Gutschein (Stamm) mit ID #1# nicht gefunden',
616 => 'Kapazität beim Gutschein #1# nicht ausreichend',
617 => 'Rechnungsempfänger fehlt',
618 => 'Zahlungsart fehlt',
619 => 'Agentur-ID fehlt',
620 => 'Agentur mit ID #1# nicht gefunden',
650 => '#1#',
700 => 'Keine Agenturen gefunden',
701 => 'Agentur mit ID #1# nicht gefunden',
800 => 'Produkt-ID fehlt',
801 => 'Produkt mit ID #1# nicht gefunden',
805 => 'Es wurden keine Produkte gefunden',
810 => 'Stammdaten (#1#) nicht gefunden',
900 => 'Buchungsart fehlt',
901 => 'Buchungsart falsch',
902 => 'Status fehlt',
903 => 'Status falsch',
904 => 'Agentur-ID fehlt',
905 => 'Agentur mit ID #1# nicht gefunden',
906 => 'Reise-ID fehlt',
907 => 'Reise mit ID #1# nicht gefunden',
908 => 'Reise mit ID #1# ist storniert',
909 => 'Beförderungen fehlen',
910 => 'Leistung mit ID #1# gehört nicht zur Reise',
911 => 'Leistung mit ID #1# gehört nicht zum Produkt',
912 => 'Beförderungsleistung für die #1# fehlt',
913 => 'Unterbringungen fehlen',
914 => 'Partner-ID fehlt',
915 => 'Partner mit ID #1# nicht gefunden',
916 => 'Ferienziel-Unterbringungen fehlen',
917 => 'Ferienziel: Zimmer-IDZ fehlt',
918 => 'Ferienziel: Kategorie fehlt',
919 => 'Ferienziel: Verpflegungs-ID fehlt',
920 => 'Ferienziel: Anreise fehlt',
921 => 'Ferienziel: Anreise passt nicht zur Beförderungsleistung (Hinfahrt)',
922 => 'Ferienziel: Abreise fehlt',
923 => 'Ferienziel: Abreise passt nicht zur Beförderungsleistung (Rückfahrt)',
924 => 'Ferienziel: Keine Preise zu den Daten gefunden',
925 => 'Ferienziel: Preis zu den Daten nicht gefunden',
930 => 'Zustiege fehlen',
931 => 'Zustieg mit ID #1# nicht gefunden',
932 => 'Zustieg mit ID #1# bei Leistung #2# nicht freigegeben',
933 => 'Sitzplan mit ID #1# bei Leistung #2# nicht freigegeben',
935 => 'Versicherung mit ID #1# nicht gefunden',
940 => 'Zahlungsart fehlt',
941 => 'Zahlungsart-ID fehlt',
942 => 'Zahlungsart mit ID #1# nicht gültig',
950 => 'Anmelder fehlt',
951 => 'Teilnehmerliste fehlt',
952 => 'Teilnehmer-ID fehlt',
960 => 'Preisfehler: Struct #1# / Obj #2#',
961 => 'Buchung konnte nicht gespeichert werden',
980 => 'Reise ist fürs Internet gesperrt',
981 => 'Reise ist nicht mehr buchbar (#1#)',
982 => 'Optionsbuchungen nicht zugelassen',
983 => 'Anfragebuchung nicht zugelassen',
984 => 'Leistung mit ID #1# nicht fürs Internet buchbar',
985 => 'Zustieg mit ID #1# nicht fürs Internet buchbar',
999 => 'Systemfehler: #1#',
];
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace App\BusProNet\Model;
class File
{
public function __construct(string $filename, string $content, string $mimeType)
{
$this->filename = $filename;
$this->content = $content;
$this->mimeType = $mimeType;
}
public ?string $filename = null;
public ?string $content = null;
public ?string $mimeType = null;
}
+14
View File
@@ -0,0 +1,14 @@
<?php
namespace App\BusProNet\Model;
class Hotel
{
public ?int $id = null;
public ?string $code = null;
public ?string $name = null;
public ?string $city = null;
public ?string $street = null;
public ?string $phone = null;
public ?string $country = null;
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace App\BusProNet\Model;
class MutableField
{
public function __construct(string $type, bool $mutable, ?\DateTimeImmutable $mutableUntil = null)
{
$this->type = $type;
$this->mutable = $mutable;
$this->mutableBefore = $mutableUntil;
}
public ?string $type = null;
public bool $mutable = false;
public ?\DateTimeImmutable $mutableBefore = null;
}
+31
View File
@@ -0,0 +1,31 @@
<?php
namespace App\BusProNet\Model;
class Notification
{
public function __construct(int $code, string $message)
{
$this->code = $code;
$this->message = $message;
}
public ?int $code;
public ?string $message;
public function isSuccessful(): bool
{
// Successful responses don't carry codes and messages
if (null === $this->code && null === $this->message) {
return true;
}
// These weird and contradictory looking assertions are required because
// of the stupid API implementation that doesn't distinguish between error
// and success responses.
$responseIsError = 100 <= $this->code || $this->message === 'Daten konnten nicht gesendet werden.';
$responseIsSuccess = 650 === $this->code && false === stripos($this->message, 'fehler');
return false === $responseIsError && true === $responseIsSuccess;
}
}
+49
View File
@@ -0,0 +1,49 @@
<?php
namespace App\BusProNet\Model;
use Symfony\Component\Validator\Constraints as Assert;
class PersonalData
{
public ?int $addressId = null;
public ?int $personId = null;
#[Assert\NotBlank(message: 'Bitte angeben')]
public ?string $name = null;
#[Assert\NotBlank(message: 'Bitte angeben')]
public ?string $firstName = null;
public ?string $salutation = null;
public ?string $title = null;
public ?string $gender = null;
public ?string $nationality = null;
public ?string $height = null;
public ?string $shoeSize = null;
public ?string $weight = null;
public ?\DateTimeImmutable $dateOfBirth = null;
#[Assert\Valid()]
public ?Address $address = null;
#[Assert\Valid()]
public ?Communication $communication = null;
public function toPayload(): array
{
// Ensure date of birth is populated
if (null === $dob = $this->dateOfBirth) {
$dob = new \DateTimeImmutable('18 years ago');
}
return [
'idadresse' => $this->addressId,
'idadresseperson' => $this->personId,
'geburtsdatum' => $dob->format('d.m.Y'),
'anrede' => $this->salutation,
'geschlecht' => $this->gender,
'nationalitaet' => $this->nationality,
'titel' => $this->title,
'vorname' => $this->firstName,
'name' => $this->name,
'anschrift' => $this->address->toPayload(),
'kommunikation' => $this->communication->toPayload(),
];
}
}
+14
View File
@@ -0,0 +1,14 @@
<?php
namespace App\BusProNet\Model;
class Pickup
{
public ?int $id = null;
public ?string $code = null;
public ?string $city = null;
public ?string $postalCode = null;
public ?string $street = null;
public ?\DateTimeImmutable $time = null;
public ?float $price = null;
}
+23
View File
@@ -0,0 +1,23 @@
<?php
namespace App\BusProNet\Model;
class Room
{
public ?int $id = null;
public ?string $code = null;
public ?string $label = null;
public ?\DateTimeImmutable $dateFrom = null;
public ?\DateTimeImmutable $dateTo = null;
public ?int $totalCount = null;
public ?int $minPax = null;
public ?int $maxPax = null;
public ?int $nights = null;
public ?string $status = null;
public ?int $available = null;
public ?string $board = null;
public array $mapping = [];
public ?float $price = null;
public ?float $totalPrice = null;
public array $individualPrice = [];
}
+31
View File
@@ -0,0 +1,31 @@
<?php
namespace App\BusProNet\Model;
class Service
{
public const TYPE_INCLUDED = 'included';
public const TYPE_ADDITIONAL = 'additional';
public const TYPE_TRANSPORTATION = 'transportation';
public const TOKEN_COURSES = 'KUR';
public const TOKEN_SKI_PASS = 'SPA';
public const TOKEN_ADDITIONAL = 'SON';
public const TOKEN_BOARD = 'VPF';
public const TOKEN_RENTALS = ['VER', 'VE2', 'VE3', 'VE4', 'VE5', 'VE6', 'VE7', 'VE8'];
public ?int $id = null;
public ?string $status = null;
public bool $mandatory = false;
public ?string $label = null;
public ?\DateTimeImmutable $dateFrom = null;
public ?\DateTimeImmutable $dateTo = null;
public ?string $subType = null;
public ?int $totalCount = null;
public array $mapping = [];
public ?float $price = null;
public ?float $totalPrice = null;
public array $individualPrice = [];
public ?string $direction = null;
public ?int $available = null;
}
+37
View File
@@ -0,0 +1,37 @@
<?php
namespace App\BusProNet\Model;
class Travel
{
public ?int $id = null;
public ?string $code = null;
public ?string $label = null;
public ?\DateTimeImmutable $dateFrom = null;
public ?\DateTimeImmutable $dateTo = null;
public ?string $type = null;
public ?float $priceFrom = null;
public array $selectionGroups = [];
public array $additionalServices = [];
public array $transportationServices = [];
public array $pickups = [];
public array $rooms = [];
public function getAdditionalServicesByGroup(mixed $group, bool $availableOnly = true): array
{
$group = (array) $group;
return array_filter($this->additionalServices, function (Service $service) use ($group, $availableOnly) {
return in_array($service->subType, $group) && (false === $availableOnly || $service->available > 0);
});
}
public function getTransportationServicesByDirection(string $direction, bool $availableOnly = true): array
{
return array_filter($this->transportationServices, function (Service $service) use ($direction, $availableOnly) {
return $direction === $service->direction
&& $service->price >= 0
&& (false === $availableOnly || $service->available > 0);
});
}
}