<?php
namespace App\Listener;
use App\DTO\Mdm\DelayComputingDTO;
use App\Event\StatusChangedEvent;
use App\Exception\DTOConstructException;
use App\Manager\Mdm\MdmManager;
use App\Manager\NotificationManager;
use App\Manager\UserRequestManager;
use App\Manager\UserRightsManagerInterface;
use App\Model\UserRequest\RequestModel;
use DateTime;
use DateTimeZone;
use Exception;
use Psr\Cache\InvalidArgumentException;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use WebServiceCollectionBundle\Model\AtlasPce\UserRequestRequestModel;
class StatusChangeSubscriber implements EventSubscriberInterface
{
public const STATUS_CHANGED = 'status.changed';
public const STATUS_CHANGED_DONE = 'status.changed.done';
public const FIELD_PROCESSING_DURATION = 'processingDuration';
public const FIELD_REALISATION_DATE = 'realisationDate';
public const FIELD_SUBMISSION_DATE = 'submissionDate';
public const STATUS_TRIGGERING_NOTIF = [
RequestModel::STATUS_TO_QUALIFY,
RequestModel::STATUS_TO_PLAN,
RequestModel::STATUS_TO_SPECIFY,
RequestModel::STATUS_PLANNED,
RequestModel::STATUS_ONGOING,
RequestModel::STATUS_DONE,
];
public const STATUS_TRIGGERING_SUEZ_NOTIF = [
RequestModel::STATUS_TO_QUALIFY,
RequestModel::STATUS_CLOSED_REJECTED,
];
/**
* @var MdmManager
*/
protected $mdmManager;
/**
* @var UserRequestManager
*/
protected $userRequestManager;
/**
* @var NotificationManager
*/
protected $notificationManager;
/**
* @var LoggerInterface
*/
protected $logger;
public function __construct(MdmManager $mdmManager, UserRequestManager $userRequestManager, NotificationManager $notificationManager, LoggerInterface $logger)
{
$this->mdmManager = $mdmManager;
$this->userRequestManager = $userRequestManager;
$this->notificationManager = $notificationManager;
$this->logger = $logger;
}
/**
* @return array
*/
public static function getSubscribedEvents(): array
{
return [
static::STATUS_CHANGED => 'onStatusChanged',
static::STATUS_CHANGED_DONE => 'onStatusChangedDone',
];
}
/**
* Bootstraps status change hooks.
*
* @param StatusChangedEvent $event
*
* @return void
*
* @throws InvalidArgumentException
* @throws Exception
*/
public function onStatusChanged(StatusChangedEvent $event)
{
$request = $event->getSubject();
$targetStatus = $event->getArgument('targetStatus');
$this->logger->info(
'Request passing to status {status}',
[
'status' => $targetStatus,
]
);
switch ($targetStatus) {
case RequestModel::STATUS_TO_QUALIFY:
$this->toQualify($request);
// When request turns to qualify, its submission time will be added into request data to keep creation date.
$this->setRequestDataDate($request, static::FIELD_SUBMISSION_DATE);
break;
case RequestModel::STATUS_DONE:
// When request turns to done, its realised time will be added into request data to calculate process duration.
$this->setRequestDataDate($request, static::FIELD_REALISATION_DATE);
break;
default:
$this->logger->info(
'Uncaught status {status}',
[
'status' => $targetStatus,
]
);
}
// If the user isn't from Suez organisation, a notification should be sent to Suez to let them know the action took place
$userRoles = $event->getArgument('userRoles');
$isNotFromSuez = !in_array(
UserRightsManagerInterface::ROLE_SUEZ,
$userRoles
); // User isn't from Suez
$statusEligibleToSuezNotif = in_array(
$targetStatus,
static::STATUS_TRIGGERING_SUEZ_NOTIF
); // Status should trigger a notification to Suez
if ($isNotFromSuez && $statusEligibleToSuezNotif) {
$this->notifySuezNewStatus($event);
}
}
public function notifySuezNewStatus(StatusChangedEvent $event): void
{
$request = $event->getSubject();
$targetStatus = $event->getArgument('targetStatus');
$this->logger->info(
'Status changed by Client user to `{targetStatus}`. Pushing notification to Asteo',
[
'targetStatus' => $targetStatus,
]
);
$notification = $this->notificationManager->getStatusChangeNotification($request, $targetStatus);
// Original email will be replaced by the consumer dedicated to pushing notifications to Suez.
// and we push
$this->notificationManager->notifyPce($notification);
}
/**
* Bootstraps status change done hooks.
*
* @param StatusChangedEvent $event
*
* @return void
*/
public function onStatusChangedDone(StatusChangedEvent $event)
{
$request = $event->getSubject();
$targetStatus = $event->getArgument('targetStatus');
if (in_array($targetStatus, static::STATUS_TRIGGERING_NOTIF)) {
$notification = $this->notificationManager->getStatusChangeNotification($request, $targetStatus);
$this->notificationManager->notify($notification);
}
}
/**
* When request turns to qualify, its processsing duration will be updated.
*
* @param UserRequestRequestModel $request
*
* @return void
*
* @throws DTOConstructException
* @throws Exception|InvalidArgumentException
*/
public function toQualify(UserRequestRequestModel $request): void
{
$data = $request->getData();
$categoryId = $data['requestCategory']['id'];
$subCategoryId = $data['requestSubCategory']['id'];
$treatmentCategory = $subCategoryId ?? $categoryId;
$desiredDate = $data['desiredDate'];
$definedTreatments = $data['requestExpectedTreatment'] ?? [];
$treatments = array_column($definedTreatments, 'id');
$dto = new DelayComputingDTO(
[
DelayComputingDTO::CATEGORY_ID => $treatmentCategory,
DelayComputingDTO::DESIRED_DATE => $desiredDate,
DelayComputingDTO::TREATMENTS => $treatments,
DelayComputingDTO::HUMANRISK => $data['requestHumanRisk'],
DelayComputingDTO::PROPERTYRISK => $data['requestPropertyRisk'],
DelayComputingDTO::SERVICERISK => $data['requestServiceRisk'],
]
);
$endOfProcessing = $this->mdmManager->getDurationForTreatments($dto);
$this->setRequestDataDate($request, static::FIELD_PROCESSING_DURATION, $endOfProcessing);
}
/**
* @param UserRequestRequestModel $request
* @param string $field
* @param DateTime|null $date
*
* @return void
*
* @throws Exception
*/
protected function setRequestDataDate(UserRequestRequestModel $request, string $field, DateTime $date = null): void
{
$date = $date ?? new DateTime('now', new DateTimeZone('Europe/Paris'));
$formattedDate = $date->format('Y-m-d H:i:s');
$request->setData($field, $formattedDate);
$this->logger->notice(
sprintf("[StatusChangeSubscriber] Setting request {id}'s %s to {%s}", $field, $field),
[
'id' => $request->getId(),
$field => $formattedDate,
]
);
$this->userRequestManager->putRequest($request);
}
}