fix(treatment): let the operator actually record an area
Starting a session created area records with no device, and the panel only ever read the device it never set — so every "اتمام این ناحیه" came back 422 with "دستگاه این ناحیه مشخص نیست". The backend tests passed because they sent resource_uuid explicitly; from the UI the flow was unusable end to end. The device now inherits from the appointment's resource, which the secretary already chose at booking; asking the operator again is taking one decision twice. The session screen offers a picker per area on top of that, because one session really does run bikini on an alexandrite and underarms on a diode. Treating without a device is allowed: botox is an injection, and requiring a device would make clinics invent a fake resource per injection. Sending readings with no device is still rejected — there would be no schema to validate against. A protocol whose service has no ResourceServiceOffering rows now says so in the tab where the manager is standing. It does not block booking: "no offering means any resource" is a deliberate, tested rule. But silence meant the gap surfaced only when the operator was already in front of a patient. Also adds the live timer the spec asked for, and wires slot-suggestions into the unbooked queue — the endpoint existed and tested green but no screen called it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -74,10 +74,23 @@ class SessionExecutionController extends BaseController
|
||||
{
|
||||
$session = $this->requireSession($user, $uuid);
|
||||
|
||||
[$entityType, $entityId] = $this->pair($user);
|
||||
$devices = $this->resources->findForPair($entityType, $entityId, ['active' => true]);
|
||||
|
||||
return $this->success($session->toArray(withAreas: true) + [
|
||||
'case' => $session->getTreatmentCase()->toArray(),
|
||||
// فرمِ هر ناحیه از نوع منبعش میآید؛ پنل نباید فیلدها را حدس بزند.
|
||||
'forms' => $this->formsFor($session),
|
||||
'case' => $session->getTreatmentCase()->toArray(),
|
||||
// دستگاههای قابل انتخاب — اپراتور باید بتواند دستگاهِ یک ناحیه را عوض کند،
|
||||
// مثل بیکینی با الکساندرایت و زیر بغل با دایود در همان جلسه.
|
||||
'devices' => array_map(
|
||||
static fn (ClinicResource $r): array => [
|
||||
'uuid' => $r->getUuid(),
|
||||
'name' => $r->getName(),
|
||||
'type' => $r->getType()->getCode(),
|
||||
],
|
||||
$devices,
|
||||
),
|
||||
// فرمِ هر دستگاه از نوعش میآید؛ پنل نباید فیلدها را حدس بزند.
|
||||
'forms' => $this->formsFor($devices),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -137,17 +150,16 @@ class SessionExecutionController extends BaseController
|
||||
return $this->success($this->executor->skipArea($this->requireAreaRecord($user, $uuid))->toArray());
|
||||
}
|
||||
|
||||
/** @return array<string, list<array<string, mixed>>> uuid منبع => تعریف فیلدها */
|
||||
private function formsFor(TreatmentSession $session): array
|
||||
/**
|
||||
* @param list<ClinicResource> $devices
|
||||
* @return array<string, list<array<string, mixed>>> uuid منبع => تعریف فیلدها
|
||||
*/
|
||||
private function formsFor(array $devices): array
|
||||
{
|
||||
$forms = [];
|
||||
|
||||
foreach ($session->getAreaRecords() as $record) {
|
||||
$resource = $record->getResource();
|
||||
|
||||
if ($resource !== null) {
|
||||
$forms[$resource->getUuid()] = $resource->getType()->getFieldSchema() ?? [];
|
||||
}
|
||||
foreach ($devices as $device) {
|
||||
$forms[$device->getUuid()] = $device->getType()->getFieldSchema() ?? [];
|
||||
}
|
||||
|
||||
return $forms;
|
||||
|
||||
@@ -9,6 +9,7 @@ use App\Doctor\Service\AddressResolver;
|
||||
use App\Shared\Constant\ErrorCodes;
|
||||
use App\Shared\Controller\BaseController;
|
||||
use App\Shared\Exception\AppException;
|
||||
use App\Resource\Repository\ResourceServiceOfferingRepository;
|
||||
use App\Treatment\Repository\TreatmentProtocolRepository;
|
||||
use App\Treatment\Service\TreatmentProtocolWriter;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
@@ -27,6 +28,7 @@ class TreatmentProtocolController extends BaseController
|
||||
private readonly TreatmentProtocolRepository $protocols,
|
||||
private readonly ServiceItemRepository $items,
|
||||
private readonly TreatmentProtocolWriter $writer,
|
||||
private readonly ResourceServiceOfferingRepository $offerings,
|
||||
private readonly AddressResolver $branches,
|
||||
private readonly EntityManagerInterface $em,
|
||||
) {}
|
||||
@@ -35,9 +37,21 @@ class TreatmentProtocolController extends BaseController
|
||||
#[Route('/api/v1/service-item/{uuid}/treatment-protocol', name: 'treatment_protocol_show', methods: ['GET'])]
|
||||
public function show(#[CurrentUser] User $user, string $uuid): JsonResponse
|
||||
{
|
||||
$protocol = $this->protocols->findForService($this->requireItem($user, $uuid));
|
||||
$service = $this->requireItem($user, $uuid);
|
||||
$protocol = $this->protocols->findForService($service);
|
||||
|
||||
return $this->success($protocol?->toArray());
|
||||
if ($protocol === null) {
|
||||
return $this->success(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* سرویسی که هیچ منبعی ارائهاش نمیدهد قفل نمیشود — قاعدهٔ «بدون offering
|
||||
* یعنی همه مجاز» عمدی و مستند است. ولی مدیر باید ببیند، وگرنه تازه وقتی
|
||||
* اپراتور جلوی بیمار میرسد معلوم میشود دستگاهی وصل نشده.
|
||||
*/
|
||||
return $this->success($protocol->toArray() + [
|
||||
'service_has_resources' => $this->offerings->hasAnyFor($service),
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route('/api/v1/service-item/{uuid}/treatment-protocol', name: 'treatment_protocol_replace', methods: ['PUT'])]
|
||||
|
||||
Reference in New Issue
Block a user