Expense Type
Data Entity
Description
Configurable catalogue of reimbursable expense categories per organization. Defines the fixed set of selectable expense types (mileage, toll, parking, public transport, etc.) that peer mentors can choose from when logging travel expenses, preventing invalid combinations and enforcing receipt and declaration requirements per type.
Data Structure
| Name | Type | Description | Constraints |
|---|---|---|---|
id |
uuid |
Primary key — surrogate UUID generated on insert | PKrequiredunique |
organization_id |
uuid |
Owning organization. Expense types are configured per organization, so each org has its own catalogue. | required |
code |
string |
Machine-readable identifier for this expense type within the organization (e.g. 'mileage', 'toll', 'parking', 'public_transport', 'honorarium'). Used in API payloads and accounting system mappings. | required |
name |
string |
Human-readable display label shown to peer mentors in the Expense Type Selector (e.g. 'Mileage', 'Toll Road', 'Parking', 'Public Transport'). | required |
description |
text |
Optional explanatory text shown as help text in the UI, clarifying when to use this expense type. | - |
category |
enum |
Broad grouping for display and reporting purposes. | required |
unit |
enum |
Unit of measurement for cost calculation. 'km' uses rate_per_unit Ă— distance; 'fixed' means the user enters an arbitrary amount; 'hours' uses rate_per_unit Ă— duration. | required |
rate_per_unit |
decimal |
Government-set or org-set reimbursement rate per unit (NOK per km, NOK per hour). Required when unit is 'km' or 'hours'. NULL for 'fixed' types where user enters total amount. | - |
max_amount |
decimal |
Maximum reimbursable amount in NOK for a single expense of this type. NULL means no cap. Enforced at registration time. | - |
requires_receipt |
boolean |
Whether a receipt photo upload is mandatory for this expense type. Overridden by receipt_threshold_amount when both are set. | required |
receipt_threshold_amount |
decimal |
If set, a receipt is required only when the expense amount exceeds this threshold (e.g. 100 NOK for HLF). Takes precedence over the flat requires_receipt flag when amount is below threshold. | - |
requires_declaration |
boolean |
When true, the peer mentor must complete a confidentiality declaration (taushetserklæring) before this expense type can be submitted. Used for driver honorarium types (Blindeforbundet). | required |
auto_approval_threshold_km |
decimal |
For mileage expense types: expenses at or below this distance (km) are auto-approved without coordinator review. NULL means manual approval always required. (HLF: 50 km threshold.) | - |
mutually_exclusive_with |
json |
Array of expense type codes that cannot be selected on the same expense registration as this type (e.g. mileage and public_transport are mutually exclusive — you cannot claim both for the same trip). Enforced in Expense Type Service at submission time. | - |
accounting_code |
string |
Ledger account code used when exporting to external accounting systems (Xledger, Dynamics). Populated during accounting integration configuration. | - |
is_active |
boolean |
Soft-delete flag. Inactive types are hidden from the Expense Type Selector but retained for historical expense records. | required |
sort_order |
integer |
Display ordering within the Expense Type Selector. Lower values appear first. | required |
created_at |
datetime |
Record creation timestamp (UTC). | required |
updated_at |
datetime |
Last modification timestamp (UTC). Updated on any field change. | required |
Database Indexes
idx_expense_types_org_active
Columns: organization_id, is_active
idx_expense_types_code_org
Columns: organization_id, code
idx_expense_types_org_sort
Columns: organization_id, sort_order
Validation Rules
code_format
error
Validation failed
name_not_empty
error
Validation failed
rate_required_for_unit_types
error
Validation failed
max_amount_positive
error
Validation failed
receipt_threshold_positive
error
Validation failed
mutually_exclusive_codes_exist
error
Validation failed
no_self_reference_in_exclusions
error
Validation failed
accounting_code_format
warning
Validation failed
Business Rules
mutually_exclusive_type_enforcement
When a peer mentor selects an expense type that declares mutually_exclusive_with entries, all conflicting expense types are immediately disabled in the Expense Type Selector. A single expense registration cannot contain two mutually exclusive types (e.g. mileage and public transport for the same trip). This is a hard technical block, not just a warning.
receipt_required_above_threshold
If receipt_threshold_amount is set and the expense amount exceeds it, the file-upload-service must receive a receipt attachment before the expense can be submitted. If requires_receipt is true and no threshold is set, receipt is always required.
declaration_required_before_submission
For expense types where requires_declaration is true, the peer mentor must have a valid confidentiality declaration on file (via Declaration Service) for the relevant period before the expense can be saved.
auto_approval_below_threshold
For mileage types with auto_approval_threshold_km set: if the distance field on the expense is ≤ threshold and no receipt is required, the expense_approval_service automatically sets approval status to 'approved' without routing to the coordinator queue.
organization_scoped_catalogue
An expense type belongs to exactly one organization. Peer mentors and coordinators only see expense types belonging to their own organization. Cross-organization type visibility is never allowed.
soft_delete_preserves_history
Expense types cannot be hard-deleted if any expense record references them. Setting is_active = false hides them from selection while keeping historical expense records intact and reportable.
accounting_code_required_for_export
If the organization has an active accounting integration (accounting_integration_service), all active expense types must have a non-null accounting_code before Bufdir export or accounting sync can proceed.