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

wp-graphql / wp-graphql-woocommerce / 11714183904

07 Nov 2024 12:23AM UTC coverage: 83.665% (-0.8%) from 84.451%
11714183904

push

github

web-flow
devops: Name officially changed to "WPGraphQL for WooCommerce" (#900)

* devops: Name officially changed to "WPGraphQL for WooCommerce"

* devops: GA workflow environment updated

* devops: GA workflow environment updated

* devops: composer-git-hooks downgraded to "2.8.5"

* devops: Unstable session manager tests skipped

* chore: cleanup applied

* devops: Docker configurations updated

* devops: Docker configurations updated

* devops: Docker configurations updated

* devops: Docker configurations updated

* devops: Docker configurations updated

2 of 8 new or added lines in 5 files covered. (25.0%)

268 existing lines in 20 files now uncovered.

12431 of 14858 relevant lines covered (83.67%)

71.79 hits per line

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

84.82
/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
use WPGraphQL\Utils\Utils;
13

14

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

39
                if ( ! $order_id ) {
4✔
40
                        return apply_filters(
4✔
41
                                "graphql_woocommerce_authorized_to_{$mutation}_orders",
4✔
42
                                current_user_can( $post_type_object->cap->edit_posts ),
4✔
43
                                $order_id,
4✔
44
                                $input,
4✔
45
                                $context,
4✔
46
                                $info
4✔
47
                        );
4✔
48
                }
49

50
                /** @var false|\WC_Order $order */
51
                $order = \wc_get_order( $order_id );
3✔
52
                if ( false === $order ) {
3✔
UNCOV
53
                        throw new UserError(
×
UNCOV
54
                                sprintf(
×
55
                                        /* translators: %d: Order ID */
UNCOV
56
                                        __( 'Failed to find order with ID of %d.', 'wp-graphql-woocommerce' ),
×
UNCOV
57
                                        $order_id
×
UNCOV
58
                                )
×
UNCOV
59
                        );
×
60
                }
61

62
                $post_type = get_post_type( $order_id );
3✔
63
                if ( false === $post_type ) {
3✔
UNCOV
64
                        throw new UserError( __( 'Failed to identify the post type of the order.', 'wp-graphql-woocommerce' ) );
×
65
                }
66

67
                // Return true if user is owner or admin.
68
                $is_owner = 0 !== get_current_user_id() && $order->get_customer_id() === get_current_user_id();
3✔
69
                $is_admin = \wc_rest_check_post_permissions( $post_type, 'edit', $order_id );
3✔
70
                return $is_owner || $is_admin;
3✔
71
        }
72

73
        /**
74
         * Create an order.
75
         *
76
         * @param array                                $input    Input data describing order.
77
         * @param \WPGraphQL\AppContext                $context  AppContext instance.
78
         * @param \GraphQL\Type\Definition\ResolveInfo $info     ResolveInfo instance.
79
         *
80
         * @return integer
81
         *
82
         * @throws \GraphQL\Error\UserError  Error creating order.
83
         */
