Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/roles-and-permissions.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ A check means the role is allowed to use the capability. A dash means it is not
| System | Use database tools and backups | ✓ | — | — | — | — |
| Orders | Use the standalone Server App | ✓ | ✓ | — | ✓ | — |
| Support | Contact support and view diagnostics | ✓ | ✓ | ✓ | ✓ | ✓ |
| Expenses | Add or delete expense categories | ✓ | ✓ | — | — | — |
| Expenses | Record expenses and due payments | ✓ | ✓ | ✓ | ✓ | ✓ |
| Expenses | Void mistyped entries, payments, and floats | ✓ | ✓ | — | — | — |
| Expenses | Log opening floats and cash counts | ✓ | ✓ | ✓ | ✓ | ✓ |

## Important scope notes

Expand All @@ -65,6 +69,8 @@ A check means the role is allowed to use the capability. A dash means it is not
- **Server App:** The standalone Server App is intentionally restricted to `server`, `manager`, and `owner` roles. It is separate from the dashboard navigation.
- **Staff management:** Managers can manage operational staff, but cannot modify or deactivate owner/manager accounts. Only owners can change roles for an existing account, and the last active owner cannot be demoted.
- **Conditional surfaces:** Business type, feature settings (such as KDS or WhatsApp), and account state can hide or disable a surface without changing the fixed role boundary.
- **Expense records are append-only:** Any staff member can record an expense or a due payment against an existing category, but no role — including owner — can edit an individual expense/payment entry once recorded; it is a permanent audit trail. Owners and managers can void a mistyped entry, payment, or opening float, which drops it from every due and total while keeping the row itself. Only the expense *category* itself can be deleted (owner/manager only, and only once its due balance is settled).
- **Cash Counter's expected-cash figure cannot be overridden:** the daily/monthly expected cash total is always calculated (opening float + cash collected from orders − cash refunds − cash paid out as expenses, same drawer rule as the Z day-close); no role can edit or replace it. Staff can log an opening float (once per day) and any number of physical cash counts, both append-only, purely as reference facts compared against the calculated figure — never a substitute for it.

## Research-backed presentation choice

Expand Down
378 changes: 378 additions & 0 deletions frontend/src/app/(dashboard)/cash-counter/page.tsx

Large diffs are not rendered by default.

426 changes: 426 additions & 0 deletions frontend/src/app/(dashboard)/expenses/page.tsx

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions frontend/src/components/layout/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import {
Sun,
Moon,
Monitor,
Receipt,
Banknote,
type LucideIcon,
} from 'lucide-react';
import { useTranslations, type AppConfig } from 'use-intl';
Expand Down Expand Up @@ -75,6 +77,8 @@ const ALL_NAV_ITEMS: NavItem[] = [
{ href: '/settings?tab=kds', labelKey: 'kds', icon: ChefHat, roles: ROLE_ACCESS.ownerManager, businessTypes: ['restaurant'] },
{ href: '/customers', labelKey: 'customers', icon: Users, roles: ROLE_ACCESS.ownerManager, businessTypes: null },
{ href: '/staff', labelKey: 'staff', icon: UserCog, roles: ROLE_ACCESS.ownerManager, businessTypes: null },
{ href: '/expenses', labelKey: 'expenses', icon: Receipt, roles: ROLE_ACCESS.allStaff, businessTypes: null },
{ href: '/cash-counter', labelKey: 'cashCounter', icon: Banknote, roles: ROLE_ACCESS.allStaff, businessTypes: null },
{ href: '/settings', labelKey: 'settings', icon: Settings, roles: ROLE_ACCESS.ownerManager, businessTypes: null },
];

