* 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:
Joshua T Flowers 2019-02-20 10:30:00 +08:00 committed by GitHub
parent 08e43c35cf
commit aef11ef586
4 changed files with 217 additions and 155 deletions

View File

@ -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;
}

View File

@ -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.
*

View File

@ -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 );

View File

@ -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.
*