WC_REST_Order_Refunds_Controller

REST API Order Refunds controller class.

Defined (1)

The class is defined in the following location(s).

/includes/api/class-wc-rest-order-refunds-controller.php  
  1. class WC_REST_Order_Refunds_Controller extends WC_REST_Orders_Controller { 
  2.  
  3. /** 
  4. * Endpoint namespace. 
  5. * @var string 
  6. */ 
  7. protected $namespace = 'wc/v2'; 
  8.  
  9. /** 
  10. * Route base. 
  11. * @var string 
  12. */ 
  13. protected $rest_base = 'orders/(?P<order_id>[\d]+)/refunds'; 
  14.  
  15. /** 
  16. * Post type. 
  17. * @var string 
  18. */ 
  19. protected $post_type = 'shop_order_refund'; 
  20.  
  21. /** 
  22. * Stores the request. 
  23. * @var array 
  24. */ 
  25. protected $request = array(); 
  26.  
  27. /** 
  28. * Order refunds actions. 
  29. */ 
  30. public function __construct() { 
  31. add_filter( "woocommerce_rest_{$this->post_type}_object_trashable", '__return_false' ); 
  32.  
  33. /** 
  34. * Register the routes for order refunds. 
  35. */ 
  36. public function register_routes() { 
  37. register_rest_route( $this->namespace, '/' . $this->rest_base, array( 
  38. 'args' => array( 
  39. 'order_id' => array( 
  40. 'description' => __( 'The order ID.', 'woocommerce' ),  
  41. 'type' => 'integer',  
  42. ),  
  43. ),  
  44. array( 
  45. 'methods' => WP_REST_Server::READABLE,  
  46. 'callback' => array( $this, 'get_items' ),  
  47. 'permission_callback' => array( $this, 'get_items_permissions_check' ),  
  48. 'args' => $this->get_collection_params(),  
  49. ),  
  50. array( 
  51. 'methods' => WP_REST_Server::CREATABLE,  
  52. 'callback' => array( $this, 'create_item' ),  
  53. 'permission_callback' => array( $this, 'create_item_permissions_check' ),  
  54. 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),  
  55. ),  
  56. 'schema' => array( $this, 'get_public_item_schema' ),  
  57. ) ); 
  58.  
  59. register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array( 
  60. 'args' => array( 
  61. 'order_id' => array( 
  62. 'description' => __( 'The order ID.', 'woocommerce' ),  
  63. 'type' => 'integer',  
  64. ),  
  65. 'id' => array( 
  66. 'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),  
  67. 'type' => 'integer',  
  68. ),  
  69. ),  
  70. array( 
  71. 'methods' => WP_REST_Server::READABLE,  
  72. 'callback' => array( $this, 'get_item' ),  
  73. 'permission_callback' => array( $this, 'get_item_permissions_check' ),  
  74. 'args' => array( 
  75. 'context' => $this->get_context_param( array( 'default' => 'view' ) ),  
  76. ),  
  77. ),  
  78. array( 
  79. 'methods' => WP_REST_Server::DELETABLE,  
  80. 'callback' => array( $this, 'delete_item' ),  
  81. 'permission_callback' => array( $this, 'delete_item_permissions_check' ),  
  82. 'args' => array( 
  83. 'force' => array( 
  84. 'default' => true,  
  85. 'type' => 'boolean',  
  86. 'description' => __( 'Required to be true, as resource does not support trashing.', 'woocommerce' ),  
  87. ),  
  88. ),  
  89. ),  
  90. 'schema' => array( $this, 'get_public_item_schema' ),  
  91. ) ); 
  92.  
  93. /** 
  94. * Get object. 
  95. * @since 3.0.0 
  96. * @param int $id Object ID. 
  97. * @return WC_Data 
  98. */ 
  99. protected function get_object( $id ) { 
  100. return wc_get_order( $id ); 
  101.  
  102. /** 
  103. * Get formatted item data. 
  104. * @since 3.0.0 
  105. * @param WC_Data $object WC_Data instance. 
  106. * @return array 
  107. */ 
  108. protected function get_formatted_item_data( $object ) { 
  109. $data = $object->get_data(); 
  110. $format_decimal = array( 'amount' ); 
  111. $format_date = array( 'date_created' ); 
  112. $format_line_items = array( 'line_items' ); 
  113.  
  114. // Format decimal values. 
  115. foreach ( $format_decimal as $key ) { 
  116. $data[ $key ] = wc_format_decimal( $data[ $key ], $this->request['dp'] ); 
  117.  
  118. // Format date values. 
  119. foreach ( $format_date as $key ) { 
  120. $datetime = $data[ $key ]; 
  121. $data[ $key ] = wc_rest_prepare_date_response( $datetime, false ); 
  122. $data[ $key . '_gmt' ] = wc_rest_prepare_date_response( $datetime ); 
  123.  
  124. // Format line items. 
  125. foreach ( $format_line_items as $key ) { 
  126. $data[ $key ] = array_values( array_map( array( $this, 'get_order_item_data' ), $data[ $key ] ) ); 
  127.  
  128. return array( 
  129. 'id' => $object->get_id(),  
  130. 'date_created' => $data['date_created'],  
  131. 'date_created_gmt' => $data['date_created_gmt'],  
  132. 'amount' => $data['amount'],  
  133. 'reason' => $data['reason'],  
  134. 'refunded_by' => $data['refunded_by'],  
  135. 'meta_data' => $data['meta_data'],  
  136. 'line_items' => $data['line_items'],  
  137. ); 
  138.  
  139. /** 
  140. * Prepare a single order output for response. 
  141. * @since 3.0.0 
  142. * @param WC_Data $object Object data. 
  143. * @param WP_REST_Request $request Request object. 
  144. * @return WP_REST_Response 
  145. */ 
  146. public function prepare_object_for_response( $object, $request ) { 
  147. $this->request = $request; 
  148. $order = wc_get_order( (int) $request['order_id'] ); 
  149.  
  150. if ( ! $order ) { 
  151. return new WP_Error( 'woocommerce_rest_invalid_order_id', __( 'Invalid order ID.', 'woocommerce' ), 404 ); 
  152.  
  153. if ( ! $object || $object->get_parent_id() !== $order->get_id() ) { 
  154. return new WP_Error( 'woocommerce_rest_invalid_order_refund_id', __( 'Invalid order refund ID.', 'woocommerce' ), 404 ); 
  155.  
  156. $data = $this->get_formatted_item_data( $object ); 
  157. $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; 
  158. $data = $this->add_additional_fields_to_object( $data, $request ); 
  159. $data = $this->filter_response_by_context( $data, $context ); 
  160.  
  161. // Wrap the data in a response object. 
  162. $response = rest_ensure_response( $data ); 
  163.  
  164. $response->add_links( $this->prepare_links( $object, $request ) ); 
  165.  
  166. /** 
  167. * Filter the data for a response. 
  168. * The dynamic portion of the hook name, $this->post_type,  
  169. * refers to object type being prepared for the response. 
  170. * @param WP_REST_Response $response The response object. 
  171. * @param WC_Data $object Object data. 
  172. * @param WP_REST_Request $request Request object. 
  173. */ 
  174. return apply_filters( "woocommerce_rest_prepare_{$this->post_type}_object", $response, $object, $request ); 
  175.  
  176. /** 
  177. * Prepare links for the request. 
  178. * @param WC_Data $object Object data. 
  179. * @param WP_REST_Request $request Request object. 
  180. * @return array Links for the given post. 
  181. */ 
  182. protected function prepare_links( $object, $request ) { 
  183. $base = str_replace( '(?P<order_id>[\d]+)', $object->get_parent_id(), $this->rest_base ); 
  184. $links = array( 
  185. 'self' => array( 
  186. 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $base, $object->get_id() ) ),  
  187. ),  
  188. 'collection' => array( 
  189. 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $base ) ),  
  190. ),  
  191. 'up' => array( 
  192. 'href' => rest_url( sprintf( '/%s/orders/%d', $this->namespace, $object->get_parent_id() ) ),  
  193. ),  
  194. ); 
  195.  
  196. return $links; 
  197.  
  198. /** 
  199. * Prepare objects query. 
  200. * @since 3.0.0 
  201. * @param WP_REST_Request $request Full details about the request. 
  202. * @return array 
  203. */ 
  204. protected function prepare_objects_query( $request ) { 
  205. $args = parent::prepare_objects_query( $request ); 
  206.  
  207. $args['post_status'] = array_keys( wc_get_order_statuses() ); 
  208. $args['post_parent__in'] = array( absint( $request['order_id'] ) ); 
  209.  
  210. return $args; 
  211.  
  212. /** 
  213. * Prepares one object for create or update operation. 
  214. * @since 3.0.0 
  215. * @param WP_REST_Request $request Request object. 
  216. * @param bool $creating If is creating a new object. 
  217. * @return WP_Error|WC_Data The prepared item, or WP_Error object on failure. 
  218. */ 
  219. protected function prepare_object_for_database( $request, $creating = false ) { 
  220. $order = wc_get_order( (int) $request['order_id'] ); 
  221.  
  222. if ( ! $order ) { 
  223. return new WP_Error( 'woocommerce_rest_invalid_order_id', __( 'Invalid order ID.', 'woocommerce' ), 404 ); 
  224.  
  225. if ( 0 > $request['amount'] ) { 
  226. return new WP_Error( 'woocommerce_rest_invalid_order_refund', __( 'Refund amount must be greater than zero.', 'woocommerce' ), 400 ); 
  227.  
  228. // Create the refund. 
  229. $refund = wc_create_refund( array( 
  230. 'order_id' => $order->get_id(),  
  231. 'amount' => $request['amount'],  
  232. 'reason' => empty( $request['reason'] ) ? null : $request['reason'],  
  233. 'line_items' => $request['line_items'],  
  234. 'refund_payment' => is_bool( $request['api_refund'] ) ? $request['api_refund'] : true,  
  235. 'restock_items' => true,  
  236. ) ); 
  237.  
  238. if ( is_wp_error( $refund ) ) { 
  239. return new WP_Error( 'woocommerce_rest_cannot_create_order_refund', $refund->get_error_message(), 500 ); 
  240.  
  241. if ( ! $refund ) { 
  242. return new WP_Error( 'woocommerce_rest_cannot_create_order_refund', __( 'Cannot create order refund, please try again.', 'woocommerce' ), 500 ); 
  243.  
  244. /** 
  245. * Filters an object before it is inserted via the REST API. 
  246. * The dynamic portion of the hook name, `$this->post_type`,  
  247. * refers to the object type slug. 
  248. * @param WC_Data $coupon Object object. 
  249. * @param WP_REST_Request $request Request object. 
  250. * @param bool $creating If is creating a new object. 
  251. */ 
  252. return apply_filters( "woocommerce_rest_pre_insert_{$this->post_type}_object", $refund, $request, $creating ); 
  253.  
  254. /** 
  255. * Save an object data. 
  256. * @since 3.0.0 
  257. * @param WP_REST_Request $request Full details about the request. 
  258. * @param bool $creating If is creating a new object. 
  259. * @return WC_Data|WP_Error 
  260. */ 
  261. protected function save_object( $request, $creating = false ) { 
  262. try { 
  263. $object = $this->prepare_object_for_database( $request, $creating ); 
  264.  
  265. if ( is_wp_error( $object ) ) { 
  266. return $object; 
  267.  
  268. return $this->get_object( $object->get_id() ); 
  269. } catch ( WC_Data_Exception $e ) { 
  270. return new WP_Error( $e->getErrorCode(), $e->getMessage(), $e->getErrorData() ); 
  271. } catch ( WC_REST_Exception $e ) { 
  272. return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); 
  273.  
  274. /** 
  275. * Get the Order's schema, conforming to JSON Schema. 
  276. * @return array 
  277. */ 
  278. public function get_item_schema() { 
  279. $schema = array( 
  280. '$schema' => 'http://json-schema.org/draft-04/schema#',  
  281. 'title' => $this->post_type,  
  282. 'type' => 'object',  
  283. 'properties' => array( 
  284. 'id' => array( 
  285. 'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),  
  286. 'type' => 'integer',  
  287. 'context' => array( 'view', 'edit' ),  
  288. 'readonly' => true,  
  289. ),  
  290. 'date_created' => array( 
  291. 'description' => __( "The date the order refund was created, in the site's timezone.", 'woocommerce' ),  
  292. 'type' => 'date-time',  
  293. 'context' => array( 'view', 'edit' ),  
  294. 'readonly' => true,  
  295. ),  
  296. 'date_created_gmt' => array( 
  297. 'description' => __( "The date the order refund was created, as GMT.", 'woocommerce' ),  
  298. 'type' => 'date-time',  
  299. 'context' => array( 'view', 'edit' ),  
  300. 'readonly' => true,  
  301. ),  
  302. 'amount' => array( 
  303. 'description' => __( 'Refund amount.', 'woocommerce' ),  
  304. 'type' => 'string',  
  305. 'context' => array( 'view', 'edit' ),  
  306. ),  
  307. 'reason' => array( 
  308. 'description' => __( 'Reason for refund.', 'woocommerce' ),  
  309. 'type' => 'string',  
  310. 'context' => array( 'view', 'edit' ),  
  311. ),  
  312. 'refunded_by' => array( 
  313. 'description' => __( 'User ID of user who created the refund.', 'woocommerce' ),  
  314. 'type' => 'integer',  
  315. 'context' => array( 'view', 'edit' ),  
  316. ),  
  317. 'meta_data' => array( 
  318. 'description' => __( 'Meta data.', 'woocommerce' ),  
  319. 'type' => 'array',  
  320. 'context' => array( 'view', 'edit' ),  
  321. 'items' => array( 
  322. 'type' => 'object',  
  323. 'properties' => array( 
  324. 'id' => array( 
  325. 'description' => __( 'Meta ID.', 'woocommerce' ),  
  326. 'type' => 'integer',  
  327. 'context' => array( 'view', 'edit' ),  
  328. 'readonly' => true,  
  329. ),  
  330. 'key' => array( 
  331. 'description' => __( 'Meta key.', 'woocommerce' ),  
  332. 'type' => 'string',  
  333. 'context' => array( 'view', 'edit' ),  
  334. ),  
  335. 'value' => array( 
  336. 'description' => __( 'Meta value.', 'woocommerce' ),  
  337. 'type' => 'string',  
  338. 'context' => array( 'view', 'edit' ),  
  339. ),  
  340. ),  
  341. ),  
  342. ),  
  343. 'line_items' => array( 
  344. 'description' => __( 'Line items data.', 'woocommerce' ),  
  345. 'type' => 'array',  
  346. 'context' => array( 'view', 'edit' ),  
  347. 'items' => array( 
  348. 'type' => 'object',  
  349. 'properties' => array( 
  350. 'id' => array( 
  351. 'description' => __( 'Item ID.', 'woocommerce' ),  
  352. 'type' => 'integer',  
  353. 'context' => array( 'view', 'edit' ),  
  354. 'readonly' => true,  
  355. ),  
  356. 'name' => array( 
  357. 'description' => __( 'Product name.', 'woocommerce' ),  
  358. 'type' => 'string',  
  359. 'context' => array( 'view', 'edit' ),  
  360. ),  
  361. 'product_id' => array( 
  362. 'description' => __( 'Product ID.', 'woocommerce' ),  
  363. 'type' => 'integer',  
  364. 'context' => array( 'view', 'edit' ),  
  365. ),  
  366. 'variation_id' => array( 
  367. 'description' => __( 'Variation ID, if applicable.', 'woocommerce' ),  
  368. 'type' => 'integer',  
  369. 'context' => array( 'view', 'edit' ),  
  370. ),  
  371. 'quantity' => array( 
  372. 'description' => __( 'Quantity ordered.', 'woocommerce' ),  
  373. 'type' => 'integer',  
  374. 'context' => array( 'view', 'edit' ),  
  375. ),  
  376. 'tax_class' => array( 
  377. 'description' => __( 'Tax class of product.', 'woocommerce' ),  
  378. 'type' => 'integer',  
  379. 'context' => array( 'view', 'edit' ),  
  380. ),  
  381. 'subtotal' => array( 
  382. 'description' => __( 'Line subtotal (before discounts).', 'woocommerce' ),  
  383. 'type' => 'string',  
  384. 'context' => array( 'view', 'edit' ),  
  385. ),  
  386. 'subtotal_tax' => array( 
  387. 'description' => __( 'Line subtotal tax (before discounts).', 'woocommerce' ),  
  388. 'type' => 'string',  
  389. 'context' => array( 'view', 'edit' ),  
  390. 'readonly' => true,  
  391. ),  
  392. 'total' => array( 
  393. 'description' => __( 'Line total (after discounts).', 'woocommerce' ),  
  394. 'type' => 'string',  
  395. 'context' => array( 'view', 'edit' ),  
  396. ),  
  397. 'total_tax' => array( 
  398. 'description' => __( 'Line total tax (after discounts).', 'woocommerce' ),  
  399. 'type' => 'string',  
  400. 'context' => array( 'view', 'edit' ),  
  401. 'readonly' => true,  
  402. ),  
  403. 'taxes' => array( 
  404. 'description' => __( 'Line taxes.', 'woocommerce' ),  
  405. 'type' => 'array',  
  406. 'context' => array( 'view', 'edit' ),  
  407. 'readonly' => true,  
  408. 'items' => array( 
  409. 'type' => 'object',  
  410. 'properties' => array( 
  411. 'id' => array( 
  412. 'description' => __( 'Tax rate ID.', 'woocommerce' ),  
  413. 'type' => 'integer',  
  414. 'context' => array( 'view', 'edit' ),  
  415. ),  
  416. 'total' => array( 
  417. 'description' => __( 'Tax total.', 'woocommerce' ),  
  418. 'type' => 'string',  
  419. 'context' => array( 'view', 'edit' ),  
  420. ),  
  421. 'subtotal' => array( 
  422. 'description' => __( 'Tax subtotal.', 'woocommerce' ),  
  423. 'type' => 'string',  
  424. 'context' => array( 'view', 'edit' ),  
  425. ),  
  426. ),  
  427. ),  
  428. ),  
  429. 'meta_data' => array( 
  430. 'description' => __( 'Meta data.', 'woocommerce' ),  
  431. 'type' => 'array',  
  432. 'context' => array( 'view', 'edit' ),  
  433. 'items' => array( 
  434. 'type' => 'object',  
  435. 'properties' => array( 
  436. 'id' => array( 
  437. 'description' => __( 'Meta ID.', 'woocommerce' ),  
  438. 'type' => 'integer',  
  439. 'context' => array( 'view', 'edit' ),  
  440. 'readonly' => true,  
  441. ),  
  442. 'key' => array( 
  443. 'description' => __( 'Meta key.', 'woocommerce' ),  
  444. 'type' => 'string',  
  445. 'context' => array( 'view', 'edit' ),  
  446. ),  
  447. 'value' => array( 
  448. 'description' => __( 'Meta value.', 'woocommerce' ),  
  449. 'type' => 'string',  
  450. 'context' => array( 'view', 'edit' ),  
  451. ),  
  452. ),  
  453. ),  
  454. ),  
  455. 'sku' => array( 
  456. 'description' => __( 'Product SKU.', 'woocommerce' ),  
  457. 'type' => 'string',  
  458. 'context' => array( 'view', 'edit' ),  
  459. 'readonly' => true,  
  460. ),  
  461. 'price' => array( 
  462. 'description' => __( 'Product price.', 'woocommerce' ),  
  463. 'type' => 'string',  
  464. 'context' => array( 'view', 'edit' ),  
  465. 'readonly' => true,  
  466. ),  
  467. ),  
  468. ),  
  469. ),  
  470. 'api_refund' => array( 
  471. 'description' => __( 'When true, the payment gateway API is used to generate the refund.', 'woocommerce' ),  
  472. 'type' => 'boolean',  
  473. 'context' => array( 'edit' ),  
  474. 'default' => true,  
  475. ),  
  476. ),  
  477. ); 
  478.  
  479. return $this->add_additional_fields_schema( $schema ); 
  480.  
  481. /** 
  482. * Get the query params for collections. 
  483. * @return array 
  484. */ 
  485. public function get_collection_params() { 
  486. $params = parent::get_collection_params(); 
  487.  
  488. unset( $params['status'], $params['customer'], $params['product'] ); 
  489.  
  490. return $params;