Covivo/mobicoop

View on GitHub
api/src/Solidary/Admin/Service/SolidaryTransportMatcher.php

Summary

Maintainability
F
1 wk
Test Coverage
<?php

/**
 * Copyright (c) 2021, 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\Solidary\Admin\Service;

use App\Carpool\Entity\Criteria;
use App\Carpool\Entity\Proposal;
use App\Solidary\Admin\Repository\SolidaryUserRepository;
use App\Solidary\Entity\Solidary;
use App\Solidary\Entity\SolidaryMatching;
use App\Solidary\Entity\SolidaryUser;
use App\Solidary\Entity\Structure;
use Doctrine\ORM\EntityManagerInterface;

/**
 * Solidary transport matcher in admin context.
 *
 * @author Sylvain Briat <sylvain.briat@mobicoop.org>
 */
class SolidaryTransportMatcher
{
    private $entityManager;
    private $solidaryUserRepository;

    /**
    * Constructor
    */
    public function __construct(EntityManagerInterface $entityManager, SolidaryUserRepository $solidaryUserRepository)
    {
        $this->entityManager = $entityManager;
        $this->solidaryUserRepository = $solidaryUserRepository;
    }

    /**
     * Match a solidary record with transport volunteers
     *
     * @param Solidary $solidary    The solidary record
     * @return void
     */
    public function match(Solidary $solidary)
    {
        // first we get the volunteers for the outward
        $outwardVolunteers = $this->solidaryUserRepository->getMatchingVolunteers($solidary, $solidary->getProposal()->getType());

        // then, we get the volunteers for the return (if relevant)
        $returnVolunteers = [];
        if ($solidary->getProposal()->getProposalLinked()) {
            $returnVolunteers = $this->solidaryUserRepository->getMatchingVolunteers($solidary, $solidary->getProposal()->getProposalLinked()->getType());
        }

        // create outward SolidaryMatchings
        $outwardMatchings = [];
        foreach ($outwardVolunteers as $volunteer) {
            /**
             * @var SolidaryUser $volunteer
             */
            $solidaryMatching = new SolidaryMatching();
            $solidaryMatching->setSolidaryUser($volunteer);
            $solidaryMatching->setSolidary($solidary);
            $solidaryMatching->setType($solidary->getProposal()->getType());
            $solidaryMatching->setCriteria($this->createMatchingCriteria($solidaryMatching));
            $solidary->addSolidaryMatching($solidaryMatching);
            $this->entityManager->persist($solidaryMatching);
            $this->entityManager->persist($solidary);
            $outwardMatchings[] = $solidaryMatching;
        }

        // create return SolidaryMatchings
        foreach ($returnVolunteers as $volunteer) {
            /**
             * @var SolidaryUser $volunteer
             */
            $solidaryMatching = new SolidaryMatching();
            $solidaryMatching->setSolidaryUser($volunteer);
            $solidaryMatching->setSolidary($solidary);
            $solidaryMatching->setType($solidary->getProposal()->getProposalLinked()->getType());
            $solidaryMatching->setCriteria($this->createMatchingCriteria($solidaryMatching));
            $solidary->addSolidaryMatching($solidaryMatching);
            // check if an outward is set for this volunteer => if so, link the solidary matchings
            foreach ($outwardMatchings as $outwardMatching) {
                /**
                 * @var SolidaryMatching $outwardMatching
                 */
                if ($volunteer->getId() === $outwardMatching->getSolidaryUser()->getId()) {
                    $solidaryMatching->setSolidaryMatchingLinked($outwardMatching);
                    break;
                }
            }
            $this->entityManager->persist($solidaryMatching);
            $this->entityManager->persist($solidary);
        }

        $this->entityManager->flush();
    }

    /**
     * Match all the solidary records of a given structure
     *
     * @param Structure $structure  The structure
     * @return void
     */
    public function matchForStructure(Structure $structure)
    {
        foreach ($structure->getSolidaryUserStructures() as $solidaryUserStructure) {
            /**
             * @var SolidaryUserStructure $solidaryUserStructure
             */
            foreach ($solidaryUserStructure->getSolidaries() as $solidary) {
                $this->match($solidary);
            }
        }
    }

