* * möglich|erfolgt * 321530 * ... * * * * 671,78 * * * * * */ 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 */ 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, ); } }