Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
fee14197 | 4 | | CiviCRM version 5 | |
6a488035 | 5 | +--------------------------------------------------------------------+ |
6b83d5bd | 6 | | Copyright CiviCRM LLC (c) 2004-2019 | |
6a488035 TO |
7 | +--------------------------------------------------------------------+ |
8 | | This file is a part of CiviCRM. | | |
9 | | | | |
10 | | CiviCRM is free software; you can copy, modify, and distribute it | | |
11 | | under the terms of the GNU Affero General Public License | | |
12 | | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. | | |
13 | | | | |
14 | | CiviCRM is distributed in the hope that it will be useful, but | | |
15 | | WITHOUT ANY WARRANTY; without even the implied warranty of | | |
16 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | | |
17 | | See the GNU Affero General Public License for more details. | | |
18 | | | | |
19 | | You should have received a copy of the GNU Affero General Public | | |
20 | | License and the CiviCRM Licensing Exception along | | |
21 | | with this program; if not, contact CiviCRM LLC | | |
22 | | at info[AT]civicrm[DOT]org. If you have questions about the | | |
23 | | GNU Affero General Public License or the licensing of CiviCRM, | | |
24 | | see the CiviCRM license FAQ at http://civicrm.org/licensing | | |
25 | +--------------------------------------------------------------------+ | |
d25dd0ee | 26 | */ |
6a488035 TO |
27 | |
28 | /** | |
29 | * | |
30 | * @package CRM | |
6b83d5bd | 31 | * @copyright CiviCRM LLC (c) 2004-2019 |
6a488035 TO |
32 | * $Id$ |
33 | * | |
34 | */ | |
35 | class CRM_Member_BAO_MembershipType extends CRM_Member_DAO_MembershipType { | |
36 | ||
37 | /** | |
4c429c82 | 38 | * Static holder for the default Membership Type. |
971e129b | 39 | * @var int |
6a488035 | 40 | */ |
971e129b | 41 | public static $_defaultMembershipType = NULL; |
6a488035 | 42 | |
971e129b | 43 | public static $_membershipTypeInfo = []; |
6a488035 TO |
44 | |
45 | /** | |
4c429c82 | 46 | * Class constructor. |
6a488035 | 47 | */ |
00be9182 | 48 | public function __construct() { |
6a488035 TO |
49 | parent::__construct(); |
50 | } | |
51 | ||
52 | /** | |
4c429c82 | 53 | * Fetch object based on array of properties. |
6a488035 | 54 | * |
b2363ea8 TO |
55 | * @param array $params |
56 | * (reference ) an assoc array of name/value pairs. | |
57 | * @param array $defaults | |
58 | * (reference ) an assoc array to hold the flattened values. | |
6a488035 | 59 | * |
16b10e64 | 60 | * @return CRM_Member_BAO_MembershipType |
6a488035 | 61 | */ |
00be9182 | 62 | public static function retrieve(&$params, &$defaults) { |
6a488035 TO |
63 | $membershipType = new CRM_Member_DAO_MembershipType(); |
64 | $membershipType->copyValues($params); | |
65 | if ($membershipType->find(TRUE)) { | |
66 | CRM_Core_DAO::storeValues($membershipType, $defaults); | |
67 | return $membershipType; | |
68 | } | |
69 | return NULL; | |
70 | } | |
71 | ||
72 | /** | |
4c429c82 | 73 | * Update the is_active flag in the db. |
6a488035 | 74 | * |
b2363ea8 TO |
75 | * @param int $id |
76 | * Id of the database record. | |
77 | * @param bool $is_active | |
78 | * Value we want to set the is_active field. | |
6a488035 | 79 | * |
8a4fede3 | 80 | * @return bool |
81 | * true if we found and updated the object, else false | |
6a488035 | 82 | */ |
00be9182 | 83 | public static function setIsActive($id, $is_active) { |
6a488035 TO |
84 | return CRM_Core_DAO::setFieldValue('CRM_Member_DAO_MembershipType', $id, 'is_active', $is_active); |
85 | } | |
86 | ||
87 | /** | |
4c429c82 | 88 | * Add the membership types. |
6a488035 | 89 | * |
b2363ea8 TO |
90 | * @param array $params |
91 | * Reference array contains the values submitted by the form. | |
92 | * @param array $ids | |
93 | * Array contains the id (deprecated). | |
6a488035 | 94 | * |
000e4e8d MW |
95 | * @return \CRM_Member_DAO_MembershipType |
96 | * @throws \CiviCRM_API3_Exception | |
6a488035 | 97 | */ |
be2fb01f | 98 | public static function add(&$params, $ids = []) { |
000e4e8d MW |
99 | // DEPRECATED Check if membershipType ID was passed in via $ids |
100 | if (empty($params['id'])) { | |
101 | if (isset($ids['membershipType'])) { | |
102 | Civi::log()->warning('Deprecated: Passing membershipType by $ids array in CRM_Member_BAO_MembershipType::add'); | |
103 | } | |
104 | $params['id'] = CRM_Utils_Array::value('membershipType', $ids); | |
105 | } | |
106 | ||
107 | $hook = empty($params['id']) ? 'create' : 'edit'; | |
108 | CRM_Utils_Hook::pre($hook, 'MembershipType', CRM_Utils_Array::value('id', $params), $params); | |
109 | ||
110 | $membershipTypeId = CRM_Utils_Array::value('id', $params); | |
111 | ||
112 | if (!$membershipTypeId) { | |
36e3b794 EM |
113 | if (!isset($params['is_active'])) { |
114 | // do we need this? | |
115 | $params['is_active'] = FALSE; | |
116 | } | |
117 | if (!isset($params['domain_id'])) { | |
118 | $params['domain_id'] = CRM_Core_Config::domainID(); | |
119 | } | |
120 | } | |
6a488035 | 121 | |
301db4f8 | 122 | // $previousID is the old organization id for membership type i.e 'member_of_contact_id'. This is used when an organization is changed. |
6a488035 | 123 | $previousID = NULL; |
000e4e8d MW |
124 | if ($membershipTypeId) { |
125 | $previousID = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $membershipTypeId, 'member_of_contact_id'); | |
6a488035 TO |
126 | } |
127 | ||
000e4e8d MW |
128 | // action is taken depending upon the mode |
129 | $membershipType = new CRM_Member_DAO_MembershipType(); | |
130 | $membershipType->copyValues($params); | |
6a488035 | 131 | $membershipType->save(); |
000e4e8d MW |
132 | |
133 | if ($membershipTypeId) { | |
806e9b71 EM |
134 | // on update we may need to retrieve some details for the price field function - otherwise we get e-notices on attempts to retrieve |
135 | // name etc - the presence of previous id tells us this is an update | |
be2fb01f | 136 | $params = array_merge(civicrm_api3('membership_type', 'getsingle', ['id' => $membershipType->id]), $params); |
806e9b71 | 137 | } |
301db4f8 | 138 | self::createMembershipPriceField($params, $previousID, $membershipType->id); |
6a488035 | 139 | // update all price field value for quick config when membership type is set CRM-11718 |
000e4e8d MW |
140 | if ($membershipTypeId) { |
141 | self::updateAllPriceFieldValue($membershipTypeId, $params); | |
6a488035 | 142 | } |
000e4e8d MW |
143 | |
144 | CRM_Utils_Hook::post($hook, 'MembershipType', $membershipType->id, $membershipType); | |
145 | ||
452b9e04 | 146 | self::flush(); |
6a488035 TO |
147 | return $membershipType; |
148 | } | |
149 | ||
452b9e04 | 150 | /** |
4c429c82 EM |
151 | * Flush anywhere that membership types might be cached. |
152 | * | |
452b9e04 EM |
153 | * @throws \CiviCRM_API3_Exception |
154 | */ | |
c8881afb | 155 | public static function flush() { |
452b9e04 | 156 | CRM_Member_PseudoConstant::membershipType(NULL, TRUE); |
be2fb01f CW |
157 | civicrm_api3('membership', 'getfields', ['cache_clear' => 1, 'fieldname' => 'membership_type_id']); |
158 | civicrm_api3('profile', 'getfields', ['action' => 'submit', 'cache_clear' => 1]); | |
452b9e04 EM |
159 | } |
160 | ||
6a488035 | 161 | /** |
4c429c82 | 162 | * Delete membership Types. |
6a488035 TO |
163 | * |
164 | * @param int $membershipTypeId | |
77b97be7 EM |
165 | * |
166 | * @throws CRM_Core_Exception | |
167 | * @return bool|mixed | |
6a488035 | 168 | */ |
00be9182 | 169 | public static function del($membershipTypeId) { |
4c429c82 | 170 | // Check dependencies. |
353ffa53 | 171 | $check = FALSE; |
be2fb01f CW |
172 | $status = []; |
173 | $dependency = [ | |
6a488035 TO |
174 | 'Membership' => 'membership_type_id', |
175 | 'MembershipBlock' => 'membership_type_default', | |
be2fb01f | 176 | ]; |
6a488035 | 177 | |
edc9b94e | 178 | foreach ($dependency as $name => $field) { |
4d5c2eb5 | 179 | $baoString = 'CRM_Member_BAO_' . $name; |
180 | $dao = new $baoString(); | |
6a488035 | 181 | $dao->$field = $membershipTypeId; |
b204fd50 | 182 | /** @noinspection PhpUndefinedMethodInspection */ |
6a488035 TO |
183 | if ($dao->find(TRUE)) { |
184 | $check = TRUE; | |
185 | $status[] = $name; | |
186 | } | |
187 | } | |
188 | if ($check) { | |
6a488035 TO |
189 | $cnt = 1; |
190 | $message = ts('This membership type cannot be deleted due to following reason(s):'); | |
191 | if (in_array('Membership', $status)) { | |
d6d6bc96 DG |
192 | $findMembersURL = CRM_Utils_System::url('civicrm/member/search', 'reset=1'); |
193 | $deleteURL = CRM_Utils_System::url('civicrm/contact/search/advanced', 'reset=1'); | |
be2fb01f | 194 | $message .= '<br/>' . ts('%3. There are some contacts who have this membership type assigned to them. Search for contacts with this membership type from <a href=\'%1\'>Find Members</a>. If you are still getting this message after deleting these memberships, there may be contacts in the Trash (deleted) with this membership type. Try using <a href="%2">Advanced Search</a> and checking "Search in Trash".', [ |
c5c263ca AH |
195 | 1 => $findMembersURL, |
196 | 2 => $deleteURL, | |
197 | 3 => $cnt, | |
be2fb01f | 198 | ]); |
6a488035 TO |
199 | $cnt++; |
200 | } | |
201 | ||
202 | if (in_array('MembershipBlock', $status)) { | |
203 | $deleteURL = CRM_Utils_System::url('civicrm/admin/contribute', 'reset=1'); | |
be2fb01f | 204 | $message .= ts('%2. This Membership Type is used in an <a href=\'%1\'>Online Contribution page</a>. Uncheck this membership type in the Memberships tab.', [ |
c5c263ca AH |
205 | 1 => $deleteURL, |
206 | 2 => $cnt, | |
be2fb01f | 207 | ]); |
dcc4f6a7 | 208 | throw new CRM_Core_Exception($message); |
6a488035 TO |
209 | } |
210 | } | |
dcc4f6a7 | 211 | CRM_Utils_Weight::delWeight('CRM_Member_DAO_MembershipType', $membershipTypeId); |
6a488035 TO |
212 | //delete from membership Type table |
213 | $membershipType = new CRM_Member_DAO_MembershipType(); | |
214 | $membershipType->id = $membershipTypeId; | |
215 | ||
216 | //fix for membership type delete api | |
217 | $result = FALSE; | |
218 | if ($membershipType->find(TRUE)) { | |
8c33a68c | 219 | return $membershipType->delete(); |
6a488035 TO |
220 | } |
221 | ||
222 | return $result; | |
223 | } | |
224 | ||
225 | /** | |
4c429c82 | 226 | * Convert membership type's 'start day' & 'rollover day' to human readable formats. |
6a488035 | 227 | * |
b2363ea8 TO |
228 | * @param array $membershipType |
229 | * An array of membershipType-details. | |
6a488035 | 230 | */ |
00be9182 | 231 | public static function convertDayFormat(&$membershipType) { |
be2fb01f | 232 | $periodDays = [ |
6a488035 TO |
233 | 'fixed_period_start_day', |
234 | 'fixed_period_rollover_day', | |
be2fb01f | 235 | ]; |
6a488035 TO |
236 | foreach ($membershipType as $id => $details) { |
237 | foreach ($periodDays as $pDay) { | |
a7488080 | 238 | if (!empty($details[$pDay])) { |
6a488035 | 239 | if ($details[$pDay] > 31) { |
353ffa53 TO |
240 | $month = substr($details[$pDay], 0, strlen($details[$pDay]) - 2); |
241 | $day = substr($details[$pDay], -2); | |
be2fb01f | 242 | $monthMap = [ |
6a488035 TO |
243 | '1' => 'Jan', |
244 | '2' => 'Feb', | |
245 | '3' => 'Mar', | |
246 | '4' => 'Apr', | |
247 | '5' => 'May', | |
248 | '6' => 'Jun', | |
249 | '7' => 'Jul', | |
250 | '8' => 'Aug', | |
251 | '9' => 'Sep', | |
252 | '10' => 'Oct', | |
253 | '11' => 'Nov', | |
254 | '12' => 'Dec', | |
be2fb01f | 255 | ]; |
6a488035 TO |
256 | $membershipType[$id][$pDay] = $monthMap[$month] . ' ' . $day; |
257 | } | |
258 | else { | |
259 | $membershipType[$id][$pDay] = $details[$pDay]; | |
260 | } | |
261 | } | |
262 | } | |
263 | } | |
264 | } | |
265 | ||
266 | /** | |
4c429c82 | 267 | * Get membership Types. |
6a488035 | 268 | * |
77b97be7 EM |
269 | * @param bool $public |
270 | * | |
271 | * @return array | |
6a488035 | 272 | */ |
00be9182 | 273 | public static function getMembershipTypes($public = TRUE) { |
be2fb01f | 274 | $membershipTypes = []; |
6a488035 TO |
275 | $membershipType = new CRM_Member_DAO_MembershipType(); |
276 | $membershipType->is_active = 1; | |
277 | if ($public) { | |
278 | $membershipType->visibility = 'Public'; | |
279 | } | |
280 | $membershipType->orderBy(' weight'); | |
281 | $membershipType->find(); | |
282 | while ($membershipType->fetch()) { | |
283 | $membershipTypes[$membershipType->id] = $membershipType->name; | |
284 | } | |
6a488035 TO |
285 | return $membershipTypes; |
286 | } | |
287 | ||
288 | /** | |
4c429c82 | 289 | * Get membership Type Details. |
6a488035 TO |
290 | * |
291 | * @param int $membershipTypeId | |
77b97be7 EM |
292 | * |
293 | * @return array|null | |
6a488035 | 294 | */ |
00be9182 | 295 | public static function getMembershipTypeDetails($membershipTypeId) { |
be2fb01f | 296 | $membershipTypeDetails = []; |
6a488035 TO |
297 | |
298 | $membershipType = new CRM_Member_DAO_MembershipType(); | |
299 | $membershipType->is_active = 1; | |
300 | $membershipType->id = $membershipTypeId; | |
301 | if ($membershipType->find(TRUE)) { | |
302 | CRM_Core_DAO::storeValues($membershipType, $membershipTypeDetails); | |
6a488035 TO |
303 | return $membershipTypeDetails; |
304 | } | |
305 | else { | |
306 | return NULL; | |
307 | } | |
308 | } | |
309 | ||
310 | /** | |
4c429c82 | 311 | * Calculate start date and end date for new membership. |
6a488035 | 312 | * |
b2363ea8 TO |
313 | * @param int $membershipTypeId |
314 | * Membership type id. | |
87ad884a | 315 | * @param string $joinDate |
b2363ea8 | 316 | * Member since ( in mysql date format ). |
87ad884a | 317 | * @param string $startDate |
b2363ea8 | 318 | * Start date ( in mysql date format ). |
da6b46f4 | 319 | * @param null $endDate |
b2363ea8 TO |
320 | * @param int $numRenewTerms |
321 | * How many membership terms are being added to end date (default is 1). | |
6a488035 | 322 | * |
a6c01b45 CW |
323 | * @return array |
324 | * associated array with start date, end date and join date for the membership | |
6a488035 TO |
325 | */ |
326 | public static function getDatesForMembershipType($membershipTypeId, $joinDate = NULL, $startDate = NULL, $endDate = NULL, $numRenewTerms = 1) { | |
327 | $membershipTypeDetails = self::getMembershipTypeDetails($membershipTypeId); | |
328 | ||
4c429c82 | 329 | // Convert all dates to 'Y-m-d' format. |
be2fb01f | 330 | foreach ([ |
c5c263ca AH |
331 | 'joinDate', |
332 | 'startDate', | |
333 | 'endDate', | |
be2fb01f | 334 | ] as $dateParam) { |
6a488035 TO |
335 | if (!empty($$dateParam)) { |
336 | $$dateParam = CRM_Utils_Date::processDate($$dateParam, NULL, FALSE, 'Y-m-d'); | |
337 | } | |
338 | } | |
339 | if (!$joinDate) { | |
340 | $joinDate = date('Y-m-d'); | |
341 | } | |
342 | $actualStartDate = $joinDate; | |
343 | if ($startDate) { | |
344 | $actualStartDate = $startDate; | |
345 | } | |
346 | ||
347 | $fixed_period_rollover = FALSE; | |
348 | if (CRM_Utils_Array::value('period_type', $membershipTypeDetails) == 'rolling') { | |
349 | if (!$startDate) { | |
350 | $startDate = $joinDate; | |
351 | } | |
352 | $actualStartDate = $startDate; | |
353 | } | |
354 | elseif (CRM_Utils_Array::value('period_type', $membershipTypeDetails) == 'fixed') { | |
5ae96933 DG |
355 | // calculate start date |
356 | // if !$startDate then use $joinDate | |
357 | $toDay = explode('-', (empty($startDate) ? $joinDate : $startDate)); | |
6a488035 TO |
358 | $year = $toDay[0]; |
359 | $month = $toDay[1]; | |
f7660a39 | 360 | $day = $toDay[2]; |
6a488035 TO |
361 | |
362 | if ($membershipTypeDetails['duration_unit'] == 'year') { | |
363 | ||
364 | //get start fixed day | |
365 | $startMonth = substr($membershipTypeDetails['fixed_period_start_day'], 0, | |
366 | strlen($membershipTypeDetails['fixed_period_start_day']) - 2 | |
367 | ); | |
368 | $startDay = substr($membershipTypeDetails['fixed_period_start_day'], -2); | |
369 | ||
f7660a39 | 370 | if (date('Y-m-d', mktime(0, 0, 0, $startMonth, $startDay, $year)) <= date('Y-m-d', mktime(0, 0, 0, $month, $day, $year))) { |
4c429c82 | 371 | $actualStartDate = date('Y-m-d', mktime(0, 0, 0, $startMonth, $startDay, $year)); |
f7660a39 DG |
372 | } |
373 | else { | |
4c429c82 | 374 | $actualStartDate = date('Y-m-d', mktime(0, 0, 0, $startMonth, $startDay, $year - 1)); |
f7660a39 | 375 | } |
82d11b3f | 376 | |
4c429c82 | 377 | $fixed_period_rollover = self::isDuringFixedAnnualRolloverPeriod($joinDate, $membershipTypeDetails, $year, $actualStartDate); |
6a488035 TO |
378 | |
379 | if (!$startDate) { | |
380 | $startDate = $actualStartDate; | |
381 | } | |
382 | } | |
383 | elseif ($membershipTypeDetails['duration_unit'] == 'month') { | |
384 | // Check if we are on or after rollover day of the month - CRM-10585 | |
385 | // If so, set fixed_period_rollover TRUE so we increment end_date month below. | |
386 | $dateParts = explode('-', $actualStartDate); | |
9b873358 | 387 | if ($dateParts[2] >= $membershipTypeDetails['fixed_period_rollover_day']) { |
b09fe5ed | 388 | $fixed_period_rollover = TRUE; |
6a488035 | 389 | } |
03e04002 | 390 | |
6a488035 TO |
391 | // Start date is always first day of actualStartDate month |
392 | if (!$startDate) { | |
393 | $actualStartDate = $startDate = $year . '-' . $month . '-01'; | |
394 | } | |
395 | } | |
396 | } | |
397 | ||
4c429c82 | 398 | // Calculate end date if it is not passed by user. |
6a488035 TO |
399 | if (!$endDate) { |
400 | //end date calculation | |
353ffa53 TO |
401 | $date = explode('-', $actualStartDate); |
402 | $year = $date[0]; | |
6a488035 | 403 | $month = $date[1]; |
353ffa53 | 404 | $day = $date[2]; |
6a488035 TO |
405 | |
406 | switch ($membershipTypeDetails['duration_unit']) { | |
407 | case 'year': | |
408 | $year = $year + ($numRenewTerms * $membershipTypeDetails['duration_interval']); | |
409 | //extend membership date by duration interval. | |
410 | if ($fixed_period_rollover) { | |
411 | $year += 1; | |
412 | } | |
413 | break; | |
414 | ||
415 | case 'month': | |
416 | $month = $month + ($numRenewTerms * $membershipTypeDetails['duration_interval']); | |
417 | //duration interval is month | |
418 | if ($fixed_period_rollover) { | |
419 | //CRM-10585 | |
420 | $month += 1; | |
421 | } | |
422 | break; | |
423 | ||
424 | case 'day': | |
425 | $day = $day + ($numRenewTerms * $membershipTypeDetails['duration_interval']); | |
426 | ||
427 | if ($fixed_period_rollover) { | |
428 | //Fix Me: Currently we don't allow rollover if | |
429 | //duration interval is day | |
430 | } | |
431 | break; | |
432 | } | |
433 | ||
434 | if ($membershipTypeDetails['duration_unit'] == 'lifetime') { | |
435 | $endDate = NULL; | |
436 | } | |
437 | else { | |
438 | $endDate = date('Y-m-d', mktime(0, 0, 0, $month, $day - 1, $year)); | |
439 | } | |
440 | } | |
441 | ||
be2fb01f | 442 | $membershipDates = [ |
c8881afb | 443 | 'start_date' => CRM_Utils_Date::customFormat($startDate, '%Y%m%d'), |
edc9b94e EM |
444 | 'end_date' => CRM_Utils_Date::customFormat($endDate, '%Y%m%d'), |
445 | 'join_date' => CRM_Utils_Date::customFormat($joinDate, '%Y%m%d'), | |
be2fb01f | 446 | ]; |
6a488035 TO |
447 | |
448 | return $membershipDates; | |
449 | } | |
450 | ||
87ad884a | 451 | /** |
fe482240 | 452 | * Does this membership start between the rollover date and the start of the next period. |
87ad884a EM |
453 | * (in which case they will get an extra membership period) |
454 | * ie if annual memberships run June - May & the rollover is in May memberships between | |
455 | * May and June will return TRUE and between June and May will return FALSE | |
456 | * | |
457 | * @param string $startDate start date of current membership period | |
87ad884a | 458 | * @param array $membershipTypeDetails |
81d97e72 | 459 | * @param int $year |
e9ac29eb | 460 | * @param string $actualStartDate |
87ad884a EM |
461 | * @return bool is this in the window where the membership gets an extra part-period added |
462 | */ | |
70a87708 | 463 | public static function isDuringFixedAnnualRolloverPeriod($startDate, $membershipTypeDetails, $year, $actualStartDate) { |
87ad884a EM |
464 | |
465 | $rolloverMonth = substr($membershipTypeDetails['fixed_period_rollover_day'], 0, | |
466 | strlen($membershipTypeDetails['fixed_period_rollover_day']) - 2 | |
467 | ); | |
468 | $rolloverDay = substr($membershipTypeDetails['fixed_period_rollover_day'], -2); | |
469 | ||
8454b618 | 470 | $calculatedRolloverDate = date('Y-m-d', mktime(0, 0, 0, $rolloverMonth, $rolloverDay, $year)); |
87ad884a EM |
471 | |
472 | //CRM-7825 -membership date rules are : | |
473 | //1. Membership should not be start in future. | |
474 | //2. rollover window should be subset of membership window. | |
475 | ||
87ad884a EM |
476 | //get the fixed end date here. |
477 | $dateParts = explode('-', $actualStartDate); | |
8454b618 | 478 | $endDateOfFirstYearMembershipPeriod = date('Y-m-d', mktime(0, 0, 0, |
87ad884a EM |
479 | $dateParts[1], |
480 | $dateParts[2] - 1, | |
6f1c82f5 | 481 | $dateParts[0] + 1 |
87ad884a EM |
482 | )); |
483 | ||
8454b618 EM |
484 | //we know the month and day of the rollover date but not the year (we're just |
485 | //using the start date year at the moment. So if it's after the end | |
486 | // of the first year of membership then it's the next period & we'll adjust back a year. If it's | |
487 | // before the start_date then it's too early & we'll adjust forward. | |
488 | if ($endDateOfFirstYearMembershipPeriod < $calculatedRolloverDate) { | |
489 | $calculatedRolloverDate = date('Y-m-d', mktime(0, 0, 0, $rolloverMonth, $rolloverDay, $year - 1)); | |
87ad884a | 490 | } |
8454b618 EM |
491 | if ($calculatedRolloverDate < $actualStartDate) { |
492 | $calculatedRolloverDate = date('Y-m-d', mktime(0, 0, 0, $rolloverMonth, $rolloverDay, $year + 1)); | |
87ad884a EM |
493 | } |
494 | ||
8454b618 | 495 | if ($calculatedRolloverDate <= $startDate) { |
87ad884a EM |
496 | return TRUE; |
497 | } | |
498 | return FALSE; | |
499 | } | |
500 | ||
6a488035 | 501 | /** |
055e2441 | 502 | * Calculate start date and end date for membership updates. |
503 | * | |
504 | * Note that this function is called by the api for any membership update although it was | |
505 | * originally written for renewal (which feels a bit fragile but hey....). | |
6a488035 TO |
506 | * |
507 | * @param int $membershipId | |
508 | * @param $changeToday | |
b4d1a1bf | 509 | * If provided, specify an alternative date to use as "today" for renewal |
b2363ea8 TO |
510 | * @param int $membershipTypeID |
511 | * If provided, overrides the membership type of the $membershipID membership. | |
512 | * @param int $numRenewTerms | |
513 | * How many membership terms are being added to end date (default is 1). | |
6a488035 TO |
514 | * |
515 | * CRM-7297 Membership Upsell - Added $membershipTypeID param to facilitate calculations of dates when membership type changes | |
516 | * | |
5396af74 | 517 | * @return array |
a6c01b45 | 518 | * array fo the start date, end date and join date of the membership |
6a488035 TO |
519 | */ |
520 | public static function getRenewalDatesForMembershipType($membershipId, $changeToday = NULL, $membershipTypeID = NULL, $numRenewTerms = 1) { | |
be2fb01f | 521 | $params = ['id' => $membershipId]; |
6a488035 | 522 | $membershipDetails = CRM_Member_BAO_Membership::getValues($params, $values); |
055e2441 | 523 | $membershipDetails = $membershipDetails[$membershipId]; |
524 | $statusID = $membershipDetails->status_id; | |
be2fb01f | 525 | $membershipDates = []; |
055e2441 | 526 | if (!empty($membershipDetails->join_date)) { |
527 | $membershipDates['join_date'] = CRM_Utils_Date::customFormat($membershipDetails->join_date, '%Y%m%d'); | |
528 | } | |
6a488035 TO |
529 | |
530 | $oldPeriodType = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', | |
353ffa53 | 531 | CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', $membershipId, 'membership_type_id'), 'period_type'); |
6a488035 TO |
532 | |
533 | // CRM-7297 Membership Upsell | |
534 | if (is_null($membershipTypeID)) { | |
055e2441 | 535 | $membershipTypeDetails = self::getMembershipTypeDetails($membershipDetails->membership_type_id); |
6a488035 TO |
536 | } |
537 | else { | |
538 | $membershipTypeDetails = self::getMembershipTypeDetails($membershipTypeID); | |
539 | } | |
540 | $statusDetails = CRM_Member_BAO_MembershipStatus::getMembershipStatus($statusID); | |
541 | ||
542 | if ($statusDetails['is_current_member'] == 1) { | |
055e2441 | 543 | $startDate = $membershipDetails->start_date; |
6a488035 TO |
544 | // CRM=7297 Membership Upsell: we need to handle null end_date in case we are switching |
545 | // from a lifetime to a different membership type | |
055e2441 | 546 | if (is_null($membershipDetails->end_date)) { |
6a488035 TO |
547 | $date = date('Y-m-d'); |
548 | } | |
549 | else { | |
055e2441 | 550 | $date = $membershipDetails->end_date; |
6a488035 | 551 | } |
353ffa53 | 552 | $date = explode('-', $date); |
3bd63a4b MW |
553 | // We have to add 1 day first in case it's the end of the month, then subtract afterwards |
554 | // eg. 2018-02-28 should renew to 2018-03-31, if we just added 1 month we'd get 2018-03-28 | |
6a488035 | 555 | $logStartDate = date('Y-m-d', mktime(0, 0, 0, |
353ffa53 TO |
556 | (double) $date[1], |
557 | (double) ($date[2] + 1), | |
558 | (double) $date[0] | |
559 | )); | |
6a488035 | 560 | |
353ffa53 TO |
561 | $date = explode('-', $logStartDate); |
562 | $year = $date[0]; | |
6a488035 | 563 | $month = $date[1]; |
353ffa53 | 564 | $day = $date[2]; |
6a488035 TO |
565 | |
566 | switch ($membershipTypeDetails['duration_unit']) { | |
567 | case 'year': | |
568 | //need to check if the upsell is from rolling to fixed and adjust accordingly | |
481a74f4 | 569 | if ($membershipTypeDetails['period_type'] == 'fixed' && $oldPeriodType == 'rolling') { |
6a488035 TO |
570 | $month = substr($membershipTypeDetails['fixed_period_start_day'], 0, strlen($membershipTypeDetails['fixed_period_start_day']) - 2); |
571 | $day = substr($membershipTypeDetails['fixed_period_start_day'], -2); | |
572 | $year += 1; | |
0db6c3e1 TO |
573 | } |
574 | else { | |
b09fe5ed | 575 | $year = $year + ($numRenewTerms * $membershipTypeDetails['duration_interval']); |
6a488035 TO |
576 | } |
577 | break; | |
578 | ||
579 | case 'month': | |
580 | $month = $month + ($numRenewTerms * $membershipTypeDetails['duration_interval']); | |
581 | break; | |
582 | ||
583 | case 'day': | |
584 | $day = $day + ($numRenewTerms * $membershipTypeDetails['duration_interval']); | |
585 | break; | |
586 | } | |
587 | if ($membershipTypeDetails['duration_unit'] == 'lifetime') { | |
588 | $endDate = NULL; | |
589 | } | |
590 | else { | |
591 | $endDate = date('Y-m-d', mktime(0, 0, 0, | |
353ffa53 TO |
592 | $month, |
593 | $day - 1, | |
594 | $year | |
595 | )); | |
6a488035 TO |
596 | } |
597 | $today = date('Y-m-d'); | |
6a488035 TO |
598 | $membershipDates['today'] = CRM_Utils_Date::customFormat($today, '%Y%m%d'); |
599 | $membershipDates['start_date'] = CRM_Utils_Date::customFormat($startDate, '%Y%m%d'); | |
600 | $membershipDates['end_date'] = CRM_Utils_Date::customFormat($endDate, '%Y%m%d'); | |
601 | $membershipDates['log_start_date'] = CRM_Utils_Date::customFormat($logStartDate, '%Y%m%d'); | |
602 | } | |
603 | else { | |
604 | $today = date('Y-m-d'); | |
605 | if ($changeToday) { | |
606 | $today = CRM_Utils_Date::processDate($changeToday, NULL, FALSE, 'Y-m-d'); | |
607 | } | |
608 | // Calculate new start/end dates when join date is today | |
609 | $renewalDates = self::getDatesForMembershipType($membershipTypeDetails['id'], | |
610 | $today, NULL, NULL, $numRenewTerms | |
611 | ); | |
6a488035 TO |
612 | $membershipDates['today'] = CRM_Utils_Date::customFormat($today, '%Y%m%d'); |
613 | $membershipDates['start_date'] = $renewalDates['start_date']; | |
614 | $membershipDates['end_date'] = $renewalDates['end_date']; | |
615 | $membershipDates['log_start_date'] = $renewalDates['start_date']; | |
41dcb974 | 616 | // CRM-18503 - set join_date as today in case the membership type is fixed. |
617 | if ($membershipTypeDetails['period_type'] == 'fixed' && !isset($membershipDates['join_date'])) { | |
618 | $membershipDates['join_date'] = $renewalDates['join_date']; | |
619 | } | |
6a488035 | 620 | } |
055e2441 | 621 | if (!isset($membershipDates['join_date'])) { |
622 | $membershipDates['join_date'] = $membershipDates['start_date']; | |
623 | } | |
6a488035 TO |
624 | |
625 | return $membershipDates; | |
626 | } | |
627 | ||
628 | /** | |
4c50ac3a MW |
629 | * @deprecated Please use the Membership API |
630 | * Retrieve all Membership Types associated with an Organization | |
6a488035 | 631 | * |
b2363ea8 TO |
632 | * @param int $orgID |
633 | * Id of Organization. | |
6a488035 | 634 | * |
5396af74 | 635 | * @return array |
a6c01b45 | 636 | * array of the details of membership types |
6a488035 | 637 | */ |
00be9182 | 638 | public static function getMembershipTypesByOrg($orgID) { |
496320c3 | 639 | CRM_Core_Error::deprecatedFunctionWarning('membership_type api'); |
be2fb01f | 640 | $memberTypesSameParentOrg = civicrm_api3('MembershipType', 'get', [ |
c8eada29 | 641 | 'member_of_contact_id' => $orgID, |
be2fb01f | 642 | 'options' => [ |
c8eada29 | 643 | 'limit' => 0, |
be2fb01f CW |
644 | ], |
645 | ]); | |
646 | return CRM_Utils_Array::value('values', $memberTypesSameParentOrg, []); | |
6a488035 TO |
647 | } |
648 | ||
649 | /** | |
fe482240 | 650 | * Retrieve all Membership Types with Member of Contact id. |
6a488035 | 651 | * |
5396af74 | 652 | * @param array $membershipTypes |
653 | * array of membership type ids | |
654 | * @return array | |
a6c01b45 | 655 | * array of the details of membership types with Member of Contact id |
6a488035 | 656 | */ |
00be9182 | 657 | public static function getMemberOfContactByMemTypes($membershipTypes) { |
be2fb01f | 658 | $memTypeOrganizations = []; |
6a488035 | 659 | if (empty($membershipTypes)) { |
b204fd50 | 660 | return $memTypeOrganizations; |
6a488035 TO |
661 | } |
662 | ||
663 | $result = CRM_Core_DAO::executeQuery("SELECT id, member_of_contact_id FROM civicrm_membership_type WHERE id IN (" . implode(',', $membershipTypes) . ")"); | |
664 | while ($result->fetch()) { | |
b204fd50 | 665 | $memTypeOrganizations[$result->id] = $result->member_of_contact_id; |
6a488035 TO |
666 | } |
667 | ||
b204fd50 | 668 | return $memTypeOrganizations; |
6a488035 TO |
669 | } |
670 | ||
77b97be7 | 671 | /** |
87ad884a | 672 | * The function returns all the Organization for all membershipTypes . |
6a488035 | 673 | * |
c490a46a | 674 | * @param int $membershipTypeId |
77b97be7 EM |
675 | * |
676 | * @return array | |
6a488035 | 677 | */ |
00be9182 | 678 | public static function getMembershipTypeOrganization($membershipTypeId = NULL) { |
be2fb01f | 679 | $allMembershipTypes = []; |
6a488035 TO |
680 | |
681 | $membershipType = new CRM_Member_DAO_MembershipType(); | |
682 | ||
683 | if (isset($membershipTypeId)) { | |
684 | $membershipType->id = $membershipTypeId; | |
685 | } | |
686 | $membershipType->find(); | |
687 | ||
688 | while ($membershipType->fetch()) { | |
b204fd50 | 689 | $allMembershipTypes[$membershipType->id] = $membershipType->member_of_contact_id; |
6a488035 | 690 | } |
b204fd50 | 691 | return $allMembershipTypes; |
6a488035 TO |
692 | } |
693 | ||
694 | /** | |
87ad884a | 695 | * Function to retrieve organization and associated membership |
6a488035 TO |
696 | * types |
697 | * | |
a6c01b45 CW |
698 | * @return array |
699 | * arrays of organization and membership types | |
6a488035 | 700 | * |
6a488035 | 701 | */ |
00be9182 | 702 | public static function getMembershipTypeInfo() { |
6a488035 | 703 | if (!self::$_membershipTypeInfo) { |
be2fb01f | 704 | $orgs = $types = []; |
6a488035 TO |
705 | |
706 | $query = 'SELECT memType.id, memType.name, memType.member_of_contact_id, c.sort_name | |
707 | FROM civicrm_membership_type memType INNER JOIN civicrm_contact c ON c.id = memType.member_of_contact_id | |
708 | WHERE memType.is_active = 1 '; | |
481a74f4 | 709 | $dao = CRM_Core_DAO::executeQuery($query); |
6a488035 TO |
710 | while ($dao->fetch()) { |
711 | $orgs[$dao->member_of_contact_id] = $dao->sort_name; | |
712 | $types[$dao->member_of_contact_id][$dao->id] = $dao->name; | |
713 | } | |
714 | ||
be2fb01f | 715 | self::$_membershipTypeInfo = [$orgs, $types]; |
6a488035 TO |
716 | } |
717 | return self::$_membershipTypeInfo; | |
718 | } | |
719 | ||
bb3a214a | 720 | /** |
c490a46a | 721 | * @param array $params |
100fef9d CW |
722 | * @param int $previousID |
723 | * @param int $membershipTypeId | |
bb3a214a | 724 | */ |
301db4f8 | 725 | public static function createMembershipPriceField($params, $previousID, $membershipTypeId) { |
6a488035 | 726 | |
9da8dc8c | 727 | $priceSetId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', 'default_membership_type_amount', 'id', 'name'); |
6a488035 | 728 | |
a7488080 | 729 | if (!empty($params['member_of_contact_id'])) { |
6a488035 TO |
730 | $fieldName = $params['member_of_contact_id']; |
731 | } | |
732 | else { | |
733 | $fieldName = $previousID; | |
734 | } | |
353ffa53 TO |
735 | $fieldLabel = 'Membership Amount'; |
736 | $optionsIds = NULL; | |
be2fb01f | 737 | $fieldParams = [ |
6a488035 TO |
738 | 'price_set_id ' => $priceSetId, |
739 | 'name' => $fieldName, | |
be2fb01f CW |
740 | ]; |
741 | $results = []; | |
9da8dc8c | 742 | CRM_Price_BAO_PriceField::retrieve($fieldParams, $results); |
6a488035 | 743 | if (empty($results)) { |
be2fb01f | 744 | $fieldParams = []; |
6a488035 TO |
745 | $fieldParams['label'] = $fieldLabel; |
746 | $fieldParams['name'] = $fieldName; | |
747 | $fieldParams['price_set_id'] = $priceSetId; | |
748 | $fieldParams['html_type'] = 'Radio'; | |
749 | $fieldParams['is_display_amounts'] = $fieldParams['is_required'] = 0; | |
750 | $fieldParams['weight'] = $fieldParams['option_weight'][1] = 1; | |
751 | $fieldParams['option_label'][1] = $params['name']; | |
0e09eaf5 | 752 | $fieldParams['option_description'][1] = CRM_Utils_Array::value('description', $params); |
03e04002 | 753 | |
6a488035 TO |
754 | $fieldParams['membership_type_id'][1] = $membershipTypeId; |
755 | $fieldParams['option_amount'][1] = empty($params['minimum_fee']) ? 0 : $params['minimum_fee']; | |
756 | $fieldParams['financial_type_id'] = CRM_Utils_Array::value('financial_type_id', $params); | |
757 | ||
758 | if ($previousID) { | |
759 | CRM_Member_Form_MembershipType::checkPreviousPriceField($previousID, $priceSetId, $membershipTypeId, $optionsIds); | |
760 | $fieldParams['option_id'] = CRM_Utils_Array::value('option_id', $optionsIds); | |
761 | } | |
806e9b71 | 762 | CRM_Price_BAO_PriceField::create($fieldParams); |
03e04002 | 763 | } |
6a488035 TO |
764 | else { |
765 | $fieldID = $results['id']; | |
be2fb01f | 766 | $fieldValueParams = [ |
6a488035 TO |
767 | 'price_field_id' => $fieldID, |
768 | 'membership_type_id' => $membershipTypeId, | |
be2fb01f CW |
769 | ]; |
770 | $results = []; | |
9da8dc8c | 771 | CRM_Price_BAO_PriceFieldValue::retrieve($fieldValueParams, $results); |
6a488035 | 772 | if (!empty($results)) { |
353ffa53 | 773 | $results['label'] = $results['name'] = $params['name']; |
6a488035 | 774 | $results['amount'] = empty($params['minimum_fee']) ? 0 : $params['minimum_fee']; |
353ffa53 | 775 | $optionsIds['id'] = $results['id']; |
03e04002 | 776 | } |
6a488035 | 777 | else { |
be2fb01f | 778 | $results = [ |
6a488035 TO |
779 | 'price_field_id' => $fieldID, |
780 | 'name' => $params['name'], | |
781 | 'label' => $params['name'], | |
782 | 'amount' => empty($params['minimum_fee']) ? 0 : $params['minimum_fee'], | |
783 | 'membership_type_id' => $membershipTypeId, | |
784 | 'is_active' => 1, | |
be2fb01f | 785 | ]; |
6a488035 TO |
786 | } |
787 | ||
788 | if ($previousID) { | |
789 | CRM_Member_Form_MembershipType::checkPreviousPriceField($previousID, $priceSetId, $membershipTypeId, $optionsIds); | |
a7488080 | 790 | if (!empty($optionsIds['option_id'])) { |
6a488035 TO |
791 | $optionsIds['id'] = current(CRM_Utils_Array::value('option_id', $optionsIds)); |
792 | } | |
793 | } | |
794 | $results['financial_type_id'] = CRM_Utils_Array::value('financial_type_id', $params); | |
0e09eaf5 | 795 | $results['description'] = CRM_Utils_Array::value('description', $params); |
9da8dc8c | 796 | CRM_Price_BAO_PriceFieldValue::add($results, $optionsIds); |
6a488035 TO |
797 | } |
798 | } | |
799 | ||
be2e0c6a TO |
800 | /** |
801 | * This function updates all price field value for quick config | |
6a488035 TO |
802 | * price set which has membership type |
803 | * | |
87ad884a | 804 | * @param int $membershipTypeId membership type id |
6a488035 | 805 | * |
87ad884a | 806 | * @param array $params |
6a488035 | 807 | */ |
00be9182 | 808 | public static function updateAllPriceFieldValue($membershipTypeId, $params) { |
be2fb01f CW |
809 | $defaults = []; |
810 | $fieldsToUpdate = [ | |
5afcf706 JP |
811 | 'financial_type_id' => 'financial_type_id', |
812 | 'name' => 'label', | |
813 | 'minimum_fee' => 'amount', | |
814 | 'description' => 'description', | |
815 | 'visibility' => 'visibility_id', | |
be2fb01f | 816 | ]; |
5afcf706 JP |
817 | $priceFieldValueBAO = new CRM_Price_BAO_PriceFieldValue(); |
818 | $priceFieldValueBAO->membership_type_id = $membershipTypeId; | |
819 | $priceFieldValueBAO->find(); | |
820 | while ($priceFieldValueBAO->fetch()) { | |
be2fb01f | 821 | $updateParams = [ |
5afcf706 JP |
822 | 'id' => $priceFieldValueBAO->id, |
823 | 'price_field_id' => $priceFieldValueBAO->price_field_id, | |
be2fb01f | 824 | ]; |
5afcf706 | 825 | //Get priceset details. |
be2fb01f | 826 | $fieldParams = ['fid' => $priceFieldValueBAO->price_field_id]; |
5afcf706 | 827 | $setID = CRM_Price_BAO_PriceSet::getSetId($fieldParams); |
be2fb01f | 828 | $setParams = ['id' => $setID]; |
5afcf706 JP |
829 | $setValues = CRM_Price_BAO_PriceSet::retrieve($setParams, $defaults); |
830 | if (!empty($setValues->is_quick_config) && $setValues->name != 'default_membership_type_amount') { | |
831 | foreach ($fieldsToUpdate as $key => $value) { | |
832 | if ($value == 'visibility_id' && !empty($params['visibility'])) { | |
833 | $updateParams['visibility_id'] = CRM_Price_BAO_PriceField::getVisibilityOptionID(strtolower($params['visibility'])); | |
834 | } | |
835 | else { | |
836 | $updateParams[$value] = CRM_Utils_Array::value($key, $params); | |
837 | } | |
0e09eaf5 | 838 | } |
5afcf706 | 839 | CRM_Price_BAO_PriceFieldValue::add($updateParams); |
0e09eaf5 PN |
840 | } |
841 | } | |
03e04002 | 842 | } |
96025800 | 843 | |
6a488035 | 844 | } |