    /**
     * Create a Criteria for a SolidaryMatching
     *
     * @param SolidaryMatching $solidaryMatching    The SolidaryMatching
     * @return Criteria                             The resulting criteria
     */
    private function createMatchingCriteria(SolidaryMatching $solidaryMatching)
    {
        switch ($solidaryMatching->getType()) {
            case Proposal::TYPE_ONE_WAY:
            case Proposal::TYPE_OUTWARD:
                if ($solidaryMatching->getSolidary()->getAdminfrequency() == Criteria::FREQUENCY_PUNCTUAL) {
                    // punctual oneway / outward => criteria is the same than the solidary proposal criteria
                    return clone $solidaryMatching->getSolidary()->getProposal()->getCriteria();
                } else {
                    // regular => build criteria from matching days
                    return $this->createCriteriaForRegular($solidaryMatching->getSolidary()->getProposal()->getCriteria(), $solidaryMatching->getSolidaryUser());
                }
                break;
            case Proposal::TYPE_RETURN:
                if ($solidaryMatching->getSolidary()->getAdminfrequency() == Criteria::FREQUENCY_PUNCTUAL) {
                    // punctual return => criteria is the same than the solidary proposalLinked criteria
                    return clone $solidaryMatching->getSolidary()->getProposal()->getProposalLinked()->getCriteria();
                } else {
                    // regular => build criteria from matching days
                    return $this->createCriteriaForRegular($solidaryMatching->getSolidary()->getProposal()->getProposalLinked()->getCriteria(), $solidaryMatching->getSolidaryUser());
                }
                break;
        }
    }

