Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.laportenard.com/llms.txt

Use this file to discover all available pages before exploring further.

The POS system implements a three-tier role system derived from Odoo group membership. Roles control access to features, payment processing, price overrides, and reporting.

Roles

Manager

Full access to all POS features. Price overrides, refunds, settings, reports, and all cashier functions. Maps to point_of_sale.group_pos_manager.

Cashier

Standard POS operations — orders, payments, split checks, discounts. Cannot override price restrictions. Maps to point_of_sale.group_pos_user.

Waiter

Order-taking only. Can create orders and add items. Cannot process payments or perform manager actions. Fallback when neither group is set.

Role assignment

Roles are resolved server-side during bootstrap:
# Priority order:
# 1. group_pos_manager → role = 'manager'
# 2. group_pos_user   → role = 'cashier'
# 3. (fallback)       → role = 'waiter'
The resolved role is included in the bootstrap payload user.role and in pos_core_data.pos_users[].role for all POS users.

Feature guards

Use canPerformAction() from src/domain/users/roleGuards.ts to check access:
import { canPerformAction, checkFeatureAccess, FeatureGuards } from "@/domain/users/roleGuards";

const canRefund  = canPerformAction(currentRole, "refund");
const canDiscount = canPerformAction(currentRole, "discount");
const canEditPrice = checkFeatureAccess(currentRole, FeatureGuards.priceEdit);

Predefined feature guards

FeatureManagerCashierWaiter
priceEdit✗ (if restricted)
discount
refund
payment
createOrder
modifyOrder
settings
cashDrawer
switchUser
reports
reprint
close_session

Role utilities

src/domain/users/types.ts:
import { isManager, isCashier, hasRoleLevel } from "@/domain/users/types";

// Check specific role
if (isManager(currentRole)) {
  enablePriceOverrides();
}

// Hierarchy check (manager > cashier > waiter)
if (hasRoleLevel(currentRole, "cashier")) {
  showPaymentInterface();
}

User switching

The SwitchUserLockScreen component provides full-screen lock with PIN and/or RFID card authentication. Dispatching SWITCH_USER to the session machine updates context.currentRole:
send({ type: "SWITCH_USER", user: selectedUser });
// currentRole automatically updates to selectedUser.role

Login method configuration

Each terminal (pos.config) has a nu_login_method field that controls which authentication methods the lock screen allows:
ValuePIN numpadRFID card readerUsers shown
pin (default)Users with a PIN set
rfidUsers with an RFID card assigned
bothUsers with a PIN or card
On the frontend, parseLockConfig() reads nu_login_method from bootstrap and derives pinEnabled and rfidEnabled booleans on LockConfig.
RFID card assignment is managed via the Settings dialog (RFID section, visible to managers when the login method includes RFID). Cards are stored in the standard Odoo res.users.barcode field.

Permissions system

The newer permissions system resolves per-user permission maps server-side (see architecture/permissions). canPerformAction() bridges legacy feature guards to the permission map:
// Checks permission map first, falls back to FeatureGuards
canPerformAction(role, "voidItem", user.permissions)

Testing

111 tests across 4 files in nu_pos_react/:
FileTestsCoverage
src/domain/users/types.test.ts21Role utilities, hierarchy
src/state/machines/sessionMachine.test.ts14State transitions, user switching
src/lib/mockBootstrapData.test.ts26Mock data validation
src/domain/users/roleGuards.test.ts50Feature guards, access control
cd nu_pos_react
npm test -- src/domain/users/