WC_REST_Orders_Controller::update_item()   B
last analyzed

Complexity

Conditions 5
Paths 3

Size

Total Lines 32
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
dl 0
loc 32
rs 8.439
c 0
b 0
f 0
eloc 15
nc 3
nop 1
1
<?php
2
/**
3
 * REST API Orders controller
4
 *
5
 * Handles requests to the /orders endpoint.
6
 *
7
 * @author   WooThemes
8
 * @category API
9
 * @package  WooCommerce/API
10
 * @since    2.6.0
11
 */
12
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit;
15
}
16
17
/**
18
 * REST API Orders controller class.
19
 *
20
 * @package WooCommerce/API
21
 * @extends WC_REST_Posts_Controller
22
 */
23
class WC_REST_Orders_Controller extends WC_REST_Posts_Controller {
24
25
	/**
26
	 * Endpoint namespace.
27
	 *
28
	 * @var string
29
	 */
30
	protected $namespace = 'wc/v1';
31
32
	/**
33
	 * Route base.
34
	 *
35
	 * @var string
36
	 */
37
	protected $rest_base = 'orders';
38
39
	/**
40
	 * Post type.
41
	 *
42
	 * @var string
43
	 */
44
	protected $post_type = 'shop_order';
45
46
	/**
47
	 * Initialize orders actions.
48
	 */
49
	public function __construct() {
50
		add_filter( "woocommerce_rest_{$this->post_type}_query", array( $this, 'query_args' ), 10, 2 );
51
	}
52
53
	/**
54
	 * Register the routes for orders.
55
	 */
56 View Code Duplication
	public function register_routes() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
57
		register_rest_route( $this->namespace, '/' . $this->rest_base, array(
58
			array(
59
				'methods'             => WP_REST_Server::READABLE,
60
				'callback'            => array( $this, 'get_items' ),
61
				'permission_callback' => array( $this, 'get_items_permissions_check' ),
62
				'args'                => $this->get_collection_params(),
63
			),
64
			array(
65
				'methods'             => WP_REST_Server::CREATABLE,
66
				'callback'            => array( $this, 'create_item' ),
67
				'permission_callback' => array( $this, 'create_item_permissions_check' ),
68
				'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
69
			),
70
			'schema' => array( $this, 'get_public_item_schema' ),
71
		) );
72
73
		register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array(
74
			array(
75
				'methods'             => WP_REST_Server::READABLE,
76
				'callback'            => array( $this, 'get_item' ),
77
				'permission_callback' => array( $this, 'get_item_permissions_check' ),
78
				'args'                => array(
79
					'context' => $this->get_context_param( array( 'default' => 'view' ) ),
80
				),
81
			),
82
			array(
83
				'methods'             => WP_REST_Server::EDITABLE,
84
				'callback'            => array( $this, 'update_item' ),
85
				'permission_callback' => array( $this, 'update_item_permissions_check' ),
86
				'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
87
			),
88
			array(
89
				'methods'             => WP_REST_Server::DELETABLE,
90
				'callback'            => array( $this, 'delete_item' ),
91
				'permission_callback' => array( $this, 'delete_item_permissions_check' ),
92
				'args'                => array(
93
					'force' => array(
94
						'default'     => false,
95
						'description' => __( 'Whether to bypass trash and force deletion.', 'woocommerce' ),
96
					),
97
					'reassign' => array(),
98
				),
99
			),
100
			'schema' => array( $this, 'get_public_item_schema' ),
101
		) );
102
103
		register_rest_route( $this->namespace, '/' . $this->rest_base . '/batch', array(
104
			array(
105
				'methods'             => WP_REST_Server::EDITABLE,
106
				'callback'            => array( $this, 'batch_items' ),
107
				'permission_callback' => array( $this, 'batch_items_permissions_check' ),
108
				'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
109
			),
110
			'schema' => array( $this, 'get_public_batch_schema' ),
111
		) );
112
	}
113
114
	/**
115
	 * Prepare a single order output for response.
116
	 *
117
	 * @param WP_Post $post Post object.
118
	 * @param WP_REST_Request $request Request object.
119
	 * @return WP_REST_Response $data
120
	 */
