dolibarr  18.0.0
blockedlog.class.php
1 <?php
2 /* Copyright (C) 2017 ATM Consulting <contact@atm-consulting.fr>
3  * Copyright (C) 2017-2020 Laurent Destailleur <eldy@destailleur.fr>
4  * Copyright (C) 2022 charlene benke <charlene@patas-monkey.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <https://www.gnu.org/licenses/>.
18  *
19  * See https://medium.com/@lhartikk/a-blockchain-in-200-lines-of-code-963cc1cc0e54
20  */
21 
22 
27 {
32  public $id;
33 
38  public $entity;
39 
43  public $error = '';
44 
48  public $errors = array();
49 
54  public $signature = '';
55 
60  public $signature_line = '';
61 
62  public $amounts = null;
63 
68  public $action = '';
69 
74  public $element = '';
75 
80  public $fk_object = 0;
81 
86  public $certified = false;
87 
92  public $fk_user = 0;
93 
97  public $date_creation;
98 
102  public $date_modification;
103 
104  public $date_object = 0;
105 
106  public $ref_object = '';
107 
108  public $object_data = null;
109  public $object_version = '';
110 
111  public $user_fullname = '';
112 
117  public $trackedevents = array();
118 
119 
120 
126  public function __construct(DoliDB $db)
127  {
128  $this->db = $db;
129  }
130 
131 
137  public function loadTrackedEvents()
138  {
139  global $conf;
140 
141  $this->trackedevents = array();
142 
143  // Customer Invoice/Facture / Payment
144  if (isModEnabled('facture')) {
145  $this->trackedevents['BILL_VALIDATE'] = 'logBILL_VALIDATE';
146  $this->trackedevents['BILL_DELETE'] = 'logBILL_DELETE';
147  $this->trackedevents['BILL_SENTBYMAIL'] = 'logBILL_SENTBYMAIL';
148  $this->trackedevents['DOC_DOWNLOAD'] = 'BlockedLogBillDownload';
149  $this->trackedevents['DOC_PREVIEW'] = 'BlockedLogBillPreview';
150  $this->trackedevents['PAYMENT_CUSTOMER_CREATE'] = 'logPAYMENT_CUSTOMER_CREATE';
151  $this->trackedevents['PAYMENT_CUSTOMER_DELETE'] = 'logPAYMENT_CUSTOMER_DELETE';
152  }
153 
154  /* Supplier
155  // Supplier Invoice / Payment
156  if (isModEnabled("fournisseur")) {
157  $this->trackedevents['BILL_SUPPLIER_VALIDATE']='BlockedLogSupplierBillValidate';
158  $this->trackedevents['BILL_SUPPLIER_DELETE']='BlockedLogSupplierBillDelete';
159  $this->trackedevents['BILL_SUPPLIER_SENTBYMAIL']='BlockedLogSupplierBillSentByEmail'; // Trigger key does not exists, we want just into array to list it as done
160  $this->trackedevents['SUPPLIER_DOC_DOWNLOAD']='BlockedLogSupplierBillDownload'; // Trigger key does not exists, we want just into array to list it as done
161  $this->trackedevents['SUPPLIER_DOC_PREVIEW']='BlockedLogSupplierBillPreview'; // Trigger key does not exists, we want just into array to list it as done
162  $this->trackedevents['PAYMENT_SUPPLIER_CREATE']='BlockedLogSupplierBillPaymentCreate';
163  $this->trackedevents['PAYMENT_SUPPLIER_DELETE']='BlockedLogsupplierBillPaymentCreate';
164  }
165  */
166 
167  // Donation
168  if (isModEnabled('don')) {
169  $this->trackedevents['DON_VALIDATE'] = 'logDON_VALIDATE';
170  $this->trackedevents['DON_DELETE'] = 'logDON_DELETE';
171  //$this->trackedevents['DON_SENTBYMAIL']='logDON_SENTBYMAIL';
172  $this->trackedevents['DONATION_PAYMENT_CREATE'] = 'logDONATION_PAYMENT_CREATE';
173  $this->trackedevents['DONATION_PAYMENT_DELETE'] = 'logDONATION_PAYMENT_DELETE';
174  }
175 
176  /*
177  // Salary
178  if (!empty($conf->salary->enabled)) {
179  $this->trackedevents['PAYMENT_SALARY_CREATE']='BlockedLogSalaryPaymentCreate';
180  $this->trackedevents['PAYMENT_SALARY_MODIFY']='BlockedLogSalaryPaymentCreate';
181  $this->trackedevents['PAYMENT_SALARY_DELETE']='BlockedLogSalaryPaymentCreate';
182  }
183  */
184 
185  // Members
186  if (isModEnabled('adherent')) {
187  $this->trackedevents['MEMBER_SUBSCRIPTION_CREATE'] = 'logMEMBER_SUBSCRIPTION_CREATE';
188  $this->trackedevents['MEMBER_SUBSCRIPTION_MODIFY'] = 'logMEMBER_SUBSCRIPTION_MODIFY';
189  $this->trackedevents['MEMBER_SUBSCRIPTION_DELETE'] = 'logMEMBER_SUBSCRIPTION_DELETE';
190  }
191 
192  // Bank
193  if (isModEnabled("banque")) {
194  $this->trackedevents['PAYMENT_VARIOUS_CREATE'] = 'logPAYMENT_VARIOUS_CREATE';
195  $this->trackedevents['PAYMENT_VARIOUS_MODIFY'] = 'logPAYMENT_VARIOUS_MODIFY';
196  $this->trackedevents['PAYMENT_VARIOUS_DELETE'] = 'logPAYMENT_VARIOUS_DELETE';
197  }
198 
199  // Cashdesk
200  // $conf->global->BANK_ENABLE_POS_CASHCONTROL must be set to 1 by all external POS modules
201  $moduleposenabled = (!empty($conf->cashdesk->enabled) || !empty($conf->takepos->enabled) || !empty($conf->global->BANK_ENABLE_POS_CASHCONTROL));
202  if ($moduleposenabled) {
203  $this->trackedevents['CASHCONTROL_VALIDATE'] = 'logCASHCONTROL_VALIDATE';
204  }
205 
206  // Add more action to track from a conf variable
207  // For example: STOCK_MOVEMENT,...
208  if (!empty($conf->global->BLOCKEDLOG_ADD_ACTIONS_SUPPORTED)) {
209  $tmparrayofmoresupportedevents = explode(',', $conf->global->BLOCKEDLOG_ADD_ACTIONS_SUPPORTED);
210  foreach ($tmparrayofmoresupportedevents as $val) {
211  $this->trackedevents[$val] = 'log'.$val;
212  }
213  }
214 
215  return 1;
216  }
217 
223  public function getObjectLink()
224  {
225  global $langs;
226 
227  if ($this->element === 'facture') {
228  require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
229 
230  $object = new Facture($this->db);
231  if ($object->fetch($this->fk_object) > 0) {
232  return $object->getNomUrl(1);
233  } else {
234  $this->error++;
235  }
236  }
237  if ($this->element === 'invoice_supplier') {
238  require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
239 
240  $object = new FactureFournisseur($this->db);
241  if ($object->fetch($this->fk_object) > 0) {
242  return $object->getNomUrl(1);
243  } else {
244  $this->error++;
245  }
246  } elseif ($this->element === 'payment') {
247  require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
248 
249  $object = new Paiement($this->db);
250  if ($object->fetch($this->fk_object) > 0) {
251  return $object->getNomUrl(1);
252  } else {
253  $this->error++;
254  }
255  } elseif ($this->element === 'payment_supplier') {
256  require_once DOL_DOCUMENT_ROOT.'/fourn/class/paiementfourn.class.php';
257 
258  $object = new PaiementFourn($this->db);
259  if ($object->fetch($this->fk_object) > 0) {
260  return $object->getNomUrl(1);
261  } else {
262  $this->error++;
263  }
264  } elseif ($this->element === 'payment_donation') {
265  require_once DOL_DOCUMENT_ROOT.'/don/class/paymentdonation.class.php';
266 
267  $object = new PaymentDonation($this->db);
268  if ($object->fetch($this->fk_object) > 0) {
269  return $object->getNomUrl(1);
270  } else {
271  $this->error++;
272  }
273  } elseif ($this->element === 'payment_various') {
274  require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/paymentvarious.class.php';
275 
276  $object = new PaymentVarious($this->db);
277  if ($object->fetch($this->fk_object) > 0) {
278  return $object->getNomUrl(1);
279  } else {
280  $this->error++;
281  }
282  } elseif ($this->element === 'don' || $this->element === 'donation') {
283  require_once DOL_DOCUMENT_ROOT.'/don/class/don.class.php';
284 
285  $object = new Don($this->db);
286  if ($object->fetch($this->fk_object) > 0) {
287  return $object->getNomUrl(1);
288  } else {
289  $this->error++;
290  }
291  } elseif ($this->element === 'subscription') {
292  require_once DOL_DOCUMENT_ROOT.'/adherents/class/subscription.class.php';
293 
294  $object = new Subscription($this->db);
295  if ($object->fetch($this->fk_object) > 0) {
296  return $object->getNomUrl(1);
297  } else {
298  $this->error++;
299  }
300  } elseif ($this->element === 'cashcontrol') {
301  require_once DOL_DOCUMENT_ROOT.'/compta/cashcontrol/class/cashcontrol.class.php';
302 
303  $object = new CashControl($this->db);
304  if ($object->fetch($this->fk_object) > 0) {
305  return $object->getNomUrl(1);
306  } else {
307  $this->error++;
308  }
309  } elseif ($this->element === 'stockmouvement') {
310  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
311 
312  $object = new MouvementStock($this->db);
313  if ($object->fetch($this->fk_object) > 0) {
314  return $object->getNomUrl(1);
315  } else {
316  $this->error++;
317  }
318  } elseif ($this->action == 'MODULE_SET') {
319  return '<i class="opacitymedium">'.$langs->trans("BlockedLogEnabled").'</i>';
320  } elseif ($this->action == 'MODULE_RESET') {
321  if ($this->signature == '0000000000') {
322  return '<i class="opacitymedium">'.$langs->trans("BlockedLogDisabled").'</i>';
323  } else {
324  return '<i class="opacitymedium">'.$langs->trans("BlockedLogDisabledBis").'</i>';
325  }
326  }
327 
328  return '<i class="opacitymedium">'.$langs->trans('ImpossibleToReloadObject', $this->element, $this->fk_object).'</i>';
329  }
330 
335  public function getUser()
336  {
337  global $langs, $cachedUser;
338 
339  if (empty($cachedUser)) {
340  $cachedUser = array();
341  }
342 
343  if (empty($cachedUser[$this->fk_user])) {
344  $u = new User($this->db);
345  if ($u->fetch($this->fk_user) > 0) {
346  $cachedUser[$this->fk_user] = $u;
347  }
348  }
349 
350  if (!empty($cachedUser[$this->fk_user])) {
351  return $cachedUser[$this->fk_user]->getNomUrl(1);
352  }
353 
354  return $langs->trans('ImpossibleToRetrieveUser', $this->fk_user);
355  }
356 
366  public function setObjectData(&$object, $action, $amounts, $fuser = null)
367  {
368  global $langs, $user, $mysoc;
369 
370  if (is_object($fuser)) {
371  $user = $fuser;
372  }
373 
374  // Generic fields
375 
376  // action
377  $this->action = $action;
378  // amount
379  $this->amounts = $amounts;
380  // date
381  if ($object->element == 'payment' || $object->element == 'payment_supplier') {
382  $this->date_object = empty($object->datepaye) ? $object->date : $object->datepaye;
383  } elseif ($object->element == 'payment_salary') {
384  $this->date_object = $object->datev;
385  } elseif ($object->element == 'payment_donation' || $object->element == 'payment_various') {
386  $this->date_object = empty($object->datepaid) ? $object->datep : $object->datepaid;
387  } elseif ($object->element == 'subscription') {
388  $this->date_object = $object->dateh;
389  } elseif ($object->element == 'cashcontrol') {
390  $this->date_object = $object->date_creation;
391  } elseif (property_exists($object, 'date')) {
392  // Generic case
393  $this->date_object = $object->date;
394  } elseif (property_exists($object, 'datem')) {
395  // Generic case (second chance, for example for stock movement)
396  $this->date_object = $object->datem;
397  }
398 
399  // ref
400  $this->ref_object = ((!empty($object->newref)) ? $object->newref : $object->ref); // newref is set when validating a draft, ref is set in other cases
401  // type of object
402  $this->element = $object->element;
403  // id of object
404  $this->fk_object = $object->id;
405 
406 
407  // Set object_data
408  $this->object_data = new stdClass();
409  // Add fields to exclude
410  $arrayoffieldstoexclude = array(
411  'table_element', 'fields', 'ref_previous', 'ref_next', 'origin', 'origin_id', 'oldcopy', 'picto', 'error', 'errors', 'model_pdf', 'modelpdf', 'last_main_doc', 'civility_id', 'contact', 'contact_id',
412  'table_element_line', 'ismultientitymanaged', 'isextrafieldmanaged',
413  'array_languages',
414  'childtables',
415  'contact_ids',
416  'context',
417  'labelStatus',
418  'labelStatusShort',
419  'linkedObjectsIds',
420  'linkedObjects',
421  'fk_delivery_address',
422  'projet', // There is already ->fk_project
423  'restrictiononfksoc',
424  'specimen',
425  );
426  // Add more fields to exclude depending on object type
427  if ($this->element == 'cashcontrol') {
428  $arrayoffieldstoexclude = array_merge($arrayoffieldstoexclude, array(
429  'name', 'lastname', 'firstname', 'region', 'region_id', 'region_code', 'state', 'state_id', 'state_code', 'country', 'country_id', 'country_code',
430  'total_ht', 'total_tva', 'total_ttc', 'total_localtax1', 'total_localtax2',
431  'barcode_type', 'barcode_type_code', 'barcode_type_label', 'barcode_type_coder', 'mode_reglement_id', 'cond_reglement_id', 'mode_reglement', 'cond_reglement', 'shipping_method_id',
432  'fk_incoterms', 'label_incoterms', 'location_incoterms', 'lines'));
433  }
434 
435  // Add thirdparty info
436  if (empty($object->thirdparty) && method_exists($object, 'fetch_thirdparty')) {
437  $object->fetch_thirdparty();
438  }
439  if (!empty($object->thirdparty)) {
440  $this->object_data->thirdparty = new stdClass();
441 
442  foreach ($object->thirdparty as $key => $value) {
443  if (in_array($key, $arrayoffieldstoexclude)) {
444  continue; // Discard some properties
445  }
446  if (!in_array($key, array(
447  'name', 'name_alias', 'ref_ext', 'address', 'zip', 'town', 'state_code', 'country_code', 'idprof1', 'idprof2', 'idprof3', 'idprof4', 'idprof5', 'idprof6', 'phone', 'fax', 'email', 'barcode',
448  'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
449  ))) {
450  continue; // Discard if not into a dedicated list
451  }
452  if (!is_object($value) && !is_null($value) && $value !== '') {
453  $this->object_data->thirdparty->$key = $value;
454  }
455  }
456  }
457 
458  // Add company info
459  if (!empty($mysoc)) {
460  $this->object_data->mycompany = new stdClass();
461 
462  foreach ($mysoc as $key => $value) {
463  if (in_array($key, $arrayoffieldstoexclude)) {
464  continue; // Discard some properties
465  }
466  if (!in_array($key, array(
467  'name', 'name_alias', 'ref_ext', 'address', 'zip', 'town', 'state_code', 'country_code', 'idprof1', 'idprof2', 'idprof3', 'idprof4', 'idprof5', 'idprof6', 'phone', 'fax', 'email', 'barcode',
468  'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
469  ))) {
470  continue; // Discard if not into a dedicated list
471  }
472  if (!is_object($value) && !is_null($value) && $value !== '') {
473  $this->object_data->mycompany->$key = $value;
474  }
475  }
476  }
477 
478  // Add user info
479  if (!empty($user)) {
480  $this->fk_user = $user->id;
481  $this->user_fullname = $user->getFullName($langs);
482  }
483 
484  // Field specific to object
485  if ($this->element == 'facture') {
486  foreach ($object as $key => $value) {
487  if (in_array($key, $arrayoffieldstoexclude)) {
488  continue; // Discard some properties
489  }
490  if (!in_array($key, array(
491  'ref', 'ref_client', 'ref_supplier', 'date', 'datef', 'datev', 'type', 'total_ht', 'total_tva', 'total_ttc', 'localtax1', 'localtax2', 'revenuestamp', 'datepointoftax', 'note_public', 'lines'
492  ))) {
493  continue; // Discard if not into a dedicated list
494  }
495  if ($key == 'lines') {
496  $lineid = 0;
497  foreach ($value as $tmpline) { // $tmpline is object FactureLine
498  $lineid++;
499  foreach ($tmpline as $keyline => $valueline) {
500  if (!in_array($keyline, array(
501  'ref', 'multicurrency_code', 'multicurrency_total_ht', 'multicurrency_total_tva', 'multicurrency_total_ttc', 'qty', 'product_type', 'vat_src_code', 'tva_tx', 'info_bits', 'localtax1_tx', 'localtax2_tx', 'total_ht', 'total_tva', 'total_ttc', 'total_localtax1', 'total_localtax2'
502  ))) {
503  continue; // Discard if not into a dedicated list
504  }
505 
506  if (empty($this->object_data->invoiceline[$lineid]) || !is_object($this->object_data->invoiceline[$lineid])) { // To avoid warning
507  $this->object_data->invoiceline[$lineid] = new stdClass();
508  }
509 
510  if (!is_object($valueline) && !is_null($valueline) && $valueline !== '') {
511  $this->object_data->invoiceline[$lineid]->$keyline = $valueline;
512  }
513  }
514  }
515  } elseif (!is_object($value) && !is_null($value) && $value !== '') {
516  $this->object_data->$key = $value;
517  }
518  }
519 
520  if (!empty($object->newref)) {
521  $this->object_data->ref = $object->newref;
522  }
523  } elseif ($this->element == 'invoice_supplier') {
524  foreach ($object as $key => $value) {
525  if (in_array($key, $arrayoffieldstoexclude)) {
526  continue; // Discard some properties
527  }
528  if (!in_array($key, array(
529  'ref', 'ref_client', 'ref_supplier', 'date', 'datef', 'type', 'total_ht', 'total_tva', 'total_ttc', 'localtax1', 'localtax2', 'revenuestamp', 'datepointoftax', 'note_public'
530  ))) {
531  continue; // Discard if not into a dedicated list
532  }
533  if (!is_object($value) && !is_null($value) && $value !== '') {
534  $this->object_data->$key = $value;
535  }
536  }
537 
538  if (!empty($object->newref)) {
539  $this->object_data->ref = $object->newref;
540  }
541  } elseif ($this->element == 'payment' || $this->element == 'payment_supplier' || $this->element == 'payment_donation' || $this->element == 'payment_various') {
542  $datepayment = $object->datepaye ? $object->datepaye : ($object->datepaid ? $object->datepaid : $object->datep);
543  $paymenttypeid = $object->paiementid ? $object->paiementid : ($object->paymenttype ? $object->paymenttype : $object->type_payment);
544 
545  $this->object_data->ref = $object->ref;
546  $this->object_data->date = $datepayment;
547  $this->object_data->type_code = dol_getIdFromCode($this->db, $paymenttypeid, 'c_paiement', 'id', 'code');
548 
549  if (!empty($object->num_payment)) {
550  $this->object_data->payment_num = $object->num_payment;
551  }
552  if (!empty($object->note_private)) {
553  $this->object_data->note_private = $object->note_private;
554  }
555  //$this->object_data->fk_account = $object->fk_account;
556  //var_dump($this->object_data);exit;
557 
558  $totalamount = 0;
559 
560  // Loop on each invoice payment amount (payment_part)
561  if (is_array($object->amounts) && !empty($object->amounts)) {
562  $paymentpartnumber = 0;
563  foreach ($object->amounts as $objid => $amount) {
564  if (empty($amount)) {
565  continue;
566  }
567 
568  $totalamount += $amount;
569 
570  $tmpobject = null;
571  if ($this->element == 'payment_supplier') {
572  include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
573  $tmpobject = new FactureFournisseur($this->db);
574  } elseif ($this->element == 'payment') {
575  include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
576  $tmpobject = new Facture($this->db);
577  } elseif ($this->element == 'payment_donation') {
578  include_once DOL_DOCUMENT_ROOT.'/don/class/don.class.php';
579  $tmpobject = new Don($this->db);
580  } elseif ($this->element == 'payment_various') {
581  include_once DOL_DOCUMENT_ROOT.'/compta/bank/class/paymentvarious.class.php';
582  $tmpobject = new PaymentVarious($this->db);
583  }
584 
585  if (!is_object($tmpobject)) {
586  continue;
587  }
588 
589  $result = $tmpobject->fetch($objid);
590 
591  if ($result <= 0) {
592  $this->error = $tmpobject->error;
593  $this->errors = $tmpobject->errors;
594  dol_syslog("Failed to fetch object with id ".$objid, LOG_ERR);
595  return -1;
596  }
597 
598  $paymentpart = new stdClass();
599  $paymentpart->amount = $amount;
600 
601  if (!in_array($this->element, array('payment_donation', 'payment_various'))) {
602  $result = $tmpobject->fetch_thirdparty();
603  if ($result == 0) {
604  $this->error = 'Failed to fetch thirdparty for object with id '.$tmpobject->id;
605  $this->errors[] = $this->error;
606  dol_syslog("Failed to fetch thirdparty for object with id ".$tmpobject->id, LOG_ERR);
607  return -1;
608  } elseif ($result < 0) {
609  $this->error = $tmpobject->error;
610  $this->errors = $tmpobject->errors;
611  return -1;
612  }
613 
614  $paymentpart->thirdparty = new stdClass();
615  foreach ($tmpobject->thirdparty as $key => $value) {
616  if (in_array($key, $arrayoffieldstoexclude)) {
617  continue; // Discard some properties
618  }
619  if (!in_array($key, array(
620  'name', 'name_alias', 'ref_ext', 'address', 'zip', 'town', 'state_code', 'country_code', 'idprof1', 'idprof2', 'idprof3', 'idprof4', 'idprof5', 'idprof6', 'phone', 'fax', 'email', 'barcode',
621  'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
622  ))) {
623  continue; // Discard if not into a dedicated list
624  }
625  if (!is_object($value) && !is_null($value) && $value !== '') {
626  $paymentpart->thirdparty->$key = $value;
627  }
628  }
629  }
630 
631  // Init object to avoid warnings
632  if ($this->element == 'payment_donation') {
633  $paymentpart->donation = new stdClass();
634  } else {
635  $paymentpart->invoice = new stdClass();
636  }
637 
638  if ($this->element != 'payment_various') {
639  foreach ($tmpobject as $key => $value) {
640  if (in_array($key, $arrayoffieldstoexclude)) {
641  continue; // Discard some properties
642  }
643  if (!in_array($key, array(
644  'ref', 'ref_client', 'ref_supplier', 'date', 'datef', 'type', 'total_ht', 'total_tva', 'total_ttc', 'localtax1', 'localtax2', 'revenuestamp', 'datepointoftax', 'note_public'
645  ))) {
646  continue; // Discard if not into a dedicated list
647  }
648  if (!is_object($value) && !is_null($value) && $value !== '') {
649  if ($this->element == 'payment_donation') {
650  $paymentpart->donation->$key = $value;
651  } elseif ($this->element == 'payment_various') {
652  $paymentpart->various->$key = $value;
653  } else {
654  $paymentpart->invoice->$key = $value;
655  }
656  }
657  }
658 
659  $paymentpartnumber++; // first payment will be 1
660  $this->object_data->payment_part[$paymentpartnumber] = $paymentpart;
661  }
662  }
663  } elseif (!empty($object->amount)) {
664  $totalamount = $object->amount;
665  }
666 
667  $this->object_data->amount = $totalamount;
668 
669  if (!empty($object->newref)) {
670  $this->object_data->ref = $object->newref;
671  }
672  } elseif ($this->element == 'payment_salary') {
673  $this->object_data->amounts = array($object->amount);
674 
675  if (!empty($object->newref)) {
676  $this->object_data->ref = $object->newref;
677  }
678  } elseif ($this->element == 'subscription') {
679  foreach ($object as $key => $value) {
680  if (in_array($key, $arrayoffieldstoexclude)) {
681  continue; // Discard some properties
682  }
683  if (!in_array($key, array(
684  'id', 'datec', 'dateh', 'datef', 'fk_adherent', 'amount', 'import_key', 'statut', 'note'
685  ))) {
686  continue; // Discard if not into a dedicated list
687  }
688  if (!is_object($value) && !is_null($value) && $value !== '') {
689  $this->object_data->$key = $value;
690  }
691  }
692 
693  if (!empty($object->newref)) {
694  $this->object_data->ref = $object->newref;
695  }
696  } elseif ($this->element == 'stockmouvement') {
697  foreach ($object as $key => $value) {
698  if (in_array($key, $arrayoffieldstoexclude)) {
699  continue; // Discard some properties
700  }
701  if (!is_object($value) && !is_null($value) && $value !== '') {
702  $this->object_data->$key = $value;
703  }
704  }
705  } else {
706  // Generic case
707  foreach ($object as $key => $value) {
708  if (in_array($key, $arrayoffieldstoexclude)) {
709  continue; // Discard some properties
710  }
711  if (!is_object($value) && !is_null($value) && $value !== '') {
712  $this->object_data->$key = $value;
713  }
714  }
715 
716  if (!empty($object->newref)) {
717  $this->object_data->ref = $object->newref;
718  }
719  }
720 
721  // A trick to be sure all the object_data is an associative array
722  // json_encode and json_decode are not able to manage mixed object (with array/object, only full arrays or full objects)
723  $this->object_data = json_decode(json_encode($this->object_data, JSON_FORCE_OBJECT), false);
724 
725  return 1;
726  }
727 
734  public function fetch($id)
735  {
736  global $langs;
737 
738  if (empty($id)) {
739  $this->error = 'BadParameter';
740  return -1;
741  }
742 
743  $sql = "SELECT b.rowid, b.date_creation, b.signature, b.signature_line, b.amounts, b.action, b.element, b.fk_object, b.entity,";
744  $sql .= " b.certified, b.tms, b.fk_user, b.user_fullname, b.date_object, b.ref_object, b.object_data, b.object_version";
745  $sql .= " FROM ".MAIN_DB_PREFIX."blockedlog as b";
746  if ($id) {
747  $sql .= " WHERE b.rowid = ".((int) $id);
748  }
749 
750  $resql = $this->db->query($sql);
751  if ($resql) {
752  $obj = $this->db->fetch_object($resql);
753  if ($obj) {
754  $this->id = $obj->rowid;
755  $this->entity = $obj->entity;
756  $this->ref = $obj->rowid;
757 
758  $this->date_creation = $this->db->jdate($obj->date_creation);
759  $this->tms = $this->db->jdate($obj->tms);
760 
761  $this->amounts = (double) $obj->amounts;
762  $this->action = $obj->action;
763  $this->element = $obj->element;
764 
765  $this->fk_object = $obj->fk_object;
766  $this->date_object = $this->db->jdate($obj->date_object);
767  $this->ref_object = $obj->ref_object;
768 
769  $this->fk_user = $obj->fk_user;
770  $this->user_fullname = $obj->user_fullname;
771 
772  $this->object_data = $this->dolDecodeBlockedData($obj->object_data);
773  $this->object_version = $obj->object_version;
774 
775  $this->signature = $obj->signature;
776  $this->signature_line = $obj->signature_line;
777  $this->certified = ($obj->certified == 1);
778 
779  return 1;
780  } else {
781  $langs->load("blockedlog");
782  $this->error = $langs->trans("RecordNotFound");
783  return 0;
784  }
785  } else {
786  $this->error = $this->db->error();
787  return -1;
788  }
789  }
790 
791 
799  public function dolEncodeBlockedData($data, $mode = 0)
800  {
801  try {
802  $aaa = json_encode($data);
803  } catch (Exception $e) {
804  //print $e->getErrs);
805  }
806  //var_dump($aaa);
807 
808  return $aaa;
809  }
810 
811 
819  public function dolDecodeBlockedData($data, $mode = 0)
820  {
821  try {
822  $aaa = (object) jsonOrUnserialize($data);
823  } catch (Exception $e) {
824  //print $e->getErrs);
825  }
826  //var_dump($aaa);
827 
828  return $aaa;
829  }
830 
831 
837  public function setCertified()
838  {
839 
840  $res = $this->db->query("UPDATE ".MAIN_DB_PREFIX."blockedlog SET certified=1 WHERE rowid=".((int) $this->id));
841  if (!$res) {
842  return false;
843  }
844 
845  return true;
846  }
847 
855  public function create($user, $forcesignature = '')
856  {
857  global $conf, $langs, $hookmanager;
858 
859  $langs->load('blockedlog');
860 
861  $error = 0;
862 
863  // Clean data
864  $this->amounts = (double) $this->amounts;
865 
866  dol_syslog(get_class($this).'::create action='.$this->action.' fk_user='.$this->fk_user.' user_fullname='.$this->user_fullname, LOG_DEBUG);
867 
868  // Check parameters/properties
869  if (!isset($this->amounts)) { // amount can be 0 for some events (like when module is disabled)
870  $this->error = $langs->trans("BlockLogNeedAmountsValue");
871  dol_syslog($this->error, LOG_WARNING);
872  return -1;
873  }
874 
875  if (empty($this->element)) {
876  $this->error = $langs->trans("BlockLogNeedElement");
877  dol_syslog($this->error, LOG_WARNING);
878  return -2;
879  }
880 
881  if (empty($this->action)) {
882  $this->error = $langs->trans("BadParameterWhenCallingCreateOfBlockedLog");
883  dol_syslog($this->error, LOG_WARNING);
884  return -3;
885  }
886  if (empty($this->fk_user)) {
887  $this->user_fullname = '(Anonymous)';
888  }
889 
890  $this->date_creation = dol_now();
891 
892  $this->object_version = ((float) DOL_VERSION);
893 
894 
895  $this->db->begin();
896 
897  $previoushash = $this->getPreviousHash(1, 0); // This get last record and lock database until insert is done
898 
899  $keyforsignature = $this->buildKeyForSignature();
900 
901  include_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
902 
903  $this->signature_line = dol_hash($keyforsignature, '5'); // Not really usefull
904  $this->signature = dol_hash($previoushash.$keyforsignature, '5');
905  if ($forcesignature) {
906  $this->signature = $forcesignature;
907  }
908  //var_dump($keyforsignature);var_dump($previoushash);var_dump($this->signature_line);var_dump($this->signature);
909 
910  $sql = "INSERT INTO ".MAIN_DB_PREFIX."blockedlog (";
911  $sql .= " date_creation,";
912  $sql .= " action,";
913  $sql .= " amounts,";
914  $sql .= " signature,";
915  $sql .= " signature_line,";
916  $sql .= " element,";
917  $sql .= " fk_object,";
918  $sql .= " date_object,";
919  $sql .= " ref_object,";
920  $sql .= " object_data,";
921  $sql .= " object_version,";
922  $sql .= " certified,";
923  $sql .= " fk_user,";
924  $sql .= " user_fullname,";
925  $sql .= " entity";
926  $sql .= ") VALUES (";
927  $sql .= "'".$this->db->idate($this->date_creation)."',";
928  $sql .= "'".$this->db->escape($this->action)."',";
929  $sql .= $this->amounts.",";
930  $sql .= "'".$this->db->escape($this->signature)."',";
931  $sql .= "'".$this->db->escape($this->signature_line)."',";
932  $sql .= "'".$this->db->escape($this->element)."',";
933  $sql .= $this->fk_object.",";
934  $sql .= "'".$this->db->idate($this->date_object)."',";
935  $sql .= "'".$this->db->escape($this->ref_object)."',";
936  $sql .= "'".$this->db->escape($this->dolEncodeBlockedData($this->object_data))."',";
937  $sql .= "'".$this->db->escape($this->object_version)."',";
938  $sql .= "0,";
939  $sql .= $this->fk_user.",";
940  $sql .= "'".$this->db->escape($this->user_fullname)."',";
941  $sql .= ($this->entity ? $this->entity : $conf->entity);
942  $sql .= ")";
943 
944  /*
945  $a = serialize($this->object_data); $a2 = unserialize($a); $a4 = print_r($a2, true);
946  $b = json_encode($this->object_data); $b2 = json_decode($b); $b4 = print_r($b2, true);
947  var_dump($a4 == print_r($this->object_data, true) ? 'a=a' : 'a not = a');
948  var_dump($b4 == print_r($this->object_data, true) ? 'b=b' : 'b not = b');
949  exit;
950  */
951 
952  $res = $this->db->query($sql);
953  if ($res) {
954  $id = $this->db->last_insert_id(MAIN_DB_PREFIX."blockedlog");
955 
956  if ($id > 0) {
957  $this->id = $id;
958 
959  $this->db->commit();
960 
961  return $this->id;
962  } else {
963  $this->db->rollback();
964  return -2;
965  }
966  } else {
967  $this->error = $this->db->error();
968  $this->db->rollback();
969  return -1;
970  }
971 
972  // The commit will release the lock so we can insert nex record
973  }
974 
982  public function checkSignature($previoushash = '', $returnarray = 0)
983  {
984  if (empty($previoushash)) {
985  $previoushash = $this->getPreviousHash(0, $this->id);
986  }
987  // Recalculate hash
988  $keyforsignature = $this->buildKeyForSignature();
989 
990  //$signature_line = dol_hash($keyforsignature, '5'); // Not really usefull
991  $signature = dol_hash($previoushash.$keyforsignature, 'sha256');
992  //var_dump($previoushash); var_dump($keyforsignature); var_dump($signature_line); var_dump($signature);
993 
994  $res = ($signature === $this->signature);
995 
996  if (!$res) {
997  $this->error = 'Signature KO';
998  }
999 
1000  if ($returnarray) {
1001  if ($returnarray == 1) {
1002  unset($keyforsignature);
1003  return array('checkresult' => $res, 'calculatedsignature' => $signature, 'previoushash' => $previoushash);
1004  } else { // Consume much memory ($keyforsignature is a large var)
1005  return array('checkresult' => $res, 'calculatedsignature' => $signature, 'previoushash' => $previoushash, 'keyforsignature'=>$keyforsignature);
1006  }
1007  } else {
1008  unset($keyforsignature);
1009  return $res;
1010  }
1011  }
1012 
1020  private function buildKeyForSignature()
1021  {
1022  //print_r($this->object_data);
1023  if (((int) $this->object_version) >= 18) {
1024  return $this->date_creation.'|'.$this->action.'|'.$this->amounts.'|'.$this->ref_object.'|'.$this->date_object.'|'.$this->user_fullname.'|'.json_encode($this->object_data, JSON_FORCE_OBJECT);
1025  } else {
1026  return $this->date_creation.'|'.$this->action.'|'.$this->amounts.'|'.$this->ref_object.'|'.$this->date_object.'|'.$this->user_fullname.'|'.print_r($this->object_data, true);
1027  }
1028  }
1029 
1030 
1038  public function getPreviousHash($withlock = 0, $beforeid = 0)
1039  {
1040  global $conf;
1041 
1042  $previoussignature = '';
1043 
1044  $sql = "SELECT rowid, signature FROM ".MAIN_DB_PREFIX."blockedlog";
1045  $sql .= " WHERE entity = ".((int) $conf->entity);
1046  if ($beforeid) {
1047  $sql .= " AND rowid < ".(int) $beforeid;
1048  }
1049  $sql .= " ORDER BY rowid DESC LIMIT 1";
1050  $sql .= ($withlock ? " FOR UPDATE " : "");
1051 
1052  $resql = $this->db->query($sql);
1053  if ($resql) {
1054  $obj = $this->db->fetch_object($resql);
1055  if ($obj) {
1056  $previoussignature = $obj->signature;
1057  }
1058  } else {
1059  dol_print_error($this->db);
1060  exit;
1061  }
1062 
1063  if (empty($previoussignature)) {
1064  // First signature line (line 0)
1065  $previoussignature = $this->getSignature();
1066  }
1067 
1068  return $previoussignature;
1069  }
1070 
1087  public function getLog($element, $fk_object, $limit = 0, $sortfield = '', $sortorder = '', $search_fk_user = -1, $search_start = -1, $search_end = -1, $search_ref = '', $search_amount = '', $search_code = '')
1088  {
1089  global $conf;
1090  //global $cachedlogs;
1091 
1092  /* $cachedlogs allow fastest search */
1093  //if (empty($cachedlogs)) $cachedlogs = array();
1094 
1095  if ($element == 'all') {
1096  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
1097  WHERE entity=".$conf->entity;
1098  } elseif ($element == 'not_certified') {
1099  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
1100  WHERE entity=".$conf->entity." AND certified = 0";
1101  } elseif ($element == 'just_certified') {
1102  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
1103  WHERE entity=".$conf->entity." AND certified = 1";
1104  } else {
1105  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
1106  WHERE entity=".$conf->entity." AND element = '".$this->db->escape($element)."'";
1107  }
1108 
1109  if ($fk_object) {
1110  $sql .= natural_search("rowid", $fk_object, 1);
1111  }
1112  if ($search_fk_user > 0) {
1113  $sql .= natural_search("fk_user", $search_fk_user, 2);
1114  }
1115  if ($search_start > 0) {
1116  $sql .= " AND date_creation >= '".$this->db->idate($search_start)."'";
1117  }
1118  if ($search_end > 0) {
1119  $sql .= " AND date_creation <= '".$this->db->idate($search_end)."'";
1120  }
1121  if ($search_ref != '') {
1122  $sql .= natural_search("ref_object", $search_ref);
1123  }
1124  if ($search_amount != '') {
1125  $sql .= natural_search("amounts", $search_amount, 1);
1126  }
1127  if ($search_code != '' && $search_code != '-1') {
1128  $sql .= natural_search("action", $search_code, 3);
1129  }
1130 
1131  $sql .= $this->db->order($sortfield, $sortorder);
1132  $sql .= $this->db->plimit($limit + 1); // We want more, because we will stop into loop later with error if we reach max
1133 
1134  $res = $this->db->query($sql);
1135  if ($res) {
1136  $results = array();
1137 
1138  $i = 0;
1139  while ($obj = $this->db->fetch_object($res)) {
1140  $i++;
1141  if ($i > $limit) {
1142  // Too many record, we will consume too much memory
1143  return -2;
1144  }
1145 
1146  //if (!isset($cachedlogs[$obj->rowid]))
1147  //{
1148  $b = new BlockedLog($this->db);
1149  $b->fetch($obj->rowid);
1150  //$b->loadTrackedEvents();
1151  //$cachedlogs[$obj->rowid] = $b;
1152  //}
1153 
1154  //$results[] = $cachedlogs[$obj->rowid];
1155  $results[] = $b;
1156  }
1157 
1158  return $results;
1159  }
1160 
1161  return -1;
1162  }
1163 
1169  public function getSignature()
1170  {
1171  global $db, $conf, $mysoc;
1172 
1173  if (empty($conf->global->BLOCKEDLOG_ENTITY_FINGERPRINT)) { // creation of a unique fingerprint
1174  require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
1175  require_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
1176  require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
1177 
1178  $fingerprint = dol_hash(print_r($mysoc, true).getRandomPassword(1), '5');
1179 
1180  dolibarr_set_const($db, 'BLOCKEDLOG_ENTITY_FINGERPRINT', $fingerprint, 'chaine', 0, 'Numeric Unique Fingerprint', $conf->entity);
1181 
1182  $conf->global->BLOCKEDLOG_ENTITY_FINGERPRINT = $fingerprint;
1183  }
1184 
1185  return $conf->global->BLOCKEDLOG_ENTITY_FINGERPRINT;
1186  }
1187 
1188 
1195  public function alreadyUsed($ignoresystem = 0)
1196  {
1197  global $conf;
1198 
1199  $result = false;
1200 
1201  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog";
1202  $sql .= " WHERE entity = ".$conf->entity;
1203  if ($ignoresystem) {
1204  $sql .= " AND action not in ('MODULE_SET','MODULE_RESET')";
1205  }
1206  $sql .= $this->db->plimit(1);
1207 
1208  $res = $this->db->query($sql);
1209  if ($res !== false) {
1210  $obj = $this->db->fetch_object($res);
1211  if ($obj) {
1212  $result = true;
1213  }
1214  } else {
1215  dol_print_error($this->db);
1216  }
1217 
1218  dol_syslog("Module Blockedlog alreadyUsed with ignoresystem=".$ignoresystem." is ".$result);
1219 
1220  return $result;
1221  }
1222 }
BlockedLog\setObjectData
setObjectData(&$object, $action, $amounts, $fuser=null)
Populate properties of log from object data.
Definition: blockedlog.class.php:366
CashControl
Class to manage cash fence.
Definition: cashcontrol.class.php:30
DoliDB
Class to manage Dolibarr database access.
Definition: DoliDB.class.php:30
BlockedLog\dolDecodeBlockedData
dolDecodeBlockedData($data, $mode=0)
Decode data.
Definition: blockedlog.class.php:819
BlockedLog\dolEncodeBlockedData
dolEncodeBlockedData($data, $mode=0)
Encode data.
Definition: blockedlog.class.php:799
FactureFournisseur
Class to manage suppliers invoices.
Definition: fournisseur.facture.class.php:51
dol_print_error
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
Definition: functions.lib.php:5107
PaymentDonation
Class to manage payments of donations.
Definition: paymentdonation.class.php:30
BlockedLog\buildKeyForSignature
buildKeyForSignature()
Return a string for signature.
Definition: blockedlog.class.php:1020
Don
Class to manage donations.
Definition: don.class.php:39
Facture
Class to manage invoices.
Definition: facture.class.php:60
BlockedLog\getSignature
getSignature()
Return the signature (hash) of the "genesis-block" (Block 0).
Definition: blockedlog.class.php:1169
BlockedLog\setCertified
setCertified()
Set block certified by authority.
Definition: blockedlog.class.php:837
getRandomPassword
getRandomPassword($generic=false, $replaceambiguouschars=null, $length=32)
Return a generated password using default module.
Definition: security2.lib.php:487
jsonOrUnserialize
jsonOrUnserialize($stringtodecode)
Decode an encode string.
Definition: functions.lib.php:11909
PaymentVarious
Class to manage various payments.
Definition: paymentvarious.class.php:32
dol_hash
dol_hash($chain, $type='0')
Returns a hash (non reversible encryption) of a string.
Definition: security.lib.php:221
Exception
BlockedLog\fetch
fetch($id)
Get object from database.
Definition: blockedlog.class.php:734
BlockedLog
Class to manage Blocked Log.
Definition: blockedlog.class.php:26
dol_getIdFromCode
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='')
Return an id or code from a code or id.
Definition: functions.lib.php:9091
BlockedLog\alreadyUsed
alreadyUsed($ignoresystem=0)
Check if module was already used or not for at least one recording.
Definition: blockedlog.class.php:1195
MouvementStock
Class to manage stock movements.
Definition: mouvementstock.class.php:31
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1741
BlockedLog\getPreviousHash
getPreviousHash($withlock=0, $beforeid=0)
Get previous signature/hash in chain.
Definition: blockedlog.class.php:1038
Subscription
Class to manage subscriptions of foundation members.
Definition: subscription.class.php:33
$sql
if(isModEnabled('facture') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->hasRight("commande", "lire") &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $sql
Social contributions to pay.
Definition: index.php:746
isModEnabled
isModEnabled($module)
Is Dolibarr module enabled.
Definition: functions.lib.php:207
BlockedLog\getObjectLink
getObjectLink()
Try to retrieve source object (it it still exists).
Definition: blockedlog.class.php:223
ref
$object ref
Definition: info.php:78
dolibarr_set_const
dolibarr_set_const($db, $name, $value, $type='chaine', $visible=0, $note='', $entity=1)
Insert a parameter (key,value) into database (delete old key then insert it again).
Definition: admin.lib.php:638
PaiementFourn
Class to manage payments for supplier invoices.
Definition: paiementfourn.class.php:39
User
Class to manage Dolibarr users.
Definition: user.class.php:47
BlockedLog\getUser
getUser()
Definition: blockedlog.class.php:335
Paiement
Class to manage payments of customer invoices.
Definition: paiement.class.php:43
natural_search
natural_search($fields, $value, $mode=0, $nofirstand=0)
Generate natural SQL search string for a criteria (this criteria can be tested on one or several fiel...
Definition: functions.lib.php:10024
BlockedLog\getLog
getLog($element, $fk_object, $limit=0, $sortfield='', $sortorder='', $search_fk_user=-1, $search_start=-1, $search_end=-1, $search_ref='', $search_amount='', $search_code='')
Return array of log objects (with criterias)
Definition: blockedlog.class.php:1087
BlockedLog\__construct
__construct(DoliDB $db)
Constructor.
Definition: blockedlog.class.php:126
dol_now
dol_now($mode='auto')
Return date for now.
Definition: functions.lib.php:3056
BlockedLog\loadTrackedEvents
loadTrackedEvents()
Load list of tracked events into $this->trackedevents.
Definition: blockedlog.class.php:137
BlockedLog\create
create($user, $forcesignature='')
Create blocked log in database.
Definition: blockedlog.class.php:855
BlockedLog\checkSignature
checkSignature($previoushash='', $returnarray=0)
Check if current signature still correct compared to the value in chain.
Definition: blockedlog.class.php:982
float
div float
Buy price without taxes.
Definition: style.css.php:921