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