f865837b27
The initial test report (run before the pilot-readiness changes) raised seven findings and a retest plan. This closes the ones still open. - F-01: a business on its free trial may run 2 active branches whatever its tier, so an owner can try transfers and per-branch stock. Only active branches count towards any limit. - F-06: owners can rename branches and deactivate/reactivate them from the Branches page. A branch can only be deactivated once it holds no stock and no active staff; its history stays in every report, and it leaves every picker. - F-04: the Products page lists deactivated products under a toggle with Reactivate. Deactivating warns about stock still on hand, which stays on the Stock page so it can be transferred or counted out. - F-05: products carry a unit (L, ml, kg, g, pcs, tray, pack) instead of everything being litres. - CAT-12: product prices must be above zero and names are unique per business, ignoring case. - F-03: a reversed report period is refused by the page and the API, and the page labels which period the cards show. Report dates are Nairobi business days. - F-07: cost of goods sold is units sold x average buying price. Stock bought in the period is reported separately, with a cash surplus line, so unsold stock no longer shows as a loss. - STA-04: staff and new branch managers can be invited with a one-time, 7-day link; the person sets their own password. Managers can issue a new link for their own cashiers. - OFF-02 / POS-02: the till shows each product's stock and deducts every sale immediately, online or offline; it warns before selling more than the recorded stock, and has a Clear sale button. - npm run backfill:stock turns purchases recorded before the stock ledger into stock, so existing tenants (and the report's ZERRO fixtures) start from what they bought. tests/retest-plan.test.ts runs the report's completion and retest plan and checks every balance and total it predicts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
59 lines
1.6 KiB
TypeScript
59 lines
1.6 KiB
TypeScript
import type { AuthUser, Product } from "@/lib/types";
|
|
|
|
/**
|
|
* The last confirmed session and catalogue, so the terminal can start and
|
|
* keep selling with no network. Only a snapshot for display and for
|
|
* labelling queued sales: the server still authenticates every sync with
|
|
* the httpOnly cookies and re-prices every line.
|
|
*/
|
|
|
|
const KEY = "aquaflow_terminal_session";
|
|
|
|
/** The branch's stock as the server last reported it. */
|
|
export interface StockSnapshot {
|
|
byProduct: Record<string, number>;
|
|
fetchedAt: string;
|
|
}
|
|
|
|
export interface SessionSnapshot {
|
|
user: AuthUser;
|
|
features: { mpesa: boolean };
|
|
products: Product[];
|
|
stock?: StockSnapshot;
|
|
savedAt: string;
|
|
}
|
|
|
|
export function loadSession(): SessionSnapshot | null {
|
|
try {
|
|
const raw = localStorage.getItem(KEY);
|
|
return raw ? (JSON.parse(raw) as SessionSnapshot) : null;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export function saveSession(update: Partial<SessionSnapshot> & { user: AuthUser }): void {
|
|
try {
|
|
const prev = loadSession();
|
|
const sameUser = prev?.user.id === update.user.id;
|
|
const next: SessionSnapshot = {
|
|
features: update.features ?? (sameUser ? prev!.features : { mpesa: false }),
|
|
products: update.products ?? (sameUser ? prev!.products : []),
|
|
stock: update.stock ?? (sameUser ? prev!.stock : undefined),
|
|
user: update.user,
|
|
savedAt: new Date().toISOString(),
|
|
};
|
|
localStorage.setItem(KEY, JSON.stringify(next));
|
|
} catch {
|
|
// Storage full or blocked: the terminal still works online.
|
|
}
|
|
}
|
|
|
|
export function clearSession(): void {
|
|
try {
|
|
localStorage.removeItem(KEY);
|
|
} catch {
|
|
// ignore
|
|
}
|
|
}
|