Skip to content

Commit cd0ddd8

Browse files
committed
Added data migration, ETL, and Controllers
1 parent 67d1080 commit cd0ddd8

24 files changed

Lines changed: 918 additions & 215 deletions

app/Http/Controllers/Api/ORCaseController.php

Lines changed: 159 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use App\Models\ORCase;
77
use Illuminate\Http\Request;
88
use Illuminate\Support\Facades\DB;
9+
use Illuminate\Support\Facades\Log;
910
use Illuminate\Support\Facades\Validator;
1011

1112
class ORCaseController extends Controller
@@ -16,9 +17,9 @@ protected function validateCase(Request $request)
1617
'patient_name' => 'required|string|max:255',
1718
'mrn' => 'required|string|max:50',
1819
'procedure_name' => 'required|string|max:255',
19-
'service_id' => 'required|exists:prod.services,service_id',
20-
'room_id' => 'required|exists:prod.rooms,room_id',
21-
'primary_surgeon_id' => 'required|exists:prod.providers,provider_id',
20+
'service_id' => 'required|exists:prod.service,service_id',
21+
'room_id' => 'required|exists:prod.room,room_id',
22+
'primary_surgeon_id' => 'required|exists:prod.provider,provider_id',
2223
'surgery_date' => 'required|date',
2324
'scheduled_start_time' => 'required|date_format:H:i',
2425
'estimated_duration' => 'required|integer|min:15',
@@ -61,140 +62,174 @@ public function update(Request $request, $id)
6162

