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