diff --git a/src/Controller/Admin/TravelMailing/IndexController.php b/src/Controller/Admin/TravelMailing/IndexController.php index bbc67a2e..34894c80 100644 --- a/src/Controller/Admin/TravelMailing/IndexController.php +++ b/src/Controller/Admin/TravelMailing/IndexController.php @@ -6,8 +6,10 @@ namespace App\Controller\Admin\TravelMailing; use App\BpnConnect\Exception\BpnConnectException; use App\BpnConnect\TravelsClient; +use App\BusProNet\Utility\DateCodeUtility; use App\Form\Admin\TravelMailingLookupType; use App\Form\Model\TravelMailingLookupDto; +use App\Service\TravelDataProvider; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -19,6 +21,7 @@ class IndexController extends AbstractController { public function __construct( private readonly TravelsClient $travelsClient, + private readonly TravelDataProvider $travelDataProvider, ) { } @@ -32,10 +35,16 @@ class IndexController extends AbstractController $form->handleRequest($request); $result = null; + $travelLabel = null; $failed = false; if ($form->isSubmitted() && $form->isValid()) { + // The local index matches codes exactly, so "lpjmp-281126" has to become "LPJMP281126" + // before the label lookup; bpn-connect gets the same code to keep both in step. + $travelCode = (new DateCodeUtility())->sanitize((string) $lookup->travelCode); + try { - $result = $this->travelsClient->getMailingRecipients((string) $lookup->travelCode); + $result = $this->travelsClient->getMailingRecipients($travelCode); + $travelLabel = $this->travelDataProvider->mapDateCodeToLabel($travelCode); } catch (BpnConnectException) { // The client has already logged the cause; the page only needs to say it failed. $failed = true; @@ -45,6 +54,7 @@ class IndexController extends AbstractController return $this->render('admin/travel_mailing/index.html.twig', [ 'form' => $form, 'result' => $result, + 'travel_label' => $travelLabel, 'failed' => $failed, ]); } diff --git a/src/Service/TravelDataProvider.php b/src/Service/TravelDataProvider.php index 8f20a3c1..4e80237c 100644 --- a/src/Service/TravelDataProvider.php +++ b/src/Service/TravelDataProvider.php @@ -420,6 +420,18 @@ class TravelDataProvider return $this->travelLookupService->mapDateCodeToId($dateCode); } + /** + * Map date code to the travel's label. + * + * @param string $dateCode The date code to map + * + * @return string|null The travel label or null if not found + */ + public function mapDateCodeToLabel(string $dateCode): ?string + { + return $this->travelLookupService->mapDateCodeToLabel($dateCode); + } + /** * Map hotel code to hotel ID. * diff --git a/src/Service/TravelIndex.php b/src/Service/TravelIndex.php index eeaf1ac0..2cf4f018 100644 --- a/src/Service/TravelIndex.php +++ b/src/Service/TravelIndex.php @@ -109,6 +109,24 @@ class TravelIndex } } + /** + * Resolve a date code to its travel label, e.g. "Davos - Sportclub Waldschlössli - Wochenende". + * + * @param string $dateCode The date code to resolve + * + * @return string|null The label, or null if the code is not found or the travel has none + */ + public function mapDateCodeToLabel(string $dateCode): ?string + { + $dateId = $this->mapDateCodeToId($dateCode); + + if (null === $dateId) { + return null; + } + + return $this->generateFilesMap()[$dateId]['label'] ?? null; + } + /** * Convert a hotel code string to its corresponding hotel ID. * diff --git a/templates/admin/travel_mailing/index.html.twig b/templates/admin/travel_mailing/index.html.twig index 702d8814..5dda24fd 100644 --- a/templates/admin/travel_mailing/index.html.twig +++ b/templates/admin/travel_mailing/index.html.twig @@ -29,9 +29,14 @@ messages: ['Keine Empfänger für %s gefunden: Reisecode unbekannt oder keine bestätigten Teilnehmer.'|format(result.travelCode|e)], } %} {% else %} -

- {{ result.data|length }} Empfänger für {{ result.travelCode }} -

+
+

+ {{ travel_label|default('Reise nicht im lokalen Reisebestand') }} +

+

+ {{ result.data|length }} Empfänger für {{ result.travelCode }} +

+
diff --git a/tests/Service/TravelIndexTest.php b/tests/Service/TravelIndexTest.php index 9181c4e5..7967f643 100644 --- a/tests/Service/TravelIndexTest.php +++ b/tests/Service/TravelIndexTest.php @@ -148,6 +148,44 @@ class TravelIndexTest extends TestCase $this->assertNull($result); } + // ------------------------------------------------------------------------- + // mapDateCodeToLabel + // ------------------------------------------------------------------------- + + public function testMapDateCodeToLabelReturnsTheTravelLabel(): void + { + $this->travelLoader->method('generateFilesMap')->willReturn([ + 42 => ['id' => 42, 'code' => 'WI25', 'label' => 'Davos - Sportclub Waldschlössli - Wochenende', 'hotels' => []], + ]); + $this->travelSnapshotService->method('generateMapping')->willReturn([]); + + $result = $this->service()->mapDateCodeToLabel('WI25'); + + $this->assertSame('Davos - Sportclub Waldschlössli - Wochenende', $result); + } + + public function testMapDateCodeToLabelReturnsNullWhenNotFound(): void + { + $this->travelLoader->method('generateFilesMap')->willReturn([]); + $this->travelSnapshotService->method('generateMapping')->willReturn([]); + + $result = $this->service()->mapDateCodeToLabel('UNKNOWN'); + + $this->assertNull($result); + } + + public function testMapDateCodeToLabelReturnsNullWhenTheTravelHasNoLabel(): void + { + $this->travelLoader->method('generateFilesMap')->willReturn([ + 42 => ['id' => 42, 'code' => 'WI25', 'label' => null, 'hotels' => []], + ]); + $this->travelSnapshotService->method('generateMapping')->willReturn([]); + + $result = $this->service()->mapDateCodeToLabel('WI25'); + + $this->assertNull($result); + } + // ------------------------------------------------------------------------- // mapHotelCodeToId // -------------------------------------------------------------------------