fix(treatment): open the treatment case when confirming from the panel

confirmWithPayments — the path behind POST /appointment/{uuid}/confirm, which
is how a secretary actually confirms — created the patient session but never
called TreatmentCaseStarter. Only onConfirmed did. So an appointment on a
service with an active protocol was confirmed and paid, and no treatment case
or sessions were ever created; the staff panel had nothing to list.

Every existing test in OpenCaseOnConfirmTest drove onConfirmed, which is why
the gap survived. Added one that drives confirmWithPayments; it fails without
the fix.

Also adds app:treatment:backfill-cases, mirroring
app:appointment:backfill-sessions: it reports confirmed appointments on a
protocol service that have no case, and with --fix replays the starter and
prints the exception the logger would otherwise keep to itself.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
hamed
2026-08-07 12:24:29 +03:30
co-authored by Claude Opus 5
parent b437390e06
commit a331aab2b8
4 changed files with 193 additions and 2 deletions
+31 -2
View File
@@ -29,7 +29,7 @@ class OpenCaseOnConfirmTest extends ApiTestCase
return static::getContainer()->get(AppointmentConfirmationService::class);
}
private function scenario(bool $withProtocol, ?string $domainCode = 'beauty'): array
private function scenario(bool $withProtocol, ?string $domainCode = 'beauty', bool $confirm = true): array
{
$doctor = new Doctor($this->createUser(['ROLE_DOCTOR']), 'دکتر آزمون');
$this->em->persist($doctor);
@@ -82,7 +82,9 @@ class OpenCaseOnConfirmTest extends ApiTestCase
$clinic,
);
$appointment->addServiceItem($service);
$appointment->transitionTo(Appointment::STATUS_CONFIRMED);
if ($confirm) {
$appointment->transitionTo(Appointment::STATUS_CONFIRMED);
}
$this->em->persist($appointment);
$this->em->flush();
@@ -111,6 +113,33 @@ class OpenCaseOnConfirmTest extends ApiTestCase
));
}
/**
* مسیر واقعیِ منشی: قطعی‌کردن از پنل با مودال پرداخت.
*
* این مسیر جدا از onConfirmed است و مدتی پروندهٔ درمان را نمی‌ساخت — نوبت قطعی
* می‌شد، پول ثبت می‌شد، و پنل پرسنل خالی می‌ماند چون هیچ جلسه‌ای وجود نداشت.
*/
public function testConfirmingFromThePanelWithPaymentsOpensACase(): void
{
[$appointment, $service] = $this->scenario(withProtocol: true, confirm: false);
$this->confirmation()->confirmWithPayments(
$appointment,
$appointment->getVersion(),
[['method' => 'cash', 'amount_rials' => 5_000_000]],
$this->createUser(['ROLE_CLINIC']),
);
$cases = $this->casesFor($service);
self::assertCount(1, $cases);
self::assertCount(3, $cases[0]->getSessions());
$sessions = $cases[0]->getSessions()->toArray();
usort($sessions, static fn (TreatmentSession $a, TreatmentSession $b): int
=> $a->getSessionNumber() <=> $b->getSessionNumber());
self::assertSame($appointment->getId(), $sessions[0]->getAppointment()?->getId());
}
/** سرویس بدون پروتکل همان نوبت تک‌جلسه‌ای است — نباید پرونده‌ای ساخته شود. */
public function testConfirmingAPlainServiceOpensNoCase(): void
{