/ app / Http / Services / TaskService.php
TaskService.php
   1  <?php
   2  
   3  namespace App\Http\Services;
   4  
   5  use App\Enums\InboxFileTypeEnum;
   6  use App\Http\Livewire\Dossiers\Dossier\Validation;
   7  use Exception;
   8  use App\Models\Task;
   9  use App\Models\User;
  10  use App\Enums\StatusEnum;
  11  use App\Enums\TaskTypeEnum;
  12  use App\Models\Dossier;
  13  use App\Models\EntityUser;
  14  use App\Models\Role;
  15  use App\Models\Stage;
  16  
  17  use Illuminate\Support\Facades\DB;
  18  use App\Notifications\TaskAssigned;
  19  use Auth;
  20  use Carbon\Carbon;
  21  
  22  class TaskService
  23  {
  24  
  25      public static function searchInStage(int $stageId, string $searchString, string $sortField, string $sortDirection)
  26      {
  27          $stageQuery = Task::where('stage_id', $stageId)
  28              ->where('is_milestone', false)
  29              ->search($searchString);
  30  
  31          if ($sortField && $sortDirection) {
  32              // Ordenamiento por campos especiales
  33              if ($sortField === 'role') {
  34                  $stageQuery->orderByRole($sortDirection);
  35              } else if ($sortField === 'dossier') {
  36                  $stageQuery->orderByDossier($sortDirection);
  37              } else if ($sortField === 'status') {
  38                  $stageQuery->orderByStatus($sortDirection);
  39              } else {
  40                  $stageQuery->orderBy($sortField, $sortDirection);
  41              }
  42              return $stageQuery;
  43          }
  44  
  45          return $stageQuery;
  46      }
  47  
  48      /**
  49       * Display a listing of the resource.
  50       *
  51       * @return \Illuminate\Http\Response
  52       */
  53      public static function find(int $taskId)
  54      {
  55          return Task::where('id', $taskId)->first();
  56      }
  57  
  58      public static function findByUserAndDossier(int $userId, int $dossierId)
  59      {
  60          return Task::where('user_id', $userId)
  61              ->whereHas('stage', function ($query) use ($dossierId) {
  62                  $query->whereHas('dossier', function ($query) use ($dossierId) {
  63                      $query->where('id', $dossierId);
  64                  });
  65              })->first();
  66      }
  67  
  68      public static function findTaskTitleAndDossier(string $taskTitle, int $dossierId)
  69      {
  70          return Task::where('title', $taskTitle)
  71              ->whereHas('stage', function ($query) use ($dossierId) {
  72                  $query->where('dossier_id', $dossierId);
  73              })->latest()->first();
  74      }
  75  
  76      public static function findByType(int $dossierId, TaskTypeEnum $type)
  77      {
  78          $dossier = Dossier::find($dossierId);
  79          return $dossier->tasks()->where('type', $type)->latest()->first();
  80      }
  81  
  82      public static function getByType(int $dossierId, TaskTypeEnum $type)
  83      {
  84          return Dossier::find($dossierId)->tasks()->where('type', $type)->get();
  85      }
  86  
  87      public static function findTaskByDossierAndDocument(int $dossierId, int $revisionId)
  88      {
  89          return Task::where('revision_id', $revisionId)
  90              ->whereHas('stage', function ($query) use ($dossierId) {
  91                  $query->where('dossier_id', $dossierId);
  92              })->first();
  93      }
  94  
  95      public static function getAllTaskByTitleAndDossier(string $taskTitle, int $dossierId)
  96      {
  97          return Task::where('title', $taskTitle)
  98              ->whereHas('stage', function ($query) use ($dossierId) {
  99                  $query->whereHas('dossier', function ($query) use ($dossierId) {
 100                      $query->where('id', $dossierId);
 101                  });
 102              })->get();
 103      }
 104  
 105      /**
 106       * Create resources
 107       *
 108       * @return \Illuminate\Http\Response
 109       */
 110      public static function searchTasks(string $searchString, string $sortField, string $sortDirection, array|null $filters, User $user = null)
 111      {
 112          $tasksQuery = Task::query();
 113  
 114          if (
 115              $user and !$user->hasRole('root') and
 116              !$user->hasRole('technical_manager') and
 117              !$user->hasRole('quality_manager') and
 118              !$user->hasRole('security_manager') and
 119              !$user->hasRole('area_manager')
 120          ) {
 121              $tasksQuery->where(function ($query) use ($user) {
 122                  $query->where(function ($query) use ($user) {
 123                      $query->where('user_id', $user->id)
 124                          ->orWhere('author_id', $user->id);
 125                  })
 126                      ->orWhere(function ($query) use ($user) {
 127                          $query->whereHas('role', function ($query) use ($user) {
 128                              $query->whereHas('users', function ($query) use ($user) {
 129                                  $query->where('users.id', $user->id);
 130                              });
 131                          });
 132                      });
 133              });
 134          }
 135  
 136          if ($filters && $filters['withTrashed']) {
 137              $tasksQuery->withTrashed();
 138          }
 139  
 140          $tasksQuery->search($searchString);
 141  
 142          if ($filters && $filters['created_at_since']) {
 143              $tasksQuery->where('created_at', '>=', $filters['created_at_since']);
 144          }
 145  
 146          if ($filters && $filters['created_at_to']) {
 147              $tasksQuery->where('created_at', '<=', $filters['created_at_to']);
 148          }
 149  
 150          if ($filters && $filters['status']) {
 151              $tasksQuery->whereIn('task_status_id', $filters['status']);
 152          }
 153  
 154          if ($filters && $filters['users']) {
 155              $tasksQuery->where(function ($query) use ($filters) {
 156                  $query->whereIn('user_id', $filters['users'])->orWhereHas('role', function ($query) use ($filters) {
 157                      $query->whereHas('users', function ($query) use ($filters) {
 158                          $query->whereIn('user_id', $filters['users']);
 159                      });
 160                  });
 161              });
 162          }
 163  
 164          if ($filters && $filters['roles']) {
 165              $tasksQuery->whereIn('role_id', $filters['roles']);
 166          }
 167  
 168          if ($filters && $filters['dossiers']) {
 169              $tasksQuery->whereHas('stage', function ($query) use ($filters) {
 170                  $query->whereIn('dossier_id', $filters['dossiers']);
 171              });
 172          }
 173  
 174          if ($filters && $filters['end_date_since']) {
 175              $tasksQuery->where('end_date', '>=', $filters['end_date_since']);
 176          }
 177  
 178          if ($filters && $filters['end_date_to']) {
 179              $tasksQuery->where('end_date', '<=', $filters['end_date_to']);
 180          }
 181  
 182          if ($filters && $filters['expiration_date_since']) {
 183              $tasksQuery->where('expiration_date', '>=', $filters['expiration_date_since']);
 184          }
 185  
 186          if ($filters && $filters['expiration_date_to']) {
 187              $tasksQuery->where('expiration_date', '<=', $filters['expiration_date_to']);
 188          }
 189  
 190          if ($sortField && $sortDirection) {
 191              // Ordenamiento por campos especiales
 192              if ($sortField === 'role') {
 193                  $tasksQuery->orderByRole($sortDirection);
 194              } else if ($sortField === 'dossier') {
 195                  $tasksQuery->orderByDossier($sortDirection);
 196              } else if ($sortField === 'status') {
 197                  $tasksQuery->orderByStatus($sortDirection);
 198              } else {
 199                  $tasksQuery->orderBy($sortField, $sortDirection);
 200              }
 201          }
 202  
 203          return $tasksQuery;
 204      }
 205  
 206      /**
 207       * Create a resource
 208       *
 209       */
 210      public static function create(array $taskData, array $relation, ?int $stageId = null, ?int $revisionId = null): Task|Exception
 211      {
 212          $task = Task::create(
 213              [
 214                  'title' => $taskData['title'],
 215                  'stage_id' => $stageId,
 216                  'user_id' => $relation['user_id'] ?? null,
 217                  'role_id' => $relation['role_id'] ?? null,
 218                  'source' => 'internal',
 219                  'description' => $taskData['description'],
 220                  'start_date' => $taskData['start_date'] ?? Carbon::now(),
 221                  'end_date' => $taskData['end_date'] ?? null,
 222                  'expiration_date' => $taskData['expiration_date'] ?? null,
 223                  'task_status_id' => $taskData['task_status_id'] ?? StatusEnum::pending()->value,
 224                  'revision_id' => $revisionId,
 225                  'type' => $taskData['type'] ?? TaskTypeEnum::default->name,
 226              ]
 227          );
 228  
 229          $users = isset($relation['role_id'])
 230              ? Role::find($relation['role_id'])->users
 231              : User::where('id', $relation['user_id'])->get();
 232  
 233          if ($task->wasRecentlyCreated) {
 234              foreach ($users as $user) {
 235                  $user->notify(new TaskAssigned($task));
 236              }
 237          }
 238  
 239          return $task;
 240      }
 241  
 242      /**
 243       * Update a resource
 244       *
 245       * @return \Illuminate\Http\Response
 246       */
 247      public static function update(array $data, int $taskId)
 248      {
 249          try {
 250              DB::beginTransaction();
 251  
 252              $task = Task::findOrFail($taskId);
 253              $task->title = $data['task']['title'];
 254              $task->description = $data['task']['description'];
 255              $task->start_date = $data['task']['start_date'];
 256              $task->end_date = $data['task']['end_date'];
 257              $task->expiration_date = $data['task']['expiration_date'];
 258              $task->user_id = $data['relation']['user_id'];
 259              $task->stage_id = $data['relation']['stage_id'];
 260              $task->role_id = $data['relation']['role_id'];
 261              $task->milestone_end_date = $task->is_milestone ? $data['task']['milestone_end_date'] : null;
 262              $task->task_status_id = $data['task']['status_id'];
 263              $task->save();
 264  
 265              DB::commit();
 266              return true;
 267          } catch (Exception $e) {
 268              logger()->error($e);
 269              DB::rollBack();
 270              //throw new Exception($e->getMessage());
 271              throw new Exception(__('tasks.task.notifications.update.error.message'));
 272          }
 273      }
 274  
 275      /**
 276       * Destroy a resource
 277       *
 278       * @return \Illuminate\Http\Response
 279       */
 280      public static function remove(int $taskId)
 281      {
 282          try {
 283              Task::find($taskId)->delete();
 284              return True;
 285          } catch (Exception $e) {
 286              throw new Exception(__('tasks.task.notifications.remove.error.message'));
 287          }
 288      }
 289  
 290      /**
 291       * Restore a resource
 292       *
 293       * @return \Illuminate\Http\Response
 294       */
 295      public static function restore(int $taskId)
 296      {
 297          try {
 298              $task = Task::withTrashed()->find($taskId);
 299              $task->restore();
 300              return True;
 301          } catch (Exception $e) {
 302              throw new Exception(__('tasks.task.notifications.restore.error.message'));
 303          }
 304      }
 305  
 306      public static function setStatus(int $taskId, int $statusEnumValue)
 307      {
 308          try {
 309              $task = Task::findOrFail($taskId);
 310  
 311              if ($statusEnumValue === StatusEnum::finished()->value) {
 312                  $task->end_date = Carbon::now();
 313                  $task->milestone_end_date = Carbon::now();
 314              } elseif ($statusEnumValue === StatusEnum::notApplicable()->value) {
 315                  $task->milestone_end_date = null;
 316              } else {
 317                  $task->end_date = null;
 318              }
 319  
 320              $task->task_status_id = $statusEnumValue;
 321              $task->save();
 322  
 323              return true;
 324          } catch (Exception $e) {
 325              DB::rollBack();
 326              throw $e;
 327          }
 328      }
 329  
 330      public static function getStatusMessage(int $taskId)
 331      {
 332          $statusId = Task::findOrFail($taskId)->task_status_id;
 333  
 334          return match ($statusId) {
 335              StatusEnum::inProcess()->value => __('tasks.task.cards.actions.statuses.' . config('template.TEMPLATE_ROUTE') . '.finished'),
 336              StatusEnum::finished()->value,
 337              StatusEnum::pending()->value => __('tasks.task.cards.actions.statuses.' . config('template.TEMPLATE_ROUTE') . '.inProcess'),
 338              default => "",
 339          };
 340      }
 341  
 342      public static function isCompleted(int $taskId)
 343      {
 344          return Task::findOrFail($taskId)->task_status_id === StatusEnum::finished()->value;
 345      }
 346  
 347      public static function createTasksFromEPJson(array $ep, int $dossierId)
 348      {
 349          try {
 350              DB::beginTransaction();
 351              $data = $ep['resources']['timePlanning'];
 352              $stage = Stage::firstOrCreate(
 353                  [
 354                      'dossier_id' => $dossierId,
 355                      'name' => 'Evaluation Plan',
 356                      'stage_status_id' => StatusEnum::pending()->value
 357                  ]
 358              );
 359              $tasks = [];
 360              foreach ($data as $task) {
 361                  $tasks[] = Task::create([
 362                      'source' => 'external',
 363                      'title' => $task['name'],
 364                      'description' => $task['justification'],
 365                      'user_id' => null,
 366                      'stage_id' => $stage->id,
 367                      'start_date' => $task['startDate'],
 368                      'end_date' => $task['endDate'],
 369                  ]);
 370              }
 371              DB::commit();
 372  
 373              return $tasks;
 374          } catch (Exception $e) {
 375              DB::rollBack();
 376              throw new Exception($e->getMessage());
 377          }
 378      }
 379  
 380      public static function generateTask($inboxFile, bool $success = true)
 381      {
 382          $stage = $inboxFile->dossier->stages()->where('name', __('stages.default.1'))->first();
 383  
 384          if (!$success) {
 385              if ($certifiers = $inboxFile->dossier->externalCertifiers()) {
 386                  foreach ($certifiers as $certifier) {
 387                      self::createRectifyTask($certifier->id, $stage->id);
 388                  }
 389              }
 390  
 391              if ($principalCertifier = $inboxFile->dossier->principalCertifier) {
 392                  self::createRectifyTask($principalCertifier->id, $stage->id);
 393              } else {
 394                  self::createRectifyTask(User::technicalManager()->id, $stage->id);
 395              }
 396          }
 397      }
 398  
 399      public static function createTask(Dossier $dossier, $title, $description, ?int $notifiableUserId = null, TaskTypeEnum $type = TaskTypeEnum::default): Task
 400      {
 401          $userId = $notifiableUser?->id ?? User::technicalManager()->id;
 402  
 403          return self::create(
 404              self::getTaskData($title, $description, type: $type),
 405              ['user_id' => $notifiableUserId],
 406              $dossier->stage->id
 407          );
 408      }
 409  
 410      public static function createNewDossierTask(Dossier $dossier, int $notifyTo = null): void
 411      {
 412          self::create(
 413              self::getTaskData(
 414                  __('tasks.assign_certifiers.title', ['code' => $dossier->code]),
 415                  __('tasks.assign_certifiers.description'),
 416                  type: TaskTypeEnum::assignCertifiers
 417              ),
 418              ['role_id' => Role::whereName('technical_manager')->first()->id],
 419              $dossier->stage->id,
 420          );
 421      }
 422  
 423      public static function finishAssignCertifiersTask(Dossier $dossier): void
 424      {
 425          $task = $dossier->tasks()
 426              ->where('type', TaskTypeEnum::assignCertifiers->name)
 427              ->whereNot('task_status_id', StatusEnum::finished()->value)
 428              ->first();
 429  
 430          if ($task) {
 431              self::setStatus($task->id, StatusEnum::finished()->value);
 432          }
 433      }
 434  
 435      public static function handleAssignCertifierTaskCompleted(Task $task): void
 436      {
 437          $dossier = $task->dossier();
 438          self::closeMilestone($dossier, __('tasks.milestones.certifiers-assigned'));
 439  
 440          // Skip
 441          if (self::existsByType($dossier, TaskTypeEnum::startCertification)) {
 442              return;
 443          }
 444  
 445          $userId = null;
 446          $roleId = null;
 447  
 448          if ($dossier->externalCertifiers()->isNotEmpty()) {
 449              $roleId = Role::whereName('external_certifier')->first()->id;
 450          } elseif ($certifier = $dossier->principalCertifier) {
 451              $userId = $certifier->id;
 452          }
 453  
 454          self::createStartCertificationTask($userId, $roleId, $dossier);
 455      }
 456  
 457      public static function createStartCertificationTask(?int $userId, ?int $roleId, Dossier $dossier): void
 458      {
 459          // searches the latest certification request in the dossier
 460          $revision_id = $dossier
 461              ->inboxfiles()
 462              ->whereType(InboxFileTypeEnum::certification_request()->value)
 463              ->latest()->first()?->document?->head_id;
 464  
 465  
 466          self::create(
 467              self::getTaskData(
 468                  __('tasks.start_certification.title'),
 469                  __('tasks.start_certification.description'),
 470                  type: TaskTypeEnum::startCertification
 471              ),
 472              ['user_id' => $userId, 'role_id' => $roleId],
 473              $dossier->current_stage_id,
 474              $revision_id,
 475          );
 476      }
 477  
 478      public static function createCloseDossier(Dossier $dossier): void
 479      {
 480          self::create(
 481              self::getTaskData(
 482                  __('tasks.close_dossier.title'),
 483                  __('tasks.close_dossier.description'),
 484                  type: TaskTypeEnum::closeDossier
 485              ),
 486              ['user_id' => $dossier->getCertifierId()],
 487              $dossier->current_stage_id
 488          );
 489      }
 490  
 491      public static function closeMilestone(Dossier $dossier, string $title): void
 492      {
 493          $milestoneId = $dossier->milestones()
 494              ->where('title', $title)
 495              ->first()->id ?? null;
 496  
 497          if ($milestoneId) {
 498              self::setStatus($milestoneId, StatusEnum::finished()->value);
 499          }
 500      }
 501  
 502      private static function existsByType(Dossier $dossier, TaskTypeEnum $type): bool
 503      {
 504          return $dossier->tasks()->where('title', $type->name)->exists();
 505      }
 506  
 507      public static function handleNotifyStartCertificationTaskCompleted(Task $task): void
 508      {
 509          self::closeMilestone($task->dossier(), __('tasks.milestones.start-notification'));
 510      }
 511  
 512      public static function handleKickOffActDone(Task $task): void
 513      {
 514          self::closeMilestone($task->dossier(), __('tasks.milestones.evaluation-meet-finished'));
 515  
 516          $principalCertifierId = $task->dossier()->principalCertifier->id ?? null;
 517          $stageId = $task->dossier()->getStage(2)->id ?? null;
 518          if (!$principalCertifierId || !$stageId) {
 519              return;
 520          }
 521          self::createSendEvaluationKickoffActTask($principalCertifierId, $stageId);
 522      }
 523  
 524      public static function handleKickOffActSent(Task $task): void
 525      {
 526          self::closeMilestone($task->dossier(), __('tasks.milestones.evaluation-meet-minutes-sent'));
 527      }
 528  
 529      public static function handlePreResolutionActDone(Task $task): void
 530      {
 531          self::closeMilestone($task->dossier(), __('tasks.milestones.pre-hearing-meeting-convened'));
 532      }
 533  
 534  
 535      public static function handlePreResolutionActSent(Task $task): void
 536      {
 537          $dossier = $task->dossier();
 538          $dossier->current_stage_id = $dossier->getStage(5)->id;
 539          $dossier->save();
 540  
 541          TaskService::createDraftResolutionProposal($dossier);
 542          self::closeMilestone($dossier, __('tasks.milestones.pre-hearing-meeting-minutes-sent'));
 543      }
 544  
 545      public static function createRectifyTask(int $userId, int $stageId): void
 546      {
 547          self::create(
 548              self::getTaskData(
 549                  __('tasks.rectify.title'),
 550                  __('tasks.rectify.description'),
 551                  StatusEnum::waiting()->value
 552              ),
 553              ['user_id' => $userId],
 554              $stageId
 555          );
 556      }
 557  
 558      public static function createReviewTask(int $roleId, int $stageId, string $documentName, int $revisionId): void
 559      {
 560          self::create(
 561              self::getTaskData(
 562                  __('tasks.review.title', ['documentName' => $documentName]),
 563                  __('tasks.review.description', ['documentName' => $documentName])
 564              ),
 565              ['role_id' => $roleId],
 566              $stageId,
 567              $revisionId
 568          );
 569      }
 570  
 571      public static function createApprovalTask(int $roleId, int $stageId, string $documentName, ?int $revisionId): void
 572      {
 573          self::create(
 574              self::getTaskData(
 575                  __('tasks.approve.title', ['documentName' => $documentName]),
 576                  __('tasks.approve.description', ['documentName' => $documentName])
 577              ),
 578              ['role_id' => $roleId],
 579              $stageId,
 580              $revisionId
 581          );
 582      }
 583  
 584      public static function createEvaluationKickoffMeetingTask(int $userId, Dossier $dossier): void
 585      {
 586          $nextStageId = $dossier->getStage(2)->id;
 587  
 588          self::create(
 589              self::getTaskData(
 590                  __('tasks.convene_evaluation_start_meet.title'),
 591                  __('tasks.convene_evaluation_start_meet.description'),
 592                  null,
 593                  null,
 594                  Carbon::now()->addMonth(),
 595                  type: TaskTypeEnum::conveneEvaluationStartMeet
 596              ),
 597              ['user_id' => $userId],
 598              $nextStageId
 599          );
 600  
 601          DossierService::setNewCurrentStage($dossier, $nextStageId);
 602      }
 603  
 604      public static function createDraftEvaluationKickoffMeetingActTask(int $userId, int $stageId): Task
 605      {
 606          return self::create(
 607              self::getTaskData(
 608                  __('tasks.draft_evaluation_kick-off_act.title'),
 609                  __('tasks.draft_evaluation_kick-off_act.description'),
 610                  type: TaskTypeEnum::draftEvaluationKickOffAct
 611              ),
 612              ['user_id' => $userId],
 613              $stageId
 614          );
 615      }
 616  
 617      public static function createSendEvaluationKickoffActTask(int $userId, int $stageId)
 618      {
 619          self::create(
 620              self::getTaskData(
 621                  __('tasks.send_act_evaluation_start.title', ['dossierCode' => Stage::find($stageId)->dossier->code]),
 622                  __('tasks.send_act_evaluation_start.description'),
 623                  type: TaskTypeEnum::sendActEvaluationStart
 624              ),
 625              ['user_id' => $userId],
 626              $stageId
 627          );
 628      }
 629  
 630      public static function createDraftPreResolutionHearingMeetingActTask(int $userId, int $stageId): Task
 631      {
 632          return self::create(
 633              self::getTaskData(
 634                  __('tasks.draft_pre_resolution_hearing_act.title'),
 635                  __('tasks.draft_pre_resolution_hearing_act.description'),
 636                  type: TaskTypeEnum::draftPreResolutionHearingAct
 637              ),
 638              ['user_id' => $userId],
 639              $stageId
 640          );
 641      }
 642  
 643      public static function createHandleDismissedDossierTask(int $userId, int $stageId): void
 644      {
 645          self::create(
 646              self::getTaskData(
 647                  __('tasks.handle_dismissed.title', ['dossierCode' => Stage::find($stageId)->dossier->code]),
 648                  __('tasks.handle_dismissed.description')
 649              ),
 650              ['user_id' => $userId],
 651              $stageId
 652          );
 653      }
 654  
 655      public static function createValidatePartialReportTask(int $userId, Dossier $dossier, string $partialClass, \App\Models\Validation $validation, bool $waiting=false): Task
 656      {
 657          $task = self::create(
 658              self::getTaskData(
 659                  __('tasks.validate_partial_report.title', ['partialClass' => $partialClass]),
 660                  __('tasks.validate_partial_report.description'),
 661                  statusId:  TaskStatus::onHold()->id,
 662                  type: TaskTypeEnum::validateEtrp
 663              ),
 664              ['user_id' => $userId],
 665              //$nextStageId
 666              $dossier->stage->id,
 667              $validation->inboxFile?->document?->head_id,
 668          );
 669  
 670          $task->milestoneValidation()->associate($validation);
 671          $task->save();
 672  
 673          return $task;
 674      }
 675  
 676      public static function createValidateETRTask(int $userId, Dossier $dossier, \App\Models\Validation $validation): Task
 677      {
 678          /*  $found = $dossier->inboxFiles()->where('type', InboxFileTypeEnum::ETR()->value)->whereColumn('updated_at', '>', 'created_at')->exists();
 679          $nextStageId = $found ? $dossier->stage->id : $dossier->nextStage()->id; */
 680  
 681          $task = self::create(
 682              self::getTaskData(
 683                  __('tasks.validate_etr.title'),
 684                  __('tasks.validate_etr.description'),
 685                  type: TaskTypeEnum::validateEtr
 686              ),
 687              ['user_id' => $userId],
 688              //$nextStageId
 689              $dossier->stage->id,
 690              $validation->inboxFile?->document?->head_id,
 691          );
 692          $task->milestoneValidation()->associate($validation);
 693          $task->save();
 694          /*
 695          if (!$found)
 696              DossierService::setNewCurrentStage($dossier, $nextStageId); */
 697  
 698          return $task;
 699      }
 700  
 701      public static function createReviewORTask(int $userId, int $stageId): void
 702      {
 703          self::create(
 704              self::getTaskData(
 705                  __('tasks.review_or.title', ['dossierCode' => Stage::find($stageId)->dossier->code]),
 706                  __('tasks.review_or.description')
 707              ),
 708              ['user_id' => $userId],
 709              $stageId
 710          );
 711      }
 712  
 713      public static function createSendETRTask(int $userId, int $stageId): Task
 714      {
 715          return self::create(
 716              self::getTaskData(
 717                  title: __('tasks.send_etr.title'),
 718                  description: __('tasks.send_etr.description'),
 719                  type: TaskTypeEnum::sendEtr
 720              ),
 721              ['user_id' => $userId],
 722              $stageId
 723          );
 724      }
 725  
 726      public static function createSendPartialReportTask(int $userId, int $stageId, string $partialClass): Task
 727      {
 728          $task = self::create(
 729              self::getTaskData(
 730                  title: __('tasks.send_partial_report.title', ['partialClass' => $partialClass]),
 731                  description: __('tasks.send_partial_report.description'),
 732                  type: TaskTypeEnum::sendEtrp
 733              ),
 734              ['user_id' => $userId],
 735              $stageId
 736          );
 737          return $task;
 738      }
 739  
 740  
 741      public static function createSendPartialReportTaskMilestone(Stage $stage, string $partialClass, Task $task, \App\Models\Validation $validation)
 742      {
 743          $milestone = TaskService::createMilestone($stage, __('tasks.milestones.etrp-sent', [
 744              'partialClass' => $partialClass,
 745              'number' => Task::where('stage_id', $stage->id)->where('title', $task->title)->count()
 746          ]), null, TaskTypeEnum::sendEtrp->name);
 747  
 748  
 749          $milestone->milestoneValidation()->associate($validation);
 750          $milestone->save();
 751  
 752          return $milestone;
 753      }
 754  
 755      public static function createValidatePartialReportTaskMilestone(Stage $stage, string $partialClass, Task $task): Task
 756      {
 757          $milestone = TaskService::createMilestone($stage, __('tasks.milestones.etrp-received', [
 758              'partialClass' => $partialClass,
 759              'number' => Task::where('stage_id', $stage->id)->where('title', $task->title)->count(),
 760          ]));
 761  
 762  
 763          return self::completeMilestoneNow($milestone);
 764      }
 765  
 766      public static function createSendETRTaskMilestone(Stage $stage, Task $task, \App\Models\Validation $validation): Task
 767      {
 768          $milestone = TaskService::createMilestone($stage, __('tasks.milestones.etr-sent', [
 769              'number' => Task::where('stage_id', $stage->id)->where('title', $task->title)->count()
 770          ]), null, TaskTypeEnum::sendEtr->name);
 771  
 772          $milestone->milestoneValidation()->associate($validation);
 773          $milestone->save();
 774          return $milestone;
 775      }
 776  
 777      public static function createValidateETRTaskMilestone(Stage $stage, Task $task): Task
 778      {
 779          $number = Task::where('stage_id', $stage->id)->where('title', $task->title)->count();
 780          $milestone = TaskService::createMilestone($stage, __('tasks.milestones.etr-received', [
 781              'number' => $number,
 782          ]));
 783  
 784          return self::completeMilestoneNow($milestone);
 785      }
 786  
 787      public static function completeMilestoneNow(Task $milestone): Task
 788      {
 789          $milestone->milestone_end_date = now();
 790          $milestone->task_status_id = StatusEnum::finished();
 791  
 792          $milestone->save();
 793  
 794          return $milestone;
 795      }
 796  
 797      public static function findMilestoneByValidation(\App\Models\Validation $validation, TaskTypeEnum $type = TaskTypeEnum::default): ?Task
 798      {
 799          return Task::where('milestone_validation_id', $validation->id)
 800              ->where('is_milestone', true)
 801              ->where('type', $type->name)
 802              ->first();
 803      }
 804  
 805      public static function CompleteMilestoneByValidation(\App\Models\Validation $validation): void
 806      {
 807          $milestone = self::findMilestoneByValidation($validation);
 808  
 809          if ($milestone)
 810              self::completeMilestoneNow($milestone);
 811      }
 812  
 813      public static function createDraftCertificationReport(int $userId, Dossier $dossier)
 814      {
 815          self::create(
 816              self::getTaskData(
 817                  __('tasks.create_draft_certification_report.title'),
 818                  __('tasks.create_draft_certification_report.description', ['dossierCode' => $dossier->code]),
 819                  type: TaskTypeEnum::createDraftCertificationReport
 820              ),
 821              ['user_id' => $userId],
 822              $dossier->current_stage_id
 823          );
 824      }
 825  
 826      public static function createSendPreResolutionHearingMeeting(int $userId, int $stageId)
 827      {
 828          self::create(
 829              self::getTaskData(
 830                  __('tasks.send_pre-hearing_minutes.title', ['dossierCode' => Stage::find($stageId)->dossier->code]),
 831                  __('tasks.send_pre-hearing_minutes.description'),
 832                  type: TaskTypeEnum::sendPreHearingMinutes
 833              ),
 834              ['user_id' => $userId],
 835              $stageId
 836          );
 837      }
 838  
 839      public static function createSendPreResolutionHearingForm(?int $userId, int $stageId): Task
 840      {
 841  
 842          return self::create(
 843              self::getTaskData(
 844                  __('tasks.send_pre-resolution_hearing_form.title', ['dossierCode' => Stage::find($stageId)->dossier->code]),
 845                  __('tasks.send_pre-resolution_hearing_form.description')
 846              ),
 847              ['user_id' => $userId],
 848              $stageId
 849          );
 850      }
 851  
 852      public static function createConveneHearingMeetingTask(int $userId, int $stageId): void
 853      {
 854          self::create(
 855              self::getTaskData(
 856                  __('tasks.convene_hearing_meeting_prior_to_resolution.title'),
 857                  __('tasks.convene_hearing_meeting_prior_to_resolution.description', ['dossierCode' => Stage::find($stageId)->dossier->code]),
 858                  type: TaskTypeEnum::convenePreResolutionMeet
 859              ),
 860              ['user_id' => $userId],
 861              $stageId
 862          );
 863      }
 864  
 865      public static function createDraftResolutionProposal(Dossier $dossier): void
 866      {
 867          self::create(
 868              self::getTaskData(
 869                  __('tasks.draft_resolution_proposal.title'),
 870                  __('tasks.draft_resolution_proposal.description', ['dossierCode' => $dossier->code]),
 871                  type: TaskTypeEnum::draftResolutionProposal
 872              ),
 873              ['user_id' => $dossier->principalCertifier->id],
 874              $dossier->current_stage_id
 875          );
 876      }
 877  
 878      public static function createProcessResolution(int $userId, int $stageId): void
 879      {
 880          self::create(
 881              self::getTaskData(
 882                  __('tasks.process_resolution.title'),
 883                  __('tasks.process_resolution.description', ['dossierCode' => Stage::find($stageId)->dossier->code]),
 884                  StatusEnum::waiting()->value,
 885                  type: TaskTypeEnum::processResolution
 886              ),
 887              ['user_id' => $userId],
 888              $stageId
 889          );
 890      }
 891  
 892      public static function handleResolutionProcessed(Task $task): void
 893      {
 894          $dossier = $task->dossier();
 895          self::closeMilestone($dossier, __('tasks.milestones.resolution-processed'));
 896          self::createFollowUpResolution($dossier);
 897      }
 898  
 899      public static function createFollowUpResolution(Dossier $dossier): void
 900      {
 901          self::create(
 902              self::getTaskData(
 903                  __('tasks.follow-up_resolution.title'),
 904                  __('tasks.follow-up_resolution.description', ['dossierCode' => $dossier->code]),
 905                  StatusEnum::waiting()->value,
 906                  type: TaskTypeEnum::followUpResolution
 907              ),
 908              ['user_id' => $dossier->principalCertifier->id],
 909              $dossier->current_stage_id
 910          );
 911      }
 912  
 913      public static function handleSignedResolution(Task $task): void
 914      {
 915          $dossier = $task->dossier();
 916  
 917          $resolution = $dossier->resolutions()->latest()->first();
 918          if (!$resolution or $resolution->approved === null)
 919              throw new Exception(__('tasks.follow-up_resolution.error'));
 920  
 921          self::closeMilestone($dossier, __('tasks.milestones.resolution-signed'));
 922  
 923          if ($resolution->approved) {
 924              self::createFollowUpSentToBoe($dossier);
 925              return;
 926          }
 927  
 928          // If resolution not approved, then skip to stage 6, setting any other milestone to N/A
 929          $task->stage->discardNonFinishedMilestones();
 930          $stage = $dossier->getStage(6);
 931          $dossier->current_stage_id = $stage->id;
 932          $dossier->save();
 933          self::finalizeCertificationReport($dossier->getCertifierId(), $dossier);
 934      }
 935  
 936      public static function createFollowUpSentToBoe(Dossier $dossier): void
 937      {
 938          self::create(
 939              self::getTaskData(
 940                  __('tasks.follow-up_sent_to_boe.title'),
 941                  __('tasks.follow-up_sent_to_boe.description', ['dossierCode' => $dossier->code]),
 942                  StatusEnum::waiting()->value,
 943                  type: TaskTypeEnum::followUpSentToBoe
 944              ),
 945              ['user_id' => $dossier->principalCertifier->id],
 946              $dossier->current_stage_id
 947          );
 948      }
 949  
 950      public static function handleSentToBoe(Task $task): void
 951      {
 952          $dossier = $task->dossier();
 953          self::closeMilestone($dossier, __('tasks.milestones.resolution-sent-to-boe'));
 954          self::createFollowUpPublishedInBoe($dossier);
 955      }
 956  
 957      public static function createFollowUpPublishedInBoe(Dossier $dossier): void
 958      {
 959          self::create(
 960              self::getTaskData(
 961                  __('tasks.follow-up_published_in_boe.title'),
 962                  __('tasks.follow-up_published_in_boe.description', ['dossierCode' => $dossier->code]),
 963                  StatusEnum::waiting()->value,
 964                  type: TaskTypeEnum::followUpPublishedInBoe
 965              ),
 966              ['user_id' => $dossier->principalCertifier->id],
 967              $dossier->current_stage_id
 968          );
 969      }
 970  
 971      public static function handlePublishedInBoe(Task $task): void
 972      {
 973          $dossier = $task->dossier();
 974          self::closeMilestone($dossier, __('tasks.milestones.resolution-published-in-boe'));
 975          self::createFollowUpCertificateSent($dossier);
 976      }
 977  
 978      public static function createFollowUpCertificateSent(Dossier $dossier): void
 979      {
 980          self::create(
 981              self::getTaskData(
 982                  __('tasks.follow-up_certificate_sent.title'),
 983                  __('tasks.follow-up_certificate_sent.description', ['dossierCode' => $dossier->code]),
 984                  StatusEnum::waiting()->value,
 985                  type: TaskTypeEnum::followUpCertificateSent
 986              ),
 987              ['user_id' => $dossier->principalCertifier->id],
 988              $dossier->current_stage_id
 989          );
 990      }
 991  
 992      public static function handleSignedCertificateSent(Task $task): void
 993      {
 994          $dossier = $task->dossier();
 995          $dossier->current_stage_id = $dossier->getStage(6)->id;
 996          $dossier->save();
 997  
 998          self::closeMilestone($dossier, __('tasks.milestones.resolution-certificate-sent'));
 999          self::finalizeCertificationReport($dossier);
1000      }
1001  
1002      public static function finalizeCertificationReport(Dossier $dossier): void
1003      {
1004          self::create(
1005              self::getTaskData(
1006                  __('tasks.finalize_certification_report.title'),
1007                  __('tasks.finalize_certification_report.description', ['dossierCode' => $dossier->code]),
1008                  type: TaskTypeEnum::finalizeCertificationReport
1009              ),
1010              ['user_id' => $dossier->getCertifierId()],
1011              $dossier->current_stage_id
1012          );
1013      }
1014  
1015      public static function updateCertifiedToeInformation(Dossier $dossier): void
1016      {
1017          self::create(
1018              self::getTaskData(
1019                  __('tasks.update_certified_toe_information.title'),
1020                  __('tasks.update_certified_toe_information.description', ['dossierCode' => $dossier->code]),
1021                  type: TaskTypeEnum::updateCertifiedToeInformation
1022              ),
1023              ['user_id' => $dossier->getCertifierId()],
1024              $dossier->current_stage_id
1025          );
1026      }
1027  
1028      public static function handleUpdatedTOE(Task $task): void
1029      {
1030          $dossier = $task->dossier();
1031          $resolution = $dossier->resolutions()->latest()->first();
1032          if (!$resolution)
1033              return;
1034  
1035          if ($resolution->approved) {
1036              self::updateCertifiedProductsList($dossier);
1037              return;
1038          }
1039  
1040          $dossier->current_stage_id = $dossier->getStage(12)->id;
1041          self::createCloseDossier($dossier);
1042      }
1043  
1044  
1045      public static function updateCertifiedProductsList(Dossier $dossier): void
1046      {
1047          self::create(
1048              self::getTaskData(
1049                  __('tasks.update_certified_products_list.title'),
1050                  __('tasks.update_certified_products_list.description', ['dossierCode' => $dossier->code]),
1051                  type: TaskTypeEnum::updateCertifiedProductsList
1052              ),
1053              ['user_id' => $dossier->getCertifierId()],
1054              $dossier->current_stage_id
1055          );
1056      }
1057  
1058      public static function handleUpdateCertifiedProductList(Task $task): void
1059      {
1060          $dossier = $task->dossier();
1061          self::closeMilestone($dossier, __('tasks.milestones.certified-list-updated'));
1062          self::publishCertifiedProductOnWeb($dossier);
1063      }
1064  
1065      public static function publishCertifiedProductOnWeb(Dossier $dossier): void
1066      {
1067          self::create(
1068              self::getTaskData(
1069                  __('tasks.publish_certified_product_on_web.title'),
1070                  __('tasks.publish_certified_product_on_web.description', ['dossierCode' => $dossier->code]),
1071                  type: TaskTypeEnum::publishCertifiedProductOnWeb
1072              ),
1073              ['user_id' => $dossier->getCertifierId()],
1074              $dossier->current_stage_id
1075          );
1076      }
1077  
1078      public static function handlePublishCertifiedProductOnWeb(Task $task): void
1079      {
1080          $dossier = $task->dossier();
1081          $dossier->current_stage_id = $dossier->getStage(12)->id;
1082          $dossier->save();
1083  
1084          self::closeMilestone($dossier, __('tasks.milestones.certified-product-web-published'));
1085          self::createCloseDossier($dossier);
1086      }
1087  
1088      public static function handleCloseDossier(Task $task): void
1089      {
1090          $dossier = $task->dossier();
1091          self::closeMilestone($dossier, __('tasks.milestones.dossier-closed'));
1092      }
1093  
1094      public static function createMilestone(Stage $stage, string $title, ?Validation $validation = null, ?string $type = null): Task
1095      {
1096          $task = new Task([
1097              'title' => $title,
1098              'description' => "",
1099              'start_date' => Carbon::now(),
1100              'task_status_id' => $type === TaskTypeEnum::certificationRequestReceived->name ? StatusEnum::finished()->value : StatusEnum::pending()->value,
1101              'stage_id' => $stage->id,
1102              'is_milestone' => true,
1103              'type' => $type->name ?? TaskTypeEnum::default->name,
1104              'milestone_end_date' => $type === TaskTypeEnum::certificationRequestReceived->name ? now() : null,
1105          ]);
1106  
1107          $task->milestone_stage_number = $stage->getNumber();
1108          $task->milestone_number = self::getMilestoneNumber($stage);
1109  
1110          $task->save();
1111  
1112          return $task;
1113      }
1114  
1115      private static function getMilestoneNumber(Stage $stage): int
1116      {
1117          return Task::where('stage_id', $stage->id)
1118              ->whereIsMilestone(true)
1119              ->count() + 1;
1120      }
1121  
1122      private static function getTaskData(
1123          string       $title,
1124          string       $description,
1125          int          $statusId = null,
1126          Carbon       $end_date = null,
1127          Carbon       $expiration_date = null,
1128          TaskTypeEnum $type = TaskTypeEnum::default
1129      ): array {
1130          if (!$statusId) {
1131              $statusId = StatusEnum::pending()->value;
1132          }
1133  
1134          return [
1135              'title' => $title,
1136              'description' => $description,
1137              'start_date' => Carbon::now(),
1138              'end_date' => $end_date,
1139              'expiration_date' => $expiration_date,
1140              'task_status_id' => $statusId,
1141              'type' => $type->name,
1142          ];
1143      }
1144  
1145      /*
1146      * This method handles the completion of a task
1147      * based on the title of the task
1148      */
1149      public static function handleCompletion(Task $task): void
1150      {
1151          $userId = $task->dossier()->getCertifierId();
1152          if (!$userId) {
1153              return;
1154          }
1155  
1156          $stageId = $task->stage->id;
1157  
1158          //ETR SENT milestones are related to a task
1159          $relatedMilestone = Task::where('milestone_related_task_id', $task->id)->first();
1160          if ($relatedMilestone) {
1161              self::completeMilestoneNow($relatedMilestone);
1162          }
1163  
1164          match ($task->type) {
1165              // stage 1
1166              'assignCertifiers' => self::handleAssignCertifierTaskCompleted($task),
1167              'startCertification' => self::handleNotifyStartCertificationTaskCompleted($task),
1168  
1169              // stage 2
1170              'conveneEvaluationStartMeet' => self::createDraftEvaluationKickoffMeetingActTask($userId, $stageId),
1171              'draftEvaluationKickOffAct' => self::handleKickOffActDone($task),
1172              'sendActEvaluationStart' => self::handleKickOffActSent($task),
1173  
1174              // stage 3
1175  
1176              // stage 4
1177              'createDraftCertificationReport' => self::createConveneHearingMeetingTask($userId, $task->stage->id),
1178              'convenePreResolutionMeet' => self::createDraftPreResolutionHearingMeetingActTask($userId, $stageId),
1179              'draftPreResolutionHearingAct' => self::handlePreResolutionActDone($task),
1180              'sendPreHearingMinutes' => self::handlePreResolutionActSent($task),
1181  
1182              // stage 5
1183              'draftResolutionProposal' => self::createProcessResolution($userId, $stageId),
1184              'processResolution' => self::handleResolutionProcessed($task),
1185              'followUpResolution' => self::handleSignedResolution($task),
1186              'followUpSentToBoe' => self::handleSentToBoe($task),
1187              'followUpPublishedInBoe' => self::handlePublishedInBoe($task),
1188              'followUpCertificateSent' => self::handleSignedCertificateSent($task),
1189  
1190              // stage 6
1191              'finalizeCertificationReport' => self::updateCertifiedToeInformation($task->dossier()),
1192              'updateCertifiedToeInformation' => self::handleUpdatedTOE($task),
1193              'updateCertifiedProductsList' => self::handleUpdateCertifiedProductList($task),
1194              'publishCertifiedProductOnWeb' => self::handlePublishCertifiedProductOnWeb($task),
1195  
1196              // stage 12
1197              'closeDossier' => self::handleCloseDossier($task),
1198              default => null,
1199          };
1200      }
1201  
1202      public static function getInternalRoles()
1203      {
1204          return Role::where('scope', 'global')
1205              ->where('is_internal', true)
1206              ->get(['id', 'name'])
1207              ->map(function ($role) {;
1208                  return [
1209                      'id' => $role->id,
1210                      'name' => __('roles.' . $role->name),
1211                  ];
1212              });
1213      }
1214  }