Manage bookings in the W&K-Sync backend group instead of at the event

Bookings get their own backend module (W&K-Sync → Anmeldungen) with a
sortable, filterable list; the operation on calendar events is removed and
the calendar module no longer exposes tl_wk_booking. Inbox edit links point
to the new module.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
admin.juergenandClaude Fable 5.1 committed 2026-09-24 17:55:46 +02:00
1 parent 142afa6e52
commit efce662b4f
10 files changed
+25 -63

No files matched your search

+2 -2
View File
@@ -67,7 +67,7 @@ vendor/bin/contao-console contao:migrate
5. **Benachrichtigungen** (Notification Center 2): Benachrichtigungen vom Typ **W&K-Anmeldung** anlegen und im Kalender zuordnen. Tokens: `##recipient_email##`, `##subscription_*##` (alle Felder der Anmeldung, Auswahlfelder zusätzlich als `##subscription_gender_label##` usw., Ja/Nein-Felder als `##subscription_vegetarian_label##`), `##event_*##` (alle Felder der Veranstaltung, Datumsfelder formatiert), `##event_datetime##`, `##event_link##`, `##event_categories##`, `##event_speakers##`, `##subscription_event_wk_id##`, `##subscription_confirmation_page_url##`, `##calendar_*##`, `##admin_email##`. Die bisherigen Token-Namen `event_organizerCity` und `event_internalEventNumber` bleiben erhalten.
6. **Benutzergruppen**: Zugriff auf die Module „W&K-Sync“ (Import & Posteingang, Kategorien, Kontaktanfragen, Protokoll) und auf den Kalender (Anmeldungen je Veranstaltung) freigeben.
6. **Benutzergruppen**: Zugriff auf die Module „W&K-Sync“ (Import & Posteingang, Anmeldungen, Kontaktanfragen, Kategorien, Protokoll) freigeben. Anmeldungen werden ausschließlich dort bearbeitet, nicht am Event im Kalender.
---
@@ -139,7 +139,7 @@ Die Bestätigungsseite wird mit `?booking=<Token>` aufgerufen. Formulare des For
## Posteingang und Export
**W&K-Sync → Import & Posteingang → Posteingang.** Neue Anmeldungen und Kontaktanfragen werden gesichtet und einzeln oder gesammelt verschoben. Doppelte Anmeldungen (gleiche E-Mail-Adresse, gleiche Veranstaltung) werden markiert. „Bearbeiten“ öffnet den Datensatz (Anmeldungen unter Kalender → Veranstaltung → Anmeldungen, Anfragen unter W&K-Sync → Kontaktanfragen).
**W&K-Sync → Import & Posteingang → Posteingang.** Neue Anmeldungen und Kontaktanfragen werden gesichtet und einzeln oder gesammelt verschoben. Doppelte Anmeldungen (gleiche E-Mail-Adresse, gleiche Veranstaltung) werden markiert. „Bearbeiten“ öffnet den Datensatz unter W&K-Sync → Anmeldungen bzw. W&K-Sync → Kontaktanfragen; dort lassen sich alle Angaben korrigieren (Liste mit Filter nach Veranstaltung und Ordner, Suche nach Name/E-Mail). Beim Löschen einer Veranstaltung werden ihre Anmeldungen mitgelöscht.
**Export**: In der Download-Liste erzeugt „Download-Liste für W&K exportieren“ die Datei `JJJJ-MM-TT_website_kontaktanfragen_wk.csv` mit den Spalten `KBNR;KNKDAN;KNKDTITEL;KNKDN2;KNKDN1;KNKDSTR;KNKDPLZ;KNKDORT;KNGEBDAT;KDEMAIL;KDTEL1;KDFREI01;KDFREI02;KDFREI03;KDFREI04;KNUKAT;KNVEG;schoolName;schoolCity`. Kontaktanfragen stehen ohne Kursnummer in der Datei. Die Datensätze werden als „Exportiert“ markiert, die freien Plätze der Veranstaltungen um die Zahl der Anmeldungen reduziert (bis zum nächsten W&K-Import), und die Datei bleibt unter „Exporte für W&K“ zum erneuten Download.
+3 -3
View File
@@ -12,6 +12,9 @@ ArrayUtil::arrayInsert($GLOBALS['BE_MOD'], 1, [
'callback' => WkSyncModule::class,
'stylesheet' => 'bundles/contaowksync/wk-sync-backend.css',
],
'wk_sync_bookings' => [
'tables' => ['tl_wk_booking'],
],
'wk_sync_categories' => [
'tables' => ['tl_wk_category'],
],
@@ -23,6 +26,3 @@ ArrayUtil::arrayInsert($GLOBALS['BE_MOD'], 1, [
],
],
]);
// Anmeldungen werden als Untertabelle der Veranstaltungen im Kalender-Modul verwaltet
$GLOBALS['BE_MOD']['content']['calendar']['tables'][] = 'tl_wk_booking';
+1 -5
View File
@@ -7,13 +7,9 @@ use Mummert\ContaoWkSyncBundle\Import\WkState;
$dca = &$GLOBALS['TL_DCA']['tl_calendar_events'];
// Anmeldungen werden mit der Veranstaltung gelöscht, aber nicht am Event bearbeitet (dafür: W&K-Sync → Anmeldungen)
$dca['config']['ctable'][] = 'tl_wk_booking';
$dca['list']['operations']['wk_bookings'] = [
'href' => 'table=tl_wk_booking',
'icon' => 'mgroup.svg',
];
$manipulator = PaletteManipulator::create()
->addLegend('wk_legend', 'title_legend', PaletteManipulator::POSITION_AFTER)
->addLegend('wk_content_legend', 'wk_legend', PaletteManipulator::POSITION_AFTER)
+14 -5
View File
@@ -26,11 +26,14 @@ $GLOBALS['TL_DCA']['tl_wk_booking'] = [
],
'list' => [
'sorting' => [
'mode' => DataContainer::MODE_PARENT,
'mode' => DataContainer::MODE_SORTABLE,
'fields' => ['dateCreated DESC'],
'headerFields' => ['title', 'wkId', 'startDate', 'endDate', 'wkPlacesLeft'],
'panelLayout' => 'filter;search,limit',
'disableGrouping' => true,
'panelLayout' => 'filter;sort,search,limit',
'defaultSearchField' => 'lastname',
],
'label' => [
'fields' => ['dateCreated', 'lastname', 'firstname', 'email', 'pid', 'state'],
'showColumns' => true,
],
'global_operations' => [
'all',
@@ -43,7 +46,7 @@ $GLOBALS['TL_DCA']['tl_wk_booking'] = [
],
'palettes' => [
'__selector__' => ['addDifferentInvoiceAddress', 'addNotes', 'teacherPosition'],
'default' => '{state_legend},state,dateCreated,notification;'
'default' => '{state_legend},pid,state,dateCreated,notification;'
.'{person_legend},gender,academicTitle,firstname,lastname,street,postal,city,email,phone,position,birthday;'
.'{school_legend},teacherPosition;'
.'{stay_legend},vegetarian,overnightStay;'
@@ -62,7 +65,11 @@ $GLOBALS['TL_DCA']['tl_wk_booking'] = [
'sql' => ['type' => 'integer', 'unsigned' => true, 'autoincrement' => true],
],
'pid' => [
'filter' => true,
'sorting' => true,
'inputType' => 'select',
'foreignKey' => 'tl_calendar_events.title',
'eval' => ['mandatory' => true, 'includeBlankOption' => true, 'chosen' => true, 'tl_class' => 'w50'],
'sql' => ['type' => 'integer', 'unsigned' => true, 'default' => 0],
'relation' => ['type' => 'belongsTo', 'load' => 'lazy'],
],
@@ -119,6 +126,7 @@ $GLOBALS['TL_DCA']['tl_wk_booking'] = [
],
'lastname' => [
'search' => true,
'sorting' => true,
'inputType' => 'text',
'eval' => ['mandatory' => true, 'maxlength' => 128, 'tl_class' => 'w50'],
'sql' => ['type' => 'string', 'length' => 128, 'default' => ''],
@@ -143,6 +151,7 @@ $GLOBALS['TL_DCA']['tl_wk_booking'] = [
],
'email' => [
'search' => true,
'sorting' => true,
'inputType' => 'text',
'eval' => ['mandatory' => true, 'rgxp' => 'email', 'maxlength' => 255, 'decodeEntities' => true, 'tl_class' => 'w50'],
'sql' => ['type' => 'string', 'length' => 255, 'default' => ''],
+1
View File
@@ -11,3 +11,4 @@ $GLOBALS['TL_LANG']['MOD']['wk_sync_log'] = ['Protokoll', 'Protokoll der Importe
$GLOBALS['TL_LANG']['FMD']['wk_sync'] = 'W&K-Sync';
$GLOBALS['TL_LANG']['FMD']['wk_booking_form'] = ['W&K-Anmeldeformular', 'Anmeldeformular zur Veranstaltung aus der URL (Alias der Veranstaltung).'];
$GLOBALS['TL_LANG']['FMD']['wk_booking_status'] = ['W&K-Anmeldestatus', 'Freie Plätze, Anmeldeschluss und Link zur Anmeldung für die Veranstaltung aus der URL.'];
$GLOBALS['TL_LANG']['MOD']['wk_sync_bookings'] = ['Anmeldungen', 'Anmeldungen zu Veranstaltungen ansehen und bearbeiten'];
+1
View File
@@ -12,6 +12,7 @@ $lang['invoice_legend'] = 'Rechnungsanschrift';
$lang['notes_legend'] = 'Nachricht';
$lang['consent_legend'] = 'Einwilligungen';
$lang['pid'] = ['Veranstaltung', 'Veranstaltung, zu der die Anmeldung gehört.'];
$lang['state'] = ['Ordner', 'Bearbeitungsstand im Posteingang. „Exportiert“ wird nur durch den Export gesetzt.'];
$lang['dateCreated'] = ['Eingegangen am', ''];
$lang['notification'] = ['Verschickte Benachrichtigung', 'ID der Benachrichtigung, die bei der Anmeldung verschickt wurde (0 = keine).'];
+1
View File
@@ -11,3 +11,4 @@ $GLOBALS['TL_LANG']['MOD']['wk_sync_log'] = ['Log', 'Log of imports and exports'
$GLOBALS['TL_LANG']['FMD']['wk_sync'] = 'W&K sync';
$GLOBALS['TL_LANG']['FMD']['wk_booking_form'] = ['W&K booking form', 'Booking form for the event given in the URL.'];
$GLOBALS['TL_LANG']['FMD']['wk_booking_status'] = ['W&K booking status', 'Free places, deadline and booking link for the event given in the URL.'];
$GLOBALS['TL_LANG']['MOD']['wk_sync_bookings'] = ['Bookings', 'View and edit bookings'];
+1
View File
@@ -12,6 +12,7 @@ $lang['invoice_legend'] = 'Rechnungsanschrift';
$lang['notes_legend'] = 'Nachricht';
$lang['consent_legend'] = 'Einwilligungen';
$lang['pid'] = ['Veranstaltung', 'Veranstaltung, zu der die Anmeldung gehört.'];
$lang['state'] = ['Ordner', 'Bearbeitungsstand im Posteingang. „Exportiert“ wird nur durch den Export gesetzt.'];
$lang['dateCreated'] = ['Eingegangen am', ''];
$lang['notification'] = ['Verschickte Benachrichtigung', 'ID der Benachrichtigung, die bei der Anmeldung verschickt wurde (0 = keine).'];
+1 -1
View File
@@ -410,7 +410,7 @@ class WkSyncBackend
private function editUrl(InboxItem $item, string $referer): string
{
$params = $item->isBooking()
? ['do' => 'calendar', 'table' => 'tl_wk_booking', 'act' => 'edit', 'id' => $item->id]
? ['do' => 'wk_sync_bookings', 'table' => 'tl_wk_booking', 'act' => 'edit', 'id' => $item->id]
: ['do' => 'wk_sync_inquiries', 'table' => 'tl_wk_inquiry', 'act' => 'edit', 'id' => $item->id];
if ('' !== $referer) {
@@ -1,47 +0,0 @@
<?php
declare(strict_types=1);
namespace Mummert\ContaoWkSyncBundle\EventListener\DataContainer;
use Contao\CoreBundle\DependencyInjection\Attribute\AsCallback;
use Contao\CoreBundle\Framework\ContaoFramework;
use Contao\Config;
use Contao\Date;
use Contao\StringUtil;
use Mummert\ContaoWkSyncBundle\Inbox\InboxState;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* Zeile in der Anmeldeliste unterhalb einer Veranstaltung.
*/
#[AsCallback(table: 'tl_wk_booking', target: 'list.sorting.child_record')]
class BookingLabelListener
{
public function __construct(
private readonly ContaoFramework $framework,
private readonly TranslatorInterface $translator,
) {
}
/**
* @param array<string, mixed> $row
*/
public function __invoke(array $row): string
{
$config = $this->framework->getAdapter(Config::class);
$date = $this->framework->getAdapter(Date::class)->parse((string) $config->get('datimFormat'), (int) $row['dateCreated']);
$state = InboxState::tryFrom((string) $row['state']) ?? InboxState::New;
$stateLabel = $this->translator->trans('MSC.wk_sync.state.'.$state->translationKey(), [], 'contao_default');
$name = trim(($row['academicTitle'] ? $row['academicTitle'].' ' : '').$row['firstname'].' '.$row['lastname']);
return \sprintf(
'<div class="tl_content_left">%s <span class="wk-sync-muted" style="color:#999;padding-left:3px">[%s]</span> <span style="color:#999;padding-left:3px">[%s]</span> <span style="color:#999;padding-left:3px">[%s]</span></div>',
StringUtil::specialchars($name),
StringUtil::specialchars((string) $row['email']),
StringUtil::specialchars($date),
StringUtil::specialchars($stateLabel),
);
}
}