Skip to main content

Overview

Transactions are the core of FinAI’s financial tracking system. Every time money moves in or out of your wallets, it’s recorded as a transaction with detailed information including amount, date, category, and description.

Database Schema

The Transaction model (app/models.py:78) is the most important table in the system:
class Transaction(db.Model):
    __tablename__ = 'giaodich'

    id = db.Column('MaGiaoDich', db.String(8), primary_key=True)
    user_id = db.Column('MaNguoiDung', db.String(8), db.ForeignKey('nguoidung.MaNguoiDung', ondelete='CASCADE'), nullable=False)
    
    wallet_id = db.Column('MaNguonTien', db.String(8), db.ForeignKey('nguontien.MaNguonTien'), nullable=False)
    dest_wallet_id = db.Column('MaNguonTien_Dich', db.String(8), db.ForeignKey('nguontien.MaNguonTien'), nullable=True)
    
    category_id = db.Column('MaDanhMuc', db.String(8), db.ForeignKey('danhmuc.MaDanhMuc', ondelete='SET NULL'), nullable=True)
    
    type = db.Column('LoaiGiaoDich', db.String(20), nullable=False) # 'thu', 'chi', 'chuyen'
    amount = db.Column('SoTien', db.Float, nullable=False)
    description = db.Column('MoTa', db.String(255))
    date = db.Column('NgayGiaoDich', db.Date, nullable=False)
    created_at = db.Column('NgayTao', db.DateTime, default=datetime.now)

    # AI-powered categorization fields
    ai_category_id = db.Column('MaDanhMuc_AI', db.String(8), db.ForeignKey('danhmuc.MaDanhMuc', ondelete='SET NULL'))
    ai_confidence = db.Column('DoTinCay_AI', db.Float)

Transaction Types

Income (Thu)

Money coming into your wallets

Expense (Chi)

Money going out of your wallets

Transfer (Chuyển)

Money moving between your own wallets

Recording Transactions

1

List All Transactions

Retrieve your transaction history sorted by date:
GET /api/transactions
Response (app/routes/transaction.py:18-30):
[
  {
    "id": "a1b2c3d4",
    "type": "chi",
    "amount": 85000,
    "description": "Cafe sáng với team",
    "date": "2026-03-07",
    "category_id": "cat123",
    "category_name": "Ăn uống",
    "wallet_id": "wallet01",
    "wallet_name": "Tiền mặt",
    "dest_wallet_id": null,
    "dest_wallet_name": null
  }
]
2

Create a New Transaction

Add an income, expense, or transfer:
POST /api/transactions
Content-Type: application/json

{
  "type": "expense",
  "amount": 350000,
  "description": "Xăng xe tháng 3",
  "date": "2026-03-07",
  "source_wallet_id": "wallet01",
  "category_id": "cat456",
  "ai_category_id": "cat456",
  "ai_confidence": 95
}
The system maps UI types to database types (app/routes/transaction.py:40):
  • expensechi
  • incomethu
  • transferchuyen
3

Update an Existing Transaction

The update process automatically handles balance corrections:
PUT /api/transactions/{trans_id}
Content-Type: application/json

{
  "type": "expense",
  "amount": 400000,
  "description": "Xăng xe tháng 3 (đã đổ thêm)",
  "date": "2026-03-07",
  "source_wallet_id": "wallet01",
  "category_id": "cat456"
}
Balance correction logic (app/routes/transaction.py:94-125):
  1. Reverse the old transaction’s effect on wallet balances
  2. Apply the new transaction data
  3. Update wallets with the new amounts
4

Delete a Transaction

Remove a transaction and restore wallet balances:
DELETE /api/transactions/{trans_id}
The system automatically refunds money to the appropriate wallet(s) (app/routes/transaction.py:142-148).

Transaction Workflows

Recording an Expense

1

Enter Description

Type what you spent money on (e.g., “Mua sữa tại Vinmart”)
2

AI Suggests Category

The system calls /api/predict-category and suggests “Ăn uống” with 95% confidence
3

Review and Confirm

You can accept the AI suggestion or manually select a different category
4

Submit Transaction

The transaction is saved and your wallet balance is automatically updated

Transferring Between Wallets

When creating a transfer transaction:
{
  "type": "transfer",
  "amount": 2000000,
  "description": "Gửi tiết kiệm",
  "source_wallet_id": "cash_wallet",
  "dest_wallet_id": "bank_wallet",
  "date": "2026-03-07"
}
The system:
  1. Deducts 2,000,000 VND from Cash wallet
  2. Adds 2,000,000 VND to Bank wallet
  3. Stores both wallet IDs in the transaction (wallet_id and dest_wallet_id)
  4. Does NOT count this as an expense in reports

AI Integration

Transactions leverage two AI-powered fields:

AI Category Prediction

When you create a transaction, the system can predict the category:
# Store AI prediction alongside user's final choice
ai_category_id = data.get('ai_category_id')  # What AI suggested
ai_confidence = data.get('ai_confidence')     # How confident AI was (0-100)
This data helps improve future predictions and provides insights into AI accuracy. See AI Categorization for details.

Transaction Date Handling

Transactions support backdating for recording past expenses:
# From app/routes/transaction.py:60
date=datetime.strptime(data.get('date'), '%Y-%m-%d') if data.get('date') else datetime.now()
You can record transactions from any date, making it easy to catch up on expenses you forgot to log.

Response Format

Successful transaction operations return:
{
  "status": "success",
  "message": "Đã lưu giao dịch!"
}
Errors return:
{
  "status": "error",
  "message": "Chưa chọn ví"
}

Balance Consistency

The system maintains balance consistency through database transactions. All wallet updates happen within the same database commit:
# From app/routes/transaction.py:64-77
db.session.add(new_trans)
wallet.balance -= amount  # Updates happen atomically
db.session.commit()        # Either all succeed or all fail
If any error occurs, db.session.rollback() restores the previous state.

Build docs developers (and LLMs) love