2020-12-17 16:42:32 +00:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* Unit tests for wc-stock-functions.php.
|
|
|
|
*
|
|
|
|
* @package WooCommerce\Tests\Functions\Stock
|
|
|
|
*/
|
|
|
|
|
2020-12-21 15:46:01 +00:00
|
|
|
/**
|
|
|
|
* Class WC_Stock_Functions_Tests.
|
|
|
|
*/
|
2020-12-17 16:42:32 +00:00
|
|
|
class WC_Stock_Functions_Tests extends \WC_Unit_Test_Case {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array List of statuses which reduces stock from inventory.
|
|
|
|
*/
|
|
|
|
public $order_stock_reduce_statuses = array(
|
|
|
|
'wc-processing',
|
|
|
|
'wc-completed',
|
|
|
|
'wc-on-hold',
|
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array List of statuses which restores stock back into inventory.
|
|
|
|
*/
|
|
|
|
public $order_stock_restore_statuses = array(
|
|
|
|
'wc-cancelled',
|
|
|
|
'wc-pending',
|
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array List of statuses which have no impact on inventory.
|
|
|
|
*/
|
|
|
|
public $order_stock_no_effect_statuses = array(
|
|
|
|
'wc-failed',
|
|
|
|
'wc-refunded',
|
|
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper function to simulate creating order from cart.
|
|
|
|
*
|
2020-12-21 10:21:07 +00:00
|
|
|
* @param string $status Status for the newly created order.
|
2020-12-17 16:42:32 +00:00
|
|
|
*/
|
2020-12-21 10:21:07 +00:00
|
|
|
private function create_order_from_cart_with_status( $status ) {
|
2020-12-17 16:42:32 +00:00
|
|
|
$product = WC_Helper_Product::create_simple_product(
|
|
|
|
true,
|
|
|
|
array(
|
|
|
|
'manage_stock' => true,
|
|
|
|
'stock_quantity' => 10,
|
|
|
|
)
|
|
|
|
);
|
|
|
|
WC()->cart->empty_cart();
|
|
|
|
WC()->cart->add_to_cart( $product->get_id(), 1 );
|
|
|
|
WC()->cart->calculate_totals();
|
|
|
|
|
|
|
|
$checkout = WC_Checkout::instance();
|
2020-12-21 15:46:01 +00:00
|
|
|
$order = new WC_Order();
|
2020-12-17 16:42:32 +00:00
|
|
|
$checkout->set_data_from_cart( $order );
|
2020-12-21 10:21:07 +00:00
|
|
|
$order->set_status( $status );
|
2020-12-17 16:42:32 +00:00
|
|
|
$order->save();
|
|
|
|
return $order;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper function to change order status and assert product inventory values.
|
|
|
|
*
|
|
|
|
* @param string $status_from Initial status of the order.
|
|
|
|
* @param string $status_to Status to transition the order to.
|
|
|
|
* @param int $before_transition Inventory value before order status is changed.
|
|
|
|
* @param int $after_transition Inventory value after order status change.
|
|
|
|
*/
|
|
|
|
private function transition_order_status_and_assert_stock_quantity( $status_from, $status_to, $before_transition, $after_transition ) {
|
|
|
|
$order = $this->create_order_from_cart_with_status( $status_from );
|
|
|
|
$order_item = array_values( $order->get_items( 'line_item' ) )[0];
|
|
|
|
|
|
|
|
$product = new WC_Product( $order_item->get_product_id() );
|
|
|
|
$this->assertEquals( $before_transition, $product->get_stock_quantity() );
|
|
|
|
|
|
|
|
// Changing status from UI also calls this method in metadata save hook. This has impact on stock levels, so simulate it here as well.
|
|
|
|
wc_save_order_items( $order, $order->get_items() );
|
|
|
|
|
|
|
|
$order->set_status( $status_to );
|
|
|
|
$order->save();
|
|
|
|
$product = new WC_Product( $order_item->get_product_id() );
|
|
|
|
$this->assertEquals( $after_transition, $product->get_stock_quantity(), "Stock levels unexpected when transitioning from $status_from to $status_to." );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-03-05 09:19:58 +00:00
|
|
|
* Test inventory count after order status transitions which reduces stock to another status which also reduces stock.
|
2020-12-21 10:21:07 +00:00
|
|
|
* Stock should have reduced once already, and should not reduce again.
|
2020-12-17 16:42:32 +00:00
|
|
|
*/
|
|
|
|
public function test_status_transition_stock_reduce_to_stock_reduce() {
|
|
|
|
foreach ( $this->order_stock_reduce_statuses as $order_status_from ) {
|
|
|
|
foreach ( $this->order_stock_reduce_statuses as $order_status_to ) {
|
|
|
|
$this->transition_order_status_and_assert_stock_quantity( $order_status_from, $order_status_to, 9, 9 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-03-05 09:19:58 +00:00
|
|
|
* Test inventory count after order status transitions which reduces stock to another status which restores stock.
|
2020-12-21 10:21:07 +00:00
|
|
|
* Should should have already reduced once, and will increase again after transitioning.
|
2020-12-17 16:42:32 +00:00
|
|
|
*/
|
|
|
|
public function test_status_transition_stock_reduce_to_stock_restore() {
|
|
|
|
foreach ( $this->order_stock_reduce_statuses as $order_status_from ) {
|
|
|
|
foreach ( $this->order_stock_restore_statuses as $order_status_to ) {
|
|
|
|
$this->transition_order_status_and_assert_stock_quantity( $order_status_from, $order_status_to, 9, 10 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-03-05 09:19:58 +00:00
|
|
|
* Test inventory count after order status transitions which reduces stock to another status which don't affect inventory.
|
2020-12-21 10:21:07 +00:00
|
|
|
* Stock should have already reduced, and will not change on transitioning.
|
2020-12-17 16:42:32 +00:00
|
|
|
*/
|
|
|
|
public function test_status_transition_stock_reduce_to_stock_no_effect() {
|
|
|
|
foreach ( $this->order_stock_reduce_statuses as $order_status_from ) {
|
|
|
|
foreach ( $this->order_stock_no_effect_statuses as $order_status_to ) {
|
|
|
|
$this->transition_order_status_and_assert_stock_quantity( $order_status_from, $order_status_to, 9, 9 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test inventory count after order status transtions which restores stock to another status which reduces stock.
|
2020-12-21 10:21:07 +00:00
|
|
|
* Stock should not have reduced, but will reduce after transition.
|
2020-12-17 16:42:32 +00:00
|
|
|
*/
|
|
|
|
public function test_status_transition_stock_restore_to_stock_reduce() {
|
|
|
|
foreach ( $this->order_stock_restore_statuses as $order_status_from ) {
|
|
|
|
foreach ( $this->order_stock_reduce_statuses as $order_status_to ) {
|
|
|
|
$this->transition_order_status_and_assert_stock_quantity( $order_status_from, $order_status_to, 10, 9 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-03-05 09:19:58 +00:00
|
|
|
* Test inventory count after order status transitions which restores stock to another status which also restores stock.
|
2020-12-21 10:21:07 +00:00
|
|
|
* Stock should not have reduced, and will remain the same even after transition (i.e. should not be restocked again).
|
2020-12-17 16:42:32 +00:00
|
|
|
*/
|
|
|
|
public function test_status_transition_stock_restore_to_stock_restore() {
|
|
|
|
foreach ( $this->order_stock_restore_statuses as $order_status_from ) {
|
|
|
|
foreach ( $this->order_stock_restore_statuses as $order_status_to ) {
|
|
|
|
$this->transition_order_status_and_assert_stock_quantity( $order_status_from, $order_status_to, 10, 10 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-03-05 09:19:58 +00:00
|
|
|
* Test inventory count after order status transitions which restores stock to another status which don't affect inventory.
|
2020-12-21 10:21:07 +00:00
|
|
|
* Stock should not have reduced, and will remain the same even after transition.
|
2020-12-17 16:42:32 +00:00
|
|
|
*/
|
|
|
|
public function test_status_transition_stock_restore_to_stock_no_effect() {
|
|
|
|
foreach ( $this->order_stock_restore_statuses as $order_status_from ) {
|
|
|
|
foreach ( $this->order_stock_no_effect_statuses as $order_status_to ) {
|
|
|
|
$this->transition_order_status_and_assert_stock_quantity( $order_status_from, $order_status_to, 10, 10 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-03-05 09:19:58 +00:00
|
|
|
* Test inventory count after order status transitions which don't affect inventory stock to another status which reduces stock.
|
2020-12-21 10:21:07 +00:00
|
|
|
* Stock would not have been affected, but will reduce after transition.
|
2020-12-17 16:42:32 +00:00
|
|
|
*/
|
|
|
|
public function test_status_transition_stock_no_effect_to_stock_reduce() {
|
|
|
|
foreach ( $this->order_stock_no_effect_statuses as $order_status_from ) {
|
|
|
|
foreach ( $this->order_stock_reduce_statuses as $order_status_to ) {
|
|
|
|
$this->transition_order_status_and_assert_stock_quantity( $order_status_from, $order_status_to, 10, 9 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-03-05 09:19:58 +00:00
|
|
|
* Test inventory count after order status transitions which don't affect inventory stock to another status which restores stock.
|
2020-12-21 10:21:07 +00:00
|
|
|
* Stock would not have been affected, and will not be restored after transition (since it was not reduced to begin with).
|
2020-12-17 16:42:32 +00:00
|
|
|
*/
|
|
|
|
public function test_status_transition_stock_no_effect_to_stock_restore() {
|
|
|
|
foreach ( $this->order_stock_no_effect_statuses as $order_status_from ) {
|
|
|
|
foreach ( $this->order_stock_restore_statuses as $order_status_to ) {
|
|
|
|
$this->transition_order_status_and_assert_stock_quantity( $order_status_from, $order_status_to, 10, 10 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-03-05 09:19:58 +00:00
|
|
|
* Test inventory count after order status transitions which don't affect inventory stock to another status which also don't affect inventory.
|
2020-12-21 10:21:07 +00:00
|
|
|
* Stock levels will not change before or after the transition.
|
2020-12-17 16:42:32 +00:00
|
|
|
*/
|
|
|
|
public function test_status_transition_stock_no_effect_to_stock_no_effect() {
|
|
|
|
foreach ( $this->order_stock_no_effect_statuses as $order_status_from ) {
|
|
|
|
foreach ( $this->order_stock_no_effect_statuses as $order_status_to ) {
|
|
|
|
$this->transition_order_status_and_assert_stock_quantity( $order_status_from, $order_status_to, 10, 10 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-03-15 17:31:31 +00:00
|
|
|
|
2021-04-20 08:17:50 +00:00
|
|
|
/**
|
|
|
|
* Assert that a value is equal to another one and is of integer type.
|
|
|
|
*
|
|
|
|
* @param mixed $expected The value $actual must be equal to.
|
|
|
|
* @param mixed $actual The value to check for equality to $expected and for type.
|
|
|
|
*/
|
|
|
|
private function assertIsIntAndEquals( $expected, $actual ) {
|
|
|
|
$this->assertEquals( $expected, $actual );
|
2021-04-20 15:16:59 +00:00
|
|
|
self::assertIsInteger( $actual );
|
2021-04-20 08:17:50 +00:00
|
|
|
}
|
|
|
|
|
2021-03-15 17:31:31 +00:00
|
|
|
/**
|
|
|
|
* Test wc_get_low_stock_amount with a simple product which has low stock amount set.
|
|
|
|
*/
|
|
|
|
public function test_wc_get_low_stock_amount_simple_set() {
|
|
|
|
$product_low_stock_amount = 5;
|
|
|
|
$site_wide_low_stock_amount = 3;
|
|
|
|
|
|
|
|
// Set the store-wide default.
|
2021-04-20 08:17:50 +00:00
|
|
|
update_option( 'woocommerce_notify_low_stock_amount', strval( $site_wide_low_stock_amount ) );
|
2021-03-15 17:31:31 +00:00
|
|
|
|
|
|
|
// Simple product, set low stock amount.
|
|
|
|
$product = WC_Helper_Product::create_simple_product(
|
|
|
|
true,
|
|
|
|
array(
|
|
|
|
'manage_stock' => true,
|
|
|
|
'stock_quantity' => 10,
|
|
|
|
'low_stock_amount' => $product_low_stock_amount,
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
2021-04-20 08:17:50 +00:00
|
|
|
$this->assertIsIntAndEquals( $product_low_stock_amount, wc_get_low_stock_amount( $product ) );
|
2021-03-15 17:31:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test wc_get_low_stock_amount with a simple product which doesn't have low stock amount set.
|
|
|
|
*/
|
|
|
|
public function test_wc_get_low_stock_amount_simple_unset() {
|
|
|
|
$site_wide_low_stock_amount = 3;
|
|
|
|
|
|
|
|
// Set the store-wide default.
|
2021-04-20 08:17:50 +00:00
|
|
|
update_option( 'woocommerce_notify_low_stock_amount', strval( $site_wide_low_stock_amount ) );
|
2021-03-15 17:31:31 +00:00
|
|
|
|
|
|
|
// Simple product, don't set low stock amount.
|
|
|
|
$product = WC_Helper_Product::create_simple_product(
|
|
|
|
true,
|
|
|
|
array(
|
2021-04-20 07:42:07 +00:00
|
|
|
'manage_stock' => true,
|
|
|
|
'stock_quantity' => 10,
|
2021-03-15 17:31:31 +00:00
|
|
|
)
|
|
|
|
);
|
|
|
|
|
2021-04-20 08:17:50 +00:00
|
|
|
$this->assertIsIntAndEquals( $site_wide_low_stock_amount, wc_get_low_stock_amount( $product ) );
|
2021-03-15 17:31:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test wc_get_low_stock_amount with a variable product which has low stock amount set on the variation level,
|
|
|
|
* but not on the parent level. Should use the value from the variation.
|
|
|
|
*/
|
|
|
|
public function test_wc_get_low_stock_amount_variation_set_parent_unset() {
|
|
|
|
$site_wide_low_stock_amount = 3;
|
|
|
|
$variation_low_stock_amount = 7;
|
|
|
|
|
|
|
|
// Set the store-wide default.
|
2021-04-20 08:17:50 +00:00
|
|
|
update_option( 'woocommerce_notify_low_stock_amount', strval( $site_wide_low_stock_amount ) );
|
2021-03-15 17:31:31 +00:00
|
|
|
|
|
|
|
// Parent low stock amount NOT set.
|
|
|
|
$variable_product = WC_Helper_Product::create_variation_product();
|
|
|
|
$variable_product->set_manage_stock( false );
|
2021-03-16 12:08:29 +00:00
|
|
|
$variable_product->save();
|
2021-03-15 17:31:31 +00:00
|
|
|
|
|
|
|
// Set the variation low stock amount.
|
|
|
|
$variations = $variable_product->get_available_variations( 'objects' );
|
2021-04-20 07:42:07 +00:00
|
|
|
$var1 = $variations[0];
|
2021-03-15 17:31:31 +00:00
|
|
|
$var1->set_manage_stock( true );
|
|
|
|
$var1->set_low_stock_amount( $variation_low_stock_amount );
|
|
|
|
$var1->save();
|
|
|
|
|
2021-04-20 08:17:50 +00:00
|
|
|
$this->assertIsIntAndEquals( $variation_low_stock_amount, wc_get_low_stock_amount( $var1 ) );
|
2021-03-15 17:31:31 +00:00
|
|
|
|
|
|
|
// Even after turning on manage stock on the parent, but with no value.
|
|
|
|
$variable_product->set_manage_stock( true );
|
2021-03-16 12:08:29 +00:00
|
|
|
$variable_product->save();
|
2021-04-20 08:17:50 +00:00
|
|
|
$this->assertIsIntAndEquals( $variation_low_stock_amount, wc_get_low_stock_amount( $var1 ) );
|
2021-03-15 17:31:31 +00:00
|
|
|
|
|
|
|
// Ans also after turning the manage stock off again on the parent.
|
2021-03-16 12:08:29 +00:00
|
|
|
$variable_product->set_manage_stock( false );
|
|
|
|
$variable_product->save();
|
2021-04-20 08:17:50 +00:00
|
|
|
$this->assertIsIntAndEquals( $variation_low_stock_amount, wc_get_low_stock_amount( $var1 ) );
|
2021-03-15 17:31:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test wc_get_low_stock_amount with a variable product which has low stock amount set on the variation level,
|
|
|
|
* and also on the parent level. Should use the value from the variation.
|
|
|
|
*/
|
|
|
|
public function test_wc_get_low_stock_amount_variation_set_parent_set() {
|
|
|
|
$site_wide_low_stock_amount = 3;
|
|
|
|
$parent_low_stock_amount = 5;
|
|
|
|
$variation_low_stock_amount = 7;
|
|
|
|
|
|
|
|
// Set the store-wide default.
|
2021-04-20 08:17:50 +00:00
|
|
|
update_option( 'woocommerce_notify_low_stock_amount', strval( $site_wide_low_stock_amount ) );
|
2021-03-15 17:31:31 +00:00
|
|
|
|
|
|
|
// Set the parent low stock amount.
|
|
|
|
$variable_product = WC_Helper_Product::create_variation_product();
|
|
|
|
$variable_product->set_manage_stock( true );
|
|
|
|
$variable_product->set_low_stock_amount( $parent_low_stock_amount );
|
|
|
|
$variable_product->save();
|
|
|
|
|
|
|
|
// Set the variation low stock amount.
|
|
|
|
$variations = $variable_product->get_available_variations( 'objects' );
|
2021-04-20 07:42:07 +00:00
|
|
|
$var1 = $variations[0];
|
2021-03-15 17:31:31 +00:00
|
|
|
$var1->set_manage_stock( true );
|
|
|
|
$var1->set_low_stock_amount( $variation_low_stock_amount );
|
|
|
|
$var1->save();
|
|
|
|
|
2021-04-20 08:17:50 +00:00
|
|
|
$this->assertIsIntAndEquals( $variation_low_stock_amount, wc_get_low_stock_amount( $var1 ) );
|
2021-03-15 17:31:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test wc_get_low_stock_amount with a variable product which has low stock amount set on the parent level,
|
|
|
|
* but NOT on the variation level. Should use the value from the parent.
|
|
|
|
*/
|
|
|
|
public function test_wc_get_low_stock_amount_variation_unset_parent_set() {
|
|
|
|
$site_wide_low_stock_amount = 3;
|
|
|
|
$parent_low_stock_amount = 5;
|
|
|
|
|
|
|
|
// Set the store-wide default.
|
2021-04-20 08:17:50 +00:00
|
|
|
update_option( 'woocommerce_notify_low_stock_amount', strval( $site_wide_low_stock_amount ) );
|
2021-03-15 17:31:31 +00:00
|
|
|
|
|
|
|
// Set the parent low stock amount.
|
|
|
|
$variable_product = WC_Helper_Product::create_variation_product();
|
|
|
|
$variable_product->set_manage_stock( true );
|
|
|
|
$variable_product->set_low_stock_amount( $parent_low_stock_amount );
|
|
|
|
$variable_product->save();
|
|
|
|
|
2021-03-16 12:08:29 +00:00
|
|
|
// Don't set the variation low stock amount.
|
2021-03-15 17:31:31 +00:00
|
|
|
$variations = $variable_product->get_available_variations( 'objects' );
|
2021-04-20 07:42:07 +00:00
|
|
|
$var1 = $variations[0];
|
2021-03-15 17:31:31 +00:00
|
|
|
|
2021-04-20 08:17:50 +00:00
|
|
|
$this->assertIsIntAndEquals( $parent_low_stock_amount, wc_get_low_stock_amount( $var1 ) );
|
2021-03-15 17:31:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test wc_get_low_stock_amount with a variable product which *doesn't have* low stock amount set either on the parent level,
|
|
|
|
* or on the variation level. Should use the value from the site-wide setting.
|
|
|
|
*/
|
|
|
|
public function test_wc_get_low_stock_amount_variation_unset_parent_unset() {
|
|
|
|
$site_wide_low_stock_amount = 3;
|
|
|
|
|
|
|
|
// Set the store-wide default.
|
2021-04-20 08:17:50 +00:00
|
|
|
update_option( 'woocommerce_notify_low_stock_amount', strval( $site_wide_low_stock_amount ) );
|
2021-03-15 17:31:31 +00:00
|
|
|
|
|
|
|
// Set the parent low stock amount.
|
|
|
|
$variable_product = WC_Helper_Product::create_variation_product();
|
|
|
|
$variable_product->set_manage_stock( false );
|
|
|
|
|
2021-03-16 12:08:29 +00:00
|
|
|
// Don't set the variation low stock amount.
|
2021-03-15 17:31:31 +00:00
|
|
|
$variations = $variable_product->get_available_variations( 'objects' );
|
2021-04-20 07:42:07 +00:00
|
|
|
$var1 = $variations[0];
|
2021-03-15 17:31:31 +00:00
|
|
|
$var1->set_manage_stock( false );
|
|
|
|
|
2021-04-20 08:17:50 +00:00
|
|
|
$this->assertIsIntAndEquals( $site_wide_low_stock_amount, wc_get_low_stock_amount( $var1 ) );
|
2021-03-15 17:31:31 +00:00
|
|
|
}
|
|
|
|
|
2020-12-17 16:42:32 +00:00
|
|
|
}
|