api_setup.class.php 70 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152
  1. <?php
  2. /* Copyright (C) 2016 Xebax Christy <xebax@wanadoo.fr>
  3. * Copyright (C) 2016 Laurent Destailleur <eldy@users.sourceforge.net>
  4. * Copyright (C) 2017 Regis Houssin <regis.houssin@inodbox.com>
  5. * Copyright (C) 2017 Neil Orley <neil.orley@oeris.fr>
  6. * Copyright (C) 2018-2021 Frédéric France <frederic.france@netlogic.fr>
  7. * Copyright (C) 2018-2022 Thibault FOUCART <support@ptibogxiv.net>
  8. *
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 3 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  22. */
  23. use Luracast\Restler\RestException;
  24. require_once DOL_DOCUMENT_ROOT.'/main.inc.php';
  25. require_once DOL_DOCUMENT_ROOT.'/core/class/cstate.class.php';
  26. require_once DOL_DOCUMENT_ROOT.'/core/class/ccountry.class.php';
  27. require_once DOL_DOCUMENT_ROOT.'/hrm/class/establishment.class.php';
  28. /**
  29. * API class for dictionaries
  30. *
  31. * @access protected
  32. * @class DolibarrApiAccess {@requires user,external}
  33. */
  34. class Setup extends DolibarrApi
  35. {
  36. private $translations = null;
  37. /**
  38. * Constructor
  39. */
  40. public function __construct()
  41. {
  42. global $db;
  43. $this->db = $db;
  44. }
  45. /**
  46. * Get the list of ordering methods.
  47. *
  48. * @param string $sortfield Sort field
  49. * @param string $sortorder Sort order
  50. * @param int $limit Number of items per page
  51. * @param int $page Page number {@min 0}
  52. * @param int $active Payment type is active or not {@min 0} {@max 1}
  53. * @param string $sqlfilters SQL criteria to filter with. Syntax example "(t.code:=:'OrderByWWW')"
  54. *
  55. * @url GET dictionary/ordering_methods
  56. *
  57. * @return array [List of ordering methods]
  58. *
  59. * @throws RestException 400
  60. */
  61. public function getOrderingMethods($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $sqlfilters = '')
  62. {
  63. $list = array();
  64. if (!DolibarrApiAccess::$user->rights->commande->lire) {
  65. throw new RestException(401);
  66. }
  67. $sql = "SELECT rowid, code, libelle as label, module";
  68. $sql .= " FROM ".MAIN_DB_PREFIX."c_input_method as t";
  69. $sql .= " WHERE t.active = ".((int) $active);
  70. // Add sql filters
  71. if ($sqlfilters) {
  72. $errormessage = '';
  73. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  74. if ($errormessage) {
  75. throw new RestException(503, 'Error when validating parameter sqlfilters -> '.$errormessage);
  76. }
  77. }
  78. $sql .= $this->db->order($sortfield, $sortorder);
  79. if ($limit) {
  80. if ($page < 0) {
  81. $page = 0;
  82. }
  83. $offset = $limit * $page;
  84. $sql .= $this->db->plimit($limit, $offset);
  85. }
  86. $result = $this->db->query($sql);
  87. if ($result) {
  88. $num = $this->db->num_rows($result);
  89. $min = min($num, ($limit <= 0 ? $num : $limit));
  90. for ($i = 0; $i < $min; $i++) {
  91. $list[] = $this->db->fetch_object($result);
  92. }
  93. } else {
  94. throw new RestException(400, $this->db->lasterror());
  95. }
  96. return $list;
  97. }
  98. /**
  99. * Get the list of ordering origins.
  100. *
  101. * @param string $sortfield Sort field
  102. * @param string $sortorder Sort order
  103. * @param int $limit Number of items per page
  104. * @param int $page Page number {@min 0}
  105. * @param int $active Payment type is active or not {@min 0} {@max 1}
  106. * @param string $sqlfilters SQL criteria to filter with. Syntax example "(t.code:=:'OrderByWWW')"
  107. *
  108. * @url GET dictionary/ordering_origins
  109. *
  110. * @return array [List of ordering reasons]
  111. *
  112. * @throws RestException 400
  113. */
  114. public function getOrderingOrigins($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $sqlfilters = '')
  115. {
  116. $list = array();
  117. if (!DolibarrApiAccess::$user->rights->commande->lire) {
  118. throw new RestException(401);
  119. }
  120. $sql = "SELECT rowid, code, label, module";
  121. $sql .= " FROM ".MAIN_DB_PREFIX."c_input_reason as t";
  122. $sql .= " WHERE t.active = ".((int) $active);
  123. // Add sql filters
  124. if ($sqlfilters) {
  125. $errormessage = '';
  126. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  127. if ($errormessage) {
  128. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  129. }
  130. }
  131. $sql .= $this->db->order($sortfield, $sortorder);
  132. if ($limit) {
  133. if ($page < 0) {
  134. $page = 0;
  135. }
  136. $offset = $limit * $page;
  137. $sql .= $this->db->plimit($limit, $offset);
  138. }
  139. $result = $this->db->query($sql);
  140. if ($result) {
  141. $num = $this->db->num_rows($result);
  142. $min = min($num, ($limit <= 0 ? $num : $limit));
  143. for ($i = 0; $i < $min; $i++) {
  144. $list[] = $this->db->fetch_object($result);
  145. }
  146. } else {
  147. throw new RestException(400, $this->db->lasterror());
  148. }
  149. return $list;
  150. }
  151. /**
  152. * Get the list of payments types.
  153. *
  154. * @param string $sortfield Sort field
  155. * @param string $sortorder Sort order
  156. * @param int $limit Number of items per page
  157. * @param int $page Page number {@min 0}
  158. * @param int $active Payment type is active or not {@min 0} {@max 1}
  159. * @param string $sqlfilters SQL criteria to filter with. Syntax example "(t.code:=:'CHQ')"
  160. *
  161. * @url GET dictionary/payment_types
  162. *
  163. * @return array [List of payment types]
  164. *
  165. * @throws RestException 400
  166. */
  167. public function getPaymentTypes($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $sqlfilters = '')
  168. {
  169. $list = array();
  170. if (!DolibarrApiAccess::$user->rights->propal->lire && !DolibarrApiAccess::$user->rights->commande->lire && !DolibarrApiAccess::$user->rights->facture->lire) {
  171. throw new RestException(401);
  172. }
  173. $sql = "SELECT id, code, type, libelle as label, module";
  174. $sql .= " FROM ".MAIN_DB_PREFIX."c_paiement as t";
  175. $sql .= " WHERE t.entity IN (".getEntity('c_paiement').")";
  176. $sql .= " AND t.active = ".((int) $active);
  177. // Add sql filters
  178. if ($sqlfilters) {
  179. $errormessage = '';
  180. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  181. if ($errormessage) {
  182. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  183. }
  184. }
  185. $sql .= $this->db->order($sortfield, $sortorder);
  186. if ($limit) {
  187. if ($page < 0) {
  188. $page = 0;
  189. }
  190. $offset = $limit * $page;
  191. $sql .= $this->db->plimit($limit, $offset);
  192. }
  193. $result = $this->db->query($sql);
  194. if ($result) {
  195. $num = $this->db->num_rows($result);
  196. $min = min($num, ($limit <= 0 ? $num : $limit));
  197. for ($i = 0; $i < $min; $i++) {
  198. $list[] = $this->db->fetch_object($result);
  199. }
  200. } else {
  201. throw new RestException(400, $this->db->lasterror());
  202. }
  203. return $list;
  204. }
  205. /**
  206. * Get the list of states/provinces.
  207. *
  208. * The names of the states will be translated to the given language if
  209. * the $lang parameter is provided. The value of $lang must be a language
  210. * code supported by Dolibarr, for example 'en_US' or 'fr_FR'.
  211. * The returned list is sorted by state ID.
  212. *
  213. * @param string $sortfield Sort field
  214. * @param string $sortorder Sort order
  215. * @param int $limit Number of items per page
  216. * @param int $page Page number (starting from zero)
  217. * @param int $country To filter on country
  218. * @param string $filter To filter the states by name
  219. * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
  220. * @return array List of states
  221. *
  222. * @url GET dictionary/states
  223. *
  224. * @throws RestException
  225. */
  226. public function getListOfStates($sortfield = "code_departement", $sortorder = 'ASC', $limit = 100, $page = 0, $country = 0, $filter = '', $sqlfilters = '')
  227. {
  228. $list = array();
  229. // Note: The filter is not applied in the SQL request because it must
  230. // be applied to the translated names, not to the names in database.
  231. $sql = "SELECT t.rowid FROM ".MAIN_DB_PREFIX."c_departements as t";
  232. if ($country) {
  233. $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_regions as d ON t.fk_region = d.code_region";
  234. }
  235. $sql .= " WHERE 1 = 1";
  236. if ($country) {
  237. $sql .= " AND d.fk_pays = ".((int) $country);
  238. }
  239. // Add sql filters
  240. if ($sqlfilters) {
  241. $errormessage = '';
  242. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  243. if ($errormessage) {
  244. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  245. }
  246. }
  247. $sql .= $this->db->order($sortfield, $sortorder);
  248. if ($limit) {
  249. if ($page < 0) {
  250. $page = 0;
  251. }
  252. $offset = $limit * $page;
  253. $sql .= $this->db->plimit($limit, $offset);
  254. }
  255. $result = $this->db->query($sql);
  256. if ($result) {
  257. $num = $this->db->num_rows($result);
  258. $min = min($num, ($limit <= 0 ? $num : $limit));
  259. for ($i = 0; $i < $min; $i++) {
  260. $obj = $this->db->fetch_object($result);
  261. $state = new Cstate($this->db);
  262. if ($state->fetch($obj->rowid) > 0) {
  263. if (empty($filter) || stripos($state->label, $filter) !== false) {
  264. $list[] = $this->_cleanObjectDatas($state);
  265. }
  266. }
  267. }
  268. } else {
  269. throw new RestException(503, 'Error when retrieving list of states');
  270. }
  271. return $list;
  272. }
  273. /**
  274. * Get state by ID.
  275. *
  276. * @param int $id ID of state
  277. * @return array Array of cleaned object properties
  278. *
  279. * @url GET dictionary/states/{id}
  280. *
  281. * @throws RestException
  282. */
  283. public function getStateByID($id)
  284. {
  285. return $this->_fetchCstate($id, '');
  286. }
  287. /**
  288. * Get state by Code.
  289. *
  290. * @param string $code Code of state
  291. * @return array Array of cleaned object properties
  292. *
  293. * @url GET dictionary/states/byCode/{code}
  294. *
  295. * @throws RestException
  296. */
  297. public function getStateByCode($code)
  298. {
  299. return $this->_fetchCstate('', $code);
  300. }
  301. /**
  302. * Get the list of countries.
  303. *
  304. * The names of the countries will be translated to the given language if
  305. * the $lang parameter is provided. The value of $lang must be a language
  306. * code supported by Dolibarr, for example 'en_US' or 'fr_FR'.
  307. * The returned list is sorted by country ID.
  308. *
  309. * @param string $sortfield Sort field
  310. * @param string $sortorder Sort order
  311. * @param int $limit Number of items per page
  312. * @param int $page Page number (starting from zero)
  313. * @param string $filter To filter the countries by name
  314. * @param string $lang Code of the language the label of the countries must be translated to
  315. * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
  316. * @return array List of countries
  317. *
  318. * @url GET dictionary/countries
  319. *
  320. * @throws RestException
  321. */
  322. public function getListOfCountries($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $filter = '', $lang = '', $sqlfilters = '')
  323. {
  324. $list = array();
  325. // Note: The filter is not applied in the SQL request because it must
  326. // be applied to the translated names, not to the names in database.
  327. $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."c_country as t";
  328. $sql .= " WHERE 1 = 1";
  329. // Add sql filters
  330. if ($sqlfilters) {
  331. $errormessage = '';
  332. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  333. if ($errormessage) {
  334. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  335. }
  336. }
  337. $sql .= $this->db->order($sortfield, $sortorder);
  338. if ($limit) {
  339. if ($page < 0) {
  340. $page = 0;
  341. }
  342. $offset = $limit * $page;
  343. $sql .= $this->db->plimit($limit, $offset);
  344. }
  345. $result = $this->db->query($sql);
  346. if ($result) {
  347. $num = $this->db->num_rows($result);
  348. $min = min($num, ($limit <= 0 ? $num : $limit));
  349. for ($i = 0; $i < $min; $i++) {
  350. $obj = $this->db->fetch_object($result);
  351. $country = new Ccountry($this->db);
  352. if ($country->fetch($obj->rowid) > 0) {
  353. // Translate the name of the country if needed
  354. // and then apply the filter if there is one.
  355. $this->translateLabel($country, $lang, 'Country');
  356. if (empty($filter) || stripos($country->label, $filter) !== false) {
  357. $list[] = $this->_cleanObjectDatas($country);
  358. }
  359. }
  360. }
  361. } else {
  362. throw new RestException(503, 'Error when retrieving list of countries');
  363. }
  364. return $list;
  365. }
  366. /**
  367. * Get country by ID.
  368. *
  369. * @param int $id ID of country
  370. * @param string $lang Code of the language the name of the
  371. * country must be translated to
  372. * @return array Array of cleaned object properties
  373. *
  374. * @url GET dictionary/countries/{id}
  375. *
  376. * @throws RestException
  377. */
  378. public function getCountryByID($id, $lang = '')
  379. {
  380. return $this->_fetchCcountry($id, '', '', $lang);
  381. }
  382. /**
  383. * Get country by Code.
  384. *
  385. * @param string $code Code of country (2 characters)
  386. * @param string $lang Code of the language the name of the
  387. * country must be translated to
  388. * @return array Array of cleaned object properties
  389. *
  390. * @url GET dictionary/countries/byCode/{code}
  391. *
  392. * @throws RestException
  393. */
  394. public function getCountryByCode($code, $lang = '')
  395. {
  396. return $this->_fetchCcountry('', $code, '', $lang);
  397. }
  398. /**
  399. * Get country by Iso.
  400. *
  401. * @param string $iso ISO of country (3 characters)
  402. * @param string $lang Code of the language the name of the
  403. * country must be translated to
  404. * @return array Array of cleaned object properties
  405. *
  406. * @url GET dictionary/countries/byISO/{iso}
  407. *
  408. * @throws RestException
  409. */
  410. public function getCountryByISO($iso, $lang = '')
  411. {
  412. return $this->_fetchCcountry('', '', $iso, $lang);
  413. }
  414. /**
  415. * Get state.
  416. *
  417. * @param int $id ID of state
  418. * @param string $code Code of state
  419. * @return array Array of cleaned object properties
  420. *
  421. * @throws RestException
  422. */
  423. private function _fetchCstate($id, $code = '')
  424. {
  425. $state = new Cstate($this->db);
  426. $result = $state->fetch($id, $code);
  427. if ($result < 0) {
  428. throw new RestException(503, 'Error when retrieving state : '.$state->error);
  429. } elseif ($result == 0) {
  430. throw new RestException(404, 'State not found');
  431. }
  432. return $this->_cleanObjectDatas($state);
  433. }
  434. /**
  435. * Get country.
  436. *
  437. * @param int $id ID of country
  438. * @param string $code Code of country (2 characters)
  439. * @param string $iso ISO of country (3 characters)
  440. * @param string $lang Code of the language the name of the
  441. * country must be translated to
  442. * @return array Array of cleaned object properties
  443. *
  444. * @throws RestException
  445. */
  446. private function _fetchCcountry($id, $code = '', $iso = '', $lang = '')
  447. {
  448. $country = new Ccountry($this->db);
  449. $result = $country->fetch($id, $code, $iso);
  450. if ($result < 0) {
  451. throw new RestException(503, 'Error when retrieving country : '.$country->error);
  452. } elseif ($result == 0) {
  453. throw new RestException(404, 'Country not found');
  454. }
  455. $this->translateLabel($country, $lang, 'Country');
  456. return $this->_cleanObjectDatas($country);
  457. }
  458. /**
  459. * Get the list of delivery times.
  460. *
  461. * @param string $sortfield Sort field
  462. * @param string $sortorder Sort order
  463. * @param int $limit Number of items per page
  464. * @param int $page Page number {@min 0}
  465. * @param int $active Delivery times is active or not {@min 0} {@max 1}
  466. * @param string $sqlfilters SQL criteria to filter with.
  467. *
  468. * @url GET dictionary/availability
  469. *
  470. * @return array [List of availability]
  471. *
  472. * @throws RestException 400
  473. */
  474. public function getAvailability($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $sqlfilters = '')
  475. {
  476. $list = array();
  477. if (!DolibarrApiAccess::$user->rights->commande->lire) {
  478. throw new RestException(401);
  479. }
  480. $sql = "SELECT rowid, code, label";
  481. $sql .= " FROM ".MAIN_DB_PREFIX."c_availability as t";
  482. $sql .= " WHERE t.active = ".((int) $active);
  483. // Add sql filters
  484. if ($sqlfilters) {
  485. $errormessage = '';
  486. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  487. if ($errormessage) {
  488. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  489. }
  490. }
  491. $sql .= $this->db->order($sortfield, $sortorder);
  492. if ($limit) {
  493. if ($page < 0) {
  494. $page = 0;
  495. }
  496. $offset = $limit * $page;
  497. $sql .= $this->db->plimit($limit, $offset);
  498. }
  499. $result = $this->db->query($sql);
  500. if ($result) {
  501. $num = $this->db->num_rows($result);
  502. $min = min($num, ($limit <= 0 ? $num : $limit));
  503. for ($i = 0; $i < $min; $i++) {
  504. $list[] = $this->db->fetch_object($result);
  505. }
  506. } else {
  507. throw new RestException(400, $this->db->lasterror());
  508. }
  509. return $list;
  510. }
  511. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
  512. /**
  513. * Clean sensible object datas
  514. *
  515. * @param Object $object Object to clean
  516. * @return Object Object with cleaned properties
  517. */
  518. protected function _cleanObjectDatas($object)
  519. {
  520. // phpcs:enable
  521. $object = parent::_cleanObjectDatas($object);
  522. unset($object->error);
  523. unset($object->errors);
  524. return $object;
  525. }
  526. /**
  527. * Translate the name of the object to the given language.
  528. *
  529. * @param object $object Object with label to translate
  530. * @param string $lang Code of the language the name of the object must be translated to
  531. * @param string $prefix Prefix for translation key
  532. * @param array $dict Array of dictionnary for translation
  533. * @return void
  534. */
  535. private function translateLabel($object, $lang, $prefix = 'Country', $dict = array('dict'))
  536. {
  537. if (!empty($lang)) {
  538. // Load the translations if this is a new language.
  539. if ($this->translations == null || $this->translations->getDefaultLang() !== $lang) {
  540. global $conf;
  541. $this->translations = new Translate('', $conf);
  542. $this->translations->setDefaultLang($lang);
  543. $this->translations->loadLangs($dict);
  544. }
  545. if ($object->code) {
  546. $key = $prefix.$object->code;
  547. $translation = $this->translations->trans($key);
  548. if ($translation != $key) {
  549. $object->label = html_entity_decode($translation);
  550. }
  551. }
  552. }
  553. }
  554. /**
  555. * Get the list of events types.
  556. *
  557. * @param string $sortfield Sort field
  558. * @param string $sortorder Sort order
  559. * @param int $limit Number of items per page
  560. * @param int $page Page number (starting from zero)
  561. * @param string $type To filter on type of event
  562. * @param string $module To filter on module events
  563. * @param int $active Event's type is active or not {@min 0} {@max 1}
  564. * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
  565. * @return array List of events types
  566. *
  567. * @url GET dictionary/event_types
  568. *
  569. * @throws RestException
  570. */
  571. public function getListOfEventTypes($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $type = '', $module = '', $active = 1, $sqlfilters = '')
  572. {
  573. $list = array();
  574. $sql = "SELECT id, code, type, libelle as label, module";
  575. $sql .= " FROM ".MAIN_DB_PREFIX."c_actioncomm as t";
  576. $sql .= " WHERE t.active = ".((int) $active);
  577. if ($type) {
  578. $sql .= " AND t.type LIKE '%".$this->db->escape($type)."%'";
  579. }
  580. if ($module) {
  581. $sql .= " AND t.module LIKE '%".$this->db->escape($module)."%'";
  582. }
  583. // Add sql filters
  584. if ($sqlfilters) {
  585. $errormessage = '';
  586. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  587. if ($errormessage) {
  588. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  589. }
  590. }
  591. $sql .= $this->db->order($sortfield, $sortorder);
  592. if ($limit) {
  593. if ($page < 0) {
  594. $page = 0;
  595. }
  596. $offset = $limit * $page;
  597. $sql .= $this->db->plimit($limit, $offset);
  598. }
  599. $result = $this->db->query($sql);
  600. if ($result) {
  601. $num = $this->db->num_rows($result);
  602. $min = min($num, ($limit <= 0 ? $num : $limit));
  603. for ($i = 0; $i < $min; $i++) {
  604. $list[] = $this->db->fetch_object($result);
  605. }
  606. } else {
  607. throw new RestException(503, 'Error when retrieving list of events types : '.$this->db->lasterror());
  608. }
  609. return $list;
  610. }
  611. /**
  612. * Get the list of Expense Report types.
  613. *
  614. * @param string $sortfield Sort field
  615. * @param string $sortorder Sort order
  616. * @param int $limit Number of items per page
  617. * @param int $page Page number (starting from zero)
  618. * @param string $module To filter on module
  619. * @param int $active Event's type is active or not {@min 0} {@max 1}
  620. * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
  621. * @return array List of expense report types
  622. *
  623. * @url GET dictionary/expensereport_types
  624. *
  625. * @throws RestException
  626. */
  627. public function getListOfExpenseReportsTypes($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $module = '', $active = 1, $sqlfilters = '')
  628. {
  629. $list = array();
  630. $sql = "SELECT id, code, label, accountancy_code, active, module, position";
  631. $sql .= " FROM ".MAIN_DB_PREFIX."c_type_fees as t";
  632. $sql .= " WHERE t.active = ".((int) $active);
  633. if ($module) {
  634. $sql .= " AND t.module LIKE '%".$this->db->escape($module)."%'";
  635. }
  636. // Add sql filters
  637. if ($sqlfilters) {
  638. $errormessage = '';
  639. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  640. if ($errormessage) {
  641. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  642. }
  643. }
  644. $sql .= $this->db->order($sortfield, $sortorder);
  645. if ($limit) {
  646. if ($page < 0) {
  647. $page = 0;
  648. }
  649. $offset = $limit * $page;
  650. $sql .= $this->db->plimit($limit, $offset);
  651. }
  652. $result = $this->db->query($sql);
  653. if ($result) {
  654. $num = $this->db->num_rows($result);
  655. $min = min($num, ($limit <= 0 ? $num : $limit));
  656. for ($i = 0; $i < $min; $i++) {
  657. $list[] = $this->db->fetch_object($result);
  658. }
  659. } else {
  660. throw new RestException(503, 'Error when retrieving list of expense report types : '.$this->db->lasterror());
  661. }
  662. return $list;
  663. }
  664. /**
  665. * Get the list of contacts types.
  666. *
  667. * @param string $sortfield Sort field
  668. * @param string $sortorder Sort order
  669. * @param int $limit Number of items per page
  670. * @param int $page Page number (starting from zero)
  671. * @param string $type To filter on type of contact
  672. * @param string $module To filter on module contacts
  673. * @param int $active Contact's type is active or not {@min 0} {@max 1}
  674. * @param string $lang Code of the language the label of the civility must be translated to
  675. * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
  676. * @return array List of Contacts types
  677. *
  678. * @url GET dictionary/contact_types
  679. *
  680. * @throws RestException
  681. */
  682. public function getListOfContactTypes($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $type = '', $module = '', $active = 1, $lang = '', $sqlfilters = '')
  683. {
  684. $list = array();
  685. $sql = "SELECT rowid, code, element as type, libelle as label, source, module, position";
  686. $sql .= " FROM ".MAIN_DB_PREFIX."c_type_contact as t";
  687. $sql .= " WHERE t.active = ".((int) $active);
  688. if ($type) {
  689. $sql .= " AND type LIKE '%".$this->db->escape($type)."%'";
  690. }
  691. if ($module) {
  692. $sql .= " AND t.module LIKE '%".$this->db->escape($module)."%'";
  693. }
  694. // Add sql filters
  695. if ($sqlfilters) {
  696. $errormessage = '';
  697. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  698. if ($errormessage) {
  699. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  700. }
  701. }
  702. $sql .= $this->db->order($sortfield, $sortorder);
  703. if ($limit) {
  704. if ($page < 0) {
  705. $page = 0;
  706. }
  707. $offset = $limit * $page;
  708. $sql .= $this->db->plimit($limit, $offset);
  709. }
  710. $result = $this->db->query($sql);
  711. if ($result) {
  712. $num = $this->db->num_rows($result);
  713. $min = min($num, ($limit <= 0 ? $num : $limit));
  714. for ($i = 0; $i < $min; $i++) {
  715. $contact_type = $this->db->fetch_object($result);
  716. $this->translateLabel($contact_type, $lang, 'TypeContact_'.$contact_type->type.'_'.$contact_type->source.'_', array("eventorganization", "resource", "projects", "contracts", "bills", "orders", "agenda", "propal", "stocks", "supplier_proposal", "interventions", "sendings", "ticket"));
  717. $list[] = $contact_type;
  718. }
  719. } else {
  720. throw new RestException(503, 'Error when retrieving list of contacts types : '.$this->db->lasterror());
  721. }
  722. return $list;
  723. }
  724. /**
  725. * Get the list of civilities.
  726. *
  727. * @param string $sortfield Sort field
  728. * @param string $sortorder Sort order
  729. * @param int $limit Number of items per page
  730. * @param int $page Page number (starting from zero)
  731. * @param string $module To filter on module events
  732. * @param int $active Civility is active or not {@min 0} {@max 1}
  733. * @param string $lang Code of the language the label of the civility must be translated to
  734. * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
  735. * @return array List of civility types
  736. *
  737. * @url GET dictionary/civilities
  738. *
  739. * @throws RestException
  740. */
  741. public function getListOfCivilities($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $module = '', $active = 1, $lang = '', $sqlfilters = '')
  742. {
  743. $list = array();
  744. $sql = "SELECT rowid, code, label, module";
  745. $sql .= " FROM ".MAIN_DB_PREFIX."c_civility as t";
  746. $sql .= " WHERE t.active = ".((int) $active);
  747. if ($module) {
  748. $sql .= " AND t.module LIKE '%".$this->db->escape($module)."%'";
  749. }
  750. // Add sql filters
  751. if ($sqlfilters) {
  752. $errormessage = '';
  753. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  754. if ($errormessage) {
  755. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  756. }
  757. }
  758. $sql .= $this->db->order($sortfield, $sortorder);
  759. if ($limit) {
  760. if ($page < 0) {
  761. $page = 0;
  762. }
  763. $offset = $limit * $page;
  764. $sql .= $this->db->plimit($limit, $offset);
  765. }
  766. $result = $this->db->query($sql);
  767. if ($result) {
  768. $num = $this->db->num_rows($result);
  769. $min = min($num, ($limit <= 0 ? $num : $limit));
  770. for ($i = 0; $i < $min; $i++) {
  771. $civility = $this->db->fetch_object($result);
  772. $this->translateLabel($civility, $lang, 'Civility', array('dict'));
  773. $list[] = $civility;
  774. }
  775. } else {
  776. throw new RestException(503, 'Error when retrieving list of civility : '.$this->db->lasterror());
  777. }
  778. return $list;
  779. }
  780. /**
  781. * Get the list of currencies.
  782. *
  783. * @param int $multicurrency Multicurrency rates (0: no multicurrency, 1: last rate, 2: all rates) {@min 0} {@max 2}
  784. * @param string $sortfield Sort field
  785. * @param string $sortorder Sort order
  786. * @param int $limit Number of items per page
  787. * @param int $page Page number (starting from zero)
  788. * @param int $active Payment term is active or not {@min 0} {@max 1}
  789. * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
  790. * @return array List of currencies
  791. *
  792. * @url GET dictionary/currencies
  793. *
  794. * @throws RestException
  795. */
  796. public function getListOfCurrencies($multicurrency = 0, $sortfield = "code_iso", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $sqlfilters = '')
  797. {
  798. $list = array();
  799. $sql = "SELECT t.code_iso, t.label, t.unicode";
  800. if (!empty($multicurrency)) {
  801. $sql .= " , cr.date_sync, cr.rate ";
  802. }
  803. $sql .= " FROM ".MAIN_DB_PREFIX."c_currencies as t";
  804. if (!empty($multicurrency)) {
  805. $sql .= " JOIN ".MAIN_DB_PREFIX."multicurrency as m ON m.code=t.code_iso";
  806. $sql .= " JOIN ".MAIN_DB_PREFIX."multicurrency_rate as cr ON (m.rowid = cr.fk_multicurrency)";
  807. }
  808. $sql .= " WHERE t.active = ".((int) $active);
  809. if (!empty($multicurrency)) {
  810. $sql .= " AND m.entity IN (".getEntity('multicurrency').")";
  811. if (!empty($multicurrency) && $multicurrency != 2) {
  812. $sql .= " AND cr.date_sync = (SELECT MAX(cr2.date_sync) FROM ".MAIN_DB_PREFIX."multicurrency_rate AS cr2 WHERE cr2.fk_multicurrency = m.rowid)";
  813. }
  814. }
  815. // Add sql filters
  816. if ($sqlfilters) {
  817. $errormessage = '';
  818. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  819. if ($errormessage) {
  820. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  821. }
  822. }
  823. $sql .= $this->db->order($sortfield, $sortorder);
  824. if ($limit) {
  825. if ($page < 0) {
  826. $page = 0;
  827. }
  828. $offset = $limit * $page;
  829. $sql .= $this->db->plimit($limit, $offset);
  830. }
  831. $result = $this->db->query($sql);
  832. if ($result) {
  833. $num = $this->db->num_rows($result);
  834. $min = min($num, ($limit <= 0 ? $num : $limit));
  835. for ($i = 0; $i < $min; $i++) {
  836. $list[] = $this->db->fetch_object($result);
  837. }
  838. } else {
  839. throw new RestException(503, 'Error when retrieving list of currency : '.$this->db->lasterror());
  840. }
  841. return $list;
  842. }
  843. /**
  844. * Get the list of extra fields.
  845. *
  846. * @param string $sortfield Sort field
  847. * @param string $sortorder Sort order
  848. * @param string $type Type of element ('adherent', 'commande', 'thirdparty', 'facture', 'propal', 'product', ...)
  849. * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.label:like:'SO-%')"
  850. * @return array List of extra fields
  851. *
  852. * @url GET extrafields
  853. *
  854. * @throws RestException
  855. */
  856. public function getListOfExtrafields($sortfield = "t.pos", $sortorder = 'ASC', $type = '', $sqlfilters = '')
  857. {
  858. $list = array();
  859. if (!DolibarrApiAccess::$user->admin) {
  860. throw new RestException(401, 'Only an admin user can get list of extrafields');
  861. }
  862. if ($type == 'thirdparty') {
  863. $type = 'societe';
  864. }
  865. if ($type == 'contact') {
  866. $type = 'socpeople';
  867. }
  868. $sql = "SELECT t.rowid, t.name, t.label, t.type, t.size, t.elementtype, t.fieldunique, t.fieldrequired, t.param, t.pos, t.alwayseditable, t.perms, t.list, t.fielddefault, t.fieldcomputed";
  869. $sql .= " FROM ".MAIN_DB_PREFIX."extrafields as t";
  870. $sql .= " WHERE t.entity IN (".getEntity('extrafields').")";
  871. if (!empty($type)) {
  872. $sql .= " AND t.elementtype = '".$this->db->escape($type)."'";
  873. }
  874. // Add sql filters
  875. if ($sqlfilters) {
  876. $errormessage = '';
  877. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  878. if ($errormessage) {
  879. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  880. }
  881. }
  882. $sql .= $this->db->order($sortfield, $sortorder);
  883. $resql = $this->db->query($sql);
  884. if ($resql) {
  885. if ($this->db->num_rows($resql)) {
  886. while ($tab = $this->db->fetch_object($resql)) {
  887. // New usage
  888. $list[$tab->elementtype][$tab->name]['type'] = $tab->type;
  889. $list[$tab->elementtype][$tab->name]['label'] = $tab->label;
  890. $list[$tab->elementtype][$tab->name]['size'] = $tab->size;
  891. $list[$tab->elementtype][$tab->name]['elementtype'] = $tab->elementtype;
  892. $list[$tab->elementtype][$tab->name]['default'] = $tab->fielddefault;
  893. $list[$tab->elementtype][$tab->name]['computed'] = $tab->fieldcomputed;
  894. $list[$tab->elementtype][$tab->name]['unique'] = $tab->fieldunique;
  895. $list[$tab->elementtype][$tab->name]['required'] = $tab->fieldrequired;
  896. $list[$tab->elementtype][$tab->name]['param'] = ($tab->param ? jsonOrUnserialize($tab->param) : ''); // This may be a string encoded with serialise() or json_encode()
  897. $list[$tab->elementtype][$tab->name]['pos'] = $tab->pos;
  898. $list[$tab->elementtype][$tab->name]['alwayseditable'] = $tab->alwayseditable;
  899. $list[$tab->elementtype][$tab->name]['perms'] = $tab->perms;
  900. $list[$tab->elementtype][$tab->name]['list'] = $tab->list;
  901. }
  902. }
  903. } else {
  904. throw new RestException(503, 'Error when retrieving list of extra fields : '.$this->db->lasterror());
  905. }
  906. if (!count($list)) {
  907. throw new RestException(404, 'No extrafield found');
  908. }
  909. return $list;
  910. }
  911. /**
  912. * Get the list of towns.
  913. *
  914. * @param string $sortfield Sort field
  915. * @param string $sortorder Sort order
  916. * @param int $limit Number of items per page
  917. * @param int $page Page number (starting from zero)
  918. * @param string $zipcode To filter on zipcode
  919. * @param string $town To filter on city name
  920. * @param int $active Town is active or not {@min 0} {@max 1}
  921. * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
  922. * @return array List of towns
  923. *
  924. * @url GET dictionary/towns
  925. *
  926. * @throws RestException
  927. */
  928. public function getListOfTowns($sortfield = "zip,town", $sortorder = 'ASC', $limit = 100, $page = 0, $zipcode = '', $town = '', $active = 1, $sqlfilters = '')
  929. {
  930. $list = array();
  931. $sql = "SELECT rowid AS id, zip, town, fk_county, fk_pays AS fk_country";
  932. $sql .= " FROM ".MAIN_DB_PREFIX."c_ziptown as t";
  933. $sql .= " WHERE t.active = ".((int) $active);
  934. if ($zipcode) {
  935. $sql .= " AND t.zip LIKE '%".$this->db->escape($zipcode)."%'";
  936. }
  937. if ($town) {
  938. $sql .= " AND t.town LIKE '%".$this->db->escape($town)."%'";
  939. }
  940. // Add sql filters
  941. if ($sqlfilters) {
  942. $errormessage = '';
  943. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  944. if ($errormessage) {
  945. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  946. }
  947. }
  948. $sql .= $this->db->order($sortfield, $sortorder);
  949. if ($limit) {
  950. if ($page < 0) {
  951. $page = 0;
  952. }
  953. $offset = $limit * $page;
  954. $sql .= $this->db->plimit($limit, $offset);
  955. }
  956. $result = $this->db->query($sql);
  957. if ($result) {
  958. $num = $this->db->num_rows($result);
  959. $min = min($num, ($limit <= 0 ? $num : $limit));
  960. for ($i = 0; $i < $min; $i++) {
  961. $list[] = $this->db->fetch_object($result);
  962. }
  963. } else {
  964. throw new RestException(503, 'Error when retrieving list of towns : '.$this->db->lasterror());
  965. }
  966. return $list;
  967. }
  968. /**
  969. * Get the list of payments terms.
  970. *
  971. * @param string $sortfield Sort field
  972. * @param string $sortorder Sort order
  973. * @param int $limit Number of items per page
  974. * @param int $page Page number {@min 0}
  975. * @param int $active Payment term is active or not {@min 0} {@max 1}
  976. * @param string $sqlfilters SQL criteria to filter. Syntax example "(t.code:=:'CHQ')"
  977. *
  978. * @url GET dictionary/payment_terms
  979. *
  980. * @return array List of payment terms
  981. *
  982. * @throws RestException 400
  983. */
  984. public function getPaymentTerms($sortfield = "sortorder", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $sqlfilters = '')
  985. {
  986. $list = array();
  987. if (!DolibarrApiAccess::$user->rights->propal->lire && !DolibarrApiAccess::$user->rights->commande->lire && !DolibarrApiAccess::$user->rights->facture->lire) {
  988. throw new RestException(401);
  989. }
  990. $sql = "SELECT rowid as id, code, sortorder, libelle as label, libelle_facture as descr, type_cdr, nbjour, decalage, module";
  991. $sql .= " FROM ".MAIN_DB_PREFIX."c_payment_term as t";
  992. $sql .= " WHERE t.entity IN (".getEntity('c_payment_term').")";
  993. $sql .= " AND t.active = ".((int) $active);
  994. // Add sql filters
  995. if ($sqlfilters) {
  996. $errormessage = '';
  997. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  998. if ($errormessage) {
  999. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  1000. }
  1001. }
  1002. $sql .= $this->db->order($sortfield, $sortorder);
  1003. if ($limit) {
  1004. if ($page < 0) {
  1005. $page = 0;
  1006. }
  1007. $offset = $limit * $page;
  1008. $sql .= $this->db->plimit($limit, $offset);
  1009. }
  1010. $result = $this->db->query($sql);
  1011. if ($result) {
  1012. $num = $this->db->num_rows($result);
  1013. $min = min($num, ($limit <= 0 ? $num : $limit));
  1014. for ($i = 0; $i < $min; $i++) {
  1015. $list[] = $this->db->fetch_object($result);
  1016. }
  1017. } else {
  1018. throw new RestException(400, $this->db->lasterror());
  1019. }
  1020. return $list;
  1021. }
  1022. /**
  1023. * Get the list of shipping methods.
  1024. *
  1025. * @param int $limit Number of items per page
  1026. * @param int $page Page number {@min 0}
  1027. * @param int $active Shipping methodsm is active or not {@min 0} {@max 1}
  1028. * @param string $lang Code of the language the label of the method must be translated to
  1029. * @param string $sqlfilters SQL criteria to filter. Syntax example "(t.code:=:'CHQ')"
  1030. *
  1031. * @url GET dictionary/shipping_methods
  1032. *
  1033. * @return array List of shipping methods
  1034. *
  1035. * @throws RestException 400
  1036. */
  1037. public function getShippingModes($limit = 100, $page = 0, $active = 1, $lang = '', $sqlfilters = '')
  1038. {
  1039. $list = array();
  1040. $sql = "SELECT rowid as id, code, libelle as label, description, tracking, module";
  1041. $sql .= " FROM ".MAIN_DB_PREFIX."c_shipment_mode as t";
  1042. $sql .= " WHERE t.entity IN (".getEntity('c_shipment_mode').")";
  1043. $sql .= " AND t.active = ".((int) $active);
  1044. // Add sql filters
  1045. if ($sqlfilters) {
  1046. $errormessage = '';
  1047. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  1048. if ($errormessage) {
  1049. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  1050. }
  1051. }
  1052. //$sql.= $this->db->order($sortfield, $sortorder);
  1053. if ($limit) {
  1054. if ($page < 0) {
  1055. $page = 0;
  1056. }
  1057. $offset = $limit * $page;
  1058. $sql .= $this->db->plimit($limit, $offset);
  1059. }
  1060. $result = $this->db->query($sql);
  1061. if ($result) {
  1062. $num = $this->db->num_rows($result);
  1063. $min = min($num, ($limit <= 0 ? $num : $limit));
  1064. for ($i = 0; $i < $min; $i++) {
  1065. $method = $this->db->fetch_object($result);
  1066. $this->translateLabel($method, $lang, '', array('dict'));
  1067. $list[] = $method;
  1068. }
  1069. } else {
  1070. throw new RestException(400, $this->db->lasterror());
  1071. }
  1072. return $list;
  1073. }
  1074. /**
  1075. * Get the list of measuring units.
  1076. *
  1077. * @param string $sortfield Sort field
  1078. * @param string $sortorder Sort order
  1079. * @param int $limit Number of items per page
  1080. * @param int $page Page number (starting from zero)
  1081. * @param int $active Measuring unit is active or not {@min 0} {@max 1}
  1082. * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
  1083. * @return array List of measuring unit
  1084. *
  1085. * @url GET dictionary/units
  1086. *
  1087. * @throws RestException
  1088. */
  1089. public function getListOfMeasuringUnits($sortfield = "rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $sqlfilters = '')
  1090. {
  1091. $list = array();
  1092. $sql = "SELECT t.rowid, t.code, t.label,t.short_label, t.active, t.scale, t.unit_type";
  1093. $sql .= " FROM ".MAIN_DB_PREFIX."c_units as t";
  1094. $sql .= " WHERE t.active = ".((int) $active);
  1095. // Add sql filters
  1096. if ($sqlfilters) {
  1097. $errormessage = '';
  1098. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  1099. if ($errormessage) {
  1100. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  1101. }
  1102. }
  1103. $sql .= $this->db->order($sortfield, $sortorder);
  1104. if ($limit) {
  1105. if ($page < 0) {
  1106. $page = 0;
  1107. }
  1108. $offset = $limit * $page;
  1109. $sql .= $this->db->plimit($limit, $offset);
  1110. }
  1111. $result = $this->db->query($sql);
  1112. if ($result) {
  1113. $num = $this->db->num_rows($result);
  1114. $min = min($num, ($limit <= 0 ? $num : $limit));
  1115. for ($i = 0; $i < $min; $i++) {
  1116. $list[] = $this->db->fetch_object($result);
  1117. }
  1118. } else {
  1119. throw new RestException(503, 'Error when retrieving list of measuring units: '.$this->db->lasterror());
  1120. }
  1121. return $list;
  1122. }
  1123. /**
  1124. * Get the list of legal form of business.
  1125. *
  1126. * @param string $sortfield Sort field
  1127. * @param string $sortorder Sort order
  1128. * @param int $limit Number of items per page
  1129. * @param int $page Page number (starting from zero)
  1130. * @param int $country To filter on country
  1131. * @param int $active Lega form is active or not {@min 0} {@max 1}
  1132. * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
  1133. * @return array List of legal form
  1134. *
  1135. * @url GET dictionary/legal_form
  1136. *
  1137. * @throws RestException
  1138. */
  1139. public function getListOfLegalForm($sortfield = "rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $country = 0, $active = 1, $sqlfilters = '')
  1140. {
  1141. $list = array();
  1142. $sql = "SELECT t.rowid, t.code, t.fk_pays, t.libelle, t.isvatexempted, t.active, t.module, t.position";
  1143. $sql .= " FROM ".MAIN_DB_PREFIX."c_forme_juridique as t";
  1144. $sql .= " WHERE t.active = ".((int) $active);
  1145. if ($country) {
  1146. $sql .= " AND t.fk_pays = ".((int) $country);
  1147. }
  1148. // Add sql filters
  1149. if ($sqlfilters) {
  1150. $errormessage = '';
  1151. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  1152. if ($errormessage) {
  1153. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  1154. }
  1155. }
  1156. $sql .= $this->db->order($sortfield, $sortorder);
  1157. if ($limit) {
  1158. if ($page < 0) {
  1159. $page = 0;
  1160. }
  1161. $offset = $limit * $page;
  1162. $sql .= $this->db->plimit($limit, $offset);
  1163. }
  1164. $result = $this->db->query($sql);
  1165. if ($result) {
  1166. $num = $this->db->num_rows($result);
  1167. $min = min($num, ($limit <= 0 ? $num : $limit));
  1168. for ($i = 0; $i < $min; $i++) {
  1169. $list[] = $this->db->fetch_object($result);
  1170. }
  1171. } else {
  1172. throw new RestException(503, 'Error when retrieving list of legal form: '.$this->db->lasterror());
  1173. }
  1174. return $list;
  1175. }
  1176. /**
  1177. * Get the list of staff.
  1178. *
  1179. * @param string $sortfield Sort field
  1180. * @param string $sortorder Sort order
  1181. * @param int $limit Number of items per page
  1182. * @param int $page Page number (starting from zero)
  1183. * @param int $active Staff is active or not {@min 0} {@max 1}
  1184. * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
  1185. * @return array List of staff
  1186. *
  1187. * @url GET dictionary/staff
  1188. *
  1189. * @throws RestException
  1190. */
  1191. public function getListOfStaff($sortfield = "id", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $sqlfilters = '')
  1192. {
  1193. $list = array();
  1194. $sql = "SELECT t.id, t.code, t.libelle, t.active, t.module";
  1195. $sql .= " FROM ".MAIN_DB_PREFIX."c_effectif as t";
  1196. $sql .= " WHERE t.active = ".((int) $active);
  1197. // Add sql filters
  1198. if ($sqlfilters) {
  1199. $errormessage = '';
  1200. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  1201. if ($errormessage) {
  1202. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  1203. }
  1204. }
  1205. $sql .= $this->db->order($sortfield, $sortorder);
  1206. if ($limit) {
  1207. if ($page < 0) {
  1208. $page = 0;
  1209. }
  1210. $offset = $limit * $page;
  1211. $sql .= $this->db->plimit($limit, $offset);
  1212. }
  1213. $result = $this->db->query($sql);
  1214. if ($result) {
  1215. $num = $this->db->num_rows($result);
  1216. $min = min($num, ($limit <= 0 ? $num : $limit));
  1217. for ($i = 0; $i < $min; $i++) {
  1218. $list[] = $this->db->fetch_object($result);
  1219. }
  1220. } else {
  1221. throw new RestException(503, 'Error when retrieving list of staff: '.$this->db->lasterror());
  1222. }
  1223. return $list;
  1224. }
  1225. /**
  1226. * Get the list of social networks.
  1227. *
  1228. * @param string $sortfield Sort field
  1229. * @param string $sortorder Sort order
  1230. * @param int $limit Number of items per page
  1231. * @param int $page Page number (starting from zero)
  1232. * @param int $active Social network is active or not {@min 0} {@max 1}
  1233. * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
  1234. * @return array List of social networks
  1235. *
  1236. * @url GET dictionary/socialnetworks
  1237. *
  1238. * @throws RestException
  1239. */
  1240. public function getListOfsocialNetworks($sortfield = "rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $sqlfilters = '')
  1241. {
  1242. global $conf;
  1243. if (!isModEnabled('socialnetworks')) {
  1244. throw new RestException(400, 'API not available: this dictionary is not enabled by setup');
  1245. }
  1246. $list = array();
  1247. //TODO link with multicurrency module
  1248. $sql = "SELECT t.rowid, t.entity, t.code, t.label, t.url, t.icon, t.active";
  1249. $sql .= " FROM ".MAIN_DB_PREFIX."c_socialnetworks as t";
  1250. $sql .= " WHERE t.entity IN (".getEntity('c_socialnetworks').")";
  1251. $sql .= " AND t.active = ".((int) $active);
  1252. // Add sql filters
  1253. if ($sqlfilters) {
  1254. $errormessage = '';
  1255. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  1256. if ($errormessage) {
  1257. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  1258. }
  1259. }
  1260. $sql .= $this->db->order($sortfield, $sortorder);
  1261. if ($limit) {
  1262. if ($page < 0) {
  1263. $page = 0;
  1264. }
  1265. $offset = $limit * $page;
  1266. $sql .= $this->db->plimit($limit, $offset);
  1267. }
  1268. $result = $this->db->query($sql);
  1269. if ($result) {
  1270. $num = $this->db->num_rows($result);
  1271. $min = min($num, ($limit <= 0 ? $num : $limit));
  1272. for ($i = 0; $i < $min; $i++) {
  1273. $list[] = $this->db->fetch_object($result);
  1274. }
  1275. } else {
  1276. throw new RestException(503, 'Error when retrieving list of social networks: '.$this->db->lasterror());
  1277. }
  1278. return $list;
  1279. }
  1280. /**
  1281. * Get the list of tickets categories.
  1282. *
  1283. * @param string $sortfield Sort field
  1284. * @param string $sortorder Sort order
  1285. * @param int $limit Number of items per page
  1286. * @param int $page Page number (starting from zero)
  1287. * @param int $active Payment term is active or not {@min 0} {@max 1}
  1288. * @param string $lang Code of the language the label of the category must be translated to
  1289. * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
  1290. * @return array List of ticket categories
  1291. *
  1292. * @url GET dictionary/ticket_categories
  1293. *
  1294. * @throws RestException
  1295. */
  1296. public function getTicketsCategories($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $lang = '', $sqlfilters = '')
  1297. {
  1298. $list = array();
  1299. $sql = "SELECT rowid, code, pos, label, use_default, description";
  1300. $sql .= " FROM ".MAIN_DB_PREFIX."c_ticket_category as t";
  1301. $sql .= " WHERE t.entity IN (".getEntity('c_ticket_category').")";
  1302. $sql .= " AND t.active = ".((int) $active);
  1303. // Add sql filters
  1304. if ($sqlfilters) {
  1305. $errormessage = '';
  1306. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  1307. if ($errormessage) {
  1308. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  1309. }
  1310. }
  1311. $sql .= $this->db->order($sortfield, $sortorder);
  1312. if ($limit) {
  1313. if ($page < 0) {
  1314. $page = 0;
  1315. }
  1316. $offset = $limit * $page;
  1317. $sql .= $this->db->plimit($limit, $offset);
  1318. }
  1319. $result = $this->db->query($sql);
  1320. if ($result) {
  1321. $num = $this->db->num_rows($result);
  1322. $min = min($num, ($limit <= 0 ? $num : $limit));
  1323. for ($i = 0; $i < $min; $i++) {
  1324. $category = $this->db->fetch_object($result);
  1325. $this->translateLabel($category, $lang, 'TicketCategoryShort', array('ticket'));
  1326. $list[] = $category;
  1327. }
  1328. } else {
  1329. throw new RestException(503, 'Error when retrieving list of ticket categories : '.$this->db->lasterror());
  1330. }
  1331. return $list;
  1332. }
  1333. /**
  1334. * Get the list of tickets severity.
  1335. *
  1336. * @param string $sortfield Sort field
  1337. * @param string $sortorder Sort order
  1338. * @param int $limit Number of items per page
  1339. * @param int $page Page number (starting from zero)
  1340. * @param int $active Payment term is active or not {@min 0} {@max 1}
  1341. * @param string $lang Code of the language the label of the severity must be translated to
  1342. * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
  1343. * @return array List of ticket severities
  1344. *
  1345. * @url GET dictionary/ticket_severities
  1346. *
  1347. * @throws RestException
  1348. */
  1349. public function getTicketsSeverities($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $lang = '', $sqlfilters = '')
  1350. {
  1351. $list = array();
  1352. $sql = "SELECT rowid, code, pos, label, use_default, color, description";
  1353. $sql .= " FROM ".MAIN_DB_PREFIX."c_ticket_severity as t";
  1354. $sql .= " WHERE t.entity IN (".getEntity('c_ticket_severity').")";
  1355. $sql .= " AND t.active = ".((int) $active);
  1356. // Add sql filters
  1357. if ($sqlfilters) {
  1358. $errormessage = '';
  1359. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  1360. if ($errormessage) {
  1361. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  1362. }
  1363. }
  1364. $sql .= $this->db->order($sortfield, $sortorder);
  1365. if ($limit) {
  1366. if ($page < 0) {
  1367. $page = 0;
  1368. }
  1369. $offset = $limit * $page;
  1370. $sql .= $this->db->plimit($limit, $offset);
  1371. }
  1372. $result = $this->db->query($sql);
  1373. if ($result) {
  1374. $num = $this->db->num_rows($result);
  1375. $min = min($num, ($limit <= 0 ? $num : $limit));
  1376. for ($i = 0; $i < $min; $i++) {
  1377. $severity = $this->db->fetch_object($result);
  1378. $this->translateLabel($severity, $lang, 'TicketSeverityShort', array('ticket'));
  1379. $list[] = $severity;
  1380. }
  1381. } else {
  1382. throw new RestException(503, 'Error when retrieving list of ticket severities : '.$this->db->lasterror());
  1383. }
  1384. return $list;
  1385. }
  1386. /**
  1387. * Get the list of tickets types.
  1388. *
  1389. * @param string $sortfield Sort field
  1390. * @param string $sortorder Sort order
  1391. * @param int $limit Number of items per page
  1392. * @param int $page Page number (starting from zero)
  1393. * @param int $active Payment term is active or not {@min 0} {@max 1}
  1394. * @param string $lang Code of the language the label of the type must be translated to
  1395. * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.code:like:'A%') and (t.active:>=:0)"
  1396. * @return array List of ticket types
  1397. *
  1398. * @url GET dictionary/ticket_types
  1399. *
  1400. * @throws RestException
  1401. */
  1402. public function getTicketsTypes($sortfield = "code", $sortorder = 'ASC', $limit = 100, $page = 0, $active = 1, $lang = '', $sqlfilters = '')
  1403. {
  1404. $list = array();
  1405. $sql = "SELECT rowid, code, pos, label, use_default, description";
  1406. $sql .= " FROM ".MAIN_DB_PREFIX."c_ticket_type as t";
  1407. $sql .= " WHERE t.entity IN (".getEntity('c_ticket_type').")";
  1408. $sql .= " AND t.active = ".((int) $active);
  1409. // Add sql filters
  1410. if ($sqlfilters) {
  1411. $errormessage = '';
  1412. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  1413. if ($errormessage) {
  1414. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  1415. }
  1416. }
  1417. $sql .= $this->db->order($sortfield, $sortorder);
  1418. if ($limit) {
  1419. if ($page < 0) {
  1420. $page = 0;
  1421. }
  1422. $offset = $limit * $page;
  1423. $sql .= $this->db->plimit($limit, $offset);
  1424. }
  1425. $result = $this->db->query($sql);
  1426. if ($result) {
  1427. $num = $this->db->num_rows($result);
  1428. $min = min($num, ($limit <= 0 ? $num : $limit));
  1429. for ($i = 0; $i < $min; $i++) {
  1430. $type =$this->db->fetch_object($result);
  1431. $this->translateLabel($type, $lang, 'TicketTypeShort', array('ticket'));
  1432. $list[] = $type;
  1433. }
  1434. } else {
  1435. throw new RestException(503, 'Error when retrieving list of ticket types : '.$this->db->lasterror());
  1436. }
  1437. return $list;
  1438. }
  1439. /**
  1440. * Get properties of company
  1441. *
  1442. * @url GET /company
  1443. *
  1444. * @return array|mixed Mysoc object
  1445. *
  1446. * @throws RestException 403 Forbidden
  1447. */
  1448. public function getCompany()
  1449. {
  1450. global $conf, $mysoc;
  1451. if (!DolibarrApiAccess::$user->admin
  1452. && (empty($conf->global->API_LOGINS_ALLOWED_FOR_GET_COMPANY) || DolibarrApiAccess::$user->login != $conf->global->API_LOGINS_ALLOWED_FOR_GET_COMPANY)) {
  1453. throw new RestException(403, 'Error API open to admin users only or to the users with logins defined into constant API_LOGINS_ALLOWED_FOR_GET_COMPANY');
  1454. }
  1455. unset($mysoc->skype);
  1456. unset($mysoc->twitter);
  1457. unset($mysoc->facebook);
  1458. unset($mysoc->linkedin);
  1459. unset($mysoc->pays);
  1460. unset($mysoc->note);
  1461. unset($mysoc->nom);
  1462. unset($mysoc->lines);
  1463. unset($mysoc->effectif);
  1464. unset($mysoc->effectif_id);
  1465. unset($mysoc->forme_juridique_code);
  1466. unset($mysoc->forme_juridique);
  1467. unset($mysoc->mode_reglement_supplier_id);
  1468. unset($mysoc->cond_reglement_supplier_id);
  1469. unset($mysoc->transport_mode_supplier_id);
  1470. unset($mysoc->fk_prospectlevel);
  1471. unset($mysoc->total_ht);
  1472. unset($mysoc->total_tva);
  1473. unset($mysoc->total_localtax1);
  1474. unset($mysoc->total_localtax2);
  1475. unset($mysoc->total_ttc);
  1476. unset($mysoc->lastname);
  1477. unset($mysoc->firstname);
  1478. unset($mysoc->civility_id);
  1479. unset($mysoc->client);
  1480. unset($mysoc->prospect);
  1481. unset($mysoc->fournisseur);
  1482. unset($mysoc->contact_id);
  1483. unset($mysoc->fk_incoterms);
  1484. unset($mysoc->label_incoterms);
  1485. unset($mysoc->location_incoterms);
  1486. return $this->_cleanObjectDatas($mysoc);
  1487. }
  1488. /**
  1489. * Get the list of establishments.
  1490. *
  1491. * @return array List of establishments
  1492. *
  1493. * @url GET /establishments
  1494. *
  1495. * @throws RestException
  1496. */
  1497. public function getEstablishments()
  1498. {
  1499. $list = array();
  1500. $limit = 0;
  1501. $sql = "SELECT e.rowid, e.rowid as ref, e.label, e.address, e.zip, e.town, e.status";
  1502. $sql .= " FROM ".MAIN_DB_PREFIX."establishment as e";
  1503. $sql .= " WHERE e.entity IN (".getEntity('establishment').')';
  1504. // if ($type) $sql .= " AND t.type LIKE '%".$this->db->escape($type)."%'";
  1505. // if ($module) $sql .= " AND t.module LIKE '%".$this->db->escape($module)."%'";
  1506. // Add sql filters
  1507. $result = $this->db->query($sql);
  1508. if ($result) {
  1509. $num = $this->db->num_rows($result);
  1510. $min = min($num, ($limit <= 0 ? $num : $limit));
  1511. for ($i = 0; $i < $min; $i++) {
  1512. $list[] = $this->db->fetch_object($result);
  1513. }
  1514. } else {
  1515. throw new RestException(503, 'Error when retrieving list of establishments : '.$this->db->lasterror());
  1516. }
  1517. return $list;
  1518. }
  1519. /**
  1520. * Get establishment by ID.
  1521. *
  1522. * @param int $id ID of establishment
  1523. * @return array Array of cleaned object properties
  1524. *
  1525. * @url GET establishments/{id}
  1526. *
  1527. * @throws RestException
  1528. */
  1529. public function getEtablishmentByID($id)
  1530. {
  1531. $establishment = new Establishment($this->db);
  1532. $result = $establishment->fetch($id);
  1533. if ($result < 0) {
  1534. throw new RestException(503, 'Error when retrieving establishment : '.$establishment->error);
  1535. } elseif ($result == 0) {
  1536. throw new RestException(404, 'Establishment not found');
  1537. }
  1538. return $this->_cleanObjectDatas($establishment);
  1539. }
  1540. /**
  1541. * Get value of a setup variables
  1542. *
  1543. * Note that conf variables that stores security key or password hashes can't be loaded with API.
  1544. *
  1545. * @param string $constantname Name of conf variable to get
  1546. * @return array|mixed Data without useless information
  1547. *
  1548. * @url GET conf/{constantname}
  1549. *
  1550. * @throws RestException 403 Forbidden
  1551. * @throws RestException 404 Error Bad or unknown value for constantname
  1552. */
  1553. public function getConf($constantname)
  1554. {
  1555. global $conf;
  1556. if (!DolibarrApiAccess::$user->admin
  1557. && (empty($conf->global->API_LOGINS_ALLOWED_FOR_CONST_READ) || DolibarrApiAccess::$user->login != $conf->global->API_LOGINS_ALLOWED_FOR_CONST_READ)) {
  1558. throw new RestException(403, 'Error API open to admin users only or to the users with logins defined into constant API_LOGINS_ALLOWED_FOR_CONST_READ');
  1559. }
  1560. if (!preg_match('/^[a-zA-Z0-9_]+$/', $constantname) || !isset($conf->global->$constantname)) {
  1561. throw new RestException(404, 'Error Bad or unknown value for constantname');
  1562. }
  1563. if (isASecretKey($constantname)) {
  1564. throw new RestException(403, 'Forbidden. This parameter cant be read with APIs');
  1565. }
  1566. return $conf->global->$constantname;
  1567. }
  1568. /**
  1569. * Do a test of integrity for files and setup.
  1570. *
  1571. * @param string $target Can be 'local' or 'default' or Url of the signatures file to use for the test. Must be reachable by the tested Dolibarr.
  1572. * @return array Result of file and setup integrity check
  1573. *
  1574. * @url GET checkintegrity
  1575. *
  1576. * @throws RestException 403 Forbidden
  1577. * @throws RestException 404 Signature file not found
  1578. * @throws RestException 500 Technical error
  1579. * @throws RestException 503 Forbidden
  1580. */
  1581. public function getCheckIntegrity($target)
  1582. {
  1583. global $langs, $conf;
  1584. if (!DolibarrApiAccess::$user->admin
  1585. && (empty($conf->global->API_LOGINS_ALLOWED_FOR_INTEGRITY_CHECK) || DolibarrApiAccess::$user->login != $conf->global->API_LOGINS_ALLOWED_FOR_INTEGRITY_CHECK)) {
  1586. throw new RestException(403, 'Error API open to admin users only or to the users with logins defined into constant API_LOGINS_ALLOWED_FOR_INTEGRITY_CHECK');
  1587. }
  1588. require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  1589. require_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
  1590. $langs->load("admin");
  1591. $outexpectedchecksum = '';
  1592. $outcurrentchecksum = '';
  1593. // Modified or missing files
  1594. $file_list = array('missing' => array(), 'updated' => array());
  1595. // Local file to compare to
  1596. $xmlshortfile = dol_sanitizeFileName(GETPOST('xmlshortfile', 'alpha') ? GETPOST('xmlshortfile', 'alpha') : 'filelist-'.DOL_VERSION.(empty($conf->global->MAIN_FILECHECK_LOCAL_SUFFIX) ? '' : $conf->global->MAIN_FILECHECK_LOCAL_SUFFIX).'.xml'.(empty($conf->global->MAIN_FILECHECK_LOCAL_EXT) ? '' : $conf->global->MAIN_FILECHECK_LOCAL_EXT));
  1597. $xmlfile = DOL_DOCUMENT_ROOT.'/install/'.$xmlshortfile;
  1598. // Remote file to compare to
  1599. $xmlremote = ($target == 'default' ? '' : $target);
  1600. if (empty($xmlremote) && !empty($conf->global->MAIN_FILECHECK_URL)) {
  1601. $xmlremote = $conf->global->MAIN_FILECHECK_URL;
  1602. }
  1603. $param = 'MAIN_FILECHECK_URL_'.DOL_VERSION;
  1604. if (empty($xmlremote) && !empty($conf->global->$param)) {
  1605. $xmlremote = $conf->global->$param;
  1606. }
  1607. if (empty($xmlremote)) {
  1608. $xmlremote = 'https://www.dolibarr.org/files/stable/signatures/filelist-'.DOL_VERSION.'.xml';
  1609. }
  1610. if ($xmlremote && !preg_match('/^https?:\/\//i', $xmlremote)) {
  1611. $langs->load("errors");
  1612. throw new RestException(500, $langs->trans("ErrorURLMustStartWithHttp", $xmlremote));
  1613. }
  1614. if ($xmlremote && !preg_match('/\.xml$/', $xmlremote)) {
  1615. $langs->load("errors");
  1616. throw new RestException(500, $langs->trans("ErrorURLMustEndWith", $xmlremote, '.xml'));
  1617. }
  1618. if ($target == 'local') {
  1619. if (dol_is_file($xmlfile)) {
  1620. $xml = simplexml_load_file($xmlfile);
  1621. } else {
  1622. throw new RestException(500, $langs->trans('XmlNotFound').': '.$xmlfile);
  1623. }
  1624. } else {
  1625. $xmlarray = getURLContent($xmlremote, 'GET', '', 1, array(), array('http', 'https'), 0); // Accept http or https links on external remote server only. Same is used into filecheck.php.
  1626. // Return array('content'=>response,'curl_error_no'=>errno,'curl_error_msg'=>errmsg...)
  1627. if (!$xmlarray['curl_error_no'] && $xmlarray['http_code'] != '400' && $xmlarray['http_code'] != '404') {
  1628. $xmlfile = $xmlarray['content'];
  1629. //print "xmlfilestart".$xmlfile."endxmlfile";
  1630. $xml = simplexml_load_string($xmlfile, 'SimpleXMLElement', LIBXML_NOCDATA|LIBXML_NONET);
  1631. } else {
  1632. $errormsg = $langs->trans('XmlNotFound').': '.$xmlremote.' - '.$xmlarray['http_code'].(($xmlarray['http_code'] == 400 && $xmlarray['content']) ? ' '.$xmlarray['content'] : '').' '.$xmlarray['curl_error_no'].' '.$xmlarray['curl_error_msg'];
  1633. throw new RestException(500, $errormsg);
  1634. }
  1635. }
  1636. if ($xml) {
  1637. $checksumconcat = array();
  1638. $file_list = array();
  1639. $out = '';
  1640. // Forced constants
  1641. if (is_object($xml->dolibarr_constants[0])) {
  1642. $out .= load_fiche_titre($langs->trans("ForcedConstants"));
  1643. $out .= '<div class="div-table-responsive-no-min">';
  1644. $out .= '<table class="noborder">';
  1645. $out .= '<tr class="liste_titre">';
  1646. $out .= '<td>#</td>';
  1647. $out .= '<td>'.$langs->trans("Constant").'</td>';
  1648. $out .= '<td class="center">'.$langs->trans("ExpectedValue").'</td>';
  1649. $out .= '<td class="center">'.$langs->trans("Value").'</td>';
  1650. $out .= '</tr>'."\n";
  1651. $i = 0;
  1652. foreach ($xml->dolibarr_constants[0]->constant as $constant) { // $constant is a simpleXMLElement
  1653. $constname = $constant['name'];
  1654. $constvalue = (string) $constant;
  1655. $constvalue = (empty($constvalue) ? '0' : $constvalue);
  1656. // Value found
  1657. $value = '';
  1658. if ($constname && $conf->global->$constname != '') {
  1659. $value = $conf->global->$constname;
  1660. }
  1661. $valueforchecksum = (empty($value) ? '0' : $value);
  1662. $checksumconcat[] = $valueforchecksum;
  1663. $i++;
  1664. $out .= '<tr class="oddeven">';
  1665. $out .= '<td>'.$i.'</td>'."\n";
  1666. $out .= '<td>'.$constname.'</td>'."\n";
  1667. $out .= '<td class="center">'.$constvalue.'</td>'."\n";
  1668. $out .= '<td class="center">'.$valueforchecksum.'</td>'."\n";
  1669. $out .= "</tr>\n";
  1670. }
  1671. if ($i == 0) {
  1672. $out .= '<tr class="oddeven"><td colspan="4" class="opacitymedium">'.$langs->trans("None").'</td></tr>';
  1673. }
  1674. $out .= '</table>';
  1675. $out .= '</div>';
  1676. $out .= '<br>';
  1677. }
  1678. // Scan htdocs
  1679. if (is_object($xml->dolibarr_htdocs_dir[0])) {
  1680. $includecustom = (empty($xml->dolibarr_htdocs_dir[0]['includecustom']) ? 0 : $xml->dolibarr_htdocs_dir[0]['includecustom']);
  1681. // Define qualified files (must be same than into generate_filelist_xml.php and in api_setup.class.php)
  1682. $regextoinclude = '\.(php|php3|php4|php5|phtml|phps|phar|inc|css|scss|html|xml|js|json|tpl|jpg|jpeg|png|gif|ico|sql|lang|txt|yml|bak|md|mp3|mp4|wav|mkv|z|gz|zip|rar|tar|less|svg|eot|woff|woff2|ttf|manifest)$';
  1683. $regextoexclude = '('.($includecustom ? '' : 'custom|').'documents|conf|install|dejavu-fonts-ttf-.*|public\/test|sabre\/sabre\/.*\/tests|Shared\/PCLZip|nusoap\/lib\/Mail|php\/example|php\/test|geoip\/sample.*\.php|ckeditor\/samples|ckeditor\/adapters)$'; // Exclude dirs
  1684. $scanfiles = dol_dir_list(DOL_DOCUMENT_ROOT, 'files', 1, $regextoinclude, $regextoexclude);
  1685. // Fill file_list with files in signature, new files, modified files
  1686. $ret = getFilesUpdated($file_list, $xml->dolibarr_htdocs_dir[0], '', DOL_DOCUMENT_ROOT, $checksumconcat); // Fill array $file_list
  1687. // Complete with list of new files
  1688. foreach ($scanfiles as $keyfile => $valfile) {
  1689. $tmprelativefilename = preg_replace('/^'.preg_quote(DOL_DOCUMENT_ROOT, '/').'/', '', $valfile['fullname']);
  1690. if (!in_array($tmprelativefilename, $file_list['insignature'])) {
  1691. $md5newfile = @md5_file($valfile['fullname']); // Can fails if we don't have permission to open/read file
  1692. $file_list['added'][] = array('filename'=>$tmprelativefilename, 'md5'=>$md5newfile);
  1693. }
  1694. }
  1695. // Files missings
  1696. $out .= load_fiche_titre($langs->trans("FilesMissing"));
  1697. $out .= '<div class="div-table-responsive-no-min">';
  1698. $out .= '<table class="noborder">';
  1699. $out .= '<tr class="liste_titre">';
  1700. $out .= '<td>#</td>';
  1701. $out .= '<td>'.$langs->trans("Filename").'</td>';
  1702. $out .= '<td class="center">'.$langs->trans("ExpectedChecksum").'</td>';
  1703. $out .= '</tr>'."\n";
  1704. $tmpfilelist = dol_sort_array($file_list['missing'], 'filename');
  1705. if (is_array($tmpfilelist) && count($tmpfilelist)) {
  1706. $i = 0;
  1707. foreach ($tmpfilelist as $file) {
  1708. $i++;
  1709. $out .= '<tr class="oddeven">';
  1710. $out .= '<td>'.$i.'</td>'."\n";
  1711. $out .= '<td>'.$file['filename'].'</td>'."\n";
  1712. $out .= '<td class="center">'.$file['expectedmd5'].'</td>'."\n";
  1713. $out .= "</tr>\n";
  1714. }
  1715. } else {
  1716. $out .= '<tr class="oddeven"><td colspan="3" class="opacitymedium">'.$langs->trans("None").'</td></tr>';
  1717. }
  1718. $out .= '</table>';
  1719. $out .= '</div>';
  1720. $out .= '<br>';
  1721. // Files modified
  1722. $out .= load_fiche_titre($langs->trans("FilesModified"));
  1723. $totalsize = 0;
  1724. $out .= '<div class="div-table-responsive-no-min">';
  1725. $out .= '<table class="noborder">';
  1726. $out .= '<tr class="liste_titre">';
  1727. $out .= '<td>#</td>';
  1728. $out .= '<td>'.$langs->trans("Filename").'</td>';
  1729. $out .= '<td class="center">'.$langs->trans("ExpectedChecksum").'</td>';
  1730. $out .= '<td class="center">'.$langs->trans("CurrentChecksum").'</td>';
  1731. $out .= '<td class="right">'.$langs->trans("Size").'</td>';
  1732. $out .= '<td class="right">'.$langs->trans("DateModification").'</td>';
  1733. $out .= '</tr>'."\n";
  1734. $tmpfilelist2 = dol_sort_array($file_list['updated'], 'filename');
  1735. if (is_array($tmpfilelist2) && count($tmpfilelist2)) {
  1736. $i = 0;
  1737. foreach ($tmpfilelist2 as $file) {
  1738. $i++;
  1739. $out .= '<tr class="oddeven">';
  1740. $out .= '<td>'.$i.'</td>'."\n";
  1741. $out .= '<td>'.$file['filename'].'</td>'."\n";
  1742. $out .= '<td class="center">'.$file['expectedmd5'].'</td>'."\n";
  1743. $out .= '<td class="center">'.$file['md5'].'</td>'."\n";
  1744. $size = dol_filesize(DOL_DOCUMENT_ROOT.'/'.$file['filename']);
  1745. $totalsize += $size;
  1746. $out .= '<td class="right">'.dol_print_size($size).'</td>'."\n";
  1747. $out .= '<td class="right">'.dol_print_date(dol_filemtime(DOL_DOCUMENT_ROOT.'/'.$file['filename']), 'dayhour').'</td>'."\n";
  1748. $out .= "</tr>\n";
  1749. }
  1750. $out .= '<tr class="liste_total">';
  1751. $out .= '<td></td>'."\n";
  1752. $out .= '<td>'.$langs->trans("Total").'</td>'."\n";
  1753. $out .= '<td align="center"></td>'."\n";
  1754. $out .= '<td align="center"></td>'."\n";
  1755. $out .= '<td class="right">'.dol_print_size($totalsize).'</td>'."\n";
  1756. $out .= '<td class="right"></td>'."\n";
  1757. $out .= "</tr>\n";
  1758. } else {
  1759. $out .= '<tr class="oddeven"><td colspan="5" class="opacitymedium">'.$langs->trans("None").'</td></tr>';
  1760. }
  1761. $out .= '</table>';
  1762. $out .= '</div>';
  1763. $out .= '<br>';
  1764. // Files added
  1765. $out .= load_fiche_titre($langs->trans("FilesAdded"));
  1766. $totalsize = 0;
  1767. $out .= '<div class="div-table-responsive-no-min">';
  1768. $out .= '<table class="noborder">';
  1769. $out .= '<tr class="liste_titre">';
  1770. $out .= '<td>#</td>';
  1771. $out .= '<td>'.$langs->trans("Filename").'</td>';
  1772. $out .= '<td class="center">'.$langs->trans("ExpectedChecksum").'</td>';
  1773. $out .= '<td class="center">'.$langs->trans("CurrentChecksum").'</td>';
  1774. $out .= '<td class="right">'.$langs->trans("Size").'</td>';
  1775. $out .= '<td class="right">'.$langs->trans("DateModification").'</td>';
  1776. $out .= '</tr>'."\n";
  1777. $tmpfilelist3 = dol_sort_array($file_list['added'], 'filename');
  1778. if (is_array($tmpfilelist3) && count($tmpfilelist3)) {
  1779. $i = 0;
  1780. foreach ($tmpfilelist3 as $file) {
  1781. $i++;
  1782. $out .= '<tr class="oddeven">';
  1783. $out .= '<td>'.$i.'</td>'."\n";
  1784. $out .= '<td>'.$file['filename'].'</td>'."\n";
  1785. $out .= '<td class="center">'.$file['expectedmd5'].'</td>'."\n";
  1786. $out .= '<td class="center">'.$file['md5'].'</td>'."\n";
  1787. $size = dol_filesize(DOL_DOCUMENT_ROOT.'/'.$file['filename']);
  1788. $totalsize += $size;
  1789. $out .= '<td class="right">'.dol_print_size($size).'</td>'."\n";
  1790. $out .= '<td class="right">'.dol_print_date(dol_filemtime(DOL_DOCUMENT_ROOT.'/'.$file['filename']), 'dayhour').'</td>'."\n";
  1791. $out .= "</tr>\n";
  1792. }
  1793. $out .= '<tr class="liste_total">';
  1794. $out .= '<td></td>'."\n";
  1795. $out .= '<td>'.$langs->trans("Total").'</td>'."\n";
  1796. $out .= '<td align="center"></td>'."\n";
  1797. $out .= '<td align="center"></td>'."\n";
  1798. $out .= '<td class="right">'.dol_print_size($totalsize).'</td>'."\n";
  1799. $out .= '<td class="right"></td>'."\n";
  1800. $out .= "</tr>\n";
  1801. } else {
  1802. $out .= '<tr class="oddeven"><td colspan="5" class="opacitymedium">'.$langs->trans("None").'</td></tr>';
  1803. }
  1804. $out .= '</table>';
  1805. $out .= '</div>';
  1806. // Show warning
  1807. if (empty($tmpfilelist) && empty($tmpfilelist2) && empty($tmpfilelist3)) {
  1808. //setEventMessages($langs->trans("FileIntegrityIsStrictlyConformedWithReference"), null, 'mesgs');
  1809. } else {
  1810. //setEventMessages($langs->trans("FileIntegritySomeFilesWereRemovedOrModified"), null, 'warnings');
  1811. }
  1812. } else {
  1813. throw new RestException(500, 'Error: Failed to found dolibarr_htdocs_dir into XML file '.$xmlfile);
  1814. }
  1815. // Scan scripts
  1816. asort($checksumconcat); // Sort list of checksum
  1817. $checksumget = md5(join(',', $checksumconcat));
  1818. $checksumtoget = trim((string) $xml->dolibarr_htdocs_dir_checksum);
  1819. $outexpectedchecksum = ($checksumtoget ? $checksumtoget : $langs->trans("Unknown"));
  1820. if ($checksumget == $checksumtoget) {
  1821. if (count($file_list['added'])) {
  1822. $resultcode = 'warning';
  1823. $resultcomment = 'FileIntegrityIsOkButFilesWereAdded';
  1824. //$outcurrentchecksum = $checksumget.' - <span class="'.$resultcode.'">'.$langs->trans("FileIntegrityIsOkButFilesWereAdded").'</span>';
  1825. $outcurrentchecksum = $checksumget;
  1826. } else {
  1827. $resultcode = 'ok';
  1828. $resultcomment = 'Success';
  1829. //$outcurrentchecksum = '<span class="'.$resultcode.'">'.$checksumget.'</span>';
  1830. $outcurrentchecksum = $checksumget;
  1831. }
  1832. } else {
  1833. $resultcode = 'error';
  1834. $resultcomment = 'Error';
  1835. //$outcurrentchecksum = '<span class="'.$resultcode.'">'.$checksumget.'</span>';
  1836. $outcurrentchecksum = $checksumget;
  1837. }
  1838. } else {
  1839. throw new RestException(404, 'No signature file known');
  1840. }
  1841. return array('resultcode'=>$resultcode, 'resultcomment'=>$resultcomment, 'expectedchecksum'=> $outexpectedchecksum, 'currentchecksum'=> $outcurrentchecksum, 'out'=>$out);
  1842. }
  1843. /**
  1844. * Get list of enabled modules
  1845. *
  1846. * @url GET /modules
  1847. *
  1848. * @return array|mixed Data without useless information
  1849. *
  1850. * @throws RestException 403 Forbidden
  1851. */
  1852. public function getModules()
  1853. {
  1854. global $conf;
  1855. if (!DolibarrApiAccess::$user->admin
  1856. && (empty($conf->global->API_LOGINS_ALLOWED_FOR_GET_MODULES) || DolibarrApiAccess::$user->login != $conf->global->API_LOGINS_ALLOWED_FOR_GET_MODULES)) {
  1857. throw new RestException(403, 'Error API open to admin users only or to the users with logins defined into constant API_LOGINS_ALLOWED_FOR_GET_MODULES');
  1858. }
  1859. sort($conf->modules);
  1860. return $this->_cleanObjectDatas($conf->modules);
  1861. }
  1862. }