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).
$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.
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.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
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.