9.8 KiB
9.8 KiB
Custom Recurring Expenses - What Changed
Database Model Changes
Before
class Subscription(db.Model):
id
name
amount
frequency # only: weekly, biweekly, monthly, quarterly, yearly
category_id
user_id
next_due_date
is_active
is_confirmed
auto_detected
confidence_score
notes
created_at
last_reminded
After ✨
class Subscription(db.Model):
id
name
amount
frequency # NOW INCLUDES: custom
custom_interval_days # 🆕 For custom frequency
category_id
user_id
next_due_date
start_date # 🆕 First occurrence
end_date # 🆕 Optional end date
total_occurrences # 🆕 Payment limit
occurrences_count # 🆕 Current count
is_active
is_confirmed
auto_detected
auto_create_expense # 🆕 Auto-creation flag
confidence_score
notes
created_at
last_reminded
last_auto_created # 🆕 Last auto-create date
# 🆕 NEW METHODS
should_create_expense_today()
advance_next_due_date()
Form Changes
Create Subscription - Before
Name: [_____]
Amount: [_____]
Frequency: [Monthly ▼] ← Only 5 options
Category: [Bills ▼]
Next Payment: [2025-01-15]
Notes: [_________]
[Cancel] [Save]
Create Subscription - After ✨
Name: [_____]
Amount: [_____]
Frequency: [Custom ▼] ← 6 options now, including Custom
→ Custom Interval: [45] days 🆕 (shown when Custom selected)
Category: [Bills ▼]
Start Date: [2025-01-01] 🆕
End Date: [2025-12-31] 🆕 (optional)
Total Payments: [12] 🆕 (optional)
☑ Auto-Create Expenses 🆕
"Automatically add expense when payment is due"
Notes: [_________]
[Cancel] [Save]
UI Display Changes
Subscription List - Before
🔄 Netflix Premium
💰 $19.99 / Monthly
📅 Next: Jan 15, 2025
📊 Annual: $239.88
[Edit] [Delete]
Subscription List - After ✨
🔄 Netflix Premium ⚡ AUTO 🆕
💰 $19.99 / Monthly
📅 Next: Jan 15, 2025
📊 Annual: $239.88
🔢 8/12 times 🆕 (if total_occurrences set)
[Edit] [Delete]
🔄 Car Maintenance
💰 $75.00 / Every 45 days 🆕 (custom interval display)
📅 Next: Feb 28, 2025
📊 Annual: $608.25
[Edit] [Delete]
Page Header Changes
Before
🔄 Subscriptions
[🔍 Detect Recurring] [➕ Add Subscription]
After ✨
🔄 Subscriptions
[⚡ Create Due Expenses] 🆕 [🔍 Detect Recurring] [➕ Add Subscription]
Route Changes
Before
GET /subscriptions # List
GET /subscriptions/create # Form
POST /subscriptions/create # Save
GET /subscriptions/<id>/edit # Edit form
POST /subscriptions/<id>/edit # Update
POST /subscriptions/<id>/delete
POST /subscriptions/detect # AI detection
POST /subscriptions/<id>/accept
POST /subscriptions/<id>/dismiss
GET /subscriptions/api/upcoming
After ✨
GET /subscriptions # List
GET /subscriptions/create # Form (now with custom fields)
POST /subscriptions/create # Save (handles custom data)
GET /subscriptions/<id>/edit # Edit form (now with custom fields)
POST /subscriptions/<id>/edit # Update (handles custom data)
POST /subscriptions/<id>/delete
POST /subscriptions/detect # AI detection
POST /subscriptions/<id>/accept
POST /subscriptions/<id>/dismiss
GET /subscriptions/api/upcoming
POST /subscriptions/auto-create # 🆕 Auto-create expenses
Translation Keys Added
English
'subscription.freq_custom': 'Custom' 🆕
'subscription.custom_interval': 'Repeat Every (Days)' 🆕
'subscription.start_date': 'Start Date' 🆕
'subscription.end_date': 'End Date' 🆕
'subscription.total_occurrences': 'Total Payments' 🆕
'subscription.auto_create': 'Auto-Create Expenses' 🆕
'subscription.create_due': 'Create Due Expenses' 🆕
'subscription.auto': 'AUTO' 🆕
'subscription.every': 'Every' 🆕
'subscription.days': 'days' 🆕
'subscription.times': 'times' 🆕
# + 5 more helper keys
Romanian + Spanish
- All keys translated in both languages ✓
Code Logic Changes
Frequency Calculation - Before
def get_frequency_days(self):
frequency_map = {
'weekly': 7,
'biweekly': 14,
'monthly': 30,
'quarterly': 90,
'yearly': 365
}
return frequency_map.get(self.frequency, 30)
Frequency Calculation - After ✨
def get_frequency_days(self):
if self.frequency == 'custom' and self.custom_interval_days: 🆕
return self.custom_interval_days 🆕
frequency_map = {
'weekly': 7,
'biweekly': 14,
'monthly': 30,
'quarterly': 90,
'yearly': 365
}
return frequency_map.get(self.frequency, 30)
New Auto-Create Logic ✨
def should_create_expense_today(self):
"""Check if expense should be auto-created today"""
if not self.auto_create_expense or not self.is_active:
return False
if not self.next_due_date or self.next_due_date != today:
return False
if self.last_auto_created == today:
return False # Already created today
if self.total_occurrences and self.occurrences_count >= self.total_occurrences:
return False # Reached limit
if self.end_date and today > self.end_date:
return False # Past end date
return True
def advance_next_due_date(self):
"""Move to next due date and check limits"""
interval_days = self.get_frequency_days()
self.next_due_date = self.next_due_date + timedelta(days=interval_days)
self.occurrences_count += 1
# Auto-deactivate if limits reached
if self.total_occurrences and self.occurrences_count >= self.total_occurrences:
self.is_active = False
if self.end_date and self.next_due_date > self.end_date:
self.is_active = False
JavaScript Changes
Create Form - Added
function toggleCustomInterval() {
const frequency = document.getElementById('frequency').value;
const customGroup = document.getElementById('custom-interval-group');
const customInput = document.getElementById('custom_interval_days');
if (frequency === 'custom') {
customGroup.style.display = 'block';
customInput.required = true;
} else {
customGroup.style.display = 'none';
customInput.required = false;
}
}
Files Created
migrate_custom_recurring.py- Migration script (Python)CUSTOM_RECURRING_GUIDE.md- Complete user guide (30+ sections)CUSTOM_RECURRING_SUMMARY.md- Quick feature summary
Files Modified
app/models/subscription.py- Added 7 fields + 2 methodsapp/routes/subscriptions.py- Updated create/edit + added auto-create endpointapp/templates/subscriptions/create.html- Added custom frequency UIapp/templates/subscriptions/edit.html- Added custom frequency UIapp/templates/subscriptions/index.html- Added AUTO badge + auto-create buttonapp/translations.py- Added 15+ keys in 3 languages
Migration Steps
Database
-- New columns added:
ALTER TABLE subscriptions ADD COLUMN custom_interval_days INTEGER;
ALTER TABLE subscriptions ADD COLUMN start_date DATE;
ALTER TABLE subscriptions ADD COLUMN end_date DATE;
ALTER TABLE subscriptions ADD COLUMN total_occurrences INTEGER;
ALTER TABLE subscriptions ADD COLUMN occurrences_count INTEGER DEFAULT 0;
ALTER TABLE subscriptions ADD COLUMN auto_create_expense BOOLEAN DEFAULT 0;
ALTER TABLE subscriptions ADD COLUMN last_auto_created DATE;
-- Backfill start_date from next_due_date:
UPDATE subscriptions
SET start_date = next_due_date
WHERE start_date IS NULL AND next_due_date IS NOT NULL;
Backward Compatibility
✅ Existing Subscriptions
- Continue working normally
custom_interval_daysis NULL (ignored)auto_create_expensedefaults to Falsestart_datebackfilled fromnext_due_date
✅ Existing Routes
- All original routes still work
- New fields optional
- Forms handle NULL values gracefully
✅ API Responses
- New fields returned but not required
- Clients can ignore new fields
- No breaking changes
Testing Scenarios
✅ Tested
- Create standard monthly subscription → Works
- Create custom 45-day interval → Works
- Enable auto-create → Works
- Set end date → Deactivates correctly
- Set total payments (12) → Counts properly
- Edit existing subscription → Preserves data
- Romanian translation → All keys present
- Spanish translation → All keys present
- Auto-create button → Creates expenses
- Dashboard widget → Shows custom intervals
Performance Impact
- Database: 7 new columns (minimal impact)
- Queries: No additional complexity
- UI: 1 additional button (negligible)
- JavaScript: 1 small function (< 1KB)
- Translation: 15 keys × 3 languages (< 2KB)
Overall: Negligible performance impact ✓
Security Considerations
- All routes require
@login_required✓ - CSRF tokens on all forms ✓
- User-scoped queries only ✓
- Input validation on custom interval ✓
- SQL injection prevented (SQLAlchemy ORM) ✓
Summary of Improvements
| Feature | Before | After | Improvement |
|---|---|---|---|
| Frequency Options | 5 | 6 (+ custom) | +20% flexibility |
| Scheduling Control | Basic | Advanced | End dates, limits |
| Automation | Manual only | Auto-create | Time savings |
| Occurrence Tracking | None | Full counter | Better insights |
| Custom Intervals | No | Yes | Unlimited flexibility |
Total Lines of Code Changed: ~500 lines New Features Added: 7 major features Languages Supported: 3 (EN, RO, ES) Database Columns Added: 7 New Routes: 1 (auto-create) Documentation Pages: 2 comprehensive guides