121
	public function prepare_item_for_response( $post, $request ) {
122
		global $wpdb;
123
124
		$order = wc_get_order( $post );
125
		$dp    = $request['dp'];
126
127
		$data = array(
128
			'id'                   => $order->id,
129
			'parent_id'            => $post->post_parent,
130
			'status'               => $order->get_status(),
131
			'order_key'            => $order->order_key,
132
			'currency'             => $order->get_order_currency(),
133
			'version'              => $order->order_version,
134
			'prices_include_tax'   => $order->prices_include_tax,
135
			'date_created'         => wc_rest_prepare_date_response( $post->post_date_gmt ),
136
			'date_modified'        => wc_rest_prepare_date_response( $post->post_modified_gmt ),
137
			'customer_id'          => $order->get_user_id(),
138
			'discount_total'       => wc_format_decimal( $order->get_total_discount(), $dp ),
139
			'discount_tax'         => wc_format_decimal( $order->cart_discount_tax, $dp ),
140
			'shipping_total'       => wc_format_decimal( $order->get_total_shipping(), $dp ),
141
			'shipping_tax'         => wc_format_decimal( $order->get_shipping_tax(), $dp ),
142
			'cart_tax'             => wc_format_decimal( $order->get_cart_tax(), $dp ),
143
			'total'                => wc_format_decimal( $order->get_total(), $dp ),
144
			'total_tax'            => wc_format_decimal( $order->get_total_tax(), $dp ),
145
			'billing'              => array(),
146
			'shipping'             => array(),
147
			'payment_method'       => $order->payment_method,
148
			'payment_method_title' => $order->payment_method_title,
149
			'transaction_id'       => $order->get_transaction_id(),
150
			'customer_ip_address'  => $order->customer_ip_address,
151
			'customer_user_agent'  => $order->customer_user_agent,
152
			'created_via'          => $order->created_via,
153
			'customer_note'        => $order->customer_note,
154
			'date_completed'       => wc_rest_prepare_date_response( $order->completed_date ),
155
			'date_paid'            => $order->paid_date,
156
			'cart_hash'            => $order->cart_hash,
157
			'line_items'           => array(),
158
			'tax_lines'            => array(),
159
			'shipping_lines'       => array(),
160
			'fee_lines'            => array(),
161
			'coupon_lines'         => array(),
162
			'refunds'              => array(),
163
		);
164
165
		// Add addresses.
166
		$data['billing']  = $order->get_address( 'billing' );
167
		$data['shipping'] = $order->get_address( 'shipping' );
168
169
		// Add line items.
170 View Code Duplication
		foreach ( $order->get_items() as $item_id => $item ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
171
			$product      = $order->get_product_from_item( $item );
172
			$product_id   = 0;
173
			$variation_id = 0;
174
			$product_sku  = null;
175
176
			// Check if the product exists.
177
			if ( is_object( $product ) ) {
178
				$product_id   = $product->id;
179
				$variation_id = $product->variation_id;
180
				$product_sku  = $product->get_sku();
181
			}
182
183
			$meta = new WC_Order_Item_Meta( $item, $product );
184
185
			$item_meta = array();
186
187
			$hideprefix = 'true' === $request['all_item_meta'] ? null : '_';
188
189
			foreach ( $meta->get_formatted( $hideprefix ) as $meta_key => $formatted_meta ) {
190
				$item_meta[] = array(
191
					'key'   => $formatted_meta['key'],
192
					'label' => $formatted_meta['label'],
193
					'value' => $formatted_meta['value'],
194
				);
195
			}
196
197
			$line_item = array(
198
				'id'           => $item_id,
199
				'name'         => $item['name'],
200
				'sku'          => $product_sku,
201
				'product_id'   => (int) $product_id,
202
				'variation_id' => (int) $variation_id,
203
				'quantity'     => wc_stock_amount( $item['qty'] ),
204
				'tax_class'    => ! empty( $item['tax_class'] ) ? $item['tax_class'] : '',
205
				'price'        => wc_format_decimal( $order->get_item_total( $item, false, false ), $dp ),
206
				'subtotal'     => wc_format_decimal( $order->get_line_subtotal( $item, false, false ), $dp ),
207
				'subtotal_tax' => wc_format_decimal( $item['line_subtotal_tax'], $dp ),
208
				'total'        => wc_format_decimal( $order->get_line_total( $item, false, false ), $dp ),
209
				'total_tax'    => wc_format_decimal( $item['line_tax'], $dp ),
210
				'taxes'        => array(),
211
				'meta'         => $item_meta,
212
			);
213
214
			$item_line_taxes = maybe_unserialize( $item['line_tax_data'] );
215
			if ( isset( $item_line_taxes['total'] ) ) {
216
				$line_tax = array();
217
218
				foreach ( $item_line_taxes['total'] as $tax_rate_id => $tax ) {
219
					$line_tax[ $tax_rate_id ] = array(
220
						'id'       => $tax_rate_id,
221
						'total'    => $tax,
222
						'subtotal' => '',
223
					);
224
				}
225
226
				foreach ( $item_line_taxes['subtotal'] as $tax_rate_id => $tax ) {
227
					$line_tax[ $tax_rate_id ]['subtotal'] = $tax;
228
				}
229
230
				$line_item['taxes'] = array_values( $line_tax );
231
			}
232
233
			$data['line_items'][] = $line_item;
234
		}
235
236
		// Add taxes.
237
		foreach ( $order->get_items( 'tax' ) as $key => $tax ) {
238
			$tax_line = array(
239
				'id'                 => $key,
240
				'rate_code'          => $tax['name'],
241
				'rate_id'            => $tax['rate_id'],
242
				'label'              => isset( $tax['label'] ) ? $tax['label'] : $tax['name'],
243
				'compound'           => (bool) $tax['compound'],
244
				'tax_total'          => wc_format_decimal( $tax['tax_amount'], $dp ),
245
				'shipping_tax_total' => wc_format_decimal( $tax['shipping_tax_amount'], $dp ),
246
			);
247
248
			$data['tax_lines'][] = $tax_line;
249
		}
250
251
		// Add shipping.
252
		foreach ( $order->get_shipping_methods() as $shipping_item_id => $shipping_item ) {
253
			$shipping_line = array(
254
				'id'           => $shipping_item_id,
255
				'method_title' => $shipping_item['name'],
256
				'method_id'    => $shipping_item['method_id'],
257
				'total'        => wc_format_decimal( $shipping_item['cost'], $dp ),
258
				'total_tax'    => wc_format_decimal( '', $dp ),
259
				'taxes'        => array(),
260
			);
261
262
			$shipping_taxes = maybe_unserialize( $shipping_item['taxes'] );
263
264
			if ( ! empty( $shipping_taxes ) ) {
265
				$shipping_line['total_tax'] = wc_format_decimal( array_sum( $shipping_taxes ), $dp );
266
267
				foreach ( $shipping_taxes as $tax_rate_id => $tax ) {
268
					$shipping_line['taxes'][] = array(
269
						'id'       => $tax_rate_id,
270
						'total'    => $tax,
271
					);
272
				}
273
			}
274
275
			$data['shipping_lines'][] = $shipping_line;
276
		}
277
278
		// Add fees.
279
		foreach ( $order->get_fees() as $fee_item_id => $fee_item ) {
280
			$fee_line = array(
281
				'id'         => $fee_item_id,
282
				'name'       => $fee_item['name'],
283
				'tax_class'  => ! empty( $fee_item['tax_class'] ) ? $fee_item['tax_class'] : '',
284
				'tax_status' => 'taxable',
285
				'total'      => wc_format_decimal( $order->get_line_total( $fee_item ), $dp ),
286
				'total_tax'  => wc_format_decimal( $order->get_line_tax( $fee_item ), $dp ),
287
				'taxes'      => array(),
288
			);
289
290
			$fee_line_taxes = maybe_unserialize( $fee_item['line_tax_data'] );
291
			if ( isset( $fee_line_taxes['total'] ) ) {
292
				$fee_tax = array();
293
294
				foreach ( $fee_line_taxes['total'] as $tax_rate_id => $tax ) {
295
					$fee_tax[ $tax_rate_id ] = array(
296
						'id'       => $tax_rate_id,
297
						'total'    => $tax,
298
						'subtotal' => '',
299
					);
300
				}
301
302
				foreach ( $fee_line_taxes['subtotal'] as $tax_rate_id => $tax ) {
303
					$fee_tax[ $tax_rate_id ]['subtotal'] = $tax;
304
				}
305
306
				$fee_line['taxes'] = array_values( $fee_tax );
307
			}
308
309
			$data['fee_lines'][] = $fee_line;
310
		}
311
312
		// Add coupons.
313
		foreach ( $order->get_items( 'coupon' ) as $coupon_item_id => $coupon_item ) {
314
			$coupon_line = array(
315
				'id'           => $coupon_item_id,
316
				'code'         => $coupon_item['name'],
317
				'discount'     => wc_format_decimal( $coupon_item['discount_amount'], $dp ),
318
				'discount_tax' => wc_format_decimal( $coupon_item['discount_amount_tax'], $dp ),
319
			);
320
321
			$data['coupon_lines'][] = $coupon_line;
322
		}
323
324
		// Add refunds.
325
		foreach ( $order->get_refunds() as $refund ) {
326
			$data['refunds'][] = array(
327
				'id'     => $refund->id,
328
				'refund' => $refund->get_refund_reason() ? $refund->get_refund_reason() : '',
329
				'total'  => '-' . wc_format_decimal( $refund->get_refund_amount(), $dp ),
330
			);
331
		}
332
333
		$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
334
		$data    = $this->add_additional_fields_to_object( $data, $request );
335
		$data    = $this->filter_response_by_context( $data, $context );
336
337
		// Wrap the data in a response object.
338
		$response = rest_ensure_response( $data );
339
340
		$response->add_links( $this->prepare_links( $order ) );
0 ignored issues
show
Documentation introduced by
$order is of type false|object, but the function expects a object<WC_Order>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
341
342
		/**
343
		 * Filter the data for a response.
344
		 *
345
		 * The dynamic portion of the hook name, $this->post_type, refers to post_type of the post being
346
		 * prepared for the response.
347
		 *
348
		 * @param WP_REST_Response   $response   The response object.
349
		 * @param WP_Post            $post       Post object.
350
		 * @param WP_REST_Request    $request    Request object.
351
		 */
352
		return apply_filters( "woocommerce_rest_prepare_{$this->post_type}", $response, $post, $request );
353
	}
354
355
	/**
356
	 * Prepare links for the request.
357
	 *
358
	 * @param WC_Order $order Order object.
359
	 * @return array Links for the given order.
360
	 */
361
	protected function prepare_links( $order ) {
362
		$links = array(
363
			'self' => array(
364
				'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $order->id ) ),
365
			),
366
			'collection' => array(
367
				'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),
368
			),
369
		);
370
371
		if ( 0 !== (int) $order->get_user_id() ) {
372
			$links['customer'] = array(
373
				'href' => rest_url( sprintf( '/%s/customers/%d', $this->namespace, $order->get_user_id() ) ),
374
			);
375
		}
376
377 View Code Duplication
		if ( 0 !== (int) $order->post->post_parent ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
378
			$links['up'] = array(
379
				'href' => rest_url( sprintf( '/%s/orders/%d', $this->namespace, $order->post->post_parent ) ),
380
			);
381
		}
382
383
		return $links;
384
	}
385
386
	/**
387
	 * Query args.
388
	 *
389
	 * @param array $args
390
	 * @param WP_REST_Request $request
391
	 * @return array
392
	 */
