# Pricing Display Implementation Plan ## Overview Implement comprehensive pricing display functionality that shows costs both inline in form options and in a detailed sidebar summary with real-time updates via HTMX. ## Goals 1. **Inline pricing** in form options (rooms, services) so users see costs while selecting 2. **Sidebar pricing summary** with itemized breakdown and grand total 3. **Real-time updates** via existing HTMX integration 4. **Professional UX** with clear pricing integrated into the booking flow ## Implementation Strategy ### 1. Core Pricing Service (`src/Service/BookingPriceCalculatorService.php`) **Purpose**: Central service for all pricing calculations **Key Methods**: - `calculateRoomPricing(BookingCreateDto $bookingDto): array` - `calculateServicePricing(BookingCreateDto $bookingDto): array` - `calculateGrandTotal(BookingCreateDto $bookingDto): float` - `getPricingBreakdown(BookingCreateDto $bookingDto): array` **Room Pricing Logic**: ```php // For each selected room: quantity × room.price foreach ($bookingDto->getSelectedRooms() as $roomSelection) { $room = $bookingDto->travel->rooms[$roomSelection->roomId]; $totalPrice = $roomSelection->quantity * $room->price; } ``` **Service Pricing Logic**: ```php // For each participant's selected services foreach ($bookingDto->getParticipants() as $participant) { // Handle different service types (single vs multiple selection) $serviceTotal += $participant->skiPass?->price ?? 0; $serviceTotal += array_sum(array_map(fn($s) => $s->price, $participant->courses)); // etc. } ``` ### 2. Enhanced Form Field Options with Pricing ✅ COMPLETED #### A. Room Selection Forms ✅ COMPLETED **File**: `src/Form/RoomSelectType.php` **Enhancement**: Choice labels include pricing information ```php 'choice_label' => function (Room $room) { $priceText = $room->price ? sprintf(' (€%.2f pro Nacht)', $room->price) : ''; return $room->label . $priceText; } ``` #### B. Service Selection Forms ✅ COMPLETED **File**: `src/Form/Service/ParticipantFieldOptionsProvider.php` **Enhancement**: Service labels include pricing via `formatServiceLabelWithPrice()` method - Zero-priced services display without price suffix (e.g., "Vollpension" instead of "Vollpension (€0,00)") - Priced services show with formatted price (e.g., "Halbpension (€45,00)") - Negative prices display as discounts (e.g., "Frühbucher-Bonus (-15,00€ Rabatt)") - All services consistently show quantity prefix (e.g., "1x", "2x") **Service Label Formatting Logic**: ```php private function formatServiceLabelWithPrice(Service $service): string { $label = $service->label; // Handle zero prices (no display) if (null === $service->price || 0.0 === $service->price) { return $label; } // Handle negative prices (discounts) if ($service->price < 0) { return sprintf('%s (-%s€ Rabatt)', $label, number_format(abs($service->price), 2, ',', '.')); } // Handle positive prices (costs) return sprintf('%s (€%s)', $label, number_format($service->price, 2, ',', '.')); } ``` **Affected Service Types**: - Courses: `"Skikurs Anfänger (€25,00)"` or `"Frühbucher-Bonus (-15,00€ Rabatt)"` - Additional Services: `"Versicherung (€15,00)"` or `"Stammgast-Vorteil (-5,00€ Rabatt)"` - Ski Pass: `"5-Tage Skipass (€120,00)"` or `"Gruppen-Rabatt (-20,00€ Rabatt)"` - Rentals: `"Ski-Set (€30,00)"` or `"Eigenes Equipment (-30,00€ Rabatt)"` - Board: `"Halbpension (€45,00)"`, `"Vollpension"` (if €0,00), or `"Selbstverpflegung (-25,00€ Rabatt)"` - Pickup Services: `"München Hbf (€15,00)"` or `"Nahverkehr (-5,00€ Rabatt)"` ### 3. Enhanced Unified Booking Summary ✅ COMPLETED #### A. Unified Summary Component ✅ COMPLETED **File**: `templates/booking/_summary.html.twig` The pricing summary has been integrated into the main booking summary, creating a single cohesive sticky sidebar that displays: **Travel Information Section**: - Travel details (destination, dates, duration) - Room selections with quantities - Participant count summary **Pricing Summary Section** (integrated): - Room pricing breakdown with quantities (e.g., "2x Doppelzimmer") - Service selections by participant with pricing - Grand total calculation **Key UX Improvements**: - Single sticky summary box (eliminated separate pricing sidebar) - Clean, unified layout with consistent typography - Service labels show quantity and pricing appropriately - Zero-priced services display without price suffix - Real-time updates via HTMX for all pricing changes #### B. Deprecated Separate Pricing Template ✅ COMPLETED **File**: `templates/booking/_pricing_summary.html.twig` - REMOVED The separate pricing summary template was removed in favor of the integrated approach within the main summary template for better UX. ### 4. Service Layer Integration ✅ COMPLETED #### A. Enhanced BookingService ✅ COMPLETED **File**: `src/Service/BookingService.php` **Implemented Pricing Methods**: ```php public function calculateServiceTotal(BookingCreateDto $bookingDto): float { // Groups services by type and calculates total pricing $serviceGroups = $this->getServiceGroups($bookingDto); return array_sum(array_column($serviceGroups, 'groupTotal')); } private function getServiceGroups(BookingCreateDto $bookingDto): array { // Groups selected services and calculates totals for pricing display // Fixed bug: Uses 'groupTotal' instead of incorrect 'totalPrice' key } ``` **Key Bug Fix**: The `calculateServiceTotal()` method was corrected to use `groupTotal` instead of `totalPrice` from the grouped array structure, ensuring selected services are properly included in the grand total calculation. ### 5. Controller Integration ✅ COMPLETED #### A. Step 1 Controller Updates ✅ COMPLETED **File**: `src/Controller/Booking/CreateStep1Controller.php` **Enhancement**: Integrated pricing calculations into existing summary methods ```php // In index() method - pricing data included in summary $summary = $this->bookingService->getRoomSummaryAndParticipantCount($bookingCreateDto); // Pricing calculated and passed to template // In roomSummary() method - HTMX endpoint includes pricing updates $summary = $this->bookingService->getRoomSummaryAndParticipantCount($bookingCreateDto); return $this->render('booking/_summary.html.twig', [ // existing data with integrated pricing ]); ``` #### B. Step 2 Controller Updates ✅ COMPLETED **File**: `src/Controller/Booking/CreateStep2Controller.php` **Enhancement**: Service pricing calculations integrated into form refresh ```php // In refresh() method - service selections update pricing in real-time $summary = $this->bookingService->getRoomSummaryAndParticipantCount($bookingCreateDto); // Service total calculation includes selected service pricing ``` #### C. HTMX Service Field Integration ✅ COMPLETED **Critical Fix**: Service field HTMX triggers were moved from container elements to individual form inputs (checkboxes/radios) to ensure real-time updates work properly for expanded choice fields. ### 6. Error Handling & Edge Cases ✅ COMPLETED **Price Data Handling** ✅ IMPLEMENTED: - Zero prices handled gracefully (services show without price suffix) - All prices rounded to 2 decimal places - German number formatting implemented (comma as decimal separator) - Null price handling via conditional display logic **Service Quantity Logic** ✅ IMPLEMENTED: - Single services (skiPass): price × 1 per participant - Multiple services (courses, rentals): sum of all selected service prices per participant - Service quantity consistently displayed (1x, 2x) in labels - Field handlers store complete Service objects (not just IDs) for pricing access **Field Handler Data Fix** ✅ COMPLETED: - All service field handlers updated to store Service objects instead of service IDs - Enables pricing calculator to access service price data - Resolves issue where selected services were ignored in total calculations ## Implementation Progress ### ✅ Completed - [x] Created implementation plan documentation - [x] Enhanced BookingService with pricing calculation methods (`calculateServiceTotal`, `getServiceGroups`) - [x] Updated ParticipantFieldOptionsProvider to add prices to service labels with smart formatting - [x] Updated RoomSelectType to add prices to room labels - [x] Integrated pricing into main summary template (unified approach) - [x] Updated controllers to include pricing data in summary calculations - [x] Fixed HTMX integration for service field real-time updates - [x] Fixed field handler data storage (Service objects vs IDs) - [x] Fixed pricing calculation bug (groupTotal vs totalPrice key) - [x] Implemented smart service label formatting (zero-price handling) - [x] Added consistent quantity display for all services - [x] Completed comprehensive testing of pricing display and HTMX integration ### ✅ Additional Improvements Completed - [x] Unified booking summary layout (eliminated separate pricing sidebar) - [x] Enhanced UX with sticky summary positioning - [x] Fixed service field HTMX triggers for expanded choice types - [x] Resolved linter warnings with proper type annotations - [x] Streamlined service label formatting logic ## Technical Considerations ### Performance - All pricing calculations done in-memory (no database queries) - Calculations triggered only on form changes via HTMX - Efficient array operations for service aggregation ### HTMX Integration ✅ COMPLETED - Uses existing `#booking-summary` target for seamless updates - **Fixed service field triggers**: HTMX attributes moved to individual form inputs for expanded choice fields - Real-time pricing updates work reliably for all service selections - Maintains current real-time update behavior with improved reliability ### Styling - CSS classes for pricing components: - `.pricing-summary` - Overall container - `.pricing-section` - Room/service sections - `.pricing-item` - Individual line items - `.pricing-total` - Grand total display ### Accessibility - Proper semantic HTML structure - ARIA labels for pricing information - Screen reader friendly number formatting ## Testing Strategy ### Unit Tests - Test pricing calculations with various room/service combinations - Test edge cases (null prices, zero quantities) - Test German number formatting ### Integration Tests - Test HTMX updates with pricing changes - Test form submission with pricing data - Test step navigation with pricing persistence ### Manual Testing Scenarios 1. Select rooms and verify inline pricing appears 2. Change room quantities and verify total updates 3. Add/remove services and verify pricing updates 4. Navigate between steps and verify pricing persistence 5. Test with services that have null/zero prices ## Future Enhancements ### Potential Additions - **Discounts/Promotions**: Add discount calculation logic - **Currency Selection**: Support multiple currencies - **Price History**: Track pricing changes during booking session - **Export Pricing**: Add pricing breakdown to booking confirmations - **Tax Calculations**: Add VAT/tax breakdown if needed ### Performance Optimizations - Cache frequently calculated pricing data - Optimize service aggregation algorithms - Consider lazy loading for complex pricing scenarios --- **Last Updated**: 2025-09-02 **Status**: ✅ Implementation completed successfully **Completed Features**: Inline pricing, unified summary, HTMX integration, service field fixes, and comprehensive UX improvements