<?php
/** @noinspection PhpUnused */
/*
* This file is part of the SynergyBot project.
*
* For the full copyright and license information,
* please read the LICENSE.md file that was distributed with this source code.
*
* The SymfonyBot project - inspiring people to chat!
*
* Copyright (c) 2022.
*/
declare(strict_types=1);
/*
* This file is part of the SynergyBot project.
*
* For the full copyright and license information,
* please read the LICENSE.md file that was distributed with this source code.
*
* The SymfonyBot project - inspiring people to chat!
*
* Copyright (c) 2022.
*/
namespace App\BillingBundle\EventListeners;
use App\BillingBundle\Config\OperationType;
use App\BillingBundle\Entity\Account;
use App\BillingBundle\Repository\AccountRepository;
use App\BillingBundle\Repository\OperationRepository;
use App\BillingBundle\Services\BillingService;
use App\ChannelBundle\Event\OnChannelMsgDelivered;
use App\ChannelBundle\Event\OnChannelMsgFail;
use Doctrine\DBAL\LockMode;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
class MsgEventListener
{
public function __construct(
private readonly EntityManagerInterface $em,
private readonly AccountRepository $accountRepository,
private readonly OperationRepository $operationRepository,
private readonly LoggerInterface $logger,
private readonly BillingService $billingService)
{
}
public function onChannelMsgDelivered(OnChannelMsgDelivered $onMsgDelivered)
{
$msg = $onMsgDelivered->getMsg();
$channel = $msg->getChannel();
$bAccount = $this->billingService->getUserBilling($channel->getUser());
$operation = $this->operationRepository->findOneByAccountAndBusinessMsgAndType($bAccount, $msg, OperationType::BLOCK);
if (!$operation) {
return;
}
/** @var Account $bAccountPartner */
$bAccountPartner = $this->accountRepository->findOneBy([
'isPartner' => true,
]);
$operationType = OperationType::PAY;
$this->em->beginTransaction();
$this->em->lock($bAccount, LockMode::PESSIMISTIC_WRITE);
$this->em->lock($bAccountPartner, LockMode::PESSIMISTIC_WRITE);
try {
$bAccountPartner->increaseBalance($operation->getAmount());
$this->em->flush();
$this->em->commit();
$operation
->setType($operationType)
->setExternalId($msg->getRequestId())
->setActivatedAt(new \DateTime());
$this->em->flush();
} catch (\Exception $exception) {
$this->logger->error($exception->getMessage(), [$exception]);
$this->em->rollback();
}
}
public function onChannelMsgFail(OnChannelMsgFail $onMsgFail)
{
$msg = $onMsgFail->getMsg();
$channel = $msg->getChannel();
$msgPattern = $msg->getMsgPattern();
if (!$msgPattern) {
return;
}
$bAccount = $this->billingService->getUserBilling($channel->getUser());
$operation = $this->operationRepository->findOneByAccountAndMsgAndType($bAccount, $msg, OperationType::BLOCK);
if (!$operation) {
return;
}
$bAccountPartner = $this->accountRepository->findOneBy([
'isPartner' => true,
]);
if (!$operation->isFree()) {
$this->em->beginTransaction();
$this->em->lock($bAccount, LockMode::PESSIMISTIC_WRITE);
$this->em->lock($bAccountPartner, LockMode::PESSIMISTIC_WRITE);
try {
$bAccount->increaseBalance($operation->getAmount());
$bAccountPartner->reduceBalance($operation->getAmount());
$this->em->flush();
$this->em->commit();
} catch (\Exception $exception) {
$this->logger->error($exception->getMessage(), [$exception]);
$this->em->rollback();
}
}
$operation
->setAmount(!$operation->isFree() ? $operation->getAmount() : 0)
->setType(OperationType::RETURN)
->setExternalId($msg->getRequestId());
$this->em->flush();
}
}