139 lines
5.3 KiB
PHP
139 lines
5.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\BusProNet\XmlParser;
|
|
|
|
use App\BusProNet\Model\BookingResponse;
|
|
use App\BusProNet\Model\PaymentTerms;
|
|
use App\BusProNet\Model\PriceItem;
|
|
use Symfony\Component\DomCrawler\Crawler;
|
|
|
|
/**
|
|
* Parses XML responses from booking requests (inquiry and final booking).
|
|
*
|
|
* Expected XML structure:
|
|
* <ergebnis>
|
|
* <satz typ="BUCHUNG" />
|
|
* <buchung>möglich|erfolgt</buchung>
|
|
* <vorgang>321530</vorgang>
|
|
* <hinweis>...</hinweis>
|
|
* <preise>
|
|
* <preis position="1" art="BEF" unterart="BUS" bezeichnung="..." ... />
|
|
* </preise>
|
|
* <gesamtpreis>671,78</gesamtpreis>
|
|
* <zahlungsbedingungen>
|
|
* <anzahlung betrag="128,00" termin="21.03.2017" />
|
|
* <restzahlung betrag="543,78" termin="12.11.2017" />
|
|
* </zahlungsbedingungen>
|
|
* </ergebnis>
|
|
*/
|
|
class BookingResponseParser extends AbstractParser
|
|
{
|
|
public function parse(Crawler $node): BookingResponse
|
|
{
|
|
$status = $this->getStringOrNullValue($node->filterXPath('//buchung'));
|
|
if (null === $status || '' === $status) {
|
|
throw new \InvalidArgumentException('Missing required booking status in booking response.');
|
|
}
|
|
|
|
$bookingNumber = $this->getIntOrNullValue($node->filterXPath('//vorgang'));
|
|
$totalPrice = $this->getFloatOrNullValue($node->filterXPath('//gesamtpreis'));
|
|
$message = $this->getStringOrNullValue($node->filterXPath('//hinweis'));
|
|
|
|
$priceItems = $this->parsePriceItems($node);
|
|
$paymentTerms = $this->parsePaymentTerms($node);
|
|
|
|
return new BookingResponse(
|
|
status: $status,
|
|
bookingNumber: $bookingNumber,
|
|
priceItems: $priceItems,
|
|
totalPrice: $totalPrice,
|
|
paymentTerms: $paymentTerms,
|
|
message: $message,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Parses individual price items from the response.
|
|
*
|
|
* @return array<int, PriceItem>
|
|
*/
|
|
private function parsePriceItems(Crawler $node): array
|
|
{
|
|
$priceItems = [];
|
|
|
|
$node->filterXPath('//preise/preis')->each(function (Crawler $priceNode) use (&$priceItems): void {
|
|
$position = (int) $this->getRequiredAttrValue($priceNode, 'position', 'booking response price item');
|
|
$type = $this->getRequiredAttrValue($priceNode, 'art', 'booking response price item');
|
|
$label = $this->getRequiredAttrValue($priceNode, 'bezeichnung', 'booking response price item');
|
|
$unitPrice = $this->stringToFloat($this->getRequiredAttrValue($priceNode, 'preis', 'booking response price item'));
|
|
$totalPrice = $this->stringToFloat($this->getRequiredAttrValue($priceNode, 'gesamtpreis', 'booking response price item'));
|
|
|
|
$priceItems[] = new PriceItem(
|
|
position: $position,
|
|
type: $type,
|
|
subType: $this->getAttrOrNullValue($priceNode, 'unterart'),
|
|
label: $label,
|
|
dateFrom: $this->getAttrOrNullValue($priceNode, 'terminvon'),
|
|
dateTo: $this->getAttrOrNullValue($priceNode, 'terminbis'),
|
|
quantity: (int) ($this->getAttrOrNullValue($priceNode, 'anzahl') ?? 0),
|
|
assignment: $this->getAttrOrNullValue($priceNode, 'zuordnung'),
|
|
unitPrice: $unitPrice,
|
|
totalPrice: $totalPrice,
|
|
id: $this->getAttrOrNullValue($priceNode, 'id')
|
|
);
|
|
});
|
|
|
|
return $priceItems;
|
|
}
|
|
|
|
/**
|
|
* Parses payment terms from the response.
|
|
*/
|
|
private function parsePaymentTerms(Crawler $node): ?PaymentTerms
|
|
{
|
|
$paymentNode = $node->filterXPath('//zahlungsbedingungen');
|
|
|
|
if (0 === $paymentNode->count()) {
|
|
return null;
|
|
}
|
|
|
|
$depositAmount = null;
|
|
$depositDate = null;
|
|
$finalPaymentAmount = null;
|
|
$finalPaymentDate = null;
|
|
|
|
$depositNode = $paymentNode->filterXPath('.//anzahlung');
|
|
if ($depositNode->count() > 0) {
|
|
$depositAmount = $this->stringToFloat($this->getAttrOrNullValue($depositNode, 'betrag'));
|
|
$depositDate = $this->getAttrOrNullValue($depositNode, 'termin');
|
|
}
|
|
|
|
$finalPaymentNode = $paymentNode->filterXPath('.//restzahlung');
|
|
if ($finalPaymentNode->count() > 0) {
|
|
$finalPaymentAmount = $this->stringToFloat($this->getAttrOrNullValue($finalPaymentNode, 'betrag'));
|
|
$finalPaymentDate = $this->getAttrOrNullValue($finalPaymentNode, 'termin');
|
|
}
|
|
|
|
// Parse purchase vouchers (kaufgutschein elements)
|
|
$appliedPurchaseVouchers = [];
|
|
$voucherNodes = $paymentNode->filterXPath('.//kaufgutschein');
|
|
$voucherNodes->each(function (Crawler $voucherNode) use (&$appliedPurchaseVouchers): void {
|
|
$amount = $this->getAttrOrNullValue($voucherNode, 'betrag');
|
|
$appliedPurchaseVouchers[] = [
|
|
'nummer' => $this->getAttrOrNullValue($voucherNode, 'nummer') ?? '',
|
|
'betrag' => $this->stringToFloat($amount),
|
|
];
|
|
});
|
|
|
|
return new PaymentTerms(
|
|
depositAmount: $depositAmount,
|
|
depositDate: $depositDate,
|
|
finalPaymentAmount: $finalPaymentAmount,
|
|
finalPaymentDate: $finalPaymentDate,
|
|
appliedPurchaseVouchers: $appliedPurchaseVouchers,
|
|
);
|
|
}
|
|
}
|