rewrite: Add docstring with user documentation.

This commit is contained in:
Brett Smith 2020-09-10 15:07:31 -04:00
parent 3219bf89d2
commit e60078933d

View file

@ -1,4 +1,130 @@
"""rewrite.py - Post rewriting for financial reports"""
"""rewrite.py - Post rewriting for financial reports
Introduction
------------
There are some kinds of posting metadata that's too impractical to write when
you enter it the books. For example, the ``expense-type`` of employee payroll
is usually determined by the employee's records or estimate at the end of the
year. It isn't known when payroll expenses are posted throughout the year, and
then there's too many of them to go back and code it manually.
Rewrite rules solve this problem. They provide a mechanism to make safe, bulk
transformations to postings just after they're loaded and before they're
reported. They let you fill in the gaps between the data in the books and
different reporting requirements.
Most reporting tools load rewrite rules written in YAML, so the examples in
this documentation are written that way. (If you're developing reporting tools,
note RewriteRule accepts a native Python dictionary.) One typical rule looks
like::
if:
- SUBJECT OP VALUE
[- SUBJECT2 OP2 VALUE2
- ]
action1:
- SUBJECT OP VALUE
[- SUBJECT2 OP2 VALUE2
- ]
[action2:
-
]
A ruleset, as in a YAML file, is just an array of hashes like this.
Conditions and Actions
----------------------
The hash must have at least two keys. One of them must be ``if``, and its value
is an array of condition strings. The rest can have any name you like and are
actions. Each action transforms an original posting that matched the ``if``
conditions and yields a new posting from it. The value is an array of action
strings. Conditions and actions are written the same way;
conditions just use test operators, while actions use assignment operators.
Subjects
--------
There are two kinds of subjects, attributes and metadata.
Attributes start with a ``.`` and access data directly on the posting line,
or from the parent transaction line. You can use these attributes:
================ =======================================================
Name Description
================ =======================================================
``.account`` The name of the account on the posting line
---------------- -------------------------------------------------------
``.date`` The date of the posting's transaction. When you work on
a date, write the value in ISO ``YYYY-MM-DD`` format.
---------------- -------------------------------------------------------
``.number`` The number part of the posting's position;
i.e., the amount without the currency.
================ =======================================================
Any other string is a metadata key. As usual, if a condition tries to read
metadata that does not exist on the posting, it will fall back to checking the
transaction. Metadata values are always treated as strings. NOTE: This means
comparisons against non-string metadata values, like dates and amounts, might
not work the way you want.
Condition Operators
-------------------
Conditions can always use Python's basic comparison operators:
``== != < <= > >=``. You can also use the following:
================ =======================================================
Name Description
================ =======================================================
``.account in`` The value is parsed as a space-separated list of
account names. The condition matches when the posting's
account is any of those named accounts, or any of their
respective subaccounts.
================ =======================================================
Action Operators
----------------
You can set ``.account`` and any metadata with ``=``. Values are always treated
as strings.
You can also transform the posting's number using ``.number *= NUMBER``. This
is mainly used to divide the posting's amount across multiple actions in one
rule.
Execution
---------
When rewrite rules are applied to postings, the first rule whose condition
matches "wins." When a source posting matches a rule's conditions, its actions
are applied, and the transformed posting(s) replace the source posting.
No more rewrite rules are considered for either the original source posting
or the transformed posting(s).
Validations
-----------
Rewrite rules are validated to help ensure that you don't break the fundamental
accounting equation, Equity = Assets - Liabilities.
* If an action assigns to ``.account``, there must also be a condition to check
that the ``.account`` is in the same category, using ``==`` or ``in``.
You cannot change an Asset into a Liability or Equity, and so on.
* All actions in a rewrite rule must multiply ``.number`` by a total of 1.
(Actions that don't explicitly multiply the number are understood to
multiply it by 1.) For example, a rewrite rule can have two actions that
each multiply the number by .5, or one by .8 and the other by .2. It
cannot have two actions that each multiply the number by 1, or .3,
etc. Otherwise, the different postings of a transaction would not balance.
* You cannot assign to ``.date`` at all. Otherwise, you might separate postings
of the same transaction in time, and the accounting equation would not hold
during the time gap.
"""
# Copyright © 2020 Brett Smith
#
# This program is free software: you can redistribute it and/or modify