Commit | Line | Data |
---|---|---|
6a488035 TO |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
39de6fd5 | 4 | | CiviCRM version 4.6 | |
6a488035 | 5 | +--------------------------------------------------------------------+ |
e7112fa7 | 6 | | Copyright CiviCRM LLC (c) 2004-2015 | |
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 | |
e7112fa7 | 31 | * @copyright CiviCRM LLC (c) 2004-2015 |
6a488035 TO |
32 | * $Id$ |
33 | * | |
34 | */ | |
35 | class CRM_Member_BAO_Membership extends CRM_Member_DAO_Membership { | |
36 | ||
37 | /** | |
fe482240 | 38 | * Static field for all the membership information that we can potentially import. |
6a488035 TO |
39 | * |
40 | * @var array | |
6a488035 TO |
41 | */ |
42 | static $_importableFields = NULL; | |
8ef12e64 | 43 | |
4e636a74 | 44 | static $_renewalActType = NULL; |
8ef12e64 | 45 | |
4e636a74 | 46 | static $_signupActType = NULL; |
8ef12e64 | 47 | |
bb3a214a | 48 | /** |
fe482240 | 49 | * Class constructor. |
bb3a214a | 50 | * |
bb3a214a EM |
51 | * @return \CRM_Member_DAO_Membership |
52 | */ | |
53 | /** | |
bb3a214a | 54 | */ |
00be9182 | 55 | public function __construct() { |
6a488035 TO |
56 | parent::__construct(); |
57 | } | |
58 | ||
59 | /** | |
fe482240 | 60 | * Takes an associative array and creates a membership object. |
6a488035 TO |
61 | * |
62 | * the function extracts all the params it needs to initialize the created | |
63 | * membership object. The params array could contain additional unused name/value | |
64 | * pairs | |
65 | * | |
b2363ea8 TO |
66 | * @param array $params |
67 | * (reference ) an assoc array of name/value pairs. | |
68 | * @param array $ids | |
69 | * The array that holds all the db ids. | |
6a488035 | 70 | * |
16b10e64 | 71 | * @return CRM_Member_BAO_Membership |
6a488035 | 72 | */ |
00be9182 | 73 | public static function add(&$params, $ids = array()) { |
a5e2b32e | 74 | $oldStatus = $oldType = NULL; |
f880fd16 EM |
75 | $params['id'] = CRM_Utils_Array::value('id', $params, CRM_Utils_Array::value('membership', $ids)); |
76 | if ($params['id']) { | |
77 | CRM_Utils_Hook::pre('edit', 'Membership', $params['id'], $params); | |
78 | } | |
79 | else { | |
1acc24d5 | 80 | CRM_Utils_Hook::pre('create', 'Membership', NULL, $params); |
f880fd16 EM |
81 | } |
82 | $id = $params['id']; | |
83 | // we do this after the hooks are called in case it has been altered | |
84 | if ($id) { | |
85 | $membershipObj = new CRM_Member_DAO_Membership(); | |
86 | $membershipObj->id = $id; | |
6a488035 TO |
87 | $membershipObj->find(); |
88 | while ($membershipObj->fetch()) { | |
89 | $oldStatus = $membershipObj->status_id; | |
90 | $oldType = $membershipObj->membership_type_id; | |
91 | } | |
92 | } | |
6a488035 TO |
93 | |
94 | if (array_key_exists('is_override', $params) && !$params['is_override']) { | |
95 | $params['is_override'] = 'null'; | |
96 | } | |
97 | ||
98 | $membership = new CRM_Member_BAO_Membership(); | |
99 | $membership->copyValues($params); | |
f880fd16 | 100 | $membership->id = $id; |
6a488035 TO |
101 | |
102 | $membership->save(); | |
103 | $membership->free(); | |
104 | ||
6a488035 TO |
105 | if (empty($membership->contact_id) || empty($membership->status_id)) { |
106 | // this means we are in renewal mode and are just updating the membership | |
107 | // record or this is an API update call and all fields are not present in the update record | |
b204fd50 | 108 | // however the hooks don't care and want all data CRM-7784 |
6a488035 TO |
109 | $tempMembership = new CRM_Member_DAO_Membership(); |
110 | $tempMembership->id = $membership->id; | |
111 | $tempMembership->find(TRUE); | |
112 | $membership = $tempMembership; | |
113 | } | |
114 | ||
115 | //get the log start date. | |
116 | //it is set during renewal of membership. | |
ca58d9b9 | 117 | $logStartDate = CRM_Utils_Array::value('log_start_date', $params); |
6a488035 | 118 | $logStartDate = ($logStartDate) ? CRM_Utils_Date::isoToMysql($logStartDate) : CRM_Utils_Date::isoToMysql($membership->start_date); |
e0556ebe | 119 | $values = self::getStatusANDTypeValues($membership->id); |
6a488035 TO |
120 | |
121 | $membershipLog = array( | |
122 | 'membership_id' => $membership->id, | |
123 | 'status_id' => $membership->status_id, | |
124 | 'start_date' => $logStartDate, | |
125 | 'end_date' => CRM_Utils_Date::isoToMysql($membership->end_date), | |
126 | 'modified_date' => date('Ymd'), | |
127 | 'membership_type_id' => $values[$membership->id]['membership_type_id'], | |
128 | 'max_related' => $membership->max_related, | |
129 | ); | |
130 | ||
131 | $session = CRM_Core_Session::singleton(); | |
132 | // If we have an authenticated session, set modified_id to that user's contact_id, else set to membership.contact_id | |
133 | if ($session->get('userID')) { | |
134 | $membershipLog['modified_id'] = $session->get('userID'); | |
135 | } | |
136 | elseif (!empty($ids['userId'])) { | |
137 | $membershipLog['modified_id'] = $ids['userId']; | |
138 | } | |
139 | else { | |
140 | $membershipLog['modified_id'] = $membership->contact_id; | |
141 | } | |
142 | ||
143 | CRM_Member_BAO_MembershipLog::add($membershipLog, CRM_Core_DAO::$_nullArray); | |
144 | ||
145 | // reset the group contact cache since smart groups might be affected due to this | |
146 | CRM_Contact_BAO_GroupContactCache::remove(); | |
147 | ||
f880fd16 | 148 | if ($id) { |
6a488035 | 149 | if ($membership->status_id != $oldStatus) { |
4d63cfde | 150 | $allStatus = CRM_Member_BAO_Membership::buildOptions('status_id', 'get'); |
6a488035 TO |
151 | $activityParam = array( |
152 | 'subject' => "Status changed from {$allStatus[$oldStatus]} to {$allStatus[$membership->status_id]}", | |
153 | 'source_contact_id' => $membershipLog['modified_id'], | |
154 | 'target_contact_id' => $membership->contact_id, | |
155 | 'source_record_id' => $membership->id, | |
4d63cfde | 156 | 'activity_type_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Change Membership Status'), |
6a488035 | 157 | 'status_id' => 2, |
6a488035 TO |
158 | 'priority_id' => 2, |
159 | 'activity_date_time' => date('Y-m-d H:i:s'), | |
6a488035 | 160 | ); |
4d63cfde | 161 | civicrm_api3('activity', 'create', $activityParam); |
6a488035 TO |
162 | } |
163 | if (isset($membership->membership_type_id) && $membership->membership_type_id != $oldType) { | |
4d63cfde | 164 | $membershipTypes = CRM_Member_BAO_Membership::buildOptions('membership_type_id', 'get'); |
6a488035 TO |
165 | $activityParam = array( |
166 | 'subject' => "Type changed from {$membershipTypes[$oldType]} to {$membershipTypes[$membership->membership_type_id]}", | |
167 | 'source_contact_id' => $membershipLog['modified_id'], | |
168 | 'target_contact_id' => $membership->contact_id, | |
169 | 'source_record_id' => $membership->id, | |
bd38fe3f | 170 | 'activity_type_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Change Membership Type'), |
6a488035 | 171 | 'status_id' => 2, |
6a488035 TO |
172 | 'priority_id' => 2, |
173 | 'activity_date_time' => date('Y-m-d H:i:s'), | |
6a488035 | 174 | ); |
4d63cfde | 175 | civicrm_api3('activity', 'create', $activityParam); |
6a488035 TO |
176 | } |
177 | CRM_Utils_Hook::post('edit', 'Membership', $membership->id, $membership); | |
178 | } | |
179 | else { | |
180 | CRM_Utils_Hook::post('create', 'Membership', $membership->id, $membership); | |
181 | } | |
182 | ||
183 | return $membership; | |
184 | } | |
185 | ||
186 | /** | |
187 | * Given the list of params in the params array, fetch the object | |
188 | * and store the values in the values array | |
189 | * | |
b2363ea8 TO |
190 | * @param array $params |
191 | * Input parameters to find object. | |
192 | * @param array $values | |
193 | * Output values of the object. | |
194 | * @param bool $active | |
195 | * Do you want only active memberships to. | |
6a488035 | 196 | * be returned |
f1e48e7f | 197 | * @param bool $relatedMemberships |
6a488035 | 198 | * @return CRM_Member_BAO_Membership|null the found object or null |
6a488035 | 199 | */ |
f1e48e7f | 200 | public static function &getValues(&$params, &$values, $active = FALSE, $relatedMemberships = FALSE) { |
6a488035 TO |
201 | if (empty($params)) { |
202 | return NULL; | |
203 | } | |
204 | $membership = new CRM_Member_BAO_Membership(); | |
205 | ||
206 | $membership->copyValues($params); | |
207 | $membership->find(); | |
208 | $memberships = array(); | |
209 | while ($membership->fetch()) { | |
210 | if ($active && | |
211 | (!CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipStatus', | |
e0556ebe TO |
212 | $membership->status_id, |
213 | 'is_current_member' | |
214 | )) | |
6a488035 TO |
215 | ) { |
216 | continue; | |
217 | } | |
218 | ||
219 | CRM_Core_DAO::storeValues($membership, $values[$membership->id]); | |
220 | $memberships[$membership->id] = $membership; | |
f1e48e7f | 221 | if ($relatedMemberships && !empty($membership->owner_membership_id)) { |
222 | $values['owner_membership_ids'][] = $membership->owner_membership_id; | |
223 | } | |
6a488035 TO |
224 | } |
225 | ||
226 | return $memberships; | |
227 | } | |
228 | ||
229 | /** | |
fe482240 | 230 | * Takes an associative array and creates a membership object. |
6a488035 | 231 | * |
b2363ea8 TO |
232 | * @param array $params |
233 | * (reference ) an assoc array of name/value pairs. | |
234 | * @param array $ids | |
235 | * The array that holds all the db ids. | |
8efea814 EM |
236 | * @param bool $skipRedirect |
237 | * @param string $activityType | |
238 | * | |
239 | * @throws CRM_Core_Exception | |
6a488035 | 240 | * |
906e6120 | 241 | * @return CRM_Member_BAO_Membership|CRM_Core_Error |
6a488035 | 242 | */ |
00be9182 | 243 | public static function create(&$params, &$ids, $skipRedirect = FALSE, $activityType = 'Membership Signup') { |
6a488035 TO |
244 | // always calculate status if is_override/skipStatusCal is not true. |
245 | // giving respect to is_override during import. CRM-4012 | |
246 | ||
247 | // To skip status calculation we should use 'skipStatusCal'. | |
248 | // eg pay later membership, membership update cron CRM-3984 | |
249 | ||
8cc574cf | 250 | if (empty($params['is_override']) && empty($params['skipStatusCal'])) { |
0042ddd9 | 251 | $dates = array('start_date', 'end_date', 'join_date'); |
ca58d9b9 | 252 | $start_date = $end_date = $join_date = NULL; // declare these out of courtesy as IDEs don't pick up the setting of them below |
0042ddd9 | 253 | foreach ($dates as $date) { |
b5588874 | 254 | $$date = $params[$date] = CRM_Utils_Date::processDate(CRM_Utils_Array::value($date, $params), NULL, TRUE, 'Ymd'); |
6a488035 TO |
255 | } |
256 | ||
257 | //fix for CRM-3570, during import exclude the statuses those having is_admin = 1 | |
258 | $excludeIsAdmin = CRM_Utils_Array::value('exclude_is_admin', $params, FALSE); | |
259 | ||
260 | //CRM-3724 always skip is_admin if is_override != true. | |
8cc574cf | 261 | if (!$excludeIsAdmin && empty($params['is_override'])) { |
6a488035 TO |
262 | $excludeIsAdmin = TRUE; |
263 | } | |
264 | ||
358f8960 MV |
265 | //CRM-15829 UPDATES |
266 | // When adding memberships to a contact and If a status is pending then there is no need to perform these calculations. Otherwise it will errernously not realise the pending state and set ot to NEW or GRACE depending on the date ranges. | |
267 | if (isset($params['status_id']) && $params['status_id'] == 5) { | |
268 | $calcStatus['id'] = $params['status_id']; | |
269 | } | |
270 | else { | |
271 | $calcStatus = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($start_date, $end_date, $join_date, | |
272 | 'today', $excludeIsAdmin, CRM_Utils_Array::value('membership_type_id', $params), $params | |
273 | ); | |
274 | } | |
275 | ||
6a488035 | 276 | if (empty($calcStatus)) { |
dcc4f6a7 | 277 | // Redirect the form in case of error |
278 | // @todo this redirect in the BAO layer is really bad & should be moved to the form layer | |
279 | // however since we have no idea how (if) this is triggered we can't safely move / remove it | |
280 | // NB I tried really hard to trigger this error from backoffice membership form in order to test it | |
281 | // and am convinced form validation is complete on that form WRT this error. | |
282 | $errorParams = array( | |
283 | 'message_title' => ts('No valid membership status for given dates.'), | |
284 | 'legacy_redirect_path' => 'civicrm/contact/view', | |
285 | 'legacy_redirect_query' => "reset=1&force=1&cid={$params['contact_id']}&selectedChild=member", | |
286 | ); | |
8c33a68c | 287 | throw new CRM_Core_Exception(ts('The membership cannot be saved because the status cannot be calculated.'), 0, $errorParams); |
6a488035 TO |
288 | } |
289 | $params['status_id'] = $calcStatus['id']; | |
290 | } | |
291 | ||
292 | // data cleanup only: all verifications on number of related memberships are done upstream in: | |
293 | // CRM_Member_BAO_Membership::createRelatedMemberships() | |
294 | // CRM_Contact_BAO_Relationship::relatedMemberships() | |
295 | if (isset($params['owner_membership_id'])) { | |
296 | unset($params['max_related']); | |
8efea814 EM |
297 | } |
298 | else { | |
6a488035 TO |
299 | // if membership allows related, default max_related to value in membership_type |
300 | if (!array_key_exists('max_related', $params) && !empty($params['membership_type_id'])) { | |
301 | $membershipType = CRM_Member_BAO_MembershipType::getMembershipTypeDetails($params['membership_type_id']); | |
302 | if (isset($membershipType['relationship_type_id'])) { | |
303 | $params['max_related'] = CRM_Utils_Array::value('max_related', $membershipType); | |
304 | } | |
305 | } | |
306 | } | |
307 | ||
308 | $transaction = new CRM_Core_Transaction(); | |
309 | ||
310 | $membership = self::add($params, $ids); | |
311 | ||
312 | if (is_a($membership, 'CRM_Core_Error')) { | |
313 | $transaction->rollback(); | |
314 | return $membership; | |
315 | } | |
316 | ||
317 | // add custom field values | |
a7488080 | 318 | if (!empty($params['custom']) && is_array($params['custom']) |
6a488035 TO |
319 | ) { |
320 | CRM_Core_BAO_CustomValueTable::store($params['custom'], 'civicrm_membership', $membership->id); | |
321 | } | |
322 | ||
323 | $params['membership_id'] = $membership->id; | |
324 | if (isset($ids['membership'])) { | |
325 | $ids['contribution'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipPayment', | |
326 | $ids['membership'], | |
327 | 'contribution_id', | |
328 | 'membership_id' | |
329 | ); | |
330 | } | |
3c0201c9 | 331 | |
d5b95619 | 332 | $params['skipLineItem'] = TRUE; |
3c0201c9 | 333 | |
6a488035 | 334 | //record contribution for this membership |
8cc574cf | 335 | if (!empty($params['contribution_status_id']) && empty($params['relate_contribution_id'])) { |
8d8bd076 | 336 | $memInfo = array_merge($params, array('membership_id' => $membership->id)); |
337 | $params['contribution'] = self::recordMembershipContribution($memInfo, $ids); | |
6a488035 | 338 | } |
3c0201c9 | 339 | |
82cc6775 PN |
340 | if (!empty($params['lineItems'])) { |
341 | $params['line_item'] = $params['lineItems']; | |
342 | } | |
343 | ||
344 | //do cleanup line items if membership edit the Membership type. | |
345 | if (empty($ids['contribution']) && !empty($ids['membership'])) { | |
346 | CRM_Price_BAO_LineItem::deleteLineItems($ids['membership'], 'civicrm_membership'); | |
347 | } | |
3c0201c9 | 348 | |
82cc6775 PN |
349 | if (!empty($params['line_item']) && empty($ids['contribution'])) { |
350 | CRM_Price_BAO_LineItem::processPriceSet($membership->id, $params['line_item'], CRM_Utils_Array::value('contribution', $params)); | |
d5b95619 | 351 | } |
6a488035 TO |
352 | |
353 | //insert payment record for this membership | |
a7488080 | 354 | if (!empty($params['relate_contribution_id'])) { |
e0556ebe | 355 | CRM_Member_BAO_MembershipPayment::create(array( |
353ffa53 TO |
356 | 'membership_id' => $membership->id, |
357 | 'contribution_id' => $params['relate_contribution_id'], | |
358 | )); | |
6a488035 TO |
359 | } |
360 | ||
361 | // add activity record only during create mode and renew mode | |
362 | // also add activity if status changed CRM-3984 and CRM-2521 | |
a7488080 | 363 | if (empty($ids['membership']) || |
e0556ebe TO |
364 | $activityType == 'Membership Renewal' || !empty($params['createActivity']) |
365 | ) { | |
a7488080 | 366 | if (!empty($ids['membership'])) { |
ca58d9b9 | 367 | $data = array(); |
6a488035 TO |
368 | CRM_Core_DAO::commonRetrieveAll('CRM_Member_DAO_Membership', |
369 | 'id', | |
370 | $membership->id, | |
371 | $data, | |
372 | array('contact_id', 'membership_type_id', 'source') | |
373 | ); | |
374 | ||
375 | $membership->contact_id = $data[$membership->id]['contact_id']; | |
376 | $membership->membership_type_id = $data[$membership->id]['membership_type_id']; | |
377 | $membership->source = CRM_Utils_Array::value('source', $data[$membership->id]); | |
378 | } | |
379 | ||
380 | // since we are going to create activity record w/ | |
381 | // individual contact as a target in case of on behalf signup, | |
382 | // so get the copy of organization id, CRM-5551 | |
383 | $realMembershipContactId = $membership->contact_id; | |
384 | ||
385 | // create activity source = individual, target = org CRM-4027 | |
386 | $targetContactID = NULL; | |
a7488080 | 387 | if (!empty($params['is_for_organization'])) { |
6a488035 TO |
388 | $targetContactID = $membership->contact_id; |
389 | $membership->contact_id = CRM_Utils_Array::value('userId', $ids); | |
390 | } | |
391 | ||
392 | if (empty($membership->contact_id) && (!empty($membership->owner_membership_id))) { | |
393 | $membership->contact_id = $realMembershipContactId; | |
394 | } | |
395 | ||
a7488080 | 396 | if (!empty($ids['membership']) && $activityType != 'Membership Signup') { |
6a488035 | 397 | CRM_Activity_BAO_Activity::addActivity($membership, $activityType, $targetContactID); |
e0556ebe TO |
398 | } |
399 | elseif (empty($ids['membership'])) { | |
6a488035 TO |
400 | CRM_Activity_BAO_Activity::addActivity($membership, $activityType, $targetContactID); |
401 | } | |
402 | ||
403 | // we might created activity record w/ individual | |
404 | // contact as target so update membership object w/ | |
405 | // original organization id, CRM-5551 | |
406 | $membership->contact_id = $realMembershipContactId; | |
407 | } | |
408 | ||
409 | $transaction->commit(); | |
410 | ||
411 | self::createRelatedMemberships($params, $membership); | |
412 | ||
413 | // do not add to recent items for import, CRM-4399 | |
a7488080 | 414 | if (empty($params['skipRecentView'])) { |
6a488035 TO |
415 | $url = CRM_Utils_System::url('civicrm/contact/view/membership', |
416 | "action=view&reset=1&id={$membership->id}&cid={$membership->contact_id}&context=home" | |
417 | ); | |
e0556ebe | 418 | if (empty($membership->membership_type_id)) {// ie in an update situation |
6a488035 TO |
419 | $membership->find(TRUE); |
420 | } | |
421 | $membershipTypes = CRM_Member_PseudoConstant::membershipType(); | |
422 | $title = CRM_Contact_BAO_Contact::displayName($membership->contact_id) . ' - ' . ts('Membership Type:') . ' ' . $membershipTypes[$membership->membership_type_id]; | |
423 | ||
424 | $recentOther = array(); | |
425 | if (CRM_Core_Permission::checkActionPermission('CiviMember', CRM_Core_Action::UPDATE)) { | |
426 | $recentOther['editUrl'] = CRM_Utils_System::url('civicrm/contact/view/membership', | |
427 | "action=update&reset=1&id={$membership->id}&cid={$membership->contact_id}&context=home" | |
428 | ); | |
429 | } | |
430 | if (CRM_Core_Permission::checkActionPermission('CiviMember', CRM_Core_Action::DELETE)) { | |
431 | $recentOther['deleteUrl'] = CRM_Utils_System::url('civicrm/contact/view/membership', | |
432 | "action=delete&reset=1&id={$membership->id}&cid={$membership->contact_id}&context=home" | |
433 | ); | |
434 | } | |
435 | ||
436 | // add the recently created Membership | |
437 | CRM_Utils_Recent::add($title, | |
438 | $url, | |
439 | $membership->id, | |
440 | 'Membership', | |
441 | $membership->contact_id, | |
442 | NULL, | |
443 | $recentOther | |
444 | ); | |
445 | } | |
446 | ||
447 | return $membership; | |
448 | } | |
449 | ||
450 | /** | |
fe482240 | 451 | * Check the membership extended through relationship. |
6a488035 | 452 | * |
b2363ea8 TO |
453 | * @param int $membershipId |
454 | * Membership id. | |
455 | * @param int $contactId | |
456 | * Contact id. | |
ada8a833 | 457 | * |
b2363ea8 | 458 | * @param int $action |
6a488035 | 459 | * |
608e6658 | 460 | * @return array |
a6c01b45 | 461 | * array of contact_id of all related contacts. |
6a488035 | 462 | */ |
00be9182 | 463 | public static function checkMembershipRelationship($membershipId, $contactId, $action = CRM_Core_Action::ADD) { |
6a488035 TO |
464 | $contacts = array(); |
465 | $membershipTypeID = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', $membershipId, 'membership_type_id'); | |
466 | ||
467 | $membershipType = CRM_Member_BAO_MembershipType::getMembershipTypeDetails($membershipTypeID); | |
468 | $relationships = array(); | |
469 | if (isset($membershipType['relationship_type_id'])) { | |
470 | $relationships = CRM_Contact_BAO_Relationship::getRelationship($contactId, | |
471 | CRM_Contact_BAO_Relationship::CURRENT | |
472 | ); | |
473 | if ($action & CRM_Core_Action::UPDATE) { | |
474 | $pastRelationships = CRM_Contact_BAO_Relationship::getRelationship($contactId, | |
475 | CRM_Contact_BAO_Relationship::PAST | |
476 | ); | |
477 | $relationships = array_merge($relationships, $pastRelationships); | |
478 | } | |
479 | } | |
480 | ||
481 | if (!empty($relationships)) { | |
482 | // check for each contact relationships | |
483 | foreach ($relationships as $values) { | |
484 | //get details of the relationship type | |
485 | $relType = array('id' => $values['civicrm_relationship_type_id']); | |
486 | $relValues = array(); | |
487 | CRM_Contact_BAO_RelationshipType::retrieve($relType, $relValues); | |
488 | // Check if contact's relationship type exists in membership type | |
e0556ebe TO |
489 | $relTypeDirs = array(); |
490 | $relTypeIds = explode(CRM_Core_DAO::VALUE_SEPARATOR, $membershipType['relationship_type_id']); | |
6a488035 TO |
491 | $relDirections = explode(CRM_Core_DAO::VALUE_SEPARATOR, $membershipType['relationship_direction']); |
492 | $bidirectional = FALSE; | |
493 | foreach ($relTypeIds as $key => $value) { | |
494 | $relTypeDirs[] = $value . '_' . $relDirections[$key]; | |
495 | if (in_array($value, $relType) && | |
496 | $relValues['name_a_b'] == $relValues['name_b_a'] | |
497 | ) { | |
498 | $bidirectional = TRUE; | |
499 | break; | |
500 | } | |
501 | } | |
502 | $relTypeDir = $values['civicrm_relationship_type_id'] . '_' . $values['rtype']; | |
503 | if ($bidirectional || in_array($relTypeDir, $relTypeDirs)) { | |
504 | // $values['status'] is going to have value for | |
505 | // current or past relationships. | |
506 | $contacts[$values['cid']] = $values['status']; | |
507 | } | |
508 | } | |
509 | } | |
510 | ||
511 | // Sort by contact_id ascending | |
512 | ksort($contacts); | |
513 | return $contacts; | |
514 | } | |
515 | ||
516 | /** | |
fe482240 EM |
517 | * Retrieve DB object based on input parameters. |
518 | * | |
519 | * It also stores all the retrieved values in the default array. | |
6a488035 | 520 | * |
b2363ea8 TO |
521 | * @param array $params |
522 | * (reference ) an assoc array of name/value pairs. | |
523 | * @param array $defaults | |
524 | * (reference ) an assoc array to hold the name / value pairs. | |
6a488035 | 525 | * in a hierarchical manner |
8efea814 | 526 | * |
16b10e64 | 527 | * @return CRM_Member_BAO_Membership |
6a488035 | 528 | */ |
00be9182 | 529 | public static function retrieve(&$params, &$defaults) { |
6a488035 TO |
530 | $membership = new CRM_Member_DAO_Membership(); |
531 | ||
532 | $membership->copyValues($params); | |
533 | ||
534 | if ($membership->find(TRUE)) { | |
535 | CRM_Core_DAO::storeValues($membership, $defaults); | |
536 | ||
537 | //get the membership status and type values. | |
538 | $statusANDType = self::getStatusANDTypeValues($membership->id); | |
539 | foreach (array( | |
e0556ebe | 540 | 'status', |
21dfd5f5 | 541 | 'membership_type', |
e0556ebe | 542 | ) as $fld) { |
6a488035 TO |
543 | $defaults[$fld] = CRM_Utils_Array::value($fld, $statusANDType[$membership->id]); |
544 | } | |
a7488080 | 545 | if (!empty($statusANDType[$membership->id]['is_current_member'])) { |
6a488035 TO |
546 | $defaults['active'] = TRUE; |
547 | } | |
548 | ||
549 | $membership->free(); | |
550 | ||
551 | return $membership; | |
552 | } | |
553 | ||
554 | return NULL; | |
555 | } | |
556 | ||
557 | /** | |
558 | * | |
c490a46a | 559 | * get membership status and membership type values |
6a488035 | 560 | * |
b2363ea8 TO |
561 | * @param int $membershipId |
562 | * Membership id of values to return. | |
6a488035 | 563 | * |
a6c01b45 | 564 | * @return array |
16b10e64 | 565 | * Array of key value pairs |
6a488035 | 566 | */ |
00be9182 | 567 | public static function getStatusANDTypeValues($membershipId) { |
6a488035 TO |
568 | $values = array(); |
569 | if (!$membershipId) { | |
570 | return $values; | |
571 | } | |
572 | $sql = ' | |
573 | SELECT membership.id as id, | |
574 | status.id as status_id, | |
575 | status.label as status, | |
576 | status.is_current_member as is_current_member, | |
577 | type.id as membership_type_id, | |
578 | type.name as membership_type, | |
579 | type.relationship_type_id as relationship_type_id | |
580 | FROM civicrm_membership membership | |
581 | INNER JOIN civicrm_membership_status status ON ( status.id = membership.status_id ) | |
582 | INNER JOIN civicrm_membership_type type ON ( type.id = membership.membership_type_id ) | |
583 | WHERE membership.id = %1'; | |
584 | $dao = CRM_Core_DAO::executeQuery($sql, array(1 => array($membershipId, 'Positive'))); | |
e0556ebe TO |
585 | $properties = array( |
586 | 'status', | |
587 | 'status_id', | |
588 | 'membership_type', | |
589 | 'membership_type_id', | |
590 | 'is_current_member', | |
21dfd5f5 | 591 | 'relationship_type_id', |
e0556ebe | 592 | ); |
6a488035 TO |
593 | while ($dao->fetch()) { |
594 | foreach ($properties as $property) { | |
595 | $values[$dao->id][$property] = $dao->$property; | |
596 | } | |
597 | } | |
598 | ||
599 | return $values; | |
600 | } | |
601 | ||
3506b6cd | 602 | /** |
100fef9d | 603 | * Delete membership. |
f5e53870 | 604 | * Wrapper for most delete calls. Use this unless you JUST want to delete related memberships w/o deleting the parent. |
3506b6cd | 605 | * |
b2363ea8 TO |
606 | * @param int $membershipId |
607 | * Membership id that needs to be deleted. | |
3506b6cd | 608 | * |
3506b6cd | 609 | * |
608e6658 | 610 | * @return int $results id of deleted Membership on success, false otherwise |
3506b6cd | 611 | */ |
00be9182 | 612 | public static function del($membershipId) { |
3506b6cd DG |
613 | //delete related first and then delete parent. |
614 | self::deleteRelatedMemberships($membershipId); | |
d824fb6e | 615 | return self::deleteMembership($membershipId); |
3506b6cd | 616 | } |
d824fb6e | 617 | |
6a488035 | 618 | /** |
100fef9d | 619 | * Delete membership. |
6a488035 | 620 | * |
b2363ea8 TO |
621 | * @param int $membershipId |
622 | * Membership id that needs to be deleted. | |
6a488035 | 623 | * |
6a488035 | 624 | * |
608e6658 | 625 | * @return int $results id of deleted Membership on success, false otherwise |
6a488035 | 626 | */ |
00be9182 | 627 | public static function deleteMembership($membershipId) { |
46d8f506 DL |
628 | // CRM-12147, retrieve membership data before we delete it for hooks |
629 | $params = array('id' => $membershipId); | |
630 | $memValues = array(); | |
631 | $memberships = self::getValues($params, $memValues); | |
3506b6cd | 632 | |
46d8f506 DL |
633 | $membership = $memberships[$membershipId]; |
634 | ||
635 | CRM_Utils_Hook::pre('delete', 'Membership', $membershipId, $memValues); | |
6a488035 TO |
636 | |
637 | $transaction = new CRM_Core_Transaction(); | |
638 | ||
639 | $results = NULL; | |
640 | //delete activity record | |
641 | $activityTypes = CRM_Core_PseudoConstant::activityType(TRUE, FALSE, FALSE, 'name'); | |
642 | ||
643 | $params = array(); | |
e0556ebe TO |
644 | $deleteActivity = FALSE; |
645 | $membershipActivities = array( | |
46d8f506 DL |
646 | 'Membership Signup', |
647 | 'Membership Renewal', | |
648 | 'Change Membership Status', | |
649 | 'Change Membership Type', | |
21dfd5f5 | 650 | 'Membership Renewal Reminder', |
46d8f506 | 651 | ); |
e0556ebe | 652 | foreach ($membershipActivities as $membershipActivity) { |
6a488035 TO |
653 | $activityId = array_search($membershipActivity, $activityTypes); |
654 | if ($activityId) { | |
655 | $params['activity_type_id'][] = $activityId; | |
e0556ebe | 656 | $deleteActivity = TRUE; |
6a488035 TO |
657 | } |
658 | } | |
659 | if ($deleteActivity) { | |
660 | $params['source_record_id'] = $membershipId; | |
46d8f506 | 661 | CRM_Activity_BAO_Activity::deleteActivity($params); |
6a488035 TO |
662 | } |
663 | self::deleteMembershipPayment($membershipId); | |
664 | ||
d0fbc816 | 665 | $results = $membership->delete(); |
6a488035 TO |
666 | $transaction->commit(); |
667 | ||
668 | CRM_Utils_Hook::post('delete', 'Membership', $membership->id, $membership); | |
669 | ||
670 | // delete the recently created Membership | |
671 | $membershipRecent = array( | |
672 | 'id' => $membershipId, | |
673 | 'type' => 'Membership', | |
674 | ); | |
675 | CRM_Utils_Recent::del($membershipRecent); | |
676 | ||
677 | return $results; | |
678 | } | |
679 | ||
3506b6cd | 680 | /** |
fe482240 | 681 | * Delete related memberships. |
3506b6cd DG |
682 | * |
683 | * @param int $ownerMembershipId | |
684 | * @param int $contactId | |
685 | * | |
686 | * @return null | |
3506b6cd | 687 | */ |
00be9182 | 688 | public static function deleteRelatedMemberships($ownerMembershipId, $contactId = NULL) { |
3506b6cd | 689 | if (!$ownerMembershipId && !$contactId) { |
608e6658 | 690 | return FALSE; |
3506b6cd DG |
691 | } |
692 | ||
693 | $membership = new CRM_Member_DAO_Membership(); | |
694 | $membership->owner_membership_id = $ownerMembershipId; | |
695 | ||
696 | if ($contactId) { | |
697 | $membership->contact_id = $contactId; | |
698 | } | |
699 | ||
700 | $membership->find(); | |
701 | while ($membership->fetch()) { | |
702 | //delete related first and then delete parent. | |
703 | self::deleteRelatedMemberships($membership->id); | |
704 | self::deleteMembership($membership->id); | |
705 | } | |
706 | $membership->free(); | |
707 | } | |
708 | ||
6a488035 | 709 | /** |
100fef9d | 710 | * Obtain active/inactive memberships from the list of memberships passed to it. |
6a488035 | 711 | * |
b2363ea8 TO |
712 | * @param array $memberships |
713 | * Membership records. | |
714 | * @param string $status | |
715 | * Active or inactive. | |
6a488035 | 716 | * |
a6c01b45 CW |
717 | * @return array |
718 | * array of memberships based on status | |
6a488035 | 719 | */ |
00be9182 | 720 | public static function activeMembers($memberships, $status = 'active') { |
6a488035 TO |
721 | $actives = array(); |
722 | if ($status == 'active') { | |
723 | foreach ($memberships as $f => $v) { | |
a7488080 | 724 | if (!empty($v['active'])) { |
6a488035 TO |
725 | $actives[$f] = $v; |
726 | } | |
727 | } | |
728 | return $actives; | |
729 | } | |
730 | elseif ($status == 'inactive') { | |
731 | foreach ($memberships as $f => $v) { | |
a7488080 | 732 | if (empty($v['active'])) { |
6a488035 TO |
733 | $actives[$f] = $v; |
734 | } | |
735 | } | |
736 | return $actives; | |
737 | } | |
738 | return NULL; | |
739 | } | |
740 | ||
741 | /** | |
fe482240 | 742 | * Build Membership Block in Contribution Pages. |
6a488035 | 743 | * |
b2363ea8 TO |
744 | * @param CRM_Core_Form $form |
745 | * Form object. | |
746 | * @param int $pageID | |
747 | * Unused?. | |
748 | * @param int $cid | |
749 | * Contact checked for having a current membership for a particular membership. | |
750 | * @param bool $formItems | |
751 | * @param int $selectedMembershipTypeID | |
752 | * Selected membership id. | |
753 | * @param bool $thankPage | |
754 | * Thank you page. | |
e46e9a0b EM |
755 | * @param null $isTest |
756 | * | |
a6c01b45 CW |
757 | * @return bool |
758 | * Is this a separate membership payment | |
6a488035 | 759 | * |
6a488035 | 760 | */ |
608e6658 | 761 | public static function buildMembershipBlock( |
500cfe81 | 762 | &$form, |
353ffa53 TO |
763 | $pageID, |
764 | $cid, | |
765 | $formItems = FALSE, | |
766 | $selectedMembershipTypeID = NULL, | |
767 | $thankPage = FALSE, | |
768 | $isTest = NULL | |
6a488035 TO |
769 | ) { |
770 | ||
771 | $separateMembershipPayment = FALSE; | |
772 | if ($form->_membershipBlock) { | |
773 | $form->_currentMemberships = array(); | |
6a488035 | 774 | |
e0556ebe TO |
775 | $membershipBlock = $form->_membershipBlock; |
776 | $membershipTypeIds = $membershipTypes = $radio = array(); | |
6a488035 TO |
777 | $membershipPriceset = (!empty($form->_priceSetId) && $form->_useForMember) ? TRUE : FALSE; |
778 | ||
779 | $allowAutoRenewMembership = $autoRenewOption = FALSE; | |
780 | $autoRenewMembershipTypeOptions = array(); | |
781 | ||
782 | $paymentProcessor = CRM_Core_PseudoConstant::paymentProcessor(FALSE, FALSE, 'is_recur = 1'); | |
783 | ||
784 | $separateMembershipPayment = CRM_Utils_Array::value('is_separate_payment', $membershipBlock); | |
785 | ||
786 | if ($membershipPriceset) { | |
787 | foreach ($form->_priceSet['fields'] as $pField) { | |
788 | if (empty($pField['options'])) { | |
789 | continue; | |
790 | } | |
791 | foreach ($pField['options'] as $opId => $opValues) { | |
a7488080 | 792 | if (empty($opValues['membership_type_id'])) { |
6a488035 TO |
793 | continue; |
794 | } | |
795 | $membershipTypeIds[$opValues['membership_type_id']] = $opValues['membership_type_id']; | |
796 | } | |
797 | } | |
798 | } | |
a7488080 | 799 | elseif (!empty($membershipBlock['membership_types'])) { |
6a488035 TO |
800 | $membershipTypeIds = explode(',', $membershipBlock['membership_types']); |
801 | } | |
802 | ||
803 | if (!empty($membershipTypeIds)) { | |
804 | //set status message if wrong membershipType is included in membershipBlock | |
805 | if (isset($form->_mid) && !$membershipPriceset) { | |
806 | $membershipTypeID = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', | |
807 | $form->_mid, | |
808 | 'membership_type_id' | |
809 | ); | |
810 | if (!in_array($membershipTypeID, $membershipTypeIds)) { | |
811 | CRM_Core_Session::setStatus(ts("Oops. The membership you're trying to renew appears to be invalid. Contact your site administrator if you need assistance. If you continue, you will be issued a new membership."), ts('Invalid Membership'), 'error'); | |
812 | } | |
813 | } | |
814 | ||
815 | $membershipTypeValues = self::buildMembershipTypeValues($form, $membershipTypeIds); | |
816 | $form->_membershipTypeValues = $membershipTypeValues; | |
817 | $endDate = NULL; | |
818 | foreach ($membershipTypeIds as $value) { | |
819 | $memType = $membershipTypeValues[$value]; | |
820 | if ($selectedMembershipTypeID != NULL) { | |
821 | if ($memType['id'] == $selectedMembershipTypeID) { | |
822 | $form->assign('minimum_fee', | |
823 | CRM_Utils_Array::value('minimum_fee', $memType) | |
824 | ); | |
825 | $form->assign('membership_name', $memType['name']); | |
826 | if (!$thankPage && $cid) { | |
827 | $membership = new CRM_Member_DAO_Membership(); | |
828 | $membership->contact_id = $cid; | |
829 | $membership->membership_type_id = $memType['id']; | |
830 | if ($membership->find(TRUE)) { | |
831 | $form->assign('renewal_mode', TRUE); | |
832 | $memType['current_membership'] = $membership->end_date; | |
833 | $form->_currentMemberships[$membership->membership_type_id] = $membership->membership_type_id; | |
834 | } | |
835 | } | |
836 | $membershipTypes[] = $memType; | |
837 | } | |
838 | } | |
839 | elseif ($memType['is_active']) { | |
840 | $javascriptMethod = NULL; | |
841 | $allowAutoRenewOpt = 1; | |
e0556ebe | 842 | if (is_array($form->_paymentProcessors)) { |
6a488035 TO |
843 | foreach ($form->_paymentProcessors as $id => $val) { |
844 | if (!$val['is_recur']) { | |
e0556ebe | 845 | $allowAutoRenewOpt = 0; |
6a488035 | 846 | continue; |
e0556ebe | 847 | } |
6a488035 TO |
848 | } |
849 | } | |
850 | ||
851 | $javascriptMethod = array('onclick' => "return showHideAutoRenew( this.value );"); | |
e0556ebe | 852 | $autoRenewMembershipTypeOptions["autoRenewMembershipType_{$value}"] = (int) $allowAutoRenewOpt * CRM_Utils_Array::value($value, CRM_Utils_Array::value('auto_renew', $form->_membershipBlock));; |
6a488035 TO |
853 | |
854 | if ($allowAutoRenewOpt) { | |
855 | $allowAutoRenewMembership = TRUE; | |
856 | } | |
857 | ||
858 | //add membership type. | |
859 | $radio[$memType['id']] = $form->createElement('radio', NULL, NULL, NULL, | |
860 | $memType['id'], $javascriptMethod | |
861 | ); | |
862 | if ($cid) { | |
863 | $membership = new CRM_Member_DAO_Membership(); | |
864 | $membership->contact_id = $cid; | |
865 | $membership->membership_type_id = $memType['id']; | |
866 | ||
867 | //show current membership, skip pending and cancelled membership records, | |
868 | //because we take first membership record id for renewal | |
869 | $membership->whereAdd('status_id != 5 AND status_id !=6'); | |
870 | ||
871 | if (!is_null($isTest)) { | |
872 | $membership->is_test = $isTest; | |
873 | } | |
874 | ||
875 | //CRM-4297 | |
876 | $membership->orderBy('end_date DESC'); | |
877 | ||
878 | if ($membership->find(TRUE)) { | |
879 | if (!$membership->end_date) { | |
880 | unset($radio[$memType['id']]); | |
881 | $form->assign('islifetime', TRUE); | |
882 | continue; | |
883 | } | |
884 | $form->assign('renewal_mode', TRUE); | |
885 | $form->_currentMemberships[$membership->membership_type_id] = $membership->membership_type_id; | |
886 | $memType['current_membership'] = $membership->end_date; | |
887 | if (!$endDate) { | |
888 | $endDate = $memType['current_membership']; | |
889 | $form->_defaultMemTypeId = $memType['id']; | |
890 | } | |
891 | if ($memType['current_membership'] < $endDate) { | |
892 | $endDate = $memType['current_membership']; | |
893 | $form->_defaultMemTypeId = $memType['id']; | |
894 | } | |
895 | } | |
896 | } | |
897 | $membershipTypes[] = $memType; | |
898 | } | |
899 | } | |
900 | } | |
901 | ||
902 | $form->assign('showRadio', $formItems); | |
903 | if ($formItems) { | |
904 | if (!$membershipPriceset) { | |
905 | if (!$membershipBlock['is_required']) { | |
906 | $form->assign('showRadioNoThanks', TRUE); | |
907 | $radio[''] = $form->createElement('radio', NULL, NULL, NULL, 'no_thanks', NULL); | |
908 | $form->addGroup($radio, 'selectMembership', NULL); | |
909 | } | |
910 | elseif ($membershipBlock['is_required'] && count($radio) == 1) { | |
911 | $temp = array_keys($radio); | |
912 | $form->add('hidden', 'selectMembership', $temp[0], array('id' => 'selectMembership')); | |
913 | $form->assign('singleMembership', TRUE); | |
914 | $form->assign('showRadio', FALSE); | |
915 | } | |
916 | else { | |
917 | $form->addGroup($radio, 'selectMembership', NULL); | |
918 | } | |
919 | ||
920 | $form->addRule('selectMembership', ts('Please select one of the memberships.'), 'required'); | |
921 | } | |
922 | else { | |
9da8dc8c | 923 | $autoRenewOption = CRM_Price_BAO_PriceSet::checkAutoRenewForPriceSet($form->_priceSetId); |
6a488035 TO |
924 | $form->assign('autoRenewOption', $autoRenewOption); |
925 | } | |
926 | ||
927 | if (!$form->_values['is_pay_later'] && is_array($form->_paymentProcessors) && ($allowAutoRenewMembership || $autoRenewOption)) { | |
928 | $form->addElement('checkbox', 'auto_renew', ts('Please renew my membership automatically.')); | |
929 | } | |
930 | ||
931 | } | |
932 | ||
933 | $form->assign('membershipBlock', $membershipBlock); | |
934 | $form->assign('membershipTypes', $membershipTypes); | |
935 | $form->assign('allowAutoRenewMembership', $allowAutoRenewMembership); | |
936 | $form->assign('autoRenewMembershipTypeOptions', json_encode($autoRenewMembershipTypeOptions)); | |
937 | ||
938 | //give preference to user submitted auto_renew value. | |
939 | $takeUserSubmittedAutoRenew = (!empty($_POST) || $form->isSubmitted()) ? TRUE : FALSE; | |
940 | $form->assign('takeUserSubmittedAutoRenew', $takeUserSubmittedAutoRenew); | |
941 | } | |
942 | ||
943 | return $separateMembershipPayment; | |
944 | } | |
945 | ||
946 | /** | |
fe482240 | 947 | * Return Membership Block info in Contribution Pages. |
6a488035 | 948 | * |
b2363ea8 TO |
949 | * @param int $pageID |
950 | * Contribution page id. | |
e46e9a0b EM |
951 | * |
952 | * @return array|null | |
6a488035 | 953 | * |
6a488035 | 954 | */ |
00be9182 | 955 | public static function getMembershipBlock($pageID) { |
e0556ebe TO |
956 | $membershipBlock = array(); |
957 | $dao = new CRM_Member_DAO_MembershipBlock(); | |
6a488035 TO |
958 | $dao->entity_table = 'civicrm_contribution_page'; |
959 | ||
960 | $dao->entity_id = $pageID; | |
961 | $dao->is_active = 1; | |
962 | if ($dao->find(TRUE)) { | |
963 | CRM_Core_DAO::storeValues($dao, $membershipBlock); | |
a7488080 | 964 | if (!empty($membershipBlock['membership_types'])) { |
6a488035 TO |
965 | $membershipTypes = unserialize($membershipBlock['membership_types']); |
966 | if (!is_array($membershipTypes)) { | |
967 | return $membershipBlock; | |
968 | } | |
969 | $memTypes = array(); | |
970 | foreach ($membershipTypes as $key => $value) { | |
971 | $membershipBlock['auto_renew'][$key] = $value; | |
972 | $memTypes[$key] = $key; | |
973 | } | |
974 | $membershipBlock['membership_types'] = implode(',', $memTypes); | |
975 | } | |
976 | } | |
977 | else { | |
978 | return NULL; | |
979 | } | |
980 | ||
981 | return $membershipBlock; | |
982 | } | |
983 | ||
984 | /** | |
fe482240 | 985 | * Return a current membership of given contact. |
c490a46a | 986 | * NB: if more than one membership meets criteria, a randomly selected one is returned. |
6a488035 | 987 | * |
b2363ea8 TO |
988 | * @param int $contactID |
989 | * Contact id. | |
990 | * @param int $memType | |
991 | * Membership type, null to retrieve all types. | |
6a488035 | 992 | * @param int $isTest |
b2363ea8 TO |
993 | * @param int $membershipId |
994 | * If provided, then determine if it is current. | |
995 | * @param bool $onlySameParentOrg | |
996 | * True if only Memberships with same parent org as the $memType wanted, false otherwise. | |
e46e9a0b EM |
997 | * |
998 | * @return array|bool | |
6a488035 | 999 | */ |
00be9182 | 1000 | public static function getContactMembership($contactID, $memType, $isTest, $membershipId = NULL, $onlySameParentOrg = FALSE) { |
6a488035 TO |
1001 | $dao = new CRM_Member_DAO_Membership(); |
1002 | if ($membershipId) { | |
1003 | $dao->id = $membershipId; | |
1004 | } | |
1005 | $dao->contact_id = $contactID; | |
1006 | $dao->membership_type_id = $memType; | |
1007 | ||
1008 | //fetch proper membership record. | |
1009 | if ($isTest) { | |
1010 | $dao->is_test = $isTest; | |
1011 | } | |
1012 | else { | |
1013 | $dao->whereAdd('is_test IS NULL OR is_test = 0'); | |
1014 | } | |
5624f515 | 1015 | |
6a488035 | 1016 | //avoid pending membership as current membership: CRM-3027 |
b5a62499 PN |
1017 | $statusIds[] = array_search('Pending', CRM_Member_PseudoConstant::membershipStatus()); |
1018 | if (!$membershipId) { | |
7ff60806 PN |
1019 | // CRM-15475 |
1020 | $statusIds[] = array_search( | |
4c16123d | 1021 | 'Cancelled', |
7ff60806 | 1022 | CRM_Member_PseudoConstant::membershipStatus( |
4c16123d EM |
1023 | NULL, |
1024 | " name = 'Cancelled' ", | |
1025 | 'name', | |
1026 | FALSE, | |
7ff60806 PN |
1027 | TRUE |
1028 | ) | |
1029 | ); | |
b5a62499 | 1030 | } |
e0556ebe | 1031 | $dao->whereAdd('status_id NOT IN ( ' . implode(',', $statusIds) . ')'); |
5624f515 | 1032 | |
6a488035 TO |
1033 | // order by start date to find most recent membership first, CRM-4545 |
1034 | $dao->orderBy('start_date DESC'); | |
1035 | ||
1036 | // CRM-8141 | |
1037 | if ($onlySameParentOrg && $memType) { | |
1038 | // require the same parent org as the $memType | |
1039 | $params = array('id' => $memType); | |
5901ddf9 | 1040 | $membershipType = array(); |
6a488035 TO |
1041 | if (CRM_Member_BAO_MembershipType::retrieve($params, $membershipType)) { |
1042 | $memberTypesSameParentOrg = CRM_Member_BAO_MembershipType::getMembershipTypesByOrg($membershipType['member_of_contact_id']); | |
1043 | $memberTypesSameParentOrgList = implode(',', array_keys($memberTypesSameParentOrg)); | |
1044 | $dao->whereAdd('membership_type_id IN (' . $memberTypesSameParentOrgList . ')'); | |
1045 | } | |
1046 | } | |
1047 | ||
1048 | if ($dao->find(TRUE)) { | |
1049 | $membership = array(); | |
1050 | CRM_Core_DAO::storeValues($dao, $membership); | |
1051 | $membership['is_current_member'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipStatus', | |
1052 | $membership['status_id'], | |
1053 | 'is_current_member', 'id' | |
1054 | ); | |
1055 | return $membership; | |
1056 | } | |
1057 | ||
1058 | // CRM-8141 | |
1059 | if ($onlySameParentOrg && $memType) { | |
1060 | // see if there is a membership that has same parent as $memType but different parent than $membershipID | |
5682e889 | 1061 | if ($dao->id && CRM_Core_Permission::check('edit memberships')) { |
1062 | // CRM-10016, This is probably a backend renewal, and make sure we return the same membership thats being renewed. | |
e0556ebe | 1063 | $dao->whereAdd(); |
5682e889 | 1064 | } |
1065 | else { | |
1066 | unset($dao->id); | |
1067 | } | |
6a488035 TO |
1068 | |
1069 | unset($dao->membership_type_id); | |
1070 | if ($dao->find(TRUE)) { | |
1071 | $membership = array(); | |
1072 | CRM_Core_DAO::storeValues($dao, $membership); | |
1073 | $membership['is_current_member'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipStatus', | |
1074 | $membership['status_id'], | |
1075 | 'is_current_member', 'id' | |
1076 | ); | |
1077 | return $membership; | |
1078 | } | |
1079 | } | |
1080 | return FALSE; | |
1081 | } | |
1082 | ||
1083 | /** | |
fe482240 | 1084 | * Combine all the importable fields from the lower levels object. |
6a488035 | 1085 | * |
b2363ea8 TO |
1086 | * @param string $contactType |
1087 | * Contact type. | |
1088 | * @param bool $status | |
6a488035 | 1089 | * |
a6c01b45 CW |
1090 | * @return array |
1091 | * array of importable Fields | |
6a488035 | 1092 | */ |
00be9182 | 1093 | public static function &importableFields($contactType = 'Individual', $status = TRUE) { |
6a488035 TO |
1094 | if (!self::$_importableFields) { |
1095 | if (!self::$_importableFields) { | |
1096 | self::$_importableFields = array(); | |
1097 | } | |
1098 | ||
1099 | if (!$status) { | |
1100 | $fields = array('' => array('title' => '- ' . ts('do not import') . ' -')); | |
1101 | } | |
1102 | else { | |
1103 | $fields = array('' => array('title' => '- ' . ts('Membership Fields') . ' -')); | |
1104 | } | |
1105 | ||
1106 | $tmpFields = CRM_Member_DAO_Membership::import(); | |
1107 | $contactFields = CRM_Contact_BAO_Contact::importableFields($contactType, NULL); | |
1108 | ||
1109 | // Using new Dedupe rule. | |
1110 | $ruleParams = array( | |
1111 | 'contact_type' => $contactType, | |
e0556ebe | 1112 | 'used' => 'Unsupervised', |
6a488035 TO |
1113 | ); |
1114 | $fieldsArray = CRM_Dedupe_BAO_Rule::dedupeRuleFields($ruleParams); | |
1115 | ||
1116 | $tmpContactField = array(); | |
1117 | if (is_array($fieldsArray)) { | |
1118 | foreach ($fieldsArray as $value) { | |
1119 | $customFieldId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomField', | |
1120 | $value, | |
1121 | 'id', | |
1122 | 'column_name' | |
1123 | ); | |
1124 | $value = $customFieldId ? 'custom_' . $customFieldId : $value; | |
1125 | $tmpContactField[trim($value)] = CRM_Utils_Array::value(trim($value), $contactFields); | |
1126 | if (!$status) { | |
1127 | $title = $tmpContactField[trim($value)]['title'] . " " . ts('(match to contact)'); | |
1128 | } | |
1129 | else { | |
1130 | $title = $tmpContactField[trim($value)]['title']; | |
1131 | } | |
1132 | $tmpContactField[trim($value)]['title'] = $title; | |
1133 | } | |
1134 | } | |
1135 | $tmpContactField['external_identifier'] = $contactFields['external_identifier']; | |
1136 | $tmpContactField['external_identifier']['title'] = $contactFields['external_identifier']['title'] . " " . ts('(match to contact)'); | |
1137 | ||
1138 | $tmpFields['membership_contact_id']['title'] = $tmpFields['membership_contact_id']['title'] . " " . ts('(match to contact)');; | |
1139 | ||
1140 | $fields = array_merge($fields, $tmpContactField); | |
1141 | $fields = array_merge($fields, $tmpFields); | |
1142 | $fields = array_merge($fields, CRM_Core_BAO_CustomField::getFieldsForImport('Membership')); | |
1143 | self::$_importableFields = $fields; | |
1144 | } | |
1145 | return self::$_importableFields; | |
1146 | } | |
1147 | ||
1148 | /** | |
fe482240 | 1149 | * Get all exportable fields. |
6a488035 TO |
1150 | * |
1151 | * @retun array return array of all exportable fields | |
6a488035 | 1152 | */ |
00be9182 | 1153 | public static function &exportableFields() { |
6a488035 | 1154 | $expFieldMembership = CRM_Member_DAO_Membership::export(); |
6a488035 TO |
1155 | |
1156 | $expFieldsMemType = CRM_Member_DAO_MembershipType::export(); | |
e0556ebe TO |
1157 | $fields = array_merge($expFieldMembership, $expFieldsMemType); |
1158 | $fields = array_merge($fields, $expFieldMembership); | |
6a488035 | 1159 | $membershipStatus = array( |
e0556ebe TO |
1160 | 'membership_status' => array( |
1161 | 'title' => 'Membership Status', | |
6a488035 TO |
1162 | 'name' => 'membership_status', |
1163 | 'type' => CRM_Utils_Type::T_STRING, | |
1164 | 'where' => 'civicrm_membership_status.name', | |
21dfd5f5 | 1165 | ), |
e0556ebe | 1166 | ); |
6a488035 TO |
1167 | //CRM-6161 fix for customdata export |
1168 | $fields = array_merge($fields, $membershipStatus, CRM_Core_BAO_CustomField::getFieldsForImport('Membership')); | |
1169 | return $fields; | |
1170 | } | |
1171 | ||
1172 | /** | |
100fef9d | 1173 | * Get membership joins/renewals for a specified membership |
4e636a74 AH |
1174 | * type. Specifically, retrieves a count of memberships whose "Membership |
1175 | * Signup" or "Membership Renewal" activity falls in the given date range. | |
8ef12e64 | 1176 | * Dates match the pattern "yyyy-mm-dd". |
6a488035 | 1177 | * |
b2363ea8 TO |
1178 | * @param int $membershipTypeId |
1179 | * Membership type id. | |
1180 | * @param int $startDate | |
1181 | * Date on which to start counting. | |
1182 | * @param int $endDate | |
1183 | * Date on which to end counting. | |
e46e9a0b EM |
1184 | * @param bool|int $isTest if true, membership is for a test site |
1185 | * @param bool|int $isOwner if true, only retrieve membership records for owners //LCD | |
6a488035 | 1186 | * |
df8d3074 | 1187 | * @return int |
a6c01b45 | 1188 | * the number of members of type $membershipTypeId whose |
688d37c6 | 1189 | * start_date is between $startDate and $endDate |
6a488035 | 1190 | */ |
6a488035 | 1191 | public static function getMembershipStarts($membershipTypeId, $startDate, $endDate, $isTest = 0, $isOwner = 0) { |
8ef12e64 | 1192 | |
4e636a74 AH |
1193 | $testClause = 'membership.is_test = 1'; |
1194 | if (!$isTest) { | |
1195 | $testClause = '( membership.is_test IS NULL OR membership.is_test = 0 )'; | |
1196 | } | |
8ef12e64 | 1197 | |
4e636a74 AH |
1198 | if (!self::$_signupActType || !self::$_renewalActType) { |
1199 | self::_getActTypes(); | |
1200 | } | |
8ef12e64 | 1201 | |
4e636a74 AH |
1202 | if (!self::$_signupActType || !self::$_renewalActType) { |
1203 | return 0; | |
1204 | } | |
1205 | ||
1206 | $query = " | |
1207 | SELECT COUNT(DISTINCT membership.id) as member_count | |
1208 | FROM civicrm_membership membership | |
1209 | INNER JOIN civicrm_activity activity ON (activity.source_record_id = membership.id AND activity.activity_type_id in (%1, %2)) | |
1210 | INNER JOIN civicrm_membership_status status ON ( membership.status_id = status.id AND status.is_current_member = 1 ) | |
1211 | INNER JOIN civicrm_contact contact ON ( contact.id = membership.contact_id AND contact.is_deleted = 0 ) | |
1212 | WHERE membership.membership_type_id = %3 | |
1213 | AND activity.activity_date_time >= '$startDate' AND activity.activity_date_time <= '$endDate 23:59:59' | |
1214 | AND {$testClause}"; | |
8ef12e64 | 1215 | |
6a488035 | 1216 | $query .= ($isOwner) ? ' AND owner_membership_id IS NULL' : ''; |
4e636a74 AH |
1217 | |
1218 | $params = array( | |
1219 | 1 => array(self::$_signupActType, 'Integer'), | |
1220 | 2 => array(self::$_renewalActType, 'Integer'), | |
8ef12e64 | 1221 | 3 => array($membershipTypeId, 'Integer'), |
6a488035 | 1222 | ); |
8ef12e64 | 1223 | |
6a488035 | 1224 | $memberCount = CRM_Core_DAO::singleValueQuery($query, $params); |
e0556ebe | 1225 | return (int) $memberCount; |
6a488035 TO |
1226 | } |
1227 | ||
1228 | /** | |
100fef9d | 1229 | * Get a count of membership for a specified membership type, |
8ef12e64 | 1230 | * optionally for a specified date. The date must have the form yyyy-mm-dd. |
6a488035 TO |
1231 | * |
1232 | * If $date is omitted, this function counts as a member anyone whose | |
1233 | * membership status_id indicates they're a current member. | |
1234 | * If $date is given, this function counts as a member anyone who: | |
1235 | * -- Has a start_date before $date and end_date after $date, or | |
1236 | * -- Has a start_date before $date and is currently a member, as indicated | |
1237 | * by the the membership's status_id. | |
1238 | * The second condition takes care of records that have no end_date. These | |
1239 | * are assumed to be lifetime memberships. | |
1240 | * | |
b2363ea8 TO |
1241 | * @param int $membershipTypeId |
1242 | * Membership type id. | |
1243 | * @param string $date | |
1244 | * The date for which to retrieve the count. | |
e46e9a0b EM |
1245 | * @param bool|int $isTest if true, membership is for a test site |
1246 | * @param bool|int $isOwner if true, only retrieve membership records for owners //LCD | |
6a488035 | 1247 | * |
72b3a70c CW |
1248 | * @return int |
1249 | * the number of members of type $membershipTypeId as of $date. | |
6a488035 TO |
1250 | */ |
1251 | public static function getMembershipCount($membershipTypeId, $date = NULL, $isTest = 0, $isOwner = 0) { | |
4e636a74 AH |
1252 | if (!CRM_Utils_Rule::date($date)) { |
1253 | CRM_Core_Error::fatal(ts('Invalid date "%1" (must have form yyyy-mm-dd).', array(1 => $date))); | |
6a488035 TO |
1254 | } |
1255 | ||
e0556ebe TO |
1256 | $params = array( |
1257 | 1 => array($membershipTypeId, 'Integer'), | |
6a488035 TO |
1258 | 2 => array($isTest, 'Boolean'), |
1259 | ); | |
1260 | $query = "SELECT count(civicrm_membership.id ) as member_count | |
1261 | FROM civicrm_membership left join civicrm_membership_status on ( civicrm_membership.status_id = civicrm_membership_status.id ) | |
1262 | WHERE civicrm_membership.membership_type_id = %1 | |
1263 | AND civicrm_membership.contact_id NOT IN (SELECT id FROM civicrm_contact WHERE is_deleted = 1) | |
1264 | AND civicrm_membership.is_test = %2"; | |
1265 | if (!$date) { | |
1266 | $query .= " AND civicrm_membership_status.is_current_member = 1"; | |
1267 | } | |
1268 | else { | |
6a488035 TO |
1269 | $query .= " AND civicrm_membership.start_date <= '$date' AND civicrm_membership_status.is_current_member = 1"; |
1270 | } | |
1271 | // LCD | |
1272 | $query .= ($isOwner) ? ' AND owner_membership_id IS NULL' : ''; | |
1273 | $memberCount = CRM_Core_DAO::singleValueQuery($query, $params); | |
e0556ebe | 1274 | return (int) $memberCount; |
6a488035 TO |
1275 | } |
1276 | ||
1277 | /** | |
fe482240 | 1278 | * Function check the status of the membership before adding membership for a contact. |
6a488035 | 1279 | * |
b2363ea8 TO |
1280 | * @param int $contactId |
1281 | * Contact id. | |
6a488035 | 1282 | * |
e46e9a0b | 1283 | * @return int |
6a488035 | 1284 | */ |
00be9182 | 1285 | public static function statusAvailabilty($contactId) { |
6a488035 TO |
1286 | $membership = new CRM_Member_DAO_MembershipStatus(); |
1287 | $membership->whereAdd('is_active=1'); | |
c905ba98 | 1288 | return $membership->count(); |
6a488035 TO |
1289 | } |
1290 | ||
1291 | /** | |
fe482240 | 1292 | * Process the Memberships. |
6a488035 | 1293 | * |
b2363ea8 TO |
1294 | * @param array $membershipParams |
1295 | * Array of membership fields. | |
1296 | * @param int $contactID | |
1297 | * Contact id. | |
1298 | * @param CRM_Contribute_Form_Contribution_Confirm $form | |
1299 | * Confirmation form object. | |
e46e9a0b | 1300 | * |
100fef9d | 1301 | * @param array $premiumParams |
e46e9a0b EM |
1302 | * @param null $customFieldsFormatted |
1303 | * @param null $includeFieldTypes | |
6a488035 | 1304 | * |
fa9d0451 | 1305 | * @param array $membershipDetails |
705b4205 | 1306 | * |
d25e4224 | 1307 | * @param array $membershipTypeIDs |
fa9d0451 EM |
1308 | * |
1309 | * @param bool $isPaidMembership | |
d25e4224 | 1310 | * @param array $membershipID |
705b4205 | 1311 | * |
38b4a5fe EM |
1312 | * @param $isProcessSeparateMembershipTransaction |
1313 | * | |
100fef9d | 1314 | * @param int $defaultContributionTypeID |
b2363ea8 TO |
1315 | * @param array $membershipLineItems |
1316 | * Line items specific to membership payment that is separate to contribution. | |
c2b5a0af | 1317 | * @param $isPayLater |
705b4205 | 1318 | * |
c2b5a0af | 1319 | * @throws \CRM_Core_Exception |
6a488035 | 1320 | */ |
500cfe81 TO |
1321 | public static function postProcessMembership( |
1322 | $membershipParams, $contactID, &$form, $premiumParams, | |
353ffa53 TO |
1323 | $customFieldsFormatted = NULL, $includeFieldTypes = NULL, $membershipDetails, $membershipTypeIDs, $isPaidMembership, $membershipID, |
1324 | $isProcessSeparateMembershipTransaction, $defaultContributionTypeID, $membershipLineItems, $isPayLater) { | |
e0556ebe TO |
1325 | $result = $membershipContribution = NULL; |
1326 | $isTest = CRM_Utils_Array::value('is_test', $membershipParams, FALSE); | |
f5d25ee9 | 1327 | $errors = $createdMemberships = array(); |
3c0201c9 | 1328 | |
cc789d46 EM |
1329 | //@todo move this into the calling function & pass in the correct financialTypeID |
1330 | if (isset($paymentParams['financial_type'])) { | |
1331 | $financialTypeID = $paymentParams['financial_type']; | |
1332 | } | |
1333 | else { | |
1334 | $financialTypeID = $defaultContributionTypeID; | |
1335 | } | |
1336 | ||
f990d7e8 | 1337 | if (CRM_Utils_Array::value('membership_source', $form->_params)) { |
1338 | $membershipParams['contribution_source'] = $form->_params['membership_source']; | |
1339 | } | |
1340 | ||
fa9d0451 | 1341 | if ($isPaidMembership) { |
6a488035 TO |
1342 | $result = CRM_Contribute_BAO_Contribution_Utils::processConfirm($form, $membershipParams, |
1343 | $premiumParams, $contactID, | |
cc789d46 EM |
1344 | $financialTypeID, |
1345 | 'membership', | |
1346 | array(), | |
1347 | $isTest, | |
1348 | $isPayLater | |
6a488035 | 1349 | ); |
d45686b0 EM |
1350 | if (is_a($result[1], 'CRM_Core_Error')) { |
1351 | $errors[1] = CRM_Core_Error::getMessages($result[1]); | |
6a488035 | 1352 | } |
d45686b0 EM |
1353 | elseif (!empty($result[1])) { |
1354 | // Save the contribution ID so that I can be used in email receipts | |
1355 | // For example, if you need to generate a tax receipt for the donation only. | |
1356 | $form->_values['contribution_other_id'] = $result[1]->id; | |
1357 | //note that this will be over-written if we are using a separate membership transaction. Otherwise there is only one | |
1358 | $membershipContribution = $result[1]; | |
6a488035 | 1359 | } |
6a488035 | 1360 | } |
6a488035 | 1361 | |
38b4a5fe | 1362 | if ($isProcessSeparateMembershipTransaction) { |
d45686b0 | 1363 | try { |
866f6e8e | 1364 | $lineItems = $form->_lineItem = $membershipLineItems; |
919e8652 | 1365 | if (empty($form->_params['auto_renew']) && !empty($membershipParams['is_recur'])) { |
1366 | unset($membershipParams['is_recur']); | |
1367 | } | |
5624f515 | 1368 | $membershipContribution = self::processSecondaryFinancialTransaction($contactID, $form, $membershipParams, $isTest, $membershipLineItems, CRM_Utils_Array::value('minimum_fee', $membershipDetails, 0), CRM_Utils_Array::value('financial_type_id', $membershipDetails)); |
6a488035 | 1369 | } |
d45686b0 EM |
1370 | catch (CRM_Core_Exception $e) { |
1371 | $errors[2] = $e->getMessage(); | |
1372 | $membershipContribution = NULL; | |
6a488035 TO |
1373 | } |
1374 | } | |
1375 | ||
8d65cef7 | 1376 | $membership = NULL; |
423c9872 | 1377 | if (!empty($membershipContribution) && !is_a($membershipContribution, 'CRM_Core_Error')) { |
dd9e2b05 EM |
1378 | $membershipContributionID = $membershipContribution->id; |
1379 | } | |
423c9872 C |
1380 | |
1381 | //@todo - why is this nested so deep? it seems like it could be just set on the calling function on the form layer | |
1382 | if (isset($membershipParams['onbehalf']) && !empty($membershipParams['onbehalf']['member_campaign_id'])) { | |
1383 | $form->_params['campaign_id'] = $membershipParams['onbehalf']['member_campaign_id']; | |
1384 | } | |
1385 | //@todo it should no longer be possible for it to get to this point & membership to not be an array | |
6e92ff36 | 1386 | if (is_array($membershipTypeIDs) && !empty($membershipContributionID)) { |
423c9872 | 1387 | $typesTerms = CRM_Utils_Array::value('types_terms', $membershipParams, array()); |
d25e4224 | 1388 | foreach ($membershipTypeIDs as $memType) { |
423c9872 C |
1389 | $numTerms = CRM_Utils_Array::value($memType, $typesTerms, 1); |
1390 | $createdMemberships[$memType] = self::createOrRenewMembership($membershipParams, $contactID, $customFieldsFormatted, $membershipID, $memType, $isTest, $numTerms, $membershipContribution, $form); | |
6a488035 | 1391 | } |
423c9872 C |
1392 | if ($form->_priceSetId && !empty($form->_useForMember) && !empty($form->_lineItem)) { |
1393 | foreach ($form->_lineItem[$form->_priceSetId] as & $priceFieldOp) { | |
1394 | if (!empty($priceFieldOp['membership_type_id']) && | |
1395 | isset($createdMemberships[$priceFieldOp['membership_type_id']]) | |
1396 | ) { | |
1397 | $membershipOb = $createdMemberships[$priceFieldOp['membership_type_id']]; | |
3b85fc04 PN |
1398 | $priceFieldOp['start_date'] = $membershipOb->start_date ? CRM_Utils_Date::customFormat($membershipOb->start_date, '%B %E%f, %Y') : '-'; |
1399 | $priceFieldOp['end_date'] = $membershipOb->end_date ? CRM_Utils_Date::customFormat($membershipOb->end_date, '%B %E%f, %Y') : '-'; | |
423c9872 C |
1400 | } |
1401 | else { | |
1402 | $priceFieldOp['start_date'] = $priceFieldOp['end_date'] = 'N/A'; | |
6a488035 | 1403 | } |
6a488035 | 1404 | } |
423c9872 C |
1405 | $form->_values['lineItem'] = $form->_lineItem; |
1406 | $form->assign('lineItem', $form->_lineItem); | |
6a488035 | 1407 | } |
6a488035 TO |
1408 | } |
1409 | ||
1410 | if (!empty($errors)) { | |
15c3308b | 1411 | $message = self::compileErrorMessage($errors); |
93a11cd6 | 1412 | throw new CRM_Core_Exception($message); |
6a488035 | 1413 | } |
8d65cef7 AC |
1414 | $form->_params['createdMembershipIDs'] = array(); |
1415 | ||
1416 | // CRM-7851 - Moved after processing Payment Errors | |
15c3308b | 1417 | //@todo - the reasoning for this being here seems a little outdated |
8d65cef7 AC |
1418 | foreach ($createdMemberships as $createdMembership) { |
1419 | CRM_Core_BAO_CustomValueTable::postProcess( | |
1420 | $form->_params, | |
1421 | CRM_Core_DAO::$_nullArray, | |
1422 | 'civicrm_membership', | |
1423 | $createdMembership->id, | |
1424 | 'Membership' | |
1425 | ); | |
1426 | $form->_params['createdMembershipIDs'][] = $createdMembership->id; | |
1427 | } | |
e0556ebe | 1428 | if (count($createdMemberships) == 1) { |
1f4d7bcb | 1429 | //presumably this is only relevant for exactly 1 membership |
12dac866 | 1430 | $form->_params['membershipID'] = $createdMembership->id; |
1f4d7bcb | 1431 | } |
6a488035 | 1432 | |
12dac866 | 1433 | //CRM-15232: Check if membership is created and on the basis of it use |
1434 | //membership reciept template to send payment reciept | |
1435 | if (count($createdMemberships)) { | |
1436 | $form->_values['isMembership'] = TRUE; | |
1437 | } | |
6a488035 TO |
1438 | if ($form->_contributeMode == 'notify') { |
1439 | if ($form->_values['is_monetary'] && $form->_amount > 0.0 && !$form->_params['is_pay_later']) { | |
dd9e2b05 | 1440 | // call postProcess hook before leaving |
6a488035 TO |
1441 | $form->postProcessHook(); |
1442 | // this does not return | |
1443 | $payment = CRM_Core_Payment::singleton($form->_mode, $form->_paymentProcessor, $form); | |
1444 | $payment->doTransferCheckout($form->_params, 'contribute'); | |
1445 | } | |
1446 | } | |
1447 | ||
dd9e2b05 EM |
1448 | if (isset($membershipContributionID)) { |
1449 | $form->_values['contribution_id'] = $membershipContributionID; | |
6a488035 TO |
1450 | } |
1451 | ||
ef26b43b EM |
1452 | // Refer to CRM-16737. Payment processors 'should' return payment_status_id |
1453 | // to denote the outcome of the transaction. | |
1454 | // | |
1455 | // In 4.7 trxn_id will no longer denote the outcome & all processor transactions must return an array | |
1456 | // containing payment_status_id. | |
1457 | // In 4.6 support (such as there was) for other ways of denoting payment outcome is retained but the use | |
1458 | // of payment_status_id is strongly encouraged. | |
a7488080 | 1459 | if (!empty($form->_params['is_recur']) && $form->_contributeMode == 'direct') { |
68e61ad6 EM |
1460 | if (!empty($membershipContribution->trxn_id) && !isset($membershipContribution->payment_status_id) |
1461 | || (!empty($membershipContribution->payment_status_id) && $membershipContribution->payment_status_id == 1)) { | |
a7a33651 | 1462 | try { |
e0556ebe | 1463 | civicrm_api3('contribution', 'completetransaction', array( |
353ffa53 TO |
1464 | 'id' => $membershipContribution->id, |
1465 | 'trxn_id' => $membershipContribution->trxn_id, | |
1466 | )); | |
a7a33651 EM |
1467 | } |
1468 | catch (CiviCRM_API3_Exception $e) { | |
1469 | // if for any reason it is already completed this will fail - e.g extensions hacking around core not completing transactions prior to CRM-15296 | |
1470 | // so let's be gentle here | |
1471 | CRM_Core_Error::debug_log_message('contribution ' . $membershipContribution->id . ' not completed with trxn_id ' . $membershipContribution->trxn_id . ' and message ' . $e->getMessage()); | |
1472 | } | |
1473 | } | |
ef26b43b EM |
1474 | // Do not send an email if Recurring transaction is done via Direct Mode |
1475 | // Email will we sent when the IPN is received. | |
5901ddf9 | 1476 | return; |
6a488035 TO |
1477 | } |
1478 | ||
1479 | //finally send an email receipt | |
1480 | CRM_Contribute_BAO_ContributionPage::sendMail($contactID, | |
1481 | $form->_values, | |
1482 | $isTest, FALSE, | |
1483 | $includeFieldTypes | |
1484 | ); | |
1485 | } | |
1486 | ||
cd125a40 FG |
1487 | /** |
1488 | * Function for updating a membership record's contribution_recur_id | |
1489 | * | |
c866eb5f | 1490 | * @param CRM_Member_DAO_Membership $membership |
5901ddf9 | 1491 | * @param \CRM_Contribute_BAO_Contribution|\CRM_Contribute_DAO_Contribution $contribution |
cd125a40 FG |
1492 | * |
1493 | * @return void | |
cd125a40 | 1494 | */ |
c866eb5f | 1495 | static public function updateRecurMembership(CRM_Member_DAO_Membership $membership, CRM_Contribute_BAO_Contribution $contribution) { |
cd125a40 FG |
1496 | |
1497 | if (empty($contribution->contribution_recur_id)) { | |
1498 | return; | |
1499 | } | |
1500 | ||
1501 | $params = array( | |
1502 | 1 => array($contribution->contribution_recur_id, 'Integer'), | |
1503 | 2 => array($membership->id, 'Integer'), | |
1504 | ); | |
1505 | ||
1506 | $sql = "UPDATE civicrm_membership SET contribution_recur_id = %1 WHERE id = %2"; | |
1507 | CRM_Core_DAO::executeQuery($sql, $params); | |
1508 | } | |
1509 | ||
6a488035 | 1510 | /** |
c98997b9 EM |
1511 | * @deprecated |
1512 | * A wrapper for renewing memberships from a form - including the form in the membership processing adds complexity | |
1513 | * as the forms are being forced to pretend similarity | |
1514 | * Try to call the renewMembership directly | |
e0efd2d0 | 1515 | * @todo - this form method needs to have the interaction with the form layer removed from it |
1516 | * as a BAO function. Note that the api now supports membership renewals & it is not clear this function does anything | |
1517 | * not done by the membership.create api (with a lot less unit tests) | |
1518 | * | |
6a488035 TO |
1519 | * This method will renew / create the membership depending on |
1520 | * whether the given contact has a membership or not. And will add | |
1521 | * the modified dates for membership and in the log table. | |
1522 | * | |
b2363ea8 TO |
1523 | * @param int $contactID |
1524 | * Id of the contact. | |
1525 | * @param int $membershipTypeID | |
1526 | * Id of the new membership type. | |
1527 | * @param bool $is_test | |
1528 | * If this is test contribution or live contribution. | |
1529 | * @param CRM_Core_Form $form | |
1530 | * Form object. | |
e46e9a0b | 1531 | * @param null $changeToday |
b2363ea8 TO |
1532 | * @param int $modifiedID |
1533 | * Individual contact id in case of On Behalf signup (CRM-4027 ). | |
e46e9a0b | 1534 | * @param null $customFieldsFormatted |
b2363ea8 TO |
1535 | * @param int $numRenewTerms |
1536 | * How many membership terms are being added to end date (default is 1). | |
1537 | * @param int $membershipID | |
1538 | * Membership ID, this should always be passed in & optionality should be removed. | |
fa9d0451 EM |
1539 | * |
1540 | * @throws CRM_Core_Exception | |
6a488035 | 1541 | * |
e46e9a0b | 1542 | */ |
608e6658 | 1543 | public static function renewMembershipFormWrapper( |
6a488035 TO |
1544 | $contactID, |
1545 | $membershipTypeID, | |
1546 | $is_test, | |
1547 | &$form, | |
1548 | $changeToday = NULL, | |
1549 | $modifiedID = NULL, | |
1550 | $customFieldsFormatted = NULL, | |
fa9d0451 | 1551 | $numRenewTerms = 1, |
b9b75df1 SB |
1552 | $membershipID = NULL, |
1553 | $pending = FALSE | |
6a488035 TO |
1554 | ) { |
1555 | $statusFormat = '%Y-%m-%d'; | |
e0556ebe TO |
1556 | $format = '%Y%m%d'; |
1557 | $ids = array(); | |
fa9d0451 | 1558 | //@todo would be better to make $membershipID a compulsory function param & make form layer responsible for extracting it |
e0556ebe | 1559 | if (!$membershipID && isset($form->_membershipId)) { |
fa9d0451 EM |
1560 | $membershipID = $form->_membershipId; |
1561 | } | |
6a488035 TO |
1562 | |
1563 | //get all active statuses of membership. | |
1564 | $allStatus = CRM_Member_PseudoConstant::membershipStatus(); | |
1565 | ||
1566 | $membershipTypeDetails = CRM_Member_BAO_MembershipType::getMembershipTypeDetails($membershipTypeID); | |
1567 | ||
1568 | // check is it pending. - CRM-4555 | |
b9b75df1 | 1569 | list($pending, $contributionRecurID, $changeToday, $membershipSource, $isPayLater, $campaignId) = self::extractFormValues($form, $changeToday, $membershipTypeDetails, $pending); |
c98997b9 | 1570 | list($membership, $renewalMode, $dates) = self::renewMembership($contactID, $membershipTypeID, $is_test, $changeToday, $modifiedID, $customFieldsFormatted, $numRenewTerms, $membershipID, $pending, $allStatus, $membershipTypeDetails, $contributionRecurID, $format, $membershipSource, $ids, $statusFormat, $isPayLater, $campaignId); |
1f4d7bcb | 1571 | $form->set('renewal_mode', $renewalMode); |
6a488035 TO |
1572 | if (!empty($dates)) { |
1573 | $form->assign('mem_start_date', | |
1574 | CRM_Utils_Date::customFormat($dates['start_date'], $format) | |
1575 | ); | |
1576 | $form->assign('mem_end_date', | |
1577 | CRM_Utils_Date::customFormat($dates['end_date'], $format) | |
1578 | ); | |
1579 | } | |
6a488035 | 1580 | return $membership; |
c98997b9 | 1581 | |
6a488035 TO |
1582 | } |
1583 | ||
1584 | /** | |
fe482240 | 1585 | * Method to fix membership status of stale membership. |
6a488035 TO |
1586 | * |
1587 | * This method first checks if the membership is stale. If it is, | |
1588 | * then status will be updated based on existing start and end | |
1589 | * dates and log will be added for the status change. | |
1590 | * | |
b2363ea8 TO |
1591 | * @param array $currentMembership |
1592 | * Reference to the array. | |
688d37c6 CW |
1593 | * containing all values of |
1594 | * the current membership | |
b2363ea8 TO |
1595 | * @param array $changeToday |
1596 | * Array of month, day, year. | |
688d37c6 CW |
1597 | * values in case today needs |
1598 | * to be customised, null otherwise | |
6a488035 TO |
1599 | * |
1600 | * @return void | |
6a488035 | 1601 | */ |
00be9182 | 1602 | public static function fixMembershipStatusBeforeRenew(&$currentMembership, $changeToday) { |
6a488035 TO |
1603 | $today = NULL; |
1604 | if ($changeToday) { | |
1605 | $today = CRM_Utils_Date::processDate($changeToday, NULL, FALSE, 'Y-m-d'); | |
1606 | } | |
1607 | ||
1608 | $status = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate( | |
1609 | CRM_Utils_Array::value('start_date', $currentMembership), | |
1610 | CRM_Utils_Array::value('end_date', $currentMembership), | |
1611 | CRM_Utils_Array::value('join_date', $currentMembership), | |
1612 | $today, | |
5f11bbcc EM |
1613 | TRUE, |
1614 | $currentMembership['membership_type_id'], | |
1615 | $currentMembership | |
6a488035 TO |
1616 | ); |
1617 | ||
1618 | if (empty($status) || | |
1619 | empty($status['id']) | |
1620 | ) { | |
1621 | CRM_Core_Error::fatal(ts('Oops, it looks like there is no valid membership status corresponding to the membership start and end dates for this membership. Contact the site administrator for assistance.')); | |
1622 | } | |
1623 | ||
1624 | $currentMembership['today_date'] = $today; | |
1625 | ||
1626 | if ($status['id'] !== $currentMembership['status_id']) { | |
1627 | $memberDAO = new CRM_Member_DAO_Membership(); | |
1628 | $memberDAO->id = $currentMembership['id']; | |
1629 | $memberDAO->find(TRUE); | |
1630 | ||
1631 | $memberDAO->status_id = $status['id']; | |
1632 | $memberDAO->join_date = CRM_Utils_Date::isoToMysql($memberDAO->join_date); | |
1633 | $memberDAO->start_date = CRM_Utils_Date::isoToMysql($memberDAO->start_date); | |
1634 | $memberDAO->end_date = CRM_Utils_Date::isoToMysql($memberDAO->end_date); | |
1635 | $memberDAO->save(); | |
1636 | CRM_Core_DAO::storeValues($memberDAO, $currentMembership); | |
1637 | $memberDAO->free(); | |
1638 | ||
1639 | $currentMembership['is_current_member'] = CRM_Core_DAO::getFieldValue( | |
1640 | 'CRM_Member_DAO_MembershipStatus', | |
1641 | $currentMembership['status_id'], | |
1642 | 'is_current_member' | |
1643 | ); | |
1644 | $format = '%Y%m%d'; | |
1645 | ||
1646 | $logParams = array( | |
1647 | 'membership_id' => $currentMembership['id'], | |
1648 | 'status_id' => $status['id'], | |
1649 | 'start_date' => CRM_Utils_Date::customFormat( | |
1650 | $currentMembership['start_date'], | |
1651 | $format | |
1652 | ), | |
1653 | 'end_date' => CRM_Utils_Date::customFormat( | |
1654 | $currentMembership['end_date'], | |
1655 | $format | |
1656 | ), | |
1657 | 'modified_date' => CRM_Utils_Date::customFormat( | |
1658 | $currentMembership['today_date'], | |
1659 | $format | |
1660 | ), | |
1661 | 'membership_type_id' => $currentMembership['membership_type_id'], | |
520c1a14 | 1662 | 'max_related' => CRM_Utils_Array::value('max_related', $currentMembership, 0), |
6a488035 TO |
1663 | ); |
1664 | ||
1665 | $session = CRM_Core_Session::singleton(); | |
1666 | // If we have an authenticated session, set modified_id to that user's contact_id, else set to membership.contact_id | |
1667 | if ($session->get('userID')) { | |
1668 | $logParams['modified_id'] = $session->get('userID'); | |
1669 | } | |
1670 | else { | |
1671 | $logParams['modified_id'] = $currentMembership['contact_id']; | |
1672 | } | |
1673 | CRM_Member_BAO_MembershipLog::add($logParams, CRM_Core_DAO::$_nullArray); | |
1674 | } | |
1675 | } | |
1676 | ||
1677 | /** | |
fe482240 | 1678 | * Get the contribution page id from the membership record. |
6a488035 | 1679 | * |
688d37c6 | 1680 | * @param int $membershipID |
6a488035 | 1681 | * |
a6c01b45 | 1682 | * @return int |
688d37c6 | 1683 | * contribution page id |
6a488035 | 1684 | */ |
00be9182 | 1685 | public static function getContributionPageId($membershipID) { |
6a488035 TO |
1686 | $query = " |
1687 | SELECT c.contribution_page_id as pageID | |
1688 | FROM civicrm_membership_payment mp, civicrm_contribution c | |
1689 | WHERE mp.contribution_id = c.id | |
1690 | AND c.contribution_page_id IS NOT NULL | |
1691 | AND mp.membership_id = " . CRM_Utils_Type::escape($membershipID, 'Integer') | |
e0556ebe | 1692 | . " ORDER BY mp.id DESC"; |
6a488035 TO |
1693 | |
1694 | return CRM_Core_DAO::singleValueQuery($query, | |
1695 | CRM_Core_DAO::$_nullArray | |
1696 | ); | |
1697 | } | |
1698 | ||
6a488035 | 1699 | /** |
fe482240 | 1700 | * Updated related memberships. |
6a488035 | 1701 | * |
b2363ea8 TO |
1702 | * @param int $ownerMembershipId |
1703 | * Owner Membership Id. | |
1704 | * @param array $params | |
1705 | * Formatted array of key => value. | |
6a488035 | 1706 | */ |
00be9182 | 1707 | public static function updateRelatedMemberships($ownerMembershipId, $params) { |
6a488035 TO |
1708 | $membership = new CRM_Member_DAO_Membership(); |
1709 | $membership->owner_membership_id = $ownerMembershipId; | |
1710 | $membership->find(); | |
1711 | ||
1712 | while ($membership->fetch()) { | |
1713 | $relatedMembership = new CRM_Member_DAO_Membership(); | |
1714 | $relatedMembership->id = $membership->id; | |
1715 | $relatedMembership->copyValues($params); | |
1716 | $relatedMembership->save(); | |
1717 | $relatedMembership->free(); | |
1718 | } | |
1719 | ||
1720 | $membership->free(); | |
1721 | } | |
1722 | ||
1723 | /** | |
fe482240 | 1724 | * Get list of membership fields for profile. |
6a488035 TO |
1725 | * For now we only allow custom membership fields to be in |
1726 | * profile | |
1727 | * | |
e46e9a0b | 1728 | * @param null $mode |
688d37c6 | 1729 | * FIXME: This param is ignored |
e46e9a0b | 1730 | * |
a6c01b45 CW |
1731 | * @return array |
1732 | * the list of membership fields | |
6a488035 | 1733 | */ |
00be9182 | 1734 | public static function getMembershipFields($mode = NULL) { |
6a488035 TO |
1735 | $fields = CRM_Member_DAO_Membership::export(); |
1736 | ||
6a488035 TO |
1737 | unset($fields['membership_contact_id']); |
1738 | $fields = array_merge($fields, CRM_Core_BAO_CustomField::getFieldsForImport('Membership')); | |
1739 | ||
1740 | $membershipType = CRM_Member_DAO_MembershipType::export(); | |
1741 | ||
1742 | $membershipStatus = CRM_Member_DAO_MembershipStatus::export(); | |
1743 | ||
1744 | $fields = array_merge($fields, $membershipType, $membershipStatus); | |
1745 | ||
1746 | return $fields; | |
1747 | } | |
1748 | ||
1749 | /** | |
fe482240 | 1750 | * Get the sort name of a contact for a particular membership. |
6a488035 | 1751 | * |
b2363ea8 TO |
1752 | * @param int $id |
1753 | * Id of the membership. | |
6a488035 | 1754 | * |
72b3a70c CW |
1755 | * @return null|string |
1756 | * sort name of the contact if found | |
6a488035 | 1757 | */ |
00be9182 | 1758 | public static function sortName($id) { |
6a488035 TO |
1759 | $id = CRM_Utils_Type::escape($id, 'Integer'); |
1760 | ||
1761 | $query = " | |
1762 | SELECT civicrm_contact.sort_name | |
1763 | FROM civicrm_membership, civicrm_contact | |
1764 | WHERE civicrm_membership.contact_id = civicrm_contact.id | |
1765 | AND civicrm_membership.id = {$id} | |
1766 | "; | |
1767 | return CRM_Core_DAO::singleValueQuery($query, CRM_Core_DAO::$_nullArray); | |
1768 | } | |
1769 | ||
1770 | /** | |
fe482240 | 1771 | * Create memberships for related contacts. |
6a488035 TO |
1772 | * takes into account the maximum related memberships |
1773 | * | |
b2363ea8 TO |
1774 | * @param array $params |
1775 | * Array of key - value pairs. | |
1776 | * @param CRM_Core_DAO $dao | |
1777 | * Membership object. | |
6a488035 | 1778 | * |
72b3a70c CW |
1779 | * @return null|array |
1780 | * array of memberships if created | |
6a488035 | 1781 | */ |
00be9182 | 1782 | public static function createRelatedMemberships(&$params, &$dao, $reset = FALSE) { |
6a488035 | 1783 | static $relatedContactIds = array(); |
6d8a45ed EM |
1784 | if ($reset) { |
1785 | // not sure why a static var is in use here - we need a way to reset it from the test suite | |
1786 | $relatedContactIds = array(); | |
608e6658 | 1787 | return FALSE; |
6d8a45ed | 1788 | } |
6a488035 TO |
1789 | |
1790 | $membership = new CRM_Member_DAO_Membership(); | |
1791 | $membership->id = $dao->id; | |
1792 | ||
1793 | // required since create method doesn't return all the | |
1794 | // parameters in the returned membership object | |
1795 | if (!$membership->find(TRUE)) { | |
1796 | return; | |
1797 | } | |
1798 | $deceasedStatusId = array_search('Deceased', CRM_Member_PseudoConstant::membershipStatus()); | |
1799 | // FIXME : While updating/ renewing the | |
1800 | // membership, if the relationship is PAST then | |
1801 | // the membership of the related contact must be | |
1802 | // expired. | |
1803 | // For that, getting Membership Status for which | |
1804 | // is_current_member is 0. It works for the | |
1805 | // generated data as there is only one membership | |
1806 | // status having is_current_member = 0. | |
1807 | // But this wont work exactly if there will be | |
1808 | // more than one status having is_current_member = 0. | |
1809 | $membershipStatus = new CRM_Member_DAO_MembershipStatus(); | |
1810 | $membershipStatus->is_current_member = 0; | |
1811 | if ($membershipStatus->find(TRUE)) { | |
1812 | $expiredStatusId = $membershipStatus->id; | |
e0556ebe TO |
1813 | } |
1814 | else { | |
6a488035 TO |
1815 | $expiredStatusId = array_search('Expired', CRM_Member_PseudoConstant::membershipStatus()); |
1816 | } | |
1817 | ||
1818 | $allRelatedContacts = array(); | |
1819 | $relatedContacts = array(); | |
1820 | if (!is_a($membership, 'CRM_Core_Error')) { | |
1821 | $allRelatedContacts = CRM_Member_BAO_Membership::checkMembershipRelationship($membership->id, | |
1822 | $membership->contact_id, | |
1823 | CRM_Utils_Array::value('action', $params) | |
1824 | ); | |
1825 | } | |
1826 | ||
1827 | // check for loops. CRM-4213 | |
1828 | // remove repeated related contacts, which already inherited membership. | |
1829 | $relatedContactIds[$membership->contact_id] = TRUE; | |
1830 | foreach ($allRelatedContacts as $cid => $status) { | |
a7488080 | 1831 | if (empty($relatedContactIds[$cid])) { |
6a488035 TO |
1832 | $relatedContactIds[$cid] = TRUE; |
1833 | ||
1834 | //don't create membership again for owner contact. | |
1835 | $nestedRelationship = FALSE; | |
1836 | if ($membership->owner_membership_id) { | |
1837 | $nestedRelMembership = new CRM_Member_DAO_Membership(); | |
1838 | $nestedRelMembership->id = $membership->owner_membership_id; | |
1839 | $nestedRelMembership->contact_id = $cid; | |
1840 | $nestedRelationship = $nestedRelMembership->find(TRUE); | |
1841 | $nestedRelMembership->free(); | |
1842 | } | |
1843 | if (!$nestedRelationship) { | |
1844 | $relatedContacts[$cid] = $status; | |
1845 | } | |
1846 | } | |
1847 | } | |
1848 | ||
1849 | //lets cleanup related membership if any. | |
1850 | if (empty($relatedContacts)) { | |
3506b6cd | 1851 | self::deleteRelatedMemberships($membership->id); |
6a488035 TO |
1852 | } |
1853 | else { | |
1854 | // Edit the params array | |
1855 | unset($params['id']); | |
1856 | // Reminder should be sent only to the direct membership | |
1857 | unset($params['reminder_date']); | |
1858 | // unset the custom value ids | |
1859 | if (is_array(CRM_Utils_Array::value('custom', $params))) { | |
1860 | foreach ($params['custom'] as $k => $v) { | |
1861 | unset($params['custom'][$k]['id']); | |
1862 | } | |
1863 | } | |
1864 | if (!isset($params['membership_type_id'])) { | |
1865 | $params['membership_type_id'] = $membership->membership_type_id; | |
1866 | } | |
1867 | ||
1868 | // max_related should be set in the parent membership | |
1869 | unset($params['max_related']); | |
1870 | // Number of inherited memberships available - NULL is interpreted as unlimited, '0' as none | |
1871 | $available = ($membership->max_related == NULL ? PHP_INT_MAX : $membership->max_related); | |
1872 | $queue = array(); // will be used to queue potential memberships to be created | |
1873 | ||
1874 | foreach ($relatedContacts as $contactId => $relationshipStatus) { | |
1875 | //use existing membership record. | |
1876 | $relMembership = new CRM_Member_DAO_Membership(); | |
1877 | $relMembership->contact_id = $contactId; | |
1878 | $relMembership->owner_membership_id = $membership->id; | |
1879 | $relMemIds = array(); | |
1880 | if ($relMembership->find(TRUE)) { | |
1881 | $params['id'] = $relMemIds['membership'] = $relMembership->id; | |
1882 | } | |
1883 | $params['contact_id'] = $contactId; | |
1884 | $params['owner_membership_id'] = $membership->id; | |
1885 | ||
1886 | // set status_id as it might have been changed for | |
1887 | // past relationship | |
1888 | $params['status_id'] = $membership->status_id; | |
1889 | ||
1890 | if ($deceasedStatusId && | |
1891 | CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $contactId, 'is_deceased') | |
1892 | ) { | |
1893 | $params['status_id'] = $deceasedStatusId; | |
1894 | } | |
1895 | elseif ((CRM_Utils_Array::value('action', $params) & CRM_Core_Action::UPDATE) && | |
1896 | ($relationshipStatus == CRM_Contact_BAO_Relationship::PAST) | |
1897 | ) { | |
e0556ebe TO |
1898 | $params['status_id'] = $expiredStatusId; |
1899 | } | |
6a488035 TO |
1900 | |
1901 | //don't calculate status again in create( ); | |
1902 | $params['skipStatusCal'] = TRUE; | |
1903 | ||
1904 | //do create activity if we changed status. | |
1905 | if ($params['status_id'] != $relMembership->status_id) { | |
1906 | $params['createActivity'] = TRUE; | |
1907 | } | |
1908 | ||
1909 | // we should not created contribution record for related contacts, CRM-3371 | |
1910 | unset($params['contribution_status_id']); | |
1911 | ||
1912 | if (($params['status_id'] == $deceasedStatusId) || ($params['status_id'] == $expiredStatusId)) { | |
1913 | // related membership is not active so does not count towards maximum | |
1914 | CRM_Member_BAO_Membership::create($params, $relMemIds); | |
8efea814 EM |
1915 | } |
1916 | else { | |
6a488035 TO |
1917 | // related membership already exists, so this is just an update |
1918 | if (isset($params['id'])) { | |
1919 | if ($available > 0) { | |
e0556ebe TO |
1920 | CRM_Member_BAO_Membership::create($params, $relMemIds); |
1921 | $available--; | |
1922 | } | |
608e6658 | 1923 | else { |
1924 | // we have run out of inherited memberships, so delete extras | |
f5e53870 | 1925 | self::deleteMembership($params['id']); |
6a488035 | 1926 | } |
e0556ebe TO |
1927 | // we need to first check if there will remain inherited memberships, so queue it up |
1928 | } | |
1929 | else { | |
6a488035 TO |
1930 | $queue[] = $params; |
1931 | } | |
1932 | } | |
1933 | } | |
1934 | // now go over the queue and create any available related memberships | |
1935 | reset($queue); | |
1936 | while (($available > 0) && ($params = each($queue))) { | |
1937 | CRM_Member_BAO_Membership::create($params['value'], $relMemIds); | |
e0556ebe | 1938 | $available--; |
6a488035 TO |
1939 | } |
1940 | } | |
1941 | } | |
1942 | ||
1943 | /** | |
fe482240 | 1944 | * Delete the record that are associated with this Membership Payment. |
6a488035 | 1945 | * |
b2363ea8 | 1946 | * @param int $membershipId |
6a488035 | 1947 | * |
608e6658 | 1948 | * @return object |
1949 | * $membershipPayment deleted membership payment object | |
6a488035 | 1950 | */ |
00be9182 | 1951 | public static function deleteMembershipPayment($membershipId) { |
6a488035 | 1952 | |
608e6658 | 1953 | $membershipPayment = new CRM_Member_DAO_MembershipPayment(); |
1954 | $membershipPayment->membership_id = $membershipId; | |
1955 | $membershipPayment->find(); | |
6a488035 | 1956 | |
608e6658 | 1957 | while ($membershipPayment->fetch()) { |
1958 | CRM_Contribute_BAO_Contribution::deleteContribution($membershipPayment->contribution_id); | |
1959 | CRM_Utils_Hook::pre('delete', 'MembershipPayment', $membershipPayment->id, $membershipPayment); | |
061a8a1e | 1960 | $membershipPayment->delete(); |
608e6658 | 1961 | CRM_Utils_Hook::post('delete', 'MembershipPayment', $membershipPayment->id, $membershipPayment); |
6a488035 | 1962 | } |
608e6658 | 1963 | return $membershipPayment; |
6a488035 TO |
1964 | } |
1965 | ||
bb3a214a | 1966 | /** |
c490a46a | 1967 | * @param CRM_Core_Form $form |
100fef9d | 1968 | * @param int $membershipTypeID |
bb3a214a EM |
1969 | * |
1970 | * @return array | |
1971 | */ | |
00be9182 | 1972 | public static function &buildMembershipTypeValues(&$form, $membershipTypeID = NULL) { |
e0556ebe | 1973 | $whereClause = " WHERE domain_id = " . CRM_Core_Config::domainID(); |
6a488035 TO |
1974 | |
1975 | if (is_array($membershipTypeID)) { | |
1976 | $allIDs = implode(',', $membershipTypeID); | |
1977 | $whereClause .= " AND id IN ( $allIDs )"; | |
1978 | } | |
1979 | elseif (is_numeric($membershipTypeID) && | |
1980 | $membershipTypeID > 0 | |
1981 | ) { | |
1982 | $whereClause .= " AND id = $membershipTypeID"; | |
1983 | } | |
1984 | ||
1985 | $query = " | |
1986 | SELECT * | |
1987 | FROM civicrm_membership_type | |
1988 | $whereClause; | |
1989 | "; | |
1990 | $dao = CRM_Core_DAO::executeQuery($query); | |
1991 | ||
1992 | $membershipTypeValues = array(); | |
1993 | $membershipTypeFields = array( | |
e0556ebe TO |
1994 | 'id', |
1995 | 'minimum_fee', | |
1996 | 'name', | |
1997 | 'is_active', | |
1998 | 'description', | |
1999 | 'financial_type_id', | |
2000 | 'auto_renew', | |
2001 | 'member_of_contact_id', | |
2002 | 'relationship_type_id', | |
2003 | 'relationship_direction', | |
2004 | 'max_related', | |
6a488035 TO |
2005 | ); |
2006 | ||
2007 | while ($dao->fetch()) { | |
2008 | $membershipTypeValues[$dao->id] = array(); | |
2009 | foreach ($membershipTypeFields as $mtField) { | |
2010 | $membershipTypeValues[$dao->id][$mtField] = $dao->$mtField; | |
2011 | } | |
2012 | } | |
2013 | $dao->free(); | |
2014 | ||
2015 | CRM_Utils_Hook::membershipTypeValues($form, $membershipTypeValues); | |
2016 | ||
2017 | if (is_numeric($membershipTypeID) && | |
2018 | $membershipTypeID > 0 | |
2019 | ) { | |
2020 | return $membershipTypeValues[$membershipTypeID]; | |
2021 | } | |
2022 | else { | |
2023 | return $membershipTypeValues; | |
2024 | } | |
2025 | } | |
2026 | ||
2027 | /** | |
fe482240 | 2028 | * Get membership record count for a Contact. |
6a488035 | 2029 | * |
c490a46a | 2030 | * @param int $contactID |
b2363ea8 | 2031 | * @param bool $activeOnly |
6a488035 | 2032 | * |
c490a46a | 2033 | * @return null|string |
6a488035 | 2034 | */ |
00be9182 | 2035 | public static function getContactMembershipCount($contactID, $activeOnly = FALSE) { |
6a488035 | 2036 | $select = "SELECT count(*) FROM civicrm_membership "; |
e0556ebe | 2037 | $where = "WHERE civicrm_membership.contact_id = {$contactID} AND civicrm_membership.is_test = 0 "; |
6a488035 TO |
2038 | |
2039 | // CRM-6627, all status below 3 (active, pending, grace) are considered active | |
2040 | if ($activeOnly) { | |
2041 | $select .= " INNER JOIN civicrm_membership_status ON civicrm_membership.status_id = civicrm_membership_status.id "; | |
e0556ebe | 2042 | $where .= " and civicrm_membership_status.is_current_member = 1"; |
6a488035 TO |
2043 | } |
2044 | ||
2045 | $query = $select . $where; | |
2046 | return CRM_Core_DAO::singleValueQuery($query); | |
2047 | } | |
2048 | ||
2049 | /** | |
100fef9d | 2050 | * Check whether payment processor supports |
6a488035 TO |
2051 | * cancellation of membership subscription |
2052 | * | |
b2363ea8 TO |
2053 | * @param int $mid |
2054 | * Membership id. | |
6a488035 | 2055 | * |
e46e9a0b EM |
2056 | * @param bool $isNotCancelled |
2057 | * | |
608e6658 | 2058 | * @return bool |
6a488035 | 2059 | */ |
00be9182 | 2060 | public static function isCancelSubscriptionSupported($mid, $isNotCancelled = TRUE) { |
6a488035 TO |
2061 | $cacheKeyString = "$mid"; |
2062 | $cacheKeyString .= $isNotCancelled ? '_1' : '_0'; | |
2063 | ||
2064 | static $supportsCancel = array(); | |
2065 | ||
2066 | if (!array_key_exists($cacheKeyString, $supportsCancel)) { | |
2067 | $supportsCancel[$cacheKeyString] = FALSE; | |
2068 | $isCancelled = FALSE; | |
2069 | ||
2070 | if ($isNotCancelled) { | |
2071 | $isCancelled = self::isSubscriptionCancelled($mid); | |
2072 | } | |
2073 | ||
2074 | $paymentObject = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($mid, 'membership', 'obj'); | |
2075 | if (!empty($paymentObject)) { | |
2076 | $supportsCancel[$cacheKeyString] = $paymentObject->isSupported('cancelSubscription') && !$isCancelled; | |
2077 | } | |
2078 | } | |
2079 | return $supportsCancel[$cacheKeyString]; | |
2080 | } | |
2081 | ||
2082 | /** | |
fe482240 | 2083 | * Check whether subscription is already cancelled. |
6a488035 | 2084 | * |
b2363ea8 TO |
2085 | * @param int $mid |
2086 | * Membership id. | |
6a488035 | 2087 | * |
a6c01b45 CW |
2088 | * @return string |
2089 | * contribution status | |
6a488035 | 2090 | */ |
00be9182 | 2091 | public static function isSubscriptionCancelled($mid) { |
6a488035 TO |
2092 | $sql = " |
2093 | SELECT cr.contribution_status_id | |
2094 | FROM civicrm_contribution_recur cr | |
2095 | LEFT JOIN civicrm_membership mem ON ( cr.id = mem.contribution_recur_id ) | |
2096 | WHERE mem.id = %1 LIMIT 1"; | |
e0556ebe | 2097 | $params = array(1 => array($mid, 'Integer')); |
6a488035 | 2098 | $statusId = CRM_Core_DAO::singleValueQuery($sql, $params); |
e0556ebe | 2099 | $status = CRM_Contribute_PseudoConstant::contributionStatus($statusId, 'name'); |
6a488035 TO |
2100 | if ($status == 'Cancelled') { |
2101 | return TRUE; | |
2102 | } | |
2103 | return FALSE; | |
2104 | } | |
2105 | ||
2106 | /** | |
100fef9d | 2107 | * Get membership joins for a specified membership |
6a488035 | 2108 | * type. Specifically, retrieves a count of still current memberships whose |
4e636a74 | 2109 | * join_date and start_date are within a specified date range. Dates match |
8ef12e64 | 2110 | * the pattern "yyyy-mm-dd". |
6a488035 | 2111 | * |
b2363ea8 TO |
2112 | * @param int $membershipTypeId |
2113 | * Membership type id. | |
2114 | * @param int $startDate | |
2115 | * Date on which to start counting. | |
2116 | * @param int $endDate | |
2117 | * Date on which to end counting. | |
e46e9a0b | 2118 | * @param bool|int $isTest if true, membership is for a test site |
6a488035 | 2119 | * |
72b3a70c CW |
2120 | * @return int |
2121 | * the number of members of type $membershipTypeId | |
2122 | * whose join_date is between $startDate and $endDate and | |
2123 | * whose start_date is between $startDate and $endDate | |
6a488035 | 2124 | */ |
00be9182 | 2125 | public static function getMembershipJoins($membershipTypeId, $startDate, $endDate, $isTest = 0) { |
6a488035 TO |
2126 | $testClause = 'membership.is_test = 1'; |
2127 | if (!$isTest) { | |
2128 | $testClause = '( membership.is_test IS NULL OR membership.is_test = 0 )'; | |
2129 | } | |
4e636a74 AH |
2130 | if (!self::$_signupActType) { |
2131 | self::_getActTypes(); | |
2132 | } | |
8ef12e64 | 2133 | |
4e636a74 AH |
2134 | if (!self::$_signupActType) { |
2135 | return 0; | |
2136 | } | |
6a488035 TO |
2137 | |
2138 | $query = " | |
8ef12e64 | 2139 | SELECT COUNT(DISTINCT membership.id) as member_count |
6a488035 | 2140 | FROM civicrm_membership membership |
8ef12e64 | 2141 | INNER JOIN civicrm_activity activity ON (activity.source_record_id = membership.id AND activity.activity_type_id = %1) |
6a488035 | 2142 | INNER JOIN civicrm_membership_status status ON ( membership.status_id = status.id AND status.is_current_member = 1 ) |
4e636a74 AH |
2143 | INNER JOIN civicrm_contact contact ON ( contact.id = membership.contact_id AND contact.is_deleted = 0 ) |
2144 | WHERE membership.membership_type_id = %2 | |
2145 | AND activity.activity_date_time >= '$startDate' AND activity.activity_date_time <= '$endDate 23:59:59' | |
6a488035 TO |
2146 | AND {$testClause}"; |
2147 | ||
4e636a74 AH |
2148 | $params = array( |
2149 | 1 => array(self::$_signupActType, 'Integer'), | |
2150 | 2 => array($membershipTypeId, 'Integer'), | |
2151 | ); | |
2152 | ||
6a488035 TO |
2153 | $memberCount = CRM_Core_DAO::singleValueQuery($query, $params); |
2154 | ||
e0556ebe | 2155 | return (int) $memberCount; |
6a488035 TO |
2156 | } |
2157 | ||
2158 | /** | |
100fef9d | 2159 | * Get membership renewals for a specified membership |
4e636a74 | 2160 | * type. Specifically, retrieves a count of still current memberships |
8ef12e64 | 2161 | * whose join_date is before and start_date is within a specified date |
4e636a74 | 2162 | * range. Dates match the pattern "yyyy-mm-dd". |
6a488035 | 2163 | * |
b2363ea8 TO |
2164 | * @param int $membershipTypeId |
2165 | * Membership type id. | |
2166 | * @param int $startDate | |
2167 | * Date on which to start counting. | |
2168 | * @param int $endDate | |
2169 | * Date on which to end counting. | |
e46e9a0b | 2170 | * @param bool|int $isTest if true, membership is for a test site |
6a488035 | 2171 | * |
df8d3074 | 2172 | * @return int |
a6c01b45 | 2173 | * returns the number of members of type $membershipTypeId |
688d37c6 CW |
2174 | * whose join_date is before $startDate and |
2175 | * whose start_date is between $startDate and $endDate | |
6a488035 | 2176 | */ |
00be9182 | 2177 | public static function getMembershipRenewals($membershipTypeId, $startDate, $endDate, $isTest = 0) { |
6a488035 TO |
2178 | $testClause = 'membership.is_test = 1'; |
2179 | if (!$isTest) { | |
2180 | $testClause = '( membership.is_test IS NULL OR membership.is_test = 0 )'; | |
2181 | } | |
4e636a74 AH |
2182 | if (!self::$_renewalActType) { |
2183 | self::_getActTypes(); | |
2184 | } | |
8ef12e64 | 2185 | |
4e636a74 AH |
2186 | if (!self::$_renewalActType) { |
2187 | return 0; | |
2188 | } | |
6a488035 TO |
2189 | |
2190 | $query = " | |
8ef12e64 | 2191 | SELECT COUNT(DISTINCT membership.id) as member_count |
6a488035 | 2192 | FROM civicrm_membership membership |
4e636a74 | 2193 | INNER JOIN civicrm_activity activity ON (activity.source_record_id = membership.id AND activity.activity_type_id = %1) |
6a488035 TO |
2194 | INNER JOIN civicrm_membership_status status ON ( membership.status_id = status.id AND status.is_current_member = 1 ) |
2195 | INNER JOIN civicrm_contact contact ON ( contact.id = membership.contact_id AND contact.is_deleted = 0 ) | |
4e636a74 | 2196 | WHERE membership.membership_type_id = %2 |
8ef12e64 | 2197 | AND activity.activity_date_time >= '$startDate' AND activity.activity_date_time <= '$endDate 23:59:59' |
6a488035 TO |
2198 | AND {$testClause}"; |
2199 | ||
4e636a74 AH |
2200 | $params = array( |
2201 | 1 => array(self::$_renewalActType, 'Integer'), | |
2202 | 2 => array($membershipTypeId, 'Integer'), | |
2203 | ); | |
6a488035 TO |
2204 | $memberCount = CRM_Core_DAO::singleValueQuery($query, $params); |
2205 | ||
e0556ebe | 2206 | return (int) $memberCount; |
6a488035 TO |
2207 | } |
2208 | ||
7273a245 | 2209 | /** |
fe482240 | 2210 | * Where a second separate financial transaction is supported we will process it here. |
236a2274 | 2211 | * |
100fef9d | 2212 | * @param int $contactID |
5624f515 | 2213 | * @param CRM_Contribute_Form_Contribution_Confirm $form |
100fef9d | 2214 | * @param array $tempParams |
7273a245 | 2215 | * @param $isTest |
100fef9d | 2216 | * @param array $lineItems |
d25e4224 | 2217 | * @param $minimumFee |
100fef9d | 2218 | * @param int $financialTypeID |
d25e4224 | 2219 | * |
5624f515 | 2220 | * @throws CRM_Core_Exception |
d25e4224 | 2221 | * @throws Exception |
236a2274 | 2222 | * @return CRM_Contribute_BAO_Contribution |
7273a245 | 2223 | */ |
5624f515 | 2224 | public static function processSecondaryFinancialTransaction($contactID, &$form, $tempParams, $isTest, $lineItems, $minimumFee, $financialTypeID) { |
2883c2b2 EM |
2225 | $financialType = new CRM_Financial_DAO_FinancialType(); |
2226 | $financialType->id = $financialTypeID; | |
2227 | if (!$financialType->find(TRUE)) { | |
7273a245 EM |
2228 | CRM_Core_Error::fatal(ts("Could not find a system table")); |
2229 | } | |
2230 | $tempParams['amount'] = $minimumFee; | |
2231 | $tempParams['invoiceID'] = md5(uniqid(rand(), TRUE)); | |
2232 | ||
2233 | $result = NULL; | |
2234 | if ($form->_values['is_monetary'] && !$form->_params['is_pay_later'] && $minimumFee > 0.0) { | |
2235 | $payment = CRM_Core_Payment::singleton($form->_mode, $form->_paymentProcessor, $form); | |
2236 | ||
2237 | if ($form->_contributeMode == 'express') { | |
2238 | $result = $payment->doExpressCheckout($tempParams); | |
a19183c1 EM |
2239 | if (is_a($result, 'CRM_Core_Error')) { |
2240 | throw new CRM_Core_Exception(CRM_Core_Error::getMessages($result)); | |
2241 | } | |
7273a245 EM |
2242 | } |
2243 | else { | |
a19183c1 | 2244 | $result = $payment->doPayment($tempParams, 'contribute'); |
7273a245 EM |
2245 | } |
2246 | } | |
2247 | ||
a19183c1 EM |
2248 | //assign receive date when separate membership payment |
2249 | //and contribution amount not selected. | |
2250 | if ($form->_amount == 0) { | |
2251 | $now = date('YmdHis'); | |
2252 | $form->_params['receive_date'] = $now; | |
2253 | $receiveDate = CRM_Utils_Date::mysqlToIso($now); | |
2254 | $form->set('params', $form->_params); | |
2255 | $form->assign('receive_date', $receiveDate); | |
7273a245 | 2256 | } |
7273a245 | 2257 | |
a19183c1 EM |
2258 | $form->set('membership_trx_id', $result['trxn_id']); |
2259 | $form->set('membership_amount', $minimumFee); | |
2260 | ||
2261 | $form->assign('membership_trx_id', $result['trxn_id']); | |
2262 | $form->assign('membership_amount', $minimumFee); | |
2263 | ||
2264 | // we don't need to create the user twice, so lets disable cms_create_account | |
2265 | // irrespective of the value, CRM-2888 | |
2266 | $tempParams['cms_create_account'] = 0; | |
2267 | ||
9cc96227 | 2268 | //CRM-16165, scenarios are |
2269 | // 1) If contribution is_pay_later and if contribution amount is > 0.0 we set pending = TRUE, vice-versa FALSE | |
2270 | // 2) If not pay later but auto-renewal membership is chosen then pending = TRUE as it later triggers | |
2271 | // pending recurring contribution, vice-versa FALSE | |
2272 | $pending = $form->_params['is_pay_later'] ? (($minimumFee > 0.0) ? TRUE : FALSE) : (!empty($form->_params['auto_renew']) ? TRUE : FALSE); | |
a19183c1 EM |
2273 | |
2274 | //set this variable as we are not creating pledge for | |
2275 | //separate membership payment contribution. | |
2276 | //so for differentiating membership contribution from | |
2277 | //main contribution. | |
2278 | $form->_params['separate_membership_payment'] = 1; | |
2279 | $membershipContribution = CRM_Contribute_Form_Contribution_Confirm::processContribution($form, | |
2280 | $tempParams, | |
2281 | $result, | |
2282 | $contactID, | |
2883c2b2 | 2283 | $financialType, |
a19183c1 EM |
2284 | $pending, |
2285 | TRUE, | |
2286 | $isTest, | |
2287 | $lineItems | |
2288 | ); | |
2289 | return $membershipContribution; | |
7273a245 EM |
2290 | } |
2291 | ||
0547ad7d EM |
2292 | /** |
2293 | * Create linkages between membership & contribution - note this is the wrong place for this code but this is a | |
2294 | * refactoring step. This should be BAO functionality | |
2295 | * @param $membership | |
2296 | * @param $membershipContribution | |
2297 | */ | |
2298 | public static function linkMembershipPayment($membership, $membershipContribution) { | |
e0556ebe | 2299 | CRM_Member_BAO_MembershipPayment::create(array( |
353ffa53 TO |
2300 | 'membership_id' => $membership->id, |
2301 | 'contribution_id' => $membershipContribution->id, | |
2302 | )); | |
0547ad7d EM |
2303 | } |
2304 | ||
8dde2f13 | 2305 | /** |
100fef9d CW |
2306 | * @param array $membershipParams |
2307 | * @param int $contactID | |
8dde2f13 | 2308 | * @param $customFieldsFormatted |
100fef9d | 2309 | * @param int $membershipID |
8dde2f13 EM |
2310 | * @param $memType |
2311 | * @param $isTest | |
2312 | * @param $numTerms | |
2313 | * @param $membershipContribution | |
c490a46a | 2314 | * @param CRM_Core_Form $form |
8dde2f13 EM |
2315 | * |
2316 | * @return array | |
2317 | */ | |
e0556ebe | 2318 | public static function createOrRenewMembership($membershipParams, $contactID, $customFieldsFormatted, $membershipID, $memType, $isTest, $numTerms, $membershipContribution, &$form) { |
b9b75df1 | 2319 | if (!empty($membershipContribution)) { |
9e98fa85 | 2320 | // CRM-16737 contribution_status_id is the deprecated return parameter from the payment processor. Use |
2321 | // payment_status_id. | |
b9b75df1 | 2322 | $pending = ($membershipContribution->contribution_status_id == 2) ? TRUE : FALSE; |
9e98fa85 | 2323 | if (isset($membershipContribution->payment_status_id)) { |
2324 | $pending = ($membershipContribution->payment_status_id == 2) ? TRUE : $pending; | |
2325 | } | |
b9b75df1 | 2326 | } |
c98997b9 | 2327 | $membership = self::renewMembershipFormWrapper($contactID, $memType, |
8dde2f13 EM |
2328 | $isTest, $form, NULL, |
2329 | CRM_Utils_Array::value('cms_contactID', $membershipParams), | |
2330 | $customFieldsFormatted, $numTerms, | |
b9b75df1 | 2331 | $membershipID, $pending |
8dde2f13 EM |
2332 | ); |
2333 | ||
8dde2f13 | 2334 | if (!empty($membershipContribution)) { |
423c9872 C |
2335 | // update recurring id for membership record |
2336 | self::updateRecurMembership($membership, $membershipContribution); | |
2337 | ||
8dde2f13 EM |
2338 | self::linkMembershipPayment($membership, $membershipContribution); |
2339 | } | |
2340 | return $membership; | |
2341 | } | |
2342 | ||
15c3308b | 2343 | /** |
fe482240 | 2344 | * Turn array of errors into message string. |
15c3308b EM |
2345 | * |
2346 | * @param array $errors | |
2347 | * | |
15c3308b EM |
2348 | * @return string |
2349 | */ | |
e0556ebe TO |
2350 | public static function compileErrorMessage($errors) { |
2351 | foreach ($errors as $error) { | |
15c3308b EM |
2352 | if (is_string($error)) { |
2353 | $message[] = $error; | |
2354 | } | |
2355 | } | |
2356 | return ts('Payment Processor Error message') . ': ' . implode('<br/>', $message); | |
2357 | } | |
2358 | ||
c98997b9 | 2359 | /** |
fe482240 | 2360 | * Extract relevant values from the form so we can separate form logic from BAO logcis. |
688d37c6 | 2361 | * |
c490a46a | 2362 | * @param CRM_Core_Form $form |
c98997b9 EM |
2363 | * @param $changeToday |
2364 | * @param $membershipTypeDetails | |
2365 | * | |
2366 | * @return array | |
2367 | */ | |
b9b75df1 | 2368 | public static function extractFormValues($form, $changeToday, $membershipTypeDetails, $pending = FALSE) { |
c98997b9 EM |
2369 | //@todo this is a BAO function & should not inspect the form - the form should do this |
2370 | // & pass required params to the BAO | |
2371 | if (CRM_Utils_Array::value('minimum_fee', $membershipTypeDetails) > 0.0) { | |
9cc96227 | 2372 | if (((isset($form->_contributeMode) && $form->_contributeMode == 'notify') || !empty($form->_params['is_pay_later']) |
c98997b9 | 2373 | ) && |
9cc96227 | 2374 | (($form->_values['is_monetary'] && $form->_amount > 0.0) || |
c98997b9 EM |
2375 | CRM_Utils_Array::value('record_contribution', $form->_params) |
2376 | ) | |
2377 | ) { | |
2378 | $pending = TRUE; | |
2379 | } | |
2380 | } | |
2381 | $contributionRecurID = isset($form->_params['contributionRecurID']) ? $form->_params['contributionRecurID'] : NULL; | |
2382 | ||
2383 | //we renew expired membership, CRM-6277 | |
2384 | if (!$changeToday) { | |
2385 | if ($form->get('renewalDate')) { | |
2386 | $changeToday = $form->get('renewalDate'); | |
2387 | } | |
2388 | elseif (get_class($form) == 'CRM_Contribute_Form_Contribution_Confirm') { | |
2389 | $changeToday = date('YmdHis'); | |
2390 | } | |
2391 | } | |
2392 | ||
c352e9fc | 2393 | $membershipSource = NULL; |
c98997b9 EM |
2394 | if (!empty($form->_params['membership_source'])) { |
2395 | $membershipSource = $form->_params['membership_source']; | |
2396 | } | |
2397 | elseif (isset($form->_values['title']) && !empty($form->_values['title'])) { | |
2398 | $membershipSource = ts('Online Contribution:') . ' ' . $form->_values['title']; | |
2399 | } | |
c352e9fc | 2400 | $isPayLater = NULL; |
e0556ebe | 2401 | if (isset($form->_params)) { |
c352e9fc C |
2402 | $isPayLater = CRM_Utils_Array::value('is_pay_later', $form->_params); |
2403 | } | |
c98997b9 EM |
2404 | $campaignId = NULL; |
2405 | if (isset($form->_values) && is_array($form->_values) && !empty($form->_values)) { | |
2406 | $campaignId = CRM_Utils_Array::value('campaign_id', $form->_params); | |
2407 | if (!array_key_exists('campaign_id', $form->_params)) { | |
2408 | $campaignId = CRM_Utils_Array::value('campaign_id', $form->_values); | |
2409 | } | |
2410 | } | |
2411 | return array($pending, $contributionRecurID, $changeToday, $membershipSource, $isPayLater, $campaignId); | |
2412 | } | |
2413 | ||
2414 | /** | |
b2363ea8 | 2415 | * @param int $contactID |
100fef9d | 2416 | * @param int $membershipTypeID |
c98997b9 EM |
2417 | * @param bool $is_test |
2418 | * @param $changeToday | |
b2363ea8 | 2419 | * @param int $modifiedID |
c98997b9 EM |
2420 | * @param $customFieldsFormatted |
2421 | * @param $numRenewTerms | |
100fef9d | 2422 | * @param int $membershipID |
c98997b9 EM |
2423 | * @param $pending |
2424 | * @param $allStatus | |
2425 | * @param array $membershipTypeDetails | |
b2363ea8 | 2426 | * @param int $contributionRecurID |
c98997b9 EM |
2427 | * @param $format |
2428 | * @param $membershipSource | |
2429 | * @param $ids | |
2430 | * @param $statusFormat | |
2431 | * @param $isPayLater | |
b2363ea8 | 2432 | * @param int $campaignId |
c98997b9 EM |
2433 | * |
2434 | * @throws CRM_Core_Exception | |
2435 | * @return array | |
2436 | */ | |
2437 | public static function renewMembership($contactID, $membershipTypeID, $is_test, $changeToday, $modifiedID, $customFieldsFormatted, $numRenewTerms, $membershipID, $pending, $allStatus, $membershipTypeDetails, $contributionRecurID, $format, $membershipSource, $ids, $statusFormat, $isPayLater, $campaignId) { | |
2438 | $renewalMode = $updateStatusId = FALSE; | |
2439 | $dates = array(); | |
d81c67a2 | 2440 | // CRM-7297 - allow membership type to be be changed during renewal so long as the parent org of new membershipType |
c98997b9 EM |
2441 | // is the same as the parent org of an existing membership of the contact |
2442 | $currentMembership = CRM_Member_BAO_Membership::getContactMembership($contactID, $membershipTypeID, | |
2443 | $is_test, $membershipID, TRUE | |
2444 | ); | |
2445 | if ($currentMembership) { | |
2446 | $activityType = 'Membership Renewal'; | |
2447 | $renewalMode = TRUE; | |
2448 | ||
2449 | // Do NOT do anything. | |
2450 | //1. membership with status : PENDING/CANCELLED (CRM-2395) | |
2451 | //2. Paylater/IPN renew. CRM-4556. | |
e0556ebe TO |
2452 | if ($pending || in_array($currentMembership['status_id'], array( |
2453 | array_search('Pending', $allStatus), | |
7ff60806 PN |
2454 | // CRM-15475 |
2455 | array_search('Cancelled', CRM_Member_PseudoConstant::membershipStatus(NULL, " name = 'Cancelled' ", 'name', FALSE, TRUE)), | |
c98997b9 EM |
2456 | )) |
2457 | ) { | |
2458 | $membership = new CRM_Member_DAO_Membership(); | |
2459 | $membership->id = $currentMembership['id']; | |
2460 | $membership->find(TRUE); | |
2461 | ||
2462 | // CRM-8141 create a membership_log entry so that we will know the membership_type_id to change to when payment completed | |
2463 | $format = '%Y%m%d'; | |
2464 | // note that we are logging the requested new membership_type_id that may be different than current membership_type_id | |
2465 | // it will be used when payment is received to update the membership_type_id to what was paid for | |
2466 | $logParams = array( | |
2467 | 'membership_id' => $membership->id, | |
2468 | 'status_id' => $membership->status_id, | |
2469 | 'start_date' => CRM_Utils_Date::customFormat( | |
2470 | $membership->start_date, | |
2471 | $format | |
2472 | ), | |
2473 | 'end_date' => CRM_Utils_Date::customFormat( | |
2474 | $membership->end_date, | |
2475 | $format | |
2476 | ), | |
2477 | 'modified_date' => CRM_Utils_Date::customFormat( | |
2478 | date('Ymd'), | |
2479 | $format | |
2480 | ), | |
2481 | 'membership_type_id' => $membershipTypeID, | |
ef0abb4c | 2482 | 'max_related' => !empty($membershipTypeDetails['max_related']) ? $membershipTypeDetails['max_related'] : NULL, |
c98997b9 EM |
2483 | ); |
2484 | $session = CRM_Core_Session::singleton(); | |
2485 | // If we have an authenticated session, set modified_id to that user's contact_id, else set to membership.contact_id | |
2486 | if ($session->get('userID')) { | |
2487 | $logParams['modified_id'] = $session->get('userID'); | |
2488 | } | |
2489 | else { | |
2490 | $logParams['modified_id'] = $membership->contact_id; | |
2491 | } | |
2492 | CRM_Member_BAO_MembershipLog::add($logParams, CRM_Core_DAO::$_nullArray); | |
2493 | ||
2494 | if (!empty($contributionRecurID)) { | |
2495 | CRM_Core_DAO::setFieldValue('CRM_Member_DAO_Membership', $membership->id, | |
2496 | 'contribution_recur_id', $contributionRecurID | |
2497 | ); | |
2498 | } | |
2499 | ||
f82cf0ed | 2500 | return array($membership, $renewalMode, $dates); |
c98997b9 EM |
2501 | } |
2502 | ||
2503 | // Check and fix the membership if it is STALE | |
2504 | self::fixMembershipStatusBeforeRenew($currentMembership, $changeToday); | |
2505 | ||
2506 | // Now Renew the membership | |
2507 | if (!$currentMembership['is_current_member']) { | |
2508 | // membership is not CURRENT | |
2509 | ||
2510 | // CRM-7297 Membership Upsell - calculate dates based on new membership type | |
2511 | $dates = CRM_Member_BAO_MembershipType::getRenewalDatesForMembershipType($currentMembership['id'], | |
2512 | $changeToday, | |
2513 | $membershipTypeID, | |
2514 | $numRenewTerms | |
2515 | ); | |
2516 | ||
2517 | $currentMembership['join_date'] = CRM_Utils_Date::customFormat($currentMembership['join_date'], $format); | |
2518 | $currentMembership['start_date'] = CRM_Utils_Array::value('start_date', $dates); | |
2519 | $currentMembership['end_date'] = CRM_Utils_Array::value('end_date', $dates); | |
2520 | $currentMembership['is_test'] = $is_test; | |
2521 | ||
2522 | if (!empty($membershipSource)) { | |
2523 | $currentMembership['source'] = $membershipSource; | |
2524 | } | |
2525 | else { | |
2526 | $currentMembership['source'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', | |
2527 | $currentMembership['id'], | |
2528 | 'source' | |
2529 | ); | |
2530 | } | |
2531 | ||
2532 | if (!empty($currentMembership['id'])) { | |
2533 | $ids['membership'] = $currentMembership['id']; | |
2534 | } | |
2535 | $memParams = $currentMembership; | |
2536 | $memParams['membership_type_id'] = $membershipTypeID; | |
2537 | ||
2538 | //set the log start date. | |
2539 | $memParams['log_start_date'] = CRM_Utils_Date::customFormat($dates['log_start_date'], $format); | |
2540 | } | |
2541 | else { | |
2542 | ||
2543 | // CURRENT Membership | |
2544 | $membership = new CRM_Member_DAO_Membership(); | |
2545 | $membership->id = $currentMembership['id']; | |
2546 | $membership->find(TRUE); | |
2547 | // CRM-7297 Membership Upsell - calculate dates based on new membership type | |
2548 | $dates = CRM_Member_BAO_MembershipType::getRenewalDatesForMembershipType($membership->id, | |
2549 | $changeToday, | |
2550 | $membershipTypeID, | |
2551 | $numRenewTerms | |
2552 | ); | |
2553 | ||
2554 | // Insert renewed dates for CURRENT membership | |
2555 | $memParams = array(); | |
2556 | $memParams['join_date'] = CRM_Utils_Date::isoToMysql($membership->join_date); | |
2557 | $memParams['start_date'] = CRM_Utils_Date::isoToMysql($membership->start_date); | |
2558 | $memParams['end_date'] = CRM_Utils_Array::value('end_date', $dates); | |
2559 | $memParams['membership_type_id'] = $membershipTypeID; | |
2560 | ||
2561 | //set the log start date. | |
2562 | $memParams['log_start_date'] = CRM_Utils_Date::customFormat($dates['log_start_date'], $format); | |
2563 | if (empty($membership->source)) { | |
2564 | if (!empty($membershipSource)) { | |
2565 | $memParams['source'] = $membershipSource; | |
2566 | } | |
2567 | else { | |
2568 | $memParams['source'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', | |
2569 | $currentMembership['id'], | |
2570 | 'source' | |
2571 | ); | |
2572 | } | |
2573 | } | |
2574 | ||
2575 | if (!empty($currentMembership['id'])) { | |
2576 | $ids['membership'] = $currentMembership['id']; | |
2577 | } | |
2578 | } | |
2579 | //CRM-4555 | |
2580 | if ($pending) { | |
2581 | $updateStatusId = array_search('Pending', $allStatus); | |
2582 | } | |
2583 | } | |
2584 | else { | |
2585 | // NEW Membership | |
2586 | ||
2587 | $activityType = 'Membership Signup'; | |
2588 | $memParams = array( | |
2589 | 'contact_id' => $contactID, | |
2590 | 'membership_type_id' => $membershipTypeID, | |
2591 | ); | |
2592 | ||
2593 | if (!$pending) { | |
2594 | $dates = CRM_Member_BAO_MembershipType::getDatesForMembershipType($membershipTypeID, NULL, NULL, NULL, $numRenewTerms); | |
2595 | ||
2596 | $memParams['join_date'] = CRM_Utils_Array::value('join_date', $dates); | |
2597 | $memParams['start_date'] = CRM_Utils_Array::value('start_date', $dates); | |
2598 | $memParams['end_date'] = CRM_Utils_Array::value('end_date', $dates); | |
2599 | ||
2600 | $status = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate(CRM_Utils_Date::customFormat($dates['start_date'], | |
2601 | $statusFormat | |
2602 | ), | |
2603 | CRM_Utils_Date::customFormat($dates['end_date'], | |
2604 | $statusFormat | |
2605 | ), | |
2606 | CRM_Utils_Date::customFormat($dates['join_date'], | |
2607 | $statusFormat | |
2608 | ), | |
2609 | 'today', | |
2610 | TRUE, | |
2611 | $membershipTypeID, | |
2612 | $memParams | |
2613 | ); | |
2614 | $updateStatusId = CRM_Utils_Array::value('id', $status); | |
2615 | } | |
2616 | else { | |
2617 | // if IPN/Pay-Later set status to: PENDING | |
2618 | $updateStatusId = array_search('Pending', $allStatus); | |
2619 | } | |
2620 | ||
2621 | if (!empty($membershipSource)) { | |
2622 | $memParams['source'] = $membershipSource; | |
2623 | } | |
2624 | $memParams['contribution_recur_id'] = $contributionRecurID; | |
2625 | ||
2626 | $memParams['is_test'] = $is_test; | |
2627 | $memParams['is_pay_later'] = $isPayLater; | |
2628 | } | |
2629 | ||
2630 | //CRM-4555 | |
2631 | //if we decided status here and want to skip status | |
2632 | //calculation in create( ); then need to pass 'skipStatusCal'. | |
2633 | if ($updateStatusId) { | |
2634 | $memParams['status_id'] = $updateStatusId; | |
2635 | $memParams['skipStatusCal'] = TRUE; | |
2636 | } | |
2637 | ||
2638 | //since we are renewing, | |
2639 | //make status override false. | |
2640 | $memParams['is_override'] = FALSE; | |
2641 | ||
2642 | //CRM-4027, create log w/ individual contact. | |
2643 | if ($modifiedID) { | |
2644 | $ids['userId'] = $modifiedID; | |
2645 | $memParams['is_for_organization'] = TRUE; | |
2646 | } | |
2647 | else { | |
2648 | $ids['userId'] = $contactID; | |
2649 | } | |
2650 | ||
2651 | //inherit campaign from contrib page. | |
2652 | if (isset($campaignId)) { | |
2653 | $memParams['campaign_id'] = $campaignId; | |
2654 | } | |
2655 | ||
2656 | $memParams['custom'] = $customFieldsFormatted; | |
2657 | $membership = self::create($memParams, $ids, FALSE, $activityType); | |
2658 | ||
2659 | // not sure why this statement is here, seems quite odd :( - Lobo: 12/26/2010 | |
2660 | // related to: http://forum.civicrm.org/index.php/topic,11416.msg49072.html#msg49072 | |
2661 | $membership->find(TRUE); | |
2662 | ||
2663 | return array($membership, $renewalMode, $dates); | |
2664 | } | |
2665 | ||
6a488035 | 2666 | /** |
100fef9d | 2667 | * Process price set and line items. |
6a488035 | 2668 | * |
100fef9d | 2669 | * @param int $membershipId |
e46e9a0b EM |
2670 | * @param $lineItem |
2671 | * | |
355ba699 | 2672 | * @return void |
6a488035 | 2673 | */ |
00be9182 | 2674 | public function processPriceSet($membershipId, $lineItem) { |
6a488035 TO |
2675 | //FIXME : need to move this too |
2676 | if (!$membershipId || !is_array($lineItem) | |
ca58d9b9 | 2677 | || CRM_Utils_System::isNull($lineItem) |
6a488035 TO |
2678 | ) { |
2679 | return; | |
2680 | } | |
2681 | ||
2682 | foreach ($lineItem as $priceSetId => $values) { | |
2683 | if (!$priceSetId) { | |
2684 | continue; | |
2685 | } | |
2686 | foreach ($values as $line) { | |
2687 | $line['entity_table'] = 'civicrm_membership'; | |
2688 | $line['entity_id'] = $membershipId; | |
2689 | CRM_Price_BAO_LineItem::create($line); | |
2690 | } | |
2691 | } | |
2692 | } | |
2693 | ||
2694 | /** | |
fe482240 | 2695 | * Retrieve the contribution id for the associated Membership id. |
ca266339 | 2696 | * @todo we should get this off the line item |
6a488035 | 2697 | * |
b2363ea8 TO |
2698 | * @param int $membershipId |
2699 | * Membership id. | |
6a488035 | 2700 | * |
df8d3074 | 2701 | * @return int |
a6c01b45 | 2702 | * contribution id |
6a488035 | 2703 | */ |
00be9182 | 2704 | public static function getMembershipContributionId($membershipId) { |
6a488035 | 2705 | |
ca266339 EM |
2706 | $membershipPayment = new CRM_Member_DAO_MembershipPayment(); |
2707 | $membershipPayment->membership_id = $membershipId; | |
2708 | if ($membershipPayment->find(TRUE)) { | |
2709 | return $membershipPayment->contribution_id; | |
6a488035 TO |
2710 | } |
2711 | return NULL; | |
2712 | } | |
2713 | ||
2714 | /** | |
e0556ebe TO |
2715 | * The function checks and updates the status of all membership records for a given domain using the |
2716 | * calc_membership_status and update_contact_membership APIs. | |
2717 | * | |
2718 | * IMPORTANT: | |
2719 | * Sending renewal reminders has been migrated from this job to the Scheduled Reminders function as of 4.3. | |
2720 | * | |
a6c01b45 | 2721 | * @return array |
e0556ebe | 2722 | */ |
00be9182 | 2723 | public static function updateAllMembershipStatus() { |
6a488035 TO |
2724 | |
2725 | //get all active statuses of membership, CRM-3984 | |
e0556ebe TO |
2726 | $allStatus = CRM_Member_PseudoConstant::membershipStatus(); |
2727 | $statusLabels = CRM_Member_PseudoConstant::membershipStatus(NULL, NULL, 'label'); | |
2728 | $allTypes = CRM_Member_PseudoConstant::membershipType(); | |
6a488035 | 2729 | |
85b6e9a2 | 2730 | // get only memberships with active membership types |
6a488035 TO |
2731 | $query = " |
2732 | SELECT civicrm_membership.id as membership_id, | |
2733 | civicrm_membership.is_override as is_override, | |
2734 | civicrm_membership.membership_type_id as membership_type_id, | |
2735 | civicrm_membership.status_id as status_id, | |
2736 | civicrm_membership.join_date as join_date, | |
2737 | civicrm_membership.start_date as start_date, | |
2738 | civicrm_membership.end_date as end_date, | |
2739 | civicrm_membership.source as source, | |
2740 | civicrm_contact.id as contact_id, | |
2741 | civicrm_contact.is_deceased as is_deceased, | |
2742 | civicrm_membership.owner_membership_id as owner_membership_id, | |
2743 | civicrm_membership.contribution_recur_id as recur_id | |
2744 | FROM civicrm_membership | |
2745 | INNER JOIN civicrm_contact ON ( civicrm_membership.contact_id = civicrm_contact.id ) | |
85b6e9a2 DL |
2746 | INNER JOIN civicrm_membership_type ON |
2747 | (civicrm_membership.membership_type_id = civicrm_membership_type.id AND civicrm_membership_type.is_active = 1) | |
6a488035 TO |
2748 | WHERE civicrm_membership.is_test = 0"; |
2749 | ||
2750 | $params = array(); | |
2751 | $dao = CRM_Core_DAO::executeQuery($query, $params); | |
2752 | ||
e0556ebe TO |
2753 | $processCount = 0; |
2754 | $updateCount = 0; | |
6a488035 TO |
2755 | |
2756 | $smarty = CRM_Core_Smarty::singleton(); | |
2757 | ||
2758 | while ($dao->fetch()) { | |
2759 | // echo "."; | |
2760 | $processCount++; | |
2761 | ||
6a488035 TO |
2762 | // Put common parameters into array for easy access |
2763 | $memberParams = array( | |
2764 | 'id' => $dao->membership_id, | |
2765 | 'status_id' => $dao->status_id, | |
2766 | 'contact_id' => $dao->contact_id, | |
2767 | 'membership_type_id' => $dao->membership_type_id, | |
2768 | 'membership_type' => $allTypes[$dao->membership_type_id], | |
2769 | 'join_date' => $dao->join_date, | |
2770 | 'start_date' => $dao->start_date, | |
2771 | 'end_date' => $dao->end_date, | |
2772 | 'source' => $dao->source, | |
2773 | 'skipStatusCal' => TRUE, | |
2774 | 'skipRecentView' => TRUE, | |
2775 | ); | |
2776 | ||
2777 | $smarty->assign_by_ref('memberParams', $memberParams); | |
2778 | ||
2779 | //update membership record to Deceased if contact is deceased | |
2780 | if ($dao->is_deceased) { | |
2781 | // check for 'Deceased' membership status, CRM-5636 | |
2782 | $deceaseStatusId = array_search('Deceased', $allStatus); | |
2783 | if (!$deceaseStatusId) { | |
2784 | CRM_Core_Error::fatal(ts("Deceased Membership status is missing or not active. <a href='%1'>Click here to check</a>.", array(1 => CRM_Utils_System::url('civicrm/admin/member/membershipStatus', 'reset=1')))); | |
2785 | } | |
2786 | ||
2787 | //process only when status change. | |
2788 | if ($dao->status_id != $deceaseStatusId) { | |
2789 | //take all params that need to save. | |
2790 | $deceasedMembership = $memberParams; | |
2791 | $deceasedMembership['status_id'] = $deceaseStatusId; | |
2792 | $deceasedMembership['createActivity'] = TRUE; | |
2793 | $deceasedMembership['version'] = 3; | |
2794 | ||
2795 | //since there is change in status. | |
2796 | $statusChange = array('status_id' => $deceaseStatusId); | |
2797 | $smarty->append_by_ref('memberParams', $statusChange, TRUE); | |
68cf2de1 | 2798 | unset( |
2799 | $deceasedMembership['contact_id'], | |
2800 | $deceasedMembership['membership_type_id'], | |
2801 | $deceasedMembership['membership_type'], | |
2802 | $deceasedMembership['join_date'], | |
2803 | $deceasedMembership['start_date'], | |
2804 | $deceasedMembership['end_date'], | |
2805 | $deceasedMembership['source'] | |
2806 | ); | |
6a488035 TO |
2807 | |
2808 | //process membership record. | |
2809 | civicrm_api('membership', 'create', $deceasedMembership); | |
2810 | } | |
2811 | continue; | |
2812 | } | |
2813 | ||
2814 | //we fetch related, since we need to check for deceased | |
2815 | //now further processing is handle w/ main membership record. | |
2816 | if ($dao->owner_membership_id) { | |
2817 | continue; | |
2818 | } | |
2819 | ||
2820 | //update membership records where status is NOT - Pending OR Cancelled. | |
2821 | //as well as membership is not override. | |
2822 | //skipping Expired membership records -> reduced extra processing( kiran ) | |
2823 | if (!$dao->is_override && | |
e0556ebe TO |
2824 | !in_array($dao->status_id, array( |
2825 | array_search('Pending', $allStatus), | |
2826 | // CRM-15475 | |
2827 | array_search( | |
2828 | 'Cancelled', | |
2829 | CRM_Member_PseudoConstant::membershipStatus(NULL, " name = 'Cancelled' ", 'name', FALSE, TRUE) | |
2830 | ), | |
2831 | array_search('Expired', $allStatus), | |
2832 | )) | |
6a488035 TO |
2833 | ) { |
2834 | ||
2835 | // CRM-7248: added excludeIsAdmin param to the following fn call to prevent moving to admin statuses | |
2836 | //get the membership status as per id. | |
2837 | $newStatus = civicrm_api('membership_status', 'calc', | |
2838 | array( | |
e0556ebe TO |
2839 | 'membership_id' => $dao->membership_id, |
2840 | 'version' => 3, | |
21dfd5f5 | 2841 | 'ignore_admin_only' => FALSE, |
e0556ebe | 2842 | ), TRUE |
6a488035 TO |
2843 | ); |
2844 | $statusId = CRM_Utils_Array::value('id', $newStatus); | |
2845 | ||
2846 | //process only when status change. | |
2847 | if ($statusId && | |
2848 | $statusId != $dao->status_id | |
2849 | ) { | |
2850 | //take all params that need to save. | |
2851 | $memParams = $memberParams; | |
2852 | $memParams['status_id'] = $statusId; | |
2853 | $memParams['createActivity'] = TRUE; | |
2854 | $memParams['version'] = 3; | |
2855 | ||
4daee127 | 2856 | // Unset columns which should remain unchanged from their current saved |
2857 | // values. This avoids race condition in which these values may have | |
2858 | // been changed by other processes. | |
2859 | unset( | |
2860 | $memParams['contact_id'], | |
2861 | $memParams['membership_type_id'], | |
2862 | $memParams['membership_type'], | |
2863 | $memParams['join_date'], | |
2864 | $memParams['start_date'], | |
2865 | $memParams['end_date'], | |
2866 | $memParams['source'] | |
2867 | ); | |
6a488035 TO |
2868 | //since there is change in status. |
2869 | $statusChange = array('status_id' => $statusId); | |
2870 | $smarty->append_by_ref('memberParams', $statusChange, TRUE); | |
2871 | ||
2872 | //process member record. | |
2873 | civicrm_api('membership', 'create', $memParams); | |
2874 | $updateCount++; | |
2875 | } | |
2876 | } | |
6a488035 TO |
2877 | } |
2878 | $result['is_error'] = 0; | |
e0556ebe | 2879 | $result['messages'] = ts('Processed %1 membership records. Updated %2 records.', array( |
353ffa53 TO |
2880 | 1 => $processCount, |
2881 | 2 => $updateCount, | |
2882 | )); | |
6a488035 TO |
2883 | return $result; |
2884 | } | |
2885 | ||
e46e9a0b | 2886 | /** |
688d37c6 | 2887 | * Returns the membership types for a particular contact |
6a488035 TO |
2888 | * who has lifetime membership without end date. |
2889 | * | |
100fef9d | 2890 | * @param int $contactID |
e46e9a0b EM |
2891 | * @param bool $isTest |
2892 | * @param bool $onlyLifeTime | |
6a488035 | 2893 | * |
e46e9a0b | 2894 | * @return array |
6a488035 | 2895 | */ |
00be9182 | 2896 | public static function getAllContactMembership($contactID, $isTest = FALSE, $onlyLifeTime = FALSE) { |
6a488035 TO |
2897 | $contactMembershipType = array(); |
2898 | if (!$contactID) { | |
2899 | return $contactMembershipType; | |
2900 | } | |
2901 | ||
e0556ebe | 2902 | $dao = new CRM_Member_DAO_Membership(); |
6a488035 TO |
2903 | $dao->contact_id = $contactID; |
2904 | $pendingStatusId = array_search('Pending', CRM_Member_PseudoConstant::membershipStatus()); | |
2905 | $dao->whereAdd("status_id != $pendingStatusId"); | |
2906 | ||
2907 | if ($isTest) { | |
2908 | $dao->is_test = $isTest; | |
2909 | } | |
2910 | else { | |
2911 | $dao->whereAdd('is_test IS NULL OR is_test = 0'); | |
2912 | } | |
2913 | ||
2914 | if ($onlyLifeTime) { | |
2915 | $dao->whereAdd('end_date IS NULL'); | |
2916 | } | |
2917 | ||
2918 | $dao->find(); | |
2919 | while ($dao->fetch()) { | |
2920 | $membership = array(); | |
2921 | CRM_Core_DAO::storeValues($dao, $membership); | |
2922 | $contactMembershipType[$dao->membership_type_id] = $membership; | |
2923 | } | |
2924 | return $contactMembershipType; | |
2925 | } | |
2926 | ||
2927 | /** | |
fe482240 | 2928 | * Record contribution record associated with membership. |
6a488035 | 2929 | * |
b2363ea8 TO |
2930 | * @param array $params |
2931 | * Array of submitted params. | |
2932 | * @param array $ids | |
2933 | * (param in process of being removed - try to use params) array of ids. | |
6a488035 | 2934 | * |
02af3683 | 2935 | * @return CRM_Contribute_BAO_Contribution |
6a488035 | 2936 | */ |
e0556ebe | 2937 | public static function recordMembershipContribution(&$params, $ids = array()) { |
d824fb6e | 2938 | $membershipId = $params['membership_id']; |
6a488035 TO |
2939 | $contributionParams = array(); |
2940 | $config = CRM_Core_Config::singleton(); | |
2941 | $contributionParams['currency'] = $config->defaultCurrency; | |
2942 | $contributionParams['receipt_date'] = (CRM_Utils_Array::value('receipt_date', $params)) ? $params['receipt_date'] : 'null'; | |
2943 | $contributionParams['source'] = CRM_Utils_Array::value('contribution_source', $params); | |
6a488035 | 2944 | $contributionParams['non_deductible_amount'] = 'null'; |
dcb032dc | 2945 | $contributionParams['payment_processor'] = CRM_Utils_Array::value('payment_processor_id', $params); |
d80dbc14 | 2946 | $contributionSoftParams = CRM_Utils_Array::value('soft_credit', $params); |
6a488035 | 2947 | $recordContribution = array( |
e0556ebe TO |
2948 | 'contact_id', |
2949 | 'total_amount', | |
2950 | 'receive_date', | |
2951 | 'financial_type_id', | |
2952 | 'payment_instrument_id', | |
2953 | 'trxn_id', | |
2954 | 'invoice_id', | |
2955 | 'is_test', | |
2956 | 'contribution_status_id', | |
2957 | 'check_number', | |
2958 | 'campaign_id', | |
2959 | 'is_pay_later', | |
2960 | 'membership_id', | |
2961 | 'tax_amount', | |
21dfd5f5 | 2962 | 'skipLineItem', |
6a488035 TO |
2963 | ); |
2964 | foreach ($recordContribution as $f) { | |
2965 | $contributionParams[$f] = CRM_Utils_Array::value($f, $params); | |
2966 | } | |
2967 | ||
2968 | // make entry in batch entity batch table | |
a7488080 | 2969 | if (!empty($params['batch_id'])) { |
6a488035 TO |
2970 | $contributionParams['batch_id'] = $params['batch_id']; |
2971 | } | |
2972 | ||
91ef9be0 | 2973 | if (!empty($params['contribution_contact_id'])) { |
2974 | // deal with possibility of a different person paying for contribution | |
2975 | $contributionParams['contact_id'] = $params['contribution_contact_id']; | |
2976 | } | |
2977 | ||
a7488080 | 2978 | if (!empty($params['processPriceSet']) && |
6a488035 TO |
2979 | !empty($params['lineItems']) |
2980 | ) { | |
2981 | $contributionParams['line_item'] = CRM_Utils_Array::value('lineItems', $params, NULL); | |
2982 | } | |
2983 | ||
2984 | $contribution = CRM_Contribute_BAO_Contribution::create($contributionParams, $ids); | |
2985 | ||
c206647d | 2986 | //CRM-13981, create new soft-credit record as to record payment from different person for this membership |
d80dbc14 | 2987 | if (!empty($contributionSoftParams)) { |
9e1854a1 | 2988 | if (!empty($params['batch_id'])) { |
2989 | foreach ($contributionSoftParams as $contributionSoft) { | |
2990 | $contributionSoft['contribution_id'] = $contribution->id; | |
2991 | $contributionSoft['currency'] = $contribution->currency; | |
2992 | CRM_Contribute_BAO_ContributionSoft::add($contributionSoft); | |
2993 | } | |
2994 | } | |
2995 | else { | |
e0556ebe TO |
2996 | $contributionSoftParams['contribution_id'] = $contribution->id; |
2997 | $contributionSoftParams['currency'] = $contribution->currency; | |
2998 | $contributionSoftParams['amount'] = $contribution->total_amount; | |
2999 | CRM_Contribute_BAO_ContributionSoft::add($contributionSoftParams); | |
a54e2c55 | 3000 | } |
d80dbc14 | 3001 | } |
3002 | ||
6a488035 TO |
3003 | // store contribution id |
3004 | $params['contribution_id'] = $contribution->id; | |
3005 | ||
6a488035 | 3006 | //insert payment record for this membership |
8cc574cf | 3007 | if (empty($ids['contribution']) || !empty($params['is_recur'])) { |
e0556ebe | 3008 | CRM_Member_BAO_MembershipPayment::create(array( |
353ffa53 TO |
3009 | 'membership_id' => $membershipId, |
3010 | 'contribution_id' => $contribution->id, | |
3011 | )); | |
6a488035 TO |
3012 | } |
3013 | return $contribution; | |
3014 | } | |
3015 | ||
3016 | /** | |
fe482240 | 3017 | * Record line items for default membership. |
6a488035 | 3018 | * |
c490a46a | 3019 | * @param CRM_Core_Form $qf |
b2363ea8 TO |
3020 | * @param array $membershipType |
3021 | * Array with membership type and organization. | |
c490a46a | 3022 | * @param int $priceSetId |
e46e9a0b | 3023 | * |
6a488035 | 3024 | */ |
00be9182 | 3025 | public static function createLineItems(&$qf, $membershipType, &$priceSetId) { |
9da8dc8c | 3026 | $qf->_priceSetId = $priceSetId = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', 'default_membership_type_amount', 'id', 'name'); |
6a488035 | 3027 | if ($priceSetId) { |
9da8dc8c | 3028 | $qf->_priceSet = $priceSets = current(CRM_Price_BAO_PriceSet::getSetDetail($priceSetId)); |
6a488035 TO |
3029 | } |
3030 | $editedFieldParams = array( | |
3031 | 'price_set_id' => $priceSetId, | |
3032 | 'name' => $membershipType[0], | |
3033 | ); | |
3034 | $editedResults = array(); | |
9da8dc8c | 3035 | CRM_Price_BAO_PriceField::retrieve($editedFieldParams, $editedResults); |
6a488035 TO |
3036 | |
3037 | if (!empty($editedResults)) { | |
3038 | unset($qf->_priceSet['fields']); | |
3039 | $qf->_priceSet['fields'][$editedResults['id']] = $priceSets['fields'][$editedResults['id']]; | |
3040 | unset($qf->_priceSet['fields'][$editedResults['id']]['options']); | |
3041 | $fid = $editedResults['id']; | |
3042 | $editedFieldParams = array( | |
3043 | 'price_field_id' => $editedResults['id'], | |
3044 | 'membership_type_id' => $membershipType[1], | |
3045 | ); | |
3046 | $editedResults = array(); | |
9da8dc8c | 3047 | CRM_Price_BAO_PriceFieldValue::retrieve($editedFieldParams, $editedResults); |
6a488035 | 3048 | $qf->_priceSet['fields'][$fid]['options'][$editedResults['id']] = $priceSets['fields'][$fid]['options'][$editedResults['id']]; |
a7488080 | 3049 | if (!empty($qf->_params['total_amount'])) { |
6a488035 TO |
3050 | $qf->_priceSet['fields'][$fid]['options'][$editedResults['id']]['amount'] = $qf->_params['total_amount']; |
3051 | } | |
3052 | } | |
3053 | ||
3054 | $fieldID = key($qf->_priceSet['fields']); | |
3055 | $qf->_params['price_' . $fieldID] = CRM_Utils_Array::value('id', $editedResults); | |
3056 | } | |
8ef12e64 | 3057 | |
e46e9a0b EM |
3058 | /** |
3059 | * @todo document me - I seem a bit out of date.... | |
3060 | */ | |
00be9182 | 3061 | public static function _getActTypes() { |
4e636a74 AH |
3062 | $activityTypes = CRM_Core_PseudoConstant::activityType(TRUE, FALSE, FALSE, 'name'); |
3063 | self::$_renewalActType = CRM_Utils_Array::key('Membership Renewal', $activityTypes); | |
3064 | self::$_signupActType = CRM_Utils_Array::key('Membership Signup', $activityTypes); | |
3065 | } | |
5624f515 | 3066 | |
b5a62499 PN |
3067 | /** |
3068 | * Get all Cancelled Membership(s) for a contact | |
3069 | * | |
b2363ea8 TO |
3070 | * @param int $contactID |
3071 | * Contact id. | |
3072 | * @param bool $isTest | |
3073 | * Mode of payment. | |
b5a62499 | 3074 | * |
a6c01b45 | 3075 | * @return array |
16b10e64 | 3076 | * Array of membership type |
b5a62499 | 3077 | */ |
00be9182 | 3078 | public static function getContactsCancelledMembership($contactID, $isTest = FALSE) { |
b5a62499 PN |
3079 | if (!$contactID) { |
3080 | return array(); | |
5624f515 | 3081 | } |
b5a62499 PN |
3082 | $query = 'SELECT membership_type_id FROM civicrm_membership WHERE contact_id = %1 AND status_id = %2 AND is_test = %3'; |
3083 | $queryParams = array( | |
3084 | 1 => array($contactID, 'Integer'), | |
7ff60806 PN |
3085 | 2 => array( |
3086 | // CRM-15475 | |
3087 | array_search( | |
4c16123d | 3088 | 'Cancelled', |
7ff60806 | 3089 | CRM_Member_PseudoConstant::membershipStatus( |
4c16123d EM |
3090 | NULL, |
3091 | " name = 'Cancelled' ", | |
3092 | 'name', | |
3093 | FALSE, | |
7ff60806 PN |
3094 | TRUE |
3095 | ) | |
4c16123d | 3096 | ), |
21dfd5f5 | 3097 | 'Integer', |
7ff60806 | 3098 | ), |
b5a62499 PN |
3099 | 3 => array($isTest, 'Boolean'), |
3100 | ); | |
5624f515 | 3101 | |
b5a62499 PN |
3102 | $dao = CRM_Core_DAO::executeQuery($query, $queryParams); |
3103 | $cancelledMembershipIds = array(); | |
3104 | while ($dao->fetch()) { | |
3105 | $cancelledMembershipIds[] = $dao->membership_type_id; | |
3106 | } | |
3107 | return $cancelledMembershipIds; | |
3108 | } | |
96025800 | 3109 | |
6a488035 | 3110 | } |