=== Plugixa Inventory ===
Contributors: zakaria04, freemius
Tags: inventory, stock, warehouse, inventory management, stock control
Requires at least: 6.5
Tested up to: 7.1
Requires PHP: 8.2
Stable tag: 1.0.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Inventory for WordPress: items, warehouses, stock movements and an append-only ledger, with CSV import and export, in a fast React admin.

== Description ==

Plugixa Inventory turns WordPress into a working stock system. It stores records in its own
normalized database tables rather than as posts, so lists, filters and reporting stay fast as your
history grows.

**Stock that is actually per warehouse**

Every quantity is held against a specific (item, warehouse) pair, so "how much is in the west
depot" is a question the dashboard can answer - rather than being netted to zero against a single
home location, which is what happens when an item has one stock number and one address.

**An append-only ledger**

Every change to every quantity is written to a stock ledger that nothing can edit or delete: no
REST route, no admin screen, and a veto in the data layer. On-hand quantities are derived from it,
and a built-in reconcile proves they still are - on demand, from the admin, or from WP-CLI.

**Records**

* Items: assets, consumables and sellable goods, with SKUs, barcodes and reorder levels
* Warehouses: locations, with their own stock levels and per-warehouse valuation
* Categories
* Recipients: the people assets are checked out to

**Operations**

* Stock movements: check in, check out, add and remove stock
* Documents are drafted, then finalized. Finalizing is what writes the ledger, and a finalized
  document cannot be edited or deleted.

**Costing**

Stock on hand is valued at what it cost you - the item's cost price, falling back to its sale price
for an item with no cost recorded. Valuing inventory at what it sells for would overstate it by your
whole margin.

Stock leaving is costed separately, on the ledger row that records the removal, so what a movement
cost and what the remaining stock is worth are two questions with two answers.

**Dashboards**

A stock dashboard with valuation by type and by warehouse, a movement trend, top movers and the
items closest to running out - and a per-warehouse view with its own stock list, low-stock list and
activity feed.

**Import and export from a spreadsheet**

Bring items, categories, warehouses and people in from a CSV, with a column-matching step before
anything is written. Categories and warehouses are found by their name or their code, so the file
can say "Power tools" rather than an id - and a line naming something that does not exist is
reported by line number instead of being invented for you.

Opening stock comes in as a real, finalized stock movement rather than a number written onto a
record, so the ledger and the valuation agree with it from the first day. Large files are imported
in batches and can be resumed, and an import can be reverted: the records it added go to the trash
and the stock it posted is taken back out with a reversing document.

Every list has an Export button that writes what you are looking at - filters and all - to a CSV.

**On the front end, not only in wp-admin**

Add `[plugixa_inventory_app]` to a page and the whole application runs there, inside your theme,
with your header and footer still on the page and a full-screen button in its toolbar. It is the
same application and the same API, so access rules are identical - staff who should not be in
wp-admin never have to go there, and there is no second set of permissions to maintain.

**Built to stay correct**

* Concurrent finalizes cannot oversell. The sufficiency check is the WHERE clause of the write,
  so there is no window between deciding and writing.
* A daily check compares every on-hand quantity against the ledger and reports anything that
  disagrees. It reports; it never silently corrects.
* `wp plugixa-inventory stock reconcile` does the same from the command line, for sites too large
  for a browser request.

== Installation ==

1. Upload the plugin to `/wp-content/plugins/plugixa-inventory`, or install it through Plugins →
   Add New.
2. Activate it. The database tables are created on activation.
3. Open **Plugixa Inventory** in the admin menu.
4. Optional: put the app on the front end of your site by adding the `[plugixa_inventory_app]`
   shortcode to a page. See the FAQ below.

Administrators have access by default. To give other people access, go to **Configuration → Roles**
and either assign the **Inventory Manager** role that ships with the plugin, or build your own from
these six capabilities:

* `plugixa_inventory_view`: see items, stock and reports
* `plugixa_inventory_create`: add records and raise documents
* `plugixa_inventory_edit`: change records and finalize documents
* `plugixa_inventory_delete`: trash and restore records
* `plugixa_inventory_export`: download CSV exports
* `plugixa_inventory_manage_settings`: change plugin settings

Grant at least `plugixa_inventory_view`, or the person can open the app but every screen in it will
refuse. Do not grant `plugixa_inventory_manage` on its own: it is derived from the six above rather
than stored, and on its own it shows the menu while every request behind it is still declined.

== Frequently Asked Questions ==

= Can staff use the inventory without going into wp-admin? =

Yes. Add `[plugixa_inventory_app]` to any page and the whole application appears on it, inside your
theme, with your header and footer where they always are. There is a full-screen button in the app's
toolbar for when someone needs the room.

It is the same application the admin screen loads and it talks to the same API, so permissions are
identical - there is no second set of rules to keep in step. Anyone without access sees a short
"sign in" notice instead, and the application is never loaded for them.

