From 3fa3654938fac6fd8e8e5705289d1ab62698adf3 Mon Sep 17 00:00:00 2001 From: Dr Masroor Ehsan Date: Sun, 12 Jan 2025 01:09:27 +0600 Subject: [PATCH] refactorings --- app/Domain/Study/StudyLevelStatus.php | 7 +- .../Controllers/Staff/ReportController.php | 105 +++++---------- app/Models/Study.php | 17 ++- app/Models/StudyReport.php | 7 + .../Pacs/Sync/Pipes/FilterStudies.php | 2 +- app/Services/Pacs/Sync/StudiesSync.php | 2 +- app/Services/Report/ReportManager.php | 126 +++++++++++++++++- .../pages}/close-window.blade.php | 0 .../views/content/pages/notice.blade.php | 15 ++- 9 files changed, 186 insertions(+), 95 deletions(-) rename resources/views/{staff/reports => content/pages}/close-window.blade.php (100%) diff --git a/app/Domain/Study/StudyLevelStatus.php b/app/Domain/Study/StudyLevelStatus.php index 1c446e2..331dc5f 100644 --- a/app/Domain/Study/StudyLevelStatus.php +++ b/app/Domain/Study/StudyLevelStatus.php @@ -5,7 +5,8 @@ enum StudyLevelStatus: int { case Pending = 0; - case StudyArrived = 1 << 1; - case StudyLocked = 1 << 2; - case StudyUnlocked = 1 << 3; + case Unassigned = 10; + case Assigned = 20; + case ReadInProgress = 30; + case ReadCompleted = 40; } diff --git a/app/Http/Controllers/Staff/ReportController.php b/app/Http/Controllers/Staff/ReportController.php index 017a9d5..a204e08 100644 --- a/app/Http/Controllers/Staff/ReportController.php +++ b/app/Http/Controllers/Staff/ReportController.php @@ -2,19 +2,18 @@ namespace App\Http\Controllers\Staff; -use App\Domain\ACL\Permission; use App\Domain\Report\ReportStatus; use App\Http\Controllers\HashidControllerBase; use App\Http\Requests\StoreReportRequest; use App\Models\Study; use App\Models\StudyReport; -use App\Services\AuditTrail\Activity; +use App\Services\Report\ReportManager; class ReportController extends HashidControllerBase { public function popup() { - abort_unless(me()->may([Permission::ReportEdit, Permission::ReportDictate, Permission::ReportApprove, Permission::ReportDownload]), 403); + ReportManager::ensureDownloadAccess(); $this->decodeKeys(); $study = Study::with(['reports.radiologist', 'reports.study', 'assignedPhysicians'])->findOrFail($this->key); if (me()->isRadiologist()) { @@ -28,104 +27,60 @@ public function popup() public function save(StoreReportRequest $request) { - abort_unless(me()->may([Permission::ReportEdit, Permission::ReportDictate, Permission::ReportApprove]), 403); + ReportManager::ensureEditAccess(); $this->decodeKeys(); - $study = Study::findOrFail($this->key); + $manager = ReportManager::make($this->key); $reportStatus = ReportStatus::from($request->integer('report_status')); - - $report = StudyReport::make([ - 'study_id' => $study->id, - 'institute_id' => $study->institute_id, - 'facility_id' => $study->facility_id, - 'report_status' => $reportStatus->value, - 'read_by_id' => me()->id, - ]); - $report->saveContent(request('content')); - $report->save(); - $report->refresh(); - - audit() - ->on($study) - ->did($reportStatus->value >= ReportStatus::Finalized->value ? Activity::Report_Finalize : Activity::Report_Save) - ->notes($report->accession_number) - ->log(); + $report = $manager->createReport(request('content'), $reportStatus); if ($reportStatus->value === ReportStatus::Finalized->value) { - $report->setStatus($reportStatus); - - $study->setReportStatus($reportStatus); - audit() - ->on($study) - ->did(Activity::Report_Finalize) - ->log(); - - $study->unlockStudy(); - audit() - ->on($study) - ->did(Activity::Study_Unlock) - ->log(); + $manager->finalizeReport($report); } - return view('staff.reports.close-window'); + return view('staff.content.pages.close-window'); } public function create() { - abort_unless(me()->may([Permission::ReportEdit, Permission::ReportDictate, Permission::ReportApprove]), 403); + ReportManager::ensureEditAccess(); $this->decodeKeys(); - $study = Study::findOrFail($this->key); - if (! $study->canEditReport()) { - return view('content.pages.notice', [ - 'color' => 'warning', - 'title' => 'Read Completed', - 'heading' => 'Read Completed', - 'message' => 'Reading has been completed already.', - ]); + $manager = ReportManager::make($this->key); + + $view = $manager->check(); + if ($view) { + return $view; } - if (! $study->canObtainLock()) { - return view('content.pages.notice', [ - 'color' => 'danger', - 'title' => 'Study Locked', - 'heading' => 'Study Locked', - 'message' => 'Study is locked by another user.', - ]); - } - - if ($study->isUnlocked()) { - $study->lockStudy(); - audit() - ->on($study) - ->did(Activity::Study_Lock) - ->log(); - } + $manager->lockStudyIfRequired(); + $study = $manager->getStudy(); + $report = $manager->latestReport(); // todo: study_status: Read in Progress - $report = StudyReport::forStudy($study) - ->where('report_status', ReportStatus::Preliminary->value) - ->select(['id', 'accession_number', 'file_path']) - ->latest() - ->first(); - return view('staff.reports.create', compact('study', 'report')); } public function edit(string $uuid) { - abort_unless(me()->may([Permission::ReportEdit, Permission::ReportDictate, Permission::ReportApprove]), 403); - $report = StudyReport::with(['study', 'radiologist'])->where('accession_number', $uuid)->firstOrFail(); - $study = $report->study; - $title = 'View Report'; - $close = false; + ReportManager::ensureEditAccess(); + $report = StudyReport::with(['study_id', 'id'])->accession($uuid)->firstOrFail(); + $manager = ReportManager::make($report->study_id); - return view('staff.reports.create', compact('study', 'report', 'close')); + $view = $manager->check(); + if ($view) { + return $view; + } + + $manager->lockStudyIfRequired(); + $study = $manager->getStudy(); + + return view('staff.reports.create', compact('study', 'report')); } public function view(string $uuid) { - abort_unless(me()->may([Permission::ReportEdit, Permission::ReportDictate, Permission::ReportApprove, Permission::ReportDownload]), 403); - $report = StudyReport::with(['study', 'radiologist'])->where('accession_number', $uuid)->firstOrFail(); + ReportManager::ensureDownloadAccess(); + $report = StudyReport::with(['study_id', 'id'])->accession($uuid)->firstOrFail(); $title = 'View Report'; return view('staff.reports.viewer.html-report', compact('report', 'title')); diff --git a/app/Models/Study.php b/app/Models/Study.php index 80b9c4e..de8b8de 100644 --- a/app/Models/Study.php +++ b/app/Models/Study.php @@ -338,14 +338,17 @@ public function isUnlocked(): bool return $this->locked_at === null; } - public function lockStudy(User|int|null $user = null): void + public function lockStudy(User|int|null $user = null, ?StudyLevelStatus $status = null): void { - $this->update( - [ - 'locking_physician_id' => me($user)->id, - 'locked_at' => now(), - ] - ); + $params = [ + 'locking_physician_id' => me($user)->id, + 'locked_at' => now(), + ]; + if ($status) { + $params['study_status'] = $status->value; + } + + $this->update($params); } public function unlockStudy(): void diff --git a/app/Models/StudyReport.php b/app/Models/StudyReport.php index 2a9c003..066dbec 100644 --- a/app/Models/StudyReport.php +++ b/app/Models/StudyReport.php @@ -29,6 +29,13 @@ public function approver(): BelongsTo return $this->belongsTo(User::class, 'approved_by_id'); } + public function scopeAccession(Builder $query, string $uuid): Builder + { + $query->wherewhere('accession_number', $uuid); + + return $query; + } + public function scopeForStudy(Builder $query, Study|int $study): Builder { $query->where('study_id', $study instanceof Study ? $study->id : $study); diff --git a/app/Services/Pacs/Sync/Pipes/FilterStudies.php b/app/Services/Pacs/Sync/Pipes/FilterStudies.php index 33f3330..8fb1aa6 100644 --- a/app/Services/Pacs/Sync/Pipes/FilterStudies.php +++ b/app/Services/Pacs/Sync/Pipes/FilterStudies.php @@ -41,7 +41,7 @@ private function checkUpdate(string $orthanc_uuid, StudiesSync $sync, Collection return; } - if ($study_status < StudyLevelStatus::StudyArrived->value) { + if ($study_status < StudyLevelStatus::Unassigned->value) { $sync->getUpdateQueue()->add($orthanc_uuid); } } diff --git a/app/Services/Pacs/Sync/StudiesSync.php b/app/Services/Pacs/Sync/StudiesSync.php index bf0cc2a..ff2c408 100644 --- a/app/Services/Pacs/Sync/StudiesSync.php +++ b/app/Services/Pacs/Sync/StudiesSync.php @@ -139,7 +139,7 @@ public function transformData(mixed $orthanc_src): array ]; if ((bool) data_get($orthanc_src, 'IsStable', false)) { - $study['study_status'] = StudyLevelStatus::StudyArrived->value; + $study['study_status'] = StudyLevelStatus::Unassigned->value; } else { $study['study_status'] = StudyLevelStatus::Pending->value; } diff --git a/app/Services/Report/ReportManager.php b/app/Services/Report/ReportManager.php index 59ad5ad..900e123 100644 --- a/app/Services/Report/ReportManager.php +++ b/app/Services/Report/ReportManager.php @@ -2,4 +2,128 @@ namespace App\Services\Report; -final class ReportManager {} +use App\Domain\ACL\Permission; +use App\Domain\Report\ReportStatus; +use App\Models\Study; +use App\Models\StudyReport; +use App\Services\AuditTrail\Activity; +use Illuminate\Contracts\View\View; +use Illuminate\Support\Collection; + +final class ReportManager +{ + public function __construct(private readonly Study $study) {} + + public static function make(int $study_id): static + { + return new self(Study::findOrFail($study_id)); + } + + public function getReports(): Collection + { + return $this->study->reports->sortByDesc('created_at'); + } + + public function createReport(string $content, ReportStatus $status): StudyReport + { + $report = StudyReport::make([ + 'study_id' => $this->study->id, + 'institute_id' => $this->study->institute_id, + 'facility_id' => $this->study->facility_id, + 'report_status' => $status->value, + 'read_by_id' => me()->id, + ]); + $report->saveContent($content); + $report->save(); + $report->refresh(); + + audit() + ->on($this->study) + ->did(Activity::Report_Save) + ->notes($report->accession_number) + ->log(); + + return $report; + } + + public function finalizeReport(StudyReport $report): void + { + $report->setStatus(ReportStatus::Finalized); + audit() + ->on($this->study) + ->did(Activity::Report_Finalize) + ->notes($report->accession_number) + ->log(); + + $this->study->setReportStatus(ReportStatus::Finalized); + + audit() + ->on($this->study) + ->did(Activity::Report_Finalize) + ->log(); + + $this->study->unlockStudy(); + audit() + ->on($this->study) + ->did(Activity::Study_Unlock) + ->log(); + } + + public function check(): ?View + { + if (! $this->study->canEditReport()) { + return view('content.pages.notice', [ + 'color' => 'warning', + 'title' => 'Read Completed', + 'heading' => 'Read Completed', + 'message' => 'The report has been finalized, and the study is now closed for any further modifications.', + ]); + } + + if (! $this->study->canObtainLock()) { + return view('content.pages.notice', [ + 'color' => 'danger', + 'title' => 'Study Locked', + 'heading' => 'Study Locked', + 'message' => 'Study is locked by another user.', + ]); + } + + return null; + } + + public function lockStudyIfRequired(): void + { + if ($this->study->isUnlocked()) { + $this->study->lockStudy(); + audit() + ->on($this->study) + ->did(Activity::Study_Lock) + ->log(); + } + } + + public function latestReport(): ?StudyReport + { + return StudyReport::forStudy($this->study) + ->where('report_status', ReportStatus::Preliminary->value) + ->select(['id', 'accession_number', 'file_path']) + ->latest() + ->first(); + } + + public function getStudy(): Study + { + return $this->study; + } + + public static function ensureDownloadAccess(): void + { + abort_unless(me()->may([Permission::ReportEdit, Permission::ReportDictate, Permission::ReportApprove, Permission::ReportDownload]), 403); + } + + public static function ensureEditAccess(): void + { + abort_unless(me()->may([Permission::ReportEdit, Permission::ReportDictate, Permission::ReportApprove]), 403); + } +} diff --git a/resources/views/staff/reports/close-window.blade.php b/resources/views/content/pages/close-window.blade.php similarity index 100% rename from resources/views/staff/reports/close-window.blade.php rename to resources/views/content/pages/close-window.blade.php diff --git a/resources/views/content/pages/notice.blade.php b/resources/views/content/pages/notice.blade.php index 71afa01..d71b1d8 100644 --- a/resources/views/content/pages/notice.blade.php +++ b/resources/views/content/pages/notice.blade.php @@ -3,16 +3,16 @@ + {{ $title }}