return $cancelledMembershipIds;
}
+ /**
+ * Merges the memberships from otherContactID to mainContactID.
+ *
+ * General idea is to merge memberships in regards to their type. We
+ * move the other contact’s contributions to the main contact’s
+ * membership which has the same type (if any) and then we update
+ * membership to avoid loosing `join_date`, `end_date`, and
+ * `status_id`. In this function, we don’t touch the contributions
+ * directly (CRM_Dedupe_Merger::moveContactBelongings() takes care
+ * of it).
+ *
+ * This function adds new SQL queries to the $sqlQueries parameter.
+ *
+ * @param int $mainContactID
+ * Contact id of main contact record.
+ * @param int $otherContactID
+ * Contact id of record which is going to merge.
+ * @param array $sqlQueries
+ * (reference) array of SQL queries to be executed.
+ * @param array $tables
+ * List of tables that have to be merged.
+ * @param array $tableOperations
+ * Special options/params for some tables to be merged.
+ *
+ * @see CRM_Dedupe_Merger::cpTables()
+ */
+ public static function mergeMemberships($mainContactID, $otherContactID, &$sqlQueries, $tables, $tableOperations) {
+ /*
+ * If the user requests not to merge memberships but to add them,
+ * just attribute the `civicrm_membership` to the
+ * `$mainContactID`. We have to do this here since the general
+ * merge process is bypassed by this function.
+ */
+ if (array_key_exists("civicrm_membership", $tableOperations) && $tableOperations['civicrm_membership']['add']) {
+ $sqlQueries[] = "UPDATE IGNORE civicrm_membership SET contact_id = $mainContactID WHERE contact_id = $otherContactID";
+ return;
+ }
+
+ /*
+ * Retrieve all memberships that belongs to each contacts and
+ * keep track of each membership type.
+ */
+ $mainContactMemberships = array();
+ $otherContactMemberships = array();
+
+ $sql = "SELECT id, membership_type_id FROM civicrm_membership membership WHERE contact_id = %1";
+ $dao = CRM_Core_DAO::executeQuery($sql, array(1 => array($mainContactID, "Integer")));
+ while ($dao->fetch()) {
+ $mainContactMemberships[$dao->id] = $dao->membership_type_id;
+ }
+
+ $dao = CRM_Core_DAO::executeQuery($sql, array(1 => array($otherContactID, "Integer")));
+ while ($dao->fetch()) {
+ $otherContactMemberships[$dao->id] = $dao->membership_type_id;
+ }
+
+ /*
+ * For each membership, move related contributions to the main
+ * contact’s membership (by updating `membership_payments`). Then,
+ * update membership’s `join_date` (if the other membership’s
+ * join_date is older) and `end_date` (if the other membership’s
+ * `end_date` is newer) and `status_id` (if the newly calculated
+ * status is different).
+ *
+ * FIXME: what should we do if we have multiple memberships with
+ * the same type (currently we only take the first one)?
+ */
+ $newSql = array();
+ foreach ($otherContactMemberships as $otherMembershipId => $otherMembershipTypeId) {
+ if ($newMembershipId = array_search($otherMembershipTypeId, $mainContactMemberships)) {
+
+ /*
+ * Move other membership’s contributions to the main one only
+ * if user requested to merge contributions.
+ */
+ if (!empty($tables) && in_array('civicrm_contribution', $tables)) {
+ $newSql[] = "UPDATE civicrm_membership_payment SET membership_id=$newMembershipId WHERE membership_id=$otherMembershipId";
+ }
+
+ $sql = "SELECT * FROM civicrm_membership membership WHERE id = %1";
+
+ $newMembership = CRM_Member_DAO_Membership::findById($newMembershipId);
+ $otherMembership = CRM_Member_DAO_Membership::findById($otherMembershipId);
+
+ $updates = array();
+ if (new DateTime($otherMembership->join_date) < new DateTime($newMembership->join_date)) {
+ $updates["join_date"] = $otherMembership->join_date;
+ }
+
+ if (new DateTime($otherMembership->end_date) > new DateTime($newMembership->end_date)) {
+ $updates["end_date"] = $otherMembership->end_date;
+ }
+
+ if (count($updates)) {
+
+ /*
+ * Update status
+ */
+ $status = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate(
+ isset($updates["start_date"]) ? $updates["start_date"] : $newMembership->start_date,
+ isset($updates["end_date"]) ? $updates["end_date"] : $newMembership->end_date,
+ isset($updates["join_date"]) ? $updates["join_date"] : $newMembership->join_date,
+ 'today',
+ FALSE,
+ $newMembershipId,
+ $newMembership
+ );
+
+ if (!empty($status['id']) and $status['id'] != $newMembership->status_id) {
+ $updates['status_id'] = $status['id'];
+ }
+
+ $updates_sql = [];
+ foreach ($updates as $k => $v) {
+ $updates_sql[] = "$k = '{$v}'";
+ }
+
+ $newSql[] = sprintf("UPDATE civicrm_membership SET %s WHERE id=%s", implode(", ", $updates_sql), $newMembershipId);
+ $newSql[] = sprintf("DELETE FROM civicrm_membership WHERE id=%s", $otherMembershipId);
+ }
+
+ }
+ }
+
+ $sqlQueries = array_merge($sqlQueries, $newSql);
+ }
+
}