diff --git a/app/Http/Controllers/ServiceController.php b/app/Http/Controllers/ServiceController.php index b2755b8..1c444f7 100644 --- a/app/Http/Controllers/ServiceController.php +++ b/app/Http/Controllers/ServiceController.php @@ -308,6 +308,7 @@ public function edit(Service $service, \App\Services\ServiceImageResolver $image 'song_id' => $ss->song_id, 'song_arrangement_id' => $ss->song_arrangement_id, 'matched_at' => $ss->matched_at?->toJSON(), + 'confirmed_at' => $ss->confirmed_at?->toJSON(), 'request_sent_at' => $ss->request_sent_at?->toJSON(), 'has_content_slides' => $ss->song ? $this->defaultArrangementHasContentSlides($ss->song) : null, 'song' => $ss->song ? [ diff --git a/app/Http/Controllers/ServiceSongController.php b/app/Http/Controllers/ServiceSongController.php index db09f83..7a6dfe1 100644 --- a/app/Http/Controllers/ServiceSongController.php +++ b/app/Http/Controllers/ServiceSongController.php @@ -7,6 +7,7 @@ use App\Services\SongMatchingService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use Illuminate\Support\Carbon; class ServiceSongController extends Controller { @@ -92,6 +93,12 @@ public function update(int $serviceSongId, Request $request): JsonResponse } } + // Bei tatsaechlicher Aenderung des Arrangements muss neu bestaetigt werden. + if (array_key_exists('song_arrangement_id', $validated) + && $validated['song_arrangement_id'] !== $serviceSong->song_arrangement_id) { + $validated['confirmed_at'] = null; + } + $serviceSong->update($validated); return response()->json([ @@ -99,4 +106,38 @@ public function update(int $serviceSongId, Request $request): JsonResponse 'service_song' => $serviceSong->fresh(), ]); } + + /** + * Zuordnung eines Service-Songs explizit bestaetigen. + */ + public function confirm(int $serviceSongId): JsonResponse + { + $serviceSong = ServiceSong::findOrFail($serviceSongId); + + $serviceSong->update([ + 'confirmed_at' => Carbon::now(), + ]); + + return response()->json([ + 'success' => true, + 'message' => 'Zuordnung wurde bestaetigt.', + ]); + } + + /** + * Bestaetigung eines Service-Songs zuruecknehmen. + */ + public function unconfirm(int $serviceSongId): JsonResponse + { + $serviceSong = ServiceSong::findOrFail($serviceSongId); + + $serviceSong->update([ + 'confirmed_at' => null, + ]); + + return response()->json([ + 'success' => true, + 'message' => 'Bestaetigung wurde zurueckgenommen.', + ]); + } } diff --git a/app/Models/ServiceSong.php b/app/Models/ServiceSong.php index a60b441..76f80fc 100644 --- a/app/Models/ServiceSong.php +++ b/app/Models/ServiceSong.php @@ -20,6 +20,7 @@ class ServiceSong extends Model 'cts_ccli_id', 'cts_song_id', 'matched_at', + 'confirmed_at', 'request_sent_at', ]; @@ -28,6 +29,7 @@ protected function casts(): array return [ 'use_translation' => 'boolean', 'matched_at' => 'datetime', + 'confirmed_at' => 'datetime', 'request_sent_at' => 'datetime', ]; } diff --git a/app/Services/SongMatchingService.php b/app/Services/SongMatchingService.php index 62f2de6..d245b20 100644 --- a/app/Services/SongMatchingService.php +++ b/app/Services/SongMatchingService.php @@ -66,6 +66,11 @@ public function manualAssign(ServiceSong $serviceSong, Song $song): void 'use_translation' => $song->has_translation, ]; + // Bei Aenderung des Songs muss die Zuordnung neu bestaetigt werden. + if ($serviceSong->song_id !== $song->id) { + $updateData['confirmed_at'] = null; + } + // Only set arrangement if currently null if ($serviceSong->song_arrangement_id === null) { // Find default arrangement: is_default → name='normal' → first @@ -112,6 +117,7 @@ public function unassign(ServiceSong $serviceSong): void $serviceSong->update([ 'song_id' => null, 'matched_at' => null, + 'confirmed_at' => null, ]); } } diff --git a/database/migrations/2026_06_21_100000_add_confirmed_at_to_service_songs_table.php b/database/migrations/2026_06_21_100000_add_confirmed_at_to_service_songs_table.php new file mode 100644 index 0000000..a96220d --- /dev/null +++ b/database/migrations/2026_06_21_100000_add_confirmed_at_to_service_songs_table.php @@ -0,0 +1,22 @@ +timestamp('confirmed_at')->nullable()->after('matched_at'); + }); + } + + public function down(): void + { + Schema::table('service_songs', function (Blueprint $table) { + $table->dropColumn('confirmed_at'); + }); + } +}; diff --git a/resources/js/Components/AgendaItemRow.vue b/resources/js/Components/AgendaItemRow.vue index de4f499..518bb49 100644 --- a/resources/js/Components/AgendaItemRow.vue +++ b/resources/js/Components/AgendaItemRow.vue @@ -1,7 +1,8 @@