feat: implement per-doctor insurance settings in multi-doctor clinics

- Updated InsuranceModal to include doctorUuid in the payload for insurance contracts.
- Enhanced TenantInsuranceContracts to allow selection of doctors and pass doctorUuid in API requests.
- Modified InsuranceController to handle doctorUuid for tenant insurance endpoints, ensuring contracts are stored per doctor.
- Updated API documentation to reflect the new optional doctor_uuid parameter for tenant insurance endpoints.
- Added tests to verify the functionality of per-doctor insurance contracts and ensure isolation of contracts between doctors.
This commit is contained in:
hamed
2026-07-21 19:21:55 +03:30
parent 7e847b62c4
commit 5507b42fd8
6 changed files with 478 additions and 25 deletions
@@ -368,9 +368,12 @@ class InsuranceController extends BaseController
#[Route('/api/v1/billing/tenant-insurances', methods: ['GET'])]
#[IsGranted('IS_AUTHENTICATED_FULLY')]
public function listTenantInsurances(#[CurrentUser] User $user): JsonResponse
public function listTenantInsurances(Request $request, #[CurrentUser] User $user): JsonResponse
{
[$entityType, $entityId] = $this->resolveEntity($user);
[$entityType, $entityId, $err] = $this->resolveTargetEntity($user, $request->query->get('doctor_uuid'), 'view');
if ($err !== null) {
return $err;
}
if ($entityId === null) {
return $this->error(ErrorCodes::ERR_FORBIDDEN_001, 'پروفایل یافت نشد', 403);
}
@@ -397,12 +400,16 @@ class InsuranceController extends BaseController
#[IsGranted('IS_AUTHENTICATED_FULLY')]
public function activateTenantInsurance(Request $request, #[CurrentUser] User $user): JsonResponse
{
[$entityType, $entityId] = $this->resolveEntity($user);
$data = json_decode($request->getContent(), true) ?? [];
[$entityType, $entityId, $err] = $this->resolveTargetEntity($user, $data['doctor_uuid'] ?? null, 'update');
if ($err !== null) {
return $err;
}
if ($entityId === null) {
return $this->error(ErrorCodes::ERR_FORBIDDEN_001, 'پروفایل یافت نشد', 403);
}
$data = json_decode($request->getContent(), true) ?? [];
$insuranceId = isset($data['insurance_id']) ? (int) $data['insurance_id'] : 0;
if ($insuranceId <= 0) {
return $this->error(ErrorCodes::ERR_VALIDATION_001, 'insurance_id الزامی است', 422);
@@ -428,13 +435,18 @@ class InsuranceController extends BaseController
#[IsGranted('IS_AUTHENTICATED_FULLY')]
public function updateTenantInsurance(string $uuid, Request $request, #[CurrentUser] User $user): JsonResponse
{
[$entityType, $entityId] = $this->resolveEntity($user);
$data = json_decode($request->getContent(), true) ?? [];
[$entityType, $entityId, $err] = $this->resolveTargetEntity($user, $data['doctor_uuid'] ?? null, 'update');
if ($err !== null) {
return $err;
}
$contract = $this->tenantInsuranceRepo->findByUuid($uuid);
if ($contract === null || $contract->getEntityType() !== $entityType || $contract->getEntityId() !== $entityId) {
return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'قرارداد یافت نشد', 404);
}
$data = json_decode($request->getContent(), true) ?? [];
if (array_key_exists('coverage_percent', $data)) {
$contract->setCoveragePercent((float) $data['coverage_percent']);
}
@@ -466,9 +478,13 @@ class InsuranceController extends BaseController
#[Route('/api/v1/billing/tenant-insurances/{uuid}', methods: ['DELETE'])]
#[IsGranted('IS_AUTHENTICATED_FULLY')]
public function deactivateTenantInsurance(string $uuid, #[CurrentUser] User $user): JsonResponse
public function deactivateTenantInsurance(string $uuid, Request $request, #[CurrentUser] User $user): JsonResponse
{
[$entityType, $entityId] = $this->resolveEntity($user);
[$entityType, $entityId, $err] = $this->resolveTargetEntity($user, $request->query->get('doctor_uuid'), 'update');
if ($err !== null) {
return $err;
}
$contract = $this->tenantInsuranceRepo->findByUuid($uuid);
if ($contract === null || $contract->getEntityType() !== $entityType || $contract->getEntityId() !== $entityId) {
return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'قرارداد یافت نشد', 404);
@@ -481,9 +497,13 @@ class InsuranceController extends BaseController
#[Route('/api/v1/billing/tenant-insurances/{uuid}/service-coverage', methods: ['GET'])]
#[IsGranted('IS_AUTHENTICATED_FULLY')]
public function listServiceCoverage(string $uuid, #[CurrentUser] User $user): JsonResponse
public function listServiceCoverage(string $uuid, Request $request, #[CurrentUser] User $user): JsonResponse
{
[$entityType, $entityId] = $this->resolveEntity($user);
[$entityType, $entityId, $err] = $this->resolveTargetEntity($user, $request->query->get('doctor_uuid'), 'view');
if ($err !== null) {
return $err;
}
$contract = $this->tenantInsuranceRepo->findByUuid($uuid);
if ($contract === null || $contract->getEntityType() !== $entityType || $contract->getEntityId() !== $entityId) {
return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'قرارداد یافت نشد', 404);
@@ -509,14 +529,18 @@ class InsuranceController extends BaseController
#[IsGranted('IS_AUTHENTICATED_FULLY')]
public function setServiceCoverage(string $uuid, Request $request, #[CurrentUser] User $user): JsonResponse
{
[$entityType, $entityId] = $this->resolveEntity($user);
$data = json_decode($request->getContent(), true) ?? [];
[$entityType, $entityId, $err] = $this->resolveTargetEntity($user, $data['doctor_uuid'] ?? null, 'update');
if ($err !== null) {
return $err;
}
$contract = $this->tenantInsuranceRepo->findByUuid($uuid);
if ($contract === null || $contract->getEntityType() !== $entityType || $contract->getEntityId() !== $entityId) {
return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'قرارداد یافت نشد', 404);
}
$data = json_decode($request->getContent(), true) ?? [];
$serviceItem = isset($data['service_item_uuid'])
? $this->serviceItemRepo->findByUuid((string) $data['service_item_uuid'])
: (isset($data['service_item_id']) ? $this->serviceItemRepo->find((int) $data['service_item_id']) : null);