wip: update docs
This commit is contained in:
@@ -0,0 +1,274 @@
|
||||
# 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)")
|
||||
- All services consistently show quantity prefix (e.g., "1x", "2x")
|
||||
|
||||
**Service Label Formatting Logic**:
|
||||
```php
|
||||
private function formatServiceLabelWithPrice(Service $service): string
|
||||
{
|
||||
$label = $service->label;
|
||||
|
||||
// Add price only if service has a cost
|
||||
if ($service->price > 0) {
|
||||
$label .= sprintf(' (€%.2f)', $service->price);
|
||||
}
|
||||
|
||||
return $label;
|
||||
}
|
||||
```
|
||||
|
||||
**Affected Service Types**:
|
||||
- Courses: `"Skikurs Anfänger (€25,00)"`
|
||||
- Additional Services: `"Versicherung (€15,00)"`
|
||||
- Ski Pass: `"5-Tage Skipass (€120,00)"`
|
||||
- Rentals: `"Ski-Set (€30,00)"`
|
||||
- Board: `"Halbpension (€45,00)"` or `"Vollpension"` (if €0,00)
|
||||
|
||||
### 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
|
||||
Reference in New Issue
Block a user