84
        public static function create_order( $input, $context, $info ) {
85
                $order = new \WC_Order();
4✔
86

87
                $order->set_currency( ! empty( $input['currency'] ) ? $input['currency'] : get_woocommerce_currency() );
4✔
88
                $order->set_prices_include_tax( 'yes' === get_option( 'woocommerce_prices_include_tax' ) );
4✔
89
                $order->set_customer_ip_address( \WC_Geolocation::get_ip_address() );
4✔
90
                $order->set_customer_user_agent( wc_get_user_agent() );
4✔
91

92
                $order_id = $order->save();
4✔
93

94
                $order_keys = [
4✔
95
                        'status'       => 'status',
4✔
96
                        'customerId'   => 'customer_id',
4✔
97
                        'customerNote' => 'customer_note',
4✔
98
                        'parent'       => 'parent',
4✔
99
                        'createdVia'   => 'created_via',
4✔
100
                ];
4✔
101

102
                $args = [ 'order_id' => $order_id ];
4✔
103
                foreach ( $input as $key => $value ) {
4✔
104
                        if ( array_key_exists( $key, $order_keys ) ) {
4✔
105
                                $args[ $order_keys[ $key ] ] = $value;
4✔
106
                        }
107
                }
108

109
                /**
110
                 * Action called before order is created.
111
                 *
112
                 * @param array                                $input   Input data describing order.
113
                 * @param \WPGraphQL\AppContext                $context Request AppContext instance.
114
                 * @param \GraphQL\Type\Definition\ResolveInfo $info    Request ResolveInfo instance.
115
                 */
116
                do_action( 'graphql_woocommerce_before_order_create', $input, $context, $info );
4✔
117

118
                $order = \wc_create_order( $args );
4✔
119
                if ( is_wp_error( $order ) ) {
4✔
UNCOV
120
                        throw new UserError( $order->get_error_code() . $order->get_error_message() );
×
121
                }
122

123
                /**
124
                 * Action called after order is created.
125
                 *
126
                 * @param \WC_Order    $order   WC_Order instance.
127
                 * @param array       $input   Input data describing order.
128
                 * @param \WPGraphQL\AppContext  $context Request AppContext instance.
129
                 * @param \GraphQL\Type\Definition\ResolveInfo $info    Request ResolveInfo instance.
130
                 */
131
                do_action( 'graphql_woocommerce_after_order_create', $order, $input, $context, $info );
4✔
132

133
                return $order->get_id();
4✔
134
        }
135

136
        /**
137
         * Add items to order.
138
         *
139
         * @param array                                $input     Input data describing order.
140
         * @param int                                  $order_id  Order object.
141
         * @param \WPGraphQL\AppContext                $context   AppContext instance.
142
         * @param \GraphQL\Type\Definition\ResolveInfo $info      ResolveInfo instance.
143
         *
144
         * @throws \Exception  Failed to retrieve order.
145
         *
146
         * @return void
147
         */
