Complete inventory management and point-of-sale system for your Larapen site. Track stock across multiple warehouses, process sales via a built-in POS, manage cash registers, and monitor inventory with real-time alerts and comprehensive reports.
Multi-Warehouse Inventory
Track stock across multiple warehouses/locations with per-warehouse quantities, reorder levels, and bin locations.
Stock Movements
Record all stock changes: receive, dispatch, transfer between warehouses, and inventory adjustments with full audit trail.
Sales Terminal
Full-screen cash register with product search, barcode scanning, cart management, and payment processing.
Cash Registers
Track cashier sessions with opening/closing amounts, expected vs counted cash, and automatic discrepancy detection.
Stock Alerts
Automatic low stock notifications when quantities drop below reorder levels. Email and database notifications.
Reports & Analytics
Dashboard with sales charts, stock valuation reports, movement analysis, and top-selling product rankings.
Use Cases
Retail Store Management
Track inventory in-store and in warehouse, process sales via POS, monitor stock levels. Get alerts when products run low and analyze sales trends with built-in reports.
Warehouse Operations
Multi-location inventory with transfers, adjustments, and comprehensive movement logging. Track every stock change with an immutable audit trail across all your warehouses.
Restaurant / Cafe
Manage ingredient stock with unit tracking (kg, liters, pieces), receive deliveries, track usage. Use the POS for front-of-house sales and monitor ingredient levels.
Requirements
- Larapen CMS v1.0.0 or later
- PHP 8.3+
- MySQL 8.0+
Installation
Step 1: Upload the Add-on
In the admin panel, go to Admin → Extensions → Add-ons and click the Upload Add-on button. Select the add-on’s ZIP file: the system extracts it automatically and the add-on appears in the installed add-ons list.
Step 2: Activate the Add-on
Find POS in the list and click Activate. Its migrations, seeders (if any) and permissions are set up automatically.
Step 3: Configure
Navigate to Admin → POS → Settings to configure outlets, registers, receipt printing, and payment methods. See Configuration.
Purchase Code (License Key)
POS is sold as a separate product, so it has its own purchase code (license key), distinct from the purchase code of the main application and from the one of every other add-on. You are asked for it when you activate POS in Admin panel → Add-ons.
Our products are sold on three platforms. The way you receive a purchase code depends on where you bought the product.
| Platform / Marketplace | How you get the purchase code | Where to find it again |
|---|---|---|
| bedigit.com Store In-site purchase (Shop) |
Generated automatically when the order is paid, then sent by email, either in its own license email, or inside the order confirmation email. | My Account → My Licenses on bedigit.com |
| Gumroad | Created as soon as Gumroad notifies us of the sale, then sent in a separate email, in addition to the Gumroad receipt. | The license email, your Gumroad Library, and My Account → My Licenses on bedigit.com |
| Envato Market CodeCanyon |
Issued by Envato, not by us, and never sent by email: you download it yourself from your Envato account. | Envato account → Downloads → License certificate & purchase code |
1. bedigit.com Store (in-site purchase)
- As soon as the order’s payment status becomes Paid, a license key is generated automatically for every licensed item in the order (one key per purchased unit: buying 3 units gives 3 distinct keys).
- It is emailed to the address used on the order, either in a dedicated license email or inside the order confirmation email. Check your inbox and your spam / junk folder.
- The key stays available in your account under My Account → My Licenses. Keys are masked in the list; open the license detail page to reveal and copy the full key, see the domains it is activated on, and deactivate a domain to free an activation slot.
- The matching invoice is under My Account → My Orders.
2. Gumroad
- A Gumroad purchase produces two separate emails: the Gumroad receipt (sent by Gumroad, giving access to the files) and a license key email (sent by bedigit.com) that contains your purchase code.
- The license key email is generated as soon as Gumroad notifies us of the sale, so it normally arrives within seconds of the payment. Here too, check your inbox and your spam / junk folder.
- When the Gumroad product uses Gumroad’s own license-key feature, the same key also appears in your Gumroad receipt and under Library → your purchase on gumroad.com.
- Use the same email address on bedigit.com as on Gumroad: your keys are then linked to your account automatically and listed under My Account → My Licenses, even if you register after the purchase. You can also add a Gumroad key manually from My Account → My Gumroad Licenses.
3. Envato Market (CodeCanyon)
- Envato purchase codes are issued and delivered by Envato Market, never emailed by us, so there is nothing to look for in your spam folder: you retrieve the code from your Envato account.
- Log in to your Envato / CodeCanyon account, open the Downloads page, find the item, and choose License certificate & purchase code from the Download dropdown. The code is written in that certificate.
- An Envato purchase code looks like
12345678-90ab-cdef-1234-567890abcdef(8-4-4-4-12 characters). It never changes, and renewing item support does not issue a new one. - Official Envato article: Where Is My Purchase Code?
Configuration
All settings are managed in Admin → POS → Settings (stored in the settings table, group pos).
Defaults are defined in config/pos.php.
General
| Setting | Description | Default |
|---|---|---|
pos_default_tax_rate |
Tax percentage applied to POS sales. | 0 |
pos_currency_symbol |
Currency symbol displayed on prices and receipts. | $ |
SKU & Barcode
| Setting | Description | Default |
|---|---|---|
pos_auto_generate_sku |
Automatically create a SKU for new products. | true |
pos_sku_prefix |
Prefix for auto-generated SKUs (e.g. STK-000001). | STK |
pos_barcode_enabled |
Enable barcode field on products and barcode scanning in the POS. | true |
Alerts
| Setting | Description | Default |
|---|---|---|
pos_low_pos_alerts_enabled |
Enable automatic low stock alert creation when quantities drop below reorder levels. | true |
pos_large_adjustment_threshold |
Quantity threshold for triggering large adjustment notifications. | 50 |
Sales & Receipts
| Setting | Description | Default |
|---|---|---|
pos_sale_number_prefix |
Prefix for generated sale numbers (e.g. SALE-000001). | SALE |
pos_receipt_header |
Custom text displayed at the top of printed receipts. | (empty) |
pos_receipt_footer |
Custom text displayed at the bottom of printed receipts. | (empty) |
Environment Variables
POS_DEFAULT_TAX_RATE=0
POS_CURRENCY_SYMBOL=$
POS_AUTO_GENERATE_SKU=true
POS_SKU_PREFIX=STK
POS_BARCODE_ENABLED=true
POS_LOW_POS_ALERTS=true
POS_LARGE_ADJUSTMENT_THRESHOLD=50
POS_SALE_PREFIX=SALE
Admin: Dashboard
The POS dashboard (POS → Dashboard) is the landing page for daily POS operations. It provides a quick overview of key metrics and fast access to common tasks.
KPI Cards
Six summary cards at the top of the page:
- Total Products: number of active POS products.
- Stock Value: total value of all inventory (cost price × quantity).
- Low Stock Alerts: count of active low stock alerts.
- Today’s Sales: number of sales completed today.
- Today’s Revenue: total revenue from today’s sales.
- Open Registers: number of currently open cash registers.
Quick Actions
One-click buttons for the most common operations:
- Open Terminal: jump to the sales terminal.
- Open Register: start a new register session.
- New Movement: go to the stock movements page.
- New Product: create a product.
- View Reports: go to the reports page.
Recent Activity
- Recent Sales: the last 5 sales with sale number, amount, status, and date.
- Recent Movements: the last 5 stock movements with product, type, quantity, and date.
Admin: Products
The Products page (POS → Products) manages your inventory catalog.
Products List
A paginated table showing:
- Name
- SKU
- Barcode
- Unit (piece, kg, g, liter, meter, box, pack)
- Cost Price
- Selling Price
- Total Stock (sum across all warehouses)
- Status (active / inactive)
Per-item actions: Edit, Delete. Bulk delete with checkbox selection. Soft-deleted products can be restored.
Creating & Editing Products
The product form includes the following fields:
- Name (translatable): product title displayed throughout the admin.
- Slug (translatable): URL-friendly identifier. Auto-generated from name if empty.
- Description (translatable): detailed product description.
- SKU: stock keeping unit. Auto-generated if
pos_auto_generate_skuis enabled. - Barcode: optional barcode value for POS scanning.
- Unit: measurement unit: piece, kg, g, liter, meter, box, or pack.
- Cost Price: purchase/manufacturing cost (used for valuation reports).
- Selling Price: retail price used in POS sales.
- Category: select from POS product categories.
- Featured Image: product image via the media library.
- Active toggle: inactive products are hidden from the POS and reports.
Stock Levels by Warehouse
On the product edit page, a Stock Levels by Warehouse table is displayed for users with the
pos.warehouses.access_all permission. This table shows each warehouse the product is assigned to
with its current stock quantity (as a read-only color-coded badge), reorder level, reorder quantity, and bin location.
The quantity is read-only: stock changes must go through the Stock Movements system to maintain a complete audit trail. Only the reorder level, reorder quantity, and bin location can be edited from this table.
SKU & Barcode
When pos_auto_generate_sku is enabled, new products automatically receive a SKU
using the format {prefix}-{zero-padded ID} (e.g. STK-000042).
You can override the auto-generated SKU at any time.
When pos_barcode_enabled is enabled, a barcode field appears on the product form.
Barcodes are used for quick product lookup in the POS via barcode scanner.
Admin: Categories
Product categories use the unified categories table with categorizable_type = 'pos_product'.
Categories are managed via POS → Categories.
- Name (translatable) and Slug (translatable, auto-generated).
- Description (translatable).
- Parent Category: supports hierarchical nesting.
- Position: ordering value.
- Is Active toggle.
Admin: Warehouses
The Warehouses page (POS → Warehouses) manages your storage locations.
Warehouse Fields
- Name (translatable): warehouse display name.
- Code: unique identifier code (e.g. WH-MAIN, WH-EAST).
- Address, City, Country: physical location.
- Phone and Email: contact information.
- Default toggle: marks this as the default warehouse for new stock movements and POS sales.
- Active toggle: inactive warehouses are excluded from movement forms and POS.
- Assigned Users: select which admin users can access this warehouse. Users not assigned to any warehouse can access all warehouses by default.
Warehouses are soft-deleted and can be restored.
Warehouse Detail Page
The warehouse detail page shows summary stats, warehouse information, assigned users, and the Products in Warehouse table.
The products table lists all products assigned to the warehouse with their stock quantity (read-only badge), reorder level, reorder quantity, bin location, and stock status. An edit button allows updating configuration fields (reorder level, reorder quantity, bin location), but stock quantity cannot be changed from this page: all quantity changes must go through Stock Movements.
A Movements button links to the Stock Movements page for recording stock in/out.
Default Warehouse
Exactly one warehouse should be marked as the default. The default warehouse is pre-selected in stock movement forms and used as the source warehouse for POS sales. If no default is set, the first active warehouse is used.
Warehouse Access Control
You can restrict which warehouses a user can access by assigning them to specific warehouses on the warehouse edit page. This controls what data they see across the entire POS module:
- Assigned users can only view and interact with data (registers, sales, movements, alerts, reports) from their assigned warehouses.
- Users with no assignment (i.e. not assigned to any warehouse) can access all warehouses by default.
- Users with the
pos.warehouses.access_allpermission bypass all warehouse filtering and can access everything regardless of assignments.
The filtering is applied automatically to all POS pages: warehouses list, registers, sales, stock movements, alerts, reports, and the sales terminal.
pos.warehouses.access_all permission.
Admin: Stock Movements
The Stock Movements page (POS → Movements) displays an immutable audit trail of all inventory changes.
Movement Types
| Type | Description | Effect |
|---|---|---|
| In | Stock received (purchase, delivery). | +quantity in destination warehouse |
| Out | Stock removed (waste, damage, write-off). | −quantity in source warehouse |
| Transfer | Stock moved between warehouses. | −source, +destination |
| Adjustment | Correct quantity after physical count. | Sets to new value |
| Sale | POS sale (created automatically). | −quantity |
| Return | Sale void (created automatically). | +quantity |
Creating Movements
Click the Record New button to open the movement creation modal directly on the movements page. The modal form includes:
- Select the movement type (In, Out, Transfer, or Adjustment).
- Select the product (searchable by name or SKU).
- Select the warehouse(s): source and/or destination depending on the type.
- Enter the quantity.
- Optionally add a reference (e.g. purchase order number) and notes.
The form dynamically adjusts based on the selected movement type (e.g. Transfer shows both source and destination warehouse fields). After submission, the table refreshes automatically via AJAX, no page reload needed.
AJAX Table & Filters
The movements list uses AJAX for both pagination and filtering: the page does not reload. Filters include: type, warehouse, and date range (from/to). Filters are applied instantly when changed.
Admin: Sales Terminal
The Sales Terminal (POS → Terminal) provides a full-screen cash register interface for processing sales directly from the admin panel.
Using the POS
The POS uses a two-panel layout:
- Left panel: product search and cart. Search by product name, SKU, or barcode. Click a product to add it to the cart. Adjust quantities or remove items inline.
- Right panel: payment processing. Select payment method (Cash, Card, or Other). For cash payments, enter the amount received to see the change calculation.
Sale Completion
After completing a sale:
- A sale number is generated using the configured prefix (e.g.
SALE-000001). - Stock quantities are automatically decreased in the register’s warehouse.
- Stock movements of type Sale are created for each item.
- The register’s running totals are updated.
- A receipt is displayed and can be printed.
Barcode Scanning
When pos_barcode_enabled is enabled, the POS search field auto-detects barcode scanner input.
Barcode scanners typically send characters followed by an Enter key, which triggers an automatic product lookup.
If a matching product is found, it is immediately added to the cart.
Receipts
After each sale, a receipt is generated containing:
- Custom header text (from
pos_receipt_headersetting). - Sale number and date/time.
- Itemized list with quantities, unit prices, and line totals.
- Subtotal, tax, and total.
- Payment method and amount.
- Change due (for cash payments).
- Custom footer text (from
pos_receipt_footersetting).
Admin: Registers
The Registers page (POS → Registers) manages cash register sessions. Each register session tracks a cashier’s shift from open to close.
Opening a Register
- Select a warehouse: all POS sales during this session are linked to this warehouse.
- Enter the opening amount: the starting cash in the register.
Only one register can be open per user at a time.
Closing a Register
When closing a register:
- Enter the counted cash: the actual amount of cash in the register.
- The system displays the expected amount (opening amount + cash sales).
- The difference between expected and counted is shown, highlighting any discrepancy.
A Register Closed notification is sent to administrators when a register is closed.
Admin: Sales
The Sales page (POS → Sales) shows all POS transactions.
Sales List
A paginated, filterable table showing sale number, customer, items, total, payment method, status, warehouse, and date. Filter by status, payment method, warehouse, and date range.
Sale Detail
The sale detail page shows:
- Sale number and date/time.
- Customer information (if provided).
- Items table: product name, SKU, quantity, unit price, and line total.
- Financial summary: subtotal, tax, and total.
Voiding Sales
To void a sale:
- A reason is required (minimum 10 characters).
- Stock is automatically reversed: quantities are restored to the warehouse.
- Return type stock movements are created for each item.
Admin: Alerts
The Alerts page (POS → Alerts) displays inventory alerts.
Alerts are automatically created when a product’s quantity in any warehouse drops to or below its reorder level. Alerts have three statuses:
- Active: stock is below the reorder level.
- Resolved: stock has been replenished above the reorder level.
- Dismissed: manually dismissed by an administrator.
Use the Run Stock Check button to perform a global sweep of all products and create/resolve alerts based on current stock levels.
Empty State
When no active alerts exist, the page shows a contextual message:
- Monitoring configured: displays a green “All Clear” message with the count of monitored products (warehouse products with a reorder level greater than 0).
- No monitoring configured: displays a yellow warning explaining that no products have a reorder level set, and that reorder levels must be configured on warehouse products to enable low-stock alerts.
Admin: Reports
The Reports page (POS → Reports) provides analytical charts, tables, and three detailed report types. Use the period filter to adjust the date range.
Overview Charts & Tables
The main reports page shows:
- Sales Over Time: line chart showing daily sales trends.
- Movements by Type: doughnut chart breaking down stock movements.
- Top Selling Products: ranked by quantity sold in the selected period.
- Stock by Warehouse: total products and quantity per warehouse.
Stock Valuation
Shows the total value of your inventory:
- Per-product value breakdown by warehouse (cost price × quantity).
- Grand total across all products and warehouses.
Movement Analysis
Analyze stock movements over a selected period:
- Period filter: select date range.
- Doughnut chart: visual breakdown by movement type.
- Breakdown table: count and total quantity per movement type.
Sales Analysis
Analyze sales performance over a selected period:
- Period filter: select date range.
- Line chart: sales trends over time.
- Payment method pie chart: revenue breakdown by payment method (Cash, Card, Other).
- Top products: ranked by quantity sold.
Admin: Settings
The settings page (POS → Settings) is organized into sections:
- General: Default tax rate, currency symbol.
- SKU & Barcode: Auto-generate SKU, SKU prefix, barcode scanning toggle.
- Alerts: Low stock alerts toggle, large adjustment threshold.
- Sales & Receipts: Sale number prefix, receipt header/footer text.
Data Reset
The settings page includes a Danger Zone card that allows you to reset all transactional POS data. This is intended for clearing test data before going live with real business operations.
What Gets Deleted
- All sales, sale items, and sale payments
- All register sessions (open/close history)
- All stock movements (adjustments, transfers)
- All stock alerts
What Gets Preserved
- Products and categories
- Warehouses
- Warehouse-product links (stock quantities are reset to zero)
- Warehouse user assignments
How It Works
- Navigate to POS → Settings and scroll to the Danger Zone card.
- Click Reset Test Data.
- In the confirmation modal, type
RESETand confirm. - All transactional data is permanently deleted and a lock file is created at
storage/app/pos-data-reset.lock.
Lock File
After a reset, a lock file (storage/app/pos-data-reset.lock) is created on the server.
This prevents accidental resets of production data. The Danger Zone card is hidden while the lock file exists.
The lock file contains audit metadata: who performed the reset, when, and from which IP address.
To re-enable the reset feature, a server administrator must manually delete the lock file:
rm storage/app/pos-data-reset.lock
pos.settings.edit permission.
Permissions
The add-on registers 27 permissions:
| Permission | Description |
|---|---|
pos.dashboard.view |
View POS dashboard |
pos.products.view |
View POS products list |
pos.products.create |
Create new POS products |
pos.products.edit |
Edit existing POS products |
pos.products.delete |
Delete POS products |
pos.categories.view |
View POS categories |
pos.categories.create |
Create POS categories |
pos.categories.edit |
Edit POS categories |
pos.categories.delete |
Delete POS categories |
pos.warehouses.view |
View warehouses |
pos.warehouses.create |
Create new warehouses |
pos.warehouses.edit |
Edit existing warehouses |
pos.warehouses.delete |
Delete warehouses |
pos.warehouses.access_all |
Access all warehouses regardless of assignment |
pos.movements.view |
View POS movements |
pos.movements.create |
Create manual POS movements |
pos.registers.view |
View cash registers |
pos.registers.open |
Open a cash register session |
pos.registers.close |
Close a cash register session |
pos.sales.view |
View POS sales |
pos.sales.create |
Create sales via POS |
pos.sales.void |
Void completed sales |
pos.alerts.view |
View POS alerts |
pos.alerts.dismiss |
Dismiss POS alerts |
pos.reports.view |
Access POS reports |
pos.settings.view |
View POS settings |
pos.settings.edit |
Edit POS settings |
Notifications
The add-on sends 3 notification types (managed via the centralized notification system at Admin → Settings → Notifications):
| Notification | Trigger | Channels |
|---|---|---|
| Low Stock Alert | Product quantity drops below its reorder level in a warehouse. | Mail, Database |
| Register Closed | A cash register session is closed by a cashier. | Mail, Database |
| Large Adjustment | A stock adjustment movement exceeds the configured threshold. | Mail, Database |
Artisan Commands
| Command | Description |
|---|---|
php artisan pos:check-levels |
Scans all warehouse stock levels and creates/resolves alerts accordingly. Recommended to schedule hourly via Laravel’s task scheduler. |
To schedule the command, add it to your routes/console.php:
Schedule::command('pos:check-levels')->hourly();
Uninstallation
Switching an add-on off without losing anything is a deactivation: go to Admin panel → Add-ons, find Point of Sale and click Deactivate.
- Its routes, views, admin menu entries and permissions stop being registered, and its front-end pages stop answering.
- Its database tables and all the data they hold are kept, and its files stay under
extensions/addons/pos/. Nothing is deleted. - The purchase code recorded at activation is kept too, so activating the add-on again does not ask for it.
- Deactivation is refused while another active add-on depends on this one: deactivate that add-on first.
Click Activate on the same card to switch it back on. Pending migrations are re-run, assets are republished, and the add-on picks up exactly where it left off.
Removing
Removing is permanent and destroys the add-on's data. The Remove button only appears on a deactivated add-on, so removal is always two steps:
- Deactivate Point of Sale (see Uninstallation).
- Click Remove on its card and confirm the prompt.
The admin panel then, in one pass:
- runs the add-on's uninstall hook, if it ships one, while its code is still on disk;
- revokes the permissions declared in its
addon.json; - rolls back its migrations (this drops its database tables and every row they hold) and purges its entries from the
migrationstable, so a later reinstall migrates from scratch; - deletes its published assets:
public/addons/pos/,public/vendor/pos/andstorage/app/public/addons/pos/; - deletes the add-on directory
extensions/addons/pos/; - deletes its row in the
addonstable (the recorded purchase code goes with it) and clears the application cache.
Removal is refused, with an explanatory message and before anything is destroyed, when the add-on is still active, when another active add-on depends on it, or when the web server (PHP) user cannot delete extensions/addons/pos/. In that last case, give that user write permission on the directory and on its parent, then try again.
Deleting the folder over FTP or SSH is not equivalent: the add-on's tables, its entries in the migrations table and its addons row are all left behind, and its card stays in the list. Use Remove in the admin panel instead.
Troubleshooting
POS not working
- Ensure you have an open register. The POS requires an active register session before processing sales.
- Only one register can be open per user at a time. Close the existing register before opening a new one.
Missing stock
- Movements are immutable: they cannot be edited or deleted once created.
- To correct stock quantities, create a new movement of type Adjustment.
- Review the movement history for the product to trace where stock was allocated.
Alerts not triggering
- Check that
pos_low_pos_alerts_enabledis set totruein settings. - Ensure the product has a
reorder_levelgreater than 0 set in the warehouse-product pivot. Products without a reorder level are not monitored. - If the alerts page shows “No Monitoring Configured”, it means no warehouse products have a reorder level set. Edit products from the warehouse detail page to set reorder levels.
- Run
php artisan pos:check-levelsto manually trigger an alert scan.
Sale numbers not sequential
- Changing the
pos_sale_number_prefixsetting resets the sequence counter. - Voided sales still consume a sale number: they are not recycled.
POS v1.0.0: Part of the Larapen CMS platform.
© BeDigit. All rights reserved.