22import logging
33import os
44import argparse
5- from datetime import datetime
65from sync import YNABClient
76
7+
88def backfill_splits (account_config : dict , dry_run : bool = False ) -> None :
99 """
1010 Backfills category splits for all previously synced transactions that haven't been split yet.
@@ -23,16 +23,17 @@ def backfill_splits(account_config: dict, dry_run: bool = False) -> None:
2323 response = ynab .request .get (
2424 f"{ ynab .base_url } /budgets/{ ynab .budget_id } /transactions"
2525 ).json ()
26-
26+
2727 transactions = response ["data" ]["transactions" ]
28-
28+
2929 # Filter for synced transactions (green flag) that don't have subtransactions
3030 synced_transactions = [
31- t for t in transactions
32- if t .get ("flag_color" ) == "green"
31+ t
32+ for t in transactions
33+ if t .get ("flag_color" ) == "green"
3334 and (not t .get ("subtransactions" ) or len (t .get ("subtransactions" )) == 0 )
3435 ]
35-
36+
3637 if not synced_transactions :
3738 logging .info ("No transactions found that need backfilling" )
3839 return
@@ -41,10 +42,14 @@ def backfill_splits(account_config: dict, dry_run: bool = False) -> None:
4142 synced_transactions .sort (key = lambda x : x ["date" ])
4243 first_transaction = synced_transactions [0 ]
4344 last_transaction = synced_transactions [- 1 ]
44- total_amount = sum (abs (t ["amount" ]) for t in synced_transactions ) / 1000 # Convert to dollars
45+ total_amount = (
46+ sum (abs (t ["amount" ]) for t in synced_transactions ) / 1000
47+ ) # Convert to dollars
4548
4649 logging .info (f"Found { len (synced_transactions )} transactions to backfill" )
47- logging .info (f"Date range: { first_transaction ['date' ]} to { last_transaction ['date' ]} " )
50+ logging .info (
51+ f"Date range: { first_transaction ['date' ]} to { last_transaction ['date' ]} "
52+ )
4853 logging .info (f"Total amount to be split: ${ total_amount :.2f} " )
4954
5055 if dry_run :
@@ -56,24 +61,24 @@ def backfill_splits(account_config: dict, dry_run: bool = False) -> None:
5661 f"Transaction: { t ['date' ]} { t ['payee_name' ]} "
5762 f"(${ abs (t ['amount' ]) / 1000 :.2f} ) would be split into:"
5863 )
59- logging .info (
60- f" - Original category: ${ abs (remaining_amount ) / 1000 :.2f} "
61- )
62- logging .info (
63- f" - Splitwise category: ${ abs (split_amount ) / 1000 :.2f} "
64- )
64+ logging .info (f" - Original category: ${ abs (remaining_amount ) / 1000 :.2f} " )
65+ logging .info (f" - Splitwise category: ${ abs (split_amount ) / 1000 :.2f} " )
6566 logging .info ("\n Summary:" )
6667 logging .info (f"Total transactions to be updated: { len (synced_transactions )} " )
67- logging .info (f"First transaction date: { first_transaction ['date' ]} ({ first_transaction ['payee_name' ]} )" )
68- logging .info (f"Last transaction date: { last_transaction ['date' ]} ({ last_transaction ['payee_name' ]} )" )
68+ logging .info (
69+ f"First transaction date: { first_transaction ['date' ]} ({ first_transaction ['payee_name' ]} )"
70+ )
71+ logging .info (
72+ f"Last transaction date: { last_transaction ['date' ]} ({ last_transaction ['payee_name' ]} )"
73+ )
6974 logging .info (f"Total amount to be split: ${ total_amount :.2f} " )
7075 return
71-
76+
7277 # Process transactions in batches of 100 to avoid API limits
7378 batch_size = 100
7479 processed_count = 0
7580 for i in range (0 , len (synced_transactions ), batch_size ):
76- batch = synced_transactions [i : i + batch_size ]
81+ batch = synced_transactions [i : i + batch_size ]
7782 try :
7883 ynab .set_transactions_synced (batch )
7984 processed_count += len (batch )
@@ -83,15 +88,23 @@ def backfill_splits(account_config: dict, dry_run: bool = False) -> None:
8388
8489 logging .info ("\n Backfill Summary:" )
8590 logging .info (f"Total transactions processed: { processed_count } " )
86- logging .info (f"First transaction date: { first_transaction ['date' ]} ({ first_transaction ['payee_name' ]} )" )
87- logging .info (f"Last transaction date: { last_transaction ['date' ]} ({ last_transaction ['payee_name' ]} )" )
91+ logging .info (
92+ f"First transaction date: { first_transaction ['date' ]} ({ first_transaction ['payee_name' ]} )"
93+ )
94+ logging .info (
95+ f"Last transaction date: { last_transaction ['date' ]} ({ last_transaction ['payee_name' ]} )"
96+ )
8897 logging .info (f"Total amount split: ${ total_amount :.2f} " )
8998
99+
90100def main ():
91101 # Set up argument parser
92- parser = argparse .ArgumentParser (description = 'Backfill YNAB transaction splits' )
93- parser .add_argument ('--dry-run' , action = 'store_true' ,
94- help = 'Show what would be done without making actual changes' )
102+ parser = argparse .ArgumentParser (description = "Backfill YNAB transaction splits" )
103+ parser .add_argument (
104+ "--dry-run" ,
105+ action = "store_true" ,
106+ help = "Show what would be done without making actual changes" ,
107+ )
95108 args = parser .parse_args ()
96109
97110 logging .basicConfig (level = os .environ .get ("LOGLEVEL" , "INFO" ).upper ())
@@ -111,5 +124,6 @@ def main():
111124
112125 logging .info ("Finished YNAB to Splitwise backfill" )
113126
127+
114128if __name__ == "__main__" :
115129 main ()
0 commit comments