From 399ef81b111bcd02b7102e14fed50b86c459e4d7 Mon Sep 17 00:00:00 2001 From: Taha Paksu <3295+tpaksu@users.noreply.github.com> Date: Tue, 15 Jun 2021 21:02:14 +0300 Subject: [PATCH] Fix currency display errors in homescreen order activity card (https://github.com/woocommerce/woocommerce-admin/pull/7181) --- .../homescreen/activity-panel/orders/index.js | 7 +- plugins/woocommerce-admin/readme.txt | 1 + .../src/API/Reports/Controller.php | 21 ++++++ .../src/API/Reports/Orders/Controller.php | 51 ++++++++------ .../tests/api/reports-orders.php | 70 ++++++++++++++++++- 5 files changed, 123 insertions(+), 27 deletions(-) diff --git a/plugins/woocommerce-admin/client/homescreen/activity-panel/orders/index.js b/plugins/woocommerce-admin/client/homescreen/activity-panel/orders/index.js index 9cffa3987d0..025395b5eb5 100644 --- a/plugins/woocommerce-admin/client/homescreen/activity-panel/orders/index.js +++ b/plugins/woocommerce-admin/client/homescreen/activity-panel/orders/index.js @@ -71,7 +71,6 @@ class OrdersPanel extends Component { renderOrders() { const { orders } = this.props; - const Currency = this.context; if ( orders.length === 0 ) { return this.renderEmptyCard(); @@ -158,15 +157,12 @@ class OrdersPanel extends Component { date_created_gmt: dateCreatedGmt, extended_info: extendedInfo, order_id: orderId, - total_sales: totalSales, } = order; const productsCount = extendedInfo && extendedInfo.products ? extendedInfo.products.length : 0; - const total = totalSales; - cards.push( - { Currency.formatAmount( total ) } + { order.total_formatted } } > @@ -347,6 +343,7 @@ export default withSelect( ( select, props ) => { 'order_number', 'status', 'total_sales', + 'total_formatted', 'extended_info.customer', 'extended_info.products', ], diff --git a/plugins/woocommerce-admin/readme.txt b/plugins/woocommerce-admin/readme.txt index 490316cdf8b..b62c8d05a6a 100644 --- a/plugins/woocommerce-admin/readme.txt +++ b/plugins/woocommerce-admin/readme.txt @@ -81,6 +81,7 @@ Release and roadmap notes are available on the [WooCommerce Developers Blog](htt - Fix: Include onboarding settings on the analytic pages #7109 - Fix: RemoteFreeExtension hide bundle when all of its plugins are not visible #7182 - Tweak: Revert Card component removal #7167 +- Fix: Currency display on Orders activity card on homescreen #7181 == 2.4.0 6/10/2021 == - Dev: Reduce the specificity and complexity of the ReportError component #6846 diff --git a/plugins/woocommerce-admin/src/API/Reports/Controller.php b/plugins/woocommerce-admin/src/API/Reports/Controller.php index 66a8b8640f8..1c1270a27dc 100644 --- a/plugins/woocommerce-admin/src/API/Reports/Controller.php +++ b/plugins/woocommerce-admin/src/API/Reports/Controller.php @@ -205,6 +205,27 @@ class Controller extends \WC_REST_Reports_Controller { return $order->get_order_number(); } + /** + * Get the order total with the related currency formatting. + * Returns the parent order total if the order is actually a refund. + * + * @param int $order_id Order ID. + * @return string + */ + public function get_total_formatted( $order_id ) { + $order = wc_get_order( $order_id ); + + if ( ! $order instanceof \WC_Order && ! $order instanceof \WC_Order_Refund ) { + return null; + } + + if ( 'shop_order_refund' === $order->get_type() ) { + $order = wc_get_order( $order->get_parent_id() ); + } + + return wp_strip_all_tags( html_entity_decode( $order->get_formatted_order_total() ), true ); + } + /** * Prepare a report object for serialization. * diff --git a/plugins/woocommerce-admin/src/API/Reports/Orders/Controller.php b/plugins/woocommerce-admin/src/API/Reports/Orders/Controller.php index fe858d71381..249aef7bf07 100644 --- a/plugins/woocommerce-admin/src/API/Reports/Orders/Controller.php +++ b/plugins/woocommerce-admin/src/API/Reports/Orders/Controller.php @@ -83,9 +83,10 @@ class Controller extends ReportsController implements ExportableInterface { $data = array(); foreach ( $report_data->data as $orders_data ) { - $orders_data['order_number'] = $this->get_order_number( $orders_data['order_id'] ); - $item = $this->prepare_item_for_response( $orders_data, $request ); - $data[] = $this->prepare_response_for_collection( $item ); + $orders_data['order_number'] = $this->get_order_number( $orders_data['order_id'] ); + $orders_data['total_formatted'] = $this->get_total_formatted( $orders_data['order_id'] ); + $item = $this->prepare_item_for_response( $orders_data, $request ); + $data[] = $this->prepare_response_for_collection( $item ); } $response = rest_ensure_response( $data ); @@ -217,6 +218,12 @@ class Controller extends ReportsController implements ExportableInterface { 'context' => array( 'view', 'edit' ), 'readonly' => true, ), + 'total_formatted' => array( + 'description' => __( 'Net total revenue (formatted).', 'woocommerce-admin' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), 'customer_type' => array( 'description' => __( 'Returning or new customer.', 'woocommerce-admin' ), 'type' => 'string', @@ -523,15 +530,16 @@ class Controller extends ReportsController implements ExportableInterface { */ public function get_export_columns() { $export_columns = array( - 'date_created' => __( 'Date', 'woocommerce-admin' ), - 'order_number' => __( 'Order #', 'woocommerce-admin' ), - 'status' => __( 'Status', 'woocommerce-admin' ), - 'customer_name' => __( 'Customer', 'woocommerce-admin' ), - 'customer_type' => __( 'Customer Type', 'woocommerce-admin' ), - 'products' => __( 'Product(s)', 'woocommerce-admin' ), - 'num_items_sold' => __( 'Items Sold', 'woocommerce-admin' ), - 'coupons' => __( 'Coupon(s)', 'woocommerce-admin' ), - 'net_total' => __( 'N. Revenue', 'woocommerce-admin' ), + 'date_created' => __( 'Date', 'woocommerce-admin' ), + 'order_number' => __( 'Order #', 'woocommerce-admin' ), + 'total_formatted' => __( 'N. Revenue (Formatted)', 'woocommerce-admin' ), + 'status' => __( 'Status', 'woocommerce-admin' ), + 'customer_name' => __( 'Customer', 'woocommerce-admin' ), + 'customer_type' => __( 'Customer Type', 'woocommerce-admin' ), + 'products' => __( 'Product(s)', 'woocommerce-admin' ), + 'num_items_sold' => __( 'Items Sold', 'woocommerce-admin' ), + 'coupons' => __( 'Coupon(s)', 'woocommerce-admin' ), + 'net_total' => __( 'N. Revenue', 'woocommerce-admin' ), ); /** @@ -554,15 +562,16 @@ class Controller extends ReportsController implements ExportableInterface { */ public function prepare_item_for_export( $item ) { $export_item = array( - 'date_created' => $item['date_created'], - 'order_number' => $item['order_number'], - 'status' => $item['status'], - 'customer_name' => isset( $item['extended_info']['customer'] ) ? $this->get_customer_name( $item['extended_info']['customer'] ) : null, - 'customer_type' => $item['customer_type'], - 'products' => isset( $item['extended_info']['products'] ) ? $this->_get_products( $item['extended_info']['products'] ) : null, - 'num_items_sold' => $item['num_items_sold'], - 'coupons' => isset( $item['extended_info']['coupons'] ) ? $this->_get_coupons( $item['extended_info']['coupons'] ) : null, - 'net_total' => $item['net_total'], + 'date_created' => $item['date_created'], + 'order_number' => $item['order_number'], + 'total_formatted' => $item['total_formatted'], + 'status' => $item['status'], + 'customer_name' => isset( $item['extended_info']['customer'] ) ? $this->get_customer_name( $item['extended_info']['customer'] ) : null, + 'customer_type' => $item['customer_type'], + 'products' => isset( $item['extended_info']['products'] ) ? $this->_get_products( $item['extended_info']['products'] ) : null, + 'num_items_sold' => $item['num_items_sold'], + 'coupons' => isset( $item['extended_info']['coupons'] ) ? $this->_get_coupons( $item['extended_info']['coupons'] ) : null, + 'net_total' => $item['net_total'], ); /** diff --git a/plugins/woocommerce-admin/tests/api/reports-orders.php b/plugins/woocommerce-admin/tests/api/reports-orders.php index fa50f8413f1..db9198da059 100644 --- a/plugins/woocommerce-admin/tests/api/reports-orders.php +++ b/plugins/woocommerce-admin/tests/api/reports-orders.php @@ -116,7 +116,7 @@ class WC_Tests_API_Reports_Orders extends WC_REST_Unit_Test_Case { $data = $response->get_data(); $properties = $data['schema']['properties']; - $this->assertEquals( 10, count( $properties ) ); + $this->assertEquals( 11, count( $properties ) ); $this->assertArrayHasKey( 'date_created_gmt', $properties ); $this->assertArrayHasKey( 'order_id', $properties ); $this->assertArrayHasKey( 'order_number', $properties ); @@ -125,6 +125,7 @@ class WC_Tests_API_Reports_Orders extends WC_REST_Unit_Test_Case { $this->assertArrayHasKey( 'customer_id', $properties ); $this->assertArrayHasKey( 'net_total', $properties ); $this->assertArrayHasKey( 'num_items_sold', $properties ); + $this->assertArrayHasKey( 'total_formatted', $properties ); $this->assertArrayHasKey( 'customer_type', $properties ); $this->assertArrayHasKey( 'extended_info', $properties ); } @@ -406,4 +407,71 @@ class WC_Tests_API_Reports_Orders extends WC_REST_Unit_Test_Case { $this->assertEquals( 1, count( $response_orders ) ); $this->assertEquals( $response_orders[0]['order_id'], $order_to_be_excluded->get_id() ); } + + /** + * Test filtering by product/variation exclusion. + * + * See: https://github.com/woocommerce/woocommerce-admin/issues/5803#issuecomment-738403405. + */ + public function test_order_price_formatting_with_different_base_currency() { + wp_set_current_user( $this->user ); + WC_Helper_Reports::reset_stats_dbs(); + + // Create a simple order with the base currency. + $first_simple_product = WC_Helper_Product::create_simple_product(); + $first_order = WC_Helper_Order::create_order( $this->user, $first_simple_product ); + $first_order->set_currency( get_woocommerce_currency() ); + $first_order->set_status( 'on-hold' ); + $first_order->save(); + + // Create another simple order with another currency. + $currencies = get_woocommerce_currencies(); + // prevent base currency to be selected again + unset( $currencies[ get_woocommerce_currency() ] ); + $second_currency = array_rand( $currencies ); + + $second_simple_product = WC_Helper_Product::create_simple_product(); + $second_order = WC_Helper_Order::create_order( $this->user, $second_simple_product ); + $second_order->set_currency( $second_currency ); + $second_order->set_status( 'on-hold' ); + $second_order->save(); + + WC_Helper_Queue::run_all_pending(); + + // Get the created orders from REST API + $request = new WP_REST_Request( 'GET', $this->endpoint ); + $request->set_query_params( + array( + 'order_status' => array( 'on-hold' ), + ) + ); + $response = $this->server->dispatch( $request ); + $response_orders = $response->get_data(); + + $this->assertCount( 2, $response_orders ); + + // Replace keys with "order_id". + $response_orders = array_reduce( + $response_orders, + function ( array $result, $item ) { + $result[ $item['order_id'] ] = $item; + return $result; + }, + array() + ); + + // Check if result has the correct orders. + $this->assertArrayHasKey( $first_order->get_id(), $response_orders ); + $this->assertArrayHasKey( $second_order->get_id(), $response_orders ); + + // Check if result orders have the correct formatted totals. + $first_order_from_response = $response_orders[ $first_order->get_id() ]; + $first_order_formatted_total = wp_strip_all_tags( html_entity_decode( $first_order->get_formatted_order_total() ), true ); + $this->assertEquals( $first_order_from_response['total_formatted'], $first_order_formatted_total ); + + $second_order_from_response = $response_orders[ $second_order->get_id() ]; + $second_order_formatted_total = wp_strip_all_tags( html_entity_decode( $second_order->get_formatted_order_total() ), true ); + $this->assertEquals( $second_order_from_response['total_formatted'], $second_order_formatted_total ); + + } }