6263
public function index(Request $request)
6364
{
64-
$query = DB::table('prod.or_cases')
65-
->join('prod.providers', 'or_cases.primary_surgeon_id', '=', 'providers.provider_id')
66-
->join('prod.rooms', 'or_cases.room_id', '=', 'rooms.room_id')
67-
->join('prod.services', 'or_cases.case_service_id', '=', 'services.service_id')
68-
->select(
69-
'or_cases.*',
70-
'providers.name as surgeon_name',
71-
'rooms.name as room_name',
72-
'services.name as service_name'
73-
)
74-
->where('or_cases.is_deleted', false);
75-
76-
// Apply filters
77-
if ($request->has('date')) {
78-
$query->where('or_cases.surgery_date', $request->date);
65+
try {
66+
$query = ORCase::with(['surgeon', 'room', 'service', 'status'])
67+
->where('is_deleted', false);
68+
69+
// Apply filters
70+
if ($request->has('date')) {
71+
$query->where('surgery_date', $request->date);
72+
}
73+
74+
if ($request->has('status') && $request->status !== '') {
75+
$query->where('status_id', $request->status);
76+
}
77+
78+
if ($request->has('service') && $request->service !== '') {
79+
$query->where('case_service_id', $request->service);
80+
}
81+
82+
if ($request->has('room') && $request->room !== '') {
83+
$query->where('room_id', $request->room);
84+
}
85+
86+
$cases = $query
87+
->orderBy('surgery_date', 'desc')
88+
->orderBy('scheduled_start_time', 'asc')
89+
->get();
90+
91+
return response()->json($cases);
92+
} catch (\Exception $e) {
93+
Log::error('Error in index: ' . $e->getMessage());
94+
Log::error($e->getTraceAsString());
95+
return response()->json([
96+
'error' => 'Internal server error',
97+
'message' => $e->getMessage(),
98+
'trace' => $e->getTraceAsString()
99+
], 500);
79100
}
80-
81-
if ($request->has('status') && $request->status !== '') {
82-
$query->where('or_cases.status', $request->status);
83-
}
84-
85-
if ($request->has('service') && $request->service !== '') {
86-
$query->where('or_cases.case_service_id', $request->service);
87-
}
88-
89-
if ($request->has('room') && $request->room !== '') {
90-
$query->where('or_cases.room_id', $request->room);
91-
}
92-
93-
$cases = $query
94-
->orderBy('or_cases.surgery_date', 'desc')
95-
->orderBy('or_cases.scheduled_start_time', 'asc')
96-
->get();
97-
98-
return response()->json($cases);
99101
}
100102

101103
public function todaysCases()
102104
{
103-
$cases = DB::table('prod.or_cases')
104-
->join('prod.providers', 'or_cases.primary_surgeon_id', '=', 'providers.provider_id')
105-
->join('prod.rooms', 'or_cases.room_id', '=', 'rooms.room_id')
106-
->join('prod.services', 'or_cases.case_service_id', '=', 'services.service_id')
107-
->select(
108-
'or_cases.*',
109-
'providers.name as surgeon_name',
110-
'rooms.name as room_name',
111-
'services.name as service_name'
112-
)
113-
->where('or_cases.surgery_date', now()->toDateString())
114-
->where('or_cases.is_deleted', false)
115-
->orderBy('or_cases.scheduled_start_time', 'asc')
116-
->get();
117-
118-
return response()->json($cases);
105+
try {
106+
Log::info('Fetching today\'s cases for date: ' . now()->toDateString());
107+
108+
$cases = ORCase::with(['surgeon', 'room', 'service', 'status'])
109+
->where('surgery_date', now()->toDateString())
110+
->where('is_deleted', false)
111+
->orderBy('scheduled_start_time', 'asc')
112+
->get();
113+
114+
Log::info('Found ' . $cases->count() . ' cases for today');
115+
return response()->json($cases);
116+
} catch (\Exception $e) {
117+
Log::error('Error in todaysCases: ' . $e->getMessage());
118+
Log::error($e->getTraceAsString());
119+
return response()->json([
120+
'error' => 'Internal server error',
121+
'message' => $e->getMessage(),
122+
'trace' => $e->getTraceAsString()
123+
], 500);
124+
}
119125
}
120126

121127
public function metrics()
122128
{
123-
$utilization = DB::table('prod.case_metrics')
124-
->join('prod.or_cases', 'case_metrics.case_id', '=', 'or_cases.case_id')
125-
->where('or_cases.surgery_date', '>=', now()->subDays(7)->toDateString())
126-
->select(
127-
'or_cases.surgery_date',
128-
DB::raw('AVG(utilization_percentage) as utilization'),
129-
DB::raw('AVG(turnover_time) as avg_turnover'),
130-
DB::raw('COUNT(*) as case_count')
131-
)
132-
->groupBy('or_cases.surgery_date')
133-
->orderBy('or_cases.surgery_date')
134-
->get();
135-
136-
return response()->json([
137-
'utilization' => $utilization,
138-
'summary' => [
139-
'avg_utilization' => $utilization->avg('utilization'),
140-
'avg_turnover' => $utilization->avg('avg_turnover'),
141-
'total_cases' => $utilization->sum('case_count')
142-
]
143-
]);
129+
try {
130+
Log::info('Fetching metrics for last 7 days');
131+
132+
$utilization = DB::table('prod.case_metrics')
133+
->join('prod.orcase', 'case_metrics.case_id', '=', 'orcase.case_id')
134+
->where('orcase.surgery_date', '>=', now()->subDays(7)->toDateString())
135+
->select(
136+
'orcase.surgery_date',
137+
DB::raw('AVG(utilization_percentage) as utilization'),
138+
DB::raw('AVG(turnover_time) as avg_turnover'),
139+
DB::raw('COUNT(*) as case_count')
140+
)
141+
->groupBy('orcase.surgery_date')
142+
->orderBy('orcase.surgery_date')
143+
->get();
144+
145+
Log::info('Found metrics for ' . $utilization->count() . ' days');
146+
return response()->json([
147+
'utilization' => $utilization,
148+
'summary' => [
149+
'avg_utilization' => $utilization->avg('utilization'),
150+
'avg_turnover' => $utilization->avg('avg_turnover'),
151+
'total_cases' => $utilization->sum('case_count')
152+
]
153+
]);
154+
} catch (\Exception $e) {
155+
Log::error('Error in metrics: ' . $e->getMessage());
156+
Log::error($e->getTraceAsString());
157+
return response()->json([
158+
'error' => 'Internal server error',
159+
'message' => $e->getMessage(),
160+
'trace' => $e->getTraceAsString()
161+
], 500);
162+
}
144163
}
145164

146165
public function roomStatus()
147166
{
148-
// Get all active rooms
149-
$rooms = DB::table('prod.rooms')
150-
->where('is_active', true)
151-
->orderBy('name')
152-
->get();
153-
154-
// Get current cases and logs
155-
$currentCases = DB::table('prod.or_cases as c')
156-
->join('prod.or_logs as l', 'c.case_id', '=', 'l.case_id')
157-
->join('prod.providers as p', 'c.primary_surgeon_id', '=', 'p.provider_id')
158-
->join('prod.services as s', 'c.case_service_id', '=', 's.service_id')
159-
->select(
160-
'c.room_id',
161-
'c.case_id',
162-
'c.procedure_name',
163-
'c.estimated_duration',
164-
'p.name as surgeon_name',
165-
's.name as service_name',
166-
'l.or_in_time',
167-
'l.or_out_time',
168-
DB::raw("
169-
CASE
170-
WHEN l.or_in_time IS NOT NULL AND l.or_out_time IS NULL THEN 'In Progress'
171-
WHEN l.or_out_time IS NOT NULL THEN 'Turnover'
172-
ELSE 'Available'
173-
END as status
174-
")
175-
)
176-
->where('c.surgery_date', now()->toDateString())
177-
->where('c.is_deleted', false)
178-
->get();
179-
180-
// Map room status
181-
$status = $rooms->map(function ($room) use ($currentCases) {
182-
$currentCase = $currentCases->firstWhere('room_id', $room->room_id);
167+
try {
168+
Log::info('Fetching room status');
183169

184-
return [
185-
'room_id' => $room->room_id,
186-
'room_name' => $room->name,
187-
'case_id' => $currentCase ? $currentCase->case_id : null,
188-
'procedure_name' => $currentCase ? $currentCase->procedure_name : null,
189-
'surgeon_name' => $currentCase ? $currentCase->surgeon_name : null,
190-
'service_name' => $currentCase ? $currentCase->service_name : null,
191-
'estimated_duration' => $currentCase ? $currentCase->estimated_duration : null,
192-
'or_in_time' => $currentCase ? $currentCase->or_in_time : null,
193-
'or_out_time' => $currentCase ? $currentCase->or_out_time : null,
194-
'status' => $currentCase ? $currentCase->status : 'Available'
195-
];
196-
});
197-
198-
return response()->json($status);
170+
// Get all active rooms
171+
$rooms = DB::table('prod.room')
172+
->where('active_status', true)
173+
->orderBy('name')
174+
->get();
175+
176+
Log::info('Found ' . $rooms->count() . ' active rooms');
177+
178+
// Get current cases and logs
179+
$currentCases = DB::table('prod.orcase as c')
180+
->join('prod.orlog as l', 'c.case_id', '=', 'l.case_id')
181+
->join('prod.provider as p', 'c.primary_surgeon_id', '=', 'p.provider_id')
182+
->join('prod.service as s', 'c.case_service_id', '=', 's.service_id')
183+
->select(
184+
'c.room_id',
185+
'c.case_id',
186+
'c.procedure_name',
187+
'c.scheduled_duration',
188+
'p.name as surgeon_name',
189+
's.name as service_name',
190+
'l.or_in_time',
191+
'l.or_out_time',
192+
DB::raw("
193+
CASE
194+
WHEN l.or_in_time IS NOT NULL AND l.or_out_time IS NULL THEN 'In Progress'
195+
WHEN l.or_out_time IS NOT NULL THEN 'Turnover'
196+
ELSE 'Available'
197+
END as status
198+
")
199+
)
200+
->where('c.surgery_date', now()->toDateString())
201+
->where('c.is_deleted', false)
202+
->get();
203+
204+
Log::info('Found ' . $currentCases->count() . ' current cases');
205+
206+
// Map room status
207+
$status = $rooms->map(function ($room) use ($currentCases) {
208+
$currentCase = $currentCases->firstWhere('room_id', $room->room_id);
209+
210+
return [
211+
'room_id' => $room->room_id,
212+
'room_name' => $room->name,
213+
'case_id' => $currentCase ? $currentCase->case_id : null,
214+
'procedure_name' => $currentCase ? $currentCase->procedure_name : null,
215+
'surgeon_name' => $currentCase ? $currentCase->surgeon_name : null,
216+
'service_name' => $currentCase ? $currentCase->service_name : null,
217+
'scheduled_duration' => $currentCase ? $currentCase->scheduled_duration : null,
218+
'or_in_time' => $currentCase ? $currentCase->or_in_time : null,
219+
'or_out_time' => $currentCase ? $currentCase->or_out_time : null,
220+
'status' => $currentCase ? $currentCase->status : 'Available'
221+
];
222+
});
223+
224+
return response()->json($status);
225+
} catch (\Exception $e) {
226+
Log::error('Error in roomStatus: ' . $e->getMessage());
227+
Log::error($e->getTraceAsString());
228+
return response()->json([
229+
'error' => 'Internal server error',
230+
'message' => $e->getMessage(),
231+
'trace' => $e->getTraceAsString()
232+
], 500);
233+
}
199234
}
200235
}

app/Models/ORCase.php

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,21 @@
22

33
namespace App\Models;
44

5+
use App\Models\Reference\ASARating;
6+
use App\Models\Reference\CancellationReason;
7+
use App\Models\Reference\CaseClass;
8+
use App\Models\Reference\CaseStatus;
9+
use App\Models\Reference\CaseType;
10+
use App\Models\Reference\PatientClass;
11+
use App\Models\Reference\Service;
512
use Illuminate\Database\Eloquent\Model;
613
use Illuminate\Database\Eloquent\Relations\BelongsTo;
714
use Illuminate\Database\Eloquent\Relations\HasOne;
815

916
class ORCase extends Model
1017
{
11-
protected $table = 'prod.or_cases';
18+
public $timestamps = false;
19+
protected $table = 'prod.orcase';
1220
protected $primaryKey = 'case_id';
1321

1422
protected $fillable = [
@@ -27,18 +35,25 @@ class ORCase extends Model
2735
'case_type_id',
2836
'case_class_id',
2937
'patient_class_id',
38+
'procedure_name',
3039
'created_by',
3140
'modified_by',
41+
'created_date',
42+
'modified_date',
3243
'is_deleted'
3344
];
3445

3546
protected $casts = [
3647
'surgery_date' => 'date',
3748
'scheduled_start_time' => 'datetime',
3849
'record_create_date' => 'datetime',
50+
'created_date' => 'datetime',
51+
'modified_date' => 'datetime',
3952
'is_deleted' => 'boolean'
4053
];
4154

55+
protected $with = ['surgeon', 'room', 'service', 'status'];
56+
4257
public function room(): BelongsTo
4358
{
4459
return $this->belongsTo(Room::class, 'room_id', 'room_id');
@@ -98,4 +113,18 @@ public function metrics(): HasOne
98113
{
99114
return $this->hasOne(CaseMetrics::class, 'case_id', 'case_id');
100115
}
116+
117+
protected static function boot()
118+
{
119+
parent::boot();
120+
121+
static::creating(function ($model) {
122+
$model->created_date = $model->freshTimestamp();
123+
$model->modified_date = $model->freshTimestamp();
124+
});
125+
126+
static::updating(function ($model) {
127+
$model->modified_date = $model->freshTimestamp();
128+
});
129+
}
101130
}

0 commit comments

Comments
 (0)