Completed
Push — master ( f47a1d...37f03f )
by Claudio
28:06
created

WC_REST_Orders_Controller::create_order()   F

Complexity

Conditions 15
Paths 1051

Size

Total Lines 76
Code Lines 41

Duplication

Lines 14
Ratio 18.42 %

Importance

Changes 3
Bugs 1 Features 0
Metric Value
dl 14
loc 76
rs 2.23
c 3
b 1
f 0
nc 1051
cc 15
eloc 41
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
1 ignored issue
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 23 and the first side effect is on line 14.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
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
104
	/**
105
	 * Prepare a single order output for response.
106
	 *
107
	 * @param WP_Post $post Post object.
108
	 * @param WP_REST_Request $request Request object.
109
	 * @return WP_REST_Response $data
110
	 */
111
	public function prepare_item_for_response( $post, $request ) {
112
		global $wpdb;
113
114
		$order = wc_get_order( $post );
115
		$dp    = $request['dp'];
116
117
		$data = array(
118
			'id'                   => $order->id,
119
			'parent_id'            => $post->post_parent,
120
			'status'               => $order->get_status(),
121
			'order_key'            => $order->order_key,
122
			'currency'             => $order->get_order_currency(),
123
			'version'              => $order->order_version,
124
			'prices_include_tax'   => $order->prices_include_tax,
125
			'date_created'         => wc_rest_prepare_date_response( $post->post_date_gmt ),
126
			'date_modified'        => wc_rest_prepare_date_response( $post->post_modified_gmt ),
127
			'customer_id'          => $order->get_user_id(),
128
			'discount_total'       => wc_format_decimal( $order->get_total_discount(), $dp ),
129
			'discount_tax'         => wc_format_decimal( $order->cart_discount_tax, $dp ),
130
			'shipping_total'       => wc_format_decimal( $order->get_total_shipping(), $dp ),
131
			'shipping_tax'         => wc_format_decimal( $order->get_shipping_tax(), $dp ),
132
			'cart_tax'             => wc_format_decimal( $order->get_cart_tax(), $dp ),
133
			'total'                => wc_format_decimal( $order->get_total(), $dp ),
134
			'total_tax'            => wc_format_decimal( $order->get_total_tax(), $dp ),
135
			'billing'              => array(),
136
			'shipping'             => array(),
137
			'payment_method'       => $order->payment_method,
138
			'payment_method_title' => $order->payment_method_title,
139
			'transaction_id'       => $order->get_transaction_id(),
140
			'customer_ip_address'  => $order->customer_ip_address,
141
			'customer_user_agent'  => $order->customer_user_agent,
142
			'created_via'          => $order->created_via,
143
			'customer_note'        => $order->customer_note,
144
			'date_completed'       => wc_rest_prepare_date_response( $order->completed_date, true ),
0 ignored issues
show
Documentation introduced by
true is of type boolean, but the function expects a string|null.

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...
145
			'date_paid'            => $order->paid_date,
146
			'cart_hash'            => $order->cart_hash,
147
			'line_items'           => array(),
148
			'tax_lines'            => array(),
149
			'shipping_lines'       => array(),
150
			'fee_lines'            => array(),
151
			'coupon_lines'         => array(),
152
		);
153
154
		// Add addresses.
155
		$data['billing']  = $order->get_address( 'billing' );
156
		$data['shipping'] = $order->get_address( 'shipping' );
157
158
		// Add line items.
159 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...
160
			$product      = $order->get_product_from_item( $item );
161
			$product_id   = 0;
162
			$variation_id = 0;
163
			$product_sku  = null;
164
165
			// Check if the product exists.
166
			if ( is_object( $product ) ) {
167
				$product_id   = $product->id;
168
				$variation_id = $product->variation_id;
169
				$product_sku  = $product->get_sku();
170
			}
171
172
			$meta = new WC_Order_Item_Meta( $item, $product );
173
174
			$item_meta = array();
175
176
			$hideprefix = 'true' === $request['all_item_meta'] ? null : '_';
177
178
			foreach ( $meta->get_formatted( $hideprefix ) as $meta_key => $formatted_meta ) {
179
				$item_meta[] = array(
180
					'key'   => $formatted_meta['key'],
181
					'label' => $formatted_meta['label'],
182
					'value' => $formatted_meta['value'],
183
				);
184
			}
185
186
			$line_item = array(
187
				'id'           => $item_id,
188
				'name'         => $item['name'],
189
				'sku'          => $product_sku,
190
				'product_id'   => (int) $product_id,
191
				'variation_id' => (int) $variation_id,
192
				'quantity'     => wc_stock_amount( $item['qty'] ),
193
				'tax_class'    => ! empty( $item['tax_class'] ) ? $item['tax_class'] : '',
194
				'price'        => wc_format_decimal( $order->get_item_total( $item, false, false ), $dp ),
195
				'subtotal'     => wc_format_decimal( $order->get_line_subtotal( $item, false, false ), $dp ),
196
				'subtotal_tax' => wc_format_decimal( $item['line_subtotal_tax'], $dp ),
197
				'total'        => wc_format_decimal( $order->get_line_total( $item, false, false ), $dp ),
198
				'total_tax'    => wc_format_decimal( $item['line_tax'], $dp ),
199
				'taxes'        => array(),
200
				'meta'         => $item_meta,
201
			);
202
203
			$item_line_taxes = maybe_unserialize( $item['line_tax_data'] );
204
			if ( isset( $item_line_taxes['total'] ) ) {
205
				$line_tax = array();
206
207
				foreach ( $item_line_taxes['total'] as $tax_rate_id => $tax ) {
208
					$line_tax[ $tax_rate_id ] = array(
209
						'id'       => $tax_rate_id,
210
						'total'    => $tax,
211
						'subtotal' => '',
212
					);
213
				}
214
215
				foreach ( $item_line_taxes['subtotal'] as $tax_rate_id => $tax ) {
216
					$line_tax[ $tax_rate_id ]['subtotal'] = $tax;
217
				}
218
219
				$line_item['taxes'] = array_values( $line_tax );
220
			}
221
222
			$data['line_items'][] = $line_item;
223
		}
224
225
		// Add taxes.
226
		foreach ( $order->get_items( 'tax' ) as $key => $tax ) {
227
			$tax_line = array(
228
				'id'                 => $key,
229
				'rate_code'          => $tax['name'],
230
				'rate_id'            => $tax['rate_id'],
231
				'label'              => isset( $tax['label'] ) ? $tax['label'] : $tax['name'],
232
				'compound'           => (bool) $tax['compound'],
233
				'tax_total'          => wc_format_decimal( $tax['tax_amount'], $dp ),
234
				'shipping_tax_total' => wc_format_decimal( $tax['shipping_tax_amount'], $dp ),
235
			);
236
237
			$data['tax_lines'][] = $tax_line;
238
		}
239
240
		// Add shipping.
241
		foreach ( $order->get_shipping_methods() as $shipping_item_id => $shipping_item ) {
242
			$shipping_line = array(
243
				'id'           => $shipping_item_id,
244
				'method_title' => $shipping_item['name'],
245
				'method_id'    => $shipping_item['method_id'],
246
				'total'        => wc_format_decimal( $shipping_item['cost'], $dp ),
247
				'total_tax'    => wc_format_decimal( '', $dp ),
248
				'taxes'        => array(),
249
			);
250
251
			$shipping_taxes = maybe_unserialize( $shipping_item['taxes'] );
252
253
			if ( ! empty( $shipping_taxes ) ) {
254
				$shipping_line['total_tax'] = wc_format_decimal( array_sum( $shipping_taxes ), $dp );
255
256
				foreach ( $shipping_taxes as $tax_rate_id => $tax ) {
257
					$shipping_line['taxes'][] = array(
258
						'id'       => $tax_rate_id,
259
						'total'    => $tax,
260
					);
261
				}
262
			}
263
264
			$data['shipping_lines'][] = $shipping_line;
265
		}
266
267
		// Add fees.