148
        public static function add_items( $input, $order_id, $context, $info ) {
149
                /** @var \WC_Order|false $order */
150
                $order = \WC_Order_Factory::get_order( $order_id );
4✔
151
                if ( false === $order ) {
4✔
UNCOV
152
                        throw new \Exception( __( 'Failed to retrieve order.', 'wp-graphql-woocommerce' ) );
×
153
                }
154

155
                $item_group_keys = [
4✔
156
                        'lineItems'     => 'line_item',
4✔
157
                        'shippingLines' => 'shipping',
4✔
158
                        'feeLines'      => 'fee',
4✔
159
                ];
4✔
160

161
                $order_items = [];
4✔
162
                foreach ( $input as $key => $group_items ) {
4✔
163
                        if ( array_key_exists( $key, $item_group_keys ) ) {
4✔
164
                                $type                 = $item_group_keys[ $key ];
4✔
165
                                $order_items[ $type ] = [];
4✔
166

167
                                /**
168
                                 * Action called before an item group is added to an order.
169
                                 *
170
                                 * @param array                                $group_items  Items data being added.
171
                                 * @param \WC_Order                            $order        Order object.
172
                                 * @param \WPGraphQL\AppContext                $context      Request AppContext instance.
173
                                 * @param \GraphQL\Type\Definition\ResolveInfo $info         Request ResolveInfo instance.
174
                                 */
175
                                do_action( "graphql_woocommerce_before_{$type}s_added_to_order", $group_items, $order, $context, $info );
4✔
176

177
                                foreach ( $group_items as $item_data ) {
4✔
178
                                        $item = self::set_item(
4✔
179
                                                $item_data,
4✔
180
                                                $type,
4✔
181
                                                $order,
4✔
182
                                                $context,
4✔
183
                                                $info
4✔
184
                                        );
4✔
185

186
                                        /**
187
                                         * Action called before an item group is added to an order.
188
                                         *
189
                                         * @param \WC_Order_Item                       $item      Order item object.
190
                                         * @param array                                $item_data Item data being added.
191
                                         * @param \WC_Order                            $order     Order object.
192
                                         * @param \WPGraphQL\AppContext                $context   Request AppContext instance.
193
                                         * @param \GraphQL\Type\Definition\ResolveInfo $info      Request ResolveInfo instance.
194
                                         */
195
                                        do_action( "graphql_woocommerce_before_{$type}_added_to_order", $item, $item_data, $order, $context, $info );
4✔
196

197
                                        if ( 0 === $item->get_id() ) {
4✔
198
                                                $order->add_item( $item );
4✔
199
                                                $order_items[ $type ][] = $item;
4✔
200
                                        } else {
201
                                                $item->save();
1✔
202
                                                $order_items[ $type ][] = $item;
1✔
203
                                        }
204
                                }
205

206
                                /**
207
                                 * Action called after an item group is added to an order, and before the order has been saved with the new items.
208
                                 *
209
                                 * @param array                                $group_items  Item data being added.
210
                                 * @param \WC_Order                            $order        Order object.
211
                                 * @param \WPGraphQL\AppContext                $context      Request AppContext instance.
212
                                 * @param \GraphQL\Type\Definition\ResolveInfo $info         Request ResolveInfo instance.
213
                                 */
214
                                do_action( "graphql_woocommerce_after_{$type}s_added_to_order", $group_items, $order, $context, $info );
4✔
215
                        }//end if
216
                }//end foreach
217

218
                /**
219
                 * Action called after all items have been added and right before the new items have been saved.
220
                 *
221
                 * @param array<string, array<\WC_Order_Item>> $order_items Order items.
222
                 * @param \WC_Order                            $order       WC_Order instance.
223
                 * @param array                                $input       Input data describing order.
224
                 * @param \WPGraphQL\AppContext                $context     Request AppContext instance.
225
                 * @param \GraphQL\Type\Definition\ResolveInfo $info        Request ResolveInfo instance.
226
                 */
227
                do_action( 'graphql_woocommerce_before_new_order_items_save', $order_items, $order, $input, $context, $info );
4✔
228

229
                $order->save();
4✔
230
        }
231

232
        /**
233
         *
234
         * @param array<string, mixed>                 $item_data  Item data.
235
         * @param string                               $type       Item type.
236
         * @param \WC_Order                            $order      Order object.
237
         * @param \WPGraphQL\AppContext                $context    AppContext instance.
238
         * @param \GraphQL\Type\Definition\ResolveInfo $info       ResolveInfo instance.
239
         *
240
         * @return \WC_Order_Item
241
         */
242
        public static function set_item( $item_data, $type, $order, $context, $info ) {
243
                $item_id    = ! empty( $item_data['id'] ) ? $item_data['id'] : 0;
4✔
244
                $item_class = self::get_order_item_classname( $type, $item_id );
4✔
245

246
                /** @var \WC_Order_Item $item */
247
                $item = new $item_class( $item_id );
4✔
248

249
                /**
250
                 * Filter the order item object before it is created.
251
                 *
252
                 * @param \WC_Order_Item                       $item       Order item object.
253
                 * @param array                                $item_data  Item data.
254
                 * @param \WC_Order                            $order      Order object.
255
                 * @param \WPGraphQL\AppContext                $context    AppContext instance.
256
                 * @param \GraphQL\Type\Definition\ResolveInfo $info       ResolveInfo instance.
257
                 */
258
                $item = apply_filters( "graphql_create_order_{$type}_object", $item, $item_data, $order, $context, $info );
4✔
259

260
                self::map_input_to_item( $item, $item_data, $type );
4✔
261

262
                /**
263
                 * Action called after an order item is created.
264
                 *
265
                 * @param \WC_Order_Item                       $item       Order item object.
266
                 * @param array                                $item_data  Item data.
267
                 * @param \WC_Order                            $order      Order object.
268
                 * @param \WPGraphQL\AppContext                $context    AppContext instance.
269
                 * @param \GraphQL\Type\Definition\ResolveInfo $info       ResolveInfo instance.
270
                 */
271
                do_action( "graphql_create_order_{$type}", $item, $item_data, $order, $context, $info );
4✔
272

273
                return $item;
4✔
274
        }
