<?php
declare(strict_types=1);
namespace ERP\BillingRequestsBundle\EventSubscriber;
use ApiPlatform\Core\Api\IriConverterInterface;
use ApiPlatform\Core\EventListener\EventPriorities;
use App\Entity\Project;
use Doctrine\ORM\EntityManagerInterface;
use ERP\BillingRequestsBundle\Entity\BillingRequestAutomation;
use ERP\BillingRequestsBundle\Entity\ProjectBillingRequestAutomationInterface;
use ERP\BillingRequestsBundle\Factory\BillingRequestAutomationFactory;
use ERP\BillingRequestsBundle\Factory\BillingRequestFactory;
use ERP\BillingRequestsBundle\Repository\BillingRequestAutomationRepository;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Security;
class BillingRequestsAutomationSubscriber implements EventSubscriberInterface
{
/**
* @var BillingRequestFactory
*/
private $billingRequestFactory;
/**
* @var EntityManagerInterface
*/
private $entityManager;
/**
* @var IriConverterInterface
*/
private $iriConverter;
/**
* @var BillingRequestAutomationFactory
*/
private $automationFactory;
/**
* @var RequestStack
*/
private $requestStack;
/**
* @var Security
*/
private $security;
/**
* BillingRequestsAutomationSubscriber constructor.
*/
public function __construct(
BillingRequestFactory $billingRequestFactory,
BillingRequestAutomationFactory $automationFactory,
EntityManagerInterface $entityManager,
IriConverterInterface $iriConverter,
RequestStack $requestStack,
Security $security
) {
$this->billingRequestFactory = $billingRequestFactory;
$this->automationFactory = $automationFactory;
$this->entityManager = $entityManager;
$this->iriConverter = $iriConverter;
$this->requestStack = $requestStack;
$this->security = $security;
}
public static function getSubscribedEvents()
{
return [
KernelEvents::VIEW => [
['removeExistingAutomations', EventPriorities::PRE_VALIDATE],
['onCreateProject', EventPriorities::POST_WRITE],
['onSerializeAutomationSetup', EventPriorities::POST_VALIDATE],
// ['onDeserializeAutomationSetup', EventPriorities::PRE_SERIALIZE],
],
KernelEvents::REQUEST => [
['checkInstallmentsChange', EventPriorities::PRE_DESERIALIZE],
],
];
}
public function removeExistingAutomations(ViewEvent $event): void
{
if (
in_array($event->getRequest()->getMethod(), [Request::METHOD_PATCH, Request::METHOD_PUT]) &&
is_object($project = $event->getControllerResult()) &&
$project instanceof Project &&
$project instanceof ProjectBillingRequestAutomationInterface
) {
$request = $this->requestStack->getCurrentRequest();
$content = json_decode($request->getContent(), true);
if (
isset($content['create_billing_requests_automatically'])
&& false === $content['create_billing_requests_automatically']
) {
$project->setAutomationConfig([]);
}
if (
$project->isCreateBillingRequestsAutomatically()
&& $project->getBillingRequestAutomations()->count()
) {
/** @var BillingRequestAutomationRepository $repo */
$repo = $this->entityManager->getRepository(BillingRequestAutomation::class);
/** @var array|BillingRequestAutomation[] $automations */
foreach ($repo->findBy(['project' => $project]) as $automation) {
if ($automation instanceof BillingRequestAutomation) {
$this->entityManager->remove($automation);
$this->entityManager->flush();
}
}
}
}
}
public function checkInstallmentsChange(RequestEvent $event): void
{
if (
in_array($event->getRequest()->getMethod(), [Request::METHOD_PATCH, Request::METHOD_PUT]) &&
is_object($project = $event->getRequest()->attributes->get('data')) &&
$project instanceof Project &&
$project instanceof ProjectBillingRequestAutomationInterface
) {
$request = $this->requestStack->getCurrentRequest();
$content = json_decode($request->getContent(), true);
if (
$project->isCreateBillingRequestsAutomatically()
&& $project->getBillingRequestAutomations()->count()
&& isset($content['installments'])
&& $content['installments'] !== $project->getInstallments()
) {
/** @var BillingRequestAutomationRepository $repo */
$repo = $this->entityManager->getRepository(BillingRequestAutomation::class);
/** @var array|BillingRequestAutomation[] $automations */
foreach ($repo->findByProjectUnusedAnytime($project) as $automation) {
if ($automation instanceof BillingRequestAutomation) {
$this->entityManager->remove($automation);
$this->entityManager->flush();
}
}
$request->attributes->set(
'data',
$project
);
}
}
}
public function onSerializeAutomationSetup(ViewEvent $event): void
{
if (
in_array($event->getRequest()->getMethod(), [Request::METHOD_POST, Request::METHOD_PATCH, Request::METHOD_PUT]) &&
is_object($project = $event->getControllerResult()) &&
$project instanceof Project &&
$project instanceof ProjectBillingRequestAutomationInterface &&
$project->isCreateBillingRequestsAutomatically()
) {
$automationSetup = [
'payment_date' => $project->getPaymentDate(),
'installments' => $project->getInstallments(),
'billing_request_description' => $project->getBillingRequestDescription(),
'payment_method' => $project->getPaymentMethod(),
'payment_term' => $project->getPaymentTerm(),
'payment_category' => $project->getPaymentCategory(),
'payment_department' => $project->getPaymentDepartment(),
'payment_amount' => $project->getPaymentAmount(),
'payment_billing_type' => $project->getPaymentBillingType(),
'payment_billing_frequency' => $project->getPaymentBillingFrequency(),
'payment_additional_subscribers' => $project->getPaymentAdditionalSubscribers(),
'interest_rate' => $project->getInterestRate(),
'amount_by_hours_worked' => $project->isAmountByHoursWorked(),
'payment_default_hourly_rate' => $project->getPaymentDefaultHourlyRate(),
'message_dismissed' => $this->messageDismissedByUser($project),
];
$project->setAutomationConfig($automationSetup);
}
}
public function onCreateProject(ViewEvent $event): void
{
if (
in_array($event->getRequest()->getMethod(), [Request::METHOD_POST, Request::METHOD_PATCH, Request::METHOD_PUT]) &&
is_object($project = $event->getControllerResult()) &&
$project instanceof ProjectBillingRequestAutomationInterface &&
$project->isCreateBillingRequestsAutomatically()
) {
$automation = $this->automationFactory->createFromProject($project);
if (is_object($automation)) {
$this->entityManager->persist($automation);
$this->entityManager->flush();
}
}
}
private function messageDismissedByUser(Project $project): array
{
$messageDismissed = $project->getAutomationConfig()['message_dismissed'] ?? [];
$userIri = $this->iriConverter->getIriFromItem($this->security->getUser());
if (!$messageDismissed && is_null($project->isMessageDismissed($userIri))) {
$project->setMessageDismissed(false);
}
foreach ($messageDismissed as &$item) {
if ($item['user'] === $userIri) {
$item['status'] = $project->isMessageDismissed($userIri);
return $messageDismissed;
}
}
$messageDismissed[] = [
'user' => $userIri,
'status' => $project->isMessageDismissed($userIri),
];
return $messageDismissed;
}
}