268
		foreach ( $order->get_fees() as $fee_item_id => $fee_item ) {
269
			$fee_line = array(
270
				'id'         => $fee_item_id,
271
				'name'       => $fee_item['name'],
272
				'tax_class'  => ! empty( $fee_item['tax_class'] ) ? $fee_item['tax_class'] : '',
273
				'tax_status' => 'taxable',
274
				'total'      => wc_format_decimal( $order->get_line_total( $fee_item ), $dp ),
275
				'total_tax'  => wc_format_decimal( $order->get_line_tax( $fee_item ), $dp ),
276
				'taxes'      => array(),
277
			);
278
279
			$fee_line_taxes = maybe_unserialize( $fee_item['line_tax_data'] );
280
			if ( isset( $fee_line_taxes['total'] ) ) {
281
				$fee_tax = array();
282
283
				foreach ( $fee_line_taxes['total'] as $tax_rate_id => $tax ) {
284
					$fee_tax[ $tax_rate_id ] = array(
285
						'id'       => $tax_rate_id,
286
						'total'    => $tax,
287
						'subtotal' => '',
288
					);
289
				}
290
291
				foreach ( $fee_line_taxes['subtotal'] as $tax_rate_id => $tax ) {
292
					$fee_tax[ $tax_rate_id ]['subtotal'] = $tax;
293
				}
294
295
				$fee_line['taxes'] = array_values( $fee_tax );
296
			}
297
298
			$data['fee_lines'][] = $fee_line;
299
		}
300
301
		// Add coupons.
302
		foreach ( $order->get_items( 'coupon' ) as $coupon_item_id => $coupon_item ) {
303
			$coupon_line = array(
304
				'id'           => $coupon_item_id,
305
				'code'         => $coupon_item['name'],
306
				'discount'     => wc_format_decimal( $coupon_item['discount_amount'], $dp ),
307
				'discount_tax' => wc_format_decimal( $coupon_item['discount_amount_tax'], $dp ),
308
			);
309
310
			$data['coupon_lines'][] = $coupon_line;
311
		}
312
313
		$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
314
		$data    = $this->add_additional_fields_to_object( $data, $request );
315
		$data    = $this->filter_response_by_context( $data, $context );
316
317
		// Wrap the data in a response object.
318
		$response = rest_ensure_response( $data );
319
320
		$response->add_links( $this->prepare_links( $order ) );
321
322
		/**
323
		 * Filter the data for a response.
324
		 *
325
		 * The dynamic portion of the hook name, $this->post_type, refers to post_type of the post being
326
		 * prepared for the response.
327
		 *
328
		 * @param WP_REST_Response   $response   The response object.
329
		 * @param WP_Post            $post       Post object.
330
		 * @param WP_REST_Request    $request    Request object.
331
		 */
332
		return apply_filters( "woocommerce_rest_prepare_{$this->post_type}", $response, $post, $request );
333
	}
334
335
	/**
336
	 * Prepare links for the request.
337
	 *
338
	 * @param WC_Order $order Order object.
339
	 * @return array Links for the given order.
340
	 */
341
	protected function prepare_links( $order ) {
342
		$links = array(
343
			'self' => array(
344
				'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $order->id ) ),
345
			),
346
			'collection' => array(
347
				'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),
348
			),
349
		);
350
351
		if ( 0 !== (int) $order->get_user_id() ) {
352
			$links['customer'] = array(
353
				'href' => rest_url( sprintf( '/%s/customers/%d', $this->namespace, $order->get_user_id() ) ),
354
			);
355
		}
356
357 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...
358
			$links['up'] = array(
359
				'href' => rest_url( sprintf( '/%s/orders/%d', $this->namespace, $order->post->post_parent ) ),
360
			);
361
		}
362
363
		return $links;
364
	}
365
366
	/**
367
	 * Query args.
368
	 *
369
	 * @param array $args
370
	 * @param WP_REST_Request $request
371
	 * @return array
372
	 */
373
	public function query_args( $args, $request ) {
374
		global $wpdb;
375
376
		// Set post_status.
377
		if ( 'any' !== $request['status'] ) {
378
			$args['post_status'] = 'wc-' . $request['status'];
379
		} else {
380
			$args['post_status'] = 'any';
381
		}
382
383 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...
384
			if ( ! empty( $args['meta_query'] ) ) {
385
				$args['meta_query'] = array();
386
			}
387
388
			$args['meta_query'][] = array(
389
				'key'   => '_customer_user',
390
				'value' => $request['customer'],
391
				'type'  => 'NUMERIC',
392
			);
393
		}
394
395
		if ( ! empty( $request['product'] ) ) {
396
			$order_ids = $wpdb->get_col( $wpdb->prepare( "
397
				SELECT order_id
398
				FROM {$wpdb->prefix}woocommerce_order_items
399
				WHERE order_item_id IN ( SELECT order_item_id FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE meta_key = '_product_id' AND meta_value = %d )
400
				AND order_item_type = 'line_item'
401
			 ", $request['product'] ) );
402
403
			// Force WP_Query return empty if don't found any order.
404
			$order_ids = ! empty( $order_ids ) ? $order_ids : array( 0 );
405
406
			$args['post__in'] = $order_ids;
407
		}
408
409
		return $args;
410
	}
411
412
	/**
413
	 * Create order.
414
	 *
415
	 * @param WP_REST_Request $request Full details about the request.
416
	 * @return int|WP_Error
417
	 */
418
	protected function create_order( $request ) {
419
		wc_transaction_query( 'start' );
420
421
		try {
422
			// Make sure customer exists.
423
			if ( 0 !== $request['customer_id'] && false === get_user_by( 'id', $request['customer_id'] ) ) {
424
				throw new WC_REST_Exception( 'woocommerce_rest_invalid_customer_id',__( 'Customer ID is invalid.', 'woocommerce' ), 400 );
425
			}
426
427
			$order = wc_create_order( array(
428
				'status'        => $request['status'],
429
				'customer_id'   => $request['customer_id'],
430
				'customer_note' => $request['customer_note'],
431
				'created_via'   => 'rest-api',
432
			) );
433
434 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...
435
				throw new WC_REST_Exception( 'woocommerce_rest_cannot_create_order', sprintf( __( 'Cannot create order: %s.', 'woocommerce' ), implode( ', ', $order->get_error_messages() ) ), 400 );
1 ignored issue
show
Bug introduced by
The method get_error_messages() does not seem to exist on object<WC_Order>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
436
			}
437
438
			// Set addresses.
439
			if ( is_array( $request['billing'] ) ) {
440
				$this->update_address( $order, $request['billing'], 'billing' );
441
			}
442
			if ( is_array( $request['shipping'] ) ) {
443
				$this->update_address( $order, $request['shipping'], 'shipping' );
444
			}
445
446
			// Set currency.
447
			update_post_meta( $order->id, '_order_currency', $request['currency'] );
448
449
			// Set lines.
450
			$lines = array(
451
				'line_item' => 'line_items',
452
				'shipping'  => 'shipping_lines',
453
				'fee'       => 'fee_lines',
454
				'coupon'    => 'coupon_lines',
455
			);
456
457 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...
458
				if ( is_array( $request[ $line ] ) ) {
459
					foreach ( $request[ $line ] as $item ) {
460
						$set_item = 'set_' . $line_type;
461
						$new_item = $this->$set_item( $order, $item, 'create' );
0 ignored issues
show
Unused Code introduced by
$new_item is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
462
					}
463
				}
464
			}
465
466
			// Calculate totals and set them.
467
			$order->calculate_totals();
468
469
			// Set payment method.
470
			if ( ! empty( $request['payment_method'] ) ) {
471
				update_post_meta( $order->id, '_payment_method', $request['payment_method'] );
472
			}
473
			if ( ! empty( $request['payment_method_title'] ) ) {
474
				update_post_meta( $order->id, '_payment_method_title', $request['payment_method'] );
475
			}
476
			if ( true === $request['set_paid'] ) {
477
				$order->payment_complete( $request['transaction_id'] );
478
			}
479
480
			// Set meta data.
481 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...
482
				$this->update_meta_data( $order->id, $request['meta_data'] );
483
			}
484
485
			wc_transaction_query( 'commit' );
486
487
			return $order->id;
488
		} catch ( WC_REST_Exception $e ) {
489
			wc_transaction_query( 'rollback' );
490
491
			return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
492
		}
493
	}
494
495
	/**
496
	 * Update address.
497
	 *
498
	 * @param WC_Order $order
499
	 * @param array $posted
500
	 * @param string $type
501
	 */
