Transaction Management
Relevant source files
The following files were used as context for generating this wiki page:
- app/src/main/java/io/github/mojri/hesabyar/domain/usecase/ManageTransactionUseCase.kt
- app/src/main/java/io/github/mojri/hesabyar/ui/TransactionViewModel.kt
- app/src/main/java/io/github/mojri/hesabyar/domain/usecase/ParseTransactionUseCase.kt
- rust/hesabyar-core/src/ai_validation.rs
- rust/hesabyar-core/src/search.rs
- app/src/main/java/io/github/mojri/hesabyar/rust/RustBridge.kt
- app/src/test/java/io/github/mojri/hesabyar/TransactionTest.kt
Introduction
Transaction Management is the core system within Hesabyar responsible for the lifecycle of financial records, including income, expenses, loans, and installments. It encompasses data persistence, natural language processing for transaction entry, and advanced search and validation logic implemented across both Kotlin and a shared Rust core (hesabyar-core).
The system is designed to handle "Persian-first" requirements, utilizing a native Rust bridge for high-performance operations like text preprocessing and search relevance scoring. It ensures financial accuracy by strictly avoiding floating-point numbers for currency, using Long (Rial) as the base unit.
Sources: README.md, AGENTS.md, rust/hesabyar-core/README.md
Core Architecture and Data Flow
The architecture follows an MVVM pattern with a Clean Architecture influence, utilizing Use Cases to bridge the UI and the data layer.
Management Components
- TransactionViewModel: Manages the UI state and triggers transaction operations via coroutines.
- ManageTransactionUseCase: Orchestrates business logic for adding, updating, and deleting transactions.
- HesabyarRepository: Interfaces with the Room database for persistence.
- RustBridge: A native interface providing access to the Rust core for complex validation and search logic.
The flow of data from user input to the database involves asynchronous processing via Kotlin Coroutines and StateFlow for real-time UI updates.
Sources: app/src/main/java/io/github/mojri/hesabyar/ui/TransactionViewModel.kt:14-23, app/src/main/java/io/github/mojri/hesabyar/domain/usecase/ManageTransactionUseCase.kt:9-11, app/src/main/java/io/github/mojri/hesabyar/rust/RustBridge.kt:18-24
Transaction Operations
Standard Transaction Lifecycle
Transactions can be created, updated, or deleted. Every transaction is associated with a type (Income, Expense, etc.) and a category.
| Operation | Implementation | Description |
|---|---|---|
| Add | addTransaction | Inserts a new Transaction object into the repository. Defaults to current system time if no date is provided. |
| Update | updateTransaction | Modifies an existing transaction record in the database. |
| Delete | deleteTransaction | Removes a transaction record from persistence. |
| Query | getTransactionsInRange | Retrieves a flow of transactions between two epoch timestamps. |
Sources: app/src/main/java/io/github/mojri/hesabyar/domain/usecase/ManageTransactionUseCase.kt:16-39, app/src/main/java/io/github/mojri/hesabyar/ui/TransactionViewModel.kt:33-51
Smart Parsing and AI Integration
Hesabyar allows users to enter transactions using natural language sentences. This process involves a parsing pipeline that can optionally use AI (Gemini/OpenRouter) or a local offline parser.
Parsing handles multiple record types:
- Income/Expense: Standard transactions.
- Loan: Maps to
LOAN_DEBTORorLOAN_CREDITOR. - Installment: Calculates due dates based on relative offsets (e.g., "days from now").
Sources: app/src/main/java/io/github/mojri/hesabyar/domain/usecase/ParseTransactionUseCase.kt:16-65, rust/hesabyar-core/src/ai_validation.rs:114-140
Validation and Data Integrity
The system enforces strict validation rules to maintain financial data integrity. Validation logic is replicated in both Kotlin (as a fallback) and Rust (for performance and consistency across platforms).
AI Output Validation
When AI generates a transaction from text, the AiParsedTransaction system in Rust performs "repairs" on the data:
- Category Normalization: Maps fine-grained categories (e.g., "Personal Care") to core DB categories ("Shopping").
- Clamping: Ensures hours (0-23), minutes (0-59), and confidence values (0.0-1.0) are within valid ranges.
- Rial Conversion: Automatically multiplies Toman values by 10 to store them as Rial
Longvalues.
// Example of Rust-side normalization logic
const CATEGORY_MAP: &[(&str, &str)] = &[
("Personal Care", "Shopping"),
("Rent & Utilities", "Bills"),
("Investment", "Other"),
];
Sources: rust/hesabyar-core/src/ai_validation.rs:55-83, rust/hesabyar-core/src/ai_validation.rs:175-185, app/src/main/java/io/github/mojri/hesabyar/rust/RustBridge.kt:133-145
Search and Filtering
Advanced transaction search is implemented in the Rust core to handle Persian text nuances.
Search Relevance Scoring
The search engine calculates a score (0.0 to 1.0) based on text similarity:
- Normalization: Removes ZWNJ (Zero-Width Non-Joiner), normalizes digits, and performs whitespace cleanup.
- Substring Match: High relevance (0.8+) for exact substring matches.
- Word-Level Match: Partial match based on the ratio of matching words.
- Consecutive Bonus: Boosts scores when multiple words appear in the same order as the query.
Filter Parameters
| Parameter | Type | Description |
|---|---|---|
min_amount / max_amount | i64 | Filters by Rial amount range. |
start_date / end_date | i64 | Filters by epoch millisecond range. |
category_id | i64 | Filters by specific category. |
tx_type | TransactionType | Filters by Income, Expense, Loan, etc. |
Sources: rust/hesabyar-core/src/search.rs:10-54, rust/hesabyar-core/src/search.rs:125-156
Financial Calculation Logic
The system uses Long integers for all monetary values to avoid precision issues associated with floating-point arithmetic.
@Test
fun `balance calculation - income minus expense`() {
val totalIncome = transactions.filter { it.type == INCOME }.sumOf { it.amount }
val totalExpense = transactions.filter { it.type == EXPENSE }.sumOf { it.amount }
val balance = totalIncome - totalExpense
}
In this example, totalIncome and totalExpense are calculated as Long sums of Rial values.
Sources: app/src/test/java/io/github/mojri/hesabyar/TransactionTest.kt:32-52, app/src/test/java/io/github/mojri/hesabyar/TransactionAmountResolverTest.kt:22-35
Summary
Transaction Management in Hesabyar provides a robust framework for handling financial data through a hybrid Kotlin-Rust architecture. By centralizing core logic like NLP parsing, search relevance, and validation in Rust, the project ensures high performance and cross-platform consistency while maintaining a modern, reactive UI via Jetpack Compose and ViewModels.