api_thirdparties.class.php 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811
  1. <?php
  2. /* Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
  3. * Copyright (C) 2018 Pierre Chéné <pierre.chene44@gmail.com>
  4. * Copyright (C) 2019 Cedric Ancelin <icedo.anc@gmail.com>
  5. * Copyright (C) 2020-2024 Frédéric France <frederic.france@free.fr>
  6. * Copyright (C) 2023 Alexandre Janniaux <alexandre.janniaux@gmail.com>
  7. * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  21. */
  22. use Luracast\Restler\RestException;
  23. /**
  24. * API class for thirdparties
  25. *
  26. * @access protected
  27. * @class DolibarrApiAccess {@requires user,external}
  28. *
  29. */
  30. class Thirdparties extends DolibarrApi
  31. {
  32. /**
  33. *
  34. * @var array $FIELDS Mandatory fields, checked when create and update object
  35. */
  36. public static $FIELDS = array(
  37. 'name'
  38. );
  39. /**
  40. * @var Societe $company {@type Societe}
  41. */
  42. public $company;
  43. /**
  44. * Constructor
  45. */
  46. public function __construct()
  47. {
  48. global $db;
  49. $this->db = $db;
  50. require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
  51. require_once DOL_DOCUMENT_ROOT.'/societe/class/societeaccount.class.php';
  52. require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
  53. require_once DOL_DOCUMENT_ROOT.'/societe/class/companybankaccount.class.php';
  54. $this->company = new Societe($this->db);
  55. if (getDolGlobalString('SOCIETE_EMAIL_MANDATORY')) {
  56. static::$FIELDS[] = 'email';
  57. }
  58. }
  59. /**
  60. * Get properties of a thirdparty object
  61. *
  62. * Return an array with thirdparty informations
  63. *
  64. * @param int $id Id of third party to load
  65. * @return Object Object with cleaned properties
  66. *
  67. * @throws RestException
  68. */
  69. public function get($id)
  70. {
  71. return $this->_fetch($id);
  72. }
  73. /**
  74. * Get properties of a thirdparty object by email.
  75. *
  76. * Return an array with thirdparty informations
  77. *
  78. * @param string $email Email of third party to load
  79. * @return array|mixed Cleaned Societe object
  80. *
  81. * @url GET email/{email}
  82. *
  83. * @throws RestException
  84. */
  85. public function getByEmail($email)
  86. {
  87. return $this->_fetch('', '', '', '', '', '', '', '', '', '', $email);
  88. }
  89. /**
  90. * Get properties of a thirdparty object by barcode.
  91. *
  92. * Return an array with thirdparty informations
  93. *
  94. * @param string $barcode Barcode of third party to load
  95. * @return array|mixed Cleaned Societe object
  96. *
  97. * @url GET barcode/{barcode}
  98. *
  99. * @throws RestException
  100. */
  101. public function getByBarcode($barcode)
  102. {
  103. return $this->_fetch('', '', '', $barcode);
  104. }
  105. /**
  106. * List thirdparties
  107. *
  108. * Get a list of thirdparties
  109. *
  110. * @param string $sortfield Sort field
  111. * @param string $sortorder Sort order
  112. * @param int $limit Limit for list
  113. * @param int $page Page number
  114. * @param int $mode Set to 1 to show only customers
  115. * Set to 2 to show only prospects
  116. * Set to 3 to show only those are not customer neither prospect
  117. * Set to 4 to show only suppliers
  118. * @param int $category Use this param to filter list by category
  119. * @param string $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "((t.nom:like:'TheCompany%') or (t.name_alias:like:'TheCompany%')) and (t.datec:<:'20160101')"
  120. * @param string $properties Restrict the data returned to theses properties. Ignored if empty. Comma separated list of properties names
  121. * @return array Array of thirdparty objects
  122. */
  123. public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $mode = 0, $category = 0, $sqlfilters = '', $properties = '')
  124. {
  125. $obj_ret = array();
  126. if (!DolibarrApiAccess::$user->hasRight('societe', 'lire')) {
  127. throw new RestException(401);
  128. }
  129. // case of external user, we force socids
  130. $socids = DolibarrApiAccess::$user->socid ? DolibarrApiAccess::$user->socid : '';
  131. // If the internal user must only see his customers, force searching by him
  132. $search_sale = 0;
  133. if (!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) {
  134. $search_sale = DolibarrApiAccess::$user->id;
  135. }
  136. $sql = "SELECT t.rowid";
  137. if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) {
  138. $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)
  139. }
  140. $sql .= " FROM ".MAIN_DB_PREFIX."societe as t";
  141. $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_extrafields AS ef ON ef.fk_object = t.rowid"; // So we will be able to filter on extrafields
  142. if ($category > 0) {
  143. if ($mode != 4) {
  144. $sql .= ", ".MAIN_DB_PREFIX."categorie_societe as c";
  145. }
  146. if (!in_array($mode, array(1, 2, 3))) {
  147. $sql .= ", ".MAIN_DB_PREFIX."categorie_fournisseur as cc";
  148. }
  149. }
  150. if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) {
  151. $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; // We need this table joined to the select in order to filter by sale
  152. }
  153. $sql .= ", ".MAIN_DB_PREFIX."c_stcomm as st";
  154. $sql .= " WHERE t.entity IN (".getEntity('societe').")";
  155. $sql .= " AND t.fk_stcomm = st.id";
  156. if ($mode == 1) {
  157. $sql .= " AND t.client IN (1, 3)";
  158. } elseif ($mode == 2) {
  159. $sql .= " AND t.client IN (2, 3)";
  160. } elseif ($mode == 3) {
  161. $sql .= " AND t.client IN (0)";
  162. } elseif ($mode == 4) {
  163. $sql .= " AND t.fournisseur IN (1)";
  164. }
  165. // Select thirdparties of given category
  166. if ($category > 0) {
  167. if (!empty($mode) && $mode != 4) {
  168. $sql .= " AND c.fk_categorie = ".((int) $category)." AND c.fk_soc = t.rowid";
  169. } elseif (!empty($mode) && $mode == 4) {
  170. $sql .= " AND cc.fk_categorie = ".((int) $category)." AND cc.fk_soc = t.rowid";
  171. } else {
  172. $sql .= " AND ((c.fk_categorie = ".((int) $category)." AND c.fk_soc = t.rowid) OR (cc.fk_categorie = ".((int) $category)." AND cc.fk_soc = t.rowid))";
  173. }
  174. }
  175. if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) {
  176. $sql .= " AND t.rowid = sc.fk_soc";
  177. }
  178. //if ($email != NULL) $sql.= " AND s.email = \"".$email."\"";
  179. if ($socids) {
  180. $sql .= " AND t.rowid IN (".$this->db->sanitize($socids).")";
  181. }
  182. if ($search_sale > 0) {
  183. $sql .= " AND t.rowid = sc.fk_soc"; // Join for the needed table to filter by sale
  184. }
  185. // Insert sale filter
  186. if ($search_sale > 0) {
  187. $sql .= " AND sc.fk_user = ".((int) $search_sale);
  188. }
  189. // Add sql filters
  190. if ($sqlfilters) {
  191. $errormessage = '';
  192. $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
  193. if ($errormessage) {
  194. throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
  195. }
  196. }
  197. $sql .= $this->db->order($sortfield, $sortorder);
  198. if ($limit) {
  199. if ($page < 0) {
  200. $page = 0;
  201. }
  202. $offset = $limit * $page;
  203. $sql .= $this->db->plimit($limit + 1, $offset);
  204. }
  205. $result = $this->db->query($sql);
  206. if ($result) {
  207. $num = $this->db->num_rows($result);
  208. $min = min($num, ($limit <= 0 ? $num : $limit));
  209. $i = 0;
  210. while ($i < $min) {
  211. $obj = $this->db->fetch_object($result);
  212. $soc_static = new Societe($this->db);
  213. if ($soc_static->fetch($obj->rowid)) {
  214. if (isModEnabled('mailing')) {
  215. $soc_static->getNoEmail();
  216. }
  217. $obj_ret[] = $this->_filterObjectProperties($this->_cleanObjectDatas($soc_static), $properties);
  218. }
  219. $i++;
  220. }
  221. } else {
  222. throw new RestException(503, 'Error when retrieve thirdparties : '.$this->db->lasterror());
  223. }
  224. if (!count($obj_ret)) {
  225. throw new RestException(404, 'Thirdparties not found');
  226. }
  227. return $obj_ret;
  228. }
  229. /**
  230. * Create thirdparty object
  231. *
  232. * @param array $request_data Request datas
  233. * @return int ID of thirdparty
  234. */
  235. public function post($request_data = null)
  236. {
  237. if (!DolibarrApiAccess::$user->rights->societe->creer) {
  238. throw new RestException(401);
  239. }
  240. // Check mandatory fields
  241. $result = $this->_validate($request_data);
  242. foreach ($request_data as $field => $value) {
  243. if ($field === 'caller') {
  244. // Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again whith the caller
  245. $this->company->context['caller'] = $request_data['caller'];
  246. continue;
  247. }
  248. $this->company->$field = $this->_checkValForAPI($field, $value, $this->company);
  249. }
  250. if ($this->company->create(DolibarrApiAccess::$user) < 0) {
  251. throw new RestException(500, 'Error creating thirdparty', array_merge(array($this->company->error), $this->company->errors));
  252. }
  253. if (isModEnabled('mailing') && !empty($this->company->email) && isset($this->company->no_email)) {
  254. $this->company->setNoEmail($this->company->no_email);
  255. }
  256. return $this->company->id;
  257. }
  258. /**
  259. * Update thirdparty
  260. *
  261. * @param int $id Id of thirdparty to update
  262. * @param array $request_data Datas
  263. * @return array|mixed|boolean
  264. */
  265. public function put($id, $request_data = null)
  266. {
  267. if (!DolibarrApiAccess::$user->rights->societe->creer) {
  268. throw new RestException(401);
  269. }
  270. $result = $this->company->fetch($id);
  271. if (!$result) {
  272. throw new RestException(404, 'Thirdparty not found');
  273. }
  274. if (!DolibarrApi::_checkAccessToResource('societe', $this->company->id)) {
  275. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  276. }
  277. foreach ($request_data as $field => $value) {
  278. if ($field == 'id') {
  279. continue;
  280. }
  281. if ($field === 'caller') {
  282. // Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again whith the caller
  283. $this->company->context['caller'] = $request_data['caller'];
  284. continue;
  285. }
  286. $this->company->$field = $this->_checkValForAPI($field, $value, $this->company);
  287. }
  288. if (isModEnabled('mailing') && !empty($this->company->email) && isset($this->company->no_email)) {
  289. $this->company->setNoEmail($this->company->no_email);
  290. }
  291. if ($this->company->update($id, DolibarrApiAccess::$user, 1, '', '', 'update', 1)) {
  292. return $this->get($id);
  293. }
  294. return false;
  295. }
  296. /**
  297. * Merge a thirdparty into another one.
  298. *
  299. * Merge content (properties, notes) and objects (like invoices, events, orders, proposals, ...) of a thirdparty into a target thirdparty,
  300. * then delete the merged thirdparty.
  301. * If a property has a defined value both in thirdparty to delete and thirdparty to keep, the value into the thirdparty to
  302. * delete will be ignored, the value of target thirdparty will remain, except for notes (content is concatenated).
  303. *
  304. * @param int $id ID of thirdparty to keep (the target thirdparty)
  305. * @param int $idtodelete ID of thirdparty to remove (the thirdparty to delete), once data has been merged into the target thirdparty.
  306. * @return int
  307. *
  308. * @url PUT {id}/merge/{idtodelete}
  309. */
  310. public function merge($id, $idtodelete)
  311. {
  312. global $user;
  313. $error = 0;
  314. if ($id == $idtodelete) {
  315. throw new RestException(400, 'Try to merge a thirdparty into itself');
  316. }
  317. if (!DolibarrApiAccess::$user->rights->societe->creer) {
  318. throw new RestException(401);
  319. }
  320. $result = $this->company->fetch($id); // include the fetch of extra fields
  321. if (!$result) {
  322. throw new RestException(404, 'Thirdparty not found');
  323. }
  324. if (!DolibarrApi::_checkAccessToResource('societe', $this->company->id)) {
  325. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  326. }
  327. $companytoremove = new Societe($this->db);
  328. $result = $companytoremove->fetch($idtodelete); // include the fetch of extra fields
  329. if (!$result) {
  330. throw new RestException(404, 'Thirdparty not found');
  331. }
  332. if (!DolibarrApi::_checkAccessToResource('societe', $companytoremove->id)) {
  333. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  334. }
  335. $user = DolibarrApiAccess::$user;
  336. $result = $this->company->mergeCompany($companytoremove->id);
  337. if ($result < 0) {
  338. throw new RestException(500, 'Error failed to merged thirdparty '.$companytoremove->id.' into '.$id.'. Enable and read log file for more information.');
  339. }
  340. return $this->get($id);
  341. }
  342. /**
  343. * Delete thirdparty
  344. *
  345. * @param int $id Thirdparty ID
  346. * @return array
  347. */
  348. public function delete($id)
  349. {
  350. if (!DolibarrApiAccess::$user->hasRight('societe', 'supprimer')) {
  351. throw new RestException(401);
  352. }
  353. $result = $this->company->fetch($id);
  354. if (!$result) {
  355. throw new RestException(404, 'Thirdparty not found');
  356. }
  357. if (!DolibarrApi::_checkAccessToResource('societe', $this->company->id)) {
  358. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  359. }
  360. $this->company->oldcopy = clone $this->company;
  361. $res = $this->company->delete($id);
  362. if ($res < 0) {
  363. throw new RestException(500, "Can't delete, error occurs");
  364. } elseif ($res == 0) {
  365. throw new RestException(409, "Can't delete, that product is probably used");
  366. }
  367. return array(
  368. 'success' => array(
  369. 'code' => 200,
  370. 'message' => 'Object deleted'
  371. )
  372. );
  373. }
  374. /**
  375. * Set new price level for the given thirdparty
  376. *
  377. * @param int $id ID of thirdparty
  378. * @param int $priceLevel Price level to apply to thirdparty
  379. * @return object Thirdparty data without useless information
  380. *
  381. * @url PUT {id}/setpricelevel/{priceLevel}
  382. *
  383. * @throws RestException 400 Price level out of bounds
  384. * @throws RestException 401 Access not allowed for your login
  385. * @throws RestException 404 Thirdparty not found
  386. * @throws RestException 500 Error fetching/setting price level
  387. * @throws RestException 501 Request needs modules "Thirdparties" and "Products" and setting Multiprices activated
  388. */
  389. public function setThirdpartyPriceLevel($id, $priceLevel)
  390. {
  391. global $conf;
  392. if (!isModEnabled('societe')) {
  393. throw new RestException(501, 'Module "Thirdparties" needed for this request');
  394. }
  395. if (!isModEnabled("product")) {
  396. throw new RestException(501, 'Module "Products" needed for this request');
  397. }
  398. if (!getDolGlobalString('PRODUIT_MULTIPRICES')) {
  399. throw new RestException(501, 'Multiprices features activation needed for this request');
  400. }
  401. if ($priceLevel < 1 || $priceLevel > $conf->global->PRODUIT_MULTIPRICES_LIMIT) {
  402. throw new RestException(400, 'Price level must be between 1 and ' . getDolGlobalString('PRODUIT_MULTIPRICES_LIMIT'));
  403. }
  404. if (empty(DolibarrApiAccess::$user->rights->societe->creer)) {
  405. throw new RestException(401, 'Access to thirdparty '.$id.' not allowed for login '.DolibarrApiAccess::$user->login);
  406. }
  407. $result = $this->company->fetch($id);
  408. if ($result < 0) {
  409. throw new RestException(404, 'Thirdparty '.$id.' not found');
  410. }
  411. if (empty($result)) {
  412. throw new RestException(500, 'Error fetching thirdparty '.$id, array_merge(array($this->company->error), $this->company->errors));
  413. }
  414. if (empty(DolibarrApi::_checkAccessToResource('societe', $this->company->id))) {
  415. throw new RestException(401, 'Access to thirdparty '.$id.' not allowed for login '.DolibarrApiAccess::$user->login);
  416. }
  417. $result = $this->company->setPriceLevel($priceLevel, DolibarrApiAccess::$user);
  418. if ($result <= 0) {
  419. throw new RestException(500, 'Error setting new price level for thirdparty '.$id, array($this->company->db->lasterror()));
  420. }
  421. return $this->_cleanObjectDatas($this->company);
  422. }
  423. /**
  424. * Get customer categories for a thirdparty
  425. *
  426. * @param int $id ID of thirdparty
  427. * @param string $sortfield Sort field
  428. * @param string $sortorder Sort order
  429. * @param int $limit Limit for list
  430. * @param int $page Page number
  431. * @return array|void
  432. *
  433. * @url GET {id}/categories
  434. */
  435. public function getCategories($id, $sortfield = "s.rowid", $sortorder = 'ASC', $limit = 0, $page = 0)
  436. {
  437. if (!DolibarrApiAccess::$user->rights->categorie->lire) {
  438. throw new RestException(401);
  439. }
  440. $result = $this->company->fetch($id);
  441. if (!$result) {
  442. throw new RestException(404, 'Thirdparty not found');
  443. }
  444. $categories = new Categorie($this->db);
  445. $arrayofcateg = $categories->getListForItem($id, 'customer', $sortfield, $sortorder, $limit, $page);
  446. if (is_numeric($arrayofcateg) && $arrayofcateg < 0) {
  447. throw new RestException(503, 'Error when retrieve category list : '.$categories->error);
  448. }
  449. if (is_numeric($arrayofcateg) && $arrayofcateg >= 0) { // To fix a return of 0 instead of empty array of method getListForItem
  450. return array();
  451. }
  452. return $arrayofcateg;
  453. }
  454. /**
  455. * Add a customer category to a thirdparty
  456. *
  457. * @param int $id Id of thirdparty
  458. * @param int $category_id Id of category
  459. * @return Object|void
  460. *
  461. * @url PUT {id}/categories/{category_id}
  462. */
  463. public function addCategory($id, $category_id)
  464. {
  465. if (!DolibarrApiAccess::$user->rights->societe->creer) {
  466. throw new RestException(401);
  467. }
  468. $result = $this->company->fetch($id);
  469. if (!$result) {
  470. throw new RestException(404, 'Thirdparty not found');
  471. }
  472. $category = new Categorie($this->db);
  473. $result = $category->fetch($category_id);
  474. if (!$result) {
  475. throw new RestException(404, 'category not found');
  476. }
  477. if (!DolibarrApi::_checkAccessToResource('societe', $this->company->id)) {
  478. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  479. }
  480. if (!DolibarrApi::_checkAccessToResource('category', $category->id)) {
  481. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  482. }
  483. $category->add_type($this->company, 'customer');
  484. return $this->_cleanObjectDatas($this->company);
  485. }
  486. /**
  487. * Remove the link between a customer category and the thirdparty
  488. *
  489. * @param int $id Id of thirdparty
  490. * @param int $category_id Id of category
  491. *
  492. * @return Object|void
  493. *
  494. * @url DELETE {id}/categories/{category_id}
  495. */
  496. public function deleteCategory($id, $category_id)
  497. {
  498. if (!DolibarrApiAccess::$user->rights->societe->creer) {
  499. throw new RestException(401);
  500. }
  501. $result = $this->company->fetch($id);
  502. if (!$result) {
  503. throw new RestException(404, 'Thirdparty not found');
  504. }
  505. $category = new Categorie($this->db);
  506. $result = $category->fetch($category_id);
  507. if (!$result) {
  508. throw new RestException(404, 'category not found');
  509. }
  510. if (!DolibarrApi::_checkAccessToResource('societe', $this->company->id)) {
  511. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  512. }
  513. if (!DolibarrApi::_checkAccessToResource('category', $category->id)) {
  514. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  515. }
  516. $category->del_type($this->company, 'customer');
  517. return $this->_cleanObjectDatas($this->company);
  518. }
  519. /**
  520. * Get supplier categories for a thirdparty
  521. *
  522. * @param int $id ID of thirdparty
  523. * @param string $sortfield Sort field
  524. * @param string $sortorder Sort order
  525. * @param int $limit Limit for list
  526. * @param int $page Page number
  527. *
  528. * @return mixed
  529. *
  530. * @url GET {id}/supplier_categories
  531. */
  532. public function getSupplierCategories($id, $sortfield = "s.rowid", $sortorder = 'ASC', $limit = 0, $page = 0)
  533. {
  534. if (!DolibarrApiAccess::$user->rights->categorie->lire) {
  535. throw new RestException(401);
  536. }
  537. $result = $this->company->fetch($id);
  538. if (!$result) {
  539. throw new RestException(404, 'Thirdparty not found');
  540. }
  541. $categories = new Categorie($this->db);
  542. $result = $categories->getListForItem($id, 'supplier', $sortfield, $sortorder, $limit, $page);
  543. if (is_numeric($result) && $result < 0) {
  544. throw new RestException(503, 'Error when retrieve category list : '.$categories->error);
  545. }
  546. if (is_numeric($result) && $result == 0) { // To fix a return of 0 instead of empty array of method getListForItem
  547. return array();
  548. }
  549. return $result;
  550. }
  551. /**
  552. * Add a supplier category to a thirdparty
  553. *
  554. * @param int $id Id of thirdparty
  555. * @param int $category_id Id of category
  556. *
  557. * @return mixed
  558. *
  559. * @url PUT {id}/supplier_categories/{category_id}
  560. */
  561. public function addSupplierCategory($id, $category_id)
  562. {
  563. if (!DolibarrApiAccess::$user->rights->societe->creer) {
  564. throw new RestException(401);
  565. }
  566. $result = $this->company->fetch($id);
  567. if (!$result) {
  568. throw new RestException(404, 'Thirdparty not found');
  569. }
  570. $category = new Categorie($this->db);
  571. $result = $category->fetch($category_id);
  572. if (!$result) {
  573. throw new RestException(404, 'category not found');
  574. }
  575. if (!DolibarrApi::_checkAccessToResource('societe', $this->company->id)) {
  576. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  577. }
  578. if (!DolibarrApi::_checkAccessToResource('category', $category->id)) {
  579. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  580. }
  581. $category->add_type($this->company, 'supplier');
  582. return $this->_cleanObjectDatas($this->company);
  583. }
  584. /**
  585. * Remove the link between a category and the thirdparty
  586. *
  587. * @param int $id Id of thirdparty
  588. * @param int $category_id Id of category
  589. *
  590. * @return mixed
  591. *
  592. * @url DELETE {id}/supplier_categories/{category_id}
  593. */
  594. public function deleteSupplierCategory($id, $category_id)
  595. {
  596. if (!DolibarrApiAccess::$user->rights->societe->creer) {
  597. throw new RestException(401);
  598. }
  599. $result = $this->company->fetch($id);
  600. if (!$result) {
  601. throw new RestException(404, 'Thirdparty not found');
  602. }
  603. $category = new Categorie($this->db);
  604. $result = $category->fetch($category_id);
  605. if (!$result) {
  606. throw new RestException(404, 'category not found');
  607. }
  608. if (!DolibarrApi::_checkAccessToResource('societe', $this->company->id)) {
  609. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  610. }
  611. if (!DolibarrApi::_checkAccessToResource('category', $category->id)) {
  612. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  613. }
  614. $category->del_type($this->company, 'supplier');
  615. return $this->_cleanObjectDatas($this->company);
  616. }
  617. /**
  618. * Get outstanding proposals of thirdparty
  619. *
  620. * @param int $id ID of the thirdparty
  621. * @param string $mode 'customer' or 'supplier'
  622. *
  623. * @url GET {id}/outstandingproposals
  624. *
  625. * @return array List of outstandings proposals of thirdparty
  626. *
  627. * @throws RestException 400
  628. * @throws RestException 401
  629. * @throws RestException 404
  630. */
  631. public function getOutStandingProposals($id, $mode = 'customer')
  632. {
  633. if (!DolibarrApiAccess::$user->hasRight('societe', 'lire')) {
  634. throw new RestException(401);
  635. }
  636. if (empty($id)) {
  637. throw new RestException(400, 'Thirdparty ID is mandatory');
  638. }
  639. if (!DolibarrApi::_checkAccessToResource('societe', $id)) {
  640. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  641. }
  642. $result = $this->company->fetch($id);
  643. if (!$result) {
  644. throw new RestException(404, 'Thirdparty not found');
  645. }
  646. $result = $this->company->getOutstandingProposals($mode);
  647. unset($result['total_ht']);
  648. unset($result['total_ttc']);
  649. return $result;
  650. }
  651. /**
  652. * Get outstanding orders of thirdparty
  653. *
  654. * @param int $id ID of the thirdparty
  655. * @param string $mode 'customer' or 'supplier'
  656. *
  657. * @url GET {id}/outstandingorders
  658. *
  659. * @return array List of outstandings orders of thirdparty
  660. *
  661. * @throws RestException 400
  662. * @throws RestException 401
  663. * @throws RestException 404
  664. */
  665. public function getOutStandingOrder($id, $mode = 'customer')
  666. {
  667. if (!DolibarrApiAccess::$user->hasRight('societe', 'lire')) {
  668. throw new RestException(401);
  669. }
  670. if (empty($id)) {
  671. throw new RestException(400, 'Thirdparty ID is mandatory');
  672. }
  673. if (!DolibarrApi::_checkAccessToResource('societe', $id)) {
  674. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  675. }
  676. $result = $this->company->fetch($id);
  677. if (!$result) {
  678. throw new RestException(404, 'Thirdparty not found');
  679. }
  680. $result = $this->company->getOutstandingOrders($mode);
  681. unset($result['total_ht']);
  682. unset($result['total_ttc']);
  683. return $result;
  684. }
  685. /**
  686. * Get outstanding invoices of thirdparty
  687. *
  688. * @param int $id ID of the thirdparty
  689. * @param string $mode 'customer' or 'supplier'
  690. *
  691. * @url GET {id}/outstandinginvoices
  692. *
  693. * @return array List of outstandings invoices of thirdparty
  694. *
  695. * @throws RestException 400
  696. * @throws RestException 401
  697. * @throws RestException 404
  698. */
  699. public function getOutStandingInvoices($id, $mode = 'customer')
  700. {
  701. if (!DolibarrApiAccess::$user->hasRight('societe', 'lire')) {
  702. throw new RestException(401);
  703. }
  704. if (empty($id)) {
  705. throw new RestException(400, 'Thirdparty ID is mandatory');
  706. }
  707. if (!DolibarrApi::_checkAccessToResource('societe', $id)) {
  708. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  709. }
  710. $result = $this->company->fetch($id);
  711. if (!$result) {
  712. throw new RestException(404, 'Thirdparty not found');
  713. }
  714. $result = $this->company->getOutstandingBills($mode);
  715. unset($result['total_ht']);
  716. unset($result['total_ttc']);
  717. return $result;
  718. }
  719. /**
  720. * Get representatives of thirdparty
  721. *
  722. * @param int $id ID of the thirdparty
  723. * @param int $mode 0=Array with properties, 1=Array of id.
  724. *
  725. * @url GET {id}/representatives
  726. *
  727. * @return array List of representatives of thirdparty
  728. *
  729. * @throws RestException 400
  730. * @throws RestException 401
  731. * @throws RestException 404
  732. */
  733. public function getSalesRepresentatives($id, $mode = 0)
  734. {
  735. if (!DolibarrApiAccess::$user->hasRight('societe', 'lire')) {
  736. throw new RestException(401);
  737. }
  738. if (empty($id)) {
  739. throw new RestException(400, 'Thirdparty ID is mandatory');
  740. }
  741. if (!DolibarrApi::_checkAccessToResource('societe', $id)) {
  742. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  743. }
  744. $result = $this->company->fetch($id);
  745. if (!$result) {
  746. throw new RestException(404, 'Thirdparty not found');
  747. }
  748. $result = $this->company->getSalesRepresentatives(DolibarrApiAccess::$user, $mode);
  749. return $result;
  750. }
  751. /**
  752. * Get fixed amount discount of a thirdparty (all sources: deposit, credit note, commercial offers...)
  753. *
  754. * @param int $id ID of the thirdparty
  755. * @param string $filter Filter exceptional discount. "none" will return every discount, "available" returns unapplied discounts, "used" returns applied discounts {@choice none,available,used}
  756. * @param string $sortfield Sort field
  757. * @param string $sortorder Sort order
  758. *
  759. * @url GET {id}/fixedamountdiscounts
  760. *
  761. * @return array List of fixed discount of thirdparty
  762. *
  763. * @throws RestException 400
  764. * @throws RestException 401
  765. * @throws RestException 404
  766. * @throws RestException 503
  767. */
  768. public function getFixedAmountDiscounts($id, $filter = "none", $sortfield = "f.type", $sortorder = 'ASC')
  769. {
  770. $obj_ret = array();
  771. if (!DolibarrApiAccess::$user->hasRight('societe', 'lire')) {
  772. throw new RestException(401);
  773. }
  774. if (empty($id)) {
  775. throw new RestException(400, 'Thirdparty ID is mandatory');
  776. }
  777. if (!DolibarrApi::_checkAccessToResource('societe', $id)) {
  778. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  779. }
  780. $result = $this->company->fetch($id);
  781. if (!$result) {
  782. throw new RestException(404, 'Thirdparty not found');
  783. }
  784. $sql = "SELECT f.ref, f.type as factype, re.fk_facture_source, re.rowid, re.amount_ht, re.amount_tva, re.amount_ttc, re.description, re.fk_facture, re.fk_facture_line";
  785. $sql .= " FROM ".MAIN_DB_PREFIX."societe_remise_except as re, ".MAIN_DB_PREFIX."facture as f";
  786. $sql .= " WHERE f.rowid = re.fk_facture_source AND re.fk_soc = ".((int) $id);
  787. if ($filter == "available") {
  788. $sql .= " AND re.fk_facture IS NULL AND re.fk_facture_line IS NULL";
  789. }
  790. if ($filter == "used") {
  791. $sql .= " AND (re.fk_facture IS NOT NULL OR re.fk_facture_line IS NOT NULL)";
  792. }
  793. $sql .= $this->db->order($sortfield, $sortorder);
  794. $result = $this->db->query($sql);
  795. if (!$result) {
  796. throw new RestException(503, $this->db->lasterror());
  797. } else {
  798. $num = $this->db->num_rows($result);
  799. while ($obj = $this->db->fetch_object($result)) {
  800. $obj_ret[] = $obj;
  801. }
  802. }
  803. return $obj_ret;
  804. }
  805. /**
  806. * Return list of invoices qualified to be replaced by another invoice.
  807. *
  808. * @param int $id Id of thirdparty
  809. *
  810. * @url GET {id}/getinvoicesqualifiedforreplacement
  811. *
  812. * @return array
  813. * @throws RestException 400
  814. * @throws RestException 401
  815. * @throws RestException 404
  816. * @throws RestException 405
  817. */
  818. public function getInvoicesQualifiedForReplacement($id)
  819. {
  820. if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
  821. throw new RestException(401);
  822. }
  823. if (empty($id)) {
  824. throw new RestException(400, 'Thirdparty ID is mandatory');
  825. }
  826. if (!DolibarrApi::_checkAccessToResource('societe', $id)) {
  827. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  828. }
  829. /*$result = $this->thirdparty->fetch($id);
  830. if( ! $result ) {
  831. throw new RestException(404, 'Thirdparty not found');
  832. }*/
  833. $invoice = new Facture($this->db);
  834. $result = $invoice->list_replacable_invoices($id);
  835. if ($result < 0) {
  836. throw new RestException(405, $invoice->error);
  837. }
  838. return $result;
  839. }
  840. /**
  841. * Return list of invoices qualified to be corrected by a credit note.
  842. * Invoices matching the following rules are returned
  843. * (validated + payment on process) or classified (paid completely or paid partialy) + not already replaced + not already a credit note
  844. *
  845. * @param int $id Id of thirdparty
  846. *
  847. * @url GET {id}/getinvoicesqualifiedforcreditnote
  848. *
  849. * @return array
  850. *
  851. * @throws RestException 400
  852. * @throws RestException 401
  853. * @throws RestException 404
  854. * @throws RestException 405
  855. */
  856. public function getInvoicesQualifiedForCreditNote($id)
  857. {
  858. if (!DolibarrApiAccess::$user->hasRight('facture', 'lire')) {
  859. throw new RestException(401);
  860. }
  861. if (empty($id)) {
  862. throw new RestException(400, 'Thirdparty ID is mandatory');
  863. }
  864. if (!DolibarrApi::_checkAccessToResource('societe', $id)) {
  865. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  866. }
  867. /*$result = $this->thirdparty->fetch($id);
  868. if( ! $result ) {
  869. throw new RestException(404, 'Thirdparty not found');
  870. }*/
  871. $invoice = new Facture($this->db);
  872. $result = $invoice->list_qualified_avoir_invoices($id);
  873. if ($result < 0) {
  874. throw new RestException(405, $invoice->error);
  875. }
  876. return $result;
  877. }
  878. /**
  879. * Get CompanyBankAccount objects for thirdparty
  880. *
  881. * @param int $id ID of thirdparty
  882. *
  883. * @return array
  884. *
  885. * @url GET {id}/bankaccounts
  886. */
  887. public function getCompanyBankAccount($id)
  888. {
  889. if (!DolibarrApiAccess::$user->rights->societe->lire) {
  890. throw new RestException(401);
  891. }
  892. if (empty($id)) {
  893. throw new RestException(400, 'Thirdparty ID is mandatory');
  894. }
  895. if (!DolibarrApi::_checkAccessToResource('societe', $id)) {
  896. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  897. }
  898. /**
  899. * We select all the records that match the socid
  900. */
  901. $sql = "SELECT rowid, fk_soc, bank, number, code_banque, code_guichet, cle_rib, bic, iban_prefix as iban, domiciliation, proprio,";
  902. $sql .= " owner_address, default_rib, label, datec, tms as datem, rum, frstrecur";
  903. $sql .= " FROM ".MAIN_DB_PREFIX."societe_rib";
  904. if ($id) {
  905. $sql .= " WHERE fk_soc = ".((int) $id);
  906. }
  907. $result = $this->db->query($sql);
  908. if ($this->db->num_rows($result) == 0) {
  909. throw new RestException(404, 'Account not found');
  910. }
  911. $i = 0;
  912. $accounts = array();
  913. if ($result) {
  914. $num = $this->db->num_rows($result);
  915. while ($i < $num) {
  916. $obj = $this->db->fetch_object($result);
  917. $account = new CompanyBankAccount($this->db);
  918. if ($account->fetch($obj->rowid)) {
  919. $accounts[] = $account;
  920. }
  921. $i++;
  922. }
  923. } else {
  924. throw new RestException(404, 'Account not found');
  925. }
  926. $fields = array('socid', 'default_rib', 'frstrecur', '1000110000001', 'datec', 'datem', 'label', 'bank', 'bic', 'iban', 'id', 'rum');
  927. $returnAccounts = array();
  928. foreach ($accounts as $account) {
  929. $object = array();
  930. foreach ($account as $key => $value) {
  931. if (in_array($key, $fields)) {
  932. $object[$key] = $value;
  933. }
  934. }
  935. $returnAccounts[] = $object;
  936. }
  937. return $returnAccounts;
  938. }
  939. /**
  940. * Create CompanyBankAccount object for thirdparty
  941. * @param int $id ID of thirdparty
  942. * @param array $request_data Request data
  943. *
  944. * @return array|mixed BankAccount of thirdparty
  945. *
  946. * @url POST {id}/bankaccounts
  947. */
  948. public function createCompanyBankAccount($id, $request_data = null)
  949. {
  950. if (!DolibarrApiAccess::$user->rights->societe->creer) {
  951. throw new RestException(401);
  952. }
  953. if ($this->company->fetch($id) <= 0) {
  954. throw new RestException(404, 'Error creating Company Bank account, Company doesn\'t exists');
  955. }
  956. $account = new CompanyBankAccount($this->db);
  957. $account->socid = $id;
  958. foreach ($request_data as $field => $value) {
  959. if ($field === 'caller') {
  960. // Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again whith the caller
  961. $this->company->context['caller'] = $request_data['caller'];
  962. continue;
  963. }
  964. $account->$field = $value;
  965. }
  966. if ($account->create(DolibarrApiAccess::$user) < 0) {
  967. throw new RestException(500, 'Error creating Company Bank account');
  968. }
  969. if (empty($account->rum)) {
  970. require_once DOL_DOCUMENT_ROOT.'/compta/prelevement/class/bonprelevement.class.php';
  971. $prelevement = new BonPrelevement($this->db);
  972. $account->rum = $prelevement->buildRumNumber($this->company->code_client, $account->datec, $account->id);
  973. $account->date_rum = dol_now();
  974. }
  975. if ($account->update(DolibarrApiAccess::$user) < 0) {
  976. throw new RestException(500, 'Error updating values');
  977. }
  978. return $this->_cleanObjectDatas($account);
  979. }
  980. /**
  981. * Update CompanyBankAccount object for thirdparty
  982. *
  983. * @param int $id ID of thirdparty
  984. * @param int $bankaccount_id ID of CompanyBankAccount
  985. * @param array $request_data Request data
  986. *
  987. * @return array|mixed BankAccount of thirdparty
  988. *
  989. * @url PUT {id}/bankaccounts/{bankaccount_id}
  990. */
  991. public function updateCompanyBankAccount($id, $bankaccount_id, $request_data = null)
  992. {
  993. if (!DolibarrApiAccess::$user->rights->societe->creer) {
  994. throw new RestException(401);
  995. }
  996. if ($this->company->fetch($id) <= 0) {
  997. throw new RestException(404, 'Error creating Company Bank account, Company doesn\'t exists');
  998. }
  999. $account = new CompanyBankAccount($this->db);
  1000. $account->fetch($bankaccount_id, $id, -1, '');
  1001. if ($account->socid != $id) {
  1002. throw new RestException(401);
  1003. }
  1004. foreach ($request_data as $field => $value) {
  1005. if ($field === 'caller') {
  1006. // Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again whith the caller
  1007. $account->context['caller'] = $request_data['caller'];
  1008. continue;
  1009. }
  1010. $account->$field = $value;
  1011. }
  1012. if (empty($account->rum)) {
  1013. require_once DOL_DOCUMENT_ROOT.'/compta/prelevement/class/bonprelevement.class.php';
  1014. $prelevement = new BonPrelevement($this->db);
  1015. $account->rum = $prelevement->buildRumNumber($this->company->code_client, $account->datec, $account->id);
  1016. $account->date_rum = dol_now();
  1017. }
  1018. if ($account->update(DolibarrApiAccess::$user) < 0) {
  1019. throw new RestException(500, 'Error updating values');
  1020. }
  1021. return $this->_cleanObjectDatas($account);
  1022. }
  1023. /**
  1024. * Delete a bank account attached to a thirdparty
  1025. *
  1026. * @param int $id ID of thirdparty
  1027. * @param int $bankaccount_id ID of CompanyBankAccount
  1028. *
  1029. * @return int -1 if error 1 if correct deletion
  1030. *
  1031. * @url DELETE {id}/bankaccounts/{bankaccount_id}
  1032. */
  1033. public function deleteCompanyBankAccount($id, $bankaccount_id)
  1034. {
  1035. if (!DolibarrApiAccess::$user->rights->societe->creer) {
  1036. throw new RestException(401);
  1037. }
  1038. $account = new CompanyBankAccount($this->db);
  1039. $account->fetch($bankaccount_id);
  1040. if (!$account->socid == $id) {
  1041. throw new RestException(401);
  1042. }
  1043. return $account->delete(DolibarrApiAccess::$user);
  1044. }
  1045. /**
  1046. * Generate a Document from a bank account record (like SEPA mandate)
  1047. *
  1048. * @param int $id Thirdparty id
  1049. * @param int $companybankid Companybank id
  1050. * @param string $model Model of document to generate
  1051. * @return array
  1052. *
  1053. * @url GET {id}/generateBankAccountDocument/{companybankid}/{model}
  1054. */
  1055. public function generateBankAccountDocument($id, $companybankid = null, $model = 'sepamandate')
  1056. {
  1057. global $conf, $langs;
  1058. $langs->loadLangs(array("main", "dict", "commercial", "products", "companies", "banks", "bills", "withdrawals"));
  1059. if ($this->company->fetch($id) <= 0) {
  1060. throw new RestException(404, 'Thirdparty not found');
  1061. }
  1062. if (!DolibarrApiAccess::$user->rights->societe->creer) {
  1063. throw new RestException(401);
  1064. }
  1065. $this->company->setDocModel(DolibarrApiAccess::$user, $model);
  1066. $this->company->fk_bank = $this->company->fk_account;
  1067. $this->company->fk_account = $this->company->fk_account;
  1068. $outputlangs = $langs;
  1069. $newlang = '';
  1070. //if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) $newlang = GETPOST('lang_id', 'aZ09');
  1071. if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
  1072. if (isset($this->company->thirdparty->default_lang)) {
  1073. $newlang = $this->company->thirdparty->default_lang; // for proposal, order, invoice, ...
  1074. } elseif (isset($this->company->default_lang)) {
  1075. $newlang = $this->company->default_lang; // for thirdparty
  1076. }
  1077. }
  1078. if (!empty($newlang)) {
  1079. $outputlangs = new Translate("", $conf);
  1080. $outputlangs->setDefaultLang($newlang);
  1081. }
  1082. $sql = "SELECT rowid";
  1083. $sql .= " FROM ".MAIN_DB_PREFIX."societe_rib";
  1084. if ($id) {
  1085. $sql .= " WHERE fk_soc = ".((int) $id);
  1086. }
  1087. if ($companybankid) {
  1088. $sql .= " AND rowid = ".((int) $companybankid);
  1089. }
  1090. $i = 0;
  1091. $accounts = array();
  1092. $result = $this->db->query($sql);
  1093. if ($result) {
  1094. if ($this->db->num_rows($result) == 0) {
  1095. throw new RestException(404, 'Bank account not found');
  1096. }
  1097. $num = $this->db->num_rows($result);
  1098. while ($i < $num) {
  1099. $obj = $this->db->fetch_object($result);
  1100. $account = new CompanyBankAccount($this->db);
  1101. if ($account->fetch($obj->rowid)) {
  1102. $accounts[] = $account;
  1103. }
  1104. $i++;
  1105. }
  1106. } else {
  1107. throw new RestException(500, 'Sql error '.$this->db->lasterror());
  1108. }
  1109. $moreparams = array(
  1110. 'use_companybankid' => $accounts[0]->id,
  1111. 'force_dir_output' => $conf->societe->multidir_output[$this->company->entity].'/'.dol_sanitizeFileName($this->company->id)
  1112. );
  1113. $result = $this->company->generateDocument($model, $outputlangs, 0, 0, 0, $moreparams);
  1114. if ($result > 0) {
  1115. return array("success" => $result);
  1116. } else {
  1117. throw new RestException(500, 'Error generating the document '.$this->company->error);
  1118. }
  1119. }
  1120. /**
  1121. * Get a specific gateway attached to a thirdparty (by specifying the site key)
  1122. *
  1123. * @param int $id ID of thirdparty
  1124. * @param string $site Site key
  1125. *
  1126. * @return array|mixed
  1127. * @throws RestException 401 Unauthorized: User does not have permission to read thirdparties
  1128. * @throws RestException 404 Not Found: Specified thirdparty ID does not belongs to an existing thirdparty
  1129. *
  1130. * @url GET {id}/gateways/
  1131. */
  1132. public function getSocieteAccounts($id, $site = null)
  1133. {
  1134. if (!DolibarrApiAccess::$user->hasRight('societe', 'lire')) {
  1135. throw new RestException(401);
  1136. }
  1137. if (!DolibarrApi::_checkAccessToResource('societe', $id)) {
  1138. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
  1139. }
  1140. /**
  1141. * We select all the records that match the socid
  1142. */
  1143. $sql = "SELECT rowid, fk_soc, key_account, site, date_creation, tms FROM ".MAIN_DB_PREFIX."societe_account";
  1144. $sql .= " WHERE fk_soc = ".((int) $id);
  1145. if ($site) {
  1146. $sql .= " AND site ='".$this->db->escape($site)."'";
  1147. }
  1148. $result = $this->db->query($sql);
  1149. if ($result && $this->db->num_rows($result) == 0) {
  1150. throw new RestException(404, 'This thirdparty does not have any gateway attached or does not exist.');
  1151. }
  1152. $i = 0;
  1153. $accounts = array();
  1154. $num = $this->db->num_rows($result);
  1155. while ($i < $num) {
  1156. $obj = $this->db->fetch_object($result);
  1157. $account = new SocieteAccount($this->db);
  1158. if ($account->fetch($obj->rowid)) {
  1159. $accounts[] = $account;
  1160. }
  1161. $i++;
  1162. }
  1163. $fields = array('id', 'fk_soc', 'key_account', 'site', 'date_creation', 'tms');
  1164. $returnAccounts = array();
  1165. foreach ($accounts as $account) {
  1166. $object = array();
  1167. foreach ($account as $key => $value) {
  1168. if (in_array($key, $fields)) {
  1169. $object[$key] = $value;
  1170. }
  1171. }
  1172. $returnAccounts[] = $object;
  1173. }
  1174. return $returnAccounts;
  1175. }
  1176. /**
  1177. * Create and attach a new gateway to an existing thirdparty
  1178. *
  1179. * Possible fields for request_data (request body) are specified in <code>llx_societe_account</code> table.<br>
  1180. * See <a href="https://wiki.dolibarr.org/index.php/Table_llx_societe_account">Table llx_societe_account</a> wiki page for more information<br><br>
  1181. * <u>Example body payload :</u> <pre>{"key_account": "cus_DAVkLSs1LYyYI", "site": "stripe"}</pre>
  1182. *
  1183. * @param int $id ID of thirdparty
  1184. * @param array $request_data Request data
  1185. *
  1186. * @return array|mixed
  1187. *
  1188. * @throws RestException 401 Unauthorized: User does not have permission to read thirdparties
  1189. * @throws RestException 409 Conflict: A SocieteAccount entity (gateway) already exists for this company and site.
  1190. * @throws RestException 422 Unprocessable Entity: You must pass the site attribute in your request data !
  1191. * @throws RestException 500 Internal Server Error: Error creating SocieteAccount account
  1192. *
  1193. * @url POST {id}/gateways
  1194. */
  1195. public function createSocieteAccount($id, $request_data = null)
  1196. {
  1197. if (!DolibarrApiAccess::$user->rights->societe->creer) {
  1198. throw new RestException(401);
  1199. }
  1200. if (!isset($request_data['site'])) {
  1201. throw new RestException(422, 'Unprocessable Entity: You must pass the site attribute in your request data !');
  1202. }
  1203. $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."societe_account WHERE fk_soc = ".((int) $id)." AND site = '".$this->db->escape($request_data['site'])."'";
  1204. $result = $this->db->query($sql);
  1205. if ($result && $this->db->num_rows($result) == 0) {
  1206. $account = new SocieteAccount($this->db);
  1207. if (!isset($request_data['login'])) {
  1208. $account->login = "";
  1209. }
  1210. $account->fk_soc = $id;
  1211. foreach ($request_data as $field => $value) {
  1212. if ($field === 'caller') {
  1213. // Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again whith the caller
  1214. $account->context['caller'] = $request_data['caller'];
  1215. continue;
  1216. }
  1217. $account->$field = $value;
  1218. }
  1219. if ($account->create(DolibarrApiAccess::$user) < 0) {
  1220. throw new RestException(500, 'Error creating SocieteAccount entity. Ensure that the ID of thirdparty provided does exist!');
  1221. }
  1222. $this->_cleanObjectDatas($account);
  1223. return $account;
  1224. } else {
  1225. throw new RestException(409, 'A SocieteAccount entity already exists for this company and site.');
  1226. }
  1227. }
  1228. /**
  1229. * Create and attach a new (or replace an existing) specific site gateway to a thirdparty
  1230. *
  1231. * You <strong>MUST</strong> pass all values to keep (otherwise, they will be deleted) !<br>
  1232. * If you just need to update specific fields prefer <code>PATCH /thirdparties/{id}/gateways/{site}</code> endpoint.<br><br>
  1233. * When a <strong>SocieteAccount</strong> entity does not exist for the <code>id</code> and <code>site</code>
  1234. * supplied, a new one will be created. In that case <code>fk_soc</code> and <code>site</code> members form
  1235. * request body payload will be ignored and <code>id</code> and <code>site</code> query strings parameters
  1236. * will be used instead.
  1237. *
  1238. * @param int $id ID of thirdparty
  1239. * @param string $site Site key
  1240. * @param array $request_data Request data
  1241. *
  1242. * @return array|mixed
  1243. *
  1244. * @throws RestException 401 Unauthorized: User does not have permission to read thirdparties
  1245. * @throws RestException 422 Unprocessable Entity: You must pass the site attribute in your request data !
  1246. * @throws RestException 500 Internal Server Error: Error updating SocieteAccount entity
  1247. *
  1248. * @url PUT {id}/gateways/{site}
  1249. */
  1250. public function putSocieteAccount($id, $site, $request_data = null)
  1251. {
  1252. if (!DolibarrApiAccess::$user->rights->societe->creer) {
  1253. throw new RestException(401);
  1254. }
  1255. $sql = "SELECT rowid, fk_user_creat, date_creation FROM ".MAIN_DB_PREFIX."societe_account WHERE fk_soc = $id AND site = '".$this->db->escape($site)."'";
  1256. $result = $this->db->query($sql);
  1257. // We do not found an existing SocieteAccount entity for this fk_soc and site ; we then create a new one.
  1258. if ($result && $this->db->num_rows == 0) {
  1259. if (!isset($request_data['key_account'])) {
  1260. throw new RestException(422, 'Unprocessable Entity: You must pass the key_account attribute in your request data !');
  1261. }
  1262. $account = new SocieteAccount($this->db);
  1263. if (!isset($request_data['login'])) {
  1264. $account->login = "";
  1265. }
  1266. foreach ($request_data as $field => $value) {
  1267. if ($field === 'caller') {
  1268. // Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again whith the caller
  1269. $account->context['caller'] = $request_data['caller'];
  1270. continue;
  1271. }
  1272. $account->$field = $value;
  1273. }
  1274. $account->fk_soc = $id;
  1275. $account->site = $site;
  1276. if ($account->create(DolibarrApiAccess::$user) < 0) {
  1277. throw new RestException(500, 'Error creating SocieteAccount entity.');
  1278. }
  1279. // We found an existing SocieteAccount entity, we are replacing it
  1280. } else {
  1281. if (isset($request_data['site']) && $request_data['site'] !== $site) {
  1282. $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."societe_account WHERE fk_soc = ".((int) $id)." AND site = '".$this->db->escape($request_data['site'])."' ";
  1283. $result = $this->db->query($sql);
  1284. if ($result && $this->db->num_rows($result) !== 0) {
  1285. throw new RestException(409, "You are trying to update this thirdparty SocieteAccount (gateway record) from $site to ".$request_data['site']." but another SocieteAccount entity already exists with this site key.");
  1286. }
  1287. }
  1288. $obj = $this->db->fetch_object($result);
  1289. $account = new SocieteAccount($this->db);
  1290. $account->id = $obj->rowid;
  1291. $account->fk_soc = $id;
  1292. $account->site = $site;
  1293. if (!isset($request_data['login'])) {
  1294. $account->login = "";
  1295. }
  1296. $account->fk_user_creat = $obj->fk_user_creat;
  1297. $account->date_creation = $obj->date_creation;
  1298. foreach ($request_data as $field => $value) {
  1299. if ($field === 'caller') {
  1300. // Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again whith the caller
  1301. $account->context['caller'] = $request_data['caller'];
  1302. continue;
  1303. }
  1304. $account->$field = $value;
  1305. }
  1306. if ($account->update(DolibarrApiAccess::$user) < 0) {
  1307. throw new RestException(500, 'Error updating SocieteAccount entity.');
  1308. }
  1309. }
  1310. $this->_cleanObjectDatas($account);
  1311. return $account;
  1312. }
  1313. /**
  1314. * Update specified values of a specific gateway attached to a thirdparty
  1315. *
  1316. * @param int $id Id of thirdparty
  1317. * @param string $site Site key
  1318. * @param array $request_data Request data
  1319. *
  1320. * @return array|mixed
  1321. *
  1322. * @throws RestException 401 Unauthorized: User does not have permission to read thirdparties
  1323. * @throws RestException 404 Not Found: Specified thirdparty ID does not belongs to an existing thirdparty
  1324. * @throws RestException 409 Conflict: Another SocieteAccount entity already exists for this thirdparty with this site key.
  1325. * @throws RestException 500 Internal Server Error: Error updating SocieteAccount entity
  1326. *
  1327. * @url PATCH {id}/gateways/{site}
  1328. */
  1329. public function patchSocieteAccount($id, $site, $request_data = null)
  1330. {
  1331. if (!DolibarrApiAccess::$user->rights->societe->creer) {
  1332. throw new RestException(401);
  1333. }
  1334. $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."societe_account WHERE fk_soc = ".((int) $id)." AND site = '".$this->db->escape($site)."'";
  1335. $result = $this->db->query($sql);
  1336. if ($result && $this->db->num_rows($result) == 0) {
  1337. throw new RestException(404, "This thirdparty does not have $site gateway attached or does not exist.");
  1338. } else {
  1339. // If the user tries to edit the site member, we check first if
  1340. if (isset($request_data['site']) && $request_data['site'] !== $site) {
  1341. $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."societe_account WHERE fk_soc = ".((int) $id)." AND site = '".$this->db->escape($request_data['site'])."' ";
  1342. $result = $this->db->query($sql);
  1343. if ($result && $this->db->num_rows($result) !== 0) {
  1344. throw new RestException(409, "You are trying to update this thirdparty SocieteAccount (gateway record) site member from ".$site." to ".$request_data['site']." but another SocieteAccount entity already exists for this thirdparty with this site key.");
  1345. }
  1346. }
  1347. $obj = $this->db->fetch_object($result);
  1348. $account = new SocieteAccount($this->db);
  1349. $account->fetch($obj->rowid);
  1350. foreach ($request_data as $field => $value) {
  1351. if ($field === 'caller') {
  1352. // Add a mention of caller so on trigger called after action, we can filter to avoid a loop if we try to sync back again whith the caller
  1353. $account->context['caller'] = $request_data['caller'];
  1354. continue;
  1355. }
  1356. $account->$field = $value;
  1357. }
  1358. if ($account->update(DolibarrApiAccess::$user) < 0) {
  1359. throw new RestException(500, 'Error updating SocieteAccount account');
  1360. }
  1361. $this->_cleanObjectDatas($account);
  1362. return $account;
  1363. }
  1364. }
  1365. /**
  1366. * Delete a specific site gateway attached to a thirdparty (by gateway id)
  1367. *
  1368. * @param int $id ID of thirdparty
  1369. * @param int $site Site key
  1370. *
  1371. * @return void
  1372. * @throws RestException 401 Unauthorized: User does not have permission to delete thirdparties gateways
  1373. * @throws RestException 404 Not Found: Specified thirdparty ID does not belongs to an existing thirdparty
  1374. * @throws RestException 500 Internal Server Error: Error deleting SocieteAccount entity
  1375. *
  1376. * @url DELETE {id}/gateways/{site}
  1377. */
  1378. public function deleteSocieteAccount($id, $site)
  1379. {
  1380. if (!DolibarrApiAccess::$user->rights->societe->creer) {
  1381. throw new RestException(401);
  1382. }
  1383. $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."societe_account WHERE fk_soc = $id AND site = '".$this->db->escape($site)."'";
  1384. $result = $this->db->query($sql);
  1385. if ($result && $this->db->num_rows($result) == 0) {
  1386. throw new RestException(404);
  1387. } else {
  1388. $obj = $this->db->fetch_object($result);
  1389. $account = new SocieteAccount($this->db);
  1390. $account->fetch($obj->rowid);
  1391. if ($account->delete(DolibarrApiAccess::$user) < 0) {
  1392. throw new RestException(500, "Error while deleting $site gateway attached to this third party");
  1393. }
  1394. }
  1395. }
  1396. /**
  1397. * Delete all gateways attached to a thirdparty
  1398. *
  1399. * @param int $id ID of thirdparty
  1400. *
  1401. * @return void
  1402. * @throws RestException 401 Unauthorized: User does not have permission to delete thirdparties gateways
  1403. * @throws RestException 404 Not Found: Specified thirdparty ID does not belongs to an existing thirdparty
  1404. * @throws RestException 500 Internal Server Error: Error deleting SocieteAccount entity
  1405. *
  1406. * @url DELETE {id}/gateways
  1407. */
  1408. public function deleteSocieteAccounts($id)
  1409. {
  1410. if (!DolibarrApiAccess::$user->rights->societe->creer) {
  1411. throw new RestException(401);
  1412. }
  1413. /**
  1414. * We select all the records that match the socid
  1415. */
  1416. $sql = "SELECT rowid, fk_soc, key_account, site, date_creation, tms";
  1417. $sql .= " FROM ".MAIN_DB_PREFIX."societe_account WHERE fk_soc = ".((int) $id);
  1418. $result = $this->db->query($sql);
  1419. if ($result && $this->db->num_rows($result) == 0) {
  1420. throw new RestException(404, 'This third party does not have any gateway attached or does not exist.');
  1421. } else {
  1422. $i = 0;
  1423. $num = $this->db->num_rows($result);
  1424. while ($i < $num) {
  1425. $obj = $this->db->fetch_object($result);
  1426. $account = new SocieteAccount($this->db);
  1427. $account->fetch($obj->rowid);
  1428. if ($account->delete(DolibarrApiAccess::$user) < 0) {
  1429. throw new RestException(500, 'Error while deleting gateways attached to this third party');
  1430. }
  1431. $i++;
  1432. }
  1433. }
  1434. }
  1435. // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
  1436. /**
  1437. * Clean sensible object datas
  1438. *
  1439. * @param Object $object Object to clean
  1440. * @return Object Object with cleaned properties
  1441. */
  1442. protected function _cleanObjectDatas($object)
  1443. {
  1444. // phpcs:enable
  1445. $object = parent::_cleanObjectDatas($object);
  1446. unset($object->nom); // ->name already defined and nom deprecated
  1447. unset($object->name_bis); // ->name_alias already defined
  1448. unset($object->note); // ->note_private and note_public already defined
  1449. unset($object->departement);
  1450. unset($object->departement_code);
  1451. unset($object->pays);
  1452. unset($object->particulier);
  1453. unset($object->prefix_comm);
  1454. unset($object->siren);
  1455. unset($object->siret);
  1456. unset($object->ape);
  1457. unset($object->commercial_id); // This property is used in create/update only. It does not exists in read mode because there is several sales representatives.
  1458. unset($object->total_ht);
  1459. unset($object->total_tva);
  1460. unset($object->total_localtax1);
  1461. unset($object->total_localtax2);
  1462. unset($object->total_ttc);
  1463. unset($object->lines);
  1464. unset($object->thirdparty);
  1465. unset($object->fk_delivery_address); // deprecated feature
  1466. return $object;
  1467. }
  1468. /**
  1469. * Validate fields before create or update object
  1470. *
  1471. * @param array $data Datas to validate
  1472. * @return array
  1473. *
  1474. * @throws RestException
  1475. */
  1476. private function _validate($data)
  1477. {
  1478. $thirdparty = array();
  1479. foreach (Thirdparties::$FIELDS as $field) {
  1480. if (!isset($data[$field])) {
  1481. throw new RestException(400, "$field field missing");
  1482. }
  1483. $thirdparty[$field] = $data[$field];
  1484. }
  1485. return $thirdparty;
  1486. }
  1487. /**
  1488. * Fetch properties of a thirdparty object.
  1489. *
  1490. * Return an array with thirdparty informations
  1491. *
  1492. * @param int $rowid Id of third party to load (Use 0 to get a specimen record, use null to use other search criterias)
  1493. * @param string $ref Reference of third party, name (Warning, this can return several records)
  1494. * @param string $ref_ext External reference of third party (Warning, this information is a free field not provided by Dolibarr)
  1495. * @param string $barcode Barcode of third party to load
  1496. * @param string $idprof1 Prof id 1 of third party (Warning, this can return several records)
  1497. * @param string $idprof2 Prof id 2 of third party (Warning, this can return several records)
  1498. * @param string $idprof3 Prof id 3 of third party (Warning, this can return several records)
  1499. * @param string $idprof4 Prof id 4 of third party (Warning, this can return several records)
  1500. * @param string $idprof5 Prof id 5 of third party (Warning, this can return several records)
  1501. * @param string $idprof6 Prof id 6 of third party (Warning, this can return several records)
  1502. * @param string $email Email of third party (Warning, this can return several records)
  1503. * @param string $ref_alias Name_alias of third party (Warning, this can return several records)
  1504. * @return array|mixed cleaned Societe object
  1505. *
  1506. * @throws RestException
  1507. */
  1508. private function _fetch($rowid, $ref = '', $ref_ext = '', $barcode = '', $idprof1 = '', $idprof2 = '', $idprof3 = '', $idprof4 = '', $idprof5 = '', $idprof6 = '', $email = '', $ref_alias = '')
  1509. {
  1510. global $conf;
  1511. if (!DolibarrApiAccess::$user->hasRight('societe', 'lire')) {
  1512. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login.'. No read permission on thirdparties.');
  1513. }
  1514. if ($rowid === 0) {
  1515. $result = $this->company->initAsSpecimen();
  1516. } else {
  1517. $result = $this->company->fetch($rowid, $ref, $ref_ext, $barcode, $idprof1, $idprof2, $idprof3, $idprof4, $idprof5, $idprof6, $email, $ref_alias);
  1518. }
  1519. if (!$result) {
  1520. throw new RestException(404, 'Thirdparty not found');
  1521. }
  1522. if (!DolibarrApi::_checkAccessToResource('societe', $this->company->id)) {
  1523. throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login.' on this thirdparty');
  1524. }
  1525. if (isModEnabled('mailing')) {
  1526. $this->company->getNoEmail();
  1527. }
  1528. if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS')) {
  1529. $filterabsolutediscount = "fk_facture_source IS NULL"; // If we want deposit to be substracted to payments only and not to total of final invoice
  1530. $filtercreditnote = "fk_facture_source IS NOT NULL"; // If we want deposit to be substracted to payments only and not to total of final invoice
  1531. } else {
  1532. $filterabsolutediscount = "fk_facture_source IS NULL OR (description LIKE '(DEPOSIT)%' AND description NOT LIKE '(EXCESS RECEIVED)%')";
  1533. $filtercreditnote = "fk_facture_source IS NOT NULL AND (description NOT LIKE '(DEPOSIT)%' OR description LIKE '(EXCESS RECEIVED)%')";
  1534. }
  1535. $absolute_discount = $this->company->getAvailableDiscounts('', $filterabsolutediscount);
  1536. $absolute_creditnote = $this->company->getAvailableDiscounts('', $filtercreditnote);
  1537. $this->company->absolute_discount = price2num($absolute_discount, 'MT');
  1538. $this->company->absolute_creditnote = price2num($absolute_creditnote, 'MT');
  1539. return $this->_cleanObjectDatas($this->company);
  1540. }
  1541. }