1
|
|
|
<?php |
|
|
|
|
2
|
|
|
/** |
3
|
|
|
* WooCommerce API Orders Class |
4
|
|
|
* |
5
|
|
|
* Handles requests to the /orders endpoint |
6
|
|
|
* |
7
|
|
|
* @author WooThemes |
8
|
|
|
* @category API |
9
|
|
|
* @package WooCommerce/API |
10
|
|
|
* @since 2.1 |
11
|
|
|
*/ |
12
|
|
|
|
13
|
|
|
if ( ! defined( 'ABSPATH' ) ) { |
14
|
|
|
exit; // Exit if accessed directly |
15
|
|
|
} |
16
|
|
|
|
17
|
|
|
class WC_API_Orders extends WC_API_Resource { |
18
|
|
|
|
19
|
|
|
/** @var string $base the route base */ |
20
|
|
|
protected $base = '/orders'; |
21
|
|
|
|
22
|
|
|
/** @var string $post_type the custom post type */ |
23
|
|
|
protected $post_type = 'shop_order'; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* Register the routes for this class |
27
|
|
|
* |
28
|
|
|
* GET|POST /orders |
29
|
|
|
* GET /orders/count |
30
|
|
|
* GET|PUT|DELETE /orders/<id> |
31
|
|
|
* GET /orders/<id>/notes |
32
|
|
|
* |
33
|
|
|
* @since 2.1 |
34
|
|
|
* @param array $routes |
35
|
|
|
* @return array |
36
|
|
|
*/ |
37
|
|
|
public function register_routes( $routes ) { |
38
|
|
|
|
39
|
|
|
# GET|POST /orders |
40
|
|
|
$routes[ $this->base ] = array( |
41
|
|
|
array( array( $this, 'get_orders' ), WC_API_Server::READABLE ), |
42
|
|
|
array( array( $this, 'create_order' ), WC_API_Server::CREATABLE | WC_API_Server::ACCEPT_DATA ), |
43
|
|
|
); |
44
|
|
|
|
45
|
|
|
# GET /orders/count |
46
|
|
|
$routes[ $this->base . '/count' ] = array( |
47
|
|
|
array( array( $this, 'get_orders_count' ), WC_API_Server::READABLE ), |
48
|
|
|
); |
49
|
|
|
|
50
|
|
|
# GET /orders/statuses |
51
|
|
|
$routes[ $this->base . '/statuses' ] = array( |
52
|
|
|
array( array( $this, 'get_order_statuses' ), WC_API_Server::READABLE ), |
53
|
|
|
); |
54
|
|
|
|
55
|
|
|
# GET|PUT|DELETE /orders/<id> |
56
|
|
|
$routes[ $this->base . '/(?P<id>\d+)' ] = array( |
57
|
|
|
array( array( $this, 'get_order' ), WC_API_Server::READABLE ), |
58
|
|
|
array( array( $this, 'edit_order' ), WC_API_Server::EDITABLE | WC_API_Server::ACCEPT_DATA ), |
59
|
|
|
array( array( $this, 'delete_order' ), WC_API_Server::DELETABLE ), |
60
|
|
|
); |
61
|
|
|
|
62
|
|
|
# GET|POST /orders/<id>/notes |
63
|
|
|
$routes[ $this->base . '/(?P<order_id>\d+)/notes' ] = array( |
64
|
|
|
array( array( $this, 'get_order_notes' ), WC_API_Server::READABLE ), |
65
|
|
|
array( array( $this, 'create_order_note' ), WC_API_SERVER::CREATABLE | WC_API_Server::ACCEPT_DATA ), |
66
|
|
|
); |
67
|
|
|
|
68
|
|
|
# GET|PUT|DELETE /orders/<order_id>/notes/<id> |
69
|
|
|
$routes[ $this->base . '/(?P<order_id>\d+)/notes/(?P<id>\d+)' ] = array( |
70
|
|
|
array( array( $this, 'get_order_note' ), WC_API_Server::READABLE ), |
71
|
|
|
array( array( $this, 'edit_order_note' ), WC_API_SERVER::EDITABLE | WC_API_Server::ACCEPT_DATA ), |
72
|
|
|
array( array( $this, 'delete_order_note' ), WC_API_SERVER::DELETABLE ), |
73
|
|
|
); |
74
|
|
|
|
75
|
|
|
# GET|POST /orders/<order_id>/refunds |
76
|
|
|
$routes[ $this->base . '/(?P<order_id>\d+)/refunds' ] = array( |
77
|
|
|
array( array( $this, 'get_order_refunds' ), WC_API_Server::READABLE ), |
78
|
|
|
array( array( $this, 'create_order_refund' ), WC_API_SERVER::CREATABLE | WC_API_Server::ACCEPT_DATA ), |
79
|
|
|
); |
80
|
|
|
|
81
|
|
|
# GET|PUT|DELETE /orders/<order_id>/refunds/<id> |
82
|
|
|
$routes[ $this->base . '/(?P<order_id>\d+)/refunds/(?P<id>\d+)' ] = array( |
83
|
|
|
array( array( $this, 'get_order_refund' ), WC_API_Server::READABLE ), |
84
|
|
|
array( array( $this, 'edit_order_refund' ), WC_API_SERVER::EDITABLE | WC_API_Server::ACCEPT_DATA ), |
85
|
|
|
array( array( $this, 'delete_order_refund' ), WC_API_SERVER::DELETABLE ), |
86
|
|
|
); |
87
|
|
|
|
88
|
|
|
# POST|PUT /orders/bulk |
89
|
|
|
$routes[ $this->base . '/bulk' ] = array( |
90
|
|
|
array( array( $this, 'bulk' ), WC_API_Server::EDITABLE | WC_API_Server::ACCEPT_DATA ), |
91
|
|
|
); |
92
|
|
|
|
93
|
|
|
return $routes; |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
/** |
97
|
|
|
* Get all orders |
98
|
|
|
* |
99
|
|
|
* @since 2.1 |
100
|
|
|
* @param string $fields |
101
|
|
|
* @param array $filter |
102
|
|
|
* @param string $status |
103
|
|
|
* @param int $page |
104
|
|
|
* @return array |
105
|
|
|
*/ |
106
|
|
View Code Duplication |
public function get_orders( $fields = null, $filter = array(), $status = null, $page = 1 ) { |
|
|
|
|
107
|
|
|
|
108
|
|
|
if ( ! empty( $status ) ) { |
109
|
|
|
$filter['status'] = $status; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
$filter['page'] = $page; |
113
|
|
|
|
114
|
|
|
$query = $this->query_orders( $filter ); |
115
|
|
|
|
116
|
|
|
$orders = array(); |
117
|
|
|
|
118
|
|
|
foreach ( $query->posts as $order_id ) { |
119
|
|
|
|
120
|
|
|
if ( ! $this->is_readable( $order_id ) ) { |
121
|
|
|
continue; |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
$orders[] = current( $this->get_order( $order_id, $fields, $filter ) ); |
|
|
|
|
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
$this->server->add_pagination_headers( $query ); |
128
|
|
|
|
129
|
|
|
return array( 'orders' => $orders ); |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* Get the order for the given ID. |
135
|
|
|
* |
136
|
|
|
* @since 2.1 |
137
|
|
|
* @param int $id The order ID. |
138
|
|
|
* @param array $fields Request fields. |
139
|
|
|
* @param array $filter Request filters. |
140
|
|
|
* @return array |
141
|
|
|
*/ |
142
|
|
|
public function get_order( $id, $fields = null, $filter = array() ) { |
143
|
|
|
|
144
|
|
|
// Ensure order ID is valid & user has permission to read. |
145
|
|
|
$id = $this->validate_request( $id, $this->post_type, 'read' ); |
146
|
|
|
|
147
|
|
|
if ( is_wp_error( $id ) ) { |
148
|
|
|
return $id; |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
// Get the decimal precession. |
152
|
|
|
$dp = ( isset( $filter['dp'] ) ? intval( $filter['dp'] ) : 2 ); |
153
|
|
|
$order = wc_get_order( $id ); |
154
|
|
|
$order_post = get_post( $id ); |
155
|
|
|
$expand = array(); |
156
|
|
|
|
157
|
|
|
if ( ! empty( $filter['expand'] ) ) { |
158
|
|
|
$expand = explode( ',', $filter['expand'] ); |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
$order_data = array( |
162
|
|
|
'id' => $order->id, |
163
|
|
|
'order_number' => $order->get_order_number(), |
164
|
|
|
'order_key' => $order->order_key, |
165
|
|
|
'created_at' => $this->server->format_datetime( $order_post->post_date_gmt ), |
166
|
|
|
'updated_at' => $this->server->format_datetime( $order_post->post_modified_gmt ), |
167
|
|
|
'completed_at' => $this->server->format_datetime( $order->completed_date, true ), |
168
|
|
|
'status' => $order->get_status(), |
169
|
|
|
'currency' => $order->get_order_currency(), |
170
|
|
|
'total' => wc_format_decimal( $order->get_total(), $dp ), |
171
|
|
|
'subtotal' => wc_format_decimal( $order->get_subtotal(), $dp ), |
172
|
|
|
'total_line_items_quantity' => $order->get_item_count(), |
173
|
|
|
'total_tax' => wc_format_decimal( $order->get_total_tax(), $dp ), |
174
|
|
|
'total_shipping' => wc_format_decimal( $order->get_total_shipping(), $dp ), |
175
|
|
|
'cart_tax' => wc_format_decimal( $order->get_cart_tax(), $dp ), |
176
|
|
|
'shipping_tax' => wc_format_decimal( $order->get_shipping_tax(), $dp ), |
177
|
|
|
'total_discount' => wc_format_decimal( $order->get_total_discount(), $dp ), |
178
|
|
|
'shipping_methods' => $order->get_shipping_method(), |
179
|
|
|
'payment_details' => array( |
180
|
|
|
'method_id' => $order->payment_method, |
181
|
|
|
'method_title' => $order->payment_method_title, |
182
|
|
|
'paid' => isset( $order->paid_date ), |
183
|
|
|
), |
184
|
|
|
'billing_address' => array( |
185
|
|
|
'first_name' => $order->billing_first_name, |
186
|
|
|
'last_name' => $order->billing_last_name, |
187
|
|
|
'company' => $order->billing_company, |
188
|
|
|
'address_1' => $order->billing_address_1, |
189
|
|
|
'address_2' => $order->billing_address_2, |
190
|
|
|
'city' => $order->billing_city, |
191
|
|
|
'state' => $order->billing_state, |
192
|
|
|
'postcode' => $order->billing_postcode, |
193
|
|
|
'country' => $order->billing_country, |
194
|
|
|
'email' => $order->billing_email, |
195
|
|
|
'phone' => $order->billing_phone, |
196
|
|
|
), |
197
|
|
|
'shipping_address' => array( |
198
|
|
|
'first_name' => $order->shipping_first_name, |
199
|
|
|
'last_name' => $order->shipping_last_name, |
200
|
|
|
'company' => $order->shipping_company, |
201
|
|
|
'address_1' => $order->shipping_address_1, |
202
|
|
|
'address_2' => $order->shipping_address_2, |
203
|
|
|
'city' => $order->shipping_city, |
204
|
|
|
'state' => $order->shipping_state, |
205
|
|
|
'postcode' => $order->shipping_postcode, |
206
|
|
|
'country' => $order->shipping_country, |
207
|
|
|
), |
208
|
|
|
'note' => $order->customer_note, |
209
|
|
|
'customer_ip' => $order->customer_ip_address, |
210
|
|
|
'customer_user_agent' => $order->customer_user_agent, |
211
|
|
|
'customer_id' => $order->get_user_id(), |
212
|
|
|
'view_order_url' => $order->get_view_order_url(), |
213
|
|
|
'line_items' => array(), |
214
|
|
|
'shipping_lines' => array(), |
215
|
|
|
'tax_lines' => array(), |
216
|
|
|
'fee_lines' => array(), |
217
|
|
|
'coupon_lines' => array(), |
218
|
|
|
'is_vat_exempt' => $order->is_vat_exempt === 'yes' ? true : false, |
219
|
|
|
); |
220
|
|
|
|
221
|
|
|
// Add line items. |
222
|
|
|
foreach ( $order->get_items() as $item_id => $item ) { |
223
|
|
|
$product = $order->get_product_from_item( $item ); |
224
|
|
|
$product_id = null; |
225
|
|
|
$product_sku = null; |
226
|
|
|
|
227
|
|
|
// Check if the product exists. |
228
|
|
View Code Duplication |
if ( is_object( $product ) ) { |
|
|
|
|
229
|
|
|
$product_id = ( isset( $product->variation_id ) ) ? $product->variation_id : $product->id; |
230
|
|
|
$product_sku = $product->get_sku(); |
231
|
|
|
} |
232
|
|
|
|
233
|
|
|
$meta = new WC_Order_Item_Meta( $item, $product ); |
234
|
|
|
|
235
|
|
|
$item_meta = array(); |
236
|
|
|
|
237
|
|
|
$hideprefix = ( isset( $filter['all_item_meta'] ) && 'true' === $filter['all_item_meta'] ) ? null : '_'; |
238
|
|
|
|
239
|
|
View Code Duplication |
foreach ( $meta->get_formatted( $hideprefix ) as $meta_key => $formatted_meta ) { |
|
|
|
|
240
|
|
|
$item_meta[] = array( |
241
|
|
|
'key' => $formatted_meta['key'], |
242
|
|
|
'label' => $formatted_meta['label'], |
243
|
|
|
'value' => $formatted_meta['value'], |
244
|
|
|
); |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
$line_item = array( |
248
|
|
|
'id' => $item_id, |
249
|
|
|
'subtotal' => wc_format_decimal( $order->get_line_subtotal( $item, false, false ), $dp ), |
250
|
|
|
'subtotal_tax' => wc_format_decimal( $item['line_subtotal_tax'], $dp ), |
251
|
|
|
'total' => wc_format_decimal( $order->get_line_total( $item, false, false ), $dp ), |
252
|
|
|
'total_tax' => wc_format_decimal( $item['line_tax'], $dp ), |
253
|
|
|
'price' => wc_format_decimal( $order->get_item_total( $item, false, false ), $dp ), |
254
|
|
|
'quantity' => wc_stock_amount( $item['qty'] ), |
255
|
|
|
'tax_class' => ( ! empty( $item['tax_class'] ) ) ? $item['tax_class'] : null, |
256
|
|
|
'name' => $item['name'], |
257
|
|
|
'product_id' => $product_id, |
258
|
|
|
'sku' => $product_sku, |
259
|
|
|
'meta' => $item_meta, |
260
|
|
|
); |
261
|
|
|
|
262
|
|
View Code Duplication |
if ( in_array( 'products', $expand ) ) { |
|
|
|
|
263
|
|
|
$_product_data = WC()->api->WC_API_Products->get_product( $product_id ); |
264
|
|
|
|
265
|
|
|
if ( isset( $_product_data['product'] ) ) { |
266
|
|
|
$line_item['product_data'] = $_product_data['product']; |
267
|
|
|
} |
268
|
|
|
} |
269
|
|
|
|
270
|
|
|
$order_data['line_items'][] = $line_item; |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
// Add shipping. |
274
|
|
View Code Duplication |
foreach ( $order->get_shipping_methods() as $shipping_item_id => $shipping_item ) { |
|
|
|
|
275
|
|
|
$order_data['shipping_lines'][] = array( |
276
|
|
|
'id' => $shipping_item_id, |
277
|
|
|
'method_id' => $shipping_item['method_id'], |
278
|
|
|
'method_title' => $shipping_item['name'], |
279
|
|
|
'total' => wc_format_decimal( $shipping_item['cost'], $dp ), |
280
|
|
|
); |
281
|
|
|
} |
282
|
|
|
|
283
|
|
|
// Add taxes. |
284
|
|
|
foreach ( $order->get_tax_totals() as $tax_code => $tax ) { |
285
|
|
|
$tax_line = array( |
286
|
|
|
'id' => $tax->id, |
287
|
|
|
'rate_id' => $tax->rate_id, |
288
|
|
|
'code' => $tax_code, |
289
|
|
|
'title' => $tax->label, |
290
|
|
|
'total' => wc_format_decimal( $tax->amount, $dp ), |
291
|
|
|
'compound' => (bool) $tax->is_compound, |
292
|
|
|
); |
293
|
|
|
|
294
|
|
|
if ( in_array( 'taxes', $expand ) ) { |
295
|
|
|
$_rate_data = WC()->api->WC_API_Taxes->get_tax( $tax->rate_id ); |
296
|
|
|
|
297
|
|
|
if ( isset( $_rate_data['tax'] ) ) { |
298
|
|
|
$tax_line['rate_data'] = $_rate_data['tax']; |
299
|
|
|
} |
300
|
|
|
} |
301
|
|
|
|
302
|
|
|
$order_data['tax_lines'][] = $tax_line; |
303
|
|
|
} |
304
|
|
|
|
305
|
|
|
// Add fees. |
306
|
|
View Code Duplication |
foreach ( $order->get_fees() as $fee_item_id => $fee_item ) { |
|
|
|
|
307
|
|
|
$order_data['fee_lines'][] = array( |
308
|
|
|
'id' => $fee_item_id, |
309
|
|
|
'title' => $fee_item['name'], |
310
|
|
|
'tax_class' => ( ! empty( $fee_item['tax_class'] ) ) ? $fee_item['tax_class'] : null, |
311
|
|
|
'total' => wc_format_decimal( $order->get_line_total( $fee_item ), $dp ), |
312
|
|
|
'total_tax' => wc_format_decimal( $order->get_line_tax( $fee_item ), $dp ), |
313
|
|
|
); |
314
|
|
|
} |
315
|
|
|
|
316
|
|
|
// Add coupons. |
317
|
|
|
foreach ( $order->get_items( 'coupon' ) as $coupon_item_id => $coupon_item ) { |
318
|
|
|
$coupon_line = array( |
319
|
|
|
'id' => $coupon_item_id, |
320
|
|
|
'code' => $coupon_item['name'], |
321
|
|
|
'amount' => wc_format_decimal( $coupon_item['discount_amount'], $dp ), |
322
|
|
|
); |
323
|
|
|
|
324
|
|
View Code Duplication |
if ( in_array( 'coupons', $expand ) ) { |
|
|
|
|
325
|
|
|
$_coupon_data = WC()->api->WC_API_Coupons->get_coupon_by_code( $coupon_item['name'] ); |
326
|
|
|
|
327
|
|
|
if ( isset( $_coupon_data['coupon'] ) ) { |
328
|
|
|
$coupon_line['coupon_data'] = $_coupon_data['coupon']; |
329
|
|
|
} |
330
|
|
|
} |
331
|
|
|
|
332
|
|
|
$order_data['coupon_lines'][] = $coupon_line; |
333
|
|
|
} |
334
|
|
|
|
335
|
|
|
return array( 'order' => apply_filters( 'woocommerce_api_order_response', $order_data, $order, $fields, $this->server ) ); |
336
|
|
|
} |
337
|
|
|
|
338
|
|
|
/** |
339
|
|
|
* Get the total number of orders |
340
|
|
|
* |
341
|
|
|
* @since 2.4 |
342
|
|
|
* @param string $status |
343
|
|
|
* @param array $filter |
344
|
|
|
* @return array |
345
|
|
|
*/ |
346
|
|
|
public function get_orders_count( $status = null, $filter = array() ) { |
347
|
|
|
|
348
|
|
|
try { |
349
|
|
|
if ( ! current_user_can( 'read_private_shop_orders' ) ) { |
350
|
|
|
throw new WC_API_Exception( 'woocommerce_api_user_cannot_read_orders_count', __( 'You do not have permission to read the orders count', 'woocommerce' ), 401 ); |
351
|
|
|
} |
352
|
|
|
|
353
|
|
|
if ( ! empty( $status ) ) { |
354
|
|
|
|
355
|
|
|
if ( $status == 'any' ) { |
356
|
|
|
|
357
|
|
|
$order_statuses = array(); |
358
|
|
|
|
359
|
|
|
foreach ( wc_get_order_statuses() as $slug => $name ) { |
360
|
|
|
$filter['status'] = str_replace( 'wc-', '', $slug ); |
361
|
|
|
$query = $this->query_orders( $filter ); |
362
|
|
|
$order_statuses[ str_replace( 'wc-', '', $slug ) ] = (int) $query->found_posts; |
363
|
|
|
} |
364
|
|
|
|
365
|
|
|
return array( 'count' => $order_statuses ); |
366
|
|
|
|
367
|
|
|
} else { |
368
|
|
|
$filter['status'] = $status; |
369
|
|
|
} |
370
|
|
|
} |
371
|
|
|
|
372
|
|
|
$query = $this->query_orders( $filter ); |
373
|
|
|
|
374
|
|
|
return array( 'count' => (int) $query->found_posts ); |
375
|
|
|
|
376
|
|
|
} catch ( WC_API_Exception $e ) { |
377
|
|
|
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); |
378
|
|
|
} |
379
|
|
|
} |
380
|
|
|
|
381
|
|
|
/** |
382
|
|
|
* Get a list of valid order statuses |
383
|
|
|
* |
384
|
|
|
* Note this requires no specific permissions other than being an authenticated |
385
|
|
|
* API user. Order statuses (particularly custom statuses) could be considered |
386
|
|
|
* private information which is why it's not in the API index. |
387
|
|
|
* |
388
|
|
|
* @since 2.1 |
389
|
|
|
* @return array |
390
|
|
|
*/ |
391
|
|
|
public function get_order_statuses() { |
392
|
|
|
|
393
|
|
|
$order_statuses = array(); |
394
|
|
|
|
395
|
|
|
foreach ( wc_get_order_statuses() as $slug => $name ) { |
396
|
|
|
$order_statuses[ str_replace( 'wc-', '', $slug ) ] = $name; |
397
|
|
|
} |
398
|
|
|
|
399
|
|
|
return array( 'order_statuses' => apply_filters( 'woocommerce_api_order_statuses_response', $order_statuses, $this ) ); |
400
|
|
|
} |
401
|
|
|
|
402
|
|
|
/** |
403
|
|
|
* Create an order |
404
|
|
|
* |
405
|
|
|
* @since 2.2 |
406
|
|
|
* @param array $data raw order data |
407
|
|
|
* @return array |
408
|
|
|
*/ |
409
|
|
|
public function create_order( $data ) { |
410
|
|
|
global $wpdb; |
411
|
|
|
|
412
|
|
|
wc_transaction_query( 'start' ); |
413
|
|
|
|
414
|
|
|
try { |
415
|
|
View Code Duplication |
if ( ! isset( $data['order'] ) ) { |
|
|
|
|
416
|
|
|
throw new WC_API_Exception( 'woocommerce_api_missing_order_data', sprintf( __( 'No %1$s data specified to create %1$s', 'woocommerce' ), 'order' ), 400 ); |
417
|
|
|
} |
418
|
|
|
|
419
|
|
|
$data = $data['order']; |
420
|
|
|
|
421
|
|
|
// permission check |
422
|
|
|
if ( ! current_user_can( 'publish_shop_orders' ) ) { |
423
|
|
|
throw new WC_API_Exception( 'woocommerce_api_user_cannot_create_order', __( 'You do not have permission to create orders', 'woocommerce' ), 401 ); |
424
|
|
|
} |
425
|
|
|
|
426
|
|
|
$data = apply_filters( 'woocommerce_api_create_order_data', $data, $this ); |
427
|
|
|
|
428
|
|
|
// default order args, note that status is checked for validity in wc_create_order() |
429
|
|
|
$default_order_args = array( |
430
|
|
|
'status' => isset( $data['status'] ) ? $data['status'] : '', |
431
|
|
|
'customer_note' => isset( $data['note'] ) ? $data['note'] : null, |
432
|
|
|
); |
433
|
|
|
|
434
|
|
|
// if creating order for existing customer |
435
|
|
|
if ( ! empty( $data['customer_id'] ) ) { |
436
|
|
|
|
437
|
|
|
// make sure customer exists |
438
|
|
|
if ( false === get_user_by( 'id', $data['customer_id'] ) ) { |
439
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_customer_id', __( 'Customer ID is invalid', 'woocommerce' ), 400 ); |
440
|
|
|
} |
441
|
|
|
|
442
|
|
|
$default_order_args['customer_id'] = $data['customer_id']; |
443
|
|
|
} |
444
|
|
|
|
445
|
|
|
// create the pending order |
446
|
|
|
$order = $this->create_base_order( $default_order_args, $data ); |
447
|
|
|
|
448
|
|
View Code Duplication |
if ( is_wp_error( $order ) ) { |
|
|
|
|
449
|
|
|
throw new WC_API_Exception( 'woocommerce_api_cannot_create_order', sprintf( __( 'Cannot create order: %s', 'woocommerce' ), implode( ', ', $order->get_error_messages() ) ), 400 ); |
|
|
|
|
450
|
|
|
} |
451
|
|
|
|
452
|
|
|
// billing/shipping addresses |
453
|
|
|
$this->set_order_addresses( $order, $data ); |
454
|
|
|
|
455
|
|
|
$lines = array( |
456
|
|
|
'line_item' => 'line_items', |
457
|
|
|
'shipping' => 'shipping_lines', |
458
|
|
|
'fee' => 'fee_lines', |
459
|
|
|
'coupon' => 'coupon_lines', |
460
|
|
|
); |
461
|
|
|
|
462
|
|
View Code Duplication |
foreach ( $lines as $line_type => $line ) { |
|
|
|
|
463
|
|
|
|
464
|
|
|
if ( isset( $data[ $line ] ) && is_array( $data[ $line ] ) ) { |
465
|
|
|
|
466
|
|
|
$set_item = "set_{$line_type}"; |
467
|
|
|
|
468
|
|
|
foreach ( $data[ $line ] as $item ) { |
469
|
|
|
|
470
|
|
|
$this->$set_item( $order, $item, 'create' ); |
471
|
|
|
} |
472
|
|
|
} |
473
|
|
|
} |
474
|
|
|
|
475
|
|
|
// set is vat exempt |
476
|
|
|
if ( isset( $data['is_vat_exempt'] ) ) { |
477
|
|
|
update_post_meta( $order->id, '_is_vat_exempt', $data['is_vat_exempt'] ? 'yes' : 'no' ); |
478
|
|
|
} |
479
|
|
|
|
480
|
|
|
// calculate totals and set them |
481
|
|
|
$order->calculate_totals(); |
482
|
|
|
|
483
|
|
|
// payment method (and payment_complete() if `paid` == true) |
|
|
|
|
484
|
|
View Code Duplication |
if ( isset( $data['payment_details'] ) && is_array( $data['payment_details'] ) ) { |
|
|
|
|
485
|
|
|
|
486
|
|
|
// method ID & title are required |
487
|
|
|
if ( empty( $data['payment_details']['method_id'] ) || empty( $data['payment_details']['method_title'] ) ) { |
488
|
|
|
throw new WC_API_Exception( 'woocommerce_invalid_payment_details', __( 'Payment method ID and title are required', 'woocommerce' ), 400 ); |
489
|
|
|
} |
490
|
|
|
|
491
|
|
|
update_post_meta( $order->id, '_payment_method', $data['payment_details']['method_id'] ); |
492
|
|
|
update_post_meta( $order->id, '_payment_method_title', $data['payment_details']['method_title'] ); |
493
|
|
|
|
494
|
|
|
// mark as paid if set |
495
|
|
|
if ( isset( $data['payment_details']['paid'] ) && true === $data['payment_details']['paid'] ) { |
496
|
|
|
$order->payment_complete( isset( $data['payment_details']['transaction_id'] ) ? $data['payment_details']['transaction_id'] : '' ); |
497
|
|
|
} |
498
|
|
|
} |
499
|
|
|
|
500
|
|
|
// set order currency |
501
|
|
View Code Duplication |
if ( isset( $data['currency'] ) ) { |
|
|
|
|
502
|
|
|
|
503
|
|
|
if ( ! array_key_exists( $data['currency'], get_woocommerce_currencies() ) ) { |
504
|
|
|
throw new WC_API_Exception( 'woocommerce_invalid_order_currency', __( 'Provided order currency is invalid', 'woocommerce'), 400 ); |
505
|
|
|
} |
506
|
|
|
|
507
|
|
|
update_post_meta( $order->id, '_order_currency', $data['currency'] ); |
508
|
|
|
} |
509
|
|
|
|
510
|
|
|
// set order meta |
511
|
|
View Code Duplication |
if ( isset( $data['order_meta'] ) && is_array( $data['order_meta'] ) ) { |
|
|
|
|
512
|
|
|
$this->set_order_meta( $order->id, $data['order_meta'] ); |
513
|
|
|
} |
514
|
|
|
|
515
|
|
|
// HTTP 201 Created |
516
|
|
|
$this->server->send_status( 201 ); |
517
|
|
|
|
518
|
|
|
wc_delete_shop_order_transients( $order->id ); |
519
|
|
|
|
520
|
|
|
do_action( 'woocommerce_api_create_order', $order->id, $data, $this ); |
521
|
|
|
|
522
|
|
|
wc_transaction_query( 'commit' ); |
523
|
|
|
|
524
|
|
|
return $this->get_order( $order->id ); |
525
|
|
|
|
526
|
|
|
} catch ( WC_API_Exception $e ) { |
527
|
|
|
|
528
|
|
|
wc_transaction_query( 'rollback' ); |
529
|
|
|
|
530
|
|
|
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); |
531
|
|
|
} |
532
|
|
|
} |
533
|
|
|
|
534
|
|
|
/** |
535
|
|
|
* Creates new WC_Order. |
536
|
|
|
* |
537
|
|
|
* Requires a separate function for classes that extend WC_API_Orders. |
538
|
|
|
* |
539
|
|
|
* @since 2.3 |
540
|
|
|
* @param $args array |
541
|
|
|
* @return WC_Order |
542
|
|
|
*/ |
543
|
|
|
protected function create_base_order( $args, $data ) { |
|
|
|
|
544
|
|
|
return wc_create_order( $args ); |
545
|
|
|
} |
546
|
|
|
|
547
|
|
|
/** |
548
|
|
|
* Edit an order |
549
|
|
|
* |
550
|
|
|
* @since 2.2 |
551
|
|
|
* @param int $id the order ID |
552
|
|
|
* @param array $data |
553
|
|
|
* @return array |
554
|
|
|
*/ |
555
|
|
|
public function edit_order( $id, $data ) { |
556
|
|
|
try { |
557
|
|
View Code Duplication |
if ( ! isset( $data['order'] ) ) { |
|
|
|
|
558
|
|
|
throw new WC_API_Exception( 'woocommerce_api_missing_order_data', sprintf( __( 'No %1$s data specified to edit %1$s', 'woocommerce' ), 'order' ), 400 ); |
559
|
|
|
} |
560
|
|
|
|
561
|
|
|
$data = $data['order']; |
562
|
|
|
|
563
|
|
|
$update_totals = false; |
564
|
|
|
|
565
|
|
|
$id = $this->validate_request( $id, $this->post_type, 'edit' ); |
566
|
|
|
|
567
|
|
|
if ( is_wp_error( $id ) ) { |
568
|
|
|
return $id; |
569
|
|
|
} |
570
|
|
|
|
571
|
|
|
$data = apply_filters( 'woocommerce_api_edit_order_data', $data, $id, $this ); |
572
|
|
|
$order = wc_get_order( $id ); |
573
|
|
|
|
574
|
|
|
if ( empty( $order ) ) { |
575
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_order_id', __( 'Order ID is invalid', 'woocommerce' ), 400 ); |
576
|
|
|
} |
577
|
|
|
|
578
|
|
|
$order_args = array( 'order_id' => $order->id ); |
579
|
|
|
|
580
|
|
|
// Customer note. |
581
|
|
|
if ( isset( $data['note'] ) ) { |
582
|
|
|
$order_args['customer_note'] = $data['note']; |
583
|
|
|
} |
584
|
|
|
|
585
|
|
|
// Customer ID. |
586
|
|
View Code Duplication |
if ( isset( $data['customer_id'] ) && $data['customer_id'] != $order->get_user_id() ) { |
|
|
|
|
587
|
|
|
// Make sure customer exists. |
588
|
|
|
if ( false === get_user_by( 'id', $data['customer_id'] ) ) { |
589
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_customer_id', __( 'Customer ID is invalid', 'woocommerce' ), 400 ); |
590
|
|
|
} |
591
|
|
|
|
592
|
|
|
update_post_meta( $order->id, '_customer_user', $data['customer_id'] ); |
593
|
|
|
} |
594
|
|
|
|
595
|
|
|
// Billing/shipping address. |
596
|
|
|
$this->set_order_addresses( $order, $data ); |
597
|
|
|
|
598
|
|
|
$lines = array( |
599
|
|
|
'line_item' => 'line_items', |
600
|
|
|
'shipping' => 'shipping_lines', |
601
|
|
|
'fee' => 'fee_lines', |
602
|
|
|
'coupon' => 'coupon_lines', |
603
|
|
|
); |
604
|
|
|
|
605
|
|
View Code Duplication |
foreach ( $lines as $line_type => $line ) { |
|
|
|
|
606
|
|
|
|
607
|
|
|
if ( isset( $data[ $line ] ) && is_array( $data[ $line ] ) ) { |
608
|
|
|
|
609
|
|
|
$update_totals = true; |
610
|
|
|
|
611
|
|
|
foreach ( $data[ $line ] as $item ) { |
612
|
|
|
|
613
|
|
|
// Item ID is always required. |
614
|
|
|
if ( ! array_key_exists( 'id', $item ) ) { |
615
|
|
|
throw new WC_API_Exception( 'woocommerce_invalid_item_id', __( 'Order item ID is required', 'woocommerce' ), 400 ); |
616
|
|
|
} |
617
|
|
|
|
618
|
|
|
// Create item. |
619
|
|
|
if ( is_null( $item['id'] ) ) { |
620
|
|
|
$this->set_item( $order, $line_type, $item, 'create' ); |
621
|
|
|
} elseif ( $this->item_is_null( $item ) ) { |
622
|
|
|
// Delete item. |
623
|
|
|
wc_delete_order_item( $item['id'] ); |
624
|
|
|
} else { |
625
|
|
|
// Update item. |
626
|
|
|
$this->set_item( $order, $line_type, $item, 'update' ); |
627
|
|
|
} |
628
|
|
|
} |
629
|
|
|
} |
630
|
|
|
} |
631
|
|
|
|
632
|
|
|
// Payment method (and payment_complete() if `paid` == true and order needs payment). |
633
|
|
|
if ( isset( $data['payment_details'] ) && is_array( $data['payment_details'] ) ) { |
634
|
|
|
|
635
|
|
|
// Method ID. |
636
|
|
|
if ( isset( $data['payment_details']['method_id'] ) ) { |
637
|
|
|
update_post_meta( $order->id, '_payment_method', $data['payment_details']['method_id'] ); |
638
|
|
|
} |
639
|
|
|
|
640
|
|
|
// Method title. |
641
|
|
|
if ( isset( $data['payment_details']['method_title'] ) ) { |
642
|
|
|
update_post_meta( $order->id, '_payment_method_title', $data['payment_details']['method_title'] ); |
643
|
|
|
} |
644
|
|
|
|
645
|
|
|
// Mark as paid if set. |
646
|
|
View Code Duplication |
if ( $order->needs_payment() && isset( $data['payment_details']['paid'] ) && true === $data['payment_details']['paid'] ) { |
|
|
|
|
647
|
|
|
$order->payment_complete( isset( $data['payment_details']['transaction_id'] ) ? $data['payment_details']['transaction_id'] : '' ); |
648
|
|
|
} |
649
|
|
|
} |
650
|
|
|
|
651
|
|
|
// Set order currency. |
652
|
|
View Code Duplication |
if ( isset( $data['currency'] ) ) { |
|
|
|
|
653
|
|
|
if ( ! array_key_exists( $data['currency'], get_woocommerce_currencies() ) ) { |
654
|
|
|
throw new WC_API_Exception( 'woocommerce_invalid_order_currency', __( 'Provided order currency is invalid', 'woocommerce' ), 400 ); |
655
|
|
|
} |
656
|
|
|
|
657
|
|
|
update_post_meta( $order->id, '_order_currency', $data['currency'] ); |
658
|
|
|
} |
659
|
|
|
|
660
|
|
|
// If items have changed, recalculate order totals. |
661
|
|
|
if ( $update_totals ) { |
662
|
|
|
$order->calculate_totals(); |
663
|
|
|
} |
664
|
|
|
|
665
|
|
|
// Update order meta. |
666
|
|
View Code Duplication |
if ( isset( $data['order_meta'] ) && is_array( $data['order_meta'] ) ) { |
|
|
|
|
667
|
|
|
$this->set_order_meta( $order->id, $data['order_meta'] ); |
668
|
|
|
} |
669
|
|
|
|
670
|
|
|
// Update the order post to set customer note/modified date. |
671
|
|
|
wc_update_order( $order_args ); |
672
|
|
|
|
673
|
|
|
// Order status. |
674
|
|
View Code Duplication |
if ( ! empty( $data['status'] ) ) { |
|
|
|
|
675
|
|
|
$order->update_status( $data['status'], isset( $data['status_note'] ) ? $data['status_note'] : '' ); |
676
|
|
|
} |
677
|
|
|
|
678
|
|
|
wc_delete_shop_order_transients( $order->id ); |
679
|
|
|
|
680
|
|
|
do_action( 'woocommerce_api_edit_order', $order->id, $data, $this ); |
681
|
|
|
|
682
|
|
|
return $this->get_order( $id ); |
683
|
|
|
} catch ( WC_API_Exception $e ) { |
684
|
|
|
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); |
685
|
|
|
} |
686
|
|
|
} |
687
|
|
|
|
688
|
|
|
/** |
689
|
|
|
* Delete an order |
690
|
|
|
* |
691
|
|
|
* @param int $id the order ID |
692
|
|
|
* @param bool $force true to permanently delete order, false to move to trash |
693
|
|
|
* @return array |
694
|
|
|
*/ |
695
|
|
View Code Duplication |
public function delete_order( $id, $force = false ) { |
|
|
|
|
696
|
|
|
|
697
|
|
|
$id = $this->validate_request( $id, $this->post_type, 'delete' ); |
698
|
|
|
|
699
|
|
|
if ( is_wp_error( $id ) ) { |
700
|
|
|
return $id; |
701
|
|
|
} |
702
|
|
|
|
703
|
|
|
wc_delete_shop_order_transients( $id ); |
704
|
|
|
|
705
|
|
|
do_action( 'woocommerce_api_delete_order', $id, $this ); |
706
|
|
|
|
707
|
|
|
return $this->delete( $id, 'order', ( 'true' === $force ) ); |
708
|
|
|
} |
709
|
|
|
|
710
|
|
|
/** |
711
|
|
|
* Helper method to get order post objects |
712
|
|
|
* |
713
|
|
|
* @since 2.1 |
714
|
|
|
* @param array $args request arguments for filtering query |
715
|
|
|
* @return WP_Query |
716
|
|
|
*/ |
717
|
|
|
protected function query_orders( $args ) { |
718
|
|
|
|
719
|
|
|
// set base query arguments |
720
|
|
|
$query_args = array( |
721
|
|
|
'fields' => 'ids', |
722
|
|
|
'post_type' => $this->post_type, |
723
|
|
|
'post_status' => array_keys( wc_get_order_statuses() ) |
724
|
|
|
); |
725
|
|
|
|
726
|
|
|
// add status argument |
727
|
|
View Code Duplication |
if ( ! empty( $args['status'] ) ) { |
|
|
|
|
728
|
|
|
$statuses = 'wc-' . str_replace( ',', ',wc-', $args['status'] ); |
729
|
|
|
$statuses = explode( ',', $statuses ); |
730
|
|
|
$query_args['post_status'] = $statuses; |
731
|
|
|
|
732
|
|
|
unset( $args['status'] ); |
733
|
|
|
} |
734
|
|
|
|
735
|
|
|
if ( ! empty( $args['customer_id'] ) ) { |
736
|
|
|
$query_args['meta_query'] = array( |
737
|
|
|
array( |
738
|
|
|
'key' => '_customer_user', |
739
|
|
|
'value' => absint( $args['customer_id'] ), |
740
|
|
|
'compare' => '=' |
741
|
|
|
) |
742
|
|
|
); |
743
|
|
|
} |
744
|
|
|
|
745
|
|
|
$query_args = $this->merge_query_args( $query_args, $args ); |
746
|
|
|
|
747
|
|
|
return new WP_Query( $query_args ); |
748
|
|
|
} |
749
|
|
|
|
750
|
|
|
/** |
751
|
|
|
* Helper method to set/update the billing & shipping addresses for |
752
|
|
|
* an order |
753
|
|
|
* |
754
|
|
|
* @since 2.1 |
755
|
|
|
* @param \WC_Order $order |
756
|
|
|
* @param array $data |
757
|
|
|
*/ |
758
|
|
View Code Duplication |
protected function set_order_addresses( $order, $data ) { |
|
|
|
|
759
|
|
|
|
760
|
|
|
$address_fields = array( |
761
|
|
|
'first_name', |
762
|
|
|
'last_name', |
763
|
|
|
'company', |
764
|
|
|
'email', |
765
|
|
|
'phone', |
766
|
|
|
'address_1', |
767
|
|
|
'address_2', |
768
|
|
|
'city', |
769
|
|
|
'state', |
770
|
|
|
'postcode', |
771
|
|
|
'country', |
772
|
|
|
); |
773
|
|
|
|
774
|
|
|
$billing_address = $shipping_address = array(); |
775
|
|
|
|
776
|
|
|
// billing address |
777
|
|
|
if ( isset( $data['billing_address'] ) && is_array( $data['billing_address'] ) ) { |
778
|
|
|
|
779
|
|
|
foreach ( $address_fields as $field ) { |
780
|
|
|
|
781
|
|
|
if ( isset( $data['billing_address'][ $field ] ) ) { |
782
|
|
|
$billing_address[ $field ] = wc_clean( $data['billing_address'][ $field ] ); |
783
|
|
|
} |
784
|
|
|
} |
785
|
|
|
|
786
|
|
|
unset( $address_fields['email'] ); |
787
|
|
|
unset( $address_fields['phone'] ); |
788
|
|
|
} |
789
|
|
|
|
790
|
|
|
// shipping address |
791
|
|
|
if ( isset( $data['shipping_address'] ) && is_array( $data['shipping_address'] ) ) { |
792
|
|
|
|
793
|
|
|
foreach ( $address_fields as $field ) { |
794
|
|
|
|
795
|
|
|
if ( isset( $data['shipping_address'][ $field ] ) ) { |
796
|
|
|
$shipping_address[ $field ] = wc_clean( $data['shipping_address'][ $field ] ); |
797
|
|
|
} |
798
|
|
|
} |
799
|
|
|
} |
800
|
|
|
|
801
|
|
|
$order->set_address( $billing_address, 'billing' ); |
802
|
|
|
$order->set_address( $shipping_address, 'shipping' ); |
803
|
|
|
|
804
|
|
|
// update user meta |
805
|
|
|
if ( $order->get_user_id() ) { |
806
|
|
|
foreach ( $billing_address as $key => $value ) { |
807
|
|
|
update_user_meta( $order->get_user_id(), 'billing_' . $key, $value ); |
808
|
|
|
} |
809
|
|
|
foreach ( $shipping_address as $key => $value ) { |
810
|
|
|
update_user_meta( $order->get_user_id(), 'shipping_' . $key, $value ); |
811
|
|
|
} |
812
|
|
|
} |
813
|
|
|
} |
814
|
|
|
|
815
|
|
|
/** |
816
|
|
|
* Helper method to add/update order meta, with two restrictions: |
817
|
|
|
* |
818
|
|
|
* 1) Only non-protected meta (no leading underscore) can be set |
819
|
|
|
* 2) Meta values must be scalar (int, string, bool) |
820
|
|
|
* |
821
|
|
|
* @since 2.2 |
822
|
|
|
* @param int $order_id valid order ID |
823
|
|
|
* @param array $order_meta order meta in array( 'meta_key' => 'meta_value' ) format |
824
|
|
|
*/ |
825
|
|
View Code Duplication |
protected function set_order_meta( $order_id, $order_meta ) { |
|
|
|
|
826
|
|
|
|
827
|
|
|
foreach ( $order_meta as $meta_key => $meta_value ) { |
828
|
|
|
|
829
|
|
|
if ( is_string( $meta_key) && ! is_protected_meta( $meta_key ) && is_scalar( $meta_value ) ) { |
830
|
|
|
update_post_meta( $order_id, $meta_key, $meta_value ); |
831
|
|
|
} |
832
|
|
|
} |
833
|
|
|
} |
834
|
|
|
|
835
|
|
|
/** |
836
|
|
|
* Helper method to check if the resource ID associated with the provided item is null |
837
|
|
|
* |
838
|
|
|
* Items can be deleted by setting the resource ID to null |
839
|
|
|
* |
840
|
|
|
* @since 2.2 |
841
|
|
|
* @param array $item item provided in the request body |
842
|
|
|
* @return bool true if the item resource ID is null, false otherwise |
843
|
|
|
*/ |
844
|
|
|
protected function item_is_null( $item ) { |
845
|
|
|
|
846
|
|
|
$keys = array( 'product_id', 'method_id', 'title', 'code' ); |
847
|
|
|
|
848
|
|
|
foreach ( $keys as $key ) { |
849
|
|
|
if ( array_key_exists( $key, $item ) && is_null( $item[ $key ] ) ) { |
850
|
|
|
return true; |
851
|
|
|
} |
852
|
|
|
} |
853
|
|
|
|
854
|
|
|
return false; |
855
|
|
|
} |
856
|
|
|
|
857
|
|
|
/** |
858
|
|
|
* Wrapper method to create/update order items |
859
|
|
|
* |
860
|
|
|
* When updating, the item ID provided is checked to ensure it is associated |
861
|
|
|
* with the order. |
862
|
|
|
* |
863
|
|
|
* @since 2.2 |
864
|
|
|
* @param \WC_Order $order order |
865
|
|
|
* @param string $item_type |
866
|
|
|
* @param array $item item provided in the request body |
867
|
|
|
* @param string $action either 'create' or 'update' |
868
|
|
|
* @throws WC_API_Exception if item ID is not associated with order |
869
|
|
|
*/ |
870
|
|
View Code Duplication |
protected function set_item( $order, $item_type, $item, $action ) { |
|
|
|
|
871
|
|
|
global $wpdb; |
872
|
|
|
|
873
|
|
|
$set_method = "set_{$item_type}"; |
874
|
|
|
|
875
|
|
|
// verify provided line item ID is associated with order |
876
|
|
|
if ( 'update' === $action ) { |
877
|
|
|
|
878
|
|
|
$result = $wpdb->get_row( |
879
|
|
|
$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}woocommerce_order_items WHERE order_item_id = %d AND order_id = %d", |
880
|
|
|
absint( $item['id'] ), |
881
|
|
|
absint( $order->id ) |
882
|
|
|
) ); |
883
|
|
|
|
884
|
|
|
if ( is_null( $result ) ) { |
885
|
|
|
throw new WC_API_Exception( 'woocommerce_invalid_item_id', __( 'Order item ID provided is not associated with order', 'woocommerce' ), 400 ); |
886
|
|
|
} |
887
|
|
|
} |
888
|
|
|
|
889
|
|
|
$this->$set_method( $order, $item, $action ); |
890
|
|
|
} |
891
|
|
|
|
892
|
|
|
/** |
893
|
|
|
* Create or update a line item |
894
|
|
|
* |
895
|
|
|
* @since 2.2 |
896
|
|
|
* @param \WC_Order $order |
897
|
|
|
* @param array $item line item data |
898
|
|
|
* @param string $action 'create' to add line item or 'update' to update it |
899
|
|
|
* @throws WC_API_Exception invalid data, server error |
900
|
|
|
*/ |
901
|
|
|
protected function set_line_item( $order, $item, $action ) { |
902
|
|
|
|
903
|
|
|
$creating = ( 'create' === $action ); |
904
|
|
|
$item_args = array(); |
905
|
|
|
|
906
|
|
|
// product is always required |
907
|
|
|
if ( ! isset( $item['product_id'] ) && ! isset( $item['sku'] ) ) { |
908
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_product_id', __( 'Product ID or SKU is required', 'woocommerce' ), 400 ); |
909
|
|
|
} |
910
|
|
|
|
911
|
|
|
// when updating, ensure product ID provided matches |
912
|
|
View Code Duplication |
if ( 'update' === $action ) { |
|
|
|
|
913
|
|
|
|
914
|
|
|
$item_product_id = wc_get_order_item_meta( $item['id'], '_product_id' ); |
915
|
|
|
$item_variation_id = wc_get_order_item_meta( $item['id'], '_variation_id' ); |
916
|
|
|
|
917
|
|
|
if ( $item['product_id'] != $item_product_id && $item['product_id'] != $item_variation_id ) { |
918
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_product_id', __( 'Product ID provided does not match this line item', 'woocommerce' ), 400 ); |
919
|
|
|
} |
920
|
|
|
} |
921
|
|
|
|
922
|
|
View Code Duplication |
if ( isset( $item['product_id'] ) ) { |
|
|
|
|
923
|
|
|
$product_id = $item['product_id']; |
924
|
|
|
} elseif ( isset( $item['sku'] ) ) { |
925
|
|
|
$product_id = wc_get_product_id_by_sku( $item['sku'] ); |
926
|
|
|
} |
927
|
|
|
|
928
|
|
|
// variations must each have a key & value |
929
|
|
|
$variation_id = 0; |
930
|
|
View Code Duplication |
if ( isset( $item['variations'] ) && is_array( $item['variations'] ) ) { |
|
|
|
|
931
|
|
|
foreach ( $item['variations'] as $key => $value ) { |
932
|
|
|
if ( ! $key || ! $value ) { |
933
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_product_variation', __( 'The product variation is invalid', 'woocommerce' ), 400 ); |
934
|
|
|
} |
935
|
|
|
} |
936
|
|
|
$item_args['variation'] = $item['variations']; |
937
|
|
|
$variation_id = $this->get_variation_id( wc_get_product( $product_id ), $item_args['variation'] ); |
938
|
|
|
} |
939
|
|
|
|
940
|
|
|
$product = wc_get_product( $variation_id ? $variation_id : $product_id ); |
941
|
|
|
|
942
|
|
|
// must be a valid WC_Product |
943
|
|
|
if ( ! is_object( $product ) ) { |
944
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_product', __( 'Product is invalid', 'woocommerce' ), 400 ); |
945
|
|
|
} |
946
|
|
|
|
947
|
|
|
// quantity must be positive float |
948
|
|
View Code Duplication |
if ( isset( $item['quantity'] ) && floatval( $item['quantity'] ) <= 0 ) { |
|
|
|
|
949
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_product_quantity', __( 'Product quantity must be a positive float', 'woocommerce' ), 400 ); |
950
|
|
|
} |
951
|
|
|
|
952
|
|
|
// quantity is required when creating |
953
|
|
|
if ( $creating && ! isset( $item['quantity'] ) ) { |
954
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_product_quantity', __( 'Product quantity is required', 'woocommerce' ), 400 ); |
955
|
|
|
} |
956
|
|
|
|
957
|
|
|
// quantity |
958
|
|
|
if ( isset( $item['quantity'] ) ) { |
959
|
|
|
$item_args['qty'] = $item['quantity']; |
960
|
|
|
} |
961
|
|
|
|
962
|
|
|
// total |
963
|
|
View Code Duplication |
if ( isset( $item['total'] ) ) { |
|
|
|
|
964
|
|
|
$item_args['totals']['total'] = floatval( $item['total'] ); |
965
|
|
|
} |
966
|
|
|
|
967
|
|
|
// total tax |
968
|
|
View Code Duplication |
if ( isset( $item['total_tax'] ) ) { |
|
|
|
|
969
|
|
|
$item_args['totals']['tax'] = floatval( $item['total_tax'] ); |
970
|
|
|
} |
971
|
|
|
|
972
|
|
|
// subtotal |
973
|
|
View Code Duplication |
if ( isset( $item['subtotal'] ) ) { |
|
|
|
|
974
|
|
|
$item_args['totals']['subtotal'] = floatval( $item['subtotal'] ); |
975
|
|
|
} |
976
|
|
|
|
977
|
|
|
// subtotal tax |
978
|
|
View Code Duplication |
if ( isset( $item['subtotal_tax'] ) ) { |
|
|
|
|
979
|
|
|
$item_args['totals']['subtotal_tax'] = floatval( $item['subtotal_tax'] ); |
980
|
|
|
} |
981
|
|
|
|
982
|
|
View Code Duplication |
if ( $creating ) { |
|
|
|
|
983
|
|
|
|
984
|
|
|
$item_id = $order->add_product( $product, $item_args['qty'], $item_args ); |
985
|
|
|
|
986
|
|
|
if ( ! $item_id ) { |
987
|
|
|
throw new WC_API_Exception( 'woocommerce_cannot_create_line_item', __( 'Cannot create line item, try again', 'woocommerce' ), 500 ); |
988
|
|
|
} |
989
|
|
|
|
990
|
|
|
} else { |
991
|
|
|
|
992
|
|
|
$item_id = $order->update_product( $item['id'], $product, $item_args ); |
993
|
|
|
|
994
|
|
|
if ( ! $item_id ) { |
995
|
|
|
throw new WC_API_Exception( 'woocommerce_cannot_update_line_item', __( 'Cannot update line item, try again', 'woocommerce' ), 500 ); |
996
|
|
|
} |
997
|
|
|
} |
998
|
|
|
} |
999
|
|
|
|
1000
|
|
|
/** |
1001
|
|
|
* Given a product ID & API provided variations, find the correct variation ID to use for calculation |
1002
|
|
|
* We can't just trust input from the API to pass a variation_id manually, otherwise you could pass |
1003
|
|
|
* the cheapest variation ID but provide other information so we have to look up the variation ID. |
1004
|
|
|
* |
1005
|
|
|
* @param WC_Product $product Product instance |
1006
|
|
|
* @return int Returns an ID if a valid variation was found for this product |
1007
|
|
|
*/ |
1008
|
|
View Code Duplication |
public function get_variation_id( $product, $variations = array() ) { |
|
|
|
|
1009
|
|
|
$variation_id = null; |
1010
|
|
|
$variations_normalized = array(); |
1011
|
|
|
|
1012
|
|
|
if ( $product->is_type( 'variable' ) && $product->has_child() ) { |
1013
|
|
|
if ( isset( $variations ) && is_array( $variations ) ) { |
1014
|
|
|
// start by normalizing the passed variations |
1015
|
|
|
foreach ( $variations as $key => $value ) { |
1016
|
|
|
$key = str_replace( 'attribute_', '', str_replace( 'pa_', '', $key ) ); // from get_attributes in class-wc-api-products.php |
1017
|
|
|
$variations_normalized[ $key ] = strtolower( $value ); |
1018
|
|
|
} |
1019
|
|
|
// now search through each product child and see if our passed variations match anything |
1020
|
|
|
foreach ( $product->get_children() as $variation ) { |
1021
|
|
|
$meta = array(); |
1022
|
|
|
foreach ( get_post_meta( $variation ) as $key => $value ) { |
1023
|
|
|
$value = $value[0]; |
1024
|
|
|
$key = str_replace( 'attribute_', '', str_replace( 'pa_', '', $key ) ); |
1025
|
|
|
$meta[ $key ] = strtolower( $value ); |
1026
|
|
|
} |
1027
|
|
|
// if the variation array is a part of the $meta array, we found our match |
1028
|
|
|
if ( $this->array_contains( $variations_normalized, $meta ) ) { |
1029
|
|
|
$variation_id = $variation; |
1030
|
|
|
break; |
1031
|
|
|
} |
1032
|
|
|
} |
1033
|
|
|
} |
1034
|
|
|
} |
1035
|
|
|
|
1036
|
|
|
return $variation_id; |
1037
|
|
|
} |
1038
|
|
|
|
1039
|
|
|
/** |
1040
|
|
|
* Utility function to see if the meta array contains data from variations |
1041
|
|
|
*/ |
1042
|
|
View Code Duplication |
protected function array_contains( $needles, $haystack ) { |
|
|
|
|
1043
|
|
|
foreach ( $needles as $key => $value ) { |
1044
|
|
|
if ( $haystack[ $key ] !== $value ) { |
1045
|
|
|
return false; |
1046
|
|
|
} |
1047
|
|
|
} |
1048
|
|
|
return true; |
1049
|
|
|
} |
1050
|
|
|
|
1051
|
|
|
/** |
1052
|
|
|
* Create or update an order shipping method |
1053
|
|
|
* |
1054
|
|
|
* @since 2.2 |
1055
|
|
|
* @param \WC_Order $order |
1056
|
|
|
* @param array $shipping item data |
1057
|
|
|
* @param string $action 'create' to add shipping or 'update' to update it |
1058
|
|
|
* @throws WC_API_Exception invalid data, server error |
1059
|
|
|
*/ |
1060
|
|
|
protected function set_shipping( $order, $shipping, $action ) { |
1061
|
|
|
|
1062
|
|
|
// total must be a positive float |
1063
|
|
|
if ( isset( $shipping['total'] ) && floatval( $shipping['total'] ) < 0 ) { |
1064
|
|
|
throw new WC_API_Exception( 'woocommerce_invalid_shipping_total', __( 'Shipping total must be a positive amount', 'woocommerce' ), 400 ); |
1065
|
|
|
} |
1066
|
|
|
|
1067
|
|
View Code Duplication |
if ( 'create' === $action ) { |
|
|
|
|
1068
|
|
|
|
1069
|
|
|
// method ID is required |
1070
|
|
|
if ( ! isset( $shipping['method_id'] ) ) { |
1071
|
|
|
throw new WC_API_Exception( 'woocommerce_invalid_shipping_item', __( 'Shipping method ID is required', 'woocommerce' ), 400 ); |
1072
|
|
|
} |
1073
|
|
|
|
1074
|
|
|
$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'] ); |
1075
|
|
|
|
1076
|
|
|
$shipping_id = $order->add_shipping( $rate ); |
1077
|
|
|
|
1078
|
|
|
if ( ! $shipping_id ) { |
1079
|
|
|
throw new WC_API_Exception( 'woocommerce_cannot_create_shipping', __( 'Cannot create shipping method, try again', 'woocommerce' ), 500 ); |
1080
|
|
|
} |
1081
|
|
|
|
1082
|
|
|
} else { |
1083
|
|
|
|
1084
|
|
|
$shipping_args = array(); |
1085
|
|
|
|
1086
|
|
|
if ( isset( $shipping['method_id'] ) ) { |
1087
|
|
|
$shipping_args['method_id'] = $shipping['method_id']; |
1088
|
|
|
} |
1089
|
|
|
|
1090
|
|
|
if ( isset( $shipping['method_title'] ) ) { |
1091
|
|
|
$shipping_args['method_title'] = $shipping['method_title']; |
1092
|
|
|
} |
1093
|
|
|
|
1094
|
|
|
if ( isset( $shipping['total'] ) ) { |
1095
|
|
|
$shipping_args['cost'] = floatval( $shipping['total'] ); |
1096
|
|
|
} |
1097
|
|
|
|
1098
|
|
|
$shipping_id = $order->update_shipping( $shipping['id'], $shipping_args ); |
1099
|
|
|
|
1100
|
|
|
if ( ! $shipping_id ) { |
1101
|
|
|
throw new WC_API_Exception( 'woocommerce_cannot_update_shipping', __( 'Cannot update shipping method, try again', 'woocommerce' ), 500 ); |
1102
|
|
|
} |
1103
|
|
|
} |
1104
|
|
|
} |
1105
|
|
|
|
1106
|
|
|
/** |
1107
|
|
|
* Create or update an order fee |
1108
|
|
|
* |
1109
|
|
|
* @since 2.2 |
1110
|
|
|
* @param \WC_Order $order |
1111
|
|
|
* @param array $fee item data |
1112
|
|
|
* @param string $action 'create' to add fee or 'update' to update it |
1113
|
|
|
* @throws WC_API_Exception invalid data, server error |
1114
|
|
|
*/ |
1115
|
|
|
protected function set_fee( $order, $fee, $action ) { |
1116
|
|
|
|
1117
|
|
|
if ( 'create' === $action ) { |
1118
|
|
|
|
1119
|
|
|
// fee title is required |
1120
|
|
|
if ( ! isset( $fee['title'] ) ) { |
1121
|
|
|
throw new WC_API_Exception( 'woocommerce_invalid_fee_item', __( 'Fee title is required', 'woocommerce' ), 400 ); |
1122
|
|
|
} |
1123
|
|
|
|
1124
|
|
|
$order_fee = new stdClass(); |
1125
|
|
|
$order_fee->id = sanitize_title( $fee['title'] ); |
1126
|
|
|
$order_fee->name = $fee['title']; |
1127
|
|
|
$order_fee->amount = isset( $fee['total'] ) ? floatval( $fee['total'] ) : 0; |
1128
|
|
|
$order_fee->taxable = false; |
1129
|
|
|
$order_fee->tax = 0; |
1130
|
|
|
$order_fee->tax_data = array(); |
1131
|
|
|
$order_fee->tax_class = ''; |
1132
|
|
|
|
1133
|
|
|
// if taxable, tax class and total are required |
1134
|
|
View Code Duplication |
if ( isset( $fee['taxable'] ) && $fee['taxable'] ) { |
|
|
|
|
1135
|
|
|
|
1136
|
|
|
if ( ! isset( $fee['tax_class'] ) ) { |
1137
|
|
|
throw new WC_API_Exception( 'woocommerce_invalid_fee_item', __( 'Fee tax class is required when fee is taxable', 'woocommerce' ), 400 ); |
1138
|
|
|
} |
1139
|
|
|
|
1140
|
|
|
$order_fee->taxable = true; |
1141
|
|
|
$order_fee->tax_class = $fee['tax_class']; |
1142
|
|
|
|
1143
|
|
|
if ( isset( $fee['total_tax'] ) ) { |
1144
|
|
|
$order_fee->tax = isset( $fee['total_tax'] ) ? wc_format_refund_total( $fee['total_tax'] ) : 0; |
1145
|
|
|
} |
1146
|
|
|
|
1147
|
|
|
if ( isset( $fee['tax_data'] ) ) { |
1148
|
|
|
$order_fee->tax = wc_format_refund_total( array_sum( $fee['tax_data'] ) ); |
1149
|
|
|
$order_fee->tax_data = array_map( 'wc_format_refund_total', $fee['tax_data'] ); |
1150
|
|
|
} |
1151
|
|
|
} |
1152
|
|
|
|
1153
|
|
|
$fee_id = $order->add_fee( $order_fee ); |
1154
|
|
|
|
1155
|
|
|
if ( ! $fee_id ) { |
1156
|
|
|
throw new WC_API_Exception( 'woocommerce_cannot_create_fee', __( 'Cannot create fee, try again', 'woocommerce' ), 500 ); |
1157
|
|
|
} |
1158
|
|
|
|
1159
|
|
View Code Duplication |
} else { |
|
|
|
|
1160
|
|
|
|
1161
|
|
|
$fee_args = array(); |
1162
|
|
|
|
1163
|
|
|
if ( isset( $fee['title'] ) ) { |
1164
|
|
|
$fee_args['name'] = $fee['title']; |
1165
|
|
|
} |
1166
|
|
|
|
1167
|
|
|
if ( isset( $fee['tax_class'] ) ) { |
1168
|
|
|
$fee_args['tax_class'] = $fee['tax_class']; |
1169
|
|
|
} |
1170
|
|
|
|
1171
|
|
|
if ( isset( $fee['total'] ) ) { |
1172
|
|
|
$fee_args['line_total'] = floatval( $fee['total'] ); |
1173
|
|
|
} |
1174
|
|
|
|
1175
|
|
|
if ( isset( $fee['total_tax'] ) ) { |
1176
|
|
|
$fee_args['line_tax'] = floatval( $fee['total_tax'] ); |
1177
|
|
|
} |
1178
|
|
|
|
1179
|
|
|
$fee_id = $order->update_fee( $fee['id'], $fee_args ); |
1180
|
|
|
|
1181
|
|
|
if ( ! $fee_id ) { |
1182
|
|
|
throw new WC_API_Exception( 'woocommerce_cannot_update_fee', __( 'Cannot update fee, try again', 'woocommerce' ), 500 ); |
1183
|
|
|
} |
1184
|
|
|
} |
1185
|
|
|
} |
1186
|
|
|
|
1187
|
|
|
/** |
1188
|
|
|
* Create or update an order coupon |
1189
|
|
|
* |
1190
|
|
|
* @since 2.2 |
1191
|
|
|
* @param \WC_Order $order |
1192
|
|
|
* @param array $coupon item data |
1193
|
|
|
* @param string $action 'create' to add coupon or 'update' to update it |
1194
|
|
|
* @throws WC_API_Exception invalid data, server error |
1195
|
|
|
*/ |
1196
|
|
|
protected function set_coupon( $order, $coupon, $action ) { |
1197
|
|
|
|
1198
|
|
|
// coupon amount must be positive float |
1199
|
|
|
if ( isset( $coupon['amount'] ) && floatval( $coupon['amount'] ) < 0 ) { |
1200
|
|
|
throw new WC_API_Exception( 'woocommerce_invalid_coupon_total', __( 'Coupon discount total must be a positive amount', 'woocommerce' ), 400 ); |
1201
|
|
|
} |
1202
|
|
|
|
1203
|
|
View Code Duplication |
if ( 'create' === $action ) { |
|
|
|
|
1204
|
|
|
|
1205
|
|
|
// coupon code is required |
1206
|
|
|
if ( empty( $coupon['code'] ) ) { |
1207
|
|
|
throw new WC_API_Exception( 'woocommerce_invalid_coupon_coupon', __( 'Coupon code is required', 'woocommerce' ), 400 ); |
1208
|
|
|
} |
1209
|
|
|
|
1210
|
|
|
$coupon_id = $order->add_coupon( $coupon['code'], isset( $coupon['amount'] ) ? floatval( $coupon['amount'] ) : 0 ); |
1211
|
|
|
|
1212
|
|
|
if ( ! $coupon_id ) { |
1213
|
|
|
throw new WC_API_Exception( 'woocommerce_cannot_create_order_coupon', __( 'Cannot create coupon, try again', 'woocommerce' ), 500 ); |
1214
|
|
|
} |
1215
|
|
|
|
1216
|
|
|
} else { |
1217
|
|
|
|
1218
|
|
|
$coupon_args = array(); |
1219
|
|
|
|
1220
|
|
|
if ( isset( $coupon['code'] ) ) { |
1221
|
|
|
$coupon_args['code'] = $coupon['code']; |
1222
|
|
|
} |
1223
|
|
|
|
1224
|
|
|
if ( isset( $coupon['amount'] ) ) { |
1225
|
|
|
$coupon_args['discount_amount'] = floatval( $coupon['amount'] ); |
1226
|
|
|
} |
1227
|
|
|
|
1228
|
|
|
$coupon_id = $order->update_coupon( $coupon['id'], $coupon_args ); |
1229
|
|
|
|
1230
|
|
|
if ( ! $coupon_id ) { |
1231
|
|
|
throw new WC_API_Exception( 'woocommerce_cannot_update_order_coupon', __( 'Cannot update coupon, try again', 'woocommerce' ), 500 ); |
1232
|
|
|
} |
1233
|
|
|
} |
1234
|
|
|
} |
1235
|
|
|
|
1236
|
|
|
/** |
1237
|
|
|
* Get the admin order notes for an order |
1238
|
|
|
* |
1239
|
|
|
* @since 2.1 |
1240
|
|
|
* @param string $order_id order ID |
1241
|
|
|
* @param string|null $fields fields to include in response |
1242
|
|
|
* @return array |
1243
|
|
|
*/ |
1244
|
|
|
public function get_order_notes( $order_id, $fields = null ) { |
1245
|
|
|
|
1246
|
|
|
// ensure ID is valid order ID |
1247
|
|
|
$order_id = $this->validate_request( $order_id, $this->post_type, 'read' ); |
1248
|
|
|
|
1249
|
|
|
if ( is_wp_error( $order_id ) ) { |
1250
|
|
|
return $order_id; |
1251
|
|
|
} |
1252
|
|
|
|
1253
|
|
|
$args = array( |
1254
|
|
|
'post_id' => $order_id, |
1255
|
|
|
'approve' => 'approve', |
1256
|
|
|
'type' => 'order_note' |
1257
|
|
|
); |
1258
|
|
|
|
1259
|
|
|
remove_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ), 10, 1 ); |
1260
|
|
|
|
1261
|
|
|
$notes = get_comments( $args ); |
1262
|
|
|
|
1263
|
|
|
add_filter( 'comments_clauses', array( 'WC_Comments', 'exclude_order_comments' ), 10, 1 ); |
1264
|
|
|
|
1265
|
|
|
$order_notes = array(); |
1266
|
|
|
|
1267
|
|
|
foreach ( $notes as $note ) { |
1268
|
|
|
|
1269
|
|
|
$order_notes[] = current( $this->get_order_note( $order_id, $note->comment_ID, $fields ) ); |
|
|
|
|
1270
|
|
|
} |
1271
|
|
|
|
1272
|
|
|
return array( 'order_notes' => apply_filters( 'woocommerce_api_order_notes_response', $order_notes, $order_id, $fields, $notes, $this->server ) ); |
1273
|
|
|
} |
1274
|
|
|
|
1275
|
|
|
/** |
1276
|
|
|
* Get an order note for the given order ID and ID |
1277
|
|
|
* |
1278
|
|
|
* @since 2.2 |
1279
|
|
|
* @param string $order_id order ID |
1280
|
|
|
* @param string $id order note ID |
1281
|
|
|
* @param string|null $fields fields to limit response to |
1282
|
|
|
* @return array |
1283
|
|
|
*/ |
1284
|
|
|
public function get_order_note( $order_id, $id, $fields = null ) { |
1285
|
|
|
try { |
1286
|
|
|
// Validate order ID |
1287
|
|
|
$order_id = $this->validate_request( $order_id, $this->post_type, 'read' ); |
1288
|
|
|
|
1289
|
|
|
if ( is_wp_error( $order_id ) ) { |
1290
|
|
|
return $order_id; |
1291
|
|
|
} |
1292
|
|
|
|
1293
|
|
|
$id = absint( $id ); |
1294
|
|
|
|
1295
|
|
|
if ( empty( $id ) ) { |
1296
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_order_note_id', __( 'Invalid order note ID', 'woocommerce' ), 400 ); |
1297
|
|
|
} |
1298
|
|
|
|
1299
|
|
|
$note = get_comment( $id ); |
1300
|
|
|
|
1301
|
|
|
if ( is_null( $note ) ) { |
1302
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_order_note_id', __( 'An order note with the provided ID could not be found', 'woocommerce' ), 404 ); |
1303
|
|
|
} |
1304
|
|
|
|
1305
|
|
|
$order_note = array( |
1306
|
|
|
'id' => $note->comment_ID, |
1307
|
|
|
'created_at' => $this->server->format_datetime( $note->comment_date_gmt ), |
1308
|
|
|
'note' => $note->comment_content, |
1309
|
|
|
'customer_note' => get_comment_meta( $note->comment_ID, 'is_customer_note', true ) ? true : false, |
1310
|
|
|
); |
1311
|
|
|
|
1312
|
|
|
return array( 'order_note' => apply_filters( 'woocommerce_api_order_note_response', $order_note, $id, $fields, $note, $order_id, $this ) ); |
1313
|
|
|
} catch ( WC_API_Exception $e ) { |
1314
|
|
|
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); |
1315
|
|
|
} |
1316
|
|
|
} |
1317
|
|
|
|
1318
|
|
|
/** |
1319
|
|
|
* Create a new order note for the given order |
1320
|
|
|
* |
1321
|
|
|
* @since 2.2 |
1322
|
|
|
* @param string $order_id order ID |
1323
|
|
|
* @param array $data raw request data |
1324
|
|
|
* @return WP_Error|array error or created note response data |
1325
|
|
|
*/ |
1326
|
|
|
public function create_order_note( $order_id, $data ) { |
1327
|
|
|
try { |
1328
|
|
View Code Duplication |
if ( ! isset( $data['order_note'] ) ) { |
|
|
|
|
1329
|
|
|
throw new WC_API_Exception( 'woocommerce_api_missing_order_note_data', sprintf( __( 'No %1$s data specified to create %1$s', 'woocommerce' ), 'order_note' ), 400 ); |
1330
|
|
|
} |
1331
|
|
|
|
1332
|
|
|
$data = $data['order_note']; |
1333
|
|
|
|
1334
|
|
|
// permission check |
1335
|
|
|
if ( ! current_user_can( 'publish_shop_orders' ) ) { |
1336
|
|
|
throw new WC_API_Exception( 'woocommerce_api_user_cannot_create_order_note', __( 'You do not have permission to create order notes', 'woocommerce' ), 401 ); |
1337
|
|
|
} |
1338
|
|
|
|
1339
|
|
|
$order_id = $this->validate_request( $order_id, $this->post_type, 'edit' ); |
1340
|
|
|
|
1341
|
|
|
if ( is_wp_error( $order_id ) ) { |
1342
|
|
|
return $order_id; |
1343
|
|
|
} |
1344
|
|
|
|
1345
|
|
|
$order = wc_get_order( $order_id ); |
1346
|
|
|
|
1347
|
|
|
$data = apply_filters( 'woocommerce_api_create_order_note_data', $data, $order_id, $this ); |
1348
|
|
|
|
1349
|
|
|
// note content is required |
1350
|
|
|
if ( ! isset( $data['note'] ) ) { |
1351
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_order_note', __( 'Order note is required', 'woocommerce' ), 400 ); |
1352
|
|
|
} |
1353
|
|
|
|
1354
|
|
|
$is_customer_note = ( isset( $data['customer_note'] ) && true === $data['customer_note'] ); |
1355
|
|
|
|
1356
|
|
|
// create the note |
1357
|
|
|
$note_id = $order->add_order_note( $data['note'], $is_customer_note ); |
|
|
|
|
1358
|
|
|
|
1359
|
|
|
if ( ! $note_id ) { |
1360
|
|
|
throw new WC_API_Exception( 'woocommerce_api_cannot_create_order_note', __( 'Cannot create order note, please try again', 'woocommerce' ), 500 ); |
1361
|
|
|
} |
1362
|
|
|
|
1363
|
|
|
// HTTP 201 Created |
1364
|
|
|
$this->server->send_status( 201 ); |
1365
|
|
|
|
1366
|
|
|
do_action( 'woocommerce_api_create_order_note', $note_id, $order_id, $this ); |
1367
|
|
|
|
1368
|
|
|
return $this->get_order_note( $order->id, $note_id ); |
1369
|
|
|
} catch ( WC_API_Exception $e ) { |
1370
|
|
|
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); |
1371
|
|
|
} |
1372
|
|
|
} |
1373
|
|
|
|
1374
|
|
|
/** |
1375
|
|
|
* Edit the order note |
1376
|
|
|
* |
1377
|
|
|
* @since 2.2 |
1378
|
|
|
* @param string $order_id order ID |
1379
|
|
|
* @param string $id note ID |
1380
|
|
|
* @param array $data parsed request data |
1381
|
|
|
* @return WP_Error|array error or edited note response data |
1382
|
|
|
*/ |
1383
|
|
|
public function edit_order_note( $order_id, $id, $data ) { |
1384
|
|
|
try { |
1385
|
|
View Code Duplication |
if ( ! isset( $data['order_note'] ) ) { |
|
|
|
|
1386
|
|
|
throw new WC_API_Exception( 'woocommerce_api_missing_order_note_data', sprintf( __( 'No %1$s data specified to edit %1$s', 'woocommerce' ), 'order_note' ), 400 ); |
1387
|
|
|
} |
1388
|
|
|
|
1389
|
|
|
$data = $data['order_note']; |
1390
|
|
|
|
1391
|
|
|
// Validate order ID |
1392
|
|
|
$order_id = $this->validate_request( $order_id, $this->post_type, 'edit' ); |
1393
|
|
|
|
1394
|
|
|
if ( is_wp_error( $order_id ) ) { |
1395
|
|
|
return $order_id; |
1396
|
|
|
} |
1397
|
|
|
|
1398
|
|
|
$order = wc_get_order( $order_id ); |
1399
|
|
|
|
1400
|
|
|
// Validate note ID |
1401
|
|
|
$id = absint( $id ); |
1402
|
|
|
|
1403
|
|
|
if ( empty( $id ) ) { |
1404
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_order_note_id', __( 'Invalid order note ID', 'woocommerce' ), 400 ); |
1405
|
|
|
} |
1406
|
|
|
|
1407
|
|
|
// Ensure note ID is valid |
1408
|
|
|
$note = get_comment( $id ); |
1409
|
|
|
|
1410
|
|
|
if ( is_null( $note ) ) { |
1411
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_order_note_id', __( 'An order note with the provided ID could not be found', 'woocommerce' ), 404 ); |
1412
|
|
|
} |
1413
|
|
|
|
1414
|
|
|
// Ensure note ID is associated with given order |
1415
|
|
|
if ( $note->comment_post_ID != $order->id ) { |
1416
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_order_note_id', __( 'The order note ID provided is not associated with the order', 'woocommerce' ), 400 ); |
1417
|
|
|
} |
1418
|
|
|
|
1419
|
|
|
$data = apply_filters( 'woocommerce_api_edit_order_note_data', $data, $note->comment_ID, $order->id, $this ); |
1420
|
|
|
|
1421
|
|
|
// Note content |
1422
|
|
|
if ( isset( $data['note'] ) ) { |
1423
|
|
|
|
1424
|
|
|
wp_update_comment( |
1425
|
|
|
array( |
1426
|
|
|
'comment_ID' => $note->comment_ID, |
1427
|
|
|
'comment_content' => $data['note'], |
1428
|
|
|
) |
1429
|
|
|
); |
1430
|
|
|
} |
1431
|
|
|
|
1432
|
|
|
// Customer note |
1433
|
|
|
if ( isset( $data['customer_note'] ) ) { |
1434
|
|
|
|
1435
|
|
|
update_comment_meta( $note->comment_ID, 'is_customer_note', true === $data['customer_note'] ? 1 : 0 ); |
1436
|
|
|
} |
1437
|
|
|
|
1438
|
|
|
do_action( 'woocommerce_api_edit_order_note', $note->comment_ID, $order->id, $this ); |
1439
|
|
|
|
1440
|
|
|
return $this->get_order_note( $order->id, $note->comment_ID ); |
1441
|
|
|
} catch ( WC_API_Exception $e ) { |
1442
|
|
|
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); |
1443
|
|
|
} |
1444
|
|
|
} |
1445
|
|
|
|
1446
|
|
|
/** |
1447
|
|
|
* Delete order note |
1448
|
|
|
* |
1449
|
|
|
* @since 2.2 |
1450
|
|
|
* @param string $order_id order ID |
1451
|
|
|
* @param string $id note ID |
1452
|
|
|
* @return WP_Error|array error or deleted message |
1453
|
|
|
*/ |
1454
|
|
|
public function delete_order_note( $order_id, $id ) { |
1455
|
|
|
try { |
1456
|
|
|
$order_id = $this->validate_request( $order_id, $this->post_type, 'delete' ); |
1457
|
|
|
|
1458
|
|
|
if ( is_wp_error( $order_id ) ) { |
1459
|
|
|
return $order_id; |
1460
|
|
|
} |
1461
|
|
|
|
1462
|
|
|
// Validate note ID |
1463
|
|
|
$id = absint( $id ); |
1464
|
|
|
|
1465
|
|
|
if ( empty( $id ) ) { |
1466
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_order_note_id', __( 'Invalid order note ID', 'woocommerce' ), 400 ); |
1467
|
|
|
} |
1468
|
|
|
|
1469
|
|
|
// Ensure note ID is valid |
1470
|
|
|
$note = get_comment( $id ); |
1471
|
|
|
|
1472
|
|
|
if ( is_null( $note ) ) { |
1473
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_order_note_id', __( 'An order note with the provided ID could not be found', 'woocommerce' ), 404 ); |
1474
|
|
|
} |
1475
|
|
|
|
1476
|
|
|
// Ensure note ID is associated with given order |
1477
|
|
|
if ( $note->comment_post_ID != $order_id ) { |
1478
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_order_note_id', __( 'The order note ID provided is not associated with the order', 'woocommerce' ), 400 ); |
1479
|
|
|
} |
1480
|
|
|
|
1481
|
|
|
// Force delete since trashed order notes could not be managed through comments list table |
1482
|
|
|
$result = wp_delete_comment( $note->comment_ID, true ); |
1483
|
|
|
|
1484
|
|
|
if ( ! $result ) { |
1485
|
|
|
throw new WC_API_Exception( 'woocommerce_api_cannot_delete_order_note', __( 'This order note cannot be deleted', 'woocommerce' ), 500 ); |
1486
|
|
|
} |
1487
|
|
|
|
1488
|
|
|
do_action( 'woocommerce_api_delete_order_note', $note->comment_ID, $order_id, $this ); |
1489
|
|
|
|
1490
|
|
|
return array( 'message' => __( 'Permanently deleted order note', 'woocommerce' ) ); |
1491
|
|
|
} catch ( WC_API_Exception $e ) { |
1492
|
|
|
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); |
1493
|
|
|
} |
1494
|
|
|
} |
1495
|
|
|
|
1496
|
|
|
/** |
1497
|
|
|
* Get the order refunds for an order |
1498
|
|
|
* |
1499
|
|
|
* @since 2.2 |
1500
|
|
|
* @param string $order_id order ID |
1501
|
|
|
* @param string|null $fields fields to include in response |
1502
|
|
|
* @return array |
1503
|
|
|
*/ |
1504
|
|
|
public function get_order_refunds( $order_id, $fields = null ) { |
1505
|
|
|
|
1506
|
|
|
// Ensure ID is valid order ID |
1507
|
|
|
$order_id = $this->validate_request( $order_id, $this->post_type, 'read' ); |
1508
|
|
|
|
1509
|
|
|
if ( is_wp_error( $order_id ) ) { |
1510
|
|
|
return $order_id; |
1511
|
|
|
} |
1512
|
|
|
|
1513
|
|
|
$refund_items = wc_get_orders( array( |
1514
|
|
|
'type' => 'shop_order_refund', |
1515
|
|
|
'parent' => $order_id, |
1516
|
|
|
'limit' => -1, |
1517
|
|
|
'return' => 'ids', |
1518
|
|
|
) ); |
1519
|
|
|
$order_refunds = array(); |
1520
|
|
|
|
1521
|
|
|
foreach ( $refund_items as $refund_id ) { |
1522
|
|
|
$order_refunds[] = current( $this->get_order_refund( $order_id, $refund_id, $fields ) ); |
|
|
|
|
1523
|
|
|
} |
1524
|
|
|
|
1525
|
|
|
return array( 'order_refunds' => apply_filters( 'woocommerce_api_order_refunds_response', $order_refunds, $order_id, $fields, $refund_items, $this ) ); |
1526
|
|
|
} |
1527
|
|
|
|
1528
|
|
|
/** |
1529
|
|
|
* Get an order refund for the given order ID and ID |
1530
|
|
|
* |
1531
|
|
|
* @since 2.2 |
1532
|
|
|
* @param string $order_id order ID |
1533
|
|
|
* @param string|null $fields fields to limit response to |
1534
|
|
|
* @return array |
1535
|
|
|
*/ |
1536
|
|
|
public function get_order_refund( $order_id, $id, $fields = null ) { |
1537
|
|
|
try { |
1538
|
|
|
// Validate order ID |
1539
|
|
|
$order_id = $this->validate_request( $order_id, $this->post_type, 'read' ); |
1540
|
|
|
|
1541
|
|
|
if ( is_wp_error( $order_id ) ) { |
1542
|
|
|
return $order_id; |
1543
|
|
|
} |
1544
|
|
|
|
1545
|
|
|
$id = absint( $id ); |
1546
|
|
|
|
1547
|
|
|
if ( empty( $id ) ) { |
1548
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_order_refund_id', __( 'Invalid order refund ID', 'woocommerce' ), 400 ); |
1549
|
|
|
} |
1550
|
|
|
|
1551
|
|
|
$order = wc_get_order( $order_id ); |
1552
|
|
|
$refund = wc_get_order( $id ); |
1553
|
|
|
|
1554
|
|
|
if ( ! $refund ) { |
1555
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_order_refund_id', __( 'An order refund with the provided ID could not be found', 'woocommerce' ), 404 ); |
1556
|
|
|
} |
1557
|
|
|
|
1558
|
|
|
$line_items = array(); |
1559
|
|
|
|
1560
|
|
|
// Add line items |
1561
|
|
|
foreach ( $refund->get_items( 'line_item' ) as $item_id => $item ) { |
1562
|
|
|
|
1563
|
|
|
$product = $order->get_product_from_item( $item ); |
1564
|
|
|
$meta = new WC_Order_Item_Meta( $item, $product ); |
1565
|
|
|
$item_meta = array(); |
1566
|
|
|
|
1567
|
|
View Code Duplication |
foreach ( $meta->get_formatted() as $meta_key => $formatted_meta ) { |
|
|
|
|
1568
|
|
|
$item_meta[] = array( |
1569
|
|
|
'key' => $meta_key, |
1570
|
|
|
'label' => $formatted_meta['label'], |
1571
|
|
|
'value' => $formatted_meta['value'], |
1572
|
|
|
); |
1573
|
|
|
} |
1574
|
|
|
|
1575
|
|
|
$line_items[] = array( |
1576
|
|
|
'id' => $item_id, |
1577
|
|
|
'subtotal' => wc_format_decimal( $order->get_line_subtotal( $item ), 2 ), |
1578
|
|
|
'subtotal_tax' => wc_format_decimal( $item['line_subtotal_tax'], 2 ), |
1579
|
|
|
'total' => wc_format_decimal( $order->get_line_total( $item ), 2 ), |
1580
|
|
|
'total_tax' => wc_format_decimal( $order->get_line_tax( $item ), 2 ), |
1581
|
|
|
'price' => wc_format_decimal( $order->get_item_total( $item ), 2 ), |
1582
|
|
|
'quantity' => (int) $item['qty'], |
1583
|
|
|
'tax_class' => ( ! empty( $item['tax_class'] ) ) ? $item['tax_class'] : null, |
1584
|
|
|
'name' => $item['name'], |
1585
|
|
|
'product_id' => ( isset( $product->variation_id ) ) ? $product->variation_id : $product->id, |
1586
|
|
|
'sku' => is_object( $product ) ? $product->get_sku() : null, |
1587
|
|
|
'meta' => $item_meta, |
1588
|
|
|
'refunded_item_id' => (int) $item['refunded_item_id'], |
1589
|
|
|
); |
1590
|
|
|
} |
1591
|
|
|
|
1592
|
|
|
$order_refund = array( |
1593
|
|
|
'id' => $refund->id, |
1594
|
|
|
'created_at' => $this->server->format_datetime( $refund->date ), |
1595
|
|
|
'amount' => wc_format_decimal( $refund->get_refund_amount(), 2 ), |
|
|
|
|
1596
|
|
|
'reason' => $refund->get_refund_reason(), |
|
|
|
|
1597
|
|
|
'line_items' => $line_items |
1598
|
|
|
); |
1599
|
|
|
|
1600
|
|
|
return array( 'order_refund' => apply_filters( 'woocommerce_api_order_refund_response', $order_refund, $id, $fields, $refund, $order_id, $this ) ); |
1601
|
|
|
} catch ( WC_API_Exception $e ) { |
1602
|
|
|
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); |
1603
|
|
|
} |
1604
|
|
|
} |
1605
|
|
|
|
1606
|
|
|
/** |
1607
|
|
|
* Create a new order refund for the given order |
1608
|
|
|
* |
1609
|
|
|
* @since 2.2 |
1610
|
|
|
* @param string $order_id order ID |
1611
|
|
|
* @param array $data raw request data |
1612
|
|
|
* @param bool $api_refund do refund using a payment gateway API |
1613
|
|
|
* @return WP_Error|array error or created refund response data |
1614
|
|
|
*/ |
1615
|
|
|
public function create_order_refund( $order_id, $data, $api_refund = true ) { |
1616
|
|
|
try { |
1617
|
|
View Code Duplication |
if ( ! isset( $data['order_refund'] ) ) { |
|
|
|
|
1618
|
|
|
throw new WC_API_Exception( 'woocommerce_api_missing_order_refund_data', sprintf( __( 'No %1$s data specified to create %1$s', 'woocommerce' ), 'order_refund' ), 400 ); |
1619
|
|
|
} |
1620
|
|
|
|
1621
|
|
|
$data = $data['order_refund']; |
1622
|
|
|
|
1623
|
|
|
// Permission check |
1624
|
|
|
if ( ! current_user_can( 'publish_shop_orders' ) ) { |
1625
|
|
|
throw new WC_API_Exception( 'woocommerce_api_user_cannot_create_order_refund', __( 'You do not have permission to create order refunds', 'woocommerce' ), 401 ); |
1626
|
|
|
} |
1627
|
|
|
|
1628
|
|
|
$order_id = absint( $order_id ); |
1629
|
|
|
|
1630
|
|
|
if ( empty( $order_id ) ) { |
1631
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_order_id', __( 'Order ID is invalid', 'woocommerce' ), 400 ); |
1632
|
|
|
} |
1633
|
|
|
|
1634
|
|
|
$data = apply_filters( 'woocommerce_api_create_order_refund_data', $data, $order_id, $this ); |
1635
|
|
|
|
1636
|
|
|
// Refund amount is required |
1637
|
|
|
if ( ! isset( $data['amount'] ) ) { |
1638
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_order_refund', __( 'Refund amount is required', 'woocommerce' ), 400 ); |
1639
|
|
|
} elseif ( 0 > $data['amount'] ) { |
1640
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_order_refund', __( 'Refund amount must be positive', 'woocommerce' ), 400 ); |
1641
|
|
|
} |
1642
|
|
|
|
1643
|
|
|
$data['order_id'] = $order_id; |
1644
|
|
|
$data['refund_id'] = 0; |
1645
|
|
|
|
1646
|
|
|
// Create the refund |
1647
|
|
|
$refund = wc_create_refund( $data ); |
1648
|
|
|
|
1649
|
|
|
if ( ! $refund ) { |
1650
|
|
|
throw new WC_API_Exception( 'woocommerce_api_cannot_create_order_refund', __( 'Cannot create order refund, please try again', 'woocommerce' ), 500 ); |
1651
|
|
|
} |
1652
|
|
|
|
1653
|
|
|
// Refund via API |
1654
|
|
View Code Duplication |
if ( $api_refund ) { |
|
|
|
|
1655
|
|
|
if ( WC()->payment_gateways() ) { |
1656
|
|
|
$payment_gateways = WC()->payment_gateways->payment_gateways(); |
1657
|
|
|
} |
1658
|
|
|
|
1659
|
|
|
$order = wc_get_order( $order_id ); |
1660
|
|
|
|
1661
|
|
|
if ( isset( $payment_gateways[ $order->payment_method ] ) && $payment_gateways[ $order->payment_method ]->supports( 'refunds' ) ) { |
1662
|
|
|
$result = $payment_gateways[ $order->payment_method ]->process_refund( $order_id, $refund->get_refund_amount(), $refund->get_refund_reason() ); |
1663
|
|
|
|
1664
|
|
|
if ( is_wp_error( $result ) ) { |
1665
|
|
|
return $result; |
1666
|
|
|
} elseif ( ! $result ) { |
1667
|
|
|
throw new WC_API_Exception( 'woocommerce_api_create_order_refund_api_failed', __( 'An error occurred while attempting to create the refund using the payment gateway API', 'woocommerce' ), 500 ); |
1668
|
|
|
} |
1669
|
|
|
} |
1670
|
|
|
} |
1671
|
|
|
|
1672
|
|
|
// HTTP 201 Created |
1673
|
|
|
$this->server->send_status( 201 ); |
1674
|
|
|
|
1675
|
|
|
do_action( 'woocommerce_api_create_order_refund', $refund->id, $order_id, $this ); |
1676
|
|
|
|
1677
|
|
|
return $this->get_order_refund( $order_id, $refund->id ); |
1678
|
|
|
} catch ( WC_API_Exception $e ) { |
1679
|
|
|
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); |
1680
|
|
|
} |
1681
|
|
|
} |
1682
|
|
|
|
1683
|
|
|
/** |
1684
|
|
|
* Edit an order refund |
1685
|
|
|
* |
1686
|
|
|
* @since 2.2 |
1687
|
|
|
* @param string $order_id order ID |
1688
|
|
|
* @param string $id refund ID |
1689
|
|
|
* @param array $data parsed request data |
1690
|
|
|
* @return WP_Error|array error or edited refund response data |
1691
|
|
|
*/ |
1692
|
|
|
public function edit_order_refund( $order_id, $id, $data ) { |
1693
|
|
|
try { |
1694
|
|
View Code Duplication |
if ( ! isset( $data['order_refund'] ) ) { |
|
|
|
|
1695
|
|
|
throw new WC_API_Exception( 'woocommerce_api_missing_order_refund_data', sprintf( __( 'No %1$s data specified to edit %1$s', 'woocommerce' ), 'order_refund' ), 400 ); |
1696
|
|
|
} |
1697
|
|
|
|
1698
|
|
|
$data = $data['order_refund']; |
1699
|
|
|
|
1700
|
|
|
// Validate order ID |
1701
|
|
|
$order_id = $this->validate_request( $order_id, $this->post_type, 'edit' ); |
1702
|
|
|
|
1703
|
|
|
if ( is_wp_error( $order_id ) ) { |
1704
|
|
|
return $order_id; |
1705
|
|
|
} |
1706
|
|
|
|
1707
|
|
|
// Validate refund ID |
1708
|
|
|
$id = absint( $id ); |
1709
|
|
|
|
1710
|
|
|
if ( empty( $id ) ) { |
1711
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_order_refund_id', __( 'Invalid order refund ID', 'woocommerce' ), 400 ); |
1712
|
|
|
} |
1713
|
|
|
|
1714
|
|
|
// Ensure order ID is valid |
1715
|
|
|
$refund = get_post( $id ); |
1716
|
|
|
|
1717
|
|
|
if ( ! $refund ) { |
1718
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_order_refund_id', __( 'An order refund with the provided ID could not be found', 'woocommerce' ), 404 ); |
1719
|
|
|
} |
1720
|
|
|
|
1721
|
|
|
// Ensure refund ID is associated with given order |
1722
|
|
|
if ( $refund->post_parent != $order_id ) { |
1723
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_order_refund_id', __( 'The order refund ID provided is not associated with the order', 'woocommerce' ), 400 ); |
1724
|
|
|
} |
1725
|
|
|
|
1726
|
|
|
$data = apply_filters( 'woocommerce_api_edit_order_refund_data', $data, $refund->ID, $order_id, $this ); |
1727
|
|
|
|
1728
|
|
|
// Update reason |
1729
|
|
|
if ( isset( $data['reason'] ) ) { |
1730
|
|
|
$updated_refund = wp_update_post( array( 'ID' => $refund->ID, 'post_excerpt' => $data['reason'] ) ); |
1731
|
|
|
|
1732
|
|
|
if ( is_wp_error( $updated_refund ) ) { |
1733
|
|
|
return $updated_refund; |
1734
|
|
|
} |
1735
|
|
|
} |
1736
|
|
|
|
1737
|
|
|
// Update refund amount |
1738
|
|
|
if ( isset( $data['amount'] ) && 0 < $data['amount'] ) { |
1739
|
|
|
update_post_meta( $refund->ID, '_refund_amount', wc_format_decimal( $data['amount'] ) ); |
1740
|
|
|
} |
1741
|
|
|
|
1742
|
|
|
do_action( 'woocommerce_api_edit_order_refund', $refund->ID, $order_id, $this ); |
1743
|
|
|
|
1744
|
|
|
return $this->get_order_refund( $order_id, $refund->ID ); |
|
|
|
|
1745
|
|
|
} catch ( WC_API_Exception $e ) { |
1746
|
|
|
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); |
1747
|
|
|
} |
1748
|
|
|
} |
1749
|
|
|
|
1750
|
|
|
/** |
1751
|
|
|
* Delete order refund |
1752
|
|
|
* |
1753
|
|
|
* @since 2.2 |
1754
|
|
|
* @param string $order_id order ID |
1755
|
|
|
* @param string $id refund ID |
1756
|
|
|
* @return WP_Error|array error or deleted message |
1757
|
|
|
*/ |
1758
|
|
|
public function delete_order_refund( $order_id, $id ) { |
1759
|
|
|
try { |
1760
|
|
|
$order_id = $this->validate_request( $order_id, $this->post_type, 'delete' ); |
1761
|
|
|
|
1762
|
|
|
if ( is_wp_error( $order_id ) ) { |
1763
|
|
|
return $order_id; |
1764
|
|
|
} |
1765
|
|
|
|
1766
|
|
|
// Validate refund ID |
1767
|
|
|
$id = absint( $id ); |
1768
|
|
|
|
1769
|
|
|
if ( empty( $id ) ) { |
1770
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_order_refund_id', __( 'Invalid order refund ID', 'woocommerce' ), 400 ); |
1771
|
|
|
} |
1772
|
|
|
|
1773
|
|
|
// Ensure refund ID is valid |
1774
|
|
|
$refund = get_post( $id ); |
1775
|
|
|
|
1776
|
|
|
if ( ! $refund ) { |
1777
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_order_refund_id', __( 'An order refund with the provided ID could not be found', 'woocommerce' ), 404 ); |
1778
|
|
|
} |
1779
|
|
|
|
1780
|
|
|
// Ensure refund ID is associated with given order |
1781
|
|
|
if ( $refund->post_parent != $order_id ) { |
1782
|
|
|
throw new WC_API_Exception( 'woocommerce_api_invalid_order_refund_id', __( 'The order refund ID provided is not associated with the order', 'woocommerce' ), 400 ); |
1783
|
|
|
} |
1784
|
|
|
|
1785
|
|
|
wc_delete_shop_order_transients( $order_id ); |
1786
|
|
|
|
1787
|
|
|
do_action( 'woocommerce_api_delete_order_refund', $refund->ID, $order_id, $this ); |
1788
|
|
|
|
1789
|
|
|
return $this->delete( $refund->ID, 'refund', true ); |
1790
|
|
|
} catch ( WC_API_Exception $e ) { |
1791
|
|
|
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); |
1792
|
|
|
} |
1793
|
|
|
} |
1794
|
|
|
|
1795
|
|
|
/** |
1796
|
|
|
* Bulk update or insert orders |
1797
|
|
|
* Accepts an array with orders in the formats supported by |
1798
|
|
|
* WC_API_Orders->create_order() and WC_API_Orders->edit_order() |
1799
|
|
|
* |
1800
|
|
|
* @since 2.4.0 |
1801
|
|
|
* @param array $data |
1802
|
|
|
* @return array |
1803
|
|
|
*/ |
1804
|
|
View Code Duplication |
public function bulk( $data ) { |
|
|
|
|
1805
|
|
|
|
1806
|
|
|
try { |
1807
|
|
|
if ( ! isset( $data['orders'] ) ) { |
1808
|
|
|
throw new WC_API_Exception( 'woocommerce_api_missing_orders_data', sprintf( __( 'No %1$s data specified to create/edit %1$s', 'woocommerce' ), 'orders' ), 400 ); |
1809
|
|
|
} |
1810
|
|
|
|
1811
|
|
|
$data = $data['orders']; |
1812
|
|
|
$limit = apply_filters( 'woocommerce_api_bulk_limit', 100, 'orders' ); |
1813
|
|
|
|
1814
|
|
|
// Limit bulk operation |
1815
|
|
|
if ( count( $data ) > $limit ) { |
1816
|
|
|
throw new WC_API_Exception( 'woocommerce_api_orders_request_entity_too_large', sprintf( __( 'Unable to accept more than %s items for this request', 'woocommerce' ), $limit ), 413 ); |
1817
|
|
|
} |
1818
|
|
|
|
1819
|
|
|
$orders = array(); |
1820
|
|
|
|
1821
|
|
|
foreach ( $data as $_order ) { |
1822
|
|
|
$order_id = 0; |
1823
|
|
|
|
1824
|
|
|
// Try to get the order ID |
1825
|
|
|
if ( isset( $_order['id'] ) ) { |
1826
|
|
|
$order_id = intval( $_order['id'] ); |
1827
|
|
|
} |
1828
|
|
|
|
1829
|
|
|
// Order exists / edit order |
1830
|
|
|
if ( $order_id ) { |
1831
|
|
|
$edit = $this->edit_order( $order_id, array( 'order' => $_order ) ); |
1832
|
|
|
|
1833
|
|
|
if ( is_wp_error( $edit ) ) { |
1834
|
|
|
$orders[] = array( |
1835
|
|
|
'id' => $order_id, |
1836
|
|
|
'error' => array( 'code' => $edit->get_error_code(), 'message' => $edit->get_error_message() ) |
1837
|
|
|
); |
1838
|
|
|
} else { |
1839
|
|
|
$orders[] = $edit['order']; |
1840
|
|
|
} |
1841
|
|
|
} |
1842
|
|
|
|
1843
|
|
|
// Order don't exists / create order |
1844
|
|
|
else { |
1845
|
|
|
$new = $this->create_order( array( 'order' => $_order ) ); |
1846
|
|
|
|
1847
|
|
|
if ( is_wp_error( $new ) ) { |
1848
|
|
|
$orders[] = array( |
1849
|
|
|
'id' => $order_id, |
1850
|
|
|
'error' => array( 'code' => $new->get_error_code(), 'message' => $new->get_error_message() ) |
1851
|
|
|
); |
1852
|
|
|
} else { |
1853
|
|
|
$orders[] = $new['order']; |
1854
|
|
|
} |
1855
|
|
|
} |
1856
|
|
|
} |
1857
|
|
|
|
1858
|
|
|
return array( 'orders' => apply_filters( 'woocommerce_api_orders_bulk_response', $orders, $this ) ); |
1859
|
|
|
} catch ( WC_API_Exception $e ) { |
1860
|
|
|
return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); |
1861
|
|
|
} |
1862
|
|
|
} |
1863
|
|
|
} |
1864
|
|
|
|
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.