Changeset - e60078933d3c
[Not reviewed]
0 1 0
Brett Smith - 4 years ago 2020-09-10 19:16:49
brettcsmith@brettcsmith.org
rewrite: Add docstring with user documentation.
1 file changed with 127 insertions and 1 deletions:
0 comments (0 inline, 0 general)
conservancy_beancount/reports/rewrite.py
Show inline comments
 
"""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
0 comments (0 inline, 0 general)