Passed
Branch develop (cac63d)
by
unknown
42:43
created

Adherent::_load_ldap_dn()   A

Complexity

Conditions 4

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 9
nop 2
dl 0
loc 15
rs 9.9666
c 0
b 0
f 0
1
<?php
2
/* Copyright (C) 2002-2003	Rodolphe Quiedeville	<[email protected]>
3
 * Copyright (C) 2002-2003	Jean-Louis Bergamo		<[email protected]>
4
 * Copyright (C) 2004-2012	Laurent Destailleur		<[email protected]>
5
 * Copyright (C) 2004		Sebastien Di Cintio		<[email protected]>
6
 * Copyright (C) 2004		Benoit Mortier			<[email protected]>
7
 * Copyright (C) 2009-2017	Regis Houssin			<[email protected]>
8
 * Copyright (C) 2014-2018	Alexandre Spangaro		<[email protected]>
9
 * Copyright (C) 2015		Marcos García			<[email protected]>
10
 * Copyright (C) 2015-2020	Frédéric France			<[email protected]>
11
 * Copyright (C) 2015		Raphaël Doursenaud		<[email protected]>
12
 * Copyright (C) 2016		Juanjo Menent			<[email protected]>
13
 * Copyright (C) 2018-2019	Thibault FOUCART		<[email protected]>
14
 * Copyright (C) 2019		Nicolas ZABOURI 		<[email protected]>
15
 * Copyright (C) 2020		Josep Lluís Amador 		<[email protected]>
16
 * Copyright (C) 2021		Waël Almoman            <[email protected]>
17
 *
18
 * This program is free software; you can redistribute it and/or modify
19
 * it under the terms of the GNU General Public License as published by
20
 * the Free Software Foundation; either version 3 of the License, or
21
 * (at your option) any later version.
22
 *
23
 * This program is distributed in the hope that it will be useful,
24
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26
 * GNU General Public License for more details.
27
 *
28
 * You should have received a copy of the GNU General Public License
29
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
30
 */
31
32
/**
33
 *	\file       htdocs/adherents/class/adherent.class.php
34
 *	\ingroup    member
35
 *	\brief      File of class to manage members of a foundation
36
 */
37
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
38
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
39
require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
40
41
42
/**
43
 *		Class to manage members of a foundation
44
 */
45
class Adherent extends CommonObject
46
{
47
	/**
48
	 * @var string ID to identify managed object
49
	 */
50
	public $element = 'member';
51
52
	/**
53
	 * @var string Name of table without prefix where object is stored
54
	 */
55
	public $table_element = 'adherent';
56
57
	/**
58
	 * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
59
	 * @var int
60
	 */
61
	public $ismultientitymanaged = 1;
62
63
	/**
64
	 * @var string picto
65
	 */
66
	public $picto = 'member';
67
68
69
	public $mesgs;
70
71
	/**
72
	 * @var string login of member
73
	 */
74
	public $login;
75
76
	/**
77
	 * @var string Clear password in memory
78
	 */
79
	public $pass;
80
81
	/**
82
	 * @var string Clear password in database (defined if DATABASE_PWD_ENCRYPTED=0)
83
	 */
84
	public $pass_indatabase;
85
86
	/**
87
	 * @var string Encrypted password in database (always defined)
88
	 */
89
	public $pass_indatabase_crypted;
90
91
	/**
92
	 * @var string company name
93
	 * @deprecated
94
	 */
95
	public $societe;
96
97
	/**
98
	 * @var string company name
99
	 */
100
	public $company;
101
102
	/**
103
	 * @var int Thirdparty ID
104
	 */
105
	public $fk_soc;
106
	public $socid;
107
108
	/**
109
	 * @var string Address
110
	 */
111
	public $address;
112
113
	/**
114
	 * @var string zipcode
115
	 */
116
	public $zip;
117
118
	/**
119
	 * @var string town
120
	 */
121
	public $town;
122
123
	/**
124
	 * @var int Id of state
125
	 */
126
	public $state_id;
127
128
	/**
129
	 * @var string Code of state
130
	 */
131
	public $state_code;
132
133
	/**
134
	 * @var string Label of state
135
	 */
136
	public $state;
137
138
	/**
139
	 * @var string email
140
	 */
141
	public $email;
142
143
	/**
144
	 * @var string url
145
	 */
146
	public $url;
147
148
	/**
149
	 * @var array array of socialnetworks
150
	 */
151
	public $socialnetworks;
152
153
	/**
154
	 * @var string skype account
155
	 * @deprecated
156
	 */
157
	public $skype;
158
159
	/**
160
	 * @var string twitter account
161
	 * @deprecated
162
	 */
163
	public $twitter;
164
165
	/**
166
	 * @var string facebook account
167
	 * @deprecated
168
	 */
169
	public $facebook;
170
171
	/**
172
	 * @var string linkedin account
173
	 * @deprecated
174
	 */
175
	public $linkedin;
176
177
	/**
178
	 * @var string Phone number
179
	 */
180
	public $phone;
181
182
	/**
183
	 * @var string Private Phone number
184
	 */
185
	public $phone_perso;
186
187
	/**
188
	 * @var string Professional Phone number
189
	 */
190
	public $phone_pro;
191
192
	/**
193
	 * @var string Mobile phone number
194
	 */
195
	public $phone_mobile;
196
197
	/**
198
	 * @var string Fax number
199
	 */
200
	public $fax;
201
202
	/**
203
	 * @var string Function
204
	 */
205
	public $poste;
206
207
	/**
208
	 * @var string mor or phy
209
	 */
210
	public $morphy;
211
212
	/**
213
	 * @var int Info can be public
214
	 */
215
	public $public;
216
217
	/**
218
	 * @var string photo of member
219
	 */
220
	public $photo;
221
222
	/**
223
	 * Date creation record (datec)
224
	 *
225
	 * @var integer
226
	 */
227
	public $datec;
228
229
	/**
230
	 * Date modification record (tms)
231
	 *
232
	 * @var integer
233
	 */
234
	public $datem;
235
236
	public $datevalid;
237
238
	/**
239
	 * @var string gender
240
	 */
241
	public $gender;
242
243
	public $birth;
244
245
	/**
246
	 * @var int id type member
247
	 */
248
	public $typeid;
249
250
	/**
251
	 * @var string label type member
252
	 */
253
	public $type;
254
255
	public $need_subscription;
256
257
	public $user_id;
258
259
	public $user_login;
260
261
	public $datefin;
262
263
264
	// Fields loaded by fetch_subscriptions() from member table
265
266
	public $first_subscription_date;
267
268
	public $first_subscription_amount;
269
270
	public $last_subscription_date;
271
272
	public $last_subscription_date_start;
273
274
	public $last_subscription_date_end;
275
276
	public $last_subscription_amount;
277
278
	public $subscriptions = array();
279
280
281
	// Fields loaded by fetchPartnerships() from partnership table
282
283
	public $partnerships = array();
284
285
286
	/**
287
	 * @var Adherent To contains a clone of this when we need to save old properties of object
288
	 */
289
	public $oldcopy;
290
291
	/**
292
	 * @var int Entity
293
	 */
294
	public $entity;
295
296
	/**
297
	 * @var array fields
298
	 */
299
	public $fields = array(
300
		'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 10),
301
		'ref' => array('type' => 'varchar(30)', 'label' => 'Ref', 'default' => 1, 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 12, 'index' => 1),
302
		'entity' => array('type' => 'integer', 'label' => 'Entity', 'default' => 1, 'enabled' => 1, 'visible' => -2, 'notnull' => 1, 'position' => 15, 'index' => 1),
303
		'ref_ext' => array('type' => 'varchar(128)', 'label' => 'Ref ext', 'enabled' => 1, 'visible' => 0, 'position' => 20),
304
		'civility' => array('type' => 'varchar(6)', 'label' => 'Civility', 'enabled' => 1, 'visible' => -1, 'position' => 25),
305
		'lastname' => array('type' => 'varchar(50)', 'label' => 'Lastname', 'enabled' => 1, 'visible' => -1, 'position' => 30, 'showoncombobox'=>1),
306
		'firstname' => array('type' => 'varchar(50)', 'label' => 'Firstname', 'enabled' => 1, 'visible' => -1, 'position' => 35, 'showoncombobox'=>1),
307
		'login' => array('type' => 'varchar(50)', 'label' => 'Login', 'enabled' => 1, 'visible' => -1, 'position' => 40),
308
		'gender' => array('type' => 'varchar(10)', 'label' => 'Gender', 'enabled' => 1, 'visible' => -1, 'position' => 250),
309
		'pass' => array('type' => 'varchar(50)', 'label' => 'Pass', 'enabled' => 1, 'visible' => -1, 'position' => 45),
310
		'pass_crypted' => array('type' => 'varchar(128)', 'label' => 'Pass crypted', 'enabled' => 1, 'visible' => -1, 'position' => 50),
311
		'fk_adherent_type' => array('type' => 'integer', 'label' => 'Fk adherent type', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 55),
312
		'morphy' => array('type' => 'varchar(3)', 'label' => 'MorPhy', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 60),
313
		'societe' => array('type' => 'varchar(128)', 'label' => 'Societe', 'enabled' => 1, 'visible' => -1, 'position' => 65, 'showoncombobox'=>2),
314
		'fk_soc' => array('type' => 'integer:Societe:societe/class/societe.class.php', 'label' => 'ThirdParty', 'enabled' => 1, 'visible' => -1, 'position' => 70),
315
		'address' => array('type' => 'text', 'label' => 'Address', 'enabled' => 1, 'visible' => -1, 'position' => 75),
316
		'zip' => array('type' => 'varchar(10)', 'label' => 'Zip', 'enabled' => 1, 'visible' => -1, 'position' => 80),
317
		'town' => array('type' => 'varchar(50)', 'label' => 'Town', 'enabled' => 1, 'visible' => -1, 'position' => 85),
318
		'state_id' => array('type' => 'integer', 'label' => 'State id', 'enabled' => 1, 'visible' => -1, 'position' => 90),
319
		'country' => array('type' => 'integer:Ccountry:core/class/ccountry.class.php', 'label' => 'Country', 'enabled' => 1, 'visible' => -1, 'position' => 95),
320
		'email' => array('type' => 'varchar(255)', 'label' => 'Email', 'enabled' => 1, 'visible' => -1, 'position' => 100),
321
		'url' =>array('type'=>'varchar(255)', 'label'=>'Url', 'enabled'=>1, 'visible'=>-1, 'position'=>110),
322
		'socialnetworks' => array('type' => 'text', 'label' => 'Socialnetworks', 'enabled' => 1, 'visible' => -1, 'position' => 105),
323
		'phone' => array('type' => 'varchar(30)', 'label' => 'Phone', 'enabled' => 1, 'visible' => -1, 'position' => 115),
324
		'phone_perso' => array('type' => 'varchar(30)', 'label' => 'Phone perso', 'enabled' => 1, 'visible' => -1, 'position' => 120),
325
		'phone_mobile' => array('type' => 'varchar(30)', 'label' => 'Phone mobile', 'enabled' => 1, 'visible' => -1, 'position' => 125),
326
		'birth' => array('type' => 'date', 'label' => 'DateOfBirth', 'enabled' => 1, 'visible' => -1, 'position' => 130),
327
		'photo' => array('type' => 'varchar(255)', 'label' => 'Photo', 'enabled' => 1, 'visible' => -1, 'position' => 135),
328
		'public' => array('type' => 'smallint(6)', 'label' => 'Public', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 145),
329
		'datefin' => array('type' => 'datetime', 'label' => 'DateEnd', 'enabled' => 1, 'visible' => -1, 'position' => 150),
330
		'note_private' => array('type' => 'text', 'label' => 'NotePublic', 'enabled' => 1, 'visible' => 0, 'position' => 155),
331
		'note_public' => array('type' => 'text', 'label' => 'NotePrivate', 'enabled' => 1, 'visible' => 0, 'position' => 160),
332
		'datevalid' => array('type' => 'datetime', 'label' => 'DateValidation', 'enabled' => 1, 'visible' => -1, 'position' => 165),
333
		'datec' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -1, 'position' => 170),
334
		'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 175),
335
		'fk_user_author' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'Fk user author', 'enabled' => 1, 'visible' => -1, 'position' => 180),
336
		'fk_user_mod' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'Fk user mod', 'enabled' => 1, 'visible' => -1, 'position' => 185),
337
		'fk_user_valid' => array('type' => 'integer:User:user/class/user.class.php', 'label' => 'UserValidation', 'enabled' => 1, 'visible' => -1, 'position' => 190),
338
		'canvas' => array('type' => 'varchar(32)', 'label' => 'Canvas', 'enabled' => 1, 'visible' => -1, 'position' => 195),
339
		'statut' => array('type' => 'smallint(6)', 'label' => 'Statut', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 500,
340
		'arrayofkeyval' => array(-1 => 'Draft', 1 => 'Validated', 0 => 'MemberStatusResiliatedShort', -2 => 'MemberStatusExcludedShort')),
341
		'model_pdf' => array('type' => 'varchar(255)', 'label' => 'Model pdf', 'enabled' => 1, 'visible' => 0, 'position' => 800),
342
		'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'visible' => -2, 'position' => 805)
343
	);
344
345
	/**
346
	 * Draft status
347
	 */
348
	const STATUS_DRAFT = -1;
349
	/**
350
	 * Validated status
351
	 */
352
	const STATUS_VALIDATED = 1;
353
	/**
354
	 * Resiliated
355
	 */
356
	const STATUS_RESILIATED = 0;
357
	/**
358
	 * Excluded
359
	 */
360
	const STATUS_EXCLUDED = -2;
361
362
363
	/**
364
	 *	Constructor
365
	 *
366
	 *	@param 		DoliDB		$db		Database handler
367
	 */
368
	public function __construct($db)
369
	{
370
		$this->db = $db;
371
		$this->statut = self::STATUS_DRAFT;
372
		$this->status = $this->statut;
373
		// l'adherent n'est pas public par defaut
374
		$this->public = 0;
375
		// les champs optionnels sont vides
376
		$this->array_options = array();
377
	}
378
379
380
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
381
	/**
382
	 *  Function sending an email to the current member with the text supplied in parameter.
383
	 *
384
	 *  @param	string	$text				Content of message (not html entities encoded)
385
	 *  @param	string	$subject			Subject of message
386
	 *  @param 	array	$filename_list      Array of attached files
387
	 *  @param 	array	$mimetype_list      Array of mime types of attached files
388
	 *  @param 	array	$mimefilename_list  Array of public names of attached files
389
	 *  @param 	string	$addr_cc            Email cc
390
	 *  @param 	string	$addr_bcc           Email bcc
391
	 *  @param 	int		$deliveryreceipt	Ask a delivery receipt
392
	 *  @param	int		$msgishtml			1=String IS already html, 0=String IS NOT html, -1=Unknown need autodetection
393
	 *  @param	string	$errors_to			erros to
394
	 *  @param	string	$moreinheader		Add more html headers
395
	 *  @return	int							<0 if KO, >0 if OK
396
	 */
397
	public function send_an_email($text, $subject, $filename_list = array(), $mimetype_list = array(), $mimefilename_list = array(), $addr_cc = "", $addr_bcc = "", $deliveryreceipt = 0, $msgishtml = -1, $errors_to = '', $moreinheader = '')
398
	{
399
		// phpcs:enable
400
		global $conf, $langs;
401
402
		// Detect if message is HTML
403
		if ($msgishtml == -1) {
404
			$msgishtml = 0;
405
			if (dol_textishtml($text, 0)) {
406
				$msgishtml = 1;
407
			}
408
		}
409
410
		dol_syslog('send_an_email msgishtml='.$msgishtml);
411
412
		$texttosend = $this->makeSubstitution($text);
413
		$subjecttosend = $this->makeSubstitution($subject);
414
		if ($msgishtml) {
415
			$texttosend = dol_htmlentitiesbr($texttosend);
416
		}
417
418
		// Envoi mail confirmation
419
		$from = $conf->email_from;
420
		if (!empty($conf->global->ADHERENT_MAIL_FROM)) {
421
			$from = $conf->global->ADHERENT_MAIL_FROM;
422
		}
423
424
		$trackid = 'mem'.$this->id;
425
426
		// Send email (substitutionarray must be done just before this)
427
		include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
428
		$mailfile = new CMailFile($subjecttosend, $this->email, $from, $texttosend, $filename_list, $mimetype_list, $mimefilename_list, $addr_cc, $addr_bcc, $deliveryreceipt, $msgishtml, '', '', $trackid, $moreinheader);
429
		if ($mailfile->sendfile()) {
430
			return 1;
431
		} else {
432
			$this->error = $langs->trans("ErrorFailedToSendMail", $from, $this->email).'. '.$mailfile->error;
433
			return -1;
434
		}
435
	}
436
437
438
	/**
439
	 * Make substitution of tags into text with value of current object.
440
	 *
441
	 * @param	string	$text       Text to make substitution to
442
	 * @return  string      		Value of input text string with substitutions done
443
	 */
444
	public function makeSubstitution($text)