275

276
        /**
277
         * Get order item class name.
278
         *
279
         * @param string $type Order item type.
280
         * @param int    $id  Order item ID.
281
         *
282
         * @return string
283
         */
284
        public static function get_order_item_classname( $type, $id = 0 ) {
285
                $classname = false;
4✔
286
                switch ( $type ) {
287
                        case 'line_item':
4✔
288
                        case 'product':
4✔
289
                                $classname = 'WC_Order_Item_Product';
4✔
290
                                break;
4✔
291
                        case 'coupon':
4✔
UNCOV
292
                                $classname = 'WC_Order_Item_Coupon';
×
UNCOV
293
                                break;
×
294
                        case 'fee':
4✔
295
                                $classname = 'WC_Order_Item_Fee';
4✔
296
                                break;
4✔
297
                        case 'shipping':
4✔
298
                                $classname = 'WC_Order_Item_Shipping';
4✔
299
                                break;
4✔
UNCOV
300
                        case 'tax':
×
UNCOV
301
                                $classname = 'WC_Order_Item_Tax';
×
UNCOV
302
                                break;
×
303
                }
304

305
                $classname = apply_filters( 'woocommerce_get_order_item_classname', $classname, $type, $id ); // phpcs:ignore WordPress.NamingConventions
4✔
306

307
                return $classname;
4✔
308
        }
309

310
        /**
311
         * Return array of item mapped with the provided $item_keys and extracts $meta_data
312
         *
313
         * @param \WC_Order_Item &$item      Order item.
314
         * @param array          $input      Item input data.
315
         * @param string         $type       Item type.
316
         *
317
         * @throws \Exception Failed to retrieve connected product.
318
         *
319
         * @return void
320
         */
321
        protected static function map_input_to_item( &$item, $input, $type ) {
322
                $item_keys = self::get_order_item_keys( $type );
4✔
323

324
                $args      = [];
4✔
325
                $meta_data = null;
4✔
326
                foreach ( $input as $key => $value ) {
4✔
327
                        if ( array_key_exists( $key, $item_keys ) ) {
4✔
328
                                $args[ $item_keys[ $key ] ] = $value;
4✔
329
                        } elseif ( 'metaData' === $key ) {
4✔
330
                                $meta_data = $value;
4✔
331
                        } else {
332
                                $args[ $key ] = $value;
4✔
333
                        }
334
                }
335

336
                // Calculate to subtotal/total for line items.
337
                if ( isset( $args['quantity'] ) ) {
4✔
338
                        $product = ( ! empty( $item['product_id'] ) )
4✔
339
                                ? wc_get_product( $item['product_id'] )
1✔
340
                                : wc_get_product( self::get_product_id( $args ) );
4✔
341
                        if ( ! is_object( $product ) ) {
4✔
UNCOV
342
                                throw new \Exception( __( 'Failed to retrieve product connected to order item.', 'wp-graphql-woocommerce' ) );
×
343
                        }
344

345
                        $total            = wc_get_price_excluding_tax( $product, [ 'qty' => $args['quantity'] ] );
4✔
346
                        $args['subtotal'] = ! empty( $args['subtotal'] ) ? $args['subtotal'] : $total;
4✔
347
                        $args['total']    = ! empty( $args['total'] ) ? $args['total'] : $total;
4✔
348
                }
349

350
                // Set item props.
351
                foreach ( $args as $key => $value ) {
4✔
352
                        if ( is_callable( [ $item, "set_{$key}" ] ) ) {
4✔
353
                                $item->{"set_{$key}"}( $value );
4✔
354
                        }
355
                }
356

357
                // Update item meta data if any is found.
358
                if ( empty( $meta_data ) ) {
4✔
359
                        return;
4✔
360
                }
361

362
                foreach ( $meta_data as $entry ) {
4✔
363
                        $exists = $item->get_meta( $entry['key'], true, 'edit' );
4✔
364
                        if ( '' !== $exists && $exists !== $entry['value'] ) {
4✔
365
                                $item->update_meta_data( $entry['key'], $entry['value'] );
1✔
366
                        } else {
367
                                $item->add_meta_data( $entry['key'], $entry['value'] );
4✔
368
                        }
369
                }
370
        }
