-
Notifications
You must be signed in to change notification settings - Fork 202
Description
First of all, I'd like to thank you for this awesome app ! Paisa have th best design that I've seen from web tools for ledgers - I really felt in love with it. Sheets is very very well realtime calculator concept - I just added some functions for rounding, etc. Now it can calculate income taxes, mortgage, and many more. One big thaks for you work again !
When testing for my personal and bussiness finances, I encountered problem, when working with auto posting.
Describe your Environment
OS: Debian
Paisa Version: 0.7.4
App Variant: Oficial docker image
Backend ledger variant: hledger
Describe the bug
When auto posting transactions added, they broke internal hiding of forecasted transactions in future. Forecasted transactions for about 2 years in future shows are normal transactions in Paisa. More info in attached example journals. I'm using auto postings for envelope budgeting, which works very well in hledger itself.
To Reproduce
Steps to reproduce the behavior:
- Create simple journal in clean installation:
~ every month from 2025-02-05 "Transaction test1"
; Testing periodic transaction
Assets:Banks:Bank1
Expenses:Groceries 15 $
= /Salary/
[Assets:Budgets:Bank1:Personal] 200 $
[Assets:Banks:Bank1] -200 $
= /Transaction test1/
[Assets:Budgets:Bank1:Osobní] *1
[Assets:Banks:Bank1] *-1
2025/12/15 * "Salary"
; salary:
Income:Salary:Customer1 -2000 $
Assets:Banks:Bank1 2000 $
When auto posting transaction is commented (starts with =), everything works as usual and only one transaction is shown.
- Open main page, or transactions page.
Expected behavior
Only one transaction should appear, not all of forecasted for about 2 years ?
Journal
I tried to investigate this problem more in depth. When I export one of problematic transaction in JSON to see metadata, it show this (when auto posting trx enabled):
{
"tcode": "",
"tcomment": "",
"tdate": "2027-12-05",
"tdate2": null,
"tdescription": "\"Transaction test1\"",
"tindex": 38,
"tpostings": [
...<REDACTED>...
],
"tprecedingcomment": "",
"tsourcepos": [
{
"sourceColumn": 1,
"sourceLine": 1,
"sourceName": "/root/Documents/paisa/periodic_transactions.ledger"
},
{
"sourceColumn": 1,
"sourceLine": 4,
"sourceName": "/root/Documents/paisa/periodic_transactions.ledger"
}
],
"tstatus": "Unmarked",
"ttags": [
[
"_modified",
""
],
[
"_generated-transaction",
"~ every month from 2025-02-05"
]
]
},
Interesting part is ttags. Let's compare tags between transactions where auto posting is enabled and disabled. I assuming that Paisa need something to recognize, that transaction is forecasted (generated), so something is broken about this mechanism:
Auto posting off:
"ttags": [
[
"_generated-transaction",
"~ every month from 2025-02-05"
]
]
Auto posting on:
"ttags": [
[
"_modified",
""
],
[
"_generated-transaction",
"~ every month from 2025-02-05"
]
]
OK, auto posting apparently added new tag _modified for matched transactions. I don't know in which version of hledger is added this behavior. Never mind. Now we try to find, where these tags are used in code and where is mechanism to hide generated transactions without auto posting enabled. Because Paisa uses GO backend for hledger, before loads transactions in SQLite, I searched in GO source. Found function buildHLedgerPostings in file internal/ledger/ledger.go:
803 func buildHLedgerPostings(p HLedgerPosting, t HLedgerTransaction, pricesTree map[string]*btree.BT 803 ree, date time.Time) ([]*posting.Posting, error) {
804 forecast := false
805 postings := []*posting.Posting{}
806
807 var tagRecurring, tagPeriod string
808 for _, tag := range t.Tags {
809 if len(tag) == 2 {
810 if tag[0] == "Recurring" {
811 tagRecurring = tag[1]
812 }
813
814 if tag[0] == "Period" {
815 tagPeriod = tag[1]
816 }
817
818 if tag[0] == "_generated-transaction" {
819 forecast = true
820 }
821 }
822 break
823 }
824
825 for _, tag := range p.Tags {
826 if len(tag) == 2 && tag[0] == "Recurring" {
827 tagRecurring = tag[1]
828 }
829
830 if len(tag) == 2 && tag[0] == "Period" {
831 tagPeriod = tag[1]
832 }
833 break
834 }
Construction at line 808 - for cycle, iterates only once. If there are more tags than one, processed is only the first tag, so generated transaction, modified with auto posting is not matched and not marked as forecast with forecast = true, which can be seen in SQLite database in column forecast:
sqlite> select transaction_id,date,payee,forecast from postings where transaction_id = 38;
transaction_id|date|payee|forecast
38|2027-12-05 00:00:00+02:00|"Transaction test1"|0
38|2027-12-05 00:00:00+02:00|"Transaction test1"|0
38|2027-12-05 00:00:00+02:00|"Transaction test1"|0
38|2027-12-05 00:00:00+02:00|"Transaction test1"|0
So i tried to remove break from line 822 and 833.
And it's working ! I don't know if I broke some other behavior, but it works. Can you please look at it and test if this change is OK and not broke anything ?