3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.6 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2015 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
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. |
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. |
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 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2015
35 class CRM_Member_BAO_Membership
extends CRM_Member_DAO_Membership
{
38 * Static field for all the membership information that we can potentially import.
42 static $_importableFields = NULL;
44 static $_renewalActType = NULL;
46 static $_signupActType = NULL;
51 * @return \CRM_Member_DAO_Membership
55 public function __construct() {
56 parent
::__construct();
60 * Takes an associative array and creates a membership object.
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
66 * @param array $params
67 * (reference ) an assoc array of name/value pairs.
69 * The array that holds all the db ids.
71 * @return CRM_Member_BAO_Membership
73 public static function add(&$params, $ids = array()) {
74 $oldStatus = $oldType = NULL;
75 $params['id'] = CRM_Utils_Array
::value('id', $params, CRM_Utils_Array
::value('membership', $ids));
77 CRM_Utils_Hook
::pre('edit', 'Membership', $params['id'], $params);
80 CRM_Utils_Hook
::pre('create', 'Membership', NULL, $params);
83 // we do this after the hooks are called in case it has been altered
85 $membershipObj = new CRM_Member_DAO_Membership();
86 $membershipObj->id
= $id;
87 $membershipObj->find();
88 while ($membershipObj->fetch()) {
89 $oldStatus = $membershipObj->status_id
;
90 $oldType = $membershipObj->membership_type_id
;
94 if (array_key_exists('is_override', $params) && !$params['is_override']) {
95 $params['is_override'] = 'null';
98 $membership = new CRM_Member_BAO_Membership();
99 $membership->copyValues($params);
100 $membership->id
= $id;
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
108 // however the hooks don't care and want all data CRM-7784
109 $tempMembership = new CRM_Member_DAO_Membership();
110 $tempMembership->id
= $membership->id
;
111 $tempMembership->find(TRUE);
112 $membership = $tempMembership;
115 //get the log start date.
116 //it is set during renewal of membership.
117 $logStartDate = CRM_Utils_Array
::value('log_start_date', $params);
118 $logStartDate = ($logStartDate) ? CRM_Utils_Date
::isoToMysql($logStartDate) : CRM_Utils_Date
::isoToMysql($membership->start_date
);
119 $values = self
::getStatusANDTypeValues($membership->id
);
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
,
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');
136 elseif (!empty($ids['userId'])) {
137 $membershipLog['modified_id'] = $ids['userId'];
140 $membershipLog['modified_id'] = $membership->contact_id
;
143 CRM_Member_BAO_MembershipLog
::add($membershipLog, CRM_Core_DAO
::$_nullArray);
145 // reset the group contact cache since smart groups might be affected due to this
146 CRM_Contact_BAO_GroupContactCache
::remove();
149 if ($membership->status_id
!= $oldStatus) {
150 $allStatus = CRM_Member_BAO_Membership
::buildOptions('status_id', 'get');
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
,
156 'activity_type_id' => CRM_Core_PseudoConstant
::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Change Membership Status'),
159 'activity_date_time' => date('Y-m-d H:i:s'),
161 civicrm_api3('activity', 'create', $activityParam);
163 if (isset($membership->membership_type_id
) && $membership->membership_type_id
!= $oldType) {
164 $membershipTypes = CRM_Member_BAO_Membership
::buildOptions('membership_type_id', 'get');
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
,
170 'activity_type_id' => CRM_Core_PseudoConstant
::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Change Membership Type'),
173 'activity_date_time' => date('Y-m-d H:i:s'),
175 civicrm_api3('activity', 'create', $activityParam);
177 CRM_Utils_Hook
::post('edit', 'Membership', $membership->id
, $membership);
180 CRM_Utils_Hook
::post('create', 'Membership', $membership->id
, $membership);
187 * Given the list of params in the params array, fetch the object
188 * and store the values in the values array
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.
197 * @param bool $relatedMemberships
198 * @return CRM_Member_BAO_Membership|null the found object or null
200 public static function &getValues(&$params, &$values, $active = FALSE, $relatedMemberships = FALSE) {
201 if (empty($params)) {
204 $membership = new CRM_Member_BAO_Membership();
206 $membership->copyValues($params);
208 $memberships = array();
209 while ($membership->fetch()) {
211 (!CRM_Core_DAO
::getFieldValue('CRM_Member_DAO_MembershipStatus',
212 $membership->status_id
,
219 CRM_Core_DAO
::storeValues($membership, $values[$membership->id
]);
220 $memberships[$membership->id
] = $membership;
221 if ($relatedMemberships && !empty($membership->owner_membership_id
)) {
222 $values['owner_membership_ids'][] = $membership->owner_membership_id
;
230 * Takes an associative array and creates a membership object.
232 * @param array $params
233 * (reference ) an assoc array of name/value pairs.
235 * The array that holds all the db ids.
236 * @param bool $skipRedirect
237 * @param string $activityType
239 * @throws CRM_Core_Exception
241 * @return CRM_Member_BAO_Membership|CRM_Core_Error
243 public static function create(&$params, &$ids, $skipRedirect = FALSE, $activityType = 'Membership Signup') {
244 // always calculate status if is_override/skipStatusCal is not true.
245 // giving respect to is_override during import. CRM-4012
247 // To skip status calculation we should use 'skipStatusCal'.
248 // eg pay later membership, membership update cron CRM-3984
250 if (empty($params['is_override']) && empty($params['skipStatusCal'])) {
251 $dates = array('start_date', 'end_date', 'join_date');
252 $start_date = $end_date = $join_date = NULL; // declare these out of courtesy as IDEs don't pick up the setting of them below
253 foreach ($dates as $date) {
254 $
$date = $params[$date] = CRM_Utils_Date
::processDate(CRM_Utils_Array
::value($date, $params), NULL, TRUE, 'Ymd');
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);
260 //CRM-3724 always skip is_admin if is_override != true.
261 if (!$excludeIsAdmin && empty($params['is_override'])) {
262 $excludeIsAdmin = TRUE;
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'];
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
276 if (empty($calcStatus)) {
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",
287 throw new CRM_Core_Exception(ts('The membership cannot be saved because the status cannot be calculated.'), 0, $errorParams);
289 $params['status_id'] = $calcStatus['id'];
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']);
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);
308 $transaction = new CRM_Core_Transaction();
310 $membership = self
::add($params, $ids);
312 if (is_a($membership, 'CRM_Core_Error')) {
313 $transaction->rollback();
317 // add custom field values
318 if (!empty($params['custom']) && is_array($params['custom'])
320 CRM_Core_BAO_CustomValueTable
::store($params['custom'], 'civicrm_membership', $membership->id
);
323 $params['membership_id'] = $membership->id
;
324 if (isset($ids['membership'])) {
325 $ids['contribution'] = CRM_Core_DAO
::getFieldValue('CRM_Member_DAO_MembershipPayment',
332 $params['skipLineItem'] = TRUE;
334 //record contribution for this membership
335 if (!empty($params['contribution_status_id']) && empty($params['relate_contribution_id'])) {
336 $memInfo = array_merge($params, array('membership_id' => $membership->id
));
337 $params['contribution'] = self
::recordMembershipContribution($memInfo, $ids);
340 if (!empty($params['lineItems'])) {
341 $params['line_item'] = $params['lineItems'];
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');
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));
353 //insert payment record for this membership
354 if (!empty($params['relate_contribution_id'])) {
355 CRM_Member_BAO_MembershipPayment
::create(array(
356 'membership_id' => $membership->id
,
357 'contribution_id' => $params['relate_contribution_id'],
361 // add activity record only during create mode and renew mode
362 // also add activity if status changed CRM-3984 and CRM-2521
363 if (empty($ids['membership']) ||
364 $activityType == 'Membership Renewal' ||
!empty($params['createActivity'])
366 if (!empty($ids['membership'])) {
368 CRM_Core_DAO
::commonRetrieveAll('CRM_Member_DAO_Membership',
372 array('contact_id', 'membership_type_id', 'source')
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
]);
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
;
385 // create activity source = individual, target = org CRM-4027
386 $targetContactID = NULL;
387 if (!empty($params['is_for_organization'])) {
388 $targetContactID = $membership->contact_id
;
389 $membership->contact_id
= CRM_Utils_Array
::value('userId', $ids);
392 if (empty($membership->contact_id
) && (!empty($membership->owner_membership_id
))) {
393 $membership->contact_id
= $realMembershipContactId;
396 if (!empty($ids['membership']) && $activityType != 'Membership Signup') {
397 CRM_Activity_BAO_Activity
::addActivity($membership, $activityType, $targetContactID);
399 elseif (empty($ids['membership'])) {
400 CRM_Activity_BAO_Activity
::addActivity($membership, $activityType, $targetContactID);
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;
409 $transaction->commit();
411 self
::createRelatedMemberships($params, $membership);
413 // do not add to recent items for import, CRM-4399
414 if (empty($params['skipRecentView'])) {
415 $url = CRM_Utils_System
::url('civicrm/contact/view/membership',
416 "action=view&reset=1&id={$membership->id}&cid={$membership->contact_id}&context=home"
418 if (empty($membership->membership_type_id
)) {// ie in an update situation
419 $membership->find(TRUE);
421 $membershipTypes = CRM_Member_PseudoConstant
::membershipType();
422 $title = CRM_Contact_BAO_Contact
::displayName($membership->contact_id
) . ' - ' . ts('Membership Type:') . ' ' . $membershipTypes[$membership->membership_type_id
];
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"
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"
436 // add the recently created Membership
437 CRM_Utils_Recent
::add($title,
441 $membership->contact_id
,
451 * Check the membership extended through relationship.
453 * @param int $membershipId
455 * @param int $contactId
461 * array of contact_id of all related contacts.
463 public static function checkMembershipRelationship($membershipId, $contactId, $action = CRM_Core_Action
::ADD
) {
465 $membershipTypeID = CRM_Core_DAO
::getFieldValue('CRM_Member_DAO_Membership', $membershipId, 'membership_type_id');
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
473 if ($action & CRM_Core_Action
::UPDATE
) {
474 $pastRelationships = CRM_Contact_BAO_Relationship
::getRelationship($contactId,
475 CRM_Contact_BAO_Relationship
::PAST
477 $relationships = array_merge($relationships, $pastRelationships);
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
489 $relTypeDirs = array();
490 $relTypeIds = explode(CRM_Core_DAO
::VALUE_SEPARATOR
, $membershipType['relationship_type_id']);
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']
498 $bidirectional = TRUE;
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'];
511 // Sort by contact_id ascending
517 * Retrieve DB object based on input parameters.
519 * It also stores all the retrieved values in the default array.
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.
525 * in a hierarchical manner
527 * @return CRM_Member_BAO_Membership
529 public static function retrieve(&$params, &$defaults) {
530 $membership = new CRM_Member_DAO_Membership();
532 $membership->copyValues($params);
534 if ($membership->find(TRUE)) {
535 CRM_Core_DAO
::storeValues($membership, $defaults);
537 //get the membership status and type values.
538 $statusANDType = self
::getStatusANDTypeValues($membership->id
);
543 $defaults[$fld] = CRM_Utils_Array
::value($fld, $statusANDType[$membership->id
]);
545 if (!empty($statusANDType[$membership->id
]['is_current_member'])) {
546 $defaults['active'] = TRUE;
559 * get membership status and membership type values
561 * @param int $membershipId
562 * Membership id of values to return.
565 * Array of key value pairs
567 public static function getStatusANDTypeValues($membershipId) {
569 if (!$membershipId) {
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')));
589 'membership_type_id',
591 'relationship_type_id',
593 while ($dao->fetch()) {
594 foreach ($properties as $property) {
595 $values[$dao->id
][$property] = $dao->$property;
604 * Wrapper for most delete calls. Use this unless you JUST want to delete related memberships w/o deleting the parent.
606 * @param int $membershipId
607 * Membership id that needs to be deleted.
610 * @return int $results id of deleted Membership on success, false otherwise
612 public static function del($membershipId) {
613 //delete related first and then delete parent.
614 self
::deleteRelatedMemberships($membershipId);
615 return self
::deleteMembership($membershipId);
621 * @param int $membershipId
622 * Membership id that needs to be deleted.
625 * @return int $results id of deleted Membership on success, false otherwise
627 public static function deleteMembership($membershipId) {
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);
633 $membership = $memberships[$membershipId];
635 CRM_Utils_Hook
::pre('delete', 'Membership', $membershipId, $memValues);
637 $transaction = new CRM_Core_Transaction();
640 //delete activity record
641 $activityTypes = CRM_Core_PseudoConstant
::activityType(TRUE, FALSE, FALSE, 'name');
644 $deleteActivity = FALSE;
645 $membershipActivities = array(
647 'Membership Renewal',
648 'Change Membership Status',
649 'Change Membership Type',
650 'Membership Renewal Reminder',
652 foreach ($membershipActivities as $membershipActivity) {
653 $activityId = array_search($membershipActivity, $activityTypes);
655 $params['activity_type_id'][] = $activityId;
656 $deleteActivity = TRUE;
659 if ($deleteActivity) {
660 $params['source_record_id'] = $membershipId;
661 CRM_Activity_BAO_Activity
::deleteActivity($params);
663 self
::deleteMembershipPayment($membershipId);
665 $results = $membership->delete();
666 $transaction->commit();
668 CRM_Utils_Hook
::post('delete', 'Membership', $membership->id
, $membership);
670 // delete the recently created Membership
671 $membershipRecent = array(
672 'id' => $membershipId,
673 'type' => 'Membership',
675 CRM_Utils_Recent
::del($membershipRecent);
681 * Delete related memberships.
683 * @param int $ownerMembershipId
684 * @param int $contactId
688 public static function deleteRelatedMemberships($ownerMembershipId, $contactId = NULL) {
689 if (!$ownerMembershipId && !$contactId) {
693 $membership = new CRM_Member_DAO_Membership();
694 $membership->owner_membership_id
= $ownerMembershipId;
697 $membership->contact_id
= $contactId;
701 while ($membership->fetch()) {
702 //delete related first and then delete parent.
703 self
::deleteRelatedMemberships($membership->id
);
704 self
::deleteMembership($membership->id
);
710 * Obtain active/inactive memberships from the list of memberships passed to it.
712 * @param array $memberships
713 * Membership records.
714 * @param string $status
715 * Active or inactive.
718 * array of memberships based on status
720 public static function activeMembers($memberships, $status = 'active') {
722 if ($status == 'active') {
723 foreach ($memberships as $f => $v) {
724 if (!empty($v['active'])) {
730 elseif ($status == 'inactive') {
731 foreach ($memberships as $f => $v) {
732 if (empty($v['active'])) {
742 * Build Membership Block in Contribution Pages.
744 * @param CRM_Core_Form $form
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
755 * @param null $isTest
758 * Is this a separate membership payment
761 public static function buildMembershipBlock(
766 $selectedMembershipTypeID = NULL,
771 $separateMembershipPayment = FALSE;
772 if ($form->_membershipBlock
) {
773 $form->_currentMemberships
= array();
775 $membershipBlock = $form->_membershipBlock
;
776 $membershipTypeIds = $membershipTypes = $radio = array();
777 $membershipPriceset = (!empty($form->_priceSetId
) && $form->_useForMember
) ?
TRUE : FALSE;
779 $allowAutoRenewMembership = $autoRenewOption = FALSE;
780 $autoRenewMembershipTypeOptions = array();
782 $paymentProcessor = CRM_Core_PseudoConstant
::paymentProcessor(FALSE, FALSE, 'is_recur = 1');
784 $separateMembershipPayment = CRM_Utils_Array
::value('is_separate_payment', $membershipBlock);
786 if ($membershipPriceset) {
787 foreach ($form->_priceSet
['fields'] as $pField) {
788 if (empty($pField['options'])) {
791 foreach ($pField['options'] as $opId => $opValues) {
792 if (empty($opValues['membership_type_id'])) {
795 $membershipTypeIds[$opValues['membership_type_id']] = $opValues['membership_type_id'];
799 elseif (!empty($membershipBlock['membership_types'])) {
800 $membershipTypeIds = explode(',', $membershipBlock['membership_types']);
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',
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');
815 $membershipTypeValues = self
::buildMembershipTypeValues($form, $membershipTypeIds);
816 $form->_membershipTypeValues
= $membershipTypeValues;
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)
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
;
836 $membershipTypes[] = $memType;
839 elseif ($memType['is_active']) {
840 $javascriptMethod = NULL;
841 $allowAutoRenewOpt = 1;
842 if (is_array($form->_paymentProcessors
)) {
843 foreach ($form->_paymentProcessors
as $id => $val) {
844 if (!$val['is_recur']) {
845 $allowAutoRenewOpt = 0;
851 $javascriptMethod = array('onclick' => "return showHideAutoRenew( this.value );");
852 $autoRenewMembershipTypeOptions["autoRenewMembershipType_{$value}"] = (int) $allowAutoRenewOpt * CRM_Utils_Array
::value($value, CRM_Utils_Array
::value('auto_renew', $form->_membershipBlock
));;
854 if ($allowAutoRenewOpt) {
855 $allowAutoRenewMembership = TRUE;
858 //add membership type.
859 $radio[$memType['id']] = $form->createElement('radio', NULL, NULL, NULL,
860 $memType['id'], $javascriptMethod
863 $membership = new CRM_Member_DAO_Membership();
864 $membership->contact_id
= $cid;
865 $membership->membership_type_id
= $memType['id'];
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');
871 if (!is_null($isTest)) {
872 $membership->is_test
= $isTest;
876 $membership->orderBy('end_date DESC');
878 if ($membership->find(TRUE)) {
879 if (!$membership->end_date
) {
880 unset($radio[$memType['id']]);
881 $form->assign('islifetime', TRUE);
884 $form->assign('renewal_mode', TRUE);
885 $form->_currentMemberships
[$membership->membership_type_id
] = $membership->membership_type_id
;
886 $memType['current_membership'] = $membership->end_date
;
888 $endDate = $memType['current_membership'];
889 $form->_defaultMemTypeId
= $memType['id'];
891 if ($memType['current_membership'] < $endDate) {
892 $endDate = $memType['current_membership'];
893 $form->_defaultMemTypeId
= $memType['id'];
897 $membershipTypes[] = $memType;
902 $form->assign('showRadio', $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);
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);
917 $form->addGroup($radio, 'selectMembership', NULL);
920 $form->addRule('selectMembership', ts('Please select one of the memberships.'), 'required');
923 $autoRenewOption = CRM_Price_BAO_PriceSet
::checkAutoRenewForPriceSet($form->_priceSetId
);
924 $form->assign('autoRenewOption', $autoRenewOption);
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.'));
933 $form->assign('membershipBlock', $membershipBlock);
934 $form->assign('membershipTypes', $membershipTypes);
935 $form->assign('allowAutoRenewMembership', $allowAutoRenewMembership);
936 $form->assign('autoRenewMembershipTypeOptions', json_encode($autoRenewMembershipTypeOptions));
938 //give preference to user submitted auto_renew value.
939 $takeUserSubmittedAutoRenew = (!empty($_POST) ||
$form->isSubmitted()) ?
TRUE : FALSE;
940 $form->assign('takeUserSubmittedAutoRenew', $takeUserSubmittedAutoRenew);
943 return $separateMembershipPayment;
947 * Return Membership Block info in Contribution Pages.
950 * Contribution page id.
955 public static function getMembershipBlock($pageID) {
956 $membershipBlock = array();
957 $dao = new CRM_Member_DAO_MembershipBlock();
958 $dao->entity_table
= 'civicrm_contribution_page';
960 $dao->entity_id
= $pageID;
962 if ($dao->find(TRUE)) {
963 CRM_Core_DAO
::storeValues($dao, $membershipBlock);
964 if (!empty($membershipBlock['membership_types'])) {
965 $membershipTypes = unserialize($membershipBlock['membership_types']);
966 if (!is_array($membershipTypes)) {
967 return $membershipBlock;
970 foreach ($membershipTypes as $key => $value) {
971 $membershipBlock['auto_renew'][$key] = $value;
972 $memTypes[$key] = $key;
974 $membershipBlock['membership_types'] = implode(',', $memTypes);
981 return $membershipBlock;
985 * Return a current membership of given contact.
986 * NB: if more than one membership meets criteria, a randomly selected one is returned.
988 * @param int $contactID
990 * @param int $memType
991 * Membership type, null to retrieve all types.
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.
1000 public static function getContactMembership($contactID, $memType, $isTest, $membershipId = NULL, $onlySameParentOrg = FALSE) {
1001 $dao = new CRM_Member_DAO_Membership();
1002 if ($membershipId) {
1003 $dao->id
= $membershipId;
1005 $dao->contact_id
= $contactID;
1006 $dao->membership_type_id
= $memType;
1008 //fetch proper membership record.
1010 $dao->is_test
= $isTest;
1013 $dao->whereAdd('is_test IS NULL OR is_test = 0');
1016 //avoid pending membership as current membership: CRM-3027
1017 $statusIds[] = array_search('Pending', CRM_Member_PseudoConstant
::membershipStatus());
1018 if (!$membershipId) {
1020 $statusIds[] = array_search(
1022 CRM_Member_PseudoConstant
::membershipStatus(
1024 " name = 'Cancelled' ",
1031 $dao->whereAdd('status_id NOT IN ( ' . implode(',', $statusIds) . ')');
1033 // order by start date to find most recent membership first, CRM-4545
1034 $dao->orderBy('start_date DESC');
1037 if ($onlySameParentOrg && $memType) {
1038 // require the same parent org as the $memType
1039 $params = array('id' => $memType);
1040 $membershipType = array();
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 . ')');
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'
1059 if ($onlySameParentOrg && $memType) {
1060 // see if there is a membership that has same parent as $memType but different parent than $membershipID
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.
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'
1084 * Combine all the importable fields from the lower levels object.
1086 * @param string $contactType
1088 * @param bool $status
1091 * array of importable Fields
1093 public static function &importableFields($contactType = 'Individual', $status = TRUE) {
1094 if (!self
::$_importableFields) {
1095 if (!self
::$_importableFields) {
1096 self
::$_importableFields = array();
1100 $fields = array('' => array('title' => '- ' . ts('do not import') . ' -'));
1103 $fields = array('' => array('title' => '- ' . ts('Membership Fields') . ' -'));
1106 $tmpFields = CRM_Member_DAO_Membership
::import();
1107 $contactFields = CRM_Contact_BAO_Contact
::importableFields($contactType, NULL);
1109 // Using new Dedupe rule.
1110 $ruleParams = array(
1111 'contact_type' => $contactType,
1112 'used' => 'Unsupervised',
1114 $fieldsArray = CRM_Dedupe_BAO_Rule
::dedupeRuleFields($ruleParams);
1116 $tmpContactField = array();
1117 if (is_array($fieldsArray)) {
1118 foreach ($fieldsArray as $value) {
1119 $customFieldId = CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_CustomField',
1124 $value = $customFieldId ?
'custom_' . $customFieldId : $value;
1125 $tmpContactField[trim($value)] = CRM_Utils_Array
::value(trim($value), $contactFields);
1127 $title = $tmpContactField[trim($value)]['title'] . " " . ts('(match to contact)');
1130 $title = $tmpContactField[trim($value)]['title'];
1132 $tmpContactField[trim($value)]['title'] = $title;
1135 $tmpContactField['external_identifier'] = $contactFields['external_identifier'];
1136 $tmpContactField['external_identifier']['title'] = $contactFields['external_identifier']['title'] . " " . ts('(match to contact)');
1138 $tmpFields['membership_contact_id']['title'] = $tmpFields['membership_contact_id']['title'] . " " . ts('(match to contact)');;
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;
1145 return self
::$_importableFields;
1149 * Get all exportable fields.
1151 * @retun array return array of all exportable fields
1153 public static function &exportableFields() {
1154 $expFieldMembership = CRM_Member_DAO_Membership
::export();
1156 $expFieldsMemType = CRM_Member_DAO_MembershipType
::export();
1157 $fields = array_merge($expFieldMembership, $expFieldsMemType);
1158 $fields = array_merge($fields, $expFieldMembership);
1159 $membershipStatus = array(
1160 'membership_status' => array(
1161 'title' => 'Membership Status',
1162 'name' => 'membership_status',
1163 'type' => CRM_Utils_Type
::T_STRING
,
1164 'where' => 'civicrm_membership_status.name',
1167 //CRM-6161 fix for customdata export
1168 $fields = array_merge($fields, $membershipStatus, CRM_Core_BAO_CustomField
::getFieldsForImport('Membership'));
1173 * Get membership joins/renewals for a specified membership
1174 * type. Specifically, retrieves a count of memberships whose "Membership
1175 * Signup" or "Membership Renewal" activity falls in the given date range.
1176 * Dates match the pattern "yyyy-mm-dd".
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.
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
1188 * the number of members of type $membershipTypeId whose
1189 * start_date is between $startDate and $endDate
1191 public static function getMembershipStarts($membershipTypeId, $startDate, $endDate, $isTest = 0, $isOwner = 0) {
1193 $testClause = 'membership.is_test = 1';
1195 $testClause = '( membership.is_test IS NULL OR membership.is_test = 0 )';
1198 if (!self
::$_signupActType ||
!self
::$_renewalActType) {
1199 self
::_getActTypes();
1202 if (!self
::$_signupActType ||
!self
::$_renewalActType) {
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'
1216 $query .= ($isOwner) ?
' AND owner_membership_id IS NULL' : '';
1219 1 => array(self
::$_signupActType, 'Integer'),
1220 2 => array(self
::$_renewalActType, 'Integer'),
1221 3 => array($membershipTypeId, 'Integer'),
1224 $memberCount = CRM_Core_DAO
::singleValueQuery($query, $params);
1225 return (int) $memberCount;
1229 * Get a count of membership for a specified membership type,
1230 * optionally for a specified date. The date must have the form yyyy-mm-dd.
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.
1241 * @param int $membershipTypeId
1242 * Membership type id.
1243 * @param string $date
1244 * The date for which to retrieve the count.
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
1249 * the number of members of type $membershipTypeId as of $date.
1251 public static function getMembershipCount($membershipTypeId, $date = NULL, $isTest = 0, $isOwner = 0) {
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)));
1257 1 => array($membershipTypeId, 'Integer'),
1258 2 => array($isTest, 'Boolean'),
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";
1266 $query .= " AND civicrm_membership_status.is_current_member = 1";
1269 $query .= " AND civicrm_membership.start_date <= '$date' AND civicrm_membership_status.is_current_member = 1";
1272 $query .= ($isOwner) ?
' AND owner_membership_id IS NULL' : '';
1273 $memberCount = CRM_Core_DAO
::singleValueQuery($query, $params);
1274 return (int) $memberCount;
1278 * Function check the status of the membership before adding membership for a contact.
1280 * @param int $contactId
1285 public static function statusAvailabilty($contactId) {
1286 $membership = new CRM_Member_DAO_MembershipStatus();
1287 $membership->whereAdd('is_active=1');
1288 return $membership->count();
1292 * Process the Memberships.
1294 * @param array $membershipParams
1295 * Array of membership fields.
1296 * @param int $contactID
1298 * @param CRM_Contribute_Form_Contribution_Confirm $form
1299 * Confirmation form object.
1301 * @param array $premiumParams
1302 * @param null $customFieldsFormatted
1303 * @param null $includeFieldTypes
1305 * @param array $membershipDetails
1307 * @param array $membershipTypeIDs
1309 * @param bool $isPaidMembership
1310 * @param array $membershipID
1312 * @param $isProcessSeparateMembershipTransaction
1314 * @param int $defaultContributionTypeID
1315 * @param array $membershipLineItems
1316 * Line items specific to membership payment that is separate to contribution.
1317 * @param $isPayLater
1319 * @throws \CRM_Core_Exception
1321 public static function postProcessMembership(
1322 $membershipParams, $contactID, &$form, $premiumParams,
1323 $customFieldsFormatted = NULL, $includeFieldTypes = NULL, $membershipDetails, $membershipTypeIDs, $isPaidMembership, $membershipID,
1324 $isProcessSeparateMembershipTransaction, $defaultContributionTypeID, $membershipLineItems, $isPayLater) {
1325 $result = $membershipContribution = NULL;
1326 $isTest = CRM_Utils_Array
::value('is_test', $membershipParams, FALSE);
1327 $errors = $createdMemberships = array();
1329 //@todo move this into the calling function & pass in the correct financialTypeID
1330 if (isset($paymentParams['financial_type'])) {
1331 $financialTypeID = $paymentParams['financial_type'];
1334 $financialTypeID = $defaultContributionTypeID;
1337 if (CRM_Utils_Array
::value('membership_source', $form->_params
)) {
1338 $membershipParams['contribution_source'] = $form->_params
['membership_source'];
1341 if ($isPaidMembership) {
1342 $result = CRM_Contribute_BAO_Contribution_Utils
::processConfirm($form, $membershipParams,
1343 $premiumParams, $contactID,
1350 if (is_a($result[1], 'CRM_Core_Error')) {
1351 $errors[1] = CRM_Core_Error
::getMessages($result[1]);
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];
1362 if ($isProcessSeparateMembershipTransaction) {
1364 $lineItems = $form->_lineItem
= $membershipLineItems;
1365 if (empty($form->_params
['auto_renew']) && !empty($membershipParams['is_recur'])) {
1366 unset($membershipParams['is_recur']);
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));
1370 catch (CRM_Core_Exception
$e) {
1371 $errors[2] = $e->getMessage();
1372 $membershipContribution = NULL;
1377 if (!empty($membershipContribution) && !is_a($membershipContribution, 'CRM_Core_Error')) {
1378 $membershipContributionID = $membershipContribution->id
;
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'];
1385 //@todo it should no longer be possible for it to get to this point & membership to not be an array
1386 if (is_array($membershipTypeIDs) && !empty($membershipContributionID)) {
1387 $typesTerms = CRM_Utils_Array
::value('types_terms', $membershipParams, array());
1388 foreach ($membershipTypeIDs as $memType) {
1389 $numTerms = CRM_Utils_Array
::value($memType, $typesTerms, 1);
1390 $createdMemberships[$memType] = self
::createOrRenewMembership($membershipParams, $contactID, $customFieldsFormatted, $membershipID, $memType, $isTest, $numTerms, $membershipContribution, $form);
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']])
1397 $membershipOb = $createdMemberships[$priceFieldOp['membership_type_id']];
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') : '-';
1402 $priceFieldOp['start_date'] = $priceFieldOp['end_date'] = 'N/A';
1405 $form->_values
['lineItem'] = $form->_lineItem
;
1406 $form->assign('lineItem', $form->_lineItem
);
1410 if (!empty($errors)) {
1411 $message = self
::compileErrorMessage($errors);
1412 throw new CRM_Core_Exception($message);
1414 $form->_params
['createdMembershipIDs'] = array();
1416 // CRM-7851 - Moved after processing Payment Errors
1417 //@todo - the reasoning for this being here seems a little outdated
1418 foreach ($createdMemberships as $createdMembership) {
1419 CRM_Core_BAO_CustomValueTable
::postProcess(
1421 CRM_Core_DAO
::$_nullArray,
1422 'civicrm_membership',
1423 $createdMembership->id
,
1426 $form->_params
['createdMembershipIDs'][] = $createdMembership->id
;
1428 if (count($createdMemberships) == 1) {
1429 //presumably this is only relevant for exactly 1 membership
1430 $form->_params
['membershipID'] = $createdMembership->id
;
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;
1438 if ($form->_contributeMode
== 'notify') {
1439 if ($form->_values
['is_monetary'] && $form->_amount
> 0.0 && !$form->_params
['is_pay_later']) {
1440 // call postProcess hook before leaving
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');
1448 if (isset($membershipContributionID)) {
1449 $form->_values
['contribution_id'] = $membershipContributionID;
1452 // Refer to CRM-16737. Payment processors 'should' return payment_status_id
1453 // to denote the outcome of the transaction.
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.
1459 if (!empty($form->_params
['is_recur']) && $form->_contributeMode
== 'direct') {
1460 if (!empty($membershipContribution->trxn_id
) && !isset($membershipContribution->payment_status_id
)
1461 ||
(!empty($membershipContribution->payment_status_id
) && $membershipContribution->payment_status_id
== 1)) {
1463 civicrm_api3('contribution', 'completetransaction', array(
1464 'id' => $membershipContribution->id
,
1465 'trxn_id' => $membershipContribution->trxn_id
,
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());
1474 // Do not send an email if Recurring transaction is done via Direct Mode
1475 // Email will we sent when the IPN is received.
1479 //finally send an email receipt
1480 CRM_Contribute_BAO_ContributionPage
::sendMail($contactID,
1488 * Function for updating a membership record's contribution_recur_id
1490 * @param CRM_Member_DAO_Membership $membership
1491 * @param \CRM_Contribute_BAO_Contribution|\CRM_Contribute_DAO_Contribution $contribution
1495 static public function updateRecurMembership(CRM_Member_DAO_Membership
$membership, CRM_Contribute_BAO_Contribution
$contribution) {
1497 if (empty($contribution->contribution_recur_id
)) {
1502 1 => array($contribution->contribution_recur_id
, 'Integer'),
1503 2 => array($membership->id
, 'Integer'),
1506 $sql = "UPDATE civicrm_membership SET contribution_recur_id = %1 WHERE id = %2";
1507 CRM_Core_DAO
::executeQuery($sql, $params);
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
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)
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.
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
1531 * @param null $changeToday
1532 * @param int $modifiedID
1533 * Individual contact id in case of On Behalf signup (CRM-4027 ).
1534 * @param null $customFieldsFormatted
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.
1540 * @throws CRM_Core_Exception
1543 public static function renewMembershipFormWrapper(
1548 $changeToday = NULL,
1550 $customFieldsFormatted = NULL,
1552 $membershipID = NULL,
1555 $statusFormat = '%Y-%m-%d';
1558 //@todo would be better to make $membershipID a compulsory function param & make form layer responsible for extracting it
1559 if (!$membershipID && isset($form->_membershipId
)) {
1560 $membershipID = $form->_membershipId
;
1563 //get all active statuses of membership.
1564 $allStatus = CRM_Member_PseudoConstant
::membershipStatus();
1566 $membershipTypeDetails = CRM_Member_BAO_MembershipType
::getMembershipTypeDetails($membershipTypeID);
1568 // check is it pending. - CRM-4555
1569 list($pending, $contributionRecurID, $changeToday, $membershipSource, $isPayLater, $campaignId) = self
::extractFormValues($form, $changeToday, $membershipTypeDetails, $pending);
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);
1571 $form->set('renewal_mode', $renewalMode);
1572 if (!empty($dates)) {
1573 $form->assign('mem_start_date',
1574 CRM_Utils_Date
::customFormat($dates['start_date'], $format)
1576 $form->assign('mem_end_date',
1577 CRM_Utils_Date
::customFormat($dates['end_date'], $format)
1585 * Method to fix membership status of stale membership.
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.
1591 * @param array $currentMembership
1592 * Reference to the array.
1593 * containing all values of
1594 * the current membership
1595 * @param array $changeToday
1596 * Array of month, day, year.
1597 * values in case today needs
1598 * to be customised, null otherwise
1602 public static function fixMembershipStatusBeforeRenew(&$currentMembership, $changeToday) {
1605 $today = CRM_Utils_Date
::processDate($changeToday, NULL, FALSE, 'Y-m-d');
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),
1614 $currentMembership['membership_type_id'],
1618 if (empty($status) ||
1619 empty($status['id'])
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.'));
1624 $currentMembership['today_date'] = $today;
1626 if ($status['id'] !== $currentMembership['status_id']) {
1627 $memberDAO = new CRM_Member_DAO_Membership();
1628 $memberDAO->id
= $currentMembership['id'];
1629 $memberDAO->find(TRUE);
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
);
1636 CRM_Core_DAO
::storeValues($memberDAO, $currentMembership);
1639 $currentMembership['is_current_member'] = CRM_Core_DAO
::getFieldValue(
1640 'CRM_Member_DAO_MembershipStatus',
1641 $currentMembership['status_id'],
1647 'membership_id' => $currentMembership['id'],
1648 'status_id' => $status['id'],
1649 'start_date' => CRM_Utils_Date
::customFormat(
1650 $currentMembership['start_date'],
1653 'end_date' => CRM_Utils_Date
::customFormat(
1654 $currentMembership['end_date'],
1657 'modified_date' => CRM_Utils_Date
::customFormat(
1658 $currentMembership['today_date'],
1661 'membership_type_id' => $currentMembership['membership_type_id'],
1662 'max_related' => CRM_Utils_Array
::value('max_related', $currentMembership, 0),
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');
1671 $logParams['modified_id'] = $currentMembership['contact_id'];
1673 CRM_Member_BAO_MembershipLog
::add($logParams, CRM_Core_DAO
::$_nullArray);
1678 * Get the contribution page id from the membership record.
1680 * @param int $membershipID
1683 * contribution page id
1685 public static function getContributionPageId($membershipID) {
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')
1692 . " ORDER BY mp.id DESC";
1694 return CRM_Core_DAO
::singleValueQuery($query,
1695 CRM_Core_DAO
::$_nullArray
1700 * Updated related memberships.
1702 * @param int $ownerMembershipId
1703 * Owner Membership Id.
1704 * @param array $params
1705 * Formatted array of key => value.
1707 public static function updateRelatedMemberships($ownerMembershipId, $params) {
1708 $membership = new CRM_Member_DAO_Membership();
1709 $membership->owner_membership_id
= $ownerMembershipId;
1710 $membership->find();
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();
1720 $membership->free();
1724 * Get list of membership fields for profile.
1725 * For now we only allow custom membership fields to be in
1729 * FIXME: This param is ignored
1732 * the list of membership fields
1734 public static function getMembershipFields($mode = NULL) {
1735 $fields = CRM_Member_DAO_Membership
::export();
1737 unset($fields['membership_contact_id']);
1738 $fields = array_merge($fields, CRM_Core_BAO_CustomField
::getFieldsForImport('Membership'));
1740 $membershipType = CRM_Member_DAO_MembershipType
::export();
1742 $membershipStatus = CRM_Member_DAO_MembershipStatus
::export();
1744 $fields = array_merge($fields, $membershipType, $membershipStatus);
1750 * Get the sort name of a contact for a particular membership.
1753 * Id of the membership.
1755 * @return null|string
1756 * sort name of the contact if found
1758 public static function sortName($id) {
1759 $id = CRM_Utils_Type
::escape($id, 'Integer');
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}
1767 return CRM_Core_DAO
::singleValueQuery($query, CRM_Core_DAO
::$_nullArray);
1771 * Create memberships for related contacts.
1772 * takes into account the maximum related memberships
1774 * @param array $params
1775 * Array of key - value pairs.
1776 * @param CRM_Core_DAO $dao
1777 * Membership object.
1779 * @return null|array
1780 * array of memberships if created
1782 public static function createRelatedMemberships(&$params, &$dao, $reset = FALSE) {
1783 static $relatedContactIds = array();
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();
1790 $membership = new CRM_Member_DAO_Membership();
1791 $membership->id
= $dao->id
;
1793 // required since create method doesn't return all the
1794 // parameters in the returned membership object
1795 if (!$membership->find(TRUE)) {
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
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
;
1815 $expiredStatusId = array_search('Expired', CRM_Member_PseudoConstant
::membershipStatus());
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)
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) {
1831 if (empty($relatedContactIds[$cid])) {
1832 $relatedContactIds[$cid] = TRUE;
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();
1843 if (!$nestedRelationship) {
1844 $relatedContacts[$cid] = $status;
1849 //lets cleanup related membership if any.
1850 if (empty($relatedContacts)) {
1851 self
::deleteRelatedMemberships($membership->id
);
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']);
1864 if (!isset($params['membership_type_id'])) {
1865 $params['membership_type_id'] = $membership->membership_type_id
;
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
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
;
1883 $params['contact_id'] = $contactId;
1884 $params['owner_membership_id'] = $membership->id
;
1886 // set status_id as it might have been changed for
1887 // past relationship
1888 $params['status_id'] = $membership->status_id
;
1890 if ($deceasedStatusId &&
1891 CRM_Core_DAO
::getFieldValue('CRM_Contact_DAO_Contact', $contactId, 'is_deceased')
1893 $params['status_id'] = $deceasedStatusId;
1895 elseif ((CRM_Utils_Array
::value('action', $params) & CRM_Core_Action
::UPDATE
) &&
1896 ($relationshipStatus == CRM_Contact_BAO_Relationship
::PAST
)
1898 $params['status_id'] = $expiredStatusId;
1901 //don't calculate status again in create( );
1902 $params['skipStatusCal'] = TRUE;
1904 //do create activity if we changed status.
1905 if ($params['status_id'] != $relMembership->status_id
) {
1906 $params['createActivity'] = TRUE;
1909 // we should not created contribution record for related contacts, CRM-3371
1910 unset($params['contribution_status_id']);
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);
1917 // related membership already exists, so this is just an update
1918 if (isset($params['id'])) {
1919 if ($available > 0) {
1920 CRM_Member_BAO_Membership
::create($params, $relMemIds);
1924 // we have run out of inherited memberships, so delete extras
1925 self
::deleteMembership($params['id']);
1927 // we need to first check if there will remain inherited memberships, so queue it up
1934 // now go over the queue and create any available related memberships
1936 while (($available > 0) && ($params = each($queue))) {
1937 CRM_Member_BAO_Membership
::create($params['value'], $relMemIds);
1944 * Delete the record that are associated with this Membership Payment.
1946 * @param int $membershipId
1949 * $membershipPayment deleted membership payment object
1951 public static function deleteMembershipPayment($membershipId) {
1953 $membershipPayment = new CRM_Member_DAO_MembershipPayment();
1954 $membershipPayment->membership_id
= $membershipId;
1955 $membershipPayment->find();
1957 while ($membershipPayment->fetch()) {
1958 CRM_Contribute_BAO_Contribution
::deleteContribution($membershipPayment->contribution_id
);
1959 CRM_Utils_Hook
::pre('delete', 'MembershipPayment', $membershipPayment->id
, $membershipPayment);
1960 $membershipPayment->delete();
1961 CRM_Utils_Hook
::post('delete', 'MembershipPayment', $membershipPayment->id
, $membershipPayment);
1963 return $membershipPayment;
1967 * @param CRM_Core_Form $form
1968 * @param int $membershipTypeID
1972 public static function &buildMembershipTypeValues(&$form, $membershipTypeID = NULL) {
1973 $whereClause = " WHERE domain_id = " . CRM_Core_Config
::domainID();
1975 if (is_array($membershipTypeID)) {
1976 $allIDs = implode(',', $membershipTypeID);
1977 $whereClause .= " AND id IN ( $allIDs )";
1979 elseif (is_numeric($membershipTypeID) &&
1980 $membershipTypeID > 0
1982 $whereClause .= " AND id = $membershipTypeID";
1987 FROM civicrm_membership_type
1990 $dao = CRM_Core_DAO
::executeQuery($query);
1992 $membershipTypeValues = array();
1993 $membershipTypeFields = array(
1999 'financial_type_id',
2001 'member_of_contact_id',
2002 'relationship_type_id',
2003 'relationship_direction',
2007 while ($dao->fetch()) {
2008 $membershipTypeValues[$dao->id
] = array();
2009 foreach ($membershipTypeFields as $mtField) {
2010 $membershipTypeValues[$dao->id
][$mtField] = $dao->$mtField;
2015 CRM_Utils_Hook
::membershipTypeValues($form, $membershipTypeValues);
2017 if (is_numeric($membershipTypeID) &&
2018 $membershipTypeID > 0
2020 return $membershipTypeValues[$membershipTypeID];
2023 return $membershipTypeValues;
2028 * Get membership record count for a Contact.
2030 * @param int $contactID
2031 * @param bool $activeOnly
2033 * @return null|string
2035 public static function getContactMembershipCount($contactID, $activeOnly = FALSE) {
2036 $select = "SELECT count(*) FROM civicrm_membership ";
2037 $where = "WHERE civicrm_membership.contact_id = {$contactID} AND civicrm_membership.is_test = 0 ";
2039 // CRM-6627, all status below 3 (active, pending, grace) are considered active
2041 $select .= " INNER JOIN civicrm_membership_status ON civicrm_membership.status_id = civicrm_membership_status.id ";
2042 $where .= " and civicrm_membership_status.is_current_member = 1";
2045 $query = $select . $where;
2046 return CRM_Core_DAO
::singleValueQuery($query);
2050 * Check whether payment processor supports
2051 * cancellation of membership subscription
2056 * @param bool $isNotCancelled
2060 public static function isCancelSubscriptionSupported($mid, $isNotCancelled = TRUE) {
2061 $cacheKeyString = "$mid";
2062 $cacheKeyString .= $isNotCancelled ?
'_1' : '_0';
2064 static $supportsCancel = array();
2066 if (!array_key_exists($cacheKeyString, $supportsCancel)) {
2067 $supportsCancel[$cacheKeyString] = FALSE;
2068 $isCancelled = FALSE;
2070 if ($isNotCancelled) {
2071 $isCancelled = self
::isSubscriptionCancelled($mid);
2074 $paymentObject = CRM_Financial_BAO_PaymentProcessor
::getProcessorForEntity($mid, 'membership', 'obj');
2075 if (!empty($paymentObject)) {
2076 $supportsCancel[$cacheKeyString] = $paymentObject->isSupported('cancelSubscription') && !$isCancelled;
2079 return $supportsCancel[$cacheKeyString];
2083 * Check whether subscription is already cancelled.
2089 * contribution status
2091 public static function isSubscriptionCancelled($mid) {
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";
2097 $params = array(1 => array($mid, 'Integer'));
2098 $statusId = CRM_Core_DAO
::singleValueQuery($sql, $params);
2099 $status = CRM_Contribute_PseudoConstant
::contributionStatus($statusId, 'name');
2100 if ($status == 'Cancelled') {
2107 * Get membership joins for a specified membership
2108 * type. Specifically, retrieves a count of still current memberships whose
2109 * join_date and start_date are within a specified date range. Dates match
2110 * the pattern "yyyy-mm-dd".
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.
2118 * @param bool|int $isTest if true, membership is for a test site
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
2125 public static function getMembershipJoins($membershipTypeId, $startDate, $endDate, $isTest = 0) {
2126 $testClause = 'membership.is_test = 1';
2128 $testClause = '( membership.is_test IS NULL OR membership.is_test = 0 )';
2130 if (!self
::$_signupActType) {
2131 self
::_getActTypes();
2134 if (!self
::$_signupActType) {
2139 SELECT COUNT(DISTINCT membership.id) as member_count
2140 FROM civicrm_membership membership
2141 INNER JOIN civicrm_activity activity ON (activity.source_record_id = membership.id AND activity.activity_type_id = %1)
2142 INNER JOIN civicrm_membership_status status ON ( membership.status_id = status.id AND status.is_current_member = 1 )
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'
2149 1 => array(self
::$_signupActType, 'Integer'),
2150 2 => array($membershipTypeId, 'Integer'),
2153 $memberCount = CRM_Core_DAO
::singleValueQuery($query, $params);
2155 return (int) $memberCount;
2159 * Get membership renewals for a specified membership
2160 * type. Specifically, retrieves a count of still current memberships
2161 * whose join_date is before and start_date is within a specified date
2162 * range. Dates match the pattern "yyyy-mm-dd".
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.
2170 * @param bool|int $isTest if true, membership is for a test site
2173 * returns the number of members of type $membershipTypeId
2174 * whose join_date is before $startDate and
2175 * whose start_date is between $startDate and $endDate
2177 public static function getMembershipRenewals($membershipTypeId, $startDate, $endDate, $isTest = 0) {
2178 $testClause = 'membership.is_test = 1';
2180 $testClause = '( membership.is_test IS NULL OR membership.is_test = 0 )';
2182 if (!self
::$_renewalActType) {
2183 self
::_getActTypes();
2186 if (!self
::$_renewalActType) {
2191 SELECT COUNT(DISTINCT membership.id) as member_count
2192 FROM civicrm_membership membership
2193 INNER JOIN civicrm_activity activity ON (activity.source_record_id = membership.id AND activity.activity_type_id = %1)
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 )
2196 WHERE membership.membership_type_id = %2
2197 AND activity.activity_date_time >= '$startDate' AND activity.activity_date_time <= '$endDate 23:59:59'
2201 1 => array(self
::$_renewalActType, 'Integer'),
2202 2 => array($membershipTypeId, 'Integer'),
2204 $memberCount = CRM_Core_DAO
::singleValueQuery($query, $params);
2206 return (int) $memberCount;
2210 * Where a second separate financial transaction is supported we will process it here.
2212 * @param int $contactID
2213 * @param CRM_Contribute_Form_Contribution_Confirm $form
2214 * @param array $tempParams
2216 * @param array $lineItems
2217 * @param $minimumFee
2218 * @param int $financialTypeID
2220 * @throws CRM_Core_Exception
2222 * @return CRM_Contribute_BAO_Contribution
2224 public static function processSecondaryFinancialTransaction($contactID, &$form, $tempParams, $isTest, $lineItems, $minimumFee, $financialTypeID) {
2225 $financialType = new CRM_Financial_DAO_FinancialType();
2226 $financialType->id
= $financialTypeID;
2227 if (!$financialType->find(TRUE)) {
2228 CRM_Core_Error
::fatal(ts("Could not find a system table"));
2230 $tempParams['amount'] = $minimumFee;
2231 $tempParams['invoiceID'] = md5(uniqid(rand(), TRUE));
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);
2237 if ($form->_contributeMode
== 'express') {
2238 $result = $payment->doExpressCheckout($tempParams);
2239 if (is_a($result, 'CRM_Core_Error')) {
2240 throw new CRM_Core_Exception(CRM_Core_Error
::getMessages($result));
2244 $result = $payment->doPayment($tempParams, 'contribute');
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);
2258 $form->set('membership_trx_id', $result['trxn_id']);
2259 $form->set('membership_amount', $minimumFee);
2261 $form->assign('membership_trx_id', $result['trxn_id']);
2262 $form->assign('membership_amount', $minimumFee);
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;
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);
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,
2289 return $membershipContribution;
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
2298 public static function linkMembershipPayment($membership, $membershipContribution) {
2299 CRM_Member_BAO_MembershipPayment
::create(array(
2300 'membership_id' => $membership->id
,
2301 'contribution_id' => $membershipContribution->id
,
2306 * @param array $membershipParams
2307 * @param int $contactID
2308 * @param $customFieldsFormatted
2309 * @param int $membershipID
2313 * @param $membershipContribution
2314 * @param CRM_Core_Form $form
2318 public static function createOrRenewMembership($membershipParams, $contactID, $customFieldsFormatted, $membershipID, $memType, $isTest, $numTerms, $membershipContribution, &$form) {
2319 if (!empty($membershipContribution)) {
2320 // CRM-16737 contribution_status_id is the deprecated return parameter from the payment processor. Use
2321 // payment_status_id.
2322 $pending = ($membershipContribution->contribution_status_id
== 2) ?
TRUE : FALSE;
2323 if (isset($membershipContribution->payment_status_id
)) {
2324 $pending = ($membershipContribution->payment_status_id
== 2) ?
TRUE : $pending;
2327 $membership = self
::renewMembershipFormWrapper($contactID, $memType,
2328 $isTest, $form, NULL,
2329 CRM_Utils_Array
::value('cms_contactID', $membershipParams),
2330 $customFieldsFormatted, $numTerms,
2331 $membershipID, $pending
2334 if (!empty($membershipContribution)) {
2335 // update recurring id for membership record
2336 self
::updateRecurMembership($membership, $membershipContribution);
2338 self
::linkMembershipPayment($membership, $membershipContribution);
2344 * Turn array of errors into message string.
2346 * @param array $errors
2350 public static function compileErrorMessage($errors) {
2351 foreach ($errors as $error) {
2352 if (is_string($error)) {
2353 $message[] = $error;
2356 return ts('Payment Processor Error message') . ': ' . implode('<br/>', $message);
2360 * Extract relevant values from the form so we can separate form logic from BAO logcis.
2362 * @param CRM_Core_Form $form
2363 * @param $changeToday
2364 * @param $membershipTypeDetails
2368 public static function extractFormValues($form, $changeToday, $membershipTypeDetails, $pending = FALSE) {
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) {
2372 if (((isset($form->_contributeMode
) && $form->_contributeMode
== 'notify') ||
!empty($form->_params
['is_pay_later'])
2374 (($form->_values
['is_monetary'] && $form->_amount
> 0.0) ||
2375 CRM_Utils_Array
::value('record_contribution', $form->_params
)
2381 $contributionRecurID = isset($form->_params
['contributionRecurID']) ?
$form->_params
['contributionRecurID'] : NULL;
2383 //we renew expired membership, CRM-6277
2384 if (!$changeToday) {
2385 if ($form->get('renewalDate')) {
2386 $changeToday = $form->get('renewalDate');
2388 elseif (get_class($form) == 'CRM_Contribute_Form_Contribution_Confirm') {
2389 $changeToday = date('YmdHis');
2393 $membershipSource = NULL;
2394 if (!empty($form->_params
['membership_source'])) {
2395 $membershipSource = $form->_params
['membership_source'];
2397 elseif (isset($form->_values
['title']) && !empty($form->_values
['title'])) {
2398 $membershipSource = ts('Online Contribution:') . ' ' . $form->_values
['title'];
2401 if (isset($form->_params
)) {
2402 $isPayLater = CRM_Utils_Array
::value('is_pay_later', $form->_params
);
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
);
2411 return array($pending, $contributionRecurID, $changeToday, $membershipSource, $isPayLater, $campaignId);
2415 * @param int $contactID
2416 * @param int $membershipTypeID
2417 * @param bool $is_test
2418 * @param $changeToday
2419 * @param int $modifiedID
2420 * @param $customFieldsFormatted
2421 * @param $numRenewTerms
2422 * @param int $membershipID
2425 * @param array $membershipTypeDetails
2426 * @param int $contributionRecurID
2428 * @param $membershipSource
2430 * @param $statusFormat
2431 * @param $isPayLater
2432 * @param int $campaignId
2434 * @throws CRM_Core_Exception
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;
2440 // CRM-7297 - allow membership type to be be changed during renewal so long as the parent org of new membershipType
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
2445 if ($currentMembership) {
2446 $activityType = 'Membership Renewal';
2447 $renewalMode = TRUE;
2449 // Do NOT do anything.
2450 //1. membership with status : PENDING/CANCELLED (CRM-2395)
2451 //2. Paylater/IPN renew. CRM-4556.
2452 if ($pending ||
in_array($currentMembership['status_id'], array(
2453 array_search('Pending', $allStatus),
2455 array_search('Cancelled', CRM_Member_PseudoConstant
::membershipStatus(NULL, " name = 'Cancelled' ", 'name', FALSE, TRUE)),
2458 $membership = new CRM_Member_DAO_Membership();
2459 $membership->id
= $currentMembership['id'];
2460 $membership->find(TRUE);
2462 // CRM-8141 create a membership_log entry so that we will know the membership_type_id to change to when payment completed
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
2467 'membership_id' => $membership->id
,
2468 'status_id' => $membership->status_id
,
2469 'start_date' => CRM_Utils_Date
::customFormat(
2470 $membership->start_date
,
2473 'end_date' => CRM_Utils_Date
::customFormat(
2474 $membership->end_date
,
2477 'modified_date' => CRM_Utils_Date
::customFormat(
2481 'membership_type_id' => $membershipTypeID,
2482 'max_related' => !empty($membershipTypeDetails['max_related']) ?
$membershipTypeDetails['max_related'] : NULL,
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');
2490 $logParams['modified_id'] = $membership->contact_id
;
2492 CRM_Member_BAO_MembershipLog
::add($logParams, CRM_Core_DAO
::$_nullArray);
2494 if (!empty($contributionRecurID)) {
2495 CRM_Core_DAO
::setFieldValue('CRM_Member_DAO_Membership', $membership->id
,
2496 'contribution_recur_id', $contributionRecurID
2500 return array($membership, $renewalMode, $dates);
2503 // Check and fix the membership if it is STALE
2504 self
::fixMembershipStatusBeforeRenew($currentMembership, $changeToday);
2506 // Now Renew the membership
2507 if (!$currentMembership['is_current_member']) {
2508 // membership is not CURRENT
2510 // CRM-7297 Membership Upsell - calculate dates based on new membership type
2511 $dates = CRM_Member_BAO_MembershipType
::getRenewalDatesForMembershipType($currentMembership['id'],
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;
2522 if (!empty($membershipSource)) {
2523 $currentMembership['source'] = $membershipSource;
2526 $currentMembership['source'] = CRM_Core_DAO
::getFieldValue('CRM_Member_DAO_Membership',
2527 $currentMembership['id'],
2532 if (!empty($currentMembership['id'])) {
2533 $ids['membership'] = $currentMembership['id'];
2535 $memParams = $currentMembership;
2536 $memParams['membership_type_id'] = $membershipTypeID;
2538 //set the log start date.
2539 $memParams['log_start_date'] = CRM_Utils_Date
::customFormat($dates['log_start_date'], $format);
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
,
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;
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;
2568 $memParams['source'] = CRM_Core_DAO
::getFieldValue('CRM_Member_DAO_Membership',
2569 $currentMembership['id'],
2575 if (!empty($currentMembership['id'])) {
2576 $ids['membership'] = $currentMembership['id'];
2581 $updateStatusId = array_search('Pending', $allStatus);
2587 $activityType = 'Membership Signup';
2589 'contact_id' => $contactID,
2590 'membership_type_id' => $membershipTypeID,
2594 $dates = CRM_Member_BAO_MembershipType
::getDatesForMembershipType($membershipTypeID, NULL, NULL, NULL, $numRenewTerms);
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);
2600 $status = CRM_Member_BAO_MembershipStatus
::getMembershipStatusByDate(CRM_Utils_Date
::customFormat($dates['start_date'],
2603 CRM_Utils_Date
::customFormat($dates['end_date'],
2606 CRM_Utils_Date
::customFormat($dates['join_date'],
2614 $updateStatusId = CRM_Utils_Array
::value('id', $status);
2617 // if IPN/Pay-Later set status to: PENDING
2618 $updateStatusId = array_search('Pending', $allStatus);
2621 if (!empty($membershipSource)) {
2622 $memParams['source'] = $membershipSource;
2624 $memParams['contribution_recur_id'] = $contributionRecurID;
2626 $memParams['is_test'] = $is_test;
2627 $memParams['is_pay_later'] = $isPayLater;
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;
2638 //since we are renewing,
2639 //make status override false.
2640 $memParams['is_override'] = FALSE;
2642 //CRM-4027, create log w/ individual contact.
2644 $ids['userId'] = $modifiedID;
2645 $memParams['is_for_organization'] = TRUE;
2648 $ids['userId'] = $contactID;
2651 //inherit campaign from contrib page.
2652 if (isset($campaignId)) {
2653 $memParams['campaign_id'] = $campaignId;
2656 $memParams['custom'] = $customFieldsFormatted;
2657 $membership = self
::create($memParams, $ids, FALSE, $activityType);
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);
2663 return array($membership, $renewalMode, $dates);
2667 * Process price set and line items.
2669 * @param int $membershipId
2674 public function processPriceSet($membershipId, $lineItem) {
2675 //FIXME : need to move this too
2676 if (!$membershipId ||
!is_array($lineItem)
2677 || CRM_Utils_System
::isNull($lineItem)
2682 foreach ($lineItem as $priceSetId => $values) {
2686 foreach ($values as $line) {
2687 $line['entity_table'] = 'civicrm_membership';
2688 $line['entity_id'] = $membershipId;
2689 CRM_Price_BAO_LineItem
::create($line);
2695 * Retrieve the contribution id for the associated Membership id.
2696 * @todo we should get this off the line item
2698 * @param int $membershipId
2704 public static function getMembershipContributionId($membershipId) {
2706 $membershipPayment = new CRM_Member_DAO_MembershipPayment();
2707 $membershipPayment->membership_id
= $membershipId;
2708 if ($membershipPayment->find(TRUE)) {
2709 return $membershipPayment->contribution_id
;
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.
2719 * Sending renewal reminders has been migrated from this job to the Scheduled Reminders function as of 4.3.
2723 public static function updateAllMembershipStatus() {
2725 //get all active statuses of membership, CRM-3984
2726 $allStatus = CRM_Member_PseudoConstant
::membershipStatus();
2727 $statusLabels = CRM_Member_PseudoConstant
::membershipStatus(NULL, NULL, 'label');
2728 $allTypes = CRM_Member_PseudoConstant
::membershipType();
2730 // get only memberships with active membership types
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 )
2746 INNER JOIN civicrm_membership_type ON
2747 (civicrm_membership.membership_type_id = civicrm_membership_type.id AND civicrm_membership_type.is_active = 1)
2748 WHERE civicrm_membership.is_test = 0";
2751 $dao = CRM_Core_DAO
::executeQuery($query, $params);
2756 $smarty = CRM_Core_Smarty
::singleton();
2758 while ($dao->fetch()) {
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,
2777 $smarty->assign_by_ref('memberParams', $memberParams);
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'))));
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;
2795 //since there is change in status.
2796 $statusChange = array('status_id' => $deceaseStatusId);
2797 $smarty->append_by_ref('memberParams', $statusChange, TRUE);
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']
2808 //process membership record.
2809 civicrm_api('membership', 'create', $deceasedMembership);
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
) {
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
&&
2824 !in_array($dao->status_id
, array(
2825 array_search('Pending', $allStatus),
2829 CRM_Member_PseudoConstant
::membershipStatus(NULL, " name = 'Cancelled' ", 'name', FALSE, TRUE)
2831 array_search('Expired', $allStatus),
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',
2839 'membership_id' => $dao->membership_id
,
2841 'ignore_admin_only' => FALSE,
2844 $statusId = CRM_Utils_Array
::value('id', $newStatus);
2846 //process only when status change.
2848 $statusId != $dao->status_id
2850 //take all params that need to save.
2851 $memParams = $memberParams;
2852 $memParams['status_id'] = $statusId;
2853 $memParams['createActivity'] = TRUE;
2854 $memParams['version'] = 3;
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.
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']
2868 //since there is change in status.
2869 $statusChange = array('status_id' => $statusId);
2870 $smarty->append_by_ref('memberParams', $statusChange, TRUE);
2872 //process member record.
2873 civicrm_api('membership', 'create', $memParams);
2878 $result['is_error'] = 0;
2879 $result['messages'] = ts('Processed %1 membership records. Updated %2 records.', array(
2887 * Returns the membership types for a particular contact
2888 * who has lifetime membership without end date.
2890 * @param int $contactID
2891 * @param bool $isTest
2892 * @param bool $onlyLifeTime
2896 public static function getAllContactMembership($contactID, $isTest = FALSE, $onlyLifeTime = FALSE) {
2897 $contactMembershipType = array();
2899 return $contactMembershipType;
2902 $dao = new CRM_Member_DAO_Membership();
2903 $dao->contact_id
= $contactID;
2904 $pendingStatusId = array_search('Pending', CRM_Member_PseudoConstant
::membershipStatus());
2905 $dao->whereAdd("status_id != $pendingStatusId");
2908 $dao->is_test
= $isTest;
2911 $dao->whereAdd('is_test IS NULL OR is_test = 0');
2914 if ($onlyLifeTime) {
2915 $dao->whereAdd('end_date IS NULL');
2919 while ($dao->fetch()) {
2920 $membership = array();
2921 CRM_Core_DAO
::storeValues($dao, $membership);
2922 $contactMembershipType[$dao->membership_type_id
] = $membership;
2924 return $contactMembershipType;
2928 * Record contribution record associated with membership.
2930 * @param array $params
2931 * Array of submitted params.
2933 * (param in process of being removed - try to use params) array of ids.
2935 * @return CRM_Contribute_BAO_Contribution
2937 public static function recordMembershipContribution(&$params, $ids = array()) {
2938 $membershipId = $params['membership_id'];
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);
2944 $contributionParams['non_deductible_amount'] = 'null';
2945 $contributionParams['payment_processor'] = CRM_Utils_Array
::value('payment_processor_id', $params);
2946 $contributionSoftParams = CRM_Utils_Array
::value('soft_credit', $params);
2947 $recordContribution = array(
2951 'financial_type_id',
2952 'payment_instrument_id',
2956 'contribution_status_id',
2964 foreach ($recordContribution as $f) {
2965 $contributionParams[$f] = CRM_Utils_Array
::value($f, $params);
2968 // make entry in batch entity batch table
2969 if (!empty($params['batch_id'])) {
2970 $contributionParams['batch_id'] = $params['batch_id'];
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'];
2978 if (!empty($params['processPriceSet']) &&
2979 !empty($params['lineItems'])
2981 $contributionParams['line_item'] = CRM_Utils_Array
::value('lineItems', $params, NULL);
2984 $contribution = CRM_Contribute_BAO_Contribution
::create($contributionParams, $ids);
2986 //CRM-13981, create new soft-credit record as to record payment from different person for this membership
2987 if (!empty($contributionSoftParams)) {
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);
2996 $contributionSoftParams['contribution_id'] = $contribution->id
;
2997 $contributionSoftParams['currency'] = $contribution->currency
;
2998 $contributionSoftParams['amount'] = $contribution->total_amount
;
2999 CRM_Contribute_BAO_ContributionSoft
::add($contributionSoftParams);
3003 // store contribution id
3004 $params['contribution_id'] = $contribution->id
;
3006 //insert payment record for this membership
3007 if (empty($ids['contribution']) ||
!empty($params['is_recur'])) {
3008 CRM_Member_BAO_MembershipPayment
::create(array(
3009 'membership_id' => $membershipId,
3010 'contribution_id' => $contribution->id
,
3013 return $contribution;
3017 * Record line items for default membership.
3019 * @param CRM_Core_Form $qf
3020 * @param array $membershipType
3021 * Array with membership type and organization.
3022 * @param int $priceSetId
3025 public static function createLineItems(&$qf, $membershipType, &$priceSetId) {
3026 $qf->_priceSetId
= $priceSetId = CRM_Core_DAO
::getFieldValue('CRM_Price_DAO_PriceSet', 'default_membership_type_amount', 'id', 'name');
3028 $qf->_priceSet
= $priceSets = current(CRM_Price_BAO_PriceSet
::getSetDetail($priceSetId));
3030 $editedFieldParams = array(
3031 'price_set_id' => $priceSetId,
3032 'name' => $membershipType[0],
3034 $editedResults = array();
3035 CRM_Price_BAO_PriceField
::retrieve($editedFieldParams, $editedResults);
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],
3046 $editedResults = array();
3047 CRM_Price_BAO_PriceFieldValue
::retrieve($editedFieldParams, $editedResults);
3048 $qf->_priceSet
['fields'][$fid]['options'][$editedResults['id']] = $priceSets['fields'][$fid]['options'][$editedResults['id']];
3049 if (!empty($qf->_params
['total_amount'])) {
3050 $qf->_priceSet
['fields'][$fid]['options'][$editedResults['id']]['amount'] = $qf->_params
['total_amount'];
3054 $fieldID = key($qf->_priceSet
['fields']);
3055 $qf->_params
['price_' . $fieldID] = CRM_Utils_Array
::value('id', $editedResults);
3059 * @todo document me - I seem a bit out of date....
3061 public static function _getActTypes() {
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);
3068 * Get all Cancelled Membership(s) for a contact
3070 * @param int $contactID
3072 * @param bool $isTest
3076 * Array of membership type
3078 public static function getContactsCancelledMembership($contactID, $isTest = FALSE) {
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'),
3089 CRM_Member_PseudoConstant
::membershipStatus(
3091 " name = 'Cancelled' ",
3099 3 => array($isTest, 'Boolean'),
3102 $dao = CRM_Core_DAO
::executeQuery($query, $queryParams);
3103 $cancelledMembershipIds = array();
3104 while ($dao->fetch()) {
3105 $cancelledMembershipIds[] = $dao->membership_type_id
;
3107 return $cancelledMembershipIds;