371

372
        /**
373
         * Returns array of item keys by item type.
374
         *
375
         * @param string $type  Order item type.
376
         *
377
         * @return array
378
         */
379
        protected static function get_order_item_keys( $type ) {
380
                switch ( $type ) {
381
                        case 'line_item':
4✔
382
                                return [
4✔
383
                                        'productId'   => 'product_id',
4✔
384
                                        'variationId' => 'variation_id',
4✔
385
                                        'taxClass'    => 'tax_class',
4✔
386
                                ];
4✔
387

388
                        case 'shipping':
4✔
389
                                return [
4✔
390
                                        'name'        => 'order_item_name',
4✔
391
                                        'methodTitle' => 'method_title',
4✔
392
                                        'methodId'    => 'method_id',
4✔
393
                                        'instanceId'  => 'instance_id',
4✔
394
                                ];
4✔
395

396
                        case 'fee':
4✔
397
                                return [
4✔
398
                                        'name'      => 'name',
4✔
399
                                        'taxClass'  => 'tax_class',
4✔
400
                                        'taxStatus' => 'tax_status',
4✔
401
                                ];
4✔
402
                        default:
403
                                /**
404
                                 * Allow filtering of order item keys for unknown item types.
405
                                 *
406
                                 * @param array  $item_keys  Order item keys.
407
                                 * @param string $type       Order item type slug.
408
                                 */
UNCOV
409
                                return apply_filters( 'woographql_get_order_item_keys', [], $type );
×
410
                }//end switch
411
        }
412

413
        /**
414
         * Gets the product ID from the SKU or line item data ID.
415
         *
416
         * @param array $data  Line item data.
417
         *
418
         * @return integer
419
         * @throws \GraphQL\Error\UserError When SKU or ID is not valid.
420
         */
421
        protected static function get_product_id( $data ) {
422
                if ( ! empty( $data['sku'] ) ) {
4✔
UNCOV
423
                        $product_id = (int) wc_get_product_id_by_sku( $data['sku'] );
×
424
                } elseif ( ! empty( $data['variation_id'] ) ) {
4✔
425
                        $product_id = (int) $data['variation_id'];
4✔
426
                } elseif ( ! empty( $data['product_id'] ) ) {
4✔
427
                        $product_id = (int) $data['product_id'];
4✔
428
                } else {
UNCOV
429
                        throw new UserError( __( 'Product ID or SKU is required.', 'wp-graphql-woocommerce' ) );
×
430
                }
431

432
                return $product_id;
4✔
433
        }
434

435
        /**
436
         * Create/Update order item meta data.
437
         *
438
         * @param int                                  $item_id    Order item ID.
439
         * @param array                                $meta_data  Array of meta data.
440
         * @param \WPGraphQL\AppContext                $context    AppContext instance.
441
         * @param \GraphQL\Type\Definition\ResolveInfo $info       ResolveInfo instance.
442
         *
443
         * @throws \GraphQL\Error\UserError|\Exception  Invalid item input | Failed to retrieve order item.
444
         *
445
         * @return void
446
         */