502
	protected function update_address( $order, $posted, $type = 'billing' ) {
503
		$fields = $order->get_address( $type );
504
505
		foreach ( array_keys( $fields ) as $field ) {
506
			if ( isset( $posted[ $field ] ) ) {
507
				$fields[ $field ] = $posted[ $field ];
508
			}
509
		}
510
511
		// Set address.
512
		$order->set_address( $fields, $type );
513
514
		// Update user meta.
515
		if ( $order->get_user_id() ) {
516
			foreach ( $fields as $key => $value ) {
517
				update_user_meta( $order->get_user_id(), $type . '_' . $key, $value );
518
			}
519
		}
520
	}
521
522
	/**
523
	 * Create or update a line item.
524
	 *
525
	 * @param WC_Order $order Order data.
526
	 * @param array $item Line item data.
527
	 * @param string $action 'create' to add line item or 'update' to update it.
528
	 * @throws WC_REST_Exception Invalid data, server error.
529
	 */
530
	protected function set_line_item( $order, $item, $action = 'create' ) {
531
		$creating  = 'create' === $action;
532
		$item_args = array();
533
534
		// Product is always required.
535
		if ( empty( $item['product_id'] ) && empty( $item['sku'] ) && empty( $item['variation_id'] ) ) {
536
			throw new WC_REST_Exception( 'woocommerce_rest_required_product_reference', __( 'Product ID or SKU is required.', 'woocommerce' ), 400 );
537
		}
538
539
		if ( ! empty( $item['product_id'] ) ) {
540
			$product_id = (int) $item['product_id'];
541
		} else if ( ! empty( $item['sku'] ) ) {
542
			$product_id = (int) wc_get_product_id_by_sku( $item['sku'] );
543
		} else if ( ! empty( $item['variation_id'] ) ) {
544
			$product_id = (int) $item['variation_id'];
545
		}
546
547
		// When updating, ensure product ID provided matches.
548
		if ( 'update' === $action && ! empty( $item['id'] ) ) {
549
			$item_product_id   = (int) wc_get_order_item_meta( $item['id'], '_product_id' );
550
			$item_variation_id = (int) wc_get_order_item_meta( $item['id'], '_variation_id' );
551
552
			if ( $product_id !== $item_product_id && $product_id !== $item_variation_id ) {
553
				throw new WC_REST_Exception( 'woocommerce_rest_required_product_reference', __( 'Product ID or variation ID provided does not match this line item.', 'woocommerce' ), 400 );
554
			}
555
		}
556
557
		$product = wc_get_product( $product_id );
558
559
		// Must be a valid WC_Product.
560
		if ( ! is_object( $product ) ) {
561
			throw new WC_REST_Exception( 'woocommerce_rest_invalid_product', __( 'Product is invalid.', 'woocommerce' ), 400 );
562
		}
563
564
		// Quantity must be positive float.
565
		if ( isset( $item['quantity'] ) && 0 >= floatval( $item['quantity'] ) ) {
566
			throw new WC_REST_Exception( 'woocommerce_rest_invalid_product_quantity', __( 'Product quantity must be a positive float.', 'woocommerce' ), 400 );
567
		}
568
569
		// Quantity is required when creating.
570
		if ( $creating && ! isset( $item['quantity'] ) ) {
571
			throw new WC_REST_Exception( 'woocommerce_rest_invalid_product_quantity', __( 'Product quantity is required.', 'woocommerce' ), 400 );
572
		}
573
574
		// Get variation attributes.
575
		if ( method_exists( $product, 'get_variation_attributes' ) ) {
576
			$item_args['variation'] = $product->get_variation_attributes();
577
		}
578
579
		// Quantity.
580
		if ( isset( $item['quantity'] ) ) {
581
			$item_args['qty'] = $item['quantity'];
582
		}
583
584
		// Total.
585
		if ( isset( $item['total'] ) ) {
586
			$item_args['totals']['total'] = floatval( $item['total'] );
587
		}
588
589
		// Total tax.
590
		if ( isset( $item['total_tax'] ) ) {
591
			$item_args['totals']['tax'] = floatval( $item['total_tax'] );
592
		}
593
594
		// Subtotal.
595
		if ( isset( $item['subtotal'] ) ) {
596
			$item_args['totals']['subtotal'] = floatval( $item['subtotal'] );
597
		}
598
599
		// Subtotal tax.
600
		if ( isset( $item['subtotal_tax'] ) ) {
601
			$item_args['totals']['subtotal_tax'] = floatval( $item['subtotal_tax'] );
602
		}
603
604 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...
605
			$item_id = $order->add_product( $product, $item_args['qty'], $item_args );
606
			if ( ! $item_id ) {
607
				throw new WC_REST_Exception( 'woocommerce_rest_cannot_create_line_item', __( 'Cannot create line item, try again.', 'woocommerce' ), 500 );
608
			}
609
		} else {
610
			$item_id = $order->update_product( $item['id'], $product, $item_args );
611
			if ( ! $item_id ) {
612
				throw new WC_REST_Exception( 'woocommerce_rest_cannot_update_line_item', __( 'Cannot update line item, try again.', 'woocommerce' ), 500 );
613
			}
614
		}
615
	}
616
617
	/**
618
	 * Create or update an order shipping method.
619
	 *
620
	 * @param WC_Order $order Order data.
621
	 * @param array $shipping Item data.
622
	 * @param string $action 'create' to add shipping or 'update' to update it.
623
	 * @throws WC_REST_Exception Invalid data, server error.
624
	 */
625
	protected function set_shipping( $order, $shipping, $action ) {
626
		// Total must be a positive float.
627
		if ( ! empty( $shipping['total'] ) && 0 > floatval( $shipping['total'] ) ) {
628
			throw new WC_REST_Exception( 'woocommerce_rest_invalid_shipping_total', __( 'Shipping total must be a positive amount.', 'woocommerce' ), 400 );
629
		}
630
631
		if ( 'create' === $action ) {
632
			// Method ID is required.
633
			if ( empty( $shipping['method_id'] ) ) {
634
				throw new WC_REST_Exception( 'woocommerce_rest_invalid_shipping_item', __( 'Shipping method ID is required.', 'woocommerce' ), 400 );
635
			}
636
637
			$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'] );
638
639
			$shipping_id = $order->add_shipping( $rate );
640
641
			if ( ! $shipping_id ) {
642
				throw new WC_REST_Exception( 'woocommerce_rest_cannot_create_shipping', __( 'Cannot create shipping method, try again.', 'woocommerce' ), 500 );
643
			}
644
645
		} else {
646
			$shipping_args = array();
647
648
			if ( isset( $shipping['method_id'] ) ) {
649
				$shipping_args['method_id'] = $shipping['method_id'];
650
			}
651
652
			if ( isset( $shipping['method_title'] ) ) {
653
				$shipping_args['method_title'] = $shipping['method_title'];
654
			}
655
656
			if ( isset( $shipping['total'] ) ) {
657
				$shipping_args['cost'] = floatval( $shipping['total'] );
658
			}
659
660
			$shipping_id = $order->update_shipping( $shipping['id'], $shipping_args );
661
662
			if ( ! $shipping_id ) {
663
				throw new WC_REST_Exception( 'woocommerce_rest_cannot_update_shipping', __( 'Cannot update shipping method, try again.', 'woocommerce' ), 500 );
664
			}
665
		}
666
	}
667
668
	/**
669
	 * Create or update an order fee.
670
	 *
671
	 * @param WC_Order $order Order data.
672
	 * @param array $fee Item data.
673
	 * @param string $action 'create' to add fee or 'update' to update it.
674
	 * @throws WC_REST_Exception Invalid data, server error.
675
	 */
