;doc:cost reporting: another rewrite

This commit is contained in:
Simon Michael 2023-07-10 18:08:17 -10:00
parent a617778f64
commit 15c1ba3e15

View File

@ -4969,100 +4969,104 @@ See also: [Budgeting and Forecasting](/budgeting-and-forecasting.html).
# Cost reporting # Cost reporting
In transactions where one commodity is exchanged for another, such as a currency conversion, or a stock purchase/sale, In some transactions - for example a currency conversion, or a purchase or sale of stock - one commodity is exchanged for another.
the conversion rate / cost / selling price (we call them all "cost" for convenience) can be recorded, or inferred. In these transactions there is a conversion rate, also called the cost (when buying) or selling price (when selling).
Then hledger can convert amounts to cost at report time, with the `-B`/`--cost` flag ("B" is from Ledger's --basis/--cost flag). In hledger docs we just say "cost", for convenience; feel free to mentally translate to "conversion rate" or "selling price" if helpful.
There are four ways to record conversion transactions ## Recording costs
(if you are unsure which to choose, pick #2):
1. You can record amounts of different commodities, leaving the cost implicit: We'll explore several ways of recording transactions involving costs.
These are also summarised at [hledger Cookbook > Cost notation](/cost-notation.md).
```journal Costs can be recorded explicitly in the journal, using the `@ UNITCOST` or `@@ TOTALCOST` notation described in [Journal > Costs](#costs).
2022-01-01
assets:dollars $-135
assets:euros €100
```
This is easy, but if you write a wrong amount hledger won't detect it. **Variant 1**:
And in fact it's easy to create entries like this through a typo.
You can prevent this by using `-s` ([strict mode](#strict-mode)).
In entries like this, the order of postings is significant: the ```journal
first posting is given a cost in the commodity of the second. 2022-01-01
assets:dollars $-135
assets:euros €100 @ $1.35 ; $1.35 per euro (unit cost)
```
2. You can record the cost on one of the amounts with @ or @@ as described in [Journal > Costs](#costs). **Variant 2**:
This improves readability and adds redundancy which helps hledger detect errors.
a. You can write the per-unit cost with @, which requires more attention to decimal places to make the transaction balance, ```journal
but reveals the cost basis and makes partial stock sales easy later: 2022-01-01
assets:dollars $-135
assets:euros €100 @@ $135 ; $135 total cost
```
```journal Typically, writing the unit cost (variant 1) is preferable;
2022-01-01 it can be more effort, requiring more attention to decimal digits;
assets:dollars $-135 but it reveals the per-unit cost basis, and makes stock sales easier.
assets:euros €100 @ $1.35
```
b. or you can write the total cost with @@, which is easier, Costs can also be left implicit, and hledger will infer the cost
but obscures the cost basis and makes partial stock sales difficult later: that is consistent with a balanced transaction.
```journal **Variant 3**:
2022-01-01
assets:dollars $-135
assets:euros €100 @@ $135
```
This kind of entry unbalances the accounting equation, causing a non-zero total in the `bse` report. ```journal
You can fix that (if needed) by adding the `--infer-equity` flag. 2022-01-01
assets:dollars $-135
assets:euros €100
```
3. You can record a pair of equity postings to balance the converted amounts. Here, hledger will attach a `@@ €100` cost to the first amount (you can see it with `hledger print -x`).
This is the most correct and standard bookkeeping entry, which preserves the accounting equation, but is more verbose: This form looks convenient, but there are downsides:
```journal - It sacrifices some error checking. For example, if you accidentally wrote €10
2022-01-01 instead of €100, hledger would not be able to detect the mistake.
assets:dollars $-135
equity:conversion $135
equity:conversion €-100
assets:euros €100
```
With this kind of entry, you'll need to add `--infer-costs` when doing cost reporting with `-B`. - It is sensitive to the order of postings - if they were reversed,
a different entry would be inferred and reports would be different.
4. You can record both the cost and the equity postings explicitly. Eg: - The per-unit cost basis is not easy to read.
```journal So generally this kind of entry is not recommended.
2022-01-01 You can make sure you have none of these by using `-s` ([strict mode](#strict-mode)),
assets:dollars $-135 or by running `hledger check balancednoautoconversion`.
equity:conversion $135
equity:conversion €-100
assets:euros €100 @ $1.35
```
This gives the benefits of both 2 and 3. ## Reporting at cost
You can convert the other forms to this one with `hledger print -x --infer-costs --infer-equity`.
In practice, most PTA users don't need to balance the accounting equation, so method 2 is a good choice. Now when you add the `-B`/`--cost` flag to reports ("B" is from Ledger's --basis/--cost flag),
any amounts which have been annotated with costs will be converted to their cost's commodity (in the report output).
Ie they will be displayed "at cost" or "at sale price".
Conversion to cost is performed before valuation (described below). Some things to note:
The rest of this section provides more detail, - Costs are attached to specific posting amounts in specific transactions, and once recorded they do not change.
as does [hledger Cookbook > Cost notation](/cost-notation.md). This contrasts with [market prices](#market-prices), which are ambient and fluctuating.
- Conversion to cost is performed before conversion to market value (described below).
## Equity conversion postings ## Equity conversion postings
Conventional double entry bookkeeping (DEB) uses There is a problem with the entries above - they are not conventional Double Entry Bookkeeping (DEB) notation,
an extra pair of equity postings to balance the transaction instead. and because of the "magical" transformation of one commodity into another,
In this style, the above entry might be written: they cause an imbalance in the Accounting Equation.
This shows up as a non-zero grand total in balance reports like `hledger bse`.
For most hledger users, this doesn't matter in practice and can safely be ignored !
But if you'd like to learn more, keep reading.
Conventional DEB uses an extra pair of equity postings to balance the transaction.
Of course you can do this in hledger as well.
**Variant 4**:
```journal ```journal
2022-01-01 one hundred euros purchased at $1.35 each 2022-01-01
assets:dollars $-135 assets:dollars $-135
assets:euros €100 assets:euros €100
equity:conversion $135 equity:conversion $135
equity:conversion €-100 equity:conversion €-100
``` ```
hledger can do cost reporting with this kind of entry too, but you must add the `--infer-costs` flag: Now the transaction is perfectly balanced according to standard DEB,
and `hledger bse`'s total will not be disrupted.
And, hledger can still infer the cost for cost reporting,
but it's not done by default - you must add the `--infer-costs` flag like so:
```shell ```shell
$ hledger print --infer-costs $ hledger print --infer-costs
@ -5074,20 +5078,35 @@ $ hledger print --infer-costs
``` ```
```shell ```shell
$ hledger bal -N --infer-costs -B $ hledger bal --infer-costs -B
€-100 assets:dollars €-100 assets:dollars
€100 assets:euros €100 assets:euros
--------------------
0
``` ```
Conversely, if you have transactions written with @/@@ cost notation, you can use the `--infer-equity` flag Here are some downsides of this kind of entry:
to add the missing equity postings,
eg to preserve the accounting equation or to produce standard entries for non-PTA-users: - The per-unit cost basis is not easy to read.
- Instead of `-B` you must remember to type `-B --infer-costs`.
- `--infer-costs` works only where hledger can identify the two equity:conversion postings
and match them up with the two non-equity postings.
So writing the journal entry in a particular format becomes more important. More on this below.
## Inferring equity conversion postings
Can we go in the other direction ? Yes, if you have transactions written with the @/@@ cost notation,
hledger can infer the missing equity postings, if you add the `--infer-equity` flag.
Eg:
```journal ```journal
2022-01-01 2022-01-01
assets:dollars -$135 assets:dollars -$135
assets:euros €100 @ $1.35 assets:euros €100 @ $1.35
``` ```
```shell ```shell
$ hledger print --infer-equity $ hledger print --infer-equity
2022-01-01 2022-01-01
@ -5097,10 +5116,17 @@ $ hledger print --infer-equity
equity:conversion:$-€:$ $135.00 equity:conversion:$-€:$ $135.00
``` ```
You can customise the generated "equity:conversion" account names by declaring an account with the [V/Conversion account type](#account-types). The equity account names will be "equity:conversion:A-B:A" and "equity:conversion:A-B:B"
where A is the alphabetically first commodity symbol.
You can customise the "equity:conversion" part by declaring an account with the `V`/`Conversion` [account type](#account-types).
Finally, you can record both the cost and the equity postings explicitly, so no inference is needed. ## Combining costs and equity conversion postings
This gives correctness, clarity, and more flexibility in how you write the entry, at the cost of being more verbose:
Finally, you can use both the @/@@ cost notation and equity postings at the same time.
This in theory gives the best of all worlds - preserving the accounting equation,
revealing the per-unit cost basis, and providing more flexibility in how you write the entry.
**Variant 5**:
```journal ```journal
2022-01-01 one hundred euros purchased at $1.35 each 2022-01-01 one hundred euros purchased at $1.35 each
@ -5110,48 +5136,50 @@ This gives correctness, clarity, and more flexibility in how you write the entry
assets:euros €100 @ $1.35 assets:euros €100 @ $1.35
``` ```
You can rewrite most conversion transactions to (a variant of) this form with: All the other variants above can (usually) be rewritten to this final form with:
```shell ```shell
$ hledger print -x --infer-costs --infer-equity $ hledger print -x --infer-costs --infer-equity
``` ```
This (detecting and allowing redundant equity postings and cost) was added in hledger 1.29 and Downsides:
is still somewhat experimental. Here are some current limitations:
- If the entry is not written in a form that hledger can recognise (see below), - This was added in hledger-1.29 and is still somewhat experimental.
it fails to detect the redundancy and gives a transaction balancing error instead.
Amounts with repeating decimals are one of the things that can trigger this ([#2051](https://github.com/simonmichael/hledger/issues/2051)).
- The [add](#add) command does not accept this kind of entry ([#2056](https://github.com/simonmichael/hledger/issues/2056)). - The precise format of the journal entry becomes more important.
If hledger can't detect and match up the cost and equity postings, it will give a transaction balancing error.
Amounts with repeating decimals are one of the things that can cause this ([#2051](https://github.com/simonmichael/hledger/issues/2051)).
## --infer-costs - The [add](#add) command does not yet accept this kind of entry ([#2056](https://github.com/simonmichael/hledger/issues/2056)).
As mentioned above, `--infer-costs` can infer and add the @/@@ cost notation - This is the most verbose form.
to transactions which have equity conversion postings.
This flag will have an effect only on transactions where: ## Requirements for detecting equity conversion postings
- There are two non-equity postings, in different commodities `--infer-costs` has certain requirements (unlike `--infer-equity`, which always works).
- And two postings to equity accounts, next to one another, which exactly balance the above. It will infer costs only in transactions with:
Equity accounts are accounts declared with account type `V`/`Conversion`,
or named `equity:conversion`, `equity:trade`, `equity:trading`,
or subaccounts of these.
The order of postings is significant: the cost will be added to the - Two non-equity postings, in different commodities.
first of the non-equity postings, in the commodity of the second non-equity posting. Their order is significant: the cost will be added to the first of them.
Multiple such four-posting groups can coexist within a single transaction. - Two postings to equity conversion accounts, next to one another, which balance the two non-equity postings exactly.
(Perhaps over-exactly, as this is currently not limited by display precision - see #2051.)
Equity conversion accounts are:
If you want to arrange a conversion transaction in some other way, - any accounts declared with account type `V`/`Conversion`, or their subaccounts
or you can't easily see why `--infer-posting` isn't working for a particular transaction, - otherwise, accounts named `equity:conversion`, `equity:trade`, or `equity:trading`, or their subaccounts.
just write the equity postings and costs explicitly.
## Always infer cost and equity ? And multiple such four-posting groups can coexist within a single transaction.
When `--infer-costs` fails, it does not infer a cost in that transaction, and does not raise an error (ie, it infers costs where it can).
Reading variant 5 journal entries, combining cost notation and equity postings, has all the same requirements.
When reading such an entry fails, hledger raises an "unbalanced transaction" error.
## Infer cost and equity by default ?
Should `--infer-costs` and `--infer-equity` be enabled by default ? Should `--infer-costs` and `--infer-equity` be enabled by default ?
Try using them always, eg with a shell alias: Try using them always, eg with a shell alias:
``` ```
alias hl="hledger --infer-equity --infer-costs" alias h="hledger --infer-equity --infer-costs"
``` ```
and let us know what problems you find. and let us know what problems you find.