feat: provision a teamer from a received application

This commit is contained in:
fromme committed 2026-09-25 14:36:24 +02:00
1 parent d5f4b12f0a
commit b530679658
23 files changed
+2433 -148

No files matched your search

@@ -0,0 +1,110 @@
<?php
namespace App\Controller\Admin\ApplicationFormSubmission;
use App\Entity\ApplicationFormSubmission;
use App\Htmx\HxRedirectResponse;
use App\Model\TeamerProvisioningResult;
use App\Service\Teamer\TeamerProvisioner;
use App\Service\Teamer\TeamerProvisioningException;
use Flagception\Manager\FeatureManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
/**
* Makes a teamer out of an applicant who passed the interview: one click, because the submission
* carries everything the CRM needs and there is nothing left for the reviewer to type.
*
* Behind a feature flag, because provisioning writes to the production CRM and cannot be rehearsed
* anywhere else - the teamer selection is only changeable there.
*/
class CreateTeamerController extends AbstractController
{
public function __construct(
private readonly TeamerProvisioner $provisioner,
private readonly FeatureManagerInterface $featureManager,
private readonly LoggerInterface $logger,
) {
}
#[Route('/admin/application-form-submission/create-teamer/{uuid}', name: 'app_admin_application_form_submission_create_teamer')]
#[IsGranted('ROLE_TEAM_ADMIN')]
public function index(ApplicationFormSubmission $submission, Request $request): Response
{
if (false === $this->featureManager->isActive('application_form_teamer_provisioning')) {
throw $this->createNotFoundException('Teamer provisioning is not enabled');
}
if (false === $request->isMethod(Request::METHOD_POST)) {
return $this->render('admin/application_form_submission/modal_create_teamer.html.twig', [
'submission' => $submission,
]);
}
try {
$result = $this->provisioner->provision($submission);
$this->addFlash('success', $this->describe($result));
$this->log($submission, $result);
} catch (TeamerProvisioningException $e) {
// Deliberately the exception's own wording: it usually carries BusPro's complaint, and
// a reviewer can act on a named mandatory field but not on "something went wrong".
$this->addFlash('error', $e->getMessage());
$this->logger->error('Unable to provision a teamer from an application form submission', [
'uuid' => $submission->getUuid(),
'error_message' => $e->getMessage(),
...$e->getContext(),
]);
}
return new HxRedirectResponse($this->generateUrl('app_admin_application_form_submission_detail', [
'uuid' => $submission->getUuid(),
'r' => $request->query->get('r'),
]));
}
/**
* Names what happened rather than "erledigt": whether BusPro recognised the applicant, whether
* an account already existed and - the one thing that needs a human afterwards - whether the
* password mail went out.
*/
private function describe(TeamerProvisioningResult $result): string
{
if (true === $result->isAlreadyProvisioned()) {
return 'Diese Bewerbung wurde bereits übernommen, es wurde nichts erneut angelegt';
}
$message = true === $result->isUserCreated()
? sprintf('%s wurde als Teamer:in angelegt', (string) $result->getUser()->getTeamer())
: sprintf('%s hat schon ein Konto und ist jetzt Teamer:in', $result->getUser()->getFullName());
if (false === $result->isAddressCreated()) {
$message .= '. In BusPro gab es die Adresse schon, sie wurde übernommen';
}
$message .= true === $result->isPasswordMailSent()
? '. BusPro hat die Passwort-Mail versendet'
: '. Die Passwort-Mail von BusPro ist nicht rausgegangen - bitte erneut anstoßen';
return $message;
}
private function log(ApplicationFormSubmission $submission, TeamerProvisioningResult $result): void
{
$this->logger->info('Provision a teamer from an application form submission', [
'uuid' => $submission->getUuid(),
'user_id' => $result->getUser()->getId(),
'user_email' => $result->getUser()->getEmail(),
'bus_pro_address_id' => $submission->getBusProAddressId(),
'bus_pro_person_id' => $submission->getBusProPersonId(),
'address_created' => $result->isAddressCreated(),
'user_created' => $result->isUserCreated(),
'already_teamer' => $result->isAlreadyTeamer(),
'already_provisioned' => $result->isAlreadyProvisioned(),
'password_mail_sent' => $result->isPasswordMailSent(),
]);
}
}