445
	{
446
		global $conf, $langs;
447
448
		$birthday = dol_print_date($this->birth, 'day');
449
450
		$msgishtml = 0;
451
		if (dol_textishtml($text, 1)) {
452
			$msgishtml = 1;
453
		}
454
455
		$infos = '';
456
		if ($this->civility_id) {
457
			$infos .= $langs->transnoentities("UserTitle").": ".$this->getCivilityLabel()."\n";
458
		}
459
		$infos .= $langs->transnoentities("id").": ".$this->id."\n";
460
		$infos .= $langs->transnoentities("ref").": ".$this->ref."\n";
461
		$infos .= $langs->transnoentities("Lastname").": ".$this->lastname."\n";
462
		$infos .= $langs->transnoentities("Firstname").": ".$this->firstname."\n";
463
		$infos .= $langs->transnoentities("Company").": ".$this->company."\n";
464
		$infos .= $langs->transnoentities("Address").": ".$this->address."\n";
465
		$infos .= $langs->transnoentities("Zip").": ".$this->zip."\n";
466
		$infos .= $langs->transnoentities("Town").": ".$this->town."\n";
467
		$infos .= $langs->transnoentities("Country").": ".$this->country."\n";
468
		$infos .= $langs->transnoentities("EMail").": ".$this->email."\n";
469
		$infos .= $langs->transnoentities("PhonePro").": ".$this->phone."\n";
470
		$infos .= $langs->transnoentities("PhonePerso").": ".$this->phone_perso."\n";
471
		$infos .= $langs->transnoentities("PhoneMobile").": ".$this->phone_mobile."\n";
472
		if (empty($conf->global->ADHERENT_LOGIN_NOT_REQUIRED)) {
473
			$infos .= $langs->transnoentities("Login").": ".$this->login."\n";
474
			$infos .= $langs->transnoentities("Password").": ".$this->pass."\n";
475
		}
476
		$infos .= $langs->transnoentities("Birthday").": ".$birthday."\n";
477
		$infos .= $langs->transnoentities("Photo").": ".$this->photo."\n";
478
		$infos .= $langs->transnoentities("Public").": ".yn($this->public);
479
480
		// Substitutions
481
		$substitutionarray = array(
482
			'__ID__' => $this->id,
483
			'__REF__' => $this->ref,
484
			'__MEMBER_ID__' => $this->id,
485
			'__CIVILITY__' => $this->getCivilityLabel(),
486
			'__FIRSTNAME__' => $msgishtml ? dol_htmlentitiesbr($this->firstname) : ($this->firstname ? $this->firstname : ''),
487
			'__LASTNAME__' => $msgishtml ? dol_htmlentitiesbr($this->lastname) : ($this->lastname ? $this->lastname : ''),
488
			'__FULLNAME__' => $msgishtml ? dol_htmlentitiesbr($this->getFullName($langs)) : $this->getFullName($langs),
489
			'__COMPANY__' => $msgishtml ? dol_htmlentitiesbr($this->company) : ($this->company ? $this->company : ''),
490
			'__ADDRESS__' => $msgishtml ? dol_htmlentitiesbr($this->address) : ($this->address ? $this->address : ''),
491
			'__ZIP__' => $msgishtml ? dol_htmlentitiesbr($this->zip) : ($this->zip ? $this->zip : ''),
492
			'__TOWN__' => $msgishtml ? dol_htmlentitiesbr($this->town) : ($this->town ? $this->town : ''),
493
			'__COUNTRY__' => $msgishtml ? dol_htmlentitiesbr($this->country) : ($this->country ? $this->country : ''),
494
			'__EMAIL__' => $msgishtml ? dol_htmlentitiesbr($this->email) : ($this->email ? $this->email : ''),
495
			'__BIRTH__' => $msgishtml ? dol_htmlentitiesbr($birthday) : ($birthday ? $birthday : ''),
496
			'__PHOTO__' => $msgishtml ? dol_htmlentitiesbr($this->photo) : ($this->photo ? $this->photo : ''),
497
			'__LOGIN__' => $msgishtml ? dol_htmlentitiesbr($this->login) : ($this->login ? $this->login : ''),
498
			'__PASSWORD__' => $msgishtml ? dol_htmlentitiesbr($this->pass) : ($this->pass ? $this->pass : ''),
499
			'__PHONE__' => $msgishtml ? dol_htmlentitiesbr($this->phone) : ($this->phone ? $this->phone : ''),
500
			'__PHONEPRO__' => $msgishtml ? dol_htmlentitiesbr($this->phone_perso) : ($this->phone_perso ? $this->phone_perso : ''),
501
			'__PHONEMOBILE__' => $msgishtml ? dol_htmlentitiesbr($this->phone_mobile) : ($this->phone_mobile ? $this->phone_mobile : ''),
502
			'__TYPE__' => $msgishtml ? dol_htmlentitiesbr($this->type) : ($this->type ? $this->type : '')
503
		);
504
505
		complete_substitutions_array($substitutionarray, $langs, $this);
506
507
		return make_substitutions($text, $substitutionarray, $langs);
508
	}
509
510
511
	/**
512
	 *	Return translated label by the nature of a adherent (physical or moral)
513
	 *
514
	 *	@param	string		$morphy		Nature of the adherent (physical or moral)
515
	 *	@return	string					Label
516
	 */
517
	public function getmorphylib($morphy = '')
518
	{
519
		global $langs;
520
		if (!$morphy) {
521
			$morphy = $this->morphy;
522
		}
523
		if ($morphy == 'phy') {
524
			return $langs->trans("Physical");
525
		}
526
		if ($morphy == 'mor') {
527
			return $langs->trans("Moral");
528
		}
529
		return $morphy;
530
	}
531
532
	/**
533
	 *	Create a member into database
534
	 *
535
	 *	@param	User	$user        	Objet user qui demande la creation
536
	 *	@param  int		$notrigger		1 ne declenche pas les triggers, 0 sinon
537
	 *	@return	int						<0 if KO, >0 if OK
538
	 */
539
	public function create($user, $notrigger = 0)
540
	{
541
		global $conf, $langs;
542
543
		$error = 0;
544
545
		$now = dol_now();
546
547
		// Clean parameters
548
		$this->import_key = trim($this->import_key);
549
550
		// Check parameters
551
		if (!empty($conf->global->ADHERENT_MAIL_REQUIRED) && !isValidEMail($this->email)) {
552
			$langs->load("errors");
553
			$this->error = $langs->trans("ErrorBadEMail", $this->email);
554
			return -1;
555
		}
556
		if (!$this->datec) {
557
			$this->datec = $now;
558
		}
559
		if (empty($conf->global->ADHERENT_LOGIN_NOT_REQUIRED)) {
560
			if (empty($this->login)) {
561
				$this->error = $langs->trans("ErrorWrongValueForParameterX", "Login");
562
				return -1;
563
			}
564
		}
565
566
		$this->db->begin();
567
568
		// Insert member
569
		$sql = "INSERT INTO ".MAIN_DB_PREFIX."adherent";
570
		$sql .= " (ref, datec,login,fk_user_author,fk_user_mod,fk_user_valid,morphy,fk_adherent_type,entity,import_key)";
571
		$sql .= " VALUES (";
572
		$sql .= " '(PROV)'";
573
		$sql .= ", '".$this->db->idate($this->datec)."'";
574
		$sql .= ", ".($this->login ? "'".$this->db->escape($this->login)."'" : "null");
575
		$sql .= ", ".($user->id > 0 ? $user->id : "null"); // Can be null because member can be created by a guest or a script
576
		$sql .= ", null, null, '".$this->db->escape($this->morphy)."'";
577
		$sql .= ", ".$this->typeid;
578
		$sql .= ", ".$conf->entity;
579
		$sql .= ", ".(!empty($this->import_key) ? "'".$this->db->escape($this->import_key)."'" : "null");
580
		$sql .= ")";
581
582
		dol_syslog(get_class($this)."::create", LOG_DEBUG);
583
		$result = $this->db->query($sql);
584
		if ($result) {
585
			$id = $this->db->last_insert_id(MAIN_DB_PREFIX."adherent");
586
			if ($id > 0) {
587
				$this->id = $id;
588
				$this->ref = (string) $id;
589
590
				// Update minor fields
591
				$result = $this->update($user, 1, 1, 0, 0, 'add'); // nosync is 1 to avoid update data of user
592
				if ($result < 0) {
593
					$this->db->rollback();
594
					return -1;
595
				}
596
597
				// Add link to user
598
				if ($this->user_id) {
599
					// Add link to user
600
					$sql = "UPDATE ".MAIN_DB_PREFIX."user SET";
601
					$sql .= " fk_member = ".$this->id;
602
					$sql .= " WHERE rowid = ".$this->user_id;
603
					dol_syslog(get_class($this)."::create", LOG_DEBUG);
604
					$resql = $this->db->query($sql);
605
					if (!$resql) {
606
						$this->error = 'Failed to update user to make link with member';
607
						$this->db->rollback();
608
						return -4;
609
					}
610
				}
611
612
				if (!$notrigger) {
613
					// Call trigger
614
					$result = $this->call_trigger('MEMBER_CREATE', $user);
615
					if ($result < 0) {
616
						$error++;
617
					}
618
					// End call triggers
619
				}
620
621
				if (count($this->errors)) {
622
					dol_syslog(get_class($this)."::create ".implode(',', $this->errors), LOG_ERR);
623
					$this->db->rollback();
624
					return -3;
625
				} else {
626
					$this->db->commit();
627
					return $this->id;
628
				}
629
			} else {
630
				$this->error = 'Failed to get last insert id';
631
				dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
632
				$this->db->rollback();
633
				return -2;
634
			}
635
		} else {
636
			$this->error = $this->db->error();
637
			$this->db->rollback();
638
			return -1;
639
		}
640
	}
641
642
643
	/**
644
	 *	Update a member in database (standard information and password)
645
	 *
646
	 *	@param	User	$user				User making update
647
	 *	@param	int		$notrigger			1=disable trigger UPDATE (when called by create)
648
	 *	@param	int		$nosyncuser			0=Synchronize linked user (standard info), 1=Do not synchronize linked user
649
	 *	@param	int		$nosyncuserpass		0=Synchronize linked user (password), 1=Do not synchronize linked user
650
	 *	@param	int		$nosyncthirdparty	0=Synchronize linked thirdparty (standard info), 1=Do not synchronize linked thirdparty
651
	 * 	@param	string	$action				Current action for hookmanager
652
	 * 	@return	int							<0 if KO, >0 if OK
653
	 */
654
	public function update($user, $notrigger = 0, $nosyncuser = 0, $nosyncuserpass = 0, $nosyncthirdparty = 0, $action = 'update')
655
	{
656
		global $conf, $langs, $hookmanager;
657
658
		$nbrowsaffected = 0;
659
		$error = 0;
660
661
		dol_syslog(get_class($this)."::update notrigger=".$notrigger.", nosyncuser=".$nosyncuser.", nosyncuserpass=".$nosyncuserpass." nosyncthirdparty=".$nosyncthirdparty.", email=".
662
			$this->email);
663
664
		// Clean parameters
665
		$this->lastname = trim($this->lastname) ? trim($this->lastname) : trim($this->lastname);
666
		$this->firstname = trim($this->firstname) ? trim($this->firstname) : trim($this->firstname);
667
		$this->gender = trim($this->gender);
668
		$this->address = ($this->address ? $this->address : $this->address);
669
		$this->zip = ($this->zip ? $this->zip : $this->zip);
670
		$this->town = ($this->town ? $this->town : $this->town);
671
		$this->country_id = ($this->country_id > 0 ? $this->country_id : $this->country_id);
672
		$this->state_id = ($this->state_id > 0 ? $this->state_id : $this->state_id);
673
		$this->setUpperOrLowerCase();
674
		$this->note_public = ($this->note_public ? $this->note_public : $this->note_public);
675
		$this->note_private = ($this->note_private ? $this->note_private : $this->note_private);
676
		$this->url = $this->url ?clean_url($this->url, 0) : '';
677
678
		// Check parameters
679
		if (!empty($conf->global->ADHERENT_MAIL_REQUIRED) && !isValidEMail($this->email)) {
680
			$langs->load("errors");
681
			$this->error = $langs->trans("ErrorBadEMail", $this->email);
682
			return -1;
683
		}
684
685
		$this->db->begin();
686
687
		$sql = "UPDATE ".MAIN_DB_PREFIX."adherent SET";
688
		$sql .= " ref = '".$this->db->escape($this->ref)."'";
689
		$sql .= ", civility = ".($this->civility_id ? "'".$this->db->escape($this->civility_id)."'" : "null");
690
		$sql .= ", firstname = ".($this->firstname ? "'".$this->db->escape($this->firstname)."'" : "null");
691
		$sql .= ", lastname = ".($this->lastname ? "'".$this->db->escape($this->lastname)."'" : "null");
692
		$sql .= ", gender = ".($this->gender != -1 ? "'".$this->db->escape($this->gender)."'" : "null"); // 'man' or 'woman'
693
		$sql .= ", login = ".($this->login ? "'".$this->db->escape($this->login)."'" : "null");
694
		$sql .= ", societe = ".($this->company ? "'".$this->db->escape($this->company)."'" : ($this->societe ? "'".$this->db->escape($this->societe)."'" : "null"));
695
		$sql .= ", fk_soc = ".($this->socid > 0 ? $this->db->escape($this->socid) : "null");
696
		$sql .= ", address = ".($this->address ? "'".$this->db->escape($this->address)."'" : "null");
697
		$sql .= ", zip = ".($this->zip ? "'".$this->db->escape($this->zip)."'" : "null");
698
		$sql .= ", town = ".($this->town ? "'".$this->db->escape($this->town)."'" : "null");
699
		$sql .= ", country = ".($this->country_id > 0 ? $this->db->escape($this->country_id) : "null");
700
		$sql .= ", state_id = ".($this->state_id > 0 ? $this->db->escape($this->state_id) : "null");
701
		$sql .= ", email = '".$this->db->escape($this->email)."'";
702
		$sql .= ", url = ".(!empty($this->url) ? "'".$this->db->escape($this->url)."'" : "null");
703
		$sql .= ", socialnetworks = '".$this->db->escape(json_encode($this->socialnetworks))."'";
704
		$sql .= ", phone = ".($this->phone ? "'".$this->db->escape($this->phone)."'" : "null");
705
		$sql .= ", phone_perso = ".($this->phone_perso ? "'".$this->db->escape($this->phone_perso)."'" : "null");
706
		$sql .= ", phone_mobile = ".($this->phone_mobile ? "'".$this->db->escape($this->phone_mobile)."'" : "null");
707
		$sql .= ", note_private = ".($this->note_private ? "'".$this->db->escape($this->note_private)."'" : "null");
708
		$sql .= ", note_public = ".($this->note_public ? "'".$this->db->escape($this->note_public)."'" : "null");
709
		$sql .= ", photo = ".($this->photo ? "'".$this->db->escape($this->photo)."'" : "null");
710
		$sql .= ", public = '".$this->db->escape($this->public)."'";
711
		$sql .= ", statut = ".$this->db->escape($this->statut);
712
		$sql .= ", fk_adherent_type = ".$this->db->escape($this->typeid);
713
		$sql .= ", morphy = '".$this->db->escape($this->morphy)."'";
714
		$sql .= ", birth = ".($this->birth ? "'".$this->db->idate($this->birth)."'" : "null");
715
		if ($this->socid) {
716
			$sql .= ", fk_soc = '".$this->db->escape($this->socid)."'"; // Must be modified only when creating from a third-party
717
		}
718
		if ($this->datefin) {
719
			$sql .= ", datefin = '".$this->db->idate($this->datefin)."'"; // Must be modified only when deleting a subscription
720
		}
721
		if ($this->datevalid) {
722
			$sql .= ", datevalid = '".$this->db->idate($this->datevalid)."'"; // Must be modified only when validating a member
723
		}
724
		$sql .= ", fk_user_mod = ".($user->id > 0 ? $user->id : 'null'); // Can be null because member can be create by a guest
725
		$sql .= " WHERE rowid = ".((int) $this->id);
726
727
		// If we change the type of membership, we set also label of new type
728
		if (!empty($this->oldcopy) && $this->typeid != $this->oldcopy->typeid) {
729
			$sql2 = "SELECT libelle as label";
730
			$sql2 .= " FROM ".MAIN_DB_PREFIX."adherent_type";
731
			$sql2 .= " WHERE rowid = ".$this->typeid;
732
			$resql2 = $this->db->query($sql2);
733
			if ($resql2) {
734
				while ($obj = $this->db->fetch_object($resql2)) {
735
					$this->type = $obj->label;
736
				}
737
			}
738
		}
739
740
		dol_syslog(get_class($this)."::update update member", LOG_DEBUG);
741
		$resql = $this->db->query($sql);
742
		if ($resql) {
743
			unset($this->country_code);
744
			unset($this->country);
745
			unset($this->state_code);
746
			unset($this->state);
747
748
			$nbrowsaffected += $this->db->affected_rows($resql);
749
750
			$action = 'update';
751
752
			// Actions on extra fields
753
			if (!$error) {
754
				$result = $this->insertExtraFields();
755
				if ($result < 0) {
756
					$error++;
757
				}
758
			}
759
760
			// Update password
761
			if (!$error && $this->pass) {
762
				dol_syslog(get_class($this)."::update update password");
763
				if ($this->pass != $this->pass_indatabase && $this->pass != $this->pass_indatabase_crypted) {
764
					$isencrypted = empty($conf->global->DATABASE_PWD_ENCRYPTED) ? 0 : 1;
765
766
					// If password to set differs from the one found into database
767
					$result = $this->setPassword($user, $this->pass, $isencrypted, $notrigger, $nosyncuserpass);
768
					if (!$nbrowsaffected) {
769
						$nbrowsaffected++;
770
					}
771
				}
772
			}
773
774
			// Remove links to user and replace with new one
775
			if (!$error) {
776
				dol_syslog(get_class($this)."::update update link to user");
777
				$sql = "UPDATE ".MAIN_DB_PREFIX."user SET fk_member = NULL WHERE fk_member = ".$this->id;
778
				dol_syslog(get_class($this)."::update", LOG_DEBUG);
779
				$resql = $this->db->query($sql);
780
				if (!$resql) {
781
					$this->error = $this->db->error();
782
					$this->db->rollback();
783
					return -5;
784
				}
785
				// If there is a user linked to this member
786
				if ($this->user_id > 0) {
787
					$sql = "UPDATE ".MAIN_DB_PREFIX."user SET fk_member = ".$this->id." WHERE rowid = ".$this->user_id;
788
					dol_syslog(get_class($this)."::update", LOG_DEBUG);
789
					$resql = $this->db->query($sql);
790
					if (!$resql) {
791
						$this->error = $this->db->error();
792
						$this->db->rollback();
793
						return -5;
794
					}
795
				}
796
			}
797
798
			if (!$error && $nbrowsaffected) { // If something has change in main data
799
				// Update information on linked user if it is an update
800
				if (!$error && $this->user_id > 0 && !$nosyncuser) {
801
					require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
802
803
					dol_syslog(get_class($this)."::update update linked user");
804
805
					$luser = new User($this->db);
806
					$result = $luser->fetch($this->user_id);
807
808
					if ($result >= 0) {
809
						//var_dump($this->user_login);exit;
810
						//var_dump($this->login);exit;
811
812
						// If option ADHERENT_LOGIN_NOT_REQUIRED is on, there is no login of member, so we do not overwrite user login to keep existing one.
813
						if (empty($conf->global->ADHERENT_LOGIN_NOT_REQUIRED)) {
814
							$luser->login = $this->login;
815
						}
816
817
						$luser->ref = $this->ref;
818
						$luser->civility_id = $this->civility_id;
819
						$luser->firstname = $this->firstname;
820
						$luser->lastname = $this->lastname;
821
						$luser->gender = $this->gender;
822
						$luser->pass = $this->pass;
823
						//$luser->socid=$this->fk_soc;		// We do not enable this. This may transform a user into an external user.
824
825
						$luser->birth = $this->birth;
826
827
						$luser->address = $this->address;
828
						$luser->zip = $this->zip;
829
						$luser->town = $this->town;
830
						$luser->country_id = $this->country_id;
831
						$luser->state_id = $this->state_id;
832
833
						$luser->email = $this->email;
834
						$luser->socialnetworks = $this->socialnetworks;
835
						$luser->office_phone = $this->phone;
836
						$luser->user_mobile = $this->phone_mobile;
837
838
						$luser->fk_member = $this->id;
839
840
						$result = $luser->update($user, 0, 1, 1); // Use nosync to 1 to avoid cyclic updates
841
						if ($result < 0) {
842
							$this->error = $luser->error;
843
							dol_syslog(get_class($this)."::update ".$this->error, LOG_ERR);
844
							$error++;
845
						}
846
					} else {
847
						$this->error = $luser->error;
848
						$error++;
849
					}
850
				}
851
852
				// Update information on linked thirdparty if it is an update
853
				if (!$error && $this->fk_soc > 0 && !$nosyncthirdparty) {
854
					require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
855
856
					dol_syslog(get_class($this)."::update update linked thirdparty");
857
858
					// This member is linked with a thirdparty, so we also update thirdparty informations
859
					// if this is an update.
860
					$lthirdparty = new Societe($this->db);
861
					$result = $lthirdparty->fetch($this->fk_soc);
862
863
					if ($result > 0) {
864
						$lthirdparty->address = $this->address;
865
						$lthirdparty->zip = $this->zip;
866
						$lthirdparty->town = $this->town;
867
						$lthirdparty->email = $this->email;
868
						$lthirdparty->socialnetworks = $this->socialnetworks;
869
						$lthirdparty->phone = $this->phone;
870
						$lthirdparty->state_id = $this->state_id;
871
						$lthirdparty->country_id = $this->country_id;
872
						//$lthirdparty->phone_mobile=$this->phone_mobile;
873
874
						$result = $lthirdparty->update($this->fk_soc, $user, 0, 1, 1, 'update'); // Use sync to 0 to avoid cyclic updates
875
876
						if ($result < 0) {
877
							$this->error = $lthirdparty->error;
878
							$this->errors = $lthirdparty->errors;
879
							dol_syslog(get_class($this)."::update ".$this->error, LOG_ERR);
880
							$error++;
881
						}
882
					} elseif ($result < 0) {
883
						$this->error = $lthirdparty->error;
884
						$error++;
885
					}
886
				}
887
			}
888
889
			if (!$error && !$notrigger) {
890
				// Call trigger
891
				$result = $this->call_trigger('MEMBER_MODIFY', $user);
892
				if ($result < 0) {
893
					$error++;
894
				}
895
				// End call triggers
896
			}
897
898
			if (!$error) {
899
				$this->db->commit();
900
				return $nbrowsaffected;
901
			} else {
902
				$this->db->rollback();
903
				return -1;
904
			}
905
		} else {
906
			$this->db->rollback();
907
			$this->error = $this->db->lasterror();
908
			return -2;
909
		}
910
	}
