Files
myep/src/BusProNet/XmlParser/BookingResponseParser.php
T

128 lines
4.4 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 = $node->filterXPath('//buchung')->text();
$transactionNumber = $this->getStringOrNullValue($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,
transactionNumber: $transactionNumber,
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 {
$priceItems[] = new PriceItem(
position: (int) $priceNode->attr('position'),
type: $priceNode->attr('art'),
subType: $priceNode->attr('unterart'),
label: $priceNode->attr('bezeichnung'),
dateFrom: $priceNode->attr('terminvon'),
dateTo: $priceNode->attr('terminbis'),
quantity: (int) $priceNode->attr('anzahl'),
assignment: $priceNode->attr('zuordnung'),
unitPrice: $this->stringToFloat($priceNode->attr('preis')),
totalPrice: $this->stringToFloat($priceNode->attr('gesamtpreis')),
id: $priceNode->attr('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($depositNode->attr('betrag'));
$depositDate = $depositNode->attr('termin');
}
$finalPaymentNode = $paymentNode->filterXPath('//restzahlung');
if ($finalPaymentNode->count() > 0) {
$finalPaymentAmount = $this->stringToFloat($finalPaymentNode->attr('betrag'));
$finalPaymentDate = $finalPaymentNode->attr('termin');
}
// Parse purchase vouchers (kaufgutschein elements)
$appliedPurchaseVouchers = [];
$voucherNodes = $paymentNode->filterXPath('//kaufgutschein');
$voucherNodes->each(function (Crawler $voucherNode) use (&$appliedPurchaseVouchers): void {
$appliedPurchaseVouchers[] = [
'nummer' => $voucherNode->attr('nummer') ?? '',
'betrag' => $this->stringToFloat($voucherNode->attr('betrag')),
];
});
return new PaymentTerms(
depositAmount: $depositAmount,
depositDate: $depositDate,
finalPaymentAmount: $finalPaymentAmount,
finalPaymentDate: $finalPaymentDate,
appliedPurchaseVouchers: $appliedPurchaseVouchers,
);
}
}