Reimbursement
Data Entity
Description
Represents a financial reimbursement record created when an expense claim is approved. Tracks the lifecycle of a payout from approval through disbursement, including amount, payment method, accounting export status, and audit trail. One reimbursement is created per approved expense, forming the authoritative financial record that feeds into accounting system exports and Bufdir reporting.
Data Structure
| Name | Type | Description | Constraints |
|---|---|---|---|
id |
uuid |
Primary key, globally unique reimbursement identifier | PKrequiredunique |
expense_id |
uuid |
Foreign key to the approved expense this reimbursement covers. Enforces one-to-one relationship — each approved expense produces exactly one reimbursement record. | requiredunique |
organization_id |
uuid |
Foreign key to the organization that owns this reimbursement. Used for multi-tenant isolation on all queries. | required |
user_id |
uuid |
Foreign key to the peer mentor or coordinator being reimbursed. Denormalized from the linked expense for query performance on per-mentor dashboards. | required |
approved_by_user_id |
uuid |
Foreign key to the coordinator or org admin who approved the underlying expense. Null when approved automatically by the auto-approval rule engine. | - |
status |
enum |
Lifecycle stage of the reimbursement payout. Pending payout is the initial state after approval. Processing indicates an accounting export is in flight. Paid confirms disbursement. Cancelled is used for reversals. | required |
amount_nok |
decimal |
Total reimbursement amount in Norwegian kroner, copied from the approved expense at approval time. Precision: 10 digits, 2 decimal places. | required |
approval_source |
enum |
Indicates whether the reimbursement was created by manual coordinator approval or triggered automatically by the auto-approval rule engine. | required |
payment_method |
enum |
The disbursement channel for this reimbursement. bank_transfer for direct salary/account transfers, accounting_system for exports to Xledger or Dynamics, manual for ad-hoc cash or check payments. | - |
payment_reference |
string |
External reference identifier from the payment system or accounting export (e.g., Xledger transaction ID, Dynamics voucher number). Set when status transitions to paid or processing. | - |
accounting_export_id |
uuid |
Foreign key to the accounting_exports record that included this reimbursement. Null until exported. Used for tracking export batches and preventing double-export. | - |
payout_date |
datetime |
Timestamp when the payment was confirmed as disbursed. Required when status is paid. Null while pending or in processing. | - |
approved_at |
datetime |
Timestamp when the underlying expense was approved and this reimbursement record was created. | required |
cancellation_reason |
text |
Free-text explanation for why a reimbursement was cancelled. Required when status transitions to cancelled. | - |
notes |
text |
Internal administrative notes visible to coordinators and org admins. Not visible to the peer mentor. | - |
created_at |
datetime |
Record creation timestamp, set automatically at insert. | required |
updated_at |
datetime |
Last modification timestamp, updated automatically on every row change. | required |
Database Indexes
idx_reimbursement_expense_id
Columns: expense_id
idx_reimbursement_organization_id_created_at
Columns: organization_id, created_at
idx_reimbursement_user_id
Columns: user_id
idx_reimbursement_status
Columns: status
idx_reimbursement_accounting_export_id
Columns: accounting_export_id
idx_reimbursement_org_status_created
Columns: organization_id, status, created_at
Validation Rules
amount_positive
error
Validation failed
valid_expense_reference
error
Validation failed
organization_consistency
error
Validation failed
user_consistency
error
Validation failed
valid_status_transition
error
Validation failed
payment_reference_format
error
Validation failed
payout_date_not_future
error
Validation failed
approved_at_not_before_expense_submission
error
Validation failed
Business Rules
one_reimbursement_per_expense
Exactly one reimbursement record may exist per expense. Enforced by the unique constraint on expense_id. Any attempt to insert a second reimbursement for the same expense must fail at the database level.
only_approved_expenses_trigger_reimbursement
A reimbursement record may only be created after the linked expense has been approved (expense_approvals.status = 'approved'). Creating a reimbursement for a pending or rejected expense is not permitted.
amount_matches_approved_expense
The amount_nok on the reimbursement must match the approved total of the linked expense at the time of approval. Any post-approval correction to the expense amount requires a corresponding update to the reimbursement record with audit logging.
tenant_isolation
All reads and writes to the reimbursements table must include an organization_id WHERE clause. Cross-organization access is never permitted. The organization_id on the reimbursement must match the organization_id of the linked expense.
no_double_export
A reimbursement that already has a non-null accounting_export_id or a status of 'processing' or 'paid' must not be included in a new accounting export batch. The accounting API service must filter these out before submitting a batch.
payout_date_required_on_paid
When status transitions to 'paid', payout_date must be set to a non-null timestamp. Transitions to 'paid' without a payout_date are rejected.
cancellation_reason_required
When status transitions to 'cancelled', cancellation_reason must contain a non-empty string explaining the reversal. This is required for audit trail completeness.
immutable_once_paid
A reimbursement with status 'paid' may not be updated to any other status except 'cancelled' via an explicit reversal workflow with audit logging. Amount and expense_id are immutable after creation.
auto_approval_source_tracking
When approval_source is 'auto', approved_by_user_id must be null and the triggering auto-approval rule ID must be recorded in audit_logs. This ensures auto-approved reimbursements are distinguishable from manual ones in financial reporting.