base_url = rtrim( $base_url, '/' ); $this->username = $username; $this->password = $password; } public static function init( $base_url, $username, $password ) { if ( null === self::$instance ) { self::$instance = new self( $base_url, $username, $password ); } return self::$instance; } public static function get_instance() { return self::$instance; } /** * Native cURL request — mirrors softra-test.php requestJson(). */ private function curl_request( $method, $url, $payload = null, $extra_headers = array() ) { $ch = curl_init( $url ); if ( false === $ch ) { return new WP_Error( 'carei_curl_init', 'cURL init failed' ); } $headers = array_merge( array( 'Accept: application/json' ), $extra_headers ); if ( null !== $payload ) { $headers[] = 'Content-Type: application/json'; } curl_setopt_array( $ch, array( CURLOPT_CUSTOMREQUEST => strtoupper( $method ), CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => $headers, CURLOPT_TIMEOUT => 30, CURLOPT_CONNECTTIMEOUT => 15, ) ); if ( null !== $payload ) { curl_setopt( $ch, CURLOPT_POSTFIELDS, json_encode( $payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ) ); } $raw = curl_exec( $ch ); $err = curl_error( $ch ); $status = (int) curl_getinfo( $ch, CURLINFO_HTTP_CODE ); curl_close( $ch ); if ( false === $raw ) { return new WP_Error( 'carei_curl_error', 'cURL error: ' . $err ); } $decoded = json_decode( $raw, true ); if ( ! is_array( $decoded ) ) { $decoded = null; } return array( 'status' => $status, 'body' => $decoded, 'raw' => $raw, ); } /** * Get JWT token (cached in WP transient). */ public function get_token() { $token = get_transient( self::TOKEN_TRANSIENT ); if ( false !== $token ) { return $token; } $res = $this->curl_request( 'POST', $this->base_url . '/account/auth', array( 'login' => $this->username, 'password' => $this->password, ) ); if ( is_wp_error( $res ) ) { return new WP_Error( 'carei_auth_failed', 'Softra API auth failed: ' . $res->get_error_message() ); } if ( 200 !== $res['status'] || empty( $res['body']['token'] ) ) { $detail = isset( $res['raw'] ) ? $res['raw'] : ''; return new WP_Error( 'carei_auth_failed', 'Softra API auth failed (HTTP ' . $res['status'] . '): ' . $detail ); } $token = $res['body']['token']; set_transient( self::TOKEN_TRANSIENT, $token, self::TOKEN_EXPIRY ); return $token; } /** * Generic API request with auth. */ public function request( $method, $endpoint, $body = null, $query_params = array() ) { $token = $this->get_token(); if ( is_wp_error( $token ) ) { return $token; } $url = $this->base_url . $endpoint; if ( ! empty( $query_params ) ) { $url .= '?' . http_build_query( $query_params ); } $res = $this->curl_request( $method, $url, $body, array( 'Authorization: Bearer ' . $token ) ); if ( is_wp_error( $res ) ) { return $res; } if ( $res['status'] < 200 || $res['status'] >= 300 ) { return new WP_Error( 'carei_api_error', 'Softra API error: HTTP ' . $res['status'], array( 'status' => $res['status'], 'body' => $res['body'] ) ); } return $res['body']; } // ─── Public API Methods ─────────────────────────────────────── public function get_branches() { return $this->request( 'GET', '/branch/list' ); } public function get_all_car_classes() { return $this->request( 'GET', '/car/class/listAll' ); } public function get_car_classes( $date_from, $date_to, $branch_name ) { return $this->request( 'POST', '/car/class/list', array( 'dateFrom' => $date_from, 'dateTo' => $date_to, 'branchName' => $branch_name, ) ); } public function get_car_models( $date_from, $date_to, $branch_name, $category = '' ) { return $this->request( 'POST', '/car/model/list', array( 'dateFrom' => $date_from, 'dateTo' => $date_to, 'branchName' => $branch_name, 'category' => $category, ), array( 'includeBrandDetails' => 'true' ) ); } public function get_pricelist( $category, $date_from, $date_to, $pickup_location, $language = 'pl', $currency = 'PLN' ) { return $this->request( 'POST', '/pricelist/list', array( 'category' => $category, 'dateFrom' => $date_from, 'dateTo' => $date_to, 'pickUpLocation' => $pickup_location, 'language' => $language, 'currency' => $currency, ) ); } public function get_pricing_summary( $params ) { return $this->request( 'POST', '/rent/princingSummary', $params ); } public function add_customer( $data ) { return $this->request( 'POST', '/customer/add', $data ); } public function make_booking( $data ) { return $this->request( 'POST', '/rent/makebooking', $data ); } public function confirm_booking( $reservation_id ) { return $this->request( 'POST', '/rent/confirm', array( 'reservationId' => $reservation_id, ) ); } public function get_agreements() { return $this->request( 'GET', '/agreement/def/list' ); } }