Files
2026-09-16 23:20:08 +07:00

68 lines
2.2 KiB
PHP

<?php
namespace App\Services;
use App\Models\Therapist;
/**
* Class WorkloadBalancer
* Enterprise Workload Calculation & Load Balancing Service
*
* @package App\Services
*/
class WorkloadBalancer
{
private Therapist $therapistModel;
public function __construct()
{
$this->therapistModel = new Therapist();
}
/**
* Update workload score for a therapist after queue completion or assignment
*
* Score Formula: (total_minutes_today / max_daily_minutes) * 10.0 + (in_progress_count * 2.0)
*/
public function updateScore(int $therapistId): float
{
$therapist = $this->therapistModel->find($therapistId);
if (!$therapist) return 0.00;
$maxMins = (int)($therapist['max_daily_minutes'] ?? 480);
if ($maxMins <= 0) $maxMins = 480;
// Query today's queues for this therapist
$db = \App\Models\Model::getDB();
$stmt = $db->prepare("SELECT
COALESCE(SUM(CASE WHEN status = 'Completed' THEN COALESCE(service_time_mins, 60) ELSE 0 END), 0) as completed_mins,
SUM(CASE WHEN status IN ('Assigned', 'In_Progress') THEN 1 ELSE 0 END) as active_queues
FROM `queues`
WHERE therapist_id = :tid AND queue_date = CURDATE()");
$stmt->execute(['tid' => $therapistId]);
$row = $stmt->fetch();
$completedMins = (float)($row['completed_mins'] ?? 0);
$activeCount = (float)($row['active_queues'] ?? 0);
// คำนวณคะแนนภาระงาน ยิ่งคะแนนต่ำยิ่งว่างและมีโอกาสได้รับคิวต่อไป
$score = round(($completedMins / $maxMins) * 10.0 + ($activeCount * 2.5), 2);
// อัปเดตลงตาราง
$this->therapistModel->update($therapistId, [
'current_workload_score' => $score,
'is_available' => ($activeCount == 0 && $completedMins < $maxMins) ? 1 : 0,
]);
return $score;
}
/**
* Reset all workload scores (Called by midnight event or manually)
*/
public function resetAll(): void
{
$db = \App\Models\Model::getDB();
$db->exec("CALL sp_reset_daily_workloads()");
}
}