reconciler: Add --full-months option to round statement dates to month boundaries
This commit is contained in:
parent
07d7737bd0
commit
8b08997fda
2 changed files with 38 additions and 0 deletions
|
@ -295,6 +295,20 @@ def format_multirecord(r1s: List[dict], r2s: List[dict], note: str) -> List[list
|
||||||
return match_output
|
return match_output
|
||||||
|
|
||||||
|
|
||||||
|
def _start_of_month(time, offset_months=0):
|
||||||
|
if offset_months > 0:
|
||||||
|
return _start_of_month(time.replace(day=28) + datetime.timedelta(days=4), offset_months - 1)
|
||||||
|
else:
|
||||||
|
return time.replace(day=1)
|
||||||
|
|
||||||
|
|
||||||
|
def round_to_month(begin_date, end_date):
|
||||||
|
"""Round a beginning and end date to beginning and end of months respectively."""
|
||||||
|
return (
|
||||||
|
_start_of_month(begin_date),
|
||||||
|
_start_of_month(end_date, offset_months=1) - datetime.timedelta(days=1))
|
||||||
|
|
||||||
|
|
||||||
def sort_records(records: List) -> List:
|
def sort_records(records: List) -> List:
|
||||||
return sorted(records, key=lambda x: (x['date'], x['amount']))
|
return sorted(records, key=lambda x: (x['date'], x['amount']))
|
||||||
|
|
||||||
|
@ -596,6 +610,7 @@ def parse_arguments(argv: List[str]) -> argparse.Namespace:
|
||||||
# parser.add_argument('--report-group-regex')
|
# parser.add_argument('--report-group-regex')
|
||||||
parser.add_argument('--show-reconciled-matches', action='store_true')
|
parser.add_argument('--show-reconciled-matches', action='store_true')
|
||||||
parser.add_argument('--non-interactive', action='store_true', help="Don't prompt to write to the books") # parser.add_argument('--statement-balance', type=parse_decimal_with_separator, required=True, help="A.K.A \"cleared balance\" taken from the end of the period on the PDF statement. Required because CSV statements don't include final or running totals")
|
parser.add_argument('--non-interactive', action='store_true', help="Don't prompt to write to the books") # parser.add_argument('--statement-balance', type=parse_decimal_with_separator, required=True, help="A.K.A \"cleared balance\" taken from the end of the period on the PDF statement. Required because CSV statements don't include final or running totals")
|
||||||
|
parser.add_argument('--full-months', action='store_true', help='Match payments over the full month, rather that just between the beginning and end dates of the CSV statement')
|
||||||
args = parser.parse_args(args=argv)
|
args = parser.parse_args(args=argv)
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
@ -676,6 +691,9 @@ def main(arglist: Optional[Sequence[str]] = None,
|
||||||
begin_date = statement_trans[0]['date']
|
begin_date = statement_trans[0]['date']
|
||||||
end_date = statement_trans[-1]['date']
|
end_date = statement_trans[-1]['date']
|
||||||
|
|
||||||
|
if args.full_months:
|
||||||
|
begin_date, end_date = round_to_month(begin_date, end_date)
|
||||||
|
|
||||||
# Query for the Beancount books data for this above period.
|
# Query for the Beancount books data for this above period.
|
||||||
#
|
#
|
||||||
# There are pros and cons for using Beancount's in-memory entries
|
# There are pros and cons for using Beancount's in-memory entries
|
||||||
|
|
|
@ -5,6 +5,8 @@ import os
|
||||||
import tempfile
|
import tempfile
|
||||||
import textwrap
|
import textwrap
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
from conservancy_beancount.reconcile.statement_reconciler import (
|
from conservancy_beancount.reconcile.statement_reconciler import (
|
||||||
date_proximity,
|
date_proximity,
|
||||||
format_output,
|
format_output,
|
||||||
|
@ -15,6 +17,7 @@ from conservancy_beancount.reconcile.statement_reconciler import (
|
||||||
read_fr_csv,
|
read_fr_csv,
|
||||||
remove_duplicate_words,
|
remove_duplicate_words,
|
||||||
remove_payee_junk,
|
remove_payee_junk,
|
||||||
|
round_to_month,
|
||||||
subset_match,
|
subset_match,
|
||||||
totals,
|
totals,
|
||||||
write_metadata_to_books,
|
write_metadata_to_books,
|
||||||
|
@ -388,3 +391,20 @@ def test_format_output():
|
||||||
matches, _, _ = match_statement_and_books(statement, books)
|
matches, _, _ = match_statement_and_books(statement, books)
|
||||||
output = format_output(matches, datetime.date(2022, 1, 1), datetime.date(2022, 2, 1), 'test.csv', True)
|
output = format_output(matches, datetime.date(2022, 1, 1), datetime.date(2022, 2, 1), 'test.csv', True)
|
||||||
assert '2022-01-01: 10.00 Patreon / Patreon / 12345 → 2022-01-01: 10.00 Patreon ✓ Matched' in output
|
assert '2022-01-01: 10.00 Patreon / Patreon / 12345 → 2022-01-01: 10.00 Patreon ✓ Matched' in output
|
||||||
|
|
||||||
|
|
||||||
|
month_test_data = [
|
||||||
|
((datetime.date(2022, 1, 2), datetime.date(2022, 1, 30)),
|
||||||
|
(datetime.date(2022, 1, 1), datetime.date(2022, 1, 31))),
|
||||||
|
((datetime.date(2022, 4, 2), datetime.date(2022, 4, 29)),
|
||||||
|
(datetime.date(2022, 4, 1), datetime.date(2022, 4, 30))),
|
||||||
|
((datetime.date(2022, 2, 2), datetime.date(2022, 2, 27)),
|
||||||
|
(datetime.date(2022, 2, 1), datetime.date(2022, 2, 28))),
|
||||||
|
((datetime.date(2024, 2, 2), datetime.date(2024, 2, 27)),
|
||||||
|
(datetime.date(2024, 2, 1), datetime.date(2024, 2, 29))),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('input_dates,rounded_dates', month_test_data)
|
||||||
|
def test_rounds_to_full_month(input_dates, rounded_dates):
|
||||||
|
assert round_to_month(*input_dates) == rounded_dates
|
||||||
|
|
Loading…
Reference in a new issue