Notification signature en ligne d'une proposition commercial

Bonjour,
Pour ma société, je souhaitais avoir une solution de mail automatique lors de la signature en ligne d’une proposition commerciale.

  • Notifier le ou les commercial/technicien affecté en tant que « Commercial suivi proposition » dans les contacts de la proposition commercial. Il est important pour moi d’automatiser une notification au risque d’oublier un client ayant signé son devis.
  • Notifier le ou les contacts clients affectés en tant que « Contact client suivi proposition » dans les contacts de la proposition commerciale. Intégrer le devis signé à l’email.
  • Je désirais différencier les validations (ou refus) « manuelles » (en passant par le bouton « Accepter/Refuser » de la proposition commerciale) des validations (ou refus) « automatique » (effectué par le client lors de la signature en ligne).

Je n’ai malheureusement pas trouvé de fonction dans dolibarr permettant cela. J’ai donc développé cette fonction. Fonction que je vous partage dans ce post, cela peut servir à certains d’entre vous !
Pour ce besoin, j’ai developpé deux nouveaux triggers (PROPAL_CLOSE_SIGNED_ONLINE & PROPAL_CLOSE_REFUSED_ONLINE). Ces triggers n’existent pas dans le core dolibarr ! Voici le code du triggers : (à mettre dans le dossier : "htdocs\core\triggers" sous le nom interface_70_modpropale_MailPropalSigne.class.php

<?php
/* Copyright (C) 2022      Brice
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
 */

/**
 *  \file       htdocs/core/triggers/interface_70_modpropale.MailPropalSigne.class.php
 *  \ingroup    core
 *  \brief      Trigger pour notif lors de changement d'état par signature en ligne d'une proposition commercial 
 */

require_once DOL_DOCUMENT_ROOT.'/core/triggers/dolibarrtriggers.class.php';
include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';

/**
 *  Class of triggers for MyModule module
 */

class InterfaceMailPropalSigne extends DolibarrTriggers
{
	/**
	 * Constructor
	 *
	 * @param DoliDB $db Database handler
	 */
	public function __construct($db)
	{
		$this->db = $db;

		$this->name = preg_replace('/^Interface/i', '', get_class($this));
		$this->family = "notification";
		$this->description = "Trigger permettant la notification lors de la signature d'un devis en ligne.";
		// 'development', 'experimental', 'dolibarr' or version
		$this->version = self::VERSION_DOLIBARR;
		$this->picto = 'email';
	}

	/**
	 * Function called when a Dolibarrr business event is done.
	 * All functions "runTrigger" are triggered if file is inside directory htdocs/core/triggers or htdocs/module/code/triggers (and declared)
	 *
	 * @param string		$action		Event action code
	 * @param Object		$object     Object
	 * @param User		    $user       Object user
	 * @param Translate 	$langs      Object langs
	 * @param conf		    $conf       Object conf
	 * @return int         				<0 if KO, 0 if no triggered ran, >0 if OK
	 */
	public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf)
	{
		//Définition du numéro d'identifiant du devis
		$idPropal=$object->id;

		//Le devis est signe.

			//Mail au commercial
			/*
			*Definition de l'adresse du commercial en charge du devis
			*fk_c_type_contact`=31 indique que nous rechercher le "Commercial suivi proposition" indiqué dans "Contacts/Adresses" de la fiche du devis.
			*/

			if ($action == 'PROPAL_CLOSE_SIGNED_ONLINE')
			{
				$sql="SELECT `lastname`,`firstname`,`email` FROM ".MAIN_DB_PREFIX."user WHERE `rowid` IN (SELECT `fk_socpeople` FROM ".MAIN_DB_PREFIX."element_contact WHERE `element_id`=$idPropal AND `fk_c_type_contact`=31)";
				$resql = $this->db->query($sql);
				$obj = $this->db->fetch_object($resql);
				$liste_commercial_lastname = array($obj->lastname);
				$liste_commercial_firstname = array($obj->firstname);
				$liste_commercial_email = array($obj->email);
				if ($resql)
				{
					$num = $this->db->num_rows($resql);
					$i = 1;
					//Création de la liste du ou des commercial/commerciaux.
					while ($i < $num) {
						$row = $this->db->fetch_row($resql);
						array_push($liste_commercial_lastname, $row['0']);
						array_push($liste_commercial_firstname, $row['1']);
						array_push($liste_commercial_email, $row['2']);
						$i++;
					}
					//Boucle d'envoie des emails a chaque commercial définie plus haut.
					$c=0;
					foreach($liste_commercial_email as $emailcommercial)
					{
						$subject = $conf->global->MAIN_INFO_SOCIETE_NOM." - Devis " .$object->ref;
						$filepath = array(DOL_DATA_ROOT."/".$object->last_main_doc);
						$mimetype = array("application/pdf");
						$filename = array($object->ref.'_Signe.pdf');
						$messagecommercial = "Bonjour ".$liste_commercial_firstname[$c].",<br><br>Le devis ".$object->ref." (ci-joint) vient d'être signé en ligne.<br><br>Cordialement<br>".$conf->global->MAIN_INFO_SOCIETE_NOM;
						$sendto = $liste_commercial_email[$c];
						$from = (empty($conf->global->MAIN_INFO_SOCIETE_NOM) ? '' : $conf->global->MAIN_INFO_SOCIETE_NOM.' ').'<'.$conf->global->MAIN_INFO_SOCIETE_MAIL.'>';
						$mailfile = new CMailFile($subject,$sendto,$from,$messagecommercial,$filepath,$mimetype,$filename,'','',0,-1,'','','','','test');
						$mailfile->sendfile();
						$c++;
					}
				}
			}

			//Mail au client
			/*
			*Definition de l'adresse du client affecté devis
			*fk_c_type_contact`=41 indique que nous rechercher le "Contact client suivi propale"
			*/
			
			if ($action == 'PROPAL_CLOSE_SIGNED_ONLINE')
			{
				$sql="SELECT `civility`,`lastname`,`firstname`,`email` FROM ".MAIN_DB_PREFIX."socpeople WHERE `rowid` IN (SELECT `fk_socpeople` FROM ".MAIN_DB_PREFIX."element_contact WHERE `element_id`=$idPropal AND `fk_c_type_contact`=41)";
				$resql = $this->db->query($sql);
				$obj = $this->db->fetch_object($resql);
				$liste_client_civility = array($obj->civility);
				$liste_client_lastname = array($obj->lastname);
				$liste_client_firstname = array($obj->firstname);
				$liste_client_email = array($obj->email);
				if ($resql)
				{
					$num = $this->db->num_rows($resql);
					$j = 1;
					//Création de la liste du ou des client(s).
					while ($j < $num) {
						$row = $this->db->fetch_row($resql);
						array_push($liste_client_civility, $row['0']);
						array_push($liste_client_lastname, $row['1']);
						array_push($liste_client_firstname, $row['2']);
						array_push($liste_client_email, $row['3']);
						$j++;
					}
					//Boucle d'envoie des emails a chaque client définie plus haut.
					$h=0;
					foreach($liste_client_email as $emailclient)
					{
						$subject = $conf->global->MAIN_INFO_SOCIETE_NOM." - Devis " .$object->ref;
						$filepath = array(DOL_DATA_ROOT."/".$object->last_main_doc);
						$mimetype = array("application/pdf");
						$filename = array($object->ref.'_Signe.pdf');
						$messageclient = "Bonjour ".$liste_client_civility[$h]." ".$liste_client_lastname[$h].",<br><br>Nous avons réceptionné votre devis signé (ci-joint). Le technicien en charge de votre projet vous recontactera dans les plus bref délais.<br><br>Cordialement<br>".$conf->global->MAIN_INFO_SOCIETE_NOM;
						$sendto = $liste_client_email[$h];
						$from = (empty($conf->global->MAIN_INFO_SOCIETE_NOM) ? '' : $conf->global->MAIN_INFO_SOCIETE_NOM.' ').'<'.$conf->global->MAIN_INFO_SOCIETE_MAIL.'>';
						$mailfile = new CMailFile($subject,$sendto,$from,$messageclient,$filepath,$mimetype,$filename,'','',0,-1,'','','','','test');
						$mailfile->sendfile();
						$h++;
					}
				}
			}

		//Le devis est refuse.
			//Mail au commercial
			/*
			*Definition de l'adresse du commercial en charge du devis
			*fk_c_type_contact`=31 indique que nous rechercher le "Commercial suivi proposition"
			*/
			if ($action == 'PROPAL_CLOSE_REFUSED_ONLINE')
			{
				$sql="SELECT `lastname`,`firstname`,`email` FROM ".MAIN_DB_PREFIX."user WHERE `rowid` IN (SELECT `fk_socpeople` FROM ".MAIN_DB_PREFIX."element_contact WHERE `element_id`=$idPropal AND `fk_c_type_contact`=31)";
				$resql = $this->db->query($sql);
				$obj = $this->db->fetch_object($resql);
				$liste_commercial_lastname = array($obj->lastname);
				$liste_commercial_firstname = array($obj->firstname);
				$liste_commercial_email = array($obj->email);
				if ($resql)
				{
					$num = $this->db->num_rows($resql);
					$i = 1;
					//Création de la liste du ou des commercial/commerciaux.
					while ($i < $num) {
						$row = $this->db->fetch_row($resql);
						array_push($liste_commercial_lastname, $row['0']);
						array_push($liste_commercial_firstname, $row['1']);
						array_push($liste_commercial_email, $row['2']);
						$i++;
					}
					//Boucle d'envoie des emails a chaque commercial définie plus haut.
					$c=0;
					foreach($liste_commercial_email as $emailcommercial)
					{
						$subject = $conf->global->MAIN_INFO_SOCIETE_NOM." - Devis " .$object->ref;
						$filepath = array(DOL_DATA_ROOT."/".$object->last_main_doc);
						$mimetype = array("application/pdf");
						$filename = array($object->ref.'.pdf');
						$messagecommercial = "Bonjour ".$liste_commercial_firstname[$c].",<br><br>Le devis ".$object->ref."(ci-joint) a été refusé par le client.<br><br>Cordialement<br>".$conf->global->MAIN_INFO_SOCIETE_NOM;
						$sendto = $liste_commercial_email[$c];
						$from = (empty($conf->global->MAIN_INFO_SOCIETE_NOM) ? '' : $conf->global->MAIN_INFO_SOCIETE_NOM.' ').'<'.$conf->global->MAIN_INFO_SOCIETE_MAIL.'>';
						$mailfile = new CMailFile($subject,$sendto,$from,$messagecommercial,$filepath,$mimetype,$filename,'','',0,-1,'','','','','test');
						$mailfile->sendfile();
						$c++;
					}
				}
			}
			//Mail au client
			/*
			*Definition de l'adresse du client affecté devis
			*fk_c_type_contact`=41 indique que nous rechercher le "Contact client suivi propale"
			*/
			
			if ($action == 'PROPAL_CLOSE_REFUSED_ONLINE')
			{
				$sql="SELECT `civility`,`lastname`,`firstname`,`email` FROM ".MAIN_DB_PREFIX."socpeople WHERE `rowid` IN (SELECT `fk_socpeople` FROM ".MAIN_DB_PREFIX."element_contact WHERE `element_id`=$idPropal AND `fk_c_type_contact`=41)";
				$resql = $this->db->query($sql);
				$obj = $this->db->fetch_object($resql);
				$liste_client_civility = array($obj->civility);
				$liste_client_lastname = array($obj->lastname);
				$liste_client_firstname = array($obj->firstname);
				$liste_client_email = array($obj->email);
				if ($resql)
				{
					$num = $this->db->num_rows($resql);
					$j = 1;
					//Création de la liste du ou des client(s).
					while ($j < $num) {
						$row = $this->db->fetch_row($resql);
						array_push($liste_client_civility, $row['0']);
						array_push($liste_client_lastname, $row['1']);
						array_push($liste_client_firstname, $row['2']);
						array_push($liste_client_email, $row['3']);
						$j++;
					}
					//Boucle d'envoie des emails a chaque client définie plus haut.
					$h=0;
					foreach($liste_client_email as $emailclient)
					{
						$subject = $conf->global->MAIN_INFO_SOCIETE_NOM." - Devis " .$object->ref;
						$filepath = array(DOL_DATA_ROOT."/".$object->last_main_doc);
						$mimetype = array("application/pdf");
						$filename = array($object->ref.'.pdf');
						$messageclient = "Bonjour ".$liste_client_civility[$h]." ".$liste_client_lastname[$h].",<br><br>Nous sommes désolé que le devis $object->ref (ci-joint) ne vous convienne pas. Le technicien en charge de votre projet vous recontactera dans les plus bref délais.<br><br>Cordialement<br>".$conf->global->MAIN_INFO_SOCIETE_NOM;
						$sendto = $liste_client_email[$h];
						$from = (empty($conf->global->MAIN_INFO_SOCIETE_NOM) ? '' : $conf->global->MAIN_INFO_SOCIETE_NOM.' ').'<'.$conf->global->MAIN_INFO_SOCIETE_MAIL.'>';
						$mailfile = new CMailFile($subject,$sendto,$from,$messageclient,$filepath,$mimetype,$filename,'','',0,-1,'','','','','test');
						$mailfile->sendfile();
						$h++;
					}
				}
			}

	}
}

