dolibarr 20.0.5
api_members.class.php
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-2024 Frédéric France <frederic.france@free.fr>
6 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22use Luracast\Restler\RestException;
23
24require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
25require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php';
26require_once DOL_DOCUMENT_ROOT.'/adherents/class/subscription.class.php';
27require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
28require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent_type.class.php';
29
30
37class Members extends DolibarrApi
38{
42 public static $FIELDS = array(
43 'morphy',
44 'typeid'
45 );
46
50 public function __construct()
51 {
52 global $db;
53 $this->db = $db;
54 }
55
67 public function get($id)
68 {
69 if (!DolibarrApiAccess::$user->hasRight('adherent', 'lire')) {
70 throw new RestException(403);
71 }
72
73 $member = new Adherent($this->db);
74 if ($id == 0) {
75 $result = $member->initAsSpecimen();
76 } else {
77 $result = $member->fetch($id);
78 }
79 if (!$result) {
80 throw new RestException(404, 'member not found');
81 }
82
83 if (!DolibarrApi::_checkAccessToResource('adherent', $member->id) && $id > 0) {
84 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
85 }
86
87 return $this->_cleanObjectDatas($member);
88 }
89
104 public function getByThirdparty($thirdparty)
105 {
106 if (!DolibarrApiAccess::$user->hasRight('adherent', 'lire')) {
107 throw new RestException(403);
108 }
109
110 $member = new Adherent($this->db);
111 $result = $member->fetch('', '', $thirdparty);
112 if (!$result) {
113 throw new RestException(404, 'member not found');
114 }
115
116 if (!DolibarrApi::_checkAccessToResource('adherent', $member->id)) {
117 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
118 }
119
120 return $this->_cleanObjectDatas($member);
121 }
122
137 public function getByThirdpartyEmail($email)
138 {
139 if (!DolibarrApiAccess::$user->hasRight('adherent', 'lire')) {
140 throw new RestException(403);
141 }
142
143 $thirdparty = new Societe($this->db);
144 $result = $thirdparty->fetch('', '', '', '', '', '', '', '', '', '', $email);
145 if (!$result) {
146 throw new RestException(404, 'thirdparty not found');
147 }
148
149 $member = new Adherent($this->db);
150 $result = $member->fetch('', '', $thirdparty->id);
151 if (!$result) {
152 throw new RestException(404, 'member not found');
153 }
154
155 if (!DolibarrApi::_checkAccessToResource('adherent', $member->id)) {
156 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
157 }
158
159 return $this->_cleanObjectDatas($member);
160 }
161
176 public function getByThirdpartyBarcode($barcode)
177 {
178 if (!DolibarrApiAccess::$user->hasRight('adherent', 'lire')) {
179 throw new RestException(403);
180 }
181
182 $thirdparty = new Societe($this->db);
183 $result = $thirdparty->fetch('', '', '', $barcode);
184 if (!$result) {
185 throw new RestException(404, 'thirdparty not found');
186 }
187
188 $member = new Adherent($this->db);
189 $result = $member->fetch('', '', $thirdparty->id);
190 if (!$result) {
191 throw new RestException(404, 'member not found');
192 }
193
194 if (!DolibarrApi::_checkAccessToResource('adherent', $member->id)) {
195 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
196 }
197
198 return $this->_cleanObjectDatas($member);
199 }
200
222 public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $typeid = '', $category = 0, $sqlfilters = '', $properties = '')
223 {
224 $obj_ret = array();
225
226 if (!DolibarrApiAccess::$user->hasRight('adherent', 'lire')) {
227 throw new RestException(403);
228 }
229
230 $sql = "SELECT t.rowid";
231 $sql .= " FROM ".MAIN_DB_PREFIX."adherent AS t LEFT JOIN ".MAIN_DB_PREFIX."adherent_extrafields AS ef ON (ef.fk_object = t.rowid)"; // Modification VMR Global Solutions to include extrafields as search parameters in the API GET call
232 if ($category > 0) {
233 $sql .= ", ".MAIN_DB_PREFIX."categorie_member as c";
234 }
235 $sql .= ' WHERE t.entity IN ('.getEntity('adherent').')';
236 if (!empty($typeid)) {
237 $sql .= ' AND t.fk_adherent_type='.((int) $typeid);
238 }
239 // Select members of given category
240 if ($category > 0) {
241 $sql .= " AND c.fk_categorie = ".((int) $category);
242 $sql .= " AND c.fk_member = t.rowid";
243 }
244 // Add sql filters
245 if ($sqlfilters) {
246 $errormessage = '';
247 $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
248 if ($errormessage) {
249 throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
250 }
251 }
252
253 $sql .= $this->db->order($sortfield, $sortorder);
254 if ($limit) {
255 if ($page < 0) {
256 $page = 0;
257 }
258 $offset = $limit * $page;
259
260 $sql .= $this->db->plimit($limit + 1, $offset);
261 }
262
263 $result = $this->db->query($sql);
264 if ($result) {
265 $i = 0;
266 $num = $this->db->num_rows($result);
267 $min = min($num, ($limit <= 0 ? $num : $limit));
268 while ($i < $min) {
269 $obj = $this->db->fetch_object($result);
270 $member = new Adherent($this->db);
271 if ($member->fetch($obj->rowid)) {
272 $obj_ret[] = $this->_filterObjectProperties($this->_cleanObjectDatas($member), $properties);
273 }
274 $i++;
275 }
276 } else {
277 throw new RestException(503, 'Error when retrieve member list : '.$this->db->lasterror());
278 }
279
280 return $obj_ret;
281 }
282
294 public function post($request_data = null)
295 {
296 if (!DolibarrApiAccess::$user->hasRight('adherent', 'creer')) {
297 throw new RestException(403);
298 }
299 // Check mandatory fields
300 $result = $this->_validate($request_data);
301
302 $member = new Adherent($this->db);
303 foreach ($request_data as $field => $value) {
304 if ($field === 'caller') {
305 // 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 with the caller
306 $member->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
307 continue;
308 }
309
310 $member->$field = $this->_checkValForAPI($field, $value, $member);
311 }
312 if ($member->create(DolibarrApiAccess::$user) < 0) {
313 throw new RestException(500, 'Error creating member', array_merge(array($member->error), $member->errors));
314 }
315 return $member->id;
316 }
317
329 public function put($id, $request_data = null)
330 {
331 if (!DolibarrApiAccess::$user->hasRight('adherent', 'creer')) {
332 throw new RestException(403);
333 }
334
335 $member = new Adherent($this->db);
336 $result = $member->fetch($id);
337 if (!$result) {
338 throw new RestException(404, 'member not found');
339 }
340
341 if (!DolibarrApi::_checkAccessToResource('member', $member->id)) {
342 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
343 }
344
345 foreach ($request_data as $field => $value) {
346 if ($field == 'id') {
347 continue;
348 }
349 if ($field === 'caller') {
350 // 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 with the caller
351 $member->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
352 continue;
353 }
354 if ($field == 'array_options' && is_array($value)) {
355 foreach ($value as $index => $val) {
356 $member->array_options[$index] = $this->_checkValForAPI($field, $val, $member);
357 }
358 continue;
359 }
360 // Process the status separately because it must be updated using
361 // the validate(), resiliate() and exclude() methods of the class Adherent.
362 if ($field == 'statut') {
363 if ($value == '0') {
364 $result = $member->resiliate(DolibarrApiAccess::$user);
365 if ($result < 0) {
366 throw new RestException(500, 'Error when resiliating member: '.$member->error);
367 }
368 } elseif ($value == '1') {
369 $result = $member->validate(DolibarrApiAccess::$user);
370 if ($result < 0) {
371 throw new RestException(500, 'Error when validating member: '.$member->error);
372 }
373 } elseif ($value == '-2') {
374 $result = $member->exclude(DolibarrApiAccess::$user);
375 if ($result < 0) {
376 throw new RestException(500, 'Error when excluding member: '.$member->error);
377 }
378 }
379 } else {
380 $member->$field = $this->_checkValForAPI($field, $value, $member);
381 }
382 }
383
384 // If there is no error, update() returns the number of affected rows
385 // so if the update is a no op, the return value is zero.
386 if ($member->update(DolibarrApiAccess::$user) >= 0) {
387 return $this->get($id);
388 } else {
389 throw new RestException(500, 'Error when updating member: '.$member->error);
390 }
391 }
392
403 public function delete($id)
404 {
405 if (!DolibarrApiAccess::$user->hasRight('adherent', 'supprimer')) {
406 throw new RestException(403);
407 }
408 $member = new Adherent($this->db);
409 $result = $member->fetch($id);
410 if (!$result) {
411 throw new RestException(404, 'member not found');
412 }
413
414 if (!DolibarrApi::_checkAccessToResource('member', $member->id)) {
415 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
416 }
417
418
419 $res = $member->delete(DolibarrApiAccess::$user);
420 if ($res < 0) {
421 throw new RestException(500, "Can't delete, error occurs");
422 }
423
424 return array(
425 'success' => array(
426 'code' => 200,
427 'message' => 'Member deleted'
428 )
429 );
430 }
431
440 private function _validate($data)
441 {
442 $member = array();
443
444 $mandatoryfields = array(
445 'morphy',
446 'typeid'
447 );
448 foreach ($mandatoryfields as $field) {
449 if (!isset($data[$field])) {
450 throw new RestException(400, "$field field missing");
451 }
452 $member[$field] = $data[$field];
453 }
454 return $member;
455 }
456
457 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
464 protected function _cleanObjectDatas($object)
465 {
466 // phpcs:enable
467 $object = parent::_cleanObjectDatas($object);
468
469 // Remove the subscriptions because they are handled as a subresource.
470 if ($object instanceof Adherent) {
471 unset($object->subscriptions);
472 unset($object->fk_incoterms);
473 unset($object->label_incoterms);
474 unset($object->location_incoterms);
475 unset($object->fk_delivery_address);
476 unset($object->shipping_method_id);
477
478 unset($object->total_ht);
479 unset($object->total_ttc);
480 unset($object->total_tva);
481 unset($object->total_localtax1);
482 unset($object->total_localtax2);
483 }
484
485 if ($object instanceof AdherentType) {
486 unset($object->linkedObjectsIds);
487 unset($object->context);
488 unset($object->canvas);
489 unset($object->fk_project);
490 unset($object->contact);
491 unset($object->contact_id);
492 unset($object->thirdparty);
493 unset($object->user);
494 unset($object->origin);
495 unset($object->origin_id);
496 unset($object->ref_ext);
497 unset($object->country);
498 unset($object->country_id);
499 unset($object->country_code);
500 unset($object->barcode_type);
501 unset($object->barcode_type_code);
502 unset($object->barcode_type_label);
503 unset($object->barcode_type_coder);
504 unset($object->mode_reglement_id);
505 unset($object->cond_reglement_id);
506 unset($object->cond_reglement);
507 unset($object->fk_delivery_address);
508 unset($object->shipping_method_id);
509 unset($object->model_pdf);
510 unset($object->fk_account);
511 unset($object->note_public);
512 unset($object->note_private);
513 unset($object->fk_incoterms);
514 unset($object->label_incoterms);
515 unset($object->location_incoterms);
516 unset($object->name);
517 unset($object->lastname);
518 unset($object->firstname);
519 unset($object->civility_id);
520 unset($object->total_ht);
521 unset($object->total_tva);
522 unset($object->total_localtax1);
523 unset($object->total_localtax2);
524 unset($object->total_ttc);
525 }
526
527 return $object;
528 }
529
543 public function getSubscriptions($id)
544 {
545 if (!DolibarrApiAccess::$user->hasRight('adherent', 'cotisation', 'lire')) {
546 throw new RestException(403);
547 }
548
549 $member = new Adherent($this->db);
550 $result = $member->fetch($id);
551 if (!$result) {
552 throw new RestException(404, 'member not found');
553 }
554
555 $obj_ret = array();
556 foreach ($member->subscriptions as $subscription) {
557 $obj_ret[] = $this->_cleanObjectDatas($subscription);
558 }
559 return $obj_ret;
560 }
561
577 public function createSubscription($id, $start_date, $end_date, $amount, $label = '')
578 {
579 if (!DolibarrApiAccess::$user->hasRight('adherent', 'cotisation', 'creer')) {
580 throw new RestException(403);
581 }
582
583 $member = new Adherent($this->db);
584 $result = $member->fetch($id);
585 if (!$result) {
586 throw new RestException(404, 'member not found');
587 }
588
589 return $member->subscription($start_date, $amount, 0, '', $label, '', '', '', $end_date);
590 }
591
609 public function getCategories($id, $sortfield = "s.rowid", $sortorder = 'ASC', $limit = 0, $page = 0)
610 {
611 if (!DolibarrApiAccess::$user->hasRight('categorie', 'lire')) {
612 throw new RestException(403);
613 }
614
615 $categories = new Categorie($this->db);
616
617 $result = $categories->getListForItem($id, 'member', $sortfield, $sortorder, $limit, $page);
618
619 if ($result < 0) {
620 throw new RestException(503, 'Error when retrieve category list : '.$categories->error);
621 }
622
623 return $result;
624 }
625
626
627
628
642 public function getType($id)
643 {
644 if (!DolibarrApiAccess::$user->hasRight('adherent', 'lire')) {
645 throw new RestException(403);
646 }
647
648 $membertype = new AdherentType($this->db);
649 $result = $membertype->fetch($id);
650 if (!$result) {
651 throw new RestException(404, 'member type not found');
652 }
653
654 if (!DolibarrApi::_checkAccessToResource('member', $membertype->id, 'adherent_type')) {
655 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
656 }
657
658 return $this->_cleanObjectDatas($membertype);
659 }
660
680 public function indexType($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $sqlfilters = '', $properties = '')
681 {
682 $obj_ret = array();
683
684 if (!DolibarrApiAccess::$user->hasRight('adherent', 'lire')) {
685 throw new RestException(403);
686 }
687
688 $sql = "SELECT t.rowid";
689 $sql .= " FROM ".MAIN_DB_PREFIX."adherent_type AS t LEFT JOIN ".MAIN_DB_PREFIX."adherent_type_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
690 $sql .= ' WHERE t.entity IN ('.getEntity('member_type').')';
691
692 // Add sql filters
693 if ($sqlfilters) {
694 $errormessage = '';
695 $sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
696 if ($errormessage) {
697 throw new RestException(503, 'Error when validating parameter sqlfilters -> '.$errormessage);
698 }
699 }
700
701 $sql .= $this->db->order($sortfield, $sortorder);
702 if ($limit) {
703 if ($page < 0) {
704 $page = 0;
705 }
706 $offset = $limit * $page;
707
708 $sql .= $this->db->plimit($limit + 1, $offset);
709 }
710
711 $result = $this->db->query($sql);
712 if ($result) {
713 $i = 0;
714 $num = $this->db->num_rows($result);
715 $min = min($num, ($limit <= 0 ? $num : $limit));
716 while ($i < $min) {
717 $obj = $this->db->fetch_object($result);
718 $membertype = new AdherentType($this->db);
719 if ($membertype->fetch($obj->rowid)) {
720 $obj_ret[] = $this->_filterObjectProperties($this->_cleanObjectDatas($membertype), $properties);
721 }
722 $i++;
723 }
724 } else {
725 throw new RestException(503, 'Error when retrieve member type list : '.$this->db->lasterror());
726 }
727
728 return $obj_ret;
729 }
730
742 public function postType($request_data = null)
743 {
744 if (!DolibarrApiAccess::$user->hasRight('adherent', 'configurer')) {
745 throw new RestException(403);
746 }
747 // Check mandatory fields
748 $result = $this->_validateType($request_data);
749
750 $membertype = new AdherentType($this->db);
751 foreach ($request_data as $field => $value) {
752 if ($field === 'caller') {
753 // 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 with the caller
754 $membertype->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
755 continue;
756 }
757
758 $membertype->$field = $this->_checkValForAPI($field, $value, $membertype);
759 }
760 if ($membertype->create(DolibarrApiAccess::$user) < 0) {
761 throw new RestException(500, 'Error creating member type', array_merge(array($membertype->error), $membertype->errors));
762 }
763 return $membertype->id;
764 }
765
779 public function putType($id, $request_data = null)
780 {
781 if (!DolibarrApiAccess::$user->hasRight('adherent', 'configurer')) {
782 throw new RestException(403);
783 }
784
785 $membertype = new AdherentType($this->db);
786 $result = $membertype->fetch($id);
787 if (!$result) {
788 throw new RestException(404, 'member type not found');
789 }
790
791 if (!DolibarrApi::_checkAccessToResource('member', $membertype->id, 'adherent_type')) {
792 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
793 }
794
795 foreach ($request_data as $field => $value) {
796 if ($field == 'id') {
797 continue;
798 }
799 if ($field === 'caller') {
800 // 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 with the caller
801 $membertype->context['caller'] = sanitizeVal($request_data['caller'], 'aZ09');
802 continue;
803 }
804 if ($field == 'array_options' && is_array($value)) {
805 foreach ($value as $index => $val) {
806 $membertype->array_options[$index] = $val;
807 }
808 continue;
809 }
810 // Process the status separately because it must be updated using
811 // the validate(), resiliate() and exclude() methods of the class AdherentType.
812 $membertype->$field = $this->_checkValForAPI($field, $value, $membertype);
813 }
814
815 // If there is no error, update() returns the number of affected rows
816 // so if the update is a no op, the return value is zero.
817 if ($membertype->update(DolibarrApiAccess::$user) >= 0) {
818 return $this->get($id);
819 } else {
820 throw new RestException(500, 'Error when updating member type: '.$membertype->error);
821 }
822 }
823
836 public function deleteType($id)
837 {
838 if (!DolibarrApiAccess::$user->hasRight('adherent', 'configurer')) {
839 throw new RestException(403);
840 }
841 $membertype = new AdherentType($this->db);
842 $result = $membertype->fetch($id);
843 if ($result < 1) {
844 throw new RestException(404, 'member type not found');
845 }
846
847 if (!DolibarrApi::_checkAccessToResource('member', $membertype->id, 'adherent_type')) {
848 throw new RestException(403, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
849 }
850
851 $res = $membertype->delete(DolibarrApiAccess::$user);
852 if ($res < 0) {
853 throw new RestException(500, "Can't delete, error occurs");
854 }
855
856 return array(
857 'success' => array(
858 'code' => 200,
859 'message' => 'Member type deleted'
860 )
861 );
862 }
863
872 private function _validateType($data)
873 {
874 $membertype = array();
875
876 $mandatoryfields = array('label');
877
878 foreach ($mandatoryfields as $field) {
879 if (!isset($data[$field])) {
880 throw new RestException(400, "$field field missing");
881 }
882 $membertype[$field] = $data[$field];
883 }
884 return $membertype;
885 }
886}
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:58
Class to manage members of a foundation.
Class to manage members type.
Class to manage categories.
Class for API REST v1.
Definition api.class.php:30
_filterObjectProperties($object, $properties)
Filter properties that will be returned on object.
static _checkAccessToResource($resource, $resource_id=0, $dbtablename='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid')
Check access by user to a given resource.
_checkValForAPI($field, $value, $object)
Check and convert a string depending on its type/name.
Definition api.class.php:82
put($id, $request_data=null)
Update member.
getType($id)
Get properties of a member type object.
createSubscription($id, $start_date, $end_date, $amount, $label='')
Add a subscription for a member.
_validate($data)
Validate fields before creating an object.
getByThirdparty($thirdparty)
Get properties of a member object by linked thirdparty.
getByThirdpartyBarcode($barcode)
Get properties of a member object by linked thirdparty barcode.
deleteType($id)
Delete member type.
__construct()
Constructor.
getCategories($id, $sortfield="s.rowid", $sortorder='ASC', $limit=0, $page=0)
Get categories for a member.
getByThirdpartyEmail($email)
Get properties of a member object by linked thirdparty email.
_cleanObjectDatas($object)
Clean sensible object datas.
_validateType($data)
Validate fields before creating an object.
putType($id, $request_data=null)
Update member type.
indexType($sortfield="t.rowid", $sortorder='ASC', $limit=100, $page=0, $sqlfilters='', $properties='')
List members types.
getSubscriptions($id)
List subscriptions of a member.
post($request_data=null)
Create member object.
index($sortfield="t.rowid", $sortorder='ASC', $limit=100, $page=0, $typeid='', $category=0, $sqlfilters='', $properties='')
List members.
postType($request_data=null)
Create member type object.
Class to manage third parties objects (customers, suppliers, prospects...)
forgeSQLFromUniversalSearchCriteria($filter, &$errorstr='', $noand=0, $nopar=0, $noerror=0)
forgeSQLFromUniversalSearchCriteria
sanitizeVal($out='', $check='alphanohtml', $filter=null, $options=null)
Return a sanitized or empty value after checking value against a rule.