apauley / hledger-flow

An hledger/ledger-cli workflow focusing on automated statement import and classification
GNU General Public License v3.0
174 stars 22 forks source link

The -closing include should be part of all-years.journal, not yyyy-include.journal #79

Open lestephane opened 4 years ago

lestephane commented 4 years ago

Description

In the situation where one has yyyy-opening.journal and yyyy-closing.journal for a specific year, running one of the hledger built-in financial reports on one specific year, the user will be faced with empty reports

$ hledger bal 2017-include.journal 
--------------------
                   0

because hledger-flow adds an include to yyyy-closing.journal in the yyyy-include.journal, which effectively brings all the counters back to zero.

Expectation

I would expect hledger <any report> -f yyyy-include.journal to just work

Solution

The yyyy-opening.journal include stays in yyyy-include.journal, but yyyy-closing.journal include needs to move to the all-years.journal file, as evidenced by the all.journal in the full-fledged-hledger project. This ensures that reports work on a per-year yyyy-include.journal basis, and that reports also work on an aggregated all-years.journal basis, with the important caveat that the very last yyyy-closing.journal must not be part of the all-years.journal (even if one such file is present on the file system), otherwise we encounter the same problem of empty reports on an aggegated all-years.journal basis.

I hope that makes sense, it's a bit tricky to explain.

Version and Runtime Information

This include behaviour has been present in hledger-flow as far back as I can remember using it.

Additional context

I only found this bug because I'm trying to use hledger-flow import for my imports, while using full-fledged-hledger's export.hs for my reports, and I got confused that I was getting empty reports.

apauley commented 4 years ago

Thanks for double checking closing journals, this is something I haven't spent a lot of thinking time on yet - initially the whole concept of closing accounts seemed foreign to my non-accounting brain. But I'm warming up to it :-)

I especially would like to hear someone else's ideas on if it possible/feasible to use hledger close to automate some of this.

OK, back to your issue. While trying to replicate it I noticed that your initial command above does not have a -f:

$ hledger bal 2017-include.journal 
--------------------
                   0

My best guess on how hledger interprets this: it is trying to produce a balance for an account with 2017-include.journal in the name (eg expenses:2017-include.journal instead of expenses:Groceries). And then an answer of 0 makes sense.

That's not to say there isn't some room for improvement in hledger-flow. But please try again with the -f and tell me what you find. Or tell me if I've got my interpretation wrong.

I tried running some reports using -f on my yearly includes. Some work and some fail. Those that fail show balance assertion errors. I think it is because I haven't spent the time to create closing account journals for December 31 in year x, with a matching opening journal for January 1 in year x+1.

I don't fully understand the proposed solution. I need to try it out myself I guess. But the proposed include logic sounds complicated. I hope we can achieve the end result (having working yearly include files) in a way that is simple to explain (and simple to implement). Especially since a change like this will have to be explained in the docs.

lestephane commented 4 years ago

uh you're right, too much bookkeeping yesterday.

I'll try to dig the exact command line that was generating an empty report and re-open with that.

lestephane commented 4 years ago

FYI this is how i implement closing the year...

#!/usr/bin/env bash

source common.sh

my_dir=$(readlink -e $(dirname "$0"))
top_dir="$(dirname "${my_dir}")"

usage() {
cat <<EOF 1>&2
Usage: $0 YEAR
EOF
exit 1
}

