dolibarr  18.0.6
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 }
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
$object ref
Definition: info.php:78
Class to manage Blocked Log.
getSignature()
Return the signature (hash) of the "genesis-block" (Block 0).
getObjectLink()
Try to retrieve source object (it it still exists).
alreadyUsed($ignoresystem=0)
Check if module was already used or not for at least one recording.
buildKeyForSignature()
Return a string for signature.
create($user, $forcesignature='')
Create blocked log in database.
dolEncodeBlockedData($data, $mode=0)
Encode data.
loadTrackedEvents()
Load list of tracked events into $this->trackedevents.
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)
__construct(DoliDB $db)
Constructor.
setObjectData(&$object, $action, $amounts, $fuser=null)
Populate properties of log from object data.
getPreviousHash($withlock=0, $beforeid=0)
Get previous signature/hash in chain.
checkSignature($previoushash='', $returnarray=0)
Check if current signature still correct compared to the value in chain.
dolDecodeBlockedData($data, $mode=0)
Decode data.
fetch($id)
Get object from database.
setCertified()
Set block certified by authority.
Class to manage cash fence.
Class to manage Dolibarr database access.
Class to manage donations.
Definition: don.class.php:40
Class to manage suppliers invoices.
Class to manage invoices.
Class to manage stock movements.
Class to manage payments for supplier invoices.
Class to manage payments of customer invoices.
Class to manage payments of donations.
Class to manage various payments.
Class to manage subscriptions of foundation members.
Class to manage Dolibarr users.
Definition: user.class.php:48
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
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
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...
dol_now($mode='auto')
Return date for now.
dol_getIdFromCode($db, $key, $tablename, $fieldkey='code', $fieldid='id', $entityfilter=0, $filters='')
Return an id or code from a code or id.
jsonOrUnserialize($stringtodecode)
Decode an encode string.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
div float
Buy price without taxes.
Definition: style.css.php:926
getRandomPassword($generic=false, $replaceambiguouschars=null, $length=32)
Return a generated password using default module.
dol_hash($chain, $type='0')
Returns a hash (non reversible encryption) of a string.