dolibarr  x.y.z
interface_20_modWorkflow_WorkflowManager.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2010 Regis Houssin <regis.houssin@inodbox.com>
3  * Copyright (C) 2011-2017 Laurent Destailleur <eldy@users.sourceforge.net>
4  * Copyright (C) 2014 Marcos GarcĂ­a <marcosgdf@gmail.com>
5  * Copyright (C) 2022 Ferran Marcet <fmarcet@2byte.es>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <https://www.gnu.org/licenses/>.
19  */
20 
27 require_once DOL_DOCUMENT_ROOT.'/core/triggers/dolibarrtriggers.class.php';
28 
29 
35 {
41  public function __construct($db)
42  {
43  $this->db = $db;
44 
45  $this->name = preg_replace('/^Interface/i', '', get_class($this));
46  $this->family = "core";
47  $this->description = "Triggers of this module allows to manage workflows";
48  // 'development', 'experimental', 'dolibarr' or version
49  $this->version = self::VERSION_DOLIBARR;
50  $this->picto = 'technic';
51  }
52 
64  public function runTrigger($action, $object, User $user, Translate $langs, Conf $conf)
65  {
66  if (empty($conf->workflow) || empty($conf->workflow->enabled)) {
67  return 0; // Module not active, we do nothing
68  }
69 
70  $ret = 0;
71 
72  // Proposals to order
73  if ($action == 'PROPAL_CLOSE_SIGNED') {
74  dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
75  if (isModEnabled('commande') && !empty($conf->global->WORKFLOW_PROPAL_AUTOCREATE_ORDER)) {
76  $object->fetchObjectLinked();
77  if (!empty($object->linkedObjectsIds['commande'])) {
78  setEventMessages($langs->trans("OrderExists"), null, 'warnings');
79  return $ret;
80  } else {
81  include_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
82  $newobject = new Commande($this->db);
83 
84  $newobject->context['createfrompropal'] = 'createfrompropal';
85  $newobject->context['origin'] = $object->element;
86  $newobject->context['origin_id'] = $object->id;
87 
88  $ret = $newobject->createFromProposal($object, $user);
89  if ($ret < 0) {
90  $this->error = $newobject->error;
91  $this->errors[] = $newobject->error;
92  }
93 
94  $object->clearObjectLinkedCache();
95 
96  return $ret;
97  }
98  }
99  }
100 
101  // Order to invoice
102  if ($action == 'ORDER_CLOSE') {
103  dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
104  if (isModEnabled('facture') && !empty($conf->global->WORKFLOW_ORDER_AUTOCREATE_INVOICE)) {
105  include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
106  $newobject = new Facture($this->db);
107 
108  $newobject->context['createfromorder'] = 'createfromorder';
109  $newobject->context['origin'] = $object->element;
110  $newobject->context['origin_id'] = $object->id;
111 
112  $ret = $newobject->createFromOrder($object, $user);
113  if ($ret < 0) {
114  $this->error = $newobject->error;
115  $this->errors[] = $newobject->error;
116  }
117 
118  $object->clearObjectLinkedCache();
119 
120  return $ret;
121  }
122  }
123 
124  // Order classify billed proposal
125  if ($action == 'ORDER_CLASSIFY_BILLED') {
126  dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
127  if (isModEnabled("propal") && !empty($conf->workflow->enabled) && !empty($conf->global->WORKFLOW_ORDER_CLASSIFY_BILLED_PROPAL)) {
128  $object->fetchObjectLinked('', 'propal', $object->id, $object->element);
129  if (!empty($object->linkedObjects)) {
130  $totalonlinkedelements = 0;
131  foreach ($object->linkedObjects['propal'] as $element) {
132  if ($element->statut == Propal::STATUS_SIGNED || $element->statut == Propal::STATUS_BILLED) {
133  $totalonlinkedelements += $element->total_ht;
134  }
135  }
136  dol_syslog("Amount of linked proposals = ".$totalonlinkedelements.", of order = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht));
137  if ($this->shouldClassify($conf, $totalonlinkedelements, $object->total_ht)) {
138  foreach ($object->linkedObjects['propal'] as $element) {
139  $ret = $element->classifyBilled($user);
140  }
141  }
142  }
143  return $ret;
144  }
145  }
146 
147  // classify billed order & billed propososal
148  if ($action == 'BILL_VALIDATE') {
149  dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
150 
151  // First classify billed the order to allow the proposal classify process
152  if (isModEnabled('commande') && !empty($conf->workflow->enabled) && !empty($conf->global->WORKFLOW_INVOICE_AMOUNT_CLASSIFY_BILLED_ORDER)) {
153  $object->fetchObjectLinked('', 'commande', $object->id, $object->element);
154  if (!empty($object->linkedObjects)) {
155  $totalonlinkedelements = 0;
156  foreach ($object->linkedObjects['commande'] as $element) {
157  if ($element->statut == Commande::STATUS_VALIDATED || $element->statut == Commande::STATUS_SHIPMENTONPROCESS || $element->statut == Commande::STATUS_CLOSED) {
158  $totalonlinkedelements += $element->total_ht;
159  }
160  }
161  dol_syslog("Amount of linked orders = ".$totalonlinkedelements.", of invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht));
162  if ($this->shouldClassify($conf, $totalonlinkedelements, $object->total_ht)) {
163  foreach ($object->linkedObjects['commande'] as $element) {
164  $ret = $element->classifyBilled($user);
165  }
166  }
167  }
168  }
169 
170  // Second classify billed the proposal.
171  if (isModEnabled("propal") && !empty($conf->workflow->enabled) && !empty($conf->global->WORKFLOW_INVOICE_CLASSIFY_BILLED_PROPAL)) {
172  $object->fetchObjectLinked('', 'propal', $object->id, $object->element);
173  if (!empty($object->linkedObjects)) {
174  $totalonlinkedelements = 0;
175  foreach ($object->linkedObjects['propal'] as $element) {
176  if ($element->statut == Propal::STATUS_SIGNED || $element->statut == Propal::STATUS_BILLED) {
177  $totalonlinkedelements += $element->total_ht;
178  }
179  }
180  dol_syslog("Amount of linked proposals = ".$totalonlinkedelements.", of invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht));
181  if ($this->shouldClassify($conf, $totalonlinkedelements, $object->total_ht)) {
182  foreach ($object->linkedObjects['propal'] as $element) {
183  $ret = $element->classifyBilled($user);
184  }
185  }
186  }
187  }
188 
189  if (isModEnabled("expedition") && !empty($conf->workflow->enabled) && !empty($conf->global->WORKFLOW_SHIPPING_CLASSIFY_CLOSED_INVOICE)) {
190  $object->fetchObjectLinked('', 'shipping', $object->id, $object->element);
191  if (!empty($object->linkedObjects)) {
192  $totalonlinkedelements = 0;
193  foreach ($object->linkedObjects['shipping'] as $element) {
194  if ($element->statut == Expedition::STATUS_VALIDATED) {
195  $totalonlinkedelements += $element->total_ht;
196  }
197  }
198  dol_syslog("Amount of linked shipment = ".$totalonlinkedelements.", of invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht), LOG_DEBUG);
199  if ($totalonlinkedelements == $object->total_ht) {
200  foreach ($object->linkedObjects['shipping'] as $element) {
201  $ret = $element->setClosed();
202  if ($ret < 0) {
203  return $ret;
204  }
205  }
206  }
207  }
208  }
209 
210  return $ret;
211  }
212 
213  // classify billed order & billed proposal
214  if ($action == 'BILL_SUPPLIER_VALIDATE') {
215  dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
216 
217  // Firstly, we set to purchase order to "Billed" if WORKFLOW_INVOICE_AMOUNT_CLASSIFY_BILLED_SUPPLIER_ORDER is set.
218  // After we will set proposals
219  if (((isModEnabled("fournisseur") && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)) || isModEnabled("supplier_order") || isModEnabled("supplier_invoice")) && !empty($conf->global->WORKFLOW_INVOICE_AMOUNT_CLASSIFY_BILLED_SUPPLIER_ORDER)) {
220  $object->fetchObjectLinked('', 'order_supplier', $object->id, $object->element);
221  if (!empty($object->linkedObjects)) {
222  $totalonlinkedelements = 0;
223  foreach ($object->linkedObjects['order_supplier'] as $element) {
225  $totalonlinkedelements += $element->total_ht;
226  }
227  }
228  dol_syslog("Amount of linked orders = ".$totalonlinkedelements.", of invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht));
229  if ($this->shouldClassify($conf, $totalonlinkedelements, $object->total_ht)) {
230  foreach ($object->linkedObjects['order_supplier'] as $element) {
231  $ret = $element->classifyBilled($user);
232  if ($ret < 0) {
233  return $ret;
234  }
235  }
236  }
237  }
238  }
239 
240  // Secondly, we set to linked Proposal to "Billed" if WORKFLOW_INVOICE_CLASSIFY_BILLED_SUPPLIER_PROPOSAL is set.
241  if (isModEnabled('supplier_proposal') && !empty($conf->global->WORKFLOW_INVOICE_CLASSIFY_BILLED_SUPPLIER_PROPOSAL)) {
242  $object->fetchObjectLinked('', 'supplier_proposal', $object->id, $object->element);
243  if (!empty($object->linkedObjects)) {
244  $totalonlinkedelements = 0;
245  foreach ($object->linkedObjects['supplier_proposal'] as $element) {
246  if ($element->statut == SupplierProposal::STATUS_SIGNED || $element->statut == SupplierProposal::STATUS_BILLED) {
247  $totalonlinkedelements += $element->total_ht;
248  }
249  }
250  dol_syslog("Amount of linked supplier proposals = ".$totalonlinkedelements.", of supplier invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht));
251  if ($this->shouldClassify($conf, $totalonlinkedelements, $object->total_ht)) {
252  foreach ($object->linkedObjects['supplier_proposal'] as $element) {
253  $ret = $element->classifyBilled($user);
254  if ($ret < 0) {
255  return $ret;
256  }
257  }
258  }
259  }
260  }
261 
262  // Then set reception to "Billed" if WORKFLOW_EXPEDITION_CLASSIFY_CLOSED_INVOICE is set
263  if (isModEnabled("reception") && !empty($conf->workflow->enabled) && !empty($conf->global->WORKFLOW_EXPEDITION_CLASSIFY_CLOSED_INVOICE)) {
264  $object->fetchObjectLinked('', 'reception', $object->id, $object->element);
265  if (!empty($object->linkedObjects)) {
266  $totalonlinkedelements = 0;
267  foreach ($object->linkedObjects['reception'] as $element) {
268  if ($element->statut == Reception::STATUS_VALIDATED) {
269  $totalonlinkedelements += $element->total_ht;
270  }
271  }
272  dol_syslog("Amount of linked reception = ".$totalonlinkedelements.", of invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht), LOG_DEBUG);
273  if ($totalonlinkedelements == $object->total_ht) {
274  foreach ($object->linkedObjects['reception'] as $element) {
275  $ret = $element->setBilled();
276  if ($ret < 0) {
277  return $ret;
278  }
279  }
280  }
281  }
282  }
283 
284  return $ret;
285  }
286 
287  // Invoice classify billed order
288  if ($action == 'BILL_PAYED') {
289  dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
290 
291  if (isModEnabled('commande') && !empty($conf->global->WORKFLOW_INVOICE_CLASSIFY_BILLED_ORDER)) {
292  $object->fetchObjectLinked('', 'commande', $object->id, $object->element);
293  if (!empty($object->linkedObjects)) {
294  $totalonlinkedelements = 0;
295  foreach ($object->linkedObjects['commande'] as $element) {
296  if ($element->statut == Commande::STATUS_VALIDATED || $element->statut == Commande::STATUS_SHIPMENTONPROCESS || $element->statut == Commande::STATUS_CLOSED) {
297  $totalonlinkedelements += $element->total_ht;
298  }
299  }
300  dol_syslog("Amount of linked orders = ".$totalonlinkedelements.", of invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht));
301  if ($this->shouldClassify($conf, $totalonlinkedelements, $object->total_ht)) {
302  foreach ($object->linkedObjects['commande'] as $element) {
303  $ret = $element->classifyBilled($user);
304  }
305  }
306  }
307  return $ret;
308  }
309  }
310 
311  // If we validate or close a shipment
312  if (($action == 'SHIPPING_VALIDATE') || ($action == 'SHIPPING_CLOSED')) {
313  dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
314 
315  if (isModEnabled('commande') && isModEnabled("expedition") && !empty($conf->workflow->enabled) &&
316  (
317  (!empty($conf->global->WORKFLOW_ORDER_CLASSIFY_SHIPPED_SHIPPING) && ($action == 'SHIPPING_VALIDATE')) ||
318  (!empty($conf->global->WORKFLOW_ORDER_CLASSIFY_SHIPPED_SHIPPING_CLOSED) && ($action == 'SHIPPING_CLOSED'))
319  )
320  ) {
321  $qtyshipped = array();
322  $qtyordred = array();
323  require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
324 
325  // Find all shipments on order origin
326  $order = new Commande($this->db);
327  $ret = $order->fetch($object->origin_id);
328  if ($ret < 0) {
329  $this->error = $order->error;
330  $this->errors = $order->errors;
331  return $ret;
332  }
333  $ret = $order->fetchObjectLinked($order->id, 'commande', null, 'shipping');
334  if ($ret < 0) {
335  $this->error = $order->error;
336  $this->errors = $order->errors;
337  return $ret;
338  }
339  //Build array of quantity shipped by product for an order
340  if (is_array($order->linkedObjects) && count($order->linkedObjects) > 0) {
341  foreach ($order->linkedObjects as $type => $shipping_array) {
342  if ($type == 'shipping' && is_array($shipping_array) && count($shipping_array) > 0) {
343  foreach ($shipping_array as $shipping) {
344  if (is_array($shipping->lines) && count($shipping->lines) > 0) {
345  foreach ($shipping->lines as $shippingline) {
346  $qtyshipped[$shippingline->fk_product] += $shippingline->qty;
347  }
348  }
349  }
350  }
351  }
352  }
353 
354  //Build array of quantity ordered to be shipped
355  if (is_array($order->lines) && count($order->lines) > 0) {
356  foreach ($order->lines as $orderline) {
357  // Exclude lines not qualified for shipment, similar code is found into calcAndSetStatusDispatch() for vendors
358  if (empty($conf->global->STOCK_SUPPORTS_SERVICES) && $orderline->product_type > 0) {
359  continue;
360  }
361  $qtyordred[$orderline->fk_product] += $orderline->qty;
362  }
363  }
364  //dol_syslog(var_export($qtyordred,true),LOG_DEBUG);
365  //dol_syslog(var_export($qtyshipped,true),LOG_DEBUG);
366  //Compare array
367  $diff_array = array_diff_assoc($qtyordred, $qtyshipped);
368  if (count($diff_array) == 0) {
369  //No diff => mean everythings is shipped
370  $ret = $order->setStatut(Commande::STATUS_CLOSED, $object->origin_id, $object->origin, 'ORDER_CLOSE');
371  if ($ret < 0) {
372  $this->error = $order->error;
373  $this->errors = $order->errors;
374  return $ret;
375  }
376  }
377  }
378  }
379 
380  // If we validate or close a shipment
381  if (($action == 'RECEPTION_VALIDATE') || ($action == 'RECEPTION_CLOSED')) {
382  dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
383 
384  if ((isModEnabled("fournisseur") || isModEnabled("supplier_order")) && isModEnabled("reception") && !empty($conf->workflow->enabled) &&
385  (
386  (!empty($conf->global->WORKFLOW_ORDER_CLASSIFY_RECEIVED_RECEPTION) && ($action == 'RECEPTION_VALIDATE')) ||
387  (!empty($conf->global->WORKFLOW_ORDER_CLASSIFY_RECEIVED_RECEPTION_CLOSED) && ($action == 'RECEPTION_CLOSED'))
388  )
389  ) {
390  $qtyshipped = array();
391  $qtyordred = array();
392  require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
393 
394  // Find all reception on purchase order origin
395  $order = new CommandeFournisseur($this->db);
396  $ret = $order->fetch($object->origin_id);
397  if ($ret < 0) {
398  $this->error = $order->error;
399  $this->errors = $order->errors;
400  return $ret;
401  }
402  $ret = $order->fetchObjectLinked($order->id, 'supplier_order', null, 'reception');
403  if ($ret < 0) {
404  $this->error = $order->error;
405  $this->errors = $order->errors;
406  return $ret;
407  }
408  //Build array of quantity received by product for a purchase order
409  if (is_array($order->linkedObjects) && count($order->linkedObjects) > 0) {
410  foreach ($order->linkedObjects as $type => $shipping_array) {
411  if ($type == 'reception' && is_array($shipping_array) && count($shipping_array) > 0) {
412  foreach ($shipping_array as $shipping) {
413  if (is_array($shipping->lines) && count($shipping->lines) > 0) {
414  foreach ($shipping->lines as $shippingline) {
415  $qtyshipped[$shippingline->fk_product] += $shippingline->qty;
416  }
417  }
418  }
419  }
420  }
421  }
422 
423  //Build array of quantity ordered to be received
424  if (is_array($order->lines) && count($order->lines) > 0) {
425  foreach ($order->lines as $orderline) {
426  // Exclude lines not qualified for shipment, similar code is found into calcAndSetStatusDispatch() for vendors
427  if (empty($conf->global->STOCK_SUPPORTS_SERVICES) && $orderline->product_type > 0) {
428  continue;
429  }
430  $qtyordred[$orderline->fk_product] += $orderline->qty;
431  }
432  }
433  //dol_syslog(var_export($qtyordred,true),LOG_DEBUG);
434  //dol_syslog(var_export($qtyshipped,true),LOG_DEBUG);
435  //Compare array
436  $diff_array = array_diff_assoc($qtyordred, $qtyshipped);
437  if (count($diff_array) == 0) {
438  //No diff => mean everythings is received
439  $ret = $order->setStatut(CommandeFournisseur::STATUS_RECEIVED_COMPLETELY, $object->origin_id, $object->origin, 'SUPPLIER_ORDER_CLOSE');
440  if ($ret < 0) {
441  $this->error = $order->error;
442  $this->errors = $order->errors;
443  return $ret;
444  }
445  }
446  }
447  }
448 
449  if ($action == 'TICKET_CREATE') {
450  dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
451  // Auto link contract
452  if (!empty($conf->contract->enabled) && isModEnabled('ticket') && isModEnabled('ficheinter') && !empty($conf->workflow->enabled) && !empty($conf->global->WORKFLOW_TICKET_LINK_CONTRACT) && !empty($conf->global->TICKET_PRODUCT_CATEGORY) && !empty($object->fk_soc)) {
453  $societe = new Societe($this->db);
454  $company_ids = (empty($conf->global->WORKFLOW_TICKET_USE_PARENT_COMPANY_CONTRACTS)) ? [$object->fk_soc] : $societe->getParentsForCompany($object->fk_soc, [$object->fk_soc]);
455 
456  $contrat = new Contrat($this->db);
457  $number_contracts_found = 0;
458  foreach ($company_ids as $company_id) {
459  $contrat->socid = $company_id;
460  $list = $contrat->getListOfContracts($option = 'all', $status = [Contrat::STATUS_DRAFT, Contrat::STATUS_VALIDATED], $product_categories = [$conf->global->TICKET_PRODUCT_CATEGORY], $line_status = [ContratLigne::STATUS_INITIAL, ContratLigne::STATUS_OPEN]);
461  if (is_array($list) && !empty($list)) {
462  $number_contracts_found = count($list);
463  if ($number_contracts_found == 1) {
464  foreach ($list as $linked_contract) {
465  $object->setContract($linked_contract->id);
466  }
467  break;
468  } elseif ($number_contracts_found > 1) {
469  foreach ($list as $linked_contract) {
470  $object->setContract($linked_contract->id);
471  // don't set '$contractid' so it is not used when creating an intervention.
472  }
473  if (empty(NOLOGIN)) setEventMessage($langs->trans('TicketManyContractsLinked'), 'warnings');
474  break;
475  }
476  }
477  }
478  if ($number_contracts_found == 0) {
479  if (empty(NOLOGIN)) setEventMessage($langs->trans('TicketNoContractFoundToLink'), 'mesgs');
480  }
481  }
482  // Automatically create intervention
483  if (isModEnabled('ficheinter') && isModEnabled('ticket') && !empty($conf->workflow->enabled) && !empty($conf->global->WORKFLOW_TICKET_CREATE_INTERVENTION)) {
484  $fichinter = new Fichinter($this->db);
485  $fichinter->socid = (int) $object->fk_soc;
486  $fichinter->fk_project = $projectid;
487  $fichinter->fk_contrat = (int) $object->fk_contract;
488  $fichinter->author = $user->id;
489  $fichinter->model_pdf = (!empty($conf->global->FICHEINTER_ADDON_PDF)) ? $conf->global->FICHEINTER_ADDON_PDF : 'soleil';
490  $fichinter->origin = $object->element;
491  $fichinter->origin_id = $object->id;
492 
493  // Extrafields
494  $extrafields = new ExtraFields($this->db);
495  $extrafields->fetch_name_optionals_label($fichinter->table_element);
496  $array_options = $extrafields->getOptionalsFromPost($fichinter->table_element);
497  $fichinter->array_options = $array_options;
498 
499  $id = $fichinter->create($user);
500  if ($id <= 0) {
501  setEventMessages($fichinter->error, null, 'errors');
502  }
503  }
504  }
505  return 0;
506  }
507 
518  private function shouldClassify($conf, $totalonlinkedelements, $object_total_ht)
519  {
520  // if the configuration allows unmatching amounts, allow classification anyway
521  if (!empty($conf->global->WORKFLOW_CLASSIFY_IF_AMOUNTS_ARE_DIFFERENTS)) {
522  return true;
523  }
524  // if the amount are same, allow classification, else deny
525  return (price2num($totalonlinkedelements, 'MT') == price2num($object_total_ht, 'MT'));
526  }
527 }
Class to manage predefined suppliers products.
const STATUS_RECEIVED_PARTIALLY
Received partially.
const STATUS_RECEIVED_COMPLETELY
Received completely.
const STATUS_ORDERSENT
Order sent, shipment on process.
Class to manage customers orders.
const STATUS_SHIPMENTONPROCESS
Shipment on process.
const STATUS_CLOSED
Closed (Sent, billed or not)
const STATUS_VALIDATED
Validated status.
Class to stock current configuration.
Definition: conf.class.php:34
Class to manage contracts.
Class that all the triggers must extend.
const STATUS_VALIDATED
Validated status.
Class to manage standard extra fields.
Class to manage invoices.
Class to manage interventions.
runTrigger($action, $object, User $user, Translate $langs, Conf $conf)
Function called when a Dolibarrr business event is done.
shouldClassify($conf, $totalonlinkedelements, $object_total_ht)
const STATUS_SIGNED
Signed quote.
const STATUS_BILLED
Billed or processed quote.
Class to manage third parties objects (customers, suppliers, prospects...)
const STATUS_SIGNED
Signed quote.
Class to manage translations.
Class to manage Dolibarr users.
Definition: user.class.php:45
print *****$script_file(".$version.") pid cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='')
Set event messages in dol_events session object.
setEventMessage($mesgs, $style='mesgs')
Set event message in dol_events session object.
isModEnabled($module)
Is Dolibarr module enabled.
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:122
$conf db
API class for accounts.
Definition: inc.php:41