Remove customer analytics data upon order deletion (https://github.com/woocommerce/woocommerce-admin/pull/5171)
This deletes the associated customer record when an order is deleted, provided that this is the only order for the customer.
This commit is contained in:
parent
4d0e062ee1
commit
f08ccc57d7
|
@ -85,6 +85,7 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
public static function init() {
|
||||
add_action( 'edit_user_profile_update', array( __CLASS__, 'update_registered_customer' ) );
|
||||
add_action( 'updated_user_meta', array( __CLASS__, 'update_registered_customer_via_last_active' ), 10, 3 );
|
||||
add_action( 'woocommerce_analytics_delete_order_stats', array( __CLASS__, 'sync_on_order_delete' ), 15, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -101,6 +102,30 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync customers data after an order was deleted.
|
||||
*
|
||||
* When an order is deleted, the customer record is deleted from the
|
||||
* table if the customer has no other orders.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @param int $customer_id Customer ID.
|
||||
*/
|
||||
public static function sync_on_order_delete( $order_id, $customer_id ) {
|
||||
$customer_id = absint( $customer_id );
|
||||
|
||||
if ( 0 === $customer_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate the amount of orders remaining for this customer.
|
||||
$order_count = self::get_order_count( $customer_id );
|
||||
|
||||
if ( 0 === $order_count ) {
|
||||
self::delete_customer( $customer_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps ordering specified by the user to columns in the database/fields in the data.
|
||||
*
|
||||
|
@ -572,6 +597,34 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the amount of orders made by a customer.
|
||||
*
|
||||
* @param int $customer_id Customer ID.
|
||||
* @return int|null Amount of orders for customer or null on failure.
|
||||
*/
|
||||
public static function get_order_count( $customer_id ) {
|
||||
global $wpdb;
|
||||
$customer_id = absint( $customer_id );
|
||||
|
||||
if ( 0 === $customer_id ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$result = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"SELECT COUNT( order_id ) FROM {$wpdb->prefix}wc_order_stats WHERE customer_id = %d",
|
||||
$customer_id
|
||||
)
|
||||
);
|
||||
|
||||
if ( is_null( $result ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (int) $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the database with customer data.
|
||||
*
|
||||
|
|
|
@ -12,6 +12,7 @@ use \Automattic\WooCommerce\Admin\API\Reports\DataStoreInterface;
|
|||
use \Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
|
||||
use \Automattic\WooCommerce\Admin\API\Reports\SqlQuery;
|
||||
use \Automattic\WooCommerce\Admin\API\Reports\Cache as ReportsCache;
|
||||
use \Automattic\WooCommerce\Admin\API\Reports\Customers\DataStore as CustomersDataStore;
|
||||
|
||||
/**
|
||||
* API\Reports\Orders\Stats\DataStore.
|
||||
|
@ -576,13 +577,19 @@ class DataStore extends ReportsDataStore implements DataStoreInterface {
|
|||
return;
|
||||
}
|
||||
|
||||
// Retrieve customer details before the order is deleted.
|
||||
$order = wc_get_order( $order_id );
|
||||
$customer_id = absint( CustomersDataStore::get_existing_customer_id_from_order( $order ) );
|
||||
|
||||
// Delete the order.
|
||||
$wpdb->delete( self::get_db_table_name(), array( 'order_id' => $order_id ) );
|
||||
/**
|
||||
* Fires when orders stats are deleted.
|
||||
*
|
||||
* @param int $order_id Order ID.
|
||||
* @param int $customer_id Customer ID.
|
||||
*/
|
||||
do_action( 'woocommerce_analytics_delete_order_stats', $order_id );
|
||||
do_action( 'woocommerce_analytics_delete_order_stats', $order_id, $customer_id );
|
||||
|
||||
ReportsCache::invalidate();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
/**
|
||||
* Reports customers tests.
|
||||
*
|
||||
* @package WooCommerce\Admin\Tests\Customers
|
||||
*/
|
||||
|
||||
use \Automattic\WooCommerce\Admin\API\Reports\Customers\Stats\DataStore;
|
||||
|
||||
/**
|
||||
* Class WC_Tests_Reports_Customers
|
||||
*/
|
||||
class WC_Tests_Reports_Customer extends WC_Unit_Test_Case {
|
||||
|
||||
/**
|
||||
* Test order count caluclation for customer.
|
||||
*
|
||||
* @covers \Automattic\WooCommerce\Admin\API\Reports\Customers\DataStore::get_order_count
|
||||
*/
|
||||
public function test_customer_order_count() {
|
||||
WC_Helper_Reports::reset_stats_dbs();
|
||||
|
||||
// Create a customer.
|
||||
$customer = WC_Helper_Customer::create_customer();
|
||||
|
||||
// Create product.
|
||||
$product = new WC_Product_Simple();
|
||||
$product->set_name( 'Test Product' );
|
||||
$product->set_regular_price( 25 );
|
||||
$product->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$customer_id = DataStore::get_customer_id_by_user_id( $customer->get_id() ); // This is the customer ID from lookup table.
|
||||
|
||||
// Create 3 orders.
|
||||
foreach ( range( 1, 3 ) as $i ) {
|
||||
$order = WC_Helper_Order::create_order( $customer->get_id(), $product );
|
||||
$order->save();
|
||||
}
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
// Customer should have 3 orders.
|
||||
$this->assertSame( 3, DataStore::get_order_count( $customer_id ) );
|
||||
|
||||
// Failure from bad customer IDs.
|
||||
$this->assertSame( null, DataStore::get_order_count( 0 ) );
|
||||
$this->assertSame( null, DataStore::get_order_count( 'ABC' ) );
|
||||
$this->assertSame( null, DataStore::get_order_count( false ) );
|
||||
$this->assertSame( null, DataStore::get_order_count( null ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test customer lookup tables are cleaned after deleting an order.
|
||||
*
|
||||
* A customer record should only be deleted if the customer has no other orders.
|
||||
*
|
||||
* @covers \Automattic\WooCommerce\Admin\API\Reports\Customers\DataStore::sync_on_order_delete
|
||||
*/
|
||||
public function test_order_deletion_removes_customer() {
|
||||
WC_Helper_Reports::reset_stats_dbs();
|
||||
|
||||
// Create a customer.
|
||||
$customer = WC_Helper_Customer::create_customer();
|
||||
|
||||
// Create products.
|
||||
$product1 = new WC_Product_Simple();
|
||||
$product1->set_name( 'Test Product 1' );
|
||||
$product1->set_regular_price( 1 );
|
||||
$product1->save();
|
||||
|
||||
$product2 = new WC_Product_Simple();
|
||||
$product2->set_name( 'Test Product 2' );
|
||||
$product2->set_regular_price( 2 );
|
||||
$product2->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
// Create the first order.
|
||||
$order1 = WC_Helper_Order::create_order( $customer->get_id(), $product1 );
|
||||
$order1->save();
|
||||
|
||||
// Create the second order.
|
||||
$order2 = WC_Helper_Order::create_order( $customer->get_id(), $product2 );
|
||||
$order2->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$customer_id = DataStore::get_customer_id_by_user_id( $customer->get_id() ); // This is the customer ID from lookup table.
|
||||
|
||||
// Customer should remain in lookup table after first order deleted.
|
||||
$order1->delete( true );
|
||||
$this->assertCount( 1, $this->get_customer_record( $customer_id ), 'customer remains' );
|
||||
|
||||
// Customer should be removed in lookup table after both orders are deleted.
|
||||
$order2->delete( true );
|
||||
$this->assertCount( 0, $this->get_customer_record( $customer_id ), 'customer removed' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a customer's record from the database.
|
||||
*
|
||||
* @param int $customer_id Analytics Customer ID (not WP User ID).
|
||||
*/
|
||||
private function get_customer_record( $customer_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$results = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"SELECT * FROM {$wpdb->prefix}wc_customer_lookup WHERE customer_id = %d",
|
||||
$customer_id
|
||||
)
|
||||
);
|
||||
|
||||
return $results;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue