From 0b21bb00cb0fc947ce0f131e3884d92484fb251a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Mon, 3 Aug 2026 16:23:47 +0200 Subject: [PATCH] feat: sort groups price services by price first, then alphabetically --- .../Admin/Accommodation/EditController.php | 23 ++++++++++++++++ src/Service/AccommodationBookingService.php | 27 +++++++++++++++++++ templates/admin/accommodation/_form.html.twig | 4 +-- templates/groups/booking/step_2.html.twig | 6 ++--- 4 files changed, 55 insertions(+), 5 deletions(-) diff --git a/src/Controller/Admin/Accommodation/EditController.php b/src/Controller/Admin/Accommodation/EditController.php index d3ea043..dbd68dd 100644 --- a/src/Controller/Admin/Accommodation/EditController.php +++ b/src/Controller/Admin/Accommodation/EditController.php @@ -5,6 +5,8 @@ declare(strict_types=1); namespace App\Controller\Admin\Accommodation; use App\Entity\Groups\Accommodation; +use App\Entity\Groups\AdditionalService; +use App\Entity\Groups\BoardService; use App\Form\Admin\Groups\AccommodationType; use App\Service\CmsDataProvider; use Doctrine\ORM\EntityManagerInterface; @@ -52,10 +54,31 @@ class EditController extends AbstractController return $this->redirectToRoute('app_admin_accommodation_edit', ['id' => $accommodation->getId()]); } + $boardServices = $accommodation->getBoardServices()->toArray(); + usort($boardServices, $this->compareServices(...)); + + $additionalServices = $accommodation->getAdditionalServices()->toArray(); + usort($additionalServices, $this->compareServices(...)); + return $this->render('admin/accommodation/edit.html.twig', [ 'accommodation' => $accommodation, 'form' => $form, 'cmsData' => $cmsData, + 'boardServices' => $boardServices, + 'additionalServices' => $additionalServices, ]); } + + /** + * DateFrom ascending, then free (price 0) before paid, then alphabetically by label. + */ + private function compareServices(BoardService|AdditionalService $a, BoardService|AdditionalService $b): int + { + $aFree = 0 === $a->getPrice() ? 0 : 1; + $bFree = 0 === $b->getPrice() ? 0 : 1; + + return $a->getDateFrom() <=> $b->getDateFrom() + ?: $aFree <=> $bFree + ?: strnatcasecmp($a->getLabel(), $b->getLabel()); + } } diff --git a/src/Service/AccommodationBookingService.php b/src/Service/AccommodationBookingService.php index 8c0d481..cda3557 100644 --- a/src/Service/AccommodationBookingService.php +++ b/src/Service/AccommodationBookingService.php @@ -156,6 +156,12 @@ class AccommodationBookingService } } + $boardServices = $this->sortServicesByPriceThenLabel($boardServices); + $ungrouped = $this->sortServicesByPriceThenLabel($ungrouped); + foreach ($grouped as $groupName => $groupServices) { + $grouped[$groupName] = $this->sortServicesByPriceThenLabel($groupServices); + } + return [ 'boardServices' => $boardServices, 'additionalServices' => $additionalServices, @@ -164,6 +170,27 @@ class AccommodationBookingService ]; } + /** + * Free services (price 0) first, then alphabetically; each group sorted alphabetically. + * + * @template T of BoardService|AdditionalService + * + * @param T[] $services + * + * @return T[] + */ + private function sortServicesByPriceThenLabel(array $services): array + { + usort($services, static function (BoardService|AdditionalService $a, BoardService|AdditionalService $b): int { + $aFree = 0 === $a->getPrice() ? 0 : 1; + $bFree = 0 === $b->getPrice() ? 0 : 1; + + return $aFree <=> $bFree ?: strnatcasecmp($a->getLabel(), $b->getLabel()); + }); + + return $services; + } + /** * Determines whether the booking must be treated as non-binding and why. * diff --git a/templates/admin/accommodation/_form.html.twig b/templates/admin/accommodation/_form.html.twig index c86978b..14a30a5 100644 --- a/templates/admin/accommodation/_form.html.twig +++ b/templates/admin/accommodation/_form.html.twig @@ -188,7 +188,7 @@ - {% for service in accommodation.boardServices %} + {% for service in boardServices %} {{ service.dateFrom | date('d.m.Y') }} - {{ service.dateTo | date('d.m.Y') }} @@ -258,7 +258,7 @@ - {% for service in accommodation.additionalServices %} + {% for service in additionalServices %} {{ service.dateFrom | date('d.m.Y') }} - {{ service.dateTo | date('d.m.Y') }} diff --git a/templates/groups/booking/step_2.html.twig b/templates/groups/booking/step_2.html.twig index 4970d39..e00355c 100644 --- a/templates/groups/booking/step_2.html.twig +++ b/templates/groups/booking/step_2.html.twig @@ -109,7 +109,7 @@ {% endif %} -
{{ (service.price / 100)|format_currency(ctx.accommodation.currency) }}
+
{% if service.price == 0 %}inkl.{% else %}{{ (service.price / 100)|format_currency(ctx.accommodation.currency) }}{% endif %}
pro Person und Nacht
@@ -155,7 +155,7 @@ {% endif %} -
{{ (service.price / 100)|format_currency(ctx.accommodation.currency) }}
+
{% if service.price == 0 %}inkl.{% else %}{{ (service.price / 100)|format_currency(ctx.accommodation.currency) }}{% endif %}
{{ service.type.label | trans }}
@@ -193,7 +193,7 @@ {% endif %} -
{{ (service.price / 100)|format_currency(ctx.accommodation.currency) }}
+
{% if service.price == 0 %}inkl.{% else %}{{ (service.price / 100)|format_currency(ctx.accommodation.currency) }}{% endif %}
{{ service.type.label | trans }}