<?php
namespace App\EventSubscriber;
use App\Entity\CheckInformation;
use App\Entity\InvoiceReview;
use App\Entity\InvoiceSupportTicket;
use App\Entity\LatePaymentChargeLogs;
use App\Entity\Municipality;
use App\Entity\MunicipalityFeePeriod;
use App\Entity\MunicipalityLateFees;
use App\Entity\MunicipalityLateFeesPeriod;
use App\Entity\RegistrationForm;
use App\Entity\RenewalForm;
use App\Entity\SupportTicket;
use App\Entity\User;
use App\Event\AppEvents;
use App\Event\FormCreatedEvent;
use App\Event\FormsDeletedEvent;
use App\Event\Support\InvoiceEvent as InvoiceSupportEvent;
use App\Event\InvoiceEvent;
use App\Helper\PropertyHelper;
use App\Repository\LatePaymentChargeLogsRepository;
use App\ValueObject\MunicipalityLateFeesType;
use App\ValueObject\SearchCriteria\MunicipalityFeeSearchCriteria;
use App\ValueObject\InvoicePaymentTypes;
use App\ValueObject\InvoiceStatuses;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\Form;
use App\Entity\Invoice;
use App\Entity\MunicipalityFee;
use App\ValueObject\InvoiceTypes;
use App\ValueObject\SearchCriteria\RenewalFormSearchCriteria;
use App\Lib\EmailSenderInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Class InvoiceListener
*/
class InvoiceSubscriber implements EventSubscriberInterface
{
/**
* @var EntityManagerInterface
*/
private $em;
/**
* @var EmailSenderInterface
*/
private $emailSender;
private LatePaymentChargeLogsRepository $latePaymentChargeLogsRepository;
public function __construct(
EntityManagerInterface $entityManager,
EmailSenderInterface $emailSender,
LatePaymentChargeLogsRepository $latePaymentChargeLogsRepository
)
{
$this->em = $entityManager;
$this->emailSender = $emailSender;
$this->latePaymentChargeLogsRepository = $latePaymentChargeLogsRepository;
}
/**
* {@inheritdoc}
*/
public static function getSubscribedEvents()
{
return [
AppEvents::FORMS_DELETED => 'onFormsDeleted',
AppEvents::INVOICE_CREATED => 'onInvoiceCreated',
AppEvents::INVOICE_DISPUTE_CREATED => 'onDisputeCreated',
AppEvents::FORM_CREATED => 'onFormCreated'
];
}
/**
* @param FormsDeletedEvent $event
*/
public function onFormsDeleted(FormsDeletedEvent $event)
{
$formIds = $event->getForms();
if (count($formIds)) {
//Delete Invoices for the forms.
$invoiceIds = $this->em->getRepository(Invoice::class)->deleteInIds($formIds);
if (count($invoiceIds)) {
//Delete Invoices Reviews.
$this->em->getRepository(InvoiceReview::class)->deleteInIds($invoiceIds);
//Delete Invoices Dispute and Support.
$invoiceTicketIds = $this->em->getRepository(InvoiceSupportTicket::class)->getTicketsInIds($invoiceIds);
if (count($invoiceTicketIds)) {
$this->em->getRepository(SupportTicket::class)->deleteInIds($invoiceTicketIds);
}
}
}
}
/**
* @param InvoiceEvent $event
*/
public function onInvoiceCreated(InvoiceEvent $event)
{
$invoice = $event->getInvoice();
/** @var Form $form */
$form = $invoice->getForm();
$form->setFeeAmount($invoice->getInvoiceAmount());
$form->setDueAmount($invoice->getInvoiceAmount());
$this->em->persist($form);
$this->em->flush();
}
/**
* @param InvoiceSupportEvent $event
*/
public function onDisputeCreated(InvoiceSupportEvent $event)
{
//Set Invoice In Dispute.
$invoice = $event->getTicket()->getInvoice();
$invoice->inDispute();
$this->em->persist($invoice);
$this->em->flush();
}
public function onFormCreated(FormCreatedEvent $event)
{
// try {
// UPDATE property p JOIN ( SELECT f.property_id, COUNT(*) AS totalRenewal FROM `renewal_form` rf INNER JOIN form f ON f.id = rf.id GROUP BY f.property_id ) rc ON p.id = rc.property_id SET p.renewal_number = rc.totalRenewal + 1;
$checkInformation = $event->getCheckInformation();
$usedPayByCheck = $event->getUsedPayByCheck();
$form = $event->getForm();
$property = $form->getProperty();
$municipality = $property->getMunicipality();
$lateFeesTriggerType = '';
if ($event->getType() == InvoiceTypes::VPR_REGISTRATION) {
$zone = $form->getZonesPropertyUse()[0];
} elseif ($event->getType() == InvoiceTypes::VPR_RENEWAL) {
$zone = $form->getProperty()->getZonesPropertyUse()->first();
}
$criteria = new MunicipalityFeeSearchCriteria();
$criteria->industrialType = strtolower($zone ? $zone->getName() : '');
$criteria->municipalityId = $municipality->getId();
$municipalityFee = null;
$municipalityFees = $this->em->getRepository(MunicipalityFee::class)->search($criteria);
$municipalityFee = $municipalityFees[0];
$amount = 0;
$invoiceDate = new \DateTime('now');
$dueDate = new \DateTime('now');
$description = '';
$nextRenewalNumber = $property->getRenewalNumber();
if ($event->getType() == InvoiceTypes::VPR_REGISTRATION) {
$dueDate = new \DateTime($property->getRegistrationDate() ? $property->getRegistrationDate()->format('Y-m-d H:i:s') : 'now'); // Y-m-d
$amount = $municipalityFee->getRegistrationFee();
$description = 'Registration Invoice for '.$property->getAddress().' registered on '.$invoiceDate->format('Y-m-d H:i:s');
} elseif ($event->getType() == InvoiceTypes::VPR_RENEWAL) {
// count past renewals
$criteria = new RenewalFormSearchCriteria();
$criteria->property = $property;
$countRenewals = $this->em->getRepository(RenewalForm::class)->countByCriteria($criteria);
if (count($municipalityFee->getPeriods()) && $countRenewals > 1) {
// count total periods including base charge for renewal
$feesIndex = $countRenewals - 1;
$nextRenewalNumber = $countRenewals + 1;
/** @var MunicipalityFee $municipalityFee*/
$feesArray = [$municipalityFee->getRenewalBaseFee()];
if (count($municipalityFee->getPeriods())) {
foreach ($municipalityFee->getPeriods() as $period) {
$feesArray[] = $period->getTotalFee();
}
}
$type = '';
switch ($municipalityFee->getPeriodFixedRecurrenceType()) {
case 'year':
$type = 'Y';
break;
case 'month':
$type = 'M';
break;
case 'day':
$type = 'D';
break;
}
$invoiceDate = new \DateTime();
$dueDate = new \DateTime();
if ($type == 'Y') {
$dueDate->modify('+'.PropertyHelper::DUE_YEAR_RENEW.' day');
}
else if ($type == 'M') {
$dueDate->modify('+'.PropertyHelper::DUE_MONTH_RENEW.' day');
}
$renewalDate = $property->getRenewalDate() ? $property->getRenewalDate()->format('Y-m-d H:i:s') : (new \DateTime())->format('Y-m-d H:i:s');
$description = 'Renewal Invoice for '.$property->getAddress().' registered on '.$renewalDate;
if (array_key_exists($feesIndex, $feesArray)) {
$amount = $feesArray[$feesIndex];
} else {
$amount = end($feesArray);
}
} else {
$dueDate = new \DateTime($property->getRegistrationDate() ? $property->getRegistrationDate()->format('Y-m-d H:i:s') : 'now'); // Y-m-d
$description = 'Renewal Invoice for '.$property->getAddress().' registered on '.$invoiceDate->format('Y-m-d H:i:s');
$amount = $municipalityFee->getRenewalBaseFee();
$nextRenewalNumber = $property->getRenewalNumber() + 1;
}
$municipalityLateFees = $this->em->getRepository(MunicipalityLateFees::class)->findOneBy(
['municipality' => $municipality->getId(), 'type' => MunicipalityLateFeesType::RENEWAL_TYPE]
);
$currentUser = $this->em->getRepository(User::class)->findOneBy(['email' => $form->getCreatedBy()]);
if ($municipalityLateFees instanceof MunicipalityLateFees) {
$lateFeesTriggerType = $municipalityLateFees->getFeesTriggerType();
$lateFeesTriggerAfter = $municipalityLateFees->getFeesTriggerAfter();
$nextRenewalDate = $property->getNextRenewalDate();
$currentDate = new \DateTime();
$dateDiff = $currentDate->diff($nextRenewalDate);
$charge = '';
$usersLatePaymentChargeLogsCount = count($this->latePaymentChargeLogsRepository->findBy(['user' => $currentUser, 'municipality' => $municipality]));
$lateFeeBaseCharge = $municipalityLateFees->getFeesAmount();
$lateChargesArray = [];
$periods = $municipalityLateFees->getPeriods()->getValues();
if (!empty($periods)) {
/**@var MunicipalityLateFeesPeriod $period */
foreach ($periods as $period) {
$municipalityLateFeesId = $period->getMunicipalityLateFees()->getId();
$lateChargesArray[(int) $municipalityLateFeesId][] = (float) $period->getTotalFee();
}
if (array_key_exists($municipalityLateFees->getId(), $lateChargesArray)) {
array_unshift($lateChargesArray[$municipalityLateFees->getId()], $municipalityLateFees->getFeesAmount());
}
if ($usersLatePaymentChargeLogsCount == 0) {
$charge = (float) $municipalityLateFees->getFeesAmount();
} elseif (array_key_exists($municipalityLateFees->getId(), $lateChargesArray) && array_key_exists($usersLatePaymentChargeLogsCount, $lateChargesArray[$municipalityLateFees->getId()])) {
$charge = $lateChargesArray[$municipalityLateFees->getId()][$usersLatePaymentChargeLogsCount];
} else {
$charge = end($lateChargesArray[$municipalityLateFees->getId()]);
}
}
}
}
$property->setRenewalNumber($nextRenewalNumber);
$this->em->persist($property);
$this->em->flush();
$totalAmount = $dueAmount = $amount;
$invoice = new Invoice(
$form->getRegistrant(),
$event->getType(),
$invoiceDate,
$dueDate,
$amount,
);
$invoice->setPaymentType(InvoicePaymentTypes::CREDIT_CARD);
$invoice->setDescription($description);
$invoice->setForm($form);
if ($checkInformation instanceof CheckInformation) {
$invoice->setCheckInformation($checkInformation);
$checkAmount = $checkInformation->getAmount();
if ($checkAmount >= $totalAmount) {
$invoiceStatus = InvoiceStatuses::PAID;
$dueAmount = 0;
} else {
$invoiceStatus = InvoiceStatuses::UNPAID;
$dueAmount = $totalAmount - $checkAmount;
}
$invoice->setStatus($invoiceStatus);
$invoice->setPaymentDate(new \DateTime());
$invoice->setPaymentType(InvoicePaymentTypes::CHECK);
$form->setPaidAmount($checkAmount);
}
if ($usedPayByCheck) {
$invoice->setPaymentType(InvoicePaymentTypes::CHECK);
}
$this->em->persist($invoice);
$this->em->flush();
if ($lateFeesTriggerType == 'day') {
$daysDiff = $dateDiff->days;
if ($daysDiff >= $lateFeesTriggerAfter) {
$this->generateLatePaymentLog($currentUser, $municipality, $invoice, $charge);
}
} else if ($lateFeesTriggerType == 'month') {
$monthsDiff = $dateDiff->m;
if ($monthsDiff >= $lateFeesTriggerAfter) {
$this->generateLatePaymentLog($currentUser, $municipality, $invoice, $charge);
}
}
if ($form instanceof RegistrationForm || $form instanceof RenewalForm) {
$form->setFeeAmount($totalAmount);
$form->setDueAmount($dueAmount);
$this->em->persist($form);
}
$this->em->flush();
}
public function generateLatePaymentLog(User $user,Municipality $municipality,Invoice $invoice, $charge)
{
$latePaymentChargeLog = $this->latePaymentChargeLogsRepository->findOneBy(['invoice' => $invoice]);
if (!$latePaymentChargeLog instanceof LatePaymentChargeLogs) {
$latePaymentChargeLog = new LatePaymentChargeLogs();
$latePaymentChargeLog->setUser($user);
$latePaymentChargeLog->setMunicipality($municipality);
$latePaymentChargeLog->setInvoice($invoice);
$latePaymentChargeLog->setMunicipalityLateFeesCharge($charge);
$this->em->persist($latePaymentChargeLog);
$this->em->flush();
}
}
}