447
        protected static function update_item_meta_data( $item_id, $meta_data, $context, $info ) {
UNCOV
448
                $item = \WC_Order_Factory::get_order_item( $item_id );
×
UNCOV
449
                if ( ! is_object( $item ) ) {
×
UNCOV
450
                        throw new \Exception( __( 'Failed to retrieve order item.', 'wp-graphql-woocommerce' ) );
×
451
                }
452

UNCOV
453
                foreach ( $meta_data as $entry ) {
×
UNCOV
454
                        $exists = $item->get_meta( $entry['key'], true, 'edit' );
×
UNCOV
455
                        if ( '' !== $exists && $exists !== $entry['value'] ) {
×
456
                                \wc_update_order_item_meta( $item_id, $entry['key'], $entry['value'] );
×
457
                        } else {
UNCOV
458
                                \wc_add_order_item_meta( $item_id, $entry['key'], $entry['value'] );
×
459
                        }
460
                }
461
        }
462

463
        /**
464
         * Add meta data not set in self::create_order().
465
         *
466
         * @param int                                  $order_id  Order ID.
467
         * @param array                                $input     Order properties.
468
         * @param \WPGraphQL\AppContext                $context   AppContext instance.
469
         * @param \GraphQL\Type\Definition\ResolveInfo $info      ResolveInfo instance.
470
         *
471
         * @throws \Exception  Failed to retrieve order.
472
         *
473
         * @return void
474
         */
475
        public static function add_order_meta( $order_id, $input, $context, $info ) {
476
                $order = \WC_Order_Factory::get_order( $order_id );
4✔
477
                if ( ! is_object( $order ) ) {
4✔
UNCOV
478
                        throw new \Exception( __( 'Failed to retrieve order.', 'wp-graphql-woocommerce' ) );
×
479
                }
480

481
                foreach ( $input as $key => $value ) {
4✔
482
                        switch ( $key ) {
483
                                case 'coupons':
4✔
484
                                case 'lineItems':
4✔
485
                                case 'shippingLines':
4✔
486
                                case 'feeLines':
4✔
487
                                case 'status':
4✔
488
                                        break;
4✔
489
                                case 'billing':
4✔
490
                                case 'shipping':
4✔
491
                                        self::update_address( $value, $order_id, $key );
4✔
492
                                        $order->apply_changes();
4✔
493
                                        break;
4✔
494
                                case 'metaData':
4✔
495
                                        if ( is_array( $value ) ) {
4✔
496
                                                foreach ( $value as $meta ) {
4✔
497
                                                        $order->update_meta_data( $meta['key'], $meta['value'], isset( $meta['id'] ) ? $meta['id'] : '' );
4✔
498
                                                }
499
                                        }
500
                                        break;
4✔
501
                                default:
502
                                        $prop = \wc_graphql_camel_case_to_underscore( $key );
4✔
503
                                        if ( is_callable( [ $order, "set_{$prop}" ] ) ) {
4✔
504
                                                $order->{"set_{$prop}"}( $value );
4✔
505
                                        }
506
                                        break;
4✔
507
                        }//end switch
508
                }//end foreach
509

510
                /**
511
                 * Action called before changes to order meta are saved.
512
                 *
513
                 * @param \WC_Order                            $order   WC_Order instance.
514
                 * @param array                                $props   Order props array.
515
                 * @param \WPGraphQL\AppContext                $context Request AppContext instance.
516
                 * @param \GraphQL\Type\Definition\ResolveInfo $info    Request ResolveInfo instance.
517
                 */
518
                do_action( 'graphql_woocommerce_before_order_meta_save', $order, $input, $context, $info );
4✔
519

520
                $order->save_meta_data();
4✔
521
                $order->save();
4✔
522
        }
523

