Skip to content

Commit

Permalink
Refactor customer ID creation (woocommerce#1619)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
joshuatf authored Feb 20, 2019
1 parent bd710c0 commit a795186
Show file tree
Hide file tree
Showing 4 changed files with 214 additions and 152 deletions.
114 changes: 57 additions & 57 deletions includes/class-wc-admin-install.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ private static function get_schema() {
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,
Expand All @@ -133,68 +133,68 @@ private static function get_schema() {
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,
discount_amount double DEFAULT 0 NOT NULL,
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;
}
Expand Down
157 changes: 86 additions & 71 deletions includes/data-stores/class-wc-admin-reports-customers-data-store.php
Original file line number Diff line number Diff line change
Expand Up @@ -414,52 +414,77 @@ public function get_data( $query_args ) {
}

/**
* 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 ) {
global $wpdb;
public static function get_existing_customer_id_from_order( $order ) {
$user_id = $order->get_customer_id();

$email = $order->get_billing_email( 'edit' );
if ( 0 === $user_id ) {
$email = $order->get_billing_email( 'edit' );

if ( empty( $email ) ) {
return false;
if ( $email ) {
return self::get_guest_id_by_email( $email );
} else {
return false;
}
} else {
return self::get_customer_id_by_user_id( $user_id );
}
}

$existing_guest = $this->get_guest_by_email( $email );
/**
* 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 );

if ( $existing_guest ) {
return $existing_guest['customer_id'];
if ( $returning_customer_id ) {
return $returning_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.
*/
Expand All @@ -469,53 +494,23 @@ public function get_or_create_guest_customer_from_order( $order ) {
}

/**
* 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;
}

/**
Expand Down Expand Up @@ -573,7 +568,7 @@ public static function update_registered_customer( $user_id ) {

$customer = new WC_Customer( $user_id );

if ( $customer->get_id() != $user_id ) {
if ( ! self::is_valid_customer( $user_id ) ) {
return false;
}

Expand Down Expand Up @@ -622,6 +617,26 @@ public static function update_registered_customer( $user_id ) {
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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ public static function update( $order ) {
'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',
Expand All @@ -417,32 +418,9 @@ public static function update( $order ) {
'%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 );

Expand Down
Loading

0 comments on commit a795186

Please sign in to comment.