Skip to content

Commit 2b35680

Browse files
committed
🐛 PrimeLunch Refunds
1 parent 81cfd40 commit 2b35680

File tree

3 files changed

+49
-16
lines changed

3 files changed

+49
-16
lines changed

docs/source/primelunch.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,14 @@ The below command runs the `PrimeLunch` update tool:
5151
lunchable plugins primelunch run -f ~/Downloads/amazon_order_history.csv
5252
```
5353

54-
The below command runs the `PrimeLunch` update tool using a date window of three days
55-
instead of 5 days:
54+
The below command runs the `PrimeLunch` update tool using a date window of fourteen days
55+
instead of the default seven days (these larger windows are especially useful for finding refunds and recurring
56+
purchases):
5657

5758
```shell
5859
lunchable plugins primelunch run \
5960
--file ~/Downloads/amazon_order_history.csv \
60-
--window 3
61+
--window 14
6162
```
6263

6364
Update all transactions without going through the confirmation prompt for each one:

lunchable/plugins/primelunch/README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,14 @@ The below command runs the `PrimeLunch` update tool:
5151
lunchable plugins primelunch run -f ~/Downloads/amazon_order_history.csv
5252
```
5353

54-
The below command runs the `PrimeLunch` update tool using a date window of three days
55-
instead of 5 days:
54+
The below command runs the `PrimeLunch` update tool using a date window of fourteen days
55+
instead of the default seven days (these larger windows are especially useful for finding refunds and recurring
56+
purchases):
5657

5758
```shell
5859
lunchable plugins primelunch run \
5960
--file ~/Downloads/amazon_order_history.csv \
60-
--window 3
61+
--window 14
6162
```
6263

6364
Update all transactions without going through the confirmation prompt for each one:

lunchable/plugins/primelunch/primelunch.py

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
from lunchable import LunchMoney, TransactionUpdateObject
2121
from lunchable._config.logging_config import set_up_logging
22-
from lunchable.models import TransactionObject
22+
from lunchable.models import CategoriesObject, TransactionObject
2323

2424
logger = logging.getLogger(__name__)
2525

@@ -32,7 +32,7 @@ class PrimeLunch:
3232
def __init__(
3333
self,
3434
file_path: str | os.PathLike,
35-
time_window: int = 5,
35+
time_window: int = 7,
3636
access_token: Optional[str] = None,
3737
) -> None:
3838
"""
@@ -43,6 +43,7 @@ def __init__(
4343
self.transaction_map: Dict[int, TransactionObject] = {}
4444
self.cached = False
4545
self.lunch = LunchMoney(access_token=access_token)
46+
self.categories: dict[int, CategoriesObject] = {}
4647

4748
@staticmethod
4849
def transactions_to_df(transactions: List[TransactionObject]) -> pd.DataFrame:
@@ -169,7 +170,7 @@ def deduplicate_matched(cls, df: pd.DataFrame) -> pd.DataFrame:
169170

170171
@classmethod
171172
def merge_transactions(
172-
cls, amazon: pd.DataFrame, transactions: pd.DataFrame, time_range: int = 5
173+
cls, amazon: pd.DataFrame, transactions: pd.DataFrame, time_range: int = 7
173174
) -> pd.DataFrame:
174175
"""
175176
Merge Amazon Transactions and LunchMoney Transaction
@@ -186,16 +187,20 @@ def merge_transactions(
186187
-------
187188
pd.DataFrame
188189
"""
190+
refunded_data = amazon[amazon["refund"] > 0].copy()
191+
refunded_data["total"] = -refunded_data["refund"]
192+
refunded_data["items"] = "REFUND: " + refunded_data["items"]
193+
complete_amazon_data = pd.concat([amazon, refunded_data], ignore_index=True)
189194
merged_data = transactions.copy()
190195
merged_data = merged_data.merge(
191-
amazon,
196+
complete_amazon_data,
192197
how="inner",
193198
left_on=["amount"],
194199
right_on=["total"],
195200
suffixes=(None, "_amazon"),
196201
)
197202
merged_data["start_date"] = merged_data["date_amazon"]
198-
merged_data["end_date"] = merged_data["start_date"] + datetime.timedelta(
203+
merged_data["end_date"] = merged_data["date_amazon"] + datetime.timedelta(
199204
days=time_range
200205
)
201206
merged_data.query(
@@ -232,14 +237,14 @@ def cache_transactions(
232237
start_date=start_date, end_date=end_cache_date
233238
)
234239
transaction_map = {item.id: item for item in transactions}
240+
self.categories = {item.id: item for item in self.lunch.get_categories()}
235241
self.transaction_map = transaction_map
236242
self.cached = True
237243
logger.info("%s transactions returned from LunchMoney", len(transactions))
238244
return transaction_map
239245

240-
@classmethod
241246
def print_transaction(
242-
cls, transaction: TransactionObject, former_transaction: TransactionObject
247+
self, transaction: TransactionObject, former_transaction: TransactionObject
243248
) -> None:
244249
"""
245250
Print a Transaction for interactive input
@@ -250,8 +255,12 @@ def print_transaction(
250255
transaction_table.add_row("🏦 Payee", former_transaction.payee)
251256
transaction_table.add_row("📅 Date", str(former_transaction.date))
252257
transaction_table.add_row(
253-
"💰 Amount", "$" + str(round(former_transaction.amount, 2))
258+
"💰 Amount", self.format_currency(amount=former_transaction.amount)
254259
)
260+
if former_transaction.category_id is not None:
261+
transaction_table.add_row(
262+
"📊 Category", self.categories[former_transaction.category_id].name
263+
)
255264
if (
256265
former_transaction.original_name is not None
257266
and former_transaction.original_name != former_transaction.payee
@@ -329,7 +338,9 @@ def process_transactions(self, confirm: bool = True):
329338
)
330339
amazon_transaction_df = self.filter_amazon_transactions(df=transaction_df)
331340
merged_data = self.merge_transactions(
332-
transactions=amazon_transaction_df, amazon=amazon_df, time_range=5
341+
transactions=amazon_transaction_df,
342+
amazon=amazon_df,
343+
time_range=self.time_window,
333344
)
334345
updated_transactions = self.df_to_transactions(df=merged_data)
335346
responses = []
@@ -339,6 +350,26 @@ def process_transactions(self, confirm: bool = True):
339350
responses.append(resp)
340351
logger.info("%s LunchMoney transactions updated", len(responses))
341352

353+
@staticmethod
354+
def format_currency(amount: float) -> str:
355+
"""
356+
Format currency amounts to be pleasant and human readable
357+
358+
Parameters
359+
----------
360+
amount: float
361+
Float Amount to be converted into a string
362+
363+
Returns
364+
-------
365+
str
366+
"""
367+
if amount < 0:
368+
float_string = "[bold red]$ ({:,.2f})[/bold red]".format(float(abs(amount)))
369+
else:
370+
float_string = "[bold green]$ {:,.2f}[/bold green]".format(float(amount))
371+
return float_string
372+
342373

343374
@click.command("run")
344375
@click.option(
@@ -356,7 +387,7 @@ def process_transactions(self, confirm: bool = True):
356387
type=click.INT,
357388
help="Allowable time window between Amazon transaction date and "
358389
"credit card transaction date",
359-
default=5,
390+
default=7,
360391
)
361392
@click.option(
362393
"-a",

0 commit comments

Comments
 (0)