When a product is saved its validate_props method is invoked,
and this recalculates the stock_status property based on whether
the product manages stock or not, the stock quantity, and the
value of the woocommerce_notify_no_stock_amount option.
In the case of variable products, and when stock is managed, the stock
was set to "instock" when the current stock was enough, but only
if the "stock_quantity" property was in the list of changed properties
for the object (the method in the base product class doen't check
for changed properties). This is a problem because the
wc_update_product_stock function updates stock_quantity but via direct
database modification, and thus stock_quantity isn't considered
modified. Therefore stock modifications via wc_update_product_stock
don't update stock_status on the product (e.g. when going from 0 to 1
after a refund the stock status will remain as "outofstock").
The fix consists of removing the check for changed properties since
it's not done anyway in the other cases (when stock is below the
woocommerce_notify_no_stock_amount threshold) nor in the base class.
Also, validate_props is refactored for readabiliyy, and an useless
set_stock_status() call placed right before save()
in wc_update_product_stock is removed.
When creating an order, if manage inventory is enabled then add a `_held_for_checkout` record with a expiry timestamp embedded. This is added in an atomic manner along with making a check whether we have current stock or not.
This record is removed when order status goes to either `processing` or `completed`.
Fixes some comments and a variable name in the stock increase methods.
There is however a logic problem remaining, I think, where the value taken for the per-item `_reduced_stock` meta value falls back to `true` when the meta key does not exists (line 266), however the key is deleted at the end of the loop (line 281), thus allowing the `wc_increase_stock_levels` methods to increase the stock again when re-run directly.
Plugins may create orders without the meta tag "_created_via"="checkout" for various purposes, e.g. a balance-due order for purchases via deposit, because only the deposit order should reduce stock on checkout. The SUMO Payment Plans plugin does exactly this, but core WC handles such orders inconsistently:
- wc_get_held_stock_quantity() counts their items against held stock, but
- wc_cancel_unpaid_orders() only cancels old orders with a meta tag of "_created_via"="checkout"
This PR fixes that inconsistency, which on my site was preventing a user from adding an in-stock product to her cart, just because a balance-due order for the same product was pending.
Workaround: clear the setting WC > Products > Inventory > Hold Time (default 60 minutes), which inhibits the use of wc_get_held_stock_quantity().
Allow product object to be passed through, remove cache clearing which is done during save(), and allow the caller to define whether or not an update routine is already in progress.