feat(secretary): implement scope separation for secretaries in clinics and personal practices
- Added `owner_type` and `clinic_id` fields to `DoctorSecretary` entity to distinguish between clinic and personal practice relationships. - Updated repository methods to be scope-aware, allowing for specific queries based on the context of the secretary's relationship (clinic or doctor). - Modified `SecretaryController` to handle secretary creation with appropriate scope based on the current user's role. - Enhanced `AuthController` to build contexts that reflect the scope of the secretary's access. - Updated `DashboardController` and `PatientController` to respect the new scope logic when retrieving data. - Created migration to update the database schema accordingly, dropping the old unique constraint and adding the new fields and constraints.
This commit is contained in:
@@ -3,10 +3,12 @@
|
||||
namespace App\Dashboard\Controller;
|
||||
|
||||
use App\Auth\Entity\User;
|
||||
use App\Auth\Repository\UserActiveContextRepository;
|
||||
use App\Clinic\Repository\ClinicRepository;
|
||||
use App\Doctor\Repository\DoctorRepository;
|
||||
use App\Patient\Repository\PatientRecordRepository;
|
||||
use App\Patient\Repository\PatientSessionRepository;
|
||||
use App\Secretary\Entity\DoctorSecretary;
|
||||
use App\Secretary\Repository\DoctorSecretaryRepository;
|
||||
use App\Shared\Constant\ErrorCodes;
|
||||
use App\Shared\Controller\BaseController;
|
||||
@@ -21,13 +23,14 @@ use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
class DashboardController extends BaseController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ClinicRepository $clinicRepo,
|
||||
private readonly DoctorRepository $doctorRepo,
|
||||
private readonly DoctorSecretaryRepository $secretaryRepo,
|
||||
private readonly EntityManagerInterface $em,
|
||||
private readonly SmsWalletService $smsWalletService,
|
||||
private readonly PatientRecordRepository $patientRecordRepo,
|
||||
private readonly PatientSessionRepository $patientSessionRepo,
|
||||
private readonly ClinicRepository $clinicRepo,
|
||||
private readonly DoctorRepository $doctorRepo,
|
||||
private readonly DoctorSecretaryRepository $secretaryRepo,
|
||||
private readonly EntityManagerInterface $em,
|
||||
private readonly SmsWalletService $smsWalletService,
|
||||
private readonly PatientRecordRepository $patientRecordRepo,
|
||||
private readonly PatientSessionRepository $patientSessionRepo,
|
||||
private readonly UserActiveContextRepository $contextRepo,
|
||||
) {}
|
||||
|
||||
// ── Clinic Dashboard ────────────────────────────────────────────────────
|
||||
@@ -250,11 +253,33 @@ class DashboardController extends BaseController
|
||||
#[IsGranted('ROLE_SECRETARY')]
|
||||
public function secretary(#[CurrentUser] User $user): JsonResponse
|
||||
{
|
||||
$rel = $this->secretaryRepo->findActiveBySecretary($user);
|
||||
if ($rel === null) {
|
||||
$activeCtx = $this->contextRepo->findByUser($user);
|
||||
$dbUuid = $activeCtx?->getDbUuid();
|
||||
|
||||
if ($dbUuid === null) {
|
||||
return $this->error(ErrorCodes::ERR_FORBIDDEN_001, 'دسترسی منشی تنظیم نشده', 403);
|
||||
}
|
||||
|
||||
// تعیین scope بر اساس db_uuid فعال
|
||||
$clinic = $this->clinicRepo->findByUuid($dbUuid);
|
||||
if ($clinic !== null) {
|
||||
return $this->secretaryClinicDashboard($user, $clinic);
|
||||
}
|
||||
|
||||
$doctor = $this->doctorRepo->findByUuid($dbUuid);
|
||||
if ($doctor !== null) {
|
||||
$rel = $this->secretaryRepo->findActiveBySecretaryForDoctor($user, $doctor);
|
||||
if ($rel === null) {
|
||||
return $this->error(ErrorCodes::ERR_FORBIDDEN_001, 'دسترسی منشی تنظیم نشده', 403);
|
||||
}
|
||||
return $this->secretaryDoctorDashboard($user, $rel);
|
||||
}
|
||||
|
||||
return $this->error(ErrorCodes::ERR_FORBIDDEN_001, 'context نامعتبر است', 403);
|
||||
}
|
||||
|
||||
private function secretaryDoctorDashboard(User $user, DoctorSecretary $rel): JsonResponse
|
||||
{
|
||||
$doctor = $rel->getDoctor();
|
||||
$permissions = $rel->getPermissions();
|
||||
$canView = (bool) ($permissions['resources']['appointments']['view'] ?? false);
|
||||
@@ -293,6 +318,7 @@ class DashboardController extends BaseController
|
||||
}
|
||||
|
||||
return $this->success([
|
||||
'scope' => 'doctor',
|
||||
'doctor' => [
|
||||
'uuid' => $doctor->getUuid(),
|
||||
'name' => $doctor->getName(),
|
||||
@@ -306,4 +332,71 @@ class DashboardController extends BaseController
|
||||
'today_appointments' => $todayAppts,
|
||||
]);
|
||||
}
|
||||
|
||||
private function secretaryClinicDashboard(User $user, \App\Clinic\Entity\Clinic $clinic): JsonResponse
|
||||
{
|
||||
$rel = $this->secretaryRepo->findActiveBySecretaryForClinic($user, $clinic);
|
||||
if ($rel === null) {
|
||||
return $this->error(ErrorCodes::ERR_FORBIDDEN_001, 'دسترسی منشی تنظیم نشده', 403);
|
||||
}
|
||||
|
||||
$permissions = $rel->getPermissions();
|
||||
$canView = (bool) ($permissions['resources']['appointments']['view'] ?? false);
|
||||
|
||||
$todayStart = strtotime('today midnight');
|
||||
$todayEnd = strtotime('tomorrow midnight') - 1;
|
||||
$tmrStart = strtotime('tomorrow midnight');
|
||||
$tmrEnd = strtotime('tomorrow midnight') + 86399;
|
||||
|
||||
$doctors = $this->secretaryRepo->findDoctorsBySecretaryInClinic($user, $clinic);
|
||||
|
||||
$todayCount = 0;
|
||||
$tmrCount = 0;
|
||||
$todayAppts = [];
|
||||
|
||||
if (!empty($doctors)) {
|
||||
$todayCount = (int) $this->em->createQuery('
|
||||
SELECT COUNT(a.id) FROM App\Appointment\Entity\Appointment a
|
||||
WHERE a.doctor IN (:doctors) AND a.slotStart >= :s AND a.slotStart <= :e
|
||||
')->setParameters(['doctors' => $doctors, 's' => $todayStart, 'e' => $todayEnd])
|
||||
->getSingleScalarResult();
|
||||
|
||||
$tmrCount = (int) $this->em->createQuery('
|
||||
SELECT COUNT(a.id) FROM App\Appointment\Entity\Appointment a
|
||||
WHERE a.doctor IN (:doctors) AND a.slotStart >= :s AND a.slotStart <= :e
|
||||
')->setParameters(['doctors' => $doctors, 's' => $tmrStart, 'e' => $tmrEnd])
|
||||
->getSingleScalarResult();
|
||||
|
||||
if ($canView) {
|
||||
$todayAppts = $this->em->createQuery('
|
||||
SELECT a.uuid, u.realName AS patient_name, u.mobileNumber AS patient_mobile,
|
||||
a.slotStart AS slot_start, a.status, d.name AS doctor_name
|
||||
FROM App\Appointment\Entity\Appointment a
|
||||
JOIN a.user u
|
||||
JOIN a.doctor d
|
||||
WHERE a.doctor IN (:doctors) AND a.slotStart >= :s AND a.slotStart <= :e
|
||||
ORDER BY a.slotStart ASC
|
||||
')->setMaxResults(20)->setParameters([
|
||||
'doctors' => $doctors,
|
||||
's' => $todayStart,
|
||||
'e' => $todayEnd,
|
||||
])->getArrayResult();
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success([
|
||||
'scope' => 'clinic',
|
||||
'clinic' => [
|
||||
'uuid' => $clinic->getUuid(),
|
||||
'name' => $clinic->getName(),
|
||||
],
|
||||
'permissions' => $permissions,
|
||||
'stats' => [
|
||||
'today_appointments' => $todayCount,
|
||||
'tomorrow_appointments' => $tmrCount,
|
||||
],
|
||||
'today_appointments' => $todayAppts,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user