Files
myep/docs/archive/PRICING_DISPLAY_IMPLEMENTATION.md
T
2025-10-01 17:57:39 +02:00

11 KiB
Raw Blame History

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:

// 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:

// 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

'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:

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:

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

// 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

// 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

  • Created implementation plan documentation
  • Enhanced BookingService with pricing calculation methods (calculateServiceTotal, getServiceGroups)
  • Updated ParticipantFieldOptionsProvider to add prices to service labels with smart formatting
  • Updated RoomSelectType to add prices to room labels
  • Integrated pricing into main summary template (unified approach)
  • Updated controllers to include pricing data in summary calculations
  • Fixed HTMX integration for service field real-time updates
  • Fixed field handler data storage (Service objects vs IDs)
  • Fixed pricing calculation bug (groupTotal vs totalPrice key)
  • Implemented smart service label formatting (zero-price handling)
  • Added consistent quantity display for all services
  • Completed comprehensive testing of pricing display and HTMX integration

Additional Improvements Completed

  • Unified booking summary layout (eliminated separate pricing sidebar)
  • Enhanced UX with sticky summary positioning
  • Fixed service field HTMX triggers for expanded choice types
  • Resolved linter warnings with proper type annotations
  • 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