From d6ef041806aad7f5cc25d89ab996f976db2d946b Mon Sep 17 00:00:00 2001 From: Geoff Taylor Date: Wed, 10 Jul 2019 15:21:01 -0400 Subject: [PATCH] "deleteOrderItems" implemented and tested. --- includes/class-actions.php | 2 + .../mutation/class-order-delete-items.php | 159 ++++++++++++++++++ .../mutation/class-order-update-items.php | 0 tests/wpunit/OrderMutationsTest.php | 155 +++++++++++++++++ vendor/composer/autoload_classmap.php | 1 + vendor/composer/autoload_static.php | 1 + 6 files changed, 318 insertions(+) delete mode 100644 includes/mutation/class-order-update-items.php diff --git a/includes/class-actions.php b/includes/class-actions.php index 7c76900dd..023c7e8c2 100644 --- a/includes/class-actions.php +++ b/includes/class-actions.php @@ -77,6 +77,7 @@ use WPGraphQL\Extensions\WooCommerce\Mutation\Order_Create; use WPGraphQL\Extensions\WooCommerce\Mutation\Order_Update; use WPGraphQL\Extensions\WooCommerce\Mutation\Order_Delete; +use WPGraphQL\Extensions\WooCommerce\Mutation\Order_Delete_Items; use WPGraphQL\Extensions\WooCommerce\Mutation\Checkout; /** @@ -176,6 +177,7 @@ public static function graphql_register_types() { Order_Create::register_mutation(); Order_Update::register_mutation(); Order_Delete::register_mutation(); + Order_Delete_Items::register_mutation(); Checkout::register_mutation(); } } diff --git a/includes/mutation/class-order-delete-items.php b/includes/mutation/class-order-delete-items.php index e69de29bb..00d12d26c 100644 --- a/includes/mutation/class-order-delete-items.php +++ b/includes/mutation/class-order-delete-items.php @@ -0,0 +1,159 @@ + self::get_input_fields(), + 'outputFields' => self::get_output_fields(), + 'mutateAndGetPayload' => self::mutate_and_get_payload(), + ) + ); + } + + /** + * Defines the mutation input field configuration + * + * @return array + */ + public static function get_input_fields() { + $input_fields = array_merge( + array( + 'id' => array( + 'type' => 'ID', + 'description' => __( 'Order global ID', 'wp-graphql-woocommerce' ), + ), + 'orderId' => array( + 'type' => 'Int', + 'description' => __( 'Order WP ID', 'wp-graphql-woocommerce' ), + ), + 'itemIds' => array( + 'type' => array( 'list_of' => 'Int' ), + 'description' => __( 'ID Order items being deleted', 'wp-graphql-woocommerce' ), + ), + ) + ); + + return $input_fields; + } + + /** + * Defines the mutation output field configuration + * + * @return array + */ + public static function get_output_fields() { + return array( + 'order' => array( + 'type' => 'Order', + 'resolve' => function( $payload ) { + return $payload['order']; + }, + ), + ); + } + + /** + * Defines the mutation data modification closure. + * + * @return callable + */ + public static function mutate_and_get_payload() { + return function( $input, AppContext $context, ResolveInfo $info ) { + if ( Order_Mutation::authorized( 'delete', $input, $context, $info ) ) { + throw new UserError( __( 'User does not have the capabilities necessary to delete an order.', 'wp-graphql-woocommerce' ) ); + } + + // Retrieve order ID. + $order_id = null; + if ( ! empty( $input['id'] ) ) { + $id_components = Relay::fromGlobalId( $input['id'] ); + if ( empty( $id_components['id'] ) || empty( $id_components['type'] ) ) { + throw new UserError( __( 'The "id" provided is invalid', 'wp-graphql-woocommerce' ) ); + } + $order_id = absint( $id_components['id'] ); + } elseif ( ! empty( $input['orderId'] ) ) { + $order_id = absint( $input['orderId'] ); + } else { + throw new UserError( __( 'No order ID provided.', 'wp-graphql-woocommerce' ) ); + } + + // Confirm item IDs. + if ( empty( $input['itemIds'] ) ) { + throw new UserError( __( 'No item IDs provided.', 'wp-graphql-woocommerce' ) ); + } elseif ( ! is_array( $input['itemIds'] ) ) { + throw new UserError( __( 'The "itemIds" provided is invalid', 'wp-graphql-woocommerce' ) ); + } + $ids = $input['itemIds']; + + // Get Order model instance for output. + $order = new Order( $order_id ); + + // Cache items to prevent null value errors. + // @codingStandardsIgnoreStart + $order->downloadableItems; + $order->get_items(); + $order->get_items( 'fee' ); + $order->get_items( 'shipping' ); + $order->get_items( 'tax' ); + $order->get_items( 'coupon' ); + // @codingStandardsIgnoreEnd. + + // Get working order model. + $working_order = new Order( $order_id ); + + /** + * Action called before order is deleted. + * + * @param WC_Order $order WC_Order instance. + * @param array $input Input data describing order. + * @param AppContext $context Request AppContext instance. + * @param ResolveInfo $info Request ResolveInfo instance. + */ + do_action( 'woocommerce_graphql_before_order_items_delete', $ids, $working_order, $input, $context, $info ); + + // Delete order. + $errors = ''; + foreach ( $ids as $id ) { + $working_order->remove_item( $id ); + } + $working_order->save(); + + /** + * Action called before order is deleted. + * + * @param WC_Order $order WC_Order instance. + * @param array $input Input data describing order + * @param AppContext $context Request AppContext instance. + * @param ResolveInfo $info Request ResolveInfo instance. + */ + do_action( 'woocommerce_graphql_after_order_delete', $ids, $working_order, $input, $context, $info ); + + return array( 'order' => $order ); + }; + } +} diff --git a/includes/mutation/class-order-update-items.php b/includes/mutation/class-order-update-items.php deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/wpunit/OrderMutationsTest.php b/tests/wpunit/OrderMutationsTest.php index 0c2b20edc..b259f13cf 100644 --- a/tests/wpunit/OrderMutationsTest.php +++ b/tests/wpunit/OrderMutationsTest.php @@ -922,4 +922,159 @@ public function testDeleteOrderMutation() { $this->assertEquals( $initial_response['data']['createOrder'], $actual['data']['deleteOrder'] ); $this->assertFalse( \WC_Order_Factory::get_order( $order->get_id() ) ); } + + public function testDeleteOrderItemsMutation() { + // Create products and coupons to be used in order creation. + $variable = $this->variation->create( $this->product->create_variable() ); + $product_ids = array( + $this->product->create_simple(), + $this->product->create_simple(), + $variable['product'], + ); + $coupon = new WC_Coupon( + $this->coupon->create( array( 'product_ids' => $product_ids ) ) + ); + + // Create initial order input. + $initial_input = array( + 'clientMutationId' => 'someId', + 'customerId' => $this->customer, + 'customerNote' => 'Customer test note', + 'coupons' => array( + $coupon->get_code(), + ), + 'paymentMethod' => 'bacs', + 'paymentMethodTitle' => 'Direct Bank Transfer', + 'billing' => array( + 'firstName' => 'May', + 'lastName' => 'Parker', + 'address1' => '20 Ingram St', + 'city' => 'New York City', + 'state' => 'NY', + 'postcode' => '12345', + 'country' => 'US', + 'email' => 'superfreak500@gmail.com', + 'phone' => '555-555-1234', + ), + 'shipping' => array( + 'firstName' => 'May', + 'lastName' => 'Parker', + 'address1' => '20 Ingram St', + 'city' => 'New York City', + 'state' => 'NY', + 'postcode' => '12345', + 'country' => 'US', + ), + 'lineItems' => array( + array( + 'productId' => $product_ids[0], + 'quantity' => 5, + 'metaData' => array( + array( + 'key' => 'test_product_key', + 'value' => 'test product value', + ), + ), + ), + array( + 'productId' => $product_ids[1], + 'quantity' => 2, + ), + array( + 'productId' => $product_ids[2], + 'quantity' => 6, + 'variationId' => $variable['variations'][0] + ), + ), + 'shippingLines' => array( + array( + 'methodId' => 'flat_rate_shipping', + 'methodTitle' => 'Flat Rate shipping', + 'total' => '10', + ), + ), + 'feeLines' => array( + array( + 'name' => 'Some Fee', + 'taxStatus' => 'TAXABLE', + 'total' => '100', + 'taxClass' => 'STANDARD', + ), + ), + 'metaData' => array( + array( + 'key' => 'test_key', + 'value' => 'test value', + ), + ), + 'isPaid' => false, + ); + + // Create order to delete. + wp_set_current_user( $this->shop_manager ); + $initial_response = $this->orderMutation( $initial_input ); + + // use --debug flag to view. + codecept_debug( $initial_response ); + + // Clear loader cache. + $this->getModule('\Helper\Wpunit')->clear_loader_cache( 'wc_post_crud' ); + + // Retrieve order and items + $order_id = $initial_response['data']['createOrder']['order']['orderId']; + $order = \WC_Order_Factory::get_order( $order_id ); + $line_items = $order->get_items(); + $shipping_lines = $order->get_items( 'shipping' ); + $fee_lines = $order->get_items( 'fee' ); + $coupon_lines = $order->get_items( 'coupon' ); + $tax_lines = $order->get_items( 'tax' ); + + // Create DeleteOrderInput. + $deleted_items_input = array( + 'clientMutationId' => 'someId', + 'orderId' => $order->get_id(), + 'itemIds' => array( + current( $line_items )->get_id(), + current( $coupon_lines )->get_id(), + ), + ); + + /** + * Assertion One + * + * User without necessary capabilities cannot delete order an order. + */ + wp_set_current_user( $this->customer ); + $actual = $this->orderMutation( + $deleted_items_input, + 'deleteOrderItems', + 'DeleteOrderItemsInput' + ); + + // use --debug flag to view. + codecept_debug( $actual ); + + $this->assertArrayHasKey('errors', $actual ); + + /** + * Assertion Two + * + * Test mutation and input. + */ + wp_set_current_user( $this->shop_manager ); + $actual = $this->orderMutation( + $deleted_items_input, + 'deleteOrderItems', + 'DeleteOrderItemsInput' + ); + + // use --debug flag to view. + codecept_debug( $actual ); + + $this->assertArrayHasKey( 'data', $actual ); + $this->assertArrayHasKey( 'deleteOrderItems', $actual['data'] ); + $this->assertEquals( $initial_response['data']['createOrder'], $actual['data']['deleteOrderItems'] ); + $this->assertFalse( \WC_Order_Factory::get_order_item( current( $line_items ) ) ); + $this->assertFalse( \WC_Order_Factory::get_order_item( current( $coupon_lines ) ) ); + } } \ No newline at end of file diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 8f00419d6..ed319afe1 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -67,6 +67,7 @@ 'WPGraphQL\\Extensions\\WooCommerce\\Mutation\\Customer_Update' => $baseDir . '/includes/mutation/class-customer-update.php', 'WPGraphQL\\Extensions\\WooCommerce\\Mutation\\Order_Create' => $baseDir . '/includes/mutation/class-order-create.php', 'WPGraphQL\\Extensions\\WooCommerce\\Mutation\\Order_Delete' => $baseDir . '/includes/mutation/class-order-delete.php', + 'WPGraphQL\\Extensions\\WooCommerce\\Mutation\\Order_Delete_Items' => $baseDir . '/includes/mutation/class-order-delete-items.php', 'WPGraphQL\\Extensions\\WooCommerce\\Mutation\\Order_Update' => $baseDir . '/includes/mutation/class-order-update.php', 'WPGraphQL\\Extensions\\WooCommerce\\Type\\WPEnum\\Backorders' => $baseDir . '/includes/type/enum/class-backorders.php', 'WPGraphQL\\Extensions\\WooCommerce\\Type\\WPEnum\\Catalog_Visibility' => $baseDir . '/includes/type/enum/class-catalog-visibility.php', diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 660d341b3..8f28cc913 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -82,6 +82,7 @@ class ComposerStaticInitee0d17af17b841ed3a93c4a0e5cc5e5f 'WPGraphQL\\Extensions\\WooCommerce\\Mutation\\Customer_Update' => __DIR__ . '/../..' . '/includes/mutation/class-customer-update.php', 'WPGraphQL\\Extensions\\WooCommerce\\Mutation\\Order_Create' => __DIR__ . '/../..' . '/includes/mutation/class-order-create.php', 'WPGraphQL\\Extensions\\WooCommerce\\Mutation\\Order_Delete' => __DIR__ . '/../..' . '/includes/mutation/class-order-delete.php', + 'WPGraphQL\\Extensions\\WooCommerce\\Mutation\\Order_Delete_Items' => __DIR__ . '/../..' . '/includes/mutation/class-order-delete-items.php', 'WPGraphQL\\Extensions\\WooCommerce\\Mutation\\Order_Update' => __DIR__ . '/../..' . '/includes/mutation/class-order-update.php', 'WPGraphQL\\Extensions\\WooCommerce\\Type\\WPEnum\\Backorders' => __DIR__ . '/../..' . '/includes/type/enum/class-backorders.php', 'WPGraphQL\\Extensions\\WooCommerce\\Type\\WPEnum\\Catalog_Visibility' => __DIR__ . '/../..' . '/includes/type/enum/class-catalog-visibility.php',