Pour déclencher le trigger, il faut modifier les pages suivants :

  • « \htdocs\core\ajax\onlineSign.php »
    Mettre le code suivant à la ligne 172 :
//Trigger propal signe en ligne
if (method_exists($object, 'call_trigger')) {
//customer is not a user !?! so could we use same user as validation ?
$user = new User($db);
$user->fetch($object->user_valid_id);
$result = $object->call_trigger('PROPAL_CLOSE_SIGNED_ONLINE', $user);
if ($result < 0) {
	$error++;
}}
//End of modification

  • « htdocs\public\onlinesign\newonlinesign.php »
    Mettre le code suivant à la ligne 176 :
	//Trigger propal signe en ligne
	if (method_exists($object, 'call_trigger')) {
	//customer is not a user !?! so could we use same user as validation ?
	$user = new User($db);
	$user->fetch($object->user_valid_id);
	$result = $object->call_trigger('PROPAL_CLOSE_REFUSED_ONLINE', $user);
	if ($result < 0) {
		$error++;
	}}
	//End of modification

Pour sélectionner les contacts (internes et externe), il suffit de les renseigner dans l’onglet Contact/Adresses de la proposition commerciale :


Dans l’exemple ci dessous, le client Thierry DUPOND et le commercial Brice seront notifié par mail lors de la signature ou refus de la proposition. L’intégralité des personnes renseigné sur cette page seront notifié ; on peut donc mettre plusieurs commerciaux ou/et plusieurs clients !

