=== Shared Stock for WooCommerce ===
Contributors: catcodestudio
Tags: woocommerce, stock, inventory, shared stock, variations
Requires at least: 6.2
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.0.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

One stock for many product cards: products and variations from the same shelf share one pool, with no overselling under simultaneous orders.

== Description ==

Some shops list one physical item more than once: the same shirt on its own and in a gift box, one fabric roll sold as several colour names, a product in two languages or two catalogues, an item sold alone and as part of a set. WooCommerce keeps a separate stock for every card, so the shop owner corrects numbers by hand and still sells the last unit twice.

Shared Stock puts such cards into a **stock pool** — one stock figure that all of them sell from.

* **One stock, many cards.** Simple products, variations with their own stock, and variable products that keep one stock on the product level can join a pool. Every member shows what the pool can still cover.
* **Every stock change goes to the pool.** Paid orders, orders put on hold or into processing, cancelled and failed orders, refunds with restock, order items edited in the admin — WooCommerce's own stock changes are sent to the pool, and all members follow.
* **Typing a stock figure into any member sets the pool.** The product screen, quick edit, bulk edit, the REST API and CSV imports keep working the way they did.
* **No overselling under simultaneous orders.** WooCommerce reserves stock per product, so two different cards of one pool could each take "the last unit" at the same second. Shared Stock reserves the pool itself: checkouts of one pool take their turn under a database lock, and stock held by other unpaid orders of *any* member is counted. Works with the classic and the block checkout.
* **Cart checks across members.** Two cards of one pool in one cart are checked together — on add to cart, on the cart page and in the block checkout — so the shopper hears about it before paying.
* **Deliveries without races.** "Add or take" on the pool screen changes the stock relative to its current value, so a delivery booked while orders come in is never lost.
* **Daily repair and WP-CLI.** Member cards are brought back to the pool figure once a day (for plugins that write stock straight into the database); `wp catcode-shared-stock list|members|set|adjust|resync` for scripts.
* **HPOS and blocks.** Compatible with High-Performance Order Storage and the Cart and Checkout blocks.


= How the numbers work =

The pool holds the real count. A member card shows the pool's stock (with units per sale, the whole sales the pool can still cover). When a member is sold, the pool goes down by the quantity sold and every member shows the new figure. A new, empty pool takes the stock of the first product added to it, so joining the first card does not wipe the count.

== Installation ==

1. Install and activate the plugin. WooCommerce must be active.
2. Open **WooCommerce → Shared Stock** and create a pool.
3. Add the products and variations that sell from the same shelf — on the pool screen, or with the "Shared stock pool" field in the Inventory tab of a product or variation.
4. Set the pool's stock, or let it take the stock of the first product you add.

== Frequently Asked Questions ==

= What happens to a product's own stock when it joins a pool? =

It starts managing its stock (if it did not) and shows the pool's stock from then on. When it leaves the pool, or the pool is deleted, it keeps the figure it showed at that moment as its own stock.

= Does it stop overselling when two customers pay at the same moment? =

Yes, as far as WooCommerce's stock hold allows: the pool is reserved when the order is placed (classic and block checkout), under a lock, counting the stock held by unpaid orders of all members. Keep "Hold stock (minutes)" in WooCommerce → Settings → Products → Inventory above 0 — with the hold switched off WooCommerce reserves nothing at checkout, and neither can the plugin.

= What about backorders? =

A member that allows backorders is not held back by the pool, exactly like WooCommerce treats a product with backorders. Its sales still take from the pool, which may go below zero; the other members then show as out of stock.

= Orders created in the admin or through the REST API? =

They change the pool when WooCommerce reduces stock for them (usually when the status becomes processing, completed or on hold). There is no checkout reservation for them, as in WooCommerce itself.

= Does it work with a persistent object cache? =

Yes. The pool is always read from the database, never from a cache, and every member card is written through WooCommerce's own stock functions, which clear the product caches.

= Which database does it need? =

MySQL or MariaDB with InnoDB, like WooCommerce. The lock between checkouts is a MySQL named lock (GET_LOCK). On a database without named locks the plugin still works, without the extra lock.

== Screenshots ==

1. Stock pools overview: stock, stock held by unpaid orders, available, members.
2. A pool: set or adjust the stock, the member cards and the stock each shows.
3. The "Shared stock pool" field in the Inventory tab of a product.

== Changelog ==

= 1.0.0 =
* First release: stock pools for products and variations, pool-level reservation at checkout under a lock, cart checks across members, HPOS and block checkout support, daily repair, WP-CLI.
