, attached_task_ids: array, skipped_task_ids: array} */ public function import(TaskCollection $collection, Event $event): array { if ($collection->tenant_id && $collection->tenant_id !== $event->tenant_id) { throw new RuntimeException('Task collection is not accessible for this tenant.'); } $collection->loadMissing('tasks'); return $this->db->transaction(function () use ($collection, $event) { $tenantId = $event->tenant_id; $targetCollection = $this->resolveTenantCollection($collection, $tenantId); $createdTaskIds = []; $attachedTaskIds = []; $skippedTaskIds = []; $event->loadMissing(['eventPackage.package', 'eventPackages.package']); $eventPackage = $event->eventPackage; if (! $eventPackage && method_exists($event, 'eventPackages')) { $eventPackage = $event->eventPackages() ->with('package') ->orderByDesc('purchased_at') ->orderByDesc('created_at') ->first(); } $taskLimit = $eventPackage?->effectiveLimits()['max_tasks'] ?? null; $remaining = $taskLimit === null ? null : max(0, (int) $taskLimit - $event->tasks()->count()); foreach ($collection->tasks as $task) { if ($remaining !== null && $remaining <= 0) { $skippedTaskIds[] = $task->id; continue; } $tenantTask = $this->resolveTenantTask($task, $targetCollection, $tenantId); if ($tenantTask->wasRecentlyCreated) { $createdTaskIds[] = $tenantTask->id; } if (! $tenantTask->assignedEvents()->where('event_id', $event->id)->exists()) { $tenantTask->assignedEvents()->attach($event->id); $attachedTaskIds[] = $tenantTask->id; if ($remaining !== null) { $remaining = max(0, $remaining - 1); } } } $event->taskCollections()->syncWithoutDetaching([ $targetCollection->id => ['sort_order' => $targetCollection->position ?? 0], ]); return [ 'collection' => $targetCollection->fresh(), 'created_task_ids' => $createdTaskIds, 'attached_task_ids' => $attachedTaskIds, 'skipped_task_ids' => $skippedTaskIds, ]; }); } protected function resolveTenantCollection(TaskCollection $collection, int $tenantId): TaskCollection { if ($collection->tenant_id === $tenantId) { return $collection; } $existing = TaskCollection::query() ->where('tenant_id', $tenantId) ->where('source_collection_id', $collection->id) ->first(); if ($existing) { return $existing; } return TaskCollection::create([ 'tenant_id' => $tenantId, 'source_collection_id' => $collection->id, 'event_type_id' => $collection->event_type_id, 'slug' => $this->buildCollectionSlug($collection->slug, $tenantId), 'name_translations' => $collection->name_translations, 'description_translations' => $collection->description_translations, 'is_default' => false, 'position' => $collection->position, ]); } protected function resolveTenantTask(Task $templateTask, TaskCollection $targetCollection, int $tenantId): Task { if ($templateTask->tenant_id === $tenantId) { if ($templateTask->collection_id !== $targetCollection->id) { $templateTask->update(['collection_id' => $targetCollection->id]); } return $templateTask; } $sourceId = $templateTask->source_task_id ?: $templateTask->id; $existing = Task::query() ->where('tenant_id', $tenantId) ->where('source_task_id', $sourceId) ->first(); if ($existing) { $existing->update([ 'collection_id' => $targetCollection->id, 'source_collection_id' => $templateTask->source_collection_id ?: $targetCollection->source_collection_id ?: $targetCollection->id, ]); return tap($existing)->refresh(); } $slugBase = $templateTask->slug ?: ($templateTask->title['en'] ?? $templateTask->title['de'] ?? 'task'); $slug = $this->buildTaskSlug($slugBase); $cloned = Task::create([ 'tenant_id' => $tenantId, 'slug' => $slug, 'emotion_id' => $templateTask->emotion_id, 'event_type_id' => $templateTask->event_type_id, 'title' => $templateTask->title, 'description' => $templateTask->description, 'example_text' => $templateTask->example_text, 'due_date' => null, 'is_completed' => false, 'priority' => $templateTask->priority, 'collection_id' => $targetCollection->id, 'difficulty' => $templateTask->difficulty, 'sort_order' => $templateTask->sort_order, 'is_active' => true, 'source_task_id' => $sourceId, 'source_collection_id' => $templateTask->source_collection_id ?: $templateTask->collection_id, ]); return $cloned; } protected function buildCollectionSlug(?string $slug, int $tenantId): string { $base = Str::slug(($slug ?: 'collection').'-'.$tenantId); do { $candidate = $base.'-'.Str::random(4); } while (TaskCollection::where('slug', $candidate)->exists()); return $candidate; } protected function buildTaskSlug(string $base): string { $slugBase = Str::slug($base) ?: 'task'; do { $candidate = $slugBase.'-'.Str::random(6); } while (Task::where('slug', $candidate)->exists()); return $candidate; } }