1<?php 2/* Copyright (C) 2016 Xebax Christy <xebax@wanadoo.fr> 3 * Copyright (C) 2017 Regis Houssin <regis.houssin@inodbox.com> 4 * Copyright (C) 2020 Thibault FOUCART<support@ptibogxiv.net> 5 * Copyright (C) 2020 Frédéric France <frederic.france@netlogic.fr> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program. If not, see <https://www.gnu.org/licenses/>. 19 */ 20 21use Luracast\Restler\RestException; 22 23require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php'; 24require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php'; 25require_once DOL_DOCUMENT_ROOT.'/adherents/class/subscription.class.php'; 26require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; 27 28/** 29 * API class for members 30 * 31 * @access protected 32 * @class DolibarrApiAccess {@requires user,external} 33 */ 34class Members extends DolibarrApi 35{ 36 /** 37 * @var array $FIELDS Mandatory fields, checked when create and update object 38 */ 39 public static $FIELDS = array( 40 'morphy', 41 'typeid' 42 ); 43 44 /** 45 * Constructor 46 */ 47 public function __construct() 48 { 49 global $db, $conf; 50 $this->db = $db; 51 } 52 53 /** 54 * Get properties of a member object 55 * 56 * Return an array with member informations 57 * 58 * @param int $id ID of member 59 * @return array|mixed data without useless information 60 * 61 * @throws RestException 62 */ 63 public function get($id) 64 { 65 if (!DolibarrApiAccess::$user->rights->adherent->lire) { 66 throw new RestException(401); 67 } 68 69 $member = new Adherent($this->db); 70 if ($id == 0) { 71 $result = $member->initAsSpecimen(); 72 } else { 73 $result = $member->fetch($id); 74 } 75 if (!$result) { 76 throw new RestException(404, 'member not found'); 77 } 78 79 if (!DolibarrApi::_checkAccessToResource('adherent', $member->id) && $id > 0) { 80 throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); 81 } 82 83 return $this->_cleanObjectDatas($member); 84 } 85 86 /** 87 * Get properties of a member object by linked thirdparty 88 * 89 * Return an array with member informations 90 * 91 * @param int $thirdparty ID of third party 92 * 93 * @return Object Data without useless information 94 * 95 * @url GET thirdparty/{thirdparty} 96 * 97 * @throws RestException 401 98 * @throws RestException 404 99 */ 100 public function getByThirdparty($thirdparty) 101 { 102 if (!DolibarrApiAccess::$user->rights->adherent->lire) { 103 throw new RestException(401); 104 } 105 106 $member = new Adherent($this->db); 107 $result = $member->fetch('', '', $thirdparty); 108 if (!$result) { 109 throw new RestException(404, 'member not found'); 110 } 111 112 if (!DolibarrApi::_checkAccessToResource('adherent', $member->id)) { 113 throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); 114 } 115 116 return $this->_cleanObjectDatas($member); 117 } 118 119 /** 120 * Get properties of a member object by linked thirdparty email 121 * 122 * Return an array with member informations 123 * 124 * @param string $email Email of third party 125 * 126 * @return Object Data without useless information 127 * 128 * @url GET thirdparty/email/{email} 129 * 130 * @throws RestException 401 131 * @throws RestException 404 132 */ 133 public function getByThirdpartyEmail($email) 134 { 135 if (!DolibarrApiAccess::$user->rights->adherent->lire) { 136 throw new RestException(401); 137 } 138 139 $thirdparty = new Societe($this->db); 140 $result = $thirdparty->fetch('', '', '', '', '', '', '', '', '', '', $email); 141 if (!$result) { 142 throw new RestException(404, 'thirdparty not found'); 143 } 144 145 $member = new Adherent($this->db); 146 $result = $member->fetch('', '', $thirdparty->id); 147 if (!$result) { 148 throw new RestException(404, 'member not found'); 149 } 150 151 if (!DolibarrApi::_checkAccessToResource('adherent', $member->id)) { 152 throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); 153 } 154 155 return $this->_cleanObjectDatas($member); 156 } 157 158 /** 159 * Get properties of a member object by linked thirdparty barcode 160 * 161 * Return an array with member informations 162 * 163 * @param string $barcode Barcode of third party 164 * 165 * @return Object Data without useless information 166 * 167 * @url GET thirdparty/barcode/{barcode} 168 * 169 * @throws RestException 401 170 * @throws RestException 404 171 */ 172 public function getByThirdpartyBarcode($barcode) 173 { 174 if (!DolibarrApiAccess::$user->rights->adherent->lire) { 175 throw new RestException(401); 176 } 177 178 $thirdparty = new Societe($this->db); 179 $result = $thirdparty->fetch('', '', '', $barcode); 180 if (!$result) { 181 throw new RestException(404, 'thirdparty not found'); 182 } 183 184 $member = new Adherent($this->db); 185 $result = $member->fetch('', '', $thirdparty->id); 186 if (!$result) { 187 throw new RestException(404, 'member not found'); 188 } 189 190 if (!DolibarrApi::_checkAccessToResource('adherent', $member->id)) { 191 throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); 192 } 193 194 return $this->_cleanObjectDatas($member); 195 } 196 197 /** 198 * List members 199 * 200 * Get a list of members 201 * 202 * @param string $sortfield Sort field 203 * @param string $sortorder Sort order 204 * @param int $limit Limit for list 205 * @param int $page Page number 206 * @param string $typeid ID of the type of member 207 * @param int $category Use this param to filter list by category 208 * @param string $sqlfilters Other criteria to filter answers separated by a comma. 209 * Example: "(t.ref:like:'SO-%') and ((t.date_creation:<:'20160101') or (t.nature:is:NULL))" 210 * @return array Array of member objects 211 * 212 * @throws RestException 213 */ 214 public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $typeid = '', $category = 0, $sqlfilters = '') 215 { 216 global $db, $conf; 217 218 $obj_ret = array(); 219 220 if (!DolibarrApiAccess::$user->rights->adherent->lire) { 221 throw new RestException(401); 222 } 223 224 $sql = "SELECT t.rowid"; 225 $sql .= " FROM ".MAIN_DB_PREFIX."adherent as t"; 226 if ($category > 0) { 227 $sql .= ", ".MAIN_DB_PREFIX."categorie_member as c"; 228 } 229 $sql .= ' WHERE t.entity IN ('.getEntity('adherent').')'; 230 if (!empty($typeid)) { 231 $sql .= ' AND t.fk_adherent_type='.((int) $typeid); 232 } 233 // Select members of given category 234 if ($category > 0) { 235 $sql .= " AND c.fk_categorie = ".((int) $category); 236 $sql .= " AND c.fk_member = t.rowid"; 237 } 238 // Add sql filters 239 if ($sqlfilters) { 240 if (!DolibarrApi::_checkFilters($sqlfilters)) { 241 throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters); 242 } 243 $regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)'; 244 $sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")"; 245 } 246 247 $sql .= $this->db->order($sortfield, $sortorder); 248 if ($limit) { 249 if ($page < 0) { 250 $page = 0; 251 } 252 $offset = $limit * $page; 253 254 $sql .= $this->db->plimit($limit + 1, $offset); 255 } 256 257 $result = $this->db->query($sql); 258 if ($result) { 259 $i = 0; 260 $num = $this->db->num_rows($result); 261 $min = min($num, ($limit <= 0 ? $num : $limit)); 262 while ($i < $min) { 263 $obj = $this->db->fetch_object($result); 264 $member = new Adherent($this->db); 265 if ($member->fetch($obj->rowid)) { 266 $obj_ret[] = $this->_cleanObjectDatas($member); 267 } 268 $i++; 269 } 270 } else { 271 throw new RestException(503, 'Error when retrieve member list : '.$this->db->lasterror()); 272 } 273 if (!count($obj_ret)) { 274 throw new RestException(404, 'No member found'); 275 } 276 277 return $obj_ret; 278 } 279 280 /** 281 * Create member object 282 * 283 * @param array $request_data Request data 284 * @return int ID of member 285 */ 286 public function post($request_data = null) 287 { 288 if (!DolibarrApiAccess::$user->rights->adherent->creer) { 289 throw new RestException(401); 290 } 291 // Check mandatory fields 292 $result = $this->_validate($request_data); 293 294 $member = new Adherent($this->db); 295 foreach ($request_data as $field => $value) { 296 $member->$field = $value; 297 } 298 if ($member->create(DolibarrApiAccess::$user) < 0) { 299 throw new RestException(500, 'Error creating member', array_merge(array($member->error), $member->errors)); 300 } 301 return $member->id; 302 } 303 304 /** 305 * Update member 306 * 307 * @param int $id ID of member to update 308 * @param array $request_data Datas 309 * @return Object Updated object 310 */ 311 public function put($id, $request_data = null) 312 { 313 if (!DolibarrApiAccess::$user->rights->adherent->creer) { 314 throw new RestException(401); 315 } 316 317 $member = new Adherent($this->db); 318 $result = $member->fetch($id); 319 if (!$result) { 320 throw new RestException(404, 'member not found'); 321 } 322 323 if (!DolibarrApi::_checkAccessToResource('member', $member->id)) { 324 throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); 325 } 326 327 foreach ($request_data as $field => $value) { 328 if ($field == 'id') { 329 continue; 330 } 331 // Process the status separately because it must be updated using 332 // the validate(), resiliate() and exclude() methods of the class Adherent. 333 if ($field == 'statut') { 334 if ($value == '0') { 335 $result = $member->resiliate(DolibarrApiAccess::$user); 336 if ($result < 0) { 337 throw new RestException(500, 'Error when resiliating member: '.$member->error); 338 } 339 } elseif ($value == '1') { 340 $result = $member->validate(DolibarrApiAccess::$user); 341 if ($result < 0) { 342 throw new RestException(500, 'Error when validating member: '.$member->error); 343 } 344 } elseif ($value == '-2') { 345 $result = $member->exclude(DolibarrApiAccess::$user); 346 if ($result < 0) { 347 throw new RestException(500, 'Error when excluding member: '.$member->error); 348 } 349 } 350 } else { 351 $member->$field = $value; 352 } 353 } 354 355 // If there is no error, update() returns the number of affected rows 356 // so if the update is a no op, the return value is zero. 357 if ($member->update(DolibarrApiAccess::$user) >= 0) { 358 return $this->get($id); 359 } else { 360 throw new RestException(500, $member->error); 361 } 362 } 363 364 /** 365 * Delete member 366 * 367 * @param int $id member ID 368 * @return array 369 */ 370 public function delete($id) 371 { 372 if (!DolibarrApiAccess::$user->rights->adherent->supprimer) { 373 throw new RestException(401); 374 } 375 $member = new Adherent($this->db); 376 $result = $member->fetch($id); 377 if (!$result) { 378 throw new RestException(404, 'member not found'); 379 } 380 381 if (!DolibarrApi::_checkAccessToResource('member', $member->id)) { 382 throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login); 383 } 384 385 if (!$member->delete($member->id, DolibarrApiAccess::$user)) { 386 throw new RestException(401, 'error when deleting member'); 387 } 388 389 return array( 390 'success' => array( 391 'code' => 200, 392 'message' => 'member deleted' 393 ) 394 ); 395 } 396 397 /** 398 * Validate fields before creating an object 399 * 400 * @param array|null $data Data to validate 401 * @return array 402 * 403 * @throws RestException 404 */ 405 private function _validate($data) 406 { 407 $member = array(); 408 foreach (Members::$FIELDS as $field) { 409 if (!isset($data[$field])) { 410 throw new RestException(400, "$field field missing"); 411 } 412 $member[$field] = $data[$field]; 413 } 414 return $member; 415 } 416 417 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore 418 /** 419 * Clean sensible object datas 420 * 421 * @param Object $object Object to clean 422 * @return Object Object with cleaned properties 423 */ 424 protected function _cleanObjectDatas($object) 425 { 426 // phpcs:enable 427 $object = parent::_cleanObjectDatas($object); 428 429 // Remove the subscriptions because they are handled as a subresource. 430 unset($object->subscriptions); 431 unset($object->fk_incoterms); 432 unset($object->label_incoterms); 433 unset($object->location_incoterms); 434 unset($object->fk_delivery_address); 435 unset($object->shipping_method_id); 436 437 unset($object->total_ht); 438 unset($object->total_ttc); 439 unset($object->total_tva); 440 unset($object->total_localtax1); 441 unset($object->total_localtax2); 442 443 return $object; 444 } 445 446 /** 447 * List subscriptions of a member 448 * 449 * Get a list of subscriptions 450 * 451 * @param int $id ID of member 452 * @return array Array of subscription objects 453 * 454 * @throws RestException 455 * 456 * @url GET {id}/subscriptions 457 */ 458 public function getSubscriptions($id) 459 { 460 $obj_ret = array(); 461 462 if (!DolibarrApiAccess::$user->rights->adherent->cotisation->lire) { 463 throw new RestException(401); 464 } 465 466 $member = new Adherent($this->db); 467 $result = $member->fetch($id); 468 if (!$result) { 469 throw new RestException(404, 'member not found'); 470 } 471 472 $obj_ret = array(); 473 foreach ($member->subscriptions as $subscription) { 474 $obj_ret[] = $this->_cleanObjectDatas($subscription); 475 } 476 return $obj_ret; 477 } 478 479 /** 480 * Add a subscription for a member 481 * 482 * @param int $id ID of member 483 * @param int $start_date Start date {@from body} {@type timestamp} 484 * @param int $end_date End date {@from body} {@type timestamp} 485 * @param float $amount Amount (may be 0) {@from body} 486 * @param string $label Label {@from body} 487 * @return int ID of subscription 488 * 489 * @url POST {id}/subscriptions 490 */ 491 public function createSubscription($id, $start_date, $end_date, $amount, $label = '') 492 { 493 if (!DolibarrApiAccess::$user->rights->adherent->cotisation->creer) { 494 throw new RestException(401); 495 } 496 497 $member = new Adherent($this->db); 498 $result = $member->fetch($id); 499 if (!$result) { 500 throw new RestException(404, 'member not found'); 501 } 502 503 return $member->subscription($start_date, $amount, 0, '', $label, '', '', '', $end_date); 504 } 505 506 /** 507 * Get categories for a member 508 * 509 * @param int $id ID of member 510 * @param string $sortfield Sort field 511 * @param string $sortorder Sort order 512 * @param int $limit Limit for list 513 * @param int $page Page number 514 * 515 * @return mixed 516 * 517 * @url GET {id}/categories 518 */ 519 public function getCategories($id, $sortfield = "s.rowid", $sortorder = 'ASC', $limit = 0, $page = 0) 520 { 521 if (!DolibarrApiAccess::$user->rights->categorie->lire) { 522 throw new RestException(401); 523 } 524 525 $categories = new Categorie($this->db); 526 527 $result = $categories->getListForItem($id, 'member', $sortfield, $sortorder, $limit, $page); 528 529 if (empty($result)) { 530 throw new RestException(404, 'No category found'); 531 } 532 533 if ($result < 0) { 534 throw new RestException(503, 'Error when retrieve category list : '.$categories->error); 535 } 536 537 return $result; 538 } 539} 540