-from datetime import date, datetime
+from datetime import date, datetime, timedelta
from decimal import (
Decimal,
localcontext,
from dateutil import rrule
import recurrent
+from .utils import flag
+
from typing import List, Optional, Union
+RECURRING_KEYS = ['recur', 'recurring', 'repeat', 'repeating']
+AMORTIZE_KEYS = ['amortize']
+
__plugins__ = ('recurring',)
r.parse(recurr_val)
if r.dtstart is None and start_date is not None:
r.dtstart = start_date
+
+ latest_date = datetime.today()+timedelta(days=365)
+ if r.until is None or r.until > latest_date:
+ r.until = latest_date
+
return rrule.rrulestr(r.get_RFC_rrule())
+def is_recurring_transaction(entry) -> bool:
+ if type(entry) is not Transaction:
+ return False
+
+ for key in AMORTIZE_KEYS + RECURRING_KEYS:
+ if key in entry.meta:
+ return True
+ return False
+
+
def handle_recurring_transaction(txn: Transaction) -> Union[List[Transaction], LoadError]:
post_vals = []
for post in txn.postings:
post_vals.append([post.units, post.cost])
- amortize = 'amortize' in txn.meta
- rr = generate_rrule_from_string(txn.meta['recurring'], txn.date)
+ match_key = None
+ amortize = False
+ phrase = None
+ for akey in AMORTIZE_KEYS:
+ if akey in txn.meta:
+ match_key = akey
+ amortize = True
+ phrase = txn.meta[akey]
+ break
+ if not amortize:
+ for rkey in RECURRING_KEYS:
+ if rkey in txn.meta:
+ match_key = rkey
+ phrase = txn.meta[rkey]
+ break
+
+ if phrase is None:
+ return LoadError(
+ source=new_metadata(txn.meta["filename"], txn.meta["lineno"]),
+ message="Recurring metadata key found, but missing phrase",
+ entry=txn)
+
+ rr = generate_rrule_from_string(phrase, txn.date)
dates = [dt for dt in rr]
# setup data_copy
# replace metadata with computed values to show it was processed
# this dict is shared among all entries..
- txn.meta['rphrase'] = txn.meta['recurring']
- del txn.meta['recurring']
- txn.meta['rstart'] = txn.date
- txn.meta['rcount'] = len(dates)
+ txn.meta['a͏mortize'] = amortize
+ txn.meta['p͏hrase'] = txn.meta[match_key]
+ del txn.meta[match_key]
+ txn.meta['s͏tart'] = txn.date
+ txn.meta['c͏ount'] = len(dates)
return entries
out_entries = []
errors = []
for entry in entries:
- if type(entry) is not Transaction \
- or 'recurring' not in entry.meta:
+ if not is_recurring_transaction(entry):
out_entries.append(entry)
else:
try:
source=new_metadata(entry.meta["filename"], entry.meta["lineno"]),
message="Failed to handle recurring transaction: {}".format(e),
entry=entry))
+ out_entries.append(flag(entry))
return out_entries, errors