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_REST_Orders_Controller 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_REST_Orders_Controller, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
23 | class WC_REST_Orders_Controller extends WC_REST_Posts_Controller { |
||
24 | |||
25 | /** |
||
26 | * Endpoint namespace. |
||
27 | * |
||
28 | * @var string |
||
29 | */ |
||
30 | protected $namespace = 'wc/v1'; |
||
31 | |||
32 | /** |
||
33 | * Route base. |
||
34 | * |
||
35 | * @var string |
||
36 | */ |
||
37 | protected $rest_base = 'orders'; |
||
38 | |||
39 | /** |
||
40 | * Post type. |
||
41 | * |
||
42 | * @var string |
||
43 | */ |
||
44 | protected $post_type = 'shop_order'; |
||
45 | |||
46 | /** |
||
47 | * Initialize orders actions. |
||
48 | */ |
||
49 | public function __construct() { |
||
52 | |||
53 | /** |
||
54 | * Register the routes for orders. |
||
55 | */ |
||
56 | View Code Duplication | public function register_routes() { |
|
113 | |||
114 | /** |
||
115 | * Prepare a single order output for response. |
||
116 | * |
||
117 | * @param WP_Post $post Post object. |
||
118 | * @param WP_REST_Request $request Request object. |
||
119 | * @return WP_REST_Response $data |
||
120 | */ |
||
121 | public function prepare_item_for_response( $post, $request ) { |
||
122 | global $wpdb; |
||
123 | |||
124 | $order = wc_get_order( $post ); |
||
125 | $dp = $request['dp']; |
||
126 | |||
127 | $data = array( |
||
128 | 'id' => $order->id, |
||
129 | 'parent_id' => $post->post_parent, |
||
130 | 'status' => $order->get_status(), |
||
131 | 'order_key' => $order->order_key, |
||
132 | 'currency' => $order->get_order_currency(), |
||
133 | 'version' => $order->order_version, |
||
134 | 'prices_include_tax' => $order->prices_include_tax, |
||
135 | 'date_created' => wc_rest_prepare_date_response( $post->post_date_gmt ), |
||
136 | 'date_modified' => wc_rest_prepare_date_response( $post->post_modified_gmt ), |
||
137 | 'customer_id' => $order->get_user_id(), |
||
138 | 'discount_total' => wc_format_decimal( $order->get_total_discount(), $dp ), |
||
139 | 'discount_tax' => wc_format_decimal( $order->cart_discount_tax, $dp ), |
||
140 | 'shipping_total' => wc_format_decimal( $order->get_total_shipping(), $dp ), |
||
141 | 'shipping_tax' => wc_format_decimal( $order->get_shipping_tax(), $dp ), |
||
142 | 'cart_tax' => wc_format_decimal( $order->get_cart_tax(), $dp ), |
||
143 | 'total' => wc_format_decimal( $order->get_total(), $dp ), |
||
144 | 'total_tax' => wc_format_decimal( $order->get_total_tax(), $dp ), |
||
145 | 'billing' => array(), |
||
146 | 'shipping' => array(), |
||
147 | 'payment_method' => $order->payment_method, |
||
148 | 'payment_method_title' => $order->payment_method_title, |
||
149 | 'transaction_id' => $order->get_transaction_id(), |
||
150 | 'customer_ip_address' => $order->customer_ip_address, |
||
151 | 'customer_user_agent' => $order->customer_user_agent, |
||
152 | 'created_via' => $order->created_via, |
||
153 | 'customer_note' => $order->customer_note, |
||
154 | 'date_completed' => wc_rest_prepare_date_response( $order->completed_date ), |
||
155 | 'date_paid' => $order->paid_date, |
||
156 | 'cart_hash' => $order->cart_hash, |
||
157 | 'line_items' => array(), |
||
158 | 'tax_lines' => array(), |
||
159 | 'shipping_lines' => array(), |
||
160 | 'fee_lines' => array(), |
||
161 | 'coupon_lines' => array(), |
||
162 | 'refunds' => array(), |
||
163 | ); |
||
164 | |||
165 | // Add addresses. |
||
166 | $data['billing'] = $order->get_address( 'billing' ); |
||
167 | $data['shipping'] = $order->get_address( 'shipping' ); |
||
168 | |||
169 | // Add line items. |
||
170 | View Code Duplication | foreach ( $order->get_items() as $item_id => $item ) { |
|
171 | $product = $order->get_product_from_item( $item ); |
||
172 | $product_id = 0; |
||
173 | $variation_id = 0; |
||
174 | $product_sku = null; |
||
175 | |||
176 | // Check if the product exists. |
||
177 | if ( is_object( $product ) ) { |
||
178 | $product_id = $product->id; |
||
179 | $variation_id = $product->variation_id; |
||
180 | $product_sku = $product->get_sku(); |
||
181 | } |
||
182 | |||
183 | $meta = new WC_Order_Item_Meta( $item, $product ); |
||
184 | |||
185 | $item_meta = array(); |
||
186 | |||
187 | $hideprefix = 'true' === $request['all_item_meta'] ? null : '_'; |
||
188 | |||
189 | foreach ( $meta->get_formatted( $hideprefix ) as $meta_key => $formatted_meta ) { |
||
190 | $item_meta[] = array( |
||
191 | 'key' => $formatted_meta['key'], |
||
192 | 'label' => $formatted_meta['label'], |
||
193 | 'value' => $formatted_meta['value'], |
||
194 | ); |
||
195 | } |
||
196 | |||
197 | $line_item = array( |
||
198 | 'id' => $item_id, |
||
199 | 'name' => $item['name'], |
||
200 | 'sku' => $product_sku, |
||
201 | 'product_id' => (int) $product_id, |
||
202 | 'variation_id' => (int) $variation_id, |
||
203 | 'quantity' => wc_stock_amount( $item['qty'] ), |
||
204 | 'tax_class' => ! empty( $item['tax_class'] ) ? $item['tax_class'] : '', |
||
205 | 'price' => wc_format_decimal( $order->get_item_total( $item, false, false ), $dp ), |
||
206 | 'subtotal' => wc_format_decimal( $order->get_line_subtotal( $item, false, false ), $dp ), |
||
207 | 'subtotal_tax' => wc_format_decimal( $item['line_subtotal_tax'], $dp ), |
||
208 | 'total' => wc_format_decimal( $order->get_line_total( $item, false, false ), $dp ), |
||
209 | 'total_tax' => wc_format_decimal( $item['line_tax'], $dp ), |
||
210 | 'taxes' => array(), |
||
211 | 'meta' => $item_meta, |
||
212 | ); |
||
213 | |||
214 | $item_line_taxes = maybe_unserialize( $item['line_tax_data'] ); |
||
215 | if ( isset( $item_line_taxes['total'] ) ) { |
||
216 | $line_tax = array(); |
||
217 | |||
218 | foreach ( $item_line_taxes['total'] as $tax_rate_id => $tax ) { |
||
219 | $line_tax[ $tax_rate_id ] = array( |
||
220 | 'id' => $tax_rate_id, |
||
221 | 'total' => $tax, |
||
222 | 'subtotal' => '', |
||
223 | ); |
||
224 | } |
||
225 | |||
226 | foreach ( $item_line_taxes['subtotal'] as $tax_rate_id => $tax ) { |
||
227 | $line_tax[ $tax_rate_id ]['subtotal'] = $tax; |
||
228 | } |
||
229 | |||
230 | $line_item['taxes'] = array_values( $line_tax ); |
||
231 | } |
||
232 | |||
233 | $data['line_items'][] = $line_item; |
||
234 | } |
||
235 | |||
236 | // Add taxes. |
||
237 | foreach ( $order->get_items( 'tax' ) as $key => $tax ) { |
||
238 | $tax_line = array( |
||
239 | 'id' => $key, |
||
240 | 'rate_code' => $tax['name'], |
||
241 | 'rate_id' => $tax['rate_id'], |
||
242 | 'label' => isset( $tax['label'] ) ? $tax['label'] : $tax['name'], |
||
243 | 'compound' => (bool) $tax['compound'], |
||
244 | 'tax_total' => wc_format_decimal( $tax['tax_amount'], $dp ), |
||
245 | 'shipping_tax_total' => wc_format_decimal( $tax['shipping_tax_amount'], $dp ), |
||
246 | ); |
||
247 | |||
248 | $data['tax_lines'][] = $tax_line; |
||
249 | } |
||
250 | |||
251 | // Add shipping. |
||
252 | foreach ( $order->get_shipping_methods() as $shipping_item_id => $shipping_item ) { |
||
253 | $shipping_line = array( |
||
254 | 'id' => $shipping_item_id, |
||
255 | 'method_title' => $shipping_item['name'], |
||
256 | 'method_id' => $shipping_item['method_id'], |
||
257 | 'total' => wc_format_decimal( $shipping_item['cost'], $dp ), |
||
258 | 'total_tax' => wc_format_decimal( '', $dp ), |
||
259 | 'taxes' => array(), |
||
260 | ); |
||
261 | |||
262 | $shipping_taxes = maybe_unserialize( $shipping_item['taxes'] ); |
||
263 | |||
264 | if ( ! empty( $shipping_taxes ) ) { |
||
265 | $shipping_line['total_tax'] = wc_format_decimal( array_sum( $shipping_taxes ), $dp ); |
||
266 | |||
267 | foreach ( $shipping_taxes as $tax_rate_id => $tax ) { |
||
268 | $shipping_line['taxes'][] = array( |
||
269 | 'id' => $tax_rate_id, |
||
270 | 'total' => $tax, |
||
271 | ); |
||
272 | } |
||
273 | } |
||
274 | |||
275 | $data['shipping_lines'][] = $shipping_line; |
||
276 | } |
||
277 | |||
278 | // Add fees. |
||
279 | foreach ( $order->get_fees() as $fee_item_id => $fee_item ) { |
||
280 | $fee_line = array( |
||
281 | 'id' => $fee_item_id, |
||
282 | 'name' => $fee_item['name'], |
||
283 | 'tax_class' => ! empty( $fee_item['tax_class'] ) ? $fee_item['tax_class'] : '', |
||
284 | 'tax_status' => 'taxable', |
||
285 | 'total' => wc_format_decimal( $order->get_line_total( $fee_item ), $dp ), |
||
286 | 'total_tax' => wc_format_decimal( $order->get_line_tax( $fee_item ), $dp ), |
||
287 | 'taxes' => array(), |
||
288 | ); |
||
289 | |||
290 | $fee_line_taxes = maybe_unserialize( $fee_item['line_tax_data'] ); |
||
291 | if ( isset( $fee_line_taxes['total'] ) ) { |
||
292 | $fee_tax = array(); |
||
293 | |||
294 | foreach ( $fee_line_taxes['total'] as $tax_rate_id => $tax ) { |
||
295 | $fee_tax[ $tax_rate_id ] = array( |
||
296 | 'id' => $tax_rate_id, |
||
297 | 'total' => $tax, |
||
298 | 'subtotal' => '', |
||
299 | ); |
||
300 | } |
||
301 | |||
302 | foreach ( $fee_line_taxes['subtotal'] as $tax_rate_id => $tax ) { |
||
303 | $fee_tax[ $tax_rate_id ]['subtotal'] = $tax; |
||
304 | } |
||
305 | |||
306 | $fee_line['taxes'] = array_values( $fee_tax ); |
||
307 | } |
||
308 | |||
309 | $data['fee_lines'][] = $fee_line; |
||
310 | } |
||
311 | |||
312 | // Add coupons. |
||
313 | foreach ( $order->get_items( 'coupon' ) as $coupon_item_id => $coupon_item ) { |
||
314 | $coupon_line = array( |
||
315 | 'id' => $coupon_item_id, |
||
316 | 'code' => $coupon_item['name'], |
||
317 | 'discount' => wc_format_decimal( $coupon_item['discount_amount'], $dp ), |
||
318 | 'discount_tax' => wc_format_decimal( $coupon_item['discount_amount_tax'], $dp ), |
||
319 | ); |
||
320 | |||
321 | $data['coupon_lines'][] = $coupon_line; |
||
322 | } |
||
323 | |||
324 | // Add refunds. |
||
325 | foreach ( $order->get_refunds() as $refund ) { |
||
326 | $data['refunds'][] = array( |
||
327 | 'id' => $refund->id, |
||
328 | 'refund' => $refund->get_refund_reason() ? $refund->get_refund_reason() : '', |
||
329 | 'total' => '-' . wc_format_decimal( $refund->get_refund_amount(), $dp ), |
||
330 | ); |
||
331 | } |
||
332 | |||
333 | $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; |
||
334 | $data = $this->add_additional_fields_to_object( $data, $request ); |
||
335 | $data = $this->filter_response_by_context( $data, $context ); |
||
336 | |||
337 | // Wrap the data in a response object. |
||
338 | $response = rest_ensure_response( $data ); |
||
339 | |||
340 | $response->add_links( $this->prepare_links( $order ) ); |
||
341 | |||
342 | /** |
||
343 | * Filter the data for a response. |
||
344 | * |
||
345 | * The dynamic portion of the hook name, $this->post_type, refers to post_type of the post being |
||
346 | * prepared for the response. |
||
347 | * |
||
348 | * @param WP_REST_Response $response The response object. |
||
349 | * @param WP_Post $post Post object. |
||
350 | * @param WP_REST_Request $request Request object. |
||
351 | */ |
||
352 | return apply_filters( "woocommerce_rest_prepare_{$this->post_type}", $response, $post, $request ); |
||
353 | } |
||
354 | |||
355 | /** |
||
356 | * Prepare links for the request. |
||
357 | * |
||
358 | * @param WC_Order $order Order object. |
||
359 | * @return array Links for the given order. |
||
360 | */ |
||
361 | protected function prepare_links( $order ) { |
||
385 | |||
386 | /** |
||
387 | * Query args. |
||
388 | * |
||
389 | * @param array $args |
||
390 | * @param WP_REST_Request $request |
||
391 | * @return array |
||
392 | */ |
||
393 | public function query_args( $args, $request ) { |
||
431 | |||
432 | /** |
||
433 | * Create order. |
||
434 | * |
||
435 | * @param WP_REST_Request $request Full details about the request. |
||
436 | * @return int|WP_Error |
||
437 | */ |
||
438 | protected function create_order( $request ) { |
||
514 | |||
515 | /** |
||
516 | * Update address. |
||
517 | * |
||
518 | * @param WC_Order $order |
||
519 | * @param array $posted |
||
520 | * @param string $type |
||
521 | */ |
||
522 | protected function update_address( $order, $posted, $type = 'billing' ) { |
||
541 | |||
542 | /** |
||
543 | * Create or update a line item. |
||
544 | * |
||
545 | * @param WC_Order $order Order data. |
||
546 | * @param array $item Line item data. |
||
547 | * @param string $action 'create' to add line item or 'update' to update it. |
||
548 | * @throws WC_REST_Exception Invalid data, server error. |
||
549 | */ |
||
550 | protected function set_line_item( $order, $item, $action = 'create' ) { |
||
551 | $creating = 'create' === $action; |
||
552 | $item_args = array(); |
||
553 | |||
554 | // Product is always required. |
||
555 | if ( empty( $item['product_id'] ) && empty( $item['sku'] ) && empty( $item['variation_id'] ) ) { |
||
556 | throw new WC_REST_Exception( 'woocommerce_rest_required_product_reference', __( 'Product ID or SKU is required.', 'woocommerce' ), 400 ); |
||
557 | } |
||
558 | |||
559 | if ( ! empty( $item['sku'] ) ) { |
||
560 | $product_id = (int) wc_get_product_id_by_sku( $item['sku'] ); |
||
561 | } elseif ( ! empty( $item['product_id'] ) && empty( $item['variation_id'] ) ) { |
||
562 | $product_id = (int) $item['product_id']; |
||
563 | } elseif ( ! empty( $item['variation_id'] ) ) { |
||
564 | $product_id = (int) $item['variation_id']; |
||
565 | } |
||
566 | |||
567 | // When updating, ensure product ID provided matches. |
||
568 | if ( 'update' === $action && ! empty( $item['id'] ) ) { |
||
569 | $item_product_id = (int) wc_get_order_item_meta( $item['id'], '_product_id' ); |
||
570 | $item_variation_id = (int) wc_get_order_item_meta( $item['id'], '_variation_id' ); |
||
571 | |||
572 | if ( $product_id !== $item_product_id && $product_id !== $item_variation_id ) { |
||
573 | throw new WC_REST_Exception( 'woocommerce_rest_required_product_reference', __( 'Product ID or variation ID provided does not match this line item.', 'woocommerce' ), 400 ); |
||
574 | } |
||
575 | } |
||
576 | |||
577 | $product = wc_get_product( $product_id ); |
||
578 | |||
579 | // Must be a valid WC_Product. |
||
580 | if ( ! is_object( $product ) ) { |
||
581 | throw new WC_REST_Exception( 'woocommerce_rest_invalid_product', __( 'Product is invalid.', 'woocommerce' ), 400 ); |
||
582 | } |
||
583 | |||
584 | // Quantity must be positive float. |
||
585 | View Code Duplication | if ( isset( $item['quantity'] ) && 0 >= floatval( $item['quantity'] ) ) { |
|
586 | throw new WC_REST_Exception( 'woocommerce_rest_invalid_product_quantity', __( 'Product quantity must be a positive float.', 'woocommerce' ), 400 ); |
||
587 | } |
||
588 | |||
589 | // Quantity is required when creating. |
||
590 | View Code Duplication | if ( $creating && ! isset( $item['quantity'] ) ) { |
|
591 | throw new WC_REST_Exception( 'woocommerce_rest_invalid_product_quantity', __( 'Product quantity is required.', 'woocommerce' ), 400 ); |
||
592 | } |
||
593 | |||
594 | // Get variation attributes. |
||
595 | if ( method_exists( $product, 'get_variation_attributes' ) ) { |
||
596 | $item_args['variation'] = $product->get_variation_attributes(); |
||
597 | } |
||
598 | |||
599 | // Quantity. |
||
600 | if ( isset( $item['quantity'] ) ) { |
||
601 | $item_args['qty'] = $item['quantity']; |
||
602 | } |
||
603 | |||
604 | // Total. |
||
605 | if ( isset( $item['total'] ) ) { |
||
606 | $item_args['totals']['total'] = floatval( $item['total'] ); |
||
607 | } |
||
608 | |||
609 | // Total tax. |
||
610 | if ( isset( $item['total_tax'] ) ) { |
||
611 | $item_args['totals']['tax'] = floatval( $item['total_tax'] ); |
||
612 | } |
||
613 | |||
614 | // Subtotal. |
||
615 | if ( isset( $item['subtotal'] ) ) { |
||
616 | $item_args['totals']['subtotal'] = floatval( $item['subtotal'] ); |
||
617 | } |
||
618 | |||
619 | // Subtotal tax. |
||
620 | if ( isset( $item['subtotal_tax'] ) ) { |
||
621 | $item_args['totals']['subtotal_tax'] = floatval( $item['subtotal_tax'] ); |
||
622 | } |
||
623 | |||
624 | View Code Duplication | if ( $creating ) { |
|
625 | $item_id = $order->add_product( $product, $item_args['qty'], $item_args ); |
||
626 | if ( ! $item_id ) { |
||
627 | throw new WC_REST_Exception( 'woocommerce_rest_cannot_create_line_item', __( 'Cannot create line item, try again.', 'woocommerce' ), 500 ); |
||
628 | } |
||
629 | } else { |
||
630 | $item_id = $order->update_product( $item['id'], $product, $item_args ); |
||
631 | if ( ! $item_id ) { |
||
632 | throw new WC_REST_Exception( 'woocommerce_rest_cannot_update_line_item', __( 'Cannot update line item, try again.', 'woocommerce' ), 500 ); |
||
633 | } |
||
634 | } |
||
635 | } |
||
636 | |||
637 | /** |
||
638 | * Create or update an order shipping method. |
||
639 | * |
||
640 | * @param WC_Order $order Order data. |
||
641 | * @param array $shipping Item data. |
||
642 | * @param string $action 'create' to add shipping or 'update' to update it. |
||
643 | * @throws WC_REST_Exception Invalid data, server error. |
||
644 | */ |
||
645 | protected function set_shipping( $order, $shipping, $action ) { |
||
646 | // Total must be a positive float. |
||
647 | if ( ! empty( $shipping['total'] ) && 0 > floatval( $shipping['total'] ) ) { |
||
648 | throw new WC_REST_Exception( 'woocommerce_rest_invalid_shipping_total', __( 'Shipping total must be a positive amount.', 'woocommerce' ), 400 ); |
||
649 | } |
||
650 | |||
651 | if ( 'create' === $action ) { |
||
652 | // Method ID is required. |
||
653 | if ( empty( $shipping['method_id'] ) ) { |
||
654 | throw new WC_REST_Exception( 'woocommerce_rest_invalid_shipping_item', __( 'Shipping method ID is required.', 'woocommerce' ), 400 ); |
||
655 | } |
||
656 | |||
657 | $rate = new WC_Shipping_Rate( $shipping['method_id'], isset( $shipping['method_title'] ) ? $shipping['method_title'] : '', isset( $shipping['total'] ) ? floatval( $shipping['total'] ) : 0, array(), $shipping['method_id'] ); |
||
658 | |||
659 | $shipping_id = $order->add_shipping( $rate ); |
||
660 | |||
661 | if ( ! $shipping_id ) { |
||
662 | throw new WC_REST_Exception( 'woocommerce_rest_cannot_create_shipping', __( 'Cannot create shipping method, try again.', 'woocommerce' ), 500 ); |
||
663 | } |
||
664 | |||
665 | View Code Duplication | } else { |
|
666 | $shipping_args = array(); |
||
667 | |||
668 | if ( isset( $shipping['method_id'] ) ) { |
||
669 | $shipping_args['method_id'] = $shipping['method_id']; |
||
670 | } |
||
671 | |||
672 | if ( isset( $shipping['method_title'] ) ) { |
||
673 | $shipping_args['method_title'] = $shipping['method_title']; |
||
674 | } |
||
675 | |||
676 | if ( isset( $shipping['total'] ) ) { |
||
677 | $shipping_args['cost'] = floatval( $shipping['total'] ); |
||
678 | } |
||
679 | |||
680 | $shipping_id = $order->update_shipping( $shipping['id'], $shipping_args ); |
||
681 | |||
682 | if ( ! $shipping_id ) { |
||
683 | throw new WC_REST_Exception( 'woocommerce_rest_cannot_update_shipping', __( 'Cannot update shipping method, try again.', 'woocommerce' ), 500 ); |
||
684 | } |
||
685 | } |
||
686 | } |
||
687 | |||
688 | /** |
||
689 | * Create or update an order fee. |
||
690 | * |
||
691 | * @param WC_Order $order Order data. |
||
692 | * @param array $fee Item data. |
||
693 | * @param string $action 'create' to add fee or 'update' to update it. |
||
694 | * @throws WC_REST_Exception Invalid data, server error. |
||
695 | */ |
||
696 | protected function set_fee( $order, $fee, $action ) { |
||
760 | |||
761 | /** |
||
762 | * Create or update an order coupon. |
||
763 | * |
||
764 | * @param WC_Order $order Order data. |
||
765 | * @param array $coupon Item data. |
||
766 | * @param string $action 'create' to add coupon or 'update' to update it. |
||
767 | * @throws WC_REST_Exception Invalid data, server error. |
||
768 | */ |
||
769 | protected function set_coupon( $order, $coupon, $action ) { |
||
770 | // Coupon discount must be positive float. |
||
771 | View Code Duplication | if ( isset( $coupon['discount'] ) && 0 > floatval( $coupon['discount'] ) ) { |
|
772 | throw new WC_REST_Exception( 'woocommerce_rest_invalid_coupon_total', __( 'Coupon discount must be a positive amount.', 'woocommerce' ), 400 ); |
||
773 | } |
||
774 | |||
775 | View Code Duplication | if ( 'create' === $action ) { |
|
776 | // Coupon code is required. |
||
777 | if ( empty( $coupon['code'] ) ) { |
||
778 | throw new WC_REST_Exception( 'woocommerce_rest_invalid_coupon_coupon', __( 'Coupon code is required.', 'woocommerce' ), 400 ); |
||
779 | } |
||
780 | |||
781 | $coupon_id = $order->add_coupon( $coupon['code'], floatval( $coupon['discount'] ) ); |
||
782 | |||
783 | if ( ! $coupon_id ) { |
||
784 | throw new WC_REST_Exception( 'woocommerce_rest_cannot_create_order_coupon', __( 'Cannot create coupon, try again.', 'woocommerce' ), 500 ); |
||
785 | } |
||
786 | |||
787 | } else { |
||
788 | $coupon_args = array(); |
||
789 | |||
790 | if ( isset( $coupon['code'] ) ) { |
||
791 | $coupon_args['code'] = $coupon['code']; |
||
792 | } |
||
793 | |||
794 | if ( isset( $coupon['discount'] ) ) { |
||
795 | $coupon_args['discount_amount'] = floatval( $coupon['discount'] ); |
||
796 | } |
||
797 | |||
798 | $coupon_id = $order->update_coupon( $coupon['id'], $coupon_args ); |
||
799 | |||
800 | if ( ! $coupon_id ) { |
||
801 | throw new WC_REST_Exception( 'woocommerce_rest_cannot_update_order_coupon', __( 'Cannot update coupon, try again.', 'woocommerce' ), 500 ); |
||
802 | } |
||
803 | } |
||
804 | } |
||
805 | |||
806 | /** |
||
807 | * Helper method to add/update meta data, with two restrictions: |
||
808 | * |
||
809 | * 1) Only non-protected meta (no leading underscore) can be set |
||
810 | * 2) Meta values must be scalar (int, string, bool) |
||
811 | * |
||
812 | * @param WC_Order $order Order data. |
||
813 | * @param array $meta_data Meta data in array( 'meta_key' => 'meta_value' ) format. |
||
814 | */ |
||
815 | View Code Duplication | protected function update_meta_data( $order_id, $meta_data ) { |
|
822 | |||
823 | /** |
||
824 | * Create a single item. |
||
825 | * |
||
826 | * @param WP_REST_Request $request Full details about the request. |
||
827 | * @return WP_Error|WP_REST_Response |
||
828 | */ |
||
829 | public function create_item( $request ) { |
||
862 | |||
863 | /** |
||
864 | * Wrapper method to create/update order items. |
||
865 | * When updating, the item ID provided is checked to ensure it is associated |
||
866 | * with the order. |
||
867 | * |
||
868 | * @param WC_Order $order order |
||
869 | * @param string $item_type |
||
870 | * @param array $item item provided in the request body |
||
871 | * @param string $action either 'create' or 'update' |
||
872 | * @throws WC_REST_Exception If item ID is not associated with order |
||
873 | */ |
||
874 | View Code Duplication | protected function set_item( $order, $item_type, $item, $action ) { |
|
894 | |||
895 | /** |
||
896 | * Helper method to check if the resource ID associated with the provided item is null. |
||
897 | * Items can be deleted by setting the resource ID to null. |
||
898 | * |
||
899 | * @param array $item Item provided in the request body. |
||
900 | * @return bool True if the item resource ID is null, false otherwise. |
||
901 | */ |
||
902 | protected function item_is_null( $item ) { |
||
913 | |||
914 | /** |
||
915 | * Update order. |
||
916 | * |
||
917 | * @param WP_REST_Request $request Full details about the request. |
||
918 | * @param WP_Post $post Post data. |
||
919 | * @return int|WP_Error |
||
920 | */ |
||
921 | protected function update_order( $request, $post ) { |
||
922 | try { |
||
923 | $update_totals = false; |
||
924 | $order = wc_get_order( $post ); |
||
925 | $order_args = array( 'order_id' => $order->id ); |
||
926 | |||
927 | // Customer note. |
||
928 | if ( isset( $request['customer_note'] ) ) { |
||
929 | $order_args['customer_note'] = $request['customer_note']; |
||
930 | } |
||
931 | |||
932 | // Customer ID. |
||
933 | View Code Duplication | if ( isset( $request['customer_id'] ) && $request['customer_id'] != $order->get_user_id() ) { |
|
934 | // Make sure customer exists. |
||
935 | if ( false === get_user_by( 'id', $request['customer_id'] ) ) { |
||
936 | throw new WC_REST_Exception( 'woocommerce_rest_invalid_customer_id', __( 'Customer ID is invalid.', 'woocommerce' ), 400 ); |
||
937 | } |
||
938 | |||
939 | update_post_meta( $order->id, '_customer_user', $request['customer_id'] ); |
||
940 | } |
||
941 | |||
942 | // Update addresses. |
||
943 | if ( is_array( $request['billing'] ) ) { |
||
944 | $this->update_address( $order, $request['billing'], 'billing' ); |
||
945 | } |
||
946 | if ( is_array( $request['shipping'] ) ) { |
||
947 | $this->update_address( $order, $request['shipping'], 'shipping' ); |
||
948 | } |
||
949 | |||
950 | $lines = array( |
||
951 | 'line_item' => 'line_items', |
||
952 | 'shipping' => 'shipping_lines', |
||
953 | 'fee' => 'fee_lines', |
||
954 | 'coupon' => 'coupon_lines', |
||
955 | ); |
||
956 | |||
957 | View Code Duplication | foreach ( $lines as $line_type => $line ) { |
|
958 | if ( isset( $request[ $line ] ) && is_array( $request[ $line ] ) ) { |
||
959 | $update_totals = true; |
||
960 | foreach ( $request[ $line ] as $item ) { |
||
961 | // Item ID is always required. |
||
962 | if ( ! array_key_exists( 'id', $item ) ) { |
||
963 | throw new WC_REST_Exception( 'woocommerce_rest_invalid_item_id', __( 'Order item ID is required.', 'woocommerce' ), 400 ); |
||
964 | } |
||
965 | |||
966 | // Create item. |
||
967 | if ( is_null( $item['id'] ) ) { |
||
968 | $this->set_item( $order, $line_type, $item, 'create' ); |
||
969 | } elseif ( $this->item_is_null( $item ) ) { |
||
970 | // Delete item. |
||
971 | wc_delete_order_item( $item['id'] ); |
||
972 | } else { |
||
973 | // Update item. |
||
974 | $this->set_item( $order, $line_type, $item, 'update' ); |
||
975 | } |
||
976 | } |
||
977 | } |
||
978 | } |
||
979 | |||
980 | // Set payment method. |
||
981 | if ( ! empty( $request['payment_method'] ) ) { |
||
982 | update_post_meta( $order->id, '_payment_method', $request['payment_method'] ); |
||
983 | } |
||
984 | if ( ! empty( $request['payment_method_title'] ) ) { |
||
985 | update_post_meta( $order->id, '_payment_method_title', $request['payment_method'] ); |
||
986 | } |
||
987 | if ( $order->needs_payment() && isset( $request['set_paid'] ) && true === $request['set_paid'] ) { |
||
988 | $order->payment_complete( ! empty( $request['transaction_id'] ) ? $request['transaction_id'] : '' ); |
||
989 | } |
||
990 | |||
991 | // Set order currency. |
||
992 | if ( isset( $request['currency'] ) ) { |
||
993 | update_post_meta( $order->id, '_order_currency', $request['currency'] ); |
||
994 | } |
||
995 | |||
996 | // If items have changed, recalculate order totals. |
||
997 | if ( $update_totals ) { |
||
998 | $order->calculate_totals(); |
||
999 | } |
||
1000 | |||
1001 | // Update meta data. |
||
1002 | View Code Duplication | if ( ! empty( $request['meta_data'] ) && is_array( $request['meta_data'] ) ) { |
|
1003 | $this->update_meta_data( $order->id, $request['meta_data'] ); |
||
1004 | } |
||
1005 | |||
1006 | // Update the order post to set customer note/modified date. |
||
1007 | wc_update_order( $order_args ); |
||
1008 | |||
1009 | // Order status. |
||
1010 | View Code Duplication | if ( ! empty( $request['status'] ) ) { |
|
1011 | $order->update_status( $request['status'], isset( $request['status_note'] ) ? $request['status_note'] : '' ); |
||
1012 | } |
||
1013 | |||
1014 | return $order->id; |
||
1015 | } catch ( WC_REST_Exception $e ) { |
||
1016 | return new WP_Error( $e->getErrorCode(), $e->getMessage(), array( 'status' => $e->getCode() ) ); |
||
1017 | } |
||
1018 | } |
||
1019 | |||
1020 | /** |
||
1021 | * Update a single order. |
||
1022 | * |
||
1023 | * @param WP_REST_Request $request Full details about the request. |
||
1024 | * @return WP_Error|WP_REST_Response |
||
1025 | */ |
||
1026 | public function update_item( $request ) { |
||
1058 | |||
1059 | /** |
||
1060 | * Get order statuses. |
||
1061 | * |
||
1062 | * @return array |
||
1063 | */ |
||
1064 | protected function get_order_statuses() { |
||
1073 | |||
1074 | /** |
||
1075 | * Create base WC Order object. |
||
1076 | * |
||
1077 | * @since 2.6.0 |
||
1078 | * @param array $args Order args. |
||
1079 | * @param WP_REST_Request $request Full details about the request. |
||
1080 | * @return WC_Order|WP_Error |
||
1081 | */ |
||
1082 | protected function create_base_order( $args, $data ) { |
||
1085 | |||
1086 | /** |
||
1087 | * Get the Order's schema, conforming to JSON Schema. |
||
1088 | * |
||
1089 | * @return array |
||
1090 | */ |
||
1091 | public function get_item_schema() { |
||
1729 | |||
1730 | /** |
||
1731 | * Get the query params for collections. |
||
1732 | * |
||
1733 | * @return array |
||
1734 | */ |
||
1735 | public function get_collection_params() { |
||
1768 | } |
||
1769 |
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.