api_orders.class.php 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109
  1. <?php
  2. /* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
  3. * Copyright (C) 2016 Laurent Destailleur <eldy@users.sourceforge.net>
  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. use Luracast\Restler\RestException;
  19. require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
  20. /**
  21. * API class for orders
  22. *
  23. * @access protected
  24. * @class DolibarrApiAccess {@requires user,external}
  25. */
  26. class Orders extends DolibarrApi
  27. {
  28. /**
  29. * @var array $FIELDS Mandatory fields, checked when create and update object
  30. */
  31. static $FIELDS = array(
  32. 'socid',
  33. 'date'
  34. );
  35. /**
  36. * @var Commande $commande {@type Commande}
  37. */
  38. public $commande;
  39. /**
  40. * Constructor
  41. */
  42. public function __construct()
  43. {
  44. global $db, $conf;
  45. $this->db = $db;
  46. $this->commande = new Commande($this->db);
  47. }
  48. /**
  49. * Get properties of an order object by id
  50. *
  51. * Return an array with order informations
  52. *
  53. * @param int $id ID of order
  54. * @param int $contact_list 0: Returned array of contacts/addresses contains all properties, 1: Return array contains just id
  55. * @return array|mixed data without useless information
  56. *
  57. * @throws RestException
  58. */
  59. public function get($id, $contact_list = 1)
  60. {
  61. return $this->_fetch($id, '', '', $contact_list);
  62. }
  63. /**
  64. * Get properties of an order object by ref
  65. *
  66. * Return an array with order informations
  67. *
  68. * @param string $ref Ref of object
  69. * @param int $contact_list 0: Returned array of contacts/addresses contains all properties, 1: Return array contains just id
  70. * @return array|mixed data without useless information
  71. *
  72. * @url GET ref/{ref}
  73. *
  74. * @throws RestException
  75. */
  76. public function getByRef($ref, $contact_list = 1)
  77. {
  78. return $this->_fetch('', $ref, '', $contact_list);
  79. }
  80. /**
  81. * Get properties of an order object by ref_ext
  82. *
  83. * Return an array with order informations
  84. *
  85. * @param string $ref_ext External reference of object
  86. * @param int $contact_list 0: Returned array of contacts/addresses contains all properties, 1: Return array contains just id
  87. * @return array|mixed data without useless information
  88. *
  89. * @url GET ref_ext/{ref_ext}
  90. *
  91. * @throws RestException
  92. */
  93. public function getByRefExt($ref_ext, $contact_list = 1)
  94. {
  95. return $this->_fetch('', '', $ref_ext, $contact_list);
  96. }
  97. /**
  98. * Get properties of an order object
  99. *
  100. * Return an array with order informations
  101. *
  102. * @param int $id ID of order
  103. * @param string $ref Ref of object
  104. * @param string $ref_ext External reference of object
  105. * @param int $contact_list 0: Returned array of contacts/addresses contains all properties, 1: Return array contains just id
  106. * @return Object Object with cleaned properties
  107. *
  108. * @throws RestException
  109. */
  110. private function _fetch($id, $ref = '', $ref_ext = '', $contact_list = 1)
  111. {
  112. if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
  113. throw new RestException(401);
  114. }
  115. $result = $this->commande->fetch($id, $ref, $ref_ext);
  116. if (!$result) {
  117. throw new RestException(404, 'Order not found');
  118. }
  119. if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
  120. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  121. }
  122. // Add external contacts ids
  123. $tmparray = $this->commande->liste_contact(-1, 'external', $contact_list);
  124. if (is_array($tmparray)) {
  125. $this->commande->contacts_ids = $tmparray;
  126. }
  127. $this->commande->fetchObjectLinked();
  128. // Add online_payment_url, cf #20477
  129. require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
  130. $this->commande->online_payment_url = getOnlinePaymentUrl(0, 'order', $this->commande->ref);
  131. return $this->_cleanObjectDatas($this->commande);
  132. }
  133. /**
  134. * List orders
  135. *
  136. * Get a list of orders
  137. *
  138. * @param string $sortfield Sort field
  139. * @param string $sortorder Sort order
  140. * @param int $limit Limit for list
  141. * @param int $page Page number
  142. * @param string $thirdparty_ids Thirdparty ids to filter orders of (example '1' or '1,2,3') {@pattern /^[0-9,]*$/i}
  143. * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
  144. * @return array Array of order objects
  145. *
  146. * @throws RestException 404 Not found
  147. * @throws RestException 503 Error
  148. */
  149. public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $thirdparty_ids = '', $sqlfilters = '')
  150. {
  151. global $db, $conf;
  152. if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
  153. throw new RestException(401);
  154. }
  155. $obj_ret = array();
  156. // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
  157. $socids = DolibarrApiAccess::$user->socid ? DolibarrApiAccess::$user->socid : $thirdparty_ids;
  158. // If the internal user must only see his customers, force searching by him
  159. $search_sale = 0;
  160. if (!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) {
  161. $search_sale = DolibarrApiAccess::$user->id;
  162. }
  163. $sql = "SELECT t.rowid";
  164. if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) {
  165. $sql .= ", sc.fk_soc, sc.fk_user"; // We need these fields in order to filter by sale (including the case where the user can only see his prospects)
  166. }
  167. $sql .= " FROM ".MAIN_DB_PREFIX."commande AS t LEFT JOIN ".MAIN_DB_PREFIX."commande_extrafields AS ef ON (ef.fk_object = t.rowid)"; // Modification VMR Global Solutions to include extrafields as search parameters in the API GET call, so we will be able to filter on extrafields
  168. if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) {
  169. $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; // We need this table joined to the select in order to filter by sale
  170. }
  171. $sql .= ' WHERE t.entity IN ('.getEntity('commande').')';
  172. if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) {
  173. $sql .= " AND t.fk_soc = sc.fk_soc";
  174. }
  175. if ($socids) {
  176. $sql .= " AND t.fk_soc IN (".$this->db->sanitize($socids).")";
  177. }
  178. if ($search_sale > 0) {
  179. $sql .= " AND t.rowid = sc.fk_soc"; // Join for the needed table to filter by sale
  180. }
  181. // Insert sale filter
  182. if ($search_sale > 0) {
  183. $sql .= " AND sc.fk_user = ".((int) $search_sale);
  184. }
  185. // Add sql filters
  186. if ($sqlfilters) {
  187. $errormessage = '';
  188. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  189. if ($errormessage) {
  190. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  191. }
  192. }
  193. $sql .= $this->db->order($sortfield, $sortorder);
  194. if ($limit) {
  195. if ($page < 0) {
  196. $page = 0;
  197. }
  198. $offset = $limit * $page;
  199. $sql .= $this->db->plimit($limit + 1, $offset);
  200. }
  201. dol_syslog("API Rest request");
  202. $result = $this->db->query($sql);
  203. if ($result) {
  204. $num = $this->db->num_rows($result);
  205. $min = min($num, ($limit <= 0 ? $num : $limit));
  206. $i = 0;
  207. while ($i < $min) {
  208. $obj = $this->db->fetch_object($result);
  209. $commande_static = new Commande($this->db);
  210. if ($commande_static->fetch($obj->rowid)) {
  211. // Add external contacts ids
  212. $tmparray = $commande_static->liste_contact(-1, 'external', 1);
  213. if (is_array($tmparray)) {
  214. $commande_static->contacts_ids = $tmparray;
  215. }
  216. // Add online_payment_url, cf #20477
  217. require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
  218. $commande_static->online_payment_url = getOnlinePaymentUrl(0, 'order', $commande_static->ref);
  219. $obj_ret[] = $this->_cleanObjectDatas($commande_static);
  220. }
  221. $i++;
  222. }
  223. } else {
  224. throw new RestException(503, 'Error when retrieve commande list : '.$this->db->lasterror());
  225. }
  226. if (!count($obj_ret)) {
  227. throw new RestException(404, 'No order found');
  228. }
  229. return $obj_ret;
  230. }
  231. /**
  232. * Create a sale order
  233. *
  234. * Exemple: { "socid": 2, "date": 1595196000, "type": 0, "lines": [{ "fk_product": 2, "qty": 1 }] }
  235. *
  236. * @param array $request_data Request data
  237. * @return int ID of order
  238. */
  239. public function post($request_data = null)
  240. {
  241. if (!DolibarrApiAccess::$user->rights->commande->creer) {
  242. throw new RestException(401, "Insuffisant rights");
  243. }
  244. // Check mandatory fields
  245. $result = $this->_validate($request_data);
  246. foreach ($request_data as $field => $value) {
  247. $this->commande->$field = $value;
  248. }
  249. /*if (isset($request_data["lines"])) {
  250. $lines = array();
  251. foreach ($request_data["lines"] as $line) {
  252. array_push($lines, (object) $line);
  253. }
  254. $this->commande->lines = $lines;
  255. }*/
  256. if ($this->commande->create(DolibarrApiAccess::$user) < 0) {
  257. throw new RestException(500, "Error creating order", array_merge(array($this->commande->error), $this->commande->errors));
  258. }
  259. return $this->commande->id;
  260. }
  261. /**
  262. * Get lines of an order
  263. *
  264. * @param int $id Id of order
  265. *
  266. * @url GET {id}/lines
  267. *
  268. * @return array
  269. */
  270. public function getLines($id)
  271. {
  272. if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
  273. throw new RestException(401);
  274. }
  275. $result = $this->commande->fetch($id);
  276. if (!$result) {
  277. throw new RestException(404, 'Order not found');
  278. }
  279. if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
  280. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  281. }
  282. $this->commande->getLinesArray();
  283. $result = array();
  284. foreach ($this->commande->lines as $line) {
  285. array_push($result, $this->_cleanObjectDatas($line));
  286. }
  287. return $result;
  288. }
  289. /**
  290. * Add a line to given order
  291. *
  292. * @param int $id Id of order to update
  293. * @param array $request_data OrderLine data
  294. *
  295. * @url POST {id}/lines
  296. *
  297. * @return int
  298. */
  299. public function postLine($id, $request_data = null)
  300. {
  301. if (!DolibarrApiAccess::$user->rights->commande->creer) {
  302. throw new RestException(401);
  303. }
  304. $result = $this->commande->fetch($id);
  305. if (!$result) {
  306. throw new RestException(404, 'Order not found');
  307. }
  308. if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
  309. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  310. }
  311. $request_data = (object) $request_data;
  312. $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
  313. $request_data->label = sanitizeVal($request_data->label);
  314. $updateRes = $this->commande->addline(
  315. $request_data->desc,
  316. $request_data->subprice,
  317. $request_data->qty,
  318. $request_data->tva_tx,
  319. $request_data->localtax1_tx,
  320. $request_data->localtax2_tx,
  321. $request_data->fk_product,
  322. $request_data->remise_percent,
  323. $request_data->info_bits,
  324. $request_data->fk_remise_except,
  325. $request_data->price_base_type ? $request_data->price_base_type : 'HT',
  326. $request_data->subprice,
  327. $request_data->date_start,
  328. $request_data->date_end,
  329. $request_data->product_type,
  330. $request_data->rang,
  331. $request_data->special_code,
  332. $request_data->fk_parent_line,
  333. $request_data->fk_fournprice,
  334. $request_data->pa_ht,
  335. $request_data->label,
  336. $request_data->array_options,
  337. $request_data->fk_unit,
  338. $request_data->origin,
  339. $request_data->origin_id,
  340. $request_data->multicurrency_subprice,
  341. $request_data->ref_ext
  342. );
  343. if ($updateRes > 0) {
  344. return $updateRes;
  345. } else {
  346. throw new RestException(400, $this->commande->error);
  347. }
  348. }
  349. /**
  350. * Update a line to given order
  351. *
  352. * @param int $id Id of order to update
  353. * @param int $lineid Id of line to update
  354. * @param array $request_data OrderLine data
  355. * @return Object|false Object with cleaned properties
  356. *
  357. * @url PUT {id}/lines/{lineid}
  358. */
  359. public function putLine($id, $lineid, $request_data = null)
  360. {
  361. if (!DolibarrApiAccess::$user->rights->commande->creer) {
  362. throw new RestException(401);
  363. }
  364. $result = $this->commande->fetch($id);
  365. if (!$result) {
  366. throw new RestException(404, 'Order not found');
  367. }
  368. if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
  369. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  370. }
  371. $request_data = (object) $request_data;
  372. $request_data->desc = sanitizeVal($request_data->desc, 'restricthtml');
  373. $request_data->label = sanitizeVal($request_data->label);
  374. $updateRes = $this->commande->updateline(
  375. $lineid,
  376. $request_data->desc,
  377. $request_data->subprice,
  378. $request_data->qty,
  379. $request_data->remise_percent,
  380. $request_data->tva_tx,
  381. $request_data->localtax1_tx,
  382. $request_data->localtax2_tx,
  383. $request_data->price_base_type ? $request_data->price_base_type : 'HT',
  384. $request_data->info_bits,
  385. $request_data->date_start,
  386. $request_data->date_end,
  387. $request_data->product_type,
  388. $request_data->fk_parent_line,
  389. 0,
  390. $request_data->fk_fournprice,
  391. $request_data->pa_ht,
  392. $request_data->label,
  393. $request_data->special_code,
  394. $request_data->array_options,
  395. $request_data->fk_unit,
  396. $request_data->multicurrency_subprice,
  397. 0,
  398. $request_data->ref_ext,
  399. $request_data->rang
  400. );
  401. if ($updateRes > 0) {
  402. $result = $this->get($id);
  403. unset($result->line);
  404. return $this->_cleanObjectDatas($result);
  405. }
  406. return false;
  407. }
  408. /**
  409. * Delete a line of a given order
  410. *
  411. * @param int $id Id of order to update
  412. * @param int $lineid Id of line to delete
  413. * @return Object Object with cleaned properties
  414. *
  415. * @url DELETE {id}/lines/{lineid}
  416. *
  417. * @throws RestException 401
  418. * @throws RestException 404
  419. */
  420. public function deleteLine($id, $lineid)
  421. {
  422. if (!DolibarrApiAccess::$user->rights->commande->creer) {
  423. throw new RestException(401);
  424. }
  425. $result = $this->commande->fetch($id);
  426. if (!$result) {
  427. throw new RestException(404, 'Order not found');
  428. }
  429. if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
  430. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  431. }
  432. $updateRes = $this->commande->deleteline(DolibarrApiAccess::$user, $lineid, $id);
  433. if ($updateRes > 0) {
  434. return $this->get($id);
  435. } else {
  436. throw new RestException(405, $this->commande->error);
  437. }
  438. }
  439. /**
  440. * Get contacts of given order
  441. *
  442. * Return an array with contact informations
  443. *
  444. * @param int $id ID of order
  445. * @param string $type Type of the contact (BILLING, SHIPPING, CUSTOMER)
  446. * @return Object Object with cleaned properties
  447. *
  448. * @url GET {id}/contacts
  449. *
  450. * @throws RestException
  451. */
  452. public function getContacts($id, $type = '')
  453. {
  454. if (!DolibarrApiAccess::$user->hasRight('commande', 'lire')) {
  455. throw new RestException(401);
  456. }
  457. $result = $this->commande->fetch($id);
  458. if (!$result) {
  459. throw new RestException(404, 'Order not found');
  460. }
  461. if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
  462. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  463. }
  464. $contacts = $this->commande->liste_contact(-1, 'external', 0, $type);
  465. return $this->_cleanObjectDatas($contacts);
  466. }
  467. /**
  468. * Add a contact type of given order
  469. *
  470. * @param int $id Id of order to update
  471. * @param int $contactid Id of contact to add
  472. * @param string $type Type of the contact (BILLING, SHIPPING, CUSTOMER)
  473. * @return array
  474. *
  475. * @url POST {id}/contact/{contactid}/{type}
  476. *
  477. * @throws RestException 401
  478. * @throws RestException 404
  479. */
  480. public function postContact($id, $contactid, $type)
  481. {
  482. if (!DolibarrApiAccess::$user->rights->commande->creer) {
  483. throw new RestException(401);
  484. }
  485. $result = $this->commande->fetch($id);
  486. if (!$result) {
  487. throw new RestException(404, 'Order not found');
  488. }
  489. if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
  490. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  491. }
  492. $result = $this->commande->add_contact($contactid, $type, 'external');
  493. if ($result < 0) {
  494. throw new RestException(500, 'Error when added the contact');
  495. }
  496. if ($result == 0) {
  497. throw new RestException(304, 'contact already added');
  498. }
  499. return array(
  500. 'success' => array(
  501. 'code' => 200,
  502. 'message' => 'Contact linked to the order'
  503. )
  504. );
  505. }
  506. /**
  507. * Unlink a contact type of given order
  508. *
  509. * @param int $id Id of order to update
  510. * @param int $contactid Id of contact
  511. * @param string $type Type of the contact (BILLING, SHIPPING, CUSTOMER).
  512. *
  513. * @url DELETE {id}/contact/{contactid}/{type}
  514. *
  515. * @return array
  516. *
  517. * @throws RestException 401
  518. * @throws RestException 404
  519. * @throws RestException 500 System error
  520. */
  521. public function deleteContact($id, $contactid, $type)
  522. {
  523. if (!DolibarrApiAccess::$user->rights->commande->creer) {
  524. throw new RestException(401);
  525. }
  526. $result = $this->commande->fetch($id);
  527. if (!$result) {
  528. throw new RestException(404, 'Order not found');
  529. }
  530. if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
  531. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  532. }
  533. $contacts = $this->commande->liste_contact();
  534. foreach ($contacts as $contact) {
  535. if ($contact['id'] == $contactid && $contact['code'] == $type) {
  536. $result = $this->commande->delete_contact($contact['rowid']);
  537. if (!$result) {
  538. throw new RestException(500, 'Error when deleted the contact');
  539. }
  540. }
  541. }
  542. return array(
  543. 'success' => array(
  544. 'code' => 200,
  545. 'message' => 'Contact unlinked from order'
  546. )
  547. );
  548. }
  549. /**
  550. * Update order general fields (won't touch lines of order)
  551. *
  552. * @param int $id Id of order to update
  553. * @param array $request_data Datas
  554. * @return Object Object with cleaned properties
  555. */
  556. public function put($id, $request_data = null)
  557. {
  558. if (!DolibarrApiAccess::$user->rights->commande->creer) {
  559. throw new RestException(401);
  560. }
  561. $result = $this->commande->fetch($id);
  562. if (!$result) {
  563. throw new RestException(404, 'Order not found');
  564. }
  565. if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
  566. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  567. }
  568. foreach ($request_data as $field => $value) {
  569. if ($field == 'id') {
  570. continue;
  571. }
  572. $this->commande->$field = $value;
  573. }
  574. // Update availability
  575. if (!empty($this->commande->availability_id)) {
  576. if ($this->commande->availability($this->commande->availability_id) < 0) {
  577. throw new RestException(400, 'Error while updating availability');
  578. }
  579. }
  580. if ($this->commande->update(DolibarrApiAccess::$user) > 0) {
  581. return $this->get($id);
  582. } else {
  583. throw new RestException(500, $this->commande->error);
  584. }
  585. }
  586. /**
  587. * Delete order
  588. *
  589. * @param int $id Order ID
  590. * @return array
  591. */
  592. public function delete($id)
  593. {
  594. if (!DolibarrApiAccess::$user->rights->commande->supprimer) {
  595. throw new RestException(401);
  596. }
  597. $result = $this->commande->fetch($id);
  598. if (!$result) {
  599. throw new RestException(404, 'Order not found');
  600. }
  601. if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
  602. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  603. }
  604. if (!$this->commande->delete(DolibarrApiAccess::$user)) {
  605. throw new RestException(500, 'Error when deleting order : '.$this->commande->error);
  606. }
  607. return array(
  608. 'success' => array(
  609. 'code' => 200,
  610. 'message' => 'Order deleted'
  611. )
  612. );
  613. }
  614. /**
  615. * Validate an order
  616. *
  617. * If you get a bad value for param notrigger check, provide this in body
  618. * {
  619. * "idwarehouse": 0,
  620. * "notrigger": 0
  621. * }
  622. *
  623. * @param int $id Order ID
  624. * @param int $idwarehouse Warehouse ID
  625. * @param int $notrigger 1=Does not execute triggers, 0= execute triggers
  626. * @return Object Object with cleaned properties
  627. *
  628. * @url POST {id}/validate
  629. *
  630. * @throws RestException 304
  631. * @throws RestException 401
  632. * @throws RestException 404
  633. * @throws RestException 500 System error
  634. *
  635. */
  636. public function validate($id, $idwarehouse = 0, $notrigger = 0)
  637. {
  638. if (!DolibarrApiAccess::$user->rights->commande->creer) {
  639. throw new RestException(401);
  640. }
  641. $result = $this->commande->fetch($id);
  642. if (!$result) {
  643. throw new RestException(404, 'Order not found');
  644. }
  645. $result = $this->commande->fetch_thirdparty(); // do not check result, as failure is not fatal (used only for mail notification substitutes)
  646. if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
  647. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  648. }
  649. $result = $this->commande->valid(DolibarrApiAccess::$user, $idwarehouse, $notrigger);
  650. if ($result == 0) {
  651. throw new RestException(304, 'Error nothing done. May be object is already validated');
  652. }
  653. if ($result < 0) {
  654. throw new RestException(500, 'Error when validating Order: '.$this->commande->error);
  655. }
  656. $result = $this->commande->fetch($id);
  657. $this->commande->fetchObjectLinked();
  658. //fix #20477 : add online_payment_url
  659. require_once DOL_DOCUMENT_ROOT.'/core/lib/payments.lib.php';
  660. $this->commande->online_payment_url = getOnlinePaymentUrl(0, 'order', $this->commande->ref);
  661. return $this->_cleanObjectDatas($this->commande);
  662. }
  663. /**
  664. * Tag the order as validated (opened)
  665. *
  666. * Function used when order is reopend after being closed.
  667. *
  668. * @param int $id Id of the order
  669. *
  670. * @url POST {id}/reopen
  671. *
  672. * @return int
  673. *
  674. * @throws RestException 304
  675. * @throws RestException 400
  676. * @throws RestException 401
  677. * @throws RestException 404
  678. * @throws RestException 405
  679. */
  680. public function reopen($id)
  681. {
  682. if (!DolibarrApiAccess::$user->rights->commande->creer) {
  683. throw new RestException(401);
  684. }
  685. if (empty($id)) {
  686. throw new RestException(400, 'Order ID is mandatory');
  687. }
  688. $result = $this->commande->fetch($id);
  689. if (!$result) {
  690. throw new RestException(404, 'Order not found');
  691. }
  692. $result = $this->commande->set_reopen(DolibarrApiAccess::$user);
  693. if ($result < 0) {
  694. throw new RestException(405, $this->commande->error);
  695. } elseif ($result == 0) {
  696. throw new RestException(304);
  697. }
  698. return $result;
  699. }
  700. /**
  701. * Classify the order as invoiced. Could be also called setbilled
  702. *
  703. * @param int $id Id of the order
  704. * @return Object Object with cleaned properties
  705. *
  706. * @url POST {id}/setinvoiced
  707. *
  708. * @throws RestException 400
  709. * @throws RestException 401
  710. * @throws RestException 404
  711. * @throws RestException 405
  712. */
  713. public function setinvoiced($id)
  714. {
  715. if (!DolibarrApiAccess::$user->rights->commande->creer) {
  716. throw new RestException(401);
  717. }
  718. if (empty($id)) {
  719. throw new RestException(400, 'Order ID is mandatory');
  720. }
  721. $result = $this->commande->fetch($id);
  722. if (!$result) {
  723. throw new RestException(404, 'Order not found');
  724. }
  725. $result = $this->commande->classifyBilled(DolibarrApiAccess::$user);
  726. if ($result < 0) {
  727. throw new RestException(400, $this->commande->error);
  728. }
  729. $result = $this->commande->fetch($id);
  730. if (!$result) {
  731. throw new RestException(404, 'Order not found');
  732. }
  733. if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
  734. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  735. }
  736. $this->commande->fetchObjectLinked();
  737. return $this->_cleanObjectDatas($this->commande);
  738. }
  739. /**
  740. * Close an order (Classify it as "Delivered")
  741. *
  742. * @param int $id Order ID
  743. * @param int $notrigger Disabled triggers
  744. * @return Object Object with cleaned properties
  745. *
  746. * @url POST {id}/close
  747. */
  748. public function close($id, $notrigger = 0)
  749. {
  750. if (!DolibarrApiAccess::$user->rights->commande->creer) {
  751. throw new RestException(401);
  752. }
  753. $result = $this->commande->fetch($id);
  754. if (!$result) {
  755. throw new RestException(404, 'Order not found');
  756. }
  757. if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
  758. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  759. }
  760. $result = $this->commande->cloture(DolibarrApiAccess::$user, $notrigger);
  761. if ($result == 0) {
  762. throw new RestException(304, 'Error nothing done. May be object is already closed');
  763. }
  764. if ($result < 0) {
  765. throw new RestException(500, 'Error when closing Order: '.$this->commande->error);
  766. }
  767. $result = $this->commande->fetch($id);
  768. if (!$result) {
  769. throw new RestException(404, 'Order not found');
  770. }
  771. if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
  772. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  773. }
  774. $this->commande->fetchObjectLinked();
  775. return $this->_cleanObjectDatas($this->commande);
  776. }
  777. /**
  778. * Set an order to draft
  779. *
  780. * @param int $id Order ID
  781. * @param int $idwarehouse Warehouse ID to use for stock change (Used only if option STOCK_CALCULATE_ON_VALIDATE_ORDER is on)
  782. * @return Object Object with cleaned properties
  783. *
  784. * @url POST {id}/settodraft
  785. */
  786. public function settodraft($id, $idwarehouse = -1)
  787. {
  788. if (!DolibarrApiAccess::$user->rights->commande->creer) {
  789. throw new RestException(401);
  790. }
  791. $result = $this->commande->fetch($id);
  792. if (!$result) {
  793. throw new RestException(404, 'Order not found');
  794. }
  795. if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
  796. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  797. }
  798. $result = $this->commande->setDraft(DolibarrApiAccess::$user, $idwarehouse);
  799. if ($result == 0) {
  800. throw new RestException(304, 'Nothing done. May be object is already closed');
  801. }
  802. if ($result < 0) {
  803. throw new RestException(500, 'Error when closing Order: '.$this->commande->error);
  804. }
  805. $result = $this->commande->fetch($id);
  806. if (!$result) {
  807. throw new RestException(404, 'Order not found');
  808. }
  809. if (!DolibarrApi::_checkAccessToResource('commande', $this->commande->id)) {
  810. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  811. }
  812. $this->commande->fetchObjectLinked();
  813. return $this->_cleanObjectDatas($this->commande);
  814. }
  815. /**
  816. * Create an order using an existing proposal.
  817. *
  818. * @param int $proposalid Id of the proposal
  819. * @return Object Object with cleaned properties
  820. *
  821. * @url POST /createfromproposal/{proposalid}
  822. *
  823. * @throws RestException 400
  824. * @throws RestException 401
  825. * @throws RestException 404
  826. * @throws RestException 405
  827. */
  828. public function createOrderFromProposal($proposalid)
  829. {
  830. require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
  831. if (!DolibarrApiAccess::$user->hasRight('propal', 'lire')) {
  832. throw new RestException(401);
  833. }
  834. if (!DolibarrApiAccess::$user->rights->commande->creer) {
  835. throw new RestException(401);
  836. }
  837. if (empty($proposalid)) {
  838. throw new RestException(400, 'Proposal ID is mandatory');
  839. }
  840. $propal = new Propal($this->db);
  841. $result = $propal->fetch($proposalid);
  842. if (!$result) {
  843. throw new RestException(404, 'Proposal not found');
  844. }
  845. $result = $this->commande->createFromProposal($propal, DolibarrApiAccess::$user);
  846. if ($result < 0) {
  847. throw new RestException(405, $this->commande->error);
  848. }
  849. $this->commande->fetchObjectLinked();
  850. return $this->_cleanObjectDatas($this->commande);
  851. }
  852. /**
  853. * Get the shipments of an order
  854. *
  855. * @param int $id Id of the order
  856. *
  857. * @url GET {id}/shipment
  858. *
  859. * @return array
  860. *
  861. * @throws RestException 401
  862. * @throws RestException 404
  863. * @throws RestException 500 System error
  864. */
  865. public function getOrderShipments($id)
  866. {
  867. require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
  868. if (!DolibarrApiAccess::$user->rights->expedition->lire) {
  869. throw new RestException(401);
  870. }
  871. $obj_ret = array();
  872. $sql = "SELECT e.rowid";
  873. $sql .= " FROM ".MAIN_DB_PREFIX."expedition as e";
  874. $sql .= " JOIN ".MAIN_DB_PREFIX."expeditiondet as edet";
  875. $sql .= " ON e.rowid = edet.fk_expedition";
  876. $sql .= " JOIN ".MAIN_DB_PREFIX."commandedet as cdet";
  877. $sql .= " ON edet.fk_origin_line = cdet.rowid";
  878. $sql .= " JOIN ".MAIN_DB_PREFIX."commande as c";
  879. $sql .= " ON cdet.fk_commande = c.rowid";
  880. $sql .= " WHERE c.rowid = ".((int) $id);
  881. $sql .= " GROUP BY e.rowid";
  882. $sql .= $this->db->order("e.rowid", "ASC");
  883. dol_syslog("API Rest request");
  884. $result = $this->db->query($sql);
  885. if ($result) {
  886. $num = $this->db->num_rows($result);
  887. if ($num <= 0) {
  888. throw new RestException(404, 'Shipments not found ');
  889. }
  890. $i = 0;
  891. while ($i < $num) {
  892. $obj = $this->db->fetch_object($result);
  893. $shipment_static = new Expedition($this->db);
  894. if ($shipment_static->fetch($obj->rowid)) {
  895. $obj_ret[] = $this->_cleanObjectDatas($shipment_static);
  896. }
  897. $i++;
  898. }
  899. } else {
  900. throw new RestException(500, 'Error when retrieve shipment list : '.$this->db->lasterror());
  901. }
  902. return $obj_ret;
  903. }
  904. /**
  905. * Create the shipment of an order
  906. *
  907. * @param int $id Id of the order
  908. * @param int $warehouse_id Id of a warehouse
  909. *
  910. * @url POST {id}/shipment/{warehouse_id}
  911. *
  912. * @return int
  913. *
  914. * @throws RestException 401
  915. * @throws RestException 404
  916. * @throws RestException 500 System error
  917. */
  918. public function createOrderShipment($id, $warehouse_id)
  919. {
  920. require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
  921. if (!DolibarrApiAccess::$user->rights->expedition->creer) {
  922. throw new RestException(401);
  923. }
  924. if ($warehouse_id <= 0) {
  925. throw new RestException(404, 'Warehouse not found');
  926. }
  927. $result = $this->commande->fetch($id);
  928. if (!$result) {
  929. throw new RestException(404, 'Order not found');
  930. }
  931. $shipment = new Expedition($this->db);
  932. $shipment->socid = $this->commande->socid;
  933. $shipment->origin_id = $this->commande->id;
  934. $result = $shipment->create(DolibarrApiAccess::$user);
  935. if ($result <= 0) {
  936. throw new RestException(500, 'Error on creating expedition :'.$this->db->lasterror());
  937. }
  938. foreach ($this->commande->lines as $line) {
  939. $result = $shipment->create_line($warehouse_id, $line->id, $line->qty);
  940. if ($result <= 0) {
  941. throw new RestException(500, 'Error on creating expedition lines:'.$this->db->lasterror());
  942. }
  943. }
  944. return $shipment->id;
  945. }
  946. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
  947. /**
  948. * Clean sensible object datas
  949. *
  950. * @param Object $object Object to clean
  951. * @return Object Object with cleaned properties
  952. */
  953. protected function _cleanObjectDatas($object)
  954. {
  955. // phpcs:enable
  956. $object = parent::_cleanObjectDatas($object);
  957. unset($object->note);
  958. unset($object->address);
  959. unset($object->barcode_type);
  960. unset($object->barcode_type_code);
  961. unset($object->barcode_type_label);
  962. unset($object->barcode_type_coder);
  963. return $object;
  964. }
  965. /**
  966. * Validate fields before create or update object
  967. *
  968. * @param array $data Array with data to verify
  969. * @return array
  970. * @throws RestException
  971. */
  972. private function _validate($data)
  973. {
  974. $commande = array();
  975. foreach (Orders::$FIELDS as $field) {
  976. if (!isset($data[$field])) {
  977. throw new RestException(400, $field." field missing");
  978. }
  979. $commande[$field] = $data[$field];
  980. }
  981. return $commande;
  982. }
  983. }