diff --git a/.env b/.env index 069976e4..d41dbf38 100644 --- a/.env +++ b/.env @@ -48,6 +48,9 @@ MAILJET_DEFAULT_LIST_ID= MAILJET_WEBHOOK_BASIC_PASSWORD=secret APP_NEWSLETTER_CONFIRMATION_TTL_HOURS=1 +BPN_CONNECT_BASE_URL=https://bpn-connect.ep-reisen.app +BPN_CONNECT_API_KEY= + APP_BPN_USER= APP_BPN_PASSWORD= APP_BPN_IP= @@ -71,9 +74,6 @@ APP_TRAVEL_PREFER_REMOTE=false APP_TRAVEL_ENABLE_FALLBACK=true APP_TRAVEL_SNAPSHOT_RETENTION_BUFFER_DAYS=14 -# Feature Flags -FEATURE_TRAVEL_SNAPSHOT=true - # Emails APP_DEFAULT_EMAIL_FROM=info@ep-reisen.de APP_DEFAULT_EMAIL_TO=info@ep-reisen.de @@ -87,8 +87,6 @@ APP_SEASON_SUMMER_FROM=2026-05-01 # Use 'O' during beta phase, switch to 'F' for production DEFAULT_BOOKING_STATUS=F -API_KEYS= - XML_EXPORT_PATH="%kernel.project_dir%/var/xmlexport" XML_EXPORT_CONTINGENTS_PATH="%kernel.project_dir%/var/xmlexportzimmer" JSON_EXPORT_PATH="%kernel.project_dir%/var/jsonexport" diff --git a/config/services.yaml b/config/services.yaml index d68f6d64..b6b470b4 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -258,6 +258,15 @@ services: arguments: $bodyDimensionRanges: '%body_dimension_ranges%' + App\BpnConnect\AbstractApiClient: + abstract: true + arguments: + $baseUrl: '%env(default::BPN_CONNECT_BASE_URL)%' + $apiKey: '%env(default::BPN_CONNECT_API_KEY)%' + + App\BpnConnect\ContingentsClient: + parent: App\BpnConnect\AbstractApiClient + App\Service\MailjetApiClient: arguments: $apiKey: '%env(default::MAILJET_API_KEY)%' diff --git a/src/BpnConnect/AbstractApiClient.php b/src/BpnConnect/AbstractApiClient.php new file mode 100644 index 00000000..22adbdff --- /dev/null +++ b/src/BpnConnect/AbstractApiClient.php @@ -0,0 +1,56 @@ + $query + * @return array + */ + protected function request(string $path, array $query = []): array + { + $this->assertConfigured(); + + try { + $response = $this->httpClient->request('GET', $this->baseUrl.$path, [ + 'headers' => [ + 'X-API-KEY' => $this->apiKey, + ], + 'query' => $query, + ]); + + return $response->toArray(); + } catch (ExceptionInterface $e) { + $this->logger->error('BpnConnect request failed', [ + 'path' => $path, + 'query' => $query, + 'error' => $e->getMessage(), + ]); + + throw new BpnConnectException('BpnConnect request failed: '.$e->getMessage(), 0, $e); + } + } + + private function assertConfigured(): void + { + if (null === $this->baseUrl || null === $this->apiKey) { + throw new BpnConnectException('BpnConnect client is not configured (missing BPN_CONNECT_BASE_URL or BPN_CONNECT_API_KEY).'); + } + } +} diff --git a/src/BpnConnect/ContingentsClient.php b/src/BpnConnect/ContingentsClient.php new file mode 100644 index 00000000..6634706a --- /dev/null +++ b/src/BpnConnect/ContingentsClient.php @@ -0,0 +1,82 @@ +request(self::CALENDAR_PATH, [ + 'hotelCode' => $hotelCode, + 'dateFrom' => $dateFrom, + 'dateTo' => $dateTo, + 'mode' => ContingentMode::Days->value, + ]); + + $entries = array_map( + static fn (array $item) => new ContingentCalendarEntry( + date: $item['date'], + status: ContingentStatus::from($item['status']), + ), + $payload['data'] ?? [], + ); + + return new ContingentCalendarResponse($this->buildMeta($payload), $entries); + } + + public function getContingentRanges( + string $hotelCode, + string $dateFrom, + string $dateTo, + ): ContingentRangeResponse { + $payload = $this->request(self::CALENDAR_PATH, [ + 'hotelCode' => $hotelCode, + 'dateFrom' => $dateFrom, + 'dateTo' => $dateTo, + 'mode' => ContingentMode::Ranges->value, + ]); + + $entries = array_map( + static fn (array $item) => new ContingentRangeEntry( + dateFrom: $item['date_from'], + dateTo: $item['date_to'], + status: ContingentStatus::from($item['status']), + ), + $payload['data'] ?? [], + ); + + return new ContingentRangeResponse($this->buildMeta($payload), $entries); + } + + /** + * @param array $payload + */ + private function buildMeta(array $payload): ContingentCalendarMeta + { + $raw = $payload['meta'] ?? []; + + return new ContingentCalendarMeta( + dateFrom: $raw['date_from'] ?? '', + dateTo: $raw['date_to'] ?? '', + mode: $raw['mode'] ?? '', + hotelCode: $raw['hotel_code'] ?? '', + hotelId: (int) ($raw['hotel_id'] ?? 0), + rowCount: (int) ($raw['row_count'] ?? 0), + ); + } +} diff --git a/src/BpnConnect/Exception/BpnConnectException.php b/src/BpnConnect/Exception/BpnConnectException.php new file mode 100644 index 00000000..e30d225e --- /dev/null +++ b/src/BpnConnect/Exception/BpnConnectException.php @@ -0,0 +1,9 @@ +