393
	public function query_args( $args, $request ) {
394
		global $wpdb;
395
396
		// Set post_status.
397
		if ( 'any' !== $request['status'] ) {
398
			$args['post_status'] = 'wc-' . $request['status'];
399
		} else {
400
			$args['post_status'] = 'any';
401
		}
402
403 View Code Duplication
		if ( ! empty( $request['customer'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
404
			if ( ! empty( $args['meta_query'] ) ) {
405
				$args['meta_query'] = array();
406
			}
407
408
			$args['meta_query'][] = array(
409
				'key'   => '_customer_user',
410
				'value' => $request['customer'],
411
				'type'  => 'NUMERIC',
412
			);
413
		}
414
415
		if ( ! empty( $request['product'] ) ) {
416
			$order_ids = $wpdb->get_col( $wpdb->prepare( "
417
				SELECT order_id
418
				FROM {$wpdb->prefix}woocommerce_order_items
419
				WHERE order_item_id IN ( SELECT order_item_id FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE meta_key = '_product_id' AND meta_value = %d )
420
				AND order_item_type = 'line_item'
421
			 ", $request['product'] ) );
422
423
			// Force WP_Query return empty if don't found any order.
424
			$order_ids = ! empty( $order_ids ) ? $order_ids : array( 0 );
425
426
			$args['post__in'] = $order_ids;
427
		}
428
429
		return $args;
430
	}
431
432
	/**
433
	 * Create order.
434
	 *
435
	 * @param WP_REST_Request $request Full details about the request.
436
	 * @return int|WP_Error
437
	 */
438
	protected function create_order( $request ) {
439
		wc_transaction_query( 'start' );
440
441
		try {
442
			// Make sure customer exists.
443
			if ( 0 !== $request['customer_id'] && false === get_user_by( 'id', $request['customer_id'] ) ) {
444
				throw new WC_REST_Exception( 'woocommerce_rest_invalid_customer_id',__( 'Customer ID is invalid.', 'woocommerce' ), 400 );
445
			}
446
447
			$order = $this->create_base_order( array(
448
				'status'        => $request['status'],
449
				'customer_id'   => $request['customer_id'],
450
				'customer_note' => $request['customer_note'],
451
				'created_via'   => 'rest-api',
452
			), $request );
453
454 View Code Duplication
			if ( is_wp_error( $order ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
455
				throw new WC_REST_Exception( 'woocommerce_rest_cannot_create_order', sprintf( __( 'Cannot create order: %s.', 'woocommerce' ), implode( ', ', $order->get_error_messages() ) ), 400 );
456
			}
457
458
			// Set addresses.
459
			if ( is_array( $request['billing'] ) ) {
460
				$this->update_address( $order, $request['billing'], 'billing' );
461
			}
462
			if ( is_array( $request['shipping'] ) ) {
463
				$this->update_address( $order, $request['shipping'], 'shipping' );
464
			}
465
466
			// Set currency.
467
			update_post_meta( $order->id, '_order_currency', $request['currency'] );
468
469
			// Set lines.
470
			$lines = array(
471
				'line_item' => 'line_items',
472
				'shipping'  => 'shipping_lines',
473
				'fee'       => 'fee_lines',
474
				'coupon'    => 'coupon_lines',
475
			);
476
477 View Code Duplication
			foreach ( $lines as $line_type => $line ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
478
				if ( is_array( $request[ $line ] ) ) {
479
					foreach ( $request[ $line ] as $item ) {
480
						$set_item = 'set_' . $line_type;
481
						$this->$set_item( $order, $item, 'create' );
482
					}
483
				}
484
			}
485
486
			// Calculate totals and set them.
487
			$order->calculate_totals();
488
489
			// Set payment method.
490
			if ( ! empty( $request['payment_method'] ) ) {
491
				update_post_meta( $order->id, '_payment_method', $request['payment_method'] );
492
			}
493
			if ( ! empty( $request['payment_method_title'] ) ) {
494
				update_post_meta( $order->id, '_payment_method_title', $request['payment_method'] );
495
			}
496
			if ( true === $request['set_paid'] ) {
497
				$order->payment_complete( $request['transaction_id'] );
498
			}
499
500
			// Set meta data.
501 View Code Duplication
			if ( ! empty( $request['meta_data'] ) && is_array( $request['meta_data'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
502
				$this->update_meta_data( $order->id, $request['meta_data'] );
503
			}
504
505
			wc_transaction_query( 'commit' );
506
507
			return $order->id;
508
		} catch ( WC_REST_Exception $e ) {
509
			wc_transaction_query( 'rollback' );
510
511
			return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
512
		}
513
	}
514
515
	/**
516
	 * Update address.
517
	 *
518
	 * @param WC_Order $order
519
	 * @param array $posted
520
	 * @param string $type
521
	 */
522
	protected function update_address( $order, $posted, $type = 'billing' ) {
523
		$fields = $order->get_address( $type );
524
525
		foreach ( array_keys( $fields ) as $field ) {
526
			if ( isset( $posted[ $field ] ) ) {
527
				$fields[ $field ] = $posted[ $field ];
528
			}
529
		}
530
531
		// Set address.
532
		$order->set_address( $fields, $type );
533
534
		// Update user meta.
535
		if ( $order->get_user_id() ) {
536
			foreach ( $fields as $key => $value ) {
537
				update_user_meta( $order->get_user_id(), $type . '_' . $key, $value );
538
			}
539
		}
540
	}
541
542
	/**
543
	 * Create or update a line item.
544
	 *
545
	 * @param WC_Order $order Order data.
546
	 * @param array $item Line item data.
547
	 * @param string $action 'create' to add line item or 'update' to update it.
548
	 * @throws WC_REST_Exception Invalid data, server error.
549
	 */
550
	protected function set_line_item( $order, $item, $action = 'create' ) {
551
		$creating  = 'create' === $action;
552
		$item_args = array();
553
554
		// Product is always required.
555
		if ( empty( $item['product_id'] ) && empty( $item['sku'] ) && empty( $item['variation_id'] ) ) {
556
			throw new WC_REST_Exception( 'woocommerce_rest_required_product_reference', __( 'Product ID or SKU is required.', 'woocommerce' ), 400 );
557
		}
558
559
		if ( ! empty( $item['sku'] ) ) {
560
			$product_id = (int) wc_get_product_id_by_sku( $item['sku'] );
561
		} elseif ( ! empty( $item['product_id'] ) && empty( $item['variation_id'] ) ) {
562
			$product_id = (int) $item['product_id'];
563
		} elseif ( ! empty( $item['variation_id'] ) ) {
564
			$product_id = (int) $item['variation_id'];
565
		}
566
567
		// When updating, ensure product ID provided matches.
568
		if ( 'update' === $action && ! empty( $item['id'] ) ) {
569
			$item_product_id   = (int) wc_get_order_item_meta( $item['id'], '_product_id' );
570
			$item_variation_id = (int) wc_get_order_item_meta( $item['id'], '_variation_id' );
571
572
			if ( $product_id !== $item_product_id && $product_id !== $item_variation_id ) {
573
				throw new WC_REST_Exception( 'woocommerce_rest_required_product_reference', __( 'Product ID or variation ID provided does not match this line item.', 'woocommerce' ), 400 );
574
			}
575
		}
576
577
		$product = wc_get_product( $product_id );
578
579
		// Must be a valid WC_Product.
580
		if ( ! is_object( $product ) ) {
581
			throw new WC_REST_Exception( 'woocommerce_rest_invalid_product', __( 'Product is invalid.', 'woocommerce' ), 400 );
582
		}
583
584
		// Quantity must be positive float.
585 View Code Duplication
		if ( isset( $item['quantity'] ) && 0 >= floatval( $item['quantity'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
586
			throw new WC_REST_Exception( 'woocommerce_rest_invalid_product_quantity', __( 'Product quantity must be a positive float.', 'woocommerce' ), 400 );
587
		}
588
589
		// Quantity is required when creating.
590 View Code Duplication
		if ( $creating && ! isset( $item['quantity'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
591
			throw new WC_REST_Exception( 'woocommerce_rest_invalid_product_quantity', __( 'Product quantity is required.', 'woocommerce' ), 400 );
592
		}
593
594
		// Get variation attributes.
595
		if ( method_exists( $product, 'get_variation_attributes' ) ) {
596
			$item_args['variation'] = $product->get_variation_attributes();
597
		}
598
599
		// Quantity.
600
		if ( isset( $item['quantity'] ) ) {
601
			$item_args['qty'] = $item['quantity'];
602
		}
603
604
		// Total.
605
		if ( isset( $item['total'] ) ) {
606
			$item_args['totals']['total'] = floatval( $item['total'] );
607
		}
608
609
		// Total tax.
610
		if ( isset( $item['total_tax'] ) ) {
611
			$item_args['totals']['tax'] = floatval( $item['total_tax'] );
612
		}
613
614
		// Subtotal.
615
		if ( isset( $item['subtotal'] ) ) {
616
			$item_args['totals']['subtotal'] = floatval( $item['subtotal'] );
617
		}
618
619
		// Subtotal tax.
620
		if ( isset( $item['subtotal_tax'] ) ) {
621
			$item_args['totals']['subtotal_tax'] = floatval( $item['subtotal_tax'] );
622
		}
623
624 View Code Duplication
		if ( $creating ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
625
			$item_id = $order->add_product( $product, $item_args['qty'], $item_args );
626
			if ( ! $item_id ) {
627
				throw new WC_REST_Exception( 'woocommerce_rest_cannot_create_line_item', __( 'Cannot create line item, try again.', 'woocommerce' ), 500 );
628
			}
629
		} else {
630
			$item_id = $order->update_product( $item['id'], $product, $item_args );
631
			if ( ! $item_id ) {
632
				throw new WC_REST_Exception( 'woocommerce_rest_cannot_update_line_item', __( 'Cannot update line item, try again.', 'woocommerce' ), 500 );
633
			}
634
		}
635
	}
636
637
	/**
638
	 * Create or update an order shipping method.
639
	 *
640
	 * @param WC_Order $order Order data.
641
	 * @param array $shipping Item data.
642
	 * @param string $action 'create' to add shipping or 'update' to update it.
643
	 * @throws WC_REST_Exception Invalid data, server error.
644
	 */
645
	protected function set_shipping( $order, $shipping, $action ) {
646
		// Total must be a positive float.
647
		if ( ! empty( $shipping['total'] ) && 0 > floatval( $shipping['total'] ) ) {
648
			throw new WC_REST_Exception( 'woocommerce_rest_invalid_shipping_total', __( 'Shipping total must be a positive amount.', 'woocommerce' ), 400 );
649
		}
650
651
		if ( 'create' === $action ) {
652
			// Method ID is required.
653
			if ( empty( $shipping['method_id'] ) ) {
654
				throw new WC_REST_Exception( 'woocommerce_rest_invalid_shipping_item', __( 'Shipping method ID is required.', 'woocommerce' ), 400 );
655
			}
656
657
			$rate = new WC_Shipping_Rate( $shipping['method_id'], isset( $shipping['method_title'] ) ? $shipping['method_title'] : '', isset( $shipping['total'] ) ? floatval( $shipping['total'] ) : 0, array(), $shipping['method_id'] );
658
659
			$shipping_id = $order->add_shipping( $rate );
660
661
			if ( ! $shipping_id ) {
662
				throw new WC_REST_Exception( 'woocommerce_rest_cannot_create_shipping', __( 'Cannot create shipping method, try again.', 'woocommerce' ), 500 );
663
			}
664
665 View Code Duplication
		} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
666
			$shipping_args = array();
667
668
			if ( isset( $shipping['method_id'] ) ) {
669
				$shipping_args['method_id'] = $shipping['method_id'];
670
			}
671
672
			if ( isset( $shipping['method_title'] ) ) {
673
				$shipping_args['method_title'] = $shipping['method_title'];
674
			}
675
676
			if ( isset( $shipping['total'] ) ) {
677
				$shipping_args['cost'] = floatval( $shipping['total'] );
678
			}
679
680
			$shipping_id = $order->update_shipping( $shipping['id'], $shipping_args );
681
682
			if ( ! $shipping_id ) {
683
				throw new WC_REST_Exception( 'woocommerce_rest_cannot_update_shipping', __( 'Cannot update shipping method, try again.', 'woocommerce' ), 500 );
684
			}
685
		}
686
	}
687
688
	/**
689
	 * Create or update an order fee.
690
	 *
691
	 * @param WC_Order $order Order data.
692
	 * @param array $fee Item data.
693
	 * @param string $action 'create' to add fee or 'update' to update it.
694
	 * @throws WC_REST_Exception Invalid data, server error.
695
	 */
696
	protected function set_fee( $order, $fee, $action ) {
697
		if ( 'create' === $action ) {
698
699
			// Fee name is required.
700
			if ( empty( $fee['name'] ) ) {
701
				throw new WC_REST_Exception( 'woocommerce_rest_invalid_fee_item', __( 'Fee name is required.', 'woocommerce' ), 400 );
702
			}
703
704
			$fee_data            = new stdClass();
705
			$fee_data->id        = sanitize_title( $fee['name'] );
706
			$fee_data->name      = $fee['name'];
707
			$fee_data->amount    = isset( $fee['total'] ) ? floatval( $fee['total'] ) : 0;
708
			$fee_data->taxable   = false;
709
			$fee_data->tax       = 0;
710
			$fee_data->tax_data  = array();
711
			$fee_data->tax_class = '';
712
713
			// If taxable, tax class and total are required.
714
			if ( isset( $fee['tax_status'] ) && 'taxable' === $fee['tax_status'] ) {
715
716
				if ( ! isset( $fee['tax_class'] ) ) {
717
					throw new WC_REST_Exception( 'woocommerce_rest_invalid_fee_item', __( 'Fee tax class is required when fee is taxable.', 'woocommerce' ), 400 );
718
				}
719
720
				$fee_data->taxable   = true;
721
				$fee_data->tax_class = $fee['tax_class'];
722
723
				if ( isset( $fee['total_tax'] ) ) {
724
					$fee_data->tax = isset( $fee['total_tax'] ) ? wc_format_refund_total( $fee['total_tax'] ) : 0;
725
				}
726
			}
727
728
			$fee_id = $order->add_fee( $fee_data );
729
730
			if ( ! $fee_id ) {
731
				throw new WC_REST_Exception( 'woocommerce_rest_cannot_create_fee', __( 'Cannot create fee, try again.', 'woocommerce' ), 500 );
732
			}
733
734
		} else {
735
			$fee_args = array();
736
737
			if ( isset( $fee['name'] ) ) {
738
				$fee_args['name'] = $fee['name'];
739
			}
740
741
			if ( isset( $fee['tax_class'] ) ) {
742
				$fee_args['tax_class'] = $fee['tax_class'];
743
			}
744
745
			if ( isset( $fee['total'] ) ) {
746
				$fee_args['line_total'] = floatval( $fee['total'] );
747
			}
748
749
			if ( isset( $fee['total_tax'] ) ) {
750
				$fee_args['line_tax'] = floatval( $fee['total_tax'] );
751
			}
752
753
			$fee_id = $order->update_fee( $fee['id'], $fee_args );
754
755
			if ( ! $fee_id ) {
756
				throw new WC_REST_Exception( 'woocommerce_rest_cannot_update_fee', __( 'Cannot update fee, try again.', 'woocommerce' ), 500 );
757
			}
758
		}
759
	}
760
761
	/**
762
	 * Create or update an order coupon.
763
	 *
764
	 * @param WC_Order $order Order data.
765
	 * @param array $coupon Item data.
766
	 * @param string $action 'create' to add coupon or 'update' to update it.
767
	 * @throws WC_REST_Exception Invalid data, server error.
768
	 */
769
	protected function set_coupon( $order, $coupon, $action ) {
770
		// Coupon discount must be positive float.
771 View Code Duplication
		if ( isset( $coupon['discount'] ) && 0 > floatval( $coupon['discount'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
772
			throw new WC_REST_Exception( 'woocommerce_rest_invalid_coupon_total', __( 'Coupon discount must be a positive amount.', 'woocommerce' ), 400 );
773
		}
774
775 View Code Duplication
		if ( 'create' === $action ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
776
			// Coupon code is required.
777
			if ( empty( $coupon['code'] ) ) {
778
				throw new WC_REST_Exception( 'woocommerce_rest_invalid_coupon_coupon', __( 'Coupon code is required.', 'woocommerce' ), 400 );
779
			}
780
781
			$coupon_id = $order->add_coupon( $coupon['code'], floatval( $coupon['discount'] ) );
782
783
			if ( ! $coupon_id ) {
784
				throw new WC_REST_Exception( 'woocommerce_rest_cannot_create_order_coupon', __( 'Cannot create coupon, try again.', 'woocommerce' ), 500 );
785
			}
786
787
		} else {
788
			$coupon_args = array();
789
790
			if ( isset( $coupon['code'] ) ) {
791
				$coupon_args['code'] = $coupon['code'];
792
			}
793
794
			if ( isset( $coupon['discount'] ) ) {
795
				$coupon_args['discount_amount'] = floatval( $coupon['discount'] );
796
			}
797
798
			$coupon_id = $order->update_coupon( $coupon['id'], $coupon_args );
799
800
			if ( ! $coupon_id ) {
801
				throw new WC_REST_Exception( 'woocommerce_rest_cannot_update_order_coupon', __( 'Cannot update coupon, try again.', 'woocommerce' ), 500 );
802
			}
803
		}
804
	}
805
806
	/**
807
	 * Helper method to add/update meta data, with two restrictions:
808
	 *
809
	 * 1) Only non-protected meta (no leading underscore) can be set
810
	 * 2) Meta values must be scalar (int, string, bool)
811
	 *
812
	 * @param WC_Order $order Order data.
0 ignored issues
show
Bug introduced by
There is no parameter named $order. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
813
	 * @param array $meta_data Meta data in array( 'meta_key' => 'meta_value' ) format.
814
	 */
815 View Code Duplication
	protected function update_meta_data( $order_id, $meta_data ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
816
		foreach ( $meta_data as $meta_key => $meta_value ) {
817
			if ( is_string( $meta_key ) && ! is_protected_meta( $meta_key ) && is_scalar( $meta_value ) ) {
818
				update_post_meta( $order_id, $meta_key, $meta_value );
819
			}
820
		}
821
	}
822
823
	/**
824
	 * Create a single item.
825
	 *
826
	 * @param WP_REST_Request $request Full details about the request.
827
	 * @return WP_Error|WP_REST_Response
828
	 */
829
	public function create_item( $request ) {
830
		if ( ! empty( $request['id'] ) ) {
831
			return new WP_Error( "woocommerce_rest_{$this->post_type}_exists", sprintf( __( 'Cannot create existing %s.', 'woocommerce' ), $this->post_type ), array( 'status' => 400 ) );
832
		}
833
834
		$order_id = $this->create_order( $request );
835
		if ( is_wp_error( $order_id ) ) {
836
			return $order_id;
837
		}
838
839
		// Clear transients.
840
		wc_delete_shop_order_transients( $order_id );
841
842
		$post = get_post( $order_id );
843
		$this->update_additional_fields_for_object( $post, $request );
844
845
		/**
846
		 * Fires after a single item is created or updated via the REST API.
847
		 *
848
		 * @param object          $post      Inserted object (not a WP_Post object).
849
		 * @param WP_REST_Request $request   Request object.
850
		 * @param boolean         $creating  True when creating item, false when updating.
851
		 */
852
		do_action( "woocommerce_rest_insert_{$this->post_type}", $post, $request, true );
853
854
		$request->set_param( 'context', 'edit' );
855
		$response = $this->prepare_item_for_response( $post, $request );
856
		$response = rest_ensure_response( $response );
857
		$response->set_status( 201 );
858
		$response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $post->ID ) ) );
859
860
		return $response;
861
	}
862
863
	/**
864
	 * Wrapper method to create/update order items.
865
	 * When updating, the item ID provided is checked to ensure it is associated
866
	 * with the order.
867
	 *
868
	 * @param WC_Order $order order
869
	 * @param string $item_type
870
	 * @param array $item item provided in the request body
871
	 * @param string $action either 'create' or 'update'
872
	 * @throws WC_REST_Exception If item ID is not associated with order
873
	 */
874 View Code Duplication
	protected function set_item( $order, $item_type, $item, $action ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
875
		global $wpdb;
876
877
		$set_method = 'set_' . $item_type;
878
879
		// Verify provided line item ID is associated with order.
880
		if ( 'update' === $action ) {
881
			$result = $wpdb->get_row(
882
				$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}woocommerce_order_items WHERE order_item_id = %d AND order_id = %d",
883
				absint( $item['id'] ),
884
				absint( $order->id )
885
			) );
886
887
			if ( is_null( $result ) ) {
888
				throw new WC_REST_Exception( 'woocommerce_rest_invalid_item_id', __( 'Order item ID provided is not associated with order.', 'woocommerce' ), 400 );
889
			}
890
		}
891
892
		$this->$set_method( $order, $item, $action );
893
	}
894
895
	/**
896
	 * Helper method to check if the resource ID associated with the provided item is null.
897
	 * Items can be deleted by setting the resource ID to null.
898
	 *
899
	 * @param array $item Item provided in the request body.
900
	 * @return bool True if the item resource ID is null, false otherwise.
901
	 */
902
	protected function item_is_null( $item ) {
903
		$keys = array( 'product_id', 'method_id', 'title', 'code' );
904
905
		foreach ( $keys as $key ) {
906
			if ( array_key_exists( $key, $item ) && is_null( $item[ $key ] ) ) {
907
				return true;
908
			}
909
		}
910
911
		return false;
912
	}
913
914
	/**
915
	 * Update order.
916
	 *
917
	 * @param WP_REST_Request $request Full details about the request.
918
	 * @param WP_Post $post Post data.
919
	 * @return int|WP_Error
920
	 */
921
	protected function update_order( $request, $post ) {
922
		try {
923
			$update_totals = false;
924
			$order         = wc_get_order( $post );
925
			$order_args    = array( 'order_id' => $order->id );
926
927
			// Customer note.
928
			if ( isset( $request['customer_note'] ) ) {
929
				$order_args['customer_note'] = $request['customer_note'];
930
			}
931
932
			// Customer ID.
933 View Code Duplication
			if ( isset( $request['customer_id'] ) && $request['customer_id'] != $order->get_user_id() ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
934
				// Make sure customer exists.
935
				if ( false === get_user_by( 'id', $request['customer_id'] ) ) {
936
					throw new WC_REST_Exception( 'woocommerce_rest_invalid_customer_id', __( 'Customer ID is invalid.', 'woocommerce' ), 400 );
937
				}
938
939
				update_post_meta( $order->id, '_customer_user', $request['customer_id'] );
940
			}
941
942
			// Update addresses.
943
			if ( is_array( $request['billing'] ) ) {
944
				$this->update_address( $order, $request['billing'], 'billing' );
0 ignored issues
show
Documentation introduced by
$order is of type false|object, but the function expects a object<WC_Order>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
945
			}
946
			if ( is_array( $request['shipping'] ) ) {
947
				$this->update_address( $order, $request['shipping'], 'shipping' );
0 ignored issues
show
Documentation introduced by
$order is of type false|object, but the function expects a object<WC_Order>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
948
			}
949
950
			$lines = array(
951
				'line_item' => 'line_items',
952
				'shipping'  => 'shipping_lines',
953
				'fee'       => 'fee_lines',
954
				'coupon'    => 'coupon_lines',
955
			);
956
957 View Code Duplication
			foreach ( $lines as $line_type => $line ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
958
				if ( isset( $request[ $line ] ) && is_array( $request[ $line ] ) ) {
959
					$update_totals = true;
960
					foreach ( $request[ $line ] as $item ) {
961
						// Item ID is always required.
962
						if ( ! array_key_exists( 'id', $item ) ) {
963
							throw new WC_REST_Exception( 'woocommerce_rest_invalid_item_id', __( 'Order item ID is required.', 'woocommerce' ), 400 );
964
						}
965
966
						// Create item.
967
						if ( is_null( $item['id'] ) ) {
968
							$this->set_item( $order, $line_type, $item, 'create' );
0 ignored issues
show
Documentation introduced by
$order is of type false|object, but the function expects a object<WC_Order>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
969
						} elseif ( $this->item_is_null( $item ) ) {
970
							// Delete item.
971
							wc_delete_order_item( $item['id'] );
972
						} else {
973
							// Update item.
974
							$this->set_item( $order, $line_type, $item, 'update' );
0 ignored issues
show
Documentation introduced by
$order is of type false|object, but the function expects a object<WC_Order>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
975
						}
976
					}
977
				}
978
			}
979
980
			// Set payment method.
981
			if ( ! empty( $request['payment_method'] ) ) {
982
				update_post_meta( $order->id, '_payment_method', $request['payment_method'] );
983
			}
984
			if ( ! empty( $request['payment_method_title'] ) ) {
985
				update_post_meta( $order->id, '_payment_method_title', $request['payment_method'] );
986
			}
987
			if ( $order->needs_payment() && isset( $request['set_paid'] ) && true === $request['set_paid'] ) {
988
				$order->payment_complete( ! empty( $request['transaction_id'] ) ? $request['transaction_id'] : '' );
989
			}
990
991
			// Set order currency.
992
			if ( isset( $request['currency'] ) ) {
993
				update_post_meta( $order->id, '_order_currency', $request['currency'] );
994
			}
995
996
			// If items have changed, recalculate order totals.
997
			if ( $update_totals ) {
998
				$order->calculate_totals();
999
			}
1000
1001
			// Update meta data.
1002 View Code Duplication
			if ( ! empty( $request['meta_data'] ) && is_array( $request['meta_data'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1003
				$this->update_meta_data( $order->id, $request['meta_data'] );
1004
			}
1005
1006
			// Update the order post to set customer note/modified date.
1007
			wc_update_order( $order_args );
1008
1009
			// Order status.
1010 View Code Duplication
			if ( ! empty( $request['status'] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1011
				$order->update_status( $request['status'], isset( $request['status_note'] ) ? $request['status_note'] : '' );
1012
			}
1013
1014
			return $order->id;
1015
		} catch ( WC_REST_Exception $e ) {
1016
			return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
1017
		}
1018
	}
1019
1020
	/**
1021
	 * Update a single order.
1022
	 *
1023
	 * @param WP_REST_Request $request Full details about the request.
1024
	 * @return WP_Error|WP_REST_Response
1025
	 */
1026
	public function update_item( $request ) {
1027
		$id   = (int) $request['id'];
1028
		$post = get_post( $id );
1029
1030
		if ( empty( $id ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) {
1031
			return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'ID is invalid.', 'woocommerce' ), array( 'status' => 400 ) );
1032
		}
1033
1034
		$order_id = $this->update_order( $request, $post );
1035
		if ( is_wp_error( $order_id ) ) {
1036
			return $order_id;
1037
		}
1038
1039
		// Clear transients.
1040
		wc_delete_shop_order_transients( $order_id );
1041
1042
		$post = get_post( $order_id );
1043
		$this->update_additional_fields_for_object( $post, $request );
1044
1045
		/**
1046
		 * Fires after a single item is created or updated via the REST API.
1047
		 *
1048
		 * @param object          $post      Inserted object (not a WP_Post object).
1049
		 * @param WP_REST_Request $request   Request object.
1050
		 * @param boolean         $creating  True when creating item, false when updating.
1051
		 */
1052
		do_action( "woocommerce_rest_insert_{$this->post_type}", $post, $request, false );
1053
1054
		$request->set_param( 'context', 'edit' );
1055
		$response = $this->prepare_item_for_response( $post, $request );
1056
		return rest_ensure_response( $response );
1057
	}
1058
1059
	/**
1060
	 * Get order statuses.
1061
	 *
1062
	 * @return array
1063
	 */
1064
	protected function get_order_statuses() {
1065
		$order_statuses = array();
1066
1067
		foreach ( array_keys( wc_get_order_statuses() ) as $status ) {
1068
			$order_statuses[] = str_replace( 'wc-', '', $status );
1069
		}
1070
1071
		return $order_statuses;
1072
	}
1073
1074
	/**
1075
	 * Create base WC Order object.
1076
	 *
1077
	 * @since 2.6.0
1078
	 * @param array $args Order args.
1079
	 * @param WP_REST_Request $request Full details about the request.
0 ignored issues
show
Bug introduced by
There is no parameter named $request. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1080
	 * @return WC_Order|WP_Error
1081
	 */
1082
	protected function create_base_order( $args, $data ) {
0 ignored issues
show
Unused Code introduced by
The parameter $data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1083
		return wc_create_order( $args );
1084
	}
1085
1086
	/**
1087
	 * Get the Order's schema, conforming to JSON Schema.
1088
	 *
1089
	 * @return array
1090
	 */
1091
	public function get_item_schema() {
1092
		$schema = array(
1093
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
1094
			'title'      => $this->post_type,
1095
			'type'       => 'object',
1096
			'properties' => array(
1097
				'id' => array(
1098
					'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
1099
					'type'        => 'integer',
1100
					'context'     => array( 'view', 'edit' ),
1101
					'readonly'    => true,
1102
				),
1103
				'parent_id' => array(
1104
					'description' => __( 'Parent order ID.', 'woocommerce' ),
1105
					'type'        => 'integer',
1106
					'context'     => array( 'view', 'edit' ),
1107
				),
1108
				'status' => array(
1109
					'description' => __( 'Order status.', 'woocommerce' ),
1110
					'type'        => 'string',
1111
					'default'     => 'pending',
1112
					'enum'        => $this->get_order_statuses(),
1113
					'context'     => array( 'view', 'edit' ),
1114
				),
1115
				'order_key' => array(
1116
					'description' => __( 'Order key.', 'woocommerce' ),
1117
					'type'        => 'string',
1118
					'context'     => array( 'view', 'edit' ),
1119
					'readonly'    => true,
1120
				),
1121
				'currency' => array(
1122
					'description' => __( 'Currency the order was created with, in ISO format.', 'woocommerce' ),
1123
					'type'        => 'string',
1124
					'default'     => get_woocommerce_currency(),
1125
					'enum'        => array_keys( get_woocommerce_currencies() ),
1126
					'context'     => array( 'view', 'edit' ),
1127
				),
1128
				'version' => array(
1129
					'description' => __( 'Version of WooCommerce when the order was made.', 'woocommerce' ),
1130
					'type'        => 'integer',
1131
					'context'     => array( 'view', 'edit' ),
1132
					'readonly'    => true,
1133
				),
1134
				'prices_include_tax' => array(
1135
					'description' => __( 'Shows if the prices included tax during checkout.', 'woocommerce' ),
1136
					'type'        => 'boolean',
1137
					'context'     => array( 'view', 'edit' ),
1138
					'readonly'    => true,
1139
				),
1140
				'date_created' => array(
1141
					'description' => __( "The date the order was created, in the site's timezone.", 'woocommerce' ),
1142
					'type'        => 'date-time',
1143
					'context'     => array( 'view', 'edit' ),
1144
					'readonly'    => true,
1145
				),
1146
				'date_modified' => array(
1147
					'description' => __( "The date the order was last modified, in the site's timezone.", 'woocommerce' ),
1148
					'type'        => 'date-time',
1149
					'context'     => array( 'view', 'edit' ),
1150
					'readonly'    => true,
1151
				),
1152
				'customer_id' => array(
1153
					'description' => __( 'User ID who owns the order. 0 for guests.', 'woocommerce' ),
1154
					'type'        => 'integer',
1155
					'default'     => 0,
1156
					'context'     => array( 'view', 'edit' ),
1157
				),
1158
				'discount_total' => array(
1159
					'description' => __( 'Total discount amount for the order.', 'woocommerce' ),
1160
					'type'        => 'string',
1161
					'context'     => array( 'view', 'edit' ),
1162
					'readonly'    => true,
1163
				),
1164
				'discount_tax' => array(
1165
					'description' => __( 'Total discount tax amount for the order.', 'woocommerce' ),
1166
					'type'        => 'string',
1167
					'context'     => array( 'view', 'edit' ),
1168
					'readonly'    => true,
1169
				),
1170
				'shipping_total' => array(
1171
					'description' => __( 'Total shipping amount for the order.', 'woocommerce' ),
1172
					'type'        => 'string',
1173
					'context'     => array( 'view', 'edit' ),
1174
					'readonly'    => true,
1175
				),
1176
				'shipping_tax' => array(
1177
					'description' => __( 'Total shipping tax amount for the order.', 'woocommerce' ),
1178
					'type'        => 'string',
1179
					'context'     => array( 'view', 'edit' ),
1180
					'readonly'    => true,
1181
				),
1182
				'cart_tax' => array(
1183
					'description' => __( 'Sum of line item taxes only.', 'woocommerce' ),
1184
					'type'        => 'string',
1185
					'context'     => array( 'view', 'edit' ),
1186
					'readonly'    => true,
1187
				),
1188
				'total' => array(
1189
					'description' => __( 'Grand total.', 'woocommerce' ),
1190
					'type'        => 'string',
1191
					'context'     => array( 'view', 'edit' ),
1192
					'readonly'    => true,
1193
				),
1194
				'total_tax' => array(
1195
					'description' => __( 'Sum of all taxes.', 'woocommerce' ),
1196
					'type'        => 'string',
1197
					'context'     => array( 'view', 'edit' ),
1198
					'readonly'    => true,
1199
				),
1200
				'billing' => array(
1201
					'description' => __( 'Billing address.', 'woocommerce' ),
1202
					'type'        => 'array',
1203
					'context'     => array( 'view', 'edit' ),
1204
					'properties'  => array(
1205
						'first_name' => array(
1206
							'description' => __( 'First name.', 'woocommerce' ),
1207
							'type'        => 'string',
1208
							'context'     => array( 'view', 'edit' ),
1209
						),
1210
						'last_name' => array(
1211
							'description' => __( 'Last name.', 'woocommerce' ),
1212
							'type'        => 'string',
1213
							'context'     => array( 'view', 'edit' ),
1214
						),
1215
						'company' => array(
1216
							'description' => __( 'Company name.', 'woocommerce' ),
1217
							'type'        => 'string',
1218
							'context'     => array( 'view', 'edit' ),
1219
						),
1220
						'address_1' => array(
1221
							'description' => __( 'Address line 1.', 'woocommerce' ),
1222
							'type'        => 'string',
1223
							'context'     => array( 'view', 'edit' ),
1224
						),
1225
						'address_2' => array(
1226
							'description' => __( 'Address line 2.', 'woocommerce' ),
1227
							'type'        => 'string',
1228
							'context'     => array( 'view', 'edit' ),
1229
						),
1230
						'city' => array(
1231
							'description' => __( 'City name.', 'woocommerce' ),
1232
							'type'        => 'string',
1233
							'context'     => array( 'view', 'edit' ),
1234
						),
1235
						'state' => array(
1236
							'description' => __( 'ISO code or name of the state, province or district.', 'woocommerce' ),
1237
							'type'        => 'string',
1238
							'context'     => array( 'view', 'edit' ),
1239
						),
1240
						'postcode' => array(
1241
							'description' => __( 'Postal code.', 'woocommerce' ),
1242
							'type'        => 'string',
1243
							'context'     => array( 'view', 'edit' ),
1244
						),
1245
						'country' => array(
1246
							'description' => __( 'Country code in ISO 3166-1 alpha-2 format.', 'woocommerce' ),
1247
							'type'        => 'string',
1248
							'context'     => array( 'view', 'edit' ),
1249
						),
1250
						'email' => array(
1251
							'description' => __( 'Email address.', 'woocommerce' ),
1252
							'type'        => 'string',
1253
							'format'      => 'email',
1254
							'context'     => array( 'view', 'edit' ),
1255
						),
1256
						'phone' => array(
1257
							'description' => __( 'Phone number.', 'woocommerce' ),
1258
							'type'        => 'string',
1259
							'context'     => array( 'view', 'edit' ),
1260
						),
1261
					),
1262
				),
1263
				'shipping' => array(
1264
					'description' => __( 'Shipping address.', 'woocommerce' ),
1265
					'type'        => 'array',
1266
					'context'     => array( 'view', 'edit' ),
1267
					'properties'  => array(
1268
						'first_name' => array(
1269
							'description' => __( 'First name.', 'woocommerce' ),
1270
							'type'        => 'string',
1271
							'context'     => array( 'view', 'edit' ),
1272
						),
1273
						'last_name' => array(
1274
							'description' => __( 'Last name.', 'woocommerce' ),
1275
							'type'        => 'string',
1276
							'context'     => array( 'view', 'edit' ),
1277
						),
1278
						'company' => array(
1279
							'description' => __( 'Company name.', 'woocommerce' ),
1280
							'type'        => 'string',
1281
							'context'     => array( 'view', 'edit' ),
1282
						),
1283
						'address_1' => array(
1284
							'description' => __( 'Address line 1.', 'woocommerce' ),
1285
							'type'        => 'string',
1286
							'context'     => array( 'view', 'edit' ),
1287
						),
1288
						'address_2' => array(
1289
							'description' => __( 'Address line 2.', 'woocommerce' ),
1290
							'type'        => 'string',
1291
							'context'     => array( 'view', 'edit' ),
1292
						),
1293
						'city' => array(
1294
							'description' => __( 'City name.', 'woocommerce' ),
1295
							'type'        => 'string',
1296
							'context'     => array( 'view', 'edit' ),
1297
						),
1298
						'state' => array(
1299
							'description' => __( 'ISO code or name of the state, province or district.', 'woocommerce' ),
1300
							'type'        => 'string',
1301
							'context'     => array( 'view', 'edit' ),
1302
						),
1303
						'postcode' => array(
1304
							'description' => __( 'Postal code.', 'woocommerce' ),
1305
							'type'        => 'string',
1306
							'context'     => array( 'view', 'edit' ),
1307
						),
1308
						'country' => array(
1309
							'description' => __( 'Country code in ISO 3166-1 alpha-2 format.', 'woocommerce' ),
1310
							'type'        => 'string',
1311
							'context'     => array( 'view', 'edit' ),
1312
						),
1313
					),
1314
				),
1315
				'payment_method' => array(
1316
					'description' => __( 'Payment method ID.', 'woocommerce' ),
1317
					'type'        => 'string',
1318
					'context'     => array( 'view', 'edit' ),
1319
				),
1320
				'payment_method_title' => array(
1321
					'description' => __( 'Payment method title.', 'woocommerce' ),
1322
					'type'        => 'string',
1323
					'context'     => array( 'view', 'edit' ),
1324
				),
1325
				'set_paid' => array(
1326
					'description' => __( 'Define if the order is paid. It will set the status to processing and reduce stock items.', 'woocommerce' ),
1327
					'type'        => 'boolean',
1328
					'default'     => false,
1329
					'context'     => array( 'edit' ),
1330
				),
1331
				'transaction_id' => array(
1332
					'description' => __( 'Unique transaction ID.', 'woocommerce' ),
1333
					'type'        => 'string',
1334
					'context'     => array( 'view', 'edit' ),
1335
				),
1336
				'customer_ip_address' => array(
1337
					'description' => __( "Customer's IP address.", 'woocommerce' ),
1338
					'type'        => 'string',
1339
					'context'     => array( 'view', 'edit' ),
1340
					'readonly'    => true,
1341
				),
1342
				'customer_user_agent' => array(
1343
					'description' => __( 'User agent of the customer.', 'woocommerce' ),
1344
					'type'        => 'string',
1345
					'context'     => array( 'view', 'edit' ),
1346
					'readonly'    => true,
1347
				),
1348
				'created_via' => array(
1349
					'description' => __( 'Shows where the order was created.', 'woocommerce' ),
1350
					'type'        => 'string',
1351
					'context'     => array( 'view', 'edit' ),
1352
					'readonly'    => true,
1353
				),
1354
				'customer_note' => array(
1355
					'description' => __( 'Note left by customer during checkout.', 'woocommerce' ),
1356
					'type'        => 'string',
1357
					'context'     => array( 'view', 'edit' ),
1358
				),
1359
				'date_completed' => array(
1360
					'description' => __( "The date the order was completed, in the site's timezone.", 'woocommerce' ),
1361
					'type'        => 'date-time',
1362
					'context'     => array( 'view', 'edit' ),
1363
					'readonly'    => true,
1364
				),
1365
				'date_paid' => array(
1366
					'description' => __( "The date the order has been paid, in the site's timezone.", 'woocommerce' ),
1367
					'type'        => 'date-time',
1368
					'context'     => array( 'view', 'edit' ),
1369
					'readonly'    => true,
1370
				),
1371
				'cart_hash' => array(
1372
					'description' => __( 'MD5 hash of cart items to ensure orders are not modified.', 'woocommerce' ),
1373
					'type'        => 'string',
1374
					'context'     => array( 'view', 'edit' ),
1375
					'readonly'    => true,
1376
				),
1377
				'line_items' => array(
1378
					'description' => __( 'Line items data.', 'woocommerce' ),
1379
					'type'        => 'array',
1380
					'context'     => array( 'view', 'edit' ),
1381
					'properties'  => array(
1382
						'id' => array(
1383
							'description' => __( 'Item ID.', 'woocommerce' ),
1384
							'type'        => 'integer',
1385
							'context'     => array( 'view', 'edit' ),
1386
							'readonly'    => true,
1387
						),
1388
						'name' => array(
1389
							'description' => __( 'Product name.', 'woocommerce' ),
1390
							'type'        => 'string',
1391
							'context'     => array( 'view', 'edit' ),
1392
							'readonly'    => true,
1393
						),
1394
						'sku' => array(
1395
							'description' => __( 'Product SKU.', 'woocommerce' ),
1396
							'type'        => 'string',
1397
							'context'     => array( 'view', 'edit' ),
1398
							'readonly'    => true,
1399
						),
1400
						'product_id' => array(
1401
							'description' => __( 'Product ID.', 'woocommerce' ),
1402
							'type'        => 'integer',
1403
							'context'     => array( 'view', 'edit' ),
1404
						),
1405
						'variation_id' => array(
1406
							'description' => __( 'Variation ID, if applicable.', 'woocommerce' ),
1407
							'type'        => 'integer',
1408
							'context'     => array( 'view', 'edit' ),
1409
						),
1410
						'quantity' => array(
1411
							'description' => __( 'Quantity ordered.', 'woocommerce' ),
1412
							'type'        => 'integer',
1413
							'context'     => array( 'view', 'edit' ),
1414
						),
1415
						'tax_class' => array(
1416
							'description' => __( 'Tax class of product.', 'woocommerce' ),
1417
							'type'        => 'integer',
1418
							'context'     => array( 'view', 'edit' ),
1419
							'readonly'    => true,
1420
						),
1421
						'price' => array(
1422
							'description' => __( 'Product price.', 'woocommerce' ),
1423
							'type'        => 'string',
1424
							'context'     => array( 'view', 'edit' ),
1425
							'readonly'    => true,
1426
						),
1427
						'subtotal' => array(
1428
							'description' => __( 'Line subtotal (before discounts).', 'woocommerce' ),
1429
							'type'        => 'string',
1430
							'context'     => array( 'view', 'edit' ),
1431
						),
1432
						'subtotal_tax' => array(
1433
							'description' => __( 'Line subtotal tax (before discounts).', 'woocommerce' ),
1434
							'type'        => 'string',
1435
							'context'     => array( 'view', 'edit' ),
1436
						),
1437
						'total' => array(
1438
							'description' => __( 'Line total (after discounts).', 'woocommerce' ),
1439
							'type'        => 'string',
1440
							'context'     => array( 'view', 'edit' ),
1441
						),
1442
						'total_tax' => array(
1443
							'description' => __( 'Line total tax (after discounts).', 'woocommerce' ),
1444
							'type'        => 'string',
1445
							'context'     => array( 'view', 'edit' ),
1446
						),
1447
						'taxes' => array(
1448
							'description' => __( 'Line taxes.', 'woocommerce' ),
1449
							'type'        => 'array',
1450
							'context'     => array( 'view', 'edit' ),
1451
							'readonly'    => true,
1452
							'properties'  => array(
1453
								'id' => array(
1454
									'description' => __( 'Tax rate ID.', 'woocommerce' ),
1455
									'type'        => 'integer',
1456
									'context'     => array( 'view', 'edit' ),
1457
									'readonly'    => true,
1458
								),
1459
								'total' => array(
1460
									'description' => __( 'Tax total.', 'woocommerce' ),
1461
									'type'        => 'string',
1462
									'context'     => array( 'view', 'edit' ),
1463
									'readonly'    => true,
1464
								),
1465
								'subtotal' => array(
1466
									'description' => __( 'Tax subtotal.', 'woocommerce' ),
1467
									'type'        => 'string',
1468
									'context'     => array( 'view', 'edit' ),
1469
									'readonly'    => true,
1470
								),
1471
							),
1472
						),
1473
						'meta' => array(
1474
							'description' => __( 'Line item meta data.', 'woocommerce' ),
1475
							'type'        => 'array',
1476
							'context'     => array( 'view', 'edit' ),
1477
							'readonly'    => true,
1478
							'properties'  => array(
1479
								'key' => array(
1480
									'description' => __( 'Meta key.', 'woocommerce' ),
1481
									'type'        => 'string',
1482
									'context'     => array( 'view', 'edit' ),
1483
									'readonly'    => true,
1484
								),
1485
								'label' => array(
1486
									'description' => __( 'Meta label.', 'woocommerce' ),
1487
									'type'        => 'string',
1488
									'context'     => array( 'view', 'edit' ),
1489
									'readonly'    => true,
1490
								),
1491
								'value' => array(
1492
									'description' => __( 'Meta value.', 'woocommerce' ),
1493
									'type'        => 'string',
1494
									'context'     => array( 'view', 'edit' ),
1495
									'readonly'    => true,
1496
								),
1497
							),
1498
						),
1499
					),
1500
				),
1501
				'tax_lines' => array(
1502
					'description' => __( 'Tax lines data.', 'woocommerce' ),
1503
					'type'        => 'array',
1504
					'context'     => array( 'view', 'edit' ),
1505
					'readonly'    => true,
1506
					'properties'  => array(
1507
						'id' => array(
1508
							'description' => __( 'Item ID.', 'woocommerce' ),
1509
							'type'        => 'integer',
1510
							'context'     => array( 'view', 'edit' ),
1511
							'readonly'    => true,
1512
						),
1513
						'rate_code' => array(
1514
							'description' => __( 'Tax rate code.', 'woocommerce' ),
1515
							'type'        => 'string',
1516
							'context'     => array( 'view', 'edit' ),
1517
							'readonly'    => true,
1518
						),
1519
						'rate_id' => array(
1520
							'description' => __( 'Tax rate ID.', 'woocommerce' ),
1521
							'type'        => 'string',
1522
							'context'     => array( 'view', 'edit' ),
1523
							'readonly'    => true,
1524
						),
1525
						'label' => array(
1526
							'description' => __( 'Tax rate label.', 'woocommerce' ),
1527
							'type'        => 'string',
1528
							'context'     => array( 'view', 'edit' ),
1529
							'readonly'    => true,
1530
						),
1531
						'compound' => array(
1532
							'description' => __( 'Show if is a compound tax rate.', 'woocommerce' ),
1533
							'type'        => 'boolean',
1534
							'context'     => array( 'view', 'edit' ),
1535
							'readonly'    => true,
1536
						),
1537
						'tax_total' => array(
1538
							'description' => __( 'Tax total (not including shipping taxes).', 'woocommerce' ),
1539
							'type'        => 'string',
1540
							'context'     => array( 'view', 'edit' ),
1541
							'readonly'    => true,
1542
						),
1543
						'shipping_tax_total' => array(
1544
							'description' => __( 'Shipping tax total.', 'woocommerce' ),
1545
							'type'        => 'string',
1546
							'context'     => array( 'view', 'edit' ),
1547
							'readonly'    => true,
1548
						),
1549
					),
1550
				),
1551
				'shipping_lines' => array(
1552
					'description' => __( 'Shipping lines data.', 'woocommerce' ),
1553
					'type'        => 'array',
1554
					'context'     => array( 'view', 'edit' ),
1555
					'properties'  => array(
1556
						'id' => array(
1557
							'description' => __( 'Item ID.', 'woocommerce' ),
1558
							'type'        => 'integer',
1559
							'context'     => array( 'view', 'edit' ),
1560
							'readonly'    => true,
1561
						),
1562
						'method_title' => array(
1563
							'description' => __( 'Shipping method name.', 'woocommerce' ),
1564
							'type'        => 'string',
1565
							'context'     => array( 'view', 'edit' ),
1566
						),
1567
						'method_id' => array(
1568
							'description' => __( 'Shipping method ID.', 'woocommerce' ),
1569
							'type'        => 'string',
1570
							'context'     => array( 'view', 'edit' ),
1571
						),
1572
						'total' => array(
1573
							'description' => __( 'Line total (after discounts).', 'woocommerce' ),
1574
							'type'        => 'string',
1575
							'context'     => array( 'view', 'edit' ),
1576
						),
1577
						'total_tax' => array(
1578
							'description' => __( 'Line total tax (after discounts).', 'woocommerce' ),
1579
							'type'        => 'string',
1580
							'context'     => array( 'view', 'edit' ),
1581
							'readonly'    => true,
1582
						),
1583
						'taxes' => array(
1584
							'description' => __( 'Line taxes.', 'woocommerce' ),
1585
							'type'        => 'array',
1586
							'context'     => array( 'view', 'edit' ),
1587
							'readonly'    => true,
1588
							'properties'  => array(
1589
								'id' => array(
1590
									'description' => __( 'Tax rate ID.', 'woocommerce' ),
1591
									'type'        => 'integer',
1592
									'context'     => array( 'view', 'edit' ),
1593
									'readonly'    => true,
1594
								),
1595
								'total' => array(
1596
									'description' => __( 'Tax total.', 'woocommerce' ),
1597
									'type'        => 'string',
1598
									'context'     => array( 'view', 'edit' ),
1599
									'readonly'    => true,
1600
								),
1601
							),
1602
						),
1603
					),
1604
				),
1605
				'fee_lines' => array(
1606
					'description' => __( 'Fee lines data.', 'woocommerce' ),
1607
					'type'        => 'array',
1608
					'context'     => array( 'view', 'edit' ),
1609
					'properties'  => array(
1610
						'id' => array(
1611
							'description' => __( 'Item ID.', 'woocommerce' ),
1612
							'type'        => 'integer',
1613
							'context'     => array( 'view', 'edit' ),
1614
							'readonly'    => true,
1615
						),
1616
						'name' => array(
1617
							'description' => __( 'Fee name.', 'woocommerce' ),
1618
							'type'        => 'string',
1619
							'context'     => array( 'view', 'edit' ),
1620
						),
1621
						'tax_class' => array(
1622
							'description' => __( 'Tax class of fee.', 'woocommerce' ),
1623
							'type'        => 'string',
1624
							'context'     => array( 'view', 'edit' ),
1625
						),
1626
						'tax_status' => array(
1627
							'description' => __( 'Tax status of fee.', 'woocommerce' ),
1628
							'type'        => 'string',
1629
							'context'     => array( 'view', 'edit' ),
1630
						),
1631
						'total' => array(
1632
							'description' => __( 'Line total (after discounts).', 'woocommerce' ),
1633
							'type'        => 'string',
1634
							'context'     => array( 'view', 'edit' ),
1635
						),
1636
						'total_tax' => array(
1637
							'description' => __( 'Line total tax (after discounts).', 'woocommerce' ),
1638
							'type'        => 'string',
1639
							'context'     => array( 'view', 'edit' ),
1640
						),
1641
						'taxes' => array(
1642
							'description' => __( 'Line taxes.', 'woocommerce' ),
1643
							'type'        => 'array',
1644
							'context'     => array( 'view', 'edit' ),
1645
							'readonly'    => true,
1646
							'properties'  => array(
1647
								'id' => array(
1648
									'description' => __( 'Tax rate ID.', 'woocommerce' ),
1649
									'type'        => 'integer',
1650
									'context'     => array( 'view', 'edit' ),
1651
									'readonly'    => true,
1652
								),
1653
								'total' => array(
1654
									'description' => __( 'Tax total.', 'woocommerce' ),
1655
									'type'        => 'string',
1656
									'context'     => array( 'view', 'edit' ),
1657
									'readonly'    => true,
1658
								),
1659
								'subtotal' => array(
1660
									'description' => __( 'Tax subtotal.', 'woocommerce' ),
1661
									'type'        => 'string',
1662
									'context'     => array( 'view', 'edit' ),
1663
									'readonly'    => true,
1664
								),
1665
							),
1666
						),
1667
					),
1668
				),
1669
				'coupon_lines' => array(
1670
					'description' => __( 'Coupons line data.', 'woocommerce' ),
1671
					'type'        => 'array',
1672
					'context'     => array( 'view', 'edit' ),
1673
					'properties'  => array(
1674
						'id' => array(
1675
							'description' => __( 'Item ID.', 'woocommerce' ),
1676
							'type'        => 'integer',
1677
							'context'     => array( 'view', 'edit' ),
1678
							'readonly'    => true,
1679
						),
1680
						'code' => array(
1681
							'description' => __( 'Coupon code.', 'woocommerce' ),
1682
							'type'        => 'string',
1683
							'context'     => array( 'view', 'edit' ),
1684
						),
1685
						'discount' => array(
1686
							'description' => __( 'Discount total.', 'woocommerce' ),
1687
							'type'        => 'string',
1688
							'context'     => array( 'view', 'edit' ),
1689
						),
1690
						'discount_tax' => array(
1691
							'description' => __( 'Discount total tax.', 'woocommerce' ),
1692
							'type'        => 'string',
1693
							'context'     => array( 'view', 'edit' ),
1694
							'readonly'    => true,
1695
						),
1696
					),
1697
				),
1698
				'refunds' => array(
1699
					'description' => __( 'List of refunds.', 'woocommerce' ),
1700
					'type'        => 'array',
1701
					'context'     => array( 'view', 'edit' ),
1702
					'readonly'    => true,
1703
					'properties'  => array(
1704
						'id' => array(
1705
							'description' => __( 'Refund ID.', 'woocommerce' ),
1706
							'type'        => 'integer',
1707
							'context'     => array( 'view', 'edit' ),
1708
							'readonly'    => true,
1709
						),
1710
						'reason' => array(
1711
							'description' => __( 'Refund reason.', 'woocommerce' ),
1712
							'type'        => 'string',
1713
							'context'     => array( 'view', 'edit' ),
1714
							'readonly'    => true,
1715
						),
1716
						'total' => array(
1717
							'description' => __( 'Refund total.', 'woocommerce' ),
1718
							'type'        => 'string',
1719
							'context'     => array( 'view', 'edit' ),
1720
							'readonly'    => true,
1721
						),
1722
					),
1723
				),
1724
			),
1725
		);
1726
1727
		return $this->add_additional_fields_schema( $schema );
1728
	}
1729
1730
	/**
1731
	 * Get the query params for collections.
1732
	 *
1733
	 * @return array
1734
	 */
1735
	public function get_collection_params() {
1736
		$params = parent::get_collection_params();
1737
1738
		$params['status'] = array(
1739
			'default'           => 'any',
1740
			'description'       => __( 'Limit result set to orders assigned a specific status.', 'woocommerce' ),
1741
			'type'              => 'string',
1742
			'enum'              => array_merge( array( 'any' ), $this->get_order_statuses() ),
1743
			'sanitize_callback' => 'sanitize_key',
1744
			'validate_callback' => 'rest_validate_request_arg',
1745
		);
1746
		$params['customer'] = array(
1747
			'description'       => __( 'Limit result set to orders assigned a specific customer.', 'woocommerce' ),
1748
			'type'              => 'integer',
1749
			'sanitize_callback' => 'absint',
1750
			'validate_callback' => 'rest_validate_request_arg',
1751
		);
1752
		$params['product'] = array(
1753
			'description'       => __( 'Limit result set to orders assigned a specific product.', 'woocommerce' ),
1754
			'type'              => 'integer',
1755
			'sanitize_callback' => 'absint',
1756
			'validate_callback' => 'rest_validate_request_arg',
1757
		);
1758
		$params['dp'] = array(
1759
			'default'           => 2,
1760
			'description'       => __( 'Number of decimal points to use in each resource.', 'woocommerce' ),
1761
			'type'              => 'integer',
1762
			'sanitize_callback' => 'absint',
1763
			'validate_callback' => 'rest_validate_request_arg',
1764
		);
1765
1766
		return $params;
1767
	}
1768
}
1769