# 📦 Inventory Management Scanner

A mobile-friendly inventory web app built with HTML, CSS, and JavaScript. It uses ZXing for camera scanning and SheetJS for Excel exports. Records and person profiles are stored in the browser's local storage on the current device.

For step-by-step instructions in plain language, see the [User Guide](USER_GUIDE.md).

## Current working version

**Stable version 1.4.0** — saved profile management and recovery improvements.

- Scans are accepted after the same normalized barcode in the same format is decoded three times within 1.8 seconds.
- A repeated scan increments quantity only when the barcode, barcode type, person in charge, and stock action all match.
- The same barcode under a different person or stock action is saved as a separate row.
- The same barcode and stock action scanned as different barcode types are saved as separate rows.
- Each accepted scan uses the current Person in Charge and Action field values, including changes made while the camera is running.
- Person in Charge profiles are saved locally. Choose a prior name or select **Add a person...** to add another; profiles remain available after clearing inventory. Use the X beside a selected saved profile to remove it when no records use it. Profiles referenced by records cannot be removed, and Undo restores a profile if it restores a record that needs it.
- UPC-A and equivalent EAN-13 values are normalized to the same barcode text; different barcode types remain separate rows.
- The app uses ZXing only; unstable and invalid reads are not saved.

The running version is displayed at the bottom right of the page footer.

The totals show the number of table entries and the sum of their quantities separately. Quantity breakdowns are grouped by person and action, with each person's breakdown on a separate line, for example `YAP - Stock Take: 2, Stock In: 3`.

## Versioning

Releases follow Semantic Versioning (`MAJOR.MINOR.PATCH`). Keep the current version unchanged during routine edits. Bump it only when the user explicitly requests a deployment: increase MAJOR for incompatible changes, MINOR for backward-compatible features, and PATCH for fixes or maintenance. Changes made after 1.2.8 through the 1.3.0 deployment were combined in that release; later changes are tracked in subsequent releases.

## Changelog

### Version 1.4.0

- Allow unused saved Person in Charge profiles to be removed; profiles referenced by records remain protected.
- Restore a removed profile when Undo restores a record that uses it.
- Harden CSV formula protection against leading whitespace and minus-prefixed expressions.

### Version 1.3.0

- Added a header Settings menu for Scan Delay, column visibility, pagination, and links to the README and User Guide; search uses the full available row width.
- Added configurable pagination with custom integer page sizes from 10 to 100; search and sorting apply across all matches, while totals cover the full inventory.
- Moved Delete to the first table column, visible only in Edit mode, and reduced the default row-number column width.
- Added a repeatable minified deployment build and kept deployment documentation in `dist/`.

### Version 1.2.8

- Added reusable Person in Charge profiles that remain saved when inventory records are cleared.
- Required three matching barcode reads before accepting a scan and kept scan delay preferences across updates.

## Barcode scanning

- ZXing's multi-format reader supports the formats available in the bundled `@zxing/library` version, including:
  - **Retail:** EAN-13, EAN-8, UPC-A, UPC-E
  - **Industrial / logistics:** Code 128, Code 39, Code 93, Codabar, ITF, GS1 DataBar (RSS-14 and RSS Expanded)
  - **2D:** QR Code, Data Matrix, PDF417, Aztec
- The reader searches ZXing's full built-in multi-format set, retries a few times per second, and enables Code 39 extended characters. Actual scan results depend on camera quality, focus, lighting, and barcode condition.
- MaxiCode is not supported by the bundled ZXing decoder.
- The scanner is designed primarily for linear barcodes. 2D formats are also accepted by the multi-format reader.
- The camera preview is digitally magnified 1.35×. Only the video image within the visible scan guide is decoded; a barcode outside that guide will not be scanned.
- Continuous autofocus is requested when supported. The hardware zoom slider and torch control appear only when reported as supported by the active camera.
- Scan Delay defaults to 1.5 seconds, can be set to 1 second or more in half-second increments, and is saved with the other settings. Existing saved preferences are preserved. It prevents the same barcode from being counted again immediately; scanning a different barcode is not blocked.
- Scan Delay starts after an accepted scan; it does not delay the first scan. When rescanning the same barcode, allow for the selected cooldown plus about 0.4 seconds for three matching decodes under ideal conditions.
- Auto-Stop is optional and stops the camera after a successful scan. When it is off, scanning continues and accepts other barcodes immediately.
- Successful scans provide sound, vibration, and scan-guide feedback when supported by the device/browser.

### Validation and matching

- EAN-13, EAN-8, UPC-A, UPC-E, GS1 DataBar, and 14-digit ITF reads are checked using the applicable GS1 check digit. Invalid reads are rejected.
- A scan is accepted after the same normalized barcode in the same format is decoded three times within 1.8 seconds. This applies to all supported formats and helps reject unstable reads.
- UPC-A is normalized to a leading-zero 13-digit value; UPC-E is expanded to the equivalent 13-digit value. Equivalent UPC/EAN representations share the same barcode text, while the barcode type still keeps their records separate.
- Barcode text case is preserved.
- A record is grouped by **barcode + type + action + person**. Repeat scans matching all four increase that row's quantity. The same barcode with a different type, action, or person creates a separate row. The displayed type and time remain those from when each row was first created.
- Each scan uses the current Person in Charge and Action values when the barcode is accepted, so changing either field while the camera is running applies to subsequent accepted scans.