911
912
913
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
914
	/**
915
	 *	Update denormalized last subscription date.
916
	 * 	This function is called when we delete a subscription for example.
917
	 *
918
	 *	@param	User	$user			User making change
919
	 *	@return	int						<0 if KO, >0 if OK
920
	 */
921
	public function update_end_date($user)
922
	{
923
		// phpcs:enable
924
		$this->db->begin();
925
926
		// Search for last subscription id and end date
927
		$sql = "SELECT rowid, datec as dateop, dateadh as datedeb, datef as datefin";
928
		$sql .= " FROM ".MAIN_DB_PREFIX."subscription";
929
		$sql .= " WHERE fk_adherent=".$this->id;
930
		$sql .= " ORDER by dateadh DESC"; // Sort by start subscription date
931
932
		dol_syslog(get_class($this)."::update_end_date", LOG_DEBUG);
933
		$resql = $this->db->query($sql);
934
		if ($resql) {
935
			$obj = $this->db->fetch_object($resql);
936
			$dateop = $this->db->jdate($obj->dateop);
937
			$datedeb = $this->db->jdate($obj->datedeb);
938
			$datefin = $this->db->jdate($obj->datefin);
939
940
			$sql = "UPDATE ".MAIN_DB_PREFIX."adherent SET";
941
			$sql .= " datefin=".($datefin != '' ? "'".$this->db->idate($datefin)."'" : "null");
942
			$sql .= " WHERE rowid = ".$this->id;
943
944
			dol_syslog(get_class($this)."::update_end_date", LOG_DEBUG);
945
			$resql = $this->db->query($sql);
946
			if ($resql) {
947
				$this->last_subscription_date = $dateop;
948
				$this->last_subscription_date_start = $datedeb;
949
				$this->last_subscription_date_end = $datefin;
950
				$this->datefin = $datefin;
951
				$this->db->commit();
952
				return 1;
953
			} else {
954
				$this->db->rollback();
955
				return -1;
956
			}
957
		} else {
958
			$this->error = $this->db->lasterror();
959
			$this->db->rollback();
960
			return -1;
961
		}
962
	}
963
964
	/**
965
	 *  Fonction qui supprime l'adherent et les donnees associees
966
	 *
967
	 *  @param	int		$rowid		Id of member to delete
968
	 *	@param	User		$user		User object
969
	 *	@param	int		$notrigger	1=Does not execute triggers, 0= execute triggers
970
	 *  @return	int					<0 if KO, 0=nothing to do, >0 if OK
971
	 */
972
	public function delete($rowid, $user, $notrigger = 0)
973
	{
974
		global $conf, $langs;
975
976
		$result = 0;
977
		$error = 0;
978
		$errorflag = 0;
979
980
		// Check parameters
981
		if (empty($rowid)) {
982
			$rowid = $this->id;
983
		}
984
985
		$this->db->begin();
986
987
		if (!$error && !$notrigger) {
988
			// Call trigger
989
			$result = $this->call_trigger('MEMBER_DELETE', $user);
990
			if ($result < 0) {
991
				$error++;
992
			}
993
			// End call triggers
994
		}
995
996
		// Remove category
997
		$sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_member WHERE fk_member = ".((int) $rowid);
998
		dol_syslog(get_class($this)."::delete", LOG_DEBUG);
999
		$resql = $this->db->query($sql);
1000
		if (!$resql) {
1001
			$error++;
1002
			$this->error .= $this->db->lasterror();
1003
			$errorflag = -1;
1004
		}
1005
1006
		// Remove subscription
1007
		if (!$error) {
1008
			$sql = "DELETE FROM ".MAIN_DB_PREFIX."subscription WHERE fk_adherent = ".((int) $rowid);
1009
			dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1010
			$resql = $this->db->query($sql);
1011
			if (!$resql) {
1012
				$error++;
1013
				$this->error .= $this->db->lasterror();
1014
				$errorflag = -2;
1015
			}
1016
		}
1017
1018
		// Remove linked user
1019
		if (!$error) {
1020
			$ret = $this->setUserId(0);
1021
			if ($ret < 0) {
1022
				$error++;
1023
				$this->error .= $this->db->lasterror();
1024
				$errorflag = -3;
1025
			}
1026
		}
1027
1028
		// Removed extrafields
1029
		if (!$error) {
1030
			$result = $this->deleteExtraFields();
1031
			if ($result < 0) {
1032
				$error++;
1033
				$errorflag = -4;
1034
				dol_syslog(get_class($this)."::delete erreur ".$errorflag." ".$this->error, LOG_ERR);
1035
			}
1036
		}
1037
1038
		// Remove adherent
1039
		if (!$error) {
1040
			$sql = "DELETE FROM ".MAIN_DB_PREFIX."adherent WHERE rowid = ".((int) $rowid);
1041
			dol_syslog(get_class($this)."::delete", LOG_DEBUG);
1042
			$resql = $this->db->query($sql);
1043
			if (!$resql) {
1044
				$error++;
1045
				$this->error .= $this->db->lasterror();
1046
				$errorflag = -5;
1047
			}
1048
		}
1049
1050
		if (!$error) {
1051
			$this->db->commit();
1052
			return 1;
1053
		} else {
1054
			$this->db->rollback();
1055
			return $errorflag;
1056
		}
1057
	}
1058
1059
1060
	/**
1061
	 *    Change password of a user
1062
	 *
1063
	 *    @param	User	$user           Object user de l'utilisateur qui fait la modification
1064
	 *    @param 	string	$password       New password (to generate if empty)
1065
	 *    @param    int		$isencrypted    0 ou 1 si il faut crypter le mot de passe en base (0 par defaut)
1066
	 *	  @param	int		$notrigger		1=Ne declenche pas les triggers
1067
	 *    @param	int		$nosyncuser		Do not synchronize linked user
1068
	 *    @return   string           		If OK return clear password, 0 if no change, < 0 if error
1069
	 */
1070
	public function setPassword($user, $password = '', $isencrypted = 0, $notrigger = 0, $nosyncuser = 0)
1071
	{
1072
		global $conf, $langs;
1073
1074
		$error = 0;
1075
1076
		dol_syslog(get_class($this)."::setPassword user=".$user->id." password=".preg_replace('/./i', '*', $password)." isencrypted=".$isencrypted);
1077
1078
		// If new password not provided, we generate one
1079
		if (!$password) {
1080
			require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
1081
			$password = getRandomPassword(false);
1082
		}
1083
1084
		// Crypt password
1085
		$password_crypted = dol_hash($password);
1086
1087
		$password_indatabase = '';
1088
		if (!$isencrypted) {
1089
			$password_indatabase = $password;
1090
		}
1091
1092
		$this->db->begin();
1093
1094
		// Mise a jour
1095
		$sql = "UPDATE ".MAIN_DB_PREFIX."adherent";
1096
		$sql .= " SET pass_crypted = '".$this->db->escape($password_crypted)."'";
1097
		//if (! empty($conf->global->DATABASE_PWD_ENCRYPTED))
1098
		if ($isencrypted) {
1099
			$sql .= ", pass = null";
1100
		} else {
1101
			$sql .= ", pass = '".$this->db->escape($password_indatabase)."'";
1102
		}
1103
		$sql .= " WHERE rowid = ".$this->id;
1104
1105
		//dol_syslog("Adherent::Password sql=hidden");
1106
		dol_syslog(get_class($this)."::setPassword", LOG_DEBUG);
1107
		$result = $this->db->query($sql);
1108
		if ($result) {
1109
			$nbaffectedrows = $this->db->affected_rows($result);
1110
1111
			if ($nbaffectedrows) {
1112
				$this->pass = $password;
1113
				$this->pass_indatabase = $password_indatabase;
1114
				$this->pass_indatabase_crypted = $password_crypted;
1115
1116
				if ($this->user_id && !$nosyncuser) {
1117
					require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
1118
1119
					// This member is linked with a user, so we also update users informations
1120
					// if this is an update.
1121
					$luser = new User($this->db);
1122
					$result = $luser->fetch($this->user_id);
1123
1124
					if ($result >= 0) {
1125
						$result = $luser->setPassword($user, $this->pass, 0, 0, 1);
1126
						if ($result < 0) {
1127
							$this->error = $luser->error;
1128
							dol_syslog(get_class($this)."::setPassword ".$this->error, LOG_ERR);
1129
							$error++;
1130
						}
1131
					} else {
1132
						$this->error = $luser->error;
1133
						$error++;
1134
					}
1135
				}
1136
1137
				if (!$error && !$notrigger) {
1138
					// Call trigger
1139
					$result = $this->call_trigger('MEMBER_NEW_PASSWORD', $user);
1140
					if ($result < 0) {
1141
						$error++;
1142
						$this->db->rollback();
1143
						return -1;
1144
					}
1145
					// End call triggers
1146
				}
1147
1148
				$this->db->commit();
1149
				return $this->pass;
1150
			} else {
1151
				$this->db->rollback();
1152
				return 0;
1153
			}
1154
		} else {
1155
			$this->db->rollback();
1156
			dol_print_error($this->db);
1157
			return -1;
1158
		}
1159
	}
1160
1161
1162
	/**
1163
	 *    Set link to a user
1164
	 *
1165
	 *    @param     int	$userid        	Id of user to link to
1166
	 *    @return    int					1=OK, -1=KO
1167
	 */
1168
	public function setUserId($userid)
1169
	{
1170
		global $conf, $langs;
1171
1172
		$this->db->begin();
1173
1174
		// If user is linked to this member, remove old link to this member
1175
		$sql = "UPDATE ".MAIN_DB_PREFIX."user SET fk_member = NULL WHERE fk_member = ".((int) $this->id);
1176
		dol_syslog(get_class($this)."::setUserId", LOG_DEBUG);
1177
		$resql = $this->db->query($sql);
1178
		if (!$resql) {
1179
			$this->error = $this->db->error();
1180
			$this->db->rollback();
1181
			return -1;
1182
		}
1183
1184
		// Set link to user
1185
		if ($userid > 0) {
1186
			$sql = "UPDATE ".MAIN_DB_PREFIX."user SET fk_member = ".((int) $this->id);
1187
			$sql .= " WHERE rowid = ".((int) $userid);
1188
			dol_syslog(get_class($this)."::setUserId", LOG_DEBUG);
1189
			$resql = $this->db->query($sql);
1190
			if (!$resql) {
1191
				$this->error = $this->db->error();
1192
				$this->db->rollback();
1193
				return -2;
1194
			}
1195
		}
1196
1197
		$this->db->commit();
1198
1199
		return 1;
1200
	}
1201
1202
1203
	/**
1204
	 *    Set link to a third party
1205
	 *
1206
	 *    @param     int	$thirdpartyid		Id of user to link to
1207
	 *    @return    int						1=OK, -1=KO
1208
	 */
1209
	public function setThirdPartyId($thirdpartyid)
