Merge branch 'main' of bitbucket.org:studiotem/jandl-taskmanager-app

This commit is contained in:
Matej Glasnák committed 2026-02-03 04:19:01 +01:00
commit 44d315c961
3 files changed
+156 -49

No files matched your search

+79 -42
View File
@@ -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']);
}
@@ -430,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)) {
@@ -450,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.',
@@ -470,48 +475,80 @@ 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);
// 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;
// Sync timeblocks ak existujú
if (isset($employee['timeblocks']) && ! empty($employee['timeblocks'])) {
$newSubtask->syncTimeblocks($employee['timeblocks']);
// Vytvoríme subtask pre každého zamestnanca
foreach ($employees as $employee) {
$subtaskData = [
'user_id' => $employee['id'],
'title' => $title,
'description' => $description,
'deadline' => $deadline,
'estimated_time' => $employee['duration'],
'created_by' => $draft->created_by,
'is_draft' => false,
'draft_data' => null,
];
$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)
+16
View File
@@ -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;
+61 -7
View File
@@ -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()