Merge pull request #13516 from woocommerce/fix-13505

Make increase_usage_count work correctly on concurrent checkout
This commit is contained in:
Mike Jolley 2017-03-10 19:07:57 +00:00 committed by GitHub
commit 38afff0031
4 changed files with 47 additions and 13 deletions

View File

@ -709,8 +709,13 @@ class WC_Coupon extends WC_Legacy_Coupon {
*/
public function increase_usage_count( $used_by = '' ) {
if ( $this->get_id() && $this->data_store ) {
$this->set_prop( 'usage_count', ( $this->get_usage_count( 'edit' ) + 1 ) );
$this->data_store->increase_usage_count( $this, $used_by );
$new_count = $this->data_store->increase_usage_count( $this, $used_by );
// Bypass set_prop and remove pending changes since the data store saves the count already.
$this->data['usage_count'] = $new_count;
if ( isset( $this->changes['usage_count'] ) ) {
unset( $this->changes['usage_count'] );
}
}
}
@ -721,8 +726,13 @@ class WC_Coupon extends WC_Legacy_Coupon {
*/
public function decrease_usage_count( $used_by = '' ) {
if ( $this->get_id() && $this->get_usage_count() > 0 && $this->data_store ) {
$this->set_prop( 'usage_count', ( $this->get_usage_count( 'edit' ) - 1 ) );
$this->data_store->decrease_usage_count( $this, $used_by );
$new_count = $this->data_store->decrease_usage_count( $this, $used_by );
// Bypass set_prop and remove pending changes since the data store saves the count already.
$this->data['usage_count'] = $new_count;
if ( isset( $this->changes['usage_count'] ) ) {
unset( $this->changes['usage_count'] );
}
}
}

View File

@ -228,13 +228,15 @@ class WC_Coupon_Data_Store_CPT extends WC_Data_Store_WP implements WC_Coupon_Dat
* @since 2.7.0
* @param WC_Coupon
* @param string $used_by Either user ID or billing email
* @return int New usage count
*/
public function increase_usage_count( &$coupon, $used_by = '' ) {
update_post_meta( $coupon->get_id(), 'usage_count', $coupon->get_usage_count( 'edit' ) );
$new_count = $this->update_usage_count_meta( $coupon, 'increase' );
if ( $used_by ) {
add_post_meta( $coupon->get_id(), '_used_by', strtolower( $used_by ) );
$coupon->set_used_by( (array) get_post_meta( $coupon->get_id(), '_used_by' ) );
}
return $new_count;
}
/**
@ -243,10 +245,11 @@ class WC_Coupon_Data_Store_CPT extends WC_Data_Store_WP implements WC_Coupon_Dat
* @since 2.7.0
* @param WC_Coupon
* @param string $used_by Either user ID or billing email
* @return int New usage count
*/
public function decrease_usage_count( &$coupon, $used_by = '' ) {
global $wpdb;
update_post_meta( $coupon->get_id(), 'usage_count', $coupon->get_usage_count() );
$new_count = $this->update_usage_count_meta( $coupon, 'decrease' );
if ( $used_by ) {
/**
* We're doing this the long way because `delete_post_meta( $id, $key, $value )` deletes.
@ -258,6 +261,27 @@ class WC_Coupon_Data_Store_CPT extends WC_Data_Store_WP implements WC_Coupon_Dat
$coupon->set_used_by( (array) get_post_meta( $coupon->get_id(), '_used_by' ) );
}
}
return $new_count;
}
/**
* Increase or decrease the usage count for a coupon by 1.
*
* @since 2.7.0
* @param WC_Coupon
* @param string $operation 'increase' or 'decrease'
* @return int New usage count
*/
private function update_usage_count_meta( &$coupon, $operation = 'increase' ) {
global $wpdb;
$id = $coupon->get_id();
$operator = ( 'increase' === $operation ) ? '+' : '-';
add_post_meta( $id, 'usage_count', $coupon->get_usage_count( 'edit' ), true );
$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->postmeta SET meta_value = meta_value {$operator} 1 WHERE meta_key = 'usage_count' AND post_id = %d;", $id ) );
// Get the latest value direct from the DB, instead of possibly the WP meta cache.
return (int) $wpdb->get_var( $wpdb->prepare( "SELECT meta_value FROM $wpdb->postmeta WHERE meta_key = 'usage_count' AND post_id = %d;", $id ) );
}
/**

View File

@ -816,10 +816,10 @@ function wc_update_coupon_usage_counts( $order_id ) {
switch ( $action ) {
case 'reduce' :
$coupon->dcr_usage_count( $used_by );
$coupon->decrease_usage_count( $used_by );
break;
case 'increase' :
$coupon->inc_usage_count( $used_by );
$coupon->increase_usage_count( $used_by );
break;
}
}

View File

@ -110,19 +110,19 @@ class WC_Tests_Coupon_Data_Store extends WC_Unit_Test_Case {
$this->assertEquals( 0, $coupon->get_usage_count() );
$this->assertEmpty( $coupon->get_used_by() );
$coupon->inc_usage_count( 'woo@woo.local' );
$coupon->increase_usage_count( 'woo@woo.local' );
$this->assertEquals( 1, $coupon->get_usage_count() );
$this->assertEquals( array( 'woo@woo.local' ), $coupon->get_used_by() );
$coupon->inc_usage_count( $user_id );
$coupon->inc_usage_count( $user_id );
$coupon->increase_usage_count( $user_id );
$coupon->increase_usage_count( $user_id );
$data_store = WC_Data_Store::load( 'coupon' );
$this->assertEquals( 2, $data_store->get_usage_by_user_id( $coupon, $user_id ) );
$coupon->dcr_usage_count( 'woo@woo.local' );
$coupon->dcr_usage_count( $user_id );
$coupon->decrease_usage_count( 'woo@woo.local' );
$coupon->decrease_usage_count( $user_id );
$this->assertEquals( 1, $coupon->get_usage_count() );
$this->assertEquals( array( 1 ), $coupon->get_used_by() );
}