1210
	{
1211
		global $conf, $langs;
1212
1213
		$this->db->begin();
1214
1215
		// Remove link to third party onto any other members
1216
		if ($thirdpartyid > 0) {
1217
			$sql = "UPDATE ".MAIN_DB_PREFIX."adherent SET fk_soc = null";
1218
			$sql .= " WHERE fk_soc = ".((int) $thirdpartyid);
1219
			$sql .= " AND entity = ".$conf->entity;
1220
			dol_syslog(get_class($this)."::setThirdPartyId", LOG_DEBUG);
1221
			$resql = $this->db->query($sql);
1222
		}
1223
1224
		// Add link to third party for current member
1225
		$sql = "UPDATE ".MAIN_DB_PREFIX."adherent SET fk_soc = ".($thirdpartyid > 0 ? $thirdpartyid : 'null');
1226
		$sql .= " WHERE rowid = ".$this->id;
1227
1228
		dol_syslog(get_class($this)."::setThirdPartyId", LOG_DEBUG);
1229
		$resql = $this->db->query($sql);
1230
		if ($resql) {
1231
			$this->db->commit();
1232
			return 1;
1233
		} else {
1234
			$this->error = $this->db->error();
1235
			$this->db->rollback();
1236
			return -1;
1237
		}
1238
	}
1239
1240
1241
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1242
	/**
1243
	 *	Method to load member from its login
1244
	 *
1245
	 *	@param	string	$login		login of member
1246
	 *	@return	void
1247
	 */
1248
	public function fetch_login($login)
1249
	{
1250
		// phpcs:enable
1251
		global $conf;
1252
1253
		$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."adherent";
1254
		$sql .= " WHERE login='".$this->db->escape($login)."'";
1255
		$sql .= " AND entity = ".$conf->entity;
1256
1257
		$resql = $this->db->query($sql);
1258
		if ($resql) {
1259
			if ($this->db->num_rows($resql)) {
1260
				$obj = $this->db->fetch_object($resql);
1261
				$this->fetch($obj->rowid);
1262
			}
1263
		} else {
1264
			dol_print_error($this->db);
1265
		}
1266
	}
1267
1268
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1269
	/**
1270
	 *	Method to load member from its name
1271
	 *
1272
	 *	@param	string	$firstname	Firstname
1273
	 *	@param	string	$lastname	Lastname
1274
	 *	@return	void
1275
	 */
1276
	public function fetch_name($firstname, $lastname)
1277
	{
1278
		// phpcs:enable
1279
		global $conf;
1280
1281
		$sql = "SELECT rowid FROM ".MAIN_DB_PREFIX."adherent";
1282
		$sql .= " WHERE firstname='".$this->db->escape($firstname)."'";
1283
		$sql .= " AND lastname='".$this->db->escape($lastname)."'";
1284
		$sql .= " AND entity = ".$conf->entity;
1285
1286
		$resql = $this->db->query($sql);
1287
		if ($resql) {
1288
			if ($this->db->num_rows($resql)) {
1289
				$obj = $this->db->fetch_object($resql);
1290
				$this->fetch($obj->rowid);
1291
			}
1292
		} else {
1293
			dol_print_error($this->db);
1294
		}
1295
	}
1296
1297
	/**
1298
	 *	Load member from database
1299
	 *
1300
	 *	@param	int		$rowid      			Id of object to load
1301
	 * 	@param	string	$ref					To load member from its ref
1302
	 * 	@param	int		$fk_soc					To load member from its link to third party
1303
	 * 	@param	string	$ref_ext				External reference
1304
	 *  @param	bool	$fetch_optionals		To load optionals (extrafields)
1305
	 *  @param	bool	$fetch_subscriptions	To load member subscriptions
1306
	 *	@return int								>0 if OK, 0 if not found, <0 if KO
1307
	 */
1308
	public function fetch($rowid, $ref = '', $fk_soc = '', $ref_ext = '', $fetch_optionals = true, $fetch_subscriptions = true)
1309
	{
1310
		global $langs;
1311
1312
		$sql = "SELECT d.rowid, d.ref, d.ref_ext, d.civility as civility_code, d.gender, d.firstname, d.lastname,";
1313
		$sql .= " d.societe as company, d.fk_soc, d.statut, d.public, d.address, d.zip, d.town, d.note_private,";
1314
		$sql .= " d.note_public,";
1315
		$sql .= " d.email, d.url, d.socialnetworks, d.phone, d.phone_perso, d.phone_mobile, d.login, d.pass, d.pass_crypted,";
1316
		$sql .= " d.photo, d.fk_adherent_type, d.morphy, d.entity,";
1317
		$sql .= " d.datec as datec,";
1318
		$sql .= " d.tms as datem,";
1319
		$sql .= " d.datefin as datefin,";
1320
		$sql .= " d.birth as birthday,";
1321
		$sql .= " d.datevalid as datev,";
1322
		$sql .= " d.country,";
1323
		$sql .= " d.state_id,";
1324
		$sql .= " d.model_pdf,";
1325
		$sql .= " c.rowid as country_id, c.code as country_code, c.label as country,";
1326
		$sql .= " dep.nom as state, dep.code_departement as state_code,";
1327
		$sql .= " t.libelle as type, t.subscription as subscription,";
1328
		$sql .= " u.rowid as user_id, u.login as user_login";
1329
		$sql .= " FROM ".MAIN_DB_PREFIX."adherent_type as t, ".MAIN_DB_PREFIX."adherent as d";
1330
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_country as c ON d.country = c.rowid";
1331
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_departements as dep ON d.state_id = dep.rowid";
1332
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."user as u ON d.rowid = u.fk_member";
1333
		$sql .= " WHERE d.fk_adherent_type = t.rowid";
1334
		if ($rowid) {
1335
			$sql .= " AND d.rowid=".((int) $rowid);
1336
		} elseif ($ref || $fk_soc) {
1337
			$sql .= " AND d.entity IN (".getEntity('adherent').")";
1338
			if ($ref) {
1339
				$sql .= " AND d.ref='".$this->db->escape($ref)."'";
1340
			} elseif ($fk_soc > 0) {
1341
				$sql .= " AND d.fk_soc=".((int) $fk_soc);
1342
			}
1343
		} elseif ($ref_ext) {
1344
			$sql .= " AND d.ref_ext='".$this->db->escape($ref_ext)."'";
1345
		}
1346
1347
		dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
1348
		$resql = $this->db->query($sql);
1349
		if ($resql) {
1350
			if ($this->db->num_rows($resql)) {
1351
				$obj = $this->db->fetch_object($resql);
1352
1353
				$this->entity = $obj->entity;
1354
				$this->id = $obj->rowid;
1355
				$this->ref = $obj->ref;
1356
				$this->ref_ext = $obj->ref_ext;
1357
1358
				$this->civility_id = $obj->civility_code; // Bad. Kept for backard compatibility
1359
				$this->civility_code = $obj->civility_code;
1360
				$this->civility = $obj->civility_code ? ($langs->trans("Civility".$obj->civility_code) != ("Civility".$obj->civility_code) ? $langs->trans("Civility".$obj->civility_code) : $obj->civility_code) : '';
1361
1362
				$this->firstname = $obj->firstname;
1363
				$this->lastname = $obj->lastname;
1364
				$this->gender = $obj->gender;
1365
				$this->login = $obj->login;
1366
				$this->societe = $obj->company;
1367
				$this->company = $obj->company;
1368
				$this->socid = $obj->fk_soc;
1369
				$this->fk_soc = $obj->fk_soc; // For backward compatibility
1370
				$this->address = $obj->address;
1371
				$this->zip = $obj->zip;
1372
				$this->town = $obj->town;
1373
1374
				$this->pass = $obj->pass;
1375
				$this->pass_indatabase = $obj->pass;
1376
				$this->pass_indatabase_crypted = $obj->pass_crypted;
1377
1378
				$this->state_id = $obj->state_id;
1379
				$this->state_code = $obj->state_id ? $obj->state_code : '';
1380
				$this->state = $obj->state_id ? $obj->state : '';
1381
1382
				$this->country_id = $obj->country_id;
1383
				$this->country_code = $obj->country_code;
1384
				if ($langs->trans("Country".$obj->country_code) != "Country".$obj->country_code) {
1385
					$this->country = $langs->transnoentitiesnoconv("Country".$obj->country_code);
1386
				} else {
1387
					$this->country = $obj->country;
1388
				}
1389
1390
				$this->phone = $obj->phone;
1391
				$this->phone_perso = $obj->phone_perso;
1392
				$this->phone_mobile = $obj->phone_mobile;
1393
				$this->email = $obj->email;
1394
				$this->url = $obj->url;
1395
1396
				$this->socialnetworks = (array) json_decode($obj->socialnetworks, true);
1397
1398
				$this->photo = $obj->photo;
1399
				$this->statut = $obj->statut;
1400
				$this->public = $obj->public;
1401
1402
				$this->datec = $this->db->jdate($obj->datec);
1403
				$this->date_creation = $this->db->jdate($obj->datec);
1404
				$this->datem = $this->db->jdate($obj->datem);
1405
				$this->date_modification = $this->db->jdate($obj->datem);
1406
				$this->datefin = $this->db->jdate($obj->datefin);
1407
				$this->datevalid = $this->db->jdate($obj->datev);
1408
				$this->date_validation = $this->db->jdate($obj->datev);
1409
				$this->birth = $this->db->jdate($obj->birthday);
1410
1411
				$this->note_private = $obj->note_private;
1412
				$this->note_public = $obj->note_public;
1413
				$this->morphy = $obj->morphy;
1414
1415
				$this->typeid = $obj->fk_adherent_type;
1416
				$this->type = $obj->type;
1417
				$this->need_subscription = $obj->subscription;
1418
1419
				$this->user_id = $obj->user_id;
1420
				$this->user_login = $obj->user_login;
1421
1422
				$this->model_pdf = $obj->model_pdf;
1423
1424
				// Retrieve all extrafield
1425
				// fetch optionals attributes and labels
1426
				if ($fetch_optionals) {
1427
					$this->fetch_optionals();
1428
				}
1429
1430
				// Load other properties
1431
				if ($fetch_subscriptions) {
1432
					$result = $this->fetch_subscriptions();
1433
				}
1434
1435
				return $this->id;
1436
			} else {
1437
				return 0;
1438
			}
1439
		} else {
1440
			$this->error = $this->db->lasterror();
1441
			return -1;
1442
		}
1443
	}
1444
1445
1446
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1447
	/**
1448
	 *	Function to get member subscriptions data:
1449
	 *  subscriptions,
1450
	 *	first_subscription_date, first_subscription_date_start, first_subscription_date_end, first_subscription_amount
1451
	 *	last_subscription_date, last_subscription_date_start, last_subscription_date_end, last_subscription_amount
1452
	 *
1453
	 *	@return		int			<0 if KO, >0 if OK
1454
	 */
1455
	public function fetch_subscriptions()
1456
	{
1457
		// phpcs:enable
1458
		global $langs;
1459
1460
		require_once DOL_DOCUMENT_ROOT.'/adherents/class/subscription.class.php';
1461
1462
		$sql = "SELECT c.rowid, c.fk_adherent, c.fk_type, c.subscription, c.note, c.fk_bank,";
1463
		$sql .= " c.tms as datem,";
1464
		$sql .= " c.datec as datec,";
1465
		$sql .= " c.dateadh as dateh,";
1466
		$sql .= " c.datef as datef";
1467
		$sql .= " FROM ".MAIN_DB_PREFIX."subscription as c";
1468
		$sql .= " WHERE c.fk_adherent = ".$this->id;
1469
		$sql .= " ORDER BY c.dateadh";
1470
		dol_syslog(get_class($this)."::fetch_subscriptions", LOG_DEBUG);
1471
1472
		$resql = $this->db->query($sql);
1473
		if ($resql) {
1474
			$this->subscriptions = array();
1475
1476
			$i = 0;
1477
			while ($obj = $this->db->fetch_object($resql)) {
1478
				if ($i == 0) {
1479
					$this->first_subscription_date = $this->db->jdate($obj->datec);
1480
					$this->first_subscription_date_start = $this->db->jdate($obj->dateh);
1481
					$this->first_subscription_date_end = $this->db->jdate($obj->datef);
1482
					$this->first_subscription_amount = $obj->subscription;
1483
				}
1484
				$this->last_subscription_date = $this->db->jdate($obj->datec);
1485
				$this->last_subscription_date_start = $this->db->jdate($obj->datef);
1486
				$this->last_subscription_date_end = $this->db->jdate($obj->datef);
1487
				$this->last_subscription_amount = $obj->subscription;
1488
1489
				$subscription = new Subscription($this->db);
1490
				$subscription->id = $obj->rowid;
1491
				$subscription->fk_adherent = $obj->fk_adherent;
1492
				$subscription->fk_type = $obj->fk_type;
1493
				$subscription->amount = $obj->subscription;
1494
				$subscription->note = $obj->note;
1495
				$subscription->fk_bank = $obj->fk_bank;
1496
				$subscription->datem = $this->db->jdate($obj->datem);
1497
				$subscription->datec = $this->db->jdate($obj->datec);
1498
				$subscription->dateh = $this->db->jdate($obj->dateh);
1499
				$subscription->datef = $this->db->jdate($obj->datef);
1500
1501
				$this->subscriptions[] = $subscription;
1502
1503
				$i++;
1504
			}
1505
			return 1;
1506
		} else {
1507
			$this->error = $this->db->error().' sql='.$sql;
1508
			return -1;
1509
		}
1510
	}
1511
1512
1513
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1514
	/**
1515
	 *	Function to get partnerships array
1516
	 *
1517
	 *  @param		string		$mode		'member' or 'thirdparty'
1518
	 *	@return		int						<0 if KO, >0 if OK
1519
	 */
1520
	public function fetchPartnerships($mode)
1521
	{
1522
		// phpcs:enable
1523
		global $langs;
1524
1525
		require_once DOL_DOCUMENT_ROOT.'/parntership/class/partnership.class.php';
1526
1527
1528
		$this->partnerships[] = array();
1529
1530
		return 1;
1531
	}
1532
1533
1534
	/**
1535
	 *	Insert subscription into database and eventually add links to banks, mailman, etc...
1536
	 *
1537
	 *	@param	int	        $date        		Date of effect of subscription
1538
	 *	@param	double		$amount     		Amount of subscription (0 accepted for some members)
1539
	 *	@param	int			$accountid			Id bank account
1540
	 *	@param	string		$operation			Type of payment (if Id bank account provided). Example: 'CB', ...
1541
	 *	@param	string		$label				Label operation (if Id bank account provided)
1542
	 *	@param	string		$num_chq			Numero cheque (if Id bank account provided)
1543
	 *	@param	string		$emetteur_nom		Name of cheque writer
1544
	 *	@param	string		$emetteur_banque	Name of bank of cheque
1545
	 *	@param	int     	$datesubend			Date end subscription
1546
	 *	@param	int     	$fk_type 			Member type id
1547
	 *	@return int         					rowid of record added, <0 if KO
1548
	 */
1549
	public function subscription($date, $amount, $accountid = 0, $operation = '', $label = '', $num_chq = '', $emetteur_nom = '', $emetteur_banque = '', $datesubend = 0, $fk_type = null)
1550
	{
1551
		global $conf, $langs, $user;
1552
1553
		require_once DOL_DOCUMENT_ROOT.'/adherents/class/subscription.class.php';
1554
1555
		$error = 0;
1556
1557
		// Clean parameters
1558
		if (!$amount) {
1559
			$amount = 0;
1560
		}
1561
1562
		$this->db->begin();
1563
1564
		if ($datesubend) {
1565
			$datefin = $datesubend;
1566
		} else {
1567
			// If no end date, end date = date + 1 year - 1 day
1568
			$datefin = dol_time_plus_duree($date, 1, 'y');
1569
			$datefin = dol_time_plus_duree($datefin, -1, 'd');
1570
		}
1571
1572
		// Create subscription
1573
		$subscription = new Subscription($this->db);
1574
		$subscription->fk_adherent = $this->id;
1575
		$subscription->dateh = $date; // Date of new subscription
1576
		$subscription->datef = $datefin; // End data of new subscription
1577
		$subscription->amount = $amount;
1578
		$subscription->note = $label; // deprecated
1579
		$subscription->note_public = $label;
1580
		$subscription->fk_type = $fk_type;
1581
1582
		$rowid = $subscription->create($user);
1583
		if ($rowid > 0) {
1584
			// Update denormalized subscription end date (read database subscription to find values)
1585
			// This will also update this->datefin
1586
			$result = $this->update_end_date($user);
1587
			if ($result > 0) {
1588
				// Change properties of object (used by triggers)
1589
				$this->last_subscription_date = dol_now();
1590
				$this->last_subscription_date_start = $date;
1591
				$this->last_subscription_date_end = $datefin;
1592
				$this->last_subscription_amount = $amount;
1593
			}
1594
1595
			if (!$error) {
1596
				$this->db->commit();
1597
				return $rowid;
1598
			} else {
1599
				$this->db->rollback();
1600
				return -2;
1601
			}
1602
		} else {
1603
			$this->error = $subscription->error;
1604
			$this->errors = $subscription->errors;
1605
			$this->db->rollback();
1606
			return -1;
1607
		}
1608
	}