Expand Down
81 changes: 79 additions & 2 deletions frontend/src/lib/i18n/messages/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,37 @@
"businessType": {
"restaurant": "Restaurant"
},
"cashCounter": {
"cashExpenses": "Barausgaben",
"cashFromOrders": "Bareinnahmen aus Bestellungen",
"cashRefunds": "Rückerstattungen (bar)",
"countLog": "Zählprotokoll",
"countRecorded": "Kassenzählung gespeichert",
"counted": "Gezählt",
"countedAmount": "Gezählter Betrag",
"date": "Datum",
"expectedCash": "Erwarteter Kassenbestand",
"failedToLoad": "Kasse konnte nicht geladen werden",
"failedToLoadMonthly": "Monatsbericht konnte nicht geladen werden",
"monthlyReport": "Monatsbericht",
"netCash": "Bargeld netto",
"noCounts": "Noch keine Zählungen",
"noPayments": "Noch keine Zahlungen",
"openingFloat": "Anfangsbestand",
"openingFloatAlreadySet": "Anfangsbestand für dieses Datum bereits gesetzt",
"openingFloatSet": "Anfangsbestand gesetzt",
"overall": "Gesamt",
"recordCount": "Zählung erfassen",
"recordedBy": "von {name}",
"selectDate": "Datum wählen",
"selectMonth": "Monat wählen",
"setOpeningFloat": "Anfangsbestand setzen",
"title": "Kasse",
"variance": "Differenz",
"varianceMatch": "Stimmt überein",
"varianceOverage": "+{amount} zu viel",
"varianceShortage": "-{amount} zu wenig"
},
"common": {
"active": "Aktiv",
"add": "Hinzufügen",
Expand Down Expand Up @@ -149,6 +180,9 @@
"total": "Gesamt",
"unknown": "Unbekannt",
"update": "Aktualisieren",
"confirmVoid": "Diesen Eintrag stornieren? Der Betrag zählt dann nicht mehr.",
"void": "Stornieren",
"voided": "Storniert",
"windowControls": "Fenstersteuerung",
"yes": "Ja",
"back": "Zurück"
Expand Down Expand Up @@ -301,6 +335,43 @@
"refundsCount": "{count} Erstattungen",
"ticketNoPayments": "Keine Zahlungen an diesem Tag"
},
"expenses": {
"addCategory": "Kategorie hinzufügen",
"addExpense": "Ausgabe hinzufügen",
"category": "Kategorie",
"categoryCreated": "Ausgabenkategorie erstellt",
"categoryDeleted": "Ausgabenkategorie gelöscht",
"categoryName": "Kategoriename",
"clearDateFilter": "Zurücksetzen",
"confirmDeleteCategory": "Kategorie \"{name}\" löschen? Kann nicht rückgängig gemacht werden.",
"date": "Datum",
"deleteCategory": "Kategorie löschen",
"deleteCategoryBlocked": "Offenen Betrag erst ausgleichen, dann löschen",
"due": "Offen",
"entryAdded": "Ausgabe erfasst",
"entryTypeExpense": "Ausgabe",
"entryTypePayment": "Zahlung",
"failedToLoad": "Ausgaben konnten nicht geladen werden",
"failedToLoadSummary": "Monatsbericht konnte nicht geladen werden",
"filterByDate": "Nach Datum filtern",
"history": "Letzte Aktivitäten",
"monthlyReport": "Monatsbericht",
"noCategories": "Noch keine Ausgabenkategorien",
"noEntries": "Noch keine Ausgaben",
"note": "Notiz",
"overall": "Gesamt",
"paymentMethod": "Zahlungsmethode",
"paymentMethodCard": "Karte",
"paymentMethodCash": "Bar",
"paymentMethodUpi": "UPI",
"paymentRecorded": "Zahlung erfasst",
"recordPayment": "Zahlung erfassen",
"recordedBy": "von {name}",
"selectMonth": "Monat wählen",
"title": "Ausgaben",
"totalExpenses": "Ausgaben gesamt",
"totalPaid": "Gezahlt gesamt"
},
"kds": {
"addonsLabel": "Zusätze",
"authFailed": "Authentifizierung fehlgeschlagen",
Expand Down Expand Up @@ -346,10 +417,12 @@
"wsConnected": "WebSocket verbunden"
},
"nav": {
"cashCounter": "Kasse",
"collapse": "Einklappen",
"confirmLogout": "Möchten Sie sich wirklich abmelden?",
"customers": "Kunden",
"dashboard": "Dashboard",
"expenses": "Ausgaben",
"heapLabel": "Speicher: ",
"kds": "KDS",
"logout": "Abmelden",
Expand Down Expand Up @@ -1920,7 +1993,8 @@
"settings": "Einstellungen",
"integrations": "Integrationen",
"system": "System",
"support": "Support"
"support": "Support",
"expenses": "Ausgaben"
},
"capabilities": {
"pos": "Kassenterminal bedienen",
Expand Down Expand Up @@ -1966,7 +2040,10 @@
"cloudAccountData": "Cloud-Konto- und Datenkontrollen verwalten",
"databaseTools": "Datenbankwerkzeuge und Sicherungen nutzen",
"serverApp": "Eigenständige Bedienungs-App verwenden",
"support": "Support kontaktieren und Diagnosedaten einsehen"
"support": "Support kontaktieren und Diagnosedaten einsehen",
"expenseCategoriesManage": "Ausgabenkategorien hinzufügen oder löschen",
"expenseEntriesRecord": "Ausgaben und Zahlungen erfassen",
"cashCounterRecord": "Anfangsbestände und Zählungen erfassen"
}
},
"support": {
Expand Down
81 changes: 79 additions & 2 deletions frontend/src/lib/i18n/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,37 @@
"businessType": {
"restaurant": "Restaurant"
},
"cashCounter": {
"cashExpenses": "Cash Expenses",
"cashFromOrders": "Cash from Orders",
"counted": "Counted",
"countedAmount": "Counted amount",
"cashRefunds": "Cash Refunds",
"countLog": "Count Log",
"countRecorded": "Cash count recorded",
"date": "Date",
"expectedCash": "Expected Cash",
"failedToLoad": "Failed to load the cash counter",
"failedToLoadMonthly": "Failed to load the monthly cash report",
"monthlyReport": "Monthly report",
"netCash": "Net cash",
"noCounts": "No counts recorded yet",
"noPayments": "No payments yet",
"openingFloat": "Opening Float",
"openingFloatAlreadySet": "Opening float already set for this date",
"openingFloatSet": "Opening float set",
"overall": "Overall",
"recordCount": "Record Count",
"recordedBy": "by {name}",
"selectDate": "Select date",
"selectMonth": "Select month",
"setOpeningFloat": "Set Opening Float",
"title": "Cash Counter",
"variance": "Variance",
"varianceMatch": "Matches",
"varianceOverage": "+{amount} over",
"varianceShortage": "-{amount} short"
},
"common": {
"active": "Active",
"add": "Add",
Expand Down Expand Up @@ -149,6 +180,9 @@
"total": "Total",
"unknown": "Unknown",
"update": "Update",
"confirmVoid": "Void this entry? Its amount will no longer count.",
"void": "Void",
"voided": "Voided",
"windowControls": "Window controls",
"yes": "Yes",
"back": "Back"
Expand Down Expand Up @@ -301,6 +335,43 @@
"refundsCount": "{count} refunds",
"ticketNoPayments": "No payments for this day"
},
"expenses": {
"addCategory": "Add Category",
"addExpense": "Add Expense",
"category": "Category",
"categoryCreated": "Expense category created",
"categoryDeleted": "Expense category deleted",
"categoryName": "Category name",
"clearDateFilter": "Clear",
"confirmDeleteCategory": "Delete the \"{name}\" category? This cannot be undone.",
"date": "Date",
"deleteCategory": "Delete category",
"deleteCategoryBlocked": "Settle the outstanding due before deleting this category",
"due": "Due",
"entryAdded": "Expense recorded",
"entryTypeExpense": "Expense",
"entryTypePayment": "Payment",
"failedToLoad": "Failed to load expenses",
"failedToLoadSummary": "Failed to load the monthly report",
"filterByDate": "Filter by date",
"history": "Recent activity",
"monthlyReport": "Monthly report",
"noCategories": "No expense categories yet",
"noEntries": "No expense activity yet",
"note": "Note",
"overall": "Overall",
"paymentMethod": "Payment method",
"paymentMethodCard": "Card",
"paymentMethodCash": "Cash",
"paymentMethodUpi": "UPI",
"paymentRecorded": "Payment recorded",
"recordPayment": "Record Payment",
"recordedBy": "by {name}",
"selectMonth": "Select month",
"title": "Expenses",
"totalExpenses": "Total expenses",
"totalPaid": "Total paid"
},
"kds": {
"addonsLabel": "Add-ons",
"authFailed": "Authentication failed",
Expand Down Expand Up @@ -346,10 +417,12 @@
"wsConnected": "WebSocket connected"
},
"nav": {
"cashCounter": "Cash Counter",
"collapse": "Collapse",
"confirmLogout": "Are you sure you want to log out?",
"customers": "Customers",
"dashboard": "Dashboard",
"expenses": "Expenses",
"heapLabel": "Heap: ",
"kds": "KDS",
"logout": "Logout",
Expand Down Expand Up @@ -1920,7 +1993,8 @@
"settings": "Settings",
"integrations": "Integrations",
"system": "System",
"support": "Support"
"support": "Support",
"expenses": "Expenses"
},
"capabilities": {
"pos": "Use the POS terminal",
Expand Down Expand Up @@ -1966,7 +2040,10 @@
"cloudAccountData": "Manage cloud account and data controls",
"databaseTools": "Use database tools and backups",
"serverApp": "Use the standalone Server App",
"support": "Contact support and view diagnostics"
"support": "Contact support and view diagnostics",
"expenseCategoriesManage": "Add or delete expense categories",
"expenseEntriesRecord": "Record expenses and due payments",
"cashCounterRecord": "Log opening floats and cash counts"
}
},
"support": {
Expand Down
Loading
Loading