55from __future__ import annotations
66
77import datetime
8+ import html
89import logging
910import os
1011import pathlib
11- from typing import Any , Dict , List , Optional
12+ from typing import Any , Dict , Optional
1213
1314import click
1415import numpy as np
1718from rich import print , table
1819from rich .prompt import Confirm
1920
20- from lunchable import LunchMoney , TransactionUpdateObject
21+ from lunchable import TransactionUpdateObject
2122from lunchable ._config .logging_config import set_up_logging
22- from lunchable .models import CategoriesObject , TransactionObject
23+ from lunchable .models import CategoriesObject , TransactionObject , UserObject
24+ from lunchable .plugins .base .pandas_app import LunchablePandasApp
2325
2426logger = logging .getLogger (__name__ )
2527
2628
27- class PrimeLunch :
29+ class PrimeLunch ( LunchablePandasApp ) :
2830 """
2931 PrimeLunch: Amazon Notes Updater
3032 """
@@ -38,59 +40,16 @@ def __init__(
3840 """
3941 Initialize and set internal data
4042 """
43+ super ().__init__ (cache_time = 0 , access_token = access_token )
4144 self .file_path = pathlib .Path (file_path )
4245 self .time_window = time_window
43- self .transaction_map : Dict [int , TransactionObject ] = {}
44- self .cached = False
45- self .lunch = LunchMoney (access_token = access_token )
46- self .categories : dict [int , CategoriesObject ] = {}
47-
48- @staticmethod
49- def transactions_to_df (transactions : List [TransactionObject ]) -> pd .DataFrame :
50- """
51- Convert Transactions Array to DataFrame
52-
53- Parameters
54- ----------
55- transactions: List[TransactionObject]
56-
57- Returns
58- -------
59- pd.DataFrame
60- """
61- return pd .DataFrame (
62- [item .dict () for item in transactions ],
63- columns = TransactionObject .__fields__ .keys (),
64- )
65-
66- @staticmethod
67- def df_to_transactions (df : pd .DataFrame ) -> List [TransactionObject ]:
68- """
69- Convert DataFrame to Transaction Array
70-
71- Parameters
72- ----------
73- df: pd.DataFrame
74-
75- Returns
76- -------
77- List[TransactionObject]
78- """
79- array_df = df .copy ()
80- array_df = array_df .fillna (np .nan ).replace ([np .nan ], [None ])
81- transaction_array = array_df .to_dict (orient = "records" )
82- return [TransactionObject (** item ) for item in transaction_array ]
8346
8447 def amazon_to_df (self ) -> pd .DataFrame :
8548 """
8649 Read an Amazon Data File to a DataFrame
8750
8851 This is pretty simple, except duplicate header rows need to be cleaned
8952
90- Parameters
91- ----------
92- file_path: os.PathLike
93-
9453 Returns
9554 -------
9655 pd.DataFrame
@@ -286,15 +245,17 @@ def cache_transactions(
286245 start_date ,
287246 end_cache_date ,
288247 )
289- transactions = self .lunch .get_transactions (
290- start_date = start_date , end_date = end_cache_date
248+ self .get_latest_cache (include = [CategoriesObject , UserObject ])
249+ self .refresh_transactions (start_date = start_date , end_date = end_cache_date )
250+ logger .info (
251+ 'Scanning LunchMoney Budget: "%s"' ,
252+ html .unescape (self .lunch_data .user .budget_name ), # type: ignore[union-attr]
291253 )
292- transaction_map = {item .id : item for item in transactions }
293- self .categories = {item .id : item for item in self .lunch .get_categories ()}
294- self .transaction_map = transaction_map
295- self .cached = True
296- logger .info ("%s transactions returned from LunchMoney" , len (transactions ))
297- return transaction_map
254+ logger .info (
255+ "%s transactions returned from LunchMoney" ,
256+ len (self .lunch_data .transactions ),
257+ )
258+ return self .lunch_data .transactions
298259
299260 def print_transaction (
300261 self , transaction : TransactionObject , former_transaction : TransactionObject
@@ -312,7 +273,8 @@ def print_transaction(
312273 )
313274 if former_transaction .category_id is not None :
314275 transaction_table .add_row (
315- "📊 Category" , self .categories [former_transaction .category_id ].name
276+ "📊 Category" ,
277+ self .lunch_data .categories [former_transaction .category_id ].name ,
316278 )
317279 if (
318280 former_transaction .original_name is not None
@@ -345,7 +307,7 @@ def update_transaction(
345307 -------
346308 Optional[Dict[str, Any]]
347309 """
348- former_transaction = self .transaction_map [transaction .id ]
310+ former_transaction = self .lunch_data . transactions [transaction .id ]
349311 response = None
350312 stripped_notes = transaction .notes .strip () # type: ignore[union-attr]
351313 acceptable_length = min (349 , len (stripped_notes ))
@@ -386,16 +348,18 @@ def process_transactions(self, confirm: bool = True):
386348 max_date ,
387349 )
388350 self .cache_transactions (start_date = min_date , end_date = max_date )
389- transaction_df = self .transactions_to_df (
390- transactions = list ( self .transaction_map . values ())
351+ transaction_df = self .models_to_df (
352+ models = self .lunch_data . transactions . values (),
391353 )
392354 amazon_transaction_df = self .filter_amazon_transactions (df = transaction_df )
393355 merged_data = self .merge_transactions (
394356 transactions = amazon_transaction_df ,
395357 amazon = amazon_df ,
396358 time_range = self .time_window ,
397359 )
398- updated_transactions = self .df_to_transactions (df = merged_data )
360+ updated_transactions = self .df_to_models (
361+ df = merged_data , model_type = TransactionObject
362+ )
399363 responses = []
400364 for item in updated_transactions :
401365 resp = self .update_transaction (transaction = item , confirm = confirm )
0 commit comments