dolibarr  20.0.0-alpha
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  // @phan-suppress-next-line PhanPluginRedundantAssignment
356  $cachedUser = array();
357  }
358 
359  if (empty($cachedUser[$this->fk_user])) {
360  $u = new User($this->db);
361  if ($u->fetch($this->fk_user) > 0) {
362  $cachedUser[$this->fk_user] = $u;
363  }
364  }
365 
366  if (!empty($cachedUser[$this->fk_user])) {
367  return $cachedUser[$this->fk_user]->getNomUrl(1);
368  }
369 
370  return $langs->trans('ImpossibleToRetrieveUser', $this->fk_user);
371  }
372 
382  public function setObjectData(&$object, $action, $amounts, $fuser = null)
383  {
384  global $langs, $user, $mysoc;
385 
386  if (is_object($fuser)) {
387  $user = $fuser;
388  }
389 
390  // Generic fields
391 
392  // action
393  $this->action = $action;
394  // amount
395  $this->amounts = $amounts;
396  // date
397  if ($object->element == 'payment' || $object->element == 'payment_supplier') {
398  $this->date_object = empty($object->datepaye) ? $object->date : $object->datepaye;
399  } elseif ($object->element == 'payment_salary') {
400  $this->date_object = $object->datev;
401  } elseif ($object->element == 'payment_donation' || $object->element == 'payment_various') {
402  $this->date_object = empty($object->datepaid) ? $object->datep : $object->datepaid;
403  } elseif ($object->element == 'subscription') {
404  $this->date_object = $object->dateh;
405  } elseif ($object->element == 'cashcontrol') {
406  $this->date_object = $object->date_creation;
407  } elseif (property_exists($object, 'date')) {
408  // Generic case
409  $this->date_object = $object->date;
410  } elseif (property_exists($object, 'datem')) {
411  // Generic case (second chance, for example for stock movement)
412  $this->date_object = $object->datem;
413  }
414 
415  // ref
416  $this->ref_object = ((!empty($object->newref)) ? $object->newref : $object->ref); // newref is set when validating a draft, ref is set in other cases
417  // type of object
418  $this->element = $object->element;
419  // id of object
420  $this->fk_object = $object->id;
421 
422 
423  // Set object_data
424  $this->object_data = new stdClass();
425  // Add fields to exclude
426  $arrayoffieldstoexclude = array(
427  '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',
428  'table_element_line', 'ismultientitymanaged', 'isextrafieldmanaged',
429  'array_languages',
430  'childtables',
431  'contact_ids',
432  'context',
433  'labelStatus',
434  'labelStatusShort',
435  'linkedObjectsIds',
436  'linkedObjects',
437  'fk_delivery_address',
438  'projet', // There is already ->fk_project
439  'restrictiononfksoc',
440  'specimen',
441  );
442  // Add more fields to exclude depending on object type
443  if ($this->element == 'cashcontrol') {
444  $arrayoffieldstoexclude = array_merge($arrayoffieldstoexclude, array(
445  'name', 'lastname', 'firstname', 'region', 'region_id', 'region_code', 'state', 'state_id', 'state_code', 'country', 'country_id', 'country_code',
446  'total_ht', 'total_tva', 'total_ttc', 'total_localtax1', 'total_localtax2',
447  'barcode_type', 'barcode_type_code', 'barcode_type_label', 'barcode_type_coder', 'mode_reglement_id', 'cond_reglement_id', 'mode_reglement', 'cond_reglement', 'shipping_method_id',
448  'fk_incoterms', 'label_incoterms', 'location_incoterms', 'lines'));
449  }
450 
451  // Add thirdparty info
452  if (empty($object->thirdparty) && method_exists($object, 'fetch_thirdparty')) {
453  $object->fetch_thirdparty();
454  }
455  if (!empty($object->thirdparty)) {
456  $this->object_data->thirdparty = new stdClass();
457 
458  foreach ($object->thirdparty as $key => $value) {
459  if (in_array($key, $arrayoffieldstoexclude)) {
460  continue; // Discard some properties
461  }
462  if (!in_array($key, array(
463  'name', 'name_alias', 'ref_ext', 'address', 'zip', 'town', 'state_code', 'country_code', 'idprof1', 'idprof2', 'idprof3', 'idprof4', 'idprof5', 'idprof6', 'phone', 'fax', 'email', 'barcode',
464  'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
465  ))) {
466  continue; // Discard if not into a dedicated list
467  }
468  if (!is_object($value) && !is_null($value) && $value !== '') {
469  $this->object_data->thirdparty->$key = $value;
470  }
471  }
472  }
473 
474  // Add company info
475  if (!empty($mysoc)) {
476  $this->object_data->mycompany = new stdClass();
477 
478  foreach ($mysoc as $key => $value) {
479  if (in_array($key, $arrayoffieldstoexclude)) {
480  continue; // Discard some properties
481  }
482  if (!in_array($key, array(
483  'name', 'name_alias', 'ref_ext', 'address', 'zip', 'town', 'state_code', 'country_code', 'idprof1', 'idprof2', 'idprof3', 'idprof4', 'idprof5', 'idprof6', 'phone', 'fax', 'email', 'barcode',
484  'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
485  ))) {
486  continue; // Discard if not into a dedicated list
487  }
488  if (!is_object($value) && !is_null($value) && $value !== '') {
489  $this->object_data->mycompany->$key = $value;
490  }
491  }
492  }
493 
494  // Add user info
495  if (!empty($user)) {
496  $this->fk_user = $user->id;
497  $this->user_fullname = $user->getFullName($langs);
498  }
499 
500  // Field specific to object
501  if ($this->element == 'facture') {
502  foreach ($object as $key => $value) {
503  if (in_array($key, $arrayoffieldstoexclude)) {
504  continue; // Discard some properties
505  }
506  if (!in_array($key, array(
507  'ref', 'ref_client', 'ref_supplier', 'date', 'datef', 'datev', 'type', 'total_ht', 'total_tva', 'total_ttc', 'localtax1', 'localtax2', 'revenuestamp', 'datepointoftax', 'note_public', 'lines'
508  ))) {
509  continue; // Discard if not into a dedicated list
510  }
511  if ($key == 'lines') {
512  $lineid = 0;
513  foreach ($value as $tmpline) { // $tmpline is object FactureLine
514  $lineid++;
515  foreach ($tmpline as $keyline => $valueline) {
516  if (!in_array($keyline, array(
517  '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'
518  ))) {
519  continue; // Discard if not into a dedicated list
520  }
521 
522  if (empty($this->object_data->invoiceline[$lineid]) || !is_object($this->object_data->invoiceline[$lineid])) { // To avoid warning
523  $this->object_data->invoiceline[$lineid] = new stdClass();
524  }
525 
526  if (!is_object($valueline) && !is_null($valueline) && $valueline !== '') {
527  $this->object_data->invoiceline[$lineid]->$keyline = $valueline;
528  }
529  }
530  }
531  } elseif (!is_object($value) && !is_null($value) && $value !== '') {
532  $this->object_data->$key = $value;
533  }
534  }
535 
536  if (!empty($object->newref)) {
537  $this->object_data->ref = $object->newref;
538  }
539  } elseif ($this->element == 'invoice_supplier') {
540  foreach ($object as $key => $value) {
541  if (in_array($key, $arrayoffieldstoexclude)) {
542  continue; // Discard some properties
543  }
544  if (!in_array($key, array(
545  'ref', 'ref_client', 'ref_supplier', 'date', 'datef', 'type', 'total_ht', 'total_tva', 'total_ttc', 'localtax1', 'localtax2', 'revenuestamp', 'datepointoftax', 'note_public'
546  ))) {
547  continue; // Discard if not into a dedicated list
548  }
549  if (!is_object($value) && !is_null($value) && $value !== '') {
550  $this->object_data->$key = $value;
551  }
552  }
553 
554  if (!empty($object->newref)) {
555  $this->object_data->ref = $object->newref;
556  }
557  } elseif ($this->element == 'payment' || $this->element == 'payment_supplier' || $this->element == 'payment_donation' || $this->element == 'payment_various') {
558  $datepayment = $object->datepaye ? $object->datepaye : ($object->datepaid ? $object->datepaid : $object->datep);
559  $paymenttypeid = $object->paiementid ? $object->paiementid : ($object->paymenttype ? $object->paymenttype : $object->type_payment);
560 
561  $this->object_data->ref = $object->ref;
562  $this->object_data->date = $datepayment;
563  $this->object_data->type_code = dol_getIdFromCode($this->db, $paymenttypeid, 'c_paiement', 'id', 'code');
564 
565  if (!empty($object->num_payment)) {
566  $this->object_data->payment_num = $object->num_payment;
567  }
568  if (!empty($object->note_private)) {
569  $this->object_data->note_private = $object->note_private;
570  }
571  //$this->object_data->fk_account = $object->fk_account;
572  //var_dump($this->object_data);exit;
573 
574  $totalamount = 0;
575 
576  // Loop on each invoice payment amount (payment_part)
577  if (is_array($object->amounts) && !empty($object->amounts)) {
578  $paymentpartnumber = 0;
579  foreach ($object->amounts as $objid => $amount) {
580  if (empty($amount)) {
581  continue;
582  }
583 
584  $totalamount += $amount;
585 
586  $tmpobject = null;
587  if ($this->element == 'payment_supplier') {
588  include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
589  $tmpobject = new FactureFournisseur($this->db);
590  } elseif ($this->element == 'payment') {
591  include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
592  $tmpobject = new Facture($this->db);
593  } elseif ($this->element == 'payment_donation') {
594  include_once DOL_DOCUMENT_ROOT.'/don/class/don.class.php';
595  $tmpobject = new Don($this->db);
596  } elseif ($this->element == 'payment_various') {
597  include_once DOL_DOCUMENT_ROOT.'/compta/bank/class/paymentvarious.class.php';
598  $tmpobject = new PaymentVarious($this->db);
599  }
600 
601  if (!is_object($tmpobject)) {
602  continue;
603  }
604 
605  $result = $tmpobject->fetch($objid);
606 
607  if ($result <= 0) {
608  $this->error = $tmpobject->error;
609  $this->errors = $tmpobject->errors;
610  dol_syslog("Failed to fetch object with id ".$objid, LOG_ERR);
611  return -1;
612  }
613 
614  $paymentpart = new stdClass();
615  $paymentpart->amount = $amount;
616 
617  if (!in_array($this->element, array('payment_donation', 'payment_various'))) {
618  $result = $tmpobject->fetch_thirdparty();
619  if ($result == 0) {
620  $this->error = 'Failed to fetch thirdparty for object with id '.$tmpobject->id;
621  $this->errors[] = $this->error;
622  dol_syslog("Failed to fetch thirdparty for object with id ".$tmpobject->id, LOG_ERR);
623  return -1;
624  } elseif ($result < 0) {
625  $this->error = $tmpobject->error;
626  $this->errors = $tmpobject->errors;
627  return -1;
628  }
629 
630  $paymentpart->thirdparty = new stdClass();
631  foreach ($tmpobject->thirdparty as $key => $value) {
632  if (in_array($key, $arrayoffieldstoexclude)) {
633  continue; // Discard some properties
634  }
635  if (!in_array($key, array(
636  'name', 'name_alias', 'ref_ext', 'address', 'zip', 'town', 'state_code', 'country_code', 'idprof1', 'idprof2', 'idprof3', 'idprof4', 'idprof5', 'idprof6', 'phone', 'fax', 'email', 'barcode',
637  'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
638  ))) {
639  continue; // Discard if not into a dedicated list
640  }
641  if (!is_object($value) && !is_null($value) && $value !== '') {
642  $paymentpart->thirdparty->$key = $value;
643  }
644  }
645  }
646 
647  // Init object to avoid warnings
648  if ($this->element == 'payment_donation') {
649  $paymentpart->donation = new stdClass();
650  } else {
651  $paymentpart->invoice = new stdClass();
652  }
653 
654  if ($this->element != 'payment_various') {
655  foreach ($tmpobject as $key => $value) {
656  if (in_array($key, $arrayoffieldstoexclude)) {
657  continue; // Discard some properties
658  }
659  if (!in_array($key, array(
660  'ref', 'ref_client', 'ref_supplier', 'date', 'datef', 'type', 'total_ht', 'total_tva', 'total_ttc', 'localtax1', 'localtax2', 'revenuestamp', 'datepointoftax', 'note_public'
661  ))) {
662  continue; // Discard if not into a dedicated list
663  }
664  if (!is_object($value) && !is_null($value) && $value !== '') {
665  if ($this->element == 'payment_donation') {
666  $paymentpart->donation->$key = $value;
667  } elseif ($this->element == 'payment_various') {
668  $paymentpart->various->$key = $value;
669  } else {
670  $paymentpart->invoice->$key = $value;
671  }
672  }
673  }
674 
675  $paymentpartnumber++; // first payment will be 1
676  $this->object_data->payment_part[$paymentpartnumber] = $paymentpart;
677  }
678  }
679  } elseif (!empty($object->amount)) {
680  $totalamount = $object->amount;
681  }
682 
683  $this->object_data->amount = $totalamount;
684 
685  if (!empty($object->newref)) {
686  $this->object_data->ref = $object->newref;
687  }
688  } elseif ($this->element == 'payment_salary') {
689  $this->object_data->amounts = array($object->amount);
690 
691  if (!empty($object->newref)) {
692  $this->object_data->ref = $object->newref;
693  }
694  } elseif ($this->element == 'subscription') {
695  foreach ($object as $key => $value) {
696  if (in_array($key, $arrayoffieldstoexclude)) {
697  continue; // Discard some properties
698  }
699  if (!in_array($key, array(
700  'id', 'datec', 'dateh', 'datef', 'fk_adherent', 'amount', 'import_key', 'statut', 'note'
701  ))) {
702  continue; // Discard if not into a dedicated list
703  }
704  if (!is_object($value) && !is_null($value) && $value !== '') {
705  $this->object_data->$key = $value;
706  }
707  }
708 
709  if (!empty($object->newref)) {
710  $this->object_data->ref = $object->newref;
711  }
712  } elseif ($this->element == 'stockmouvement') {
713  foreach ($object as $key => $value) {
714  if (in_array($key, $arrayoffieldstoexclude)) {
715  continue; // Discard some properties
716  }
717  if (!is_object($value) && !is_null($value) && $value !== '') {
718  $this->object_data->$key = $value;
719  }
720  }
721  } else {
722  // Generic case
723  foreach ($object as $key => $value) {
724  if (in_array($key, $arrayoffieldstoexclude)) {
725  continue; // Discard some properties
726  }
727  if (!is_object($value) && !is_null($value) && $value !== '') {
728  $this->object_data->$key = $value;
729  }
730  }
731 
732  if (!empty($object->newref)) {
733  $this->object_data->ref = $object->newref;
734  }
735  }
736 
737  // A trick to be sure all the object_data is an associative array
738  // json_encode and json_decode are not able to manage mixed object (with array/object, only full arrays or full objects)
739  $this->object_data = json_decode(json_encode($this->object_data, JSON_FORCE_OBJECT), false);
740 
741  return 1;
742  }
743 
750  public function fetch($id)
751  {
752  global $langs;
753 
754  if (empty($id)) {
755  $this->error = 'BadParameter';
756  return -1;
757  }
758 
759  $sql = "SELECT b.rowid, b.date_creation, b.signature, b.signature_line, b.amounts, b.action, b.element, b.fk_object, b.entity,";
760  $sql .= " b.certified, b.tms, b.fk_user, b.user_fullname, b.date_object, b.ref_object, b.object_data, b.object_version";
761  $sql .= " FROM ".MAIN_DB_PREFIX."blockedlog as b";
762  if ($id) {
763  $sql .= " WHERE b.rowid = ".((int) $id);
764  }
765 
766  $resql = $this->db->query($sql);
767  if ($resql) {
768  $obj = $this->db->fetch_object($resql);
769  if ($obj) {
770  $this->id = $obj->rowid;
771  $this->entity = $obj->entity;
772 
773  $this->date_creation = $this->db->jdate($obj->date_creation);
774  $this->date_modification = $this->db->jdate($obj->tms);
775 
776  $this->amounts = (float) $obj->amounts;
777  $this->action = $obj->action;
778  $this->element = $obj->element;
779 
780  $this->fk_object = $obj->fk_object;
781  $this->date_object = $this->db->jdate($obj->date_object);
782  $this->ref_object = $obj->ref_object;
783 
784  $this->fk_user = $obj->fk_user;
785  $this->user_fullname = $obj->user_fullname;
786 
787  $this->object_data = $this->dolDecodeBlockedData($obj->object_data);
788  $this->object_version = $obj->object_version;
789 
790  $this->signature = $obj->signature;
791  $this->signature_line = $obj->signature_line;
792  $this->certified = ($obj->certified == 1);
793 
794  return 1;
795  } else {
796  $langs->load("blockedlog");
797  $this->error = $langs->trans("RecordNotFound");
798  return 0;
799  }
800  } else {
801  $this->error = $this->db->error();
802  return -1;
803  }
804  }
805 
806 
814  public function dolEncodeBlockedData($data, $mode = 0)
815  {
816  try {
817  $aaa = json_encode($data);
818  } catch (Exception $e) {
819  //print $e->getErrs);
820  }
821  //var_dump($aaa);
822 
823  return $aaa;
824  }
825 
826 
834  public function dolDecodeBlockedData($data, $mode = 0)
835  {
836  try {
837  $aaa = (object) jsonOrUnserialize($data);
838  } catch (Exception $e) {
839  //print $e->getErrs);
840  }
841  //var_dump($aaa);
842 
843  return $aaa;
844  }
845 
846 
852  public function setCertified()
853  {
854  $res = $this->db->query("UPDATE ".MAIN_DB_PREFIX."blockedlog SET certified=1 WHERE rowid=".((int) $this->id));
855  if (!$res) {
856  return false;
857  }
858 
859  return true;
860  }
861 
869  public function create($user, $forcesignature = '')
870  {
871  global $conf, $langs, $hookmanager;
872 
873  $langs->load('blockedlog');
874 
875  $error = 0;
876 
877  // Clean data
878  $this->amounts = (float) $this->amounts;
879 
880  dol_syslog(get_class($this).'::create action='.$this->action.' fk_user='.$this->fk_user.' user_fullname='.$this->user_fullname, LOG_DEBUG);
881 
882  // Check parameters/properties
883  if (!isset($this->amounts)) { // amount can be 0 for some events (like when module is disabled)
884  $this->error = $langs->trans("BlockLogNeedAmountsValue");
885  dol_syslog($this->error, LOG_WARNING);
886  return -1;
887  }
888 
889  if (empty($this->element)) {
890  $this->error = $langs->trans("BlockLogNeedElement");
891  dol_syslog($this->error, LOG_WARNING);
892  return -2;
893  }
894 
895  if (empty($this->action)) {
896  $this->error = $langs->trans("BadParameterWhenCallingCreateOfBlockedLog");
897  dol_syslog($this->error, LOG_WARNING);
898  return -3;
899  }
900  if (empty($this->fk_user)) {
901  $this->user_fullname = '(Anonymous)';
902  }
903 
904  $this->date_creation = dol_now();
905 
906  $this->object_version = ((float) DOL_VERSION);
907 
908 
909  $this->db->begin();
910 
911  $previoushash = $this->getPreviousHash(1, 0); // This get last record and lock database until insert is done
912 
913  $keyforsignature = $this->buildKeyForSignature();
914 
915  include_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
916 
917  $this->signature_line = dol_hash($keyforsignature, '5'); // Not really useful
918  $this->signature = dol_hash($previoushash.$keyforsignature, '5');
919  if ($forcesignature) {
920  $this->signature = $forcesignature;
921  }
922  //var_dump($keyforsignature);var_dump($previoushash);var_dump($this->signature_line);var_dump($this->signature);
923 
924  $sql = "INSERT INTO ".MAIN_DB_PREFIX."blockedlog (";
925  $sql .= " date_creation,";
926  $sql .= " action,";
927  $sql .= " amounts,";
928  $sql .= " signature,";
929  $sql .= " signature_line,";
930  $sql .= " element,";
931  $sql .= " fk_object,";
932  $sql .= " date_object,";
933  $sql .= " ref_object,";
934  $sql .= " object_data,";
935  $sql .= " object_version,";
936  $sql .= " certified,";
937  $sql .= " fk_user,";
938  $sql .= " user_fullname,";
939  $sql .= " entity";
940  $sql .= ") VALUES (";
941  $sql .= "'".$this->db->idate($this->date_creation)."',";
942  $sql .= "'".$this->db->escape($this->action)."',";
943  $sql .= $this->amounts.",";
944  $sql .= "'".$this->db->escape($this->signature)."',";
945  $sql .= "'".$this->db->escape($this->signature_line)."',";
946  $sql .= "'".$this->db->escape($this->element)."',";
947  $sql .= $this->fk_object.",";
948  $sql .= "'".$this->db->idate($this->date_object)."',";
949  $sql .= "'".$this->db->escape($this->ref_object)."',";
950  $sql .= "'".$this->db->escape($this->dolEncodeBlockedData($this->object_data))."',";
951  $sql .= "'".$this->db->escape($this->object_version)."',";
952  $sql .= "0,";
953  $sql .= $this->fk_user.",";
954  $sql .= "'".$this->db->escape($this->user_fullname)."',";
955  $sql .= ($this->entity ? $this->entity : $conf->entity);
956  $sql .= ")";
957 
958  /*
959  $a = serialize($this->object_data); $a2 = unserialize($a); $a4 = print_r($a2, true);
960  $b = json_encode($this->object_data); $b2 = json_decode($b); $b4 = print_r($b2, true);
961  var_dump($a4 == print_r($this->object_data, true) ? 'a=a' : 'a not = a');
962  var_dump($b4 == print_r($this->object_data, true) ? 'b=b' : 'b not = b');
963  exit;
964  */
965 
966  $res = $this->db->query($sql);
967  if ($res) {
968  $id = $this->db->last_insert_id(MAIN_DB_PREFIX."blockedlog");
969 
970  if ($id > 0) {
971  $this->id = $id;
972 
973  $this->db->commit();
974 
975  return $this->id;
976  } else {
977  $this->db->rollback();
978  return -2;
979  }
980  } else {
981  $this->error = $this->db->error();
982  $this->db->rollback();
983  return -1;
984  }
985 
986  // The commit will release the lock so we can insert nex record
987  }
988 
996  public function checkSignature($previoushash = '', $returnarray = 0)
997  {
998  if (empty($previoushash)) {
999  $previoushash = $this->getPreviousHash(0, $this->id);
1000  }
1001  // Recalculate hash
1002  $keyforsignature = $this->buildKeyForSignature();
1003 
1004  //$signature_line = dol_hash($keyforsignature, '5'); // Not really useful
1005  $signature = dol_hash($previoushash.$keyforsignature, 'sha256');
1006  //var_dump($previoushash); var_dump($keyforsignature); var_dump($signature_line); var_dump($signature);
1007 
1008  $res = ($signature === $this->signature);
1009 
1010  if (!$res) {
1011  $this->error = 'Signature KO';
1012  }
1013 
1014  if ($returnarray) {
1015  if ($returnarray == 1) {
1016  unset($keyforsignature);
1017  return array('checkresult' => $res, 'calculatedsignature' => $signature, 'previoushash' => $previoushash);
1018  } else { // Consume much memory ($keyforsignature is a large var)
1019  return array('checkresult' => $res, 'calculatedsignature' => $signature, 'previoushash' => $previoushash, 'keyforsignature' => $keyforsignature);
1020  }
1021  } else {
1022  unset($keyforsignature);
1023  return $res;
1024  }
1025  }
1026 
1034  private function buildKeyForSignature()
1035  {
1036  //print_r($this->object_data);
1037  if (((int) $this->object_version) >= 18) {
1038  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);
1039  } else {
1040  return $this->date_creation.'|'.$this->action.'|'.$this->amounts.'|'.$this->ref_object.'|'.$this->date_object.'|'.$this->user_fullname.'|'.print_r($this->object_data, true);
1041  }
1042  }
1043 
1044 
1052  public function getPreviousHash($withlock = 0, $beforeid = 0)
1053  {
1054  global $conf;
1055 
1056  $previoussignature = '';
1057 
1058  $sql = "SELECT rowid, signature FROM ".MAIN_DB_PREFIX."blockedlog";
1059  $sql .= " WHERE entity = ".((int) $conf->entity);
1060  if ($beforeid) {
1061  $sql .= " AND rowid < ".(int) $beforeid;
1062  }
1063  $sql .= " ORDER BY rowid DESC LIMIT 1";
1064  $sql .= ($withlock ? " FOR UPDATE " : "");
1065 
1066  $resql = $this->db->query($sql);
1067  if ($resql) {
1068  $obj = $this->db->fetch_object($resql);
1069  if ($obj) {
1070  $previoussignature = $obj->signature;
1071  }
1072  } else {
1073  dol_print_error($this->db);
1074  exit;
1075  }
1076 
1077  if (empty($previoussignature)) {
1078  // First signature line (line 0)
1079  $previoussignature = $this->getSignature();
1080  }
1081 
1082  return $previoussignature;
1083  }
1084 
1101  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 = '')
1102  {
1103  global $conf;
1104  //global $cachedlogs;
1105 
1106  /* $cachedlogs allow fastest search */
1107  //if (empty($cachedlogs)) $cachedlogs = array();
1108 
1109  if ($element == 'all') {
1110  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
1111  WHERE entity=".$conf->entity;
1112  } elseif ($element == 'not_certified') {
1113  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
1114  WHERE entity=".$conf->entity." AND certified = 0";
1115  } elseif ($element == 'just_certified') {
1116  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
1117  WHERE entity=".$conf->entity." AND certified = 1";
1118  } else {
1119  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
1120  WHERE entity=".$conf->entity." AND element = '".$this->db->escape($element)."'";
1121  }
1122 
1123  if ($fk_object) {
1124  $sql .= natural_search("rowid", $fk_object, 1);
1125  }
1126  if ($search_fk_user > 0) {
1127  $sql .= natural_search("fk_user", $search_fk_user, 2);
1128  }
1129  if ($search_start > 0) {
1130  $sql .= " AND date_creation >= '".$this->db->idate($search_start)."'";
1131  }
1132  if ($search_end > 0) {
1133  $sql .= " AND date_creation <= '".$this->db->idate($search_end)."'";
1134  }
1135  if ($search_ref != '') {
1136  $sql .= natural_search("ref_object", $search_ref);
1137  }
1138  if ($search_amount != '') {
1139  $sql .= natural_search("amounts", $search_amount, 1);
1140  }
1141  if ($search_code != '' && $search_code != '-1') {
1142  $sql .= natural_search("action", $search_code, 3);
1143  }
1144 
1145  $sql .= $this->db->order($sortfield, $sortorder);
1146  $sql .= $this->db->plimit($limit + 1); // We want more, because we will stop into loop later with error if we reach max
1147 
1148  $res = $this->db->query($sql);
1149  if ($res) {
1150  $results = array();
1151 
1152  $i = 0;
1153  while ($obj = $this->db->fetch_object($res)) {
1154  $i++;
1155  if ($i > $limit) {
1156  // Too many record, we will consume too much memory
1157  return -2;
1158  }
1159 
1160  //if (!isset($cachedlogs[$obj->rowid]))
1161  //{
1162  $b = new BlockedLog($this->db);
1163  $b->fetch($obj->rowid);
1164  //$b->loadTrackedEvents();
1165  //$cachedlogs[$obj->rowid] = $b;
1166  //}
1167 
1168  //$results[] = $cachedlogs[$obj->rowid];
1169  $results[] = $b;
1170  }
1171 
1172  return $results;
1173  }
1174 
1175  return -1;
1176  }
1177 
1183  public function getSignature()
1184  {
1185  global $db, $conf, $mysoc;
1186 
1187  if (!getDolGlobalString('BLOCKEDLOG_ENTITY_FINGERPRINT')) { // creation of a unique fingerprint
1188  require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
1189  require_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
1190  require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
1191 
1192  $fingerprint = dol_hash(print_r($mysoc, true).getRandomPassword(1), '5');
1193 
1194  dolibarr_set_const($db, 'BLOCKEDLOG_ENTITY_FINGERPRINT', $fingerprint, 'chaine', 0, 'Numeric Unique Fingerprint', $conf->entity);
1195 
1196  $conf->global->BLOCKEDLOG_ENTITY_FINGERPRINT = $fingerprint;
1197  }
1198 
1199  return $conf->global->BLOCKEDLOG_ENTITY_FINGERPRINT;
1200  }
1201 
1202 
1209  public function alreadyUsed($ignoresystem = 0)
1210  {
1211  global $conf;
1212 
1213  $result = false;
1214 
1215  $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog";
1216  $sql .= " WHERE entity = ".$conf->entity;
1217  if ($ignoresystem) {
1218  $sql .= " AND action not in ('MODULE_SET','MODULE_RESET')";
1219  }
1220  $sql .= $this->db->plimit(1);
1221 
1222  $res = $this->db->query($sql);
1223  if ($res !== false) {
1224  $obj = $this->db->fetch_object($res);
1225  if ($obj) {
1226  $result = true;
1227  }
1228  } else {
1229  dol_print_error($this->db);
1230  }
1231 
1232  dol_syslog("Module Blockedlog alreadyUsed with ignoresystem=".$ignoresystem." is ".json_encode($result));
1233 
1234  return $result;
1235  }
1236 }
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:655
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:744
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:959
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.