Skip to content

Commit fc584e9

Browse files
Multiple notification changes (2 emails being sent, currency in mail notification)
1 parent 1da4a3a commit fc584e9

File tree

1 file changed

+61
-16
lines changed

1 file changed

+61
-16
lines changed

app/email.py

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,20 @@
77
from apscheduler.schedulers.background import BackgroundScheduler
88
import atexit
99

10+
def get_currency_symbol(currency_code):
11+
"""Get currency symbol for display"""
12+
currency_symbols = {
13+
'USD': '$', 'EUR': '€', 'GBP': '£', 'JPY': '¥', 'CHF': 'CHF ',
14+
'CAD': 'C$', 'AUD': 'A$', 'NZD': 'NZ$', 'SEK': 'kr', 'NOK': 'kr',
15+
'DKK': 'kr', 'PLN': 'zł', 'CZK': 'Kč', 'HUF': 'Ft', 'RON': 'lei',
16+
'BGN': 'лв', 'HRK': 'kn', 'RSD': 'RSD', 'TRY': '₺', 'RUB': '₽',
17+
'CNY': '¥', 'INR': '₹', 'KRW': '₩', 'SGD': 'S$', 'HKD': 'HK$',
18+
'MYR': 'RM', 'THB': '฿', 'PHP': '₱', 'IDR': 'Rp', 'VND': '₫',
19+
'BRL': 'R$', 'ARS': '$', 'CLP': '$', 'COP': '$', 'PEN': 'S/',
20+
'MXN': '$', 'ZAR': 'R', 'EGP': 'E£', 'MAD': 'MAD', 'NGN': '₦'
21+
}
22+
return currency_symbols.get(currency_code, currency_code + ' ')
23+
1024
def format_date_for_user(date_obj, user):
1125
"""Format date based on user's date format preference"""
1226
if not date_obj:
@@ -29,6 +43,11 @@ def format_date_for_user(date_obj, user):
2943
def create_email_body(user, subscriptions):
3044
"""Create HTML email body for subscription notifications"""
3145

46+
# Get user's preferred currency
47+
user_settings = user.settings or UserSettings()
48+
user_currency = user_settings.currency or 'EUR'
49+
currency_symbol = get_currency_symbol(user_currency)
50+
3251
html_body = f"""
3352
<html>
3453
<head>
@@ -66,13 +85,17 @@ def create_email_body(user, subscriptions):
6685
css_class = "subscription"
6786
urgency = "ℹ️ NOTICE"
6887

88+
# Get costs in user's preferred currency
89+
raw_cost = subscription.get_raw_cost_in_currency(user_currency)
90+
monthly_cost = subscription.get_monthly_cost_in_currency(user_currency)
91+
6992
html_body += f"""
7093
<div class="{css_class}">
7194
<h3>{urgency} - {subscription.name}</h3>
7295
<p><strong>Company:</strong> {subscription.company}</p>
7396
<p><strong>Category:</strong> {subscription.category or 'Not specified'}</p>
74-
<p><strong>Cost:</strong> <span class="cost">${subscription.cost:.2f}</span> ({subscription.billing_cycle})</p>
75-
<p><strong>Monthly Cost:</strong> <span class="cost">${subscription.get_monthly_cost():.2f}</span></p>
97+
<p><strong>Cost:</strong> <span class="cost">{currency_symbol}{raw_cost:.2f}</span> ({subscription.billing_cycle})</p>
98+
<p><strong>Monthly Cost:</strong> <span class="cost">{currency_symbol}{monthly_cost:.2f}</span></p>
7699
<p><strong>Expires in:</strong> {days_left} day(s) ({format_date_for_user(subscription.end_date, user)})</p>
77100
{f'<p><strong>Notes:</strong> {subscription.notes}</p>' if subscription.notes else ''}
78101
</div>
@@ -120,6 +143,10 @@ def send_expiry_notification(app, user, subscriptions):
120143
msg['To'] = to_email
121144