Le type de mail recu :
Côté commercial :
image
Côté client :

Info sur ce trigger :

  • Developpé sous dolibarr V15.0.2.
  • Impose que le module « Propositions commerciales » soit activé !

Cordialement.
Brice.

7 « J'aime »

Salut @Brice1 ,

tu devrais faire une PR ou au moins poster tes propositions sur le github dolibarr . (le forum étant habituellement plus destiné « user finaux »)

Ca sera surement refusé de prime abord car tu as mis des choses très spécifiques avec des raccourci de dev, propres à ta boite (le mail aux commerciaux par exemple, directement intégré ici)

Avant de poster : regarde ce qui s’est fait en V16 ou sur develop : avec les retours de la v15, il y a déjà eu des modifs en V16, et peut être des choses sur la branche dev en cours/pas validées.

Bref : discussion à avoir sur Github avec les dev, pas ici → tu auras plus de retours :slight_smile:

Salut j ai bien essayer ta technique mais cela ne fonctionne pas aurais tu oublier quelque chose ??

Bonjour,
En quelques version de dolobarr êtes vous ?
Brice.

15.0.2

Bonjour.
Verifier que le trigger soit présent et actif dans Outil d’administration → Dolibarr → trigger


La page devrait indiquer cela :

Brice

1 « J'aime »

