=== Clypper's Bin Locations for WooCommerce ===
Contributors: casperh123
Tags: bin location, warehouse, pick list, packing slip, barcode
Requires at least: 6.8
Tested up to: 7.1
Requires PHP: 8.1
Stable tag: 1.2.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Know where every product sits, and pick orders in walking order with sorted pick lists, packing slips and barcode labels.

== Description ==

If you ship from your own stockroom, you know the routine. An order comes in, and someone walks the shelves looking for each product. New staff ask where things are. The packing slip lists items in whatever order the customer added them.

Clypper's Bin Locations gives every product a place, such as `A-01-03` for aisle A, shelf 1, bin 3, and puts that place everywhere your team picks and packs.

= Pick orders in one walk =

Select a batch of orders and choose "Generate pick list". You get one list for all of them, with each product on a single line, the quantities added up, and everything in walking order, so `A-2` comes before `A-10`. Print it, or open it on a phone and tick lines off as you go: tap a line, or scan a bin label or product barcode, and the list says how many to take and how far along you are, at the top of the screen while you scroll. One link makes a pick list of every processing order. Picking changes no orders; if you want, a setting adds a button that marks the picked orders completed.

= Packing slips in shelf order =

Packing slips and delivery notes list items by bin location, with the location under each item. This works with these packing slip plugins:

* PDF Invoices & Packing Slips for WooCommerce (WP Overnight)
* Print Invoice & Delivery Notes for WooCommerce (Tyche Softwares)
* PDF Invoices, Packing Slips, Delivery Notes and Shipping Labels (WebToffee)

= Find anything with a scan =

Print barcode labels for your shelves and products on standard A4 or US Letter label sheets, or on a 4 × 2″ label printer. Product labels carry the SKU, shelf labels the bin, and one button prints a label for every bin in use. On the Products → Bin locations page, scan a shelf to see what is in it, or scan a product to see where it lives. Move one product, or the whole shelf, in one step, and undo a recent move with one click. Any USB or Bluetooth scanner works, and phones can use their camera (Android and iPhone).

= Easy to set up and keep tidy =

* Add bin locations in the product editor, with quick edit, or with bulk edit for many products at once. Moving aisle A to aisle B is one bulk edit, variations included.
* Import a whole stockroom from a CSV file with WooCommerce's own product importer. A column named "Bin location", "Bin" or "Bin number" is matched by itself (only the first, if a file has several). Several places in one "Also stored in" cell are separated by commas or semicolons. An empty cell clears the product's bin location, so leave the column out to keep the bins you have.
* Variations use their parent's bin location until you give them their own.
* Products stored in more than one place list the other places under "Also stored in".
* A filter in the product list shows which products still need a bin location.
* Bin locations are stored in uppercase, so `a-1` and `A-1` never become two places (a setting). Bins saved before are uppercased with one click.
* An overview flags places spelled two ways, such as `A-1-3` and `A-01-03`, and merges them in one click.
* Each product remembers who changed its bin location, and when.
* Call it "Shelf", "Location" or anything else. The name is a setting and is used everywhere.

= Free, and private =

Every feature is free. The plugin runs entirely on your own site and only shows bin locations to your staff: in the admin, on pick lists and packing slips, and in emails to the shop. It works with High-Performance Order Storage (HPOS).

= For developers =

Bin locations are available in the WooCommerce REST API (`wc/v3` products and variations) and from WP-CLI. A sync that sends unchanged values does not save the product again.

* `bin_location`: the product's or variation's own bin location. An empty string clears it; `null` leaves it alone.
* `bin_location_overflow`: a list of the other places it is stored. Entries holding commas or semicolons are split, as in every other form.
* `bin_location_effective` (read-only): the bin used for picking, a variation's parent's when it has none.
* `bin_location_history` (read-only, `context=edit`): the last 20 changes, each with `time`, `user`, `from`, `to`, `via` and `kind: "overflow"` for overflow changes.
* `?bin_location=A-1` lists what is stored there (ignoring case, inherited bins included; on products, a variable product counts for its variations). `?bin_location_missing=true` lists what has none. Both are listed under `OPTIONS`.
* Values are cleaned (one line, no `<` or `>`) and, with the uppercase setting on, read back in uppercase: `a-1` is returned as `A-1`.
* The bin meta (`_clypper_bin_number`, `_clypper_bin_overflow`) is written through the plugin even when sent in `meta_data`, and left out of `meta_data` in responses: use the fields.
* The action `clypper_bin_location_changed( $product, $from, $to, $via, $kind )` fires on every change, before the product is saved. The filter `clypper_bin_location_pick_list_limit` sets how many processing orders one pick list holds (200).

WP-CLI commands exit with code 1 when a product, order or bin location is not found, or `get` finds no bin location:

