]> git.walde.dev - beanbeanbean/commitdiff
Add date formatting for recurring transactions
authorDustin Walde <redacted>
Sun, 12 Nov 2023 20:40:06 +0000 (12:40 -0800)
committerDustin Walde <redacted>
Sun, 12 Nov 2023 20:40:06 +0000 (12:40 -0800)
src/beanbeanbean/recurring.py

index 676109a8d194da0b7f9b10d145a291d0c6d6b8c0..023f9993b0cf2abc910dac24fd04328fadec138a 100644 (file)
@@ -53,7 +53,7 @@ def is_recurring_transaction(entry) -> bool:
     return False
 
 
-def handle_recurring_transaction(txn: Transaction) -> Union[List[Transaction], LoadError]:
+def handle_recurring_transaction(txn: Transaction, format_token: str) -> Union[List[Transaction], LoadError]:
     post_vals = []
     balances = {}
     for post in txn.postings:
@@ -106,9 +106,11 @@ def handle_recurring_transaction(txn: Transaction) -> Union[List[Transaction], L
     entries = []
 
     for i, dt in enumerate(dates):
-        new_txn = Transaction(date=dt.date(), postings=[], **txn_dict)
+        new_txn_dict = dict(txn_dict)
+        new_txn_dict["date"] = dt.date()
+        new_txn_dict["postings"] = []
+        new_txn_dict["meta"] = dict(txn.meta)
         if amortize:
-            new_postings = []
             balances = {}
             for j, posting in enumerate(txn.postings):
                 post_dict = posting._asdict()
@@ -142,13 +144,13 @@ def handle_recurring_transaction(txn: Transaction) -> Union[List[Transaction], L
                     remaining[1] = remaining[0]
                 else:
                     remaining[1] = amount.sub(remaining[1], amortized_cost)
-                new_postings.append(post_dict)
+                new_txn_dict["postings"].append(post_dict)
 
             if balanced:
                 # verify it all still balances
                 for remainder in balances.values():
                     if amount.abs(remainder).number >= tolerances[remainder.currency]:
-                        for post in new_postings:
+                        for post in new_txn_dict["postings"]:
                             cost = post['cost']
                             if cost is not None and cost.currency == remainder.currency:
                                 post['cost'] = amount.sub(cost, remainder)
@@ -157,22 +159,37 @@ def handle_recurring_transaction(txn: Transaction) -> Union[List[Transaction], L
                                 post['units'] = amount.sub(post['units'], remainder)
                                 break
 
-            for pd in new_postings:
+            for pd in new_txn_dict["postings"]:
                 if pd['cost'] is not None:
                     pd['cost'] = position.Cost(pd['cost'].number, pd['cost'].currency, txn.date, 'amortized')
-                new_txn.postings.append(Posting(**pd))
+                for k, v in pd["meta"].items():
+                    if type(v) is str:
+                        pd["meta"][k] = new_txn_dict["date"].strftime(v)
+                new_txn_dict["postings"].append(Posting(**pd))
         else:
             for posting in txn.postings:
-                new_txn.postings.append(posting)
-        entries.append(new_txn)
-
-    # replace metadata with computed values to show it was processed
-    # this dict is a shared reference among all entries..
-    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)
+                new_txn_dict["postings"].append(posting)
+
+        new_date = new_txn_dict["date"]
+        new_meta = new_txn_dict["meta"]
+        if new_txn_dict["narration"] is not None:
+            new_txn_dict["narration"] = new_date.strftime(new_txn_dict["narration"])
+        for set_name in ("tags", "links"):
+            if new_txn_dict[set_name] is not None:
+                tags = set()
+                for tag in new_txn_dict[set_name]:
+                    tags.add(new_date.strftime(tag.replace(format_token, "%")))
+                new_txn_dict[set_name] = frozenset(tags)
+        for k, v in new_meta.items():
+            if type(v) is str:
+                new_meta[k] = new_date.strftime(v)
+        # replace metadata with computed values to show it was processed
+        new_meta['a͏mortize'] = amortize
+        new_meta['p͏hrase'] = new_meta[match_key]
+        del new_meta[match_key]
+        new_meta['s͏tart'] = txn.date
+        new_meta['c͏ount'] = len(dates)
+        entries.append(Transaction(**new_txn_dict))
 
     return entries
 
@@ -186,14 +203,12 @@ def recurring(entries: Entries, options_map, config_string=""):
             out_entries.append(entry)
         else:
             try:
-                res = handle_recurring_transaction(entry)
+                res = handle_recurring_transaction(entry, "/")
                 if type(res) is list:
                     out_entries.extend(res)
                 else:
                     errors.append(res)
             except Exception as e:
-                import traceback
-                print(traceback.format_exc())
                 errors.append(LoadError(
                     source=new_metadata(entry.meta["filename"], entry.meta["lineno"]),
                     message="Failed to handle recurring transaction: {}".format(e),