Bien présent pas de soucis, les tiers dans la propositions sont bien notifié je ne comprend pas
merci a toi de prendre le temps

Je rectifie la méthode fonctionne comme un gants merciiiiii <3<3<3

Merci beaucoup pour ces modifications.

Je les ai appliquer sur la v16, il y a juste la propale non signé en PJ des mails qui ressort.
Peut-on encore faire une modif pour envoyer le devis signé (il ne porte que le nom du devis_signe) ?

Merci encore !
JF

Bonjour.
Je n’ai pas tester ce bout de code sur dolibarr v16. Quand j’aurais un peu de temps, je tester. Pouvez vous me dire précisément se qu’il ne va pas ?

  • Les internes à la société paramétrés en tant que commercial sur la propositions reçoivent le mail ?
  • Les client paramétrés en tant que client suivie de propositions sur la propositions reçoivent le mail ?
  • Les documents signés sont ils en pièces jointe des mails ?
    Brice.

Bonjour,
Pour répondre aux questions :

  • Les internes paramétrés sur la proposition reçoivent bien le mail de validation de signature
  • Les clients paramétrés reçoivent bien le mail de validation de signature également
  • Par contre tous deux ne reçoivent que la proposition non signée.

Bonne journée,
JF

Bonjour,
Ok le document envoyé en pièces jointe n’est donc pas le bon. J’installe une instance V16, procède à des tests et modifie le code pour permettre de le rendre fonctionnel en V16.
Cdlt
Brice.

