blockedlog.class.php 35 KB

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