Files
carei.pagedev.pl/wp-content/plugins/carei-reservation/includes/class-rest-proxy.php
2026-04-22 22:00:50 +02:00

365 lines
14 KiB
PHP

<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* WP REST API proxy to Softra Rent API.
* Namespace: carei/v1
*/
class Carei_REST_Proxy {
const NAMESPACE = 'carei/v1';
public function __construct() {
add_action( 'rest_api_init', array( $this, 'register_routes' ) );
}
public function register_routes() {
// GET /branches
register_rest_route( self::NAMESPACE, '/branches', array(
'methods' => 'GET',
'callback' => array( $this, 'get_branches' ),
'permission_callback' => '__return_true',
) );
// GET /car-classes-all (all defined classes, no params needed)
register_rest_route( self::NAMESPACE, '/car-classes-all', array(
'methods' => 'GET',
'callback' => array( $this, 'get_all_car_classes' ),
'permission_callback' => '__return_true',
) );
// GET /segments-branches-map (cached segment→branches mapping)
register_rest_route( self::NAMESPACE, '/segments-branches-map', array(
'methods' => 'GET',
'callback' => array( $this, 'get_segments_branches_map' ),
'permission_callback' => '__return_true',
) );
// POST /car-classes
register_rest_route( self::NAMESPACE, '/car-classes', array(
'methods' => 'POST',
'callback' => array( $this, 'get_car_classes' ),
'permission_callback' => array( $this, 'check_nonce' ),
'args' => array(
'dateFrom' => array( 'required' => true, 'sanitize_callback' => 'sanitize_text_field' ),
'dateTo' => array( 'required' => true, 'sanitize_callback' => 'sanitize_text_field' ),
'branchName' => array( 'required' => true, 'sanitize_callback' => 'sanitize_text_field' ),
),
) );
// POST /car-models
register_rest_route( self::NAMESPACE, '/car-models', array(
'methods' => 'POST',
'callback' => array( $this, 'get_car_models' ),
'permission_callback' => array( $this, 'check_nonce' ),
'args' => array(
'dateFrom' => array( 'required' => true, 'sanitize_callback' => 'sanitize_text_field' ),
'dateTo' => array( 'required' => true, 'sanitize_callback' => 'sanitize_text_field' ),
'branchName' => array( 'required' => true, 'sanitize_callback' => 'sanitize_text_field' ),
'category' => array( 'required' => false, 'sanitize_callback' => 'sanitize_text_field', 'default' => '' ),
),
) );
// POST /pricelist
register_rest_route( self::NAMESPACE, '/pricelist', array(
'methods' => 'POST',
'callback' => array( $this, 'get_pricelist' ),
'permission_callback' => array( $this, 'check_nonce' ),
'args' => array(
'category' => array( 'required' => true, 'sanitize_callback' => 'sanitize_text_field' ),
'dateFrom' => array( 'required' => true, 'sanitize_callback' => 'sanitize_text_field' ),
'dateTo' => array( 'required' => true, 'sanitize_callback' => 'sanitize_text_field' ),
'pickUpLocation' => array( 'required' => true, 'sanitize_callback' => 'sanitize_text_field' ),
),
) );
// POST /pricing-summary
register_rest_route( self::NAMESPACE, '/pricing-summary', array(
'methods' => 'POST',
'callback' => array( $this, 'get_pricing_summary' ),
'permission_callback' => array( $this, 'check_nonce' ),
) );
// POST /customer
register_rest_route( self::NAMESPACE, '/customer', array(
'methods' => 'POST',
'callback' => array( $this, 'add_customer' ),
'permission_callback' => array( $this, 'check_nonce' ),
) );
// POST /booking
register_rest_route( self::NAMESPACE, '/booking', array(
'methods' => 'POST',
'callback' => array( $this, 'make_booking' ),
'permission_callback' => array( $this, 'check_nonce' ),
) );
// POST /booking/confirm
register_rest_route( self::NAMESPACE, '/booking/confirm', array(
'methods' => 'POST',
'callback' => array( $this, 'confirm_booking' ),
'permission_callback' => array( $this, 'check_nonce' ),
'args' => array(
'reservationId' => array( 'required' => true, 'sanitize_callback' => 'sanitize_text_field' ),
),
) );
// POST /booking/cancel
register_rest_route( self::NAMESPACE, '/booking/cancel', array(
'methods' => 'POST',
'callback' => array( $this, 'cancel_booking' ),
'permission_callback' => array( $this, 'check_nonce' ),
'args' => array(
'reservationId' => array( 'required' => true, 'sanitize_callback' => 'sanitize_text_field' ),
'reason' => array( 'required' => true, 'sanitize_callback' => 'sanitize_text_field' ),
),
) );
// GET /branches-full (cached, full branch objects with descriptions)
register_rest_route( self::NAMESPACE, '/branches-full', array(
'methods' => 'GET',
'callback' => array( $this, 'get_branches_full' ),
'permission_callback' => '__return_true',
) );
// GET /agreements
register_rest_route( self::NAMESPACE, '/agreements', array(
'methods' => 'GET',
'callback' => array( $this, 'get_agreements' ),
'permission_callback' => '__return_true',
) );
// GET /protection-packages
register_rest_route( self::NAMESPACE, '/protection-packages', array(
'methods' => 'GET',
'callback' => array( $this, 'get_protection_packages' ),
'permission_callback' => '__return_true',
) );
}
/**
* Verify WP REST nonce for POST requests.
*/
public function check_nonce( WP_REST_Request $request ) {
$nonce = $request->get_header( 'X-WP-Nonce' );
if ( ! $nonce || ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
return new WP_Error( 'rest_forbidden', __( 'Invalid nonce.', 'carei-reservation' ), array( 'status' => 403 ) );
}
return true;
}
/**
* Get API instance or return error.
*/
private function api() {
$api = Carei_Softra_API::get_instance();
if ( null === $api ) {
return new WP_Error( 'carei_not_configured', __( 'Softra API not configured.', 'carei-reservation' ), array( 'status' => 500 ) );
}
return $api;
}
/**
* Wrap API response.
*/
private function respond( $result ) {
if ( is_wp_error( $result ) ) {
return $result;
}
return new WP_REST_Response( $result, 200 );
}
// ─── Callbacks ────────────────────────────────────────────────
public function get_segments_branches_map( WP_REST_Request $request ) {
$api = $this->api();
if ( is_wp_error( $api ) ) {
return $api;
}
return $this->respond( $api->get_segments_branches_map() );
}
public function get_all_car_classes( WP_REST_Request $request ) {
$api = $this->api();
if ( is_wp_error( $api ) ) {
return $api;
}
return $this->respond( $api->get_all_car_classes() );
}
public function get_branches( WP_REST_Request $request ) {
$api = $this->api();
if ( is_wp_error( $api ) ) {
return $api;
}
return $this->respond( $api->get_branches() );
}
public function get_car_classes( WP_REST_Request $request ) {
$api = $this->api();
if ( is_wp_error( $api ) ) {
return $api;
}
return $this->respond( $api->get_car_classes(
$request->get_param( 'dateFrom' ),
$request->get_param( 'dateTo' ),
$request->get_param( 'branchName' )
) );
}
public function get_car_models( WP_REST_Request $request ) {
$api = $this->api();
if ( is_wp_error( $api ) ) {
return $api;
}
return $this->respond( $api->get_car_models(
$request->get_param( 'dateFrom' ),
$request->get_param( 'dateTo' ),
$request->get_param( 'branchName' ),
$request->get_param( 'category' )
) );
}
public function get_pricelist( WP_REST_Request $request ) {
$api = $this->api();
if ( is_wp_error( $api ) ) {
return $api;
}
$pricelists = $api->get_pricelist(
$request->get_param( 'category' ),
$request->get_param( 'dateFrom' ),
$request->get_param( 'dateTo' ),
$request->get_param( 'pickUpLocation' )
);
// Auto-collect PL extra names + per-locale translate (Phase 19).
if ( is_array( $pricelists ) ) {
$locale = $this->resolve_locale( $request );
$translations = Carei_Admin_Panel::get_extras_translations();
foreach ( $pricelists as &$pricelist ) {
if ( ! is_array( $pricelist ) || empty( $pricelist['additionalItems'] ) || ! is_array( $pricelist['additionalItems'] ) ) continue;
foreach ( $pricelist['additionalItems'] as &$item ) {
if ( ! is_array( $item ) || ! isset( $item['name'] ) || ! is_string( $item['name'] ) ) continue;
$pl_name = trim( $item['name'] );
if ( $pl_name === '' ) continue;
Carei_Admin_Panel::remember_extra_name( $pl_name );
if ( $locale === 'en' && isset( $translations[ $pl_name ] ) && $translations[ $pl_name ] !== '' ) {
$item['name'] = $translations[ $pl_name ];
}
}
unset( $item );
}
unset( $pricelist );
}
return $this->respond( $pricelists );
}
public function get_pricing_summary( WP_REST_Request $request ) {
$api = $this->api();
if ( is_wp_error( $api ) ) {
return $api;
}
$params = $request->get_json_params();
return $this->respond( $api->get_pricing_summary( $params ) );
}
public function add_customer( WP_REST_Request $request ) {
$api = $this->api();
if ( is_wp_error( $api ) ) {
return $api;
}
$data = $request->get_json_params();
return $this->respond( $api->add_customer( $data ) );
}
public function make_booking( WP_REST_Request $request ) {
$api = $this->api();
if ( is_wp_error( $api ) ) {
return $api;
}
$data = $request->get_json_params();
$result = $api->make_booking( $data );
// Save reservation to WP on success (fire-and-forget)
if ( ! is_wp_error( $result ) && isset( $result['success'] ) && $result['success'] ) {
Carei_Admin_Panel::save_reservation( $data, $result );
}
return $this->respond( $result );
}
public function confirm_booking( WP_REST_Request $request ) {
$api = $this->api();
if ( is_wp_error( $api ) ) {
return $api;
}
return $this->respond( $api->confirm_booking(
$request->get_param( 'reservationId' )
) );
}
public function cancel_booking( WP_REST_Request $request ) {
$api = $this->api();
if ( is_wp_error( $api ) ) {
return $api;
}
return $this->respond( $api->cancel_booking(
$request->get_param( 'reservationId' ),
$request->get_param( 'reason' )
) );
}
public function get_branches_full( WP_REST_Request $request ) {
$api = $this->api();
if ( is_wp_error( $api ) ) {
return $api;
}
return $this->respond( $api->get_branches_cached() );
}
public function get_agreements( WP_REST_Request $request ) {
$api = $this->api();
if ( is_wp_error( $api ) ) {
return $api;
}
return $this->respond( $api->get_agreements() );
}
public function get_protection_packages( WP_REST_Request $request ) {
$all = Carei_Admin_Panel::get_protection_packages();
$locale = $this->resolve_locale( $request );
$out = array( 'soft' => null, 'premium' => null );
foreach ( array( 'soft', 'premium' ) as $key ) {
if ( isset( $all[ $key ] ) && ! empty( $all[ $key ]['active'] ) ) {
$pkg = $all[ $key ];
if ( 'en' === $locale ) {
$name = ! empty( $pkg['name_en'] ) ? $pkg['name_en'] : $pkg['name'];
$desc = ! empty( $pkg['description_en'] ) ? $pkg['description_en'] : $pkg['description'];
} else {
$name = $pkg['name'];
$desc = $pkg['description'];
}
$out[ $key ] = array(
'key' => $key,
'name' => $name,
'pricePerDay' => (float) $pkg['pricePerDay'],
'description' => $desc,
);
}
}
return rest_ensure_response( $out );
}
private function resolve_locale( WP_REST_Request $request ) {
$lang = $request->get_param( 'lang' );
if ( $lang && in_array( strtolower( $lang ), array( 'pl', 'en' ), true ) ) {
return strtolower( $lang );
}
$locale = function_exists( 'determine_locale' ) ? determine_locale() : get_locale();
return ( 0 === strpos( (string) $locale, 'en' ) ) ? 'en' : 'pl';
}
}