This commit is contained in:
2026-03-25 00:41:16 +01:00
parent 1739f354d1
commit a82ec90a51
48 changed files with 4019 additions and 0 deletions

View File

@@ -0,0 +1,209 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Softra Rent API client with JWT token caching.
* Uses native cURL (matching softra-test.php) instead of WP HTTP API.
*/
class Carei_Softra_API {
private static $instance = null;
private $base_url;
private $username;
private $password;
const TOKEN_TRANSIENT = 'carei_softra_token';
const TOKEN_EXPIRY = 3000; // 50 minutes (token valid 60 min)
private function __construct( $base_url, $username, $password ) {
$this->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' );
}
}