1609
1610
1611
	/**
1612
	 *	Do complementary actions after subscription recording.
1613
	 *
1614
	 *	@param	int			$subscriptionid			Id of created subscription
1615
	 *  @param	string		$option					Which action ('bankdirect', 'bankviainvoice', 'invoiceonly', ...)
1616
	 *	@param	int			$accountid				Id bank account
1617
	 *	@param	int			$datesubscription		Date of subscription
1618
	 *	@param	int			$paymentdate			Date of payment
1619
	 *	@param	string		$operation				Code of type of operation (if Id bank account provided). Example 'CB', ...
1620
	 *	@param	string		$label					Label operation (if Id bank account provided)
1621
	 *	@param	double		$amount     			Amount of subscription (0 accepted for some members)
1622
	 *	@param	string		$num_chq				Numero cheque (if Id bank account provided)
1623
	 *	@param	string		$emetteur_nom			Name of cheque writer
1624
	 *	@param	string		$emetteur_banque		Name of bank of cheque
1625
	 *  @param	string		$autocreatethirdparty	Auto create new thirdparty if member not yet linked to a thirdparty and we request an option that generate invoice.
1626
	 *  @param  string      $ext_payment_id         External id of payment (for example Stripe charge id)
1627
	 *  @param  string      $ext_payment_site       Name of external paymentmode (for example 'stripe')
1628
	 *	@return int									<0 if KO, >0 if OK
1629
	 */
1630
	public function subscriptionComplementaryActions($subscriptionid, $option, $accountid, $datesubscription, $paymentdate, $operation, $label, $amount, $num_chq, $emetteur_nom = '', $emetteur_banque = '', $autocreatethirdparty = 0, $ext_payment_id = '', $ext_payment_site = '')
1631
	{
1632
		global $conf, $langs, $user, $mysoc;
1633
1634
		$error = 0;
1635
1636
		$this->invoice = null; // This will contains invoice if an invoice is created
1637
1638
		dol_syslog("subscriptionComplementaryActions subscriptionid=".$subscriptionid." option=".$option." accountid=".$accountid." datesubscription=".$datesubscription." paymentdate=".
1639
			$paymentdate." label=".$label." amount=".$amount." num_chq=".$num_chq." autocreatethirdparty=".$autocreatethirdparty);
1640
1641
		// Insert into bank account directlty (if option choosed for) + link to llx_subscription if option is 'bankdirect'
1642
		if ($option == 'bankdirect' && $accountid) {
1643
			require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
1644
1645
			$acct = new Account($this->db);
1646
			$result = $acct->fetch($accountid);
1647
1648
			$dateop = $paymentdate;
1649
1650
			$insertid = $acct->addline($dateop, $operation, $label, $amount, $num_chq, '', $user, $emetteur_nom, $emetteur_banque);
1651
			if ($insertid > 0) {
1652
				$inserturlid = $acct->add_url_line($insertid, $this->id, DOL_URL_ROOT.'/adherents/card.php?rowid=', $this->getFullname($langs), 'member');
1653
				if ($inserturlid > 0) {
1654
					// Update table subscription
1655
					$sql = "UPDATE ".MAIN_DB_PREFIX."subscription SET fk_bank=".((int) $insertid);
1656
					$sql .= " WHERE rowid=".((int) $subscriptionid);
1657
1658
					dol_syslog("subscription::subscription", LOG_DEBUG);
1659
					$resql = $this->db->query($sql);
1660
					if (!$resql) {
1661
						$error++;
1662
						$this->error = $this->db->lasterror();
1663
						$this->errors[] = $this->error;
1664
					}
1665
				} else {
1666
					$error++;
1667
					$this->error = $acct->error;
1668
					$this->errors = $acct->errors;
1669
				}
1670
			} else {
1671
				$error++;
1672
				$this->error = $acct->error;
1673
				$this->errors = $acct->errors;
1674
			}
1675
		}
1676
1677
		// If option choosed, we create invoice
1678
		if (($option == 'bankviainvoice' && $accountid) || $option == 'invoiceonly') {
1679
			require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
1680
			require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/paymentterm.class.php';
1681
1682
			$invoice = new Facture($this->db);
1683
			$customer = new Societe($this->db);
1684
1685
			if (!$error) {
1686
				if (!($this->fk_soc > 0)) { // If not yet linked to a company
1687
					if ($autocreatethirdparty) {
1688
						// Create a linked thirdparty to member
1689
						$companyalias = '';
1690
						$fullname = $this->getFullName($langs);
1691
1692
						if ($this->morphy == 'mor') {
1693
							$companyname = $this->company;
1694
							if (!empty($fullname)) {
1695
								$companyalias = $fullname;
1696
							}
1697
						} else {
1698
							$companyname = $fullname;
1699
							if (!empty($this->company)) {
1700
								$companyalias = $this->company;
1701
							}
1702
						}
1703
1704
						$result = $customer->create_from_member($this, $companyname, $companyalias);
1705
						if ($result < 0) {
1706
							$this->error = $customer->error;
1707
							$this->errors = $customer->errors;
1708
							$error++;
1709
						} else {
1710
							$this->fk_soc = $result;
1711
						}
1712
					} else {
1713
						$langs->load("errors");
1714
						$this->error = $langs->trans("ErrorMemberNotLinkedToAThirpartyLinkOrCreateFirst");
1715
						$this->errors[] = $this->error;
1716
						$error++;
1717
					}
1718
				}
1719
			}
1720
			if (!$error) {
1721
				$result = $customer->fetch($this->fk_soc);
1722
				if ($result <= 0) {
1723
					$this->error = $customer->error;
1724
					$this->errors = $customer->errors;
1725
					$error++;
1726
				}
1727
			}
1728
1729
			if (!$error) {
1730
				// Create draft invoice
1731
				$invoice->type = Facture::TYPE_STANDARD;
1732
				$invoice->cond_reglement_id = $customer->cond_reglement_id;
1733
				if (empty($invoice->cond_reglement_id)) {
1734
					$paymenttermstatic = new PaymentTerm($this->db);
1735
					$invoice->cond_reglement_id = $paymenttermstatic->getDefaultId();
1736
					if (empty($invoice->cond_reglement_id)) {
1737
						$error++;
1738
						$this->error = 'ErrorNoPaymentTermRECEPFound';
1739
						$this->errors[] = $this->error;
1740
					}
1741
				}
1742
				$invoice->socid = $this->fk_soc;
1743
				$invoice->date = $datesubscription;
1744
1745
				// Possibility to add external linked objects with hooks
1746
				$invoice->linked_objects['subscription'] = $subscriptionid;
1747
				if (!empty($_POST['other_linked_objects']) && is_array($_POST['other_linked_objects'])) {
1748
					$invoice->linked_objects = array_merge($invoice->linked_objects, $_POST['other_linked_objects']);
1749
				}
1750
1751
				$result = $invoice->create($user);
1752
				if ($result <= 0) {
1753
					$this->error = $invoice->error;
1754
					$this->errors = $invoice->errors;
1755
					$error++;
1756
				} else {
1757
					$this->invoice = $invoice;
1758
				}
1759
			}
1760
1761
			if (!$error) {
1762
				// Add line to draft invoice
1763
				$idprodsubscription = 0;
1764
				if (!empty($conf->global->ADHERENT_PRODUCT_ID_FOR_SUBSCRIPTIONS) && (!empty($conf->product->enabled) || !empty($conf->service->enabled))) {
1765
					$idprodsubscription = $conf->global->ADHERENT_PRODUCT_ID_FOR_SUBSCRIPTIONS;
1766
				}
1767
1768
				$vattouse = 0;
1769
				if (isset($conf->global->ADHERENT_VAT_FOR_SUBSCRIPTIONS) && $conf->global->ADHERENT_VAT_FOR_SUBSCRIPTIONS == 'defaultforfoundationcountry') {
1770
					$vattouse = get_default_tva($mysoc, $mysoc, $idprodsubscription);
1771
				}
1772
				//print xx".$vattouse." - ".$mysoc." - ".$customer;exit;
1773
				$result = $invoice->addline($label, 0, 1, $vattouse, 0, 0, $idprodsubscription, 0, $datesubscription, '', 0, 0, '', 'TTC', $amount, 1);
1774
				if ($result <= 0) {
1775
					$this->error = $invoice->error;
1776
					$this->errors = $invoice->errors;
1777
					$error++;
1778
				}
1779
			}
1780
1781
			if (!$error) {
1782
				// Validate invoice
1783
				$result = $invoice->validate($user);
1784
				if ($result <= 0) {
1785
					$this->error = $invoice->error;
1786
					$this->errors = $invoice->errors;
1787
					$error++;
1788
				}
1789
			}
1790
1791
			if (!$error) {
1792
				// TODO Link invoice with subscription ?
1793
			}
1794
1795
			// Add payment onto invoice
1796
			if (!$error && $option == 'bankviainvoice' && $accountid) {
1797
				require_once DOL_DOCUMENT_ROOT.'/compta/paiement/class/paiement.class.php';
1798
				require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
1799
				require_once DOL_DOCUMENT_ROOT.'/core/lib/functions.lib.php';
1800
1801
				$amounts = array();
1802
				$amounts[$invoice->id] = price2num($amount);
1803
1804
				$paiement = new Paiement($this->db);
1805
				$paiement->datepaye = $paymentdate;
1806
				$paiement->amounts = $amounts;
1807
				$paiement->paiementid = dol_getIdFromCode($this->db, $operation, 'c_paiement', 'code', 'id', 1);
1808
				$paiement->num_payment = $num_chq;
1809
				$paiement->note_public = $label;
1810
				$paiement->ext_payment_id = $ext_payment_id;
1811
				$paiement->ext_payment_site = $ext_payment_site;
1812
1813
				if (!$error) {
1814
					// Create payment line for invoice
1815
					$paiement_id = $paiement->create($user);
1816
					if (!$paiement_id > 0) {
1817
						$this->error = $paiement->error;
1818
						$this->errors = $paiement->errors;
1819
						$error++;
1820
					}
1821
				}
1822
1823
				if (!$error) {
1824
					// Add transaction into bank account
1825
					$bank_line_id = $paiement->addPaymentToBank($user, 'payment', '(SubscriptionPayment)', $accountid, $emetteur_nom, $emetteur_banque);
1826
					if (!($bank_line_id > 0)) {
1827
						$this->error = $paiement->error;
1828
						$this->errors = $paiement->errors;
1829
						$error++;
1830
					}
1831
				}
1832
1833
				if (!$error && !empty($bank_line_id)) {
1834
					// Update fk_bank into subscription table
1835
					$sql = 'UPDATE '.MAIN_DB_PREFIX.'subscription SET fk_bank='.$bank_line_id;
1836
					$sql .= ' WHERE rowid='.$subscriptionid;
1837
1838
					$result = $this->db->query($sql);
1839
					if (!$result) {
1840
						$error++;
1841
					}
1842
				}
1843
1844
				if (!$error) {
1845
					// Set invoice as paid
1846
					$invoice->setPaid($user);
1847
				}
1848
			}
1849
1850
			if (!$error) {
1851
				// Define output language
1852
				$outputlangs = $langs;
1853
				$newlang = '';
1854
				$lang_id = GETPOST('lang_id');
1855
				if ($conf->global->MAIN_MULTILANGS && empty($newlang) && !empty($lang_id)) {
1856
					$newlang = $lang_id;
1857
				}
1858
				if ($conf->global->MAIN_MULTILANGS && empty($newlang)) {
1859
					$newlang = $customer->default_lang;
1860
				}
1861
				if (!empty($newlang)) {
1862
					$outputlangs = new Translate("", $conf);
1863
					$outputlangs->setDefaultLang($newlang);
1864
				}
1865
				// Generate PDF (whatever is option MAIN_DISABLE_PDF_AUTOUPDATE) so we can include it into email
1866
				//if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE))
1867
1868
				$invoice->generateDocument($invoice->model_pdf, $outputlangs);
1869
			}
1870
		}
1871
1872
		if ($error) {
1873
			return -1;
1874
		} else {
1875
			return 1;
1876
		}
1877
	}
1878
1879
1880
	/**
1881
	 *		Function that validate a member
1882
	 *
1883
	 *		@param	User	$user		user adherent qui valide
1884
	 *		@return	int					<0 if KO, 0 if nothing done, >0 if OK
1885
	 */
1886
	public function validate($user)
1887
	{
1888
		global $langs, $conf;
1889
1890
		$error = 0;
1891
		$now = dol_now();
1892
1893
		// Check parameters
1894
		if ($this->statut == self::STATUS_VALIDATED) {
1895
			dol_syslog(get_class($this)."::validate statut of member does not allow this", LOG_WARNING);
1896
			return 0;
1897
		}
1898
1899
		$this->db->begin();
1900
1901
		$sql = "UPDATE ".MAIN_DB_PREFIX."adherent SET";
1902
		$sql .= " statut = ".self::STATUS_VALIDATED;
1903
		$sql .= ", datevalid = '".$this->db->idate($now)."'";
1904
		$sql .= ", fk_user_valid=".$user->id;
1905
		$sql .= " WHERE rowid = ".$this->id;
1906
1907
		dol_syslog(get_class($this)."::validate", LOG_DEBUG);
1908
		$result = $this->db->query($sql);
1909
		if ($result) {
1910
			$this->statut = self::STATUS_VALIDATED;
1911
1912
			// Call trigger
1913
			$result = $this->call_trigger('MEMBER_VALIDATE', $user);
1914
			if ($result < 0) {
1915
				$error++;
1916
				$this->db->rollback();
1917
				return -1;
1918
			}
1919
			// End call triggers
1920
1921
			$this->datevalid = $now;
1922
1923
			$this->db->commit();
1924
			return 1;
1925
		} else {
1926
			$this->error = $this->db->error();
1927
			$this->db->rollback();
1928
			return -1;
1929
		}
1930
	}
1931
1932
1933
	/**
1934
	 *		Fonction qui resilie un adherent
1935
	 *
1936
	 *		@param	User	$user		User making change
1937
	 *		@return	int					<0 if KO, >0 if OK
1938
	 */
1939
	public function resiliate($user)
1940
	{
1941
		global $langs, $conf;
1942
1943
		$error = 0;
1944
1945
		// Check parameters
1946
		if ($this->statut == self::STATUS_RESILIATED) {
1947
			dol_syslog(get_class($this)."::resiliate statut of member does not allow this", LOG_WARNING);
1948
			return 0;
1949
		}
1950
1951
		$this->db->begin();
1952
1953
		$sql = "UPDATE ".MAIN_DB_PREFIX."adherent SET";
1954
		$sql .= " statut = ".self::STATUS_RESILIATED;
1955
		$sql .= ", fk_user_valid=".$user->id;
1956
		$sql .= " WHERE rowid = ".$this->id;
1957
1958
		$result = $this->db->query($sql);
1959
		if ($result) {
1960
			$this->statut = self::STATUS_RESILIATED;
1961
1962
			// Call trigger
1963
			$result = $this->call_trigger('MEMBER_RESILIATE', $user);
1964
			if ($result < 0) {
1965
				$error++;
1966
				$this->db->rollback();
1967
				return -1;
1968
			}
1969
			// End call triggers
1970
1971
			$this->db->commit();
1972
			return 1;
1973
		} else {
1974
			$this->error = $this->db->error();
1975
			$this->db->rollback();
1976
			return -1;
1977
		}
1978
	}
1979
1980
	/**
1981
	 *		Functiun to exlude (set adherent.status to -2) a member
1982
	 *		TODO
1983
	 *		A private note should be added to know why the member has been excluded
1984
	 *		For historical purpose it add an "extra-subscription" type excluded
1985
	 *
1986
	 *		@param	User	$user		User making change
1987
	 *		@return	int					<0 if KO, >0 if OK
1988
	 */
1989
	public function exclude($user)
1990
	{
1991
		global $langs, $conf;
1992
1993
		$error = 0;
1994
1995
		// Check parameters
1996
		if ($this->statut == self::STATUS_EXCLUDED) {
1997
			dol_syslog(get_class($this)."::resiliate statut of member does not allow this", LOG_WARNING);
1998
			return 0;
1999
		}
2000
2001
		$this->db->begin();
2002
2003
		$sql = "UPDATE ".MAIN_DB_PREFIX."adherent SET";
2004
		$sql .= " statut = ".self::STATUS_EXCLUDED;
2005
		$sql .= ", fk_user_valid=".$user->id;
2006
		$sql .= " WHERE rowid = ".$this->id;
2007
2008
		$result = $this->db->query($sql);
2009
		if ($result) {
2010
			$this->statut = self::STATUS_EXCLUDED;
2011
2012
			// Call trigger
2013
			$result = $this->call_trigger('MEMBER_EXCLUDE', $user);
2014
			if ($result < 0) {
2015
				$error++;
2016
				$this->db->rollback();
2017
				return -1;
2018
			}
2019
			// End call triggers
2020
2021
			$this->db->commit();
2022
			return 1;
2023
		} else {
2024
			$this->error = $this->db->error();
2025
			$this->db->rollback();
2026
			return -1;
2027
		}
2028
	}
