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_UPDATE'] = 'logBILL_UPDATE';
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 'module_source', 'pos_source'
537 ))) {
538 continue; // Discard if not into a dedicated list
539 }
540 if ($key == 'lines') {
541 $lineid = 0;
542 foreach ($value as $tmpline) { // $tmpline is object FactureLine
543 $lineid++;
544 foreach ($tmpline as $keyline => $valueline) {
545 if (!in_array($keyline, array(
546 'ref', 'product_type', 'product_label',
547 'qty',
548 'subprice',
549 'vat_src_code', 'tva_tx', 'localtax1_tx', 'localtax2_tx',
550 'total_ht', 'total_tva', 'total_ttc', 'total_localtax1', 'total_localtax2',
551 'multicurrency_code', 'multicurrency_total_ht', 'multicurrency_total_tva', 'multicurrency_total_ttc',
552 'info_bits', 'special_code',
553 ))) {
554 continue; // Discard if not into a dedicated list
555 }
556
557 if (empty($this->object_data->invoiceline[$lineid]) || !is_object($this->object_data->invoiceline[$lineid])) { // To avoid warning
558 $this->object_data->invoiceline[$lineid] = new stdClass();
559 }
560
561 if (!is_object($valueline) && !is_null($valueline) && $valueline !== '') {
562 $this->object_data->invoiceline[$lineid]->$keyline = $valueline;
563 }
564 }
565 }
566 } elseif (!is_object($value) && !is_null($value) && $value !== '') {
567 $this->object_data->$key = $value;
568 }
569 }
570
571 if (!empty($object->newref)) {
572 $this->object_data->ref = $object->newref;
573 }
574 } elseif ($this->element == 'invoice_supplier') {
575 '@phan-var-force FactureFournisseur $object';
576 foreach ($object as $key => $value) {
577 if (in_array($key, $arrayoffieldstoexclude)) {
578 continue; // Discard some properties
579 }
580 if (!in_array($key, array(
581 'ref', 'ref_client', 'ref_supplier', 'date', 'datef', 'type', 'total_ht', 'total_tva', 'total_ttc', 'localtax1', 'localtax2', 'revenuestamp', 'datepointoftax', 'note_public'
582 ))) {
583 continue; // Discard if not into a dedicated list
584 }
585 if (!is_object($value) && !is_null($value) && $value !== '') {
586 $this->object_data->$key = $value;
587 }
588 }
589
590 if (!empty($object->newref)) {
591 $this->object_data->ref = $object->newref;
592 }
593 } elseif ($this->element == 'payment' || $this->element == 'payment_supplier' || $this->element == 'payment_donation' || $this->element == 'payment_various') {
594 '@phan-var-force Paiement|PaiementFourn|PaymentDonation|PaymentVarious $object';
595 $datepayment = $object->datepaye ? $object->datepaye : ($object->datepaid ? $object->datepaid : $object->datep);
596 $paymenttypeid = $object->paiementid ? $object->paiementid : ($object->paymenttype ? $object->paymenttype : $object->type_payment);
597
598 $this->object_data->ref = $object->ref;
599 $this->object_data->date = $datepayment;
600 $this->object_data->type_code = dol_getIdFromCode($this->db, $paymenttypeid, 'c_paiement', 'id', 'code');
601
602 if (!empty($object->num_payment)) {
603 $this->object_data->payment_num = $object->num_payment;
604 }
605 if (!empty($object->note_private)) {
606 $this->object_data->note_private = $object->note_private;
607 }
608 //$this->object_data->fk_account = $object->fk_account;
609 //var_dump($this->object_data);exit;
610
611 $totalamount = 0;
612
613 // Loop on each invoice payment amount (payment_part)
614 if (is_array($object->amounts) && !empty($object->amounts)) {
615 $paymentpartnumber = 0;
616 foreach ($object->amounts as $objid => $amount) {
617 if (empty($amount)) {
618 continue;
619 }
620
621 $totalamount += $amount;
622
623 $tmpobject = null;
624 if ($this->element == 'payment_supplier') {
625 include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
626 $tmpobject = new FactureFournisseur($this->db);
627 } elseif ($this->element == 'payment') {
628 include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
629 $tmpobject = new Facture($this->db);
630 } elseif ($this->element == 'payment_donation') {
631 include_once DOL_DOCUMENT_ROOT.'/don/class/don.class.php';
632 $tmpobject = new Don($this->db);
633 } elseif ($this->element == 'payment_various') {
634 include_once DOL_DOCUMENT_ROOT.'/compta/bank/class/paymentvarious.class.php';
635 $tmpobject = new PaymentVarious($this->db);
636 }
637
638 if (!is_object($tmpobject)) {
639 continue;
640 }
641
642 $result = $tmpobject->fetch($objid);
643
644 if ($result <= 0) {
645 $this->error = $tmpobject->error;
646 $this->errors = $tmpobject->errors;
647 dol_syslog("Failed to fetch object with id ".$objid, LOG_ERR);
648 return -1;
649 }
650
651 $paymentpart = new stdClass();
652 $paymentpart->amount = $amount;
653
654 if (!in_array($this->element, array('payment_donation', 'payment_various'))) {
655 $result = $tmpobject->fetch_thirdparty();
656 if ($result == 0) {
657 $this->error = 'Failed to fetch thirdparty for object with id '.$tmpobject->id;
658 $this->errors[] = $this->error;
659 dol_syslog("Failed to fetch thirdparty for object with id ".$tmpobject->id, LOG_ERR);
660 return -1;
661 } elseif ($result < 0) {
662 $this->error = $tmpobject->error;
663 $this->errors = $tmpobject->errors;
664 return -1;
665 }
666
667 $paymentpart->thirdparty = new stdClass();
668 foreach ($tmpobject->thirdparty as $key => $value) {
669 if (in_array($key, $arrayoffieldstoexclude)) {
670 continue; // Discard some properties
671 }
672 if (!in_array($key, array(
673 'name', 'name_alias', 'ref_ext', 'address', 'zip', 'town', 'state_code', 'country_code', 'idprof1', 'idprof2', 'idprof3', 'idprof4', 'idprof5', 'idprof6', 'phone', 'fax', 'email', 'barcode',
674 'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
675 ))) {
676 continue; // Discard if not into a dedicated list
677 }
678 if (!is_object($value) && !is_null($value) && $value !== '') {
679 $paymentpart->thirdparty->$key = $value;
680 }
681 }
682 }
683
684 // Init object to avoid warnings
685 if ($this->element == 'payment_donation') {
686 $paymentpart->donation = new stdClass();
687 } else {
688 $paymentpart->invoice = new stdClass();
689 }
690
691 if ($this->element != 'payment_various') {
692 foreach ($tmpobject as $key => $value) {
693 if (in_array($key, $arrayoffieldstoexclude)) {
694 continue; // Discard some properties
695 }
696 if (!in_array($key, array(
697 'ref', 'ref_client', 'ref_supplier', 'date', 'datef', 'type', 'total_ht', 'total_tva', 'total_ttc', 'localtax1', 'localtax2', 'revenuestamp', 'datepointoftax', 'note_public'
698 ))) {
699 continue; // Discard if not into a dedicated list
700 }
701 if (!is_object($value) && !is_null($value) && $value !== '') {
702 if ($this->element == 'payment_donation') {
703 $paymentpart->donation->$key = $value;
704 } elseif ($this->element == 'payment_various') {
705 $paymentpart->various->$key = $value;
706 } else {
707 $paymentpart->invoice->$key = $value;
708 }
709 }
710 }
711
712 $paymentpartnumber++; // first payment will be 1
713 $this->object_data->payment_part[$paymentpartnumber] = $paymentpart;
714 }
715 }
716 } elseif (!empty($object->amount)) {
717 $totalamount = $object->amount;
718 }
719
720 $this->object_data->amount = $totalamount;
721
722 if (!empty($object->newref)) {
723 $this->object_data->ref = $object->newref;
724 }
725 } elseif ($this->element == 'payment_salary') {
726 '@phan-var-force PaymentSalary $object';
727 $this->object_data->amounts = array($object->amount);
728
729 if (!empty($object->newref)) {
730 $this->object_data->ref = $object->newref;
731 }
732 } elseif ($this->element == 'subscription') {
733 '@phan-var-force Subscription $object';
734 foreach ($object as $key => $value) {
735 if (in_array($key, $arrayoffieldstoexclude)) {
736 continue; // Discard some properties
737 }
738 if (!in_array($key, array(
739 'id', 'datec', 'dateh', 'datef', 'fk_adherent', 'amount', 'import_key', 'statut', 'note'
740 ))) {
741 continue; // Discard if not into a dedicated list
742 }
743 if (!is_object($value) && !is_null($value) && $value !== '') {
744 $this->object_data->$key = $value;
745 }
746 }
747
748 if (!empty($object->newref)) {
749 $this->object_data->ref = $object->newref;
750 }
751 } elseif ($this->element == 'stockmouvement') {
752 '@phan-var-force StockTransfer $object';
753 foreach ($object as $key => $value) {
754 if (in_array($key, $arrayoffieldstoexclude)) {
755 continue; // Discard some properties
756 }
757 if (!is_object($value) && !is_null($value) && $value !== '') {
758 $this->object_data->$key = $value;
759 }
760 }
761 } else {
762 // Generic case
763 foreach ($object as $key => $value) {
764 if (in_array($key, $arrayoffieldstoexclude)) {
765 continue; // Discard some properties
766 }
767 if (!is_object($value) && !is_null($value) && $value !== '') {
768 $this->object_data->$key = $value;
769 }
770 }
771
772 if (!empty($object->newref)) {
773 $this->object_data->ref = $object->newref;
774 }
775 }
776
777 // A trick to be sure all the object_data is an associative array
778 // json_encode and json_decode are not able to manage mixed object (with array/object, only full arrays or full objects)
779 $this->object_data = json_decode(json_encode($this->object_data, JSON_FORCE_OBJECT), false);
780
781 return 1;
782 }
783
790 public function fetch($id)
791 {
792 global $langs;
793
794 if (empty($id)) {
795 $this->error = 'BadParameter';
796 return -1;
797 }
798
799 $sql = "SELECT b.rowid, b.date_creation, b.signature, b.signature_line, b.amounts, b.action, b.element, b.fk_object, b.entity,";
800 $sql .= " b.certified, b.tms, b.fk_user, b.user_fullname, b.date_object, b.ref_object, b.object_data, b.object_version";
801 $sql .= " FROM ".MAIN_DB_PREFIX."blockedlog as b";
802 if ($id) {
803 $sql .= " WHERE b.rowid = ".((int) $id);
804 }
805
806 $resql = $this->db->query($sql);
807 if ($resql) {
808 $obj = $this->db->fetch_object($resql);
809 if ($obj) {
810 $this->id = $obj->rowid;
811 $this->entity = $obj->entity;
812
813 $this->date_creation = $this->db->jdate($obj->date_creation);
814 $this->date_modification = $this->db->jdate($obj->tms);
815
816 $this->amounts = (float) $obj->amounts;
817 $this->action = $obj->action;
818 $this->element = $obj->element;
819
820 $this->fk_object = $obj->fk_object;
821 $this->date_object = $this->db->jdate($obj->date_object);
822 $this->ref_object = $obj->ref_object;
823
824 $this->fk_user = $obj->fk_user;
825 $this->user_fullname = $obj->user_fullname;
826
827 $this->object_data = $this->dolDecodeBlockedData($obj->object_data);
828 $this->object_version = $obj->object_version;
829
830 $this->signature = $obj->signature;
831 $this->signature_line = $obj->signature_line;
832 $this->certified = ($obj->certified == 1);
833
834 return 1;
835 } else {
836 $langs->load("blockedlog");
837 $this->error = $langs->trans("RecordNotFound");
838 return 0;
839 }
840 } else {
841 $this->error = $this->db->error();
842 return -1;
843 }
844 }
845
846
854 public function dolEncodeBlockedData($data, $mode = 0)
855 {
856 $aaa = '';
857 try {
858 $aaa = json_encode($data);
859 } catch (Exception $e) {
860 // print $e->getErrs);
861 }
862
863 return $aaa;
864 }
865
866
874 public function dolDecodeBlockedData($data, $mode = 0)
875 {
876 $aaa = null;
877 try {
878 $aaa = (object) jsonOrUnserialize($data);
879 } catch (Exception $e) {
880 // print $e->getErrs);
881 }
882
883 return $aaa;
884 }
885
886
892 public function setCertified()
893 {
894 $res = $this->db->query("UPDATE ".MAIN_DB_PREFIX."blockedlog SET certified=1 WHERE rowid=".((int) $this->id));
895 if (!$res) {
896 return false;
897 }
898
899 return true;
900 }
901
909 public function create($user, $forcesignature = '')
910 {
911 global $conf, $langs;
912
913 $langs->load('blockedlog');
914
915 // Clean data
916 $this->amounts = (float) $this->amounts;
917
918 dol_syslog(get_class($this).'::create action='.$this->action.' fk_user='.$this->fk_user.' user_fullname='.$this->user_fullname, LOG_DEBUG);
919
920 // Check parameters/properties
921 if (!isset($this->amounts)) { // amount can be 0 for some events (like when module is disabled)
922 $this->error = $langs->trans("BlockLogNeedAmountsValue");
923 dol_syslog($this->error, LOG_WARNING);
924 return -1;
925 }
926
927 if (empty($this->element)) {
928 $this->error = $langs->trans("BlockLogNeedElement");
929 dol_syslog($this->error, LOG_WARNING);
930 return -2;
931 }
932
933 if (empty($this->action)) {
934 $this->error = $langs->trans("BadParameterWhenCallingCreateOfBlockedLog");
935 dol_syslog($this->error, LOG_WARNING);
936 return -3;
937 }
938 if (empty($this->fk_user)) {
939 $this->user_fullname = '(Anonymous)';
940 }
941
942 $this->date_creation = dol_now();
943
944 $this->object_version = DOL_VERSION;
945
946
947 $this->db->begin();
948
949 $previoushash = $this->getPreviousHash(1, 0); // This get last record and lock database until insert is done and transaction closed
950
951 $keyforsignature = $this->buildKeyForSignature(); // All the information for the has (meta data + data saved)
952
953 include_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
954
955 $this->signature_line = dol_hash($keyforsignature, '5'); // Not really useful
956 $this->signature = dol_hash($previoushash.$keyforsignature, '5');
957 if ($forcesignature) {
958 $this->signature = $forcesignature;
959 }
960 //var_dump($keyforsignature);var_dump($previoushash);var_dump($this->signature_line);var_dump($this->signature);
961
962 $sql = "INSERT INTO ".MAIN_DB_PREFIX."blockedlog (";
963 $sql .= " date_creation,";
964 $sql .= " action,";
965 $sql .= " amounts,";
966 $sql .= " signature,";
967 $sql .= " signature_line,";
968 $sql .= " element,";
969 $sql .= " fk_object,";
970 $sql .= " date_object,";
971 $sql .= " ref_object,";
972 $sql .= " object_data,";
973 $sql .= " object_version,";
974 $sql .= " certified,";
975 $sql .= " fk_user,";
976 $sql .= " user_fullname,";
977 $sql .= " entity";
978 $sql .= ") VALUES (";
979 $sql .= "'".$this->db->idate($this->date_creation)."',";
980 $sql .= "'".$this->db->escape($this->action)."',";
981 $sql .= $this->amounts.",";
982 $sql .= "'".$this->db->escape($this->signature)."',";
983 $sql .= "'".$this->db->escape($this->signature_line)."',";
984 $sql .= "'".$this->db->escape($this->element)."',";
985 $sql .= (int) $this->fk_object.",";
986 $sql .= "'".$this->db->idate($this->date_object)."',";
987 $sql .= "'".$this->db->escape($this->ref_object)."',";
988 $sql .= "'".$this->db->escape($this->dolEncodeBlockedData($this->object_data))."',";
989 $sql .= "'".$this->db->escape($this->object_version)."',";
990 $sql .= "0,";
991 $sql .= $this->fk_user.",";
992 $sql .= "'".$this->db->escape($this->user_fullname)."',";
993 $sql .= ($this->entity ? $this->entity : $conf->entity);
994 $sql .= ")";
995
996 /*
997 $a = serialize($this->object_data); $a2 = unserialize($a); $a4 = print_r($a2, true);
998 $b = json_encode($this->object_data); $b2 = json_decode($b); $b4 = print_r($b2, true);
999 var_dump($a4 == print_r($this->object_data, true) ? 'a=a' : 'a not = a');
1000 var_dump($b4 == print_r($this->object_data, true) ? 'b=b' : 'b not = b');
1001 exit;
1002 */
1003
1004 $res = $this->db->query($sql);
1005 if ($res) {
1006 $id = $this->db->last_insert_id(MAIN_DB_PREFIX."blockedlog");
1007
1008 if ($id > 0) {
1009 $this->id = $id;
1010
1011 $this->db->commit();
1012
1013 return $this->id;
1014 } else {
1015 $this->db->rollback();
1016 return -2;
1017 }
1018 } else {
1019 $this->error = $this->db->error();
1020 $this->db->rollback();
1021 return -1;
1022 }
1023
1024 // The commit will release the lock so we can insert nex record
1025 }
1026
1034 public function checkSignature($previoushash = '', $returnarray = 0)
1035 {
1036 if (empty($previoushash)) {
1037 $previoushash = $this->getPreviousHash(0, $this->id);
1038 }
1039 // Recalculate hash
1040 $keyforsignature = $this->buildKeyForSignature();
1041
1042 //$signature_line = dol_hash($keyforsignature, '5'); // Not really useful
1043 $signature = dol_hash($previoushash.$keyforsignature, 'sha256');
1044 //var_dump($previoushash); var_dump($keyforsignature); var_dump($signature_line); var_dump($signature);
1045
1046 $res = ($signature === $this->signature);
1047
1048 if (!$res) {
1049 $this->error = 'Signature KO';
1050 }
1051
1052 if ($returnarray) {
1053 if ($returnarray == 1) {
1054 unset($keyforsignature);
1055 return array('checkresult' => $res, 'calculatedsignature' => $signature, 'previoushash' => $previoushash);
1056 } else { // Consume much memory ($keyforsignature is a large var)
1057 return array('checkresult' => $res, 'calculatedsignature' => $signature, 'previoushash' => $previoushash, 'keyforsignature' => $keyforsignature);
1058 }
1059 } else {
1060 unset($keyforsignature);
1061 return $res;
1062 }
1063 }
1064
1072 private function buildKeyForSignature()
1073 {
1074 //print_r($this->object_data);
1075 if (((int) $this->object_version) >= 18) {
1076 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);
1077 } else {
1078 return $this->date_creation.'|'.$this->action.'|'.$this->amounts.'|'.$this->ref_object.'|'.$this->date_object.'|'.$this->user_fullname.'|'.print_r($this->object_data, true);
1079 }
1080 }
1081
1082
1090 public function getPreviousHash($withlock = 0, $beforeid = 0)
1091 {
1092 global $conf;
1093
1094 $previoussignature = '';
1095
1096 // Fast search of previous record by searching with beforeid - 1. This is very fast and will work 99% of time.
1097 if ($beforeid) {
1098 $sql = "SELECT rowid, signature FROM ".MAIN_DB_PREFIX."blockedlog";
1099 $sql .= " WHERE entity = ".((int) $conf->entity);
1100 $sql .= " AND rowid = ".((int) $beforeid - 1);
1101 $sql .= ($withlock ? " FOR UPDATE " : "");
1102
1103 $resql = $this->db->query($sql);
1104 if ($resql) {
1105 $obj = $this->db->fetch_object($resql);
1106 if ($obj) {
1107 $previoussignature = $obj->signature;
1108 }
1109 } else {
1110 dol_print_error($this->db);
1111 exit;
1112 }
1113 }
1114
1115 if (empty($previoussignature)) {
1116 $sql = "SELECT rowid, signature FROM ".MAIN_DB_PREFIX."blockedlog";
1117 if ($beforeid) {
1118 $sql.= $this->db->hintindex('entity_rowid', 1);
1119 }
1120 $sql .= " WHERE entity = ".((int) $conf->entity);
1121 if ($beforeid) {
1122 $sql .= " AND rowid < ".(int) $beforeid;
1123 }
1124 $sql .= " ORDER BY rowid DESC LIMIT 1";
1125 $sql .= ($withlock ? " FOR UPDATE " : "");
1126
1127 $resql = $this->db->query($sql);
1128 if ($resql) {
1129 $obj = $this->db->fetch_object($resql);
1130 if ($obj) {
1131 $previoussignature = $obj->signature;
1132 }
1133 } else {
1134 dol_print_error($this->db);
1135 exit;
1136 }
1137 }
1138
1139 if (empty($previoussignature)) {
1140 // First signature line (line 0)
1141 $previoussignature = $this->getSignature();
1142 }
1143
1144 return $previoussignature;
1145 }
1146
1163 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 = '')
1164 {
1165 global $conf;
1166 //global $cachedlogs;
1167
1168 /* $cachedlogs allow fastest search */
1169 //if (empty($cachedlogs)) $cachedlogs = array();
1170
1171 if ($element == 'all') {
1172 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
1173 WHERE entity=".$conf->entity;
1174 } elseif ($element == 'not_certified') {
1175 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
1176 WHERE entity=".$conf->entity." AND certified = 0";
1177 } elseif ($element == 'just_certified') {
1178 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
1179 WHERE entity=".$conf->entity." AND certified = 1";
1180 } else {
1181 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
1182 WHERE entity=".$conf->entity." AND element = '".$this->db->escape($element)."'";
1183 }
1184
1185 if ($fk_object) {
1186 $sql .= natural_search("rowid", (string) $fk_object, 1);
1187 }
1188 if ($search_fk_user > 0) {
1189 $sql .= natural_search("fk_user", (string) $search_fk_user, 2);
1190 }
1191 if ($search_start > 0) {
1192 $sql .= " AND date_creation >= '".$this->db->idate($search_start)."'";
1193 }
1194 if ($search_end > 0) {
1195 $sql .= " AND date_creation <= '".$this->db->idate($search_end)."'";
1196 }
1197 if ($search_ref != '') {
1198 $sql .= natural_search("ref_object", $search_ref);
1199 }
1200 if ($search_amount != '') {
1201 $sql .= natural_search("amounts", $search_amount, 1);
1202 }
1203 if (is_array($search_code)) {
1204 if (!empty($search_code)) {
1205 $sql .= natural_search("action", implode(',', $search_code), 3);
1206 }
1207 } else {
1208 if ($search_code != '' && $search_code != '-1') {
1209 $sql .= natural_search("action", $search_code, 3);
1210 }
1211 }
1212
1213 $sql .= $this->db->order($sortfield, $sortorder);
1214 $sql .= $this->db->plimit($limit + 1); // We want more, because we will stop into loop later with error if we reach max
1215
1216 $res = $this->db->query($sql);
1217 if ($res) {
1218 $results = array();
1219
1220 $i = 0;
1221 while ($obj = $this->db->fetch_object($res)) {
1222 $i++;
1223 if ($i > $limit) {
1224 // Too many record, we will consume too much memory
1225 return -2;
1226 }
1227
1228 //if (!isset($cachedlogs[$obj->rowid]))
1229 //{
1230 $b = new BlockedLog($this->db);
1231 $b->fetch($obj->rowid);
1232 //$b->loadTrackedEvents();
1233 //$cachedlogs[$obj->rowid] = $b;
1234 //}
1235
1236 //$results[] = $cachedlogs[$obj->rowid];
1237 $results[] = $b;
1238 }
1239
1240 return $results;
1241 }
1242
1243 return -1;
1244 }
1245
1251 public function getSignature()
1252 {
1253 global $db, $conf, $mysoc;
1254
1255 if (!getDolGlobalString('BLOCKEDLOG_ENTITY_FINGERPRINT')) { // creation of a unique fingerprint
1256 require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
1257 require_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
1258 require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
1259
1260 $fingerprint = dol_hash(print_r($mysoc, true).getRandomPassword(true), '5');
1261
1262 dolibarr_set_const($db, 'BLOCKEDLOG_ENTITY_FINGERPRINT', $fingerprint, 'chaine', 0, 'Numeric Unique Fingerprint', $conf->entity);
1263
1264 $conf->global->BLOCKEDLOG_ENTITY_FINGERPRINT = $fingerprint;
1265 }
1266
1267 return $conf->global->BLOCKEDLOG_ENTITY_FINGERPRINT;
1268 }
1269
1270
1277 public function alreadyUsed($ignoresystem = 0)
1278 {
1279 global $conf;
1280
1281 $result = false;
1282
1283 $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog";
1284 $sql .= " WHERE entity = ".$conf->entity;
1285 if ($ignoresystem) {
1286 $sql .= " AND action not in ('MODULE_SET','MODULE_RESET')";
1287 }
1288 $sql .= $this->db->plimit(1);
1289
1290 $res = $this->db->query($sql);
1291 if ($res !== false) {
1292 $obj = $this->db->fetch_object($res);
1293 if ($obj) {
1294 $result = true;
1295 }
1296 } else {
1297 dol_print_error($this->db);
1298 }
1299
1300 dol_syslog("Module Blockedlog alreadyUsed(ignoresystem=".$ignoresystem.") returns ".json_encode($result));
1301
1302 return $result;
1303 }
1304}
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.