Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Commit

Permalink
Sync order data with cart data when cart is updated from any route (#…
Browse files Browse the repository at this point in the history
…5379)

* Link order controller to cart routes

* Remove order controller from checkout route

* Fix PHP warnings in abstract schema

* Fix PHP warnings in abstract route

* Update shipping phone handling

* Includes are handled in core now

* Remove maybe_update_order_from_customer

* Add cart_updated routine to all cart routes

* Remove abstract method

* Remove test for woocommerce_blocks_cart_update_order_from_customer_request

* Remove do_order_callback
  • Loading branch information
mikejolley authored Dec 21, 2021
1 parent e50f2ce commit f8e1560
Show file tree
Hide file tree
Showing 11 changed files with 78 additions and 123 deletions.
6 changes: 3 additions & 3 deletions bin/hook-docs/data/actions.json
Original file line number Diff line number Diff line change
Expand Up @@ -268,11 +268,11 @@
}
},
{
"name": "woocommerce_blocks_cart_update_order_from_customer_request",
"file": "StoreApi/Routes/CartUpdateCustomer.php",
"name": "woocommerce_blocks_cart_update_order_from_request",
"file": "StoreApi/Routes/AbstractCartRoute.php",
"type": "action",
"doc": {
"description": "Fires when the Checkout Block/Store API updates an existing draft order from customer data.",
"description": "Fires when the order is synced with cart data from a cart route.",
"long_description": "",
"tags": [
{
Expand Down
10 changes: 5 additions & 5 deletions docs/extensibility/actions.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
- [woocommerce_blocks_cart_enqueue_data](#woocommerce_blocks_cart_enqueue_data)
- [woocommerce_blocks_cart_enqueue_data](#woocommerce_blocks_cart_enqueue_data-1)
- [woocommerce_blocks_cart_update_customer_from_request](#woocommerce_blocks_cart_update_customer_from_request)
- [woocommerce_blocks_cart_update_order_from_customer_request](#woocommerce_blocks_cart_update_order_from_customer_request)
- [woocommerce_blocks_cart_update_order_from_request](#woocommerce_blocks_cart_update_order_from_request)
- [woocommerce_blocks_checkout_enqueue_data](#woocommerce_blocks_checkout_enqueue_data)
- [woocommerce_blocks_checkout_order_processed](#woocommerce_blocks_checkout_order_processed)
- [woocommerce_blocks_checkout_update_order_from_request](#woocommerce_blocks_checkout_update_order_from_request)
Expand Down Expand Up @@ -261,13 +261,13 @@ File: [StoreApi/Routes/CartUpdateCustomer.php](../src/StoreApi/Routes/CartUpdate

---

## woocommerce_blocks_cart_update_order_from_customer_request
## woocommerce_blocks_cart_update_order_from_request


Fires when the Checkout Block/Store API updates an existing draft order from customer data.
Fires when the order is synced with cart data from a cart route.

```php
do_action( 'woocommerce_blocks_cart_update_order_from_customer_request', \WC_Order $draft_order, \WC_Customer $customer, \WP_REST_Request $request )
do_action( 'woocommerce_blocks_cart_update_order_from_request', \WC_Order $draft_order, \WC_Customer $customer, \WP_REST_Request $request )
```

### Parameters
Expand All @@ -281,7 +281,7 @@ do_action( 'woocommerce_blocks_cart_update_order_from_customer_request', \WC_Ord
### Source


File: [StoreApi/Routes/CartUpdateCustomer.php](../src/StoreApi/Routes/CartUpdateCustomer.php)
File: [StoreApi/Routes/AbstractCartRoute.php](../src/StoreApi/Routes/AbstractCartRoute.php)

---

Expand Down
53 changes: 45 additions & 8 deletions src/StoreApi/Routes/AbstractCartRoute.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
use Automattic\WooCommerce\Blocks\StoreApi\Schemas\AbstractSchema;
use Automattic\WooCommerce\Blocks\StoreApi\Schemas\CartSchema;
use Automattic\WooCommerce\Blocks\StoreApi\Utilities\CartController;

use Automattic\WooCommerce\Blocks\StoreApi\Utilities\DraftOrderTrait;
use Automattic\WooCommerce\Blocks\StoreApi\Utilities\OrderController;
/**
* Abstract Cart Route
*
* @internal This API is used internally by Blocks--it is still in flux and may be subject to revisions.
*/
abstract class AbstractCartRoute extends AbstractRoute {
use DraftOrderTrait;

/**
* Schema class for this route's response.
*
Expand All @@ -32,18 +35,27 @@ abstract class AbstractCartRoute extends AbstractRoute {
*/
protected $cart_controller;

/**
* Order controller class instance.
*
* @var OrderController
*/
protected $order_controller;

/**
* Constructor accepts two types of schema; one for the item being returned, and one for the cart as a whole. These
* may be the same depending on the route.
*
* @param CartSchema $cart_schema Schema class for the cart.
* @param AbstractSchema $item_schema Schema class for this route's items if it differs from the cart schema.
* @param CartController $cart_controller Cart controller class.
* @param CartSchema $cart_schema Schema class for the cart.
* @param AbstractSchema $item_schema Schema class for this route's items if it differs from the cart schema.
* @param CartController $cart_controller Cart controller class.
* @param OrderController $order_controller Order controller class.
*/
public function __construct( CartSchema $cart_schema, AbstractSchema $item_schema = null, CartController $cart_controller ) {
$this->schema = is_null( $item_schema ) ? $cart_schema : $item_schema;
$this->cart_schema = $cart_schema;
$this->cart_controller = $cart_controller;
public function __construct( CartSchema $cart_schema, AbstractSchema $item_schema = null, CartController $cart_controller, OrderController $order_controller ) {
$this->schema = is_null( $item_schema ) ? $cart_schema : $item_schema;
$this->cart_schema = $cart_schema;
$this->cart_controller = $cart_controller;
$this->order_controller = $order_controller;
}

/**
Expand Down Expand Up @@ -74,6 +86,8 @@ public function get_response( \WP_REST_Request $request ) {

if ( is_wp_error( $response ) ) {
$response = $this->error_to_response( $response );
} elseif ( in_array( $request->get_method(), [ 'POST', 'PUT', 'PATCH', 'DELETE' ], true ) ) {
$this->cart_updated( $request );
}

return $this->add_nonce_headers( $response );
Expand Down Expand Up @@ -102,6 +116,29 @@ protected function requires_nonce( \WP_REST_Request $request ) {
return 'GET' !== $request->get_method();
}

/**
* Triggered after an update to cart data. Re-calculates totals and updates draft orders (if they already exist) to
* keep all data in sync.
*
* @param \WP_REST_Request $request Request object.
*/
protected function cart_updated( \WP_REST_Request $request ) {
$draft_order = $this->get_draft_order();

if ( $draft_order ) {
$this->order_controller->update_order_from_cart( $draft_order );

/**
* Fires when the order is synced with cart data from a cart route.
*
* @param \WC_Order $draft_order Order object.
* @param \WC_Customer $customer Customer object.
* @param \WP_REST_Request $request Full details about the request.
*/
do_action( 'woocommerce_blocks_cart_update_order_from_request', $draft_order, $request );
}
}

/**
* Ensures the cart totals are calculated before an API response is generated.
*/
Expand Down
4 changes: 2 additions & 2 deletions src/StoreApi/Routes/AbstractRoute.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ public function get_response( \WP_REST_Request $request ) {
/**
* Converts an error to a response object. Based on \WP_REST_Server.
*
* @param WP_Error $error WP_Error instance.
* @return WP_REST_Response List of associative arrays with code and message keys.
* @param \WP_Error $error WP_Error instance.
* @return \WP_REST_Response List of associative arrays with code and message keys.
*/
protected function error_to_response( $error ) {
$error_data = $error->get_error_data();
Expand Down
53 changes: 0 additions & 53 deletions src/StoreApi/Routes/CartUpdateCustomer.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ protected function get_route_post_response( \WP_REST_Request $request ) {
$customer->save();

$this->calculate_totals();
$this->maybe_update_order_from_customer( $customer, $request );

return rest_ensure_response( $this->schema->get_item_response( $cart ) );
}
Expand All @@ -146,56 +145,4 @@ protected function get_customer_billing_address( \WC_Customer $customer ) {
'phone' => $customer->get_billing_phone(),
];
}

/**
* If there is a draft order, update the customer data within that also so the
* cart and order are kept in sync.
*
* @param \WC_Customer $customer Customer object.
* @param \WP_REST_Request $request Request object.
*/
protected function maybe_update_order_from_customer( \WC_Customer $customer, \WP_REST_Request $request ) {
$draft_order = $this->get_draft_order();

if ( ! $draft_order ) {
return;
}

$draft_order->set_props(
[
'billing_first_name' => $customer->get_billing_first_name(),
'billing_last_name' => $customer->get_billing_last_name(),
'billing_company' => $customer->get_billing_company(),
'billing_address_1' => $customer->get_billing_address_1(),
'billing_address_2' => $customer->get_billing_address_2(),
'billing_city' => $customer->get_billing_city(),
'billing_state' => $customer->get_billing_state(),
'billing_postcode' => $customer->get_billing_postcode(),
'billing_country' => $customer->get_billing_country(),
'billing_email' => $customer->get_billing_email(),
'billing_phone' => $customer->get_billing_phone(),
'shipping_first_name' => $customer->get_shipping_first_name(),
'shipping_last_name' => $customer->get_shipping_last_name(),
'shipping_company' => $customer->get_shipping_company(),
'shipping_address_1' => $customer->get_shipping_address_1(),
'shipping_address_2' => $customer->get_shipping_address_2(),
'shipping_city' => $customer->get_shipping_city(),
'shipping_state' => $customer->get_shipping_state(),
'shipping_postcode' => $customer->get_shipping_postcode(),
'shipping_country' => $customer->get_shipping_country(),
'shipping_phone' => $customer->get_shipping_phone(),
]
);

/**
* Fires when the Checkout Block/Store API updates an existing draft order from customer data.
*
* @param \WC_Order $draft_order Order object.
* @param \WC_Customer $customer Customer object.
* @param \WP_REST_Request $request Full details about the request.
*/
do_action( 'woocommerce_blocks_cart_update_order_from_customer_request', $draft_order, $customer, $request );

$draft_order->save();
}
}
24 changes: 0 additions & 24 deletions src/StoreApi/Routes/Checkout.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
use Automattic\WooCommerce\Blocks\StoreApi\Utilities\OrderController;
use Automattic\WooCommerce\Checkout\Helpers\ReserveStock;
use Automattic\WooCommerce\Checkout\Helpers\ReserveStockException;

/**
* Checkout class.
*
Expand All @@ -29,29 +28,6 @@ class Checkout extends AbstractCartRoute {
*/
private $order = null;

/**
* Order controller class instance.
*
* @var OrderController
*/
protected $order_controller;

/**
* Constructor accepts two types of schema; one for the item being returned, and one for the cart as a whole. These
* may be the same depending on the route.
*
* @param CartSchema $cart_schema Schema class for the cart.
* @param AbstractSchema $item_schema Schema class for this route's items if it differs from the cart schema.
* @param CartController $cart_controller Cart controller class.
* @param OrderController $order_controller Order controller class.
*/
public function __construct( CartSchema $cart_schema, AbstractSchema $item_schema = null, CartController $cart_controller, OrderController $order_controller ) {
$this->schema = is_null( $item_schema ) ? $cart_schema : $item_schema;
$this->cart_schema = $cart_schema;
$this->cart_controller = $cart_controller;
$this->order_controller = $order_controller;
}

/**
* Get the path of this REST route.
*
Expand Down
26 changes: 13 additions & 13 deletions src/StoreApi/RoutesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,19 +75,19 @@ protected function initialize() {
$order_controller = new OrderController();

$this->routes = [
'cart' => new Routes\Cart( $this->schemas->get( 'cart' ), null, $cart_controller ),
'cart-add-item' => new Routes\CartAddItem( $this->schemas->get( 'cart' ), null, $cart_controller ),
'cart-apply-coupon' => new Routes\CartApplyCoupon( $this->schemas->get( 'cart' ), null, $cart_controller ),
'cart-coupons' => new Routes\CartCoupons( $this->schemas->get( 'cart' ), $this->schemas->get( 'cart-coupon' ), $cart_controller ),
'cart-coupons-by-code' => new Routes\CartCouponsByCode( $this->schemas->get( 'cart' ), $this->schemas->get( 'cart-coupon' ), $cart_controller ),
'cart-extensions' => new Routes\CartExtensions( $this->schemas->get( 'cart' ), $this->schemas->get( 'cart-extensions' ), $cart_controller ),
'cart-items' => new Routes\CartItems( $this->schemas->get( 'cart' ), $this->schemas->get( 'cart-item' ), $cart_controller ),
'cart-items-by-key' => new Routes\CartItemsByKey( $this->schemas->get( 'cart' ), $this->schemas->get( 'cart-item' ), $cart_controller ),
'cart-remove-coupon' => new Routes\CartRemoveCoupon( $this->schemas->get( 'cart' ), null, $cart_controller ),
'cart-remove-item' => new Routes\CartRemoveItem( $this->schemas->get( 'cart' ), null, $cart_controller ),
'cart-select-shipping-rate' => new Routes\CartSelectShippingRate( $this->schemas->get( 'cart' ), null, $cart_controller ),
'cart-update-item' => new Routes\CartUpdateItem( $this->schemas->get( 'cart' ), null, $cart_controller ),
'cart-update-customer' => new Routes\CartUpdateCustomer( $this->schemas->get( 'cart' ), null, $cart_controller ),
'cart' => new Routes\Cart( $this->schemas->get( 'cart' ), null, $cart_controller, $order_controller ),
'cart-add-item' => new Routes\CartAddItem( $this->schemas->get( 'cart' ), null, $cart_controller, $order_controller ),
'cart-apply-coupon' => new Routes\CartApplyCoupon( $this->schemas->get( 'cart' ), null, $cart_controller, $order_controller ),
'cart-coupons' => new Routes\CartCoupons( $this->schemas->get( 'cart' ), $this->schemas->get( 'cart-coupon' ), $cart_controller, $order_controller ),
'cart-coupons-by-code' => new Routes\CartCouponsByCode( $this->schemas->get( 'cart' ), $this->schemas->get( 'cart-coupon' ), $cart_controller, $order_controller ),
'cart-extensions' => new Routes\CartExtensions( $this->schemas->get( 'cart' ), $this->schemas->get( 'cart-extensions' ), $cart_controller, $order_controller ),
'cart-items' => new Routes\CartItems( $this->schemas->get( 'cart' ), $this->schemas->get( 'cart-item' ), $cart_controller, $order_controller ),
'cart-items-by-key' => new Routes\CartItemsByKey( $this->schemas->get( 'cart' ), $this->schemas->get( 'cart-item' ), $cart_controller, $order_controller ),
'cart-remove-coupon' => new Routes\CartRemoveCoupon( $this->schemas->get( 'cart' ), null, $cart_controller, $order_controller ),
'cart-remove-item' => new Routes\CartRemoveItem( $this->schemas->get( 'cart' ), null, $cart_controller, $order_controller ),
'cart-select-shipping-rate' => new Routes\CartSelectShippingRate( $this->schemas->get( 'cart' ), null, $cart_controller, $order_controller ),
'cart-update-item' => new Routes\CartUpdateItem( $this->schemas->get( 'cart' ), null, $cart_controller, $order_controller ),
'cart-update-customer' => new Routes\CartUpdateCustomer( $this->schemas->get( 'cart' ), null, $cart_controller, $order_controller ),
'checkout' => new Routes\Checkout( $this->schemas->get( 'cart' ), $this->schemas->get( 'checkout' ), $cart_controller, $order_controller ),
'product-attributes' => new Routes\ProductAttributes( $this->schemas->get( 'product-attribute' ) ),
'product-attributes-by-id' => new Routes\ProductAttributesById( $this->schemas->get( 'product-attribute' ) ),
Expand Down
11 changes: 9 additions & 2 deletions src/StoreApi/Schemas/AbstractSchema.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<?php
namespace Automattic\WooCommerce\Blocks\StoreApi\Schemas;

use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Domain\Services\ExtendRestApi;

/**
* AbstractSchema class.
*
Expand Down Expand Up @@ -56,6 +56,13 @@ public function get_item_schema() {
);
}

/**
* Return schema properties.
*
* @return array
*/
abstract public function get_properties();

/**
* Recursive removal of arg_options.
*
Expand Down Expand Up @@ -94,7 +101,7 @@ public function get_public_item_schema() {
/**
* Returns extended data for a specific endpoint.
*
* @param string $endpoint The endpoint identifer.
* @param string $endpoint The endpoint identifier.
* @param array ...$passed_args An array of arguments to be passed to callbacks.
* @return object the data that will get added.
*/
Expand Down
2 changes: 0 additions & 2 deletions src/StoreApi/Utilities/CartController.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ class CartController {
*/
public function load_cart() {
if ( ! did_action( 'woocommerce_load_cart_from_session' ) && function_exists( 'wc_load_cart' ) ) {
include_once WC_ABSPATH . 'includes/wc-cart-functions.php';
include_once WC_ABSPATH . 'includes/wc-notice-functions.php';
wc_load_cart();
}
}
Expand Down
9 changes: 1 addition & 8 deletions src/StoreApi/Utilities/OrderController.php
Original file line number Diff line number Diff line change
Expand Up @@ -505,15 +505,8 @@ protected function update_addresses_from_cart( \WC_Order $order ) {
'shipping_state' => wc()->customer->get_shipping_state(),
'shipping_postcode' => wc()->customer->get_shipping_postcode(),
'shipping_country' => wc()->customer->get_shipping_country(),
'shipping_phone' => wc()->customer->get_shipping_phone(),
]
);

$shipping_phone_value = is_callable( [ wc()->customer, 'get_shipping_phone' ] ) ? wc()->customer->get_shipping_phone() : wc()->customer->get_meta( 'shipping_phone', true );

if ( is_callable( [ $order, 'set_shipping_phone' ] ) ) {
$order->set_shipping_phone( $shipping_phone_value );
} else {
$order->update_meta_data( '_shipping_phone', $shipping_phone_value );
}
}
}
3 changes: 0 additions & 3 deletions tests/php/StoreApi/Routes/Cart.php
Original file line number Diff line number Diff line change
Expand Up @@ -188,16 +188,13 @@ public function test_update_customer() {

$action_callback = \Mockery::mock( 'ActionCallback' );
$action_callback->shouldReceive( 'do_customer_callback' )->once();
$action_callback->shouldReceive( 'do_order_callback' )->once();

add_action( 'woocommerce_blocks_cart_update_customer_from_request', array( $action_callback, 'do_customer_callback' ) );
add_action( 'woocommerce_blocks_cart_update_order_from_customer_request', array( $action_callback, 'do_order_callback' ) );

$response = rest_get_server()->dispatch( $request );
$data = $response->get_data();

remove_action( 'woocommerce_blocks_cart_update_customer_from_request', array( $action_callback, 'do_customer_callback' ) );
remove_action( 'woocommerce_blocks_cart_update_order_from_customer_request', array( $action_callback, 'do_order_callback' ) );

$this->assertEquals( 200, $response->get_status(), print_r( $response, true ) );
$this->assertArrayHasKey( 'shipping_rates', $data );
Expand Down

0 comments on commit f8e1560

Please sign in to comment.