2029
2030
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2031
	/**
2032
	 *  Function to add member into external tools mailing-list, spip, etc.
2033
	 *
2034
	 *  @return		int		<0 if KO, >0 if OK
2035
	 */
2036
	public function add_to_abo()
2037
	{
2038
		// phpcs:enable
2039
		global $conf, $langs;
2040
2041
		include_once DOL_DOCUMENT_ROOT.'/mailmanspip/class/mailmanspip.class.php';
2042
		$mailmanspip = new MailmanSpip($this->db);
2043
2044
		$err = 0;
2045
2046
		// mailman
2047
		if (!empty($conf->global->ADHERENT_USE_MAILMAN) && !empty($conf->mailmanspip->enabled)) {
2048
			$result = $mailmanspip->add_to_mailman($this);
2049
2050
			if ($result < 0) {
2051
				if (!empty($mailmanspip->error)) {
2052
					$this->errors[] = $mailmanspip->error;
2053
				}
2054
				$err += 1;
2055
			}
2056
			foreach ($mailmanspip->mladded_ko as $tmplist => $tmpemail) {
2057
				$langs->load("errors");
2058
				$this->errors[] = $langs->trans("ErrorFailedToAddToMailmanList", $tmpemail, $tmplist);
2059
			}
2060
			foreach ($mailmanspip->mladded_ok as $tmplist => $tmpemail) {
2061
				$langs->load("mailmanspip");
2062
				$this->mesgs[] = $langs->trans("SuccessToAddToMailmanList", $tmpemail, $tmplist);
2063
			}
2064
		}
2065
2066
		// spip
2067
		if (!empty($conf->global->ADHERENT_USE_SPIP) && !empty($conf->mailmanspip->enabled)) {
2068
			$result = $mailmanspip->add_to_spip($this);
2069
			if ($result < 0) {
2070
				$this->errors[] = $mailmanspip->error;
2071
				$err += 1;
2072
			}
2073
		}
2074
		if ($err) {
2075
			return -$err;
2076
		} else {
2077
			return 1;
2078
		}
2079
	}
2080
2081
2082
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2083
	/**
2084
	 *  Function to delete a member from external tools like mailing-list, spip, etc.
2085
	 *
2086
	 *  @return     int     <0 if KO, >0 if OK
2087
	 */
2088
	public function del_to_abo()
2089
	{
2090
		// phpcs:enable
2091
		global $conf, $langs;
2092
2093
		include_once DOL_DOCUMENT_ROOT.'/mailmanspip/class/mailmanspip.class.php';
2094
		$mailmanspip = new MailmanSpip($this->db);
2095
2096
		$err = 0;
2097
2098
		// mailman
2099
		if (!empty($conf->global->ADHERENT_USE_MAILMAN)) {
2100
			$result = $mailmanspip->del_to_mailman($this);
2101
			if ($result < 0) {
2102
				if (!empty($mailmanspip->error)) {
2103
					$this->errors[] = $mailmanspip->error;
2104
				}
2105
				$err += 1;
2106
			}
2107
2108
			foreach ($mailmanspip->mlremoved_ko as $tmplist => $tmpemail) {
2109
				$langs->load("errors");
2110
				$this->errors[] = $langs->trans("ErrorFailedToRemoveToMailmanList", $tmpemail, $tmplist);
2111
			}
2112
			foreach ($mailmanspip->mlremoved_ok as $tmplist => $tmpemail) {
2113
				$langs->load("mailmanspip");
2114
				$this->mesgs[] = $langs->trans("SuccessToRemoveToMailmanList", $tmpemail, $tmplist);
2115
			}
2116
		}
2117
2118
		if ($conf->global->ADHERENT_USE_SPIP && !empty($conf->mailmanspip->enabled)) {
2119
			$result = $mailmanspip->del_to_spip($this);
2120
			if ($result < 0) {
2121
				$this->errors[] = $mailmanspip->error;
2122
				$err += 1;
2123
			}
2124
		}
2125
		if ($err) {
2126
			// error
2127
			return -$err;
2128
		} else {
2129
			return 1;
2130
		}
2131
	}
2132
2133
2134
	/**
2135
	 *    Return civility label of a member
2136
	 *
2137
	 *    @return   string              	Translated name of civility (translated with transnoentitiesnoconv)
2138
	 */
2139
	public function getCivilityLabel()
2140
	{
2141
		global $langs;
2142
		$langs->load("dict");
2143
2144
		$code = (empty($this->civility_id) ? '' : $this->civility_id);
2145
		if (empty($code)) {
2146
			return '';
2147
		}
2148
		return $langs->getLabelFromKey($this->db, "Civility".$code, "c_civility", "code", "label", $code);
2149
	}
2150
2151
	/**
2152
	 *  Return clicable name (with picto eventually)
2153
	 *
2154
	 *	@param	int		$withpictoimg				0=No picto, 1=Include picto into link, 2=Only picto, -1=Include photo into link, -2=Only picto photo, -3=Only photo very small)
2155
	 *	@param	int		$maxlen						length max label
2156
	 *	@param	string	$option						Page for link ('card', 'category', 'subscription', ...)
2157
	 *	@param  string  $mode           			''=Show firstname+lastname as label (using default order), 'firstname'=Show only firstname, 'lastname'=Show only lastname, 'login'=Show login, 'ref'=Show ref
2158
	 *	@param  string  $morecss        			Add more css on link
2159
	 *	@param  int		$save_lastsearch_value    	-1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking
2160
	 *	@param	int		$notooltip					1=Disable tooltip
2161
	 *	@param  int		$addlinktonotes				1=Add link to notes
2162
	 *	@return	string								Chaine avec URL
2163
	 */
2164
	public function getNomUrl($withpictoimg = 0, $maxlen = 0, $option = 'card', $mode = '', $morecss = '', $save_lastsearch_value = -1, $notooltip = 0, $addlinktonotes = 0)
2165
	{
2166
		global $conf, $langs;
2167
2168
		if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER) && $withpictoimg) {
2169
			$withpictoimg = 0;
2170
		}
2171
2172
		$result = '';
2173
		$label = '';
2174
		$linkstart = '';
2175
		$linkend = '';
2176
2177
		if (!empty($this->photo)) {
2178
			$label .= '<div class="photointooltip">';
2179
			$label .= Form::showphoto('memberphoto', $this, 80, 0, 0, 'photowithmargin photologintooltip', 'small', 0, 1);
2180
			$label .= '</div><div style="clear: both;"></div>';
2181
		}
2182
2183
		$label .= '<div class="centpercent">';
2184
		$label .= img_picto('', $this->picto).' <u class="paddingrightonly">'.$langs->trans("Member").'</u>';
2185
		$label .= ' '.$this->getLibStatut(4);
2186
		if (!empty($this->ref)) {
2187
			$label .= '<br><b>'.$langs->trans('Ref').':</b> '.$this->ref;
2188
		}
2189
		if (!empty($this->firstname) || !empty($this->lastname)) {
2190
			$label .= '<br><b>'.$langs->trans('Name').':</b> '.$this->getFullName($langs);
2191
		}
2192
		if (!empty($this->company)) {
2193
			$label .= '<br><b>'.$langs->trans('Company').':</b> '.$this->company;
2194
		}
2195
		$label .= '</div>';
2196
2197
		$url = DOL_URL_ROOT.'/adherents/card.php?rowid='.((int) $this->id);
2198
		if ($option == 'subscription') {
2199
			$url = DOL_URL_ROOT.'/adherents/subscription.php?rowid='.((int) $this->id);
2200
		}
2201
2202
		if ($option != 'nolink') {
2203
			// Add param to save lastsearch_values or not
2204
			$add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0);
2205
			if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) {
2206
				$add_save_lastsearch_values = 1;
2207
			}
2208
			if ($add_save_lastsearch_values) {
2209
				$url .= '&save_lastsearch_values=1';
2210
			}
2211
		}
2212
2213
		$linkstart .= '<a href="'.$url.'"';
2214
		$linkclose = "";
2215
		if (empty($notooltip)) {
2216
			if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2217
				$langs->load("users");
2218
				$label = $langs->trans("ShowUser");
2219
				$linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"';
2220
			}
2221
			$linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"';
2222
			$linkclose .= ' class="classfortooltip'.($morecss ? ' '.$morecss : '').'"';
2223
		}
2224
2225
		$linkstart .= $linkclose.'>';
2226
		$linkend = '</a>';
2227
2228
		$result .= $linkstart;
2229
		if ($withpictoimg) {
2230
			$result .= '<div class="inline-block nopadding valignmiddle">';
2231
		}
2232
		if ($withpictoimg) {
2233
			$paddafterimage = '';
2234
			if (abs($withpictoimg) == 1) {
2235
				$paddafterimage = 'style="margin-right: 3px;"';
2236
			}
2237
			// Only picto
2238
			if ($withpictoimg > 0) {
2239
				$picto = '<span class="nopadding'.($morecss ? ' userimg'.$morecss : '').'">'.
2240
					img_object('', 'user', $paddafterimage.' '.($notooltip ? '' : 'class="classfortooltip"'), 0, 0, $notooltip ? 0 : 1).'</span>';
2241
			} else {
2242
				// Picto must be a photo
2243
				$picto = '<span class="nopadding'.($morecss ? ' userimg'.$morecss : '').'"'.($paddafterimage ? ' '.$paddafterimage : '').'>';
2244
				$picto .= Form::showphoto('memberphoto', $this, 0, 0, 0, 'userphoto'.($withpictoimg == -3 ? 'small' : ''), 'mini', 0, 1);
2245
				$picto .= '</span>';
2246
			}
2247
			$result .= $picto;
2248
		}
2249
		if ($withpictoimg > -2 && $withpictoimg != 2) {
2250
			if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2251
				$result .= '<span class="nopadding valignmiddle'.((!isset($this->statut) || $this->statut) ? '' : ' strikefordisabled').
2252
				($morecss ? ' usertext'.$morecss : '').'">';
2253
			}
2254
			if ($mode == 'login') {
2255
				$result .= dol_trunc($this->login, $maxlen);
2256
			} elseif ($mode == 'ref') {
2257
				$result .= $this->ref;
2258
			} else {
2259
				$result .= $this->getFullName($langs, '', ($mode == 'firstname' ? 2 : ($mode == 'lastname' ? 4 : -1)), $maxlen);
2260
			}
2261
			if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) {
2262
				$result .= '</span>';
2263
			}
2264
		}
2265
		if ($withpictoimg) {
2266
			$result .= '</div>';
2267
		}
2268
		$result .= $linkend;
2269
2270
		if ($addlinktonotes) {
2271
			if ($this->note_private) {
2272
				$notetoshow = $langs->trans("ViewPrivateNote").':<br>'.dol_string_nohtmltag($this->note_private, 1);
2273
				$result .= ' <span class="note inline-block">';
2274
				$result .= '<a href="'.DOL_URL_ROOT.'/adherents/note.php?id='.$this->id.'" class="classfortooltip" title="'.dol_escape_htmltag($notetoshow).'">';
2275
				$result .= img_picto('', 'note');
2276
				$result .= '</a>';
2277
				$result .= '</span>';
2278
			}
2279
		}
2280
2281
		return $result;
2282
	}
2283
2284
	/**
2285
	 *  Retourne le libelle du statut d'un adherent (brouillon, valide, resilie, exclu)
2286
	 *
2287
	 *  @param	int		$mode       0=libelle long, 1=libelle court, 2=Picto + Libelle court, 3=Picto, 4=Picto + Libelle long, 5=Libelle court + Picto
2288
	 *  @return string				Label
2289
	 */
2290
	public function getLibStatut($mode = 0)
2291
	{
2292
		return $this->LibStatut($this->statut, $this->need_subscription, $this->datefin, $mode);
2293
	}
2294
2295
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2296
	/**
2297
	 *  Renvoi le libelle d'un statut donne
2298
	 *
2299
	 *  @param	int			$status      			Id status
2300
	 *	@param	int			$need_subscription		1 if member type need subscription, 0 otherwise
2301
	 *	@param	int     	$date_end_subscription	Date fin adhesion
2302
	 *  @param  int		    $mode                   0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
2303
	 *  @return string      						Label
2304
	 */
2305
	public function LibStatut($status, $need_subscription, $date_end_subscription, $mode = 0)
2306
	{
2307
		// phpcs:enable
2308
		global $langs;
2309
		$langs->load("members");
2310
2311
		$statusType = '';
2312
		$labelStatus = '';
2313
		$labelStatusShort = '';
2314
2315
		if ($status == self::STATUS_DRAFT) {
2316
			$statusType = 'status0';
2317
			$labelStatus = $langs->trans("MemberStatusDraft");
2318
			$labelStatusShort = $langs->trans("MemberStatusDraftShort");
2319
		} elseif ($status >= self::STATUS_VALIDATED) {
2320
			if ($need_subscription == 0) {
2321
				$statusType = 'status4';
2322
				$labelStatus = $langs->trans("MemberStatusNoSubscription");
2323
				$labelStatusShort = $langs->trans("MemberStatusNoSubscriptionShort");
2324
			} elseif (!$date_end_subscription) {
2325
				$statusType = 'status1';
2326
				$labelStatus = $langs->trans("MemberStatusActive");
2327
				$labelStatusShort = $langs->trans("MemberStatusActiveShort");
2328
			} elseif ($date_end_subscription < dol_now()) {
2329
				$statusType = 'status3';
2330
				$labelStatus = $langs->trans("MemberStatusActiveLate");
2331
				$labelStatusShort = $langs->trans("MemberStatusActiveLateShort");
2332
			} else {
2333
				$statusType = 'status4';
2334
				$labelStatus = $langs->trans("MemberStatusPaid");
2335
				$labelStatusShort = $langs->trans("MemberStatusPaidShort");
2336
			}
2337
		} elseif ($status == self::STATUS_RESILIATED) {
2338
			$statusType = 'status6';
2339
			$labelStatus = $langs->trans("MemberStatusResiliated");
2340
			$labelStatusShort = $langs->trans("MemberStatusResiliatedShort");
2341
		} elseif ($status == self::STATUS_EXCLUDED) {
2342
			$statusType = 'status10';
2343
			$labelStatus = $langs->trans("MemberStatusExcluded");
2344
			$labelStatusShort = $langs->trans("MemberStatusExcludedShort");
2345
		}
2346
2347
		return dolGetStatus($labelStatus, $labelStatusShort, '', $statusType, $mode);
2348
	}
2349
2350
2351
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2352
	/**
2353
	 *      Charge indicateurs this->nb de tableau de bord
2354
	 *
2355
	 *      @return     int         <0 if KO, >0 if OK
2356
	 */
2357
	public function load_state_board()
2358
	{
2359
		// phpcs:enable
2360
		global $conf;
2361
2362
		$this->nb = array();
2363
2364
		$sql = "SELECT count(a.rowid) as nb";
2365
		$sql .= " FROM ".MAIN_DB_PREFIX."adherent as a";
2366
		$sql .= " WHERE a.statut > 0";
2367
		$sql .= " AND a.entity IN (".getEntity('adherent').")";
2368
2369
		$resql = $this->db->query($sql);
2370
		if ($resql) {
2371
			while ($obj = $this->db->fetch_object($resql)) {
2372
				$this->nb["members"] = $obj->nb;
2373
			}
2374
			$this->db->free($resql);
2375
			return 1;
2376
		} else {
2377
			dol_print_error($this->db);
2378
			$this->error = $this->db->error();
2379
			return -1;
2380
		}
2381
	}
2382
2383
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2384
	/**
2385
	 *      Load indicators for dashboard (this->nbtodo and this->nbtodolate)
2386
	 *
2387
	 *      @param	User	$user   		Objet user
2388
	 *      @param  string	$mode           "expired" for membership to renew, "shift" for member to validate
2389
	 *      @return WorkboardResponse|int 	<0 if KO, WorkboardResponse if OK
2390
	 */
2391
	public function load_board($user, $mode)
