Covivo/mobicoop

View on GitHub
api/src/Payment/Repository/CarpoolPaymentRepository.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php

/**
 * Copyright (c) 2020, MOBICOOP. All rights reserved.
 * This project is dual licensed under AGPL and proprietary licence.
 ***************************
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Affero General Public License as
 *    published by the Free Software Foundation, either version 3 of the
 *    License, or (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <gnu.org/licenses>.
 ***************************
 *    Licence MOBICOOP described in the file
 *    LICENSE
 */

namespace App\Payment\Repository;

use App\Incentive\Entity\LongDistanceJourney;
use App\Payment\Entity\CarpoolItem;
use App\Payment\Entity\CarpoolPayment;
use App\User\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;

class CarpoolPaymentRepository
{
    /**
     * @var EntityManagerInterface
     */
    private $_em;

    /**
     * @var EntityRepository
     */
    private $repository;

    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->_em = $entityManager;
        $this->repository = $entityManager->getRepository(CarpoolPayment::class);
    }

    public function find(int $id): ?CarpoolPayment
    {
        return $this->repository->find($id);
    }

    public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): ?array
    {
        return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
    }

    public function findOneBy(array $criteria): ?CarpoolPayment
    {
        return $this->repository->findOneBy($criteria);
    }

    /**
     * Find successful electronic payment and related items for the given period.
     *
     * @param \DateTime $fromDate The start date and time
     * @param \DateTime $toDate   The end date and time
     *
     * @return null|CarpoolPayment[] The carpool payments if found
     */
    public function findSuccessfulElectronicPaymentsForPeriod(\DateTime $fromDate, \DateTime $toDate): ?array
    {
        $query = $this->repository->createQueryBuilder('cp')
            ->join('cp.carpoolItems', 'ci')
            ->where('ci.debtorStatus = :debtorStatus')
            ->andWhere('cp.status = :success and cp.transactionId IS NOT NULL')
            ->andWhere('cp.transactionDate between :fromDate and :toDate')
            ->setParameter('debtorStatus', CarpoolItem::DEBTOR_STATUS_ONLINE)
            ->setParameter('success', CarpoolPayment::STATUS_SUCCESS)
            ->setParameter('fromDate', $fromDate->format('Y-m-d H:i:s'))
            ->setParameter('toDate', $toDate->format('Y-m-d H:i:s'))
        ;

        return $query->getQuery()->getResult();
    }

    /**
     * Find a carpoolpayment made by $debtor about a $carpoolItem.
     *
     * @return null|CarpoolPayment[]
     */
    public function findCarpoolPaymentByDebtorAndCarpoolItem(User $debtor, CarpoolItem $carpoolItem): ?array
    {
        $query = $this->repository->createQueryBuilder('cp')
            ->join('cp.carpoolItems', 'ci')
            ->where('cp.user = :debtor')
            ->andWhere('ci.id = :carpoolItemId')
            ->setParameter('debtor', $debtor)
            ->setParameter('carpoolItemId', $carpoolItem->getId())
        ;

        return $query->getQuery()->getResult();
    }

    public function findPendingCarpoolPayments(): array
    {
        $past24h = new \DateTime('now');
        $past24h->modify('-24 hour');

        $query = $this->repository->createQueryBuilder('cp')
            ->join('cp.carpoolItems', 'ci')
            ->where('cp.status = :success')
            ->andWhere('cp.transactionId IS NOT NULL')
            ->andWhere('ci.debtorStatus  = :pendingDebtorStatus OR ci.debtorStatus  = :successDebtorStatus')
            ->andWhere('ci.creditorStatus = :creditorStatus')
            ->andWhere('cp.createdDate >= :past24h')
            ->setParameter('success', CarpoolPayment::STATUS_SUCCESS)
            ->setParameter('pendingDebtorStatus', CarpoolItem::DEBTOR_STATUS_PENDING_ONLINE)
            ->setParameter('successDebtorStatus', CarpoolItem::DEBTOR_STATUS_ONLINE)
            ->setParameter('creditorStatus', CarpoolItem::CREDITOR_STATUS_PENDING_ONLINE)
            ->setParameter('past24h', $past24h)
        ;

        return $query->getQuery()->getResult();
    }

    public function findLastSuccessfullCarpoolPayment(CarpoolItem $carpoolItem)
    {
        $query = $this->repository->createQueryBuilder('cp')
            ->join('cp.carpoolItems', 'ci')
            ->where('ci.id = :carpoolItemId')
            ->andWhere('cp.status = :success')
            ->orderBy('cp.createdDate', 'DESC')
            ->setParameter('carpoolItemId', $carpoolItem->getId())
            ->setParameter('success', CarpoolPayment::STATUS_SUCCESS)
        ;

        return $query->getQuery()->getResult();
    }

    public function findOneByCarpoolItem(CarpoolItem $carpoolItem): ?CarpoolPayment
    {
        $repository = $this->_em->getRepository(LongDistanceJourney::class);

        $qb1 = $repository->createQueryBuilder('ld');
        $qb1
            ->select('cp.id')
            ->innerJoin('ld.carpoolPayment', 'cp')
            ->distinct()
            ->where('ld.carpoolPayment IS NOT NULL')
        ;

        $carpoolPaymentIds = array_map(function (array $item) {
            return $item['id'];
        }, $qb1->getQuery()->getResult());

        $qb2 = $this->repository->createQueryBuilder('cp');

        $parameters = [
            'carpoolItemId' => $carpoolItem->getId(),
            'creditorStatus' => CarpoolItem::CREDITOR_STATUS_ONLINE,
            'paymentIds' => $carpoolPaymentIds,
            'paymentStatus' => CarpoolPayment::STATUS_SUCCESS,
        ];

        $qb2
            ->innerJoin('cp.carpoolItems', 'ci')
            ->where('ci.id = :carpoolItemId')
            ->andWhere('ci.creditorStatus = :creditorStatus')
            ->andWhere('cp.status = :paymentStatus')
            ->andWhere('cp.transactionId IS NOT NULL')
            ->andWhere('cp.id NOT IN (:paymentIds)')
            ->setParameters($parameters)
        ;

        $results = $qb2->getQuery()->getResult();

        // It is not possible to determine the exact payment when the journeys are not validated chronologically. It's a bub but we could not fix it
        return empty($results) ? null : $results[0];
    }
}