From a5f6fbd720e305fbda55f3f6e67b09f7187d3ecd Mon Sep 17 00:00:00 2001 From: Michal Feher Date: Mon, 26 Jan 2026 14:30:59 +0100 Subject: [PATCH 1/2] no message --- be/app/Http/Controllers/SubTaskController.php | 105 +++++++++++------- be/app/Http/Resources/SubTaskResource.php | 16 +++ be/app/Models/SubTask.php | 68 ++++++++++-- 3 files changed, 144 insertions(+), 45 deletions(-) diff --git a/be/app/Http/Controllers/SubTaskController.php b/be/app/Http/Controllers/SubTaskController.php index 98de214..44976ec 100644 --- a/be/app/Http/Controllers/SubTaskController.php +++ b/be/app/Http/Controllers/SubTaskController.php @@ -11,6 +11,8 @@ use App\Models\SubTask; use App\Models\User; use Carbon\Carbon; use Illuminate\Http\Request; +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Validator; class SubTaskController extends Controller @@ -412,8 +414,9 @@ class SubTaskController extends Controller $subtask->syncTimesheets($data['data']['timesheets']); } - // syncnutie timeblocks - if (isset($data['data']['timeblocks'])) { + // syncnutie timeblocks - PRE DRAFTY s viacerými zamestnancami NIE! + // Timeblocks pre drafty s employees sú uložené v draft_data, nie v tabuľke timeblocks + if (isset($data['data']['timeblocks']) && ! $isDraftWithMultipleEmployees) { $subtask->syncTimeblocks($data['data']['timeblocks']); } @@ -470,48 +473,74 @@ class SubTaskController extends Controller $mastertask = $draft->mastertask; $createdSubtasks = []; - // Vytvoríme subtask pre každého zamestnanca - foreach ($employees as $employee) { - $subtaskData = [ - 'user_id' => $employee['id'], - 'title' => $draft->title, - 'description' => $draft->description, - 'deadline' => $draft->deadline, - 'estimated_time' => $employee['duration'], - 'created_by' => $draft->created_by, - 'is_draft' => false, - 'draft_data' => null, - ]; + // Použijeme transakciu pre atomicitu operácie + try { + DB::beginTransaction(); - $newSubtask = $mastertask->subtasks()->create($subtaskData); + // Vytvoríme subtask pre každého zamestnanca + foreach ($employees as $employee) { + $subtaskData = [ + 'user_id' => $employee['id'], + 'title' => $draft->title, + 'description' => $draft->description, + 'deadline' => $draft->deadline, + 'estimated_time' => $employee['duration'], + 'created_by' => $draft->created_by, + 'is_draft' => false, + 'draft_data' => null, + ]; - // Sync timeblocks ak existujú - if (isset($employee['timeblocks']) && ! empty($employee['timeblocks'])) { - $newSubtask->syncTimeblocks($employee['timeblocks']); + $newSubtask = $mastertask->subtasks()->create($subtaskData); + + // Sync timeblocks ak existujú - DÔLEŽITÉ: odstránime ID aby sa vytvorili nové záznamy + if (isset($employee['timeblocks']) && ! empty($employee['timeblocks'])) { + $cleanTimeblocks = array_map(function ($timeblock) { + // Odstránime ID a sub_task_id, aby sa vytvorili nové záznamy + unset($timeblock['id']); + unset($timeblock['sub_task_id']); + return $timeblock; + }, $employee['timeblocks']); + $newSubtask->createTimeblocks($cleanTimeblocks); + } + + // Skopírujeme attachmenty z pôvodného draftu + foreach ($draft->attachments as $attachment) { + $newSubtask->attachments()->create([ + 'name' => $attachment->name, + 'path' => $attachment->path, + 'size' => $attachment->size, + 'type' => $attachment->type, + ]); + } + + $createdSubtasks[] = $newSubtask; } - // Skopírujeme attachmenty z pôvodného draftu - foreach ($draft->attachments as $attachment) { - $newSubtask->attachments()->create([ - 'name' => $attachment->name, - 'path' => $attachment->path, - 'size' => $attachment->size, - 'type' => $attachment->type, - ]); - } + // Zmažeme pôvodný draft + $draft->timeblocks()->delete(); + $draft->attachments()->delete(); // attachmenty sú už skopírované + $draft->delete(); - $createdSubtasks[] = $newSubtask; + DB::commit(); + + return response()->json([ + 'message' => 'Draft published successfully', + 'subtasks' => SubTaskResource::collection($createdSubtasks), + ], 201); + + } catch (\Exception $e) { + DB::rollBack(); + Log::error('Failed to publish draft: ' . $e->getMessage(), [ + 'draft_id' => $draft->id, + 'employees' => $employees, + 'exception' => $e, + ]); + + return response()->json([ + 'message' => 'Failed to publish draft. Please try again.', + 'error' => $e->getMessage(), + ], 500); } - - // Zmažeme pôvodný draft - $draft->timeblocks()->delete(); - $draft->attachments()->delete(); // attachmenty sú už skopírované - $draft->delete(); - - return response()->json([ - 'message' => 'Draft published successfully', - 'subtasks' => SubTaskResource::collection($createdSubtasks), - ], 201); } public function delete($id) diff --git a/be/app/Http/Resources/SubTaskResource.php b/be/app/Http/Resources/SubTaskResource.php index c667db9..078c6ce 100644 --- a/be/app/Http/Resources/SubTaskResource.php +++ b/be/app/Http/Resources/SubTaskResource.php @@ -44,6 +44,22 @@ class SubTaskResource extends JsonResource // Pre drafty pridáme employees dáta if ($this->is_draft && $this->draft_data) { $data['employees'] = $this->draft_data; + + // Agregované timeblocks zo všetkých zamestnancov pre kalendárne zobrazenie + $allDraftTimeblocks = []; + foreach ($this->draft_data as $employee) { + if (isset($employee['timeblocks']) && is_array($employee['timeblocks'])) { + foreach ($employee['timeblocks'] as $timeblock) { + $allDraftTimeblocks[] = [ + 'employee_id' => $employee['id'], + 'start' => $timeblock['start'] ?? null, + 'end' => $timeblock['end'] ?? null, + 'is_finished' => $timeblock['is_finished'] ?? false, + ]; + } + } + } + $data['all_draft_timeblocks'] = $allDraftTimeblocks; } return $data; diff --git a/be/app/Models/SubTask.php b/be/app/Models/SubTask.php index 518f379..451bbf7 100644 --- a/be/app/Models/SubTask.php +++ b/be/app/Models/SubTask.php @@ -84,21 +84,75 @@ class SubTask extends Model $this->touch(); } + /** + * Synchronizácia timeblocks - aktualizuje existujúce, vytvorí nové, zmaže nepoužité + */ public function syncTimeblocks(Array $timeblocks) { if (empty($timeblocks)) { return $this->timeblocks()->delete(); } - // pripravenie array na upsert - $timeblocks = array_map(function($item) { + + // Získame ID existujúcich timeblocks tohto subtasku + $existingIds = $this->timeblocks()->pluck('id')->toArray(); + + // Rozdelíme na existujúce (s ID) a nové (bez ID alebo s neexistujúcim ID) + $timeblocksToUpdate = []; + $timeblocksToCreate = []; + $receivedIds = []; + + foreach ($timeblocks as $item) { $item['sub_task_id'] = $this->id; - return $item; + + // Ak má ID a toto ID existuje v našich timeblocks, aktualizujeme + if (isset($item['id']) && in_array($item['id'], $existingIds)) { + $timeblocksToUpdate[] = $item; + $receivedIds[] = $item['id']; + } else { + // Nový timeblock - odstránime ID aby sa vytvoril nový záznam + unset($item['id']); + $timeblocksToCreate[] = $item; + } + } + + // Zmažeme timeblocks, ktoré neboli poslané z frontendu + $this->timeblocks()->whereNotIn('id', $receivedIds)->delete(); + + // Aktualizujeme existujúce + foreach ($timeblocksToUpdate as $timeblock) { + $this->timeblocks()->where('id', $timeblock['id'])->update([ + 'start' => $timeblock['start'], + 'end' => $timeblock['end'], + ]); + } + + // Vytvoríme nové + if (! empty($timeblocksToCreate)) { + $this->timeblocks()->createMany($timeblocksToCreate); + } + } + + /** + * Vytvorenie nových timeblocks - pre použitie pri publikovaní draftu + */ + public function createTimeblocks(Array $timeblocks) + { + if (empty($timeblocks)) { + return; + } + + $timeblocksToCreate = array_map(function($item) { + // Odstránime ID a sub_task_id pre istotu + unset($item['id']); + unset($item['sub_task_id']); + return [ + 'start' => $item['start'], + 'end' => $item['end'], + 'is_finished' => $item['is_finished'] ?? false, + ]; }, $timeblocks); - // zmazanie vykazov, ktore neboli poslane z frontendu - $this->timeblocks()->whereNotIn('id', collect($timeblocks)->pluck('id')->filter())->delete(); - - $this->timeblocks()->upsert($timeblocks, ['id']); + $this->timeblocks()->createMany($timeblocksToCreate); } public function deleteAttachments() From c71f0d931dffafb395b2fd2e47f907d82f1bcfff Mon Sep 17 00:00:00 2001 From: Michal Feher Date: Fri, 30 Jan 2026 14:24:21 +0100 Subject: [PATCH 2/2] no message --- .../plugins/tm@_components/z-files-upload.vue | 2 +- be/app/Http/Controllers/SubTaskController.php | 22 +++++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/app/src/plugins/tm@_components/z-files-upload.vue b/app/src/plugins/tm@_components/z-files-upload.vue index f5b836c..3d0fd4a 100644 --- a/app/src/plugins/tm@_components/z-files-upload.vue +++ b/app/src/plugins/tm@_components/z-files-upload.vue @@ -92,4 +92,4 @@ export default { .gif-loader height: 30px - \ No newline at end of file + diff --git a/be/app/Http/Controllers/SubTaskController.php b/be/app/Http/Controllers/SubTaskController.php index 44976ec..aa09ede 100644 --- a/be/app/Http/Controllers/SubTaskController.php +++ b/be/app/Http/Controllers/SubTaskController.php @@ -433,7 +433,8 @@ class SubTaskController extends Controller */ private function publishDraftWithMultipleEmployees(SubTask $draft, Request $request) { - $employees = $draft->draft_data; + // Použij employees z requestu ak existujú, inak fallback na draft_data z DB + $employees = $request->all()['data']['employees'] ?? $draft->draft_data; // Ak je employees pole prázdne, zlyhaj if (empty($employees)) { @@ -453,15 +454,16 @@ class SubTaskController extends Controller // Ak duration nie je nastavený, vypočítaj ho z timeblocks if (! isset($employee['duration']) || $employee['duration'] === null) { if (isset($employee['timeblocks']) && ! empty($employee['timeblocks'])) { - $totalDuration = 0; + $totalDurationMinutes = 0; foreach ($employee['timeblocks'] as $timeblock) { if (isset($timeblock['start']) && isset($timeblock['end'])) { $start = Carbon::parse($timeblock['start']); $end = Carbon::parse($timeblock['end']); - $totalDuration += $end->diffInMinutes($start); + $totalDurationMinutes += $end->diffInMinutes($start); } } - $employees[$key]['duration'] = $totalDuration; + // Konvertuj na hodiny (frontend očakáva hodiny) + $employees[$key]['duration'] = $totalDurationMinutes / 60; } else { return response()->json([ 'message' => 'Draft cannot be published. Each employee must have duration or timeblocks.', @@ -477,13 +479,19 @@ class SubTaskController extends Controller try { DB::beginTransaction(); + // Získame aktuálne hodnoty z requestu (ak existujú), inak fallback na draft + $requestData = $request->all()['data'] ?? []; + $title = $requestData['title'] ?? $draft->title; + $description = $requestData['description'] ?? $draft->description; + $deadline = $requestData['deadline'] ?? $draft->deadline; + // Vytvoríme subtask pre každého zamestnanca foreach ($employees as $employee) { $subtaskData = [ 'user_id' => $employee['id'], - 'title' => $draft->title, - 'description' => $draft->description, - 'deadline' => $draft->deadline, + 'title' => $title, + 'description' => $description, + 'deadline' => $deadline, 'estimated_time' => $employee['duration'], 'created_by' => $draft->created_by, 'is_draft' => false,