2392
	{
2393
		// phpcs:enable
2394
		global $conf, $langs;
2395
2396
		if ($user->socid) {
2397
			return -1; // protection pour eviter appel par utilisateur externe
2398
		}
2399
2400
		$now = dol_now();
2401
2402
		$sql = "SELECT a.rowid, a.datefin, a.statut";
2403
		$sql .= " FROM ".MAIN_DB_PREFIX."adherent as a";
2404
		$sql .= ", ".MAIN_DB_PREFIX."adherent_type as t";
2405
		$sql .= " WHERE a.fk_adherent_type = t.rowid";
2406
		if ($mode == 'expired') {
2407
			$sql .= " AND a.statut = ".self::STATUS_VALIDATED;
2408
			$sql .= " AND a.entity IN (".getEntity('adherent').")";
2409
			$sql .= " AND ((a.datefin IS NULL or a.datefin < '".$this->db->idate($now)."') AND t.subscription = '1')";
2410
		} elseif ($mode == 'shift') {
2411
			$sql .= " AND a.statut = ".self::STATUS_DRAFT;
2412
			$sql .= " AND a.entity IN (".getEntity('adherent').")";
2413
		}
2414
2415
		$resql = $this->db->query($sql);
2416
		if ($resql) {
2417
			$langs->load("members");
2418
2419
			$warning_delay = 0;
2420
			$url = '';
2421
			$label = '';
2422
			$labelShort = '';
2423
2424
			if ($mode == 'expired') {
2425
				$warning_delay = $conf->adherent->subscription->warning_delay / 60 / 60 / 24;
2426
				$label = $langs->trans("MembersWithSubscriptionToReceive");
2427
				$labelShort = $langs->trans("MembersWithSubscriptionToReceiveShort");
2428
				$url = DOL_URL_ROOT.'/adherents/list.php?mainmenu=members&amp;statut='.self::STATUS_VALIDATED.'&amp;filter=outofdate';
2429
			} elseif ($mode == 'shift') {
2430
				$warning_delay = $conf->adherent->subscription->warning_delay / 60 / 60 / 24;
2431
				$url = DOL_URL_ROOT.'/adherents/list.php?mainmenu=members&amp;statut='.self::STATUS_DRAFT;
2432
				$label = $langs->trans("MembersListToValid");
2433
				$labelShort = $langs->trans("ToValidate");
2434
			}
2435
2436
			$response = new WorkboardResponse();
2437
			$response->warning_delay = $warning_delay;
2438
			$response->label = $label;
2439
			$response->labelShort = $labelShort;
2440
			$response->url = $url;
2441
			$response->img = img_object('', "user");
2442
2443
			$adherentstatic = new Adherent($this->db);
2444
2445
			while ($obj = $this->db->fetch_object($resql)) {
2446
				$response->nbtodo++;
2447
2448
				$adherentstatic->datefin = $this->db->jdate($obj->datefin);
2449
				$adherentstatic->statut = $obj->statut;
2450
2451
				if ($adherentstatic->hasDelay()) {
2452
					$response->nbtodolate++;
2453
				}
2454
			}
2455
2456
			return $response;
2457
		} else {
2458
			dol_print_error($this->db);
2459
			$this->error = $this->db->error();
2460
			return -1;
2461
		}
2462
	}
2463
2464
2465
	/**
2466
	 *  Create a document onto disk according to template module.
2467
	 *
2468
	 *  @param	    string		$modele			Force template to use ('' to not force)
2469
	 *  @param		Translate	$outputlangs	objet lang a utiliser pour traduction
2470
	 *  @param      int			$hidedetails    Hide details of lines
2471
	 *  @param      int			$hidedesc       Hide description
2472
	 *  @param      int			$hideref        Hide ref
2473
	 *  @param   null|array  $moreparams     Array to provide more information
2474
	 *  @return     int         				0 if KO, 1 if OK
2475
	 */
2476
	public function generateDocument($modele, $outputlangs, $hidedetails = 0, $hidedesc = 0, $hideref = 0, $moreparams = null)
2477
	{
2478
		global $conf, $langs;
2479
2480
		$langs->load("orders");
2481
2482
		if (!dol_strlen($modele)) {
2483
			$modele = 'standard';
2484
2485
			if ($this->model_pdf) {
2486
				$modele = $this->model_pdf;
2487
			} elseif (!empty($conf->global->ADHERENT_ADDON_PDF)) {
2488
				$modele = $conf->global->ADHERENT_ADDON_PDF;
2489
			}
2490
		}
2491
2492
		$modelpath = "core/modules/member/doc/";
2493
2494
		return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);
2495
	}
2496
2497
2498
	/**
2499
	 *  Initialise an instance with random values.
2500
	 *  Used to build previews or test instances.
2501
	 *	id must be 0 if object instance is a specimen.
2502
	 *
2503
	 *  @return	int
2504
	 */
2505
	public function initAsSpecimen()
2506
	{
2507
		global $user, $langs;
2508
		$now = dol_now();
2509
2510
		// Initialise parametres
2511
		$this->id = 0;
2512
		$this->ref = 'ABC001';
2513
		$this->entity = 1;
2514
		$this->specimen = 1;
2515
		$this->civility_id = 0;
2516
		$this->lastname = 'DOLIBARR';
2517
		$this->firstname = 'SPECIMEN';
2518
		$this->gender = 'man';
2519
		$this->login = 'dolibspec';
2520
		$this->pass = 'dolibspec';
2521
		$this->company = 'Societe ABC';
2522
		$this->address = '61 jump street';
2523
		$this->zip = '75000';
2524
		$this->town = 'Paris';
2525
		$this->country_id = 1;
2526
		$this->country_code = 'FR';
2527
		$this->country = 'France';
2528
		$this->morphy = 'mor';
2529
		$this->email = '[email protected]';
2530
		$this->socialnetworks = array(
2531
			'skype' => 'skypepseudo',
2532
			'twitter' => 'twitterpseudo',
2533
			'facebook' => 'facebookpseudo',
2534
			'linkedin' => 'linkedinpseudo',
2535
		);
2536
		$this->phone = '0999999999';
2537
		$this->phone_perso = '0999999998';
2538
		$this->phone_mobile = '0999999997';
2539
		$this->note_public = 'This is a public note';
2540
		$this->note_private = 'This is a private note';
2541
		$this->birth = $now;
2542
		$this->photo = '';
2543
		$this->public = 1;
2544
		$this->statut = self::STATUS_DRAFT;
2545
2546
		$this->datefin = $now;
2547
		$this->datevalid = $now;
2548
2549
		$this->typeid = 1; // Id type adherent
2550
		$this->type = 'Type adherent'; // Libelle type adherent
2551
		$this->need_subscription = 0;
2552
2553
		$this->first_subscription_date = $now;
2554
		$this->first_subscription_date_start = $this->first_subscription_date;
2555
		$this->first_subscription_date_end = dol_time_plus_duree($this->first_subscription_date_start, 1, 'y');
2556
		$this->first_subscription_amount = 10;
2557
2558
		$this->last_subscription_date = $this->first_subscription_date;
2559
		$this->last_subscription_date_start = $this->first_subscription_date;
2560
		$this->last_subscription_date_end = dol_time_plus_duree($this->last_subscription_date_start, 1, 'y');
2561
		$this->last_subscription_amount = 10;
2562
		return 1;
2563
	}
2564
2565
2566
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2567
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
2568
	/**
2569
	 *	Retourne chaine DN complete dans l'annuaire LDAP pour l'objet
2570
	 *
2571
	 *	@param	array	$info		Info array loaded by _load_ldap_info
2572
	 *	@param	int		$mode		0=Return full DN (uid=qqq,ou=xxx,dc=aaa,dc=bbb)
2573
	 *								1=Return DN without key inside (ou=xxx,dc=aaa,dc=bbb)
2574
	 *								2=Return key only (uid=qqq)
2575
	 *	@return	string				DN
2576
	 */
2577
	public function _load_ldap_dn($info, $mode = 0)
2578
	{
2579
		// phpcs:enable
2580
		global $conf;
2581
		$dn = '';
2582
		if ($mode == 0) {
2583
			$dn = $conf->global->LDAP_KEY_MEMBERS."=".$info[$conf->global->LDAP_KEY_MEMBERS].",".$conf->global->LDAP_MEMBER_DN;
2584
		}
2585
		if ($mode == 1) {
2586
			$dn = $conf->global->LDAP_MEMBER_DN;
2587
		}
2588
		if ($mode == 2) {
2589
			$dn = $conf->global->LDAP_KEY_MEMBERS."=".$info[$conf->global->LDAP_KEY_MEMBERS];
2590
		}
2591
		return $dn;
2592
	}
2593
2594
2595
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2596
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
2597
	/**
2598
	 *	Initialise tableau info (tableau des attributs LDAP)
2599
	 *
2600
	 *	@return		array		Tableau info des attributs
2601
	 */
2602
	public function _load_ldap_info()
2603
	{
2604
		// phpcs:enable
2605
		global $conf, $langs;
2606
2607
		$info = array();
2608
		$socialnetworks = getArrayOfSocialNetworks();
2609
		$keymodified = false;
2610
2611
		// Object classes
2612
		$info["objectclass"] = explode(',', $conf->global->LDAP_MEMBER_OBJECT_CLASS);
2613
2614
		$this->fullname = $this->getFullName($langs);
2615
2616
		// For avoid ldap error when firstname and lastname are empty
2617
		if ($this->morphy == 'mor' && (empty($this->fullname) || $this->fullname == $this->company)) {
2618
			$this->fullname = $this->company;
2619
			$this->lastname = $this->company;
2620
		}
2621
2622
		// Possible LDAP KEY (constname => varname)
2623
		$ldapkey = array(
2624
			'LDAP_MEMBER_FIELD_FULLNAME' => 'fullname',
2625
			'LDAP_MEMBER_FIELD_NAME' => 'lastname',
2626
			'LDAP_MEMBER_FIELD_LOGIN' => 'login',
2627
			'LDAP_MEMBER_FIELD_LOGIN_SAMBA' => 'login',
2628
			'LDAP_MEMBER_FIELD_MAIL' => 'email'
2629
		);
2630
2631
		// Member
2632
		foreach ($ldapkey as $constname => $varname) {
2633
			if (!empty($this->$varname) && !empty($conf->global->$constname)) {
2634
				$info[$conf->global->$constname] = $this->$varname;
2635
2636
				// Check if it is the LDAP key and if its value has been changed
2637
				if (!empty($conf->global->LDAP_KEY_MEMBERS) && $conf->global->LDAP_KEY_MEMBERS == $conf->global->$constname) {
2638
					if (!empty($this->oldcopy) && $this->$varname != $this->oldcopy->$varname) {
2639
						$keymodified = true; // For check if LDAP key has been modified
2640
					}
2641
				}
2642
			}
2643
		}
2644
		if ($this->firstname && !empty($conf->global->LDAP_MEMBER_FIELD_FIRSTNAME)) {
2645
			$info[$conf->global->LDAP_MEMBER_FIELD_FIRSTNAME] = $this->firstname;
2646
		}
2647
		if ($this->poste && !empty($conf->global->LDAP_MEMBER_FIELD_TITLE)) {
2648
			$info[$conf->global->LDAP_MEMBER_FIELD_TITLE] = $this->poste;
2649
		}
2650
		if ($this->company && !empty($conf->global->LDAP_MEMBER_FIELD_COMPANY)) {
2651
			$info[$conf->global->LDAP_MEMBER_FIELD_COMPANY] = $this->company;
2652
		}
2653
		if ($this->address && !empty($conf->global->LDAP_MEMBER_FIELD_ADDRESS)) {
2654
			$info[$conf->global->LDAP_MEMBER_FIELD_ADDRESS] = $this->address;
2655
		}
2656
		if ($this->zip && !empty($conf->global->LDAP_MEMBER_FIELD_ZIP)) {
2657
			$info[$conf->global->LDAP_MEMBER_FIELD_ZIP] = $this->zip;
2658
		}
2659
		if ($this->town && !empty($conf->global->LDAP_MEMBER_FIELD_TOWN)) {
2660
			$info[$conf->global->LDAP_MEMBER_FIELD_TOWN] = $this->town;
2661
		}
2662
		if ($this->country_code && !empty($conf->global->LDAP_MEMBER_FIELD_COUNTRY)) {
2663
			$info[$conf->global->LDAP_MEMBER_FIELD_COUNTRY] = $this->country_code;
2664
		}
2665
		foreach ($socialnetworks as $key => $value) {
2666
			if ($this->socialnetworks[$value['label']] && !empty($conf->global->{'LDAP_MEMBER_FIELD_'.strtoupper($value['label'])})) {
2667
				$info[$conf->global->{'LDAP_MEMBER_FIELD_'.strtoupper($value['label'])}] = $this->socialnetworks[$value['label']];
2668
			}
2669
		}
2670
		if ($this->phone && !empty($conf->global->LDAP_MEMBER_FIELD_PHONE)) {
2671
			$info[$conf->global->LDAP_MEMBER_FIELD_PHONE] = $this->phone;
2672
		}
2673
		if ($this->phone_perso && !empty($conf->global->LDAP_MEMBER_FIELD_PHONE_PERSO)) {
2674
			$info[$conf->global->LDAP_MEMBER_FIELD_PHONE_PERSO] = $this->phone_perso;
2675
		}
2676
		if ($this->phone_mobile && !empty($conf->global->LDAP_MEMBER_FIELD_MOBILE)) {
2677
			$info[$conf->global->LDAP_MEMBER_FIELD_MOBILE] = $this->phone_mobile;
2678
		}
2679
		if ($this->fax && !empty($conf->global->LDAP_MEMBER_FIELD_FAX)) {
2680
			$info[$conf->global->LDAP_MEMBER_FIELD_FAX] = $this->fax;
2681
		}
2682
		if ($this->note_private && !empty($conf->global->LDAP_MEMBER_FIELD_DESCRIPTION)) {
2683
			$info[$conf->global->LDAP_MEMBER_FIELD_DESCRIPTION] = dol_string_nohtmltag($this->note_private, 2);
2684
		}
2685
		if ($this->note_public && !empty($conf->global->LDAP_MEMBER_FIELD_NOTE_PUBLIC)) {
2686
			$info[$conf->global->LDAP_MEMBER_FIELD_NOTE_PUBLIC] = dol_string_nohtmltag($this->note_public, 2);
2687
		}
2688
		if ($this->birth && !empty($conf->global->LDAP_MEMBER_FIELD_BIRTHDATE)) {
2689
			$info[$conf->global->LDAP_MEMBER_FIELD_BIRTHDATE] = dol_print_date($this->birth, 'dayhourldap');
2690
		}
2691
		if (isset($this->statut) && !empty($conf->global->LDAP_FIELD_MEMBER_STATUS)) {
2692
			$info[$conf->global->LDAP_FIELD_MEMBER_STATUS] = $this->statut;
2693
		}
2694
		if ($this->datefin && !empty($conf->global->LDAP_FIELD_MEMBER_END_LASTSUBSCRIPTION)) {
2695
			$info[$conf->global->LDAP_FIELD_MEMBER_END_LASTSUBSCRIPTION] = dol_print_date($this->datefin, 'dayhourldap');
2696
		}
2697
2698
		// When password is modified
2699
		if (!empty($this->pass)) {
2700
			if (!empty($conf->global->LDAP_MEMBER_FIELD_PASSWORD)) {
2701
				$info[$conf->global->LDAP_MEMBER_FIELD_PASSWORD] = $this->pass; // this->pass = mot de passe non crypte
2702
			}
2703
			if (!empty($conf->global->LDAP_MEMBER_FIELD_PASSWORD_CRYPTED)) {
2704
				$info[$conf->global->LDAP_MEMBER_FIELD_PASSWORD_CRYPTED] = dol_hash($this->pass, 4); // Create OpenLDAP MD5 password (TODO add type of encryption)
2705
			}
2706
		} elseif ($conf->global->LDAP_SERVER_PROTOCOLVERSION !== '3') {
2707
			// Set LDAP password if possible
2708
			// If ldap key is modified and LDAPv3 we use ldap_rename function for avoid lose encrypt password
2709
			if (!empty($conf->global->DATABASE_PWD_ENCRYPTED)) {
2710
				// Just for the default MD5 !
2711
				if (empty($conf->global->MAIN_SECURITY_HASH_ALGO)) {
2712
					if ($this->pass_indatabase_crypted && !empty($conf->global->LDAP_MEMBER_FIELD_PASSWORD_CRYPTED)) {
2713
						// Create OpenLDAP MD5 password from Dolibarr MD5 password
2714
						// Note: This suppose that "pass_indatabase_crypted" is a md5 (guaranted by the previous test if "(empty($conf->global->MAIN_SECURITY_HASH_ALGO))"
2715
						$info[$conf->global->LDAP_MEMBER_FIELD_PASSWORD_CRYPTED] = '{md5}'.base64_encode(hex2bin($this->pass_indatabase_crypted));
2716
					}
2717
				}
2718
			} elseif (!empty($this->pass_indatabase)) {
2719
				// Use $this->pass_indatabase value if exists
2720
				if (!empty($conf->global->LDAP_MEMBER_FIELD_PASSWORD)) {
2721
					$info[$conf->global->LDAP_MEMBER_FIELD_PASSWORD] = $this->pass_indatabase; // $this->pass_indatabase = mot de passe non crypte
2722
				}
2723
				if (!empty($conf->global->LDAP_MEMBER_FIELD_PASSWORD_CRYPTED)) {
2724
					$info[$conf->global->LDAP_MEMBER_FIELD_PASSWORD_CRYPTED] = dol_hash($this->pass_indatabase, 4); // md5 for OpenLdap TODO add type of encryption
2725
				}
2726
			}
2727
		}
2728
2729
		// Subscriptions
2730
		if ($this->first_subscription_date && !empty($conf->global->LDAP_FIELD_MEMBER_FIRSTSUBSCRIPTION_DATE)) {
2731
			$info[$conf->global->LDAP_FIELD_MEMBER_FIRSTSUBSCRIPTION_DATE] = dol_print_date($this->first_subscription_date, 'dayhourldap');
2732
		}
2733
		if (isset($this->first_subscription_amount) && !empty($conf->global->LDAP_FIELD_MEMBER_FIRSTSUBSCRIPTION_AMOUNT)) {
2734
			$info[$conf->global->LDAP_FIELD_MEMBER_FIRSTSUBSCRIPTION_AMOUNT] = $this->first_subscription_amount;
2735
		}
2736
		if ($this->last_subscription_date && !empty($conf->global->LDAP_FIELD_MEMBER_LASTSUBSCRIPTION_DATE)) {
2737
			$info[$conf->global->LDAP_FIELD_MEMBER_LASTSUBSCRIPTION_DATE] = dol_print_date($this->last_subscription_date, 'dayhourldap');
2738
		}
2739
		if (isset($this->last_subscription_amount) && !empty($conf->global->LDAP_FIELD_MEMBER_LASTSUBSCRIPTION_AMOUNT)) {
2740
			$info[$conf->global->LDAP_FIELD_MEMBER_LASTSUBSCRIPTION_AMOUNT] = $this->last_subscription_amount;
2741
		}
2742
2743
		return $info;
2744
	}