## Inventory and controls

- A Person in Charge profile is required to start scanning. Add reusable names with **Add a person...**; profiles remain when inventory is cleared. Available actions are **Stock Take**, **Stock In**, and **Stock Out**.
- The table shows barcode, type, quantity, action, person, time, and a delete control. Open **Settings** with the gear button to change Scan Delay, set Rows per page, or show and hide columns other than Delete. Pagination appears only when matching results exceed the selected page size; totals continue to include the full inventory. Drag a column heading's right-hand divider to resize it, or focus the divider and use the left/right arrow keys. Column visibility and widths are saved in local storage. The table can be scrolled horizontally.
- Totals show **Total Items** as the number of table rows and **Total Quantity** as the sum of row quantities. The action breakdown groups quantities by person, with each person on a separate line, for example `YAP - Stock Take: 2, Stock In: 3`.
- Search matches all record fields and updates 120 ms after typing pauses. Table columns with sort indicators can be sorted by tapping/clicking their headers.
- Edit mode allows changes to quantity and action. Changing an action to one already present for the same barcode and person merges the quantities.
- Undo restores the last scan, edit, or delete (up to 50 actions in the current page session). Undo history is not saved across reloads. Deleting the final record and clearing all records remove the undo history.
- Manual quantity/action edits are recorded in the edit log. Deletes are not logged. Clearing records also clears the edit log and requires confirmation; it cannot be undone.
- Records, edit logs, person profiles, person/action/scan-delay settings, and table column preferences are saved automatically in local storage. Profiles remain when inventory is cleared. Data is not synchronized to other devices or browsers.

## Exporting

- **Excel (.xlsx):** exports a Records sheet and, when edits exist, an Edit Log sheet.
- The Excel export library is loaded from its CDN the first time Excel export is requested, reducing initial page load for scanning and CSV use.
- **CSV:** exports the records as one file and, when edits exist, the edit log as a second file.
- Exported record fields are Barcode, Type, Quantity, Action, Person, and Time. The edit log contains Barcode, Field, Old Value, New Value, Person, Timestamp, and Modified.
- **Download** saves the export file(s) to the device.
- **Share or save to cloud** opens the device/browser share sheet when file sharing is supported. Choose an available destination, such as a messaging or cloud-storage app. Available destinations depend on the device and installed apps; the app does not upload directly to a specific cloud provider.
- If file sharing is unavailable, the app offers a download so the files can be shared manually.
- Chrome on Android does not currently allow websites to share `.xlsx` files through the Web Share API. Download Excel exports, then attach or upload them from the destination app. CSV exports can be shared when the browser supports file sharing.
- Use HTTPS (or localhost) and a mobile browser with Web Share API file support for the share sheet. Open the site directly in the browser rather than inside an embedded in-app browser; embedded frames may block sharing.
- CSV files can lose leading zeroes or display long numeric barcodes in scientific notation when opened directly in spreadsheet software. Import the Barcode column as text to preserve it.

## Setup

1. Keep `index.html`, `style.css`, and all `scanner.*.js` files together.
2. Serve the folder from `localhost` for local use or from a site using HTTPS. Camera access generally requires a secure context; opening the HTML directly as a file may not permit it.
3. Open the page in a modern browser and grant camera permission.
4. Internet access is required for the scanner to load ZXing from its CDN. SheetJS is loaded from its CDN when Excel export is first requested.

The app uses deferred scripts to avoid blocking initial page parsing. The local scripts are loaded in order: `scanner.core.js`, `scanner.ui.js`, `scanner.validation.js`, then `scanner.export.js`.

For deployment, serve the contents of `dist/`. It contains the minified app assets and copies of this README and the User Guide so the settings links open successfully. After changing root app sources, run `powershell -ExecutionPolicy Bypass -File .\.vscode\build.ps1` from the project folder to regenerate the minified deployment assets and HTML. Version numbers remain unchanged until a deployment is explicitly requested.

## Troubleshooting and limitations

- If styling or behavior is missing, keep the app files together and use their exact filenames.
- If the camera does not start, check browser camera permission, close other apps using the camera, and confirm the page is served from HTTPS or localhost.
- If torch or hardware zoom controls are hidden, the active camera/browser does not report support for that feature.
- Scan quality still depends on the barcode condition, lighting, camera resolution, and framing. Keep the complete barcode inside the guide; use torch or hardware zoom when available.
- This app stores data in browser local storage. Clearing browser/site data or switching devices/browsers can make the saved inventory unavailable.

## Project files

| File | Purpose |
| --- | --- |
| `index.html` | Interface and dependency loading |
| `style.css` | Responsive layout and visual styles |
| `scanner.core.js` | App state, camera lifecycle, scanning, cooldown, persistence |
| `scanner.ui.js` | Table, sorting, search, edit mode, undo, and messages |
| `scanner.validation.js` | Barcode normalization and validation |
| `scanner.export.js` | Excel/CSV generation and sharing |
| `.vscode/build.ps1` | Minified deployment build |
| `README.md` | Project overview and release history |
| `USER_GUIDE.md` | Step-by-step operating guide |

## Design notes

- ZXing is pinned to `@zxing/library@0.21.3` rather than tracking the latest release.
- Similar-looking barcodes are not automatically merged: near-identical codes may identify different products.
