• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

wp-graphql / wp-graphql-woocommerce / 5603640472

pending completion
5603640472

push

github

web-flow
fix: clean up unnecessary variables and ternaries (#766)

21 of 21 new or added lines in 16 files covered. (100.0%)

10249 of 12438 relevant lines covered (82.4%)

54.02 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.36
/includes/data/mutation/class-order-mutation.php
1
<?php
2
/**
3
 * Defines helper functions for executing mutations related to the orders.
4
 *
5
 * @package WPGraphQL\WooCommerce\Data\Mutation
6
 * @since 0.2.0
7
 */
8

9
namespace WPGraphQL\WooCommerce\Data\Mutation;
10

11
use GraphQL\Error\UserError;
12

13
/**
14
 * Class - Order_Mutation
15
 */
16
class Order_Mutation {
17
        /**
18
         * Filterable authentication function.
19
         *
20
         * @param array                                $input     Input data describing order.
21
         * @param \WPGraphQL\AppContext                $context   AppContext instance.
22
         * @param \GraphQL\Type\Definition\ResolveInfo $info      ResolveInfo instance.
23
         * @param string                               $mutation  Mutation being executed.
24
         * @param integer|null                         $order_id  Order ID.
25
         *
26
         * @return boolean
27
         */
28
        public static function authorized( $input, $context, $info, $mutation = 'create', $order_id = null ) {
29
                /**
30
                 * Get order post type.
31
                 *
32
                 * @var \WP_Post_Type $post_type_object
33
                 */
34
                $post_type_object = get_post_type_object( 'shop_order' );
4✔
35

36
                return apply_filters(
4✔
37
                        "graphql_woocommerce_authorized_to_{$mutation}_orders",
4✔
38
                        current_user_can(
4✔
39
                                'delete' === $mutation
4✔
40
                                        ? $post_type_object->cap->delete_posts
1✔
41
                                        : $post_type_object->cap->edit_posts
4✔
42
                        ),
4✔
43
                        $order_id,
4✔
44
                        $input,
4✔
45
                        $context,
4✔
46
                        $info
4✔
47
                );
4✔
48
        }
49

50
        /**
51
         * Create an order.
52
         *
53
         * @param array                                $input    Input data describing order.
54
         * @param \WPGraphQL\AppContext                $context  AppContext instance.
55
         * @param \GraphQL\Type\Definition\ResolveInfo $info     ResolveInfo instance.
56
         *
57
         * @return integer
58
         *
59
         * @throws \GraphQL\Error\UserError  Error creating order.
60
         */
61
        public static function create_order( $input, $context, $info ) {
62
                $order_keys = [
4✔
63
                        'status'       => 'status',
4✔
64
                        'customerId'   => 'customer_id',
4✔
65
                        'customerNote' => 'customer_note',
4✔
66
                        'parent'       => 'parent',
4✔
67
                        'createdVia'   => 'created_via',
4✔
68
                        'orderId'      => 'order_id',
4✔
69
                ];
4✔
70

71
                $args = [];
4✔
72
                foreach ( $input as $key => $value ) {
4✔
73
                        if ( array_key_exists( $key, $order_keys ) ) {
4✔
74
                                $args[ $order_keys[ $key ] ] = $value;
4✔
75
                        }
76
                }
77

78
                /**
79
                 * Action called before order is created.
80
                 *
81
                 * @param array       $input   Input data describing order.
82
                 * @param \WPGraphQL\AppContext  $context Request AppContext instance.
83
                 * @param \GraphQL\Type\Definition\ResolveInfo $info    Request ResolveInfo instance.
84
                 */
85
                do_action( 'graphql_woocommerce_before_order_create', $input, $context, $info );
4✔
86

87
                $order = \wc_create_order( $args );
4✔
88
                if ( is_wp_error( $order ) ) {
4✔
89
                        throw new UserError( $order->get_error_code() . $order->get_error_message() );
×
90
                }
91

92
                /**
93
                 * Action called after order is created.
94
                 *
95
                 * @param \WC_Order    $order   WC_Order instance.
96
                 * @param array       $input   Input data describing order.
97
                 * @param \WPGraphQL\AppContext  $context Request AppContext instance.
98
                 * @param \GraphQL\Type\Definition\ResolveInfo $info    Request ResolveInfo instance.
99
                 */
100
                do_action( 'graphql_woocommerce_after_order_create', $order, $input, $context, $info );
4✔
101

102
                return $order->get_id();
4✔
103
        }
104

105
        /**
106
         * Add items to order.
107
         *
108
         * @param array                                $input     Input data describing order.
109
         * @param int                                  $order_id  Order object.
110
         * @param \WPGraphQL\AppContext                $context   AppContext instance.
111
         * @param \GraphQL\Type\Definition\ResolveInfo $info      ResolveInfo instance.
112
         *
113
         * @return void
114
         */
115
        public static function add_items( $input, $order_id, $context, $info ) {
116
                $item_group_keys = [
4✔
117
                        'lineItems'     => 'line_item',
4✔
118
                        'shippingLines' => 'shipping',
4✔
119
                        'feeLines'      => 'fee',
4✔
120
                ];
4✔
121

122
                $item_groups = [];
4✔
123
                foreach ( $input as $key => $items ) {
4✔
124
                        if ( array_key_exists( $key, $item_group_keys ) ) {
4✔
125
                                $type = $item_group_keys[ $key ];
4✔
126

127
                                /**
128
                                 * Action called before an item group is added to an order.
129
                                 *
130
                                 * @param array       $items     Item data being added.
131
                                 * @param integer     $order_id  ID of target order.
132
                                 * @param \WPGraphQL\AppContext  $context   Request AppContext instance.
133
                                 * @param \GraphQL\Type\Definition\ResolveInfo $info      Request ResolveInfo instance.
134
                                 */
135
                                do_action( "graphql_woocommerce_before_{$type}s_added_to_order", $items, $order_id, $context, $info );
4✔
136

137
                                foreach ( $items as $item_data ) {
4✔
138
                                        // Create Order item.
139
                                        $item_id = ( ! empty( $item_data['id'] ) && \WC_Order_Factory::get_order_item( $item_data['id'] ) )
4✔
140
                                                ? $item_data['id']
1✔
141
                                                : \wc_add_order_item( $order_id, [ 'order_item_type' => $type ] );
4✔
142

143
                                        // Continue if order item creation failed.
144
                                        if ( ! $item_id ) {
4✔
145
                                                continue;
×
146
                                        }
147

148
                                        // Add input item data to order item.
149
                                        $item_keys = self::get_order_item_keys( $type );
4✔
150
                                        self::map_input_to_item( $item_id, $item_data, $item_keys, $context, $info );
4✔
151
                                }
152

153
                                /**
154
                                 * Action called after an item group is added to an order.
155
                                 *
156
                                 * @param array       $items     Item data being added.
157
                                 * @param integer     $order_id  ID of target order.
158
                                 * @param \WPGraphQL\AppContext  $context   Request AppContext instance.
159
                                 * @param \GraphQL\Type\Definition\ResolveInfo $info      Request ResolveInfo instance.
160
                                 */
161
                                do_action( "graphql_woocommerce_after_{$type}s_added_to_order", $items, $order_id, $context, $info );
4✔
162
                        }//end if
163
                }//end foreach
164
        }
165

166
        /**
167
         * Return array of item mapped with the provided $item_keys and extracts $meta_data
168
         *
169
         * @param integer                              $item_id    Order item ID.
170
         * @param array                                $input      Item input data.
171
         * @param array                                $item_keys  Item key map.
172
         * @param \WPGraphQL\AppContext                $context    AppContext instance.
173
         * @param \GraphQL\Type\Definition\ResolveInfo $info       ResolveInfo instance.
174
         *
175
         * @throws \Exception  Failed to retrieve order item | Failed to retrieve connected product.
176
         *
177
         * @return int
178
         */
179
        protected static function map_input_to_item( $item_id, $input, $item_keys, $context, $info ) {
180
                $order_item = \WC_Order_Factory::get_order_item( $item_id );
4✔
181
                if ( ! is_object( $order_item ) ) {
4✔
182
                        throw new \Exception( __( 'Failed to retrieve order item.', 'wp-graphql-woocommerce' ) );
×
183
                }
184

185
                $args      = [];
4✔
186
                $meta_data = null;
4✔
187
                foreach ( $input as $key => $value ) {
4✔
188
                        if ( array_key_exists( $key, $item_keys ) ) {
4✔
189
                                $args[ $item_keys[ $key ] ] = $value;
4✔
190
                        } elseif ( 'metaData' === $key ) {
4✔
191
                                $meta_data = $value;
4✔
192
                        } else {
193
                                $args[ $key ] = $value;
4✔
194
                        }
195
                }
196

197
                // Calculate to subtotal/total for line items.
198

199
                if ( isset( $args['quantity'] ) ) {
4✔
200
                        $product = ( ! empty( $order_item['product_id'] ) )
4✔
201
                                ? wc_get_product( $order_item['product_id'] )
1✔
202
                                : wc_get_product( self::get_product_id( $args ) );
4✔
203
                        if ( ! is_object( $product ) ) {
4✔
204
                                throw new \Exception( __( 'Failed to retrieve product connected to order item.', 'wp-graphql-woocommerce' ) );
×
205
                        }
206

207
                        $total            = wc_get_price_excluding_tax( $product, [ 'qty' => $args['quantity'] ] );
4✔
208
                        $args['subtotal'] = ! empty( $args['subtotal'] ) ? $args['subtotal'] : $total;
4✔
209
                        $args['total']    = ! empty( $args['total'] ) ? $args['total'] : $total;
4✔
210
                }
211

212
                // Set item props.
213
                foreach ( $args as $key => $value ) {
4✔
214
                        if ( is_callable( [ $order_item, "set_{$key}" ] ) ) {
4✔
215
                                $order_item->{"set_{$key}"}( $value );
4✔
216
                        }
217
                }
218

219
                // Update item meta data if any is found.
220
                if ( 0 !== $item_id && ! empty( $meta_data ) ) {
4✔
221
                        // Update item meta data.
222
                        self::update_item_meta_data( $item_id, $meta_data, $context, $info );
4✔
223
                }
224

225
                return $order_item->save();
4✔
226
        }
227

228
        /**
229
         * Returns array of item keys by item type.
230
         *
231
         * @param string $type  Order item type.
232
         *
233
         * @return array
234
         */
235
        protected static function get_order_item_keys( $type ) {
236
                switch ( $type ) {
237
                        case 'line_item':
4✔
238
                                return [
4✔
239
                                        'productId'   => 'product_id',
4✔
240
                                        'variationId' => 'variation_id',
4✔
241
                                        'taxClass'    => 'tax_class',
4✔
242
                                ];
4✔
243

244
                        case 'shipping':
4✔
245
                                return [
4✔
246
                                        'name'        => 'order_item_name',
4✔
247
                                        'methodTitle' => 'method_title',
4✔
248
                                        'methodId'    => 'method_id',
4✔
249
                                        'instanceId'  => 'instance_id',
4✔
250
                                ];
4✔
251

252
                        case 'fee':
4✔
253
                                return [
4✔
254
                                        'name'      => 'name',
4✔
255
                                        'taxClass'  => 'tax_class',
4✔
256
                                        'taxStatus' => 'tax_status',
4✔
257
                                ];
4✔
258
                        default:
259
                                /**
260
                                 * Allow filtering of order item keys for unknown item types.
261
                                 *
262
                                 * @param array  $item_keys  Order item keys.
263
                                 * @param string $type       Order item type slug.
264
                                 */
265
                                return apply_filters( 'woographql_get_order_item_keys', [], $type );
×
266
                }//end switch
267
        }
268

269
        /**
270
         * Gets the product ID from the SKU or line item data ID.
271
         *
272
         * @param array $data  Line item data.
273
         *
274
         * @return integer
275
         * @throws \GraphQL\Error\UserError When SKU or ID is not valid.
276
         */
277
        protected static function get_product_id( $data ) {
278
                if ( ! empty( $data['sku'] ) ) {
4✔
279
                        $product_id = (int) wc_get_product_id_by_sku( $data['sku'] );
×
280
                } elseif ( ! empty( $data['product_id'] ) && empty( $data['variation_id'] ) ) {
4✔
281
                        $product_id = (int) $data['product_id'];
4✔
282
                } elseif ( ! empty( $data['variation_id'] ) ) {
4✔
283
                        $product_id = (int) $data['variation_id'];
4✔
284
                } else {
285
                        throw new UserError( __( 'Product ID or SKU is required.', 'wp-graphql-woocommerce' ) );
×
286
                }
287

288
                return $product_id;
4✔
289
        }
290

291
        /**
292
         * Create/Update order item meta data.
293
         *
294
         * @param int                                  $item_id    Order item ID.
295
         * @param array                                $meta_data  Array of meta data.
296
         * @param \WPGraphQL\AppContext                $context    AppContext instance.
297
         * @param \GraphQL\Type\Definition\ResolveInfo $info       ResolveInfo instance.
298
         *
299
         * @throws \GraphQL\Error\UserError|\Exception  Invalid item input | Failed to retrieve order item.
300
         *
301
         * @return void
302
         */
303
        protected static function update_item_meta_data( $item_id, $meta_data, $context, $info ) {
304
                $item = \WC_Order_Factory::get_order_item( $item_id );
4✔
305
                if ( ! is_object( $item ) ) {
4✔
306
                        throw new \Exception( __( 'Failed to retrieve order item.', 'wp-graphql-woocommerce' ) );
×
307
                }
308

309
                foreach ( $meta_data as $entry ) {
4✔
310
                        $exists = $item->get_meta( $entry['key'], true, 'edit' );
4✔
311
                        if ( '' !== $exists && $exists !== $entry['value'] ) {
4✔
312
                                \wc_update_order_item_meta( $item_id, $entry['key'], $entry['value'] );
1✔
313
                        } else {
314
                                \wc_add_order_item_meta( $item_id, $entry['key'], $entry['value'] );
4✔
315
                        }
316
                }
317
        }
318

319
        /**
320
         * Add meta data not set in self::create_order().
321
         *
322
         * @param int                                  $order_id  Order ID.
323
         * @param array                                $input     Order properties.
324
         * @param \WPGraphQL\AppContext                $context   AppContext instance.
325
         * @param \GraphQL\Type\Definition\ResolveInfo $info      ResolveInfo instance.
326
         *
327
         * @throws \Exception  Failed to retrieve order.
328
         *
329
         * @return void
330
         */
331
        public static function add_order_meta( $order_id, $input, $context, $info ) {
332
                $order = \WC_Order_Factory::get_order( $order_id );
4✔
333
                if ( ! is_object( $order ) ) {
4✔
334
                        throw new \Exception( __( 'Failed to retrieve order.', 'wp-graphql-woocommerce' ) );
×
335
                }
336

337
                foreach ( $input as $key => $value ) {
4✔
338
                        switch ( $key ) {
339
                                case 'coupons':
4✔
340
                                case 'lineItems':
4✔
341
                                case 'shippingLines':
4✔
342
                                case 'feeLines':
4✔
343
                                case 'status':
4✔
344
                                        break;
4✔
345
                                case 'billing':
4✔
346
                                case 'shipping':
4✔
347
                                        self::update_address( $value, $order_id, $key );
4✔
348
                                        $order->apply_changes();
4✔
349
                                        break;
4✔
350
                                case 'metaData':
4✔
351
                                        if ( is_array( $value ) ) {
4✔
352
                                                foreach ( $value as $meta ) {
4✔
353
                                                        $order->update_meta_data( $meta['key'], $meta['value'], isset( $meta['id'] ) ? $meta['id'] : '' );
4✔
354
                                                }
355
                                        }
356
                                        break;
4✔
357
                                default:
358
                                        $prop = \wc_graphql_camel_case_to_underscore( $key );
4✔
359
                                        if ( is_callable( [ $order, "set_{$prop}" ] ) ) {
4✔
360
                                                $order->{"set_{$prop}"}( $value );
4✔
361
                                        }
362
                                        break;
4✔
363
                        }//end switch
364
                }//end foreach
365

366
                /**
367
                 * Action called before changes to order meta are saved.
368
                 *
369
                 * @param \WC_Order   $order   WC_Order instance.
370
                 * @param array       $props   Order props array.
371
                 * @param \WPGraphQL\AppContext  $context Request AppContext instance.
372
                 * @param \GraphQL\Type\Definition\ResolveInfo $info    Request ResolveInfo instance.
373
                 */
374
                do_action( 'graphql_woocommerce_before_order_meta_save', $order, $input, $context, $info );
4✔
375

376
                $order->save();
4✔
377
        }
378

379
        /**
380
         * Update address.
381
         *
382
         * @param array   $address   Address data.
383
         * @param integer $order_id  WC_Order instance.
384
         * @param string  $type      Address type.
385
         *
386
         * @throws \Exception  Failed to retrieve order.
387
         *
388
         * @return void
389
         */
390
        protected static function update_address( $address, $order_id, $type = 'billing' ) {
391
                $order = \WC_Order_Factory::get_order( $order_id );
4✔
392
                if ( ! is_object( $order ) ) {
4✔
393
                        throw new \Exception( __( 'Failed to retrieve order.', 'wp-graphql-woocommerce' ) );
×
394
                }
395

396
                $formatted_address = Customer_Mutation::address_input_mapping( $address, $type );
4✔
397
                foreach ( $formatted_address as $key => $value ) {
4✔
398
                        if ( is_callable( [ $order, "set_{$type}_{$key}" ] ) ) {
4✔
399
                                $order->{"set_{$type}_{$key}"}( $value );
4✔
400
                        }
401
                }
402
                $order->save();
4✔
403
        }
404

405
        /**
406
         * Applies coupons to WC_Order instance
407
         *
408
         * @param int   $order_id  Order ID.
409
         * @param array $coupons   Coupon codes to be applied to order.
410
         *
411
         * @throws \Exception  Failed to retrieve order.
412
         *
413
         * @return void
414
         */
415
        public static function apply_coupons( $order_id, $coupons ) {
416
                $order = \WC_Order_Factory::get_order( $order_id );
4✔
417
                if ( ! is_object( $order ) ) {
4✔
418
                        throw new \Exception( __( 'Failed to retrieve order.', 'wp-graphql-woocommerce' ) );
×
419
                }
420

421
                // Remove all coupons first to ensure calculation is correct.
422
                foreach ( $order->get_items( 'coupon' ) as $coupon ) {
4✔
423
                        /**
424
                         * Order item coupon.
425
                         *
426
                         * @var \WC_Order_Item_Coupon $coupon
427
                         */
428

429
                        $order->remove_coupon( $coupon->get_code() );
1✔
430
                }
431

432
                foreach ( $coupons as $code ) {
4✔
433
                        $results = $order->apply_coupon( sanitize_text_field( $code ) );
4✔
434
                        if ( is_wp_error( $results ) ) {
4✔
435
                                do_action( 'graphql_woocommerce_' . $results->get_error_code(), $results, $code, $coupons, $order );
×
436
                        }
437
                }
438

439
                $order->save();
4✔
440
        }
441

442
        /**
443
         * Validates order customer
444
         *
445
         * @param array $input  Input data describing order.
446
         *
447
         * @return bool
448
         */
449
        public static function validate_customer( $input ) {
450
                if ( ! empty( $input['customerId'] ) ) {
4✔
451
                        // Make sure customer exists.
452
                        if ( false === get_user_by( 'id', $input['customerId'] ) ) {
4✔
453
                                return false;
×
454
                        }
455
                        // Make sure customer is part of blog.
456
                        if ( is_multisite() && ! is_user_member_of_blog( $input['customerId'] ) ) {
4✔
457
                                add_user_to_blog( get_current_blog_id(), $input['customerId'], 'customer' );
×
458
                        }
459

460
                        return true;
4✔
461
                }
462

463
                return false;
×
464
        }
465

466
        /**
467
         * Purge object when creating.
468
         *
469
         * @param null|\WC_Order|\WPGraphQL\WooCommerce\Model\Order $order         Object data.
470
         * @param boolean                                           $force_delete  Delete or put in trash.
471
         *
472
         * @return bool
473
         * @throws \GraphQL\Error\UserError  Failed to delete order.
474
         */
475
        public static function purge( $order, $force_delete = true ) {
476
                if ( ! empty( $order ) ) {
1✔
477
                        return $order->delete( $force_delete );
1✔
478
                }
479

480
                return false;
×
481
        }
482
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc