Skip to content
Snippets Groups Projects
Select Git revision
  • e4433a9f8e153d2df7a6104090e5cdb1c3d9808b
  • master default protected
  • update-2.0.0-dev
  • alc-refactoring-entity
  • sb-comments-update
  • alc-dev
  • 2.0.2
  • 2.0.1
  • 2.0.0
  • 1.0.7
  • 1.0.6
  • 1.0.5
  • 1.0.4
  • 1.0.3
  • 1.0.2
  • 1.0.1
  • 0.1.5
  • 1.0.0
  • 0.1.4
  • 0.1.3
  • 0.1.2
  • 0.1.1
  • 0.0.15
  • 0.0.14
  • 0.0.13
  • 0.0.12
26 results

ProcessService.php

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    ProcessService.php 14.28 KiB
    <?php
    
    namespace UnicaenSignature\Service;
    
    use DoctrineModule\Persistence\ProvidesObjectManager;
    use Exception;
    use Laminas\EventManager\EventManager;
    use UnicaenSignature\Entity\Db\Process;
    use UnicaenSignature\Entity\Db\ProcessStep;
    use UnicaenSignature\Entity\Db\Signature;
    use UnicaenSignature\Entity\Db\SignatureFlow;
    use UnicaenSignature\Entity\Db\SignatureObserver;
    use UnicaenSignature\Entity\Db\SignatureRecipient;
    use UnicaenSignature\Entity\Repository\ProcessRepository;
    use UnicaenSignature\Event\ProcessEvent;
    use UnicaenSignature\Exception\SignatureException;
    
    class ProcessService
    {
        use
            LoggerServiceAwareTrait,
            ProvidesObjectManager,
            SharedEventManagerAwareTrait,
            SignatureConfigurationServiceAwareTrait,
            SignatureServiceAwareTrait;
    
        /**
         * @return ProcessRepository
         */
        protected function getProcessRepository(): ProcessRepository
        {
            return $this->getObjectManager()->getRepository(Process::class);
        }
    
        //////////////////////////////////////////////////////////////////////////////////////////////////////////
    
        /**
         * @return SignatureFlow[]
         */
        public function getSignatureFlows(): array
        {
            return $this->getSignatureService()->getSignatureFlows();
        }
    
        public function getSignatureFlow(int $id): SignatureFlow
        {
            return $this->getSignatureService()->getSignatureFlowById($id);
        }
    
        /**
         * @return Process[]
         */
        public function getProcesses(): array
        {
            return $this->getObjectManager()->getRepository(Process::class)->findAll();
        }
    
        /**
         * @param int $processId
         *
         * @return Process
         * @throws SignatureException
         */
        public function getProcessById(int $processId): Process
        {
            try {
                return $this->getObjectManager()->getRepository(Process::class)->find($processId);
            } catch (Exception $e) {
                $this->getLoggerService()->errorLogAndThrow($e, "Impossible de charger le processus '$processId'");
            }
        }
    
        /**
         * @param int $processId
         *
         * @return void
         * @throws SignatureException
         */
        public function deleteProcessById(int $processId): void
        {
            $this->deleteProcess($this->getProcessById($processId));
        }
    
        /**
         * Suppression d'un processus.
         *
         * @param Process $process
         * @return void
         * @throws SignatureException
         */
        public function deleteProcess(Process $process): void
        {
            try {
                // Emplacement du document
                $document = $this->getSignatureConfigurationService()->getDocumentsLocation()
                    . DIRECTORY_SEPARATOR
                    . $process->getDocumentName();
    
                foreach ($process->getSteps() as $step) {
                    $signature = $step->getSignature();
                    $this->getSignatureService()->deleteSignature($signature, false, false);
                    $this->getObjectManager()->remove($step);
                }
    
                $this->getObjectManager()->remove($process);
                $this->getObjectManager()->flush();
    
                if (!@unlink($document)) {
                    $err = error_get_last()['message'] ?? "unknown error";
                    $this->getLoggerService()->warning("Impossible de supprimer le document '$document' : $err");
                }
            } catch (Exception $e) {
                $this->getLoggerService()->errorLogAndThrow($e, "Impossible de supprimer le processus");
            }
        }
    
        /**
         * Retourne les informations du document du processus.
         *
         * @param Process $process
         * @return array
         * @throws SignatureException
         */
        public function getProcessDocumentDatas(Process $process): array
        {
            $docDir = $this->getSignatureConfigurationService()->getDocumentsLocation();
            $docName = $process->getDocumentName();
            $docPath = $docDir . DIRECTORY_SEPARATOR . $docName;
            $docMime = mime_content_type($docPath);
            $docDatas = file_get_contents($docPath);
            return [
                'name'  => $docName,
                'mime'  => $docMime,
                'path'  => $docPath,
                'datas' => $docDatas,
            ];
        }
    
        /**
         * Création d'un processus vide.
         *
         * @param string $documentName
         * @param int $signatureFlowId
         * @return Process
         */
        public function createUnconfiguredProcess(string $documentName, int $signatureFlowId): Process
        {
            $process = new Process();
            $this->getObjectManager()->persist($process);
            $process->setDocumentName($documentName)
                ->setStatus(Signature::STATUS_PROCESS_UNCONFIGURED)
                ->setSignatureFlow($this->getSignatureFlow($signatureFlowId));
            $this->getObjectManager()->flush();
            return $process;
        }
    
        /**
         * Configuration du processus
         *
         * [
         *  'steps':[
         *    'label': string,
         *    'description': string,
         *    'allSignToComplete': boolean,
         *    'letterfilename': string,
         *    'level': string,
         *    'order': integer,
         *    'recipients': [
         *      {'firstname': string, 'lastname': string, 'email': string }
         *    ]
         *  ]
         *
         * @param Process $process
         * @param array $jsonDatas
         * @return void
         * @throws SignatureException
         */
        public function configureProcess(Process $process, array $jsonDatas): void
        {
            $signatureFlow = $process->getSignatureFlow();
    
            $process->setDateCreated(new \DateTime())
                ->setStatus(Signature::STATUS_SIGNATURE_DRAFT);
    
            foreach ($jsonDatas['steps'] as $stepData) {
                $signatureFlowStep = $signatureFlow->getStepAtOrder($stepData['order']);
    
                // Création des étapes
                $processStep = new ProcessStep();
                $this->getObjectManager()->persist($processStep);
    
                $processStep->setSignatureFlowStep($signatureFlowStep);
                $processStep->setProcess($process);
                $process->getSteps()->add($processStep);
    
                // Création de la signature
                $signature = new Signature();
                $this->getObjectManager()->persist($signature);
                $signature->setDocumentPath($process->getDocumentName())
                    ->setStatus(Signature::STATUS_SIGNATURE_DRAFT)
                    ->setDateCreated(new \DateTime())
                    ->setLabel($process->getLabel() . ' - ' . $stepData['label'])
                    ->setContextShort($stepData['context_subject'] ?? "")
                    ->setContextLong($stepData['context_body'] ?? "")
                    ->setDescription($stepData['description'])
                    ->setAllSignToComplete($stepData['allSignToComplete'])
                    ->setNotificationsRecipients($signatureFlowStep->isNotificationsRecipients())
                    ->setLetterfileKey($stepData['letterfilename'])
                    ->setOrder($signatureFlowStep->getOrder())
                    ->setType($stepData['level']);
    
                $processStep->setSignature($signature);
    
                foreach ($stepData['recipients'] as $recipientData) {
                    $signatureRecipient = new SignatureRecipient();
                    $this->getObjectManager()->persist($signatureRecipient);
                    $signatureRecipient->setSignature($signature)
                        ->setStatus(Signature::STATUS_SIGNATURE_DRAFT)
                        ->setLastname($recipientData['lastname'])
                        ->setFirstname($recipientData['firstname'])
                        ->setEmail($recipientData['email']);
                    $signature->getRecipients()->add($signatureRecipient);
                }
    
                foreach ($stepData['observers'] as $observerData) {
                    $signatureObserver = new SignatureObserver();
                    $this->getObjectManager()->persist($signatureObserver);
                    $signatureObserver->setSignature($signature)
                        ->setLastname($observerData['lastname'])
                        ->setFirstname($observerData['firstname'])
                        ->setEmail($observerData['email']);
                    $signature->getObservers()->add($signatureObserver);
                }
            }
    
            try {
                $this->getObjectManager()->flush();
            } catch (Exception $e) {
                $this->getLoggerService()->errorLogAndThrow($e, 'Impossible de configurer la procédure');
            }
        }
    
        /**
         * @param int $idProcess
         * @param bool $forceFirstSend
         * @return void
         * @throws SignatureException
         * @see trigger
         */
        public function triggerById(int $idProcess, bool $forceFirstSend = false)
        {
            $this->trigger($this->getProcessById($idProcess), $forceFirstSend);
        }
    
        /**
         * Déclenchement / recalcule du processus.
         *
         * @param Process $process
         * @param bool $forceFirstSend
         * @return void
         * @throws SignatureException
         */
        public function trigger(Process $process, bool $forceFirstSend = false): void
        {
            if ($process->isSendable() && $forceFirstSend) {
                try {
                    $process->setCurrentStep(1);
                    $processStep = $process->getStep();
                    $process->setStatus(Signature::STATUS_SIGNATURE_WAIT);
                    $this->getObjectManager()->flush();
                    $this->getObjectManager()->refresh($process);
                    $this->getObjectManager()->refresh($processStep);
                    $this->getSignatureService()->sendSignature($processStep->getSignature());
                    $this->triggerProcessEvent($process, ProcessEvent::EVENT_TYPE_START);
                } catch (Exception $e) {
                    $this->getLoggerService()->errorLogAndThrow(
                        $e,
                        "Impossible d'envoyer le document à signer : " . $e->getMessage()
                    );
                }
                return;
            }
    
            // Envoi (etape 1)
            if ($process->isTriggerable()) {
                try {
                    $processStep = $process->getStep();
    
                    if ($processStep->getStatus() == Signature::STATUS_SIGNATURE_DRAFT) {
                        $this->getSignatureService()->sendSignature($processStep->getSignature());
                        $this->triggerProcessEvent($process, ProcessEvent::EVENT_TYPE_STEP);
                        return;
                    }
    
                    $this->getSignatureService()->updateStatusSignature($processStep->getSignature());
    
                    if ($processStep->getStatus() == Signature::STATUS_SIGNATURE_REJECT) {
                        $process->setStatus(Signature::STATUS_SIGNATURE_REJECT);
                        /** @var SignatureRecipient $recipient */
                        foreach ($processStep->getSignature()->getRecipients() as $recipient) {
                            if ($recipient->getStatus() != Signature::STATUS_SIGNATURE_REJECT) {
                                $recipient->setStatus(Signature::STATUS_SIGNATURE_CANCEL);
                            }
                        }
                        $this->getObjectManager()->flush();
                        $this->triggerProcessEvent($process, ProcessEvent::EVENT_TYPE_REJECTED);
                        return;
                    }
    
                    if ($processStep->getStatus() == Signature::STATUS_SIGNATURE_SIGNED) {
                        $totalSteps = count($process->getSteps());
                        $currentStep = $processStep->getOrder();
                        $this->getLoggerService()->info(
                            " - progression étapes : " . $processStep->getOrder() . '/' . count($process->getSteps())
                        );
                        if ($currentStep == $totalSteps) {
                            // FIN du PROCESSUS
                            $process->setStatus(Signature::STATUS_SIGNATURE_SIGNED);
                            $this->getObjectManager()->flush();
                            $this->triggerProcessEvent($process, ProcessEvent::EVENT_TYPE_SIGNED);
                            return;
                        }
                        else {
                            // PASSAGE à l'ETAPE SUIVANTE
                            $process->setCurrentStep($process->getCurrentStep() + 1);
                            $this->getObjectManager()->flush();
                            $this->trigger($process);
                        }
    
                        return;
                    }
                } catch (Exception $e) {
                    $this->getLoggerService()->errorLogAndThrow(
                        $e,
                        "Impossible d'actualiser le processus : " . $e->getMessage()
                    );
                }
            }
            elseif ($process->isFinished()) {
                $this->getLoggerService()->info("Processus terminé");
                throw new SignatureException("Ce processus est terminé");
            }
            else {
                $this->getLoggerService()->info("Processus " . $process->getStatusText());
            }
        }
    
        /**
         * Méthode qui renvoie une synthèse des infos process de signature pour affichage
         *
         * @param Process $process
         * @return array
        */
        public function getInfosProcess(Process $process): array
        {
            $infosProcess = [];
            foreach ($process->getSteps() as $keyStep => $step) {
                if ($step->getStatus() == Signature::STATUS_SIGNATURE_SIGNED ||
                    $step->getStatus() == Signature::STATUS_SIGNATURE_WAIT) {
                    $infosProcess[$keyStep] = $step->toArray();
                    if ($step->getStatus() == Signature::STATUS_SIGNATURE_SIGNED) {
                        $labelInfo     = 'signé par ';
                        $recipient     = current($infosProcess[$keyStep]['recipients']);
                        $dateSignature = new \DateTime($recipient['dateFinished']);
                        $labelInfo     .= $recipient['fullname'] . ' le ' . $dateSignature->format('d/m/Y');
    
                        $infosProcess[$keyStep]['labelInfos'] = $labelInfo;
                    }
                    if ($step->getStatus() == Signature::STATUS_SIGNATURE_WAIT) {
                        $labelInfo                                           = 'en attente de signature';
                        $infosProcess[$keyStep]['labelInfos'] = $labelInfo;
                    }
                }
    
            }
    
            return $infosProcess;
    
        }
    
        /**
         * @param Process $process
         * @param string $eventType
         * @return void
         */
        protected function triggerProcessEvent(Process $process, string $eventType): void
        {
            $this->getLoggerService()->info("[EVENT PROCESS] >>> $eventType : $process");
            $em = new EventManager($this->getSharedEventManager());
            $em->triggerEvent(new ProcessEvent($eventType, null, ['id' => $process->getId()]));
        }
    }