File: /storage/v4513/tepnot/public_html/wp-content/plugins/dokan-pro/includes/Refund/Request.php
<?php
namespace WeDevs\DokanPro\Refund;
use ArrayAccess;
use WP_Error;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
/**
* A helper class to mimic WP_REST_Request
*
* Useful when a request comes from other than REST, for example Ajax request.
*
* @see \WeDevs\DokanPro\Refund\Ajax for usage
*/
class Request implements ArrayAccess {
/**
* The refund model
*
* @since 3.0.0
*
* @var null|Refund
*/
protected $model = null;
/**
* Required params
*
* @since 3.0.0
*
* @var null|array
*/
protected $required = null;
/**
* Errors during request process
*
* @since 3.0.0
*
* @var null|WP_Error
*/
protected $error = null;
/**
* Class constructor
*
* @since 3.0.0
*
* @param array $data
*/
public function __construct( $data ) {
$this->model = new Refund( $data );
}
/**
* ArrayAccess method override
*
* @since 3.0.0
*
* @param string $offset
*
* @return bool
*/
public function offsetExists( $offset ): bool {
$data = $this->get_params();
return isset( $data[ $offset ] );
}
/**
* ArrayAccess offset method override
*
* @since 3.0.0
*
* @param string $offset
* @param mixed $value
*
* @return void
*/
#[\ReturnTypeWillChange]
public function offsetSet( $offset, $value ) {
$this->set_param( $offset, $value );
}
/**
* ArrayAccess method override
*
* @since 3.0.0
*
* @param string $offset
*
* @return mixed
*/
#[\ReturnTypeWillChange]
public function offsetGet( $offset ) {
return $this->get_param( $offset );
}
/**
* ArrayAccess method override
*
* @since 3.0.0
*
* @param string $offset
*
* @return void
*/
#[\ReturnTypeWillChange]
public function offsetUnset( $offset ) {
// not using this method here!
}
/**
* Get the refund model
*
* @since 3.0.0
*
* @return Refund
*/
public function get_model() {
return $this->model;
}
/**
* Get model data
*
* @since 3.0.0
*
* @return array
*/
public function get_params() {
return $this->model->get_data();
}
/**
* Set model param/data
*
* @since 3.0.0
*
* @param string $param
* @param mixed $value
*
* @return void
*/
public function set_param( $param, $value ) {
$setter = "set_$param";
$this->model->$setter( $value );
}
/**
* Get a model param value
*
* @since 3.0.0
*
* @param string $param
*
* @return mixed
*/
public function get_param( $param ) {
$data = $this->get_params();
if ( isset( $data[ $param ] ) ) {
return $data[ $param ];
}
return null;
}
/**
* Add error
*
* @since 3.0.0
*
* @param WP_Error $error
*
* @return void
*/
protected function add_error( $error ) {
if ( ! $this->has_error() ) {
$this->error = new WP_Error();
}
$this->error->add( $error->get_error_code(), $error->get_error_message(), $error->get_error_data() );
}
/**
* Set required fields/params
*
* @since 3.0.0
*
* @param array $required
*
* @return void
*/
public function set_required( $required ) {
$this->required = $required;
}
/**
* Checks if Request has any error
*
* @since 3.0.0
*
* @return bool
*/
public function has_error() {
return ! is_null( $this->get_error() );
}
/**
* Get request error
*
* @since 3.0.0
*
* @return WP_Error
*/
public function get_error() {
return $this->error;
}
/**
* Validate a request
*
* @since 3.0.0
*
* @return void
*/
public function validate() {
$data = $this->model->get_data();
if ( is_array( $this->required ) ) {
$missing_required = [];
foreach ( $this->required as $param => $message ) {
if ( empty( $data[ $param ] ) ) {
$missing_required[] = $message;
}
}
if ( $missing_required ) {
$this->add_error(
new WP_Error(
'dokan_pro_missing_params',
// translators: %s is a list of required params
sprintf( __( 'Missing parameter(s): %s', 'dokan' ), implode( ', ', $missing_required ) ),
[
'status' => 400,
'params' => $missing_required,
]
)
);
return;
}
}
$is_refund_amount_valid = $this->validate_refund_amount( $data );
if ( ! $is_refund_amount_valid ) {
return;
}
foreach ( $data as $param => $value ) {
$method = "validate_$param";
if ( method_exists( Validator::class, $method ) ) {
$validate = Validator::$method( $value, $this, $param );
if ( is_wp_error( $validate ) ) {
$this->add_error( $validate );
return;
}
}
}
}
/**
* Sanitize a request
*
* @since 3.0.0
*
* @return void
*/
public function sanitize() {
$data = $this->model->get_data();
foreach ( $data as $param => $value ) {
$method = "sanitize_$param";
if ( method_exists( Sanitizer::class, $method ) ) {
$sanitized = Sanitizer::$method( $value, $this, $param );
if ( is_wp_error( $sanitized ) ) {
$this->add_error( $sanitized );
} else {
$this->set_param( $param, $sanitized );
}
}
}
}
/**
* Validate amount for over issue.
*
* @param array $data Refund request data.
*
* @since 3.2.3
* @since 3.3.3 Approvable and pending request validation added.
* @since 3.3.3 LineItem name added with validation message.
*
* @return bool
*/
public function validate_refund_amount( $data ): bool {
global $wpdb;
$order_id = $data['order_id'];
$order = wc_get_order( $order_id );
$item_totals_request = $data['item_totals'];
$item_tax_totals_request = $data['item_tax_totals'];
$already_refunded = array();
$refund_manager = new Manager();
if ( $refund_manager->has_pending_request( $order_id ) ) {
$this->add_error(
new WP_Error(
'dokan_pro_refund_error_has_pending_request',
__( 'There is already a pending refund request for this order.', 'dokan' )
)
);
return false;
}
$results = $wpdb->get_results(
$wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}dokan_refund WHERE order_id=%d AND status != %d",
$order_id,
2 // 2 is refund status cancel.
)
);
foreach ( $results as $previous_refund ) {
if ( ! empty( $previous_refund->item_totals ) ) {
$item_totals_arr = json_decode( $previous_refund->item_totals, true );
foreach ( $item_totals_arr as $line_item_id => $amount ) {
$already_refunded[ $line_item_id ]['item_totals'] = ( isset( $already_refunded[ $line_item_id ]['item_totals'] ) ) ? ( (float) $already_refunded[ $line_item_id ]['item_totals'] + (float) $amount ) : (float) $amount;
}
}
if ( ! empty( $previous_refund->item_tax_totals ) ) {
$item_tax_totals_arr = json_decode( $previous_refund->item_tax_totals, true );
foreach ( $item_tax_totals_arr as $line_item_id => $amount_array ) {
$already_refunded[ $line_item_id ]['item_tax_totals'] = ( isset( $already_refunded[ $line_item_id ]['item_tax_totals'] ) ) ? ( (float) $already_refunded[ $line_item_id ]['item_tax_totals'] + (float) array_sum( $amount_array ) ) : (float) array_sum( $amount_array );
}
}
unset( $item_totals_arr );
unset( $item_tax_totals_arr );
}
foreach ( $order->get_items( [ 'line_item', 'shipping', 'fee' ] ) as $order_line_item_id => $order_line_item ) {
$refunded_amount = ( isset( $already_refunded[ $order_line_item_id ] ) && ! empty( $already_refunded[ $order_line_item_id ]['item_totals'] ) ) ? (float) wc_format_decimal( $already_refunded[ $order_line_item_id ]['item_totals'], '' ) : 0.00;
$refunded_tax = ( isset( $already_refunded[ $order_line_item_id ] ) && ! empty( $already_refunded[ $order_line_item_id ]['item_tax_totals'] ) ) ? (float) wc_format_decimal( $already_refunded[ $order_line_item_id ]['item_tax_totals'], '' ) : 0.00;
if ( isset( $item_totals_request[ $order_line_item_id ] ) ) {
$order_line_item_total = (float) wc_format_decimal( $order_line_item->get_total(), '' );
$order_line_item_request_total = (float) wc_format_decimal( $item_totals_request[ $order_line_item_id ], '' );
if ( $order_line_item_total < ( $refunded_amount + $order_line_item_request_total ) ) {
$this->add_error(
new WP_Error(
'dokan_pro_refund_error_excess_refund',
// translators: Order Line Item name.
sprintf( __( 'The refund amount %1$s is more than the permitted amount for line %2$s', 'dokan' ), wc_format_decimal( $item_totals_request[ $order_line_item_id ], wc_get_price_decimals() ), $order_line_item->get_name() )
)
);
return false;
} elseif ( $order_line_item_request_total < 0 ) {
$this->add_error(
new WP_Error(
'dokan_pro_refund_error_negative_refund_amount',
// translators: Order Line Item name.
sprintf( __( 'The Refund amount is negative number for line %s.', 'dokan' ), $order_line_item->get_name() )
)
);
return false;
}
}
if ( ! isset( $item_tax_totals_request[ $order_line_item_id ] ) ) {
continue;
}
$order_line_item_total_tax = (float) wc_format_decimal( $order_line_item->get_total_tax(), '' );
$order_line_item_total_request_tax = (float) wc_format_decimal( array_sum( $item_tax_totals_request[ $order_line_item_id ] ), '' );
if ( $order_line_item_total_tax < ( $refunded_tax + $order_line_item_total_request_tax ) ) {
$this->add_error(
new WP_Error(
'dokan_pro_refund_error_tax_excess_refund',
// translators: Order Line Item name.
sprintf( __( 'The Refund tax amount is more than permitted amount for line %s', 'dokan' ), $order_line_item->get_name() )
)
);
return false;
} elseif ( min( $item_tax_totals_request[ $order_line_item_id ] ) < 0 ) {
$this->add_error(
new WP_Error(
'dokan_pro_refund_error_negative_refund_tax_amount',
// translators: Order Line Item name.
sprintf( __( 'The Refund tax amount is negative number for line %s', 'dokan' ), $order_line_item->get_name() )
)
);
return false;
}
}
return true;
}
}