= What options does the shortcode take? =

* `width`: `wide` (default), `full` or `content`. `wide` and `full` use your theme's own wide and
  full alignments. `content` keeps the app in the normal text column, which is usually too narrow to
  be comfortable.
* `height`: a number of pixels. Left out, the app sizes itself to the window.
* `mode`: `embed` (default), or `full` to give the app the whole page with no theme around it.

For example: `[plugixa_inventory_app width="full" height="800"]`

= Why does the app appear in a frame rather than directly in the page? =

Because it is the only way it can keep working on any theme. The application is built with Material
UI, whose styling is deliberately low-specificity so that it is easy to override - and a theme's own
form styling beats it by construction. Any reset strong enough to protect the app would also flatten
the theme around it, and the app's own baseline styles would restyle your header and footer links
and repaint the page background.

A frame keeps the two apart completely, so your theme stays exactly as you designed it and the
inventory looks the same on every site.

= What happens to my inventory if I delete the plugin? =

Nothing, unless you ask for it. Deleting the plugin removes its files and keeps every item,
warehouse, document and ledger row, so installing it again picks up exactly where you left off.
Deactivating never deletes anything either.

To remove the data as well, a site administrator turns on Settings → Uninstall → "Delete all
inventory data when the plugin is deleted" before deleting. Even then nothing is removed while
another copy of the plugin is still installed - for example the Pro build beside the free one - 
because that copy uses the same data.

= Does it store stock as posts or custom post types? =

No. It uses its own database tables. Stock levels, ledger rows and document lines are all
relational data, and storing them as posts and post meta makes every list and report slower as the
history grows.

= Can stock go negative, or be sold twice? =

No. The check that there is enough stock is part of the same SQL statement that removes it, so two
people finalizing at the same moment cannot both succeed against the same units. The second one is
told the stock changed and nothing is written.

= Can I delete a ledger row? =

No, and there is no setting for it. The ledger is the record that every on-hand quantity is derived
from; a ledger somebody can edit is not an audit trail. Correct a mistake with a second, opposite
document, which is visible - the same thing every stock system does, and what the audit trail is
for.

= Does it need any external service? =

Not to manage your inventory. Every item, warehouse, document, ledger row and report is read from
and written to your own WordPress database, and no inventory data is ever sent anywhere. There is
no analytics call, no remote rendering and no vendor phone-home.

The one connection the plugin can make is to Freemius, which handles licensing and updates, and it
is described in full under "External services" below.

= Where is the source for the JavaScript the plugin loads? =

Inside the plugin, not on a server somewhere. The admin application is written in TypeScript and
ships at `assets/backend/app/src/`, beside the `package.json`, `package-lock.json` and
`vite.config.js` that build it, so what you download is what the bundle was compiled from.

Rebuild it with `cd assets/backend/app && npm install && npm run build`, which needs Node.js 20.19+
or 22.12+. Every dependency version is pinned in the lock file, so the build is reproducible.

The compiled output carries the same directions: `assets/backend/build/SOURCE.txt` names the source
directory and the rebuild command, and each bundle opens with a comment saying it is generated and
where its source is.

== Screenshots ==

1. Dashboard: stock value, low stock, movement trend and top movers
2. Items: the catalogue, with on-hand totals per item
3. Stock movement: a draft document before it is finalized
4. Stock ledger: every change ever made, newest first
5. Warehouse overview: stock, low stock and activity for one location
6. Stock health: the reconcile that proves the numbers still follow from the ledger

== External services ==

This plugin connects to one third-party service, and only for licensing and updates. No inventory
data - no item, warehouse, document, quantity, cost or ledger row - is sent to it or to anywhere
else, ever.

= Freemius =

Used for licence activation, plugin updates, and an optional opt-in. On activation you are shown
an opt-in screen; if you skip it, no identifiable data is sent. When you activate a licence or
check for an update, your site URL, the plugin and SDK versions and your licence key are sent to
https://api.freemius.com. If you opt in, the data that screen lists is sent to the same address:
your WordPress user's first and last name and email address; your site's homepage URL and title,
WordPress and PHP versions and site language; the plugin's version and whether it is active or
uninstalled; and, unless you switch that item off on the opt-in screen, the names, slugs and
versions of your installed plugins and themes and whether each is active.
Terms of service: https://freemius.com/terms/
Privacy policy: https://freemius.com/privacy/

There is no other outbound request. The Freemius SDK in `vendor/freemius/` is the only code in the
plugin that performs one - the plugin's own code contains no `wp_remote_*` or cURL call at all.
Fonts and icons are served from your own site; nothing is loaded from a CDN or from Google Fonts.

== Changelog ==

= 1.0.0 =
* Initial release.

== Upgrade Notice ==

= 1.0.0 =
Initial release.
