dolibarr 24.0.0-beta
modules_mailings.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2003-2004 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2008 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
5 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
6 * Copyright (C) 2025 Frédéric France <frederic.france@free.fr>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 * or see https://www.gnu.org/
21 */
22
28require_once DOL_DOCUMENT_ROOT.'/core/lib/functions.lib.php';
29
30
34class MailingTargets // This can't be abstract as it is used for some method
35{
39 public $db;
40
44 public $error = '';
45
49 public $errors;
50
54 public $enabled;
55
59 public $name;
60
64 public $desc;
65
69 public $tooltip = '';
70
74 public $sql;
75
76
80 public $evenunsubscribe = 0;
81
82
88 public function __construct($db)
89 {
90 $this->db = $db;
91 }
92
98 public function getDesc()
99 {
100 global $langs, $form;
101
102 $langs->load("mails");
103 $transstring = "MailingModuleDesc".$this->name;
104 $s = '';
105
106 if ($langs->trans($this->name) != $this->name) {
107 $s = $langs->trans($this->name);
108 } elseif ($langs->trans($transstring) != $transstring) {
109 $s = $langs->trans($transstring);
110 } else {
111 $s = $this->desc;
112 }
113
114 if ($this->tooltip && is_object($form)) {
115 $s .= ' '.$form->textwithpicto('', $langs->trans($this->tooltip), 1, 'help');
116 }
117 return $s;
118 }
119
125 public function getNbOfRecords()
126 {
127 return 0;
128 }
129
136 public function getNbOfRecipients($sql)
137 {
138 $result = $this->db->query($sql);
139 if ($result) {
140 $total = 0;
141 while ($obj = $this->db->fetch_object($result)) {
142 $total += (int) $obj->nb;
143 }
144 return $total;
145 } else {
146 $this->error = $this->db->lasterror();
147 return -1;
148 }
149 }
150
157 public function formFilter()
158 {
159 return '';
160 }
161
162 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
169 public function update_nb($mailing_id)
170 {
171 // phpcs:enable
172 // Update the number of recipients in the mailing table
173 $sql = "SELECT COUNT(*) nb FROM ".$this->db->prefix()."mailing_cibles";
174 $sql .= " WHERE fk_mailing = ".((int) $mailing_id);
175 $result = $this->db->query($sql);
176 if ($result) {
177 $obj = $this->db->fetch_object($result);
178 $nb = (int) $obj->nb;
179
180 $sql = "UPDATE ".$this->db->prefix()."mailing";
181 $sql .= " SET nbemail = ".((int) $nb)." WHERE rowid = ".((int) $mailing_id);
182 if (!$this->db->query($sql)) {
183 dol_syslog($this->db->error());
184 $this->error = $this->db->error();
185 return -1;
186 }
187 } else {
188 return -1;
189 }
190 return $nb;
191 }
192
200 public function addTargetsToDatabase($mailing_id, $cibles)
201 {
202 global $conf;
203
204 $this->db->begin();
205
206
207 // Insert emailing targets from array into database
208 $j = 0;
209 $num = count($cibles);
210 foreach ($cibles as $targetarray) {
211 if (!empty($targetarray['email'])) { // avoid empty email address
212 $sql = "INSERT INTO ".$this->db->prefix()."mailing_cibles";
213 $sql .= " (fk_mailing,";
214 $sql .= " fk_contact,";
215 $sql .= " lastname, firstname, email, other, source_url, source_id,";
216 $sql .= " tag,";
217 $sql .= " source_type)";
218 $sql .= " VALUES (".((int) $mailing_id).",";
219 $sql .= (empty($targetarray['fk_contact']) ? '0' : (int) $targetarray['fk_contact']).",";
220 $sql .= "'".$this->db->escape($targetarray['lastname'])."',";
221 $sql .= "'".$this->db->escape($targetarray['firstname'])."',";
222 $sql .= "'".$this->db->escape($targetarray['email'])."',";
223 $sql .= "'".$this->db->escape($targetarray['other'])."',";
224 $sql .= "'".$this->db->escape($targetarray['source_url'])."',";
225 $sql .= (empty($targetarray['source_id']) ? 'null' : (int) $targetarray['source_id']).",";
226 $sql .= "'".$this->db->escape(dol_hash($conf->file->instance_unique_id.";".$targetarray['email'].";".$targetarray['lastname'].";".((int) $mailing_id).";".getDolGlobalString('MAILING_EMAIL_UNSUBSCRIBE_KEY'), 'md5'))."',";
227 $sql .= "'".$this->db->escape($targetarray['source_type'])."')";
228 dol_syslog(__METHOD__, LOG_DEBUG);
229 $result = $this->db->query($sql);
230 if ($result) {
231 $j++;
232 } else {
233 if ($this->db->errno() != 'DB_ERROR_RECORD_ALREADY_EXISTS') {
234 // Si erreur autre que doublon
235 dol_syslog($this->db->error().' : '.$targetarray['email']);
236 $this->error = $this->db->error().' : '.$targetarray['email'];
237 $this->db->rollback();
238 return -1;
239 }
240 }
241 }
242 }
243
244 dol_syslog(__METHOD__.": mailing ".$j." targets added");
245
246 /*
247 //Update the status to show thirdparty mail that don't want to be contacted anymore'
248 $sql = "UPDATE ".$this->db->prefix()."mailing_cibles";
249 $sql .= " SET statut=3";
250 $sql .= " WHERE fk_mailing = ".((int) $mailing_id)." AND email in (SELECT email FROM ".$this->db->prefix()."societe where fk_stcomm=-1)";
251 $sql .= " AND source_type='thirdparty'";
252 dol_syslog(__METHOD__.": mailing update status to display thirdparty mail that do not want to be contacted");
253 $result=$this->db->query($sql);
254
255 //Update the status to show contact mail that don't want to be contacted anymore'
256 $sql = "UPDATE ".$this->db->prefix()."mailing_cibles";
257 $sql .= " SET statut=3";
258 $sql .= " WHERE fk_mailing = ".((int) $mailing_id)." AND source_type='contact' AND (email in (SELECT sc.email FROM ".$this->db->prefix()."socpeople AS sc ";
259 $sql .= " INNER JOIN ".$this->db->prefix()."societe s ON s.rowid=sc.fk_soc WHERE s.fk_stcomm=-1 OR no_email=1))";
260 dol_syslog(__METHOD__.": mailing update status to display contact mail that do not want to be contacted",LOG_DEBUG);
261 $result=$this->db->query($sql);
262 */
263
264 if (empty($this->evenunsubscribe)) {
265 $sql = "UPDATE ".$this->db->prefix()."mailing_cibles as mc";
266 $sql .= " SET statut = 3";
267 $sql .= " WHERE fk_mailing = ".((int) $mailing_id);
268 $sql .= " AND EXISTS (SELECT rowid FROM ".$this->db->prefix()."mailing_unsubscribe as mu WHERE mu.email = mc.email and mu.entity = ".((int) $conf->entity).")";
269
270 dol_syslog(__METHOD__.":mailing update status to display emails that do not want to be contacted anymore", LOG_DEBUG);
271 $result = $this->db->query($sql);
272 if (!$result) {
273 dol_print_error($this->db);
274 }
275 }
276
277 // Update nb of recipient into emailing record
278 $this->update_nb($mailing_id);
279
280 $this->db->commit();
281
282 return $j;
283 }
284
285 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
292 public function clear_target($mailing_id)
293 {
294 // phpcs:enable
295 $sql = "DELETE FROM ".$this->db->prefix()."mailing_cibles";
296 $sql .= " WHERE fk_mailing = ".((int) $mailing_id);
297
298 if (!$this->db->query($sql)) {
299 dol_syslog($this->db->error());
300 }
301
302 $this->update_nb($mailing_id);
303 }
304
305
313 public static function getEmailingSelectorsList($forcedir = null)
314 {
315 global $langs, $db;
316
317 $files = array();
318 $fullpath = array();
319 $relpath = array();
320 $iscoreorexternal = array();
321 $modules = array();
322 $orders = array();
323 $i = 0;
324
325 $diremailselector = array('/core/modules/mailings/'); // $conf->modules_parts['emailings'] is not required
326 if (is_array($forcedir)) {
327 $diremailselector = $forcedir;
328 }
329
330 foreach ($diremailselector as $reldir) {
331 $dir = dol_buildpath($reldir, 0);
332 $newdir = dol_osencode($dir);
333
334 // Check if directory exists (we do not use dol_is_dir to avoid loading files.lib.php at each call)
335 if (!is_dir($newdir)) {
336 continue;
337 }
338
339 $handle = opendir($newdir);
340 if (is_resource($handle)) {
341 while (($file = readdir($handle)) !== false) {
342 $reg = array();
343 if (is_readable($newdir.'/'.$file) && preg_match('/^(.+)\.modules.php/', $file, $reg)) {
344 if (preg_match('/\.back$/', $file) || preg_match('/^(.+)\.disabled\.php/', $file)) {
345 continue;
346 }
347
348 $part1 = $reg[1];
349
350 //$modName = ucfirst($reg[1]);
351 $modName = 'mailing_'.$reg[1]; // name of selector submodule
352 //print "file=$file modName=$modName"; exit;
353 if (in_array($modName, $modules)) {
354 $langs->load("errors");
355 print '<div class="error">'.$langs->trans("Error").' : '.$langs->trans("ErrorDuplicateEmalingSelector", $modName, "").'</div>';
356 } else {
357 try {
358 //print $newdir.'/'.$file;
359 include_once $newdir.'/'.$file;
360 } catch (Exception $e) {
361 print $e->getMessage();
362 }
363 }
364
365 $files[$i] = $file;
366 $fullpath[$i] = $dir.'/'.$file;
367 $relpath[$i] = preg_replace('/^\//', '', $reldir).'/'.$file;
368 $iscoreorexternal[$i] = ($reldir == '/core/modules/mailings/' ? 'internal' : 'external');
369 $modules[$i] = $modName;
370 $orders[$i] = $part1; // Set sort criteria value
371
372 $i++;
373 }
374 }
375 closedir($handle);
376 }
377 }
378 //echo "<pre>";print_r($modules);echo "</pre>";
379
380 asort($orders);
381
382 $widget = array();
383 $j = 0;
384
385 // Loop on each emailing selector
386 foreach ($orders as $key => $value) {
387 $modName = $modules[$key];
388 if (empty($modName)) {
389 continue;
390 }
391
392 if (!class_exists($modName)) {
393 print 'Error: An emailing selector file was found but its class "'.$modName.'" was not found.'."<br>\n";
394 continue;
395 }
396
397 $objMod = new $modName($db);
398 if (is_object($objMod)) {
399 '@phan-var-force ModeleBoxes $objMod';
400 // Define disabledbyname and disabledbymodule
401 $disabledbyname = 0;
402 $disabledbymodule = 0; // TODO Set to 2 if module is not enabled
403 $module = '';
404
405 // Check if widget file is disabled by name
406 if (preg_match('/NORUN$/i', $files[$key])) {
407 $disabledbyname = 1;
408 }
409
410 // We set info of modules @phan-suppress-next-line PhanUndeclaredProperty
411 $widget[$j]['picto'] = (empty($objMod->picto) ? (empty($objMod->boximg) ? img_object('', 'generic') : $objMod->boximg) : img_object('', $objMod->picto));
412 $widget[$j]['file'] = $files[$key];
413 $widget[$j]['fullpath'] = $fullpath[$key];
414 $widget[$j]['relpath'] = $relpath[$key];
415 $widget[$j]['iscoreorexternal'] = $iscoreorexternal[$key];
416 $widget[$j]['version'] = empty($objMod->version) ? '' : $objMod->version;
417 $widget[$j]['status'] = img_picto($langs->trans("Active"), 'tick', 'class="pictofixedwidth"');
418 if ($disabledbyname > 0 || $disabledbymodule > 1) {
419 $widget[$j]['status'] = '';
420 }
421
422 $text = '<b>'.$langs->trans("Description").':</b><br>';
423 $text .= $objMod->boxlabel.'<br>';
424 $text .= '<br><b>'.$langs->trans("Status").':</b><br>';
425 if ($disabledbymodule == 2) {
426 $text .= $langs->trans("WidgetDisabledAsModuleDisabled", $module).'<br>';
427 }
428
429 $widget[$j]['info'] = $text;
430 }
431 $j++;
432 }
433
434 return $widget;
435 }
436
437
446 public function getSqlArrayForStats()
447 {
448 // Needs to be implemented in child class
449 $msg = get_class($this)."::".__FUNCTION__." not implemented";
450 dol_syslog($msg, LOG_ERR);
451 return array();
452 }
453
454 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
461 public function add_to_target($mailing_id)
462 {
463 // phpcs:enable
464 // Needs to be implemented in child class
465 $msg = get_class($this)."::".__FUNCTION__." not implemented";
466 dol_syslog($msg, LOG_ERR);
467 return -1;
468 }
469}
Parent class of emailing target selectors modules.
__construct($db)
Constructor.
add_to_target($mailing_id)
Add destinations in the targets table.
static getEmailingSelectorsList($forcedir=null)
Return list of widget.
addTargetsToDatabase($mailing_id, $cibles)
Add a list of targets into the database.
getDesc()
Return description of email selector.
getNbOfRecipients($sql)
Return the number of recipients.
clear_target($mailing_id)
Supprime tous les destinataires de la table des cibles.
update_nb($mailing_id)
Update the number of recipients.
formFilter()
Affiche formulaire de filtre qui apparait dans page de selection des destinataires de mailings.
getNbOfRecords()
Return number of records for email selector.
getSqlArrayForStats()
On the main mailing area, there is a box with statistics.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $db
API class for accounts.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
dol_osencode($str)
Return a string encoded into OS filesystem encoding.
img_object($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $allowothertags=array())
Show a picto called object_picto (generic function)
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:133
dol_hash($chain, $type='0', $nosalt=0, $mode=0)
Returns a hash (non reversible encryption) of a string.