Repository: bvanelli/actualpy

Issue:
Read Accounts Notes
### Description

I could not find how to query an account's note via actualpy, but I have seen someone who said he did it with the official api on discord. 

Is it possible to implement? 

Below, the code example he have posted, I don't know if it is helpful:

```
getAccountNote: async function (account) {
    const notes = await api.runQuery(
      api.q('notes')
        .filter({ id: `account-${account.id}` })
        .select('*')
      );
    if (notes.data.length && notes.data[0].note) {
      return notes.data[0].note;
    }
    return undefined;
  },
```

Thank you!

Discussion:
@bvanelli: Accounts don't have notes as far as I remember, do you mean transaction notes?

Maybe show what exactly you want to retrieve from the database. With the sqlalchemy wrapper you can read pretty much anything that has a model.@tcpr1: I mean this field displayed there:

![image](https://github.com/user-attachments/assets/bb8165a3-36e3-46a6-a83d-a600c367b812)

@bvanelli: Thanks for the report, I believe this might be an old implementation that I missed because the weird foreign key implemented:

<img width="927" alt="image" src="https://github.com/user-attachments/assets/ac668ea7-4a91-490b-8241-403c8c94288f">

Anyways, you may now use `Accounts.notes` to access that field:

```python
from actual import Actual
from actual.queries import get_accounts

with Actual(base_url="http://localhost:5006", password="mypass", file="CSV Importer") as actual:
    accounts = get_accounts(actual.session)
    for a in accounts:
        print(f"Notes for {a.name} are: {a.notes}")
```

For me, it prints:

```
Notes for Current Checking Account are: This are my notes for Current Checking Account
Notes for Current Savings Account are: These are my notes for Current Savings Account
Notes for Current Cash in Wallet are: These are my notes for Current Cash in Wallet
Notes for No notes are: None
```

Let me know if it works for you
@tcpr1: It works, thank you!

Solution patch:
diff --git a/actual/database.py b/actual/database.py
index 72a34f1..a33d46e 100644
--- a/actual/database.py
+++ b/actual/database.py
@@ -214,6 +214,11 @@ def balance(self) -> decimal.Decimal:
         )
         return decimal.Decimal(value) / 100
 
+    @property
+    def notes(self) -> Optional[str]:
+        """Returns notes for the account. If none are present, returns `None`."""
+        return object_session(self).scalar(select(Notes.note).where(Notes.id == f"account-{self.id}"))
+
 
 class Banks(BaseModel, table=True):
     id: Optional[str] = Field(default=None, sa_column=Column("id", Text, primary_key=True))
@@ -366,7 +371,7 @@ class MessagesCrdt(SQLModel, table=True):
     id: Optional[int] = Field(default=None, sa_column=Column("id", Integer, primary_key=True))
 
 
-class Notes(SQLModel, table=True):
+class Notes(BaseModel, table=True):
     id: Optional[str] = Field(default=None, sa_column=Column("id", Text, primary_key=True))
     note: Optional[str] = Field(default=None, sa_column=Column("note", Text))
 


Test patch:
diff --git a/tests/test_database.py b/tests/test_database.py
index 794bdba..f09297a 100644
--- a/tests/test_database.py
+++ b/tests/test_database.py
@@ -5,6 +5,7 @@
 import pytest
 
 from actual import ActualError
+from actual.database import Notes
 from actual.queries import (
     create_account,
     create_rule,
@@ -181,3 +182,12 @@ def test_rollback(session):
     assert len(session.info["messages"])
     session.rollback()
     assert "messages" not in session.info
+
+
+def test_model_notes(session):
+    account_with_note = create_account(session, "Bank 1")
+    account_without_note = create_account(session, "Bank 2")
+    session.add(Notes(id=f"account-{account_with_note.id}", note="My note"))
+    session.commit()
+    assert account_with_note.notes == "My note"
+    assert account_without_note.notes is None