fix(clinic-invitation): provision doctor accounts and repair panel actions
The invitation flow never created an account for the invitee. accept() only looked up an existing doctor by mobile, so for a brand-new invitee it marked the invitation accepted and burned the token while leaving doctor_id NULL — no login, no clinic link, and every doctor-facing endpoint 404ing afterwards. - invite/accept now provision the users + doctors pair, claim the profile on accept, link it to the clinic, and SMS generated credentials when the user has no password. Existing passwords are never overwritten. - accept runs in one transaction so an invitation can no longer be marked accepted without its doctor profile and clinic link. - changeStatus accepts `pending`, refreshing the token and re-sending the SMS so reactivating a suspended invitation yields a link that actually works. Answered invitations are rejected with 409. - DELETE returns 200 with the standard envelope instead of a bodyless 204, which made the admin panel show a false error toast; api.ts also stops calling res.json() on empty responses. - The clinic-doctors settings page sent the active context uuid as the clinic uuid, so users holding both a doctor and a clinic context got 404 on every invitation action. It now always resolves the clinic context. - Adds app:invitations:repair to fix invitations already left orphaned. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace App\ClinicInvitation\Command;
|
||||
|
||||
use App\ClinicInvitation\Entity\ClinicDoctorInvitation;
|
||||
use App\ClinicInvitation\Repository\ClinicDoctorInvitationRepository;
|
||||
use App\ClinicInvitation\Service\ClinicInvitationService;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* دعوتنامههای پذیرفتهشدهای که قبل از رفع باگ بدون پروفایل پزشک ماندهاند را ترمیم میکند:
|
||||
* کاربر و پروفایل پزشک را میسازد و پزشک را به کلینیک متصل میکند.
|
||||
*/
|
||||
#[AsCommand(name: 'app:invitations:repair', description: 'ترمیم دعوتنامههای پذیرفتهشده بدون پروفایل پزشک')]
|
||||
class RepairAcceptedInvitationsCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private readonly ClinicDoctorInvitationRepository $invRepo,
|
||||
private readonly ClinicInvitationService $invitationService,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->addOption('dry-run', null, InputOption::VALUE_NONE, 'فقط گزارش بده، چیزی را تغییر نده');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$dryRun = (bool) $input->getOption('dry-run');
|
||||
|
||||
$orphans = $this->invRepo->createQueryBuilder('i')
|
||||
->where('i.status = :status')
|
||||
->andWhere('i.doctor IS NULL')
|
||||
->setParameter('status', ClinicDoctorInvitation::STATUS_ACCEPTED)
|
||||
->getQuery()
|
||||
->getResult();
|
||||
|
||||
if ($orphans === []) {
|
||||
$io->success('دعوتنامهی ناقصی یافت نشد.');
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$io->writeln(sprintf('%d دعوتنامه ناقص یافت شد.', count($orphans)));
|
||||
|
||||
$repaired = 0;
|
||||
foreach ($orphans as $inv) {
|
||||
$io->writeln(sprintf(
|
||||
' - %s (%s) → کلینیک %s',
|
||||
$inv->getMobile(),
|
||||
$inv->getInvitedName() ?? '—',
|
||||
$inv->getClinic()->getName() ?? $inv->getClinic()->getUuid(),
|
||||
));
|
||||
|
||||
if ($dryRun) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->invitationService->repairAccepted($inv);
|
||||
$repaired++;
|
||||
}
|
||||
|
||||
$io->success($dryRun ? 'حالت آزمایشی — چیزی تغییر نکرد.' : sprintf('%d دعوتنامه ترمیم شد.', $repaired));
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user