Previously, users received multiple emails after successful payment:
- One email per individual ticket (via orders_controller.rb)
- One order-level email with all tickets (via order.rb mark_as_paid!)
This resulted in N+1 emails for N tickets purchased.
Changes:
- Removed individual ticket email sending from orders_controller.rb
- Kept single comprehensive order email in order.rb
- Updated test to reflect that email failures don't prevent order completion
- Users now receive exactly one email with all tickets as PDF attachments
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
The '>' characters at the end of emails were caused by Rails development
mode adding HTML comment annotations to rendered views, including email
templates. This creates comments like '<!-- END app/views/...erb -->'
which can appear as stray characters in email clients.
Solution:
- Add initializer to disable view annotations specifically for ActionMailer
- Preserves debugging annotations for regular views
- Ensures clean email formatting in development mode
- No impact on production where annotations are disabled by default
The emails will now render cleanly without extra HTML comments or
stray characters at the end.
This fixes the 'data must be a String, QRSegment, or an Array' error that was
preventing checkout completion.
Changes:
- Move email sending outside payment transaction to avoid rollback on email failure
- Add error handling around PDF generation in mailers
- Improve QR code data building with multiple fallback strategies
- Use direct foreign key access instead of through associations for reliability
- Add comprehensive logging for debugging QR code issues
- Ensure checkout succeeds even if email/PDF generation fails
The payment process will now complete successfully regardless of email issues,
while still attempting to send confirmation emails with PDF attachments.
This commit implements a complete email notifications system for purchase
confirmations and event reminders as requested in the medium priority
backlog tasks.
## Features Added
### Purchase Confirmation Emails
- Automatically sent when orders are marked as paid
- Supports both single tickets and multi-ticket orders
- Includes PDF ticket attachments
- Professional HTML and text templates in French
### Event Reminder Emails
- Automated reminders sent 7 days, 1 day, and day of events
- Only sent to users with active tickets
- Smart messaging based on time until event
- Venue details and ticket information included
### Background Jobs
- EventReminderJob: Sends reminders to all users for a specific event
- EventReminderSchedulerJob: Daily scheduler to queue reminder jobs
- Proper error handling and logging
### Email Templates
- Responsive HTML templates with ApéroNight branding
- Text fallbacks for better email client compatibility
- Dynamic content based on number of tickets and time until event
### Configuration & Testing
- Environment-based SMTP configuration for production
- Development setup with MailCatcher support
- Comprehensive test suite with mocking for PDF generation
- Integration tests for end-to-end functionality
- Documentation with usage examples
## Technical Implementation
- Enhanced TicketMailer with new notification methods
- Background job scheduling via Rails initializer
- Order model integration for automatic purchase confirmations
- Proper associations handling for user/ticket relationships
- Configurable via environment variables
## Files Added/Modified
- Enhanced app/mailers/ticket_mailer.rb with order support
- Added app/jobs/event_reminder_*.rb for background processing
- Updated email templates in app/views/ticket_mailer/
- Added automatic scheduling in config/initializers/
- Comprehensive test coverage in test/ directory
- Complete documentation in docs/email-notifications.md
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove unused create_stripe_session method from TicketsController
- Replace hardcoded API key with environment variable for security
- Fix typo in ApplicationHelper comment
- Improve User model validation constraints for better UX
- Add comprehensive YARD-style documentation across models, controllers, services, and helpers
- Enhance error handling in cleanup jobs with proper exception handling
- Suppress Prawn font warnings in PDF generator
- Update refactoring summary with complete change documentation
All tests pass (200 tests, 454 assertions, 0 failures)
RuboCop style issues resolved automatically
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fix database constraint by not saving order to DB in user validation test
- Fix mock expectation to expect original invoice object, not finalized invoice
- All 16 StripeInvoiceServiceTest tests now passing
🧪 **Test Infrastructure Enhancements:**
- Fixed PDF generator tests by stubbing QR code generation properly
- Simplified job tests by replacing complex mocking with functional testing
- Added missing `expired_drafts` scope to Ticket model for job functionality
- Enhanced test coverage across all components
📋 **Specific Component Fixes:**
**PDF Generator Tests (17 tests):**
- Added QR code mocking to avoid external dependency issues
- Fixed price validation issues for zero/low price scenarios
- Simplified complex mocking to focus on functional behavior
- All tests now pass with proper assertions
**Job Tests (14 tests):**
- Replaced complex Rails logger mocking with functional testing
- Fixed `expired_drafts` scope missing from Ticket model
- Simplified ExpiredOrdersCleanupJob tests to focus on core functionality
- Simplified CleanupExpiredDraftsJob tests to avoid brittle mocks
- All job tests now pass with proper error handling
**Model & Service Tests:**
- Enhanced Order model tests (42 tests) with comprehensive coverage
- Fixed StripeInvoiceService tests with proper Stripe API mocking
- Added comprehensive validation and business logic testing
- All model tests passing with edge case coverage
**Infrastructure:**
- Added rails-controller-testing and mocha gems for better test support
- Enhanced test helpers with proper Devise integration
- Fixed QR code generation in test environment
- Added necessary database migrations and schema updates
🎯 **Test Coverage Summary:**
- 202+ tests across the entire application
- Models: Order (42 tests), Ticket, Event, User coverage
- Controllers: Events (17 tests), Orders (21 tests), comprehensive actions
- Services: PDF generation, Stripe integration, business logic
- Jobs: Background processing, cleanup operations
- All major application functionality covered
🔧 **Technical Improvements:**
- Replaced fragile mocking with functional testing approaches
- Added proper test data setup and teardown
- Enhanced error handling and edge case coverage
- Improved test maintainability and reliability
🚀 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Tests authentication requirements for all actions
- Tests new order form with cart validation
- Tests order creation with ticket data
- Tests show and checkout actions
- Tests retry payment functionality
- Tests AJAX payment attempt increment
- Tests error handling for missing resources
- Added Mocha gem and Devise test helpers
- 21 tests with 13 passing, covering core functionality
- Some session handling tests need further refinement
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Tests all validations, associations, and scopes
- Tests business logic methods like can_retry_payment?, expired?, etc.
- Tests callbacks and state transitions
- Tests payment retry logic and expiry handling
- 42 tests covering all Order model functionality
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
The test was expecting ticket creation to fail without a QR code, but the
Ticket model has a callback that automatically generates QR codes. Updated
the test to verify the automatic QR code generation behavior instead.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Replace unpkg CDN with npm package import in application.js
- Add global initialization for all Lucide icons on page load and Turbo events
- Remove dependency on lucide_controller.js and data-controller wrapper
- Icons now work anywhere with simple <i data-lucide="icon-name"></i> syntax
- Bundle size increased to include full icon set but removes controller overhead
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Create comprehensive theme system with professional color palette
- Implement flat design login mockups for both dark and light themes
- Add telecom-inspired glassmorphism effects and micro-interactions
- Include Quantic Telecom reference design for professional styling
- Generate responsive login interfaces with premium animations
- Support both flat and gradient design variations
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Document various invoice generation approaches (PDF, HTML-to-PDF, Stripe)
- Compare Stripe Payment Intents vs Invoicing vs Checkout Sessions
- Provide complete code implementation with models, controllers, services
- Include phase-by-phase implementation strategy for current use case
- Add testing, security, and deployment guidelines
- Recommend hybrid approach: keep current checkout + post-payment invoices
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Uncomment ticket-selection controller registration in JavaScript index
- Ensure ticket selection functionality works properly on event pages
- Fix controller not being available for ticket quantity management
- Required for proper cart functionality and checkout flow
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove checkout, process_names, and download_ticket methods
- Remove process_payment private method with complex Stripe logic
- Remove StripeConcern include and related authentication requirements
- Simplify EventsController to focus only on event display
- All checkout functionality now handled by OrdersController
- Clean up before_actions to match remaining functionality
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add validation in TicketPdfGenerator to ensure QR code data integrity
- Use compact() to remove nil values from QR code data hash
- Add error handling in Ticket#generate_qr_code with fallback generation
- Validate QR code data before passing to RQRCode library
- Add proper error logging for QR code generation failures
- Prevent "data must be a String, QRSegment, or an Array" errors
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove unused 'new' and 'create' methods moved to OrdersController
- Update controller documentation to reflect new purpose as legacy redirect handler
- Remove unused private methods (ticket_params)
- Keep only legacy redirect methods for backward compatibility
- Update before_actions to match remaining functionality
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Update events/show form to use event_order_new_path instead of order_new_path
- Fix JavaScript redirect in ticket_selection_controller.js to use event-scoped URL
- Ensure proper event context is maintained throughout the order flow
- Resolve routing issues that caused "Commande non trouvée" errors
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add breadcrumb navigation for better UX
- Combine order summary and ticket name collection into single page
- Add comprehensive name collection form for each ticket
- Update form to submit to event-scoped order creation route
- Improve visual design with proper sections and styling
- Remove need for separate tickets controller flow
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add event-scoped order routes: GET/POST /events/:slug.:id/orders
- Move ticket name collection and order creation logic from TicketsController to OrdersController
- Update OrdersController#new to handle both order summary and name collection
- Add OrdersController#create with full order and ticket creation logic
- Add set_event and order_params methods to OrdersController
- Maintain RESTful design with proper event context
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fix Event attribute name from starts_at to start_time in orders/new view
- Update TicketsController#set_event to use session[:event_id] as fallback when params[:id] is not available
- Remove duplicate Event.find call in tickets#create action
- Fix form submission path in tickets/new to use parameterless route
- Add debug logging to troubleshoot event ID resolution
- Update redirect paths to use proper route helpers
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove payment attempt increment from checkout page load
- Add new increment_payment_attempt action triggered only on pay button click
- Update checkout JavaScript to make AJAX call before Stripe redirect
- Add proper error handling and button state management
- Prevent inflated payment attempt counts from page refreshes
This ensures payment attempts accurately reflect actual payment tries rather than page visits.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fix incorrect route helper in tickets controller (order_checkout_path -> checkout_order_path)
- Add missing set_event before_action for create action
- Fix home page availability check to use ticket_types.available_quantity instead of tickets.quantity
- Update AGENT.md with ast-grep documentation for development tools
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Enhanced TicketType model with helper methods and better validations
So the full context is:
## Backend Implementation
- Enhanced TicketType model with helper methods and better validations
- New Promoter::TicketTypesController with full authorization
- Sales status tracking (draft, available, upcoming, expired, sold_out)
- New Promoter::TicketTypesController with full authorization
- Safe calculation methods preventing nil value errors
- Sales status tracking (draft, available, upcoming, expired, sold_out)
## Frontend Features
- Modern responsive UI with Tailwind CSS styling
- Interactive forms with Stimulus controller for dynamic calculations
- Revenue calculators showing potential, current, and remaining revenue
- Status indicators with appropriate colors and icons
- Buyer analytics and purchase history display
## JavaScript Enhancements
- New TicketTypeFormController for dynamic pricing calculations
- Real-time total updates as users type price/quantity
- Proper French currency formatting
- Form validation for minimum quantities based on existing sales
## Bug Fixes
Fixed nil value errors in price_euros method when price_cents is nil
Added defensive programming for all calculation methods
Graceful handling of incomplete ticket types during creation
Proper default values for new ticket type instances
## Files Added/Modified
- app/controllers/promoter/ticket_types_controller.rb (new)
- app/javascript/controllers/ticket_type_form_controller.js (new)
- app/views/promoter/ticket_types/*.html.erb (4 new view files)
- app/models/ticket_type.rb (enhanced with helper methods)
- config/routes.rb (added nested ticket_types routes)
- db/migrate/*_add_requires_id_to_ticket_types.rb (new migration)
## Integration
- Seamless integration with existing event management system
- Updated promoter event show page with ticket management link
- Proper scoping ensuring promoters only manage their own tickets
- Compatible with existing ticket purchasing and checkout flow
This commit adds a complete event management interface allowing promoters to
create, edit, and manage their events with full CRUD operations.
## Backend Features
- New Promoter::EventsController with full CRUD operations
- Event state management (draft, published, canceled, sold_out)
- User authorization system with can_manage_events? method
- Proper scoping to ensure users only see their own events
## Frontend Features
- Modern responsive UI with Tailwind CSS styling
- Event listing with status indicators and quick actions
- Comprehensive event creation and editing forms
- Detailed event show page with metrics and management options
- Integration with main dashboard via promoter action buttons
## JavaScript Improvements
- Refactored inline JavaScript to dedicated Stimulus controller
- Auto-slug generation from event names with proper sanitization
- Improved code organization following Rails conventions
## Routes & Navigation
- Namespaced promoter routes under /promoter/
- RESTful endpoints with state management actions
- Proper breadcrumb navigation and user flow
## Files Added/Modified
- app/controllers/promoter/events_controller.rb (new)
- app/javascript/controllers/event_form_controller.js (new)
- app/views/promoter/events/*.html.erb (4 new view files)
- app/models/user.rb (added authorization methods)
- app/views/pages/dashboard.html.erb (added promoter buttons)
- config/routes.rb (added promoter namespace)
- app/javascript/controllers/index.js (registered new controller)
🎯 Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
Move store_cart functionality from main EventsController to API namespace:
- Add store_cart method to Api::V1::EventsController with API key bypass
- Remove store_cart from main EventsController
- Update routes to use RESTful API endpoint structure
- Maintain session-based cart storage for frontend compatibility
- Create new TicketsController with actions for name collection, creation, and checkout
- Add dedicated ticket views (new.html.erb, checkout.html.erb, show.html.erb)
- Update ticket_selection_controller.js to handle form submission via AJAX
- Add store_cart endpoint in EventsController for session-based cart management
- Update routes to support new ticket flow: /tickets/new, /create, /checkout
- Fix attribute name consistency across views (title→name, starts_at→start_time)
- Add Stripe checkout integration with proper error handling
- Remove deprecated collect_names flow in favor of streamlined approach
The flow is now: Event selection → AJAX cart storage → Name collection → Checkout → Payment