Expenses
A complete guide to the Expenses module — recording clinic operational costs, categorizing expenses by department, linking to vendors and inventory, and tracking financial outflows.
Written By Dev010
Last updated 19 days ago
The Expenses module tracks all money going out of the clinic — from medical supplies and equipment purchases to utility bills and staff costs. Expenses are categorized by type and department, and can be linked to lab vendors and inventory items for complete financial traceability. Together with Invoices and Payments, Expenses completes the financial picture of clinic operations.
Accessing the Module
Sidebar → Expenses
Direct URL:
https://yourdomain.com/dashboard/expensesWho can access:
Expenses are accessible to Admin and Receptionist roles by default. Adjust in Dashboard → Permissions if needed.
Expenses List
The main expenses page shows a paginated, searchable list of all recorded clinic expenses.
Each row displays:
Title
Category
Amount
Payment method
Department
Vendor
Date
Status badge
Action buttons (edit, delete)
Search
The search bar filters expenses by:
Title
Vendor name
Category
Results update as you type.
Expense Statuses
Status defaults to
pendingwhen an expense is first recorded. Update topaidonce the payment has been made.
Creating an Expense
Click the Add Expense button on the expenses list page.
Direct URL:
https://yourdomain.com/dashboard/expenses/newRequired Fields
Optional Fields
Description:
Classification:
Vendor:
Inventory:
Supporting Document:
Notes:
Saving the Expense
Click Create Expense to save. The expense appears immediately in the list and is included in the Admin dashboard financial calculations.
Expense Categories
Categories classify what type of expense was incurred. Using consistent categories makes financial reporting meaningful.
CareNova includes the following default expense categories:
Categories are defined as constants in
lib/constants/expenses.ts. To add custom categories, update this file in the codebase.
Payment Methods
Expense payment methods follow the same free text approach as invoice payment methods. Common values:
Use consistent naming across your team to ensure clean payment method reporting and reconciliation.
Linking Expenses to Departments
Assigning an expense to a department enables department-level financial reporting — essential for understanding the true cost of running each part of your clinic.
When creating an expense:
In the Department field, select the relevant department
Save
To compare department expenses against their budgets:
SELECT d.name as department,
d.annual_budget,
SUM(e.amount) as total_expenses,
d.annual_budget - SUM(e.amount) as budget_remaining
FROM expenses e
JOIN departments d ON e.department_id = d.id
WHERE e.status = 'paid'
AND DATE_TRUNC('year', e.date) = DATE_TRUNC('year', now())
GROUP BY d.id, d.name, d.annual_budget
ORDER BY total_expenses DESC;Linking Expenses to Vendors
If the expense was paid to a supplier that exists in the Lab Vendors module, link the expense to the vendor record:
In the Vendor ID field, search for and select the vendor
The free text Vendor field is also available for vendors not in the system
This creates a complete picture of how much the clinic spends with each supplier — useful for contract negotiations and supplier performance reviews.
Total Spend Per Vendor
SELECT lv.name as vendor,
COUNT(e.id) as expense_count,
SUM(e.amount) as total_spend
FROM expenses e
JOIN lab_vendors lv ON e.vendor_id = lv.id
WHERE e.status = 'paid'
GROUP BY lv.id, lv.name
ORDER BY total_spend DESC;Linking Expenses to Inventory
When an expense represents a stock purchase, link it to the inventory item being restocked:
In the Inventory Item field, search for and select the item
After saving the expense, update the item quantity in Sidebar → Inventory
This connects the financial cost of purchasing stock to the physical inventory item — giving visibility into the true per-unit cost of maintaining specific stock items.
Cost Per Inventory Item
SELECT i.name as item,
i.quantity,
i.unit,
COUNT(e.id) as purchase_count,
SUM(e.amount) as total_spent
FROM inventory i
LEFT JOIN expenses e ON e.inventory_item_id = i.id
AND e.status = 'paid'
GROUP BY i.id, i.name, i.quantity, i.unit
ORDER BY total_spent DESC;Receipt Management
The Receipt URL field stores a link to a digital receipt or supplier invoice. Recommended workflow:
Upload the receipt to Supabase Storage (medical-attachments bucket or a dedicated receipts bucket)
Copy the public URL
Paste into the Receipt URL field when creating the expense
CareNova does not currently include a built-in receipt upload button on the expense form. Upload files manually via Supabase Storage and paste the URL into the field.
Expense Approval Workflow
For clinics that require expense approval before payment:
Step 1 — Receptionist submits:
Sidebar → Expenses → Add Expense
Fill in all details
Set Status to
pendingSet Submitted By to their own user account
Save
Step 2 — Admin reviews:
Sidebar → Expenses
Filter by
pendingstatusReview expense details
Edit → set Status to
approvedorrejectedSave
Step 3 — Admin marks as paid:
After payment is made to vendor
Edit expense → set Status to
paidAdd transaction reference in Notes if applicable
Save
Revenue vs Expenses Chart
Expense data feeds directly into the Admin dashboard Revenue vs Expenses bar chart. The chart compares monthly revenue (from paid invoices) against monthly expenses (from paid expense records).
For accurate chart data:
Set expense status to
paidonce the payment has been madeEnsure the Date field reflects when the expense was actually incurred
Keep consistent category usage for meaningful breakdowns
Financial Reporting Queries
Monthly Expense Summary
SELECT DATE_TRUNC('month', date) as month,
COUNT(*) as expense_count,
SUM(amount) as total_expenses
FROM expenses
WHERE status = 'paid'
GROUP BY DATE_TRUNC('month', date)
ORDER BY month DESC;Expenses by Category This Month
SELECT category,
COUNT(*) as count,
SUM(amount) as total
FROM expenses
WHERE status = 'paid'
AND DATE_TRUNC('month', date) =
DATE_TRUNC('month', now())
GROUP BY category
ORDER BY total DESC;Pending Expenses Awaiting Approval
SELECT title, amount, category,
vendor, date, submitted_by
FROM expenses
WHERE status = 'pending'
ORDER BY date ASC;Net Income Calculation
SELECT
(SELECT SUM(amount) FROM payments
WHERE status = 'completed'
AND DATE_TRUNC('month', created_at) =
DATE_TRUNC('month', now())) as revenue,
(SELECT SUM(amount) FROM expenses
WHERE status = 'paid'
AND DATE_TRUNC('month', date) =
DATE_TRUNC('month', now())) as expenses,
(SELECT SUM(amount) FROM payments
WHERE status = 'completed'
AND DATE_TRUNC('month', created_at) =
DATE_TRUNC('month', now())) -
(SELECT SUM(amount) FROM expenses
WHERE status = 'paid'
AND DATE_TRUNC('month', date) =
DATE_TRUNC('month', now())) as net_income;Database Schema Reference
expenses
Indexes are set on date, status, category, department_id, submitted_by, vendor_id, and inventory_item_id for fast filtering and reporting.
Relationship to Other Modules
Workflow Examples
Recording a medical supplies purchase:
Supplier delivers new stock
Sidebar → Expenses → Add Expense
Title: Surgical Gloves Restock — March
Amount: 245.00
Category: Medical Supplies
Payment Method: Bank Transfer
Date: today
Department: General Medicine
Vendor ID: link to supplier in Lab Vendors
Inventory Item: link to Surgical Gloves in Inventory
Status: paid (if already paid) or pending (if awaiting payment)
Save
Also update inventory quantity in Sidebar → Inventory
Recording a monthly utility bill:
Sidebar → Expenses → Add Expense
Title: Electricity Bill — March 2026
Amount: 380.00
Category: Utilities
Payment Method: Direct Debit
Date: billing date
Department: Administration
Status: paid
Save
Submitting an expense for admin approval:
Receptionist → Add Expense
Fill in all details
Submitted By: select own account
Status: pending
Save — admin will review and approve or reject
Month-end financial review:
Run monthly expense summary query above in SQL Editor
Compare against previous months
Review expenses by category to identify unusual spending
Compare department totals against budgets
Ensure all pending expenses are approved and marked paid
Tracking a recurring expense: Each month when the bill arrives:
Add Expense with current month in the title
Use consistent category and department each month
This builds a clean monthly history for that expense type
Troubleshooting
Expenses not visible in sidebar:
Confirm your role has
billing.viewpermission in Dashboard → PermissionsDoctor and Nurse do not have billing access by default
Revenue vs Expenses chart not showing expense data:
Confirm expense status is
paid— pending and approved expenses are excluded from chart calculationsConfirm the expense Date falls within the chart's displayed date range
Hard refresh the Admin dashboard
Department dropdown empty:
No active departments configured
Go to Sidebar → Departments and create departments first
Vendor ID dropdown empty:
No Lab Vendor records exist
Go to Sidebar → Lab Vendors and create vendor records first
Or use the free text Vendor field for vendors not in the system
Inventory Item dropdown empty:
No active inventory items exist
Go to Sidebar → Inventory and add items first
Cannot delete an expense:
Expense deletion is restricted to Admin role only
Receptionist can create and edit but not delete
Consider setting status to
cancelledinstead of deleting to preserve the audit trail
Expense amount not appearing in department budget comparison:
Confirm the expense has a department assigned
Confirm expense status is
paidRun the department budget comparison query above manually in SQL Editor
Next Step
Continue to the Blog & News module guide to learn how to create and manage clinic blog posts and news articles in CareNova.