    /**
     * Create a Criteria from a base criteria and a volunteer (find regular matching days and times)
     *
     * @param Criteria $baseCriteria    The base criteria
     * @param SolidaryUser $volunteer   The volunteer
     * @return void
     */
    private function createCriteriaForRegular(Criteria $baseCriteria, SolidaryUser $volunteer)
    {
        // we clone the base criteria and we replace the schedule by the availabilities
        $criteria = clone $baseCriteria;
        $criteria->setMonCheck(false);
        $criteria->setMonMinTime(null);
        $criteria->setMonMaxTime(null);
        $criteria->setMonTime(null);
        $criteria->setTueCheck(false);
        $criteria->setTueMinTime(null);
        $criteria->setTueMaxTime(null);
        $criteria->setTueTime(null);
        $criteria->setWedCheck(false);
        $criteria->setWedMinTime(null);
        $criteria->setWedMaxTime(null);
        $criteria->setWedTime(null);
        $criteria->setThuCheck(false);
        $criteria->setThuMinTime(null);
        $criteria->setThuMaxTime(null);
        $criteria->setThuTime(null);
        $criteria->setFriCheck(false);
        $criteria->setFriMinTime(null);
        $criteria->setFriMaxTime(null);
        $criteria->setFriTime(null);
        $criteria->setSatCheck(false);
        $criteria->setSatMinTime(null);
        $criteria->setSatMaxTime(null);
        $criteria->setSatTime(null);
        $criteria->setSunCheck(false);
        $criteria->setSunMinTime(null);
        $criteria->setSunMaxTime(null);
        $criteria->setSunTime(null);
        if (
            $baseCriteria->isMonCheck() &&
            (
                ($volunteer->hasMMon() && strtotime($baseCriteria->getMonMinTime()->format('H:i:s')) < strtotime($volunteer->getMMaxTime()->format('H:i:s')) && strtotime($baseCriteria->getMonMaxTime()->format('H:i:s')) >= strtotime($volunteer->getMMinTime()->format('H:i:s'))) ||
                ($volunteer->hasAMon() && strtotime($baseCriteria->getMonMinTime()->format('H:i:s')) < strtotime($volunteer->getAMaxTime()->format('H:i:s')) && strtotime($baseCriteria->getMonMaxTime()->format('H:i:s')) >= strtotime($volunteer->getAMinTime()->format('H:i:s'))) ||
                ($volunteer->hasEMon() && strtotime($baseCriteria->getMonMinTime()->format('H:i:s')) < strtotime($volunteer->getEMaxTime()->format('H:i:s')) && strtotime($baseCriteria->getMonMaxTime()->format('H:i:s')) >= strtotime($volunteer->getEMinTime()->format('H:i:s')))
            )
        ) {
            $criteria->setMonCheck(true);
            $criteria->setMonMinTime($baseCriteria->getMonMinTime());
            $criteria->setMonMaxTime($baseCriteria->getMonMaxTime());
            $criteria->setMonTime($baseCriteria->getMonTime());
        }
        if (
            $baseCriteria->isTueCheck() &&
            (
                ($volunteer->hasMTue() && strtotime($baseCriteria->getTueMinTime()->format('H:i:s')) < strtotime($volunteer->getMMaxTime()->format('H:i:s')) && strtotime($baseCriteria->getTueMaxTime()->format('H:i:s')) >= strtotime($volunteer->getMMinTime()->format('H:i:s'))) ||
                ($volunteer->hasATue() && strtotime($baseCriteria->getTueMinTime()->format('H:i:s')) < strtotime($volunteer->getAMaxTime()->format('H:i:s')) && strtotime($baseCriteria->getTueMaxTime()->format('H:i:s')) >= strtotime($volunteer->getAMinTime()->format('H:i:s'))) ||
                ($volunteer->hasETue() && strtotime($baseCriteria->getTueMinTime()->format('H:i:s')) < strtotime($volunteer->getEMaxTime()->format('H:i:s')) && strtotime($baseCriteria->getTueMaxTime()->format('H:i:s')) >= strtotime($volunteer->getEMinTime()->format('H:i:s')))
            )
        ) {
            $criteria->setTueCheck(true);
            $criteria->setTueMinTime($baseCriteria->getTueMinTime());
            $criteria->setTueMaxTime($baseCriteria->getTueMaxTime());
            $criteria->setTueTime($baseCriteria->getTueTime());
        }
        if (
            $baseCriteria->isWedCheck() &&
            (
                ($volunteer->hasMWed() && strtotime($baseCriteria->getWedMinTime()->format('H:i:s')) < strtotime($volunteer->getMMaxTime()->format('H:i:s')) && strtotime($baseCriteria->getWedMaxTime()->format('H:i:s')) >= strtotime($volunteer->getMMinTime()->format('H:i:s'))) ||
                ($volunteer->hasAWed() && strtotime($baseCriteria->getWedMinTime()->format('H:i:s')) < strtotime($volunteer->getAMaxTime()->format('H:i:s')) && strtotime($baseCriteria->getWedMaxTime()->format('H:i:s')) >= strtotime($volunteer->getAMinTime()->format('H:i:s'))) ||
                ($volunteer->hasEWed() && strtotime($baseCriteria->getWedMinTime()->format('H:i:s')) < strtotime($volunteer->getEMaxTime()->format('H:i:s')) && strtotime($baseCriteria->getWedMaxTime()->format('H:i:s')) >= strtotime($volunteer->getEMinTime()->format('H:i:s')))
            )
        ) {
            $criteria->setWedCheck(true);
            $criteria->setWedMinTime($baseCriteria->getWedMinTime());
            $criteria->setWedMaxTime($baseCriteria->getWedMaxTime());
            $criteria->setWedTime($baseCriteria->getWedTime());
        }
        if (
            $baseCriteria->isThuCheck() &&
            (
                ($volunteer->hasMThu() && strtotime($baseCriteria->getThuMinTime()->format('H:i:s')) < strtotime($volunteer->getMMaxTime()->format('H:i:s')) && strtotime($baseCriteria->getThuMaxTime()->format('H:i:s')) >= strtotime($volunteer->getMMinTime()->format('H:i:s'))) ||
                ($volunteer->hasAThu() && strtotime($baseCriteria->getThuMinTime()->format('H:i:s')) < strtotime($volunteer->getAMaxTime()->format('H:i:s')) && strtotime($baseCriteria->getThuMaxTime()->format('H:i:s')) >= strtotime($volunteer->getAMinTime()->format('H:i:s'))) ||
                ($volunteer->hasEThu() && strtotime($baseCriteria->getThuMinTime()->format('H:i:s')) < strtotime($volunteer->getEMaxTime()->format('H:i:s')) && strtotime($baseCriteria->getThuMaxTime()->format('H:i:s')) >= strtotime($volunteer->getEMinTime()->format('H:i:s')))
            )
        ) {
            $criteria->setThuCheck(true);
            $criteria->setThuMinTime($baseCriteria->getThuMinTime());
            $criteria->setThuMaxTime($baseCriteria->getThuMaxTime());
            $criteria->setThuTime($baseCriteria->getThuTime());
        }
        if (
            $baseCriteria->isFriCheck() &&
            (
                ($volunteer->hasMFri() && strtotime($baseCriteria->getFriMinTime()->format('H:i:s')) < strtotime($volunteer->getMMaxTime()->format('H:i:s')) && strtotime($baseCriteria->getFriMaxTime()->format('H:i:s')) >= strtotime($volunteer->getMMinTime()->format('H:i:s'))) ||
                ($volunteer->hasAFri() && strtotime($baseCriteria->getFriMinTime()->format('H:i:s')) < strtotime($volunteer->getAMaxTime()->format('H:i:s')) && strtotime($baseCriteria->getFriMaxTime()->format('H:i:s')) >= strtotime($volunteer->getAMinTime()->format('H:i:s'))) ||
                ($volunteer->hasEFri() && strtotime($baseCriteria->getFriMinTime()->format('H:i:s')) < strtotime($volunteer->getEMaxTime()->format('H:i:s')) && strtotime($baseCriteria->getFriMaxTime()->format('H:i:s')) >= strtotime($volunteer->getEMinTime()->format('H:i:s')))
            )
        ) {
            $criteria->setFriCheck(true);
            $criteria->setFriMinTime($baseCriteria->getFriMinTime());
            $criteria->setFriMaxTime($baseCriteria->getFriMaxTime());
            $criteria->setFriTime($baseCriteria->getFriTime());
        }
        if (
            $baseCriteria->isSatCheck() &&
            (
                ($volunteer->hasMSat() && strtotime($baseCriteria->getSatMinTime()->format('H:i:s')) < strtotime($volunteer->getMMaxTime()->format('H:i:s')) && strtotime($baseCriteria->getSatMaxTime()->format('H:i:s')) >= strtotime($volunteer->getMMinTime()->format('H:i:s'))) ||
                ($volunteer->hasASat() && strtotime($baseCriteria->getSatMinTime()->format('H:i:s')) < strtotime($volunteer->getAMaxTime()->format('H:i:s')) && strtotime($baseCriteria->getSatMaxTime()->format('H:i:s')) >= strtotime($volunteer->getAMinTime()->format('H:i:s'))) ||
                ($volunteer->hasESat() && strtotime($baseCriteria->getSatMinTime()->format('H:i:s')) < strtotime($volunteer->getEMaxTime()->format('H:i:s')) && strtotime($baseCriteria->getSatMaxTime()->format('H:i:s')) >= strtotime($volunteer->getEMinTime()->format('H:i:s')))
            )
        ) {
            $criteria->setSatCheck(true);
            $criteria->setSatMinTime($baseCriteria->getSatMinTime());
            $criteria->setSatMaxTime($baseCriteria->getSatMaxTime());
            $criteria->setSatTime($baseCriteria->getSatTime());
        }
        if (
            $baseCriteria->isSunCheck() &&
            (
                ($volunteer->hasMSun() && strtotime($baseCriteria->getSunMinTime()->format('H:i:s')) < strtotime($volunteer->getMMaxTime()->format('H:i:s')) && strtotime($baseCriteria->getSunMaxTime()->format('H:i:s')) >= strtotime($volunteer->getMMinTime()->format('H:i:s'))) ||
                ($volunteer->hasASun() && strtotime($baseCriteria->getSunMinTime()->format('H:i:s')) < strtotime($volunteer->getAMaxTime()->format('H:i:s')) && strtotime($baseCriteria->getSunMaxTime()->format('H:i:s')) >= strtotime($volunteer->getAMinTime()->format('H:i:s'))) ||
                ($volunteer->hasESun() && strtotime($baseCriteria->getSunMinTime()->format('H:i:s')) < strtotime($volunteer->getEMaxTime()->format('H:i:s')) && strtotime($baseCriteria->getSunMaxTime()->format('H:i:s')) >= strtotime($volunteer->getEMinTime()->format('H:i:s')))
            )
        ) {
            $criteria->setSunCheck(true);
            $criteria->setSunMinTime($baseCriteria->getSunMinTime());
            $criteria->setSunMaxTime($baseCriteria->getSunMaxTime());
            $criteria->setSunTime($baseCriteria->getSunTime());
        }
        return $criteria;
    }
}