* `wp clypper-bin get <product>` and `wp clypper-bin set <product> <bin>`, by ID or SKU
* `wp clypper-bin list` lists every bin location in use, with how many products are in it
* `wp clypper-bin rename <from>... --to=<bin>` moves everything in one or more bin locations
* `wp clypper-bin audit` lists published products and variations without a bin location, each variation on its own (the product list's filter shows the variable product instead, and counts drafts too)
* `wp clypper-bin pick-list [--orders=<ids>]` prints a pick list

Clypper's Bin Locations is made by [Clypper Technology](https://clyppertechnology.com), a Danish company that builds and runs WooCommerce shops. Questions and ideas are welcome in the support forum.

== Installation ==

1. Install and activate the plugin from Plugins → Add New. WooCommerce must be active.
2. Go to Products → Bin locations. Until products have bin locations, it shows these steps with links.
3. Open a product, go to the Inventory tab, and fill in "Bin location". For many products at once, use quick edit, bulk edit or import a CSV with a "Bin location" column. Or scan a shelf's code on the Bin locations page and put products away by scanning their SKUs.
4. On the Orders screen, click "Pick list: processing orders", or select some orders and choose "Generate pick list".

Settings are under WooCommerce → Settings → Products → Bin locations.

== Frequently Asked Questions ==

= What format should bin locations have? =

Any format you like: `A-01-03`, `Shelf 3`, `R2/S4`. Use one place per field; other places go under "Also stored in". Numbers are sorted as numbers, so `A-2` comes before `A-10`.

= Which permissions does a picker need? =

Shop managers can do everything. For a custom "picker" role, the pick list needs `edit_shop_orders` and `edit_others_shop_orders` (to see every customer's order) plus `view_admin_dashboard`, or WooCommerce sends the user to My Account. Products → Bin locations needs `edit_products`; the overview, merges and labels for every bin also need `edit_others_products`.

= Can customers see bin locations? =

No. They only appear in the admin, on pick lists and packing slips, and in emails sent to the shop.

= Does it change my stock levels? =

No. The plugin only stores and shows where products are.

= Can a product be in more than one place? =

Yes. Give it a main bin location and any number of others under "Also stored in". The pick list sorts by the main one and mentions the others, and labels and lookups cover all of them.

= Which barcode scanners work? =

Any scanner that types like a keyboard, which is most USB and Bluetooth scanners. Android phones and iPhones can also scan with their camera. Labels use Code 128, which every scanner reads.

= Can I get the pick list as a PDF? =

Print it and choose "Save as PDF".

= What happens to my data if I uninstall? =

Deleting the plugin removes its settings. Bin locations, "Also stored in" places and the change history stay on your products and variations, and order lines keep the bin they were picked from, so everything is back if you reinstall.

To remove them from every product and variation too, run this WP-CLI command, before or after deleting the plugin:

`wp eval 'foreach ( array( "_clypper_bin_number", "_clypper_bin_overflow", "_clypper_bin_history" ) as $key ) { delete_metadata( "post", 0, $key, "", true ); }'`

The bin on past order lines is stored under `_clypper_bin_location`. To remove it as well, with WooCommerce active, run `wp eval 'delete_metadata( "order_item", 0, "_clypper_bin_location", "", true );'`.

= Does the plugin include third-party code? =

Yes, for camera scanning in browsers without a built-in barcode reader (Safari, Firefox), in `assets/zxing`:

* [barcode-detector 3.2.3](https://github.com/Sec-ant/barcode-detector/tree/v3.2.3) (MIT), as `barcode-detector.js` (its `dist/iife/polyfill.js`). One change: its default download address for the decoder is blanked, since the plugin always loads the decoder from your site.
* [zxing-wasm 3.1.6](https://github.com/Sec-ant/zxing-wasm/tree/v3.1.6) (MIT), as `zxing_reader.wasm` (unchanged), compiled from [zxing-cpp](https://github.com/zxing-cpp/zxing-cpp) (Apache-2.0).

Both are loaded from your own site, never from elsewhere. The licences and the source of each file are in `assets/zxing/LICENSE.txt`.

== Screenshots ==

1. A pick list for a batch of orders: one line per product, in walking order. Scan a bin label or barcode to tick it off and see how far along you are.
2. Barcode labels, ready to print on label sheets or a label printer.
3. The Bin locations page: everything in a bin location, with a one-step move.
4. The product list sorted by bin location, with a filter for products whose bin location is missing.
5. A variation without its own bin location shows the one it inherits.
6. Bulk edit: replace a prefix when you re-rack an aisle.
7. A packing slip with items in bin location order.
8. Settings: your own label, uppercase storage, admin emails, packing slip sorting and completing orders from a pick list.
9. The bin overview: every bin location in use, with misspellings flagged and merged in one click.
10. The same pick list on a phone with a Bluetooth scanner: each scan ticks a line and says what to take next.

== Changelog ==

= 1.2.0 =
* New: Products → Bin locations, the plugin's home. Scan a shelf or a product with a scanner or a phone's camera (Android and iPhone), move one product or a whole shelf, put products away by scanning, and undo a recent move.
* New: pick lists for a batch of orders, or for every processing order in one click: each product on one line, in walking order. Tick lines off on a phone by tapping or scanning; a setting adds a button that completes the picked orders.
* New: packing slips sorted by bin location, now also with Print Invoice & Delivery Notes (Tyche Softwares) and WebToffee's packing slips and delivery notes.
* New: barcode labels for products and shelves, on A4 or US Letter label sheets or a 4 × 2″ label printer.
* New: bin locations for variations, which use their parent's until they get their own.
* New: "Also stored in", for products kept in more than one place.
* New: quick edit, bulk edit (including replacing a prefix), CSV import and export, and a sortable column, filter and search in the product list.
* New: an overview of every bin location in use, which merges places spelled two ways in one click. Bin locations are stored in uppercase (a setting).
* New: a change history on each product, your own name for "Bin location", bin locations in emails to the shop, a Danish translation, and REST API and WP-CLI support.
* Fix: bin locations now appear on "PDF Invoices & Packing Slips" packing slips, and on orders for variations.
* Requires PHP 8.1, WordPress 6.8 and WooCommerce 9.8. Works with High-Performance Order Storage (HPOS).

= 1.0.0 =
* Initial release.