2745
2746
2747
	/**
2748
	 *      Load type info information in the member object
2749
	 *
2750
	 *      @param  int		$id       Id of member to load
2751
	 *      @return	void
2752
	 */
2753
	public function info($id)
2754
	{
2755
		$sql = 'SELECT a.rowid, a.datec as datec,';
2756
		$sql .= ' a.datevalid as datev,';
2757
		$sql .= ' a.tms as datem,';
2758
		$sql .= ' a.fk_user_author, a.fk_user_valid, a.fk_user_mod';
2759
		$sql .= ' FROM '.MAIN_DB_PREFIX.'adherent as a';
2760
		$sql .= ' WHERE a.rowid = '.((int) $id);
2761
2762
		dol_syslog(get_class($this)."::info", LOG_DEBUG);
2763
		$result = $this->db->query($sql);
2764
		if ($result) {
2765
			if ($this->db->num_rows($result)) {
2766
				$obj = $this->db->fetch_object($result);
2767
				$this->id = $obj->rowid;
2768
				if ($obj->fk_user_author) {
2769
					$cuser = new User($this->db);
2770
					$cuser->fetch($obj->fk_user_author);
2771
					$this->user_creation = $cuser;
2772
				}
2773
2774
				if ($obj->fk_user_valid) {
2775
					$vuser = new User($this->db);
2776
					$vuser->fetch($obj->fk_user_valid);
2777
					$this->user_validation = $vuser;
2778
				}
2779
2780
				if ($obj->fk_user_mod) {
2781
					$muser = new User($this->db);
2782
					$muser->fetch($obj->fk_user_mod);
2783
					$this->user_modification = $muser;
2784
				}
2785
2786
				$this->date_creation = $this->db->jdate($obj->datec);
2787
				$this->date_validation = $this->db->jdate($obj->datev);
2788
				$this->date_modification = $this->db->jdate($obj->datem);
2789
			}
2790
2791
			$this->db->free($result);
2792
		} else {
2793
			dol_print_error($this->db);
2794
		}
2795
	}
2796
2797
	/**
2798
	 *  Return number of mass Emailing received by this member with its email
2799
	 *
2800
	 *  @return       int     Number of EMailings
2801
	 */
2802
	public function getNbOfEMailings()
2803
	{
2804
		$sql = "SELECT count(mc.email) as nb";
2805
		$sql .= " FROM ".MAIN_DB_PREFIX."mailing_cibles as mc";
2806
		$sql .= " WHERE mc.email = '".$this->db->escape($this->email)."'";
2807
		$sql .= " AND mc.statut NOT IN (-1,0)"; // -1 erreur, 0 non envoye, 1 envoye avec succes
2808
2809
		$resql = $this->db->query($sql);
2810
		if ($resql) {
2811
			$obj = $this->db->fetch_object($resql);
2812
			$nb = $obj->nb;
2813
2814
			$this->db->free($resql);
2815
			return $nb;
2816
		} else {
2817
			$this->error = $this->db->error();
2818
			return -1;
2819
		}
2820
	}
2821
2822
	/**
2823
	 * Sets object to supplied categories.
2824
	 *
2825
	 * Deletes object from existing categories not supplied.
2826
	 * Adds it to non existing supplied categories.
2827
	 * Existing categories are left untouch.
2828
	 *
2829
	 * @param int[]|int $categories Category or categories IDs
2830
	 * @return void
2831
	 */
2832
	public function setCategories($categories)
2833
	{
2834
		require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
2835
		return parent::setCategoriesCommon($categories, Categorie::TYPE_MEMBER);
2836
	}
2837
2838
	/**
2839
	 * Function used to replace a thirdparty id with another one.
2840
	 *
2841
	 * @param DoliDB 	$db 			Database handler
2842
	 * @param int 		$origin_id 		Old thirdparty id
2843
	 * @param int 		$dest_id 		New thirdparty id
2844
	 * @return bool
2845
	 */
2846
	public static function replaceThirdparty($db, $origin_id, $dest_id)
2847
	{
2848
		$tables = array('adherent');
2849
2850
		return CommonObject::commonReplaceThirdparty($db, $origin_id, $dest_id, $tables);
2851
	}
2852
2853
	/**
2854
	 * Return if a member is late (subscription late) or not
2855
	 *
2856
	 * @return boolean     True if late, False if not late
2857
	 */
2858
	public function hasDelay()
2859
	{
2860
		global $conf;
2861
2862
		//Only valid members
2863
		if ($this->statut != self::STATUS_VALIDATED) {
2864
			return false;
2865
		}
2866
		if (!$this->datefin) {
2867
			return false;
2868
		}
2869
2870
		$now = dol_now();
2871
2872
		return $this->datefin < ($now - $conf->adherent->subscription->warning_delay);
2873
	}
2874
2875
2876
	/**
2877
	 * Send reminders by emails before subscription end
2878
	 * CAN BE A CRON TASK
2879
	 *
2880
	 * @param	string		$daysbeforeendlist		Nb of days before end of subscription (negative number = after subscription). Can be a list of delay, separated by a semicolon, for example '10;5;0;-5'
2881
	 * @return	int									0 if OK, <>0 if KO (this function is used also by cron so only 0 is OK)
2882
	 */
2883
	public function sendReminderForExpiredSubscription($daysbeforeendlist = '10')
2884
	{
2885
		global $conf, $langs, $mysoc, $user;
2886
2887
		$error = 0;
2888
		$this->output = '';
2889
		$this->error = '';
2890
2891
		$blockingerrormsg = '';
2892
2893
		if (empty($conf->adherent->enabled)) { // Should not happen. If module disabled, cron job should not be visible.
2894
			$langs->load("agenda");
2895
			$this->output = $langs->trans('ModuleNotEnabled', $langs->transnoentitiesnoconv("Adherent"));
2896
			return 0;
2897
		}
2898
		if (empty($conf->global->MEMBER_REMINDER_EMAIL)) {
2899
			$langs->load("agenda");
2900
			$this->output = $langs->trans('EventRemindersByEmailNotEnabled', $langs->transnoentitiesnoconv("Adherent"));
2901
			return 0;
2902
		}
2903
2904
		$now = dol_now();
2905
		$nbok = 0;
2906
		$nbko = 0;
2907
2908
		$listofmembersok = array();
2909
		$listofmembersko = array();
2910
2911
		$arraydaysbeforeend = explode(';', $daysbeforeendlist);
2912
		foreach ($arraydaysbeforeend as $daysbeforeend) { // Loop on each delay
2913
			dol_syslog(__METHOD__.' - Process delta = '.$daysbeforeend, LOG_DEBUG);
2914
2915
			if (!is_numeric($daysbeforeend)) {
2916
				$blockingerrormsg = "Value for delta is not a positive or negative numeric";
2917
				$nbko++;
2918
				break;
2919
			}
2920
2921
			$tmp = dol_getdate($now);
2922
			$datetosearchfor = dol_time_plus_duree(dol_mktime(0, 0, 0, $tmp['mon'], $tmp['mday'], $tmp['year']), $daysbeforeend, 'd');
2923
2924
			$sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'adherent';
2925
			$sql .= " WHERE entity = ".$conf->entity; // Do not use getEntity('adherent').")" here, we want the batch to be on its entity only;
2926
			$sql .= " AND datefin = '".$this->db->idate($datetosearchfor)."'";
2927
2928
			$resql = $this->db->query($sql);
2929
			if ($resql) {
2930
				$num_rows = $this->db->num_rows($resql);
2931
2932
				include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
2933
				$adherent = new Adherent($this->db);
2934
				$formmail = new FormMail($this->db);
2935
2936
				$i = 0;
2937
				while ($i < $num_rows) {
2938
					$obj = $this->db->fetch_object($resql);
2939
2940
					$adherent->fetch($obj->rowid, '', '', '', true, true);
2941
2942
					if (empty($adherent->email)) {
2943
						$nbko++;
2944
						$listofmembersko[$adherent->id] = $adherent->id;
2945
					} else {
2946
						$adherent->fetch_thirdparty();
2947
2948
						// Language code to use ($languagecodeformember) is default language of thirdparty, if no thirdparty, the language found from country of member then country of thirdparty, and if still not found we use the language of company.
2949
						$languagefromcountrycode = getLanguageCodeFromCountryCode($adherent->country_code ? $adherent->country_code : $adherent->thirdparty->country_code);
2950
						$languagecodeformember = (empty($adherent->thirdparty->default_lang) ? ($languagefromcountrycode ? $languagefromcountrycode : $mysoc->default_lang) : $adherent->thirdparty->default_lang);
2951
2952
						// Send reminder email
2953
						$outputlangs = new Translate('', $conf);
2954
						$outputlangs->setDefaultLang($languagecodeformember);
2955
						$outputlangs->loadLangs(array("main", "members"));
2956
						dol_syslog("sendReminderForExpiredSubscription Language for member id ".$adherent->id." set to ".$outputlangs->defaultlang." mysoc->default_lang=".$mysoc->default_lang);
2957
2958
						$arraydefaultmessage = null;
2959
						$labeltouse = $conf->global->ADHERENT_EMAIL_TEMPLATE_REMIND_EXPIRATION;
2960
2961
						if (!empty($labeltouse)) {
2962
							$arraydefaultmessage = $formmail->getEMailTemplate($this->db, 'member', $user, $outputlangs, 0, 1, $labeltouse);
2963
						}
2964
2965
						if (!empty($labeltouse) && is_object($arraydefaultmessage) && $arraydefaultmessage->id > 0) {
2966
							$substitutionarray = getCommonSubstitutionArray($outputlangs, 0, null, $adherent);
2967
							//if (is_array($adherent->thirdparty)) $substitutionarraycomp = ...
2968
							complete_substitutions_array($substitutionarray, $outputlangs, $adherent);
2969
2970
							$subject = make_substitutions($arraydefaultmessage->topic, $substitutionarray, $outputlangs);
2971
							$msg = make_substitutions($arraydefaultmessage->content, $substitutionarray, $outputlangs);
2972
							$from = $conf->global->ADHERENT_MAIL_FROM;
2973
							$to = $adherent->email;
2974
2975
							$trackid = 'mem'.$adherent->id;
2976
							$moreinheader = 'X-Dolibarr-Info: sendReminderForExpiredSubscription'."\r\n";
2977
2978
							include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php';
2979
							$cmail = new CMailFile($subject, $to, $from, $msg, array(), array(), array(), '', '', 0, 1, '', '', $trackid, $moreinheader);
2980
							$result = $cmail->sendfile();
2981
							if (!$result) {
2982
								$error++;
2983
								$this->error = $cmail->error;
2984
								if (!is_null($cmail->errors)) {
2985
									$this->errors += $cmail->errors;
2986
								}
2987
								$nbko++;
2988
								$listofmembersko[$adherent->id] = $adherent->id;
2989
							} else {
2990
								$nbok++;
2991
								$listofmembersok[$adherent->id] = $adherent->id;
2992
2993
								$message = $msg;
2994
								$sendto = $to;
2995
								$sendtocc = '';
2996
								$sendtobcc = '';
2997
								$actioncode = 'EMAIL';
2998
								$extraparams = '';
2999
3000
								$actionmsg = '';
3001
								$actionmsg2 = $langs->transnoentities('MailSentBy').' '.CMailFile::getValidAddress($from, 4, 0, 1).' '.$langs->transnoentities('To').' '.
3002
									CMailFile::getValidAddress($sendto, 4, 0, 1);
3003
								if ($message) {
3004
									$actionmsg = $langs->transnoentities('MailFrom').': '.dol_escape_htmltag($from);
3005
									$actionmsg = dol_concatdesc($actionmsg, $langs->transnoentities('MailTo').': '.dol_escape_htmltag($sendto));
3006
									if ($sendtocc) {
3007
										$actionmsg = dol_concatdesc($actionmsg, $langs->transnoentities('Bcc').": ".dol_escape_htmltag($sendtocc));
3008
									}
3009
									$actionmsg = dol_concatdesc($actionmsg, $langs->transnoentities('MailTopic').": ".$subject);
3010
									$actionmsg = dol_concatdesc($actionmsg, $langs->transnoentities('TextUsedInTheMessageBody').":");
3011
									$actionmsg = dol_concatdesc($actionmsg, $message);
3012
								}
3013
3014
								require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
3015
3016
								// Insert record of emails sent
3017
								$actioncomm = new ActionComm($this->db);
3018
3019
								$actioncomm->type_code = 'AC_OTH_AUTO'; // Type of event ('AC_OTH', 'AC_OTH_AUTO', 'AC_XXX'...)
3020
								$actioncomm->code = 'AC_'.$actioncode;
3021
								$actioncomm->label = $actionmsg2;
3022
								$actioncomm->note_private = $actionmsg;
3023
								$actioncomm->fk_project = 0;
3024
								$actioncomm->datep = $now;
3025
								$actioncomm->datef = $now;
3026
								$actioncomm->percentage = -1; // Not applicable
3027
								$actioncomm->socid = $adherent->thirdparty->id;
3028
								$actioncomm->contact_id = 0;
3029
								$actioncomm->authorid = $user->id; // User saving action
3030
								$actioncomm->userownerid = $user->id; // Owner of action
3031
								// Fields when action is en email (content should be added into note)
3032
								$actioncomm->email_msgid = $cmail->msgid;
3033
								$actioncomm->email_from = $from;
3034
								$actioncomm->email_sender = '';
3035
								$actioncomm->email_to = $to;
3036
								$actioncomm->email_tocc = $sendtocc;
3037
								$actioncomm->email_tobcc = $sendtobcc;
3038
								$actioncomm->email_subject = $subject;
3039
								$actioncomm->errors_to = '';
3040
3041
								$actioncomm->fk_element = $adherent->id;
3042
								$actioncomm->elementtype = $adherent->element;
3043
3044
								$actioncomm->extraparams = $extraparams;
3045
3046
								$actioncomm->create($user);
3047
							}
3048
						} else {
3049
							$blockingerrormsg = "Can't find email template, defined into member module setup, to use for reminding";
3050
3051
							$nbko++;
3052
							$listofmembersko[$adherent->id] = $adherent->id;
3053
3054
							break;
3055
						}
3056
					}
3057
3058
					$i++;
3059
				}
3060
			} else {
3061
				$this->error = $this->db->lasterror();
3062
				return 1;
3063
			}
3064
		}
3065
3066
		if ($blockingerrormsg) {
3067
			$this->error = $blockingerrormsg;
3068
			return 1;
3069
		} else {
3070
			$this->output = 'Found '.($nbok + $nbko).' members to send reminder to.';
3071
			$this->output .= ' Send email successfuly to '.$nbok.' members';
3072
			if (is_array($listofmembersok)) {
3073
				$listofids = '';
3074
				$i = 0;
3075
				foreach ($listofmembersok as $idmember) {
3076
					if ($i > 100) {
3077
						$listofids .= ', ...';
3078
						break;
3079
					}
3080
					if (empty($listofids)) {
3081
						$listofids .= ' [';
3082
					} else {
3083
						$listofids .= ', ';
3084
					}
3085
					$listofids .= $idmember;
3086
					$i++;
3087
				}
3088
				if ($listofids) {
3089
					$listofids .= ']';
3090
				}
3091
				$this->output .= $listofids;
3092
			}
3093
			if ($nbko) {
3094
				$this->output .= ' - Canceled for '.$nbko.' member (no email or email sending error)';
3095
				if (is_array($listofmembersko)) {
3096
					$listofids = '';
3097
					$i = 0;
3098
					foreach ($listofmembersko as $idmember) {
3099
						if ($i > 100) {
3100
							$listofids .= ', ...';
3101
							break;
3102
						}
3103
						if (empty($listofids)) {
3104
							$listofids .= ' [';
3105
						} else {
3106
							$listofids .= ', ';
3107
						}
3108
						$listofids .= $idmember;
3109
						$i++;
3110
					}
3111
					if ($listofids) {
3112
						$listofids .= ']';
3113
					}
3114
					$this->output .= $listofids;
3115
				}
3116
			}
3117
		}
3118
3119
		return 0;
3120
	}
3121
}
3122