[ $# -eq 1 ] || usage
[ $1 -gt 2000 ] || usage

CLOSEYEAR="$1"
OPENYEAR=$((CLOSEYEAR + 1))

"${my_dir}/clear-year.sh" "${CLOSEYEAR}"

echo "closing year ${CLOSEYEAR}..." 1>&2

OPENING_FILE="${top_dir}/import/${OPENYEAR}-opening.journal"
CLOSING_FILE="${top_dir}/import/${CLOSEYEAR}-closing.journal"

../hledger close \
  --auto \
  -e "${OPENYEAR}" \
  -f "${CLOSEYEAR}.journal" \
  'Assets|liabilities|Transfers:' |
    awk \
    -v cf="${CLOSING_FILE}" \
    -v of="${OPENING_FILE}" '
      /closing balances/ { f = cf }
      /opening balances/ { f = of }
      { print > f }
    '
lestephane commented 4 years ago

Here is more information:

$ hledger bs -f includes.journal -f import/2017-include.journal 
Balance Sheet 2017/12/31

             || 2017/12/31 
=============++============
 Assets      ||            
-------------++------------
-------------++------------
             ||          0 
=============++============
 Liabilities ||            
-------------++------------
-------------++------------
             ||          0 
=============++============
 Net:        ||          0 

To test my theory that the closing journal inclusion is causing the empty report, i excluded the closing balances as follows, and suddenly the balance sheet report 'works', because the balance sheet has data (the closing balances were bringing everything down to zero, causing the empty report):

$ hledger bs -f includes.journal -f import/2017-include.journal "not:desc:closing balances" --depth 2 -XEUR cur:EUR | tr '[:digit:]' 'X'
Balance Sheet XXXX/XX/XX, current value

               ||      XXXX/XX/XX 
===============++=================
 Assets        ||                 
---------------++-----------------
 Business-DE   || -X.XXX,XXXX EUR 
   Assets      || -X.XXX,XXXX EUR 
 Personal      ||  X.XXX,XXXX EUR 
   Assets      ||  X.XXX,XXXX EUR 
---------------++-----------------
               ||  X.XXX,XXXX EUR 
===============++=================
 Liabilities   ||                 
---------------++-----------------
 Business-DE   ||     XX,XXXX EUR 
   Liabilities ||     XX,XXXX EUR 
---------------++-----------------
               ||     XX,XXXX EUR 
===============++=================
 Net:          ||  X.XXX,XXXX EUR 

Does my issue make more sense now?

apauley commented 4 years ago

Yes, I see the problem, I'll try to find out some more good practices around closing balances before implementing a solution.

apauley commented 4 years ago

The issue is discussed in the hledger documentation here: https://hledger.org/hledger.html#close-usage

When playing around with bal and balancesheet, I get good results when excluding the opening and closing balances transactions with a bs:

$ hledger bs --yearly not:desc:"(opening|closing) balances"

It seems that the proposed solution where we craft includes so that only the all-years.journal have closing balances will only result in expected balances when using each individual yearly account as the journal - the zeroed out balances will still be present when using the default all-years.journal without any special exclusion tricks.

Possible approaches to deal with this:

Since this issue is generally present in hledger, and since the closing balances in hledger-flow generally follow the hledger docs, I don't think this is a bug.

The specific line in the docs, for reference:

save the closing transaction as last entry of the old file, and the opening transaction as the first entry of the new file

(the files mentioned are yearly include files)

And even though it isn't a bug, we could still implement something to make this aspect of hledger-flow better.

We should definitely point our closing balances docs to the hledger docs, and suggest some good options.

apauley commented 4 years ago

Here is a more detailed examination with some simple example journals: https://github.com/apauley/hledger-acorns

lestephane commented 4 years ago

The approach I now take is as follows

readonly opening_file="${top_dir}/import/${open_year}-opening.journal"
readonly closing_file="${top_dir}/import/${close_year}-closing.journal"

hledger close \
  --auto \
  -e "${open_year}" \
  -f "${top_dir}/includes.journal" \
  -f "${top_dir}/import/${close_year}-include.journal" \
      'Assets|Liabilities|Transfers' |
        awk \
        -v cf="${closing_file}" \
        -v of="${opening_file}" '
          /closing balances/ { f = cf }
          /opening balances/ { f = of }
          { print > f }
        '

sed -e "s#\!include #\!include ${top_dir}/import/#g" \
    -e "s/.*closing.journal/#\0/g" \
    "${top_dir}/import/${close_year}-include.journal" >> "${my_dir}/${close_year}-includes.journal"

echo '!include' "${top_dir}/includes.journal" > "${my_dir}/${close_year}.journal"
hledger print -f "${my_dir}/${close_year}-includes.journal" >> "${my_dir}/${close_year}.journal"
$ cat 2018-includes.journal
### Generated by hledger-flow - DO NOT EDIT ###

!include /scrubbed/import/2018-opening.journal
!include /scrubbed/import/x/2018-include.journal
!include /scrubbed/import/y/2018-include.journal
!include /scrubbed/import/z/2018-include.journal
#!include /scrubbed/import/2018-closing.journal

So now the 2017-include.journal from hledger-flow and the 2017.journal for full-fledged-hledger can live their own separate lives, fulfilling their own separate purposes.

apauley commented 4 years ago

I've updated the README section on closing balances to point to this issue: https://github.com/apauley/hledger-flow#a-note-of-caution-regarding-closing-balances