# Custom Recurring Expenses - What Changed ## Database Model Changes ### Before ```python 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 ✨ ```python 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 ```html Name: [_____] Amount: [_____] Frequency: [Monthly ▼] ← Only 5 options Category: [Bills ▼] Next Payment: [2025-01-15] Notes: [_________] [Cancel] [Save] ``` ### Create Subscription - After ✨ ```html 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 ```python GET /subscriptions # List GET /subscriptions/create # Form POST /subscriptions/create # Save GET /subscriptions//edit # Edit form POST /subscriptions//edit # Update POST /subscriptions//delete POST /subscriptions/detect # AI detection POST /subscriptions//accept POST /subscriptions//dismiss GET /subscriptions/api/upcoming ``` ### After ✨ ```python GET /subscriptions # List GET /subscriptions/create # Form (now with custom fields) POST /subscriptions/create # Save (handles custom data) GET /subscriptions//edit # Edit form (now with custom fields) POST /subscriptions//edit # Update (handles custom data) POST /subscriptions//delete POST /subscriptions/detect # AI detection POST /subscriptions//accept POST /subscriptions//dismiss GET /subscriptions/api/upcoming POST /subscriptions/auto-create # 🆕 Auto-create expenses ``` ## Translation Keys Added ### English ```python '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 ```python 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 ✨ ```python 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 ✨ ```python 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 ```javascript 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 1. `migrate_custom_recurring.py` - Migration script (Python) 2. `CUSTOM_RECURRING_GUIDE.md` - Complete user guide (30+ sections) 3. `CUSTOM_RECURRING_SUMMARY.md` - Quick feature summary ## Files Modified 1. `app/models/subscription.py` - Added 7 fields + 2 methods 2. `app/routes/subscriptions.py` - Updated create/edit + added auto-create endpoint 3. `app/templates/subscriptions/create.html` - Added custom frequency UI 4. `app/templates/subscriptions/edit.html` - Added custom frequency UI 5. `app/templates/subscriptions/index.html` - Added AUTO badge + auto-create button 6. `app/translations.py` - Added 15+ keys in 3 languages ## Migration Steps ### Database ```sql -- 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_days` is NULL (ignored) - `auto_create_expense` defaults to False - `start_date` backfilled from `next_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 1. Create standard monthly subscription → Works 2. Create custom 45-day interval → Works 3. Enable auto-create → Works 4. Set end date → Deactivates correctly 5. Set total payments (12) → Counts properly 6. Edit existing subscription → Preserves data 7. Romanian translation → All keys present 8. Spanish translation → All keys present 9. Auto-create button → Creates expenses 10. 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