dolibarr  18.0.6
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  if (empty($object->context['closedfromonlinesignature'])) {
79  $langs->load("orders");
80  setEventMessages($langs->trans("OrderExists"), null, 'warnings');
81  }
82  return $ret;
83  } else {
84  include_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
85  $newobject = new Commande($this->db);
86 
87  $newobject->context['createfrompropal'] = 'createfrompropal';
88  $newobject->context['origin'] = $object->element;
89  $newobject->context['origin_id'] = $object->id;
90 
91  $ret = $newobject->createFromProposal($object, $user);
92  if ($ret < 0) {
93  $this->error = $newobject->error;
94  $this->errors[] = $newobject->error;
95  }
96 
97  $object->clearObjectLinkedCache();
98 
99  return $ret;
100  }
101  }
102  }
103 
104  // Order to invoice
105  if ($action == 'ORDER_CLOSE') {
106  dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
107  if (isModEnabled('facture') && !empty($conf->global->WORKFLOW_ORDER_AUTOCREATE_INVOICE)) {
108  include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
109  $newobject = new Facture($this->db);
110 
111  $newobject->context['createfromorder'] = 'createfromorder';
112  $newobject->context['origin'] = $object->element;
113  $newobject->context['origin_id'] = $object->id;
114 
115  $ret = $newobject->createFromOrder($object, $user);
116  if ($ret < 0) {
117  $this->error = $newobject->error;
118  $this->errors[] = $newobject->error;
119  } else {
120  if (empty($object->fk_account) && !empty($object->thirdparty->fk_account) && !getDolGlobalInt('BANK_ASK_PAYMENT_BANK_DURING_ORDER')) {
121  $res = $newobject->setBankAccount($object->thirdparty->fk_account, true, $user);
122  if ($ret < 0) {
123  $this->error = $newobject->error;
124  $this->errors[] = $newobject->error;
125  }
126  }
127  }
128 
129  $object->clearObjectLinkedCache();
130 
131  return $ret;
132  }
133  }
134 
135  // Order classify billed proposal
136  if ($action == 'ORDER_CLASSIFY_BILLED') {
137  dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
138  if (isModEnabled("propal") && !empty($conf->workflow->enabled) && !empty($conf->global->WORKFLOW_ORDER_CLASSIFY_BILLED_PROPAL)) {
139  $object->fetchObjectLinked('', 'propal', $object->id, $object->element);
140  if (!empty($object->linkedObjects)) {
141  $totalonlinkedelements = 0;
142  foreach ($object->linkedObjects['propal'] as $element) {
143  if ($element->statut == Propal::STATUS_SIGNED || $element->statut == Propal::STATUS_BILLED) {
144  $totalonlinkedelements += $element->total_ht;
145  }
146  }
147  dol_syslog("Amount of linked proposals = ".$totalonlinkedelements.", of order = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht));
148  if ($this->shouldClassify($conf, $totalonlinkedelements, $object->total_ht)) {
149  foreach ($object->linkedObjects['propal'] as $element) {
150  $ret = $element->classifyBilled($user);
151  }
152  }
153  }
154  return $ret;
155  }
156  }
157 
158  // classify billed order & billed propososal
159  if ($action == 'BILL_VALIDATE') {
160  dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
161 
162  // First classify billed the order to allow the proposal classify process
163  if (isModEnabled('commande') && !empty($conf->workflow->enabled) && !empty($conf->global->WORKFLOW_INVOICE_AMOUNT_CLASSIFY_BILLED_ORDER)) {
164  $object->fetchObjectLinked('', 'commande', $object->id, $object->element);
165  if (!empty($object->linkedObjects)) {
166  $totalonlinkedelements = 0;
167  foreach ($object->linkedObjects['commande'] as $element) {
168  if ($element->statut == Commande::STATUS_VALIDATED || $element->statut == Commande::STATUS_SHIPMENTONPROCESS || $element->statut == Commande::STATUS_CLOSED) {
169  $totalonlinkedelements += $element->total_ht;
170  }
171  }
172  dol_syslog("Amount of linked orders = ".$totalonlinkedelements.", of invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht));
173  if ($this->shouldClassify($conf, $totalonlinkedelements, $object->total_ht)) {
174  foreach ($object->linkedObjects['commande'] as $element) {
175  $ret = $element->classifyBilled($user);
176  }
177  }
178  }
179  }
180 
181  // Second classify billed the proposal.
182  if (isModEnabled("propal") && !empty($conf->workflow->enabled) && !empty($conf->global->WORKFLOW_INVOICE_CLASSIFY_BILLED_PROPAL)) {
183  $object->fetchObjectLinked('', 'propal', $object->id, $object->element);
184  if (!empty($object->linkedObjects)) {
185  $totalonlinkedelements = 0;
186  foreach ($object->linkedObjects['propal'] as $element) {
187  if ($element->statut == Propal::STATUS_SIGNED || $element->statut == Propal::STATUS_BILLED) {
188  $totalonlinkedelements += $element->total_ht;
189  }
190  }
191  dol_syslog("Amount of linked proposals = ".$totalonlinkedelements.", of invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht));
192  if ($this->shouldClassify($conf, $totalonlinkedelements, $object->total_ht)) {
193  foreach ($object->linkedObjects['propal'] as $element) {
194  $ret = $element->classifyBilled($user);
195  }
196  }
197  }
198  }
199 
200  if (isModEnabled("expedition") && !empty($conf->workflow->enabled) && !empty($conf->global->WORKFLOW_SHIPPING_CLASSIFY_CLOSED_INVOICE)) {
201  $object->fetchObjectLinked('', 'shipping', $object->id, $object->element);
202  if (!empty($object->linkedObjects)) {
203  $totalonlinkedelements = 0;
204  foreach ($object->linkedObjects['shipping'] as $element) {
205  if ($element->statut == Expedition::STATUS_VALIDATED) {
206  $totalonlinkedelements += $element->total_ht;
207  }
208  }
209  dol_syslog("Amount of linked shipment = ".$totalonlinkedelements.", of invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht), LOG_DEBUG);
210  if ($totalonlinkedelements == $object->total_ht) {
211  foreach ($object->linkedObjects['shipping'] as $element) {
212  $ret = $element->setClosed();
213  if ($ret < 0) {
214  return $ret;
215  }
216  }
217  }
218  }
219  }
220 
221  return $ret;
222  }
223 
224  // classify billed order & billed proposal
225  if ($action == 'BILL_SUPPLIER_VALIDATE') {
226  dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
227 
228  // Firstly, we set to purchase order to "Billed" if WORKFLOW_INVOICE_AMOUNT_CLASSIFY_BILLED_SUPPLIER_ORDER is set.
229  // After we will set proposals
230  if ((isModEnabled("supplier_order") || isModEnabled("supplier_invoice")) && !empty($conf->global->WORKFLOW_INVOICE_AMOUNT_CLASSIFY_BILLED_SUPPLIER_ORDER)) {
231  $object->fetchObjectLinked('', 'order_supplier', $object->id, $object->element);
232  if (!empty($object->linkedObjects)) {
233  $totalonlinkedelements = 0;
234  foreach ($object->linkedObjects['order_supplier'] as $element) {
236  $totalonlinkedelements += $element->total_ht;
237  }
238  }
239  dol_syslog("Amount of linked orders = ".$totalonlinkedelements.", of invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht));
240  if ($this->shouldClassify($conf, $totalonlinkedelements, $object->total_ht)) {
241  foreach ($object->linkedObjects['order_supplier'] as $element) {
242  $ret = $element->classifyBilled($user);
243  if ($ret < 0) {
244  return $ret;
245  }
246  }
247  }
248  }
249  }
250 
251  // Secondly, we set to linked Proposal to "Billed" if WORKFLOW_INVOICE_CLASSIFY_BILLED_SUPPLIER_PROPOSAL is set.
252  if (isModEnabled('supplier_proposal') && !empty($conf->global->WORKFLOW_INVOICE_CLASSIFY_BILLED_SUPPLIER_PROPOSAL)) {
253  $object->fetchObjectLinked('', 'supplier_proposal', $object->id, $object->element);
254  if (!empty($object->linkedObjects)) {
255  $totalonlinkedelements = 0;
256  foreach ($object->linkedObjects['supplier_proposal'] as $element) {
257  if ($element->statut == SupplierProposal::STATUS_SIGNED || $element->statut == SupplierProposal::STATUS_BILLED) {
258  $totalonlinkedelements += $element->total_ht;
259  }
260  }
261  dol_syslog("Amount of linked supplier proposals = ".$totalonlinkedelements.", of supplier invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht));
262  if ($this->shouldClassify($conf, $totalonlinkedelements, $object->total_ht)) {
263  foreach ($object->linkedObjects['supplier_proposal'] as $element) {
264  $ret = $element->classifyBilled($user);
265  if ($ret < 0) {
266  return $ret;
267  }
268  }
269  }
270  }
271  }
272 
273  // Then set reception to "Billed" if WORKFLOW_RECEPTION_CLASSIFY_CLOSED_INVOICE is set
274  if (isModEnabled("reception") && !empty($conf->workflow->enabled) && !empty($conf->global->WORKFLOW_RECEPTION_CLASSIFY_CLOSED_INVOICE)) {
275  $object->fetchObjectLinked('', 'reception', $object->id, $object->element);
276  if (!empty($object->linkedObjects)) {
277  $totalonlinkedelements = 0;
278  foreach ($object->linkedObjects['reception'] as $element) {
279  if ($element->statut == Reception::STATUS_VALIDATED || $element->statut == Reception::STATUS_CLOSED) {
280  $totalonlinkedelements += $element->total_ht;
281  }
282  }
283  dol_syslog("Amount of linked reception = ".$totalonlinkedelements.", of invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht), LOG_DEBUG);
284  if ($totalonlinkedelements == $object->total_ht) {
285  foreach ($object->linkedObjects['reception'] as $element) {
286  $ret = $element->setBilled();
287  if ($ret < 0) {
288  return $ret;
289  }
290  }
291  }
292  }
293  }
294 
295  return $ret;
296  }
297 
298  // Invoice classify billed order
299  if ($action == 'BILL_PAYED') {
300  dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
301 
302  if (isModEnabled('commande') && !empty($conf->global->WORKFLOW_INVOICE_CLASSIFY_BILLED_ORDER)) {
303  $object->fetchObjectLinked('', 'commande', $object->id, $object->element);
304  if (!empty($object->linkedObjects)) {
305  $totalonlinkedelements = 0;
306  foreach ($object->linkedObjects['commande'] as $element) {
307  if ($element->statut == Commande::STATUS_VALIDATED || $element->statut == Commande::STATUS_SHIPMENTONPROCESS || $element->statut == Commande::STATUS_CLOSED) {
308  $totalonlinkedelements += $element->total_ht;
309  }
310  }
311  dol_syslog("Amount of linked orders = ".$totalonlinkedelements.", of invoice = ".$object->total_ht.", egality is ".($totalonlinkedelements == $object->total_ht));
312  if ($this->shouldClassify($conf, $totalonlinkedelements, $object->total_ht)) {
313  foreach ($object->linkedObjects['commande'] as $element) {
314  $ret = $element->classifyBilled($user);
315  }
316  }
317  }
318  return $ret;
319  }
320  }
321 
322  // If we validate or close a shipment
323  if (($action == 'SHIPPING_VALIDATE') || ($action == 'SHIPPING_CLOSED')) {
324  dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
325 
326  if (isModEnabled('commande') && isModEnabled("expedition") && !empty($conf->workflow->enabled) &&
327  (
328  (!empty($conf->global->WORKFLOW_ORDER_CLASSIFY_SHIPPED_SHIPPING) && ($action == 'SHIPPING_VALIDATE')) ||
329  (!empty($conf->global->WORKFLOW_ORDER_CLASSIFY_SHIPPED_SHIPPING_CLOSED) && ($action == 'SHIPPING_CLOSED'))
330  )
331  ) {
332  $qtyshipped = array();
333  $qtyordred = array();
334  require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
335 
336  // Find all shipments on order origin
337  $order = new Commande($this->db);
338  $ret = $order->fetch($object->origin_id);
339  if ($ret < 0) {
340  $this->error = $order->error;
341  $this->errors = $order->errors;
342  return $ret;
343  }
344  $ret = $order->fetchObjectLinked($order->id, 'commande', null, 'shipping');
345  if ($ret < 0) {
346  $this->error = $order->error;
347  $this->errors = $order->errors;
348  return $ret;
349  }
350  //Build array of quantity shipped by product for an order
351  if (is_array($order->linkedObjects) && count($order->linkedObjects) > 0) {
352  foreach ($order->linkedObjects as $type => $shipping_array) {
353  if ($type == 'shipping' && is_array($shipping_array) && count($shipping_array) > 0) {
354  foreach ($shipping_array as $shipping) {
355  if (is_array($shipping->lines) && count($shipping->lines) > 0) {
356  foreach ($shipping->lines as $shippingline) {
357  $qtyshipped[$shippingline->fk_product] += $shippingline->qty;
358  }
359  }
360  }
361  }
362  }
363  }
364 
365  //Build array of quantity ordered to be shipped
366  if (is_array($order->lines) && count($order->lines) > 0) {
367  foreach ($order->lines as $orderline) {
368  // Exclude lines not qualified for shipment, similar code is found into calcAndSetStatusDispatch() for vendors
369  if (empty($conf->global->STOCK_SUPPORTS_SERVICES) && $orderline->product_type > 0) {
370  continue;
371  }
372  $qtyordred[$orderline->fk_product] += $orderline->qty;
373  }
374  }
375  //dol_syslog(var_export($qtyordred,true),LOG_DEBUG);
376  //dol_syslog(var_export($qtyshipped,true),LOG_DEBUG);
377  //Compare array
378  $diff_array = array_diff_assoc($qtyordred, $qtyshipped);
379  if (count($diff_array) == 0) {
380  //No diff => mean everythings is shipped
381  $ret = $order->setStatut(Commande::STATUS_CLOSED, $object->origin_id, $object->origin, 'ORDER_CLOSE');
382  if ($ret < 0) {
383  $this->error = $order->error;
384  $this->errors = $order->errors;
385  return $ret;
386  }
387  }
388  }
389  }
390 
391  // If we validate or close a shipment
392  if (($action == 'RECEPTION_VALIDATE') || ($action == 'RECEPTION_CLOSED')) {
393  dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
394 
395  if ((isModEnabled("fournisseur") || isModEnabled("supplier_order")) && isModEnabled("reception") && !empty($conf->workflow->enabled) &&
396  (
397  (!empty($conf->global->WORKFLOW_ORDER_CLASSIFY_RECEIVED_RECEPTION) && ($action == 'RECEPTION_VALIDATE')) ||
398  (!empty($conf->global->WORKFLOW_ORDER_CLASSIFY_RECEIVED_RECEPTION_CLOSED) && ($action == 'RECEPTION_CLOSED'))
399  )
400  ) {
401  $qtyshipped = array();
402  $qtyordred = array();
403  require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
404 
405  // Find all reception on purchase order origin
406  $order = new CommandeFournisseur($this->db);
407  $ret = $order->fetch($object->origin_id);
408  if ($ret < 0) {
409  $this->error = $order->error;
410  $this->errors = $order->errors;
411  return $ret;
412  }
413  $ret = $order->fetchObjectLinked($order->id, $order->element, null, 'reception');
414  if ($ret < 0) {
415  $this->error = $order->error;
416  $this->errors = $order->errors;
417  return $ret;
418  }
419  //Build array of quantity received by product for a purchase order
420  if (is_array($order->linkedObjects) && count($order->linkedObjects) > 0) {
421  foreach ($order->linkedObjects as $type => $shipping_array) {
422  if ($type == 'reception' && is_array($shipping_array) && count($shipping_array) > 0) {
423  foreach ($shipping_array as $shipping) {
424  if (is_array($shipping->lines) && count($shipping->lines) > 0) {
425  foreach ($shipping->lines as $shippingline) {
426  $qtyshipped[$shippingline->fk_product] += $shippingline->qty;
427  }
428  }
429  }
430  }
431  }
432  }
433 
434  //Build array of quantity ordered to be received
435  if (is_array($order->lines) && count($order->lines) > 0) {
436  foreach ($order->lines as $orderline) {
437  // Exclude lines not qualified for shipment, similar code is found into calcAndSetStatusDispatch() for vendors
438  if (empty($conf->global->STOCK_SUPPORTS_SERVICES) && $orderline->product_type > 0) {
439  continue;
440  }
441  $qtyordred[$orderline->fk_product] += $orderline->qty;
442  }
443  }
444  //dol_syslog(var_export($qtyordred,true),LOG_DEBUG);
445  //dol_syslog(var_export($qtyshipped,true),LOG_DEBUG);
446  //Compare array
447  $diff_array = array_diff_assoc($qtyordred, $qtyshipped);
448  if (count($diff_array) == 0) {
449  //No diff => mean everythings is received
450  $ret = $order->setStatut(CommandeFournisseur::STATUS_RECEIVED_COMPLETELY, null, null, 'SUPPLIER_ORDER_CLOSE');
451  if ($ret < 0) {
452  $this->error = $order->error;
453  $this->errors = $order->errors;
454  return $ret;
455  }
456  }
457  }
458  }
459 
460  if ($action == 'TICKET_CREATE') {
461  dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id);
462  // Auto link contract
463  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)) {
464  $societe = new Societe($this->db);
465  $company_ids = (empty($conf->global->WORKFLOW_TICKET_USE_PARENT_COMPANY_CONTRACTS)) ? [$object->fk_soc] : $societe->getParentsForCompany($object->fk_soc, [$object->fk_soc]);
466 
467  $contrat = new Contrat($this->db);
468  $number_contracts_found = 0;
469  foreach ($company_ids as $company_id) {
470  $contrat->socid = $company_id;
471  $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]);
472  if (is_array($list) && !empty($list)) {
473  $number_contracts_found = count($list);
474  if ($number_contracts_found == 1) {
475  foreach ($list as $linked_contract) {
476  $object->setContract($linked_contract->id);
477  }
478  break;
479  } elseif ($number_contracts_found > 1) {
480  foreach ($list as $linked_contract) {
481  $object->setContract($linked_contract->id);
482  // don't set '$contractid' so it is not used when creating an intervention.
483  }
484  if (empty(NOLOGIN)) setEventMessage($langs->trans('TicketManyContractsLinked'), 'warnings');
485  break;
486  }
487  }
488  }
489  if ($number_contracts_found == 0) {
490  if (empty(NOLOGIN)) setEventMessage($langs->trans('TicketNoContractFoundToLink'), 'mesgs');
491  }
492  }
493  // Automatically create intervention
494  if (isModEnabled('ficheinter') && isModEnabled('ticket') && !empty($conf->workflow->enabled) && !empty($conf->global->WORKFLOW_TICKET_CREATE_INTERVENTION)) {
495  $fichinter = new Fichinter($this->db);
496  $fichinter->socid = (int) $object->fk_soc;
497  $fichinter->fk_project = $projectid;
498  $fichinter->fk_contrat = (int) $object->fk_contract;
499  $fichinter->author = $user->id;
500  $fichinter->model_pdf = (!empty($conf->global->FICHEINTER_ADDON_PDF)) ? $conf->global->FICHEINTER_ADDON_PDF : 'soleil';
501  $fichinter->origin = $object->element;
502  $fichinter->origin_id = $object->id;
503 
504  // Extrafields
505  $extrafields = new ExtraFields($this->db);
506  $extrafields->fetch_name_optionals_label($fichinter->table_element);
507  $array_options = $extrafields->getOptionalsFromPost($fichinter->table_element);
508  $fichinter->array_options = $array_options;
509 
510  $id = $fichinter->create($user);
511  if ($id <= 0) {
512  setEventMessages($fichinter->error, null, 'errors');
513  }
514  }
515  }
516  return 0;
517  }
518 
529  private function shouldClassify($conf, $totalonlinkedelements, $object_total_ht)
530  {
531  // if the configuration allows unmatching amounts, allow classification anyway
532  if (!empty($conf->global->WORKFLOW_CLASSIFY_IF_AMOUNTS_ARE_DIFFERENTS)) {
533  return true;
534  }
535  // if the amount are same, allow classification, else deny
536  return (price2num($totalonlinkedelements, 'MT') == price2num($object_total_ht, 'MT'));
537  }
538 }
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:48
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 '.
setEventMessage($mesgs, $style='mesgs', $noduplicate=0)
Set event message in dol_events session object.
getDolGlobalInt($key, $default=0)
Return dolibarr global constant int value.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0)
Set event messages 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:123