Refactor customer ID creation (https://github.com/woocommerce/woocommerce-admin/pull/1619)
* Fix indendtation for table creations * Refactor how customers are created on order update * Check if user has a role of customer or previous orders before storing * Add tests for user creation * Allow null emails for customers * Only select customer_id in guest ID query
This commit is contained in:
parent
08e43c35cf
commit
aef11ef586
|
@ -112,8 +112,8 @@ class WC_Admin_Install {
|
|||
KEY date_created (date_created),
|
||||
KEY customer_id (customer_id),
|
||||
KEY status (status)
|
||||
) $collate;
|
||||
CREATE TABLE {$wpdb->prefix}wc_order_product_lookup (
|
||||
) $collate;
|
||||
CREATE TABLE {$wpdb->prefix}wc_order_product_lookup (
|
||||
order_item_id BIGINT UNSIGNED NOT NULL,
|
||||
order_id BIGINT UNSIGNED NOT NULL,
|
||||
product_id BIGINT UNSIGNED NOT NULL,
|
||||
|
@ -133,19 +133,19 @@ class WC_Admin_Install {
|
|||
KEY product_id (product_id),
|
||||
KEY customer_id (customer_id),
|
||||
KEY date_created (date_created)
|
||||
) $collate;
|
||||
CREATE TABLE {$wpdb->prefix}wc_order_tax_lookup (
|
||||
order_id BIGINT UNSIGNED NOT NULL,
|
||||
tax_rate_id BIGINT UNSIGNED NOT NULL,
|
||||
date_created datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
|
||||
shipping_tax double DEFAULT 0 NOT NULL,
|
||||
order_tax double DEFAULT 0 NOT NULL,
|
||||
total_tax double DEFAULT 0 NOT NULL,
|
||||
PRIMARY KEY (order_id, tax_rate_id),
|
||||
KEY tax_rate_id (tax_rate_id),
|
||||
KEY date_created (date_created)
|
||||
) $collate;
|
||||
CREATE TABLE {$wpdb->prefix}wc_order_coupon_lookup (
|
||||
) $collate;
|
||||
CREATE TABLE {$wpdb->prefix}wc_order_tax_lookup (
|
||||
order_id BIGINT UNSIGNED NOT NULL,
|
||||
tax_rate_id BIGINT UNSIGNED NOT NULL,
|
||||
date_created datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
|
||||
shipping_tax double DEFAULT 0 NOT NULL,
|
||||
order_tax double DEFAULT 0 NOT NULL,
|
||||
total_tax double DEFAULT 0 NOT NULL,
|
||||
PRIMARY KEY (order_id, tax_rate_id),
|
||||
KEY tax_rate_id (tax_rate_id),
|
||||
KEY date_created (date_created)
|
||||
) $collate;
|
||||
CREATE TABLE {$wpdb->prefix}wc_order_coupon_lookup (
|
||||
order_id BIGINT UNSIGNED NOT NULL,
|
||||
coupon_id BIGINT UNSIGNED NOT NULL,
|
||||
date_created datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
|
||||
|
@ -153,48 +153,48 @@ class WC_Admin_Install {
|
|||
PRIMARY KEY (order_id, coupon_id),
|
||||
KEY coupon_id (coupon_id),
|
||||
KEY date_created (date_created)
|
||||
) $collate;
|
||||
CREATE TABLE {$wpdb->prefix}wc_admin_notes (
|
||||
note_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
name varchar(255) NOT NULL,
|
||||
type varchar(20) NOT NULL,
|
||||
locale varchar(20) NOT NULL,
|
||||
title longtext NOT NULL,
|
||||
content longtext NOT NULL,
|
||||
icon varchar(200) NOT NULL,
|
||||
content_data longtext NULL default null,
|
||||
status varchar(200) NOT NULL,
|
||||
source varchar(200) NOT NULL,
|
||||
date_created datetime NOT NULL default '0000-00-00 00:00:00',
|
||||
date_reminder datetime NULL default null,
|
||||
PRIMARY KEY (note_id)
|
||||
) $collate;
|
||||
CREATE TABLE {$wpdb->prefix}wc_admin_note_actions (
|
||||
action_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
note_id BIGINT UNSIGNED NOT NULL,
|
||||
name varchar(255) NOT NULL,
|
||||
label varchar(255) NOT NULL,
|
||||
query longtext NOT NULL,
|
||||
PRIMARY KEY (action_id),
|
||||
KEY note_id (note_id)
|
||||
) $collate;
|
||||
CREATE TABLE {$wpdb->prefix}wc_customer_lookup (
|
||||
customer_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
user_id BIGINT UNSIGNED DEFAULT NULL,
|
||||
username varchar(60) DEFAULT '' NOT NULL,
|
||||
first_name varchar(255) NOT NULL,
|
||||
last_name varchar(255) NOT NULL,
|
||||
email varchar(100) NOT NULL,
|
||||
date_last_active timestamp NULL default null,
|
||||
date_registered timestamp NULL default null,
|
||||
country char(2) DEFAULT '' NOT NULL,
|
||||
postcode varchar(20) DEFAULT '' NOT NULL,
|
||||
city varchar(100) DEFAULT '' NOT NULL,
|
||||
PRIMARY KEY (customer_id),
|
||||
UNIQUE KEY user_id (user_id),
|
||||
KEY email (email)
|
||||
) $collate;
|
||||
";
|
||||
) $collate;
|
||||
CREATE TABLE {$wpdb->prefix}wc_admin_notes (
|
||||
note_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
name varchar(255) NOT NULL,
|
||||
type varchar(20) NOT NULL,
|
||||
locale varchar(20) NOT NULL,
|
||||
title longtext NOT NULL,
|
||||
content longtext NOT NULL,
|
||||
icon varchar(200) NOT NULL,
|
||||
content_data longtext NULL default null,
|
||||
status varchar(200) NOT NULL,
|
||||
source varchar(200) NOT NULL,
|
||||
date_created datetime NOT NULL default '0000-00-00 00:00:00',
|
||||
date_reminder datetime NULL default null,
|
||||
PRIMARY KEY (note_id)
|
||||
) $collate;
|
||||
CREATE TABLE {$wpdb->prefix}wc_admin_note_actions (
|
||||
action_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
note_id BIGINT UNSIGNED NOT NULL,
|
||||
name varchar(255) NOT NULL,
|
||||
label varchar(255) NOT NULL,
|
||||
query longtext NOT NULL,
|
||||
PRIMARY KEY (action_id),
|
||||
KEY note_id (note_id)
|
||||
) $collate;
|
||||
CREATE TABLE {$wpdb->prefix}wc_customer_lookup (
|
||||
customer_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
user_id BIGINT UNSIGNED DEFAULT NULL,
|
||||
username varchar(60) DEFAULT '' NOT NULL,
|
||||
first_name varchar(255) NOT NULL,
|
||||
last_name varchar(255) NOT NULL,
|
||||
email varchar(100) NULL default NULL,
|
||||
date_last_active timestamp NULL default null,
|
||||
date_registered timestamp NULL default null,
|
||||
country char(2) DEFAULT '' NOT NULL,
|
||||
postcode varchar(20) DEFAULT '' NOT NULL,
|
||||
city varchar(100) DEFAULT '' NOT NULL,
|
||||
PRIMARY KEY (customer_id),
|
||||
UNIQUE KEY user_id (user_id),
|
||||
KEY email (email)
|
||||
) $collate;
|
||||
";
|
||||
|
||||
return $tables;
|
||||
}
|
||||
|
|
|
@ -414,52 +414,77 @@ class WC_Admin_Reports_Customers_Data_Store extends WC_Admin_Reports_Data_Store
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the guest (no user_id) customer ID or creates a new one for
|
||||
* the corresponding billing email in the provided WC_Order
|
||||
* Returns an existing customer ID for an order if one exists.
|
||||
*
|
||||
* @param WC_Order $order Order to get/create guest customer data with.
|
||||
* @return int|false The ID of the retrieved/created customer, or false on error.
|
||||
* @param object $order WC Order.
|
||||
* @return int|bool
|
||||
*/
|
||||
public function get_or_create_guest_customer_from_order( $order ) {
|
||||
public static function get_existing_customer_id_from_order( $order ) {
|
||||
$user_id = $order->get_customer_id();
|
||||
|
||||
if ( 0 === $user_id ) {
|
||||
$email = $order->get_billing_email( 'edit' );
|
||||
|
||||
if ( $email ) {
|
||||
return self::get_guest_id_by_email( $email );
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return self::get_customer_id_by_user_id( $user_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or create a customer from a given order.
|
||||
*
|
||||
* @param object $order WC Order.
|
||||
* @return int|bool
|
||||
*/
|
||||
public static function get_or_create_customer_from_order( $order ) {
|
||||
global $wpdb;
|
||||
$returning_customer_id = self::get_existing_customer_id_from_order( $order );
|
||||
|
||||
$email = $order->get_billing_email( 'edit' );
|
||||
|
||||
if ( empty( $email ) ) {
|
||||
return false;
|
||||
if ( $returning_customer_id ) {
|
||||
return $returning_customer_id;
|
||||
}
|
||||
|
||||
$existing_guest = $this->get_guest_by_email( $email );
|
||||
|
||||
if ( $existing_guest ) {
|
||||
return $existing_guest['customer_id'];
|
||||
}
|
||||
|
||||
$result = $wpdb->insert(
|
||||
$wpdb->prefix . self::TABLE_NAME,
|
||||
array(
|
||||
'first_name' => $order->get_billing_first_name( 'edit' ),
|
||||
'last_name' => $order->get_billing_last_name( 'edit' ),
|
||||
'email' => $email,
|
||||
'city' => $order->get_billing_city( 'edit' ),
|
||||
'postcode' => $order->get_billing_postcode( 'edit' ),
|
||||
'country' => $order->get_billing_country( 'edit' ),
|
||||
'date_last_active' => date( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ),
|
||||
),
|
||||
array(
|
||||
'%s',
|
||||
'%s',
|
||||
'%s',
|
||||
'%s',
|
||||
'%s',
|
||||
'%s',
|
||||
'%s',
|
||||
)
|
||||
$data = array(
|
||||
'first_name' => $order->get_billing_first_name( 'edit' ),
|
||||
'last_name' => $order->get_billing_last_name( 'edit' ),
|
||||
'email' => $order->get_billing_email( 'edit' ),
|
||||
'city' => $order->get_billing_city( 'edit' ),
|
||||
'postcode' => $order->get_billing_postcode( 'edit' ),
|
||||
'country' => $order->get_billing_country( 'edit' ),
|
||||
'date_last_active' => date( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ),
|
||||
);
|
||||
$format = array(
|
||||
'%s',
|
||||
'%s',
|
||||
'%s',
|
||||
'%s',
|
||||
'%s',
|
||||
'%s',
|
||||
'%s',
|
||||
);
|
||||
|
||||
// Add registered customer data.
|
||||
if ( 0 !== $order->get_user_id() ) {
|
||||
$user_id = $order->get_user_id();
|
||||
$customer = new WC_Customer( $user_id );
|
||||
$data['user_id'] = $user_id;
|
||||
$data['username'] = $customer->get_username( 'edit' );
|
||||
$data['date_registered'] = $customer->get_date_created( 'edit' )->date( WC_Admin_Reports_Interval::$sql_datetime_format );
|
||||
$format[] = '%d';
|
||||
$format[] = '%s';
|
||||
$format[] = '%s';
|
||||
}
|
||||
|
||||
$result = $wpdb->insert( $wpdb->prefix . self::TABLE_NAME, $data, $format );
|
||||
$customer_id = $wpdb->insert_id;
|
||||
|
||||
/**
|
||||
* Fires when customser's reports are created.
|
||||
* Fires when a new report customer is created.
|
||||
*
|
||||
* @param int $customer_id Customer ID.
|
||||
*/
|
||||
|
@ -469,53 +494,23 @@ class WC_Admin_Reports_Customers_Data_Store extends WC_Admin_Reports_Data_Store
|
|||
}
|
||||
|
||||
/**
|
||||
* Retrieve a guest (no user_id) customer row by email.
|
||||
* Retrieve a guest ID (when user_id is null) by email.
|
||||
*
|
||||
* @param string $email Email address.
|
||||
* @return false|array Customer array if found, boolean false if not.
|
||||
*/
|
||||
public function get_guest_by_email( $email ) {
|
||||
public static function get_guest_id_by_email( $email ) {
|
||||
global $wpdb;
|
||||
|
||||
$table_name = $wpdb->prefix . self::TABLE_NAME;
|
||||
$guest_row = $wpdb->get_row(
|
||||
$table_name = $wpdb->prefix . self::TABLE_NAME;
|
||||
$customer_id = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"SELECT * FROM {$table_name} WHERE email = %s AND user_id IS NULL LIMIT 1",
|
||||
"SELECT customer_id FROM {$table_name} WHERE email = %s AND user_id IS NULL LIMIT 1",
|
||||
$email
|
||||
),
|
||||
ARRAY_A
|
||||
)
|
||||
); // WPCS: unprepared SQL ok.
|
||||
|
||||
if ( $guest_row ) {
|
||||
return $this->cast_numbers( $guest_row );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a registered customer row by user_id.
|
||||
*
|
||||
* @param string|int $user_id User ID.
|
||||
* @return false|array Customer array if found, boolean false if not.
|
||||
*/
|
||||
public function get_customer_by_user_id( $user_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$table_name = $wpdb->prefix . self::TABLE_NAME;
|
||||
$customer = $wpdb->get_row(
|
||||
$wpdb->prepare(
|
||||
"SELECT * FROM {$table_name} WHERE user_id = %d LIMIT 1",
|
||||
$user_id
|
||||
),
|
||||
ARRAY_A
|
||||
); // WPCS: unprepared SQL ok.
|
||||
|
||||
if ( $customer ) {
|
||||
return $this->cast_numbers( $customer );
|
||||
}
|
||||
|
||||
return false;
|
||||
return $customer_id ? (int) $customer_id : false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -573,7 +568,7 @@ class WC_Admin_Reports_Customers_Data_Store extends WC_Admin_Reports_Data_Store
|
|||
|
||||
$customer = new WC_Customer( $user_id );
|
||||
|
||||
if ( $customer->get_id() != $user_id ) {
|
||||
if ( ! self::is_valid_customer( $user_id ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -622,6 +617,26 @@ class WC_Admin_Reports_Customers_Data_Store extends WC_Admin_Reports_Data_Store
|
|||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a user ID is a valid customer or other user role with past orders.
|
||||
*
|
||||
* @param int $user_id User ID.
|
||||
* @return bool
|
||||
*/
|
||||
protected static function is_valid_customer( $user_id ) {
|
||||
$customer = new WC_Customer( $user_id );
|
||||
|
||||
if ( $customer->get_id() !== $user_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $customer->get_order_count() < 1 && 'customer' !== $customer->get_role() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns string to be used as cache key for the data.
|
||||
*
|
||||
|
|
|
@ -404,6 +404,7 @@ class WC_Admin_Reports_Orders_Stats_Data_Store extends WC_Admin_Reports_Data_Sto
|
|||
'net_total' => self::get_net_total( $order ),
|
||||
'returning_customer' => self::is_returning_customer( $order ),
|
||||
'status' => self::normalize_order_status( $order->get_status() ),
|
||||
'customer_id' => WC_Admin_Reports_Customers_Data_Store::get_or_create_customer_from_order( $order ),
|
||||
);
|
||||
$format = array(
|
||||
'%d',
|
||||
|
@ -417,32 +418,9 @@ class WC_Admin_Reports_Orders_Stats_Data_Store extends WC_Admin_Reports_Data_Sto
|
|||
'%f',
|
||||
'%d',
|
||||
'%s',
|
||||
'%d',
|
||||
);
|
||||
|
||||
// Ensure we're associating this order with a Customer in the lookup table.
|
||||
$order_user_id = $order->get_customer_id();
|
||||
$customers_data_store = new WC_Admin_Reports_Customers_Data_Store();
|
||||
|
||||
if ( 0 === $order_user_id ) {
|
||||
$email = $order->get_billing_email( 'edit' );
|
||||
|
||||
if ( $email ) {
|
||||
$customer_id = $customers_data_store->get_or_create_guest_customer_from_order( $order );
|
||||
|
||||
if ( $customer_id ) {
|
||||
$data['customer_id'] = $customer_id;
|
||||
$format[] = '%d';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$customer = $customers_data_store->get_customer_by_user_id( $order_user_id );
|
||||
|
||||
if ( $customer && $customer['customer_id'] ) {
|
||||
$data['customer_id'] = $customer['customer_id'];
|
||||
$format[] = '%d';
|
||||
}
|
||||
}
|
||||
|
||||
// Update or add the information to the DB.
|
||||
$result = $wpdb->replace( $table_name, $data, $format );
|
||||
|
||||
|
|
|
@ -106,6 +106,75 @@ class WC_Tests_API_Reports_Customers extends WC_REST_Unit_Test_Case {
|
|||
$this->assertFalse( $result );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test creation of various user roles
|
||||
*
|
||||
* @since 3.5.0
|
||||
*/
|
||||
public function test_user_creation() {
|
||||
wp_set_current_user( $this->user );
|
||||
$admin_id = wp_insert_user(
|
||||
array(
|
||||
'user_login' => 'testadmin',
|
||||
'user_pass' => null,
|
||||
'role' => 'administrator',
|
||||
)
|
||||
);
|
||||
|
||||
// Admin user without orders should not be shown.
|
||||
$request = new WP_REST_Request( 'GET', $this->endpoint );
|
||||
$request->set_query_params( array( 'per_page' => 10 ) );
|
||||
$response = $this->server->dispatch( $request );
|
||||
$reports = $response->get_data();
|
||||
$headers = $response->get_headers();
|
||||
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
$this->assertCount( 0, $reports );
|
||||
|
||||
// Creating an order with admin should return the admin.
|
||||
$product = new WC_Product_Simple();
|
||||
$product->set_name( 'Test Product' );
|
||||
$product->set_regular_price( 25 );
|
||||
$product->save();
|
||||
|
||||
$order = WC_Helper_Order::create_order( $admin_id, $product );
|
||||
$order->set_status( 'processing' );
|
||||
$order->set_total( 100 );
|
||||
$order->save();
|
||||
|
||||
WC_Helper_Queue::run_all_pending();
|
||||
|
||||
$request = new WP_REST_Request( 'GET', $this->endpoint );
|
||||
$request->set_query_params( array( 'per_page' => 10 ) );
|
||||
$response = $this->server->dispatch( $request );
|
||||
$reports = $response->get_data();
|
||||
$headers = $response->get_headers();
|
||||
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
$this->assertCount( 1, $reports );
|
||||
$this->assertEquals( $admin_id, $reports[0]['user_id'] );
|
||||
|
||||
// Creating a customer should show up regardless of orders.
|
||||
$customer = WC_Helper_Customer::create_customer( 'customer', 'password', 'customer@example.com' );
|
||||
|
||||
$request = new WP_REST_Request( 'GET', $this->endpoint );
|
||||
$request->set_query_params(
|
||||
array(
|
||||
'per_page' => 10,
|
||||
'order' => 'asc',
|
||||
'orderby' => 'username',
|
||||
)
|
||||
);
|
||||
$response = $this->server->dispatch( $request );
|
||||
$reports = $response->get_data();
|
||||
$headers = $response->get_headers();
|
||||
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
$this->assertCount( 2, $reports );
|
||||
$this->assertEquals( $customer->get_id(), $reports[0]['user_id'] );
|
||||
$this->assertEquals( $admin_id, $reports[1]['user_id'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting reports.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue