Completed
Branch develop (5b8006)
by
unknown
43:45
created

BlockedLog::dolDecodeBlockedData()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 2
dl 0
loc 15
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/* Copyright (C) 2017 ATM Consulting      <[email protected]>
3
 * Copyright (C) 2017 Laurent Destailleur <[email protected]>
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17
 *
18
 * See https://medium.com/@lhartikk/a-blockchain-in-200-lines-of-code-963cc1cc0e54
19
 */
20
21
22
23
24
/*ini_set('unserialize_callback_func', 'mycallback');
25
26
function mycallback($classname)
27
{
28
	//var_dump($classname);
29
	include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
30
31
}*/
32
33
34
35
/**
36
 *	Class to manage Blocked Log
37
 */
38
class BlockedLog
39
{
40
	/**
41
	 * Id of the log
42
	 * @var int
43
	 */
44
	public $id;
45
	/**
46
	 * Entity
47
	 * @var int
48
	 */
49
	public $entity;
50
51
	public $error = '';
52
	public $errors = array();
53
54
	/**
55
	 * Unique fingerprint of the log
56
	 * @var string
57
	 */
58
	public $signature = '';
59
60
	/**
61
	 * Unique fingerprint of the line log content
62
	 * @var string
63
	 */
64
	public $signature_line = '';
65
66
	public $amounts = null;
67
68
	/**
69
	 * trigger action
70
	 * @var string
71
	 */
72
	public $action = '';
73
74
	/**
75
	 * Object element
76
	 * @var string
77
	 */
78
	public $element = '';
79
80
	/**
81
	 * Object id
82
	 * @var int
83
	 */
84
	public $fk_object = 0;
85
86
	/**
87
	 * Log certified by remote authority or not
88
	 * @var boolean
89
	 */
90
	public $certified = false;
91
92
	/**
93
	 * Author
94
	 * @var int
95
	 */
96
	public $fk_user = 0;
97
98
	public $date_creation;
99
	public $date_modification;
100
101
	public $date_object = 0;
102
103
	public $ref_object = '';
104
105
	public $object_data = null;
106
107
	/**
108
	 * Array of tracked event codes
109
	 * @var string[]
110
	 */
111
	public $trackedevents = array();
112
113
114
115
	/**
116
	 *      Constructor
117
	 *
118
	 *      @param		DoliDB		$db      Database handler
119
	 */
120
	public function __construct(DoliDB $db)
121
	{
122
		global $conf;
123
124
		$this->db = $db;
125
126
		$this->trackedevents = array();
127
128
		if ($conf->facture->enabled) $this->trackedevents['BILL_VALIDATE']='logBILL_VALIDATE';
129
		if ($conf->facture->enabled) $this->trackedevents['BILL_DELETE']='logBILL_DELETE';
130
		if ($conf->facture->enabled) $this->trackedevents['BILL_SENTBYMAIL']='logBILL_SENTBYMAIL';
131
		if ($conf->facture->enabled) $this->trackedevents['DOC_DOWNLOAD']='BlockedLogBillDownload';
132
		if ($conf->facture->enabled) $this->trackedevents['DOC_PREVIEW']='BlockedLogBillPreview';
133
134
		if ($conf->facture->enabled) $this->trackedevents['PAYMENT_CUSTOMER_CREATE']='logPAYMENT_CUSTOMER_CREATE';
135
		if ($conf->facture->enabled) $this->trackedevents['PAYMENT_CUSTOMER_DELETE']='logPAYMENT_CUSTOMER_DELETE';
136
137
		/* Supplier
138
		if ($conf->fournisseur->enabled) $this->trackedevents['BILL_SUPPLIER_VALIDATE']='BlockedLogSupplierBillValidate';
139
		if ($conf->fournisseur->enabled) $this->trackedevents['BILL_SUPPLIER_DELETE']='BlockedLogSupplierBillDelete';
140
		if ($conf->fournisseur->enabled) $this->trackedevents['BILL_SUPPLIER_SENTBYMAIL']='BlockedLogSupplierBillSentByEmail'; // Trigger key does not exists, we want just into array to list it as done
141
		if ($conf->fournisseur->enabled) $this->trackedevents['SUPPLIER_DOC_DOWNLOAD']='BlockedLogSupplierBillDownload';		// Trigger key does not exists, we want just into array to list it as done
142
		if ($conf->fournisseur->enabled) $this->trackedevents['SUPPLIER_DOC_PREVIEW']='BlockedLogSupplierBillPreview';		// Trigger key does not exists, we want just into array to list it as done
143
144
		if ($conf->fournisseur->enabled) $this->trackedevents['PAYMENT_SUPPLIER_CREATE']='BlockedLogSupplierBillPaymentCreate';
145
		if ($conf->fournisseur->enabled) $this->trackedevents['PAYMENT_SUPPLIER_DELETE']='BlockedLogsupplierBillPaymentCreate';
146
		*/
147
148
		if ($conf->don->enabled) $this->trackedevents['DON_VALIDATE']='logDON_VALIDATE';
149
		if ($conf->don->enabled) $this->trackedevents['DON_DELETE']='logDON_DELETE';
150
		//if ($conf->don->enabled) $this->trackedevents['DON_SENTBYMAIL']='logDON_SENTBYMAIL';
151
152
		if ($conf->don->enabled) $this->trackedevents['DONATION_PAYMENT_CREATE']='logDONATION_PAYMENT_CREATE';
153
		if ($conf->don->enabled) $this->trackedevents['DONATION_PAYMENT_DELETE']='logDONATION_PAYMENT_DELETE';
154
155
		/*
156
		if ($conf->salary->enabled) $this->trackedevents['PAYMENT_SALARY_CREATE']='BlockedLogSalaryPaymentCreate';
157
		if ($conf->salary->enabled) $this->trackedevents['PAYMENT_SALARY_MODIFY']='BlockedLogSalaryPaymentCreate';
158
		if ($conf->salary->enabled) $this->trackedevents['PAYMENT_SALARY_DELETE']='BlockedLogSalaryPaymentCreate';
159
		*/
160
161
		if ($conf->adherent->enabled) $this->trackedevents['MEMBER_SUBSCRIPTION_CREATE']='logMEMBER_SUBSCRIPTION_CREATE';
162
		if ($conf->adherent->enabled) $this->trackedevents['MEMBER_SUBSCRIPTION_MODIFY']='logMEMBER_SUBSCRIPTION_MODIFY';
163
		if ($conf->adherent->enabled) $this->trackedevents['MEMBER_SUBSCRIPTION_DELETE']='logMEMBER_SUBSCRIPTION_DELETE';
164
165
166
		if ($conf->banque->enabled) $this->trackedevents['PAYMENT_VARIOUS_CREATE']='logPAYMENT_VARIOUS_CREATE';
167
		if ($conf->banque->enabled) $this->trackedevents['PAYMENT_VARIOUS_MODIFY']='logPAYMENT_VARIOUS_MODIFY';
168
		if ($conf->banque->enabled) $this->trackedevents['PAYMENT_VARIOUS_DELETE']='logPAYMENT_VARIOUS_DELETE';
169
	}
170
171
	/**
172
	 *  Try to retrieve source object (it it still exists)
173
	 */
174
	public function getObjectLink()
175
	{
176
		global $langs;
177
178
		if($this->element === 'facture') {
179
			require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
180
181
			$object = new Facture($this->db);
182
			if ($object->fetch($this->fk_object)>0) {
183
				return $object->getNomUrl(1);
184
			}
185
			else{
186
				$this->error++;
187
			}
188
		}
189
		if($this->element === 'invoice_supplier') {
190
			require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
191
192
			$object = new FactureFournisseur($this->db);
193
			if ($object->fetch($this->fk_object)>0) {
194
				return $object->getNomUrl(1);
195
			}
196
			else{
197
				$this->error++;
198
			}
199
		}
200
		else if($this->element === 'payment') {
201
			require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
202
203
			$object = new Paiement($this->db);
204
			if ($object->fetch($this->fk_object)>0) {
205
				return $object->getNomUrl(1);
206
			}
207
			else{
208
				$this->error++;
209
			}
210
		}
211
		else if($this->element === 'payment_supplier') {
212
			require_once DOL_DOCUMENT_ROOT.'/fourn/class/paiementfourn.class.php';
213
214
			$object = new PaiementFourn($this->db);
215
			if ($object->fetch($this->fk_object)>0) {
216
				return $object->getNomUrl(1);
217
			}
218
			else{
219
				$this->error++;
220
			}
221
		}
222
		else if($this->element === 'payment_donation') {
223
			require_once DOL_DOCUMENT_ROOT.'/don/class/paymentdonation.class.php';
224
225
			$object = new PaymentDonation($this->db);
226
			if ($object->fetch($this->fk_object)>0) {
227
				return $object->getNomUrl(1);
228
			}
229
			else{
230
				$this->error++;
231
			}
232
		}
233
		else if($this->element === 'payment_various') {
234
			require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/paymentvarious.class.php';
235
236
			$object = new PaymentVarious($this->db);
237
			if ($object->fetch($this->fk_object)>0) {
238
				return $object->getNomUrl(1);
239
			}
240
			else{
241
				$this->error++;
242
			}
243
		}
244
		else if($this->element === 'don' || $this->element === 'donation') {
245
			require_once DOL_DOCUMENT_ROOT.'/don/class/don.class.php';
246
247
			$object = new Don($this->db);
248
			if ($object->fetch($this->fk_object)>0) {
249
				return $object->getNomUrl(1);
250
			}
251
			else{
252
				$this->error++;
253
			}
254
		}
255
		else if($this->element === 'subscription') {
256
			require_once DOL_DOCUMENT_ROOT.'/adherents/class/subscription.class.php';
257
258
			$object = new Subscription($this->db);
259
			if ($object->fetch($this->fk_object)>0) {
260
				return $object->getNomUrl(1);
261
			}
262
			else{
263
				$this->error++;
264
			}
265
		}
266
		else if ($this->action == 'MODULE_SET')
267
		{
268
			return '<i class="opacitymedium">System to track events into unalterable logs were enabled</i>';
269
		}
270
		else if ($this->action == 'MODULE_RESET')
271
		{
272
			if ($this->signature == '0000000000')
273
			{
274
				return '<i class="opacitymedium">System to track events into unalterable logs were disabled after some recording were done. We saved a special Fingerprint to track the chain as broken.</i>';
275
			}
276
			else
277
			{
278
				return '<i class="opacitymedium">System to track events into unalterable logs were disabled. This is possible because no record were done yet.</i>';
279
			}
280
		}
281
282
		return '<i class="opacitymedium">'.$langs->trans('ImpossibleToReloadObject', $this->element, $this->fk_object).'</i>';
283
284
	}
285
286
	/**
287
	 *      try to retrieve user author
288
	 */
289
	public function getUser()
290
	{
291
		global $langs, $cachedUser;
292
293
		if(empty($cachedUser))$cachedUser=array();
294
295
		if(empty($cachedUser[$this->fk_user])) {
296
			$u=new User($this->db);
297
			if($u->fetch($this->fk_user)>0) {
298
				$cachedUser[$this->fk_user] = $u;
299
			}
300
		}
301
302
		if(!empty($cachedUser[$this->fk_user])) {
303
			return $cachedUser[$this->fk_user]->getNomUrl(1);
304
		}
305
306
		return $langs->trans('ImpossibleToRetrieveUser', $this->fk_user);
307
	}
308
309
	/**
310
	 *      Populate properties of log from object data
311
	 *
312
	 *      @param		Object		$object     object to store
313
	 *      @param		string		$action     action
314
	 *      @param		string		$amounts    amounts
315
	 *      @return		int						>0 if OK, <0 if KO
316
	 */
317
	public function setObjectData(&$object, $action, $amounts)
318
	{
319
		global $langs, $user, $mysoc;
320
321
		// Generic fields
322
323
		// action
324
		$this->action = $action;
325
		// amount
326
		$this->amounts= $amounts;
327
		// date
328
		if ($object->element == 'payment' || $object->element == 'payment_supplier')
329
		{
330
			$this->date_object = $object->datepaye;
331
		}
332
		elseif ($object->element=='payment_salary')
333
		{
334
			$this->date_object = $object->datev;
335
		}
336
		elseif ($object->element == 'payment_donation' || $object->element == 'payment_various')
337
		{
338
			$this->date_object = $object->datepaid?$object->datepaid:$object->datep;
339
		}
340
		elseif ($object->element=='subscription')
341
		{
342
			$this->date_object = $object->dateh;
343
		}
344
		else {
345
			$this->date_object = $object->date;
346
		}
347
		// ref
348
		$this->ref_object = ((! empty($object->newref)) ? $object->newref : $object->ref);		// newref is set when validating a draft, ref is set in other cases
349
		// type of object
350
		$this->element = $object->element;
351
		// id of object
352
		$this->fk_object = $object->id;
353
354
355
		// Set object_data
356
		$this->object_data=new stdClass();
357
		$arrayoffieldstoexclude = array('table_element','fields','ref_previous','ref_next','origin','origin_id','oldcopy','picto','error','modelpdf','table_element_line','linkedObjectsIds','linkedObjects','fk_delivery_address');
358
359
		// Add thirdparty info
360
		if (empty($object->thirdparty) && method_exists($object, 'fetch_thirdparty')) $object->fetch_thirdparty();
361
		if (! empty($object->thirdparty))
362
		{
363
			$this->object_data->thirdparty = new stdClass();
364
365
			foreach($object->thirdparty as $key=>$value)
366
			{
367
				if (in_array($key, $arrayoffieldstoexclude)) continue;	// Discard some properties
368
				if (! in_array($key, array(
369
				'name','name_alias','ref_ext','address','zip','town','state_code','country_code','idprof1','idprof2','idprof3','idprof4','idprof5','idprof6','phone','fax','email','barcode',
370
				'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
371
				))) continue;								// Discard if not into a dedicated list
372
				if (!is_object($value)) $this->object_data->thirdparty->{$key} = $value;
373
			}
374
		}
375
376
		// Add company info
377
		if (! empty($mysoc))
378
		{
379
			$this->object_data->mycompany = new stdClass();
380
381
			foreach($mysoc as $key=>$value)
382
			{
383
				if (in_array($key, $arrayoffieldstoexclude)) continue;	// Discard some properties
384
				if (! in_array($key, array(
385
				'name','name_alias','ref_ext','address','zip','town','state_code','country_code','idprof1','idprof2','idprof3','idprof4','idprof5','idprof6','phone','fax','email','barcode',
386
				'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
387
				))) continue;									// Discard if not into a dedicated list
388
				if (!is_object($value)) $this->object_data->mycompany->{$key} = $value;
389
			}
390
		}
391
392
		// Add user info
393
		if (! empty($user))
394
		{
395
			$this->fk_user = $user->id;
396
			$this->user_fullname = $user->getFullName($langs);
397
		}
398
399
		// Field specific to object
400
		if ($this->element == 'facture')
401
		{
402
			foreach($object as $key=>$value)
403
			{
404
				if (in_array($key, $arrayoffieldstoexclude)) continue;	// Discard some properties
405
				if (! in_array($key, array(
406
				'ref','facnumber','ref_client','ref_supplier','date','datef','type','total_ht','total_tva','total_ttc','localtax1','localtax2','revenuestamp','datepointoftax','note_public','lines'
407
				))) continue;									// Discard if not into a dedicated list
408
				if ($key == 'lines')
409
				{
410
					$lineid=0;
411
					foreach($value as $tmpline)	// $tmpline is object FactureLine
412
					{
413
						$lineid++;
414
						foreach($tmpline as $keyline => $valueline)
415
						{
416
							if (! in_array($keyline, array(
417
							'ref','multicurrency_code','multicurrency_total_ht','multicurrency_total_tva','multicurrency_total_ttc','qty','product_type','vat_src_code','tva_tx','info_bits','localtax1_tx','localtax2_tx','total_ht','total_tva','total_ttc','total_localtax1','total_localtax2'
418
							))) continue;									// Discard if not into a dedicated list
419
420
							if (! is_object($this->object_data->invoiceline[$lineid])) $this->object_data->invoiceline[$lineid] = new stdClass();
421
422
							$this->object_data->invoiceline[$lineid]->{$keyline} = $valueline;
423
						}
424
					}
425
				}
426
				else if (!is_object($value)) $this->object_data->{$key} = $value;
427
			}
428
429
			if (! empty($object->newref)) $this->object_data->ref = $object->newref;
430
		}
431
		elseif ($this->element == 'invoice_supplier')
432
		{
433
			foreach($object as $key=>$value)
434
			{
435
				if (in_array($key, $arrayoffieldstoexclude)) continue;	// Discard some properties
436
				if (! in_array($key, array(
437
				'ref','facnumber','ref_client','ref_supplier','date','datef','type','total_ht','total_tva','total_ttc','localtax1','localtax2','revenuestamp','datepointoftax','note_public'
438
				))) continue;									// Discard if not into a dedicated list
439
				if (!is_object($value)) $this->object_data->{$key} = $value;
440
			}
441
442
			if (! empty($object->newref)) $this->object_data->ref = $object->newref;
443
		}
444
		elseif ($this->element == 'payment' || $this->element == 'payment_supplier' || $this->element == 'payment_donation' || $this->element == 'payment_various')
445
		{
446
			$datepayment = $object->datepaye?$object->datepaye:($object->datepaid?$object->datepaid:$object->datep);
447
			$paymenttypeid = $object->paiementid?$object->paiementid:($object->paymenttype?$object->paymenttype:$object->type_payment);
448
449
			$this->object_data->ref = $object->ref;
450
			$this->object_data->date = $datepayment;
451
			$this->object_data->type_code = dol_getIdFromCode($this->db, $paymenttypeid, 'c_paiement', 'id', 'code');
452
			$this->object_data->payment_num = ($object->num_paiement?$object->num_paiement:$object->num_payment);
453
			//$this->object_data->fk_account = $object->fk_account;
454
			$this->object_data->note = $object->note;
455
			//var_dump($this->object_data);exit;
456
457
			$totalamount=0;
458
459
			if (! is_array($object->amounts) && $object->amount)
460
			{
461
				$object->amounts=array($object->id => $object->amount);
462
			}
463
464
			$paymentpartnumber=0;
465
			foreach($object->amounts as $objid => $amount)
466
			{
467
				if (empty($amount)) continue;
468
469
				$totalamount += $amount;
470
471
				$tmpobject = null;
472
				if ($this->element == 'payment_supplier')
473
				{
474
					include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
475
					$tmpobject = new FactureFournisseur($this->db);
476
				}
477
				elseif ($this->element == 'payment')
478
				{
479
					include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
480
					$tmpobject = new Facture($this->db);
481
				}
482
				elseif ($this->element == 'payment_donation')
483
				{
484
					include_once DOL_DOCUMENT_ROOT.'/don/class/don.class.php';
485
					$tmpobject = new Don($this->db);
486
				}
487
				elseif ($this->element == 'payment_various')
488
				{
489
					include_once DOL_DOCUMENT_ROOT.'/compta/bank/class/paymentvarious.class.php';
490
					$tmpobject = new PaymentVarious($this->db);
491
				}
492
493
				if (! is_object($tmpobject))
494
				{
495
					continue;
496
				}
497
498
				$result = $tmpobject->fetch($objid);
499
500
				if ($result <= 0)
501
				{
502
					$this->error = $tmpobject->error;
503
					$this->errors = $tmpobject->errors;
504
					dol_syslog("Failed to fetch object with id ".$objid, LOG_ERR);
505
					return -1;
506
				}
507
508
				$paymentpart = new stdClass();
509
				$paymentpart->amount = $amount;
510
511
				if (! in_array($this->element, array('payment_donation', 'payment_various')))
512
				{
513
					$result = $tmpobject->fetch_thirdparty();
514
					if ($result == 0)
515
					{
516
						$this->error='Failed to fetch thirdparty for object with id '.$tmpobject->id;
517
						$this->errors[] = $this->error;
518
						dol_syslog("Failed to fetch thirdparty for object with id ".$tmpobject->id, LOG_ERR);
519
						return -1;
520
					}
521
					elseif ($result < 0)
522
					{
523
						$this->error = $tmpobject->error;
524
						$this->errors = $tmpobject->errors;
525
						return -1;
526
					}
527
528
					$paymentpart->thirdparty = new stdClass();
529
					foreach($tmpobject->thirdparty as $key=>$value)
530
					{
531
						if (in_array($key, $arrayoffieldstoexclude)) continue;	// Discard some properties
532
						if (! in_array($key, array(
533
						'name','name_alias','ref_ext','address','zip','town','state_code','country_code','idprof1','idprof2','idprof3','idprof4','idprof5','idprof6','phone','fax','email','barcode',
534
						'tva_intra', 'localtax1_assuj', 'localtax1_value', 'localtax2_assuj', 'localtax2_value', 'managers', 'capital', 'typent_code', 'forme_juridique_code', 'code_client', 'code_fournisseur'
535
						))) continue;									// Discard if not into a dedicated list
536
						if (!is_object($value)) $paymentpart->thirdparty->{$key} = $value;
537
					}
538
				}
539
540
				// Init object to avoid warnings
541
				if ($this->element == 'payment_donation') $paymentpart->donation = new stdClass();
542
				else $paymentpart->invoice = new stdClass();
543
544
				if ($this->element != 'payment_various')
545
				{
546
					foreach($tmpobject as $key=>$value)
547
					{
548
						if (in_array($key, $arrayoffieldstoexclude)) continue;	// Discard some properties
549
						if (! in_array($key, array(
550
						'ref','facnumber','ref_client','ref_supplier','date','datef','type','total_ht','total_tva','total_ttc','localtax1','localtax2','revenuestamp','datepointoftax','note_public'
551
						))) continue;									// Discard if not into a dedicated list
552
						if (!is_object($value))
553
						{
554
							if ($this->element == 'payment_donation') $paymentpart->donation->{$key} = $value;
555
							elseif ($this->element == 'payment_various') $paymentpart->various->{$key} = $value;
556
							else $paymentpart->invoice->{$key} = $value;
557
						}
558
					}
559
560
					$paymentpartnumber++;	// first payment will be 1
561
					$this->object_data->payment_part[$paymentpartnumber] = $paymentpart;
562
				}
563
			}
564
565
			$this->object_data->amount = $totalamount;
566
567
			if (! empty($object->newref)) $this->object_data->ref = $object->newref;
568
		}
569
		elseif($this->element == 'payment_salary')
570
		{
571
			$this->object_data->amounts = array($object->amount);
572
573
			if (! empty($object->newref)) $this->object_data->ref = $object->newref;
574
		}
575
		elseif($this->element == 'subscription')
576
		{
577
			foreach($object as $key=>$value)
578
			{
579
				if (in_array($key, $arrayoffieldstoexclude)) continue;	// Discard some properties
580
				if (! in_array($key, array(
581
					'id','datec','dateh','datef','fk_adherent','amount','import_key','statut','note'
582
				))) continue;									// Discard if not into a dedicated list
583
				if (!is_object($value)) $this->object_data->{$key} = $value;
584
			}
585
586
			if (! empty($object->newref)) $this->object_data->ref = $object->newref;
587
		}
588
		else 	// Generic case
589
		{
590
			foreach($object as $key=>$value)
591
			{
592
				if (in_array($key, $arrayoffieldstoexclude)) continue;	// Discard some properties
593
				if (!is_object($value)) $this->object_data->{$key} = $value;
594
			}
595
596
			if (! empty($object->newref)) $this->object_data->ref = $object->newref;
597
		}
598
599
		return 1;
600
	}
601
602
	/**
603
	 *	Get object from database
604
	 *
605
	 *	@param      int		$id       	Id of object to load
606
	 *	@return     int         			>0 if OK, <0 if KO, 0 if not found
607
	 */
608
	public function fetch($id) {
609
610
		global $langs;
611
612
		dol_syslog(get_class($this)."::fetch id=".$id, LOG_DEBUG);
613
614
		if (empty($id))
615
		{
616
			$this->error='BadParameter';
617
			return -1;
618
		}
619
620
		$langs->load("blockedlog");
621
622
		$sql = "SELECT b.rowid, b.date_creation, b.signature, b.signature_line, b.amounts, b.action, b.element, b.fk_object, b.entity,";
623
		$sql.= " b.certified, b.tms, b.fk_user, b.user_fullname, b.date_object, b.ref_object, b.object_data";
624
		$sql.= " FROM ".MAIN_DB_PREFIX."blockedlog as b";
625
		if ($id) $sql.= " WHERE b.rowid = ". $id;
626
627
		$resql=$this->db->query($sql);
628
		if ($resql)
629
		{
630
			if ($this->db->num_rows($resql))
631
			{
632
				$obj = $this->db->fetch_object($resql);
633
634
				$this->id				= $obj->rowid;
635
				$this->entity			= $obj->entity;
636
				$this->ref				= $obj->rowid;
637
638
				$this->date_creation    = $this->db->jdate($obj->date_creation);
639
				$this->tms				= $this->db->jdate($obj->tms);
640
641
				$this->amounts			= (double) $obj->amounts;
642
				$this->action			= $obj->action;
643
				$this->element			= $obj->element;
644
645
				$this->fk_object		= $obj->fk_object;
646
				$this->date_object		= $this->db->jdate($obj->date_object);
647
				$this->ref_object		= $obj->ref_object;
648
649
				$this->fk_user 			= $obj->fk_user;
650
				$this->user_fullname	= $obj->user_fullname;
651
652
				$this->object_data		= $this->dolDecodeBlockedData($obj->object_data);
653
654
				$this->signature		= $obj->signature;
655
				$this->signature_line	= $obj->signature_line;
656
				$this->certified		= ($obj->certified == 1);
657
658
				return 1;
659
			}
660
			else
661
			{
662
				$this->error=$langs->trans("RecordNotFound");
663
				return 0;
664
			}
665
		}
666
		else
667
		{
668
			$this->error=$this->db->error();
669
			return -1;
670
		}
671
672
	}
673
674
675
	/**
676
	 * Decode data
677
	 *
678
	 * @param	string	$data	Data to unserialize
679
	 * @param	string	$mode	0=unserialize, 1=json_decode
680
	 * @return 	string			Value unserialized
681
	 */
682
	public function dolDecodeBlockedData($data, $mode=0)
683
	{
684
		try
685
		{
686
			//include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
687
			//include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
688
			$aaa = unserialize($data);
689
			//$aaa = unserialize($data);
690
		}
691
		catch(Exception $e)
692
		{
693
			//print $e->getErrs);
694
		}
695
		return $aaa;
696
	}
697
698
699
	/**
700
	 *	Set block certified by authority
701
	 *
702
	 *	@return	boolean
703
	 */
704
	public function setCertified() {
705
706
		$res = $this->db->query("UPDATE ".MAIN_DB_PREFIX."blockedlog SET certified=1 WHERE rowid=".$this->id);
707
		if($res===false) return false;
708
709
		return true;
710
711
712
	}
713
714
	/**
715
	 *	Create blocked log in database.
716
	 *
717
	 *	@param	User	$user      			Object user that create
718
	 *  @param	int		$forcesignature		Force signature (for example '0000000000' when we disabled the module)
719
	 *	@return	int							<0 if KO, >0 if OK
720
	 */
721
	public function create($user, $forcesignature='') {
722
723
		global $conf,$langs,$hookmanager;
724
725
		$langs->load('blockedlog');
726
727
		$error=0;
728
729
		// Clean data
730
		$this->amounts=(double) $this->amounts;
731
732
		dol_syslog(get_class($this).'::create action='.$this->action.' fk_user='.$this->fk_user.' user_fullname='.$this->user_fullname, LOG_DEBUG);
733
734
		// Check parameters/properties
735
		if (! isset($this->amounts))	// amount can be 0 for some events (like when module is disabled)
736
		{
737
			$this->error=$langs->trans("BlockLogNeedAmountsValue");
738
			dol_syslog($this->error, LOG_WARNING);
739
			return -1;
740
		}
741
742
		if (empty($this->element)) {
743
			$this->error=$langs->trans("BlockLogNeedElement");
744
			dol_syslog($this->error, LOG_WARNING);
745
			return -2;
746
		}
747
748
		if (empty($this->action)) {
749
			$this->error=$langs->trans("BadParameterWhenCallingCreateOfBlockedLog");
750
			dol_syslog($this->error, LOG_WARNING);
751
			return -3;
752
		}
753
		if (empty($this->fk_user)) $this->user_fullname='(Anonymous)';
754
755
		$this->date_creation = dol_now();
756
757
		$this->db->begin();
758
759
		$previoushash = $this->getPreviousHash(1, 0);	// This get last record and lock database until insert is done
760
761
		$keyforsignature = $this->buildKeyForSignature();
762
763
		$this->signature_line = dol_hash($keyforsignature, '5');		// Not really usefull
764
		$this->signature = dol_hash($previoushash . $keyforsignature, '5');
765
		if ($forcesignature) $this->signature = $forcesignature;
766
		//var_dump($keyforsignature);var_dump($previoushash);var_dump($this->signature_line);var_dump($this->signature);
767
768
		$sql = "INSERT INTO ".MAIN_DB_PREFIX."blockedlog (";
769
		$sql.= " date_creation,";
770
		$sql.= " action,";
771
		$sql.= " amounts,";
772
		$sql.= " signature,";
773
		$sql.= " signature_line,";
774
		$sql.= " element,";
775
		$sql.= " fk_object,";
776
		$sql.= " date_object,";
777
		$sql.= " ref_object,";
778
		$sql.= " object_data,";
779
		$sql.= " certified,";
780
		$sql.= " fk_user,";
781
		$sql.= " user_fullname,";
782
		$sql.= " entity";
783
		$sql.= ") VALUES (";
784
		$sql.= "'".$this->db->idate($this->date_creation)."',";
785
		$sql.= "'".$this->db->escape($this->action)."',";
786
		$sql.= $this->amounts.",";
787
		$sql.= "'".$this->db->escape($this->signature)."',";
788
		$sql.= "'".$this->db->escape($this->signature_line)."',";
789
		$sql.= "'".$this->db->escape($this->element)."',";
790
		$sql.= $this->fk_object.",";
791
		$sql.= "'".$this->db->idate($this->date_object)."',";
792
		$sql.= "'".$this->db->escape($this->ref_object)."',";
793
		$sql.= "'".$this->db->escape(serialize($this->object_data))."',";
794
		$sql.= "0,";
795
		$sql.= $this->fk_user.",";
796
		$sql.= "'".$this->db->escape($this->user_fullname)."',";
797
		$sql.= ($this->entity ? $this->entity : $conf->entity);
798
		$sql.= ")";
799
800
		$res = $this->db->query($sql);
801
		if ($res)
802
		{
803
			$id = $this->db->last_insert_id(MAIN_DB_PREFIX."blockedlog");
804
805
			if ($id > 0)
806
			{
807
				$this->id = $id;
808
809
				$this->db->commit();
810
811
				return $this->id;
812
			}
813
			else
814
			{
815
				$this->db->rollback();
816
				return -2;
817
			}
818
		}
819
		else
820
		{
821
			$this->error=$this->db->error();
822
			$this->db->rollback();
823
			return -1;
824
		}
825
826
		// The commit will release the lock so we can insert nex record
827
	}
828
829
	/**
830
	 *	Check if current signature still correct compared to the value in chain
831
	 *
832
	 *	@param	string		$previoushash		If previous signature hash is known, we can provide it to avoid to make a search of it in database.
833
	 *	@return	boolean							True if OK, False if KO
834
	 */
835
	public function checkSignature($previoushash='')
836
	{
837
		if (empty($previoushash))
838
		{
839
			$previoushash = $this->getPreviousHash(0, $this->id);
840
		}
841
		// Recalculate hash
842
		$keyforsignature = $this->buildKeyForSignature();
843
844
		$signature_line = dol_hash($keyforsignature, '5');		// Not really usefull
845
		$signature = dol_hash($previoushash . $keyforsignature, '5');
846
		//var_dump($previoushash); var_dump($keyforsignature); var_dump($signature_line); var_dump($signature);
847
848
		$res = ($signature === $this->signature);
849
850
		if (!$res) {
851
			$this->error = 'Signature KO';
852
		}
853
854
		return $res;
855
	}
856
857
	/**
858
	 * Return a string for signature.
859
	 * Note: rowid of line not included as it is not a business data and this allow to make backup of a year
860
	 * and restore it into another database with different id wihtout comprimising checksums
861
	 *
862
	 * @return string		Key for signature
863
	 */
864
	private function buildKeyForSignature()
865
	{
866
		//print_r($this->object_data);
867
		return $this->date_creation.'|'.$this->action.'|'.$this->amounts.'|'.$this->ref_object.'|'.$this->date_object.'|'.$this->user_fullname.'|'.print_r($this->object_data, true);
868
	}
869
870
871
	/**
872
	 *	Get previous signature/hash in chain
873
	 *
874
	 *	@param int	$withlock		1=With a lock
875
	 *	@param int	$beforeid		ID of a record
876
	 *  @return	string				Hash of previous record (if beforeid is defined) or hash of last record (if beforeid is 0)
877
	 */
878
	 public function getPreviousHash($withlock=0, $beforeid=0)
879
	 {
880
		global $conf;
881
882
		$previoussignature='';
883
884
	 	$sql = "SELECT rowid, signature FROM ".MAIN_DB_PREFIX."blockedlog";
885
	 	$sql.= " WHERE entity=".$conf->entity;
886
	 	if ($beforeid) $sql.= " AND rowid < ".(int) $beforeid;
887
	 	$sql.=" ORDER BY rowid DESC LIMIT 1";
888
	 	$sql.=($withlock ? " FOR UPDATE ": "");
889
890
	 	$resql = $this->db->query($sql);
891
	 	if ($resql) {
892
	 		$obj = $this->db->fetch_object($resql);
893
	 		if ($obj)
894
	 		{
895
	 			$previoussignature = $obj->signature;
896
	 		}
897
	 	}
898
	 	else
899
	 	{
900
	 		dol_print_error($this->db);
901
	 		exit;
902
	 	}
903
904
	 	if (empty($previoussignature))
905
	 	{
906
			// First signature line (line 0)
907
	 		$previoussignature = $this->getSignature();
908
	 	}
909
910
	 	return $previoussignature;
911
	}
912
913
	/**
914
	 *	Return array of log objects (with criterias)
915
	 *
916
	 *	@param	string 	$element      	element to search
917
	 *	@param	int 	$fk_object		id of object to search
918
	 *	@param	int 	$limit      	max number of element, 0 for all
919
	 *	@param	string 	$sortfield     	sort field
920
	 *	@param	string 	$sortorder     	sort order
921
	 *	@param	int 	$search_fk_user id of user(s)
922
	 *	@param	int 	$search_start   start time limit
923
	 *	@param	int 	$search_end     end time limit
924
	 *  @param	string	$search_ref		search ref
925
	 *  @param	string	$search_amount	search amount
926
	 *  @param	string	$search_code	search code
927
	 *	@return	array|int				Array of object log or <0 if error
928
	 */
929
	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='')
