Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like WC_CLI_Order often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use WC_CLI_Order, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
11 | class WC_CLI_Order extends WC_CLI_Command { |
||
12 | |||
13 | /** |
||
14 | * Create an order. |
||
15 | * |
||
16 | * ## OPTIONS |
||
17 | * |
||
18 | * [--<field>=<value>] |
||
19 | * : Associative args for the new order. |
||
20 | * |
||
21 | * [--porcelain] |
||
22 | * : Outputs just the new order id. |
||
23 | * |
||
24 | * ## AVAILABLE FIELDS |
||
25 | * |
||
26 | * Required fields: |
||
27 | * |
||
28 | * * customer_id |
||
29 | * |
||
30 | * Optional fields: |
||
31 | * |
||
32 | * * status |
||
33 | * * note |
||
34 | * * currency |
||
35 | * * order_meta |
||
36 | * |
||
37 | * Payment detail fields: |
||
38 | * |
||
39 | * * payment_details.method_id |
||
40 | * * payment_details.method_title |
||
41 | * * payment_details.paid |
||
42 | * |
||
43 | * Billing address fields: |
||
44 | * |
||
45 | * * billing_address.first_name |
||
46 | * * billing_address.last_name |
||
47 | * * billing_address.company |
||
48 | * * billing_address.address_1 |
||
49 | * * billing_address.address_2 |
||
50 | * * billing_address.city |
||
51 | * * billing_address.state |
||
52 | * * billing_address.postcode |
||
53 | * * billing_address.country |
||
54 | * * billing_address.email |
||
55 | * * billing_address.phone |
||
56 | * |
||
57 | * Shipping address fields: |
||
58 | * |
||
59 | * * shipping_address.first_name |
||
60 | * * shipping_address.last_name |
||
61 | * * shipping_address.company |
||
62 | * * shipping_address.address_1 |
||
63 | * * shipping_address.address_2 |
||
64 | * * shipping_address.city |
||
65 | * * shipping_address.state |
||
66 | * * shipping_address.postcode |
||
67 | * * shipping_address.country |
||
68 | * |
||
69 | * Line item fields (numeric array, started with index zero): |
||
70 | * |
||
71 | * * line_items.0.product_id |
||
72 | * * line_items.0.quantity |
||
73 | * * line_items.0.variations.pa_color |
||
74 | * |
||
75 | * For second line item: line_items.1.product_id and so on. |
||
76 | * |
||
77 | * Shipping line fields (numeric array, started with index zero): |
||
78 | * |
||
79 | * * shipping_lines.0.method_id |
||
80 | * * shipping_lines.0.method_title |
||
81 | * * shipping_lines.0.total |
||
82 | * |
||
83 | * For second shipping item: shipping_lines.1.method_id and so on. |
||
84 | * |
||
85 | * ## EXAMPLES |
||
86 | * |
||
87 | * wp wc order create --customer_id=1 --status=pending ... |
||
88 | * |
||
89 | * @since 2.5.0 |
||
90 | */ |
||
91 | public function create( $__, $assoc_args ) { |
||
92 | global $wpdb; |
||
93 | |||
94 | wc_transaction_query( 'start' ); |
||
95 | |||
96 | try { |
||
97 | $porcelain = isset( $assoc_args['porcelain'] ); |
||
98 | unset( $assoc_args['porcelain'] ); |
||
99 | |||
100 | $data = apply_filters( 'woocommerce_cli_create_order_data', $this->unflatten_array( $assoc_args ) ); |
||
101 | |||
102 | // default order args, note that status is checked for validity in wc_create_order() |
||
103 | $default_order_args = array( |
||
104 | 'status' => isset( $data['status'] ) ? $data['status'] : '', |
||
105 | 'customer_note' => isset( $data['note'] ) ? $data['note'] : null, |
||
106 | ); |
||
107 | |||
108 | if ( empty( $data['customer_id'] ) ) { |
||
109 | throw new WC_CLI_Exception( 'woocommerce_cli_missing_customer_id', __( 'Missing customer_id field', 'woocommerce' ) ); |
||
110 | } |
||
111 | |||
112 | // make sure customer exists |
||
113 | if ( false === get_user_by( 'id', $data['customer_id'] ) ) { |
||
114 | throw new WC_CLI_Exception( 'woocommerce_cli_invalid_customer_id', __( 'Customer ID is invalid', 'woocommerce' ) ); |
||
115 | } |
||
116 | $default_order_args['customer_id'] = $data['customer_id']; |
||
117 | |||
118 | // create the pending order |
||
119 | $order = $this->create_base_order( $default_order_args, $data ); |
||
120 | |||
121 | View Code Duplication | if ( is_wp_error( $order ) ) { |
|
|
|||
122 | throw new WC_CLI_Exception( 'woocommerce_cli_cannot_create_order', sprintf( __( 'Cannot create order: %s', 'woocommerce' ), implode( ', ', $order->get_error_messages() ) ) ); |
||
123 | } |
||
124 | |||
125 | // billing/shipping addresses |
||
126 | $this->set_order_addresses( $order, $data ); |
||
127 | |||
128 | $lines = array( |
||
129 | 'line_item' => 'line_items', |
||
130 | 'shipping' => 'shipping_lines', |
||
131 | 'fee' => 'fee_lines', |
||
132 | 'coupon' => 'coupon_lines', |
||
133 | ); |
||
134 | |||
135 | View Code Duplication | foreach ( $lines as $line_type => $line ) { |
|
136 | if ( isset( $data[ $line ] ) && is_array( $data[ $line ] ) ) { |
||
137 | $set_item = "set_{$line_type}"; |
||
138 | foreach ( $data[ $line ] as $item ) { |
||
139 | $this->$set_item( $order, $item, 'create' ); |
||
140 | } |
||
141 | } |
||
142 | } |
||
143 | |||
144 | // calculate totals and set them |
||
145 | $order->calculate_totals(); |
||
146 | |||
147 | // payment method (and payment_complete() if `paid` == true) |
||
148 | if ( isset( $data['payment_details'] ) && is_array( $data['payment_details'] ) ) { |
||
149 | // method ID & title are required |
||
150 | if ( empty( $data['payment_details']['method_id'] ) || empty( $data['payment_details']['method_title'] ) ) { |
||
151 | throw new WC_CLI_Exception( 'woocommerce_invalid_payment_details', __( 'Payment method ID and title are required', 'woocommerce' ) ); |
||
152 | } |
||
153 | |||
154 | update_post_meta( $order->id, '_payment_method', $data['payment_details']['method_id'] ); |
||
155 | update_post_meta( $order->id, '_payment_method_title', $data['payment_details']['method_title'] ); |
||
156 | |||
157 | // Mark as paid if set. |
||
158 | View Code Duplication | if ( isset( $data['payment_details']['paid'] ) && $this->is_true( $data['payment_details']['paid'] ) ) { |
|
159 | $order->payment_complete( isset( $data['payment_details']['transaction_id'] ) ? $data['payment_details']['transaction_id'] : '' ); |
||
160 | } |
||
161 | } |
||
162 | |||
163 | // Set order currency. |
||
164 | if ( isset( $data['currency'] ) ) { |
||
165 | if ( ! array_key_exists( $data['currency'], get_woocommerce_currencies() ) ) { |
||
166 | throw new WC_CLI_Exception( 'woocommerce_invalid_order_currency', __( 'Provided order currency is invalid', 'woocommerce') ); |
||
167 | } |
||
168 | |||
169 | update_post_meta( $order->id, '_order_currency', $data['currency'] ); |
||
170 | } |
||
171 | |||
172 | // Set order meta. |
||
173 | View Code Duplication | if ( isset( $data['order_meta'] ) && is_array( $data['order_meta'] ) ) { |
|
174 | $this->set_order_meta( $order->id, $data['order_meta'] ); |
||
175 | } |
||
176 | |||
177 | wc_delete_shop_order_transients( $order->id ); |
||
178 | |||
179 | do_action( 'woocommerce_cli_create_order', $order->id, $data ); |
||
180 | |||
181 | wc_transaction_query( 'commit' ); |
||
182 | |||
183 | if ( $porcelain ) { |
||
184 | WP_CLI::line( $order->id ); |
||
185 | } else { |
||
186 | WP_CLI::success( "Created order {$order->id}." ); |
||
187 | } |
||
188 | } catch ( WC_CLI_Exception $e ) { |
||
189 | wc_transaction_query( 'rollback' ); |
||
190 | |||
191 | WP_CLI::error( $e->getMessage() ); |
||
192 | } |
||
193 | } |
||
194 | |||
195 | /** |
||
196 | * Delete one or more orders. |
||
197 | * |
||
198 | * ## OPTIONS |
||
199 | * |
||
200 | * <id>... |
||
201 | * : The order ID to delete. |
||
202 | * |
||
203 | * ## EXAMPLES |
||
204 | * |
||
205 | * wp wc order delete 123 |
||
206 | * |
||
207 | * @since 2.5.0 |
||
208 | */ |
||
209 | public function delete( $args, $assoc_args ) { |
||
231 | |||
232 | /** |
||
233 | * Get an order. |
||
234 | * |
||
235 | * ## OPTIONS |
||
236 | * |
||
237 | * <id> |
||
238 | * : Order ID. |
||
239 | * |
||
240 | * [--field=<field>] |
||
241 | * : Instead of returning the whole order fields, returns the value of a single fields. |
||
242 | * |
||
243 | * [--fields=<fields>] |
||
244 | * : Get a specific subset of the order's fields. |
||
245 | * |
||
246 | * [--format=<format>] |
||
247 | * : Accepted values: table, json, csv. Default: table. |
||
248 | * |
||
249 | * ## AVAILABLE FIELDS |
||
250 | * |
||
251 | * These fields will be displayed by default: |
||
252 | * |
||
253 | * * id |
||
254 | * * order_number |
||
255 | * * customer_id |
||
256 | * * total |
||
257 | * * status |
||
258 | * * created_at |
||
259 | * |
||
260 | * For more fields, see: wp wc order list --help |
||
261 | * |
||
262 | * ## EXAMPLES |
||
263 | * |
||
264 | * wp wc order get 123 --fields=id,title,sku |
||
265 | * |
||
266 | * @since 2.5.0 |
||
267 | */ |
||
268 | View Code Duplication | public function get( $args, $assoc_args ) { |
|
282 | |||
283 | /** |
||
284 | * List orders. |
||
285 | * |
||
286 | * ## OPTIONS |
||
287 | * |
||
288 | * [--<field>=<value>] |
||
289 | * : Filter orders based on order property. |
||
290 | * |
||
291 | * [--field=<field>] |
||
292 | * : Prints the value of a single field for each order. |
||
293 | * |
||
294 | * [--fields=<fields>] |
||
295 | * : Limit the output to specific order fields. |
||
296 | * |
||
297 | * [--format=<format>] |
||
298 | * : Acceptec values: table, csv, json, count, ids. Default: table. |
||
299 | * |
||
300 | * ## AVAILABLE FIELDS |
||
301 | * |
||
302 | * These fields will be displayed by default for each order: |
||
303 | * |
||
304 | * * id |
||
305 | * * order_number |
||
306 | * * customer_id |
||
307 | * * total |
||
308 | * * status |
||
309 | * * created_at |
||
310 | * |
||
311 | * These fields are optionally available: |
||
312 | * |
||
313 | * * updated_at |
||
314 | * * completed_at |
||
315 | * * currency |
||
316 | * * subtotal |
||
317 | * * total_line_items_quantity |
||
318 | * * total_tax |
||
319 | * * total_shipping |
||
320 | * * cart_tax |
||
321 | * * shipping_tax |
||
322 | * * total_discount |
||
323 | * * shipping_methods |
||
324 | * * note |
||
325 | * * customer_ip |
||
326 | * * customer_user_agent |
||
327 | * * view_order_url |
||
328 | * |
||
329 | * Payment detail fields: |
||
330 | * |
||
331 | * * payment_details.method_id |
||
332 | * * payment_details.method_title |
||
333 | * * payment_details.paid |
||
334 | * |
||
335 | * Billing address fields: |
||
336 | * |
||
337 | * * billing_address.first_name |
||
338 | * * billing_address.last_name |
||
339 | * * billing_address.company |
||
340 | * * billing_address.address_1 |
||
341 | * * billing_address.address_2 |
||
342 | * * billing_address.city |
||
343 | * * billing_address.state |
||
344 | * * billing_address.postcode |
||
345 | * * billing_address.country |
||
346 | * * billing_address.email |
||
347 | * * billing_address.phone |
||
348 | * |
||
349 | * Shipping address fields: |
||
350 | * |
||
351 | * * shipping_address.first_name |
||
352 | * * shipping_address.last_name |
||
353 | * * shipping_address.company |
||
354 | * * shipping_address.address_1 |
||
355 | * * shipping_address.address_2 |
||
356 | * * shipping_address.city |
||
357 | * * shipping_address.state |
||
358 | * * shipping_address.postcode |
||
359 | * * shipping_address.country |
||
360 | * |
||
361 | * Line item fields (numeric array, started with index zero): |
||
362 | * |
||
363 | * * line_items.0.product_id |
||
364 | * * line_items.0.quantity |
||
365 | * * line_items.0.variations.pa_color |
||
366 | * |
||
367 | * For second line item: line_items.1.product_id and so on. |
||
368 | * |
||
369 | * Shipping line fields (numeric array, started with index zero): |
||
370 | * |
||
371 | * * shipping_lines.0.method_id |
||
372 | * * shipping_lines.0.method_title |
||
373 | * * shipping_lines.0.total |
||
374 | * |
||
375 | * For second shipping item: shipping_lines.1.method_id and so on. |
||
376 | * |
||
377 | * ## EXAMPLES |
||
378 | * |
||
379 | * wp wc order list |
||
380 | * |
||
381 | * @subcommand list |
||
382 | * @since 2.5.0 |
||
383 | */ |
||
384 | View Code Duplication | public function list_( $args, $assoc_args ) { |
|
398 | |||
399 | /** |
||
400 | * Update an order. |
||
401 | * |
||
402 | * ## OPTIONS |
||
403 | * |
||
404 | * <id> |
||
405 | * : Product ID |
||
406 | * |
||
407 | * [--<field>=<value>] |
||
408 | * : One or more fields to update. |
||
409 | * |
||
410 | * ## AVAILABLE FIELDS |
||
411 | * |
||
412 | * For available fields, see: wp wc order create --help |
||
413 | * |
||
414 | * ## EXAMPLES |
||
415 | * |
||
416 | * wp wc order update 123 --status=completed |
||
417 | * |
||
418 | * @todo gedex |
||
419 | * @since 2.5.0 |
||
420 | */ |
||
421 | public function update( $args, $assoc_args ) { |
||
422 | try { |
||
423 | $id = $args[0]; |
||
424 | $data = apply_filters( 'woocommerce_cli_update_order_data', $this->unflatten_array( $assoc_args ) ); |
||
425 | $update_totals = false; |
||
426 | $order = wc_get_order( $id ); |
||
427 | |||
428 | if ( empty( $order ) ) { |
||
429 | throw new WC_CLI_Exception( 'woocommerce_cli_invalid_order_id', __( 'Order ID is invalid', 'woocommerce' ) ); |
||
430 | } |
||
431 | |||
432 | $order_args = array( 'order_id' => $order->id ); |
||
433 | |||
434 | // customer note |
||
435 | if ( isset( $data['note'] ) ) { |
||
436 | $order_args['customer_note'] = $data['note']; |
||
437 | } |
||
438 | |||
439 | // order status |
||
440 | View Code Duplication | if ( ! empty( $data['status'] ) ) { |
|
441 | |||
442 | $order->update_status( $data['status'], isset( $data['status_note'] ) ? $data['status_note'] : '', true ); |
||
443 | } |
||
444 | |||
445 | // customer ID |
||
446 | View Code Duplication | if ( isset( $data['customer_id'] ) && $data['customer_id'] != $order->get_user_id() ) { |
|
447 | |||
448 | // make sure customer exists |
||
449 | if ( false === get_user_by( 'id', $data['customer_id'] ) ) { |
||
450 | throw new WC_CLI_Exception( 'woocommerce_cli_invalid_customer_id', __( 'Customer ID is invalid', 'woocommerce' ) ); |
||
451 | } |
||
452 | |||
453 | update_post_meta( $order->id, '_customer_user', $data['customer_id'] ); |
||
454 | } |
||
455 | |||
456 | // billing/shipping address |
||
457 | $this->set_order_addresses( $order, $data ); |
||
458 | |||
459 | $lines = array( |
||
460 | 'line_item' => 'line_items', |
||
461 | 'shipping' => 'shipping_lines', |
||
462 | 'fee' => 'fee_lines', |
||
463 | 'coupon' => 'coupon_lines', |
||
464 | ); |
||
465 | |||
466 | View Code Duplication | foreach ( $lines as $line_type => $line ) { |
|
467 | |||
468 | if ( isset( $data[ $line ] ) && is_array( $data[ $line ] ) ) { |
||
469 | |||
470 | $update_totals = true; |
||
471 | |||
472 | foreach ( $data[ $line ] as $item ) { |
||
473 | |||
474 | // item ID is always required |
||
475 | if ( ! array_key_exists( 'id', $item ) ) { |
||
476 | throw new WC_CLI_Exception( 'woocommerce_invalid_item_id', __( 'Order item ID is required', 'woocommerce' ) ); |
||
477 | } |
||
478 | |||
479 | // create item |
||
480 | if ( is_null( $item['id'] ) ) { |
||
481 | |||
482 | $this->set_item( $order, $line_type, $item, 'create' ); |
||
483 | |||
484 | } elseif ( $this->item_is_null( $item ) ) { |
||
485 | |||
486 | // delete item |
||
487 | wc_delete_order_item( $item['id'] ); |
||
488 | |||
489 | } else { |
||
490 | |||
491 | // update item |
||
492 | $this->set_item( $order, $line_type, $item, 'update' ); |
||
493 | } |
||
494 | } |
||
495 | } |
||
496 | } |
||
497 | |||
498 | // payment method (and payment_complete() if `paid` == true and order needs payment) |
||
499 | if ( isset( $data['payment_details'] ) && is_array( $data['payment_details'] ) ) { |
||
500 | |||
501 | // method ID |
||
502 | if ( isset( $data['payment_details']['method_id'] ) ) { |
||
503 | update_post_meta( $order->id, '_payment_method', $data['payment_details']['method_id'] ); |
||
504 | } |
||
505 | |||
506 | // method title |
||
507 | if ( isset( $data['payment_details']['method_title'] ) ) { |
||
508 | update_post_meta( $order->id, '_payment_method_title', $data['payment_details']['method_title'] ); |
||
509 | } |
||
510 | |||
511 | // mark as paid if set |
||
512 | View Code Duplication | if ( $order->needs_payment() && isset( $data['payment_details']['paid'] ) && $this->is_true( $data['payment_details']['paid'] ) ) { |
|
513 | $order->payment_complete( isset( $data['payment_details']['transaction_id'] ) ? $data['payment_details']['transaction_id'] : '' ); |
||
514 | } |
||
515 | } |
||
516 | |||
517 | // set order currency |
||
518 | if ( isset( $data['currency'] ) ) { |
||
519 | |||
520 | if ( ! array_key_exists( $data['currency'], get_woocommerce_currencies() ) ) { |
||
521 | throw new WC_CLI_Exception( 'woocommerce_invalid_order_currency', __( 'Provided order currency is invalid', 'woocommerce' ) ); |
||
522 | } |
||
523 | |||
524 | update_post_meta( $order->id, '_order_currency', $data['currency'] ); |
||
525 | } |
||
526 | |||
527 | // set order number |
||
528 | if ( isset( $data['order_number'] ) ) { |
||
529 | |||
530 | update_post_meta( $order->id, '_order_number', $data['order_number'] ); |
||
531 | } |
||
532 | |||
533 | // if items have changed, recalculate order totals |
||
534 | if ( $update_totals ) { |
||
535 | $order->calculate_totals(); |
||
536 | } |
||
537 | |||
538 | // update order meta |
||
539 | View Code Duplication | if ( isset( $data['order_meta'] ) && is_array( $data['order_meta'] ) ) { |
|
540 | $this->set_order_meta( $order->id, $data['order_meta'] ); |
||
541 | } |
||
542 | |||
543 | // update the order post to set customer note/modified date |
||
544 | wc_update_order( $order_args ); |
||
545 | |||
546 | wc_delete_shop_order_transients( $order->id ); |
||
547 | |||
548 | do_action( 'woocommerce_cli_update_order', $order->id, $data ); |
||
549 | |||
550 | WP_CLI::success( "Updated order {$order->id}." ); |
||
551 | |||
552 | } catch ( WC_CLI_Exception $e ) { |
||
553 | WP_CLI::error( $e->getMessage() ); |
||
554 | } |
||
555 | } |
||
556 | |||
557 | /** |
||
558 | * Get query args for list subcommand. |
||
559 | * |
||
560 | * @since 2.5.0 |
||
561 | * @param array $args Args from command line |
||
562 | * @return array |
||
563 | */ |
||
564 | protected function get_list_query_args( $args ) { |
||
589 | |||
590 | /** |
||
591 | * Get default format fields that will be used in `list` and `get` subcommands. |
||
592 | * |
||
593 | * @since 2.5.0 |
||
594 | * @return string |
||
595 | */ |
||
596 | protected function get_default_format_fields() { |
||
599 | |||
600 | /** |
||
601 | * Format posts from WP_Query result to items in which each item contain |
||
602 | * common properties of item. |
||
603 | * |
||
604 | * @since 2.5.0 |
||
605 | * @param array $posts Array of post |
||
606 | * @return array Items |
||
607 | */ |
||
608 | protected function format_posts_to_items( $posts ) { |
||
620 | |||
621 | /** |
||
622 | * Get the order data for the given ID. |
||
623 | * |
||
624 | * @since 2.5.0 |
||
625 | * @param WC_Order $order The order instance |
||
626 | * @return array |
||
627 | */ |
||
628 | protected function get_order_data( $order ) { |
||
774 | |||
775 | /** |
||
776 | * Creates new WC_Order. |
||
777 | * |
||
778 | * @since 2.5.0 |
||
779 | * @param $args array |
||
780 | * @return WC_Order |
||
781 | */ |
||
782 | protected function create_base_order( $args ) { |
||
785 | |||
786 | /** |
||
787 | * Helper method to set/update the billing & shipping addresses for an order. |
||
788 | * |
||
789 | * @since 2.5.0 |
||
790 | * @param WC_Order $order |
||
791 | * @param array $data |
||
792 | */ |
||
793 | protected function set_order_addresses( $order, $data ) { |
||
843 | |||
844 | /** |
||
845 | * Helper method to add/update order meta, with two restrictions: |
||
846 | * |
||
847 | * 1) Only non-protected meta (no leading underscore) can be set |
||
848 | * 2) Meta values must be scalar (int, string, bool) |
||
849 | * |
||
850 | * @since 2.5.0 |
||
851 | * @param int $order_id valid order ID |
||
852 | * @param array $order_meta order meta in array( 'meta_key' => 'meta_value' ) format |
||
853 | */ |
||
854 | View Code Duplication | protected function set_order_meta( $order_id, $order_meta ) { |
|
863 | |||
864 | /** |
||
865 | * Wrapper method to create/update order items |
||
866 | * |
||
867 | * When updating, the item ID provided is checked to ensure it is associated |
||
868 | * with the order. |
||
869 | * |
||
870 | * @since 2.5.0 |
||
871 | * @param WC_Order $order order |
||
872 | * @param string $item_type |
||
873 | * @param array $item item provided in the request body |
||
874 | * @param string $action either 'create' or 'update' |
||
875 | * @throws WC_CLI_Exception if item ID is not associated with order |
||
876 | */ |
||
877 | View Code Duplication | protected function set_item( $order, $item_type, $item, $action ) { |
|
897 | |||
898 | /** |
||
899 | * Create or update a line item |
||
900 | * |
||
901 | * @since 2.5.0 |
||
902 | * @param WC_Order $order |
||
903 | * @param array $item line item data |
||
904 | * @param string $action 'create' to add line item or 'update' to update it |
||
905 | * @throws WC_CLI_Exception invalid data, server error |
||
906 | */ |
||
907 | protected function set_line_item( $order, $item, $action ) { |
||
908 | |||
909 | $creating = ( 'create' === $action ); |
||
910 | |||
911 | // product is always required |
||
912 | if ( ! isset( $item['product_id'] ) && ! isset( $item['sku'] ) ) { |
||
913 | throw new WC_CLI_Exception( 'woocommerce_cli_invalid_product_id', __( 'Product ID or SKU is required', 'woocommerce' ) ); |
||
914 | } |
||
915 | |||
916 | // when updating, ensure product ID provided matches |
||
917 | if ( 'update' === $action ) { |
||
918 | |||
919 | $item_product_id = wc_get_order_item_meta( $item['id'], '_product_id' ); |
||
920 | $item_variation_id = wc_get_order_item_meta( $item['id'], '_variation_id' ); |
||
921 | |||
922 | if ( $item['product_id'] != $item_product_id && $item['product_id'] != $item_variation_id ) { |
||
923 | throw new WC_CLI_Exception( 'woocommerce_cli_invalid_product_id', __( 'Product ID provided does not match this line item', 'woocommerce' ) ); |
||
924 | } |
||
925 | } |
||
926 | |||
927 | if ( isset( $item['product_id'] ) ) { |
||
928 | $product_id = $item['product_id']; |
||
929 | } elseif ( isset( $item['sku'] ) ) { |
||
930 | $product_id = wc_get_product_id_by_sku( $item['sku'] ); |
||
931 | } |
||
932 | |||
933 | // variations must each have a key & value |
||
934 | $variation_id = 0; |
||
935 | if ( isset( $item['variations'] ) && is_array( $item['variations'] ) ) { |
||
936 | foreach ( $item['variations'] as $key => $value ) { |
||
937 | if ( ! $key || ! $value ) { |
||
938 | throw new WC_CLI_Exception( 'woocommerce_cli_invalid_product_variation', __( 'The product variation is invalid', 'woocommerce' ) ); |
||
939 | } |
||
940 | } |
||
941 | $item_args['variation'] = $item['variations']; |
||
942 | $variation_id = $this->get_variation_id( wc_get_product( $product_id ), $item_args['variation'] ); |
||
943 | } |
||
944 | |||
945 | $product = wc_get_product( $variation_id ? $variation_id : $product_id ); |
||
946 | |||
947 | // must be a valid WC_Product |
||
948 | if ( ! is_object( $product ) ) { |
||
949 | throw new WC_CLI_Exception( 'woocommerce_cli_invalid_product', __( 'Product is invalid', 'woocommerce' ) ); |
||
950 | } |
||
951 | |||
952 | // quantity must be positive float |
||
953 | View Code Duplication | if ( isset( $item['quantity'] ) && floatval( $item['quantity'] ) <= 0 ) { |
|
954 | throw new WC_CLI_Exception( 'woocommerce_cli_invalid_product_quantity', __( 'Product quantity must be a positive float', 'woocommerce' ) ); |
||
955 | } |
||
956 | |||
957 | // quantity is required when creating |
||
958 | if ( $creating && ! isset( $item['quantity'] ) ) { |
||
959 | throw new WC_CLI_Exception( 'woocommerce_cli_invalid_product_quantity', __( 'Product quantity is required', 'woocommerce' ) ); |
||
960 | } |
||
961 | |||
962 | $item_args = array(); |
||
963 | |||
964 | // quantity |
||
965 | if ( isset( $item['quantity'] ) ) { |
||
966 | $item_args['qty'] = $item['quantity']; |
||
967 | } |
||
968 | |||
969 | // total |
||
970 | View Code Duplication | if ( isset( $item['total'] ) ) { |
|
971 | $item_args['totals']['total'] = floatval( $item['total'] ); |
||
972 | } |
||
973 | |||
974 | // total tax |
||
975 | View Code Duplication | if ( isset( $item['total_tax'] ) ) { |
|
976 | $item_args['totals']['tax'] = floatval( $item['total_tax'] ); |
||
977 | } |
||
978 | |||
979 | // subtotal |
||
980 | View Code Duplication | if ( isset( $item['subtotal'] ) ) { |
|
981 | $item_args['totals']['subtotal'] = floatval( $item['subtotal'] ); |
||
982 | } |
||
983 | |||
984 | // subtotal tax |
||
985 | View Code Duplication | if ( isset( $item['subtotal_tax'] ) ) { |
|
986 | $item_args['totals']['subtotal_tax'] = floatval( $item['subtotal_tax'] ); |
||
987 | } |
||
988 | |||
989 | $item_args = apply_filters( 'woocommerce_cli_order_line_item_args', $item_args, $item, $order, $action ); |
||
990 | |||
991 | View Code Duplication | if ( $creating ) { |
|
992 | |||
993 | $item_id = $order->add_product( $product, $item_args['qty'], $item_args ); |
||
994 | |||
995 | if ( ! $item_id ) { |
||
996 | throw new WC_CLI_Exception( 'woocommerce_cannot_create_line_item', __( 'Cannot create line item, try again', 'woocommerce' ) ); |
||
997 | } |
||
998 | |||
999 | } else { |
||
1000 | |||
1001 | $item_id = $order->update_product( $item['id'], $product, $item_args ); |
||
1002 | |||
1003 | if ( ! $item_id ) { |
||
1004 | throw new WC_CLI_Exception( 'woocommerce_cannot_update_line_item', __( 'Cannot update line item, try again', 'woocommerce' ) ); |
||
1005 | } |
||
1006 | } |
||
1007 | } |
||
1008 | |||
1009 | /** |
||
1010 | * Given a product ID & variations, find the correct variation ID to use for |
||
1011 | * calculation. We can't just trust input from the CLI to pass a variation_id |
||
1012 | * manually, otherwise you could pass the cheapest variation ID but provide |
||
1013 | * other information so we have to look up the variation ID. |
||
1014 | * |
||
1015 | * @since 2.5.0 |
||
1016 | * @param WC_Product $product Product instance |
||
1017 | * @return int Returns an ID if a valid variation was found for this product |
||
1018 | */ |
||
1019 | protected function get_variation_id( $product, $variations = array() ) { |
||
1049 | |||
1050 | /** |
||
1051 | * Utility function to see if the meta array contains data from variations. |
||
1052 | * |
||
1053 | * @since 2.5.0 |
||
1054 | * @return bool Returns true if meta array contains data from variations |
||
1055 | */ |
||
1056 | protected function array_contains( $needles, $haystack ) { |
||
1064 | |||
1065 | /** |
||
1066 | * Create or update an order shipping method |
||
1067 | * |
||
1068 | * @since 2.5.0 |
||
1069 | * @param \WC_Order $order |
||
1070 | * @param array $shipping item data |
||
1071 | * @param string $action 'create' to add shipping or 'update' to update it |
||
1072 | * @throws WC_CLI_Exception invalid data, server error |
||
1073 | */ |
||
1074 | protected function set_shipping( $order, $shipping, $action ) { |
||
1075 | |||
1076 | // total must be a positive float |
||
1077 | if ( isset( $shipping['total'] ) && floatval( $shipping['total'] ) < 0 ) { |
||
1078 | throw new WC_CLI_Exception( 'woocommerce_invalid_shipping_total', __( 'Shipping total must be a positive amount', 'woocommerce' ) ); |
||
1079 | } |
||
1080 | |||
1081 | if ( 'create' === $action ) { |
||
1082 | |||
1083 | // method ID is required |
||
1084 | if ( ! isset( $shipping['method_id'] ) ) { |
||
1085 | throw new WC_CLI_Exception( 'woocommerce_invalid_shipping_item', __( 'Shipping method ID is required', 'woocommerce' ) ); |
||
1086 | } |
||
1087 | |||
1088 | $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'] ); |
||
1089 | |||
1090 | $shipping_id = $order->add_shipping( $rate ); |
||
1091 | |||
1092 | if ( ! $shipping_id ) { |
||
1093 | throw new WC_CLI_Exception( 'woocommerce_cannot_create_shipping', __( 'Cannot create shipping method, try again', 'woocommerce' ) ); |
||
1094 | } |
||
1095 | |||
1096 | View Code Duplication | } else { |
|
1097 | |||
1098 | $shipping_args = array(); |
||
1099 | |||
1100 | if ( isset( $shipping['method_id'] ) ) { |
||
1101 | $shipping_args['method_id'] = $shipping['method_id']; |
||
1102 | } |
||
1103 | |||
1104 | if ( isset( $shipping['method_title'] ) ) { |
||
1105 | $shipping_args['method_title'] = $shipping['method_title']; |
||
1106 | } |
||
1107 | |||
1108 | if ( isset( $shipping['total'] ) ) { |
||
1109 | $shipping_args['cost'] = floatval( $shipping['total'] ); |
||
1110 | } |
||
1111 | |||
1112 | $shipping_id = $order->update_shipping( $shipping['id'], $shipping_args ); |
||
1113 | |||
1114 | if ( ! $shipping_id ) { |
||
1115 | throw new WC_CLI_Exception( 'woocommerce_cannot_update_shipping', __( 'Cannot update shipping method, try again', 'woocommerce' ) ); |
||
1116 | } |
||
1117 | } |
||
1118 | } |
||
1119 | |||
1120 | /** |
||
1121 | * Create or update an order fee. |
||
1122 | * |
||
1123 | * @since 2.5.0 |
||
1124 | * @param \WC_Order $order |
||
1125 | * @param array $fee item data |
||
1126 | * @param string $action 'create' to add fee or 'update' to update it |
||
1127 | * @throws WC_CLI_Exception invalid data, server error |
||
1128 | */ |
||
1129 | protected function set_fee( $order, $fee, $action ) { |
||
1200 | |||
1201 | /** |
||
1202 | * Create or update an order coupon |
||
1203 | * |
||
1204 | * @since 2.5.0 |
||
1205 | * @param \WC_Order $order |
||
1206 | * @param array $coupon item data |
||
1207 | * @param string $action 'create' to add coupon or 'update' to update it |
||
1208 | * @throws WC_CLI_Exception invalid data, server error |
||
1209 | */ |
||
1210 | protected function set_coupon( $order, $coupon, $action ) { |
||
1249 | } |
||
1250 |
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.