blockedlog.class.php 34 KB

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