dolibarr  13.0.2
actions_massactions.inc.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2015-2017 Laurent Destailleur <eldy@users.sourceforge.net>
3  * Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
4  * Copyright (C) 2018 Juanjo Menent <jmenent@2byte.es>
5  * Copyright (C) 2019 Ferran Marcet <fmarcet@2byte.es>
6  * Copyright (C) 2019-2021 Frédéric France <frederic.france@netlogic.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 
29 // $massaction must be defined
30 // $objectclass and $objectlabel must be defined
31 // $parameters, $object, $action must be defined for the hook.
32 
33 // $permissiontoread, $permissiontoadd, $permissiontodelete, $permissiontoclose may be defined
34 // $uploaddir may be defined (example to $conf->projet->dir_output."/";)
35 // $toselect may be defined
36 // $diroutputmassaction may be defined
37 
38 
39 // Protection
40 if (empty($objectclass) || empty($uploaddir))
41 {
42  dol_print_error(null, 'include of actions_massactions.inc.php is done but var $objectclass or $uploaddir was not defined');
43  exit;
44 }
45 
46 // For backward compatibility
47 if (!empty($permtoread) && empty($permissiontoread)) $permissiontoread = $permtoread;
48 if (!empty($permtocreate) && empty($permissiontoadd)) $permissiontoadd = $permtocreate;
49 if (!empty($permtodelete) && empty($permissiontodelete)) $permissiontodelete = $permtodelete;
50 
51 
52 // Mass actions. Controls on number of lines checked.
53 $maxformassaction = (empty($conf->global->MAIN_LIMIT_FOR_MASS_ACTIONS) ? 1000 : $conf->global->MAIN_LIMIT_FOR_MASS_ACTIONS);
54 if (!empty($massaction) && is_array($toselect) && count($toselect) < 1)
55 {
56  $error++;
57  setEventMessages($langs->trans("NoRecordSelected"), null, "warnings");
58 }
59 if (!$error && is_array($toselect) && count($toselect) > $maxformassaction)
60 {
61  setEventMessages($langs->trans('TooManyRecordForMassAction', $maxformassaction), null, 'errors');
62  $error++;
63 }
64 
65 if (!$error && $massaction == 'confirm_presend' && !GETPOST('sendmail')) // If we do not choose button send (for example when we change template or limit), we must not send email, but keep on send email form
66 {
67  $massaction = 'presend';
68 }
69 if (!$error && $massaction == 'confirm_presend')
70 {
71  $resaction = '';
72  $nbsent = 0;
73  $nbignored = 0;
74  $langs->load("mails");
75  include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
76 
77  $listofobjectid = array();
78  $listofobjectthirdparties = array();
79  $listofobjectcontacts = array();
80  $listofobjectref = array();
81  $contactidtosend = array();
82  $attachedfilesThirdpartyObj = array();
83  $oneemailperrecipient = (GETPOST('oneemailperrecipient') == 'on' ? 1 : 0);
84 
85  if (!$error)
86  {
87  $thirdparty = new Societe($db);
88 
89  $objecttmp = new $objectclass($db);
90  if ($objecttmp->element == 'expensereport') $thirdparty = new User($db);
91  if ($objecttmp->element == 'holiday') $thirdparty = new User($db);
92 
93  foreach ($toselect as $toselectid)
94  {
95  $objecttmp = new $objectclass($db); // we must create new instance because instance is saved into $listofobjectref array for future use
96  $result = $objecttmp->fetch($toselectid);
97  if ($result > 0)
98  {
99  $listofobjectid[$toselectid] = $toselectid;
100 
101  $thirdpartyid = ($objecttmp->fk_soc ? $objecttmp->fk_soc : $objecttmp->socid);
102  if ($objecttmp->element == 'societe') $thirdpartyid = $objecttmp->id;
103  if ($objecttmp->element == 'expensereport') $thirdpartyid = $objecttmp->fk_user_author;
104  if ($objecttmp->element == 'holiday') $thirdpartyid = $objecttmp->fk_user;
105  if (empty($thirdpartyid)) $thirdpartyid = 0;
106 
107  if ($objectclass == 'Facture') {
108  $tmparraycontact = array();
109  $tmparraycontact = $objecttmp->liste_contact(-1, 'external', 0, 'BILLING');
110  if (is_array($tmparraycontact) && count($tmparraycontact) > 0) {
111  foreach ($tmparraycontact as $data_email) {
112  $listofobjectcontacts[$toselectid][$data_email['id']] = $data_email['email'];
113  }
114  }
115  }
116 
117  $listofobjectthirdparties[$thirdpartyid] = $thirdpartyid;
118  $listofobjectref[$thirdpartyid][$toselectid] = $objecttmp;
119  }
120  }
121  }
122 
123  // Check mandatory parameters
124  if (GETPOST('fromtype', 'alpha') === 'user' && empty($user->email))
125  {
126  $error++;
127  setEventMessages($langs->trans("NoSenderEmailDefined"), null, 'warnings');
128  $massaction = 'presend';
129  }
130 
131  $receiver = $_POST['receiver'];
132  if (!is_array($receiver))
133  {
134  if (empty($receiver) || $receiver == '-1') $receiver = array();
135  else $receiver = array($receiver);
136  }
137  if (!trim($_POST['sendto']) && count($receiver) == 0 && count($listofobjectthirdparties) == 1) // if only one recipient, receiver is mandatory
138  {
139  $error++;
140  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Recipient")), null, 'warnings');
141  $massaction = 'presend';
142  }
143 
144  if (!GETPOST('subject', 'restricthtml'))
145  {
146  $error++;
147  setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("MailTopic")), null, 'warnings');
148  $massaction = 'presend';
149  }
150 
151  // Loop on each recipient/thirdparty
152  if (!$error)
153  {
154  foreach ($listofobjectthirdparties as $thirdpartyid)
155  {
156  $result = $thirdparty->fetch($thirdpartyid);
157  if ($result < 0)
158  {
159  dol_print_error($db);
160  exit;
161  }
162 
163  $sendto = '';
164  $sendtocc = '';
165  $sendtobcc = '';
166  $sendtoid = array();
167 
168  // Define $sendto
169  $tmparray = array();
170  if (trim($_POST['sendto']))
171  {
172  // Recipients are provided into free text
173  $tmparray[] = trim($_POST['sendto']);
174  }
175  if (count($receiver) > 0)
176  {
177  foreach ($receiver as $key=>$val)
178  {
179  // Recipient was provided from combo list
180  if ($val == 'thirdparty') // Id of third party or user
181  {
182  $tmparray[] = $thirdparty->name.' <'.$thirdparty->email.'>';
183  } elseif ($val && method_exists($thirdparty, 'contact_get_property')) // Id of contact
184  {
185  $tmparray[] = $thirdparty->contact_get_property((int) $val, 'email');
186  $sendtoid[] = $val;
187  }
188  }
189  }
190  $sendto = implode(',', $tmparray);
191 
192  // Define $sendtocc
193  $receivercc = $_POST['receivercc'];
194  if (!is_array($receivercc))
195  {
196  if ($receivercc == '-1') $receivercc = array();
197  else $receivercc = array($receivercc);
198  }
199  $tmparray = array();
200  if (trim($_POST['sendtocc']))
201  {
202  $tmparray[] = trim($_POST['sendtocc']);
203  }
204  if (count($receivercc) > 0)
205  {
206  foreach ($receivercc as $key=>$val)
207  {
208  // Recipient was provided from combo list
209  if ($val == 'thirdparty') // Id of third party
210  {
211  $tmparray[] = $thirdparty->name.' <'.$thirdparty->email.'>';
212  } elseif ($val) // Id du contact
213  {
214  $tmparray[] = $thirdparty->contact_get_property((int) $val, 'email');
215  //$sendtoid[] = $val; TODO Add also id of contact in CC ?
216  }
217  }
218  }
219  $sendtocc = implode(',', $tmparray);
220 
221  //var_dump($listofobjectref);exit;
222  $listofqualifiedobj = array();
223  $listofqualifiedref = array();
224  $thirdpartywithoutemail = array();
225 
226  foreach ($listofobjectref[$thirdpartyid] as $objectid => $objectobj)
227  {
228  //var_dump($thirdpartyid.' - '.$objectid.' - '.$objectobj->statut);
229  if ($objectclass == 'Propal' && $objectobj->statut == Propal::STATUS_DRAFT)
230  {
231  $langs->load("errors");
232  $nbignored++;
233  $resaction .= '<div class="error">'.$langs->trans('ErrorOnlyProposalNotDraftCanBeSentInMassAction', $objectobj->ref).'</div><br>';
234  continue; // Payment done or started or canceled
235  }
236  if ($objectclass == 'Commande' && $objectobj->statut == Commande::STATUS_DRAFT)
237  {
238  $langs->load("errors");
239  $nbignored++;
240  $resaction .= '<div class="error">'.$langs->trans('ErrorOnlyOrderNotDraftCanBeSentInMassAction', $objectobj->ref).'</div><br>';
241  continue;
242  }
243  if ($objectclass == 'Facture' && $objectobj->statut == Facture::STATUS_DRAFT)
244  {
245  $langs->load("errors");
246  $nbignored++;
247  $resaction .= '<div class="error">'.$langs->trans('ErrorOnlyInvoiceValidatedCanBeSentInMassAction', $objectobj->ref).'</div><br>';
248  continue; // Payment done or started or canceled
249  }
250 
251  // Test recipient
252  if (empty($sendto)) // For the case, no recipient were set (multi thirdparties send)
253  {
254  if ($objectobj->element == 'societe')
255  {
256  $sendto = $objectobj->email;
257  } elseif ($objectobj->element == 'expensereport')
258  {
259  $fuser = new User($db);
260  $fuser->fetch($objectobj->fk_user_author);
261  $sendto = $fuser->email;
262  } elseif ($objectobj->element == 'holiday')
263  {
264  $fuser = new User($db);
265  $fuser->fetch($objectobj->fk_user);
266  $sendto = $fuser->email;
267  } elseif ($objectobj->element == 'facture' && !empty($listofobjectcontacts[$objectid]))
268  {
269  $emails_to_sends = array();
270  $objectobj->fetch_thirdparty();
271  $contactidtosend = array();
272  foreach ($listofobjectcontacts[$objectid] as $contactemailid => $contactemailemail) {
273  $emails_to_sends[] = $objectobj->thirdparty->contact_get_property($contactemailid, 'email');
274  if (!in_array($contactemailid, $contactidtosend)) {
275  $contactidtosend[] = $contactemailid;
276  }
277  }
278  if (count($emails_to_sends) > 0) {
279  $sendto = implode(',', $emails_to_sends);
280  }
281  } else {
282  $objectobj->fetch_thirdparty();
283  $sendto = $objectobj->thirdparty->email;
284  }
285  }
286 
287  if (empty($sendto))
288  {
289  if ($objectobj->element == 'societe') {
290  $objectobj->thirdparty = $objectobj; // Hack so following code is comaptible when objectobj is a thirdparty
291  }
292 
293  //print "No recipient for thirdparty ".$objectobj->thirdparty->name;
294  $nbignored++;
295  if (empty($thirdpartywithoutemail[$objectobj->thirdparty->id]))
296  {
297  $resaction .= '<div class="error">'.$langs->trans('NoRecipientEmail', $objectobj->thirdparty->name).'</div><br>';
298  }
299  dol_syslog('No recipient for thirdparty: '.$objectobj->thirdparty->name, LOG_WARNING);
300  $thirdpartywithoutemail[$objectobj->thirdparty->id] = 1;
301  continue;
302  }
303 
304  if ($_POST['addmaindocfile'])
305  {
306  // TODO Use future field $objectobj->fullpathdoc to know where is stored default file
307  // TODO If not defined, use $objectobj->modelpdf (or defaut invoice config) to know what is template to use to regenerate doc.
308  $filename = dol_sanitizeFileName($objectobj->ref).'.pdf';
309  $subdir = '';
310  // TODO Set subdir to be compatible with multi levels dir trees
311  // $subdir = get_exdir($objectobj->id, 2, 0, 0, $objectobj, $objectobj->element)
312  $filedir = $uploaddir.'/'.$subdir.dol_sanitizeFileName($objectobj->ref);
313  $file = $filedir.'/'.$filename;
314 
315  // For supplier invoices, we use the file provided by supplier, not the one we generate
316  if ($objectobj->element == 'invoice_supplier')
317  {
318  $fileparams = dol_most_recent_file($uploaddir.'/'.get_exdir($objectobj->id, 2, 0, 0, $objectobj, $objectobj->element).$objectobj->ref, preg_quote($objectobj->ref, '/').'([^\-])+');
319  $file = $fileparams['fullname'];
320  }
321 
322  $mime = dol_mimetype($file);
323 
324  if (dol_is_file($file))
325  {
326  // Create form object
327  $attachedfilesThirdpartyObj[$thirdpartyid][$objectid] = array(
328  'paths'=>array($file),
329  'names'=>array($filename),
330  'mimes'=>array($mime)
331  );
332  } else {
333  $nbignored++;
334  $langs->load("errors");
335  $resaction .= '<div class="error">'.$langs->trans('ErrorCantReadFile', $file).'</div><br>';
336  dol_syslog('Failed to read file: '.$file, LOG_WARNING);
337  continue;
338  }
339  }
340 
341  // Object of thirdparty qualified, we add it
342  $listofqualifiedobj[$objectid] = $objectobj;
343  $listofqualifiedref[$objectid] = $objectobj->ref;
344 
345 
346  //var_dump($listofqualifiedref);
347  }
348 
349  // Send email if there is at least one qualified object for current thirdparty
350  if (count($listofqualifiedobj) > 0)
351  {
352  $langs->load("commercial");
353 
354  $reg = array();
355  $fromtype = GETPOST('fromtype');
356  if ($fromtype === 'user') {
357  $from = $user->getFullName($langs).' <'.$user->email.'>';
358  } elseif ($fromtype === 'company') {
359  $from = $conf->global->MAIN_INFO_SOCIETE_NOM.' <'.$conf->global->MAIN_INFO_SOCIETE_MAIL.'>';
360  } elseif (preg_match('/user_aliases_(\d+)/', $fromtype, $reg)) {
361  $tmp = explode(',', $user->email_aliases);
362  $from = trim($tmp[($reg[1] - 1)]);
363  } elseif (preg_match('/global_aliases_(\d+)/', $fromtype, $reg)) {
364  $tmp = explode(',', $conf->global->MAIN_INFO_SOCIETE_MAIL_ALIASES);
365  $from = trim($tmp[($reg[1] - 1)]);
366  } elseif (preg_match('/senderprofile_(\d+)_(\d+)/', $fromtype, $reg)) {
367  $sql = 'SELECT rowid, label, email FROM '.MAIN_DB_PREFIX.'c_email_senderprofile WHERE rowid = '.(int) $reg[1];
368  $resql = $db->query($sql);
369  $obj = $db->fetch_object($resql);
370  if ($obj)
371  {
372  $from = $obj->label.' <'.$obj->email.'>';
373  }
374  } else {
375  $from = $_POST['fromname'].' <'.$_POST['frommail'].'>';
376  }
377 
378  $replyto = $from;
379  $subject = GETPOST('subject', 'restricthtml');
380  $message = GETPOST('message', 'restricthtml');
381 
382  $sendtobcc = GETPOST('sendtoccc');
383  if ($objectclass == 'Propal') $sendtobcc .= (empty($conf->global->MAIN_MAIL_AUTOCOPY_PROPOSAL_TO) ? '' : (($sendtobcc ? ", " : "").$conf->global->MAIN_MAIL_AUTOCOPY_PROPOSAL_TO));
384  if ($objectclass == 'Commande') $sendtobcc .= (empty($conf->global->MAIN_MAIL_AUTOCOPY_ORDER_TO) ? '' : (($sendtobcc ? ", " : "").$conf->global->MAIN_MAIL_AUTOCOPY_ORDER_TO));
385  if ($objectclass == 'Facture') $sendtobcc .= (empty($conf->global->MAIN_MAIL_AUTOCOPY_INVOICE_TO) ? '' : (($sendtobcc ? ", " : "").$conf->global->MAIN_MAIL_AUTOCOPY_INVOICE_TO));
386  if ($objectclass == 'Supplier_Proposal') $sendtobcc .= (empty($conf->global->MAIN_MAIL_AUTOCOPY_SUPPLIER_PROPOSAL_TO) ? '' : (($sendtobcc ? ", " : "").$conf->global->MAIN_MAIL_AUTOCOPY_SUPPLIER_PROPOSAL_TO));
387  if ($objectclass == 'CommandeFournisseur') $sendtobcc .= (empty($conf->global->MAIN_MAIL_AUTOCOPY_SUPPLIER_ORDER_TO) ? '' : (($sendtobcc ? ", " : "").$conf->global->MAIN_MAIL_AUTOCOPY_SUPPLIER_ORDER_TO));
388  if ($objectclass == 'FactureFournisseur') $sendtobcc .= (empty($conf->global->MAIN_MAIL_AUTOCOPY_SUPPLIER_INVOICE_TO) ? '' : (($sendtobcc ? ", " : "").$conf->global->MAIN_MAIL_AUTOCOPY_SUPPLIER_INVOICE_TO));
389  if ($objectclass == 'Project') $sendtobcc .= (empty($conf->global->MAIN_MAIL_AUTOCOPY_PROJECT_TO) ? '' : (($sendtobcc ? ", " : "").$conf->global->MAIN_MAIL_AUTOCOPY_PROJECT_TO));
390 
391  // $listofqualifiedobj is array with key = object id and value is instance of qualified objects, for the current thirdparty (but thirdparty property is not loaded yet)
392  // $looparray will be an array with number of email to send for the current thirdparty (so 1 or n if n object for same thirdparty)
393  $looparray = array();
394  if (!$oneemailperrecipient)
395  {
396  $looparray = $listofqualifiedobj;
397  foreach ($looparray as $key => $objecttmp)
398  {
399  $looparray[$key]->thirdparty = $thirdparty; // Force thirdparty on object
400  }
401  } else {
402  $objectforloop = new $objectclass($db);
403  $objectforloop->thirdparty = $thirdparty; // Force thirdparty on object (even if object was not loaded)
404  $looparray[0] = $objectforloop;
405  }
406  //var_dump($looparray);exit;
407  dol_syslog("We have set an array of ".count($looparray)." emails to send. oneemailperrecipient=".$oneemailperrecipient);
408  //var_dump($oneemailperrecipient); var_dump($listofqualifiedobj); var_dump($listofqualifiedref);
409  foreach ($looparray as $objectid => $objecttmp) // $objecttmp is a real object or an empty object if we choose to send one email per thirdparty instead of one per object
410  {
411  // Make substitution in email content
412  if (!empty($conf->projet->enabled) && method_exists($objecttmp, 'fetch_projet') && is_null($objecttmp->project))
413  {
414  $objecttmp->fetch_projet();
415  }
416  $substitutionarray = getCommonSubstitutionArray($langs, 0, null, $objecttmp);
417  $substitutionarray['__ID__'] = ($oneemailperrecipient ? join(', ', array_keys($listofqualifiedobj)) : $objecttmp->id);
418  $substitutionarray['__REF__'] = ($oneemailperrecipient ? join(', ', $listofqualifiedref) : $objecttmp->ref);
419  $substitutionarray['__EMAIL__'] = $thirdparty->email;
420  $substitutionarray['__CHECK_READ__'] = '<img src="'.DOL_MAIN_URL_ROOT.'/public/emailing/mailing-read.php?tag='.$thirdparty->tag.'&securitykey='.urlencode($conf->global->MAILING_EMAIL_UNSUBSCRIBE_KEY).'" width="1" height="1" style="width:1px;height:1px" border="0"/>';
421 
422  $parameters = array('mode'=>'formemail');
423 
424  if (!empty($listofobjectthirdparties)) {
425  $parameters['listofobjectthirdparties'] = $listofobjectthirdparties;
426  }
427  if (!empty($listofobjectref)) {
428  $parameters['listofobjectref'] = $listofobjectref;
429  }
430 
431  complete_substitutions_array($substitutionarray, $langs, $objecttmp, $parameters);
432 
433  $subjectreplaced = make_substitutions($subject, $substitutionarray);
434  $messagereplaced = make_substitutions($message, $substitutionarray);
435 
436  $attachedfiles = array('paths'=>array(), 'names'=>array(), 'mimes'=>array());
437  if ($oneemailperrecipient)
438  {
439  // if "one email per recipient" is check we must collate $attachedfiles by thirdparty
440  if (is_array($attachedfilesThirdpartyObj[$thirdparty->id]) && count($attachedfilesThirdpartyObj[$thirdparty->id]))
441  {
442  foreach ($attachedfilesThirdpartyObj[$thirdparty->id] as $keyObjId => $objAttachedFiles) {
443  // Create form object
444  $attachedfiles = array(
445  'paths'=>array_merge($attachedfiles['paths'], $objAttachedFiles['paths']),
446  'names'=>array_merge($attachedfiles['names'], $objAttachedFiles['names']),
447  'mimes'=>array_merge($attachedfiles['mimes'], $objAttachedFiles['mimes'])
448  );
449  }
450  }
451  } elseif (!empty($attachedfilesThirdpartyObj[$thirdparty->id][$objectid])) {
452  // Create form object
453  // if "one email per recipient" isn't check we must separate $attachedfiles by object
454  $attachedfiles = $attachedfilesThirdpartyObj[$thirdparty->id][$objectid];
455  }
456 
457  $filepath = $attachedfiles['paths'];
458  $filename = $attachedfiles['names'];
459  $mimetype = $attachedfiles['mimes'];
460 
461  // Define the trackid when emails sent from the mass action
462  if ($oneemailperrecipient)
463  {
464  $trackid = 'thi'.$thirdparty->id;
465  if ($objecttmp->element == 'expensereport') $trackid = 'use'.$thirdparty->id;
466  if ($objecttmp->element == 'holiday') $trackid = 'use'.$thirdparty->id;
467  } else {
468  $trackid = strtolower(get_class($objecttmp));
469  if (get_class($objecttmp) == 'Contrat') $trackid = 'con';
470  if (get_class($objecttmp) == 'Propal') $trackid = 'pro';
471  if (get_class($objecttmp) == 'Commande') $trackid = 'ord';
472  if (get_class($objecttmp) == 'Facture') $trackid = 'inv';
473  if (get_class($objecttmp) == 'Supplier_Proposal') $trackid = 'spr';
474  if (get_class($objecttmp) == 'CommandeFournisseur') $trackid = 'sor';
475  if (get_class($objecttmp) == 'FactureFournisseur') $trackid = 'sin';
476 
477  $trackid .= $objecttmp->id;
478  }
479  //var_dump($filepath);
480  //var_dump($trackid);exit;
481  //var_dump($subjectreplaced);
482 
483  if (empty($sendcontext)) $sendcontext = 'standard';
484 
485  // Send mail (substitutionarray must be done just before this)
486  require_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
487  $mailfile = new CMailFile($subjectreplaced, $sendto, $from, $messagereplaced, $filepath, $mimetype, $filename, $sendtocc, $sendtobcc, $deliveryreceipt, -1, '', '', $trackid, '', $sendcontext);
488  if ($mailfile->error)
489  {
490  $resaction .= '<div class="error">'.$mailfile->error.'</div>';
491  } else {
492  $result = $mailfile->sendfile();
493  if ($result)
494  {
495  $resaction .= $langs->trans('MailSuccessfulySent', $mailfile->getValidAddress($from, 2), $mailfile->getValidAddress($sendto, 2)).'<br>'; // Must not contain "
496 
497  $error = 0;
498 
499  // Insert logs into agenda
500  foreach ($listofqualifiedobj as $objid2 => $objectobj2)
501  {
502  if ((!$oneemailperrecipient) && $objid2 != $objectid) continue; // We discard this pass to avoid duplicate with other pass in looparray at higher level
503 
504  dol_syslog("Try to insert email event into agenda for objid=".$objid2." => objectobj=".get_class($objectobj2));
505 
506  /*if ($objectclass == 'Propale') $actiontypecode='AC_PROP';
507  if ($objectclass == 'Commande') $actiontypecode='AC_COM';
508  if ($objectclass == 'Facture') $actiontypecode='AC_FAC';
509  if ($objectclass == 'Supplier_Proposal') $actiontypecode='AC_SUP_PRO';
510  if ($objectclass == 'CommandeFournisseur') $actiontypecode='AC_SUP_ORD';
511  if ($objectclass == 'FactureFournisseur') $actiontypecode='AC_SUP_INV';*/
512 
513  $actionmsg = $langs->transnoentities('MailSentBy').' '.$from.' '.$langs->transnoentities('To').' '.$sendto;
514  if ($message)
515  {
516  if ($sendtocc) $actionmsg = dol_concatdesc($actionmsg, $langs->transnoentities('Bcc').": ".$sendtocc);
517  $actionmsg = dol_concatdesc($actionmsg, $langs->transnoentities('MailTopic').": ".$subjectreplaced);
518  $actionmsg = dol_concatdesc($actionmsg, $langs->transnoentities('TextUsedInTheMessageBody').":");
519  $actionmsg = dol_concatdesc($actionmsg, $messagereplaced);
520  }
521  $actionmsg2 = '';
522 
523  // Initialisation donnees
524  $objectobj2->sendtoid = (empty($contactidtosend) ? 0 : $contactidtosend);
525  $objectobj2->actionmsg = $actionmsg; // Long text
526  $objectobj2->actionmsg2 = $actionmsg2; // Short text
527  $objectobj2->fk_element = $objid2;
528  $objectobj2->elementtype = $objectobj2->element;
529 
530  $triggername = strtoupper(get_class($objectobj2)).'_SENTBYMAIL';
531  if ($triggername == 'SOCIETE_SENTBYMAIL') $triggername = 'COMPANY_SENTBYMAIL';
532  if ($triggername == 'CONTRAT_SENTBYMAIL') $triggername = 'CONTRACT_SENTBYMAIL';
533  if ($triggername == 'COMMANDE_SENTBYMAIL') $triggername = 'ORDER_SENTBYMAIL';
534  if ($triggername == 'FACTURE_SENTBYMAIL') $triggername = 'BILL_SENTBYMAIL';
535  if ($triggername == 'EXPEDITION_SENTBYMAIL') $triggername = 'SHIPPING_SENTBYMAIL';
536  if ($triggername == 'COMMANDEFOURNISSEUR_SENTBYMAIL') $triggername = 'ORDER_SUPPLIER_SENTBYMAIL';
537  if ($triggername == 'FACTUREFOURNISSEUR_SENTBYMAIL') $triggername = 'BILL_SUPPLIER_SENTBYMAIL';
538  if ($triggername == 'SUPPLIERPROPOSAL_SENTBYMAIL') $triggername = 'PROPOSAL_SUPPLIER_SENTBYMAIL';
539 
540  if (!empty($triggername))
541  {
542  // Call trigger
543  $result = $objectobj2->call_trigger($triggername, $user);
544  if ($result < 0) $error++;
545  // End call triggers
546 
547  if ($error)
548  {
549  setEventMessages($db->lasterror(), $errors, 'errors');
550  dol_syslog("Error in trigger ".$triggername.' '.$db->lasterror(), LOG_ERR);
551  }
552  }
553 
554  $nbsent++; // Nb of object sent
555  }
556  } else {
557  $langs->load("other");
558  if ($mailfile->error)
559  {
560  $resaction .= $langs->trans('ErrorFailedToSendMail', $from, $sendto);
561  $resaction .= '<br><div class="error">'.$mailfile->error.'</div>';
562  } else {
563  $resaction .= '<div class="warning">No mail sent. Feature is disabled by option MAIN_DISABLE_ALL_MAILS</div>';
564  }
565  }
566  }
567  }
568  }
569  }
570 
571  $resaction .= ($resaction ? '<br>' : $resaction);
572  $resaction .= '<strong>'.$langs->trans("ResultOfMailSending").':</strong><br>'."\n";
573  $resaction .= $langs->trans("NbSelected").': '.count($toselect)."\n<br>";
574  $resaction .= $langs->trans("NbIgnored").': '.($nbignored ? $nbignored : 0)."\n<br>";
575  $resaction .= $langs->trans("NbSent").': '.($nbsent ? $nbsent : 0)."\n<br>";
576 
577  if ($nbsent)
578  {
579  $action = ''; // Do not show form post if there was at least one successfull sent
580  //setEventMessages($langs->trans("EMailSentToNRecipients", $nbsent.'/'.count($toselect)), null, 'mesgs');
581  setEventMessages($langs->trans("EMailSentForNElements", $nbsent.'/'.count($toselect)), null, 'mesgs');
582  setEventMessages($resaction, null, 'mesgs');
583  } else {
584  //setEventMessages($langs->trans("EMailSentToNRecipients", 0), null, 'warnings'); // May be object has no generated PDF file
585  setEventMessages($resaction, null, 'warnings');
586  }
587 
588  $action = 'list';
589  $massaction = '';
590  }
591 }
592 
593 if ($massaction == 'confirm_createbills') // Create bills from orders
594 {
595  $orders = GETPOST('toselect', 'array');
596  $createbills_onebythird = GETPOST('createbills_onebythird', 'int');
597  $validate_invoices = GETPOST('validate_invoices', 'int');
598 
599  $TFact = array();
600  $TFactThird = array();
601 
602  $nb_bills_created = 0;
603 
604  $db->begin();
605 
606  foreach ($orders as $id_order)
607  {
608  $cmd = new Commande($db);
609  if ($cmd->fetch($id_order) <= 0) continue;
610 
611  $objecttmp = new Facture($db);
612  if (!empty($createbills_onebythird) && !empty($TFactThird[$cmd->socid])) $objecttmp = $TFactThird[$cmd->socid]; // If option "one bill per third" is set, we use already created order.
613  else {
614  // Load extrafields of order
615  $cmd->fetch_optionals();
616 
617  $objecttmp->socid = $cmd->socid;
618  $objecttmp->type = $objecttmp::TYPE_STANDARD;
619  $objecttmp->cond_reglement_id = $cmd->cond_reglement_id;
620  $objecttmp->mode_reglement_id = $cmd->mode_reglement_id;
621  $objecttmp->fk_project = $cmd->fk_project;
622  $objecttmp->multicurrency_code = $cmd->multicurrency_code;
623  if (empty($createbills_onebythird)) $objecttmp->ref_client = $cmd->ref_client;
624 
625  $datefacture = dol_mktime(12, 0, 0, GETPOST('remonth', 'int'), GETPOST('reday', 'int'), GETPOST('reyear', 'int'));
626  if (empty($datefacture))
627  {
628  $datefacture = dol_now();
629  }
630 
631  $objecttmp->date = $datefacture;
632  $objecttmp->origin = 'commande';
633  $objecttmp->origin_id = $id_order;
634 
635  $objecttmp->array_options = $cmd->array_options; // Copy extrafields
636 
637  $res = $objecttmp->create($user);
638 
639  if ($res > 0) $nb_bills_created++;
640  }
641 
642  if ($objecttmp->id > 0)
643  {
644  $sql = "INSERT INTO ".MAIN_DB_PREFIX."element_element (";
645  $sql .= "fk_source";
646  $sql .= ", sourcetype";
647  $sql .= ", fk_target";
648  $sql .= ", targettype";
649  $sql .= ") VALUES (";
650  $sql .= $id_order;
651  $sql .= ", '".$db->escape($objecttmp->origin)."'";
652  $sql .= ", ".$objecttmp->id;
653  $sql .= ", '".$db->escape($objecttmp->element)."'";
654  $sql .= ")";
655 
656  if (!$db->query($sql))
657  {
658  $error++;
659  }
660 
661  if (!$error)
662  {
663  $lines = $cmd->lines;
664  if (empty($lines) && method_exists($cmd, 'fetch_lines'))
665  {
666  $cmd->fetch_lines();
667  $lines = $cmd->lines;
668  }
669 
670  $fk_parent_line = 0;
671  $num = count($lines);
672 
673  for ($i = 0; $i < $num; $i++)
674  {
675  $desc = ($lines[$i]->desc ? $lines[$i]->desc : '');
676  // If we build one invoice for several order, we must put the invoice of order on the line
677  if (!empty($createbills_onebythird))
678  {
679  $desc = dol_concatdesc($desc, $langs->trans("Order").' '.$cmd->ref.' - '.dol_print_date($cmd->date, 'day'));
680  }
681 
682  if ($lines[$i]->subprice < 0)
683  {
684  // Negative line, we create a discount line
685  $discount = new DiscountAbsolute($db);
686  $discount->fk_soc = $objecttmp->socid;
687  $discount->amount_ht = abs($lines[$i]->total_ht);
688  $discount->amount_tva = abs($lines[$i]->total_tva);
689  $discount->amount_ttc = abs($lines[$i]->total_ttc);
690  $discount->tva_tx = $lines[$i]->tva_tx;
691  $discount->fk_user = $user->id;
692  $discount->description = $desc;
693  $discountid = $discount->create($user);
694  if ($discountid > 0)
695  {
696  $result = $objecttmp->insert_discount($discountid);
697  //$result=$discount->link_to_invoice($lineid,$id);
698  } else {
699  setEventMessages($discount->error, $discount->errors, 'errors');
700  $error++;
701  break;
702  }
703  } else {
704  // Positive line
705  $product_type = ($lines[$i]->product_type ? $lines[$i]->product_type : 0);
706  // Date start
707  $date_start = false;
708  if ($lines[$i]->date_debut_prevue) $date_start = $lines[$i]->date_debut_prevue;
709  if ($lines[$i]->date_debut_reel) $date_start = $lines[$i]->date_debut_reel;
710  if ($lines[$i]->date_start) $date_start = $lines[$i]->date_start;
711  //Date end
712  $date_end = false;
713  if ($lines[$i]->date_fin_prevue) $date_end = $lines[$i]->date_fin_prevue;
714  if ($lines[$i]->date_fin_reel) $date_end = $lines[$i]->date_fin_reel;
715  if ($lines[$i]->date_end) $date_end = $lines[$i]->date_end;
716  // Reset fk_parent_line for no child products and special product
717  if (($lines[$i]->product_type != 9 && empty($lines[$i]->fk_parent_line)) || $lines[$i]->product_type == 9)
718  {
719  $fk_parent_line = 0;
720  }
721 
722  // Extrafields
723  if (method_exists($lines[$i], 'fetch_optionals')) {
724  $lines[$i]->fetch_optionals();
725  $array_options = $lines[$i]->array_options;
726  }
727 
728  $result = $objecttmp->addline(
729  $desc,
730  $lines[$i]->subprice,
731  $lines[$i]->qty,
732  $lines[$i]->tva_tx,
733  $lines[$i]->localtax1_tx,
734  $lines[$i]->localtax2_tx,
735  $lines[$i]->fk_product,
736  $lines[$i]->remise_percent,
737  $date_start,
738  $date_end,
739  0,
740  $lines[$i]->info_bits,
741  $lines[$i]->fk_remise_except,
742  'HT',
743  0,
744  $product_type,
745  $lines[$i]->rang,
746  $lines[$i]->special_code,
747  $objecttmp->origin,
748  $lines[$i]->rowid,
749  $fk_parent_line,
750  $lines[$i]->fk_fournprice,
751  $lines[$i]->pa_ht,
752  $lines[$i]->label,
753  $array_options,
754  100,
755  0,
756  $lines[$i]->fk_unit
757  );
758  if ($result > 0)
759  {
760  $lineid = $result;
761  } else {
762  $lineid = 0;
763  $error++;
764  break;
765  }
766  // Defined the new fk_parent_line
767  if ($result > 0 && $lines[$i]->product_type == 9)
768  {
769  $fk_parent_line = $result;
770  }
771  }
772  }
773  }
774  }
775 
776  //$cmd->classifyBilled($user); // Disabled. This behavior must be set or not using the workflow module.
777 
778  if (!empty($createbills_onebythird) && empty($TFactThird[$cmd->socid])) $TFactThird[$cmd->socid] = $objecttmp;
779  else $TFact[$objecttmp->id] = $objecttmp;
780  }
781 
782  // Build doc with all invoices
783  $TAllFact = empty($createbills_onebythird) ? $TFact : $TFactThird;
784  $toselect = array();
785 
786  if (!$error && $validate_invoices)
787  {
788  $massaction = $action = 'builddoc';
789 
790  foreach ($TAllFact as &$objecttmp)
791  {
792  $result = $objecttmp->validate($user);
793  if ($result <= 0)
794  {
795  $error++;
796  setEventMessages($objecttmp->error, $objecttmp->errors, 'errors');
797  break;
798  }
799 
800  $id = $objecttmp->id; // For builddoc action
801  $object = $objecttmp;
802 
803  // Builddoc
804  $donotredirect = 1;
805  $upload_dir = $conf->facture->dir_output;
806  $permissiontoadd = $user->rights->facture->creer;
807 
808  // Call action to build doc
809  $savobject = $object;
810  $object = $objecttmp;
811  include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
812  $object = $savobject;
813  }
814 
815  $massaction = $action = 'confirm_createbills';
816  }
817 
818  if (!$error)
819  {
820  $db->commit();
821  setEventMessages($langs->trans('BillCreated', $nb_bills_created), null, 'mesgs');
822 
823  // Make a redirect to avoid to bill twice if we make a refresh or back
824  $param = '';
825  if (!empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param .= '&contextpage='.urlencode($contextpage);
826  if ($limit > 0 && $limit != $conf->liste_limit) $param .= '&limit='.urlencode($limit);
827  if ($sall) $param .= '&sall='.urlencode($sall);
828  if ($socid > 0) $param .= '&socid='.urlencode($socid);
829  if ($search_status != '') $param .= '&search_status='.urlencode($search_status);
830  if ($search_orderday) $param .= '&search_orderday='.urlencode($search_orderday);
831  if ($search_ordermonth) $param .= '&search_ordermonth='.urlencode($search_ordermonth);
832  if ($search_orderyear) $param .= '&search_orderyear='.urlencode($search_orderyear);
833  if ($search_deliveryday) $param .= '&search_deliveryday='.urlencode($search_deliveryday);
834  if ($search_deliverymonth) $param .= '&search_deliverymonth='.urlencode($search_deliverymonth);
835  if ($search_deliveryyear) $param .= '&search_deliveryyear='.urlencode($search_deliveryyear);
836  if ($search_ref) $param .= '&search_ref='.urlencode($search_ref);
837  if ($search_company) $param .= '&search_company='.urlencode($search_company);
838  if ($search_ref_customer) $param .= '&search_ref_customer='.urlencode($search_ref_customer);
839  if ($search_user > 0) $param .= '&search_user='.urlencode($search_user);
840  if ($search_sale > 0) $param .= '&search_sale='.urlencode($search_sale);
841  if ($search_total_ht != '') $param .= '&search_total_ht='.urlencode($search_total_ht);
842  if ($search_total_vat != '') $param .= '&search_total_vat='.urlencode($search_total_vat);
843  if ($search_total_ttc != '') $param .= '&search_total_ttc='.urlencode($search_total_ttc);
844  if ($search_project_ref >= 0) $param .= "&search_project_ref=".urlencode($search_project_ref);
845  if ($show_files) $param .= '&show_files='.urlencode($show_files);
846  if ($optioncss != '') $param .= '&optioncss='.urlencode($optioncss);
847  if ($billed != '') $param .= '&billed='.urlencode($billed);
848 
849  header("Location: ".$_SERVER['PHP_SELF'].'?'.$param);
850  exit;
851  } else {
852  $db->rollback();
853  $action = 'create';
854  $_GET["origin"] = $_POST["origin"];
855  $_GET["originid"] = $_POST["originid"];
856  setEventMessages("Error", null, 'errors');
857  $error++;
858  }
859 }
860 
861 if (!$error && $massaction == 'cancelorders')
862 {
863  $db->begin();
864 
865  $nbok = 0;
866 
867 
868  $orders = GETPOST('toselect', 'array');
869  foreach ($orders as $id_order)
870  {
871  $cmd = new Commande($db);
872  if ($cmd->fetch($id_order) <= 0)
873  continue;
874 
875  if ($cmd->statut != Commande::STATUS_VALIDATED)
876  {
877  $langs->load('errors');
878  setEventMessages($langs->trans("ErrorObjectMustHaveStatusValidToBeCanceled", $cmd->ref), null, 'errors');
879  $error++;
880  break;
881  } else {
882  // TODO We do not provide warehouse so no stock change here for the moment.
883  $result = $cmd->cancel();
884  }
885 
886  if ($result < 0)
887  {
888  setEventMessages($cmd->error, $cmd->errors, 'errors');
889  $error++;
890  break;
891  } else $nbok++;
892  }
893  if (!$error)
894  {
895  if ($nbok > 1)
896  setEventMessages($langs->trans("RecordsModified", $nbok), null, 'mesgs');
897  else setEventMessages($langs->trans("RecordsModified", $nbok), null, 'mesgs');
898  $db->commit();
899  } else {
900  $db->rollback();
901  }
902 }
903 
904 
905 if (!$error && $massaction == "builddoc" && $permissiontoread && !GETPOST('button_search'))
906 {
907  if (empty($diroutputmassaction))
908  {
909  dol_print_error(null, 'include of actions_massactions.inc.php is done but var $diroutputmassaction was not defined');
910  exit;
911  }
912 
913  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
914  require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php';
915  require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
916 
917  $objecttmp = new $objectclass($db);
918  $listofobjectid = array();
919  $listofobjectthirdparties = array();
920  $listofobjectref = array();
921  foreach ($toselect as $toselectid)
922  {
923  $objecttmp = new $objectclass($db); // must create new instance because instance is saved into $listofobjectref array for future use
924  $result = $objecttmp->fetch($toselectid);
925  if ($result > 0)
926  {
927  $listofobjectid[$toselectid] = $toselectid;
928  $thirdpartyid = $objecttmp->fk_soc ? $objecttmp->fk_soc : $objecttmp->socid;
929  $listofobjectthirdparties[$thirdpartyid] = $thirdpartyid;
930  $listofobjectref[$toselectid] = $objecttmp->ref;
931  }
932  }
933 
934  $arrayofinclusion = array();
935  foreach ($listofobjectref as $tmppdf) $arrayofinclusion[] = '^'.preg_quote(dol_sanitizeFileName($tmppdf), '/').'\.pdf$';
936  foreach ($listofobjectref as $tmppdf) $arrayofinclusion[] = '^'.preg_quote(dol_sanitizeFileName($tmppdf), '/').'_[a-zA-Z0-9-_]+\.pdf$'; // To include PDF generated from ODX files
937  $listoffiles = dol_dir_list($uploaddir, 'all', 1, implode('|', $arrayofinclusion), '\.meta$|\.png', 'date', SORT_DESC, 0, true);
938 
939  // build list of files with full path
940  $files = array();
941  foreach ($listofobjectref as $basename)
942  {
943  $basename = dol_sanitizeFileName($basename);
944  foreach ($listoffiles as $filefound)
945  {
946  if (strstr($filefound["name"], $basename))
947  {
948  $files[] = $uploaddir.'/'.$basename.'/'.$filefound["name"];
949  break;
950  }
951  }
952  }
953 
954  // Define output language (Here it is not used because we do only merging existing PDF)
955  $outputlangs = $langs;
956  $newlang = '';
957  if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id', 'aZ09')) $newlang = GETPOST('lang_id', 'aZ09');
958  if ($conf->global->MAIN_MULTILANGS && empty($newlang)) $newlang = $objecttmp->thirdparty->default_lang;
959  if (!empty($newlang)) {
960  $outputlangs = new Translate("", $conf);
961  $outputlangs->setDefaultLang($newlang);
962  }
963 
964  if (!empty($conf->global->USE_PDFTK_FOR_PDF_CONCAT))
965  {
966  // Create output dir if not exists
967  dol_mkdir($diroutputmassaction);
968 
969  // Defined name of merged file
970  $filename = strtolower(dol_sanitizeFileName($langs->transnoentities($objectlabel)));
971  $filename = preg_replace('/\s/', '_', $filename);
972 
973  // Save merged file
974  if (in_array($objecttmp->element, array('facture', 'facture_fournisseur')) && $search_status == Facture::STATUS_VALIDATED)
975  {
976  if ($option == 'late') $filename .= '_'.strtolower(dol_sanitizeFileName($langs->transnoentities("Unpaid"))).'_'.strtolower(dol_sanitizeFileName($langs->transnoentities("Late")));
977  else $filename .= '_'.strtolower(dol_sanitizeFileName($langs->transnoentities("Unpaid")));
978  }
979  if ($year) $filename .= '_'.$year;
980  if ($month) $filename .= '_'.$month;
981 
982  if (count($files) > 0)
983  {
984  $now = dol_now();
985  $file = $diroutputmassaction.'/'.$filename.'_'.dol_print_date($now, 'dayhourlog').'.pdf';
986 
987  $input_files = '';
988  foreach ($files as $f) {
989  $input_files .= ' '.escapeshellarg($f);
990  }
991 
992  $cmd = 'pdftk '.$input_files.' cat output '.escapeshellarg($file);
993  exec($cmd);
994 
995  // check if pdftk is installed
996  if (file_exists($file)) {
997  if (!empty($conf->global->MAIN_UMASK))
998  @chmod($file, octdec($conf->global->MAIN_UMASK));
999 
1000  $langs->load("exports");
1001  setEventMessages($langs->trans('FileSuccessfullyBuilt', $filename.'_'.dol_print_date($now, 'dayhourlog')), null, 'mesgs');
1002  } else {
1003  setEventMessages($langs->trans('ErrorPDFTkOutputFileNotFound'), null, 'errors');
1004  }
1005  } else {
1006  setEventMessages($langs->trans('NoPDFAvailableForDocGenAmongChecked'), null, 'errors');
1007  }
1008  } else {
1009  // Create empty PDF
1010  $formatarray = pdf_getFormat();
1011  $page_largeur = $formatarray['width'];
1012  $page_hauteur = $formatarray['height'];
1013  $format = array($page_largeur, $page_hauteur);
1014 
1015  $pdf = pdf_getInstance($format);
1016 
1017  if (class_exists('TCPDF'))
1018  {
1019  $pdf->setPrintHeader(false);
1020  $pdf->setPrintFooter(false);
1021  }
1022  $pdf->SetFont(pdf_getPDFFont($outputlangs));
1023 
1024  if (!empty($conf->global->MAIN_DISABLE_PDF_COMPRESSION)) $pdf->SetCompression(false);
1025 
1026  // Add all others
1027  foreach ($files as $file)
1028  {
1029  // Charge un document PDF depuis un fichier.
1030  $pagecount = $pdf->setSourceFile($file);
1031  for ($i = 1; $i <= $pagecount; $i++)
1032  {
1033  $tplidx = $pdf->importPage($i);
1034  $s = $pdf->getTemplatesize($tplidx);
1035  $pdf->AddPage($s['h'] > $s['w'] ? 'P' : 'L');
1036  $pdf->useTemplate($tplidx);
1037  }
1038  }
1039 
1040  // Create output dir if not exists
1041  dol_mkdir($diroutputmassaction);
1042 
1043  // Defined name of merged file
1044  $filename = strtolower(dol_sanitizeFileName($langs->transnoentities($objectlabel)));
1045  $filename = preg_replace('/\s/', '_', $filename);
1046 
1047  // Save merged file
1048  if (in_array($objecttmp->element, array('facture', 'facture_fournisseur')) && $search_status == Facture::STATUS_VALIDATED)
1049  {
1050  if ($option == 'late') $filename .= '_'.strtolower(dol_sanitizeFileName($langs->transnoentities("Unpaid"))).'_'.strtolower(dol_sanitizeFileName($langs->transnoentities("Late")));
1051  else $filename .= '_'.strtolower(dol_sanitizeFileName($langs->transnoentities("Unpaid")));
1052  }
1053  if ($year) $filename .= '_'.$year;
1054  if ($month) $filename .= '_'.$month;
1055  if ($pagecount)
1056  {
1057  $now = dol_now();
1058  $file = $diroutputmassaction.'/'.$filename.'_'.dol_print_date($now, 'dayhourlog').'.pdf';
1059  $pdf->Output($file, 'F');
1060  if (!empty($conf->global->MAIN_UMASK))
1061  @chmod($file, octdec($conf->global->MAIN_UMASK));
1062 
1063  $langs->load("exports");
1064  setEventMessages($langs->trans('FileSuccessfullyBuilt', $filename.'_'.dol_print_date($now, 'dayhourlog')), null, 'mesgs');
1065  } else {
1066  setEventMessages($langs->trans('NoPDFAvailableForDocGenAmongChecked'), null, 'errors');
1067  }
1068  }
1069 }
1070 
1071 // Remove a file from massaction area
1072 if ($action == 'remove_file')
1073 {
1074  require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
1075 
1076  $langs->load("other");
1077  $upload_dir = $diroutputmassaction;
1078  $file = $upload_dir.'/'.GETPOST('file');
1079  $ret = dol_delete_file($file);
1080  if ($ret) setEventMessages($langs->trans("FileWasRemoved", GETPOST('file')), null, 'mesgs');
1081  else setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('file')), null, 'errors');
1082  $action = '';
1083 }
1084 
1085 
1086 // Validate records
1087 if (!$error && $massaction == 'validate' && $permissiontoadd)
1088 {
1089  $objecttmp = new $objectclass($db);
1090 
1091  if (($objecttmp->element == 'facture' || $objecttmp->element == 'invoice') && !empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_BILL))
1092  {
1093  $langs->load("errors");
1094  setEventMessages($langs->trans('ErrorMassValidationNotAllowedWhenStockIncreaseOnAction'), null, 'errors');
1095  $error++;
1096  }
1097  if ($objecttmp->element == 'invoice_supplier' && !empty($conf->stock->enabled) && !empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL))
1098  {
1099  $langs->load("errors");
1100  setEventMessages($langs->trans('ErrorMassValidationNotAllowedWhenStockIncreaseOnAction'), null, 'errors');
1101  $error++;
1102  }
1103  if (!$error)
1104  {
1105  $db->begin();
1106 
1107  $nbok = 0;
1108  foreach ($toselect as $toselectid)
1109  {
1110  $result = $objecttmp->fetch($toselectid);
1111  if ($result > 0)
1112  {
1113  $result = $objecttmp->validate($user);
1114  if ($result == 0) {
1115  $langs->load("errors");
1116  setEventMessages($langs->trans("ErrorObjectMustHaveStatusDraftToBeValidated", $objecttmp->ref), null, 'errors');
1117  $error++;
1118  break;
1119  } elseif ($result < 0) {
1120  setEventMessages($objecttmp->error, $objecttmp->errors, 'errors');
1121  $error++;
1122  break;
1123  } else {
1124  // validate() rename pdf but do not regenerate
1125  // Define output language
1126  if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE)) {
1127  $outputlangs = $langs;
1128  $newlang = '';
1129  if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1130  $newlang = GETPOST('lang_id', 'aZ09');
1131  }
1132  if ($conf->global->MAIN_MULTILANGS && empty($newlang)) {
1133  $newlang = $objecttmp->thirdparty->default_lang;
1134  }
1135  if (!empty($newlang)) {
1136  $outputlangs = new Translate("", $conf);
1137  $outputlangs->setDefaultLang($newlang);
1138  $outputlangs->load('products');
1139  }
1140  $model = $objecttmp->model_pdf;
1141  $ret = $objecttmp->fetch($objecttmp->id); // Reload to get new records
1142  // To be sure vars is defined
1143  $hidedetails = !empty($hidedetails) ? $hidedetails : 0;
1144  $hidedesc = !empty($hidedesc) ? $hidedesc : 0;
1145  $hideref = !empty($hideref) ? $hideref : 0;
1146  $moreparams = !empty($moreparams) ? $moreparams : null;
1147 
1148  $result = $objecttmp->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
1149  if ($result < 0) {
1150  setEventMessages($objecttmp->error, $objecttmp->errors, 'errors');
1151  }
1152  }
1153  $nbok++;
1154  }
1155  } else {
1156  setEventMessages($objecttmp->error, $objecttmp->errors, 'errors');
1157  $error++;
1158  break;
1159  }
1160  }
1161 
1162  if (!$error)
1163  {
1164  if ($nbok > 1) setEventMessages($langs->trans("RecordsModified", $nbok), null, 'mesgs');
1165  else setEventMessages($langs->trans("RecordsModified", $nbok), null, 'mesgs');
1166  $db->commit();
1167  } else {
1168  $db->rollback();
1169  }
1170  //var_dump($listofobjectthirdparties);exit;
1171  }
1172 }
1173 
1174 // Closed records
1175 if (!$error && $massaction == 'closed' && $objectclass == "Propal" && $permissiontoclose) {
1176  $db->begin();
1177 
1178  $objecttmp = new $objectclass($db);
1179  $nbok = 0;
1180  foreach ($toselect as $toselectid) {
1181  $result = $objecttmp->fetch($toselectid);
1182  if ($result > 0) {
1183  $result = $objecttmp->cloture($user, 3);
1184  if ($result <= 0) {
1185  setEventMessages($objecttmp->error, $objecttmp->errors, 'errors');
1186  $error++;
1187  break;
1188  } else $nbok++;
1189  } else {
1190  setEventMessages($objecttmp->error, $objecttmp->errors, 'errors');
1191  $error++;
1192  break;
1193  }
1194  }
1195 
1196  if (!$error) {
1197  if ($nbok > 1)
1198  setEventMessages($langs->trans("RecordsModified", $nbok), null, 'mesgs');
1199  else setEventMessages($langs->trans("RecordsModified", $nbok), null, 'mesgs');
1200  $db->commit();
1201  } else {
1202  $db->rollback();
1203  }
1204 }
1205 
1206 //var_dump($_POST);var_dump($massaction);exit;
1207 
1208 // Delete record from mass action (massaction = 'delete' for direct delete, action/confirm='delete'/'yes' with a confirmation step before)
1209 if (!$error && ($massaction == 'delete' || ($action == 'delete' && $confirm == 'yes')) && $permissiontodelete)
1210 {
1211  $db->begin();
1212 
1213  $objecttmp = new $objectclass($db);
1214  $nbok = 0;
1215  foreach ($toselect as $toselectid)
1216  {
1217  $result = $objecttmp->fetch($toselectid);
1218  if ($result > 0)
1219  {
1220  // Refuse deletion for some objects/status
1221  if ($objectclass == 'Facture' && empty($conf->global->INVOICE_CAN_ALWAYS_BE_REMOVED) && $objecttmp->status != Facture::STATUS_DRAFT)
1222  {
1223  $langs->load("errors");
1224  $nbignored++;
1225  $resaction .= '<div class="error">'.$langs->trans('ErrorOnlyDraftStatusCanBeDeletedInMassAction', $objecttmp->ref).'</div><br>';
1226  continue;
1227  }
1228 
1229  if ($objectclass == "Task" && $objecttmp->hasChildren() > 0)
1230  {
1231  $sql = "UPDATE ".MAIN_DB_PREFIX."projet_task SET fk_task_parent = 0 WHERE fk_task_parent = ".$objecttmp->id;
1232  $res = $db->query($sql);
1233 
1234  if (!$res)
1235  {
1236  setEventMessage('ErrorRecordParentingNotModified', 'errors');
1237  $error++;
1238  }
1239  }
1240 
1241  if (in_array($objecttmp->element, array('societe', 'member'))) $result = $objecttmp->delete($objecttmp->id, $user, 1);
1242  else $result = $objecttmp->delete($user);
1243 
1244  if ($result <= 0)
1245  {
1246  setEventMessages($objecttmp->error, $objecttmp->errors, 'errors');
1247  $error++;
1248  break;
1249  } else $nbok++;
1250  } else {
1251  setEventMessages($objecttmp->error, $objecttmp->errors, 'errors');
1252  $error++;
1253  break;
1254  }
1255  }
1256 
1257  if (!$error)
1258  {
1259  if ($nbok > 1) setEventMessages($langs->trans("RecordsDeleted", $nbok), null, 'mesgs');
1260  else setEventMessages($langs->trans("RecordDeleted", $nbok), null, 'mesgs');
1261  $db->commit();
1262  } else {
1263  $db->rollback();
1264  }
1265  //var_dump($listofobjectthirdparties);exit;
1266 }
1267 
1268 // Generate document foreach object according to model linked to object
1269 // @todo : propose model selection
1270 if (!$error && $massaction == 'generate_doc' && $permissiontoread)
1271 {
1272  $db->begin();
1273 
1274  $objecttmp = new $objectclass($db);
1275  $nbok = 0;
1276  foreach ($toselect as $toselectid)
1277  {
1278  $result = $objecttmp->fetch($toselectid);
1279  if ($result > 0)
1280  {
1281  $outputlangs = $langs;
1282  $newlang = '';
1283 
1284  if ($conf->global->MAIN_MULTILANGS && empty($newlang) && GETPOST('lang_id', 'aZ09')) $newlang = GETPOST('lang_id', 'aZ09');
1285  if ($conf->global->MAIN_MULTILANGS && empty($newlang) && isset($objecttmp->thirdparty->default_lang)) $newlang = $objecttmp->thirdparty->default_lang; // for proposal, order, invoice, ...
1286  if ($conf->global->MAIN_MULTILANGS && empty($newlang) && isset($objecttmp->default_lang)) $newlang = $objecttmp->default_lang; // for thirdparty
1287  if (!empty($newlang))
1288  {
1289  $outputlangs = new Translate("", $conf);
1290  $outputlangs->setDefaultLang($newlang);
1291  }
1292 
1293  // To be sure vars is defined
1294  if (empty($hidedetails)) $hidedetails = 0;
1295  if (empty($hidedesc)) $hidedesc = 0;
1296  if (empty($hideref)) $hideref = 0;
1297  if (empty($moreparams)) $moreparams = null;
1298 
1299  $result = $objecttmp->generateDocument($objecttmp->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
1300 
1301  if ($result <= 0)
1302  {
1303  setEventMessages($objecttmp->error, $objecttmp->errors, 'errors');
1304  $error++;
1305  break;
1306  } else $nbok++;
1307  } else {
1308  setEventMessages($objecttmp->error, $objecttmp->errors, 'errors');
1309  $error++;
1310  break;
1311  }
1312  }
1313 
1314  if (!$error)
1315  {
1316  if ($nbok > 1) setEventMessages($langs->trans("RecordsGenerated", $nbok), null, 'mesgs');
1317  else setEventMessages($langs->trans("RecordGenerated", $nbok), null, 'mesgs');
1318  $db->commit();
1319  } else {
1320  $db->rollback();
1321  }
1322 }
1323 
1324 $parameters['toselect'] = $toselect;
1325 $parameters['uploaddir'] = $uploaddir;
1326 $parameters['massaction'] = $massaction;
1327 $parameters['diroutputmassaction'] = $diroutputmassaction;
1328 
1329 $reshook = $hookmanager->executeHooks('doMassActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
1330 if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
pdf_getFormat(Translate $outputlangs=null, $mode= 'setup')
Return array with format properties of default PDF format.
Definition: pdf.lib.php:45
GETPOST($paramname, $check= 'alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm= 'auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
dol_now($mode= 'auto')
Return date for now.
Class to manage Dolibarr users.
Definition: user.class.php:44
setEventMessage($mesgs, $style= 'mesgs')
Set event message in dol_events session object.
pdf_getPDFFont($outputlangs)
Return font name to use for PDF generation.
Definition: pdf.lib.php:222
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
getCommonSubstitutionArray($outputlangs, $onlykey=0, $exclude=null, $object=null)
Return array of possible common substitutions.
setEventMessages($mesg, $mesgs, $style= 'mesgs', $messagekey= '')
Set event messages in dol_events session object.
Class to manage third parties objects (customers, suppliers, prospects...)
const STATUS_VALIDATED
Validated (need to be paid)
dol_mimetype($file, $default= 'application/octet-stream', $mode=0)
Return mime type of a file.
Class to send emails (with attachments or not) Usage: $mailfile = new CMailFile($subject,$sendto,$replyto,$message,$filepath,$mimetype,$filename,$cc,$ccc,$deliveryreceipt,$msgishtml,$errors_to,$css,$trackid,$moreinheader,$sendcontext,$replyto); $mailfile-&gt;sendfile();.
Class to manage customers orders.
const STATUS_DRAFT
Draft status.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename= '', $restricttologhandler= '', $logcontext=null)
Write log message into outputs.
const STATUS_DRAFT
Draft status.
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart= '')
Return a path to have a the directory according to object where files are stored. ...
dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1)
Remove a file or several files with a mask.
Definition: files.lib.php:1144
Class to manage translations.
dol_sanitizeFileName($str, $newstr= '_', $unaccent=1)
Clean a string to use it as a file name.
dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0)
Scan a directory and return a list of files/directories.
Definition: files.lib.php:60
dol_is_file($pathoffile)
Return if path is a file.
Definition: files.lib.php:457
print $_SERVER["PHP_SELF"]
Edit parameters.
const STATUS_DRAFT
Draft status.
const STATUS_VALIDATED
Validated status.
pdf_getInstance($format= '', $metric= 'mm', $pagetype= 'P')
Return a PDF instance object.
Definition: pdf.lib.php:88
dol_print_date($time, $format= '', $tzoutput= 'auto', $outputlangs= '', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
dol_most_recent_file($dir, $regexfilter= '', $excludefilter=array('(\.meta|_preview.*\.png)$', '^\.'), $nohook=false, $mode= '')
Return file(s) into a directory (by default most recent)
Definition: files.lib.php:2212
if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) if(!empty($conf->don->enabled)&&$user->rights->don->lire) if(!empty($conf->tax->enabled)&&$user->rights->tax->charges->lire) if(!empty($conf->facture->enabled)&&!empty($conf->commande->enabled)&&$user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) $resql
Social contributions to pay.
Definition: index.php:1232
dol_print_error($db= '', $error= '', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
Class to manage absolute discounts.
make_substitutions($text, $substitutionarray, $outputlangs=null)
Make substitution into a text string, replacing keys with vals from $substitutionarray (oldval=&gt;newva...
Class to manage invoices.
dol_mkdir($dir, $dataroot= '', $newmask=null)
Creation of a directory (this can create recursive subdir)
complete_substitutions_array(&$substitutionarray, $outputlangs, $object=null, $parameters=null, $callfunc="completesubstitutionarray")
Complete the $substitutionarray with more entries coming from external module that had set the &quot;subst...