/** * gracefully terminates RCUR mandates * * @return success as boolean * @author endres -at- systopia.de */ static function terminateMandate($mandate_id, $new_end_date_str, $cancel_reason = NULL) { $contribution_id_pending = CRM_Core_OptionGroup::getValue('contribution_status', 'Pending', 'name'); // use a lock, in case somebody is batching just now $lock = CRM_Sepa_Logic_Settings::getLock(); if (empty($lock)) { CRM_Core_Session::setStatus(sprintf(ts("Cannot terminate mandate [%s], batching in progress!"), $mandate_id), ts('Error'), 'error'); return FALSE; } // first, load the mandate $mandate = civicrm_api("SepaMandate", "getsingle", array('id' => $mandate_id, 'version' => 3)); if (isset($mandate['is_error'])) { CRM_Core_Session::setStatus(sprintf(ts("Cannot read mandate [%s]. Error was: '%s'"), $mandate_id, $mandate['error_message']), ts('Error'), 'error'); $lock->release(); return FALSE; } // check the mandate type if ($mandate['type'] == "OOFF") { return CRM_Sepa_BAO_SEPAMandate::terminateOOFFMandate($mandate_id, $new_end_date_str, $cancel_reason, $mandate); } elseif ($mandate['type'] != "RCUR") { CRM_Core_Session::setStatus(ts("You can only modify the end date of recurring contribution mandates."), ts('Error'), 'error'); $lock->release(); return FALSE; } // load the contribution $contribution_id = $mandate['entity_id']; $contribution = civicrm_api('ContributionRecur', "getsingle", array('id' => $contribution_id, 'version' => 3)); if (isset($contribution['is_error']) && $contribution['is_error']) { CRM_Core_Session::setStatus(sprintf(ts("Cannot read contribution [%s]. Error was: '%s'"), $contribution_id, $contribution['error_message']), ts('Error'), 'error'); $lock->release(); return FALSE; } // check the date $today = strtotime("today"); $new_end_date = strtotime($new_end_date_str); if ($new_end_date < $today) { CRM_Core_Session::setStatus(sprintf(ts("You cannot set an end date in the past."), $contribution_id, $contribution['error_message']), ts('Error'), 'error'); $lock->release(); return FALSE; } // actually set the date $query = array('version' => 3, 'id' => $contribution_id, 'currency' => 'EUR', 'end_date' => date('YmdHis', $new_end_date)); if ($cancel_reason) { // FIXME: cancel_reason does not exist in contribution_recur!! //$query['cancel_reason'] = $cancel_reason; $query['cancel_date'] = $query['end_date']; } $result = civicrm_api("ContributionRecur", "create", $query); if (isset($result['is_error']) && $result['is_error']) { CRM_Core_Session::setStatus(sprintf(ts("Cannot modify recurring contribution [%s]. Error was: '%s'"), $contribution_id, $result['error_message']), ts('Error'), 'error'); $lock->release(); return FALSE; } // set the cancel reason if ($cancel_reason) { // ..and create a note, since the contribution_recur does not have cancel_reason $note_result = civicrm_api("Note", "create", array('version' => 3, 'entity_table' => 'civicrm_contribution_recur', 'entity_id' => $contribution_id, 'modified_date' => date('YmdHis'), 'subject' => 'cancel_reason', 'note' => $cancel_reason, 'privacy' => 0)); if (isset($note_result['is_error']) && $note_result['is_error']) { CRM_Core_Session::setStatus(sprintf(ts("Cannot set cancel reason for mandate [%s]. Error was: '%s'"), $mandate_id, $note_result['error_message']), ts('Error'), 'warn'); } } // find already created contributions that are now obsolete... $obsolete_ids = array(); $deleted_ids = array(); $obsolete_query = "\n SELECT id\n FROM civicrm_contribution\n WHERE receive_date > '{$new_end_date_str}'\n AND contribution_recur_id = {$contribution_id}\n AND contribution_status_id = {$contribution_id_pending};"; $obsolete_ids_query = CRM_Core_DAO::executeQuery($obsolete_query); while ($obsolete_ids_query->fetch()) { array_push($obsolete_ids, $obsolete_ids_query->id); } // ...and delete them: foreach ($obsolete_ids as $obsolete_id) { $delete_result = civicrm_api("Contribution", "delete", array('id' => $obsolete_id, 'version' => 3)); if (isset($delete_result['is_error']) && $delete_result['is_error']) { CRM_Core_Session::setStatus(sprintf(ts("Cannot delete scheduled contribution [%s]. Error was: '%s'"), $obsolete_id, $delete_result['error_message']), ts('Error'), 'warn'); } else { array_push($deleted_ids, $obsolete_id); } } if (count($deleted_ids)) { // also, remove them from the groups $deleted_ids_string = implode(',', $deleted_ids); CRM_Core_DAO::executeQuery("DELETE FROM civicrm_sdd_contribution_txgroup WHERE contribution_id IN ({$deleted_ids_string});"); } // finally, let the API close the mandate if end_date is now if ($new_end_date <= $today) { $close_result = civicrm_api("SepaAlternativeBatching", "closeended", array('version' => 3)); if (isset($close_result['is_error']) && $close_result['is_error']) { CRM_Core_Session::setStatus(sprintf(ts("Closing Mandate failed. Error was: '%s'"), $close_result['error_message']), ts('Error'), 'warn'); } } CRM_Core_Session::setStatus(ts("New end date set."), ts('Mandate updated.'), 'info'); CRM_Core_Session::setStatus(ts("Please note, that any <i>closed</i> batches that include this mandate cannot be changed any more - all pending contributions will still be executed."), ts('Mandate updated.'), 'warn'); if (count($deleted_ids)) { CRM_Core_Session::setStatus(sprintf(ts("Successfully deleted %d now obsolete contributions."), count($deleted_ids)), ts('Mandate updated.'), 'info'); } $lock->release(); return TRUE; }