676
	protected function set_fee( $order, $fee, $action ) {
677
		if ( 'create' === $action ) {
678
679
			// Fee name is required.
680
			if ( empty( $fee['name'] ) ) {
681
				throw new WC_REST_Exception( 'woocommerce_rest_invalid_fee_item', __( 'Fee name is required.', 'woocommerce' ), 400 );
682
			}
683
684
			$fee_data            = new stdClass();
685
			$fee_data->id        = sanitize_title( $fee['name'] );
686
			$fee_data->name      = $fee['name'];
687
			$fee_data->amount    = isset( $fee['total'] ) ? floatval( $fee['total'] ) : 0;
688
			$fee_data->taxable   = false;
689
			$fee_data->tax       = 0;
690
			$fee_data->tax_data  = array();
691
			$fee_data->tax_class = '';
692
693
			// If taxable, tax class and total are required.
694
			if ( isset( $fee['tax_status'] ) && 'taxable' === $fee['tax_status'] ) {
695
696
				if ( ! isset( $fee['tax_class'] ) ) {
697
					throw new WC_REST_Exception( 'woocommerce_rest_invalid_fee_item', __( 'Fee tax class is required when fee is taxable.', 'woocommerce' ), 400 );
698
				}
699
700
				$fee_data->taxable   = true;
701
				$fee_data->tax_class = $fee['tax_class'];
702
703
				if ( isset( $fee['total_tax'] ) ) {
704
					$fee_data->tax = isset( $fee['total_tax'] ) ? wc_format_refund_total( $fee['total_tax'] ) : 0;
705
				}
706
			}
707
708
			$fee_id = $order->add_fee( $fee_data );
709
710
			if ( ! $fee_id ) {
711
				throw new WC_REST_Exception( 'woocommerce_rest_cannot_create_fee', __( 'Cannot create fee, try again.', 'woocommerce' ), 500 );
712
			}
713
714
		} else {
715
			$fee_args = array();
716
717
			if ( isset( $fee['name'] ) ) {
718
				$fee_args['name'] = $fee['name'];
719
			}
720
721
			if ( isset( $fee['tax_class'] ) ) {
722
				$fee_args['tax_class'] = $fee['tax_class'];
723
			}
724
725
			if ( isset( $fee['total'] ) ) {
726
				$fee_args['line_total'] = floatval( $fee['total'] );
727
			}
728
729
			if ( isset( $fee['total_tax'] ) ) {
730
				$fee_args['line_tax'] = floatval( $fee['total_tax'] );
731
			}
732
733
			$fee_id = $order->update_fee( $fee['id'], $fee_args );
734
735
			if ( ! $fee_id ) {
736
				throw new WC_REST_Exception( 'woocommerce_rest_cannot_update_fee', __( 'Cannot update fee, try again.', 'woocommerce' ), 500 );
737
			}
738
		}
739
	}
740
741
	/**
742
	 * Create or update an order coupon.
743
	 *
744
	 * @param WC_Order $order Order data.
745
	 * @param array $coupon Item data.
746
	 * @param string $action 'create' to add coupon or 'update' to update it.
747
	 * @throws WC_REST_Exception Invalid data, server error.
748
	 */
749
	protected function set_coupon( $order, $coupon, $action ) {
750
		// Coupon discount must be positive float.
751
		if ( isset( $coupon['discount'] ) && 0 > floatval( $coupon['discount'] ) ) {
752
			throw new WC_REST_Exception( 'woocommerce_rest_invalid_coupon_total', __( 'Coupon discount must be a positive amount.', 'woocommerce' ), 400 );
753
		}
754
755
		if ( 'create' === $action ) {
756
			// Coupon code is required.
757
			if ( empty( $coupon['code'] ) ) {
758
				throw new WC_REST_Exception( 'woocommerce_rest_invalid_coupon_coupon', __( 'Coupon code is required.', 'woocommerce' ), 400 );
759
			}
760
761
			$coupon_id = $order->add_coupon( $coupon['code'], floatval( $coupon['discount'] ) );
762
763
			if ( ! $coupon_id ) {
764
				throw new WC_REST_Exception( 'woocommerce_rest_cannot_create_order_coupon', __( 'Cannot create coupon, try again.', 'woocommerce' ), 500 );
765
			}
766
767
		} else {
768
			$coupon_args = array();
769
770
			if ( isset( $coupon['code'] ) ) {
771
				$coupon_args['code'] = $coupon['code'];
772
			}
773
774
			if ( isset( $coupon['discount'] ) ) {
775
				$coupon_args['discount_amount'] = floatval( $coupon['discount'] );
776
			}
777
778
			$coupon_id = $order->update_coupon( $coupon['id'], $coupon_args );
779
780
			if ( ! $coupon_id ) {
781
				throw new WC_REST_Exception( 'woocommerce_rest_cannot_update_order_coupon', __( 'Cannot update coupon, try again.', 'woocommerce' ), 500 );
782
			}
783
		}
784
	}
785
786
	/**
787
	 * Helper method to add/update meta data, with two restrictions:
788
	 *
789
	 * 1) Only non-protected meta (no leading underscore) can be set
790
	 * 2) Meta values must be scalar (int, string, bool)
791
	 *
792
	 * @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...
793
	 * @param array $meta_data Meta data in array( 'meta_key' => 'meta_value' ) format.
794
	 */
795 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...
796
		foreach ( $meta_data as $meta_key => $meta_value ) {
797
			if ( is_string( $meta_key ) && ! is_protected_meta( $meta_key ) && is_scalar( $meta_value ) ) {
798
				update_post_meta( $order_id, $meta_key, $meta_value );
799
			}
800
		}
801
	}
802
803
	/**
804
	 * Create a single item.
805
	 *
806
	 * @param WP_REST_Request $request Full details about the request.
807
	 * @return WP_Error|WP_REST_Response
808
	 */
809
	public function create_item( $request ) {
810
		if ( ! empty( $request['id'] ) ) {
811
			return new WP_Error( "woocommerce_rest_{$this->post_type}_exists", sprintf( __( 'Cannot create existing %s.', 'woocommerce' ), $this->post_type ), array( 'status' => 400 ) );
812
		}
813
814
		$order_id = $this->create_order( $request );
815
		if ( is_wp_error( $order_id ) ) {
816
			return $order_id;
817
		}
818
819
		// Clear transients.
820
		wc_delete_shop_order_transients( $order_id );
821
822
		$post = get_post( $order_id );
823
		$this->update_additional_fields_for_object( $post, $request );
824
825
		/**
826
		 * Fires after a single item is created or updated via the REST API.
827
		 *
828
		 * @param object          $post      Inserted object (not a WP_Post object).
829
		 * @param WP_REST_Request $request   Request object.
830
		 * @param boolean         $creating  True when creating item, false when updating.
831
		 */
832
		do_action( "woocommerce_rest_insert_{$this->post_type}", $post, $request, true );
833
834
		$request->set_param( 'context', 'edit' );
835
		$response = $this->prepare_item_for_response( $post, $request );
836
		$response = rest_ensure_response( $response );
837
		$response->set_status( 201 );
838
		$response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $post->ID ) ) );
839
840
		return $response;
841
	}
842
843
	/**
844
	 * Wrapper method to create/update order items.
845
	 * When updating, the item ID provided is checked to ensure it is associated
846
	 * with the order.
847
	 *
848
	 * @param WC_Order $order order
849
	 * @param string $item_type
850
	 * @param array $item item provided in the request body
851
	 * @param string $action either 'create' or 'update'
852
	 * @throws WC_REST_Exception If item ID is not associated with order
853
	 */
854 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...
855
		global $wpdb;
856
857
		$set_method = 'set_' . $item_type;
858
859
		// Verify provided line item ID is associated with order.
860
		if ( 'update' === $action ) {
861
			$result = $wpdb->get_row(
862
				$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}woocommerce_order_items WHERE order_item_id = %d AND order_id = %d",
863
				absint( $item['id'] ),
864
				absint( $order->id )
865
			) );
866
867
			if ( is_null( $result ) ) {
868
				throw new WC_REST_Exception( 'woocommerce_rest_invalid_item_id', __( 'Order item ID provided is not associated with order.', 'woocommerce' ), 400 );
869
			}
870
		}
871
872
		$this->$set_method( $order, $item, $action );
873
	}
874
875
	/**
876
	 * Helper method to check if the resource ID associated with the provided item is null.
877
	 * Items can be deleted by setting the resource ID to null.
878
	 *
879
	 * @param array $item Item provided in the request body.
880
	 * @return bool True if the item resource ID is null, false otherwise.
881
	 */
882 View Code Duplication
	protected function item_is_null( $item ) {
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...
883
		$keys = array( 'product_id', 'method_id', 'title', 'code' );
884
885
		foreach ( $keys as $key ) {
886
			if ( array_key_exists( $key, $item ) && is_null( $item[ $key ] ) ) {
887
				return true;
888
			}
889
		}
890
891
		return false;
892
	}
893
894
	/**
895
	 * Update order.
896
	 *
897
	 * @param WP_REST_Request $request Full details about the request.
898
	 * @param WP_Post $post Post data.
899
	 * @return int|WP_Error
900
	 */
