<?php
namespace Services\PaymentBundle\Event;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use App\BackOffice\ConfigurationBundle\Services\ApiPayment\BillingService;
use Psr\Log\LoggerInterface;
use Services\PaymentBundle\Entity\PaymentStatus;
use Services\PaymentBundle\Repository\BillingRepository;
class PaymentSubscriber implements EventSubscriberInterface
{
private BillingRepository $billingRepository;
private BillingService $billingService;
private LoggerInterface $logger;
public function __construct(
BillingRepository $billingRepository,
BillingService $billingService,
LoggerInterface $logger
) {
$this->billingRepository = $billingRepository;
$this->billingService = $billingService;
$this->logger = $logger;
}
public static function getSubscribedEvents()
{
return [
PaymentEvent::PAYMENT_MODIFICATION_EVENT => array('onPaymentUpdated', 0),
];
}
/**
* Update the billing table with the information of the updated Payment
*/
public function onPaymentUpdated(PaymentEvent $event)
{
$payment = $event->getPayment();
$user = $payment->getUser();
$campaignType = $user->getUserInfos()->getCampaignType();
$periodMonths = $campaignType->getDays();
$pdate = $payment->getDebtPeriodDate() ?? $payment->getSubscriptionDate();
$subtotal = $campaignType->getPrice();
$paymentStatusId = $payment->getPaymentStatus()->getId();
if ($payment->getIsFirst()) {
$subtotal = $campaignType->getFirstPrice();
} elseif ($campaignType->getSecondPrice()) {
$billingsList = $this->billingRepository->getBillingsByUser($user);
if (count($billingsList) == 1) { // This is the second period
$subtotal = $campaignType->getSecondPrice();
}
}
$currentPeriod = $this->billingService->getCurrentPeriodStartEnd(
$user,
$pdate,
$periodMonths,
$payment->getDebtPeriodDate() ? false : true
);
$billing = $currentPeriod['billing'] ?? null;
if (!$billing && $currentPeriod) {
$billing = $this->billingRepository->findByUserAndPeriodStart($user, $currentPeriod['start']);
}
if (!$billing) {
if (PaymentStatus::STATUS_PAIEMENT_SIMPLE == $paymentStatusId) {
$billing = $this->billingRepository->add(
$user,
$subtotal,
false,
$currentPeriod['start'],
$currentPeriod['end'],
$payment->getSubscriptionDate()
);
} elseif (PaymentStatus::STATUS_RETRY_DEBT == $paymentStatusId) {
$start = (clone $payment->getDebtPeriodDate())->modify('first day of this month');
$end = $payment->getDebtPeriodDate();
$billing = $this->billingRepository->findByUserAndDebtMonth($user, $start);
if (!$billing) {
$billing = $this->billingRepository->add(
$user,
$subtotal,
false,
$start,
$end->add(new \DateInterval('P' . $campaignType->getDays() . 'M'))->modify('last day of this month'),
$payment->getSubscriptionDate()
);
}
} else {
$billingList = $this->billingRepository->generateFromUserPayments($user);
foreach ($billingList as $b) {
if ($currentPeriod['start'] == $b->getPeriodStart()) {
$billing = $b;
break;
}
}
}
if ($billing) {
$payment->setBilling($billing);
}
} else {
$fullQuotasPaid = $payment->getTransactionPrice() >= $subtotal ? 1 : 0;
$splitQuotasPaid = $fullQuotasPaid ? 0 : 1;
$paidAmountSplit = $fullQuotasPaid ? 0 : $payment->getTransactionPrice();
$paidAmountFull = $fullQuotasPaid ? $payment->getTransactionPrice() : 0;
if (
in_array(
$event->getEventType(),
[PaymentEvent::PAYMENT_SUCCESS, PaymentEvent::PAYMENT_CHARGEBACK_REVERSED]
)
) {
$billing->setFullQuotasPaid($billing->getFullQuotasPaid() + $fullQuotasPaid);
$billing->setSplitQuotasPaid($billing->getSplitQuotasPaid() + $splitQuotasPaid);
$billing->setPaidAmountFull($billing->getPaidAmountFull() + $paidAmountFull);
$billing->setPaidAmountSplit($billing->getPaidAmountSplit() + $paidAmountSplit);
$billing->setPaidAmount($billing->getPaidAmount() + $payment->getTransactionPrice());
} elseif (
in_array($event->getEventType(), [PaymentEvent::PAYMENT_REFUND, PaymentEvent::PAYMENT_CHARGEBACK])
) {
$fullQuotasPaid = $billing->getFullQuotasPaid() - $fullQuotasPaid;
$billing->setFullQuotasPaid($fullQuotasPaid < 0.9 ? 0 : $fullQuotasPaid);
$splitQuotasPaid = $billing->getSplitQuotasPaid() - $splitQuotasPaid;
$billing->setSplitQuotasPaid($splitQuotasPaid < 0.9 ? 0 : $splitQuotasPaid);
$billing->setPaidAmountFull($billing->getPaidAmountFull() - $paidAmountFull);
$billing->setPaidAmountSplit($billing->getPaidAmountSplit() - $paidAmountSplit);
$billing->setPaidAmount($billing->getPaidAmount() - $payment->getTransactionPrice());
}
if (!$billing->getSubscriptionDate()) {
$billing->setSubscriptionDate($payment->getSubscriptionDate());
}
// Link payment to its billing
$payment->setBilling($billing);
}
if ($billing) {
$billing->setIsPaid(($billing->getPaidAmount()) >= $subtotal);
$billing->setUpdatedAt(new \DateTime());
if (!$billing->getSubscriptionDate()) {
$billing->setSubscriptionDate($payment->getSubscriptionDate());
}
}
try {
$this->billingRepository->flush();
} catch (\Exception $e) {
$this->logger->error('PaymentSubscriber::onPaymentUpdated: ' . $e->getMessage());
}
// Clear cache of total debt calculation for this user
$cache = new FilesystemAdapter();
$cacheKey = BillingService::TOTAL_DEBT_CACHE_KEY . '_' . $user->getId();
$cache->delete($cacheKey);
}
}