524
        /**
525
         * Update address.
526
         *
527
         * @param array   $address   Address data.
528
         * @param integer $order_id  WC_Order instance.
529
         * @param string  $type      Address type.
530
         *
531
         * @throws \Exception  Failed to retrieve order.
532
         *
533
         * @return void
534
         */
535
        protected static function update_address( $address, $order_id, $type = 'billing' ) {
536
                $order = \WC_Order_Factory::get_order( $order_id );
4✔
537
                if ( ! is_object( $order ) ) {
4✔
UNCOV
538
                        throw new \Exception( __( 'Failed to retrieve order.', 'wp-graphql-woocommerce' ) );
×
539
                }
540

541
                $formatted_address = Customer_Mutation::address_input_mapping( $address, $type );
4✔
542
                foreach ( $formatted_address as $key => $value ) {
4✔
543
                        if ( is_callable( [ $order, "set_{$type}_{$key}" ] ) ) {
4✔
544
                                $order->{"set_{$type}_{$key}"}( $value );
4✔
545
                        }
546
                }
547
                $order->save();
4✔
548
        }
549

550
        /**
551
         * Applies coupons to WC_Order instance
552
         *
553
         * @param int   $order_id  Order ID.
554
         * @param array $coupons   Coupon codes to be applied to order.
555
         *
556
         * @throws \Exception  Failed to retrieve order.
557
         *
558
         * @return void
559
         */
560
        public static function apply_coupons( $order_id, $coupons ) {
561
                $order = \WC_Order_Factory::get_order( $order_id );
4✔
562
                if ( ! is_object( $order ) ) {
4✔
UNCOV
563
                        throw new \Exception( __( 'Failed to retrieve order.', 'wp-graphql-woocommerce' ) );
×
564
                }
565

566
                // Remove all coupons first to ensure calculation is correct.
567
                foreach ( $order->get_items( 'coupon' ) as $coupon ) {
4✔
568
                        /**
569
                         * Order item coupon.
570
                         *
571
                         * @var \WC_Order_Item_Coupon $coupon
572
                         */
573

574
                        $order->remove_coupon( $coupon->get_code() );
1✔
575
                }
576

577
                foreach ( $coupons as $code ) {
4✔
578
                        $results = $order->apply_coupon( sanitize_text_field( $code ) );
4✔
579
                        if ( is_wp_error( $results ) ) {
4✔
580
                                do_action( 'graphql_woocommerce_' . $results->get_error_code(), $results, $code, $coupons, $order );
×
581
                        }
582
                }
583

584
                $order->save();
4✔
585
        }
586

587
        /**
588
         * Validates order customer
589
         *
590
         * @param string $customer_id  ID of customer for order.
591
         *
592
         * @return bool
593
         */
594
        public static function validate_customer( $customer_id ) {
595
                $id = Utils::get_database_id_from_id( $customer_id );
4✔
596
                if ( ! $id ) {
4✔
UNCOV
597
                        return false;
×
598
                }
599

600
                if ( false === get_user_by( 'id', $id ) ) {
4✔
UNCOV
601
                        return false;
×
602
                }
603

604
                // Make sure customer is part of blog.
605
                if ( is_multisite() && ! is_user_member_of_blog( $id ) ) {
4✔
UNCOV
606
                        add_user_to_blog( get_current_blog_id(), $id, 'customer' );
×
607
                }
608

609
                return true;
4✔
610
        }
611

612
        /**
613
         * Purge object when creating.
614
         *
615
         * @param null|\WC_Order|\WPGraphQL\WooCommerce\Model\Order $order         Object data.
616
         * @param boolean                                           $force_delete  Delete or put in trash.
617
         *
618
         * @return bool
619
         * @throws \GraphQL\Error\UserError  Failed to delete order.
620
         */
621
        public static function purge( $order, $force_delete = true ) {
622
                if ( ! empty( $order ) ) {
1✔
623
                        return $order->delete( $force_delete );
1✔
624
                }
625

UNCOV
626
                return false;
×
627
        }
628
}
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