930
	{
931
		global $conf, $cachedlogs;
932
933
		/* $cachedlogs allow fastest search */
934
		if (empty($cachedlogs)) $cachedlogs=array();
935
936
		if ($element=='all') {
937
938
	 		$sql="SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
939
	         WHERE entity=".$conf->entity;
940
941
		}
942
		else if ($element=='not_certified') {
943
			$sql="SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
944
	         WHERE entity=".$conf->entity." AND certified = 0";
945
946
		}
947
		else if ($element=='just_certified') {
948
			$sql="SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
949
	         WHERE entity=".$conf->entity." AND certified = 1";
950
951
		}
952
		else{
953
			$sql="SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog
954
	         WHERE entity=".$conf->entity." AND element='".$element."' AND fk_object=".(int) $fk_object;
955
		}
956
957
		if ($search_fk_user > 0)  $sql.=natural_search("fk_user", $search_fk_user, 2);
958
		if ($search_start > 0)    $sql.=" AND date_creation >= '".$this->db->idate($search_start)."'";
959
		if ($search_end > 0)      $sql.=" AND date_creation <= '".$this->db->idate($search_end)."'";
960
		if ($search_ref != '')    $sql.=natural_search("ref_object", $search_ref);
961
		if ($search_amount != '') $sql.=natural_search("amounts", $search_amount, 1);
962
		if ($search_code != '' && $search_code != '-1')   $sql.=natural_search("action", $search_code, 3);
963
964
		$sql.=$this->db->order($sortfield, $sortorder);
965
		$sql.=$this->db->plimit($limit+1);					// We want more, because we will stop into loop later with error if we reach max
966
967
		$res = $this->db->query($sql);
968
		if($res) {
969
970
			$results=array();
971
972
			$i = 0;
973
			while ($obj = $this->db->fetch_object($res))
974
			{
975
				$i++;
976
				if ($i > $limit)
977
				{
978
					// Too many record, we will consume too much memory
979
					return -2;
980
				}
981
982
				if (!isset($cachedlogs[$obj->rowid]))
983
				{
984
					$b=new BlockedLog($this->db);
985
					$b->fetch($obj->rowid);
986
987
					$cachedlogs[$obj->rowid] = $b;
988
				}
989
990
				$results[] = $cachedlogs[$obj->rowid];
991
			}
992
993
			return $results;
994
		}
995
996
		return -1;
997
	}