Bonjour,
Je viens de faire des tests sur une instance de test dolibarr !
Il faut mettre le code suivant à la page \htdocs\core\ajax\onlineSign.php à la ligne 206 (et non 172 sous dolibarr V15) :

//Trigger propal signe en ligne
if (method_exists($object, 'call_trigger')) {
//customer is not a user !?! so could we use same user as validation ?
$user = new User($db);
$user->fetch($object->user_valid_id);
$result = $object->call_trigger('PROPAL_CLOSE_SIGNED_ONLINE', $user);
if ($result < 0) {
	$error++;
}}
//End of modification


Je reçois à ce moment là bien les mails avec le document signé.

Edit : ne fonctionne pas sur une instance avec PHP8 ! Il faut rester sur PHP7 pour que cela soit fonctionnel

Cdlt.
Brice.

1 « J'aime »

Bonjour,

Super !
La modification fonctionne super bien !
De toute façon je crois que la v16 a du mal avec PHP8 :thinking:

Enorme merci !
Cdlt

JF

Bonjour,

Petit retour : La modification est fonctionnelle sous notre dolibarr v16 en PHP8 !

Cdlt
JF

Bonjour,
Est-ce que cela va être intégré à dolibarr prochainement?
Merci

Bonjour,
Je n’ai pas fais de demande auprès de dolibarr pour intégrer cette amélioration dans le core.
Cordialement.
Brice.

Bonjour,
Ok allez-vous la faire la demande? Car cela me semble probant comme intégration.
Merci.

Bonjour,

Êtes-vous familier avec GitHub ?

Si oui, faite un PR sur : https://github.com/Dolibarr/dolibarr/pulls

Hello,
C’est fais NEW|New [trigger online sign] by HC-Brice · Pull Request #22838 · Dolibarr/dolibarr · GitHub.
Brice.

2 « J'aime »