901
	protected function update_order( $request, $post ) {
902
		try {
903
			$update_totals = false;
904
			$order         = wc_get_order( $post );
905
			$order_args    = array( 'order_id' => $order->id );
906
907
			// Customer note.
908
			if ( isset( $request['customer_note'] ) ) {
909
				$order_args['customer_note'] = $request['customer_note'];
910
			}
911
912
			// Customer ID.
913
			if ( isset( $request['customer_id'] ) && $request['customer_id'] != $order->get_user_id() ) {
914
				// Make sure customer exists.
915
				if ( false === get_user_by( 'id', $request['customer_id'] ) ) {
916
					throw new WC_REST_Exception( 'woocommerce_rest_invalid_customer_id', __( 'Customer ID is invalid.', 'woocommerce' ), 400 );
917
				}
918
919
				update_post_meta( $order->id, '_customer_user', $request['customer_id'] );
920
			}
921
922
			// Update addresses.
923
			if ( is_array( $request['billing'] ) ) {
924
				$this->update_address( $order, $request['billing'], 'billing' );
925
			}
926
			if ( is_array( $request['shipping'] ) ) {
927
				$this->update_address( $order, $request['shipping'], 'shipping' );
928
			}
929
930
			$lines = array(
931
				'line_item' => 'line_items',
932
				'shipping'  => 'shipping_lines',
933
				'fee'       => 'fee_lines',
934
				'coupon'    => 'coupon_lines',
935
			);
936
937
			foreach ( $lines as $line_type => $line ) {
938
				if ( isset( $request[ $line ] ) && is_array( $request[ $line ] ) ) {
939
					$update_totals = true;
940
					foreach ( $request[ $line ] as $item ) {
941
						// Item ID is always required.
942
						if ( ! array_key_exists( 'id', $item ) ) {
943
							throw new WC_REST_Exception( 'woocommerce_rest_invalid_item_id', __( 'Order item ID is required.', 'woocommerce' ), 400 );
944
						}
945
946
						// Create item.
947
						if ( is_null( $item['id'] ) ) {
948
							$this->set_item( $order, $line_type, $item, 'create' );
949
						} elseif ( $this->item_is_null( $item ) ) {
950
							// Delete item.
951
							wc_delete_order_item( $item['id'] );
952
						} else {
953
							// Update item.
954
							$this->set_item( $order, $line_type, $item, 'update' );
955
						}
956
					}
957
				}
958
			}
959
960
			// Set payment method.
961
			if ( ! empty( $request['payment_method'] ) ) {
962
				update_post_meta( $order->id, '_payment_method', $request['payment_method'] );
963
			}
964
			if ( ! empty( $request['payment_method_title'] ) ) {
965
				update_post_meta( $order->id, '_payment_method_title', $request['payment_method'] );
966
			}
967
			if ( $order->needs_payment() && isset( $request['set_paid'] ) && true === $request['set_paid'] ) {
968
				$order->payment_complete( ! empty( $request['transaction_id'] ) ? $request['transaction_id'] : '' );
969
			}
970
971
			// Set order currency.
972
			if ( isset( $request['currency'] ) ) {
973
				update_post_meta( $order->id, '_order_currency', $request['currency'] );
974
			}
975
976
			// If items have changed, recalculate order totals.
977
			if ( $update_totals ) {
978
				$order->calculate_totals();
979
			}
980
981
			// Update meta data.
982 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...
983
				$this->update_meta_data( $order->id, $request['meta_data'] );
984
			}
985
986
			// Update the order post to set customer note/modified date.
987
			wc_update_order( $order_args );
988
989
			// Order status.
990
			if ( ! empty( $request['status'] ) ) {
991
				$order->update_status( $request['status'], isset( $request['status_note'] ) ? $request['status_note'] : '' );
992
			}
993
994
			return $order->id;
995
		} catch ( WC_REST_Exception $e ) {
996
			return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) );
997
		}
998
	}
999
1000
	/**
1001
	 * Update a single order.
1002
	 *
1003
	 * @param WP_REST_Request $request Full details about the request.
1004
	 * @return WP_Error|WP_REST_Response
1005
	 */
