Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Balance assignment on date #2274

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

dbear496
Copy link
Contributor

This changes the behavior of balance assignment/assertion to take into consideration the date of the posting. When computing the account balance for the purpose of balance assignment, the account postings are filtered to only include those that occur on or before the date of the balance assignment.

My practical use case is I have a journal file that is automatically generated/updated by a script, and then I include this generated journal in my main journal. So it is quite normal for my larger journal to appear out of order as some generated transactions are more recent than some manually entered transactions even though all the generated transactions appear first in the journal. Before this PR, a balance assignment in the manual part of the journal would be affected by newer transactions in the generated journal. On top of that, the posting amount that is computed from the balance assignment would change each time I update the generated journal. This PR fixes this so I can use balance assignments in the manual journal and they will only be affected by transactions from the generated journal that have an earlier (or same) date.

Unfortunately, this does not help me put balance assignments in the generated journal as they will never be affected by postings that are parsed later (in the manually-entered part of the journal). Doing so could lead to ambiguities in computing balance assignments.

As a bonus, I fixed a bug that was left over from PR #1857. And I fixed #2273 even though I am still only 95% sure that it was broken in the first place as I haven't yet seen any comments on that issue.

This will help keep balance assertions/assignments consistent when 
transactions are be out of order.
The balance of virtual accounts reflects postings from the same real 
account, and not vice-versa. The same should be true for postings in the 
same transaction.
@jwiegley
Copy link
Member

It is part of the design of Ledger that anything syntactic is based on the actual ordering of transactions in the journal, and not the meaning of things like "dates" — even though I agree that this can become counter-intuitive at times.

My suggestion would be to use Ledger itself to sort the data that you import, so that your balance assertions can be applied to the expected transactions, rather than to add new logic like this to Ledger itself, since no other aspect of Ledger incorporates design elements like this.

@dbear496
Copy link
Contributor Author

dbear496 commented Jul 11, 2024

@jwiegley, now that you mention it, I agree that ordering by date for the purpose of balance assertions is completely arbitrary. However, I still do not quite understand how to achieve the use case in the OP by "using Ledger itself to sort the data that you import"; perhaps you can explain further.

Keep in mind that the imported data is already sorted, and the manual section of the journal is also practically sorted. But when the two sections are combined by includeing the imported data from the manual section, the the combined result is unsorted. Here is a minimal example of the use case:

# generated.ldg

2024-01-15
  income:job  $-2000.00
  assets:checking  $2000.00

2024-02-15
  income:job  $-2000.00
  assets:checking  $2000.00

2024-03-15
  income:job  $2000.00
  assets:checking  $2000.00
# manual.ldg

include generated.ldg

2024-01-20
  expenses:groceries  $100.00
  assets:checking  $-100.00

# here I balance my bank statement
2024-02-01
  assets:checking  $0 = $1900.00

2024-02-18
  expenses:car repair  $500.00
  assets:checking  $-500.00

# and I balance my bank statement again
2024-03-01
  assets:checking  $0 = $3400.00

# and this one is fine
2024-04-01
  assets:checking  $0 = $5400.00

Running ledger --args-only -f manual.ldg bal:

While parsing file "/tmp/tmp.GqPyNX8cUB/manual.ldg", line 9:
While parsing posting:
  assets:checking  $0 = $1900.00
                        ^^^^^^^^
Error: Balance assertion off by $-4000.00 (expected to see $5900.00)
While parsing file "/tmp/tmp.GqPyNX8cUB/manual.ldg", line 17:
While parsing posting:
  assets:checking  $0 = $3400.00
                        ^^^^^^^^
Error: Balance assertion off by $-2000.00 (expected to see $5400.00)

Because of this error, it is not even possible to "use Ledger itself to sort the data that you import". And even if the error wasn't an issue, that workflow would require running a pass to merge the manual/generated sections every time I update the journal, which is not user friendly at all.

@dbear496
Copy link
Contributor Author

Perhaps it would be possible to add a command line option to specify the sort order to use for evaluating balance assertions. That way, evaluating it based on the date is not arbitrarily hard-coded.

@dbear496
Copy link
Contributor Author

Since the desired (default) behavior is to evaluate balance assertions based on the original order of transactions, I think it would be good to add a test case for that. (It's just a bit odd that I made this PR without breaking any existing test cases.)

@jwiegley
Copy link
Member

You are right that including from two sources creates an impossible scenario for the current implementation. This is why I created support for UUID-based shadowing:

If two transactions, possibly in different files, have the same UUID metadata tag (i.e., UUID: some-string-you-create), Ledger will check that they are equal (except for soft data, like balance assertions), but otherwise all but the first are ignored.

This allows you to track the same transaction by multiple "views", such as in different files and with a different balance assertion on each, so long as the amounts reflected and the UUID are identical.

@dbear496
Copy link
Contributor Author

That is an interesting idea to use the UUID tag. If I do that, would I have to keep around all the old versions of the generated file and manually include the most recent version before each balance assertion?

@dbear496
Copy link
Contributor Author

If we decide to reject this PR, then I think we should consider cherrypicking fac14ce and af24ffd.

@jwiegley
Copy link
Member

That is an interesting idea to use the UUID tag. If I do that, would I have to keep around all the old versions of the generated file and manually include the most recent version before each balance assertion?

I don't think I fully understand this question. Why wouldn't you keep around all past data?

@dbear496
Copy link
Contributor Author

I don't think I fully understand this question. Why wouldn't you keep around all past data?

"Keeping around all past data" and "keeping around all old versions of a file" are very different. If I use the UUID feature instead of the filtered balance assertion, then my example above would turn into this:

# generated_2024-02-01.ldg

2024-01-15
  ; UUID: 11111111
  income:job  $-2000.00
  assets:checking  $2000.00
# generated_2024-03-01.ldg

2024-01-15
  ; UUID: 11111111
  income:job  $-2000.00
  assets:checking  $2000.00

2024-02-15
  ; UUID: 22222222
  income:job  $-2000.00
  assets:checking  $2000.00
# generated_2024-04-01.ldg

2024-01-15
  ; UUID: 11111111
  income:job  $-2000.00
  assets:checking  $2000.00

2024-02-15
  ; UUID: 22222222
  income:job  $-2000.00
  assets:checking  $2000.00

2024-03-15
  ; UUID: 33333333
  income:job  $2000.00
  assets:checking  $2000.00
# manual.ldg

2024-01-20
  expenses:groceries  $100.00
  assets:checking  $-100.00

include generated_2024-02-01.ldg

# here I balance my bank statement
2024-02-01
  assets:checking  $0 = $1900.00

2024-02-18
  expenses:car repair  $500.00
  assets:checking  $-500.00

include generated_2024-03-01.ldg

# and I balance my bank statement again
2024-03-01
  assets:checking  $0 = $3400.00

include generated_2024-04-01.ldg

# and this one is fine
2024-04-01
  assets:checking  $0 = $5400.00

Notice that I have to keep all the old versions of the generated file even though newer versions contain all the same data.

@jwiegley
Copy link
Member

I see. There is another recent PR that offers the ability to print hashes of entry data, that would be stable in this situation and could be used as the UUID...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

What does the expr argument do in account_t::amount?
2 participants