Compare commits
16 Commits
e9ada6f2b3
...
72b1bbc0e7
Author | SHA1 | Date | |
---|---|---|---|
72b1bbc0e7 | |||
27c3cd5d8d | |||
7f5e916d80 | |||
8853528b0a | |||
3d5cceb125 | |||
db97aef03c | |||
ba705bb98b | |||
9e2315b89b | |||
bdf1ad1ca3 | |||
5292865bef | |||
d1d6f0d7af | |||
3f2a38faa6 | |||
ef170b5357 | |||
b32ebecfaa | |||
15d8ebf3c7 | |||
6bffd31f2f |
@ -1,4 +1,5 @@
|
|||||||
APP_NAME=Laravel
|
APP_NAME="PixelBridge"
|
||||||
|
APP_VERSION="25.1/a"
|
||||||
APP_ENV=local
|
APP_ENV=local
|
||||||
APP_KEY=
|
APP_KEY=
|
||||||
APP_DEBUG=true
|
APP_DEBUG=true
|
||||||
|
@ -2,12 +2,13 @@
|
|||||||
|
|
||||||
namespace App\DAL;
|
namespace App\DAL;
|
||||||
|
|
||||||
|
use App\Domain\ACL\Role;
|
||||||
use App\Services\UserService;
|
use App\Services\UserService;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
final readonly class Radiologists
|
final readonly class Radiologists
|
||||||
{
|
{
|
||||||
public static function worklist_stats(int $days, int $report_status)
|
public static function worklist_stats(int $days, int $workflow_level)
|
||||||
{
|
{
|
||||||
$sql = <<<'SQL'
|
$sql = <<<'SQL'
|
||||||
SELECT
|
SELECT
|
||||||
@ -28,12 +29,12 @@ public static function worklist_stats(int $days, int $report_status)
|
|||||||
WHERE
|
WHERE
|
||||||
--st.received_at :: DATE >= NOW() - INTERVAL '3 DAY'
|
--st.received_at :: DATE >= NOW() - INTERVAL '3 DAY'
|
||||||
st.received_at::DATE >= NOW() - INTERVAL '%d DAY'
|
st.received_at::DATE >= NOW() - INTERVAL '%d DAY'
|
||||||
AND st.report_status < %d
|
AND st.workflow_level < %d
|
||||||
AND st.read_at IS NULL
|
AND st.read_at IS NULL
|
||||||
GROUP BY
|
GROUP BY
|
||||||
sa.user_id) AS cte ON cte.user_id = users."id"
|
sa.user_id) AS cte ON cte.user_id = users."id"
|
||||||
WHERE
|
WHERE
|
||||||
roles."name" = 'radiologist'
|
roles."name" = '%s'
|
||||||
AND users.is_active = TRUE
|
AND users.is_active = TRUE
|
||||||
GROUP BY
|
GROUP BY
|
||||||
users."id",
|
users."id",
|
||||||
@ -42,7 +43,7 @@ public static function worklist_stats(int $days, int $report_status)
|
|||||||
users.display_name
|
users.display_name
|
||||||
SQL;
|
SQL;
|
||||||
|
|
||||||
$rows = DB::select(sprintf($sql, $days, $report_status));
|
$rows = DB::select(sprintf($sql, $days, $workflow_level, Role::Radiologist->value));
|
||||||
foreach ($rows as $row) {
|
foreach ($rows as $row) {
|
||||||
$row->last_seen = UserService::getLastSeen((int) $row->id);
|
$row->last_seen = UserService::getLastSeen((int) $row->id);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
namespace App\DAL\Studies;
|
namespace App\DAL\Studies;
|
||||||
|
|
||||||
use App\Domain\Report\ReportStatus;
|
|
||||||
use App\Domain\Study\WorkflowLevel;
|
use App\Domain\Study\WorkflowLevel;
|
||||||
use Illuminate\Contracts\Database\Eloquent\Builder;
|
use Illuminate\Contracts\Database\Eloquent\Builder;
|
||||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||||
@ -13,8 +12,6 @@ public function setRadiologist(int $radiologist_id): self;
|
|||||||
|
|
||||||
public function setWorkflowLevel(WorkflowLevel $status): self;
|
public function setWorkflowLevel(WorkflowLevel $status): self;
|
||||||
|
|
||||||
public function setReportStatus(ReportStatus $status): self;
|
|
||||||
|
|
||||||
public function setPerPage(int $size): self;
|
public function setPerPage(int $size): self;
|
||||||
|
|
||||||
public function setSortOrder(string $order): self;
|
public function setSortOrder(string $order): self;
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
namespace App\DAL\Studies;
|
namespace App\DAL\Studies;
|
||||||
|
|
||||||
use App\Domain\Report\ReportStatus;
|
|
||||||
use App\Domain\Study\WorkflowLevel;
|
use App\Domain\Study\WorkflowLevel;
|
||||||
use App\Models\Study;
|
use App\Models\Study;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
@ -21,8 +20,6 @@ abstract class WorklistBase implements IUserStudyLister
|
|||||||
|
|
||||||
private ?WorkflowLevel $workflowLevel = null;
|
private ?WorkflowLevel $workflowLevel = null;
|
||||||
|
|
||||||
private ?ReportStatus $reportStatus = null;
|
|
||||||
|
|
||||||
private ?bool $locked = null;
|
private ?bool $locked = null;
|
||||||
|
|
||||||
private ?bool $archived = null;
|
private ?bool $archived = null;
|
||||||
@ -41,7 +38,7 @@ abstract class WorklistBase implements IUserStudyLister
|
|||||||
|
|
||||||
protected static function reportCompleteQuery(Builder $query): Builder
|
protected static function reportCompleteQuery(Builder $query): Builder
|
||||||
{
|
{
|
||||||
return $query->where('report_status', '=', ReportStatus::Approved->value);
|
return $query->where('workflow_level', '=', WorkflowLevel::Published->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setRadiologist(int $radiologist_id): self
|
public function setRadiologist(int $radiologist_id): self
|
||||||
@ -58,13 +55,6 @@ public function setWorkflowLevel(WorkflowLevel $status): self
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setReportStatus(ReportStatus $status): self
|
|
||||||
{
|
|
||||||
$this->reportStatus = $status;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function query(?int $user_id = null): Builder
|
public function query(?int $user_id = null): Builder
|
||||||
{
|
{
|
||||||
$query = $this->buildQuery($user_id);
|
$query = $this->buildQuery($user_id);
|
||||||
@ -236,15 +226,6 @@ private function applyWorkflowLevel(Builder $query): Builder
|
|||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function applyReportStatus(Builder $query): Builder
|
|
||||||
{
|
|
||||||
if ($this->reportStatus != null) {
|
|
||||||
$query = $query->where('report_status', '=', $this->reportStatus->value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $query;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getPageSize(?int $user_id = null): int
|
private function getPageSize(?int $user_id = null): int
|
||||||
{
|
{
|
||||||
return $this->perPage ?? user_per_page($user_id);
|
return $this->perPage ?? user_per_page($user_id);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
namespace App\DataTables;
|
namespace App\DataTables;
|
||||||
|
|
||||||
use App\DAL\Studies\WorklistFactory;
|
use App\DAL\Studies\WorklistFactory;
|
||||||
use App\Domain\Report\ReportStatus;
|
use App\Domain\Study\WorkflowLevel;
|
||||||
use App\Models\Study;
|
use App\Models\Study;
|
||||||
use App\Services\ACL\WorklistButton;
|
use App\Services\ACL\WorklistButton;
|
||||||
use App\Services\ACL\WorklistColumn;
|
use App\Services\ACL\WorklistColumn;
|
||||||
@ -47,7 +47,7 @@ public function dataTable(QueryBuilder $query): EloquentDataTable
|
|||||||
$dataTable = new EloquentDataTable($query);
|
$dataTable = new EloquentDataTable($query);
|
||||||
$rawColumns = [
|
$rawColumns = [
|
||||||
'priority_icon',
|
'priority_icon',
|
||||||
'report_status_led',
|
'workflow_level_led',
|
||||||
];
|
];
|
||||||
foreach ($this->renderCustomColumns() as $column => $content) {
|
foreach ($this->renderCustomColumns() as $column => $content) {
|
||||||
$dataTable->addColumn($column, $content);
|
$dataTable->addColumn($column, $content);
|
||||||
@ -148,11 +148,11 @@ public function getColumns(): array
|
|||||||
->title('');
|
->title('');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WorklistColumn::ReportStatus:
|
case WorklistColumn::WorkflowLevel:
|
||||||
$columns[] = Column::make($col->value)
|
$columns[] = Column::make($col->value)
|
||||||
->searchable(false)
|
->searchable(false)
|
||||||
->hidden();
|
->hidden();
|
||||||
$columns[] = Column::make('report_status_led')
|
$columns[] = Column::make('workflow_level_led')
|
||||||
->searchable(false)
|
->searchable(false)
|
||||||
->orderable(false)
|
->orderable(false)
|
||||||
->addClass('text-center p-0 ps-2')
|
->addClass('text-center p-0 ps-2')
|
||||||
@ -330,10 +330,10 @@ private function filterStatus(QueryBuilder $query, ?string $status): void
|
|||||||
|
|
||||||
switch ($status) {
|
switch ($status) {
|
||||||
case 'unread':
|
case 'unread':
|
||||||
$query->where('report_status', '<', ReportStatus::Finalized->value);
|
$query->where('workflow_level', '<', WorkflowLevel::Finalized->value);
|
||||||
break;
|
break;
|
||||||
case 'read':
|
case 'read':
|
||||||
$query->where('report_status', '>=', ReportStatus::Finalized->value);
|
$query->where('workflow_level', '>=', WorkflowLevel::Finalized->value);
|
||||||
break;
|
break;
|
||||||
case 'progress':
|
case 'progress':
|
||||||
$query->whereNotNull('locked_at');
|
$query->whereNotNull('locked_at');
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Domain\Report;
|
|
||||||
|
|
||||||
enum ReportStatus: int
|
|
||||||
{
|
|
||||||
case Unread = 0;
|
|
||||||
case Dictated = 10;
|
|
||||||
case Transcribed = 20;
|
|
||||||
case Preliminary = 30;
|
|
||||||
case Finalized = 40;
|
|
||||||
case Approved = 90;
|
|
||||||
case Cancelled = 199;
|
|
||||||
}
|
|
@ -4,9 +4,36 @@
|
|||||||
|
|
||||||
enum WorkflowLevel: int
|
enum WorkflowLevel: int
|
||||||
{
|
{
|
||||||
case Pending = 0;
|
case Received = 10;
|
||||||
case Unassigned = 10;
|
case Unassigned = 20;
|
||||||
case Assigned = 20;
|
case Assigned = 30;
|
||||||
case ReadInProgress = 30;
|
case Dictated = 40;
|
||||||
case ReadCompleted = 40;
|
case Transcribed = 50;
|
||||||
|
case Repetition = 60;
|
||||||
|
case ReadInProgress = 70;
|
||||||
|
case DraftAvailable = 80;
|
||||||
|
case Finalized = 90;
|
||||||
|
case UnderReview = 100;
|
||||||
|
case Published = 110;
|
||||||
|
case Archived = 200;
|
||||||
|
case Cancelled = 240;
|
||||||
|
|
||||||
|
public function description(): string
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::Received => 'Study Received',
|
||||||
|
self::Unassigned => 'Unassigned',
|
||||||
|
self::Assigned => 'Assigned',
|
||||||
|
self::Dictated => 'Dictated',
|
||||||
|
self::Transcribed => 'Transcribed',
|
||||||
|
self::Repetition => 'Repetition',
|
||||||
|
self::ReadInProgress => 'Read In Progress',
|
||||||
|
self::DraftAvailable => 'Draft interpretation available',
|
||||||
|
self::Finalized => 'Repoort finalized',
|
||||||
|
self::UnderReview => 'Under Review',
|
||||||
|
self::Published => 'Report published',
|
||||||
|
self::Archived => 'Study archived',
|
||||||
|
self::Cancelled => 'Cancelled',
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
93
app/Filament/Resources/DepartmentResource.php
Normal file
93
app/Filament/Resources/DepartmentResource.php
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources;
|
||||||
|
|
||||||
|
use App\Filament\Resources\DepartmentResource\Pages;
|
||||||
|
use App\Models\Department;
|
||||||
|
use Filament\Forms\Components\Select;
|
||||||
|
use Filament\Forms\Components\TextInput;
|
||||||
|
use Filament\Forms\Components\Toggle;
|
||||||
|
use Filament\Forms\Form;
|
||||||
|
use Filament\Resources\Resource;
|
||||||
|
use Filament\Tables;
|
||||||
|
use Filament\Tables\Columns\IconColumn;
|
||||||
|
use Filament\Tables\Columns\TextColumn;
|
||||||
|
use Filament\Tables\Table;
|
||||||
|
use Ramsey\Uuid\Uuid;
|
||||||
|
|
||||||
|
class DepartmentResource extends Resource
|
||||||
|
{
|
||||||
|
protected static ?string $model = Department::class;
|
||||||
|
|
||||||
|
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
|
||||||
|
|
||||||
|
public static function form(Form $form): Form
|
||||||
|
{
|
||||||
|
return $form
|
||||||
|
->schema([
|
||||||
|
TextInput::make('guid')
|
||||||
|
->required()
|
||||||
|
->maxLength(40)
|
||||||
|
->default(sprintf('FAC-%s', Uuid::uuid4())),
|
||||||
|
Toggle::make('is_active')
|
||||||
|
->required(),
|
||||||
|
Select::make('organization_id')
|
||||||
|
->relationship('organization', 'name')
|
||||||
|
->required(),
|
||||||
|
TextInput::make('name')
|
||||||
|
->required()
|
||||||
|
->maxLength(255),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function table(Table $table): Table
|
||||||
|
{
|
||||||
|
return $table
|
||||||
|
->columns([
|
||||||
|
TextColumn::make('guid')
|
||||||
|
->searchable(),
|
||||||
|
IconColumn::make('is_active')
|
||||||
|
->boolean(),
|
||||||
|
TextColumn::make('organization.name')
|
||||||
|
->numeric()
|
||||||
|
->sortable(),
|
||||||
|
TextColumn::make('name')
|
||||||
|
->searchable(),
|
||||||
|
TextColumn::make('created_at')
|
||||||
|
->dateTime()
|
||||||
|
->sortable()
|
||||||
|
->toggleable(isToggledHiddenByDefault: true),
|
||||||
|
TextColumn::make('updated_at')
|
||||||
|
->dateTime()
|
||||||
|
->sortable()
|
||||||
|
->toggleable(isToggledHiddenByDefault: true),
|
||||||
|
])
|
||||||
|
->filters([
|
||||||
|
//
|
||||||
|
])
|
||||||
|
->actions([
|
||||||
|
Tables\Actions\EditAction::make(),
|
||||||
|
])
|
||||||
|
->bulkActions([
|
||||||
|
Tables\Actions\BulkActionGroup::make([
|
||||||
|
Tables\Actions\DeleteBulkAction::make(),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getRelations(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
//
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getPages(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'index' => Pages\ListDepartments::route('/'),
|
||||||
|
'create' => Pages\CreateDepartment::route('/create'),
|
||||||
|
'edit' => Pages\EditDepartment::route('/{record}/edit'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\DepartmentResource\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Resources\DepartmentResource;
|
||||||
|
use Filament\Resources\Pages\CreateRecord;
|
||||||
|
|
||||||
|
class CreateDepartment extends CreateRecord
|
||||||
|
{
|
||||||
|
protected static string $resource = DepartmentResource::class;
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\DepartmentResource\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Resources\DepartmentResource;
|
||||||
|
use Filament\Actions;
|
||||||
|
use Filament\Resources\Pages\EditRecord;
|
||||||
|
|
||||||
|
class EditDepartment extends EditRecord
|
||||||
|
{
|
||||||
|
protected static string $resource = DepartmentResource::class;
|
||||||
|
|
||||||
|
protected function getHeaderActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
Actions\DeleteAction::make(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\DepartmentResource\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Resources\DepartmentResource;
|
||||||
|
use Filament\Actions;
|
||||||
|
use Filament\Resources\Pages\ListRecords;
|
||||||
|
|
||||||
|
class ListDepartments extends ListRecords
|
||||||
|
{
|
||||||
|
protected static string $resource = DepartmentResource::class;
|
||||||
|
|
||||||
|
protected function getHeaderActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
Actions\CreateAction::make(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
96
app/Filament/Resources/OrganizationResource.php
Normal file
96
app/Filament/Resources/OrganizationResource.php
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources;
|
||||||
|
|
||||||
|
use App\Filament\Resources\OrganizationResource\Pages;
|
||||||
|
use App\Models\Organization;
|
||||||
|
use Filament\Forms\Components\TextInput;
|
||||||
|
use Filament\Forms\Components\Toggle;
|
||||||
|
use Filament\Forms\Form;
|
||||||
|
use Filament\Resources\Resource;
|
||||||
|
use Filament\Tables\Actions\BulkActionGroup;
|
||||||
|
use Filament\Tables\Actions\DeleteBulkAction;
|
||||||
|
use Filament\Tables\Actions\EditAction;
|
||||||
|
use Filament\Tables\Columns\IconColumn;
|
||||||
|
use Filament\Tables\Columns\TextColumn;
|
||||||
|
use Filament\Tables\Table;
|
||||||
|
use Ramsey\Uuid\Uuid;
|
||||||
|
|
||||||
|
class OrganizationResource extends Resource
|
||||||
|
{
|
||||||
|
protected static ?string $model = Organization::class;
|
||||||
|
|
||||||
|
protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';
|
||||||
|
|
||||||
|
public static function form(Form $form): Form
|
||||||
|
{
|
||||||
|
return $form
|
||||||
|
->schema([
|
||||||
|
TextInput::make('guid')
|
||||||
|
->required()
|
||||||
|
->maxLength(40)
|
||||||
|
->default(sprintf('INS-%s', Uuid::uuid4())),
|
||||||
|
TextInput::make('name')
|
||||||
|
->required()
|
||||||
|
->maxLength(255),
|
||||||
|
Toggle::make('is_active')
|
||||||
|
->required(),
|
||||||
|
TextInput::make('address')
|
||||||
|
->maxLength(255),
|
||||||
|
TextInput::make('logo_path')
|
||||||
|
->maxLength(255),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function table(Table $table): Table
|
||||||
|
{
|
||||||
|
return $table
|
||||||
|
->columns([
|
||||||
|
TextColumn::make('guid')
|
||||||
|
->searchable(),
|
||||||
|
TextColumn::make('name')
|
||||||
|
->searchable(),
|
||||||
|
IconColumn::make('is_active')
|
||||||
|
->boolean(),
|
||||||
|
TextColumn::make('address')
|
||||||
|
->searchable(),
|
||||||
|
TextColumn::make('logo_path')
|
||||||
|
->searchable(),
|
||||||
|
TextColumn::make('created_at')
|
||||||
|
->dateTime()
|
||||||
|
->sortable()
|
||||||
|
->toggleable(isToggledHiddenByDefault: true),
|
||||||
|
TextColumn::make('updated_at')
|
||||||
|
->dateTime()
|
||||||
|
->sortable()
|
||||||
|
->toggleable(isToggledHiddenByDefault: true),
|
||||||
|
])
|
||||||
|
->filters([
|
||||||
|
//
|
||||||
|
])
|
||||||
|
->actions([
|
||||||
|
EditAction::make(),
|
||||||
|
])
|
||||||
|
->bulkActions([
|
||||||
|
BulkActionGroup::make([
|
||||||
|
DeleteBulkAction::make(),
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getRelations(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
//
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getPages(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'index' => Pages\ListOrganizations::route('/'),
|
||||||
|
'create' => Pages\CreateOrganization::route('/create'),
|
||||||
|
'edit' => Pages\EditOrganization::route('/{record}/edit'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\OrganizationResource\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Resources\OrganizationResource;
|
||||||
|
use Filament\Resources\Pages\CreateRecord;
|
||||||
|
|
||||||
|
class CreateOrganization extends CreateRecord
|
||||||
|
{
|
||||||
|
protected static string $resource = OrganizationResource::class;
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\OrganizationResource\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Resources\OrganizationResource;
|
||||||
|
use Filament\Actions;
|
||||||
|
use Filament\Resources\Pages\EditRecord;
|
||||||
|
|
||||||
|
class EditOrganization extends EditRecord
|
||||||
|
{
|
||||||
|
protected static string $resource = OrganizationResource::class;
|
||||||
|
|
||||||
|
protected function getHeaderActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
Actions\DeleteAction::make(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\Resources\OrganizationResource\Pages;
|
||||||
|
|
||||||
|
use App\Filament\Resources\OrganizationResource;
|
||||||
|
use Filament\Actions;
|
||||||
|
use Filament\Resources\Pages\ListRecords;
|
||||||
|
|
||||||
|
class ListOrganizations extends ListRecords
|
||||||
|
{
|
||||||
|
protected static string $resource = OrganizationResource::class;
|
||||||
|
|
||||||
|
protected function getHeaderActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
Actions\CreateAction::make(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@
|
|||||||
use App\DAL\Radiologists;
|
use App\DAL\Radiologists;
|
||||||
use App\Domain\ACL\Permission;
|
use App\Domain\ACL\Permission;
|
||||||
use App\Domain\ACL\Role;
|
use App\Domain\ACL\Role;
|
||||||
use App\Domain\Report\ReportStatus;
|
use App\Domain\Study\WorkflowLevel;
|
||||||
use App\Http\Controllers\HashedStudyControllerBase;
|
use App\Http\Controllers\HashedStudyControllerBase;
|
||||||
use App\Http\Requests\AssignPhysicianRequest;
|
use App\Http\Requests\AssignPhysicianRequest;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
@ -22,7 +22,7 @@ public function show()
|
|||||||
->get(['id', 'display_name', 'profile_photo_path', 'first_name', 'last_name', 'created_at'])
|
->get(['id', 'display_name', 'profile_photo_path', 'first_name', 'last_name', 'created_at'])
|
||||||
->each(fn ($rad) => $rad->info = ['workload' => '', 'last_seen' => '']);
|
->each(fn ($rad) => $rad->info = ['workload' => '', 'last_seen' => '']);
|
||||||
|
|
||||||
$stats = Radiologists::worklist_stats(3, ReportStatus::Finalized->value);
|
$stats = Radiologists::worklist_stats(3, WorkflowLevel::Finalized->value);
|
||||||
foreach ($stats as $rad) {
|
foreach ($stats as $rad) {
|
||||||
$found = $rads->where('id', $rad->id)->first();
|
$found = $rads->where('id', $rad->id)->first();
|
||||||
if ($found) {
|
if ($found) {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
namespace App\Http\Controllers\Staff;
|
namespace App\Http\Controllers\Staff;
|
||||||
|
|
||||||
use App\Domain\ACL\Permission;
|
use App\Domain\ACL\Permission;
|
||||||
use App\Domain\Report\ReportStatus;
|
use App\Domain\Study\WorkflowLevel;
|
||||||
use App\Http\Controllers\HashedStudyControllerBase;
|
use App\Http\Controllers\HashedStudyControllerBase;
|
||||||
use App\Http\Requests\StudyMetadataUpdateRequest;
|
use App\Http\Requests\StudyMetadataUpdateRequest;
|
||||||
use App\Models\Study;
|
use App\Models\Study;
|
||||||
@ -32,7 +32,7 @@ public function edit()
|
|||||||
|
|
||||||
public function save(StudyMetadataUpdateRequest $request)
|
public function save(StudyMetadataUpdateRequest $request)
|
||||||
{
|
{
|
||||||
abort_unless(auth()->user()->may(Permission::StudyMetadataEdit), 403);
|
abort_unless(may(Permission::StudyMetadataEdit), 403);
|
||||||
$study = $this->getStudy();
|
$study = $this->getStudy();
|
||||||
if ($study->isReportReady()) {
|
if ($study->isReportReady()) {
|
||||||
return $this->lockedNotice();
|
return $this->lockedNotice();
|
||||||
@ -43,7 +43,7 @@ public function save(StudyMetadataUpdateRequest $request)
|
|||||||
$payload['patient_sex'] = strtoupper($payload['patient_sex']);
|
$payload['patient_sex'] = strtoupper($payload['patient_sex']);
|
||||||
if ($request->has('cancel_read')) {
|
if ($request->has('cancel_read')) {
|
||||||
// lock the study if report is not needed
|
// lock the study if report is not needed
|
||||||
$payload['report_status'] = ReportStatus::Cancelled->value;
|
$payload['workflow_level'] = WorkflowLevel::Cancelled->value;
|
||||||
$payload['locked_at'] = now();
|
$payload['locked_at'] = now();
|
||||||
unset($payload['cancel_read']);
|
unset($payload['cancel_read']);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Staff;
|
namespace App\Http\Controllers\Staff;
|
||||||
|
|
||||||
use App\Domain\Report\ReportStatus;
|
use App\Domain\Study\WorkflowLevel;
|
||||||
use App\Http\Controllers\HashidControllerBase;
|
use App\Http\Controllers\HashidControllerBase;
|
||||||
use App\Http\Requests\StoreReportRequest;
|
use App\Http\Requests\StoreReportRequest;
|
||||||
use App\Models\Study;
|
use App\Models\Study;
|
||||||
@ -39,10 +39,10 @@ public function save(StoreReportRequest $request)
|
|||||||
ReportManager::ensureEditAccess();
|
ReportManager::ensureEditAccess();
|
||||||
$this->decodeKeys();
|
$this->decodeKeys();
|
||||||
$manager = ReportManager::make($this->key);
|
$manager = ReportManager::make($this->key);
|
||||||
$reportStatus = ReportStatus::from($request->integer('report_status'));
|
$workflow_level = WorkflowLevel::from($request->integer('report_status'));
|
||||||
$report = $manager->createReport(request('content'), $reportStatus);
|
$report = $manager->createReport(request('content'), $workflow_level);
|
||||||
|
|
||||||
if ($reportStatus->value === ReportStatus::Finalized->value) {
|
if ($workflow_level->value === WorkflowLevel::Finalized->value) {
|
||||||
$manager->finalizeReport($report);
|
$manager->finalizeReport($report);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Requests;
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
use App\Domain\Report\ReportStatus;
|
use App\Domain\Study\WorkflowLevel;
|
||||||
use App\Models\Study;
|
use App\Models\Study;
|
||||||
use App\Rules\ExistsByHash;
|
use App\Rules\ExistsByHash;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
@ -22,7 +22,7 @@ public function rules(): array
|
|||||||
'content' => 'required',
|
'content' => 'required',
|
||||||
'report_status' => [
|
'report_status' => [
|
||||||
'required',
|
'required',
|
||||||
Rule::enum(ReportStatus::class)->only([ReportStatus::Preliminary, ReportStatus::Finalized, ReportStatus::Approved]),
|
Rule::enum(WorkflowLevel::class)->only([WorkflowLevel::DraftAvailable, WorkflowLevel::Finalized, WorkflowLevel::Published]),
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -175,22 +175,23 @@ public function isArchived(): bool
|
|||||||
return $this->archived_at !== null;
|
return $this->archived_at !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getReportStatusLedAttribute(): string
|
public function getWorkflowLevelLedAttribute(): string
|
||||||
{
|
{
|
||||||
$color = match ($this->report_status) {
|
// todo: implement
|
||||||
ReportStatus::Unread => 'bg-white',
|
$color = match ($this->workflow_level) {
|
||||||
|
WorkflowLevel::Unassigned => 'bg-white',
|
||||||
// ReportStatus::Opened => 'bg-secondary',
|
// ReportStatus::Opened => 'bg-secondary',
|
||||||
ReportStatus::Preliminary => 'bg-info',
|
WorkflowLevel::DraftAvailable => 'bg-info',
|
||||||
ReportStatus::Finalized => 'bg-primary',
|
WorkflowLevel::Finalized => 'bg-primary',
|
||||||
ReportStatus::Approved => 'bg-success',
|
WorkflowLevel::Published => 'bg-success',
|
||||||
default => 'bg-light',
|
default => 'bg-light',
|
||||||
};
|
};
|
||||||
// <i class="fa-solid fa-spinner"></i>
|
// <i class="fa-solid fa-spinner"></i>
|
||||||
$icon = match ($this->report_status) {
|
$icon = match ($this->workflow_level) {
|
||||||
ReportStatus::Unread => 'spinner text-muted',
|
WorkflowLevel::Unassigned => 'spinner text-muted',
|
||||||
ReportStatus::Preliminary => 'pen-to-square',
|
WorkflowLevel::DraftAvailable => 'pen-to-square',
|
||||||
ReportStatus::Finalized => 'badge-check',
|
WorkflowLevel::Finalized => 'badge-check',
|
||||||
ReportStatus::Approved => 'shield-check',
|
WorkflowLevel::Published => 'shield-check',
|
||||||
default => 'spinner text-muted',
|
default => 'spinner text-muted',
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -315,7 +316,7 @@ public function toArray(): array
|
|||||||
'reader_name' => $this->readingPhysician?->display_name,
|
'reader_name' => $this->readingPhysician?->display_name,
|
||||||
// 'assigned_physician_name' => $this->assignedPhysician?->display_name,
|
// 'assigned_physician_name' => $this->assignedPhysician?->display_name,
|
||||||
'reader_photo' => $this->readingPhysician?->profile_photo_url,
|
'reader_photo' => $this->readingPhysician?->profile_photo_url,
|
||||||
'report_status_led' => $this->getReportStatusLedAttribute(),
|
'workflow_level_led' => $this->getWorkflowLevelLedAttribute(),
|
||||||
'priority_icon' => $this->getPriorityIcon(),
|
'priority_icon' => $this->getPriorityIcon(),
|
||||||
'sex_age' => $this->sexAge(),
|
'sex_age' => $this->sexAge(),
|
||||||
'num_instances' => $this->numInstances(),
|
'num_instances' => $this->numInstances(),
|
||||||
@ -456,18 +457,18 @@ public function canObtainLock(User|int|null $user = null): bool
|
|||||||
return $this->isUnlocked() || $this->isLockedBy($user);
|
return $this->isUnlocked() || $this->isLockedBy($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setReportStatus(ReportStatus $status, User|int|null $user = null): void
|
public function setReportWorkflowLevel(WorkflowLevel $level, User|int|null $user = null): void
|
||||||
{
|
{
|
||||||
$user_id = me($user)->id;
|
$user_id = me($user)->id;
|
||||||
$params = ['report_status' => $status->value];
|
$params = ['workflow_level' => $level->value];
|
||||||
|
|
||||||
switch ($status) {
|
switch ($level) {
|
||||||
case ReportStatus::Finalized:
|
case WorkflowLevel::Finalized:
|
||||||
$params['reading_physician_id'] = $user_id;
|
$params['reading_physician_id'] = $user_id;
|
||||||
$params['read_at'] = now();
|
$params['read_at'] = now();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ReportStatus::Approved:
|
case WorkflowLevel::Published:
|
||||||
if ($this->reading_physician_id === null) {
|
if ($this->reading_physician_id === null) {
|
||||||
$params['reading_physician_id'] = $user_id;
|
$params['reading_physician_id'] = $user_id;
|
||||||
$params['read_at'] = now();
|
$params['read_at'] = now();
|
||||||
@ -483,18 +484,18 @@ public function setReportStatus(ReportStatus $status, User|int|null $user = null
|
|||||||
public function canEditReport(): bool
|
public function canEditReport(): bool
|
||||||
{
|
{
|
||||||
// todo: check if the study disallows reporting
|
// todo: check if the study disallows reporting
|
||||||
return $this->isActive() && $this->reportStatusBefore(ReportStatus::Finalized);
|
return $this->isActive() && $this->reportStatusBefore(WorkflowLevel::Finalized);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function reportStatusBefore(ReportStatus $checkpoint): bool
|
public function reportStatusBefore(WorkflowLevel $checkpoint): bool
|
||||||
{
|
{
|
||||||
return $this->report_status->value < $checkpoint->value;
|
return $this->workflow_level->value < $checkpoint->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canEditMetadata(): bool
|
public function canEditMetadata(): bool
|
||||||
{
|
{
|
||||||
return $this->isActive() && $this->reportStatusBefore(ReportStatus::Finalized);
|
return $this->isActive() && $this->reportStatusBefore(WorkflowLevel::Finalized);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canAssignRad(): bool
|
public function canAssignRad(): bool
|
||||||
@ -503,7 +504,7 @@ public function canAssignRad(): bool
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->isActive() && $this->reportStatusBefore(ReportStatus::Preliminary);
|
return $this->isActive() && $this->reportStatusBefore(WorkflowLevel::DraftAvailable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasReports(): bool
|
public function hasReports(): bool
|
||||||
@ -513,13 +514,13 @@ public function hasReports(): bool
|
|||||||
|
|
||||||
public function isReportReady(): bool
|
public function isReportReady(): bool
|
||||||
{
|
{
|
||||||
return ($this->report_status->value == ReportStatus::Finalized->value) ||
|
return ($this->workflow_level->value == WorkflowLevel::Finalized->value) ||
|
||||||
($this->report_status->value == ReportStatus::Approved->value);
|
($this->workflow_level->value == WorkflowLevel::Published->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isStudyComplete(): bool
|
public function isStudyComplete(): bool
|
||||||
{
|
{
|
||||||
return $this->report_status->value >= ReportStatus::Finalized->value;
|
return $this->workflow_level->value >= WorkflowLevel::Finalized->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function bookmarkedByUsers()
|
public function bookmarkedByUsers()
|
||||||
@ -531,7 +532,6 @@ protected function casts(): array
|
|||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'workflow_level' => WorkflowLevel::class,
|
'workflow_level' => WorkflowLevel::class,
|
||||||
'report_status' => ReportStatus::class,
|
|
||||||
'priority' => Priority::class,
|
'priority' => Priority::class,
|
||||||
'archived_at' => 'immutable_datetime',
|
'archived_at' => 'immutable_datetime',
|
||||||
'approved_at' => 'immutable_datetime',
|
'approved_at' => 'immutable_datetime',
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Domain\Report\ExportFormat;
|
use App\Domain\Report\ExportFormat;
|
||||||
use App\Domain\Report\ReportStatus;
|
use App\Domain\Study\WorkflowLevel;
|
||||||
use App\Services\Report\ReportStorage;
|
use App\Services\Report\ReportStorage;
|
||||||
use Illuminate\Database\Eloquent\Builder;
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
use Illuminate\Database\Eloquent\Concerns\HasTimestamps;
|
use Illuminate\Database\Eloquent\Concerns\HasTimestamps;
|
||||||
@ -43,19 +43,19 @@ public function scopeForStudy(Builder $query, Study|int $study): Builder
|
|||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setStatus(ReportStatus $status, User|int|null $user = null): void
|
public function setWorkflowLevel(WorkflowLevel $level, User|int|null $user = null): void
|
||||||
{
|
{
|
||||||
$user_id = me($user)->id;
|
$user_id = me($user)->id;
|
||||||
$params = ['report_status' => $status->value];
|
$params = ['workflow_level' => $level->value];
|
||||||
switch ($status) {
|
switch ($level) {
|
||||||
case ReportStatus::Dictated:
|
case WorkflowLevel::Dictated:
|
||||||
$params['dictated_by_id'] = $user_id;
|
$params['dictated_by_id'] = $user_id;
|
||||||
break;
|
break;
|
||||||
case ReportStatus::Preliminary:
|
case WorkflowLevel::DraftAvailable:
|
||||||
case ReportStatus::Finalized:
|
case WorkflowLevel::Finalized:
|
||||||
$params['read_by_id'] = $user_id;
|
$params['read_by_id'] = $user_id;
|
||||||
break;
|
break;
|
||||||
case ReportStatus::Approved:
|
case WorkflowLevel::Published:
|
||||||
$params['approved_by_id'] = $user_id;
|
$params['approved_by_id'] = $user_id;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -96,12 +96,12 @@ public function getContent(): ?string
|
|||||||
|
|
||||||
public function eligibleForExport(): bool
|
public function eligibleForExport(): bool
|
||||||
{
|
{
|
||||||
return $this->report_status->value >= ReportStatus::Finalized->value;
|
return $this->workflow_level->value >= WorkflowLevel::Finalized->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canRemove(User|int|null $user = null): bool
|
public function canRemove(User|int|null $user = null): bool
|
||||||
{
|
{
|
||||||
if ($this->report_status->value < ReportStatus::Finalized->value) {
|
if ($this->workflow_level->value < WorkflowLevel::Finalized->value) {
|
||||||
if ($this->read_by_id === me($user)->id) {
|
if ($this->read_by_id === me($user)->id) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -117,7 +117,7 @@ public function canRemove(User|int|null $user = null): bool
|
|||||||
|
|
||||||
public function canEdit(User|int|null $user = null): bool
|
public function canEdit(User|int|null $user = null): bool
|
||||||
{
|
{
|
||||||
if ($this->report_status->value < ReportStatus::Finalized->value &&
|
if ($this->workflow_level->value < WorkflowLevel::Finalized->value &&
|
||||||
$this->study->canEditReport() &&
|
$this->study->canEditReport() &&
|
||||||
$this->read_by_id === me($user)->id) {
|
$this->read_by_id === me($user)->id) {
|
||||||
return true;
|
return true;
|
||||||
@ -128,7 +128,7 @@ public function canEdit(User|int|null $user = null): bool
|
|||||||
|
|
||||||
public function isFinalized(): bool
|
public function isFinalized(): bool
|
||||||
{
|
{
|
||||||
return $this->report_status->value >= ReportStatus::Finalized->value;
|
return $this->workflow_level->value >= WorkflowLevel::Finalized->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -137,7 +137,7 @@ public function isFinalized(): bool
|
|||||||
protected function casts(): array
|
protected function casts(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'report_status' => ReportStatus::class,
|
'workflow_level' => WorkflowLevel::class,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ class User extends Authenticatable implements FilamentUser
|
|||||||
use HasProfilePhoto;
|
use HasProfilePhoto;
|
||||||
use HasRoles;
|
use HasRoles;
|
||||||
use Notifiable;
|
use Notifiable;
|
||||||
use TwoFactorAuthenticatable;
|
// use TwoFactorAuthenticatable;
|
||||||
|
|
||||||
public array $info = [];
|
public array $info = [];
|
||||||
|
|
||||||
|
@ -9,13 +9,6 @@ final class RoleService
|
|||||||
{
|
{
|
||||||
private static array $roles = [];
|
private static array $roles = [];
|
||||||
|
|
||||||
private static function initCache(): void
|
|
||||||
{
|
|
||||||
if (empty(self::$roles)) {
|
|
||||||
self::$roles = SpatieRole::pluck('id', 'name')->toArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function select(): array
|
public static function select(): array
|
||||||
{
|
{
|
||||||
// self::initCache();
|
// self::initCache();
|
||||||
@ -25,4 +18,11 @@ public static function select(): array
|
|||||||
->mapWithKeys(fn (Role $r) => [$r->value => $r->name])
|
->mapWithKeys(fn (Role $r) => [$r->value => $r->name])
|
||||||
->toArray();
|
->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function initCache(): void
|
||||||
|
{
|
||||||
|
if (empty(self::$roles)) {
|
||||||
|
self::$roles = SpatieRole::pluck('id', 'name')->toArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
enum WorklistColumn: string
|
enum WorklistColumn: string
|
||||||
{
|
{
|
||||||
case WorkflowLevel = 'workflow_level';
|
case WorkflowLevel = 'workflow_level';
|
||||||
case ReportStatus = 'report_status';
|
|
||||||
case StudyHash = 'hash';
|
case StudyHash = 'hash';
|
||||||
case PatientName = 'patient_name';
|
case PatientName = 'patient_name';
|
||||||
case PatientId = 'patient_id';
|
case PatientId = 'patient_id';
|
||||||
|
@ -14,7 +14,7 @@ public static function worklistColumns(User|int|null $usr = null): Collection
|
|||||||
$user = me($usr);
|
$user = me($usr);
|
||||||
$columns = collect([
|
$columns = collect([
|
||||||
WorklistColumn::Priority,
|
WorklistColumn::Priority,
|
||||||
WorklistColumn::ReportStatus,
|
WorklistColumn::WorkflowLevel,
|
||||||
WorklistColumn::ActionButtons,
|
WorklistColumn::ActionButtons,
|
||||||
// WorklistColumn::AssignedPhysician,
|
// WorklistColumn::AssignedPhysician,
|
||||||
WorklistColumn::PatientId,
|
WorklistColumn::PatientId,
|
||||||
|
@ -180,7 +180,7 @@ public function transformData(mixed $orthanc_src): array
|
|||||||
|
|
||||||
$study['workflow_level'] = $stable_study
|
$study['workflow_level'] = $stable_study
|
||||||
? WorkflowLevel::Unassigned->value
|
? WorkflowLevel::Unassigned->value
|
||||||
: WorkflowLevel::Pending->value;
|
: WorkflowLevel::Received->value;
|
||||||
$study['patient_birthdate'] = null;
|
$study['patient_birthdate'] = null;
|
||||||
$dob = data_get($orthanc_src, 'PatientMainDicomTags.PatientBirthDate');
|
$dob = data_get($orthanc_src, 'PatientMainDicomTags.PatientBirthDate');
|
||||||
if (filled($dob)) {
|
if (filled($dob)) {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
namespace App\Services\Report;
|
namespace App\Services\Report;
|
||||||
|
|
||||||
use App\Domain\ACL\Permission;
|
use App\Domain\ACL\Permission;
|
||||||
use App\Domain\Report\ReportStatus;
|
use App\Domain\Study\WorkflowLevel;
|
||||||
use App\Models\Study;
|
use App\Models\Study;
|
||||||
use App\Models\StudyReport;
|
use App\Models\StudyReport;
|
||||||
use App\Services\AuditTrail\Activity;
|
use App\Services\AuditTrail\Activity;
|
||||||
@ -41,13 +41,13 @@ public function getReports(): Collection
|
|||||||
return $this->study->reports->sortByDesc('created_at');
|
return $this->study->reports->sortByDesc('created_at');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createReport(string $content, ReportStatus $status): StudyReport
|
public function createReport(string $content, WorkflowLevel $level): StudyReport
|
||||||
{
|
{
|
||||||
$report = StudyReport::make([
|
$report = StudyReport::make([
|
||||||
'study_id' => $this->study->id,
|
'study_id' => $this->study->id,
|
||||||
'organization_id' => $this->study->organization_id,
|
'organization_id' => $this->study->organization_id,
|
||||||
'department_id' => $this->study->department_id,
|
'department_id' => $this->study->department_id,
|
||||||
'report_status' => $status->value,
|
'workflow_level' => $level->value,
|
||||||
'read_by_id' => me()->id,
|
'read_by_id' => me()->id,
|
||||||
]);
|
]);
|
||||||
$report->saveContent($content);
|
$report->saveContent($content);
|
||||||
@ -65,14 +65,14 @@ public function createReport(string $content, ReportStatus $status): StudyReport
|
|||||||
|
|
||||||
public function finalizeReport(StudyReport $report): void
|
public function finalizeReport(StudyReport $report): void
|
||||||
{
|
{
|
||||||
$report->setStatus(ReportStatus::Finalized);
|
$report->setWorkflowLevel(WorkflowLevel::Finalized);
|
||||||
audit()
|
audit()
|
||||||
->on($this->study)
|
->on($this->study)
|
||||||
->did(Activity::Report_Finalize)
|
->did(Activity::Report_Finalize)
|
||||||
->notes($report->accession_number)
|
->notes($report->accession_number)
|
||||||
->log();
|
->log();
|
||||||
|
|
||||||
$this->study->setReportStatus(ReportStatus::Finalized);
|
$this->study->setReportWorkflowLevel(WorkflowLevel::Finalized);
|
||||||
|
|
||||||
audit()
|
audit()
|
||||||
->on($this->study)
|
->on($this->study)
|
||||||
@ -123,7 +123,7 @@ public function lockStudyIfRequired(): void
|
|||||||
public function latestReport(): ?StudyReport
|
public function latestReport(): ?StudyReport
|
||||||
{
|
{
|
||||||
return StudyReport::forStudy($this->study)
|
return StudyReport::forStudy($this->study)
|
||||||
->where('report_status', ReportStatus::Preliminary->value)
|
->where('workflow_level', WorkflowLevel::DraftAvailable->value)
|
||||||
->select(['id', 'accession_number', 'file_path'])
|
->select(['id', 'accession_number', 'file_path'])
|
||||||
->latest()
|
->latest()
|
||||||
->first();
|
->first();
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
namespace App\Services\Workflow;
|
namespace App\Services\Workflow;
|
||||||
|
|
||||||
use App\Domain\ACL\Permission;
|
use App\Domain\ACL\Permission;
|
||||||
use App\Domain\Report\ReportStatus;
|
use App\Domain\Study\WorkflowLevel;
|
||||||
use App\Models\Study;
|
use App\Models\Study;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Closure;
|
use Closure;
|
||||||
@ -42,28 +42,28 @@ public function can(Permission $permission): bool
|
|||||||
|
|
||||||
public function canAssignPhysician(): bool
|
public function canAssignPhysician(): bool
|
||||||
{
|
{
|
||||||
return $this->activeStudy(fn () => $this->study->report_status <= ReportStatus::Preliminary);
|
return $this->activeStudy(fn () => $this->study->workflow_level <= WorkflowLevel::DraftAvailable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canStudyHistoryEdit(): bool
|
public function canStudyHistoryEdit(): bool
|
||||||
{
|
{
|
||||||
return $this->activeStudy(fn () => $this->study->report_status <= ReportStatus::Preliminary);
|
return $this->activeStudy(fn () => $this->study->workflow_level <= WorkflowLevel::DraftAvailable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canAttachmentUpload(): bool
|
public function canAttachmentUpload(): bool
|
||||||
{
|
{
|
||||||
return $this->activeStudy(fn () => $this->study->report_status <= ReportStatus::Preliminary);
|
return $this->activeStudy(fn () => $this->study->workflow_level <= WorkflowLevel::DraftAvailable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canReportDownload(): bool
|
public function canReportDownload(): bool
|
||||||
{
|
{
|
||||||
return $this->activeStudy(fn () => $this->study->report_status >= ReportStatus::Finalized);
|
return $this->activeStudy(fn () => $this->study->workflow_level >= WorkflowLevel::Finalized);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function canReportEdit(): bool
|
public function canReportEdit(): bool
|
||||||
{
|
{
|
||||||
return $this->activeStudy(fn () => $this->study->isUnlocked() &&
|
return $this->activeStudy(fn () => $this->study->isUnlocked() &&
|
||||||
$this->study->report_status <= ReportStatus::Preliminary &&
|
$this->study->workflow_level <= WorkflowLevel::DraftAvailable &&
|
||||||
$this->study->isAssignedTo($this->user)
|
$this->study->isAssignedTo($this->user)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,9 @@
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'name' => env('APP_NAME', 'Laravel'),
|
'name' => env('APP_NAME', 'PixelBridge'),
|
||||||
|
|
||||||
|
'version' => env('APP_VERSION', '0.1.0'),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use App\Domain\Report\ReportStatus;
|
|
||||||
use App\Domain\Study\Priority;
|
use App\Domain\Study\Priority;
|
||||||
use App\Domain\Study\WorkflowLevel;
|
use App\Domain\Study\WorkflowLevel;
|
||||||
use App\Models\Department;
|
use App\Models\Department;
|
||||||
@ -21,8 +20,7 @@ public function up(): void
|
|||||||
$table->foreignIdFor(Department::class)->nullable()->index();
|
$table->foreignIdFor(Department::class)->nullable()->index();
|
||||||
|
|
||||||
$table->unsignedTinyInteger('priority')->default(Priority::Routine->value);
|
$table->unsignedTinyInteger('priority')->default(Priority::Routine->value);
|
||||||
$table->unsignedTinyInteger('workflow_level')->default(WorkflowLevel::Pending->value);
|
$table->unsignedTinyInteger('workflow_level')->default(WorkflowLevel::Received->value);
|
||||||
$table->unsignedTinyInteger('report_status')->default(ReportStatus::Unread->value);
|
|
||||||
$table->boolean('requires_approval')->default(false);
|
$table->boolean('requires_approval')->default(false);
|
||||||
|
|
||||||
$table->string('orthanc_uuid')->index();
|
$table->string('orthanc_uuid')->index();
|
||||||
@ -73,7 +71,7 @@ public function up(): void
|
|||||||
$table->index(['department_id', 'assigned_at']);
|
$table->index(['department_id', 'assigned_at']);
|
||||||
$table->index(['department_id', 'locked_at']);
|
$table->index(['department_id', 'locked_at']);
|
||||||
|
|
||||||
$table->index(['requires_approval', 'report_status']);
|
$table->index(['requires_approval', 'workflow_level']);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use App\Domain\Report\ReportStatus;
|
use App\Domain\Study\WorkflowLevel;
|
||||||
use App\Models\Department;
|
use App\Models\Department;
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
use App\Models\Study;
|
use App\Models\Study;
|
||||||
@ -15,7 +15,7 @@ public function up(): void
|
|||||||
{
|
{
|
||||||
Schema::create('study_reports', function (Blueprint $table) {
|
Schema::create('study_reports', function (Blueprint $table) {
|
||||||
$table->id();
|
$table->id();
|
||||||
$table->unsignedTinyInteger('report_status')->default(ReportStatus::Unread->value);
|
$table->unsignedTinyInteger('workflow_level')->default(WorkflowLevel::Received->value);
|
||||||
$table->string('accession_number', 64)->unique()->index()->default(DB::raw("concat('REP-', gen_random_uuid())"));
|
$table->string('accession_number', 64)->unique()->index()->default(DB::raw("concat('REP-', gen_random_uuid())"));
|
||||||
|
|
||||||
$table->foreignIdFor(Organization::class)->index()->nullable()->constrained()->nullOnDelete();
|
$table->foreignIdFor(Organization::class)->index()->nullable()->constrained()->nullOnDelete();
|
||||||
|
@ -15,9 +15,9 @@ public function run(): void
|
|||||||
// User::factory(10)->create();
|
// User::factory(10)->create();
|
||||||
|
|
||||||
$usr = User::factory()->create([
|
$usr = User::factory()->create([
|
||||||
'first_name' => 'PACS Sync',
|
'first_name' => 'PACS Agent',
|
||||||
'display_name' => 'PACS Sync Agent',
|
'display_name' => 'PACS Agent',
|
||||||
'username' => '$$_pacs_sync_$$',
|
'username' => '$$_pacs_agent_$$',
|
||||||
'password' => bcrypt(fake()->password(20)),
|
'password' => bcrypt(fake()->password(20)),
|
||||||
'is_active' => false,
|
'is_active' => false,
|
||||||
]);
|
]);
|
||||||
@ -30,6 +30,7 @@ public function run(): void
|
|||||||
'email' => 'admin@example.com',
|
'email' => 'admin@example.com',
|
||||||
'email_verified_at' => now(),
|
'email_verified_at' => now(),
|
||||||
'phone' => '+8801733938582',
|
'phone' => '+8801733938582',
|
||||||
|
'is_active' => true,
|
||||||
]);
|
]);
|
||||||
$usr->assignRole(Role::Admin);
|
$usr->assignRole(Role::Admin);
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<div class="{{ $containerFooter }}">
|
<div class="{{ $containerFooter }}">
|
||||||
<div class="footer-container d-flex align-items-center justify-content-between py-4 flex-md-row flex-column">
|
<div class="footer-container d-flex align-items-center justify-content-between py-4 flex-md-row flex-column">
|
||||||
<div class="text-body mb-2 mb-md-0 fw-light">
|
<div class="text-body mb-2 mb-md-0 fw-light">
|
||||||
© 2024-<script>document.write(new Date().getFullYear())</script> {{ config('app.name') }}. All rights reserved.
|
© 2024-<script>document.write(new Date().getFullYear())</script> {{ config('app.name') }} v{{ config('app.version') }}. All rights reserved.
|
||||||
</div>
|
</div>
|
||||||
<div class="text-body d-none d-lg-inline-block">
|
<div class="text-body d-none d-lg-inline-block">
|
||||||
Made with <span class="text-danger"><i class="tf-icons ri-heart-fill"></i></span> by
|
Made with <span class="text-danger"><i class="tf-icons ri-heart-fill"></i></span> by
|
||||||
|
@ -52,7 +52,7 @@ class="ck-editor editor-container editor-container_classic-editor fixed-containe
|
|||||||
<div class="form-check form-check-success custom-option custom-option-basic">
|
<div class="form-check form-check-success custom-option custom-option-basic">
|
||||||
<label class="form-check-label custom-option-content" for="radio_prelim">
|
<label class="form-check-label custom-option-content" for="radio_prelim">
|
||||||
<input name="report_status" class="form-check-input" type="radio"
|
<input name="report_status" class="form-check-input" type="radio"
|
||||||
value="{{ \App\Domain\Report\ReportStatus::Preliminary->value }}"
|
value="{{ \App\Domain\Study\WorkflowLevel::DraftAvailable->value }}"
|
||||||
id="radio_prelim" checked/>
|
id="radio_prelim" checked/>
|
||||||
|
|
||||||
<span class="custom-option-body">
|
<span class="custom-option-body">
|
||||||
@ -68,7 +68,7 @@ class="ck-editor editor-container editor-container_classic-editor fixed-containe
|
|||||||
<div class="form-check form-check-success custom-option custom-option-basic">
|
<div class="form-check form-check-success custom-option custom-option-basic">
|
||||||
<label class="form-check-label custom-option-content" for="radio_final">
|
<label class="form-check-label custom-option-content" for="radio_final">
|
||||||
<input name="report_status" class="form-check-input" type="radio"
|
<input name="report_status" class="form-check-input" type="radio"
|
||||||
value="{{ \App\Domain\Report\ReportStatus::Finalized->value }}"
|
value="{{ \App\Domain\Study\WorkflowLevel::Finalized->value }}"
|
||||||
id="radio_final"/>
|
id="radio_final"/>
|
||||||
|
|
||||||
<span class="custom-option-body">
|
<span class="custom-option-body">
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<td class="bg-gray-100">{{ $report->created_at }}</td>
|
<td class="bg-gray-100">{{ $report->created_at }}</td>
|
||||||
<td>
|
<td>
|
||||||
<a target="_blank" href="{{ $report->viewUrl() }}">
|
<a target="_blank" href="{{ $report->viewUrl() }}">
|
||||||
{{ $report->report_status->name }}
|
{{ $report->workflow_level->name }}
|
||||||
<i class="fa-regular fa-square-arrow-up-right ms-1"></i>
|
<i class="fa-regular fa-square-arrow-up-right ms-1"></i>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
Loading…
Reference in New Issue
Block a user