dolibarr 21.0.0-beta
blockedlog.class.php
1<?php
2/* Copyright (C) 2017 ATM Consulting <contact@atm-consulting.fr>
3 * Copyright (C) 2017-2020 Laurent Destailleur <eldy@destailleur.fr>
4 * Copyright (C) 2022 charlene benke <charlene@patas-monkey.com>
5 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
6 * Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 *
21 * See https://medium.com/@lhartikk/a-blockchain-in-200-lines-of-code-963cc1cc0e54
22 */
23
24
29{
33 public $db;
34
39 public $id;
40
45 public $entity;
46
50 public $error = '';
51
55 public $errors = array();
56
61 public $signature = '';
62
67 public $signature_line = '';
68
72 public $amounts = null;
73
78 public $action = '';
79
84 public $element = '';
85
90 public $fk_object = 0;
91
96 public $certified = false;
97
102 public $fk_user = 0;
103
107 public $date_creation;
108
112 public $date_modification;
113
117 public $date_object = 0;
118
122 public $ref_object = '';
123
127 public $object_data = null;
128
132 public $object_version = '';
133
137 public $user_fullname = '';
138
143 public $trackedevents = array();
144
145
146
152 public function __construct(DoliDB $db)
153 {
154 $this->db = $db;
155 }
156
157
163 public function loadTrackedEvents()
164 {
165 global $conf;
166
167 $this->trackedevents = array();
168
169 // Customer Invoice/Facture / Payment
170 if (isModEnabled('invoice')) {
171 $this->trackedevents['BILL_VALIDATE'] = 'logBILL_VALIDATE';
172 $this->trackedevents['BILL_DELETE'] = 'logBILL_DELETE';
173 $this->trackedevents['BILL_SENTBYMAIL'] = 'logBILL_SENTBYMAIL';
174 $this->trackedevents['DOC_DOWNLOAD'] = 'BlockedLogBillDownload';
175 $this->trackedevents['DOC_PREVIEW'] = 'BlockedLogBillPreview';
176 $this->trackedevents['PAYMENT_CUSTOMER_CREATE'] = 'logPAYMENT_CUSTOMER_CREATE';
177 $this->trackedevents['PAYMENT_CUSTOMER_DELETE'] = 'logPAYMENT_CUSTOMER_DELETE';
178 }
179
180 /* Supplier
181 // Supplier Invoice / Payment
182 if (isModEnabled("fournisseur")) {
183 $this->trackedevents['BILL_SUPPLIER_VALIDATE']='BlockedLogSupplierBillValidate';
184 $this->trackedevents['BILL_SUPPLIER_DELETE']='BlockedLogSupplierBillDelete';
185 $this->trackedevents['BILL_SUPPLIER_SENTBYMAIL']='BlockedLogSupplierBillSentByEmail'; // Trigger key does not exists, we want just into array to list it as done
186 $this->trackedevents['SUPPLIER_DOC_DOWNLOAD']='BlockedLogSupplierBillDownload'; // Trigger key does not exists, we want just into array to list it as done
187 $this->trackedevents['SUPPLIER_DOC_PREVIEW']='BlockedLogSupplierBillPreview'; // Trigger key does not exists, we want just into array to list it as done
188 $this->trackedevents['PAYMENT_SUPPLIER_CREATE']='BlockedLogSupplierBillPaymentCreate';
189 $this->trackedevents['PAYMENT_SUPPLIER_DELETE']='BlockedLogsupplierBillPaymentCreate';
190 }
191 */
192
193 // Donation
194 if (isModEnabled('don')) {
195 $this->trackedevents['DON_VALIDATE'] = 'logDON_VALIDATE';
196 $this->trackedevents['DON_DELETE'] = 'logDON_DELETE';
197 //$this->trackedevents['DON_SENTBYMAIL']='logDON_SENTBYMAIL';
198 $this->trackedevents['DONATION_PAYMENT_CREATE'] = 'logDONATION_PAYMENT_CREATE';
199 $this->trackedevents['DONATION_PAYMENT_DELETE'] = 'logDONATION_PAYMENT_DELETE';
200 }
201
202 /*
203 // Salary
204 if (isModEnabled('salary')) {
205 $this->trackedevents['PAYMENT_SALARY_CREATE']='BlockedLogSalaryPaymentCreate';
206 $this->trackedevents['PAYMENT_SALARY_MODIFY']='BlockedLogSalaryPaymentCreate';
207 $this->trackedevents['PAYMENT_SALARY_DELETE']='BlockedLogSalaryPaymentCreate';
208 }
209 */
210
211 // Members
212 if (isModEnabled('member')) {
213 $this->trackedevents['MEMBER_SUBSCRIPTION_CREATE'] = 'logMEMBER_SUBSCRIPTION_CREATE';
214 $this->trackedevents['MEMBER_SUBSCRIPTION_MODIFY'] = 'logMEMBER_SUBSCRIPTION_MODIFY';
215 $this->trackedevents['MEMBER_SUBSCRIPTION_DELETE'] = 'logMEMBER_SUBSCRIPTION_DELETE';
216 }
217
218 // Bank
219 if (isModEnabled("bank")) {
220 $this->trackedevents['PAYMENT_VARIOUS_CREATE'] = 'logPAYMENT_VARIOUS_CREATE';
221 $this->trackedevents['PAYMENT_VARIOUS_MODIFY'] = 'logPAYMENT_VARIOUS_MODIFY';
222 $this->trackedevents['PAYMENT_VARIOUS_DELETE'] = 'logPAYMENT_VARIOUS_DELETE';
223 }
224
225 // Cashdesk
226 // $conf->global->BANK_ENABLE_POS_CASHCONTROL must be set to 1 by all external POS modules
227 $moduleposenabled = (!empty($conf->cashdesk->enabled) || !empty($conf->takepos->enabled) || getDolGlobalString('BANK_ENABLE_POS_CASHCONTROL'));
228 if ($moduleposenabled) {
229 $this->trackedevents['CASHCONTROL_VALIDATE'] = 'logCASHCONTROL_VALIDATE';
230 }
231
232 // Add more action to track from a conf variable
233 // For example: STOCK_MOVEMENT,...
234 if (getDolGlobalString('BLOCKEDLOG_ADD_ACTIONS_SUPPORTED')) {
235 $tmparrayofmoresupportedevents = explode(',', getDolGlobalString('BLOCKEDLOG_ADD_ACTIONS_SUPPORTED'));
236 foreach ($tmparrayofmoresupportedevents as $val) {
237 $this->trackedevents[$val] = 'log'.$val;
238 }
239 }
240
241 return 1;
242 }
243
249 public function getObjectLink()
250 {
251 global $langs;
252
253 if ($this->element === 'facture') {
254 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
255
256 $object = new Facture($this->db);
257 if ($object->fetch($this->fk_object) > 0) {
258 return $object->getNomUrl(1);
259 } else {
260 $this->error = (string) (((int) $this->error) + 1);
261 }
262 }
263 if ($this->element === 'invoice_supplier') {
264 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
265
266 $object = new FactureFournisseur($this->db);
267 if ($object->fetch($this->fk_object) > 0) {
268 return $object->getNomUrl(1);
269 } else {
270 $this->error = (string) (((int) $this->error) + 1);
271 }
272 } elseif ($this->element === 'payment') {
273 require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
274
275 $object = new Paiement($this->db);
276 if ($object->fetch($this->fk_object) > 0) {
277 return $object->getNomUrl(1);
278 } else {
279 $this->error = (string) (((int) $this->error) + 1);
280 }
281 } elseif ($this->element === 'payment_supplier') {
282 require_once DOL_DOCUMENT_ROOT.'/fourn/class/paiementfourn.class.php';
283
284 $object = new PaiementFourn($this->db);
285 if ($object->fetch($this->fk_object) > 0) {
286 return $object->getNomUrl(1);
287 } else {
288 $this->error = (string) (((int) $this->error) + 1);
289 }
290 } elseif ($this->element === 'payment_donation') {
291 require_once DOL_DOCUMENT_ROOT.'/don/class/paymentdonation.class.php';
292
293 $object = new PaymentDonation($this->db);
294 if ($object->fetch($this->fk_object) > 0) {
295 return $object->getNomUrl(1);
296 } else {
297 $this->error = (string) (((int) $this->error) + 1);
298 }
299 } elseif ($this->element === 'payment_various') {
300 require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/paymentvarious.class.php';
301
302 $object = new PaymentVarious($this->db);
303 if ($object->fetch($this->fk_object) > 0) {
304 return $object->getNomUrl(1);
305 } else {
306 $this->error = (string) (((int) $this->error) + 1);
307 }
308 } elseif ($this->element === 'don' || $this->element === 'donation') {
309 require_once DOL_DOCUMENT_ROOT.'/don/class/don.class.php';
310
311 $object = new Don($this->db);
312 if ($object->fetch($this->fk_object) > 0) {
313 return $object->getNomUrl(1);
314 } else {
315 $this->error = (string) (((int) $this->error) + 1);
316 }
317 } elseif ($this->element === 'subscription') {
318 require_once DOL_DOCUMENT_ROOT.'/adherents/class/subscription.class.php';
319
320 $object = new Subscription($this->db);
321 if ($object->fetch($this->fk_object) > 0) {
322 return $object->getNomUrl(1);
323 } else {
324 $this->error = (string) (((int) $this->error) + 1);
325 }
326 } elseif ($this->element === 'cashcontrol') {
327 require_once DOL_DOCUMENT_ROOT.'/compta/cashcontrol/class/cashcontrol.class.php';
328
329 $object = new CashControl($this->db);
330 if ($object->fetch($this->fk_object) > 0) {
331 return $object->getNomUrl(1);
332 } else {
333 $this->error = (string) (((int) $this->error) + 1);
334 }
335 } elseif ($this->element === 'stockmouvement') {
336 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
337
338 $object = new MouvementStock($this->db);
339 if ($object->fetch($this->fk_object) > 0) {
340 return $object->getNomUrl(1);
341 } else {
342 $this->error = (string) (((int) $this->error) + 1);
343 }
344 } elseif ($this->element === 'project') {
345 require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
346
347 $object = new Project($this->db);
348 if ($object->fetch($this->fk_object) > 0) {
349 return $object->getNomUrl(1);
350 } else {
351 $this->error = (string) (((int) $this->error) + 1);
352 }
353 } elseif ($this->action == 'BLOCKEDLOG_EXPORT') {
354 return '<i class="opacitymedium">'.$langs->trans("logBLOCKEDLOG_EXPORT").'</i>';
355 } elseif ($this->action == 'MODULE_SET') {
356 return '<i class="opacitymedium">'.$langs->trans("BlockedLogEnabled").'</i>';
357 } elseif ($this->action == 'MODULE_RESET') {
358 if ($this->signature == '0000000000') {
359 return '<i class="opacitymedium">'.$langs->trans("BlockedLogDisabled").'</i>';
360 } else {
361 return '<i class="opacitymedium">'.$langs->trans("BlockedLogDisabledBis").'</i>';
362 }
363 }
364
365 return '<i class="opacitymedium">'.$langs->trans('ImpossibleToReloadObject', $this->element, $this->fk_object).'</i>';
366 }
367
373 public function getUser()
374 {
375 global $langs, $cachedUser;
376
377 if (empty($cachedUser)) {
378 $cachedUser = array();
379 }
380
381 if (empty($cachedUser[$this->fk_user])) {
382 $u = new User($this->db);
383 if ($u->fetch($this->fk_user) > 0) {
384 $cachedUser[$this->fk_user] = $u;
385 }
386 }
387
388 if (!empty($cachedUser[$this->fk_user])) {
389 return $cachedUser[$this->fk_user]->getNomUrl(1);
390 }
391
392 return $langs->trans('ImpossibleToRetrieveUser', $this->fk_user);
393 }
394
404 public function setObjectData(&$object, $action, $amounts, $fuser = null)
405 {
406 global $langs, $user, $mysoc;
407
408 if (is_object($fuser)) {
409 $user = $fuser;
410 }
411
412 // Generic fields
413
414 // action
415 $this->action = $action;
416 // amount
417 $this->amounts = $amounts;
418 // date
419 if ($object->element == 'payment' || $object->element == 'payment_supplier') {
420 '@phan-var-force Paiement|PaiementFourn $object';
421 $this->date_object = empty($object->datepaye) ? $object->date : $object->datepaye;
422 } elseif ($object->element == 'payment_salary') {
423 '@phan-var-force PaymentSalary $object';
424 $this->date_object = $object->datev;
425 } elseif ($object->element == 'payment_donation' || $object->element == 'payment_various') {
426 '@phan-var-force PaymentDonation $object';
427 $this->date_object = empty($object->datepaid) ? $object->datep : $object->datepaid;
428 } elseif ($object->element == 'subscription') {
429 '@phan-var-force Subscription $object';
430 $this->date_object = $object->dateh;
431 } elseif ($object->element == 'cashcontrol') {
432 '@phan-var-force CashControl $object';
433 $this->date_object = $object->date_creation;
434 } elseif (property_exists($object, 'date')) {
435 // Generic case
436 $this->date_object = $object->date; // @phan-suppress-current-line PhanUndeclaredProperty
437 } elseif (property_exists($object, 'datem')) {
438 // Generic case (second chance, for example for stock movement)
439 $this->date_object = $object->datem; // @phan-suppress-current-line PhanUndeclaredProperty
440 }
441
442 // ref
443 $this->ref_object = ((!empty($object->newref)) ? $object->newref : $object->ref); // newref is set when validating a draft, ref is set in other cases
444 // type of object
445 $this->element = $object->element;
446 // id of object
447 $this->fk_object = $object->id;
448
449
450 // Set object_data
451 $this->object_data = new stdClass();
452 // Add fields to exclude
453 $arrayoffieldstoexclude = array(
454 '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',
455 'table_element_line', 'ismultientitymanaged', 'isextrafieldmanaged',
456 'array_languages',
457 'childtables',
458 'contact_ids',
459 'context',
460 'labelStatus',
461 'labelStatusShort',
462 'linkedObjectsIds',
463 'linkedObjects',
464 'fk_delivery_address',
465 'projet', // There is already ->fk_project
466 'restrictiononfksoc',
467 'specimen',
468 );
469 // Add more fields to exclude depending on object type
470 if ($this->element == 'cashcontrol') {
471 $arrayoffieldstoexclude = array_merge($arrayoffieldstoexclude, array(
472 'name', 'lastname', 'firstname', 'region', 'region_id', 'region_code', 'state', 'state_id', 'state_code', 'country', 'country_id', 'country_code',
473 'total_ht', 'total_tva', 'total_ttc', 'total_localtax1', 'total_localtax2',
474 'barcode_type', 'barcode_type_code', 'barcode_type_label', 'barcode_type_coder', 'mode_reglement_id', 'cond_reglement_id', 'mode_reglement', 'cond_reglement', 'shipping_method_id',
475 'fk_incoterms', 'label_incoterms', 'location_incoterms', 'lines'));
476 }
477
478 // Add thirdparty info
479 if (empty($object->thirdparty) && method_exists($object, 'fetch_thirdparty')) {
480 $object->fetch_thirdparty();
481 }
482 if (!empty($object->thirdparty)) {
483 $this->object_data->thirdparty = new stdClass();
484
485 foreach ($object->thirdparty as $key => $value) {
486 if (in_array($key, $arrayoffieldstoexclude)) {
487 continue; // Discard some properties
488 }
489 if (!in_array($key, array(
490 'name', 'name_alias', 'ref_ext', 'address', 'zip', 'town', 'state_code', 'country_code', 'idprof1', 'idprof2', 'idprof3', 'idprof4', 'idprof5', 'idprof6', 'phone', 'fax', 'email', 'barcode',
491 'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
492 ))) {
493 continue; // Discard if not into a dedicated list
494 }
495 if (!is_object($value) && !is_null($value) && $value !== '') {
496 $this->object_data->thirdparty->$key = $value;
497 }
498 }
499 }
500
501 // Add company info
502 if (!empty($mysoc)) {
503 $this->object_data->mycompany = new stdClass();
504
505 foreach ($mysoc as $key => $value) {
506 if (in_array($key, $arrayoffieldstoexclude)) {
507 continue; // Discard some properties
508 }
509 if (!in_array($key, array(
510 'name', 'name_alias', 'ref_ext', 'address', 'zip', 'town', 'state_code', 'country_code', 'idprof1', 'idprof2', 'idprof3', 'idprof4', 'idprof5', 'idprof6', 'phone', 'fax', 'email', 'barcode',
511 'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
512 ))) {
513 continue; // Discard if not into a dedicated list
514 }
515 if (!is_object($value) && !is_null($value) && $value !== '') {
516 $this->object_data->mycompany->$key = $value;
517 }
518 }
519 }
520
521 // Add user info
522 if (!empty($user)) {
523 $this->fk_user = $user->id;
524 $this->user_fullname = $user->getFullName($langs);
525 }
526
527 // Field specific to object
528 if ($this->element == 'facture') {
529 '@phan-var-force Facture $object';
530 foreach ($object as $key => $value) {
531 if (in_array($key, $arrayoffieldstoexclude)) {
532 continue; // Discard some properties
533 }
534 if (!in_array($key, array(
535 'ref', 'ref_client', 'ref_supplier', 'date', 'datef', 'datev', 'type', 'total_ht', 'total_tva', 'total_ttc', 'localtax1', 'localtax2', 'revenuestamp', 'datepointoftax', 'note_public', 'lines'
536 ))) {
537 continue; // Discard if not into a dedicated list
538 }
539 if ($key == 'lines') {
540 $lineid = 0;
541 foreach ($value as $tmpline) { // $tmpline is object FactureLine
542 $lineid++;
543 foreach ($tmpline as $keyline => $valueline) {
544 if (!in_array($keyline, array(
545 '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'
546 ))) {
547 continue; // Discard if not into a dedicated list
548 }
549
550 if (empty($this->object_data->invoiceline[$lineid]) || !is_object($this->object_data->invoiceline[$lineid])) { // To avoid warning
551 $this->object_data->invoiceline[$lineid] = new stdClass();
552 }
553
554 if (!is_object($valueline) && !is_null($valueline) && $valueline !== '') {
555 $this->object_data->invoiceline[$lineid]->$keyline = $valueline;
556 }
557 }
558 }
559 } elseif (!is_object($value) && !is_null($value) && $value !== '') {
560 $this->object_data->$key = $value;
561 }
562 }
563
564 if (!empty($object->newref)) {
565 $this->object_data->ref = $object->newref;
566 }
567 } elseif ($this->element == 'invoice_supplier') {
568 '@phan-var-force FactureFournisseur $object';
569 foreach ($object as $key => $value) {
570 if (in_array($key, $arrayoffieldstoexclude)) {
571 continue; // Discard some properties
572 }
573 if (!in_array($key, array(
574 'ref', 'ref_client', 'ref_supplier', 'date', 'datef', 'type', 'total_ht', 'total_tva', 'total_ttc', 'localtax1', 'localtax2', 'revenuestamp', 'datepointoftax', 'note_public'
575 ))) {
576 continue; // Discard if not into a dedicated list
577 }
578 if (!is_object($value) && !is_null($value) && $value !== '') {
579 $this->object_data->$key = $value;
580 }
581 }
582
583 if (!empty($object->newref)) {
584 $this->object_data->ref = $object->newref;
585 }
586 } elseif ($this->element == 'payment' || $this->element == 'payment_supplier' || $this->element == 'payment_donation' || $this->element == 'payment_various') {
587 '@phan-var-force Paiement|PaiementFourn|PaymentDonation|PaymentVarious $object';
588 $datepayment = $object->datepaye ? $object->datepaye : ($object->datepaid ? $object->datepaid : $object->datep);
589 $paymenttypeid = $object->paiementid ? $object->paiementid : ($object->paymenttype ? $object->paymenttype : $object->type_payment);
590
591 $this->object_data->ref = $object->ref;
592 $this->object_data->date = $datepayment;
593 $this->object_data->type_code = dol_getIdFromCode($this->db, $paymenttypeid, 'c_paiement', 'id', 'code');
594
595 if (!empty($object->num_payment)) {
596 $this->object_data->payment_num = $object->num_payment;
597 }
598 if (!empty($object->note_private)) {
599 $this->object_data->note_private = $object->note_private;
600 }
601 //$this->object_data->fk_account = $object->fk_account;
602 //var_dump($this->object_data);exit;
603
604 $totalamount = 0;
605
606 // Loop on each invoice payment amount (payment_part)
607 if (is_array($object->amounts) && !empty($object->amounts)) {
608 $paymentpartnumber = 0;
609 foreach ($object->amounts as $objid => $amount) {
610 if (empty($amount)) {
611 continue;
612 }
613
614 $totalamount += $amount;
615
616 $tmpobject = null;
617 if ($this->element == 'payment_supplier') {
618 include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
619 $tmpobject = new FactureFournisseur($this->db);
620 } elseif ($this->element == 'payment') {
621 include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
622 $tmpobject = new Facture($this->db);
623 } elseif ($this->element == 'payment_donation') {
624 include_once DOL_DOCUMENT_ROOT.'/don/class/don.class.php';
625 $tmpobject = new Don($this->db);
626 } elseif ($this->element == 'payment_various') {
627 include_once DOL_DOCUMENT_ROOT.'/compta/bank/class/paymentvarious.class.php';
628 $tmpobject = new PaymentVarious($this->db);
629 }
630
631 if (!is_object($tmpobject)) {
632 continue;
633 }
634
635 $result = $tmpobject->fetch($objid);
636
637 if ($result <= 0) {
638 $this->error = $tmpobject->error;
639 $this->errors = $tmpobject->errors;
640 dol_syslog("Failed to fetch object with id ".$objid, LOG_ERR);
641 return -1;
642 }
643
644 $paymentpart = new stdClass();
645 $paymentpart->amount = $amount;
646
647 if (!in_array($this->element, array('payment_donation', 'payment_various'))) {
648 $result = $tmpobject->fetch_thirdparty();
649 if ($result == 0) {
650 $this->error = 'Failed to fetch thirdparty for object with id '.$tmpobject->id;
651 $this->errors[] = $this->error;
652 dol_syslog("Failed to fetch thirdparty for object with id ".$tmpobject->id, LOG_ERR);
653 return -1;
654 } elseif ($result < 0) {
655 $this->error = $tmpobject->error;
656 $this->errors = $tmpobject->errors;
657 return -1;
658 }
659
660 $paymentpart->thirdparty = new stdClass();
661 foreach ($tmpobject->thirdparty as $key => $value) {
662 if (in_array($key, $arrayoffieldstoexclude)) {
663 continue; // Discard some properties
664 }
665 if (!in_array($key, array(
666 'name', 'name_alias', 'ref_ext', 'address', 'zip', 'town', 'state_code', 'country_code', 'idprof1', 'idprof2', 'idprof3', 'idprof4', 'idprof5', 'idprof6', 'phone', 'fax', 'email', 'barcode',
667 'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
668 ))) {
669 continue; // Discard if not into a dedicated list
670 }
671 if (!is_object($value) && !is_null($value) && $value !== '') {
672 $paymentpart->thirdparty->$key = $value;
673 }
674 }
675 }
676
677 // Init object to avoid warnings
678 if ($this->element == 'payment_donation') {
679 $paymentpart->donation = new stdClass();
680 } else {
681 $paymentpart->invoice = new stdClass();
682 }
683
684 if ($this->element != 'payment_various') {
685 foreach ($tmpobject as $key => $value) {
686 if (in_array($key, $arrayoffieldstoexclude)) {
687 continue; // Discard some properties
688 }
689 if (!in_array($key, array(
690 'ref', 'ref_client', 'ref_supplier', 'date', 'datef', 'type', 'total_ht', 'total_tva', 'total_ttc', 'localtax1', 'localtax2', 'revenuestamp', 'datepointoftax', 'note_public'
691 ))) {
692 continue; // Discard if not into a dedicated list
693 }
694 if (!is_object($value) && !is_null($value) && $value !== '') {
695 if ($this->element == 'payment_donation') {
696 $paymentpart->donation->$key = $value;
697 } elseif ($this->element == 'payment_various') {
698 $paymentpart->various->$key = $value;
699 } else {
700 $paymentpart->invoice->$key = $value;
701 }
702 }
703 }
704
705 $paymentpartnumber++; // first payment will be 1
706 $this->object_data->payment_part[$paymentpartnumber] = $paymentpart;
707 }
708 }
709 } elseif (!empty($object->amount)) {
710 $totalamount = $object->amount;
711 }
712
713 $this->object_data->amount = $totalamount;
714
715 if (!empty($object->newref)) {
716 $this->object_data->ref = $object->newref;
717 }
718 } elseif ($this->element == 'payment_salary') {
719 '@phan-var-force PaymentSalary $object';
720 $this->object_data->amounts = array($object->amount);
721
722 if (!empty($object->newref)) {
723 $this->object_data->ref = $object->newref;
724 }
725 } elseif ($this->element == 'subscription') {
726 '@phan-var-force Subscription $object';
727 foreach ($object as $key => $value) {
728 if (in_array($key, $arrayoffieldstoexclude)) {
729 continue; // Discard some properties
730 }
731 if (!in_array($key, array(
732 'id', 'datec', 'dateh', 'datef', 'fk_adherent', 'amount', 'import_key', 'statut', 'note'
733 ))) {
734 continue; // Discard if not into a dedicated list
735 }
736 if (!is_object($value) && !is_null($value) && $value !== '') {
737 $this->object_data->$key = $value;
738 }
739 }
740
741 if (!empty($object->newref)) {
742 $this->object_data->ref = $object->newref;
743 }
744 } elseif ($this->element == 'stockmouvement') {
745 '@phan-var-force StockTransfer $object';
746 foreach ($object as $key => $value) {
747 if (in_array($key, $arrayoffieldstoexclude)) {
748 continue; // Discard some properties
749 }
750 if (!is_object($value) && !is_null($value) && $value !== '') {
751 $this->object_data->$key = $value;
752 }
753 }
754 } else {
755 // Generic case
756 foreach ($object as $key => $value) {
757 if (in_array($key, $arrayoffieldstoexclude)) {
758 continue; // Discard some properties
759 }
760 if (!is_object($value) && !is_null($value) && $value !== '') {
761 $this->object_data->$key = $value;
762 }
763 }
764
765 if (!empty($object->newref)) {
766 $this->object_data->ref = $object->newref;
767 }
768 }
769
770 // A trick to be sure all the object_data is an associative array
771 // json_encode and json_decode are not able to manage mixed object (with array/object, only full arrays or full objects)
772 $this->object_data = json_decode(json_encode($this->object_data, JSON_FORCE_OBJECT), false);
773
774 return 1;
775 }
776
783 public function fetch($id)
784 {
785 global $langs;
786
787 if (empty($id)) {
788 $this->error = 'BadParameter';
789 return -1;
790 }
791
792 $sql = "SELECT b.rowid, b.date_creation, b.signature, b.signature_line, b.amounts, b.action, b.element, b.fk_object, b.entity,";
793 $sql .= " b.certified, b.tms, b.fk_user, b.user_fullname, b.date_object, b.ref_object, b.object_data, b.object_version";
794 $sql .= " FROM ".MAIN_DB_PREFIX."blockedlog as b";
795 if ($id) {
796 $sql .= " WHERE b.rowid = ".((int) $id);
797 }
798
799 $resql = $this->db->query($sql);
800 if ($resql) {
801 $obj = $this->db->fetch_object($resql);
802 if ($obj) {
803 $this->id = $obj->rowid;
804 $this->entity = $obj->entity;
805
806 $this->date_creation = $this->db->jdate($obj->date_creation);
807 $this->date_modification = $this->db->jdate($obj->tms);
808
809 $this->amounts = (float) $obj->amounts;
810 $this->action = $obj->action;
811 $this->element = $obj->element;
812
813 $this->fk_object = $obj->fk_object;
814 $this->date_object = $this->db->jdate($obj->date_object);
815 $this->ref_object = $obj->ref_object;
816
817 $this->fk_user = $obj->fk_user;
818 $this->user_fullname = $obj->user_fullname;
819
820 $this->object_data = $this->dolDecodeBlockedData($obj->object_data);
821 $this->object_version = $obj->object_version;
822
823 $this->signature = $obj->signature;
824 $this->signature_line = $obj->signature_line;
825 $this->certified = ($obj->certified == 1);
826
827 return 1;
828 } else {
829 $langs->load("blockedlog");
830 $this->error = $langs->trans("RecordNotFound");
831 return 0;
832 }
833 } else {
834 $this->error = $this->db->error();
835 return -1;
836 }
837 }
838
839
847 public function dolEncodeBlockedData($data, $mode = 0)
848 {
849 try {
850 $aaa = json_encode($data);
851 } catch (Exception $e) {
852 //print $e->getErrs);
853 }
854 //var_dump($aaa);
855
856 return $aaa;
857 }
858
859
867 public function dolDecodeBlockedData($data, $mode = 0)
868 {
869 try {
870 $aaa = (object) jsonOrUnserialize($data);
871 } catch (Exception $e) {
872 //print $e->getErrs);
873 }
874 //var_dump($aaa);
875
876 return $aaa;
877 }
878
879
885 public function setCertified()
886 {
887 $res = $this->db->query("UPDATE ".MAIN_DB_PREFIX."blockedlog SET certified=1 WHERE rowid=".((int) $this->id));
888 if (!$res) {
889 return false;
890 }
891
892 return true;
893 }
894
902 public function create($user, $forcesignature = '')
903 {
904 global $conf, $langs, $hookmanager;
905
906 $langs->load('blockedlog');
907
908 $error = 0;
909
910 // Clean data
911 $this->amounts = (float) $this->amounts;
912
913 dol_syslog(get_class($this).'::create action='.$this->action.' fk_user='.$this->fk_user.' user_fullname='.$this->user_fullname, LOG_DEBUG);
914
915 // Check parameters/properties
916 if (!isset($this->amounts)) { // amount can be 0 for some events (like when module is disabled)
917 $this->error = $langs->trans("BlockLogNeedAmountsValue");
918 dol_syslog($this->error, LOG_WARNING);
919 return -1;
920 }
921
922 if (empty($this->element)) {
923 $this->error = $langs->trans("BlockLogNeedElement");
924 dol_syslog($this->error, LOG_WARNING);
925 return -2;
926 }
927
928 if (empty($this->action)) {
929 $this->error = $langs->trans("BadParameterWhenCallingCreateOfBlockedLog");
930 dol_syslog($this->error, LOG_WARNING);
931 return -3;
932 }
933 if (empty($this->fk_user)) {
934 $this->user_fullname = '(Anonymous)';
935 }
936
937 $this->date_creation = dol_now();
938
939 $this->object_version = DOL_VERSION;
940
941
942 $this->db->begin();
943
944 $previoushash = $this->getPreviousHash(1, 0); // This get last record and lock database until insert is done
945
946 $keyforsignature = $this->buildKeyForSignature();
947
948 include_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
949
950 $this->signature_line = dol_hash($keyforsignature, '5'); // Not really useful
951 $this->signature = dol_hash($previoushash.$keyforsignature, '5');
952 if ($forcesignature) {
953 $this->signature = $forcesignature;
954 }
955 //var_dump($keyforsignature);var_dump($previoushash);var_dump($this->signature_line);var_dump($this->signature);
956
957 $sql = "INSERT INTO ".MAIN_DB_PREFIX."blockedlog (";
958 $sql .= " date_creation,";
959 $sql .= " action,";
960 $sql .= " amounts,";
961 $sql .= " signature,";
962 $sql .= " signature_line,";
963 $sql .= " element,";
964 $sql .= " fk_object,";
965 $sql .= " date_object,";
966 $sql .= " ref_object,";
967 $sql .= " object_data,";
968 $sql .= " object_version,";
969 $sql .= " certified,";
970 $sql .= " fk_user,";
971 $sql .= " user_fullname,";
972 $sql .= " entity";
973 $sql .= ") VALUES (";
974 $sql .= "'".$this->db->idate($this->date_creation)."',";
975 $sql .= "'".$this->db->escape($this->action)."',";
976 $sql .= $this->amounts.",";
977 $sql .= "'".$this->db->escape($this->signature)."',";
978 $sql .= "'".$this->db->escape($this->signature_line)."',";
979 $sql .= "'".$this->db->escape($this->element)."',";
980 $sql .= (int) $this->fk_object.",";
981 $sql .= "'".$this->db->idate($this->date_object)."',";
982 $sql .= "'".$this->db->escape($this->ref_object)."',";
983 $sql .= "'".$this->db->escape($this->dolEncodeBlockedData($this->object_data))."',";
984 $sql .= "'".$this->db->escape($this->object_version)."',";
985 $sql .= "0,";
986 $sql .= $this->fk_user.",";
987 $sql .= "'".$this->db->escape($this->user_fullname)."',";
988 $sql .= ($this->entity ? $this->entity : $conf->entity);
989 $sql .= ")";
990
991 /*
992 $a = serialize($this->object_data); $a2 = unserialize($a); $a4 = print_r($a2, true);
993 $b = json_encode($this->object_data); $b2 = json_decode($b); $b4 = print_r($b2, true);
994 var_dump($a4 == print_r($this->object_data, true) ? 'a=a' : 'a not = a');
995 var_dump($b4 == print_r($this->object_data, true) ? 'b=b' : 'b not = b');
996 exit;
997 */
998
999 $res = $this->db->query($sql);
1000 if ($res) {
1001 $id = $this->db->last_insert_id(MAIN_DB_PREFIX."blockedlog");
1002
1003 if ($id > 0) {
1004 $this->id = $id;
1005
1006 $this->db->commit();
1007
1008 return $this->id;
1009 } else {
1010 $this->db->rollback();
1011 return -2;
1012 }
1013 } else {
1014 $this->error = $this->db->error();
1015 $this->db->rollback();
1016 return -1;
1017 }
1018
1019 // The commit will release the lock so we can insert nex record
1020 }
1021
1029 public function checkSignature($previoushash = '', $returnarray = 0)
1030 {
1031 if (empty($previoushash)) {
1032 $previoushash = $this->getPreviousHash(0, $this->id);
1033 }
1034 // Recalculate hash
1035 $keyforsignature = $this->buildKeyForSignature();
1036
1037 //$signature_line = dol_hash($keyforsignature, '5'); // Not really useful
1038 $signature = dol_hash($previoushash.$keyforsignature, 'sha256');
1039 //var_dump($previoushash); var_dump($keyforsignature); var_dump($signature_line); var_dump($signature);
1040
1041 $res = ($signature === $this->signature);
1042
1043 if (!$res) {
1044 $this->error = 'Signature KO';
1045 }
1046
1047 if ($returnarray) {
1048 if ($returnarray == 1) {
1049 unset($keyforsignature);
1050 return array('checkresult' => $res, 'calculatedsignature' => $signature, 'previoushash' => $previoushash);
1051 } else { // Consume much memory ($keyforsignature is a large var)
1052 return array('checkresult' => $res, 'calculatedsignature' => $signature, 'previoushash' => $previoushash, 'keyforsignature' => $keyforsignature);
1053 }
1054 } else {
1055 unset($keyforsignature);
1056 return $res;
1057 }
1058 }
1059
1067 private function buildKeyForSignature()
1068 {
1069 //print_r($this->object_data);
1070 if (((int) $this->object_version) >= 18) {
1071 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);
1072 } else {
1073 return $this->date_creation.'|'.$this->action.'|'.$this->amounts.'|'.$this->ref_object.'|'.$this->date_object.'|'.$this->user_fullname.'|'.print_r($this->object_data, true);
1074 }
1075 }
1076
1077
1085 public function getPreviousHash($withlock = 0, $beforeid = 0)
1086 {
1087 global $conf;
1088
1089 $previoussignature = '';
1090
1091 // Fast search of previous record by searching with beforeid - 1. This is very fast and will work 99% of time.
1092 if ($beforeid) {
1093 $sql = "SELECT rowid, signature FROM ".MAIN_DB_PREFIX."blockedlog";
1094 $sql .= " WHERE entity = ".((int) $conf->entity);
1095 $sql .= " AND rowid = ".((int) $beforeid - 1);
1096 $sql .= ($withlock ? " FOR UPDATE " : "");
1097
1098 $resql = $this->db->query($sql);
1099 if ($resql) {
1100 $obj = $this->db->fetch_object($resql);
1101 if ($obj) {
1102 $previoussignature = $obj->signature;
1103 }
1104 } else {
1105 dol_print_error($this->db);
1106 exit;
1107 }
1108 }
1109
1110 if (empty($previoussignature)) {
1111 $sql = "SELECT rowid, signature FROM ".MAIN_DB_PREFIX."blockedlog";
1112 if ($beforeid) {
1113 $sql.= $this->db->hintindex('entity_rowid', 1);
1114 }
1115 $sql .= " WHERE entity = ".((int) $conf->entity);
1116 if ($beforeid) {
1117 $sql .= " AND rowid < ".(int) $beforeid;
1118 }
1119 $sql .= " ORDER BY rowid DESC LIMIT 1";
1120 $sql .= ($withlock ? " FOR UPDATE " : "");
1121
1122 $resql = $this->db->query($sql);
1123 if ($resql) {
1124 $obj = $this->db->fetch_object($resql);
1125 if ($obj) {
1126 $previoussignature = $obj->signature;
1127 }
1128 } else {
1129 dol_print_error($this->db);
1130 exit;
1131 }
1132 }
1133
1134 if (empty($previoussignature)) {
1135 // First signature line (line 0)
1136 $previoussignature = $this->getSignature();
1137 }
1138
1139 return $previoussignature;
1140 }
1141
1158 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 = '')
1159 {
1160 global $conf;
1161 //global $cachedlogs;
1162
1163 /* $cachedlogs allow fastest search */
1164 //if (empty($cachedlogs)) $cachedlogs = array();
1165
1166 if ($element == 'all') {
1167 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
1168 WHERE entity=".$conf->entity;
1169 } elseif ($element == 'not_certified') {
1170 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
1171 WHERE entity=".$conf->entity." AND certified = 0";
1172 } elseif ($element == 'just_certified') {
1173 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
1174 WHERE entity=".$conf->entity." AND certified = 1";
1175 } else {
1176 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
1177 WHERE entity=".$conf->entity." AND element = '".$this->db->escape($element)."'";
1178 }
1179
1180 if ($fk_object) {
1181 $sql .= natural_search("rowid", (string) $fk_object, 1);
1182 }
1183 if ($search_fk_user > 0) {
1184 $sql .= natural_search("fk_user", (string) $search_fk_user, 2);
1185 }
1186 if ($search_start > 0) {
1187 $sql .= " AND date_creation >= '".$this->db->idate($search_start)."'";
1188 }
1189 if ($search_end > 0) {
1190 $sql .= " AND date_creation <= '".$this->db->idate($search_end)."'";
1191 }
1192 if ($search_ref != '') {
1193 $sql .= natural_search("ref_object", $search_ref);
1194 }
1195 if ($search_amount != '') {
1196 $sql .= natural_search("amounts", $search_amount, 1);
1197 }
1198 if ($search_code != '' && $search_code != '-1') {
1199 $sql .= natural_search("action", $search_code, 3);
1200 }
1201
1202 $sql .= $this->db->order($sortfield, $sortorder);
1203 $sql .= $this->db->plimit($limit + 1); // We want more, because we will stop into loop later with error if we reach max
1204
1205 $res = $this->db->query($sql);
1206 if ($res) {
1207 $results = array();
1208
1209 $i = 0;
1210 while ($obj = $this->db->fetch_object($res)) {
1211 $i++;
1212 if ($i > $limit) {
1213 // Too many record, we will consume too much memory
1214 return -2;
1215 }
1216
1217 //if (!isset($cachedlogs[$obj->rowid]))
1218 //{
1219 $b = new BlockedLog($this->db);
1220 $b->fetch($obj->rowid);
1221 //$b->loadTrackedEvents();
1222 //$cachedlogs[$obj->rowid] = $b;
1223 //}
1224
1225 //$results[] = $cachedlogs[$obj->rowid];
1226 $results[] = $b;
1227 }
1228
1229 return $results;
1230 }
1231
1232 return -1;
1233 }
1234
1240 public function getSignature()
1241 {
1242 global $db, $conf, $mysoc;
1243
1244 if (!getDolGlobalString('BLOCKEDLOG_ENTITY_FINGERPRINT')) { // creation of a unique fingerprint
1245 require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
1246 require_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
1247 require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
1248
1249 $fingerprint = dol_hash(print_r($mysoc, true).getRandomPassword(true), '5');
1250
1251 dolibarr_set_const($db, 'BLOCKEDLOG_ENTITY_FINGERPRINT', $fingerprint, 'chaine', 0, 'Numeric Unique Fingerprint', $conf->entity);
1252
1253 $conf->global->BLOCKEDLOG_ENTITY_FINGERPRINT = $fingerprint;
1254 }
1255
1256 return $conf->global->BLOCKEDLOG_ENTITY_FINGERPRINT;
1257 }
1258
1259
1266 public function alreadyUsed($ignoresystem = 0)
1267 {
1268 global $conf;
1269
1270 $result = false;
1271
1272 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog";
1273 $sql .= " WHERE entity = ".$conf->entity;
1274 if ($ignoresystem) {
1275 $sql .= " AND action not in ('MODULE_SET','MODULE_RESET')";
1276 }
1277 $sql .= $this->db->plimit(1);
1278
1279 $res = $this->db->query($sql);
1280 if ($res !== false) {
1281 $obj = $this->db->fetch_object($res);
1282 if ($obj) {
1283 $result = true;
1284 }
1285 } else {
1286 dol_print_error($this->db);
1287 }
1288
1289 dol_syslog("Module Blockedlog alreadyUsed(ignoresystem=".$ignoresystem.") returns ".json_encode($result));
1290
1291 return $result;
1292 }
1293}
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:66
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.
getUser()
Try to retrieve user author.
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 a Dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
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.