Commit 4baf94be authored by Mathieu Lutfy's avatar Mathieu Lutfy Committed by Aegir user
Browse files

Upgrade sumfields to 4.0.1

parent 906e6f44
# Changelog
All notable changes for the Summary Fields extension will be noted here.
## [Unreleased]
### Changed
## [4.0.0] - 2019-02-05
### Added
- This changelog.
- If you are extending Summary Fields, you can now use trigger tables
that don't have the contact_id field. You can specify a tables array
containing the information needed for summary fields to properly
process changes to these tables. See custom.php and civicrm_line_item
table for an example.
### Changed
- All contribution summary fields are now calculated according to the
CiviCRM line item table instead of the contribution table. That means
contributions split between different financial types due to clever
use of price fields will now be calculated properly
- Improved documentation.
- Don't count test participation records.
<?php
use CRM_Sumfields_ExtensionUtil as E;
require_once 'CRM/Core/Form.php';
class CRM_Sumfields_Form_SumFields extends CRM_Core_Form {
......@@ -7,7 +9,7 @@ class CRM_Sumfields_Form_SumFields extends CRM_Core_Form {
$custom = sumfields_get_custom_field_definitions();
if (empty($custom['fields'])) {
// This means neither CiviEvent or CiviContribute are enabled.
CRM_Core_Session::setStatus(ts("Summary Fields is not particularly useful if CiviContribute and CiviEvent are both disabled. Try enabling at least one.", array('domain' => 'net.ourpowerbase.sumfields')));
CRM_Core_Session::setStatus(E::ts("Summary Fields is not particularly useful if CiviContribute and CiviEvent are both disabled. Try enabling at least one."));
return;
}
$trigger_tables = $fieldsets = $field_options = array();
......@@ -23,7 +25,7 @@ class CRM_Sumfields_Form_SumFields extends CRM_Core_Form {
$status_icon = 'fa-times';
if (empty($apply_settings_status)) {
$display_status = ts('The settings have never been saved (newly enabled)', array('domain' => 'net.ourpowerbase.sumfields'));
$display_status = E::ts('The settings have never been saved (newly enabled)');
$status_icon = 'fa-minus-circle';
}
else {
......@@ -43,26 +45,26 @@ class CRM_Sumfields_Form_SumFields extends CRM_Core_Form {
switch($matches[1]) {
case 'scheduled-triggers':
$display_status = ts("Setting changes were saved on %1, but not yet applied; they should be applied shortly.", array(1 => $date, 'domain' => 'net.ourpowerbase.sumfields'));
$display_status = E::ts("Setting changes were saved on %1, but not yet applied; they should be applied shortly.", array(1 => $date));
$status_icon = 'fa-hourglass-start';
break;
case 'scheduled-cron':
$display_status = ts("Setting changes were saved on %1, data calculation will be performed on every cron run.", array(1 => $date, 'domain' => 'net.ourpowerbase.sumfields'));
$display_status = E::ts("Setting changes were saved on %1, data calculation will be performed on every cron run.", array(1 => $date));
$status_icon = 'fa-hourglass-start';
break;
case 'running':
$display_status = ts("Setting changes are in the process of being applied; the process started on %1.", array(1 => $date, 'domain' => 'net.ourpowerbase.sumfields'));
$display_status = E::ts("Setting changes are in the process of being applied; the process started on %1.", array(1 => $date));
$status_icon = 'fa-hourglass-end';
break;
case 'success':
$display_status = ts("Setting changes were successfully applied on %1.", array(1 => $date, 'domain' => 'net.ourpowerbase.sumfields'));
$display_status = E::ts("Setting changes were successfully applied on %1.", array(1 => $date));
$status_icon = 'fa-check';
break;
case 'failed':
$display_status = ts("Setting changes failed to apply; the failed attempt happend on %1.", array(1 => $date, 'domain' => 'net.ourpowerbase.sumfields'));
$display_status = E::ts("Setting changes failed to apply; the failed attempt happend on %1.", array(1 => $date));
break;
default:
$display_status = ts("Unable to determine status (%1).", array(1 => $apply_settings_status, 'domain' => 'net.ourpowerbase.sumfields'));
$display_status = E::ts("Unable to determine status (%1).", array(1 => $apply_settings_status));
}
}
......@@ -89,25 +91,25 @@ class CRM_Sumfields_Form_SumFields extends CRM_Core_Form {
// Add extra settings to fieldsets
if (sumfields_component_enabled('CiviContribute')) {
$label = ts('Financial Types', array('domain' => 'net.ourpowerbase.sumfields'));
$label = E::ts('Financial Types');
$this->add('select', 'financial_type_ids', $label, sumfields_get_all_financial_types(), TRUE, array('multiple' => TRUE, 'class' => 'crm-select2 huge'));
$fieldsets[$custom['optgroups']['fundraising']['fieldset']]['financial_type_ids'] = ts("Financial types to include when calculating contribution related summary fields.", array('domain' => 'net.ourpowerbase.sumfields'));
$fieldsets[$custom['optgroups']['fundraising']['fieldset']]['financial_type_ids'] = E::ts("Financial types to include when calculating contribution related summary fields.");
}
if (sumfields_component_enabled('CiviMember')) {
$label = ts('Financial Types', array('domain' => 'net.ourpowerbase.sumfields'));
$label = E::ts('Financial Types');
$this->add('select', 'membership_financial_type_ids', $label, sumfields_get_all_financial_types(), TRUE, array('multiple' => TRUE, 'class' => 'crm-select2 huge'));
$fieldsets[$custom['optgroups']['membership']['fieldset']]['membership_financial_type_ids'] = ts("Financial types to include when calculating membership related summary fields.", array('domain' => 'net.ourpowerbase.sumfields'));
$fieldsets[$custom['optgroups']['membership']['fieldset']]['membership_financial_type_ids'] = E::ts("Financial types to include when calculating membership related summary fields.");
}
if (sumfields_component_enabled('CiviEvent')) {
$label = ts('Event Types', array('domain' => 'net.ourpowerbase.sumfields'));
$label = E::ts('Event Types');
$this->add('select', 'event_type_ids', $label, sumfields_get_all_event_types(), TRUE, array('multiple' => TRUE, 'class' => 'crm-select2 huge'));
$label = ts('Participant Status (attended)', array('domain' => 'net.ourpowerbase.sumfields'));
$label = E::ts('Participant Status (attended)');
$this->add('select', 'participant_status_ids', $label, sumfields_get_all_participant_status_types(), TRUE, array('multiple' => TRUE, 'class' => 'crm-select2 huge'));
$label = ts('Participant Status (did not attend)', array('domain' => 'net.ourpowerbase.sumfields'));
$label = E::ts('Participant Status (did not attend)');
$this->add('select', 'participant_noshow_status_ids', $label, sumfields_get_all_participant_status_types(), TRUE, array('multiple' => TRUE, 'class' => 'crm-select2 huge'));
$fieldsets[$custom['optgroups']['event_standard']['fieldset']] += array(
......@@ -119,30 +121,30 @@ class CRM_Sumfields_Form_SumFields extends CRM_Core_Form {
$this->assign('fieldsets', $fieldsets);
$bd_label = ts('How often should summary data be updated?', array('domain' => 'net.ourpowerbase.sumfields'));
$bd_label = E::ts('How often should summary data be updated?');
$bd_options = array(
'via_triggers' => ts("Instantly", array('domain' => 'net.ourpowerbase.sumfields')),
'via_cron' => ts("When ever the cron job is run (increases performance on large installation)", array('domain' => 'net.ourpowerbase.sumfields'))
'via_triggers' => E::ts("Instantly"),
'via_cron' => E::ts("When ever the cron job is run (increases performance on large installation)")
);
$this->addRadio('data_update_method', $bd_label, $bd_options);
$label = ts('When should these changes be applied?', array('domain' => 'net.ourpowerbase.sumfields'));
$label = E::ts('When should these changes be applied?');
$options = array(
'via_cron' => ts("On the next scheduled job (cron)", array('domain' => 'net.ourpowerbase.sumfields')),
'on_submit' => ts("When I submit this form", array('domain' => 'net.ourpowerbase.sumfields'))
'via_cron' => E::ts("On the next scheduled job (cron)"),
'on_submit' => E::ts("When I submit this form")
);
$this->addRadio('when_to_apply_change', $label, $options);
$this->addButtons(array(
array(
'type' => 'next',
'name' => ts('Save'),
'name' => E::ts('Save'),
'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
'isDefault' => TRUE,
),
array(
'type' => 'cancel',
'name' => ts('Cancel'),
'name' => E::ts('Cancel'),
),
)
);
......@@ -205,14 +207,14 @@ class CRM_Sumfields_Form_SumFields extends CRM_Core_Form {
if ($values['when_to_apply_change'] == 'on_submit') {
$returnValues = array();
if (!sumfields_gen_data($returnValues)) {
$session::setStatus(ts("There was an error applying your changes.", array('domain' => 'net.ourpowerbase.sumfields')), ts('Error'), 'error');
$session::setStatus(E::ts("There was an error applying your changes."), E::ts('Error'), 'error');
}
else {
$session::setStatus(ts("Changes were applied successfully.", array('domain' => 'net.ourpowerbase.sumfields')), ts('Saved'), 'success');
$session::setStatus(E::ts("Changes were applied successfully."), E::ts('Saved'), 'success');
}
}
else {
$session::setStatus(ts("Your summary fields will begin being generated on the next scheduled job. It may take up to an hour to complete.", array('domain' => 'net.ourpowerbase.sumfields')), ts('Saved'), 'success');
$session::setStatus(E::ts("Your summary fields will begin being generated on the next scheduled job. It may take up to an hour to complete."), E::ts('Saved'), 'success');
}
$session->replaceUserContext(CRM_Utils_System::url('civicrm/admin/setting/sumfields'));
}
......
<?php
use CRM_Sumfields_ExtensionUtil as E;
/**
* Collection of upgrade steps.
*/
class CRM_Sumfields_Upgrader extends CRM_Sumfields_Upgrader_Base {
/**
* Re-build triggers and re-generate data.
*
* Since version 4.0.0 now tracks contributions by line items, we need
* to rebuild triggers and rebuild data to ensure we are current.
*
* @return TRUE on success
* @throws Exception
**/
public function upgrade_4000() {
$this->ctx->log->info('Planning update 4000'); // PEAR Log interface
$this->addTask(E::ts('Regenerate Data'), 'regenerateData');
$this->addTask(E::ts('Rebuild Triggers'), 'triggerRebuild');
return TRUE;
}
public function triggerRebuild() {
CRM_Core_DAO::triggerRebuild();
return TRUE;
}
public function regenerateData() {
return sumfields_generate_data_based_on_current_data();
}
}
<
<?php
// AUTO-GENERATED FILE -- Civix may overwrite any changes made to this file
use CRM_Sumfields_ExtensionUtil as E;
/**
* Base class which provides helpers to execute upgrade logic
*/
class CRM_Sumfields_Upgrader_Base {
/**
* @var varies, subclass of ttis
*/
static $instance;
/**
* @var CRM_Queue_TaskContext
*/
protected $ctx;
/**
* @var string, eg 'com.example.myextension'
*/
protected $extensionName;
/**
* @var string, full path to the extension's source tree
*/
protected $extensionDir;
/**
* @var array(revisionNumber) sorted numerically
*/
private $revisions;
/**
* @var boolean
* Flag to clean up extension revision data in civicrm_setting
*/
private $revisionStorageIsDeprecated = FALSE;
/**
* Obtain a reference to the active upgrade handler.
*/
static public function instance() {
if (!self::$instance) {
// FIXME auto-generate
self::$instance = new CRM_Sumfields_Upgrader(
'net.ourpowerbase.sumfields',
realpath(__DIR__ . '/../../../')
);
}
return self::$instance;
}
/**
* Adapter that lets you add normal (non-static) member functions to the queue.
*
* Note: Each upgrader instance should only be associated with one
* task-context; otherwise, this will be non-reentrant.
*
* @code
* CRM_Sumfields_Upgrader_Base::_queueAdapter($ctx, 'methodName', 'arg1', 'arg2');
* @endcode
*/
static public function _queueAdapter() {
$instance = self::instance();
$args = func_get_args();
$instance->ctx = array_shift($args);
$instance->queue = $instance->ctx->queue;
$method = array_shift($args);
return call_user_func_array(array($instance, $method), $args);
}
public function __construct($extensionName, $extensionDir) {
$this->extensionName = $extensionName;
$this->extensionDir = $extensionDir;
}
// ******** Task helpers ********
/**
* Run a CustomData file.
*
* @param string $relativePath the CustomData XML file path (relative to this extension's dir)
* @return bool
*/
public function executeCustomDataFile($relativePath) {
$xml_file = $this->extensionDir . '/' . $relativePath;
return $this->executeCustomDataFileByAbsPath($xml_file);
}
/**
* Run a CustomData file
*
* @param string $xml_file the CustomData XML file path (absolute path)
*
* @return bool
*/
protected static function executeCustomDataFileByAbsPath($xml_file) {
$import = new CRM_Utils_Migrate_Import();
$import->run($xml_file);
return TRUE;
}
/**
* Run a SQL file.
*
* @param string $relativePath the SQL file path (relative to this extension's dir)
*
* @return bool
*/
public function executeSqlFile($relativePath) {
CRM_Utils_File::sourceSQLFile(
CIVICRM_DSN,
$this->extensionDir . DIRECTORY_SEPARATOR . $relativePath
);
return TRUE;
}
/**
* @param string $tplFile
* The SQL file path (relative to this extension's dir).
* Ex: "sql/mydata.mysql.tpl".
* @return bool
*/
public function executeSqlTemplate($tplFile) {
// Assign multilingual variable to Smarty.
$upgrade = new CRM_Upgrade_Form();
$tplFile = CRM_Utils_File::isAbsolute($tplFile) ? $tplFile : $this->extensionDir . DIRECTORY_SEPARATOR . $tplFile;
$smarty = CRM_Core_Smarty::singleton();
$smarty->assign('domainID', CRM_Core_Config::domainID());
CRM_Utils_File::sourceSQLFile(
CIVICRM_DSN, $smarty->fetch($tplFile), NULL, TRUE
);
return TRUE;
}
/**
* Run one SQL query.
*
* This is just a wrapper for CRM_Core_DAO::executeSql, but it
* provides syntatic sugar for queueing several tasks that
* run different queries
*/
public function executeSql($query, $params = array()) {
// FIXME verify that we raise an exception on error
CRM_Core_DAO::executeQuery($query, $params);
return TRUE;
}
/**
* Syntatic sugar for enqueuing a task which calls a function in this class.
*
* The task is weighted so that it is processed
* as part of the currently-pending revision.
*
* After passing the $funcName, you can also pass parameters that will go to
* the function. Note that all params must be serializable.
*/
public function addTask($title) {
$args = func_get_args();
$title = array_shift($args);
$task = new CRM_Queue_Task(
array(get_class($this), '_queueAdapter'),
$args,
$title
);
return $this->queue->createItem($task, array('weight' => -1));
}
// ******** Revision-tracking helpers ********
/**
* Determine if there are any pending revisions.
*
* @return bool
*/
public function hasPendingRevisions() {
$revisions = $this->getRevisions();
$currentRevision = $this->getCurrentRevision();
if (empty($revisions)) {
return FALSE;
}
if (empty($currentRevision)) {
return TRUE;
}
return ($currentRevision < max($revisions));
}
/**
* Add any pending revisions to the queue.
*/
public function enqueuePendingRevisions(CRM_Queue_Queue $queue) {
$this->queue = $queue;
$currentRevision = $this->getCurrentRevision();
foreach ($this->getRevisions() as $revision) {
if ($revision > $currentRevision) {
$title = ts('Upgrade %1 to revision %2', array(
1 => $this->extensionName,
2 => $revision,
));
// note: don't use addTask() because it sets weight=-1
$task = new CRM_Queue_Task(
array(get_class($this), '_queueAdapter'),
array('upgrade_' . $revision),
$title
);
$this->queue->createItem($task);
$task = new CRM_Queue_Task(
array(get_class($this), '_queueAdapter'),
array('setCurrentRevision', $revision),
$title
);
$this->queue->createItem($task);
}
}
}
/**
* Get a list of revisions.
*
* @return array(revisionNumbers) sorted numerically
*/
public function getRevisions() {
if (!is_array($this->revisions)) {
$this->revisions = array();
$clazz = new ReflectionClass(get_class($this));
$methods = $clazz->getMethods();
foreach ($methods as $method) {
if (preg_match('/^upgrade_(.*)/', $method->name, $matches)) {
$this->revisions[] = $matches[1];
}
}
sort($this->revisions, SORT_NUMERIC);
}
return $this->revisions;
}
public function getCurrentRevision() {
$revision = CRM_Core_BAO_Extension::getSchemaVersion($this->extensionName);
if (!$revision) {
$revision = $this->getCurrentRevisionDeprecated();
}
return $revision;
}
private function getCurrentRevisionDeprecated() {
$key = $this->extensionName . ':version';
if ($revision = CRM_Core_BAO_Setting::getItem('Extension', $key)) {
$this->revisionStorageIsDeprecated = TRUE;
}
return $revision;
}
public function setCurrentRevision($revision) {
CRM_Core_BAO_Extension::setSchemaVersion($this->extensionName, $revision);
// clean up legacy schema version store (CRM-19252)
$this->deleteDeprecatedRevision();
return TRUE;
}
private function deleteDeprecatedRevision() {
if ($this->revisionStorageIsDeprecated) {
$setting = new CRM_Core_BAO_Setting();
$setting->name = $this->extensionName . ':version';
$setting->delete();
CRM_Core_Error::debug_log_message("Migrated extension schema revision ID for {$this->extensionName} from civicrm_setting (deprecated) to civicrm_extension.\n");
}
}
// ******** Hook delegates ********
/**
* @see https://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_install
*/
public function onInstall() {
$files = glob($this->extensionDir . '/sql/*_install.sql');
if (is_array($files)) {
foreach ($files as $file) {
CRM_Utils_File::sourceSQLFile(CIVICRM_DSN, $file);
}
}
$files = glob($this->extensionDir . '/sql/*_install.mysql.tpl');
if (is_array($files)) {
foreach ($files as $file) {
$this->executeSqlTemplate($file);
}
}
$files = glob($this->extensionDir . '/xml/*_install.xml');
if (is_array($files)) {
foreach ($files as $file) {
$this->executeCustomDataFileByAbsPath($file);
}
}
if (is_callable(array($this, 'install'))) {
$this->install();
}
}
/**
* @see https://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_postInstall
*/
public function onPostInstall() {
$revisions = $this->getRevisions();
if (!empty($revisions)) {
$this->setCurrentRevision(max($revisions));
}
if (is_callable(array($this, 'postInstall'))) {
$this->postInstall();
}
}
/**
* @see https://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_uninstall
*/
public function onUninstall() {
$files = glob($this->extensionDir . '/sql/*_uninstall.mysql.tpl');
if (is_array($files)) {
foreach ($files as $file) {
$this->executeSqlTemplate($file);
}
}
if (is_callable(array($this, 'uninstall'))) {
$this->uninstall();
}
$files = glob($this->extensionDir . '/sql/*_uninstall.sql');
if (is_array($files)) {
foreach ($files as $file) {
CRM_Utils_File::sourceSQLFile(CIVICRM_DSN, $file);
}
}
}
/**
* @see https://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_enable
*/
public function onEnable() {
// stub for possible future use
if (is_callable(array($this, 'enable'))) {
$this->enable();
}
}
/**
* @see https://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_disable
*/
public function onDisable() {
// stub for possible future use
if (is_callable(array($this, 'disable'))) {
$this->disable();
}
}
public function onUpgrade($op, CRM_Queue_Queue $queue = NULL) {
switch ($op) {
case 'check':
return array($this->hasPendingRevisions());
case 'enqueue':
return $this->enqueuePendingRevisions($queue);
default:
}