<?php
/**
* This file is part of the CosaVostra, TrackPay package.
*
* (c) Mohamed Radhi GUENNICHI <rg@mate.tn> <+216 50 711 816>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace App\EventSubscriber;
use App\Connector\DriverRegistry;
use App\Event\ConnectorSynchronization;
use App\Repository\ConnectorRepository;
use Carbon\Carbon;
use DateTime;
use Exception;
use QuickBooksOnline\API\Exception\ServiceException;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use function Sentry\captureException;
class ConnectorSynchronizationSubscriber implements EventSubscriberInterface
{
/**
* @var ConnectorRepository
*/
protected $connectorRepository;
/**
* @var DriverRegistry
*/
protected $driverRegistry;
public function __construct(DriverRegistry $driverRegistry, ConnectorRepository $connectorRepository)
{
$this->connectorRepository = $connectorRepository;
$this->driverRegistry = $driverRegistry;
}
public function onSynchronizing(ConnectorSynchronization $event): void
{
$connectors = $event->isNotEmpty() ?
$this->connectorRepository->findBy(['id' => $event->getConnectorsIds()]) :
// The priority for manual synchronization demands (synchronized => 0).
$this->connectorRepository->findBy([], ['synchronized' => 'ASC']);
$output = $event->getOutput();
foreach ($connectors as $connector) {
$driver = $this->driverRegistry->get($connector);
$connectError = false;
try {
$loader = $driver->connect($connector);
} catch (ServiceException $serviceException) {
if ((int)$serviceException->getCode() !== 400) {
captureException($serviceException);
}
$this->log($output, "CANNOT CONNECT TO {$serviceException->getMessage()}");
$this->log($output, '=============================');
// Update connector "connected" flag
$connector->setConnected(false);
$connector->setLastConnectedCheckDate(new DateTime());
continue;
}
$connectorInfos = $connector->getName() . '@' . $connector->getId();
$this->log($output, "CONNECTING TO $connectorInfos");
if ($connectError || !$loader->isConnected()) {
$this->log($output, "CANNOT CONNECT TO $connectorInfos");
$this->log($output, '=============================');
// Update connector "connected" flag
$connector->setConnected(false);
$connector->setLastConnectedCheckDate(new DateTime());
continue;
}
// Update connector "connected" flag
$connector->setConnected(true);
$connector->setLastConnectedCheckDate(new DateTime());
$this->connectorRepository->save($connector);
try {
// TODO Radhi : Do not parse 3 time each invoice with sellsy : Use a single method to add, update and delete invoices ?
$this->log($output, 'INVOICES CREATE ' . $connectorInfos);
$loader->createInvoices();
$this->log($output, 'SYNCHRONISED');
// todo Radhi : use sleep only in driver after each call (in Loader ?) Maybe need to redefine sleep value. and do not user specific (sellsy) driver value
sleep($driver::SLEEP_BETWEEN_OPERATIONS);
$this->log($output, 'INVOICES UPDATE ' . $connectorInfos);
$loader->updateInvoices();
$this->log($output, 'SYNCHRONISED');
sleep($driver::SLEEP_BETWEEN_OPERATIONS);
$this->log($output, 'INVOICES DELETE ' . $connectorInfos);
$loader->deleteInvoices();
$this->log($output, 'SYNCHRONISED');
$this->log($output, '=============================');
sleep($driver::SLEEP_BETWEEN_OPERATIONS);
if (!$connector->isSynchronized()) {
$connector->setSynchronized(true);
$this->connectorRepository->save($connector);
}
} catch (Exception $exception) {
$this->log($output, "EXCEPTION $connectorInfos SKIP: ". $exception->getMessage());
$this->log($output, '=============================');
// Capture exception and continue iteration.
captureException($exception);
continue;
}
}
}
/**
* @inheritDoc
*/
public static function getSubscribedEvents()
{
return [
ConnectorSynchronization::class => 'onSynchronizing'
];
}
protected function log(?OutputInterface $output, string $message, string $level = 'info'): void
{
if (null !== $output) {
$output->writeln(
sprintf('%s [%s] %s', (new Carbon())->toDateTimeString(), $level, $message)
);
}
}
}