Select Git revision
VolumeHoraireController.php
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
SignatureService.php 41.95 KiB
<?php
namespace UnicaenSignature\Service;
use DoctrineModule\Persistence\ProvidesObjectManager;
use Exception;
use JetBrains\PhpStorm\NoReturn;
use Laminas\EventManager\EventManager;
use UnicaenSignature\Entity\Db\Process;
use UnicaenSignature\Entity\Db\Signature;
use UnicaenSignature\Entity\Db\SignatureFlow;
use UnicaenSignature\Entity\Db\SignatureFlowStep;
use UnicaenSignature\Entity\Db\SignatureRecipient;
use UnicaenSignature\Entity\Repository\SignatureFlowRepository;
use UnicaenSignature\Entity\Repository\SignatureRecipientRepository;
use UnicaenSignature\Entity\Repository\SignatureRepository;
use UnicaenSignature\Event\SignatureEvent;
use UnicaenSignature\Formatter\ObjectFormatter;
use UnicaenSignature\Utils\SignatureConstants;
use UnicaenSignature\Exception\SignatureException;
class SignatureService
{
use
LetterfileServiceAwareTrait,
LoggerServiceAwareTrait,
ProvidesObjectManager,
SharedEventManagerAwareTrait,
ServiceContainerAwareTrait,
SignatureConfigurationServiceAwareTrait;
const ERR_SIGNATURETYPE_LIST = "Impossible de charger la liste des types de signature";
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///// GET/READ
public function getSignatureRepository(): SignatureRepository
{
return $this->getObjectManager()->getRepository(Signature::class);
}
protected function getSignatureFlowRepository(): SignatureFlowRepository
{
return $this->getObjectManager()->getRepository(SignatureFlow::class);
}
protected function getProcessRepository()
{
return $this->getObjectManager()->getRepository(Process::class);
}
/**
* @return SignatureRecipientRepository
*/
protected function getSignatureRecipientRepository()
{
return $this->getObjectManager()
->getRepository(SignatureRecipient::class);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///// LISTES
/**
* @return Signature[]
* @throws Exception
*/
public function getSignatures(): array
{
try {
return $this->getSignatureRepository()->findAll();
} catch (Exception $e) {
$this->getLoggerService()->critical("Get signature ERROR : " . $e->getMessage());
throw new SignatureException("Impossible de charger les signatures");
}
}
/**
* @return Signature[]
* @throws SignatureException
*/
public function getSignaturesSimples(): array
{
try {
return $this->getSignatureRepository()->getSignaturesSimples();
} catch (Exception $e) {
$this->getLoggerService()->critical("Get signature ERROR : " . $e->getMessage());
throw new SignatureException("Impossible de charger les signatures");
}
}
/**
* @return Signature[]
* @throws SignatureException
*/
public function getSignaturesUpdatable(): array
{
try {
return $this->getSignatureRepository()->getSignaturesUpdatable();
} catch (Exception $e) {
$this->getLoggerService()->error($e->getMessage());
throw new SignatureException("Impossible de charger les signatures éligibles à une mise à jour");
}
}
/**
* @param int $id
* @return Signature
* @throws SignatureException
*/
public function getSignature(int $id): Signature
{
try {
/** @var Signature $signature */
$s = $this->getSignatureRepository()->find($id);
if ($s === null) {
throw new Exception("Signature avec l'ID '$id' non-trouvée");
}
return $s;
} catch (Exception $e) {
$msg = "Impossible de trouver la demande de signature '$id'";
$this->getLoggerService()->error("$msg : " . $e->getMessage());
throw new SignatureException($msg);
}
}
/**
* @param string|null $email
* @return SignatureRecipient[]
* @throws SignatureException
*/
public function getSignaturesRecipientsByEmail(?string $email): array
{
if ($email) {
return $this->getSignatureRecipientRepository()->getRecipientSignatures(
$email,
[
Signature::STATUS_SIGNATURE_WAIT,
Signature::STATUS_SIGNATURE_SIGNED,
Signature::STATUS_SIGNATURE_REJECT
]
);
}
throw new SignatureException("Impossible de charger vos documents (Vous n'avez pas d'email)");
}
/**
* @param string|null $email
* @param string|null $letterfile
* @return SignatureRecipient[]
* @throws SignatureException
*/
public function getSignaturesRecipientsByEmailWaiting(?string $email, string|null $letterfile = null): array
{
if ($email) {
return $this->getSignatureRecipientRepository()->getRecipientSignatures(
$email,
[
Signature::STATUS_SIGNATURE_WAIT
],
$letterfile
);
}
throw new SignatureException("Impossible de charger vos documents (Vous n'avez pas d'email)");
}
/**
* Affichage des informations du document.
*
* @param Signature $signature
* @return array
* @throws SignatureException
*/
public function getDocumentData(Signature $signature): array
{
$docDir = $this->getSignatureConfigurationService()->getDocumentsLocation();
$docName = $signature->getDocumentPath();
$docPath = $docDir . DIRECTORY_SEPARATOR . $docName;
$docMime = mime_content_type($docPath);
$docDatas = file_get_contents($docPath);
return [
'name' => $docName,
'mime' => $docMime,
'path' => $docPath,
'datas' => $docDatas,
];
}
/**
* @param string $letterFileKey
* @return array
* @throws SignatureException
*/
public function getMarksSelectFromLetterFile(string $letterFileKey): array
{
$letterFile = $this->getLetterfileService()->getLetterFileStrategy($letterFileKey);
return $this->getMarksSelectFrom(array_keys($letterFile->getLevels()));
}
/**
* @param array $marksKeys
* @return array
* @throws SignatureException
*/
public function getMarksSelectFrom(array $marksKeys): array
{
$select = [];
foreach ($marksKeys as $mark) {
$levelInfos = $this->getSignatureConfigurationService()->getLevelByName($mark);
$select[$mark] = $levelInfos->getLabel();
}
return $select;
}
/**
* Construction des données pour déclencher une procédure de signature.
*
* @param string $urlDocPreview
* @param int $signatureFlowId
* @param array $extrasOptions
* @return array
*/
public function createSignatureFlowDatasById(
string $urlDocPreview,
int $signatureFlowId,
array $extrasOptions
): array {
$out = [];
/** @var SignatureFlow $signatureFlow */
$signatureFlow = $this->getSignatureFlowRepository()->find($signatureFlowId);
$out['signatureflow'] = [
'id' => $signatureFlow->getId(),
'label' => $signatureFlow->getLabel(),
'description' => $signatureFlow->getDescription(),
//'missing_recipients' => false,
'doc_url' => $urlDocPreview,
'steps' => []
];
$context_subject = "";
$context_body = "";
// Extration du contexte depuis les options
if (array_key_exists("context_subject", $extrasOptions)) {
$context_subject = $extrasOptions['context_subject'];
}
// Extration du contexte depuis les options
if (array_key_exists("context_body", $extrasOptions)) {
$context_body = $extrasOptions['context_body'];
}
$missing_recipients = false;
$letterfiles = $this->getSignatureConfigurationService()->getLetterFiles();
/** @var SignatureFlowStep $step */
foreach ($signatureFlow->getSteps() as $step) {
$letterfile = $letterfiles[$step->getLetterfileName()];
$levels = $letterfile['levels_infos'];
$method = $this->getSignatureConfigurationService()->getMethodByKey($step->getRecipientsMethod());
$currentStep = [];
$currentStep['id'] = $step->getId();
$currentStep['label'] = $step->getLabel();
$currentStep['context_subject'] = $context_subject;
$currentStep['context_body'] = $context_body;
$currentStep['description'] = "";
$currentStep['order'] = $step->getOrder();
$currentStep['letterfilename'] = $step->getLetterfileName();
$currentStep['letterfile_label'] = $letterfile['label'];
$currentStep['level'] = $step->getLevel();
$currentStep['level_label'] = $levels[$step->getLevel()]['label'];
$currentStep['level_in_letterfile'] = $levels[$step->getLevel()]['key_in_letterfile'];
$currentStep['allSignToComplete'] = $step->isAllRecipientsSign();
$currentStep['editable'] = $step->isEditableRecipients();
$currentStep['missing_recipients'] = false;
$currentStep['recipient_method'] = $step->getRecipientsMethod();
$currentStep['options'] = $step->getOptions();
$currentStep['dynamicRecipients'] = (!empty($method))?is_callable($method['getRecipients']):false;
$currentStep['recipients'] = [];
$currentStep['observers'] = [];
if ($step->getObserversMethod()) {
$methodObservers = $this->getSignatureConfigurationService()->getMethodByKey(
$step->getObserversMethod()
);
if (is_callable($methodObservers['getRecipients'])) {
$options = array_merge_recursive($extrasOptions, $step->getObserversOptions());
$observersDatas = $methodObservers['getRecipients']($this->getServiceContainer(), $options);
$observers = array_values($observersDatas);
}
else {
$observers = $step->getOptions()['observers'];
}
}
else {
$observers = [];
}
//Uniquement si on a définit des méthodes dynamiques de récupération dans la config unicaen-signature
if (is_callable($method['getRecipients'])) {
$options = array_merge_recursive($extrasOptions, $step->getOptions());
$recipientsDatas = $method['getRecipients']($this->getServiceContainer(), $options);
$recipients = array_values($recipientsDatas);
}
else {
$recipients = $step->getOptions()['recipients'];
}
if ($recipients == null) {
$recipients = [];
}
if ($observers == null) {
$observers = [];
}
if ($step->isEditableRecipients()) {
foreach ($recipients as &$recipient) {
$recipient['selected'] = true;
}
foreach ($observers as &$observer) {
$observer['selected'] = true;
}
}
$currentStep['recipients'] = $recipients;
$currentStep['observers'] = $observers;
if (count($currentStep['recipients']) == 0) {
$missing_recipients = true;
$currentStep['missing_recipients'] = true;
}
$out['signatureflow']['steps'][] = $currentStep;
}
$out['signatureflow']['missing_recipients'] = $missing_recipients;
return $out;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// API
///
public function saveSignatureFlowFromJSON(array $jsonSend): void
{
$id = $jsonSend['id'];
if ($id) {
try {
$signatureFlow = $this->getSignatureFlowRepository()->find($id);
} catch (Exception $e) {
$this->getLoggerService()->errorLogAndThrow($e, "Impossible de charger le processus '$id'");
}
}
else {
$signatureFlow = new SignatureFlow();
$this->getObjectManager()->persist($signatureFlow);
}
try {
$signatureFlow->setLabel($jsonSend['label'])
->setEnabled($jsonSend['enabled'])
->setDescription($jsonSend['description']);
$existStep = $signatureFlow->getStepsIndexed();
$remove = array_keys($existStep);
$stepsOrder = [];
foreach ($jsonSend['steps'] as $stepData) {
if ($stepData['id']) {
$step = $existStep[$stepData['id']];
$stepsOrder[] = $step;
$k = array_search($stepData['id'], $remove);
unset($remove[$k]);
}
else {
$step = new SignatureFlowStep();
$stepsOrder[] = $step;
$this->getObjectManager()->persist($step);
$signatureFlow->getSteps()->add($step);
$step->setSignatureFlow($signatureFlow);
}
$step->setLabel($stepData['label'])
->setAllRecipientsSign($stepData['allRecipientsSign'] && $stepData['allRecipientsSign'] == true)
->setNotificationsRecipients(
$stepData['notificationsRecipients'] && $stepData['notificationsRecipients'] == true
)
->setEditableRecipients($stepData['editable'] && $stepData['editable'] == true)
->setOptions($stepData['options'] ? $stepData['options'] : [])
->setLetterfileName($stepData['letterfile'])
->setObserversMethod($stepData['observers_method'])
->setObserversOptions($stepData['observers_options'])
->setRecipientsMethod($stepData['method'])
->setLevel($stepData['level']);
}
$order = 1;
foreach ($stepsOrder as $step) {
$step->setOrder($order);
$order++;
}
foreach ($remove as $id) {
$this->getObjectManager()->remove($existStep[$id]);
}
try {
$this->getObjectManager()->flush();
} catch (Exception $e) {
$this->getLoggerService()->errorLogAndThrow($e, "Impossible d'enregistrer la procédure");
}
} catch (Exception $e) {
$this->getLoggerService()->errorLogAndThrow($e, "Impossible d'enregistrer le processus de signature");
}
}
public function deleteSignatureFlowFromJSON(array $jsonSend): void
{
try {
$id = $jsonSend['id'];
$signatureFlow = $this->getSignatureFlowRepository()->find($id);
} catch (Exception $e) {
$this->getLoggerService()->errorLogAndThrow($e, "Impossible de charger le processus '$id'");
}
try {
$this->getObjectManager()->remove($signatureFlow);
$this->getObjectManager()->flush();
} catch (Exception $e) {
$this->getLoggerService()->errorLogAndThrow($e, "Impossible de supprimer le processus '$id'");
}
}
public function getSignatureFlows(
string $format = SignatureConstants::FORMAT_DEFAULT,
bool $justActives = false
): array {
try {
$objectFormatter = new ObjectFormatter();
if ($justActives) {
$signatureFlows = $this->getObjectManager()->getRepository(SignatureFlow::class)->findBy(
[
'enabled' => true
]
);
}
else {
$signatureFlows = $this->getObjectManager()->getRepository(SignatureFlow::class)->findAll();
}
return $objectFormatter->formatCollection($signatureFlows, ObjectFormatter::FORMAT_JSON);
} catch (Exception $e) {
$this->getLoggerService()->errorLogAndThrow($e, "Impossible de charger la liste des processus");
}
}
public function getSignatureFlowById(int $id): SignatureFlow
{
try {
$signatureFlow = $this->getObjectManager()->getRepository(SignatureFlow::class)->find($id);
if (!$signatureFlow) {
throw new SignatureException("Absent de la base de données");
}
return $signatureFlow;
} catch (Exception $e) {
$this->getLoggerService()->errorLogAndThrow($e, "Impossible de charger le modèle de processus");
}
}
public function getLetterFiles(string $format = SignatureConstants::FORMAT_DEFAULT): array
{
$config = $this->getSignatureConfigurationService()->getLetterfileConfiguration();
$levels = $this->getSignatureConfigurationService()->getLevels();
$out = [];
foreach ($config as $c) {
$levels = [];
foreach ($c['levels'] as $level => $useName) {
$levels[] = $this->getSignatureConfigurationService()->getLevelByName($level)->toArray();
}
$out[] = [
'name' => $c['name'],
'label' => $c['label'],
'description' => $c['description'],
'default' => $c['default'],
'levels' => $levels,
];
}
return $out;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/**
* Création d'une signature.
*
* @param Signature $signature
* @param bool $pushToLetterFile
* @return void
* @throws Exception
*/
public function saveNewSignature(Signature $signature, bool $pushToLetterFile = false): void
{
$this->getLoggerService()->info("Enregistrement de la demande de signature");
try {
$signature->setStatus(Signature::STATUS_SIGNATURE_DRAFT);
$this->getObjectManager()->persist($signature);
$this->getObjectManager()->flush($signature);
if ($pushToLetterFile) {
$this->getObjectManager()->refresh($signature);
$this->sendSignature($signature);
}
} catch (Exception $e) {
$msg = "Impossible d'enregistrer la demande de signature";
$this->getLoggerService()->critical("$msg : " . $e->getMessage());
throw new Exception($msg);
}
}
/**
* @param int $id
* @return void
* @throws SignatureException
*/
public function updateStatusSignatureById(int $id): void
{
$this->updateStatusSignature($this->getSignature($id));
}
/**
* @param Signature $signature
* @return void
* @throws SignatureException
*/
public function updateStatusSignature(
Signature $signature,
bool $callProcessStep = false,
bool $writeDocument = true
): bool {
$this->getLoggerService()->debug("### UPDATE STATUS '$signature'");
try {
if (!$signature->isFinished()) {
$documentSrc = $this->getSignatureConfigurationService()->getDocumentsLocation()
. DIRECTORY_SEPARATOR
. $signature->getDocumentPath();
if ($writeDocument && !is_writable($documentSrc)) {
$err = "L'emplacement de dépôt du document n'est pas accessible en écriture";
$this->getLoggerService()->critical("[update] $err : '$documentSrc'");
throw new SignatureException($err);
}
$letterFileStrategy = $this->getLetterfileService()->getLetterFileStrategy(
$signature->getLetterfileKey()
);
try {
$infos = $letterFileStrategy->getSignatureInfos($signature);
$status = $infos->getStatus();
} catch (Exception $e) {
$this->getLoggerService()->critical(
"[update] Impossible de mettre à jour le statut depuis le parapheur : "
. $e->getMessage()
);
throw new SignatureException("Impossible de mettre à jour le statut depuis le parapheur");
}
$statusChanged = $signature->getStatus() !== $status;
$signature->setStatus($status);
if ($statusChanged) {
$this->getLoggerService()->info(
"[update] Le statut a changé"
);
$signature->setDateUpdate(new \DateTime());
} else {
$this->getLoggerService()->info(
"[update] Le statut N'A PAS changé"
);
}
$events = [];
$infosObservers = [];
$subject = "[suivi] ";
$message = "";
foreach ($signature->getRecipients() as $recipient) {
$updateRequired = $recipient->isForceUpdate() || !$recipient->isDone();
if ($infos->isAccepted($recipient->getEmail()) && $updateRequired) {
$this->getLoggerService()->debug("$recipient a signé");
$recipient->setStatus(Signature::STATUS_SIGNATURE_SIGNED, true);
$recipient->setDateFinished($infos->getDateDone($recipient->getEmail()));
$events[] = [
'spot' => 'recipient',
'type' => SignatureEvent::EVENT_TYPE_RECIPIENT_SIGNED,
'id' => $recipient->getId()
];
$message .= " - $recipient a " . $signature->getParticiple() . " le document.\n\r";
}
if ($infos->isRefused($recipient->getEmail()) && $updateRequired) {
$recipient->setStatus(Signature::STATUS_SIGNATURE_REJECT, true);
$this->getLoggerService()->debug("$recipient a REJETé");
$events[] = [
'spot' => 'recipient',
'type' => SignatureEvent::EVENT_TYPE_SIGNED,
'id' => $recipient->getId()
];
$message .= " - $recipient a refusé le document.\n\r";
// TODO vérifier si on a la date de refus
}
if ($signature->isFinished() && $recipient->getStatus() == Signature::STATUS_SIGNATURE_WAIT) {
$this->getLoggerService()->debug("$recipient passé à ANNULé");
$recipient
->setStatus(Signature::STATUS_SIGNATURE_CANCEL, true)
->setDateUpdate(new \DateTime());
}
}
$this->getObjectManager()->flush();
if ($signature->getStatus() == Signature::STATUS_SIGNATURE_SIGNED) {
if ($writeDocument) {
$this->getLoggerService()->info("[update] Enregistrement du document");
$documentSrc = $this->getSignatureConfigurationService()->getDocumentsLocation()
. DIRECTORY_SEPARATOR
. $signature->getDocumentPath();
if (!file_put_contents(
$documentSrc,
$this->getDocumentSignedSignature($signature)
)) {
$this->getLoggerService()->errorLogAndThrow(
new SignatureException("Impossible de récupérer le document signé"),
"Impossible d'écrire le document"
);
}
}
if( $signature->getProcessStep() ){
$step = $signature->getProcessStep()->getOrder();
$steps = count($signature->getProcessStep()->getProcess()->getSteps());
$subject = "[suivi] étape $step/$steps du Document {DOCUMENT} terminée";
}
$events[] = [
'spot' => 'signature',
'type' => SignatureConstants::EVENT_SIGNATURE_SIGNED,
'id' => $signature->getId()
];
}
if ($signature->getStatus() == Signature::STATUS_SIGNATURE_REJECT) {
$subject = "[suivi] étape $step/$steps du Document {DOCUMENT} rejetée";
$events[] = [
'spot' => 'signature',
'type' => SignatureConstants::EVENT_SIGNATURE_REJECTED,
'id' => $signature->getId()
];
}
if( $message ){
foreach ($signature->getObservers() as $observer) {
$this->sendNotificationTo(
$observer->getEmail(),
$subject,
$message,
$signature
);
}
}
if (count($events)) {
$this->getLoggerService()->debug("Envoi des événements");
$em = new EventManager($this->getSharedEventManager());
foreach ($events as $event) {
$this->getLoggerService()->info(
sprintf(
'[EVENT %s] - %s (id = %s)',
$event['spot'],
$event['type'],
$event['id']
)
);
$em->trigger($event['type'], null, ['id' => $event['id']]);
}
}
if ($callProcessStep && $signature->getProcessStep()) {
/** @var ProcessService $processService */
$processService = $this->getServiceContainer()->get(ProcessService::class);
$processService->trigger($signature->getProcessStep()->getProcess());
}
return true;
}
} catch (Exception $e) {
throw new SignatureException("Impossible de mettre à jour le statut de la signature : " . $e->getMessage());
}
return false;
}
public function observersNotifications(array $events): void
{
}
/**
* Notification des destinataires.
*
* @return void
*/
#[NoReturn] public function recipientsNotifications(): void
{
$template = [
'subject' => 'Vous avez des documents à {action}',
'body' => "Bonjour,\n\rVous avez des documents à {action},\n\rVous pouvez vous rendre à l'URL {url}\n\r",
];
$recipients = $this->getSignatureRecipientRepository()->getRecipientsNotifiable();
foreach ($recipients as $recipient) {
echo "$recipient (" . $recipient->getSignature() . ")\n";
}
die("todo");
}
public function testTrigger()
{
$em = new EventManager($this->getSharedEventManager());
$em->trigger(SignatureConstants::EVENT_SIGNATURE_SIGNED, null, ['id' => 666]);
}
/**
* Mise à jour des signatures.
*
* @return void
* @throws SignatureException
*/
public function updateAll(): void
{
$signatures = $this->getSignatureRepository()->getSignaturesUpdatable();
foreach ($signatures as $signature) {
$this->updateStatusSignature($signature);
}
}
/**
* @param int $id
* @return void
* @throws SignatureException
*/
public function deleteSignatureById(int $id): void
{
$this->deleteSignature($this->getSignature($id));
}
/**
* Suppression d'une demande signature.
*
* @param Signature $signature
* @param bool $flush Enregistre les changements en BDD
* @param bool $removedoc Suppression du document source
* @return void
* @throws SignatureException
*/
public function deleteSignature(Signature $signature, bool $flush = true, bool $removedoc = true): void
{
$docName = $signature->getDocumentPath();
if ($signature->getStatus() == Signature::STATUS_SIGNATURE_DRAFT) {
try {
foreach ($signature->getRecipients() as $recipient) {
$this->getObjectManager()->remove($recipient);
}
foreach ($signature->getObservers() as $observer) {
$this->getObjectManager()->remove($observer);
}
$this->getObjectManager()->remove($signature);
if ($flush) {
$this->getObjectManager()->flush();
}
} catch (Exception $exception) {
$this->getLoggerService()->error("Error DB : " . $exception->getMessage());
throw new SignatureException("Impossible de supprimer la demande de la base de donnée");
}
}
else {
// Suppression dans le parapheur
try {
$letterFile = $this->getLetterfileService()->getLetterFileStrategy($signature->getLetterfileKey());
$letterFile->deleteSignature($signature);
} catch (Exception $e) {
$this->getLoggerService()->error("Erreur de suppression dans le parapheur : " . $e->getMessage());
}
try {
foreach ($signature->getRecipients() as $recipient) {
$this->getObjectManager()->remove($recipient);
}
$this->getObjectManager()->remove($signature);
if ($flush) {
$this->getObjectManager()->flush();
}
} catch (Exception $exception) {
$this->getLoggerService()->error("Error DB : " . $exception->getMessage());
throw new SignatureException("Impossible de supprimer la demande de la base de donnée");
}
}
if ($removedoc) {
$doc = $this->getSignatureConfigurationService()->getDocumentsLocation()
. DIRECTORY_SEPARATOR
. $docName;
if (!unlink($doc)) {
$error = error_get_last();
$err = 'Erreur inconnue';
if (is_array($error) && array_key_exists('message', $error)) {
$err = $error['message'];
}
$this->getLoggerService()->error(
"Impossible de supprimer le fichier '$doc' associé à la signature supprimée : $err"
);
}
}
}
/**
* @param int $id
* @return string
* @throws SignatureException
*/
public function getDocumentSignedSignatureById(int $id): string
{
return $this->getDocumentSignedSignature($this->getSignature($id));
}
/**
* Retourne le document (Flux de données).
*
* @param Signature $signature
* @return string
* @throws SignatureException
*/
public function getDocumentSignedSignature(Signature $signature): string
{
if ($signature->isDownloadable()) {
try {
return $this->getLetterfileService()
->getLetterFileStrategy($signature->getLetterfileKey())
->getLastDocumentSignature($signature);
} catch (Exception $e) {
$msg = "Impossible de charger le document depuis la parapheur";
$this->getLoggerService()->critical($msg . " : " . $e->getMessage());
throw new SignatureException($msg);
}
}
else {
throw new SignatureException(
"Le document n'est pas téléchargeable pour la demande"
);
}
}
/**
* Permet, si la signature le permet, de réinitialiser l'état d'un document.
*
* @param Signature $signature
* @return void
*/
public function resetSignatureDocument(Signature $signature): void
{
}
/**
* @param int $id
* @return void
* @throws SignatureException
*/
public function sendSignatureById(int $id): void
{
$this->sendSignature($this->getSignature($id));
}
/**
* Envoi de la signature au parafeur.
*
* @param Signature $signature
* @return void
* @throws SignatureException
*/
public function sendSignature(Signature $signature): void
{
if ($signature->isSendable()) {
// Envoi au parafeur
try {
$this->getLetterfileService()->getLetterFileStrategy(
$signature->getLetterfileKey()
)->sendSignature($signature);
} catch (Exception $e) {
$msg = "Un problème est survenu lors de l'envoi au parapheur";
$this->getLoggerService()->critical($msg . " : " . $e->getMessage());
throw new SignatureException($msg);
}
// Enregistrement des informations d'envoi en local
try {
$signature
->setDateSend(new \DateTime())
->setDateUpdate(new \DateTime())
->setStatus(Signature::STATUS_SIGNATURE_WAIT);
foreach ($signature->getRecipients() as $recipient) {
$recipient
->setStatus(Signature::STATUS_SIGNATURE_WAIT)
->setDateUpdate(new \DateTime());
}
$this->getObjectManager()->flush();
// Event
$this->triggerSignatureEvent($signature, SignatureEvent::EVENT_TYPE_SEND);
// Notifications
if( $signature->isNotifiable() ){
foreach ($signature->getRecipients() as $recipient) {
$this->notificationRecipientSend($recipient);
}
}
if( $signature->isNotifiableObserver() ){
$this->notificationObserversSend($signature);
}
} catch (Exception $exception) {
$this->getLoggerService()->critical(
"Can't save Signature, DB error : " . $exception->getMessage(
) . " - " . $exception->getTraceAsString()
);
throw new SignatureException(
"La demande a été envoyé mais un problème est survenu lors de l'enregistrement."
);
}
}
else {
throw new SignatureException("La demande '" . $signature->getId() . "' ne peut pas être envoyée");
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* @param string $name
* @param array|null $params
* @param bool $absolute
* @return string
* @throws \Psr\Container\ContainerExceptionInterface
* @throws \Psr\Container\NotFoundExceptionInterface
*/
protected function forgeLink(string $name, ?array $params, bool $absolute = true ): string {
static $urlBuilder;
try {
if( !$urlBuilder ){
$urlBuilder = $this->getServiceContainer()
->get('ViewHelperManager')
->get('url');
}
return ($absolute ? $this->getSignatureConfigurationService()->getNotificationsBaseUrl() : '')
.$urlBuilder($name, $params);
} catch (Exception $e) {
$this->getLoggerService()->error("URL ERROR : " . $e->getMessage());
return "URL_EXCEPTION";
}
}
/// NOTIFICATION des SIGNATAIRES
/**
* Envoi d'un avis de signature au destinataire.
*
* @param SignatureRecipient $signatureRecipient
* @return void
*/
public function notificationRecipientSend( SignatureRecipient $signatureRecipient ):void {
// Obtenir le lien
$link = $signatureRecipient->getUrlDocument();
$subject = "[signature] Vous avez un document à {SIGN_VERB} - {DOCUMENT}";
$message = "Bonjour, vous avez un document '{DOCUMENT}' à {SIGN_VERB} : $link\n";
if( $signatureRecipient->getSignature()->getProcessStep() ){
$subject .= " (étape {ETAPE}/{TOTAL_ETAPES})";
$previousSteps = $signatureRecipient->getSignature()->getProcessStep()->getProcess()->previousSteps();
if( count($previousSteps) ){
$message .= "étapes précédentes : \n";
// Calcule des étapes
foreach ($signatureRecipient->getSignature()->getProcessStep()->getProcess()->previousSteps() as $step) {
$message .= " - ". $step->getMessage() . "\n";
}
}
}
$message .= "Merci\n(Ce message est automatique, ne pas répondre)";
$this->sendNotificationTo(
$signatureRecipient->getEmail(),
$subject,
$message,
$signatureRecipient->getSignature()
);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// NOTIFICATIONS des OBSERVATEURS
public function notificationObserversSend( Signature $signature ):void {
if( $signature->isNotifiableObserver() ) {
$nbrRecipients = count($signature->getRecipients());
$subject = "[suivi signature] Document '{DOCUMENT} envoyé pour {SIGN_NOUN}";
if( $signature->getProcessStep() ){
$this->getLoggerService()->debug("SUBJECT -> Ajout étape");
$subject .= " (étape {ETAPE}/{TOTAL_ETAPES})";
}
//$url = $this->forgeLink('unicaen-signature/my-documents', []);
foreach ($signature->getObservers() as $observer) {
$this->sendNotificationTo(
$observer->getEmail(),
$subject,
"Bonjour,\n le document '{DOCUMENT}' a été envoyé pour {SIGN_NOUN} à $nbrRecipients destinataire(s)"
,
$signature
);
}
}
}
protected function sendNotificationTo(
string $email,
string $subject,
string $message,
Signature $signature
): void {
$datas = [
'{RECIPIENT}' => 'NO-RECIPIENT',
];
$datas['{DOCUMENT}'] = $signature->getContextShort() ?: 'Document';
$datas['{SIGN_NOUN}'] = $signature->getNoun();
$datas['{SIGN_VERB}'] = $signature->getVerb();
$datas['{SIGN_PARTICIPLE}'] = $signature->getParticiple();
$datas['{LINK}'] = "LINK TO BUILD";
if ($signature->getProcessStep()) {
$datas['{ETAPE}'] = $signature->getProcessStep()->getOrder();
$datas['{TOTAL_ETAPES}'] = count($signature->getProcessStep()->getProcess()->getSteps());
}
$find = array_keys($datas);
$replace = array_values($datas);
$body = str_ireplace($find, $replace, $message);
$subject = str_ireplace($find, $replace, $subject);;
$strategy = $this->getSignatureConfigurationService()->getNotificationStrategy();
foreach ($strategy as $str) {
try {
if (is_string($str)) {
$this->getServiceContainer()->get($str)->sendNotification($email, $subject, $body);
}
elseif (is_callable($str)) {
$str($this->getServiceContainer(), $email, $subject, $body);
}
} catch (Exception $e) {
$this->getLoggerService()->error(
"Problème lors de l'envoi des notifications : " . $e->getMessage()
);
}
}
}
///// CREATE
public function createSignature(
string $documentDatas,
string $levelKey,
array $recipientsDatas,
array $letterFileDatas = []
): void {
$level = $this->getSignatureConfigurationService()->getLevelByName($levelKey);
$signature = new Signature();
$signature->setStatus(Signature::STATUS_SIGNATURE_DRAFT);
$signature->setType($level->getKey());
foreach ($recipientsDatas as $recipientData) {
$signatureRecipient = new SignatureRecipient();
$signatureRecipient->setStatus(Signature::STATUS_SIGNATURE_DRAFT);
$signatureRecipient->setSignature($signature);
$signatureRecipient->setFirstname($recipientData['firstname']);
$signatureRecipient->setLastname($recipientData['lastname']);
$signatureRecipient->setEmail($recipientData['email']);
$signatureRecipient->setPhone($recipientData['phone']);
}
}
/**
* Diffusion d'événement.
*
* @param Signature $signature
* @return void
*/
protected function triggerSignatureEvent(Signature $signature, string $eventType): void
{
$em = new EventManager($this->getSharedEventManager());
$em->trigger($eventType, null, ['id' => $signature->getId()]);
}
protected function triggerRecipientEvent(SignatureRecipient $signatureRecipient, string $eventType): void
{
$em = new EventManager($this->getSharedEventManager());
$em->trigger($eventType, null, ['id' => $signatureRecipient->getId()]);
}
}