998
999
	/**
1000
	 *	Return the signature (hash) of the "genesis-block" (Block 0).
1001
	 *
1002
	 *	@return	string					Signature of genesis-block for current conf->entity
1003
	 */
1004
	public function getSignature()
1005
	{
1006
		global $db,$conf,$mysoc;
1007
1008
		if (empty($conf->global->BLOCKEDLOG_ENTITY_FINGERPRINT)) { // creation of a unique fingerprint
1009
1010
			require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
1011
			require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
1012
1013
			$fingerprint = dol_hash(print_r($mysoc,true).getRandomPassword(1), '5');
1014
1015
			dolibarr_set_const($db, 'BLOCKEDLOG_ENTITY_FINGERPRINT', $fingerprint, 'chaine',0,'Numeric Unique Fingerprint', $conf->entity);
1016
1017
			$conf->global->BLOCKEDLOG_ENTITY_FINGERPRINT=$fingerprint;
1018
		}
1019
1020
		return $conf->global->BLOCKEDLOG_ENTITY_FINGERPRINT;
1021
	}
1022
1023
1024
	/**
1025
	 * Check if module was already used or not for at least one recording.
1026
	 *
1027
	 * @param	int		$ignoresystem		Ignore system events for the test
1028
	 */
1029
	function alreadyUsed($ignoresystem=0)
1030
	{
1031
		global $conf;
1032
1033
		$result = false;
1034
1035
		$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."blockedlog";
1036
		$sql.= " WHERE entity = ".$conf->entity;
1037
		if ($ignoresystem) $sql.=" AND action not in ('MODULE_SET','MODULE_RESET')";
1038
		$sql.= $this->db->plimit(1);
1039
1040
		$res = $this->db->query($sql);
1041
		if ($res!==false)
1042
		{
1043
			$obj = $this->db->fetch_object($res);
1044
			if ($obj) $result = true;
1045
		}
1046
		else dol_print_error($this->db);
1047
1048
		dol_syslog("Module Blockedlog alreadyUsed with ignoresystem=".$ignoresystem." is ".$result);
1049
1050
		return $result;
1051
	}
1052
1053
}
1054
1055