dolibarr  20.0.0-beta
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  * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
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  * See https://medium.com/@lhartikk/a-blockchain-in-200-lines-of-code-963cc1cc0e54
21  */
22 
23 
28 {
32  public $db;
33 
38  public $id;
39 
44  public $entity;
45 
49  public $error = '';
50 
54  public $errors = array();
55 
60  public $signature = '';
61 
66  public $signature_line = '';
67 
68  public $amounts = null;
69 
74  public $action = '';
75 
80  public $element = '';
81 
86  public $fk_object = 0;
87 
92  public $certified = false;
93 
98  public $fk_user = 0;
99 
103  public $date_creation;
104 
108  public $date_modification;
109 
110  public $date_object = 0;
111 
112  public $ref_object = '';
113 
114  public $object_data = null;
115  public $object_version = '';
116 
117  public $user_fullname = '';
118 
123  public $trackedevents = array();
124 
125 
126 
132  public function __construct(DoliDB $db)
133  {
134  $this->db = $db;
135  }
136 
137 
143  public function loadTrackedEvents()
144  {
145  global $conf;
146 
147  $this->trackedevents = array();
148 
149  // Customer Invoice/Facture / Payment
150  if (isModEnabled('invoice')) {
151  $this->trackedevents['BILL_VALIDATE'] = 'logBILL_VALIDATE';
152  $this->trackedevents['BILL_DELETE'] = 'logBILL_DELETE';
153  $this->trackedevents['BILL_SENTBYMAIL'] = 'logBILL_SENTBYMAIL';
154  $this->trackedevents['DOC_DOWNLOAD'] = 'BlockedLogBillDownload';
155  $this->trackedevents['DOC_PREVIEW'] = 'BlockedLogBillPreview';
156  $this->trackedevents['PAYMENT_CUSTOMER_CREATE'] = 'logPAYMENT_CUSTOMER_CREATE';
157  $this->trackedevents['PAYMENT_CUSTOMER_DELETE'] = 'logPAYMENT_CUSTOMER_DELETE';
158  }
159 
160  /* Supplier
161  // Supplier Invoice / Payment
162  if (isModEnabled("fournisseur")) {
163  $this->trackedevents['BILL_SUPPLIER_VALIDATE']='BlockedLogSupplierBillValidate';
164  $this->trackedevents['BILL_SUPPLIER_DELETE']='BlockedLogSupplierBillDelete';
165  $this->trackedevents['BILL_SUPPLIER_SENTBYMAIL']='BlockedLogSupplierBillSentByEmail'; // Trigger key does not exists, we want just into array to list it as done
166  $this->trackedevents['SUPPLIER_DOC_DOWNLOAD']='BlockedLogSupplierBillDownload'; // Trigger key does not exists, we want just into array to list it as done
167  $this->trackedevents['SUPPLIER_DOC_PREVIEW']='BlockedLogSupplierBillPreview'; // Trigger key does not exists, we want just into array to list it as done
168  $this->trackedevents['PAYMENT_SUPPLIER_CREATE']='BlockedLogSupplierBillPaymentCreate';
169  $this->trackedevents['PAYMENT_SUPPLIER_DELETE']='BlockedLogsupplierBillPaymentCreate';
170  }
171  */
172 
173  // Donation
174  if (isModEnabled('don')) {
175  $this->trackedevents['DON_VALIDATE'] = 'logDON_VALIDATE';
176  $this->trackedevents['DON_DELETE'] = 'logDON_DELETE';
177  //$this->trackedevents['DON_SENTBYMAIL']='logDON_SENTBYMAIL';
178  $this->trackedevents['DONATION_PAYMENT_CREATE'] = 'logDONATION_PAYMENT_CREATE';
179  $this->trackedevents['DONATION_PAYMENT_DELETE'] = 'logDONATION_PAYMENT_DELETE';
180  }
181 
182  /*
183  // Salary
184  if (!empty($conf->salary->enabled)) {
185  $this->trackedevents['PAYMENT_SALARY_CREATE']='BlockedLogSalaryPaymentCreate';
186  $this->trackedevents['PAYMENT_SALARY_MODIFY']='BlockedLogSalaryPaymentCreate';
187  $this->trackedevents['PAYMENT_SALARY_DELETE']='BlockedLogSalaryPaymentCreate';
188  }
189  */
190 
191  // Members
192  if (isModEnabled('member')) {
193  $this->trackedevents['MEMBER_SUBSCRIPTION_CREATE'] = 'logMEMBER_SUBSCRIPTION_CREATE';
194  $this->trackedevents['MEMBER_SUBSCRIPTION_MODIFY'] = 'logMEMBER_SUBSCRIPTION_MODIFY';
195  $this->trackedevents['MEMBER_SUBSCRIPTION_DELETE'] = 'logMEMBER_SUBSCRIPTION_DELETE';
196  }
197 
198  // Bank
199  if (isModEnabled("bank")) {
200  $this->trackedevents['PAYMENT_VARIOUS_CREATE'] = 'logPAYMENT_VARIOUS_CREATE';
201  $this->trackedevents['PAYMENT_VARIOUS_MODIFY'] = 'logPAYMENT_VARIOUS_MODIFY';
202  $this->trackedevents['PAYMENT_VARIOUS_DELETE'] = 'logPAYMENT_VARIOUS_DELETE';
203  }
204 
205  // Cashdesk
206  // $conf->global->BANK_ENABLE_POS_CASHCONTROL must be set to 1 by all external POS modules
207  $moduleposenabled = (!empty($conf->cashdesk->enabled) || !empty($conf->takepos->enabled) || getDolGlobalString('BANK_ENABLE_POS_CASHCONTROL'));
208  if ($moduleposenabled) {
209  $this->trackedevents['CASHCONTROL_VALIDATE'] = 'logCASHCONTROL_VALIDATE';
210  }
211 
212  // Add more action to track from a conf variable
213  // For example: STOCK_MOVEMENT,...
214  if (getDolGlobalString('BLOCKEDLOG_ADD_ACTIONS_SUPPORTED')) {
215  $tmparrayofmoresupportedevents = explode(',', getDolGlobalString('BLOCKEDLOG_ADD_ACTIONS_SUPPORTED'));
216  foreach ($tmparrayofmoresupportedevents as $val) {
217  $this->trackedevents[$val] = 'log'.$val;
218  }
219  }
220 
221  return 1;
222  }
223 
229  public function getObjectLink()
230  {
231  global $langs;
232 
233  if ($this->element === 'facture') {
234  require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
235 
236  $object = new Facture($this->db);
237  if ($object->fetch($this->fk_object) > 0) {
238  return $object->getNomUrl(1);
239  } else {
240  $this->error++;
241  }
242  }
243  if ($this->element === 'invoice_supplier') {
244  require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
245 
246  $object = new FactureFournisseur($this->db);
247  if ($object->fetch($this->fk_object) > 0) {
248  return $object->getNomUrl(1);
249  } else {
250  $this->error++;
251  }
252  } elseif ($this->element === 'payment') {
253  require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
254 
255  $object = new Paiement($this->db);
256  if ($object->fetch($this->fk_object) > 0) {
257  return $object->getNomUrl(1);
258  } else {
259  $this->error++;
260  }
261  } elseif ($this->element === 'payment_supplier') {
262  require_once DOL_DOCUMENT_ROOT.'/fourn/class/paiementfourn.class.php';
263 
264  $object = new PaiementFourn($this->db);
265  if ($object->fetch($this->fk_object) > 0) {
266  return $object->getNomUrl(1);
267  } else {
268  $this->error++;
269  }
270  } elseif ($this->element === 'payment_donation') {
271  require_once DOL_DOCUMENT_ROOT.'/don/class/paymentdonation.class.php';
272 
273  $object = new PaymentDonation($this->db);
274  if ($object->fetch($this->fk_object) > 0) {
275  return $object->getNomUrl(1);
276  } else {
277  $this->error++;
278  }
279  } elseif ($this->element === 'payment_various') {
280  require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/paymentvarious.class.php';
281 
282  $object = new PaymentVarious($this->db);
283  if ($object->fetch($this->fk_object) > 0) {
284  return $object->getNomUrl(1);
285  } else {
286  $this->error++;
287  }
288  } elseif ($this->element === 'don' || $this->element === 'donation') {
289  require_once DOL_DOCUMENT_ROOT.'/don/class/don.class.php';
290 
291  $object = new Don($this->db);
292  if ($object->fetch($this->fk_object) > 0) {
293  return $object->getNomUrl(1);
294  } else {
295  $this->error++;
296  }
297  } elseif ($this->element === 'subscription') {
298  require_once DOL_DOCUMENT_ROOT.'/adherents/class/subscription.class.php';
299 
300  $object = new Subscription($this->db);
301  if ($object->fetch($this->fk_object) > 0) {
302  return $object->getNomUrl(1);
303  } else {
304  $this->error++;
305  }
306  } elseif ($this->element === 'cashcontrol') {
307  require_once DOL_DOCUMENT_ROOT.'/compta/cashcontrol/class/cashcontrol.class.php';
308 
309  $object = new CashControl($this->db);
310  if ($object->fetch($this->fk_object) > 0) {
311  return $object->getNomUrl(1);
312  } else {
313  $this->error++;
314  }
315  } elseif ($this->element === 'stockmouvement') {
316  require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
317 
318  $object = new MouvementStock($this->db);
319  if ($object->fetch($this->fk_object) > 0) {
320  return $object->getNomUrl(1);
321  } else {
322  $this->error++;
323  }
324  } elseif ($this->element === 'project') {
325  require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
326 
327  $object = new Project($this->db);
328  if ($object->fetch($this->fk_object) > 0) {
329  return $object->getNomUrl(1);
330  } else {
331  $this->error++;
332  }
333  } elseif ($this->action == 'MODULE_SET') {
334  return '<i class="opacitymedium">'.$langs->trans("BlockedLogEnabled").'</i>';
335  } elseif ($this->action == 'MODULE_RESET') {
336  if ($this->signature == '0000000000') {
337  return '<i class="opacitymedium">'.$langs->trans("BlockedLogDisabled").'</i>';
338  } else {
339  return '<i class="opacitymedium">'.$langs->trans("BlockedLogDisabledBis").'</i>';
340  }
341  }
342 
343  return '<i class="opacitymedium">'.$langs->trans('ImpossibleToReloadObject', $this->element, $this->fk_object).'</i>';
344  }
345 
350  public function getUser()
351  {
352  global $langs, $cachedUser;
353 
354  if (empty($cachedUser)) {
355  $cachedUser = array();
356  }
357 
358  if (empty($cachedUser[$this->fk_user])) {
359  $u = new User($this->db);
360  if ($u->fetch($this->fk_user) > 0) {
361  $cachedUser[$this->fk_user] = $u;
362  }
363  }
364 
365  if (!empty($cachedUser[$this->fk_user])) {
366  return $cachedUser[$this->fk_user]->getNomUrl(1);
367  }
368 
369  return $langs->trans('ImpossibleToRetrieveUser', $this->fk_user);
370  }
371 
381  public function setObjectData(&$object, $action, $amounts, $fuser = null)
382  {
383  global $langs, $user, $mysoc;
384 
385  if (is_object($fuser)) {
386  $user = $fuser;
387  }
388 
389  // Generic fields
390 
391  // action
392  $this->action = $action;
393  // amount
394  $this->amounts = $amounts;
395  // date
396  if ($object->element == 'payment' || $object->element == 'payment_supplier') {
397  $this->date_object = empty($object->datepaye) ? $object->date : $object->datepaye;
398  } elseif ($object->element == 'payment_salary') {
399  $this->date_object = $object->datev;
400  } elseif ($object->element == 'payment_donation' || $object->element == 'payment_various') {
401  $this->date_object = empty($object->datepaid) ? $object->datep : $object->datepaid;
402  } elseif ($object->element == 'subscription') {
403  $this->date_object = $object->dateh;
404  } elseif ($object->element == 'cashcontrol') {
405  $this->date_object = $object->date_creation;
406  } elseif (property_exists($object, 'date')) {
407  // Generic case
408  $this->date_object = $object->date;
409  } elseif (property_exists($object, 'datem')) {
410  // Generic case (second chance, for example for stock movement)
411  $this->date_object = $object->datem;
412  }
413 
414  // ref
415  $this->ref_object = ((!empty($object->newref)) ? $object->newref : $object->ref); // newref is set when validating a draft, ref is set in other cases
416  // type of object
417  $this->element = $object->element;
418  // id of object
419  $this->fk_object = $object->id;
420 
421 
422  // Set object_data
423  $this->object_data = new stdClass();
424  // Add fields to exclude
425  $arrayoffieldstoexclude = array(
426  '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',
427  'table_element_line', 'ismultientitymanaged', 'isextrafieldmanaged',
428  'array_languages',
429  'childtables',
430  'contact_ids',
431  'context',
432  'labelStatus',
433  'labelStatusShort',
434  'linkedObjectsIds',
435  'linkedObjects',
436  'fk_delivery_address',
437  'projet', // There is already ->fk_project
438  'restrictiononfksoc',
439  'specimen',
440  );
441  // Add more fields to exclude depending on object type
442  if ($this->element == 'cashcontrol') {
443  $arrayoffieldstoexclude = array_merge($arrayoffieldstoexclude, array(
444  'name', 'lastname', 'firstname', 'region', 'region_id', 'region_code', 'state', 'state_id', 'state_code', 'country', 'country_id', 'country_code',
445  'total_ht', 'total_tva', 'total_ttc', 'total_localtax1', 'total_localtax2',
446  'barcode_type', 'barcode_type_code', 'barcode_type_label', 'barcode_type_coder', 'mode_reglement_id', 'cond_reglement_id', 'mode_reglement', 'cond_reglement', 'shipping_method_id',
447  'fk_incoterms', 'label_incoterms', 'location_incoterms', 'lines'));
448  }
449 
450  // Add thirdparty info
451  if (empty($object->thirdparty) && method_exists($object, 'fetch_thirdparty')) {
452  $object->fetch_thirdparty();
453  }
454  if (!empty($object->thirdparty)) {
455  $this->object_data->thirdparty = new stdClass();
456 
457  foreach ($object->thirdparty as $key => $value) {
458  if (in_array($key, $arrayoffieldstoexclude)) {
459  continue; // Discard some properties
460  }
461  if (!in_array($key, array(
462  'name', 'name_alias', 'ref_ext', 'address', 'zip', 'town', 'state_code', 'country_code', 'idprof1', 'idprof2', 'idprof3', 'idprof4', 'idprof5', 'idprof6', 'phone', 'fax', 'email', 'barcode',
463  'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
464  ))) {
465  continue; // Discard if not into a dedicated list
466  }
467  if (!is_object($value) && !is_null($value) && $value !== '') {
468  $this->object_data->thirdparty->$key = $value;
469  }
470  }
471  }
472 
473  // Add company info
474  if (!empty($mysoc)) {
475  $this->object_data->mycompany = new stdClass();
476 
477  foreach ($mysoc as $key => $value) {
478  if (in_array($key, $arrayoffieldstoexclude)) {
479  continue; // Discard some properties
480  }
481  if (!in_array($key, array(
482  'name', 'name_alias', 'ref_ext', 'address', 'zip', 'town', 'state_code', 'country_code', 'idprof1', 'idprof2', 'idprof3', 'idprof4', 'idprof5', 'idprof6', 'phone', 'fax', 'email', 'barcode',
483  'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
484  ))) {
485  continue; // Discard if not into a dedicated list
486  }
487  if (!is_object($value) && !is_null($value) && $value !== '') {
488  $this->object_data->mycompany->$key = $value;
489  }
490  }
491  }
492 
493  // Add user info
494  if (!empty($user)) {
495  $this->fk_user = $user->id;
496  $this->user_fullname = $user->getFullName($langs);
497  }
498 
499  // Field specific to object
500  if ($this->element == 'facture') {
501  foreach ($object as $key => $value) {
502  if (in_array($key, $arrayoffieldstoexclude)) {
503  continue; // Discard some properties
504  }
505  if (!in_array($key, array(
506  'ref', 'ref_client', 'ref_supplier', 'date', 'datef', 'datev', 'type', 'total_ht', 'total_tva', 'total_ttc', 'localtax1', 'localtax2', 'revenuestamp', 'datepointoftax', 'note_public', 'lines'
507  ))) {
508  continue; // Discard if not into a dedicated list
509  }
510  if ($key == 'lines') {
511  $lineid = 0;
512  foreach ($value as $tmpline) { // $tmpline is object FactureLine
513  $lineid++;
514  foreach ($tmpline as $keyline => $valueline) {
515  if (!in_array($keyline, array(
516  'ref', 'multicurrency_code', 'multicurrency_total_ht', 'multicurrency_total_tva', 'multicurrency_total_ttc', 'qty', 'product_type', 'product_label', 'vat_src_code', 'tva_tx', 'info_bits', 'localtax1_tx', 'localtax2_tx', 'total_ht', 'total_tva', 'total_ttc', 'total_localtax1', 'total_localtax2'
517  ))) {
518  continue; // Discard if not into a dedicated list
519  }
520 
521  if (empty($this->object_data->invoiceline[$lineid]) || !is_object($this->object_data->invoiceline[$lineid])) { // To avoid warning
522  $this->object_data->invoiceline[$lineid] = new stdClass();
523  }
524 
525  if (!is_object($valueline) && !is_null($valueline) && $valueline !== '') {
526  $this->object_data->invoiceline[$lineid]->$keyline = $valueline;
527  }
528  }
529  }
530  } elseif (!is_object($value) && !is_null($value) && $value !== '') {
531  $this->object_data->$key = $value;
532  }
533  }
534 
535  if (!empty($object->newref)) {
536  $this->object_data->ref = $object->newref;
537  }
538  } elseif ($this->element == 'invoice_supplier') {
539  foreach ($object as $key => $value) {
540  if (in_array($key, $arrayoffieldstoexclude)) {
541  continue; // Discard some properties
542  }
543  if (!in_array($key, array(
544  'ref', 'ref_client', 'ref_supplier', 'date', 'datef', 'type', 'total_ht', 'total_tva', 'total_ttc', 'localtax1', 'localtax2', 'revenuestamp', 'datepointoftax', 'note_public'
545  ))) {
546  continue; // Discard if not into a dedicated list
547  }
548  if (!is_object($value) && !is_null($value) && $value !== '') {
549  $this->object_data->$key = $value;
550  }
551  }
552 
553  if (!empty($object->newref)) {
554  $this->object_data->ref = $object->newref;
555  }
556  } elseif ($this->element == 'payment' || $this->element == 'payment_supplier' || $this->element == 'payment_donation' || $this->element == 'payment_various') {
557  $datepayment = $object->datepaye ? $object->datepaye : ($object->datepaid ? $object->datepaid : $object->datep);
558  $paymenttypeid = $object->paiementid ? $object->paiementid : ($object->paymenttype ? $object->paymenttype : $object->type_payment);
559 
560  $this->object_data->ref = $object->ref;
561  $this->object_data->date = $datepayment;
562  $this->object_data->type_code = dol_getIdFromCode($this->db, $paymenttypeid, 'c_paiement', 'id', 'code');
563 
564  if (!empty($object->num_payment)) {
565  $this->object_data->payment_num = $object->num_payment;
566  }
567  if (!empty($object->note_private)) {
568  $this->object_data->note_private = $object->note_private;
569  }
570  //$this->object_data->fk_account = $object->fk_account;
571  //var_dump($this->object_data);exit;
572 
573  $totalamount = 0;
574 
575  // Loop on each invoice payment amount (payment_part)
576  if (is_array($object->amounts) && !empty($object->amounts)) {
577  $paymentpartnumber = 0;
578  foreach ($object->amounts as $objid => $amount) {
579  if (empty($amount)) {
580  continue;
581  }
582 
583  $totalamount += $amount;
584 
585  $tmpobject = null;
586  if ($this->element == 'payment_supplier') {
587  include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
588  $tmpobject = new FactureFournisseur($this->db);
589  } elseif ($this->element == 'payment') {
590  include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
591  $tmpobject = new Facture($this->db);
592  } elseif ($this->element == 'payment_donation') {
593  include_once DOL_DOCUMENT_ROOT.'/don/class/don.class.php';
594  $tmpobject = new Don($this->db);
595  } elseif ($this->element == 'payment_various') {
596  include_once DOL_DOCUMENT_ROOT.'/compta/bank/class/paymentvarious.class.php';
597  $tmpobject = new PaymentVarious($this->db);
598  }
599 
600  if (!is_object($tmpobject)) {
601  continue;
602  }
603 
604  $result = $tmpobject->fetch($objid);
605 
606  if ($result <= 0) {
607  $this->error = $tmpobject->error;
608  $this->errors = $tmpobject->errors;
609  dol_syslog("Failed to fetch object with id ".$objid, LOG_ERR);
610  return -1;
611  }
612 
613  $paymentpart = new stdClass();
614  $paymentpart->amount = $amount;
615 
616  if (!in_array($this->element, array('payment_donation', 'payment_various'))) {
617  $result = $tmpobject->fetch_thirdparty();
618  if ($result == 0) {
619  $this->error = 'Failed to fetch thirdparty for object with id '.$tmpobject->id;
620  $this->errors[] = $this->error;
621  dol_syslog("Failed to fetch thirdparty for object with id ".$tmpobject->id, LOG_ERR);
622  return -1;
623  } elseif ($result < 0) {
624  $this->error = $tmpobject->error;
625  $this->errors = $tmpobject->errors;
626  return -1;
627  }
628 
629  $paymentpart->thirdparty = new stdClass();
630  foreach ($tmpobject->thirdparty as $key => $value) {
631  if (in_array($key, $arrayoffieldstoexclude)) {
632  continue; // Discard some properties
633  }
634  if (!in_array($key, array(
635  'name', 'name_alias', 'ref_ext', 'address', 'zip', 'town', 'state_code', 'country_code', 'idprof1', 'idprof2', 'idprof3', 'idprof4', 'idprof5', 'idprof6', 'phone', 'fax', 'email', 'barcode',
636  'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
637  ))) {
638  continue; // Discard if not into a dedicated list
639  }
640  if (!is_object($value) && !is_null($value) && $value !== '') {
641  $paymentpart->thirdparty->$key = $value;
642  }
643  }
644  }
645 
646  // Init object to avoid warnings
647  if ($this->element == 'payment_donation') {
648  $paymentpart->donation = new stdClass();
649  } else {
650  $paymentpart->invoice = new stdClass();
651  }
652 
653  if ($this->element != 'payment_various') {
654  foreach ($tmpobject as $key => $value) {
655  if (in_array($key, $arrayoffieldstoexclude)) {
656  continue; // Discard some properties
657  }
658  if (!in_array($key, array(
659  'ref', 'ref_client', 'ref_supplier', 'date', 'datef', 'type', 'total_ht', 'total_tva', 'total_ttc', 'localtax1', 'localtax2', 'revenuestamp', 'datepointoftax', 'note_public'
660  ))) {
661  continue; // Discard if not into a dedicated list
662  }
663  if (!is_object($value) && !is_null($value) && $value !== '') {
664  if ($this->element == 'payment_donation') {
665  $paymentpart->donation->$key = $value;
666  } elseif ($this->element == 'payment_various') {
667  $paymentpart->various->$key = $value;
668  } else {
669  $paymentpart->invoice->$key = $value;
670  }
671  }
672  }
673 
674  $paymentpartnumber++; // first payment will be 1
675  $this->object_data->payment_part[$paymentpartnumber] = $paymentpart;
676  }
677  }
678  } elseif (!empty($object->amount)) {
679  $totalamount = $object->amount;
680  }
681 
682  $this->object_data->amount = $totalamount;
683 
684  if (!empty($object->newref)) {
685  $this->object_data->ref = $object->newref;
686  }
687  } elseif ($this->element == 'payment_salary') {
688  $this->object_data->amounts = array($object->amount);
689 
690  if (!empty($object->newref)) {
691  $this->object_data->ref = $object->newref;
692  }
693  } elseif ($this->element == 'subscription') {
694  foreach ($object as $key => $value) {
695  if (in_array($key, $arrayoffieldstoexclude)) {
696  continue; // Discard some properties
697  }
698  if (!in_array($key, array(
699  'id', 'datec', 'dateh', 'datef', 'fk_adherent', 'amount', 'import_key', 'statut', 'note'
700  ))) {
701  continue; // Discard if not into a dedicated list
702  }
703  if (!is_object($value) && !is_null($value) && $value !== '') {
704  $this->object_data->$key = $value;
705  }
706  }
707 
708  if (!empty($object->newref)) {
709  $this->object_data->ref = $object->newref;
710  }
711  } elseif ($this->element == 'stockmouvement') {
712  foreach ($object as $key => $value) {
713  if (in_array($key, $arrayoffieldstoexclude)) {
714  continue; // Discard some properties
715  }
716  if (!is_object($value) && !is_null($value) && $value !== '') {
717  $this->object_data->$key = $value;
718  }
719  }
720  } else {
721  // Generic case
722  foreach ($object as $key => $value) {
723  if (in_array($key, $arrayoffieldstoexclude)) {
724  continue; // Discard some properties
725  }
726  if (!is_object($value) && !is_null($value) && $value !== '') {
727  $this->object_data->$key = $value;
728  }
729  }
730 
731  if (!empty($object->newref)) {
732  $this->object_data->ref = $object->newref;
733  }
734  }
735 
736  // A trick to be sure all the object_data is an associative array
737  // json_encode and json_decode are not able to manage mixed object (with array/object, only full arrays or full objects)
738  $this->object_data = json_decode(json_encode($this->object_data, JSON_FORCE_OBJECT), false);
739 
740  return 1;
741  }
742 
749  public function fetch($id)
750  {
751  global $langs;
752 
753  if (empty($id)) {
754  $this->error = 'BadParameter';
755  return -1;
756  }
757 
758  $sql = "SELECT b.rowid, b.date_creation, b.signature, b.signature_line, b.amounts, b.action, b.element, b.fk_object, b.entity,";
759  $sql .= " b.certified, b.tms, b.fk_user, b.user_fullname, b.date_object, b.ref_object, b.object_data, b.object_version";
760  $sql .= " FROM ".MAIN_DB_PREFIX."blockedlog as b";
761  if ($id) {
762  $sql .= " WHERE b.rowid = ".((int) $id);
763  }
764 
765  $resql = $this->db->query($sql);
766  if ($resql) {
767  $obj = $this->db->fetch_object($resql);
768  if ($obj) {
769  $this->id = $obj->rowid;
770  $this->entity = $obj->entity;
771 
772  $this->date_creation = $this->db->jdate($obj->date_creation);
773  $this->date_modification = $this->db->jdate($obj->tms);
774 
775  $this->amounts = (float) $obj->amounts;
776  $this->action = $obj->action;
777  $this->element = $obj->element;
778 
779  $this->fk_object = $obj->fk_object;
780  $this->date_object = $this->db->jdate($obj->date_object);
781  $this->ref_object = $obj->ref_object;
782 
783  $this->fk_user = $obj->fk_user;
784  $this->user_fullname = $obj->user_fullname;
785 
786  $this->object_data = $this->dolDecodeBlockedData($obj->object_data);
787  $this->object_version = $obj->object_version;
788 
789  $this->signature = $obj->signature;
790  $this->signature_line = $obj->signature_line;
791  $this->certified = ($obj->certified == 1);
792 
793  return 1;
794  } else {
795  $langs->load("blockedlog");
796  $this->error = $langs->trans("RecordNotFound");
797  return 0;
798  }
799  } else {
800  $this->error = $this->db->error();
801  return -1;
802  }
803  }
804 
805 
813  public function dolEncodeBlockedData($data, $mode = 0)
814  {
815  try {
816  $aaa = json_encode($data);
817  } catch (Exception $e) {
818  //print $e->getErrs);
819  }
820  //var_dump($aaa);
821 
822  return $aaa;
823  }
824 
825 
833  public function dolDecodeBlockedData($data, $mode = 0)
834  {
835  try {
836  $aaa = (object) jsonOrUnserialize($data);
837  } catch (Exception $e) {
838  //print $e->getErrs);
839  }
840  //var_dump($aaa);
841 
842  return $aaa;
843  }
844 
845 
851  public function setCertified()
852  {
853  $res = $this->db->query("UPDATE ".MAIN_DB_PREFIX."blockedlog SET certified=1 WHERE rowid=".((int) $this->id));
854  if (!$res) {
855  return false;
856  }
857 
858  return true;
859  }
860 
868  public function create($user, $forcesignature = '')
869  {
870  global $conf, $langs, $hookmanager;
871 
872  $langs->load('blockedlog');
873 
874  $error = 0;
875 
876  // Clean data
877  $this->amounts = (float) $this->amounts;
878 
879  dol_syslog(get_class($this).'::create action='.$this->action.' fk_user='.$this->fk_user.' user_fullname='.$this->user_fullname, LOG_DEBUG);
880 
881  // Check parameters/properties
882  if (!isset($this->amounts)) { // amount can be 0 for some events (like when module is disabled)
883  $this->error = $langs->trans("BlockLogNeedAmountsValue");
884  dol_syslog($this->error, LOG_WARNING);
885  return -1;
886  }
887 
888  if (empty($this->element)) {
889  $this->error = $langs->trans("BlockLogNeedElement");
890  dol_syslog($this->error, LOG_WARNING);
891  return -2;
892  }
893 
894  if (empty($this->action)) {
895  $this->error = $langs->trans("BadParameterWhenCallingCreateOfBlockedLog");
896  dol_syslog($this->error, LOG_WARNING);
897  return -3;
898  }
899  if (empty($this->fk_user)) {
900  $this->user_fullname = '(Anonymous)';
901  }
902 
903  $this->date_creation = dol_now();
904 
905  $this->object_version = ((float) DOL_VERSION);
906 
907 
908  $this->db->begin();
909 
910  $previoushash = $this->getPreviousHash(1, 0); // This get last record and lock database until insert is done
911 
912  $keyforsignature = $this->buildKeyForSignature();
913 
914  include_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
915 
916  $this->signature_line = dol_hash($keyforsignature, '5'); // Not really useful
917  $this->signature = dol_hash($previoushash.$keyforsignature, '5');
918  if ($forcesignature) {
919  $this->signature = $forcesignature;
920  }
921  //var_dump($keyforsignature);var_dump($previoushash);var_dump($this->signature_line);var_dump($this->signature);
922 
923  $sql = "INSERT INTO ".MAIN_DB_PREFIX."blockedlog (";
924  $sql .= " date_creation,";
925  $sql .= " action,";
926  $sql .= " amounts,";
927  $sql .= " signature,";
928  $sql .= " signature_line,";
929  $sql .= " element,";
930  $sql .= " fk_object,";
931  $sql .= " date_object,";
932  $sql .= " ref_object,";
933  $sql .= " object_data,";
934  $sql .= " object_version,";
935  $sql .= " certified,";
936  $sql .= " fk_user,";
937  $sql .= " user_fullname,";
938  $sql .= " entity";
939  $sql .= ") VALUES (";
940  $sql .= "'".$this->db->idate($this->date_creation)."',";
941  $sql .= "'".$this->db->escape($this->action)."',";
942  $sql .= $this->amounts.",";
943  $sql .= "'".$this->db->escape($this->signature)."',";
944  $sql .= "'".$this->db->escape($this->signature_line)."',";
945  $sql .= "'".$this->db->escape($this->element)."',";
946  $sql .= $this->fk_object.",";
947  $sql .= "'".$this->db->idate($this->date_object)."',";
948  $sql .= "'".$this->db->escape($this->ref_object)."',";
949  $sql .= "'".$this->db->escape($this->dolEncodeBlockedData($this->object_data))."',";
950  $sql .= "'".$this->db->escape($this->object_version)."',";
951  $sql .= "0,";
952  $sql .= $this->fk_user.",";
953  $sql .= "'".$this->db->escape($this->user_fullname)."',";
954  $sql .= ($this->entity ? $this->entity : $conf->entity);
955  $sql .= ")";
956 
957  /*
958  $a = serialize($this->object_data); $a2 = unserialize($a); $a4 = print_r($a2, true);
959  $b = json_encode($this->object_data); $b2 = json_decode($b); $b4 = print_r($b2, true);
960  var_dump($a4 == print_r($this->object_data, true) ? 'a=a' : 'a not = a');
961  var_dump($b4 == print_r($this->object_data, true) ? 'b=b' : 'b not = b');
962  exit;
963  */
964 
965  $res = $this->db->query($sql);
966  if ($res) {
967  $id = $this->db->last_insert_id(MAIN_DB_PREFIX."blockedlog");
968 
969  if ($id > 0) {
970  $this->id = $id;
971 
972  $this->db->commit();
973 
974  return $this->id;
975  } else {
976  $this->db->rollback();
977  return -2;
978  }
979  } else {
980  $this->error = $this->db->error();
981  $this->db->rollback();
982  return -1;
983  }
984 
985  // The commit will release the lock so we can insert nex record
986  }
987 
995  public function checkSignature($previoushash = '', $returnarray = 0)
996  {
997  if (empty($previoushash)) {
998  $previoushash = $this->getPreviousHash(0, $this->id);
999  }
1000  // Recalculate hash
1001  $keyforsignature = $this->buildKeyForSignature();
1002 
1003  //$signature_line = dol_hash($keyforsignature, '5'); // Not really useful
1004  $signature = dol_hash($previoushash.$keyforsignature, 'sha256');
1005  //var_dump($previoushash); var_dump($keyforsignature); var_dump($signature_line); var_dump($signature);
1006 
1007  $res = ($signature === $this->signature);
1008 
1009  if (!$res) {
1010  $this->error = 'Signature KO';
1011  }
1012 
1013  if ($returnarray) {
1014  if ($returnarray == 1) {
1015  unset($keyforsignature);
1016  return array('checkresult' => $res, 'calculatedsignature' => $signature, 'previoushash' => $previoushash);
1017  } else { // Consume much memory ($keyforsignature is a large var)
1018  return array('checkresult' => $res, 'calculatedsignature' => $signature, 'previoushash' => $previoushash, 'keyforsignature' => $keyforsignature);
1019  }
1020  } else {
1021  unset($keyforsignature);
1022  return $res;
1023  }
1024  }
1025 
1033  private function buildKeyForSignature()
1034  {
1035  //print_r($this->object_data);
1036  if (((int) $this->object_version) >= 18) {
1037  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);
1038  } else {
1039  return $this->date_creation.'|'.$this->action.'|'.$this->amounts.'|'.$this->ref_object.'|'.$this->date_object.'|'.$this->user_fullname.'|'.print_r($this->object_data, true);
1040  }
1041  }
1042 
1043 
1051  public function getPreviousHash($withlock = 0, $beforeid = 0)
1052  {
1053  global $conf;
1054 
1055  $previoussignature = '';
1056 
1057  $sql = "SELECT rowid, signature FROM ".MAIN_DB_PREFIX."blockedlog";
1058  $sql .= " WHERE entity = ".((int) $conf->entity);
1059  if ($beforeid) {
1060  $sql .= " AND rowid < ".(int) $beforeid;
1061  }
1062  $sql .= " ORDER BY rowid DESC LIMIT 1";
1063  $sql .= ($withlock ? " FOR UPDATE " : "");
1064 
1065  $resql = $this->db->query($sql);
1066  if ($resql) {
1067  $obj = $this->db->fetch_object($resql);
1068  if ($obj) {
1069  $previoussignature = $obj->signature;
1070  }
1071  } else {
1072  dol_print_error($this->db);
1073  exit;
1074  }
1075 
1076  if (empty($previoussignature)) {
1077  // First signature line (line 0)
1078  $previoussignature = $this->getSignature();
1079  }
1080 
1081  return $previoussignature;
1082  }
1083 
1100  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 = '')
1101  {
1102  global $conf;
1103  //global $cachedlogs;
1104 
1105  /* $cachedlogs allow fastest search */
1106  //if (empty($cachedlogs)) $cachedlogs = array();
1107 
1108  if ($element == 'all') {
1109  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
1110  WHERE entity=".$conf->entity;
1111  } elseif ($element == 'not_certified') {
1112  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
1113  WHERE entity=".$conf->entity." AND certified = 0";
1114  } elseif ($element == 'just_certified') {
1115  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
1116  WHERE entity=".$conf->entity." AND certified = 1";
1117  } else {
1118  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
1119  WHERE entity=".$conf->entity." AND element = '".$this->db->escape($element)."'";
1120  }
1121 
1122  if ($fk_object) {
1123  $sql .= natural_search("rowid", $fk_object, 1);
1124  }
1125  if ($search_fk_user > 0) {
1126  $sql .= natural_search("fk_user", $search_fk_user, 2);
1127  }
1128  if ($search_start > 0) {
1129  $sql .= " AND date_creation >= '".$this->db->idate($search_start)."'";
1130  }
1131  if ($search_end > 0) {
1132  $sql .= " AND date_creation <= '".$this->db->idate($search_end)."'";
1133  }
1134  if ($search_ref != '') {
1135  $sql .= natural_search("ref_object", $search_ref);
1136  }
1137  if ($search_amount != '') {
1138  $sql .= natural_search("amounts", $search_amount, 1);
1139  }
1140  if ($search_code != '' && $search_code != '-1') {
1141  $sql .= natural_search("action", $search_code, 3);
1142  }
1143 
1144  $sql .= $this->db->order($sortfield, $sortorder);
1145  $sql .= $this->db->plimit($limit + 1); // We want more, because we will stop into loop later with error if we reach max
1146 
1147  $res = $this->db->query($sql);
1148  if ($res) {
1149  $results = array();
1150 
1151  $i = 0;
1152  while ($obj = $this->db->fetch_object($res)) {
1153  $i++;
1154  if ($i > $limit) {
1155  // Too many record, we will consume too much memory
1156  return -2;
1157  }
1158 
1159  //if (!isset($cachedlogs[$obj->rowid]))
1160  //{
1161  $b = new BlockedLog($this->db);
1162  $b->fetch($obj->rowid);
1163  //$b->loadTrackedEvents();
1164  //$cachedlogs[$obj->rowid] = $b;
1165  //}
1166 
1167  //$results[] = $cachedlogs[$obj->rowid];
1168  $results[] = $b;
1169  }
1170 
1171  return $results;
1172  }
1173 
1174  return -1;
1175  }
1176 
1182  public function getSignature()
1183  {
1184  global $db, $conf, $mysoc;
1185 
1186  if (!getDolGlobalString('BLOCKEDLOG_ENTITY_FINGERPRINT')) { // creation of a unique fingerprint
1187  require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
1188  require_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
1189  require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
1190 
1191  $fingerprint = dol_hash(print_r($mysoc, true).getRandomPassword(1), '5');
1192 
1193  dolibarr_set_const($db, 'BLOCKEDLOG_ENTITY_FINGERPRINT', $fingerprint, 'chaine', 0, 'Numeric Unique Fingerprint', $conf->entity);
1194 
1195  $conf->global->BLOCKEDLOG_ENTITY_FINGERPRINT = $fingerprint;
1196  }
1197 
1198  return $conf->global->BLOCKEDLOG_ENTITY_FINGERPRINT;
1199  }
1200 
1201 
1208  public function alreadyUsed($ignoresystem = 0)
1209  {
1210  global $conf;
1211 
1212  $result = false;
1213 
1214  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog";
1215  $sql .= " WHERE entity = ".$conf->entity;
1216  if ($ignoresystem) {
1217  $sql .= " AND action not in ('MODULE_SET','MODULE_RESET')";
1218  }
1219  $sql .= $this->db->plimit(1);
1220 
1221  $res = $this->db->query($sql);
1222  if ($res !== false) {
1223  $obj = $this->db->fetch_object($res);
1224  if ($obj) {
1225  $result = true;
1226  }
1227  } else {
1228  dol_print_error($this->db);
1229  }
1230 
1231  dol_syslog("Module Blockedlog alreadyUsed with ignoresystem=".$ignoresystem." is ".json_encode($result));
1232 
1233  return $result;
1234  }
1235 }
if($user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition: card.php:58
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:656
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 criteria)
__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:41
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 projects.
Class to manage subscriptions of foundation members.
Class to manage Dolibarr users.
Definition: user.class.php:50
if(isModEnabled('invoice') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&!getDolGlobalString('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') && $user->hasRight('tax', 'charges', 'lire')) if(isModEnabled('invoice') &&isModEnabled('order') && $user->hasRight("commande", "lire") &&!getDolGlobalString('WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER')) $sql
Social contributions to pay.
Definition: index.php:745
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.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
jsonOrUnserialize($stringtodecode)
Decode an encode string.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
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:960
getRandomPassword($generic=false, $replaceambiguouschars=null, $length=32)
Return a generated password using default module.
dol_hash($chain, $type='0', $nosalt=0)
Returns a hash (non reversible encryption) of a string.