122145
# Create plain text version
146+
user_settings = user.settings or UserSettings()
147+
user_currency = user_settings.currency or 'EUR'
148+
currency_symbol = get_currency_symbol(user_currency)
149+
123150
text_body = f"""
124151
Hello {user.username},
125152
@@ -129,11 +156,14 @@ def send_expiry_notification(app, user, subscriptions):
129156

130157
for subscription in subscriptions:
131158
days_left = subscription.days_until_expiry()
159+
raw_cost = subscription.get_raw_cost_in_currency(user_currency)
160+
monthly_cost = subscription.get_monthly_cost_in_currency(user_currency)
161+
132162
text_body += f"""
133163
- {subscription.name} ({subscription.company})
134164
Expires in {days_left} day(s) on {format_date_for_user(subscription.end_date, user)}
135-
Cost: ${subscription.cost:.2f} ({subscription.billing_cycle})
136-
Monthly Cost: ${subscription.get_monthly_cost():.2f}
165+
Cost: {currency_symbol}{raw_cost:.2f} ({subscription.billing_cycle})
166+
Monthly Cost: {currency_symbol}{monthly_cost:.2f}
137167
138168
"""
139169

@@ -176,14 +206,6 @@ def send_expiry_notification(app, user, subscriptions):
176206
print("📨 Sending email...")
177207
server.send_message(msg)
178208

179-
# Update last notification date for the user (not individual subscriptions)
180-
user_settings = user.settings or UserSettings()
181-
user_settings.last_notification_sent = datetime.now().date()
182-
if not user.settings:
183-
user_settings.user_id = user.id
184-
db.session.add(user_settings)
185-
db.session.commit()
186-
187209
print(f"✅ Notification sent to {user.username} for {len(subscriptions)} subscriptions")
188210
return True
189211

@@ -221,10 +243,15 @@ def check_expiring_subscriptions(app):
221243
print(f"⏭️ Skipping {user.username} - notifications disabled")
222244
continue
223245

224-
# Check if we already sent a notification today for this user
246+
# Double-check if we already sent a notification today for this user (database level check)
225247
today = current_time.date()
248+
# Refresh user_settings from database to get latest value
249+
if user.settings:
250+
db.session.refresh(user.settings)
251+
user_settings = user.settings
252+
226253
if user_settings.last_notification_sent == today:
227-
print(f"⏭️ Skipping {user.username} - already notified today")
254+
print(f"⏭️ Skipping {user.username} - already notified today (last sent: {user_settings.last_notification_sent})")
228255
continue
229256

230257
# Check if it's the user's preferred notification time (±1 hour window)
@@ -250,18 +277,35 @@ def check_expiring_subscriptions(app):
250277

251278
if expiring_subscriptions:
252279
print(f"📧 Sending notification to {user.username} for {len(expiring_subscriptions)} subscriptions at preferred time {preferred_hour}:00")
280+
281+
# Set the notification sent flag BEFORE sending email to prevent race conditions
282+
if not user.settings:
283+
user_settings = UserSettings(user_id=user.id)
284+
db.session.add(user_settings)
285+
user_settings.last_notification_sent = today
286+
db.session.commit()
287+
253288
success = send_expiry_notification(app, user, expiring_subscriptions)
254289
if success:
255290
total_notifications += 1
291+
print(f"✅ Notification successfully sent and marked as sent for {user.username}")
256292
else:
257-
print(f"❌ Failed to send notification to {user.username}")
293+
# If email failed, remove the notification flag so it can be retried later
294+
user_settings.last_notification_sent = None
295+
db.session.commit()
296+
print(f"❌ Failed to send notification to {user.username}, will retry later")
258297
else:
259298
print(f"✅ No expiring subscriptions for {user.username}")
260299

261300
print(f"📊 Notification check completed. Sent {total_notifications} notifications.")
262301

263302
def start_scheduler(app):
264303
"""Start the background scheduler for checking expiring subscriptions"""
304+
# Check if scheduler is already running to prevent duplicates
305+
if hasattr(app, '_notification_scheduler') and app._notification_scheduler:
306+
print("⚠️ Notification scheduler already running, skipping initialization")
307+
return
308+
265309
scheduler = BackgroundScheduler()
266310

267311
# Check every hour to respect user-specific notification times
@@ -274,8 +318,9 @@ def start_scheduler(app):
274318
)
275319

276320
scheduler.start()
321+
app._notification_scheduler = scheduler
277322
atexit.register(lambda: scheduler.shutdown())
278-
print("Email notification scheduler started (checking hourly)")
323+
print("Email notification scheduler started (checking hourly)")
279324

280325
def send_test_email(app, user):
281326
"""Send a test email to verify email configuration"""

0 commit comments

Comments
 (0)