5.8 KiB
Transaction Limits
Overview
Each company is assigned a package tier that defines how many documents they can create per day and per week. When a quota is hit, report endpoints return HTTP 402 — operations (create, edit, approve) are never blocked.
Package Tiers
Defined in app/config.php under $packages. Edit the array directly to adjust quotas or add tiers — no migration required.
| Package | Daily limit | Weekly limit | Locked on limit |
|---|---|---|---|
free |
10 | 30 | dashboard, reports |
starter |
30 | 100 | dashboard, reports |
growth |
150 | 500 | dashboard, reports |
pro |
unlimited | unlimited | nothing |
lock_on_limit is an array of feature group keys. When either limit is hit, any endpoint that calls assertFeatureAccessible('<key>') returns 402 for that company until the quota resets.
A company's package is stored in wms.company_list.package (default 'starter'). Change it with:
UPDATE company_list SET package = 'growth' WHERE company_id = 1;
What Counts as a Transaction
One document created = one count. Updates to existing documents do not count.
| Endpoint | Document type |
|---|---|
ics/api/engine/manage_stock_in.php |
Stock In |
ics/api/engine/manage_stock_out.php |
Stock Out |
ics/api/engine/manage_stock_transfer.php |
Stock Transfer |
order/api/engine/manage_order.php |
WMS Sales Order |
order/api/engine/confirm_order.php |
Auto-created WMS Invoice on confirm |
order/api/engine/manage_invoice.php |
WMS Invoice / Credit Note |
order/api/engine/proceed_to_invoice.php |
WMS Invoice from Sales Order |
order/api/engine/manage_return.php |
Customer Return |
order/api/engine/confirm_return.php |
Auto-created Credit Note on return confirm |
order/api/engine/proceed_to_credit_note.php |
Credit Note from Customer Return |
po/api/engine/manage_po.php |
Purchase Order |
po/api/engine/manage_supplier_return.php |
Supplier Return |
po/api/engine/confirm_supplier_return.php |
Auto-created Supplier Credit Note on supplier return confirm |
po/api/engine/proceed_to_purchase_invoice.php |
Purchase Invoice from Purchase Order |
po/api/engine/proceed_to_supplier_credit_note.php |
Supplier Credit Note from Supplier Return |
revenue/api/engine/manage_order.php |
Revenue Sales Order |
revenue/api/engine/proceed_to_invoice.php |
Revenue Invoice from Sales Order |
revenue/api/engine/manage_credit_note.php |
Customer Credit Note |
revenue/api/engine/manage_quotation.php |
Quotation |
finance/api/engine/manage_receipt_billing.php |
Receipt Billing |
finance/api/engine/manage_receipt.php |
Receipt |
finance/api/engine/manage_payment_billing.php |
Payment Billing |
finance/api/engine/manage_payment.php |
Payment |
expense/api/engine/manage_purchase_request.php |
Purchase Request |
expense/api/engine/manage_supplier_credit_note.php |
Supplier Credit Note |
What Gets Locked
Two feature group keys are defined:
dashboard — gated on dashboard/report summary endpoints. The low-stock detail endpoint and accounting posting-window endpoint are not gated:
dashboard/api/engine_report/reports_stats.php(WMS dashboard)ac_dashboard/api/engine/by_source.phpac_dashboard/api/engine/journals.phpac_dashboard/api/engine/pl.phpac_dashboard/api/engine/recent.phpac_dashboard/api/engine/trend.php
reports — gated on all report endpoints:
accounting/api/engine/get_trial_balance.phpaccounting/api/engine/get_pl_statement.phpaccounting/api/engine/get_balance_sheet.phpaccounting/api/engine/get_gl_movement.phpaccounting/api/engine/get_vat_report.phpreports/api/engine_report/stock_movement.phpreports/api/engine_report/stock_movement_sku.phpreports/api/engine_report/expired_stock.phpreports/api/engine_report/lot_stock_log.phpreports/api/engine_report/product_lot.phpreports/api/engine_report/rack_log.phpreports/api/engine_report/rack_occupancy.php
How Quotas Reset
- Daily — resets at midnight each day.
company_usagestores one row per company perday_date; a new day is a new row with count 0. - Weekly — resets at 00:00 Monday. The weekly count is the SUM of
daily_countfor all rows from Monday to today.
Database
wms.company_usage — one row per company per day:
CREATE TABLE company_usage (
id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
company_id INT(11) NOT NULL,
day_date DATE NOT NULL,
daily_count INT(11) NOT NULL DEFAULT 0,
PRIMARY KEY (id),
UNIQUE KEY uq_company_day (company_id, day_date),
KEY idx_company_id (company_id)
);
Key Files
| File | Role |
|---|---|
app/config.php |
$packages array — all tier definitions |
app/assets/utils/classes/UsageGuard.php |
increment(), assertFeatureAccessible(), getStatus() |
app/include_topbar.php |
Reads getStatus() on every page load; renders warning badge |
app/assets/js/custom.js |
Global 402 handler in ajax_request — shows usage detail alert |
Topbar Warning Badge
include_topbar.php calls UsageGuard::getStatus() on every page load and renders a badge in the nav bar:
- ≥ 80% of either limit — amber badge showing percentage
- ≥ 100% — red badge "Limit reached — reports locked"
Hovering the badge shows raw counts: Daily: 28/30 | Weekly: 87/100.
Adding a New Gated Feature
- Pick a key name (e.g.
'export'). - Add it to
lock_on_limitarrays in the relevant package tiers inconfig.php. - Add
(new UsageGuard($pdo1, $company_id, $packages))->assertFeatureAccessible('export');at the top of the target endpoint(s).