1006
	public function update_item( $request ) {
1007
		$id   = (int) $request['id'];
1008
		$post = get_post( $id );
1009
1010
		if ( empty( $id ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) {
1011
			return new WP_Error( "woocommerce_rest_{$this->post_type}_invalid_id", __( 'ID is invalid.', 'woocommerce' ), array( 'status' => 400 ) );
1012
		}
1013
1014
		$order_id = $this->update_order( $request, $post );
1015
		if ( is_wp_error( $order_id ) ) {
1016
			return $order_id;
1017
		}
1018
1019
		// Clear transients.
1020
		wc_delete_shop_order_transients( $order_id );
1021
1022
		$post = get_post( $order_id );
1023
		$this->update_additional_fields_for_object( $post, $request );
1024
1025
		/**
1026
		 * Fires after a single item is created or updated via the REST API.
1027
		 *
1028
		 * @param object          $post      Inserted object (not a WP_Post object).
1029
		 * @param WP_REST_Request $request   Request object.
1030
		 * @param boolean         $creating  True when creating item, false when updating.
1031
		 */
1032
		do_action( "woocommerce_rest_insert_{$this->post_type}", $post, $request, false );
1033
1034
		$request->set_param( 'context', 'edit' );
1035
		$response = $this->prepare_item_for_response( $post, $request );
1036
		return rest_ensure_response( $response );
1037
	}
1038
1039
	/**
1040
	 * Get order statuses.
1041
	 *
1042
	 * @return array
1043
	 */
1044
	protected function get_order_statuses() {
1045
		$order_statuses = array();
1046
1047
		foreach ( array_keys( wc_get_order_statuses() ) as $status ) {
1048
			$order_statuses[] = str_replace( 'wc-', '', $status );
1049
		}
1050
1051
		return $order_statuses;
1052
	}
1053
1054
	/**
1055
	 * Get the Order's schema, conforming to JSON Schema.
1056
	 *
1057
	 * @return array
1058
	 */
1059
	public function get_item_schema() {
1060
		$schema = array(
1061
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
1062
			'title'      => $this->post_type,
1063
			'type'       => 'object',
1064
			'properties' => array(
1065
				'id' => array(
1066
					'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
1067
					'type'        => 'integer',
1068
					'context'     => array( 'view', 'edit' ),
1069
					'readonly'    => true,
1070
				),
1071
				'parent_id' => array(
1072
					'description' => __( 'Parent order ID.', 'woocommerce' ),
1073
					'type'        => 'integer',
1074
					'context'     => array( 'view', 'edit' ),
1075
				),
1076
				'status' => array(
1077
					'description' => __( 'Order status.', 'woocommerce' ),
1078
					'type'        => 'string',
1079
					'default'     => 'pending',
1080
					'enum'        => $this->get_order_statuses(),
1081
					'context'     => array( 'view', 'edit' ),
1082
				),
1083
				'order_key' => array(
1084
					'description' => __( 'Order key.', 'woocommerce' ),
1085
					'type'        => 'string',
1086
					'context'     => array( 'view', 'edit' ),
1087
					'readonly'    => true,
1088
				),
1089
				'currency' => array(
1090
					'description' => __( 'Currency the order was created with, in ISO format.', 'woocommerce' ),
1091
					'type'        => 'string',
1092
					'default'     => get_woocommerce_currency(),
1093
					'enum'        => array_keys( get_woocommerce_currencies() ),
1094
					'context'     => array( 'view', 'edit' ),
1095
				),
1096
				'version' => array(
1097
					'description' => __( 'Version of WooCommerce when the order was made.', 'woocommerce' ),
1098
					'type'        => 'integer',
1099
					'context'     => array( 'view', 'edit' ),
1100
					'readonly'    => true,
1101
				),
1102
				'prices_include_tax' => array(
1103
					'description' => __( 'Shows if the prices included tax during checkout.', 'woocommerce' ),
1104
					'type'        => 'boolean',
1105
					'context'     => array( 'view', 'edit' ),
1106
					'readonly'    => true,
1107
				),
1108
				'date_created' => array(
1109
					'description' => __( "The date the order was created, in the site's timezone.", 'woocommerce' ),
1110
					'type'        => 'date-time',
1111
					'context'     => array( 'view', 'edit' ),
1112
					'readonly'    => true,
1113
				),
1114
				'date_modified' => array(
1115
					'description' => __( "The date the order was last modified, in the site's timezone.", 'woocommerce' ),
1116
					'type'        => 'date-time',
1117
					'context'     => array( 'view', 'edit' ),
1118
					'readonly'    => true,
1119
				),
1120
				'customer_id' => array(
1121
					'description' => __( 'User ID who owns the order. 0 for guests.', 'woocommerce' ),
1122
					'type'        => 'integer',
1123
					'default'     => 0,
1124
					'context'     => array( 'view', 'edit' ),
1125
				),
1126
				'discount_total' => array(
1127
					'description' => __( 'Total discount amount for the order.', 'woocommerce' ),
1128
					'type'        => 'string',
1129
					'context'     => array( 'view', 'edit' ),
1130
					'readonly'    => true,
1131
				),
1132
				'discount_tax' => array(
1133
					'description' => __( 'Total discount tax amount for the order.', 'woocommerce' ),
1134
					'type'        => 'string',
1135
					'context'     => array( 'view', 'edit' ),
1136
					'readonly'    => true,
1137
				),
1138
				'shipping_total' => array(
1139
					'description' => __( 'Total shipping amount for the order.', 'woocommerce' ),
1140
					'type'        => 'string',
1141
					'context'     => array( 'view', 'edit' ),
1142
					'readonly'    => true,
1143
				),
1144
				'shipping_tax' => array(
1145
					'description' => __( 'Total shipping tax amount for the order.', 'woocommerce' ),
1146
					'type'        => 'string',
1147
					'context'     => array( 'view', 'edit' ),
1148
					'readonly'    => true,
1149
				),
1150
				'cart_tax' => array(
1151
					'description' => __( 'Sum of line item taxes only.', 'woocommerce' ),
1152
					'type'        => 'string',
1153
					'context'     => array( 'view', 'edit' ),
1154
					'readonly'    => true,
1155
				),
1156
				'total' => array(
1157
					'description' => __( 'Grand total.', 'woocommerce' ),
1158
					'type'        => 'string',
1159
					'context'     => array( 'view', 'edit' ),
1160
					'readonly'    => true,
1161
				),
1162
				'total_tax' => array(
1163
					'description' => __( 'Sum of all taxes.', 'woocommerce' ),
1164
					'type'        => 'string',
1165
					'context'     => array( 'view', 'edit' ),
1166
					'readonly'    => true,
1167
				),
1168
				'billing' => array(
1169
					'description' => __( 'Billing address.', 'woocommerce' ),
1170
					'type'        => 'array',
1171
					'context'     => array( 'view', 'edit' ),
1172
					'properties'  => array(
1173
						'first_name' => array(
1174
							'description' => __( 'First name.', 'woocommerce' ),
1175
							'type'        => 'string',
1176
							'context'     => array( 'view', 'edit' ),
1177
						),
1178
						'last_name' => array(
1179
							'description' => __( 'Last name.', 'woocommerce' ),
1180
							'type'        => 'string',
1181
							'context'     => array( 'view', 'edit' ),
1182
						),
1183
						'company' => array(
1184
							'description' => __( 'Company name.', 'woocommerce' ),
1185
							'type'        => 'string',
1186
							'context'     => array( 'view', 'edit' ),
1187
						),
1188
						'address_1' => array(
1189
							'description' => __( 'Address line 1.', 'woocommerce' ),
1190
							'type'        => 'string',
1191
							'context'     => array( 'view', 'edit' ),
1192
						),
1193
						'address_2' => array(
1194
							'description' => __( 'Address line 2.', 'woocommerce' ),
1195
							'type'        => 'string',
1196
							'context'     => array( 'view', 'edit' ),
1197
						),
1198
						'city' => array(
1199
							'description' => __( 'City name.', 'woocommerce' ),
1200
							'type'        => 'string',
1201
							'context'     => array( 'view', 'edit' ),
1202
						),
1203
						'state' => array(
1204
							'description' => __( 'ISO code or name of the state, province or district.', 'woocommerce' ),
1205
							'type'        => 'string',
1206
							'context'     => array( 'view', 'edit' ),
1207
						),
1208
						'postcode' => array(
1209
							'description' => __( 'Postal code.', 'woocommerce' ),
1210
							'type'        => 'string',
1211
							'context'     => array( 'view', 'edit' ),
1212
						),
1213
						'country' => array(
1214
							'description' => __( 'Country code in ISO 3166-1 alpha-2 format.', 'woocommerce' ),
1215
							'type'        => 'string',
1216
							'context'     => array( 'view', 'edit' ),
1217
						),
1218
						'email' => array(
1219
							'description' => __( 'Email address.', 'woocommerce' ),
1220
							'type'        => 'string',
1221
							'format'      => 'email',
1222
							'context'     => array( 'view', 'edit' ),
1223
						),
1224
						'phone' => array(
1225
							'description' => __( 'Phone number.', 'woocommerce' ),
1226
							'type'        => 'string',
1227
							'context'     => array( 'view', 'edit' ),
1228
						),
1229
					),
1230
				),
1231
				'shipping' => array(
1232
					'description' => __( 'Shipping address.', 'woocommerce' ),
1233
					'type'        => 'array',
1234
					'context'     => array( 'view', 'edit' ),
1235
					'properties'  => array(
1236
						'first_name' => array(
1237
							'description' => __( 'First name.', 'woocommerce' ),
1238
							'type'        => 'string',
1239
							'context'     => array( 'view', 'edit' ),
1240
						),
1241
						'last_name' => array(
1242
							'description' => __( 'Last name.', 'woocommerce' ),
1243
							'type'        => 'string',
1244
							'context'     => array( 'view', 'edit' ),
1245
						),
1246
						'company' => array(
1247
							'description' => __( 'Company name.', 'woocommerce' ),
1248
							'type'        => 'string',
1249
							'context'     => array( 'view', 'edit' ),
1250
						),
1251
						'address_1' => array(
1252
							'description' => __( 'Address line 1.', 'woocommerce' ),
1253
							'type'        => 'string',
1254
							'context'     => array( 'view', 'edit' ),
1255
						),
1256
						'address_2' => array(
1257
							'description' => __( 'Address line 2.', 'woocommerce' ),
1258
							'type'        => 'string',
1259
							'context'     => array( 'view', 'edit' ),
1260
						),
1261
						'city' => array(
1262
							'description' => __( 'City name.', 'woocommerce' ),
1263
							'type'        => 'string',
1264
							'context'     => array( 'view', 'edit' ),
1265
						),
1266
						'state' => array(
1267
							'description' => __( 'ISO code or name of the state, province or district.', 'woocommerce' ),
1268
							'type'        => 'string',
1269
							'context'     => array( 'view', 'edit' ),
1270
						),
1271
						'postcode' => array(
1272
							'description' => __( 'Postal code.', 'woocommerce' ),
1273
							'type'        => 'string',
1274
							'context'     => array( 'view', 'edit' ),
1275
						),
1276
						'country' => array(
1277
							'description' => __( 'Country code in ISO 3166-1 alpha-2 format.', 'woocommerce' ),
1278
							'type'        => 'string',
1279
							'context'     => array( 'view', 'edit' ),
1280
						),
1281
					),
1282
				),
1283
				'payment_method' => array(
1284
					'description' => __( 'Payment method ID.', 'woocommerce' ),
1285
					'type'        => 'string',
1286
					'context'     => array( 'view', 'edit' ),
1287
				),
1288
				'payment_method_title' => array(
1289
					'description' => __( 'Payment method title.', 'woocommerce' ),
1290
					'type'        => 'string',
1291
					'context'     => array( 'view', 'edit' ),
1292
				),
1293
				'set_paid' => array(
1294
					'description' => __( 'Define if the order is paid. It will set the status to processing and reduce stock items.', 'woocommerce' ),
1295
					'type'        => 'boolean',
1296
					'default'     => false,
1297
					'context'     => array( 'view', 'edit' ),
1298
					'writeonly'   => true,
1299
				),
1300
				'transaction_id' => array(
1301
					'description' => __( 'Unique transaction ID.', 'woocommerce' ),
1302
					'type'        => 'boolean',
1303
					'context'     => array( 'view', 'edit' ),
1304
				),
1305
				'customer_ip_address' => array(
1306
					'description' => __( "Customer's IP address.", 'woocommerce' ),
1307
					'type'        => 'string',
1308
					'context'     => array( 'view', 'edit' ),
1309
					'readonly'    => true,
1310
				),
1311
				'customer_user_agent' => array(
1312
					'description' => __( 'User agent of the customer.', 'woocommerce' ),
1313
					'type'        => 'string',
1314
					'context'     => array( 'view', 'edit' ),
1315
					'readonly'    => true,
1316
				),
1317
				'created_via' => array(
1318
					'description' => __( 'Shows where the order was created.', 'woocommerce' ),
1319
					'type'        => 'string',
1320
					'context'     => array( 'view', 'edit' ),
1321
					'readonly'    => true,
1322
				),
1323
				'customer_note' => array(
1324
					'description' => __( 'Note left by customer during checkout.', 'woocommerce' ),
1325
					'type'        => 'string',
1326
					'context'     => array( 'view', 'edit' ),
1327
				),
1328
				'date_completed' => array(
1329
					'description' => __( "The date the order was completed, in the site's timezone.", 'woocommerce' ),
1330
					'type'        => 'date-time',
1331
					'context'     => array( 'view', 'edit' ),
1332
					'readonly'    => true,
1333
				),
1334
				'date_paid' => array(
1335
					'description' => __( "The date the order has been paid, in the site's timezone.", 'woocommerce' ),
1336
					'type'        => 'date-time',
1337
					'context'     => array( 'view', 'edit' ),
1338
					'readonly'    => true,
1339
				),
1340
				'cart_hash' => array(
1341
					'description' => __( 'MD5 hash of cart items to ensure orders are not modified.', 'woocommerce' ),
1342
					'type'        => 'float',
1343
					'context'     => array( 'view', 'edit' ),
1344
					'readonly'    => true,
1345
				),
1346
				'line_items' => array(
1347
					'description' => __( 'Line items data.', 'woocommerce' ),
1348
					'type'        => 'array',
1349
					'context'     => array( 'view', 'edit' ),
1350
					'properties'  => array(
1351
						'id' => array(
1352
							'description' => __( 'Item ID.', 'woocommerce' ),
1353
							'type'        => 'integer',
1354
							'context'     => array( 'view', 'edit' ),
1355
							'readonly'    => true,
1356
						),
1357
						'name' => array(
1358
							'description' => __( 'Product name.', 'woocommerce' ),
1359
							'type'        => 'integer',
1360
							'context'     => array( 'view', 'edit' ),
1361
							'readonly'    => true,
1362
						),
1363
						'sku' => array(
1364
							'description' => __( 'Product SKU.', 'woocommerce' ),
1365
							'type'        => 'string',
1366
							'context'     => array( 'view', 'edit' ),
1367
							'readonly'    => true,
1368
						),
1369
						'product_id' => array(
1370
							'description' => __( 'Product ID.', 'woocommerce' ),
1371
							'type'        => 'integer',
1372
							'context'     => array( 'view', 'edit' ),
1373
						),
1374
						'variation_id' => array(
1375
							'description' => __( 'Variation ID, if applicable.', 'woocommerce' ),
1376
							'type'        => 'integer',
1377
							'context'     => array( 'view', 'edit' ),
1378
						),
1379
						'quantity' => array(
1380
							'description' => __( 'Quantity ordered.', 'woocommerce' ),
1381
							'type'        => 'integer',
1382
							'context'     => array( 'view', 'edit' ),
1383
						),
1384
						'tax_class' => array(
1385
							'description' => __( 'Tax class of product.', 'woocommerce' ),
1386
							'type'        => 'integer',
1387
							'context'     => array( 'view', 'edit' ),
1388
							'readonly'    => true,
1389
						),
1390
						'price' => array(
1391
							'description' => __( 'Product price.', 'woocommerce' ),
1392
							'type'        => 'string',
1393
							'context'     => array( 'view', 'edit' ),
1394
							'readonly'    => true,
1395
						),
1396
						'subtotal' => array(
1397
							'description' => __( 'Line subtotal (before discounts).', 'woocommerce' ),
1398
							'type'        => 'string',
1399
							'context'     => array( 'view', 'edit' ),
1400
						),
1401
						'subtotal_tax' => array(
1402
							'description' => __( 'Line subtotal tax (before discounts).', 'woocommerce' ),
1403
							'type'        => 'string',
1404
							'context'     => array( 'view', 'edit' ),
1405
						),
1406
						'total' => array(
1407
							'description' => __( 'Line total (after discounts).', 'woocommerce' ),
1408
							'type'        => 'string',
1409
							'context'     => array( 'view', 'edit' ),
1410
						),
1411
						'total_tax' => array(
1412
							'description' => __( 'Line total tax (after discounts).', 'woocommerce' ),
1413
							'type'        => 'string',
1414
							'context'     => array( 'view', 'edit' ),
1415
						),
1416
						'taxes' => array(
1417
							'description' => __( 'Line total tax.', 'woocommerce' ),
1418
							'type'        => 'array',
1419
							'context'     => array( 'view', 'edit' ),
1420
							'readonly'    => true,
1421
							'properties'  => array(
1422
								'id' => array(
1423
									'description' => __( 'Tax rate ID.', 'woocommerce' ),
1424
									'type'        => 'integer',
1425
									'context'     => array( 'view', 'edit' ),
1426
									'readonly'    => true,
1427
								),
1428
								'total' => array(
1429
									'description' => __( 'Tax total.', 'woocommerce' ),
1430
									'type'        => 'string',
1431
									'context'     => array( 'view', 'edit' ),
1432
									'readonly'    => true,
1433
								),
1434
								'subtotal' => array(
1435
									'description' => __( 'Tax subtotal.', 'woocommerce' ),
1436
									'type'        => 'string',
1437
									'context'     => array( 'view', 'edit' ),
1438
									'readonly'    => true,
1439
								),
1440
							),
1441
						),
1442
						'meta' => array(
1443
							'description' => __( 'Line item meta data.', 'woocommerce' ),
1444
							'type'        => 'array',
1445
							'context'     => array( 'view', 'edit' ),
1446
							'readonly'    => true,
1447
							'properties'  => array(
1448
								'key' => array(
1449
									'description' => __( 'Meta key.', 'woocommerce' ),
1450
									'type'        => 'string',
1451
									'context'     => array( 'view', 'edit' ),
1452
									'readonly'    => true,
1453
								),
1454
								'label' => array(
1455
									'description' => __( 'Meta label.', 'woocommerce' ),
1456
									'type'        => 'string',
1457
									'context'     => array( 'view', 'edit' ),
1458
									'readonly'    => true,
1459
								),
1460
								'value' => array(
1461
									'description' => __( 'Meta value.', 'woocommerce' ),
1462
									'type'        => 'string',
1463
									'context'     => array( 'view', 'edit' ),
1464
									'readonly'    => true,
1465
								),
1466
							),
1467
						),
1468
					),
1469
				),
1470
				'tax_lines' => array(
1471
					'description' => __( 'Tax lines data.', 'woocommerce' ),
1472
					'type'        => 'array',
1473
					'context'     => array( 'view', 'edit' ),
1474
					'readonly'    => true,
1475
					'properties'  => array(
1476
						'id' => array(
1477
							'description' => __( 'Item ID.', 'woocommerce' ),
1478
							'type'        => 'integer',
1479
							'context'     => array( 'view', 'edit' ),
1480
							'readonly'    => true,
1481
						),
1482
						'rate_code' => array(
1483
							'description' => __( 'Tax rate code.', 'woocommerce' ),
1484
							'type'        => 'string',
1485
							'context'     => array( 'view', 'edit' ),
1486
							'readonly'    => true,
1487
						),
1488
						'rate_id' => array(
1489
							'description' => __( 'Tax rate ID.', 'woocommerce' ),
1490
							'type'        => 'string',
1491
							'context'     => array( 'view', 'edit' ),
1492
							'readonly'    => true,
1493
						),
1494
						'label' => array(
1495
							'description' => __( 'Tax rate label.', 'woocommerce' ),
1496
							'type'        => 'string',
1497
							'context'     => array( 'view', 'edit' ),
1498
							'readonly'    => true,
1499
						),
1500
						'compound' => array(
1501
							'description' => __( 'Show if is a compound tax rate.', 'woocommerce' ),
1502
							'type'        => 'boolean',
1503
							'context'     => array( 'view', 'edit' ),
1504
							'readonly'    => true,
1505
						),
1506
						'tax_total' => array(
1507
							'description' => __( 'Tax total (not including shipping taxes).', 'woocommerce' ),
1508
							'type'        => 'string',
1509
							'context'     => array( 'view', 'edit' ),
1510
							'readonly'    => true,
1511
						),
1512
						'shipping_tax_total' => array(
1513
							'description' => __( 'Shipping tax total.', 'woocommerce' ),
1514
							'type'        => 'string',
1515
							'context'     => array( 'view', 'edit' ),
1516
							'readonly'    => true,
1517
						),
1518
					),
1519
				),
1520
				'shipping_lines' => array(
1521
					'description' => __( 'Shipping lines data.', 'woocommerce' ),
1522
					'type'        => 'array',
1523
					'context'     => array( 'view', 'edit' ),
1524
					'properties'  => array(
1525
						'id' => array(
1526
							'description' => __( 'Item ID.', 'woocommerce' ),
1527
							'type'        => 'integer',
1528
							'context'     => array( 'view', 'edit' ),
1529
							'readonly'    => true,
1530
						),
1531
						'method_title' => array(
1532
							'description' => __( 'Shipping method name.', 'woocommerce' ),
1533
							'type'        => 'string',
1534
							'context'     => array( 'view', 'edit' ),
1535
						),
1536
						'method_id' => array(
1537
							'description' => __( 'Shipping method ID.', 'woocommerce' ),
1538
							'type'        => 'integer',
1539
							'context'     => array( 'view', 'edit' ),
1540
						),
1541
						'total' => array(
1542
							'description' => __( 'Line total (after discounts).', 'woocommerce' ),
1543
							'type'        => 'string',
1544
							'context'     => array( 'view', 'edit' ),
1545
						),
1546
						'total_tax' => array(
1547
							'description' => __( 'Line total tax (after discounts).', 'woocommerce' ),
1548
							'type'        => 'string',
1549
							'context'     => array( 'view', 'edit' ),
1550
							'readonly'    => true,
1551
						),
1552
						'taxes' => array(
1553
							'description' => __( 'Line total tax.', 'woocommerce' ),
1554
							'type'        => 'array',
1555
							'context'     => array( 'view', 'edit' ),
1556
							'readonly'    => true,
1557
							'properties'  => array(
1558
								'id' => array(
1559
									'description' => __( 'Tax rate ID.', 'woocommerce' ),
1560
									'type'        => 'integer',
1561
									'context'     => array( 'view', 'edit' ),
1562
									'readonly'    => true,
1563
								),
1564
								'total' => array(
1565
									'description' => __( 'Tax total.', 'woocommerce' ),
1566
									'type'        => 'string',
1567
									'context'     => array( 'view', 'edit' ),
1568
									'readonly'    => true,
1569
								),
1570
							),
1571
						),
1572
					),
1573
				),
1574
				'fee_lines' => array(
1575
					'description' => __( 'Fee lines data.', 'woocommerce' ),
1576
					'type'        => 'array',
1577
					'context'     => array( 'view', 'edit' ),
1578
					'properties'  => array(
1579
						'id' => array(
1580
							'description' => __( 'Item ID.', 'woocommerce' ),
1581
							'type'        => 'integer',
1582
							'context'     => array( 'view', 'edit' ),
1583
							'readonly'    => true,
1584
						),
1585
						'name' => array(
1586
							'description' => __( 'Fee name.', 'woocommerce' ),
1587
							'type'        => 'string',
1588
							'context'     => array( 'view', 'edit' ),
1589
						),
1590
						'tax_class' => array(
1591
							'description' => __( 'Tax class of fee.', 'woocommerce' ),
1592
							'type'        => 'string',
1593
							'context'     => array( 'view', 'edit' ),
1594
						),
1595
						'tax_status' => array(
1596
							'description' => __( 'Tax status of fee.', 'woocommerce' ),
1597
							'type'        => 'string',
1598
							'context'     => array( 'view', 'edit' ),
1599
						),
1600
						'total' => array(
1601
							'description' => __( 'Line total tax (after discounts).', 'woocommerce' ),
1602
							'type'        => 'string',
1603
							'context'     => array( 'view', 'edit' ),
1604
						),
1605
						'total_tax' => array(
1606
							'description' => __( 'Line total tax (after discounts).', 'woocommerce' ),
1607
							'type'        => 'string',
1608
							'context'     => array( 'view', 'edit' ),
1609
						),
1610
						'taxes' => array(
1611
							'description' => __( 'Line total tax.', 'woocommerce' ),
1612
							'type'        => 'array',
1613
							'context'     => array( 'view', 'edit' ),
1614
							'readonly'    => true,
1615
							'properties'  => array(
1616
								'id' => array(
1617
									'description' => __( 'Tax rate ID.', 'woocommerce' ),
1618
									'type'        => 'integer',
1619
									'context'     => array( 'view', 'edit' ),
1620
									'readonly'    => true,
1621
								),
1622
								'total' => array(
1623
									'description' => __( 'Tax total.', 'woocommerce' ),
1624
									'type'        => 'string',
1625
									'context'     => array( 'view', 'edit' ),
1626
									'readonly'    => true,
1627
								),
1628
								'subtotal' => array(
1629
									'description' => __( 'Tax subtotal.', 'woocommerce' ),
1630
									'type'        => 'string',
1631
									'context'     => array( 'view', 'edit' ),
1632
									'readonly'    => true,
1633
								),
1634
							),
1635
						),
1636
					),
1637
				),
1638
				'coupon_lines' => array(
1639
					'description' => __( 'Coupons line data.', 'woocommerce' ),
1640
					'type'        => 'array',
1641
					'context'     => array( 'view', 'edit' ),
1642
					'properties'  => array(
1643
						'id' => array(
1644
							'description' => __( 'Item ID.', 'woocommerce' ),
1645
							'type'        => 'integer',
1646
							'context'     => array( 'view', 'edit' ),
1647
							'readonly'    => true,
1648
						),
1649
						'code' => array(
1650
							'description' => __( 'Coupon code.', 'woocommerce' ),
1651
							'type'        => 'string',
1652
							'context'     => array( 'view', 'edit' ),
1653
						),
1654
						'discount' => array(
1655
							'description' => __( 'Discount total.', 'woocommerce' ),
1656
							'type'        => 'string',
1657
							'context'     => array( 'view', 'edit' ),
1658
						),
1659
						'discount_tax' => array(
1660
							'description' => __( 'Discount total tax.', 'woocommerce' ),
1661
							'type'        => 'string',
1662
							'context'     => array( 'view', 'edit' ),
1663
							'readonly'    => true,
1664
						),
1665
					),
1666
				),
1667
			),
1668
		);
1669
1670
		return $this->add_additional_fields_schema( $schema );
1671
	}
1672
1673
	/**
1674
	 * Get the query params for collections.
1675
	 *
1676
	 * @return array
1677
	 */
1678
	public function get_collection_params() {
1679
		$params = parent::get_collection_params();
1680
1681
		$params['status'] = array(
1682
			'default'           => 'any',
1683
			'description'       => __( 'Limit result set to orders assigned a specific status.', 'woocommerce' ),
1684
			'type'              => 'string',
1685
			'enum'              => array_merge( array( 'any' ), $this->get_order_statuses() ),
1686
			'sanitize_callback' => 'sanitize_key',
1687
			'validate_callback' => 'rest_validate_request_arg',
1688
		);
1689
		$params['customer'] = array(
1690
			'description'       => __( 'Limit result set to orders assigned a specific customer.', 'woocommerce' ),
1691
			'type'              => 'integer',
1692
			'sanitize_callback' => 'absint',
1693
			'validate_callback' => 'rest_validate_request_arg',
1694
		);
1695
		$params['product'] = array(
1696
			'description'       => __( 'Limit result set to orders assigned a specific product.', 'woocommerce' ),
1697
			'type'              => 'integer',
1698
			'sanitize_callback' => 'absint',
1699
			'validate_callback' => 'rest_validate_request_arg',
1700
		);
1701
		$params['dp'] = array(
1702
			'default'           => 2,
1703
			'description'       => __( 'Number of decimal points to use in each resource.', 'woocommerce' ),
1704
			'type'              => 'integer',
1705
			'sanitize_callback' => 'absint',
1706
			'validate_callback' => 'rest_validate_request_arg',
1707
		);
1708
1709
		return $params;
1710
	}
1711
}
1712