Merge pull request #14118 from eileenmcnaughton/no_fin_item
authorEileen McNaughton <eileen@mcnaughty.com>
Sat, 11 May 2019 23:49:48 +0000 (11:49 +1200)
committerGitHub <noreply@github.com>
Sat, 11 May 2019 23:49:48 +0000 (11:49 +1200)
Fix financial acl permissions to respect check_permissions

139 files changed:
CRM/Activity/BAO/Activity.php
CRM/Activity/BAO/ICalendar.php
CRM/Activity/Selector/Activity.php
CRM/Admin/Form/RelationshipType.php
CRM/Batch/BAO/Batch.php
CRM/Campaign/Form/Search/Campaign.php
CRM/Case/BAO/Case.php
CRM/Case/Form/Activity/OpenCase.php
CRM/Case/Selector/Search.php
CRM/Contact/BAO/Relationship.php
CRM/Contact/DAO/Group.php
CRM/Contact/Form/DedupeRules.php
CRM/Contact/Form/Search/Custom/FullText.php
CRM/Contact/Form/Task.php
CRM/Contact/Form/Task/SaveSearch.php
CRM/Contact/Import/ImportJob.php
CRM/Contact/Import/Parser.php
CRM/Contribute/BAO/Contribution.php
CRM/Contribute/BAO/ContributionPage.php
CRM/Contribute/BAO/ContributionRecur.php
CRM/Contribute/BAO/Query.php
CRM/Contribute/DAO/ContributionRecur.php
CRM/Contribute/Form/ContributionRecur.php
CRM/Core/Action.php
CRM/Core/BAO/Address.php
CRM/Core/BAO/Block.php
CRM/Core/BAO/CustomField.php
CRM/Core/BAO/CustomOption.php
CRM/Core/BAO/CustomValueTable.php
CRM/Core/BAO/File.php
CRM/Core/BAO/Job.php
CRM/Core/BAO/Location.php
CRM/Core/BAO/Note.php
CRM/Core/BAO/OptionValue.php
CRM/Core/BAO/Tag.php
CRM/Core/BAO/UFGroup.php
CRM/Core/DAO.php
CRM/Core/Error.php
CRM/Core/Form.php
CRM/Core/Form/EntityFormTrait.php
CRM/Core/Payment.php
CRM/Core/PseudoConstant.php
CRM/Core/Resources.php
CRM/Dedupe/Merger.php
CRM/Event/BAO/Event.php
CRM/Event/Cart/Form/Checkout/ParticipantsAndPrices.php
CRM/Event/Cart/Form/Checkout/Payment.php
CRM/Event/Page/ManageEvent.php
CRM/Export/BAO/Export.php
CRM/Financial/BAO/ExportFormat/IIF.php
CRM/Financial/BAO/Payment.php
CRM/Group/Form/Edit.php
CRM/Mailing/ActionTokens.php
CRM/Mailing/BAO/Mailing.php
CRM/Mailing/Page/View.php
CRM/Mailing/Selector/Search.php
CRM/Mailing/Tokens.php
CRM/Price/BAO/PriceSet.php
CRM/Report/Form.php
CRM/Report/Form/Campaign/SurveyDetails.php
CRM/Report/Form/Contribute/Sybunt.php
CRM/Report/Form/Extended.php [deleted file]
CRM/Upgrade/Incremental/Base.php
CRM/Upgrade/Incremental/php/FiveFifteen.php [new file with mode: 0644]
CRM/Upgrade/Incremental/php/FiveFourteen.php
CRM/Upgrade/Incremental/sql/5.14.beta1.mysql.tpl [new file with mode: 0644]
CRM/Upgrade/Incremental/sql/5.15.alpha1.mysql.tpl [new file with mode: 0644]
CRM/Utils/Check/Component/FinancialTypeAcls.php
CRM/Utils/Hook.php
CRM/Utils/SQL/TempTable.php
CRM/Utils/System.php
CRM/Utils/System/Backdrop.php
CRM/Utils/System/Base.php
CRM/Utils/System/Drupal8.php
CRM/Utils/System/WordPress.php
Civi/Core/AssetBuilder.php
Civi/Core/Container.php
Civi/Install/Requirements.php
ang/crmMailingAB/WinnerDialogCtrl.js
ang/crmMailingAB/services.js
api/v3/Activity.php
api/v3/Mailing.php
api/v3/MailingAB.php
api/v3/Payment.php
bin/cli.class.php
contributor-key.yml
css/crm-menubar.css
css/menubar-backdrop.css
css/menubar-drupal7.css
css/menubar-drupal8.css
css/menubar-joomla.css
css/menubar-wordpress.css
extern/rest.php
js/crm.menubar.js
release-notes.md
release-notes/5.12.4.md [new file with mode: 0644]
release-notes/5.13.0.md [new file with mode: 0644]
release-notes/5.13.1.md [new file with mode: 0644]
release-notes/5.13.2.md [new file with mode: 0644]
sql/civicrm_generated.mysql
templates/CRM/Activity/Form/Search/Common.tpl
templates/CRM/Campaign/Form/Search/Campaign.tpl
templates/CRM/Core/DatePickerRangeWrapper.tpl [new file with mode: 0644]
templates/CRM/Event/Cart/Form/Checkout/Payment.tpl
templates/CRM/common/batchCopy.tpl
tests/phpunit/CRM/Activity/BAO/ActivityTest.php
tests/phpunit/CRM/Case/BAO/CaseTest.php
tests/phpunit/CRM/Contact/Import/Parser/ContactTest.php
tests/phpunit/CRM/Contribute/Form/AdditionalPaymentTest.php
tests/phpunit/CRM/Contribute/Form/SearchTest.php
tests/phpunit/CRM/Core/BAO/RecurringEntityTest.php
tests/phpunit/CRM/Mailing/TokensTest.php
tests/phpunit/api/v3/MailingABTest.php
tests/phpunit/api/v3/MailingTest.php
tests/phpunit/api/v3/PaymentTest.php
tools/bin/scripts/ImportTags.php
tools/bin/scripts/NormalizePhone.php
tools/bin/scripts/ckeditorConfigScraper.php
tools/bin/scripts/cli.php
tools/bin/scripts/memcache.php
tools/bin/scripts/set-version.php
tools/bin/scripts/testProcess.php
tools/bin/scripts/updateNameCache.php
tools/drupal/modules/civicrm_webtest/civicrm_webtest.install
tools/extensions/org.civicrm.angularex/angularex.civix.php
tools/extensions/org.civicrm.angularex/angularex.php
tools/extensions/org.civicrm.demoqueue/CRM/Demoqueue/Page/DemoQueue.php
tools/extensions/org.civicrm.demoqueue/CRM/Demoqueue/Page/DemoQueueDone.php
tools/extensions/org.civicrm.demoqueue/demoqueue.civix.php
tools/scripts/check-angular.php
tools/scripts/civimail-spooler/civimail-spooler.php
tools/scripts/composer/patches/civicrm-custom-patches-zetacompoents-mail.patch
tools/scripts/solr/createSolrJSON.php
tools/scripts/solr/createSolrXML.php
tools/scripts/solr/createSyncJSON.php
tools/scripts/tpl-lint
xml/schema/Contact/Group.xml
xml/schema/Contribute/ContributionRecur.xml
xml/version.xml

index af4961d5ab5ee4115f7928d79e39f95b73c470d5..8aeadbde9a7928da3f1a7e3c0e5a262df5b603de 100644 (file)
@@ -2414,7 +2414,7 @@ INNER JOIN  civicrm_option_group grp ON (grp.id = option_group_id AND grp.name =
   }
 
   /**
-   * Checks if user has permissions to edit inbound e-mails, either bsic info
+   * Checks if user has permissions to edit inbound e-mails, either basic info
    * or both basic information and content.
    *
    * @return bool
index 4ebc2b0b54bdff0598d3f0243cf7d16061468ef8..cb2cb014eff745ed34526d7214b9f82f2dcf577f 100644 (file)
@@ -67,8 +67,7 @@ class CRM_Activity_BAO_ICalendar {
   public function addAttachment(&$attachments, $contacts) {
     // Check preferences setting
     if (Civi::settings()->get('activity_assignee_notification_ics')) {
-      $config = &CRM_Core_Config::singleton();
-      $this->icsfile = tempnam($config->customFileUploadDir, 'ics');
+      $this->icsfile = tempnam(CRM_Core_Config::singleton()->customFileUploadDir, 'ics');
       if ($this->icsfile !== FALSE) {
         rename($this->icsfile, $this->icsfile . '.ics');
         $this->icsfile .= '.ics';
index e03072dbdd175adf0321ad4882139e375a46d92e..6fef52aaff359b1ef55f3e9c4df1444164b8d7d8 100644 (file)
@@ -181,9 +181,7 @@ class CRM_Activity_Selector_Activity extends CRM_Core_Selector_Base implements C
         $url = 'civicrm/contact/view/activity';
         $qsView = "atype={$activityTypeId}&action=view&reset=1&id=%%id%%&cid=%%cid%%&context=%%cxt%%{$extraParams}";
 
-        if (CRM_Core_Permission::check('edit inbound email basic information')
-          || CRM_Core_Permission::check('edit inbound email basic information and content')
-        ) {
+        if (CRM_Activity_BAO_Activity::checkEditInboundEmailsPermissions()) {
           $showDelete = $showUpdate = TRUE;
           $qsUpdate = "atype={$activityTypeId}&action=update&reset=1&id=%%id%%&cid=%%cid%%&context=%%cxt%%{$extraParams}";
         }
index 1b537f90634a305db517969247910842db35e329..b0c604c0103ba659cdc0c1a0b809953b58c221da 100644 (file)
@@ -208,8 +208,8 @@ class CRM_Admin_Form_RelationshipType extends CRM_Admin_Form {
 
       if (empty($params['id'])) {
         // Set name on created but don't update on update as the machine name is not exposed.
-        $params['name_b_a'] = CRM_Utils_String::munge($params['label_b_a']);
-        $params['name_a_b'] = CRM_Utils_String::munge($params['label_a_b']);
+        $params['name_b_a'] = $params['label_b_a'];
+        $params['name_a_b'] = $params['label_a_b'];
       }
 
       $result = civicrm_api3('RelationshipType', 'create', $params);
index aa87f7076f52eca51fbd6a2ce5cc61e2e1785f30..fb2b2a326194d20ab2e40f98ddc18535d189a1a9 100644 (file)
@@ -560,7 +560,6 @@ class CRM_Batch_BAO_Batch extends CRM_Batch_DAO_Batch {
       while ($dao->fetch()) {
         $totals[$dao->batch_id] = (array) $dao;
       }
-      $dao->free();
     }
     return $totals;
   }
index 6fc5d63ab848583b26da230833933e9be33c3ebd..f292272399c593a112c880420adaa3681fe2cc90 100644 (file)
  */
 class CRM_Campaign_Form_Search_Campaign extends CRM_Core_Form {
 
+  /**
+   * Explicitly declare the entity api name.
+   *
+   * @return string
+   */
+  public function getDefaultEntity() {
+    return 'Campaign';
+  }
+
   /**
    * Are we forced to run a search.
    *
@@ -78,11 +87,8 @@ class CRM_Campaign_Form_Search_Campaign extends CRM_Core_Form {
     //campaign description.
     $this->add('text', 'description', ts('Description'), $attributes['description']);
 
-    //campaign start date.
-    $this->addDate('start_date', ts('From'), FALSE, ['formatType' => 'searchDate']);
-
-    //campaign end date.
-    $this->addDate('end_date', ts('To'), FALSE, ['formatType' => 'searchDate']);
+    $this->add('datepicker', 'start_date', ts('Campaign Start Date'), [], FALSE, ['time' => FALSE]);
+    $this->add('datepicker', 'end_date', ts('Campaign End Date'), [], FALSE, ['time' => FALSE]);
 
     //campaign type.
     $campaignTypes = CRM_Campaign_PseudoConstant::campaignType();
index 091b4e9f046f74b26202acd3c39bd5fac2f95fc2..222860016a0125dbbdd91beeb93e281a0613b555 100644 (file)
@@ -429,121 +429,60 @@ WHERE cc.contact_id = %1 AND civicrm_case_type.name = '{$caseType}'";
       'civicrm_phone.phone as phone',
       'civicrm_contact.contact_type as contact_type',
       'civicrm_contact.contact_sub_type as contact_sub_type',
-      't_act.activity_type_id',
-      'c_type.title as case_type',
+      't_act.activity_type_id as activity_type_id',
       'civicrm_case.case_type_id as case_type_id',
-      'cov_status.label as case_status',
-      'cov_status.label as case_status_name',
-      't_act.status_id',
+      'civicrm_case.status_id as case_status_id',
+      't_act.status_id as status_id',
       'civicrm_case.start_date as case_start_date',
       'case_relation_type.label_b_a as case_role',
+      't_act.activity_date_time as activity_date_time',
+      't_act.id as activity_id',
     );
 
-    if ($type == 'upcoming') {
-      $selectClauses = array_merge($selectClauses, array(
-        't_act.desired_date as case_scheduled_activity_date',
-        't_act.id as case_scheduled_activity_id',
-        't_act.act_type_name as case_scheduled_activity_type_name',
-        't_act.act_type AS case_scheduled_activity_type',
-      ));
-    }
-    elseif ($type == 'recent') {
-      $selectClauses = array_merge($selectClauses, array(
-        't_act.desired_date as case_recent_activity_date',
-        't_act.id as case_recent_activity_id',
-        't_act.act_type_name as case_recent_activity_type_name',
-        't_act.act_type AS case_recent_activity_type',
-      ));
-    }
-    elseif ($type == 'any') {
-      $selectClauses = array_merge($selectClauses, array(
-        't_act.desired_date as case_activity_date',
-        't_act.id as case_activity_id',
-        't_act.act_type_name as case_activity_type_name',
-        't_act.act_type AS case_activity_type',
-      ));
-    }
-
     $query = CRM_Contact_BAO_Query::appendAnyValueToSelect($selectClauses, 'case_id');
 
-    $query .= " FROM civicrm_case
-                  INNER JOIN civicrm_case_contact ON civicrm_case.id = civicrm_case_contact.case_id
-                  INNER JOIN civicrm_contact ON civicrm_case_contact.contact_id = civicrm_contact.id ";
-
-    if ($type == 'upcoming') {
-      // This gets the earliest activity per case that's scheduled within 14 days from now.
-      // Note we have an inner select to get the min activity id in order to remove duplicates in case there are two with the same datetime.
-      // In this case we don't really care which one, so min(id) works.
-      // optimized in CRM-11837
-      $query .= " INNER JOIN
-(
-  SELECT case_id, act.id, activity_date_time AS desired_date, activity_type_id, status_id, aov.name AS act_type_name, aov.label AS act_type
-  FROM (
-    SELECT *
-    FROM (
-      SELECT *
-      FROM civicrm_view_case_activity_upcoming
-      ORDER BY activity_date_time ASC, id ASC
-      ) AS upcomingOrdered
-    ) AS act
-  LEFT JOIN civicrm_option_group aog ON aog.name='activity_type'
-  LEFT JOIN civicrm_option_value aov ON ( aov.option_group_id = aog.id AND aov.value = act.activity_type_id )
-) AS t_act
-";
-    }
-    elseif ($type == 'recent') {
-      // Similarly, the most recent activity in the past 14 days, and exclude scheduled.
-      //improve query performance - CRM-10598
-      $query .= " INNER JOIN
-(
-  SELECT case_id, act.id, activity_date_time AS desired_date, activity_type_id, status_id, aov.name AS act_type_name, aov.label AS act_type
-  FROM (
-    SELECT *
-    FROM (
-      SELECT *
-      FROM civicrm_view_case_activity_recent
-      ORDER BY activity_date_time DESC, id ASC
-      ) AS recentOrdered
-    ) AS act
-LEFT JOIN civicrm_option_group aog ON aog.name='activity_type'
-  LEFT JOIN civicrm_option_value aov ON ( aov.option_group_id = aog.id AND aov.value = act.activity_type_id )
-) AS t_act ";
-    }
-    elseif ($type == 'any') {
-      $query .= " LEFT JOIN
-(
-  SELECT ca4.case_id, act4.id AS id, act4.activity_date_time AS desired_date, act4.activity_type_id, act4.status_id, aov.name AS act_type_name, aov.label AS act_type
-  FROM civicrm_activity act4
-  LEFT JOIN civicrm_case_activity ca4
-    ON ca4.activity_id = act4.id
-    AND act4.is_current_revision = 1
-  LEFT JOIN civicrm_option_group aog
-    ON aog.name='activity_type'
-  LEFT JOIN civicrm_option_value aov
-    ON aov.option_group_id = aog.id
-    AND aov.value = act4.activity_type_id
-) AS t_act";
-    }
-
-    $query .= "
-        ON t_act.case_id = civicrm_case.id
- LEFT JOIN civicrm_phone ON (civicrm_phone.contact_id = civicrm_contact.id AND civicrm_phone.is_primary=1)
- LEFT JOIN civicrm_relationship case_relationship
- ON ( case_relationship.contact_id_a = civicrm_case_contact.contact_id AND case_relationship.contact_id_b = {$userID} AND case_relationship.is_active AND case_relationship.case_id = civicrm_case.id )
- LEFT JOIN civicrm_relationship_type case_relation_type
- ON ( case_relation_type.id = case_relationship.relationship_type_id
-      AND case_relation_type.id = case_relationship.relationship_type_id )
-
- LEFT JOIN civicrm_case_type c_type
- ON civicrm_case.case_type_id = c_type.id
-
- LEFT JOIN civicrm_option_group cog_status
- ON cog_status.name = 'case_status'
-
- LEFT JOIN civicrm_option_value cov_status
- ON ( civicrm_case.status_id = cov_status.value
-      AND cog_status.id = cov_status.option_group_id )
-";
+    $query .= <<<HERESQL
+      FROM civicrm_case
+        INNER JOIN civicrm_case_contact ON civicrm_case.id = civicrm_case_contact.case_id
+        INNER JOIN civicrm_contact ON civicrm_case_contact.contact_id = civicrm_contact.id
+HERESQL;
+
+    switch ($type) {
+      case 'upcoming':
+      case 'recent':
+        // civicrm_view_case_activity_upcoming and
+        // civicrm_view_case_activity_recent are views that show the next
+        // scheduled and most recent not-scheduled activity on each case,
+        // respectively.
+        $query .= <<<HERESQL
+        INNER JOIN civicrm_view_case_activity_$type t_act
+          ON t_act.case_id = civicrm_case.id
+HERESQL;
+        break;
+
+      case 'any':
+        $query .= <<<HERESQL
+        LEFT JOIN civicrm_case_activity ca4
+          ON civicrm_case.id = ca4.case_id
+        LEFT JOIN civicrm_activity t_act
+          ON t_act.id = ca4.activity_id
+          AND t_act.is_current_revision = 1
+HERESQL;
+    }
+
+    $query .= <<<HERESQL
+        LEFT JOIN civicrm_phone
+          ON civicrm_phone.contact_id = civicrm_contact.id
+            AND civicrm_phone.is_primary = 1
+        LEFT JOIN civicrm_relationship case_relationship
+          ON case_relationship.contact_id_a = civicrm_case_contact.contact_id
+            AND case_relationship.contact_id_b = {$userID}
+            AND case_relationship.is_active
+            AND case_relationship.case_id = civicrm_case.id
+        LEFT JOIN civicrm_relationship_type case_relation_type
+          ON case_relation_type.id = case_relationship.relationship_type_id
+            AND case_relation_type.id = case_relationship.relationship_type_id
+HERESQL;
 
     if ($condition) {
       // CRM-8749 backwards compatibility - callers of this function expect to start $condition with "AND"
@@ -551,20 +490,7 @@ LEFT JOIN civicrm_option_group aog ON aog.name='activity_type'
     }
     $query .= " GROUP BY case_id ";
 
-    if ($order) {
-      $query .= $order;
-    }
-    else {
-      if ($type == 'upcoming') {
-        $query .= " ORDER BY case_scheduled_activity_date ASC ";
-      }
-      elseif ($type == 'recent') {
-        $query .= " ORDER BY case_recent_activity_date ASC ";
-      }
-      elseif ($type == 'any') {
-        $query .= " ORDER BY case_activity_date ASC ";
-      }
-    }
+    $query .= ($order) ?: ' ORDER BY activity_date_time ASC';
 
     if ($limit) {
       $query .= $limit;
@@ -601,20 +527,6 @@ LEFT JOIN civicrm_option_group aog ON aog.name='activity_type'
     $type = CRM_Utils_Array::value('type', $params, 'upcoming');
     $userID = CRM_Core_Session::singleton()->get('userID');
 
-    $caseActivityTypeColumn = 'case_activity_type_name';
-    $caseActivityDateColumn = 'case_activity_date';
-    $caseActivityIDColumn = 'case_activity_id';
-    if ($type == 'upcoming') {
-      $caseActivityDateColumn = 'case_scheduled_activity_date';
-      $caseActivityTypeColumn = 'case_scheduled_activity_type';
-      $caseActivityIDColumn = 'case_scheduled_activity_id';
-    }
-    elseif ($type == 'recent') {
-      $caseActivityDateColumn = 'case_recent_activity_date';
-      $caseActivityTypeColumn = 'case_recent_activity_type';
-      $caseActivityIDColumn = 'case_recent_activity_id';
-    }
-
     // validate access for all cases.
     if ($allCases && !CRM_Core_Permission::check('access all cases and activities')) {
       $allCases = FALSE;
@@ -654,7 +566,7 @@ LEFT JOIN civicrm_option_group aog ON aog.name='activity_type'
     $order = NULL;
     if (!empty($params['sortBy'])) {
       if (strstr($params['sortBy'], 'date ')) {
-        $params['sortBy'] = str_replace('date', $caseActivityDateColumn, $params['sortBy']);
+        $params['sortBy'] = str_replace('date', 'activity_date_time', $params['sortBy']);
       }
       $order = "ORDER BY " . $params['sortBy'];
     }
@@ -662,8 +574,6 @@ LEFT JOIN civicrm_option_group aog ON aog.name='activity_type'
     $query = self::getCaseActivityQuery($type, $userID, $condition, $limit, $order);
     $result = CRM_Core_DAO::executeQuery($query);
 
-    $caseStatus = CRM_Core_OptionGroup::values('case_status', FALSE, FALSE, FALSE, " AND v.name = 'Urgent' ");
-
     // we're going to use the usual actions, so doesn't make sense to duplicate definitions
     $actions = CRM_Case_Selector_Search::links();
 
@@ -679,7 +589,12 @@ LEFT JOIN civicrm_option_group aog ON aog.name='activity_type'
     }
     $mask = CRM_Core_Action::mask($permissions);
 
+    // Pseudoconstants to populate labels
+    $caseStatuses = CRM_Case_PseudoConstant::caseStatus('label', FALSE);
     $caseTypes = CRM_Case_PseudoConstant::caseType('name');
+    $caseTypeTitles = CRM_Case_PseudoConstant::caseType('title', FALSE);
+    $activityTypeLabels = CRM_Activity_BAO_Activity::buildOptions('activity_type_id');
+
     foreach ($result->fetchAll() as $case) {
       $key = $case['case_id'];
       $casesList[$key] = array();
@@ -701,30 +616,31 @@ LEFT JOIN civicrm_option_group aog ON aog.name='activity_type'
         $case['case_id']
       );
       $casesList[$key]['subject'] = $case['case_subject'];
-      $casesList[$key]['case_status'] = in_array($case['case_status'], $caseStatus) ? sprintf('<strong>%s</strong>', strtoupper($case['case_status'])) : $case['case_status'];
-      $casesList[$key]['case_type'] = $case['case_type'];
+      $casesList[$key]['case_status'] = CRM_Utils_Array::value($case['case_status_id'], $caseStatuses);
+      if ($case['case_status_id'] == CRM_Case_PseudoConstant::getKey('CRM_Case_BAO_Case', 'case_status_id', 'Urgent')) {
+        $casesList[$key]['case_status'] = sprintf('<strong>%s</strong>', strtoupper($casesList[$key]['case_status']));
+      }
+      $casesList[$key]['case_type'] = CRM_Utils_Array::value($case['case_type_id'], $caseTypeTitles);
       $casesList[$key]['case_role'] = CRM_Utils_Array::value('case_role', $case, '---');
       $casesList[$key]['manager'] = self::getCaseManagerContact($caseTypes[$case['case_type_id']], $case['case_id']);
 
-      $casesList[$key]['date'] = $case[$caseActivityTypeColumn];
-      if (($actId = CRM_Utils_Array::value('case_scheduled_activity_id', $case)) ||
-        ($actId = CRM_Utils_Array::value('case_recent_activity_id', $case))
-      ) {
+      $casesList[$key]['date'] = CRM_Utils_Array::value($case['activity_type_id'], $activityTypeLabels);
+      if ($actId = CRM_Utils_Array::value('activity_id', $case)) {
         if (self::checkPermission($actId, 'view', $case['activity_type_id'], $userID)) {
           if ($type == 'recent') {
             $casesList[$key]['date'] = sprintf('<a class="action-item crm-hover-button" href="%s" title="%s">%s</a>',
-              CRM_Utils_System::url('civicrm/case/activity/view', array('reset' => 1, 'cid' => $case['contact_id'], 'aid' => $case[$caseActivityIDColumn])),
+              CRM_Utils_System::url('civicrm/case/activity/view', array('reset' => 1, 'cid' => $case['contact_id'], 'aid' => $case['activity_id'])),
               ts('View activity'),
-              $case[$caseActivityTypeColumn]
+              CRM_Utils_Array::value($case['activity_type_id'], $activityTypeLabels)
             );
           }
           else {
-            $status = CRM_Utils_Date::overdue($case[$caseActivityDateColumn]) ? 'status-overdue' : 'status-scheduled';
+            $status = CRM_Utils_Date::overdue($case['activity_date_time']) ? 'status-overdue' : 'status-scheduled';
             $casesList[$key]['date'] = sprintf('<a class="crm-popup %s" href="%s" title="%s">%s</a> &nbsp;&nbsp;',
              $status,
-              CRM_Utils_System::url('civicrm/case/activity/view', array('reset' => 1, 'cid' => $case['contact_id'], 'aid' => $case[$caseActivityIDColumn])),
+              CRM_Utils_System::url('civicrm/case/activity/view', array('reset' => 1, 'cid' => $case['contact_id'], 'aid' => $case['activity_id'])),
               ts('View activity'),
-              $case[$caseActivityTypeColumn]
+              CRM_Utils_Array::value($case['activity_type_id'], $activityTypeLabels)
             );
           }
         }
@@ -735,7 +651,7 @@ LEFT JOIN civicrm_option_group aog ON aog.name='activity_type'
           );
         }
       }
-      $casesList[$key]['date'] .= "<br/>" . CRM_Utils_Date::customFormat($case[$caseActivityDateColumn]);
+      $casesList[$key]['date'] .= "<br/>" . CRM_Utils_Date::customFormat($case['activity_date_time']);
       $casesList[$key]['links'] = CRM_Core_Action::formLink($actions['primaryActions'], $mask,
         array(
           'id' => $case['case_id'],
@@ -1151,9 +1067,18 @@ SELECT case_status.label AS case_status, status_id, civicrm_case_type.title AS c
 
       // Activity Status Label for Case activities list
       $caseActivities[$caseActivityId]['status_id'] = CRM_Core_PseudoConstant::getLabel('CRM_Activity_BAO_Activity', 'activity_status_id', $dao->status);
+      $deleted = '';
+      if ($dao->deleted) {
+        $deleted = '<br /> ' . ts('(deleted)');
+      }
+      $caseActivities[$caseActivityId]['status_id'] = CRM_Core_PseudoConstant::getLabel('CRM_Activity_BAO_Activity', 'activity_status_id', $dao->status) . $deleted;
+      // if there are file attachments we will return how many
+      if (!empty($dao->attachment_ids)) {
+        $attachmentIDs = array_unique(explode(',', $dao->attachment_ids));
+        $caseActivity['no_attachments'] = count($attachmentIDs);
+      }
 
-      $caseActivities[$caseActivityId]
-        = self::addCaseActivityLinks($caseID, $contactID, $userID, $context, $dao, $caseActivities[$caseActivityId]);
+      $caseActivities[$caseActivityId]['links'] = self::addCaseActivityLinks($caseID, $contactID, $userID, $context, $dao);
     }
 
     $caseActivitiesDT = array();
@@ -1173,11 +1098,11 @@ SELECT case_status.label AS case_status, status_id, civicrm_case_type.title AS c
    * @param int $userID
    * @param string $context
    * @param \CRM_Core_DAO $dao
-   * @param array $caseActivity
    *
-   * @return array caseActivity
+   * @return string
+   *   HTML formatted Link
    */
-  public static function addCaseActivityLinks($caseID, $contactID, $userID, $context, $dao, $caseActivity) {
+  private static function addCaseActivityLinks($caseID, $contactID, $userID, $context, $dao) {
     // FIXME: Why are we not using CRM_Core_Action for these links? This is too much manual work and likely to get out-of-sync with core markup.
     $caseActivityId = $dao->id;
     $allowView = self::checkPermission($caseActivityId, 'view', $dao->activity_type_id, $userID);
@@ -1221,7 +1146,6 @@ SELECT case_status.label AS case_status, status_id, civicrm_case_type.title AS c
     }
     elseif (!$caseDeleted) {
       $url = ' <a ' . $css . ' href="' . $restoreUrl . $additionalUrl . '">' . ts('Restore') . '</a>';
-      $caseActivity['status_id'] = $caseActivity['status_id'] . '<br /> (deleted)';
     }
 
     //check for operations.
@@ -1233,12 +1157,10 @@ SELECT case_status.label AS case_status, status_id, civicrm_case_type.title AS c
     }
     // if there are file attachments we will return how many and, if only one, add a link to it
     if (!empty($dao->attachment_ids)) {
-      $attachmentIDs = array_unique(explode(',', $dao->attachment_ids));
-      $caseActivity['no_attachments'] = count($attachmentIDs);
       $url .= implode(' ', CRM_Core_BAO_File::paperIconAttachment('civicrm_activity', $caseActivityId));
     }
-    $caseActivity['links'] = $url;
-    return $caseActivity;
+
+    return $url;
   }
 
   /**
@@ -1621,18 +1543,19 @@ SELECT case_status.label AS case_status, status_id, civicrm_case_type.title AS c
  AND civicrm_case.is_deleted     = {$cases['case_deleted']}";
 
     $query = self::getCaseActivityQuery($type, $userID, $condition);
+    $activityTypes = CRM_Activity_BAO_Activity::buildOptions('activity_type_id');
 
     $res = CRM_Core_DAO::executeQuery($query);
 
     $activityInfo = array();
     while ($res->fetch()) {
       if ($type == 'upcoming') {
-        $activityInfo[$res->case_id]['date'] = $res->case_scheduled_activity_date;
-        $activityInfo[$res->case_id]['type'] = $res->case_scheduled_activity_type;
+        $activityInfo[$res->case_id]['date'] = $res->activity_date_time;
+        $activityInfo[$res->case_id]['type'] = CRM_Utils_Array::value($res->activity_type_id, $activityTypes);
       }
       else {
-        $activityInfo[$res->case_id]['date'] = $res->case_recent_activity_date;
-        $activityInfo[$res->case_id]['type'] = $res->case_recent_activity_type;
+        $activityInfo[$res->case_id]['date'] = $res->activity_date_time;
+        $activityInfo[$res->case_id]['type'] = CRM_Utils_Array::value($res->activity_type_id, $activityTypes);
       }
     }
 
@@ -2750,9 +2673,7 @@ WHERE id IN (' . implode(',', $copiedActivityIds) . ')';
       //allow edit operation.
       $allowEditNames = array('Open Case');
 
-      if (CRM_Core_Permission::check('edit inbound email basic information') ||
-        CRM_Core_Permission::check('edit inbound email basic information and content')
-      ) {
+      if (CRM_Activity_BAO_Activity::checkEditInboundEmailsPermissions()) {
         $allowEditNames[] = 'Inbound Email';
       }
 
@@ -3051,8 +2972,8 @@ WHERE id IN (' . implode(',', $copiedActivityIds) . ')';
  AS SELECT ca.case_id, a.id, a.activity_date_time, a.status_id, a.activity_type_id
  FROM civicrm_case_activity ca
  INNER JOIN civicrm_activity a ON ca.activity_id=a.id
- WHERE a.activity_date_time =
-(SELECT b.activity_date_time FROM civicrm_case_activity bca
+ WHERE a.id =
+(SELECT b.id FROM civicrm_case_activity bca
  INNER JOIN civicrm_activity b ON bca.activity_id=b.id
  WHERE b.activity_date_time <= DATE_ADD( NOW(), INTERVAL 14 DAY )
  AND b.is_current_revision = 1 AND b.is_deleted=0 AND b.status_id = $scheduled_id
@@ -3064,8 +2985,8 @@ WHERE id IN (' . implode(',', $copiedActivityIds) . ')';
  AS SELECT ca.case_id, a.id, a.activity_date_time, a.status_id, a.activity_type_id
  FROM civicrm_case_activity ca
  INNER JOIN civicrm_activity a ON ca.activity_id=a.id
- WHERE a.activity_date_time =
-(SELECT b.activity_date_time FROM civicrm_case_activity bca
+ WHERE a.id =
+(SELECT b.id FROM civicrm_case_activity bca
  INNER JOIN civicrm_activity b ON bca.activity_id=b.id
  WHERE b.activity_date_time >= DATE_SUB( NOW(), INTERVAL 14 DAY )
  AND b.is_current_revision = 1 AND b.is_deleted=0 AND b.status_id <> $scheduled_id
index 37f794492e22f487e50d0addeeb02dc26d16d522..ed571d76f3ad37edddc1965634af4174d056967b 100644 (file)
@@ -204,7 +204,6 @@ class CRM_Case_Form_Activity_OpenCase {
         'type' => 'upload',
         'name' => ts('Save and New'),
         'subName' => 'new',
-        'submitOnce' => TRUE,
       ],
       [
         'type' => 'cancel',
index 55c396e60ee1260aded7a33a1f24b1c853e79f57..8d63a8ea2923221bb55f0d399c4bdb65c2e1f959 100644 (file)
@@ -322,7 +322,7 @@ class CRM_Case_Selector_Search extends CRM_Core_Selector_Base {
       $isDeleted = FALSE;
       if ($result->case_deleted) {
         $isDeleted = TRUE;
-        $row['case_status_id'] = empty($row['case_status_id']) ? "" : $row['case_status_id'] . '<br />(deleted)';
+        $row['case_status_id'] = empty($row['case_status_id']) ? "" : $row['case_status_id'] . '<br />' . ts('(deleted)');
       }
 
       $scheduledInfo['case_id'][] = $result->case_id;
index e271d16cb1332e6dc4d7b7d60e7c2ba4cdba2f64..2fc3d2629d8f03c7d5496ed25d175809792629f5 100644 (file)
@@ -473,7 +473,7 @@ class CRM_Contact_BAO_Relationship extends CRM_Contact_DAO_Relationship {
    */
   public static function getdefaults() {
     return array(
-      'is_active' => 0,
+      'is_active' => 1,
       'is_permission_a_b' => self::NONE,
       'is_permission_b_a' => self::NONE,
       'description' => '',
index 1174320105e3e1798b5f70751ed592566194e78a..71b28d33673296d1aed5d0aaa48678217e1f78dc 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contact/Group.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:48373e283a62b36aa59ac812f8cb4134)
+ * (GenCodeChecksum:21b3e21494b0831994f860083cd82e24)
  */
 
 /**
@@ -236,6 +236,9 @@ class CRM_Contact_DAO_Group extends CRM_Core_DAO {
           'entity' => 'Group',
           'bao' => 'CRM_Contact_BAO_Group',
           'localizable' => 1,
+          'html' => [
+            'type' => 'Text',
+          ],
         ],
         'description' => [
           'name' => 'description',
index c33f4d5010e7d3534ffb4fc6a431ae4e937ecd0d..318138ff760792c1a1ebf924fbb73e4f6d8c1806 100644 (file)
@@ -113,22 +113,16 @@ class CRM_Contact_Form_DedupeRules extends CRM_Admin_Form {
     );
 
     $this->addField('used', ['label' => ts('Usage')], TRUE);
-    $disabled = [];
     $reserved = $this->addField('is_reserved', ['label' => ts('Reserved?')]);
     if (!empty($this->_defaults['is_reserved'])) {
       $reserved->freeze();
     }
 
     $attributes = ['class' => 'two'];
-    if (!empty($disabled)) {
-      $attributes = array_merge($attributes, $disabled);
-    }
 
     for ($count = 0; $count < self::RULES_COUNT; $count++) {
       $this->add('select', "where_$count", ts('Field'),
-        [
-          NULL => ts('- none -'),
-        ] + $this->_fields, FALSE, $disabled
+        $this->_fields, FALSE, ['class' => 'crm-select2', 'placeholder' => ts('Select Field')]
       );
       $this->addField("length_$count", ['entity' => 'Rule', 'name' => 'rule_length'] + $attributes);
       $this->addField("weight_$count", ['entity' => 'Rule', 'name' => 'rule_weight'] + $attributes);
index e8868722cb9edcf7dbda5a240abd9eda2afecaa7..28f61bbb1918a9316e2d00ff966cacc3502b809d 100644 (file)
@@ -151,7 +151,7 @@ class CRM_Contact_Form_Search_Custom_FullText extends CRM_Contact_Form_Search_Cu
   }
 
   public function buildTempTable() {
-    $table = CRM_Utils_SQL_TempTable::build()->setCategory('custom')->setMemory()->setUtf8();
+    $table = CRM_Utils_SQL_TempTable::build()->setCategory('custom')->setMemory();
     $this->_tableName = $table->getName();
 
     $this->_tableFields = [
@@ -216,7 +216,7 @@ class CRM_Contact_Form_Search_Custom_FullText extends CRM_Contact_Form_Search_Cu
 ";
     $table->createWithColumns($sql);
 
-    $entityIdTable = CRM_Utils_SQL_TempTable::build()->setCategory('custom')->setMemory()->setUtf8();
+    $entityIdTable = CRM_Utils_SQL_TempTable::build()->setCategory('custom')->setMemory();
     $this->_entityIDTableName = $entityIdTable->getName();
     $sql = "
   id int unsigned NOT NULL AUTO_INCREMENT,
index 8e1c3a3aa14543abacc470e6728522606ad855a2..397a8d50a99fecd3ed45a7bd6b4625fa4cfd5a05 100644 (file)
@@ -154,7 +154,7 @@ class CRM_Contact_Form_Task extends CRM_Core_Form_Task {
     $form->assign('taskName', CRM_Utils_Array::value($form->_task, $crmContactTaskTasks));
 
     if ($useTable) {
-      $tempTable = CRM_Utils_SQL_TempTable::build()->setCategory('tskact')->setDurable()->setId($qfKey)->setUtf8();
+      $tempTable = CRM_Utils_SQL_TempTable::build()->setCategory('tskact')->setDurable()->setId($qfKey);
       $form->_componentTable = $tempTable->getName();
       $tempTable->drop();
       $tempTable->createWithColumns('contact_id int primary key');
index f871162a3433de67a4fb493d2548cb61a9d1cf91..1b888a6b53f8586f133473b5c7a866f9c3c044e9 100644 (file)
@@ -67,7 +67,7 @@ class CRM_Contact_Form_Task_SaveSearch extends CRM_Contact_Form_Task {
     }
 
     // Get Task name
-    $modeValue = CRM_Contact_Form_Search::getModeValue($values['component_mode']);
+    $modeValue = CRM_Contact_Form_Search::getModeValue(CRM_Utils_Array::value('component_mode', $values, CRM_Contact_BAO_Query::MODE_CONTACTS));
     $className = $modeValue['taskClassName'];
     $taskList = $className::taskTitles();
     $this->_task = CRM_Utils_Array::value('task', $values);
index 1cec44c09e8d921bd0ee454a099645086a9d838f..fff23875c7a71c0f3089d5a335794ce2e6b45dae 100644 (file)
@@ -416,7 +416,7 @@ class CRM_Contact_Import_ImportJob {
     $result = CRM_Core_DAO::executeQuery($query, array($database));
     $incompleteImportTables = array();
     while ($importTable = $result->fetch()) {
-      if (!$this->isComplete($importTable)) {
+      if (!self::isComplete($importTable)) {
         $incompleteImportTables[] = $importTable;
       }
     }
index ddd5bcd073c597822ce21f6778f8245a3e3ebb6f..c9d41c2cb1b101abacf3b7e412d3b8030329c089 100644 (file)
@@ -1219,33 +1219,19 @@ abstract class CRM_Contact_Import_Parser extends CRM_Import_Parser {
 
       $fields[$block] = $this->getMetadataForEntity($block);
 
-      $blockCnt = count($params[$blockFieldName]);
-
       // copy value to dao field name.
       if ($blockFieldName == 'im') {
         $values['name'] = $values[$blockFieldName];
       }
 
       _civicrm_api3_store_values($fields[$block], $values,
-        $params[$blockFieldName][++$blockCnt]
+        $params[$blockFieldName][$values['location_type_id']]
       );
 
-      if ($values['location_type_id'] === 'Primary') {
-        if (!empty($params['id'])) {
-          $primary = civicrm_api3($block, 'get', [
-            'return' => 'location_type_id',
-            'contact_id' => $params['id'],
-            'is_primary' => 1,
-            'sequential' => 1
-          ]);
-        }
-        $defaultLocationType = CRM_Core_BAO_LocationType::getDefault();
-        $values['location_type_id'] = (isset($primary) && $primary['count']) ? $primary['values'][0]['location_type_id'] : $defaultLocationType->id;
-        $values['is_primary'] = 1;
-      }
+      $this->fillPrimary($params[$blockFieldName][$values['location_type_id']], $values, $block, CRM_Utils_Array::value('id', $params));
 
-      if (empty($params['id']) && ($blockCnt == 1)) {
-        $params[$blockFieldName][$blockCnt]['is_primary'] = TRUE;
+      if (empty($params['id']) && (count($params[$blockFieldName]) == 1)) {
+        $params[$blockFieldName][$values['location_type_id']]['is_primary'] = TRUE;
       }
 
       // we only process single block at a time.
@@ -1328,20 +1314,7 @@ abstract class CRM_Contact_Import_Parser extends CRM_Import_Parser {
       }
     }
 
-    if ($values['location_type_id'] === 'Primary') {
-      if (!empty($params['id'])) {
-        $primary = civicrm_api3('Address', 'get', [
-          'return' => 'location_type_id',
-          'contact_id' => $params['id'],
-          'is_primary' => 1,
-          'sequential' => 1
-        ]);
-      }
-      $defaultLocationType = CRM_Core_BAO_LocationType::getDefault();
-      $params['address'][$values['location_type_id']]['location_type_id'] = (isset($primary) && $primary['count']) ? $primary['values'][0]['location_type_id'] : $defaultLocationType->id;
-      $params['address'][$values['location_type_id']]['is_primary'] = 1;
-
-    }
+    $this->fillPrimary($params['address'][$values['location_type_id']], $values, 'address', CRM_Utils_Array::value('id', $params));
     return TRUE;
   }
 
@@ -1360,4 +1333,34 @@ abstract class CRM_Contact_Import_Parser extends CRM_Import_Parser {
     return $this->fieldMetadata[$entity];
   }
 
+  /**
+   * Fill in the primary location.
+   *
+   * If the contact has a primary address we update it. Otherwise
+   * we add an address of the default location type.
+   *
+   * @param array $params
+   *   Address block parameters
+   * @param array $values
+   *   Input values
+   * @param string $entity
+   *  - address, email, phone
+   * @param int|NULL $contactID
+   */
+  protected function fillPrimary(&$params, $values, $entity, $contactID) {
+    if ($values['location_type_id'] === 'Primary') {
+      if ($contactID) {
+        $primary = civicrm_api3($entity, 'get', [
+          'return' => 'location_type_id',
+          'contact_id' => $contactID,
+          'is_primary' => 1,
+          'sequential' => 1
+        ]);
+      }
+      $defaultLocationType = CRM_Core_BAO_LocationType::getDefault();
+      $params['location_type_id'] = (int) (isset($primary) && $primary['count']) ? $primary['values'][0]['location_type_id'] : $defaultLocationType->id;
+      $params['is_primary'] = 1;
+    }
+  }
+
 }
index 48e16a4dbf27fcec5c0434e1df457e5f5a2f5dff..d5f7a0b76e0c8a0b379ba2a67e308960bafeaa34 100644 (file)
@@ -897,18 +897,18 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
       $inputParams['id'] = $participantId;
       $values = [];
       $ids = [];
-      $component = 'event';
       $entityObj = CRM_Event_BAO_Participant::getValues($inputParams, $values, $ids);
       $entityObj = $entityObj[$participantId];
+      $title = CRM_Core_DAO::getFieldValue('CRM_Event_BAO_Event', $entityObj->event_id, 'title');
     }
     else {
       $entityObj = new CRM_Contribute_BAO_Contribution();
       $entityObj->id = $contributionId;
       $entityObj->find(TRUE);
-      $component = 'contribution';
+      $title = ts('Contribution');
     }
 
-    self::addActivityForPayment($entityObj, $financialTrxn, $activityType, $component, $contributionId);
+    self::addActivityForPayment($entityObj->contact_id, $financialTrxn, $activityType, $title, $contributionId);
   }
 
   /**
@@ -970,6 +970,92 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
     ])['values'];
   }
 
+  /**
+   * Cancel contribution.
+   *
+   * This function should only be called from transitioncomponents - it is an interim step in refactoring.
+   *
+   * @param $processContributionObject
+   * @param $memberships
+   * @param $contributionId
+   * @param $membershipStatuses
+   * @param $updateResult
+   * @param $participant
+   * @param $oldStatus
+   * @param $pledgePayment
+   * @param $pledgeID
+   * @param $pledgePaymentIDs
+   * @param $contributionStatusId
+   * @return array
+   */
+  protected static function cancel($processContributionObject, $memberships, $contributionId, $membershipStatuses, $updateResult, $participant, $oldStatus, $pledgePayment, $pledgeID, $pledgePaymentIDs, $contributionStatusId) {
+    $processContribution = FALSE;
+    $participantStatuses = CRM_Event_PseudoConstant::participantStatus();
+    if (is_array($memberships)) {
+      foreach ($memberships as $membership) {
+        $update = TRUE;
+        //Update Membership status if there is no other completed contribution associated with the membership.
+        $relatedContributions = CRM_Member_BAO_Membership::getMembershipContributionId($membership->id, TRUE);
+        foreach ($relatedContributions as $contriId) {
+          if ($contriId == $contributionId) {
+            continue;
+          }
+          $statusId = CRM_Core_DAO::getFieldValue('CRM_Contribute_BAO_Contribution', $contriId, 'contribution_status_id');
+          if (CRM_Core_PseudoConstant::getName('CRM_Contribute_BAO_Contribution', 'contribution_status_id', $statusId) === 'Completed') {
+            $update = FALSE;
+          }
+        }
+        if ($membership && $update) {
+          $newStatus = array_search('Cancelled', $membershipStatuses);
+
+          // Create activity
+          $allStatus = CRM_Member_BAO_Membership::buildOptions('status_id', 'get');
+          $activityParam = [
+            'subject' => "Status changed from {$allStatus[$membership->status_id]} to {$allStatus[$newStatus]}",
+            'source_contact_id' => CRM_Core_Session::singleton()->get('userID'),
+            'target_contact_id' => $membership->contact_id,
+            'source_record_id' => $membership->id,
+            'activity_type_id' => 'Change Membership Status',
+            'status_id' => 'Completed',
+            'priority_id' => 'Normal',
+            'activity_date_time' => 'now',
+          ];
+
+          $membership->status_id = $newStatus;
+          $membership->is_override = TRUE;
+          $membership->status_override_end_date = 'null';
+          $membership->save();
+          civicrm_api3('activity', 'create', $activityParam);
+
+          $updateResult['updatedComponents']['CiviMember'] = $membership->status_id;
+          if ($processContributionObject) {
+            $processContribution = TRUE;
+          }
+        }
+      }
+    }
+
+    if ($participant) {
+      $updatedStatusId = array_search('Cancelled', $participantStatuses);
+      CRM_Event_BAO_Participant::updateParticipantStatus($participant->id, $oldStatus, $updatedStatusId, TRUE);
+
+      $updateResult['updatedComponents']['CiviEvent'] = $updatedStatusId;
+      if ($processContributionObject) {
+        $processContribution = TRUE;
+      }
+    }
+
+    if ($pledgePayment) {
+      CRM_Pledge_BAO_PledgePayment::updatePledgePaymentStatus($pledgeID, $pledgePaymentIDs, $contributionStatusId);
+
+      $updateResult['updatedComponents']['CiviPledge'] = $contributionStatusId;
+      if ($processContributionObject) {
+        $processContribution = TRUE;
+      }
+    }
+    return [$updateResult, $processContribution];
+  }
+
   /**
    * @inheritDoc
    */
@@ -1757,9 +1843,9 @@ LEFT JOIN  civicrm_contribution contribution ON ( componentPayment.contribution_
     $participant = &$objects['participant'];
     $pledgePayment = &$objects['pledge_payment'];
     $contribution = &$objects['contribution'];
-
+    $pledgeID = $oldStatus = NULL;
+    $pledgePaymentIDs = [];
     if ($pledgePayment) {
-      $pledgePaymentIDs = array();
       foreach ($pledgePayment as $key => $object) {
         $pledgePaymentIDs[] = $object->id;
       }
@@ -1778,68 +1864,8 @@ LEFT JOIN  civicrm_contribution contribution ON ( componentPayment.contribution_
     // we might want to process contribution object.
     $processContribution = FALSE;
     if ($contributionStatusId == array_search('Cancelled', $contributionStatuses)) {
-      if (is_array($memberships)) {
-        foreach ($memberships as $membership) {
-          $update = TRUE;
-          //Update Membership status if there is no other completed contribution associated with the membership.
-          $relatedContributions = CRM_Member_BAO_Membership::getMembershipContributionId($membership->id, TRUE);
-          foreach ($relatedContributions as $contriId) {
-            if ($contriId == $contributionId) {
-              continue;
-            }
-            $statusId = CRM_Core_DAO::getFieldValue('CRM_Contribute_BAO_Contribution', $contriId, 'contribution_status_id');
-            if (CRM_Core_PseudoConstant::getName('CRM_Contribute_BAO_Contribution', 'contribution_status_id', $statusId) === 'Completed') {
-              $update = FALSE;
-            }
-          }
-          if ($membership && $update) {
-            $newStatus = array_search('Cancelled', $membershipStatuses);
-
-            // Create activity
-            $allStatus = CRM_Member_BAO_Membership::buildOptions('status_id', 'get');
-            $activityParam = array(
-              'subject' => "Status changed from {$allStatus[$membership->status_id]} to {$allStatus[$newStatus]}",
-              'source_contact_id' => CRM_Core_Session::singleton()->get('userID'),
-              'target_contact_id' => $membership->contact_id,
-              'source_record_id' => $membership->id,
-              'activity_type_id' => 'Change Membership Status',
-              'status_id' => 'Completed',
-              'priority_id' => 'Normal',
-              'activity_date_time' => 'now',
-            );
-
-            $membership->status_id = $newStatus;
-            $membership->is_override = TRUE;
-            $membership->status_override_end_date = 'null';
-            $membership->save();
-            civicrm_api3('activity', 'create', $activityParam);
-
-            $updateResult['updatedComponents']['CiviMember'] = $membership->status_id;
-            if ($processContributionObject) {
-              $processContribution = TRUE;
-            }
-          }
-        }
-      }
-
-      if ($participant) {
-        $updatedStatusId = array_search('Cancelled', $participantStatuses);
-        CRM_Event_BAO_Participant::updateParticipantStatus($participant->id, $oldStatus, $updatedStatusId, TRUE);
-
-        $updateResult['updatedComponents']['CiviEvent'] = $updatedStatusId;
-        if ($processContributionObject) {
-          $processContribution = TRUE;
-        }
-      }
-
-      if ($pledgePayment) {
-        CRM_Pledge_BAO_PledgePayment::updatePledgePaymentStatus($pledgeID, $pledgePaymentIDs, $contributionStatusId);
-
-        $updateResult['updatedComponents']['CiviPledge'] = $contributionStatusId;
-        if ($processContributionObject) {
-          $processContribution = TRUE;
-        }
-      }
+      // Call interim cancel function - with a goal to cleaning up the signature on it and switching to a tested api Contribution.cancel function.
+      list($updateResult, $processContribution) = self::cancel($processContributionObject, $memberships, $contributionId, $membershipStatuses, $updateResult, $participant, $oldStatus, $pledgePayment, $pledgeID, $pledgePaymentIDs, $contributionStatusId);
     }
     elseif ($contributionStatusId == array_search('Failed', $contributionStatuses)) {
       if (is_array($memberships)) {
@@ -3337,6 +3363,9 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
         'net_amount' => CRM_Utils_Array::value('net_amount', $params, $totalAmount),
         'currency' => $params['contribution']->currency,
         'trxn_id' => $params['contribution']->trxn_id,
+        // @todo - this is getting the status id from the contribution - that is BAD - ie the contribution could be partially
+        // paid but each payment is completed. The work around is to pass in the status_id in the trxn_params but
+        // this should really default to completed (after discussion).
         'status_id' => $statusId,
         'payment_instrument_id' => CRM_Utils_Array::value('payment_instrument_id', $params, $params['contribution']->payment_instrument_id),
         'check_number' => CRM_Utils_Array::value('check_number', $params),
@@ -3890,6 +3919,7 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
       $financialTrxn = CRM_Financial_BAO_Payment::recordPayment($contributionId, $trxnsData, $participantId);
     }
     elseif ($paymentType == 'refund') {
+      $trxnsData['total_amount'] = -$trxnsData['total_amount'];
       $financialTrxn = CRM_Financial_BAO_Payment::recordRefundPayment($contributionId, $trxnsData, $updateStatus);
       if ($participantId) {
         // update participant status
@@ -3912,25 +3942,18 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
   }
 
   /**
-   * @param $entityObj
+   * @param int $targetCid
    * @param $trxnObj
    * @param $activityType
-   * @param $component
+   * @param string $title
    * @param int $contributionId
    *
    * @throws CRM_Core_Exception
    */
-  public static function addActivityForPayment($entityObj, $trxnObj, $activityType, $component, $contributionId) {
-    if ($component == 'event') {
-      $title = CRM_Core_DAO::getFieldValue('CRM_Event_BAO_Event', $entityObj->event_id, 'title');
-    }
-    else {
-      $title = ts('Contribution');
-    }
+  public static function addActivityForPayment($targetCid, $trxnObj, $activityType, $title, $contributionId) {
     $paymentAmount = CRM_Utils_Money::format($trxnObj->total_amount, $trxnObj->currency);
     $subject = "{$paymentAmount} - Offline {$activityType} for {$title}";
     $date = CRM_Utils_Date::isoToMysql($trxnObj->trxn_date);
-    $targetCid = $entityObj->contact_id;
     // source record id would be the contribution id
     $srcRecId = $contributionId;
 
index 492afdb67c0bc163bd0ce227482b0fb182e0e437..fa6c55592e32e76087eafd1c25caa7497d46dea4 100644 (file)
@@ -672,33 +672,33 @@ class CRM_Contribute_BAO_ContributionPage extends CRM_Contribute_DAO_Contributio
         'title' => ts('Copy of') . ' ',
       ],
     ];
-    $copy = &CRM_Core_DAO::copyGeneric('CRM_Contribute_DAO_ContributionPage', [
+    $copy = CRM_Core_DAO::copyGeneric('CRM_Contribute_DAO_ContributionPage', [
       'id' => $id,
     ], NULL, $fieldsFix);
 
     //copying all the blocks pertaining to the contribution page
-    $copyPledgeBlock = &CRM_Core_DAO::copyGeneric('CRM_Pledge_DAO_PledgeBlock', [
+    $copyPledgeBlock = CRM_Core_DAO::copyGeneric('CRM_Pledge_DAO_PledgeBlock', [
       'entity_id' => $id,
       'entity_table' => 'civicrm_contribution_page',
     ], [
       'entity_id' => $copy->id,
     ]);
 
-    $copyMembershipBlock = &CRM_Core_DAO::copyGeneric('CRM_Member_DAO_MembershipBlock', [
+    $copyMembershipBlock = CRM_Core_DAO::copyGeneric('CRM_Member_DAO_MembershipBlock', [
       'entity_id' => $id,
       'entity_table' => 'civicrm_contribution_page',
     ], [
       'entity_id' => $copy->id,
     ]);
 
-    $copyUFJoin = &CRM_Core_DAO::copyGeneric('CRM_Core_DAO_UFJoin', [
+    $copyUFJoin = CRM_Core_DAO::copyGeneric('CRM_Core_DAO_UFJoin', [
       'entity_id' => $id,
       'entity_table' => 'civicrm_contribution_page',
     ], [
       'entity_id' => $copy->id,
     ]);
 
-    $copyWidget = &CRM_Core_DAO::copyGeneric('CRM_Contribute_DAO_Widget', [
+    $copyWidget = CRM_Core_DAO::copyGeneric('CRM_Contribute_DAO_Widget', [
       'contribution_page_id' => $id,
     ], [
       'contribution_page_id' => $copy->id,
@@ -707,14 +707,14 @@ class CRM_Contribute_BAO_ContributionPage extends CRM_Contribute_DAO_Contributio
     //copy price sets
     CRM_Price_BAO_PriceSet::copyPriceSet('civicrm_contribution_page', $id, $copy->id);
 
-    $copyTellFriend = &CRM_Core_DAO::copyGeneric('CRM_Friend_DAO_Friend', [
+    $copyTellFriend = CRM_Core_DAO::copyGeneric('CRM_Friend_DAO_Friend', [
       'entity_id' => $id,
       'entity_table' => 'civicrm_contribution_page',
     ], [
       'entity_id' => $copy->id,
     ]);
 
-    $copyPersonalCampaignPages = &CRM_Core_DAO::copyGeneric('CRM_PCP_DAO_PCPBlock', [
+    $copyPersonalCampaignPages = CRM_Core_DAO::copyGeneric('CRM_PCP_DAO_PCPBlock', [
       'entity_id' => $id,
       'entity_table' => 'civicrm_contribution_page',
     ], [
@@ -722,7 +722,7 @@ class CRM_Contribute_BAO_ContributionPage extends CRM_Contribute_DAO_Contributio
       'target_entity_id' => $copy->id,
     ]);
 
-    $copyPremium = &CRM_Core_DAO::copyGeneric('CRM_Contribute_DAO_Premium', [
+    $copyPremium = CRM_Core_DAO::copyGeneric('CRM_Contribute_DAO_Premium', [
       'entity_id' => $id,
       'entity_table' => 'civicrm_contribution_page',
     ], [
index 73a6cdc3e7a845e10fcf2266f718747a9fdb5997..a416a9573f2031f630ffaa4deec4b5f363d66a68 100644 (file)
@@ -263,7 +263,7 @@ class CRM_Contribute_BAO_ContributionRecur extends CRM_Contribute_DAO_Contributi
    * @return bool
    */
   public static function cancelRecurContribution($params) {
-    if (is_int($params)) {
+    if (is_numeric($params)) {
       CRM_Core_Error::deprecatedFunctionWarning('You are using a BAO function whose signature has changed. Please use the ContributionRecur.cancel api');
       $params = ['id' => $params];
     }
index c8b16b983f68aae9cd7220d9df1a65c15997379b..56e688cf067c6cac2879732619a69388a36e603b 100644 (file)
@@ -47,8 +47,12 @@ class CRM_Contribute_BAO_Query extends CRM_Core_BAO_Query {
    *   Associative array of contribution fields
    */
   public static function getFields($checkPermission = TRUE) {
-    if (!isset(\Civi::$statics[__CLASS__]) || !isset(\Civi::$statics[__CLASS__]['fields']) || !isset(\Civi::$statics[__CLASS__]['contribution'])) {
-      $fields = CRM_Contribute_BAO_Contribution::exportableFields($checkPermission);
+    if (!isset(\Civi::$statics[__CLASS__]) || !isset(\Civi::$statics[__CLASS__]['fields']) || !isset(\Civi::$statics[__CLASS__]['fields']['contribution'])) {
+      // Adding fields with some care as those without unique names could clobber others.
+      // Refer to CRM_Contribute_Form_SearchTest for existing tests ... and to add more!
+      $testedRecurFields = array_fill_keys(['contribution_recur_trxn_id', 'contribution_recur_processor_id', 'contribution_recur_payment_processor_id'], 1);
+      $recurFields = array_intersect_key(CRM_Contribute_DAO_ContributionRecur::fields(), $testedRecurFields);
+      $fields = array_merge($recurFields, CRM_Contribute_BAO_Contribution::exportableFields($checkPermission));
       CRM_Contribute_BAO_Contribution::appendPseudoConstantsToFields($fields);
       unset($fields['contribution_contact_id']);
       \Civi::$statics[__CLASS__]['fields']['contribution'] = $fields;
@@ -382,13 +386,12 @@ class CRM_Contribute_BAO_Query extends CRM_Core_BAO_Query {
 
       case 'contribution_recur_processor_id':
       case 'contribution_recur_trxn_id':
-        $fieldName = str_replace('contribution_recur_', '', $name);
-        $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("civicrm_contribution_recur.{$fieldName}",
+        $spec = $fields[$name];
+        $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause($spec['where'],
           $op, $value, "String"
         );
-        $recurFields = CRM_Contribute_DAO_ContributionRecur::fields();
-        $query->_qill[$grouping][] = ts("Recurring Contribution %1 %2 '%3'", [1 => $recurFields[$fieldName]['title'], 2 => $op, 3 => $value]);
-        $query->_tables['civicrm_contribution_recur'] = $query->_whereTables['civicrm_contribution_recur'] = 1;
+        $query->_qill[$grouping][] = ts("Recurring Contribution %1 %2 '%3'", [1 => $fields[$name]['title'], 2 => $op, 3 => $value]);
+        $query->_tables[$spec['table_name']] = $query->_whereTables[$spec['table_name']] = 1;
         return;
 
       case 'contribution_recur_payment_made':
index 9eedb5c3079750467909577d6861f2e20d0b5d38..525f08b968f5e2a4d53ef7f7424b84d78ca8f19e 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contribute/ContributionRecur.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:2ccc42487b9e4e5774fcfcde7db9c5ae)
+ * (GenCodeChecksum:9859d3b98d51f0f1df207253199186ab)
  */
 
 /**
@@ -262,7 +262,7 @@ class CRM_Contribute_DAO_ContributionRecur extends CRM_Core_DAO {
   public static function &fields() {
     if (!isset(Civi::$statics[__CLASS__]['fields'])) {
       Civi::$statics[__CLASS__]['fields'] = [
-        'id' => [
+        'contribution_recur_id' => [
           'name' => 'id',
           'type' => CRM_Utils_Type::T_INT,
           'title' => ts('Recurring Contribution ID'),
@@ -474,7 +474,7 @@ class CRM_Contribute_DAO_ContributionRecur extends CRM_Core_DAO {
             'formatType' => 'activityDate',
           ],
         ],
-        'processor_id' => [
+        'contribution_recur_processor_id' => [
           'name' => 'processor_id',
           'type' => CRM_Utils_Type::T_STRING,
           'title' => ts('Processor ID'),
@@ -502,7 +502,7 @@ class CRM_Contribute_DAO_ContributionRecur extends CRM_Core_DAO {
           'localizable' => 0,
           'FKClassName' => 'CRM_Financial_DAO_PaymentToken',
         ],
-        'trxn_id' => [
+        'contribution_recur_trxn_id' => [
           'name' => 'trxn_id',
           'type' => CRM_Utils_Type::T_STRING,
           'title' => ts('Transaction ID'),
@@ -534,7 +534,7 @@ class CRM_Contribute_DAO_ContributionRecur extends CRM_Core_DAO {
             'type' => 'Text',
           ],
         ],
-        'contribution_status_id' => [
+        'contribution_recur_contribution_status_id' => [
           'name' => 'contribution_status_id',
           'type' => CRM_Utils_Type::T_INT,
           'title' => ts('Status'),
@@ -647,7 +647,7 @@ class CRM_Contribute_DAO_ContributionRecur extends CRM_Core_DAO {
             'type' => 'CheckBox',
           ],
         ],
-        'payment_processor_id' => [
+        'contribution_recur_payment_processor_id' => [
           'name' => 'payment_processor_id',
           'type' => CRM_Utils_Type::T_INT,
           'title' => ts('Payment Processor'),
index 6d3416ff788cc20a2295957d1dda08cb37b1596f..24ad75822273808065cae65e4001a053d9d3aea3 100644 (file)
@@ -36,6 +36,8 @@
  */
 class CRM_Contribute_Form_ContributionRecur extends CRM_Core_Form {
 
+  use CRM_Core_Form_EntityFormTrait;
+
   /**
    * @var int Contribution ID
    */
@@ -76,6 +78,21 @@ class CRM_Contribute_Form_ContributionRecur extends CRM_Core_Form {
    */
   public $_paymentProcessor = [];
 
+  /**
+   * Fields for the entity to be assigned to the template.
+   *
+   * Fields may have keys
+   *  - name (required to show in tpl from the array)
+   *  - description (optional, will appear below the field)
+   *  - not-auto-addable - this class will not attempt to add the field using addField.
+   *    (this will be automatically set if the field does not have html in it's metadata
+   *    or is not a core field on the form's entity).
+   *  - help (option) add help to the field - e.g ['id' => 'id-source', 'file' => 'CRM/Contact/Form/Contact']]
+   *  - template - use a field specific template to render this field
+   * @var array
+   */
+  protected $entityFields = [];
+
   /**
    * Explicitly declare the entity api name.
    */
@@ -94,6 +111,7 @@ class CRM_Contribute_Form_ContributionRecur extends CRM_Core_Form {
    * Set variables up before form is built.
    */
   public function preProcess() {
+    $this->setAction(CRM_Core_Action::UPDATE);
     $this->_mid = CRM_Utils_Request::retrieve('mid', 'Integer', $this, FALSE);
     $this->_crid = CRM_Utils_Request::retrieve('crid', 'Integer', $this, FALSE);
     $this->contributionRecurID = $this->_crid;
index 638976ea32831afba220f0b4e638c8bead94f141..f93583590f0fc5511fc88b3823b306afd2b44105 100644 (file)
@@ -298,6 +298,65 @@ class CRM_Core_Action {
     return $result;
   }
 
+  /**
+   * Given a set of links and a mask, return a filtered (by mask) array containing the final links with parsed values
+   *   and calling hooks as appropriate.
+   * Use this when passing a set of action links to the API or to the form without adding html formatting.
+   *
+   * @param array $links
+   *   The set of link items.
+   * @param int $mask
+   *   The mask to be used. a null mask means all items.
+   * @param array $values
+   *   The array of values for parameter substitution in the link items.
+   * @param null $op
+   * @param null $objectName
+   * @param int $objectId
+   *
+   * @return array|null
+   *   The array describing each link
+   */
+  public static function filterLinks(
+    $links,
+    $mask,
+    $values,
+    $op = NULL,
+    $objectName = NULL,
+    $objectId = NULL
+  ) {
+    if (empty($links)) {
+      return NULL;
+    }
+
+    // make links indexed sequentially instead of by bitmask
+    // otherwise it's next to impossible to reliably add new ones
+    $seqLinks = array();
+    foreach ($links as $bit => $link) {
+      $link['bit'] = $bit;
+      $seqLinks[] = $link;
+    }
+
+    if ($op && $objectName && $objectId) {
+      CRM_Utils_Hook::links($op, $objectName, $objectId, $seqLinks, $mask, $values);
+    }
+
+    foreach ($seqLinks as $i => $link) {
+      if (!$mask || !array_key_exists('bit', $link) || ($mask & $link['bit'])) {
+        $seqLinks[$i]['extra'] = isset($link['extra']) ? self::replace($link['extra'], $values) : NULL;
+
+        if (isset($link['qs']) && !CRM_Utils_System::isNull($link['qs'])) {
+          $seqLinks[$i]['url'] = self::replace($link['url'], $values);
+          $seqLinks[$i]['qs'] = self::replace($link['qs'], $values);
+        }
+      }
+      else {
+        unset($seqLinks[$i]);
+      }
+    }
+
+    return $seqLinks;
+  }
+
   /**
    * Given a string and an array of values, substitute the real values
    * in the placeholder in the str in the CiviCRM format
index b5ec97d74863f4ae97c01a1364d571eddc120270..3ce2b0cdbb2bd3fb783a44241d4e601cb4b78627 100644 (file)
@@ -1063,7 +1063,6 @@ SELECT is_primary,
       $addressDAO->copyValues($params);
       $addressDAO->id = $dao->id;
       $addressDAO->save();
-      $addressDAO->free();
     }
   }
 
index a9ffa34e2f4461182c95675d6de1e5b2f9f67675..d37b01d94e5d24e40af664835c94a122a3b7fd66 100644 (file)
@@ -277,7 +277,6 @@ class CRM_Core_BAO_Block {
             $block->is_primary = FALSE;
             $block->save();
           }
-          $block->free();
         }
       }
     }
index 6dd3d5b208c345ae3cc4fba20c2228a32354aaa0..19f1ce3bf50789d406807e0ee5ee85bfce13f2de 100644 (file)
@@ -2038,7 +2038,6 @@ AND    cf.id = %1";
       if (!$dao->fetch()) {
         CRM_Core_Error::fatal();
       }
-      $dao->free();
       $fieldValues = array($dao->table_name, $dao->column_name, $dao->id);
       $cache->set($cacheKey, $fieldValues);
     }
index 9fa273922bbb6d0e3027af413435b48c1c7bacfd..0eb77b2cfff97317443cae486ef77a05cdf61336 100644 (file)
@@ -348,10 +348,8 @@ SET    {$dao->columnName} = REPLACE( {$dao->columnName}, %1, %2 )";
         ];
       }
       $sql = "UPDATE `{$customGroup->table_name}` SET `{$customField->column_name}` = REPLACE(`{$customField->column_name}`, %1, %2) WHERE `{$customField->column_name}` LIKE %3";
-      $customGroup->free();
       CRM_Core_DAO::executeQuery($sql, $params);
     }
-    $customField->free();
   }
 
 }
index 9740318b97f10cdc1066bc6feaef27289c505817..759e83a71954d764bceecafa0e8195dd8a95b45d 100644 (file)
@@ -176,7 +176,6 @@ class CRM_Core_BAO_CustomValueTable {
               $entityFileDAO->entity_id = $field['entity_id'];
               $entityFileDAO->file_id = $field['file_id'];
               $entityFileDAO->save();
-              $entityFileDAO->free();
               $value = $field['file_id'];
               $type = 'String';
               break;
index c9a1265d671ed7dec42d0752e4e6e171cd2a8549..c2c06bd279fbc166fe15af0537e3f7c2afe6d840 100644 (file)
@@ -210,7 +210,7 @@ class CRM_Core_BAO_File extends CRM_Core_DAO_File {
     $fileDAO = new CRM_Core_DAO_File();
     $fileDAO->id = $fileID;
     if (!$fileDAO->find(TRUE)) {
-      CRM_Core_Error::fatal();
+      throw new CRM_Core_Exception(ts('File not found'));
     }
 
     // lets call a pre hook before the delete, so attachments hooks can get the info before things
@@ -226,7 +226,7 @@ class CRM_Core_BAO_File extends CRM_Core_DAO_File {
     $entityFileDAO->entity_table = $tableName;
 
     if (!$entityFileDAO->find(TRUE)) {
-      CRM_Core_Error::fatal(sprintf('No record found for given file ID - %d and entity ID - %d', $fileID, $entityID));
+      throw new CRM_Core_Exception(sprintf('No record found for given file ID - %d and entity ID - %d', $fileID, $entityID));
     }
 
     $entityFileDAO->delete();
index 0509a0af47b60aaeb5182445c65831af7c3b3850..867a0433754a84742218e980137447d5c3cb7f8a 100644 (file)
@@ -159,7 +159,7 @@ class CRM_Core_BAO_Job extends CRM_Core_DAO_Job {
       ],
       'replace' => $params,
     ];
-    $copy = &CRM_Core_DAO::copyGeneric('CRM_Core_DAO_Job', ['id' => $id], NULL, $fieldsFix);
+    $copy = CRM_Core_DAO::copyGeneric('CRM_Core_DAO_Job', ['id' => $id], NULL, $fieldsFix);
     $copy->save();
     CRM_Utils_Hook::copy('Job', $copy);
 
index 72899e00757a09d6550c721cd61084d85859aaaf..b0c68d1b8a932b2f1b9124cb1657af612ae8eae2 100644 (file)
@@ -211,7 +211,6 @@ WHERE e.id = %1";
         $dao->id = $id;
         $dao->find(TRUE);
         $dao->delete();
-        $dao->free();
       }
     }
   }
@@ -314,6 +313,7 @@ WHERE e.id = %1";
    *   newly created/updated location block id.
    */
   public static function copyLocBlock($locBlockId, $updateLocBlockId = NULL) {
+    CRM_Core_Error::deprecatedFunctionWarning('unused function which will be removed');
     //get the location info.
     $defaults = $updateValues = [];
     $locBlock = ['id' => $locBlockId];
@@ -345,7 +345,7 @@ WHERE e.id = %1";
       }
     }
 
-    $copyLocation = &CRM_Core_DAO::copyGeneric('CRM_Core_DAO_LocBlock',
+    $copyLocation = CRM_Core_DAO::copyGeneric('CRM_Core_DAO_LocBlock',
       ['id' => $locBlock['id']],
       $copyLocationParams
     );
index d30ae5bfaad89cf8e3fe74518f07b21b2289249c..dabc8123bc2606994f98d045d512dabed5eaeefc 100644 (file)
@@ -315,12 +315,10 @@ class CRM_Core_BAO_Note extends CRM_Core_DAO_Note {
       $childNote = new CRM_Core_DAO_Note();
       $childNote->id = $childId;
       $childNote->delete();
-      $childNote->free();
       $recent[] = $childId;
     }
 
     $return = $note->delete();
-    $note->free();
     if ($showStatus) {
       CRM_Core_Session::setStatus($status, ts('Deleted'), 'success');
     }
index a681756418c02361e4d8d56d445227fdc35bda9d..072f8cd5c051acd51faed80b05b82698ec2e4eb7 100644 (file)
@@ -480,7 +480,6 @@ class CRM_Core_BAO_OptionValue extends CRM_Core_DAO_OptionValue {
         $optionValue->weight = $opWeight;
         $optionValue->save();
       }
-      $optionValue->free();
     }
   }
 
index ef8336593152ea2e98e766f5baae152bc981725f..9007864c1c53765de4c4bd14015cf2f6690e5045 100644 (file)
@@ -185,7 +185,6 @@ class CRM_Core_BAO_Tag extends CRM_Core_DAO_Tag {
           $tags[$tag->id]['color'] = !empty($tag->color) ? $tag->color : NULL;
         }
       }
-      $tag->free();
     }
 
     return $tags;
@@ -270,7 +269,6 @@ class CRM_Core_BAO_Tag extends CRM_Core_DAO_Tag {
       }
     }
 
-    $dao->free();
     // While we have nodes left to build, shift the first (alphabetically)
     // node of the list, place it in our tags list and loop through the
     // list of unplaced nodes to find its children. We make a copy to
@@ -514,7 +512,6 @@ class CRM_Core_BAO_Tag extends CRM_Core_DAO_Tag {
     while ($dao->fetch()) {
       $tagSets[$dao->id] = $dao->name;
     }
-    $dao->free();
     return $tagSets;
   }
 
index 5d7f256eb0a4788713c6f61bdeb30a8579d81485..3adba27015c53d0b4b0268721538da21f6fbc0ef 100644 (file)
@@ -2692,7 +2692,7 @@ AND    ( entity_id IS NULL OR entity_id <= 0 )
       ),
     );
 
-    $copy = &CRM_Core_DAO::copyGeneric('CRM_Core_DAO_UFGroup',
+    $copy = CRM_Core_DAO::copyGeneric('CRM_Core_DAO_UFGroup',
       array('id' => $id),
       NULL,
       $fieldsFix
@@ -2704,14 +2704,14 @@ AND    ( entity_id IS NULL OR entity_id <= 0 )
     $copy->name = CRM_Utils_String::munge($copy->name, '_', 56) . "_{$copy->id}";
     $copy->save();
 
-    $copyUFJoin = &CRM_Core_DAO::copyGeneric('CRM_Core_DAO_UFJoin',
+    $copyUFJoin = CRM_Core_DAO::copyGeneric('CRM_Core_DAO_UFJoin',
       array('uf_group_id' => $id),
       array('uf_group_id' => $copy->id),
       NULL,
       'entity_table'
     );
 
-    $copyUFField = &CRM_Core_DAO::copyGeneric('CRM_Core_BAO_UFField',
+    $copyUFField = CRM_Core_DAO::copyGeneric('CRM_Core_BAO_UFField',
       array('uf_group_id' => $id),
       array('uf_group_id' => $copy->id)
     );
index 027dba4a89fd3b0b262541ac9b4ca2980ddc6f5b..09295bf02828f39d5ace0c4490a80144b38212f6 100644 (file)
@@ -936,7 +936,7 @@ class CRM_Core_DAO extends DB_DataObject {
 
     if (!array_key_exists($tableName, $show)) {
       $query = "SHOW CREATE TABLE $tableName";
-      $dao = CRM_Core_DAO::executeQuery($query);
+      $dao = CRM_Core_DAO::executeQuery($query, [], TRUE, NULL, FALSE, FALSE);
 
       if (!$dao->fetch()) {
         CRM_Core_Error::fatal();
@@ -963,7 +963,7 @@ class CRM_Core_DAO extends DB_DataObject {
     foreach ($tables as $tableName) {
       if (!array_key_exists($tableName, $show)) {
         $query = "SHOW CREATE TABLE $tableName";
-        $dao = CRM_Core_DAO::executeQuery($query);
+        $dao = CRM_Core_DAO::executeQuery($query, [], TRUE, NULL, FALSE, FALSE);
 
         if (!$dao->fetch()) {
           CRM_Core_Error::fatal();
@@ -1600,11 +1600,12 @@ FROM   civicrm_domain
    *   Fields that you want to block from.
    *   getting copied
    *
-   * @return CRM_Core_DAO
-   *   the newly created copy of the object
+   * @return CRM_Core_DAO|bool
+   *   the newly created copy of the object. False if none created.
    */
-  public static function &copyGeneric($daoName, $criteria, $newData = NULL, $fieldsFix = NULL, $blockCopyOfDependencies = NULL) {
+  public static function copyGeneric($daoName, $criteria, $newData = NULL, $fieldsFix = NULL, $blockCopyOfDependencies = NULL) {
     $object = new $daoName();
+    $newObject = FALSE;
     if (!$newData) {
       $object->id = $criteria['id'];
     }
@@ -1670,15 +1671,71 @@ FROM   civicrm_domain
         }
       }
       $newObject->save();
-      if (!empty($newData['custom'])) {
-        CRM_Core_BAO_CustomValueTable::store($newData['custom'], $newObject::getTableName(), $newObject->id);
-      }
+      $newObject->copyCustomFields($object->id, $newObject->id);
       CRM_Utils_Hook::post('create', CRM_Core_DAO_AllCoreTables::getBriefName($daoName), $newObject->id, $newObject);
     }
 
     return $newObject;
   }
 
+  /**
+   * Method that copies custom fields values from an old entity to a new one.
+   *
+   * Fixes bug CRM-19302,
+   * where if a custom field of File type was present, left both events using the same file,
+   * breaking download URL's for the old event.
+   *
+   * @todo the goal here is to clean this up so that it works for any entity. Copy Generic already DOES some custom field stuff
+   * but it seems to be bypassed & perhaps less good than this (or this just duplicates it...)
+   *
+   * @param int $entityID
+   * @param int $newEntityID
+   */
+  public function copyCustomFields($entityID, $newEntityID) {
+    $entity = CRM_Core_DAO_AllCoreTables::getBriefName(get_class($this));
+    $tableName = CRM_Core_DAO_AllCoreTables::getTableForClass(get_class($this));
+    // Obtain custom values for old event
+    $customParams = $htmlType = [];
+    $customValues = CRM_Core_BAO_CustomValueTable::getEntityValues($entityID, $entity);
+
+    // If custom values present, we copy them
+    if (!empty($customValues)) {
+      // Get Field ID's and identify File type attributes, to handle file copying.
+      $fieldIds = implode(', ', array_keys($customValues));
+      $sql = "SELECT id FROM civicrm_custom_field WHERE html_type = 'File' AND id IN ( {$fieldIds} )";
+      $result = CRM_Core_DAO::executeQuery($sql);
+
+      // Build array of File type fields
+      while ($result->fetch()) {
+        $htmlType[] = $result->id;
+      }
+
+      // Build params array of custom values
+      foreach ($customValues as $field => $value) {
+        if ($value !== NULL) {
+          // Handle File type attributes
+          if (in_array($field, $htmlType)) {
+            $fileValues = CRM_Core_BAO_File::path($value, $entityID);
+            $customParams["custom_{$field}_-1"] = [
+              'name' => CRM_Utils_File::duplicate($fileValues[0]),
+              'type' => $fileValues[1],
+            ];
+          }
+          // Handle other types
+          else {
+            $customParams["custom_{$field}_-1"] = $value;
+          }
+        }
+      }
+
+      // Save Custom Fields for new Event
+      CRM_Core_BAO_CustomValueTable::postProcess($customParams, $tableName, $newEntityID, $entity);
+    }
+
+    // copy activity attachments ( if any )
+    CRM_Core_BAO_File::copyEntityFile($tableName, $entityID, $tableName, $newEntityID);
+  }
+
   /**
    * Cascade update through related entities.
    *
index 52ee98d4dc47be9393627998cf81b595b6d5acf7..16ac8caf4dd8f7b518a6026b4ad7e9cd868ecdf1 100644 (file)
@@ -617,7 +617,7 @@ class CRM_Core_Error extends PEAR_ErrorStack {
     if (!empty(\Civi::$statics[__CLASS__]['userFrameworkLogging'])) {
       // should call $config->userSystem->logger($message) here - but I got a situation where userSystem was not an object - not sure why
       if ($config->userSystem->is_drupal and function_exists('watchdog')) {
-        watchdog('civicrm', '%message', ['%message' => $message], WATCHDOG_DEBUG);
+        watchdog('civicrm', '%message', ['%message' => $message], isset($priority) ? $priority : WATCHDOG_DEBUG);
       }
     }
 
index b396667fe7f4306d153fa680da40dc5e47eacf8c..8d0c6b20d6477347c501a1d11c1ea60c65f4f44f 100644 (file)
@@ -1314,7 +1314,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
       $label,
       $options,
       $required,
-      NULL
+      ['class' => 'crm-select2']
     );
     $attributes = ['format' => 'searchDate'];
     $extra = ['time' => $isDateTime];
index 38f2548208f0268ee380624dd24b9e13b9f3d5c1..00a5c5b6e0922e7143081f1163669e29914d59aa 100644 (file)
@@ -64,6 +64,20 @@ trait CRM_Core_Form_EntityFormTrait {
     return $this->deleteMessage;
   }
 
+  /**
+   * Set the delete message.
+   *
+   * We do this from the constructor in order to do a translation.
+   */
+  public function setDeleteMessage() {
+  }
+
+  /**
+   * Set entity fields to be assigned to the form.
+   */
+  protected function setEntityFields() {
+  }
+
   /**
    * Get the entity id being edited.
    *
index f7a5067668b064d83673c2ebf195e6772fe14485..1e5f6462231da332699ab5891c477643bbcf96e8 100644 (file)
@@ -1190,7 +1190,7 @@ abstract class CRM_Core_Payment {
 
   /**
    * Calling this from outside the payment subsystem is deprecated - use doPayment.
-   *
+   * @deprecated
    * Does a server to server payment transaction.
    *
    * @param array $params
@@ -1205,33 +1205,25 @@ abstract class CRM_Core_Payment {
 
   /**
    * Process payment - this function wraps around both doTransferCheckout and doDirectPayment.
+   * Any processor that still implements the deprecated doTransferCheckout() or doDirectPayment() should be updated to use doPayment().
    *
-   * The function ensures an exception is thrown & moves some of this logic out of the form layer and makes the forms
-   * more agnostic.
-   *
-   * Payment processors should set payment_status_id. This function adds some historical defaults ie. the
-   * assumption that if a 'doDirectPayment' processors comes back it completed the transaction & in fact
-   * doTransferCheckout would not traditionally come back.
-   *
-   * doDirectPayment does not do an immediate payment for Authorize.net or Paypal so the default is assumed
-   * to be Pending.
+   * This function adds some historical defaults ie. the assumption that if a 'doDirectPayment' processors comes back it completed
+   *   the transaction & in fact doTransferCheckout would not traditionally come back.
+   * Payment processors should throw exceptions and not return Error objects as they may have done with the old functions.
    *
-   * Once this function is fully rolled out then it will be preferred for processors to throw exceptions than to
-   * return Error objects
+   * Payment processors should set payment_status_id (which is really contribution_status_id) in the returned array. The default is assumed to be Pending.
+   *   In some cases the IPN will set the payment to "Completed" some time later.
    *
-   * Usage:
-   * Payment processors should override this function directly instead of using doDirectPayment/doTransferCheckout which are deprecated.
-   * Payment processors should set and return payment_status_id (Pending if the IPN will complete it, Completed if successful).
-   * @fixme For the contribution workflow we have a contributionID, but for the event and membership workflow the contribution has not yet been created
-   *  so we can't update params directly on the contribution.  However if you return trxn_id, fee_amount, net_amount they will be set on the contribution
-   *  by those workflows.  Ideally all workflows would create a pending contribution BEFORE calling doPayment (eg. https://github.com/civicrm/civicrm-core/pull/13763 for events)
+   * @fixme Creating a contribution record is inconsistent! We should always create a contribution BEFORE calling doPayment...
+   *  For the current status see: https://lab.civicrm.org/dev/financial/issues/53
+   * If we DO have a contribution ID, then the payment processor can (and should) update parameters on the contribution record as necessary.
    *
    * @param array $params
    *
    * @param string $component
    *
    * @return array
-   *   Result array
+   *   Result array (containing at least the key payment_status_id)
    *
    * @throws \Civi\Payment\Exception\PaymentProcessorException
    */
index 0af4bd1e105fa78cb1e19915f544dcdc8468fa14..28984e107d1c2d7571f2c3e47701901e8178e760 100644 (file)
@@ -220,14 +220,12 @@ class CRM_Core_PseudoConstant {
       if ($options && $flip) {
         $options = array_flip($options);
       }
-      $customField->free();
       return $options;
     }
 
     // Core field: load schema
     $dao = new $daoName();
     $fieldSpec = $dao->getFieldSpec($fieldName);
-    $dao->free();
 
     // Ensure we have the canonical name for this field
     $fieldName = CRM_Utils_Array::value('name', $fieldSpec, $fieldName);
@@ -313,7 +311,6 @@ class CRM_Core_PseudoConstant {
           // Get list of fields for the option table
           $dao = new $daoName();
           $availableFields = array_keys($dao->fieldKeys());
-          $dao->free();
 
           $select = "SELECT %1 AS id, %2 AS label";
           $from = "FROM %3";
@@ -375,7 +372,6 @@ class CRM_Core_PseudoConstant {
           while ($dao->fetch()) {
             $output[$dao->id] = $dao->label;
           }
-          $dao->free();
           // Localize results
           if (!empty($params['localize']) || $pseudoconstant['table'] == 'civicrm_country' || $pseudoconstant['table'] == 'civicrm_state_province') {
             $I18nParams = [];
index 3c88fedb387f36e91bdcc24fcd8b77f4cfb5bc43..69f9e46150897be1f34182783e58665513c253d9 100644 (file)
@@ -767,6 +767,9 @@ class CRM_Core_Resources {
       $items[] = 'js/crm.menubar.js';
       $items[] = Civi::service('asset_builder')->getUrl('crm-menubar.css', [
         'color' => Civi::settings()->get('menubar_color'),
+        'height' => 40,
+        'breakpoint' => 768,
+        'opacity' => .88,
       ]);
       $items[] = [
         'menubar' => [
@@ -852,8 +855,11 @@ class CRM_Core_Resources {
     }
     $vars = [
       'resourceBase' => rtrim($config->resourceBase, '/'),
+      'menubarHeight' => $e->params['height'] . 'px',
+      'breakMin' => $e->params['breakpoint'] . 'px',
+      'breakMax' => ($e->params['breakpoint'] - 1) . 'px',
       'menubarColor' => $color,
-      'semiTransparentMenuColor' => 'rgba(' . implode(', ', CRM_Utils_Color::getRgb($color)) . ', .85)',
+      'menuItemColor' => 'rgba(' . implode(', ', CRM_Utils_Color::getRgb($color)) . ", {$e->params['opacity']})",
       'highlightColor' => CRM_Utils_Color::getHighlight($color),
       'textColor' => CRM_Utils_Color::getContrast($color, '#333', '#ddd'),
     ];
index 869454b0ca23b997f1fa0d538fbff87713fb74c5..6703e57a7cda0e1c7a73a94f5cce7343c2a497ac 100644 (file)
@@ -924,92 +924,13 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
    *   -  Does a force merge otherwise (aggressive mode).
    *
    * @param array $conflicts
+   *  An empty array to be filed with conflict information.
    *
    * @return bool
    */
   public static function skipMerge($mainId, $otherId, &$migrationInfo, $mode = 'safe', &$conflicts = []) {
 
-    $originalMigrationInfo = $migrationInfo;
-    foreach ($migrationInfo as $key => $val) {
-      if ($val === "null") {
-        // Rule: Never overwrite with an empty value (in any mode)
-        unset($migrationInfo[$key]);
-        continue;
-      }
-      elseif ((in_array(substr($key, 5), CRM_Dedupe_Merger::getContactFields()) or
-          substr($key, 0, 12) == 'move_custom_'
-        ) and $val != NULL
-      ) {
-        // Rule: If both main-contact, and other-contact have a field with a
-        // different value, then let $mode decide if to merge it or not
-        if (
-          (!empty($migrationInfo['rows'][$key]['main'])
-            // For custom fields a 0 (e.g in an int field) could be a true conflict. This
-            // is probably true for other fields too - e.g. 'do_not_email' but
-            // leaving that investigation as a @todo - until tests can be written.
-            // Note the handling of this has test coverage - although the data-typing
-            // of '0' feels flakey we have insurance.
-            || ($migrationInfo['rows'][$key]['main'] === '0' && substr($key, 0, 12) == 'move_custom_')
-          )
-          && $migrationInfo['rows'][$key]['main'] != $migrationInfo['rows'][$key]['other']
-        ) {
-
-          // note it down & lets wait for response from the hook.
-          // For no response $mode will decide if to skip this merge
-          $conflicts[$key] = NULL;
-        }
-      }
-      elseif (substr($key, 0, 14) == 'move_location_' and $val != NULL) {
-        $locField = explode('_', $key);
-        $fieldName = $locField[2];
-        $fieldCount = $locField[3];
-
-        // Rule: Catch address conflicts (same address type on both contacts)
-        if (
-          isset($migrationInfo['main_details']['location_blocks'][$fieldName]) &&
-          !empty($migrationInfo['main_details']['location_blocks'][$fieldName])
-        ) {
-
-          // Load the address we're inspecting from the 'other' contact
-          $addressRecord = $migrationInfo['other_details']['location_blocks'][$fieldName][$fieldCount];
-          $addressRecordLocTypeId = CRM_Utils_Array::value('location_type_id', $addressRecord);
-
-          // If it exists on the 'main' contact already, skip it. Otherwise
-          // if the location type exists already, log a conflict.
-          foreach ($migrationInfo['main_details']['location_blocks'][$fieldName] as $mainAddressKey => $mainAddressRecord) {
-            if (self::locationIsSame($addressRecord, $mainAddressRecord)) {
-              unset($migrationInfo[$key]);
-              break;
-            }
-            elseif ($addressRecordLocTypeId == $mainAddressRecord['location_type_id']) {
-              $conflicts[$key] = NULL;
-              break;
-            }
-          }
-        }
-
-        // For other locations, don't merge/add if the values are the same
-        elseif (CRM_Utils_Array::value('main', $migrationInfo['rows'][$key]) == $migrationInfo['rows'][$key]['other']) {
-          unset($migrationInfo[$key]);
-        }
-      }
-    }
-
-    // A hook to implement other algorithms for choosing which contact to bias to when
-    // there's a conflict (to handle "gotchas"). fields_in_conflict could be modified here
-    // merge happens with new values filled in here. For a particular field / row not to be merged
-    // field should be unset from fields_in_conflict.
-    $migrationData = [
-      'old_migration_info' => $originalMigrationInfo,
-      'mode' => $mode,
-      'fields_in_conflict' => $conflicts,
-      'merge_mode' => $mode,
-      'migration_info' => $migrationInfo,
-    ];
-    CRM_Utils_Hook::merge('batch', $migrationData, $mainId, $otherId);
-    $conflicts = $migrationData['fields_in_conflict'];
-    // allow hook to override / manipulate migrationInfo as well
-    $migrationInfo = $migrationData['migration_info'];
+    $conflicts = self::getConflicts($migrationInfo, $mainId, $otherId, $mode);
 
     if (!empty($conflicts)) {
       foreach ($conflicts as $key => $val) {
@@ -1023,9 +944,7 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
         }
       }
       // if there are conflicts and mode is aggressive, allow hooks to decide if to skip merges
-      if (array_key_exists('skip_merge', $migrationData)) {
-        return (bool) $migrationData['skip_merge'];
-      }
+      return (bool) $migrationInfo['skip_merge'];
     }
     return FALSE;
   }
@@ -1609,14 +1528,12 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
       return FALSE;
     }
 
-    $qfZeroBug = 'e8cddb72-a257-11dc-b9cc-0016d3330ee9';
+    $contactType = $migrationInfo['main_details']['contact_type'];
     $relTables = CRM_Dedupe_Merger::relTables();
-    $submittedCustomFields = $moveTables = $locationMigrationInfo = $tableOperations = $removeTables = [];
+    $submittedCustomFields = $moveTables = $tableOperations = $removeTables = [];
 
+    self::swapOutFieldsAffectedByQFZeroBug($migrationInfo);
     foreach ($migrationInfo as $key => $value) {
-      if ($value == $qfZeroBug) {
-        $value = '0';
-      }
 
       if (substr($key, 0, 12) == 'move_custom_' && $value != NULL) {
         $submitted[substr($key, 5)] = $value;
@@ -1625,10 +1542,6 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
       elseif (in_array(substr($key, 5), CRM_Dedupe_Merger::getContactFields()) && $value != NULL) {
         $submitted[substr($key, 5)] = $value;
       }
-      // Set up initial information for handling migration of location blocks
-      elseif (substr($key, 0, 14) == 'move_location_' and $value != NULL) {
-        $locationMigrationInfo[$key] = $value;
-      }
       elseif (substr($key, 0, 15) == 'move_rel_table_' and $value == '1') {
         $moveTables = array_merge($moveTables, $relTables[substr($key, 5)]['tables']);
         if (array_key_exists('operation', $migrationInfo)) {
@@ -1643,7 +1556,7 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
         $removeTables = array_merge($moveTables, $relTables[substr($key, 5)]['tables']);
       }
     }
-    self::mergeLocations($mainId, $otherId, $locationMigrationInfo, $migrationInfo);
+    self::mergeLocations($mainId, $otherId, $migrationInfo);
 
     // **** Do contact related migrations
     $customTablesToCopyValues = self::getAffectedCustomTables($submittedCustomFields);
@@ -1684,180 +1597,18 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
       'groupName' => 'postal_greeting',
     ];
     CRM_Core_OptionGroup::lookupValues($submitted, $names, TRUE);
-
     // fix custom fields so they're edible by createProfileContact()
-    $treeCache = [];
-    if (!array_key_exists($migrationInfo['main_details']['contact_type'], $treeCache)) {
-      $treeCache[$migrationInfo['main_details']['contact_type']] = CRM_Core_BAO_CustomGroup::getTree(
-        $migrationInfo['main_details']['contact_type'],
-        NULL,
-        NULL,
-        -1,
-        [],
-        NULL,
-        TRUE,
-        NULL,
-        FALSE,
-        FALSE
-      );
-    }
-
-    $cFields = [];
-    foreach ($treeCache[$migrationInfo['main_details']['contact_type']] as $key => $group) {
-      if (!isset($group['fields'])) {
-        continue;
-      }
-      foreach ($group['fields'] as $fid => $field) {
-        $cFields[$fid]['attributes'] = $field;
-      }
-    }
+    $cFields = self::getCustomFieldMetadata($contactType);
 
     if (!isset($submitted)) {
       $submitted = [];
     }
+    $customFiles = [];
     foreach ($submitted as $key => $value) {
-      if (substr($key, 0, 7) == 'custom_') {
-        $fid = (int) substr($key, 7);
-        if (empty($cFields[$fid])) {
-          continue;
-        }
-        $htmlType = $cFields[$fid]['attributes']['html_type'];
-        switch ($htmlType) {
-          case 'File':
-            $customFiles[] = $fid;
-            unset($submitted["custom_$fid"]);
-            break;
-
-          case 'Select Country':
-          case 'Select State/Province':
-            $submitted[$key] = CRM_Core_BAO_CustomField::displayValue($value, $fid);
-            break;
-
-          case 'Select Date':
-            if ($cFields[$fid]['attributes']['is_view']) {
-              $submitted[$key] = date('YmdHis', strtotime($submitted[$key]));
-            }
-            break;
-
-          case 'CheckBox':
-          case 'Multi-Select':
-          case 'Multi-Select Country':
-          case 'Multi-Select State/Province':
-            // Merge values from both contacts for multivalue fields, CRM-4385
-            // get the existing custom values from db.
-            $customParams = ['entityID' => $mainId, $key => TRUE];
-            $customfieldValues = CRM_Core_BAO_CustomValueTable::getValues($customParams);
-            if (!empty($customfieldValues[$key])) {
-              $existingValue = explode(CRM_Core_DAO::VALUE_SEPARATOR, $customfieldValues[$key]);
-              if (is_array($existingValue) && !empty($existingValue)) {
-                $mergeValue = $submittedCustomFields = [];
-                if ($value == 'null') {
-                  // CRM-19074 if someone has deliberately chosen to overwrite with 'null', respect it.
-                  $submitted[$key] = $value;
-                }
-                else {
-                  if ($value) {
-                    $submittedCustomFields = explode(CRM_Core_DAO::VALUE_SEPARATOR, $value);
-                  }
-
-                  // CRM-19653: overwrite or add the existing custom field value with dupicate contact's
-                  // custom field value stored at $submittedCustomValue.
-                  foreach ($submittedCustomFields as $k => $v) {
-                    if ($v != '' && !in_array($v, $mergeValue)) {
-                      $mergeValue[] = $v;
-                    }
-                  }
-
-                  //keep state and country as array format.
-                  //for checkbox and m-select format w/ VALUE_SEPARATOR
-                  if (in_array($htmlType, [
-                    'CheckBox',
-                    'Multi-Select',
-                  ])) {
-                    $submitted[$key] = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR,
-                        $mergeValue
-                      ) . CRM_Core_DAO::VALUE_SEPARATOR;
-                  }
-                  else {
-                    $submitted[$key] = $mergeValue;
-                  }
-                }
-              }
-            }
-            elseif (in_array($htmlType, [
-              'Multi-Select Country',
-              'Multi-Select State/Province',
-            ])) {
-              //we require submitted values should be in array format
-              if ($value) {
-                $mergeValueArray = explode(CRM_Core_DAO::VALUE_SEPARATOR, $value);
-                //hack to remove null values from array.
-                $mergeValue = [];
-                foreach ($mergeValueArray as $k => $v) {
-                  if ($v != '') {
-                    $mergeValue[] = $v;
-                  }
-                }
-                $submitted[$key] = $mergeValue;
-              }
-            }
-            break;
-
-          default:
-            break;
-        }
-      }
+      list($cFields, $customFiles, $submitted) = self::processCustomFields($mainId, $key, $cFields, $customFiles, $submitted, $value);
     }
 
-    // **** Do file custom fields related migrations
-    // FIXME: move this someplace else (one of the BAOs) after discussing
-    // where to, and whether CRM_Core_BAO_File::deleteFileReferences() shouldn't actually,
-    // like, delete a file...
-
-    if (!isset($customFiles)) {
-      $customFiles = [];
-    }
-    foreach ($customFiles as $customId) {
-      list($tableName, $columnName, $groupID) = CRM_Core_BAO_CustomField::getTableColumnGroup($customId);
-
-      // get the contact_id -> file_id mapping
-      $fileIds = [];
-      $sql = "SELECT entity_id, {$columnName} AS file_id FROM {$tableName} WHERE entity_id IN ({$mainId}, {$otherId})";
-      $dao = CRM_Core_DAO::executeQuery($sql);
-      while ($dao->fetch()) {
-        $fileIds[$dao->entity_id] = $dao->file_id;
-        if ($dao->entity_id == $mainId) {
-          CRM_Core_BAO_File::deleteFileReferences($fileIds[$mainId], $mainId, $customId);
-        }
-      }
-
-      // move the other contact's file to main contact
-      //NYSS need to INSERT or UPDATE depending on whether main contact has an existing record
-      if (CRM_Core_DAO::singleValueQuery("SELECT id FROM {$tableName} WHERE entity_id = {$mainId}")) {
-        $sql = "UPDATE {$tableName} SET {$columnName} = {$fileIds[$otherId]} WHERE entity_id = {$mainId}";
-      }
-      else {
-        $sql = "INSERT INTO {$tableName} ( entity_id, {$columnName} ) VALUES ( {$mainId}, {$fileIds[$otherId]} )";
-      }
-      CRM_Core_DAO::executeQuery($sql);
-
-      if (CRM_Core_DAO::singleValueQuery("
-        SELECT id
-        FROM civicrm_entity_file
-        WHERE entity_table = '{$tableName}' AND file_id = {$fileIds[$otherId]}")
-      ) {
-        $sql = "
-          UPDATE civicrm_entity_file
-          SET entity_id = {$mainId}
-          WHERE entity_table = '{$tableName}' AND file_id = {$fileIds[$otherId]}";
-      }
-      else {
-        $sql = "
-          INSERT INTO civicrm_entity_file ( entity_table, entity_id, file_id )
-          VALUES ( '{$tableName}', {$mainId}, {$fileIds[$otherId]} )";
-      }
-      CRM_Core_DAO::executeQuery($sql);
-    }
+    self::processCustomFieldFiles($mainId, $otherId, $customFiles);
 
     // move view only custom fields CRM-5362
     $viewOnlyCustomFields = [];
@@ -2234,14 +1985,16 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
    *
    * @param int $mainId
    * @param int $otherId
-   * @param array $locationMigrationInfo
-   *   Portion of the migration_info that holds location migration information.
    *
    * @param array $migrationInfo
    *   Migration info for the merge. This is passed to the hook as informational only.
    */
-  public static function mergeLocations($mainId, $otherId, $locationMigrationInfo, $migrationInfo) {
-    foreach ($locationMigrationInfo as $key => $value) {
+  public static function mergeLocations($mainId, $otherId, $migrationInfo) {
+    foreach ($migrationInfo as $key => $value) {
+      $isLocationField = (substr($key, 0, 14) == 'move_location_' and $value != NULL);
+      if (!$isLocationField) {
+        continue;
+      }
       $locField = explode('_', $key);
       $fieldName = $locField[2];
       $fieldCount = $locField[3];
@@ -2408,4 +2161,327 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
     }
   }
 
+  /**
+   * Replace the pseudo QFKey with zero if it is present.
+   *
+   * @todo - on the slim chance this is still relevant it should be moved to the form layer.
+   *
+   * Details about this bug are somewhat obscured by the move from svn but perhaps JIRA
+   * can still help.
+   *
+   * @param array $migrationInfo
+   */
+  protected static function swapOutFieldsAffectedByQFZeroBug(&$migrationInfo) {
+    $qfZeroBug = 'e8cddb72-a257-11dc-b9cc-0016d3330ee9';
+    foreach ($migrationInfo as $key => &$value) {
+      if ($value == $qfZeroBug) {
+        $value = '0';
+      }
+    }
+  }
+
+  /**
+   * Honestly - what DOES this do - hopefully some refactoring will reveal it's purpose.
+   *
+   * @param $mainId
+   * @param $key
+   * @param $cFields
+   * @param $customFiles
+   * @param $submitted
+   * @param $value
+   *
+   * @return array
+   */
+  protected static function processCustomFields($mainId, $key, $cFields, $customFiles, $submitted, $value) {
+    if (substr($key, 0, 7) == 'custom_') {
+      $fid = (int) substr($key, 7);
+      if (empty($cFields[$fid])) {
+        return [$cFields, $customFiles, $submitted];
+      }
+      $htmlType = $cFields[$fid]['attributes']['html_type'];
+      switch ($htmlType) {
+        case 'File':
+          $customFiles[] = $fid;
+          unset($submitted["custom_$fid"]);
+          break;
+
+        case 'Select Country':
+        case 'Select State/Province':
+          $submitted[$key] = CRM_Core_BAO_CustomField::displayValue($value, $fid);
+          break;
+
+        case 'Select Date':
+          if ($cFields[$fid]['attributes']['is_view']) {
+            $submitted[$key] = date('YmdHis', strtotime($submitted[$key]));
+          }
+          break;
+
+        case 'CheckBox':
+        case 'Multi-Select':
+        case 'Multi-Select Country':
+        case 'Multi-Select State/Province':
+          // Merge values from both contacts for multivalue fields, CRM-4385
+          // get the existing custom values from db.
+          $customParams = ['entityID' => $mainId, $key => TRUE];
+          $customfieldValues = CRM_Core_BAO_CustomValueTable::getValues($customParams);
+          if (!empty($customfieldValues[$key])) {
+            $existingValue = explode(CRM_Core_DAO::VALUE_SEPARATOR, $customfieldValues[$key]);
+            if (is_array($existingValue) && !empty($existingValue)) {
+              $mergeValue = $submittedCustomFields = [];
+              if ($value == 'null') {
+                // CRM-19074 if someone has deliberately chosen to overwrite with 'null', respect it.
+                $submitted[$key] = $value;
+              }
+              else {
+                if ($value) {
+                  $submittedCustomFields = explode(CRM_Core_DAO::VALUE_SEPARATOR, $value);
+                }
+
+                // CRM-19653: overwrite or add the existing custom field value with dupicate contact's
+                // custom field value stored at $submittedCustomValue.
+                foreach ($submittedCustomFields as $k => $v) {
+                  if ($v != '' && !in_array($v, $mergeValue)) {
+                    $mergeValue[] = $v;
+                  }
+                }
+
+                //keep state and country as array format.
+                //for checkbox and m-select format w/ VALUE_SEPARATOR
+                if (in_array($htmlType, [
+                  'CheckBox',
+                  'Multi-Select',
+                ])) {
+                  $submitted[$key] = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR,
+                      $mergeValue
+                    ) . CRM_Core_DAO::VALUE_SEPARATOR;
+                }
+                else {
+                  $submitted[$key] = $mergeValue;
+                }
+              }
+            }
+          }
+          elseif (in_array($htmlType, [
+            'Multi-Select Country',
+            'Multi-Select State/Province',
+          ])) {
+            //we require submitted values should be in array format
+            if ($value) {
+              $mergeValueArray = explode(CRM_Core_DAO::VALUE_SEPARATOR, $value);
+              //hack to remove null values from array.
+              $mergeValue = [];
+              foreach ($mergeValueArray as $k => $v) {
+                if ($v != '') {
+                  $mergeValue[] = $v;
+                }
+              }
+              $submitted[$key] = $mergeValue;
+            }
+          }
+          break;
+
+        default:
+          break;
+      }
+    }
+    return [$cFields, $customFiles, $submitted];
+  }
+
+  /**
+   * Get metadata for the custom fields for the merge.
+   *
+   * @param string $contactType
+   *
+   * @return array
+   */
+  protected static function getCustomFieldMetadata($contactType) {
+    $treeCache = [];
+    if (!array_key_exists($contactType, $treeCache)) {
+      $treeCache[$contactType] = CRM_Core_BAO_CustomGroup::getTree(
+        $contactType,
+        NULL,
+        NULL,
+        -1,
+        [],
+        NULL,
+        TRUE,
+        NULL,
+        FALSE,
+        FALSE
+      );
+    }
+
+    $cFields = [];
+    foreach ($treeCache[$contactType] as $key => $group) {
+      if (!isset($group['fields'])) {
+        continue;
+      }
+      foreach ($group['fields'] as $fid => $field) {
+        $cFields[$fid]['attributes'] = $field;
+      }
+    }
+    return $cFields;
+  }
+
+  /**
+   * Get conflicts for proposed merge pair.
+   *
+   * @param array $migrationInfo
+   *   This is primarily to inform hooks. The can also modify it which feels
+   *   pretty fragile to do it here - but it is historical.
+   * @param int $mainId
+   *   Main contact with whom merge has to happen.
+   * @param int $otherId
+   *   Duplicate contact which would be deleted after merge operation.
+   * @param string $mode
+   *   Helps decide how to behave when there are conflicts.
+   *   -  A 'safe' value skips the merge if there are any un-resolved conflicts.
+   *   -  Does a force merge otherwise (aggressive mode).
+   *
+   * @return array
+   */
+  public static function getConflicts(&$migrationInfo, $mainId, $otherId, $mode) {
+    $conflicts = [];
+    $originalMigrationInfo = $migrationInfo;
+    foreach ($migrationInfo as $key => $val) {
+      if ($val === "null") {
+        // Rule: Never overwrite with an empty value (in any mode)
+        unset($migrationInfo[$key]);
+        continue;
+      }
+      elseif ((in_array(substr($key, 5), CRM_Dedupe_Merger::getContactFields()) or
+          substr($key, 0, 12) == 'move_custom_'
+        ) and $val != NULL
+      ) {
+        // Rule: If both main-contact, and other-contact have a field with a
+        // different value, then let $mode decide if to merge it or not
+        if (
+          (!empty($migrationInfo['rows'][$key]['main'])
+            // For custom fields a 0 (e.g in an int field) could be a true conflict. This
+            // is probably true for other fields too - e.g. 'do_not_email' but
+            // leaving that investigation as a @todo - until tests can be written.
+            // Note the handling of this has test coverage - although the data-typing
+            // of '0' feels flakey we have insurance.
+            || ($migrationInfo['rows'][$key]['main'] === '0' && substr($key, 0, 12) == 'move_custom_')
+          )
+          && $migrationInfo['rows'][$key]['main'] != $migrationInfo['rows'][$key]['other']
+        ) {
+
+          // note it down & lets wait for response from the hook.
+          // For no response $mode will decide if to skip this merge
+          $conflicts[$key] = NULL;
+        }
+      }
+      elseif (substr($key, 0, 14) == 'move_location_' and $val != NULL) {
+        $locField = explode('_', $key);
+        $fieldName = $locField[2];
+        $fieldCount = $locField[3];
+
+        // Rule: Catch address conflicts (same address type on both contacts)
+        if (
+          isset($migrationInfo['main_details']['location_blocks'][$fieldName]) &&
+          !empty($migrationInfo['main_details']['location_blocks'][$fieldName])
+        ) {
+
+          // Load the address we're inspecting from the 'other' contact
+          $addressRecord = $migrationInfo['other_details']['location_blocks'][$fieldName][$fieldCount];
+          $addressRecordLocTypeId = CRM_Utils_Array::value('location_type_id', $addressRecord);
+
+          // If it exists on the 'main' contact already, skip it. Otherwise
+          // if the location type exists already, log a conflict.
+          foreach ($migrationInfo['main_details']['location_blocks'][$fieldName] as $mainAddressKey => $mainAddressRecord) {
+            if (self::locationIsSame($addressRecord, $mainAddressRecord)) {
+              unset($migrationInfo[$key]);
+              break;
+            }
+            elseif ($addressRecordLocTypeId == $mainAddressRecord['location_type_id']) {
+              $conflicts[$key] = NULL;
+              break;
+            }
+          }
+        }
+
+        // For other locations, don't merge/add if the values are the same
+        elseif (CRM_Utils_Array::value('main', $migrationInfo['rows'][$key]) == $migrationInfo['rows'][$key]['other']) {
+          unset($migrationInfo[$key]);
+        }
+      }
+    }
+
+    // A hook to implement other algorithms for choosing which contact to bias to when
+    // there's a conflict (to handle "gotchas"). fields_in_conflict could be modified here
+    // merge happens with new values filled in here. For a particular field / row not to be merged
+    // field should be unset from fields_in_conflict.
+    $migrationData = [
+      'old_migration_info' => $originalMigrationInfo,
+      'mode' => $mode,
+      'fields_in_conflict' => $conflicts,
+      'merge_mode' => $mode,
+      'migration_info' => $migrationInfo,
+    ];
+    CRM_Utils_Hook::merge('batch', $migrationData, $mainId, $otherId);
+    $conflicts = $migrationData['fields_in_conflict'];
+    // allow hook to override / manipulate migrationInfo as well
+    $migrationInfo = $migrationData['migration_info'];
+    $migrationInfo['skip_merge'] = CRM_Utils_Array::value('skip_merge', $migrationData);
+    return $conflicts;
+  }
+
+  /**
+   * Do file custom fields related migrations.
+   * FIXME: move this someplace else (one of the BAOs) after discussing
+   * where to, and whether CRM_Core_BAO_File::deleteFileReferences() shouldn't actually,
+   * like, delete a file...
+   *
+   * Note outstanding bug https://lab.civicrm.org/dev/core/issues/723
+   * relates to this code....
+   *
+   * @param $mainId
+   * @param $otherId
+   * @param $customFiles
+   */
+  protected static function processCustomFieldFiles($mainId, $otherId, $customFiles) {
+    foreach ($customFiles as $customId) {
+      list($tableName, $columnName, $groupID) = CRM_Core_BAO_CustomField::getTableColumnGroup($customId);
+
+      // get the contact_id -> file_id mapping
+      $fileIds = [];
+      $sql = "SELECT entity_id, {$columnName} AS file_id FROM {$tableName} WHERE entity_id IN ({$mainId}, {$otherId})";
+      $dao = CRM_Core_DAO::executeQuery($sql);
+      while ($dao->fetch()) {
+        $fileIds[$dao->entity_id] = $dao->file_id;
+        if ($dao->entity_id == $mainId) {
+          CRM_Core_BAO_File::deleteFileReferences($fileIds[$mainId], $mainId, $customId);
+        }
+      }
+
+      // move the other contact's file to main contact
+      //NYSS need to INSERT or UPDATE depending on whether main contact has an existing record
+      if (CRM_Core_DAO::singleValueQuery("SELECT id FROM {$tableName} WHERE entity_id = {$mainId}")) {
+        $sql = "UPDATE {$tableName} SET {$columnName} = {$fileIds[$otherId]} WHERE entity_id = {$mainId}";
+      }
+      else {
+        $sql = "INSERT INTO {$tableName} ( entity_id, {$columnName} ) VALUES ( {$mainId}, {$fileIds[$otherId]} )";
+      }
+      CRM_Core_DAO::executeQuery($sql);
+
+      if (CRM_Core_DAO::singleValueQuery("
+        SELECT id
+        FROM civicrm_entity_file
+        WHERE entity_table = '{$tableName}' AND file_id = {$fileIds[$otherId]}")
+      ) {
+        $sql = "
+          UPDATE civicrm_entity_file
+          SET entity_id = {$mainId}
+          WHERE entity_table = '{$tableName}' AND file_id = {$fileIds[$otherId]}";
+      }
+      else {
+        $sql = "
+          INSERT INTO civicrm_entity_file ( entity_table, entity_id, file_id )
+          VALUES ( '{$tableName}', {$mainId}, {$fileIds[$otherId]} )";
+      }
+      CRM_Core_DAO::executeQuery($sql);
+    }
+  }
+
 }
index 518bc9bd0bb325e78c6398865ef82a0e251f563f..22034dd9f5d3b0d7f783b5578dfa673dc6bc1278 100644 (file)
@@ -986,7 +986,6 @@ WHERE civicrm_event.is_active = 1
       ['entity_value' => $id, 'mapping_id' => $oldMapping->getId()],
       ['entity_value' => $copyEvent->id, 'mapping_id' => $copyMapping->getId()]
     );
-    self::copyCustomFields($id, $copyEvent->id);
 
     $copyEvent->save();
 
@@ -996,57 +995,6 @@ WHERE civicrm_event.is_active = 1
     return $copyEvent;
   }
 
-  /**
-   * Method that copies custom fields values from an old event to a new one. Fixes bug CRM-19302,
-   * where if a custom field of File type was present, left both events using the same file,
-   * breaking download URL's for the old event.
-   *
-   * @param int $oldEventID
-   * @param int $newCopyID
-   */
-  public static function copyCustomFields($oldEventID, $newCopyID) {
-    // Obtain custom values for old event
-    $customParams = $htmlType = [];
-    $customValues = CRM_Core_BAO_CustomValueTable::getEntityValues($oldEventID, 'Event');
-
-    // If custom values present, we copy them
-    if (!empty($customValues)) {
-      // Get Field ID's and identify File type attributes, to handle file copying.
-      $fieldIds = implode(', ', array_keys($customValues));
-      $sql = "SELECT id FROM civicrm_custom_field WHERE html_type = 'File' AND id IN ( {$fieldIds} )";
-      $result = CRM_Core_DAO::executeQuery($sql);
-
-      // Build array of File type fields
-      while ($result->fetch()) {
-        $htmlType[] = $result->id;
-      }
-
-      // Build params array of custom values
-      foreach ($customValues as $field => $value) {
-        if ($value !== NULL) {
-          // Handle File type attributes
-          if (in_array($field, $htmlType)) {
-            $fileValues = CRM_Core_BAO_File::path($value, $oldEventID);
-            $customParams["custom_{$field}_-1"] = [
-              'name' => CRM_Utils_File::duplicate($fileValues[0]),
-              'type' => $fileValues[1],
-            ];
-          }
-          // Handle other types
-          else {
-            $customParams["custom_{$field}_-1"] = $value;
-          }
-        }
-      }
-
-      // Save Custom Fields for new Event
-      CRM_Core_BAO_CustomValueTable::postProcess($customParams, 'civicrm_event', $newCopyID, 'Event');
-    }
-
-    // copy activity attachments ( if any )
-    CRM_Core_BAO_File::copyEntityFile('civicrm_event', $oldEventID, 'civicrm_event', $newCopyID);
-  }
-
   /**
    * This is sometimes called in a loop (during event search).
    *
index a78d34f0263c3f8f0d8258fb0b8c7840b637793b..45767901189b3f8324c87fd0748b1311160f6861 100644 (file)
@@ -151,6 +151,11 @@ class CRM_Event_Cart_Form_Checkout_ParticipantsAndPrices extends CRM_Event_Cart_
         }
       }
 
+      // Validate if participant is already registered
+      if ($event_in_cart->event->allow_same_participant_emails) {
+        continue;
+      }
+
       foreach ($event_in_cart->participants as $mer_participant) {
         $participant_fields = $fields['event'][$event_in_cart->event_id]['participant'][$mer_participant->id];
         //TODO what to do when profile responses differ for the same contact?
index d6906fd94ce61da937f21bf09938857bb08b26d8..143096e3525826f0ec24af0a33f7bcf5b880c73a 100644 (file)
@@ -175,6 +175,10 @@ class CRM_Event_Cart_Form_Checkout_Payment extends CRM_Event_Cart_Form_Cart {
       );
       $this->assign('pay_later_instructions', $this->pay_later_receipt);
     }
+
+    // Event Cart does not support multiple payment processors
+    // so we cannot call $this->preProcessPaymentOptions();
+    CRM_Financial_Form_Payment::addCreditCardJs($this->_paymentProcessor['id']);
   }
 
   /**
@@ -351,7 +355,7 @@ class CRM_Event_Cart_Form_Checkout_Payment extends CRM_Event_Cart_Form_Cart {
     $send_template_params = [
       'table' => 'civicrm_msg_template',
       'contactId' => $this->payer_contact_id,
-      'from' => CRM_Core_BAO_Domain::getNameAndEmail(TRUE, TRUE),
+      'from' => current(CRM_Core_BAO_Domain::getNameAndEmail(TRUE, TRUE)),
       'groupName' => 'msg_tpl_workflow_event',
       'isTest' => FALSE,
       'toEmail' => $contact_details[1],
@@ -502,6 +506,8 @@ class CRM_Event_Cart_Form_Checkout_Payment extends CRM_Event_Cart_Form_Cart {
         $ctype,
         TRUE
       );
+
+      $params['contact_id'] = $this->payer_contact_id;
     }
 
     $params['now'] = date('YmdHis');
index afc523e0347e41242ce1d240ae740f5f52f7a6f5..1a316ef657d658c3e80d48808d25305de115cce2 100644 (file)
@@ -314,7 +314,10 @@ class CRM_Event_Page_ManageEvent extends CRM_Core_Page {
     $this->_searchResult = CRM_Utils_Request::retrieve('searchResult', 'Boolean', $this);
 
     $whereClause = $this->whereClause($params, FALSE, $this->_force);
-    $this->pagerAToZ($whereClause, $params);
+
+    if (CRM_Core_Config::singleton()->includeAlphabeticalPager) {
+      $this->pagerAToZ($whereClause, $params);
+    }
 
     $params = [];
     $whereClause = $this->whereClause($params, TRUE, $this->_force);
index 778ac58c90b9ed36a247e07bd0a55333e2f4f285..eb1e98a5c8d265856185f71de36c0332715eb238 100644 (file)
@@ -652,7 +652,7 @@ VALUES $sqlValueString
    */
   public static function createTempTable($sqlColumns) {
     //creating a temporary table for the search result that need be exported
-    $exportTempTable = CRM_Utils_SQL_TempTable::build()->setDurable()->setCategory('export')->setUtf8();
+    $exportTempTable = CRM_Utils_SQL_TempTable::build()->setDurable()->setCategory('export');
 
     // also create the sql table
     $exportTempTable->drop();
index 8ff0ef4b9b0d02655adc6559456a87de76a2836a..71c61539489958e6cc78725bccec83378b68c4b5 100644 (file)
@@ -286,7 +286,6 @@ class CRM_Financial_BAO_ExportFormat_IIF extends CRM_Financial_BAO_ExportFormat
               'currency' => $this->format($itemDAO->currency),
             ];
           } // end items loop
-          $itemDAO->free();
         }
         else {
           // In this case, split record just uses the FROM account from the trxn, and there's only one record here
index fbb3e58de800cf03a6b1db3909c4f987f54b722f..e743d2d796851b6e7983565a65cb1345fdc4b371 100644 (file)
@@ -63,7 +63,7 @@ class CRM_Financial_BAO_Payment {
     // should be handled through Payment.create.
     $isSkipRecordingPaymentHereForLegacyHandlingReasons = ($contributionStatus == 'Pending' && $isPaymentCompletesContribution);
 
-    if (!$isSkipRecordingPaymentHereForLegacyHandlingReasons) {
+    if (!$isSkipRecordingPaymentHereForLegacyHandlingReasons && $params['total_amount'] > 0) {
       $trxn = CRM_Contribute_BAO_Contribution::recordPartialPayment($contribution, $params);
 
       if (CRM_Utils_Array::value('line_item', $params) && !empty($trxn)) {
@@ -99,6 +99,9 @@ class CRM_Financial_BAO_Payment {
         CRM_Contribute_BAO_Contribution::assignProportionalLineItems($params, $trxn->id, $contribution['total_amount']);
       }
     }
+    elseif ($params['total_amount'] < 0) {
+      $trxn = self::recordRefundPayment($params['contribution_id'], $params, FALSE);
+    }
 
     if ($isPaymentCompletesContribution) {
       civicrm_api3('Contribution', 'completetransaction', ['id' => $contribution['id']]);
@@ -311,7 +314,7 @@ class CRM_Financial_BAO_Payment {
     $arAccountId = CRM_Contribute_PseudoConstant::getRelationalFinancialAccount($contributionDAO->financial_type_id, 'Accounts Receivable Account is');
     $completedStatusId = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
 
-    $trxnData['total_amount'] = $trxnData['net_amount'] = -$trxnData['total_amount'];
+    $trxnData['total_amount'] = $trxnData['net_amount'] = $trxnData['total_amount'];
     $trxnData['from_financial_account_id'] = $arAccountId;
     $trxnData['status_id'] = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Refunded');
     // record the entry
index 789689886fd8d2543d080254f98fede1429f88a0..3c3e9722fbde2ab91c1b9e614fe0ac7248c946d1 100644 (file)
@@ -36,6 +36,8 @@
  */
 class CRM_Group_Form_Edit extends CRM_Core_Form {
 
+  use CRM_Core_Form_EntityFormTrait;
+
   /**
    * The group id, used when editing a group
    *
@@ -78,6 +80,35 @@ class CRM_Group_Form_Edit extends CRM_Core_Form {
    */
   protected $_groupOrganizationID;
 
+  /**
+   * Set entity fields to be assigned to the form.
+   */
+  protected function setEntityFields() {
+    $this->entityFields = [
+      'title' => [
+        'name' => 'title',
+        'required' => TRUE,
+      ],
+      'description' => ['name' => 'description'],
+    ];
+  }
+
+  /**
+   * Set the delete message.
+   *
+   * We do this from the constructor in order to do a translation.
+   */
+  public function setDeleteMessage() {
+    $this->deleteMessage = '';
+  }
+
+  /**
+   * Explicitly declare the entity api name.
+   */
+  public function getDefaultEntity() {
+    return 'Group';
+  }
+
   /**
    * Set up variables to build the form.
    */
@@ -213,18 +244,8 @@ class CRM_Group_Form_Edit extends CRM_Core_Form {
    * Build the form object.
    */
   public function buildQuickForm() {
-    if ($this->_action == CRM_Core_Action::DELETE) {
-      $this->addButtons(array(
-        array(
-          'type' => 'next',
-          'name' => ts('Delete Group'),
-          'isDefault' => TRUE,
-        ),
-        array(
-          'type' => 'cancel',
-          'name' => ts('Cancel'),
-        ),
-      ));
+    self::buildQuickEntityForm();
+    if ($this->_action & CRM_Core_Action::DELETE) {
       return;
     }
 
@@ -233,15 +254,6 @@ class CRM_Group_Form_Edit extends CRM_Core_Form {
       $this->preventAjaxSubmit();
     }
 
-    $this->applyFilter('__ALL__', 'trim');
-    $this->add('text', 'title', ts('Name') . ' ',
-      CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Group', 'title'), TRUE
-    );
-
-    $this->add('textarea', 'description', ts('Description') . ' ',
-      CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Group', 'description')
-    );
-
     $groupTypes = CRM_Core_OptionGroup::values('group_type', TRUE);
 
     if (isset($this->_id) && !empty($this->_groupValues['saved_search_id'])) {
@@ -272,18 +284,6 @@ class CRM_Group_Form_Edit extends CRM_Core_Form {
     //build custom data
     CRM_Custom_Form_CustomData::buildQuickForm($this);
 
-    $this->addButtons(array(
-      array(
-        'type' => 'upload',
-        'name' => ($this->_action == CRM_Core_Action::ADD) ? ts('Continue') : ts('Save'),
-        'isDefault' => TRUE,
-      ),
-      array(
-        'type' => 'cancel',
-        'name' => ts('Cancel'),
-      ),
-    ));
-
     $doParentCheck = FALSE;
     if (CRM_Core_Permission::isMultisiteEnabled()) {
       $doParentCheck = ($this->_id && CRM_Core_BAO_Domain::isDomainGroup($this->_id)) ? FALSE : TRUE;
index 85e893ca4dfd0c24ff662bdde2d840d5f15645db..8e609c0d1478431e841f991e5014e4cb979ca7cc 100644 (file)
@@ -65,7 +65,8 @@ class CRM_Mailing_ActionTokens extends \Civi\Token\AbstractTokenSubscriber {
    * @inheritDoc
    */
   public function checkActive(\Civi\Token\TokenProcessor $processor) {
-    return !empty($processor->context['mailingId']) || !empty($processor->context['mailing']);
+    return !empty($processor->context['mailingId']) || !empty($processor->context['mailing'])
+      || in_array('mailingId', $processor->context['schema']) || in_array('mailing', $processor->context['schema']);
   }
 
   /**
@@ -85,7 +86,9 @@ class CRM_Mailing_ActionTokens extends \Civi\Token\AbstractTokenSubscriber {
     // replaceSubscribeInviteTokens().
 
     if (empty($row->context['mailingJobId']) || empty($row->context['mailingActionTarget']['hash'])) {
-      throw new \CRM_Core_Exception("Error: Cannot use action tokens unless context defines mailingJobId and mailingActionTarget.");
+      // Strictly speaking, it doesn't make much sense to generate action-tokens when there's no job ID, but traditional CiviMail
+      // does this in v5.6+ for "Preview" functionality. Relaxing this strictness check ensures parity between newer+older styles.
+      // throw new \CRM_Core_Exception("Error: Cannot use action tokens unless context defines mailingJobId and mailingActionTarget.");
     }
 
     if ($field === 'eventQueueId') {
index f0ced3b8d881c77010710a14236a9736045661f5..21d10f7c5f77d2aab9ed34ad29bb15daed6f7446 100644 (file)
@@ -1363,6 +1363,10 @@ ORDER BY   civicrm_email.is_bulkmail DESC
       $numSlices = count($embed_data);
       $url = '';
       for ($i = 0; $i < $numSlices; $i++) {
+        $embed_url_data = parse_url($embed_data[$i]);
+        if (!empty($embed_url_data['scheme'])) {
+          $token_a['embed_parts'][$i] = preg_replace("/href=\"(https*:\/\/)/", "href=\"", $token_a['embed_parts'][$i]);
+        }
         $url .= "{$token_a['embed_parts'][$i]}{$embed_data[$i]}";
       }
       if (isset($token_a['embed_parts'][$numSlices])) {
index b8282405a3e51edcf65107a0772d19220ee04145..b06d61cf34e3046f9005998a22e06025d6bd98e5 100644 (file)
  * A page for mailing preview.
  */
 class CRM_Mailing_Page_View extends CRM_Core_Page {
+
+  /**
+   * @var Signal to Flexmailer that this version of the class is usable.
+   */
+  const USES_MAILING_PREVIEW_API = 1;
+
   protected $_mailingID;
   protected $_mailing;
   protected $_contactID;
@@ -132,59 +138,27 @@ class CRM_Mailing_Page_View extends CRM_Core_Page {
       return NULL;
     }
 
-    CRM_Mailing_BAO_Mailing::tokenReplace($this->_mailing);
-
-    // get and format attachments
-    $attachments = CRM_Core_BAO_File::getEntityFile('civicrm_mailing',
-      $this->_mailing->id
-    );
-
-    // get contact detail and compose if contact id exists
-    $returnProperties = $this->_mailing->getReturnProperties();
-    if (isset($this->_contactID)) {
-      // get details of contact with token value including Custom Field Token Values.CRM-3734
-      $params = ['contact_id' => $this->_contactID];
-      $details = CRM_Utils_Token::getTokenDetails($params,
-        $returnProperties,
-        FALSE, TRUE, NULL,
-        $this->_mailing->getFlattenedTokens(),
-        get_class($this)
-      );
-      $details = $details[0][$this->_contactID];
-      $contactId = $this->_contactID;
-    }
-    else {
-      // get tokens that are not contact specific resolved
-      $params = ['contact_id' => 0];
-      $details = CRM_Utils_Token::getAnonymousTokenDetails($params,
-        $returnProperties,
-        TRUE, TRUE, NULL,
-        $this->_mailing->getFlattenedTokens(),
-        get_class($this)
-      );
-
-      $details = CRM_Utils_Array::value(0, $details[0]);
-      $contactId = 0;
-    }
-    $mime = $this->_mailing->compose(NULL, NULL, NULL, $contactId,
-      $this->_mailing->from_email,
-      $this->_mailing->from_email,
-      TRUE, $details, $attachments
-    );
+    $contactId = isset($this->_contactID) ? $this->_contactID : 0;
+
+    $result = civicrm_api3('Mailing', 'preview', [
+      'id' => $this->_mailingID,
+      'contact_id' => $contactId,
+    ]);
+    $mailing = \CRM_Utils_Array::value('values', $result);
 
     $title = NULL;
-    if (isset($this->_mailing->body_html) && empty($_GET['text'])) {
+    if (isset($mailing['body_html']) && empty($_GET['text'])) {
       $header = 'text/html; charset=utf-8';
-      $content = $mime->getHTMLBody();
+      $content = $mailing['body_html'];
       if (strpos($content, '<head>') === FALSE && strpos($content, '<title>') === FALSE) {
-        $title = '<head><title>' . $this->_mailing->subject . '</title></head>';
+        $title = '<head><title>' . $mailing['subject'] . '</title></head>';
       }
     }
     else {
       $header = 'text/plain; charset=utf-8';
-      $content = $mime->getTXTBody();
+      $content = $mailing['body_text'];
     }
-    CRM_Utils_System::setTitle($this->_mailing->subject);
+    CRM_Utils_System::setTitle($mailing['subject']);
 
     if (CRM_Utils_Array::value('snippet', $_GET) === 'json') {
       CRM_Core_Page_AJAX::returnJsonResponse($content);
index e50406bd8359b9560cfefa4d5dbf3d78aaedcede..65ad8038ce66c12b7dd251994827fb60c990eb88 100644 (file)
@@ -341,8 +341,10 @@ class CRM_Mailing_Selector_Search extends CRM_Core_Selector_Base implements CRM_
    *   the column headers that need to be displayed
    */
   public function &getColumnHeaders($action = NULL, $output = NULL) {
+
     if (!isset(self::$_columnHeaders)) {
-      self::$_columnHeaders = [
+      $isMultiLingual = CRM_Core_I18n::isMultiLingual();
+      $headers = [
         ['desc' => ts('Contact Type')],
         [
           'name' => ts('Name'),
@@ -359,11 +361,17 @@ class CRM_Mailing_Selector_Search extends CRM_Core_Selector_Base implements CRM_
           'sort' => 'mailing_name',
           'direction' => CRM_Utils_Sort::DONTCARE,
         ],
-        [
+      ];
+
+      // Check to see if languages column should be displayed.
+      if ($isMultiLingual) {
+        $headers[] = [
           'name' => ts('Language'),
           'sort' => 'language',
           'direction' => CRM_Utils_Sort::DONTCARE,
-        ],
+        ];
+      }
+      self::$_columnHeaders = array_merge($headers, [
         [
           'name' => ts('Mailing Subject'),
           'sort' => 'mailing_subject',
@@ -380,7 +388,7 @@ class CRM_Mailing_Selector_Search extends CRM_Core_Selector_Base implements CRM_
           'direction' => CRM_Utils_Sort::DONTCARE,
         ],
         ['desc' => ts('Actions')],
-      ];
+      ]);
     }
     return self::$_columnHeaders;
   }
index 74cd6adee41dc14b2e761d96bb0aede1127846ad..efde6376b2e261e0919c6229a9d5327967a9272f 100644 (file)
@@ -61,7 +61,8 @@ class CRM_Mailing_Tokens extends \Civi\Token\AbstractTokenSubscriber {
    * @inheritDoc
    */
   public function checkActive(\Civi\Token\TokenProcessor $processor) {
-    return !empty($processor->context['mailingId']) || !empty($processor->context['mailing']);
+    return !empty($processor->context['mailingId']) || !empty($processor->context['mailing'])
+      || in_array('mailingId', $processor->context['schema']) || in_array('mailing', $processor->context['schema']);
   }
 
   /**
index ff2e0c3b7712cac169bfcd3d82309ac2bab4a934..69e1f7fcd69f656bc65f6f51ab5599094c232f0a 100644 (file)
@@ -1559,7 +1559,7 @@ WHERE       ps.id = %1
         CRM_Price_BAO_PriceSet::addTo($baoName, $newId, $copyPriceSet->id);
       }
       else {
-        $copyPriceSet = &CRM_Core_DAO::copyGeneric('CRM_Price_DAO_PriceSetEntity',
+        $copyPriceSet = CRM_Core_DAO::copyGeneric('CRM_Price_DAO_PriceSetEntity',
           [
             'entity_id' => $id,
             'entity_table' => $baoName,
index 8e36623d68b2c8b127fbf924a467835fa53fd303..76ade8a72987c29a382a3d3eec08b4bf68e6774b 100644 (file)
@@ -1164,7 +1164,7 @@ class CRM_Report_Form extends CRM_Core_Form {
    * @return string
    */
   public function createTemporaryTable($identifier, $sql, $isColumns = FALSE, $isMemory = FALSE) {
-    $tempTable = CRM_Utils_SQL_TempTable::build()->setUtf8();
+    $tempTable = CRM_Utils_SQL_TempTable::build();
     if ($isMemory) {
       $tempTable->setMemory();
     }
index e8b7f84b47d2791dcd037f9feca24acb6e8910dc..e0b7588e36e64585b90b56814cff2841efb8a05e 100644 (file)
@@ -655,7 +655,6 @@ INNER JOIN  civicrm_custom_group cg ON ( cg.id = cf.custom_group_id )
         $fieldValueMap[$responseField->option_group_id][$responseField->value] = $value;
       }
     }
-    $responseField->free();
 
     //actual data formatting.
     $hasData = FALSE;
index 22c337eb8cecf035d9a868ea22da108d143c9535..3a2cb5f47f1b1dfc8c1bb49847ecb16aca3812db 100644 (file)
@@ -446,7 +446,6 @@ class CRM_Report_Form_Contribute_Sybunt extends CRM_Report_Form {
       while ($dao->fetch()) {
         $contactIds[] = $dao->cid;
       }
-      $dao->free();
       $this->setPager();
     }
 
@@ -497,7 +496,6 @@ class CRM_Report_Form_Contribute_Sybunt extends CRM_Report_Form {
           $contributionSum = 0;
         }
       }
-      $dao->free();
     }
     // format result set.
     $this->formatDisplay($rows, FALSE);
diff --git a/CRM/Report/Form/Extended.php b/CRM/Report/Form/Extended.php
deleted file mode 100644 (file)
index 873665e..0000000
+++ /dev/null
@@ -1,1420 +0,0 @@
-<?php
-/*
- +--------------------------------------------------------------------+
- | CiviCRM version 5                                                  |
- +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2019                                |
- +--------------------------------------------------------------------+
- | This file is a part of CiviCRM.                                    |
- |                                                                    |
- | CiviCRM is free software; you can copy, modify, and distribute it  |
- | under the terms of the GNU Affero General Public License           |
- | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
- |                                                                    |
- | CiviCRM is distributed in the hope that it will be useful, but     |
- | WITHOUT ANY WARRANTY; without even the implied warranty of         |
- | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
- | See the GNU Affero General Public License for more details.        |
- |                                                                    |
- | You should have received a copy of the GNU Affero General Public   |
- | License and the CiviCRM Licensing Exception along                  |
- | with this program; if not, contact CiviCRM LLC                     |
- | at info[AT]civicrm[DOT]org. If you have questions about the        |
- | GNU Affero General Public License or the licensing of CiviCRM,     |
- | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
- +--------------------------------------------------------------------+
- */
-
-/**
- *
- * @package CRM
- * @copyright CiviCRM LLC (c) 2004-2019
- * $Id$
- *
- */
-class CRM_Report_Form_Extended extends CRM_Report_Form {
-  protected $_addressField = FALSE;
-
-  protected $_emailField = FALSE;
-
-  protected $_summary = NULL;
-
-  protected $_customGroupExtends = [];
-  protected $_baseTable = 'civicrm_contact';
-
-  /**
-   *
-   */
-  public function __construct() {
-    parent::__construct();
-  }
-
-  /**
-   *
-   */
-  public function preProcess() {
-    parent::preProcess();
-  }
-
-  /**
-   *
-   */
-  public function select() {
-    parent::select();
-  }
-
-  /**
-   * From clause build where baseTable & fromClauses are defined
-   */
-  public function from() {
-    if (!empty($this->_baseTable)) {
-      $this->buildACLClause($this->_aliases['civicrm_contact']);
-      $this->_from = "FROM {$this->_baseTable}   {$this->_aliases[$this->_baseTable]}";
-      $availableClauses = $this->getAvailableJoins();
-      foreach ($this->fromClauses() as $fromClause) {
-        $fn = $availableClauses[$fromClause]['callback'];
-        $this->$fn();
-      }
-      if (strstr($this->_from, 'civicrm_contact')) {
-        $this->_from .= $this->_aclFrom;
-      }
-    }
-  }
-
-  /**
-   * Define any from clauses in use (child classes to override)
-   *
-   * @return array
-   */
-  public function fromClauses() {
-    return [];
-  }
-
-  public function groupBy() {
-    parent::groupBy();
-    //@todo - need to re-visit this - bad behaviour from pa
-    if ($this->_groupBy == 'GROUP BY') {
-      $this->_groupBY = NULL;
-    }
-    // if a stat field has been selected the do a group by
-    if (!empty($this->_statFields) && empty($this->_groupBy)) {
-      $this->_groupBy[] = $this->_aliases[$this->_baseTable] . ".id";
-    }
-    //@todo - this should be in the parent function or at parent level - perhaps build query should do this?
-    if (!empty($this->_groupBy) && is_array($this->_groupBy)) {
-      $this->_groupBy = 'GROUP BY ' . implode(',', $this->_groupBy);
-    }
-  }
-
-  public function orderBy() {
-    parent::orderBy();
-  }
-
-  /**
-   * @param array $rows
-   *
-   * @return array
-   */
-  public function statistics(&$rows) {
-    return parent::statistics($rows);
-  }
-
-  public function postProcess() {
-    if (!empty($this->_aclTable) && !empty($this->_aliases[$this->_aclTable])) {
-      $this->buildACLClause($this->_aliases[$this->_aclTable]);
-    }
-    parent::postProcess();
-  }
-
-  /**
-   * Alter display of rows.
-   *
-   * Iterate through the rows retrieved via SQL and make changes for display purposes,
-   * such as rendering contacts as links.
-   *
-   * @param array $rows
-   *   Rows generated by SQL, with an array for each row.
-   */
-  public function alterDisplay(&$rows) {
-    parent::alterDisplay($rows);
-
-    //THis is all generic functionality which can hopefully go into the parent class
-    // it introduces the option of defining an alter display function as part of the column definition
-    // @tod tidy up the iteration so it happens in this function
-    list($firstRow) = $rows;
-    // no result to alter
-    if (empty($firstRow)) {
-      return;
-    }
-    $selectedFields = array_keys($firstRow);
-
-    $alterfunctions = $altermap = [];
-    foreach ($this->_columns as $tablename => $table) {
-      if (array_key_exists('fields', $table)) {
-        foreach ($table['fields'] as $field => $specs) {
-          if (in_array($tablename . '_' . $field, $selectedFields) &&
-            array_key_exists('alter_display', $specs)
-          ) {
-            $alterfunctions[$tablename . '_' .
-            $field] = $specs['alter_display'];
-            $altermap[$tablename . '_' . $field] = $field;
-          }
-        }
-      }
-    }
-    if (empty($alterfunctions)) {
-      // - no manipulation to be done
-      return;
-    }
-
-    foreach ($rows as $index => & $row) {
-      foreach ($row as $selectedfield => $value) {
-        if (array_key_exists($selectedfield, $alterfunctions)) {
-          $rows[$index][$selectedfield] = $this->{$alterfunctions[$selectedfield]}($value, $row, $selectedfield, $altermap[$selectedfield]);
-        }
-      }
-    }
-  }
-
-  /**
-   * @return array
-   */
-  public function getLineItemColumns() {
-    return [
-      'civicrm_line_item' => [
-        'dao' => 'CRM_Price_BAO_LineItem',
-        'fields' => [
-          'qty' => [
-            'title' => ts('Quantity'),
-            'type' => CRM_Utils_Type::T_INT,
-            'statistics' => ['sum' => ts('Total Quantity Selected')],
-          ],
-          'unit_price' => [
-            'title' => ts('Unit Price'),
-          ],
-          'line_total' => [
-            'title' => ts('Line Total'),
-            'type' => CRM_Utils_Type::T_MONEY,
-            'statistics' => ['sum' => ts('Total of Line Items')],
-          ],
-        ],
-        'participant_count' => [
-          'title' => ts('Participant Count'),
-          'statistics' => ['sum' => ts('Total Participants')],
-        ],
-        'filters' => [
-          'qty' => [
-            'title' => ts('Quantity'),
-            'type' => CRM_Utils_Type::T_INT,
-            'operator' => CRM_Report_Form::OP_INT,
-          ],
-        ],
-        'group_bys' => [
-          'price_field_id' => [
-            'title' => ts('Price Field'),
-          ],
-          'price_field_value_id' => [
-            'title' => ts('Price Field Option'),
-          ],
-          'line_item_id' => [
-            'title' => ts('Individual Line Item'),
-            'name' => 'id',
-          ],
-        ],
-      ],
-    ];
-  }
-
-  /**
-   * @return array
-   */
-  public function getPriceFieldValueColumns() {
-    return [
-      'civicrm_price_field_value' => [
-        'dao' => 'CRM_Price_BAO_PriceFieldValue',
-        'fields' => [
-          'price_field_value_label' => [
-            'title' => ts('Price Field Value Label'),
-            'name' => 'label',
-          ],
-        ],
-        'filters' => [
-          'price_field_value_label' => [
-            'title' => ts('Price Fields Value Label'),
-            'type' => CRM_Utils_Type::T_STRING,
-            'operator' => 'like',
-            'name' => 'label',
-          ],
-        ],
-        'order_bys' => [
-          'label' => [
-            'title' => ts('Price Field Value Label'),
-          ],
-        ],
-        //note that we have a requirement to group by label such that all 'Promo book' lines
-        'group_bys' =>
-        // are grouped together across price sets but there may be a separate need to group
-        // by id so that entries in one price set are distinct from others. Not quite sure what
-        // to call the distinction for end users benefit
-        [
-          'price_field_value_label' => [
-            'title' => ts('Price Field Value Label'),
-            'name' => 'label',
-          ],
-        ],
-      ],
-    ];
-  }
-
-  /**
-   * @return array
-   */
-  public function getPriceFieldColumns() {
-    return [
-      'civicrm_price_field' => [
-        'dao' => 'CRM_Price_BAO_PriceField',
-        'fields' => [
-          'price_field_label' => [
-            'title' => ts('Price Field Label'),
-            'name' => 'label',
-          ],
-        ],
-        'filters' => [
-          'price_field_label' => [
-            'title' => ts('Price Field Label'),
-            'type' => CRM_Utils_Type::T_STRING,
-            'operator' => 'like',
-            'name' => 'label',
-          ],
-        ],
-        'order_bys' => [
-          'price_field_label' => [
-            'title' => ts('Price Field Label'),
-            'name' => 'label',
-          ],
-        ],
-        'group_bys' => [
-          'price_field_label' => [
-            'title' => ts('Price Field Label'),
-            'name' => 'label',
-          ],
-        ],
-      ],
-    ];
-  }
-
-  /**
-   * @return array
-   */
-  public function getParticipantColumns() {
-    static $_events = [];
-    if (!isset($_events['all'])) {
-      CRM_Core_PseudoConstant::populate($_events['all'], 'CRM_Event_DAO_Event', FALSE, 'title', 'is_active', "is_template IS NULL OR is_template = 0", 'end_date DESC');
-    }
-    return [
-      'civicrm_participant' => [
-        'dao' => 'CRM_Event_DAO_Participant',
-        'fields' => [
-          'participant_id' => ['title' => ts('Participant ID')],
-          'participant_record' => [
-            'name' => 'id',
-            'title' => ts('Participant ID'),
-          ],
-          'event_id' => [
-            'title' => ts('Event ID'),
-            'type' => CRM_Utils_Type::T_STRING,
-            'alter_display' => 'alterEventID',
-          ],
-          'status_id' => [
-            'title' => ts('Status'),
-            'alter_display' => 'alterParticipantStatus',
-          ],
-          'role_id' => [
-            'title' => ts('Role'),
-            'alter_display' => 'alterParticipantRole',
-          ],
-          'participant_fee_level' => NULL,
-          'participant_fee_amount' => NULL,
-          'participant_register_date' => ['title' => ts('Registration Date')],
-        ],
-        'grouping' => 'event-fields',
-        'filters' => [
-          'event_id' => [
-            'name' => 'event_id',
-            'title' => ts('Event'),
-            'operatorType' => CRM_Report_Form::OP_MULTISELECT,
-            'options' => $_events['all'],
-          ],
-          'sid' => [
-            'name' => 'status_id',
-            'title' => ts('Participant Status'),
-            'operatorType' => CRM_Report_Form::OP_MULTISELECT,
-            'options' => CRM_Event_PseudoConstant::participantStatus(NULL, NULL, 'label'),
-          ],
-          'rid' => [
-            'name' => 'role_id',
-            'title' => ts('Participant Role'),
-            'operatorType' => CRM_Report_Form::OP_MULTISELECT,
-            'options' => CRM_Event_PseudoConstant::participantRole(),
-          ],
-          'participant_register_date' => [
-            'title' => ts('Registration Date'),
-            'operatorType' => CRM_Report_Form::OP_DATE,
-          ],
-        ],
-        'order_bys' => [
-          'event_id' => [
-            'title' => ts('Event'),
-            'default_weight' => '1',
-            'default_order' => 'ASC',
-          ],
-        ],
-        'group_bys' => [
-          'event_id' => ['title' => ts('Event')],
-        ],
-      ],
-    ];
-  }
-
-  /**
-   * @return array
-   */
-  public function getMembershipColumns() {
-    return [
-      'civicrm_membership' => [
-        'dao' => 'CRM_Member_DAO_Membership',
-        'grouping' => 'member-fields',
-        'fields' => [
-          'membership_type_id' => [
-            'title' => ts('Membership Type'),
-            'required' => TRUE,
-            'alter_display' => 'alterMembershipTypeID',
-          ],
-          'status_id' => [
-            'title' => ts('Membership Status'),
-            'required' => TRUE,
-            'alter_display' => 'alterMembershipStatusID',
-          ],
-          'join_date' => NULL,
-          'start_date' => [
-            'title' => ts('Current Cycle Start Date'),
-          ],
-          'end_date' => [
-            'title' => ts('Current Membership Cycle End Date'),
-          ],
-        ],
-        'group_bys' => [
-          'membership_type_id' => [
-            'title' => ts('Membership Type'),
-          ],
-        ],
-        'filters' => [
-          'join_date' => [
-            'type' => CRM_Utils_Type::T_DATE,
-            'operatorType' => CRM_Report_Form::OP_DATE,
-          ],
-        ],
-      ],
-    ];
-  }
-
-  /**
-   * @return array
-   */
-  public function getMembershipTypeColumns() {
-    return [
-      'civicrm_membership_type' => [
-        'dao' => 'CRM_Member_DAO_MembershipType',
-        'grouping' => 'member-fields',
-        'filters' => [
-          'gid' => [
-            'name' => 'id',
-            'title' => ts('Membership Types'),
-            'operatorType' => CRM_Report_Form::OP_MULTISELECT,
-            'type' => CRM_Utils_Type::T_INT + CRM_Utils_Type::T_ENUM,
-            'options' => CRM_Member_PseudoConstant::membershipType(),
-          ],
-        ],
-      ],
-    ];
-  }
-
-  /**
-   * @return array
-   */
-  public function getEventColumns() {
-    return [
-      'civicrm_event' => [
-        'dao' => 'CRM_Event_DAO_Event',
-        'fields' => [
-          'id' => [
-            'no_display' => TRUE,
-            'required' => TRUE,
-          ],
-          'title' => [
-            'title' => ts('Event Title'),
-            'required' => TRUE,
-          ],
-          'event_type_id' => [
-            'title' => ts('Event Type'),
-            'required' => TRUE,
-            'alter_display' => 'alterEventType',
-          ],
-          'fee_label' => ['title' => ts('Fee Label')],
-          'event_start_date' => [
-            'title' => ts('Event Start Date'),
-          ],
-          'event_end_date' => ['title' => ts('Event End Date')],
-          'max_participants' => [
-            'title' => ts('Capacity'),
-            'type' => CRM_Utils_Type::T_INT,
-          ],
-        ],
-        'grouping' => 'event-fields',
-        'filters' => [
-          'event_type_id' => [
-            'name' => 'event_type_id',
-            'title' => ts('Event Type'),
-            'operatorType' => CRM_Report_Form::OP_MULTISELECT,
-            'options' => CRM_Core_OptionGroup::values('event_type'),
-          ],
-          'event_title' => [
-            'name' => 'title',
-            'title' => ts('Event Title'),
-            'operatorType' => CRM_Report_Form::OP_STRING,
-          ],
-        ],
-        'order_bys' => [
-          'event_type_id' => [
-            'title' => ts('Event Type'),
-            'default_weight' => '2',
-            'default_order' => 'ASC',
-          ],
-        ],
-        'group_bys' => [
-          'event_type_id' => [
-            'title' => ts('Event Type'),
-          ],
-        ],
-      ],
-    ];
-  }
-
-  /**
-   * @return array
-   */
-  public function getContributionColumns() {
-    return [
-      'civicrm_contribution' => [
-        'dao' => 'CRM_Contribute_DAO_Contribution',
-        'fields' => [
-          'contribution_id' => [
-            'name' => 'id',
-          ],
-          'financial_type_id' => [
-            'title' => ts('Financial Type'),
-            'default' => TRUE,
-            'alter_display' => 'alterContributionType',
-          ],
-          'payment_instrument_id' => [
-            'title' => ts('Payment Method'),
-            'alter_display' => 'alterPaymentType',
-          ],
-          'source' => ['title' => ts('Contribution Source')],
-          'trxn_id' => NULL,
-          'receive_date' => ['default' => TRUE],
-          'receipt_date' => NULL,
-          'fee_amount' => NULL,
-          'net_amount' => NULL,
-          'total_amount' => [
-            'title' => ts('Amount'),
-            'statistics' => ['sum' => ts('Total Amount')],
-            'type' => CRM_Utils_Type::T_MONEY,
-          ],
-        ],
-        'filters' => [
-          'receive_date' => ['operatorType' => CRM_Report_Form::OP_DATE],
-          'financial_type_id' => [
-            'title' => ts('Financial Type'),
-            'operatorType' => CRM_Report_Form::OP_MULTISELECT,
-            'options' => CRM_Contribute_PseudoConstant::financialType(),
-          ],
-          'payment_instrument_id' => [
-            'title' => ts('Payment Type'),
-            'operatorType' => CRM_Report_Form::OP_MULTISELECT,
-            'options' => CRM_Contribute_PseudoConstant::paymentInstrument(),
-          ],
-          'contribution_status_id' => [
-            'title' => ts('Contribution Status'),
-            'operatorType' => CRM_Report_Form::OP_MULTISELECT,
-            'options' => CRM_Contribute_PseudoConstant::contributionStatus(),
-          ],
-          'total_amount' => ['title' => ts('Contribution Amount')],
-        ],
-        'order_bys' => [
-          'payment_instrument_id' => [
-            'title' => ts('Payment Method'),
-          ],
-          'financial_type_id' => [
-            'title' => ts('Financial Type'),
-          ],
-        ],
-        'group_bys' => [
-          'financial_type_id' => ['title' => ts('Financial Type')],
-          'payment_instrument_id' => ['title' => ts('Payment Method')],
-          'contribution_id' => [
-            'title' => ts('Individual Contribution'),
-            'name' => 'id',
-          ],
-          'source' => ['title' => ts('Contribution Source')],
-        ],
-        'grouping' => 'contribution-fields',
-      ],
-    ];
-  }
-
-  /**
-   * @return array
-   */
-  public function getContactColumns() {
-    return [
-      'civicrm_contact' => [
-        'dao' => 'CRM_Contact_DAO_Contact',
-        'fields' => [
-          'display_name' => [
-            'title' => ts('Contact Name'),
-          ],
-          'id' => [
-            'title' => ts('Contact ID'),
-            'alter_display' => 'alterContactID',
-          ],
-          'first_name' => [
-            'title' => ts('First Name'),
-          ],
-          'last_name' => [
-            'title' => ts('Last Name'),
-          ],
-          'nick_name' => [
-            'title' => ts('Nickname'),
-            'alter_display' => 'alterNickname',
-          ],
-        ],
-        'filters' => [
-          'id' => [
-            'title' => ts('Contact ID'),
-          ],
-          'sort_name' => [
-            'title' => ts('Contact Name'),
-          ],
-        ],
-        'grouping' => 'contact-fields',
-        'order_bys' => [
-          'sort_name' => [
-            'title' => ts('Last Name, First Name'),
-            'default' => '1',
-            'default_weight' => '0',
-            'default_order' => 'ASC',
-          ],
-        ],
-      ],
-    ];
-  }
-
-  /**
-   * @return array
-   */
-  public function getCaseColumns() {
-    return [
-      'civicrm_case' => [
-        'dao' => 'CRM_Case_DAO_Case',
-        'fields' => [
-          'id' => [
-            'title' => ts('Case ID'),
-            'required' => FALSE,
-          ],
-          'subject' => [
-            'title' => ts('Case Subject'),
-            'default' => TRUE,
-          ],
-          'status_id' => [
-            'title' => ts('Status'),
-            'default' => TRUE,
-          ],
-          'case_type_id' => [
-            'title' => ts('Case Type'),
-            'default' => TRUE,
-          ],
-          'case_start_date' => [
-            'title' => ts('Case Start Date'),
-            'name' => 'start_date',
-            'default' => TRUE,
-          ],
-          'case_end_date' => [
-            'title' => ts('Case End Date'),
-            'name' => 'end_date',
-            'default' => TRUE,
-          ],
-          'case_duration' => [
-            'name' => 'duration',
-            'title' => ts('Duration (Days)'),
-            'default' => FALSE,
-          ],
-          'case_is_deleted' => [
-            'name' => 'is_deleted',
-            'title' => ts('Case Deleted?'),
-            'default' => FALSE,
-            'type' => CRM_Utils_Type::T_INT,
-          ],
-        ],
-        'filters' => [
-          'case_start_date' => [
-            'title' => ts('Case Start Date'),
-            'operatorType' => CRM_Report_Form::OP_DATE,
-            'type' => CRM_Utils_Type::T_DATE,
-            'name' => 'start_date',
-          ],
-          'case_end_date' => [
-            'title' => ts('Case End Date'),
-            'operatorType' => CRM_Report_Form::OP_DATE,
-            'type' => CRM_Utils_Type::T_DATE,
-            'name' => 'end_date',
-          ],
-          'case_type_id' => [
-            'title' => ts('Case Type'),
-            'operatorType' => CRM_Report_Form::OP_MULTISELECT,
-            'options' => $this->case_types,
-          ],
-          'case_status_id' => [
-            'title' => ts('Case Status'),
-            'operatorType' => CRM_Report_Form::OP_MULTISELECT,
-            'options' => $this->case_statuses,
-            'name' => 'status_id',
-          ],
-          'case_is_deleted' => [
-            'title' => ts('Case Deleted?'),
-            'type' => CRM_Report_Form::OP_INT,
-            'operatorType' => CRM_Report_Form::OP_SELECT,
-            'options' => $this->deleted_labels,
-            'default' => 0,
-            'name' => 'is_deleted',
-          ],
-        ],
-      ],
-    ];
-  }
-
-  /**
-   * Get address columns to add to array.
-   *
-   * @param array $options
-   *   Options for the report.
-   *   - prefix prefix to add (e.g. 'honor' when getting address details for honor contact
-   *   - prefix_label optional prefix lable eg. "Honoree " for front end
-   *   - group_by enable these fields for group by - default false
-   *   - order_by enable these fields for order by
-   *   - filters enable these fields for filtering
-   *   - defaults - (is this working?) values to pre-populate
-   *
-   * @return array
-   *   address columns definition
-   */
-  public function getAddressColumns($options = []) {
-    $defaultOptions = [
-      'prefix' => '',
-      'prefix_label' => '',
-      'group_by' => FALSE,
-      'order_by' => TRUE,
-      'filters' => TRUE,
-      'defaults' => [
-        'country_id' => TRUE,
-      ],
-    ];
-
-    $options = array_merge($defaultOptions, $options);
-
-    $addressFields = [
-      $options['prefix'] . 'civicrm_address' => [
-        'dao' => 'CRM_Core_DAO_Address',
-        'name' => 'civicrm_address',
-        'alias' => $options['prefix'] . 'civicrm_address',
-        'fields' => [
-          $options['prefix'] . 'name' => [
-            'title' => ts($options['prefix_label'] . 'Address Name'),
-            'default' => CRM_Utils_Array::value('name', $options['defaults'], FALSE),
-            'name' => 'name',
-          ],
-          $options['prefix'] . 'street_address' => [
-            'title' => ts($options['prefix_label'] . 'Street Address'),
-            'default' => CRM_Utils_Array::value('street_address', $options['defaults'], FALSE),
-            'name' => 'street_address',
-          ],
-          $options['prefix'] . 'supplemental_address_1' => [
-            'title' => ts($options['prefix_label'] .
-              'Supplementary Address Field 1'),
-            'default' => CRM_Utils_Array::value('supplemental_address_1', $options['defaults'], FALSE),
-            'name' => 'supplemental_address_1',
-          ],
-          $options['prefix'] . 'supplemental_address_2' => [
-            'title' => ts($options['prefix_label'] .
-              'Supplementary Address Field 2'),
-            'default' => CRM_Utils_Array::value('supplemental_address_2', $options['defaults'], FALSE),
-            'name' => 'supplemental_address_2',
-          ],
-          $options['prefix'] . 'supplemental_address_3' => [
-            'title' => ts($options['prefix_label'] .
-              'Supplementary Address Field 3'),
-            'default' => CRM_Utils_Array::value('supplemental_address_3', $options['defaults'], FALSE),
-            'name' => 'supplemental_address_3',
-          ],
-          $options['prefix'] . 'street_number' => [
-            'name' => 'street_number',
-            'title' => ts($options['prefix_label'] . 'Street Number'),
-            'type' => 1,
-            'default' => CRM_Utils_Array::value('street_number', $options['defaults'], FALSE),
-          ],
-          $options['prefix'] . 'street_name' => [
-            'name' => 'street_name',
-            'title' => ts($options['prefix_label'] . 'Street Name'),
-            'type' => 1,
-            'default' => CRM_Utils_Array::value('street_name', $options['defaults'], FALSE),
-          ],
-          $options['prefix'] . 'street_unit' => [
-            'name' => 'street_unit',
-            'title' => ts($options['prefix_label'] . 'Street Unit'),
-            'type' => 1,
-            'default' => CRM_Utils_Array::value('street_unit', $options['defaults'], FALSE),
-          ],
-          $options['prefix'] . 'city' => [
-            'title' => ts($options['prefix_label'] . 'City'),
-            'default' => CRM_Utils_Array::value('city', $options['defaults'], FALSE),
-            'name' => 'city',
-          ],
-          $options['prefix'] . 'postal_code' => [
-            'title' => ts($options['prefix_label'] . 'Postal Code'),
-            'default' => CRM_Utils_Array::value('postal_code', $options['defaults'], FALSE),
-            'name' => 'postal_code',
-          ],
-          $options['prefix'] . 'county_id' => [
-            'title' => ts($options['prefix_label'] . 'County'),
-            'default' => CRM_Utils_Array::value('county_id', $options['defaults'], FALSE),
-            'alter_display' => 'alterCountyID',
-            'name' => 'county_id',
-          ],
-          $options['prefix'] . 'state_province_id' => [
-            'title' => ts($options['prefix_label'] . 'State/Province'),
-            'default' => CRM_Utils_Array::value('state_province_id', $options['defaults'], FALSE),
-            'alter_display' => 'alterStateProvinceID',
-            'name' => 'state_province_id',
-          ],
-          $options['prefix'] . 'country_id' => [
-            'title' => ts($options['prefix_label'] . 'Country'),
-            'default' => CRM_Utils_Array::value('country_id', $options['defaults'], FALSE),
-            'alter_display' => 'alterCountryID',
-            'name' => 'country_id',
-          ],
-        ],
-        'grouping' => 'location-fields',
-      ],
-    ];
-
-    if ($options['filters']) {
-      $addressFields[$options['prefix'] . 'civicrm_address']['filters'] = [
-        $options['prefix'] . 'street_number' => [
-          'title' => ts($options['prefix_label'] . 'Street Number'),
-          'type' => 1,
-          'name' => 'street_number',
-        ],
-        $options['prefix'] . 'street_name' => [
-          'title' => ts($options['prefix_label'] . 'Street Name'),
-          'name' => $options['prefix'] . 'street_name',
-          'operator' => 'like',
-        ],
-        $options['prefix'] . 'postal_code' => [
-          'title' => ts($options['prefix_label'] . 'Postal Code'),
-          'type' => 1,
-          'name' => 'postal_code',
-        ],
-        $options['prefix'] . 'city' => [
-          'title' => ts($options['prefix_label'] . 'City'),
-          'operator' => 'like',
-          'name' => 'city',
-        ],
-        $options['prefix'] . 'county_id' => [
-          'name' => 'county_id',
-          'title' => ts($options['prefix_label'] . 'County'),
-          'type' => CRM_Utils_Type::T_INT,
-          'operatorType' => CRM_Report_Form::OP_MULTISELECT,
-          'options' => CRM_Core_PseudoConstant::county(),
-        ],
-        $options['prefix'] . 'state_province_id' => [
-          'name' => 'state_province_id',
-          'title' => ts($options['prefix_label'] . 'State/Province'),
-          'type' => CRM_Utils_Type::T_INT,
-          'operatorType' => CRM_Report_Form::OP_MULTISELECT,
-          'options' => CRM_Core_PseudoConstant::stateProvince(),
-        ],
-        $options['prefix'] . 'country_id' => [
-          'name' => 'country_id',
-          'title' => ts($options['prefix_label'] . 'Country'),
-          'type' => CRM_Utils_Type::T_INT,
-          'operatorType' => CRM_Report_Form::OP_MULTISELECT,
-          'options' => CRM_Core_PseudoConstant::country(),
-        ],
-      ];
-    }
-
-    if ($options['order_by']) {
-      $addressFields[$options['prefix'] .
-      'civicrm_address']['order_bys'] = [
-        $options['prefix'] . 'street_name' => [
-          'title' => ts($options['prefix_label'] . 'Street Name'),
-          'name' => 'street_name',
-        ],
-        $options['prefix'] . 'street_number' => [
-          'title' => ts($options['prefix_label'] . 'Odd / Even Street Number'),
-          'name' => 'street_number',
-        ],
-        $options['prefix'] . 'street_address' => [
-          'title' => ts($options['prefix_label'] . 'Street Address'),
-          'name' => 'street_address',
-        ],
-        $options['prefix'] . 'city' => [
-          'title' => ts($options['prefix_label'] . 'City'),
-          'name' => 'city',
-        ],
-        $options['prefix'] . 'postal_code' => [
-          'title' => ts($options['prefix_label'] . 'Post Code'),
-          'name' => 'postal_code',
-        ],
-      ];
-    }
-
-    if ($options['group_by']) {
-      $addressFields['civicrm_address']['group_bys'] = [
-        $options['prefix'] . 'street_address' => [
-          'title' => ts($options['prefix_label'] . 'Street Address'),
-          'name' => 'street_address',
-        ],
-        $options['prefix'] . 'city' => [
-          'title' => ts($options['prefix_label'] . 'City'),
-          'name' => 'city',
-        ],
-        $options['prefix'] . 'postal_code' => [
-          'title' => ts($options['prefix_label'] . 'Post Code'),
-          'name' => 'postal_code',
-        ],
-        $options['prefix'] . 'state_province_id' => [
-          'title' => ts($options['prefix_label'] . 'State/Province'),
-          'name' => 'state_province_id',
-        ],
-        $options['prefix'] . 'country_id' => [
-          'title' => ts($options['prefix_label'] . 'Country'),
-          'name' => 'country_id',
-        ],
-        $options['prefix'] . 'county_id' => [
-          'title' => ts($options['prefix_label'] . 'County'),
-          'name' => 'county_id',
-        ],
-      ];
-    }
-    return $addressFields;
-  }
-
-  /**
-   * Get Information about advertised Joins.
-   *
-   * @return array
-   */
-  public function getAvailableJoins() {
-    return [
-      'priceFieldValue_from_lineItem' => [
-        'leftTable' => 'civicrm_line_item',
-        'rightTable' => 'civicrm_price_field_value',
-        'callback' => 'joinPriceFieldValueFromLineItem',
-      ],
-      'priceField_from_lineItem' => [
-        'leftTable' => 'civicrm_line_item',
-        'rightTable' => 'civicrm_price_field',
-        'callback' => 'joinPriceFieldFromLineItem',
-      ],
-      'participant_from_lineItem' => [
-        'leftTable' => 'civicrm_line_item',
-        'rightTable' => 'civicrm_participant',
-        'callback' => 'joinParticipantFromLineItem',
-      ],
-      'contribution_from_lineItem' => [
-        'leftTable' => 'civicrm_line_item',
-        'rightTable' => 'civicrm_contribution',
-        'callback' => 'joinContributionFromLineItem',
-      ],
-      'membership_from_lineItem' => [
-        'leftTable' => 'civicrm_line_item',
-        'rightTable' => 'civicrm_membership',
-        'callback' => 'joinMembershipFromLineItem',
-      ],
-      'contribution_from_participant' => [
-        'leftTable' => 'civicrm_participant',
-        'rightTable' => 'civicrm_contribution',
-        'callback' => 'joinContributionFromParticipant',
-      ],
-      'contribution_from_membership' => [
-        'leftTable' => 'civicrm_membership',
-        'rightTable' => 'civicrm_contribution',
-        'callback' => 'joinContributionFromMembership',
-      ],
-      'membership_from_contribution' => [
-        'leftTable' => 'civicrm_contribution',
-        'rightTable' => 'civicrm_membership',
-        'callback' => 'joinMembershipFromContribution',
-      ],
-      'membershipType_from_membership' => [
-        'leftTable' => 'civicrm_membership',
-        'rightTable' => 'civicrm_membership_type',
-        'callback' => 'joinMembershipTypeFromMembership',
-      ],
-      'lineItem_from_contribution' => [
-        'leftTable' => 'civicrm_contribution',
-        'rightTable' => 'civicrm_line_item',
-        'callback' => 'joinLineItemFromContribution',
-      ],
-      'lineItem_from_membership' => [
-        'leftTable' => 'civicrm_membership',
-        'rightTable' => 'civicrm_line_item',
-        'callback' => 'joinLineItemFromMembership',
-      ],
-      'contact_from_participant' => [
-        'leftTable' => 'civicrm_participant',
-        'rightTable' => 'civicrm_contact',
-        'callback' => 'joinContactFromParticipant',
-      ],
-      'contact_from_membership' => [
-        'leftTable' => 'civicrm_membership',
-        'rightTable' => 'civicrm_contact',
-        'callback' => 'joinContactFromMembership',
-      ],
-      'contact_from_contribution' => [
-        'leftTable' => 'civicrm_contribution',
-        'rightTable' => 'civicrm_contact',
-        'callback' => 'joinContactFromContribution',
-      ],
-      'event_from_participant' => [
-        'leftTable' => 'civicrm_participant',
-        'rightTable' => 'civicrm_event',
-        'callback' => 'joinEventFromParticipant',
-      ],
-      'address_from_contact' => [
-        'leftTable' => 'civicrm_contact',
-        'rightTable' => 'civicrm_address',
-        'callback' => 'joinAddressFromContact',
-      ],
-    ];
-  }
-
-  /**
-   * Add join from contact table to address. Prefix will be added to both tables
-   * as it's assumed you are using it to get address of a secondary contact
-   *
-   * @param string $prefix
-   */
-  public function joinAddressFromContact($prefix = '') {
-    $this->_from .= " LEFT JOIN civicrm_address {$this->_aliases[$prefix .
-    'civicrm_address']}
-      ON {$this->_aliases[$prefix .
-    'civicrm_address']}.contact_id = {$this->_aliases[$prefix .
-    'civicrm_contact']}.id";
-  }
-
-  public function joinPriceFieldValueFromLineItem() {
-    $this->_from .= " LEFT JOIN civicrm_price_field_value {$this->_aliases['civicrm_price_field_value']}
-                          ON {$this->_aliases['civicrm_line_item']}.price_field_value_id = {$this->_aliases['civicrm_price_field_value']}.id";
-  }
-
-  public function joinPriceFieldFromLineItem() {
-    $this->_from .= "
-       LEFT JOIN civicrm_price_field {$this->_aliases['civicrm_price_field']}
-      ON {$this->_aliases['civicrm_line_item']}.price_field_id = {$this->_aliases['civicrm_price_field']}.id
-     ";
-  }
-
-  /**
-   * Define join from line item table to participant table.
-   */
-  public function joinParticipantFromLineItem() {
-    $this->_from .= " LEFT JOIN civicrm_participant {$this->_aliases['civicrm_participant']}
-      ON ( {$this->_aliases['civicrm_line_item']}.entity_id = {$this->_aliases['civicrm_participant']}.id
-      AND {$this->_aliases['civicrm_line_item']}.entity_table = 'civicrm_participant')
-    ";
-  }
-
-  /**
-   * Define join from line item table to Membership table. Seems to be still via contribution
-   * as the entity. Have made 'inner' to restrict does that make sense?
-   */
-  public function joinMembershipFromLineItem() {
-    $this->_from .= " INNER JOIN civicrm_contribution {$this->_aliases['civicrm_contribution']}
-      ON ( {$this->_aliases['civicrm_line_item']}.entity_id = {$this->_aliases['civicrm_contribution']}.id
-      AND {$this->_aliases['civicrm_line_item']}.entity_table = 'civicrm_contribution')
-      LEFT JOIN civicrm_membership_payment pp
-      ON {$this->_aliases['civicrm_contribution']}.id = pp.contribution_id
-      LEFT JOIN civicrm_membership {$this->_aliases['civicrm_membership']}
-      ON pp.membership_id = {$this->_aliases['civicrm_membership']}.id
-    ";
-  }
-
-  /**
-   * Define join from Participant to Contribution table.
-   */
-  public function joinContributionFromParticipant() {
-    $this->_from .= " LEFT JOIN civicrm_participant_payment pp
-        ON {$this->_aliases['civicrm_participant']}.id = pp.participant_id
-        LEFT JOIN civicrm_contribution {$this->_aliases['civicrm_contribution']}
-        ON pp.contribution_id = {$this->_aliases['civicrm_contribution']}.id
-      ";
-  }
-
-  /**
-   * Define join from Membership to Contribution table.
-   */
-  public function joinContributionFromMembership() {
-    $this->_from .= " LEFT JOIN civicrm_membership_payment pp
-        ON {$this->_aliases['civicrm_membership']}.id = pp.membership_id
-        LEFT JOIN civicrm_contribution {$this->_aliases['civicrm_contribution']}
-        ON pp.contribution_id = {$this->_aliases['civicrm_contribution']}.id
-      ";
-  }
-
-  public function joinParticipantFromContribution() {
-    $this->_from .= " LEFT JOIN civicrm_participant_payment pp
-                          ON {$this->_aliases['civicrm_contribution']}.id = pp.contribution_id
-        LEFT JOIN civicrm_participant {$this->_aliases['civicrm_participant']}
-                          ON pp.participant_id = {$this->_aliases['civicrm_participant']}.id";
-  }
-
-  public function joinMembershipFromContribution() {
-    $this->_from .= "
-       LEFT JOIN civicrm_membership_payment pp
-      ON {$this->_aliases['civicrm_contribution']}.id = pp.contribution_id
-      LEFT JOIN civicrm_membership {$this->_aliases['civicrm_membership']}
-      ON pp.membership_id = {$this->_aliases['civicrm_membership']}.id";
-  }
-
-  public function joinMembershipTypeFromMembership() {
-    $this->_from .= "
-       LEFT JOIN civicrm_membership_type {$this->_aliases['civicrm_membership_type']}
-      ON {$this->_aliases['civicrm_membership']}.membership_type_id = {$this->_aliases['civicrm_membership_type']}.id
-      ";
-  }
-
-  public function joinContributionFromLineItem() {
-
-    // this can be stored as a temp table & indexed for more speed. Not done at this state.
-    // another option is to cache it but I haven't tried to put that code in yet (have used it before for one hour caching
-    $this->_from .= "  LEFT JOIN (SELECT line_item_civireport.id as lid, contribution_civireport_direct.*
-FROM civicrm_line_item line_item_civireport
-LEFT JOIN civicrm_contribution contribution_civireport_direct
-                       ON (line_item_civireport.line_total > 0 AND line_item_civireport.entity_id = contribution_civireport_direct.id AND line_item_civireport.entity_table = 'civicrm_contribution')
-
-
-WHERE  contribution_civireport_direct.id IS NOT NULL
-
-UNION SELECT line_item_civireport.id as lid, contribution_civireport.*
-  FROM civicrm_line_item line_item_civireport
-  LEFT JOIN civicrm_participant participant_civireport
-                          ON (line_item_civireport.line_total > 0 AND line_item_civireport.entity_id = participant_civireport.id AND line_item_civireport.entity_table = 'civicrm_participant')
-
-LEFT JOIN civicrm_participant_payment pp
-                          ON participant_civireport.id = pp.participant_id
-        LEFT JOIN civicrm_contribution contribution_civireport
-                          ON pp.contribution_id = contribution_civireport.id
-
-UNION SELECT line_item_civireport.id as lid,contribution_civireport.*
-  FROM civicrm_line_item line_item_civireport
-  LEFT JOIN civicrm_membership membership_civireport
-                          ON (line_item_civireport.line_total > 0 AND line_item_civireport.entity_id =membership_civireport.id AND line_item_civireport.entity_table = 'civicrm_membership')
-
-LEFT JOIN civicrm_membership_payment pp
-                          ON membership_civireport.id = pp.membership_id
-        LEFT JOIN civicrm_contribution contribution_civireport
-                          ON pp.contribution_id = contribution_civireport.id
-) as {$this->_aliases['civicrm_contribution']}
-  ON {$this->_aliases['civicrm_contribution']}.lid = {$this->_aliases['civicrm_line_item']}.id
- ";
-  }
-
-  public function joinLineItemFromContribution() {
-
-    // this can be stored as a temp table & indexed for more speed. Not done at this stage.
-    // another option is to cache it but I haven't tried to put that code in yet (have used it before for one hour caching
-    $this->_from .= "
-       LEFT JOIN (
-SELECT contribution_civireport_direct.id AS contid, line_item_civireport.*
-FROM civicrm_contribution contribution_civireport_direct
-LEFT JOIN civicrm_line_item line_item_civireport ON (line_item_civireport.line_total > 0 AND line_item_civireport.entity_id = contribution_civireport_direct.id AND line_item_civireport.entity_table = 'civicrm_contribution')
-WHERE line_item_civireport.id IS NOT NULL
-
-UNION
-SELECT contribution_civireport_direct.id AS contid, line_item_civireport.*
-FROM civicrm_contribution contribution_civireport_direct
-LEFT JOIN civicrm_participant_payment pp ON contribution_civireport_direct.id = pp.contribution_id
-LEFT JOIN civicrm_participant p ON pp.participant_id = p.id
-LEFT JOIN civicrm_line_item line_item_civireport ON (line_item_civireport.line_total > 0 AND line_item_civireport.entity_id = p.id AND line_item_civireport.entity_table = 'civicrm_participant')
-WHERE line_item_civireport.id IS NOT NULL
-
-UNION
-
-SELECT contribution_civireport_direct.id AS contid, line_item_civireport.*
-FROM civicrm_contribution contribution_civireport_direct
-LEFT JOIN civicrm_membership_payment pp ON contribution_civireport_direct.id = pp.contribution_id
-LEFT JOIN civicrm_membership p ON pp.membership_id = p.id
-LEFT JOIN civicrm_line_item line_item_civireport ON (line_item_civireport.line_total > 0 AND line_item_civireport.entity_id = p.id AND line_item_civireport.entity_table = 'civicrm_membership')
-WHERE   line_item_civireport.id IS NOT NULL
-) as {$this->_aliases['civicrm_line_item']}
-  ON {$this->_aliases['civicrm_line_item']}.contid = {$this->_aliases['civicrm_contribution']}.id
-
-
-  ";
-  }
-
-  public function joinLineItemFromMembership() {
-
-    // this can be stored as a temp table & indexed for more speed. Not done at this stage.
-    // another option is to cache it but I haven't tried to put that code in yet (have used it before for one hour caching
-    $this->_from .= "
-       LEFT JOIN (
-SELECT contribution_civireport_direct.id AS contid, line_item_civireport.*
-FROM civicrm_contribution contribution_civireport_direct
-LEFT JOIN civicrm_line_item line_item_civireport
-ON (line_item_civireport.line_total > 0 AND line_item_civireport.entity_id = contribution_civireport_direct.id AND line_item_civireport.entity_table = 'civicrm_contribution')
-
-WHERE   line_item_civireport.id IS NOT NULL
-
-UNION
-
-SELECT contribution_civireport_direct.id AS contid, line_item_civireport.*
-FROM civicrm_contribution contribution_civireport_direct
-LEFT JOIN civicrm_membership_payment pp ON contribution_civireport_direct.id = pp.contribution_id
-LEFT JOIN civicrm_membership p ON pp.membership_id = p.id
-LEFT JOIN civicrm_line_item line_item_civireport ON (line_item_civireport.line_total > 0 AND line_item_civireport.entity_id = p.id AND line_item_civireport.entity_table = 'civicrm_membership')
-WHERE   line_item_civireport.id IS NOT NULL
-) as {$this->_aliases['civicrm_line_item']}
-  ON {$this->_aliases['civicrm_line_item']}.contid = {$this->_aliases['civicrm_contribution']}.id
-  ";
-  }
-
-  public function joinContactFromParticipant() {
-    $this->_from .= " LEFT JOIN civicrm_contact {$this->_aliases['civicrm_contact']}
-                          ON {$this->_aliases['civicrm_participant']}.contact_id = {$this->_aliases['civicrm_contact']}.id";
-  }
-
-  public function joinContactFromMembership() {
-    $this->_from .= " LEFT JOIN civicrm_contact {$this->_aliases['civicrm_contact']}
-                          ON {$this->_aliases['civicrm_membership']}.contact_id = {$this->_aliases['civicrm_contact']}.id";
-  }
-
-  public function joinContactFromContribution() {
-    $this->_from .= " LEFT JOIN civicrm_contact {$this->_aliases['civicrm_contact']}
-                          ON {$this->_aliases['civicrm_contribution']}.contact_id = {$this->_aliases['civicrm_contact']}.id";
-  }
-
-  public function joinEventFromParticipant() {
-    $this->_from .= "  LEFT JOIN civicrm_event {$this->_aliases['civicrm_event']}
-                    ON ({$this->_aliases['civicrm_event']}.id = {$this->_aliases['civicrm_participant']}.event_id ) AND
-                       ({$this->_aliases['civicrm_event']}.is_template IS NULL OR
-                        {$this->_aliases['civicrm_event']}.is_template = 0)";
-  }
-
-  /**
-   * Retrieve text for financial type from pseudoconstant.
-   *
-   * @param $value
-   * @param array $row
-   *
-   * @return string
-   */
-  public function alterNickName($value, &$row) {
-    if (empty($row['civicrm_contact_id'])) {
-      return NULL;
-    }
-    $contactID = $row['civicrm_contact_id'];
-    return "<div id=contact-{$contactID} class='crm-entity'>
-           <span class='crm-editable crmf-nick_name crm-editable-enabled'>
-           " . $value . "</span></div>";
-  }
-
-  /**
-   * Retrieve text for contribution type from pseudoconstant.
-   *
-   * @param $value
-   * @param array $row
-   *
-   * @return array|string
-   */
-  public function alterContributionType($value, &$row) {
-    return is_string(CRM_Contribute_PseudoConstant::financialType($value, FALSE)) ? CRM_Contribute_PseudoConstant::financialType($value, FALSE) : '';
-  }
-
-  /**
-   * Retrieve text for contribution status from pseudoconstant.
-   *
-   * @param $value
-   * @param array $row
-   *
-   * @return array
-   */
-  public function alterContributionStatus($value, &$row) {
-    return CRM_Contribute_PseudoConstant::contributionStatus($value);
-  }
-
-  /**
-   * Retrieve text for payment instrument from pseudoconstant.
-   *
-   * @param $value
-   * @param array $row
-   *
-   * @return array
-   */
-  public function alterEventType($value, &$row) {
-    return CRM_Event_PseudoConstant::eventType($value);
-  }
-
-  /**
-   * @param $value
-   * @param array $row
-   *
-   * @return array|string
-   */
-  public function alterEventID($value, &$row) {
-    return is_string(CRM_Event_PseudoConstant::event($value, FALSE)) ? CRM_Event_PseudoConstant::event($value, FALSE) : '';
-  }
-
-  /**
-   * @param $value
-   * @param array $row
-   *
-   * @return array|string
-   */
-  public function alterMembershipTypeID($value, &$row) {
-    return is_string(CRM_Member_PseudoConstant::membershipType($value, FALSE)) ? CRM_Member_PseudoConstant::membershipType($value, FALSE) : '';
-  }
-
-  /**
-   * @param $value
-   * @param array $row
-   *
-   * @return array|string
-   */
-  public function alterMembershipStatusID($value, &$row) {
-    return is_string(CRM_Member_PseudoConstant::membershipStatus($value, FALSE)) ? CRM_Member_PseudoConstant::membershipStatus($value, FALSE) : '';
-  }
-
-  /**
-   * @param $value
-   * @param array $row
-   * @param $selectedfield
-   * @param string $criteriaFieldName
-   *
-   * @return array
-   */
-  public function alterCountryID($value, &$row, $selectedfield, $criteriaFieldName) {
-    $url = CRM_Utils_System::url(CRM_Utils_System::currentPath(), "reset=1&force=1&{$criteriaFieldName}_op=in&{$criteriaFieldName}_value={$value}", $this->_absoluteUrl);
-    $row[$selectedfield . '_link'] = $url;
-    $row[$selectedfield .
-    '_hover'] = ts("%1 for this country.", [1 => $value]);
-    $countries = CRM_Core_PseudoConstant::country($value, FALSE);
-    if (!is_array($countries)) {
-      return $countries;
-    }
-  }
-
-  /**
-   * @param $value
-   * @param array $row
-   * @param $selectedfield
-   * @param string $criteriaFieldName
-   *
-   * @return array
-   */
-  public function alterCountyID($value, &$row, $selectedfield, $criteriaFieldName) {
-    $url = CRM_Utils_System::url(CRM_Utils_System::currentPath(), "reset=1&force=1&{$criteriaFieldName}_op=in&{$criteriaFieldName}_value={$value}", $this->_absoluteUrl);
-    $row[$selectedfield . '_link'] = $url;
-    $row[$selectedfield .
-    '_hover'] = ts("%1 for this county.", [1 => $value]);
-    $counties = CRM_Core_PseudoConstant::county($value, FALSE);
-    if (!is_array($counties)) {
-      return $counties;
-    }
-  }
-
-  /**
-   * @param $value
-   * @param array $row
-   * @param $selectedfield
-   * @param string $criteriaFieldName
-   *
-   * @return array
-   */
-  public function alterStateProvinceID($value, &$row, $selectedfield, $criteriaFieldName) {
-    $url = CRM_Utils_System::url(CRM_Utils_System::currentPath(), "reset=1&force=1&{$criteriaFieldName}_op=in&{$criteriaFieldName}_value={$value}", $this->_absoluteUrl);
-    $row[$selectedfield . '_link'] = $url;
-    $row[$selectedfield .
-    '_hover'] = ts("%1 for this state.", [1 => $value]);
-
-    $states = CRM_Core_PseudoConstant::stateProvince($value, FALSE);
-    if (!is_array($states)) {
-      return $states;
-    }
-  }
-
-  /**
-   * @param $value
-   * @param array $row
-   * @param string $fieldname
-   *
-   * @return mixed
-   */
-  public function alterContactID($value, &$row, $fieldname) {
-    $row[$fieldname . '_link'] = CRM_Utils_System::url("civicrm/contact/view",
-      'reset=1&cid=' . $value, $this->_absoluteUrl);
-    return $value;
-  }
-
-  /**
-   * @param $value
-   *
-   * @return array
-   */
-  public function alterParticipantStatus($value) {
-    if (empty($value)) {
-      return NULL;
-    }
-    return CRM_Event_PseudoConstant::participantStatus($value, FALSE, 'label');
-  }
-
-  /**
-   * @param $value
-   *
-   * @return string|void
-   */
-  public function alterParticipantRole($value) {
-    if (empty($value)) {
-      return NULL;
-    }
-    $roles = explode(CRM_Core_DAO::VALUE_SEPARATOR, $value);
-    $value = [];
-    foreach ($roles as $role) {
-      $value[$role] = CRM_Event_PseudoConstant::participantRole($role, FALSE);
-    }
-    return implode(', ', $value);
-  }
-
-  /**
-   * @param $value
-   *
-   * @return mixed
-   */
-  public function alterPaymentType($value) {
-    $paymentInstruments = CRM_Contribute_PseudoConstant::paymentInstrument();
-    return $paymentInstruments[$value];
-  }
-
-}
index 1ee17e37e8568bc7c8df863d7f0e2708831aa0e6..c787ca4ac2cd683ad702db5f2bf98948f5f4a328 100644 (file)
@@ -156,12 +156,12 @@ class CRM_Upgrade_Incremental_Base {
     $domain = new CRM_Core_DAO_Domain();
     $domain->find(TRUE);
     $queries = [];
-    if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists($table, $column)) {
+    if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists($table, $column, FALSE)) {
       if ($domain->locales) {
         if ($localizable) {
           $locales = explode(CRM_Core_DAO::VALUE_SEPARATOR, $domain->locales);
           foreach ($locales as $locale) {
-            if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists($table, "{$column}_{$locale}")) {
+            if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists($table, "{$column}_{$locale}", FALSE)) {
               $queries[] = "ALTER TABLE `$table` ADD COLUMN `{$column}_{$locale}` $properties";
             }
           }
diff --git a/CRM/Upgrade/Incremental/php/FiveFifteen.php b/CRM/Upgrade/Incremental/php/FiveFifteen.php
new file mode 100644 (file)
index 0000000..39f1b1b
--- /dev/null
@@ -0,0 +1,87 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 5                                                  |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2019                                |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM.                                    |
+ |                                                                    |
+ | CiviCRM is free software; you can copy, modify, and distribute it  |
+ | under the terms of the GNU Affero General Public License           |
+ | Version 3, 19 November 2007.                                       |
+ |                                                                    |
+ | CiviCRM is distributed in the hope that it will be useful, but     |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of         |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
+ | See the GNU Affero General Public License for more details.        |
+ |                                                                    |
+ | You should have received a copy of the GNU Affero General Public   |
+ | License along with this program; if not, contact CiviCRM LLC       |
+ | at info[AT]civicrm[DOT]org. If you have questions about the        |
+ | GNU Affero General Public License or the licensing of CiviCRM,     |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ * Upgrade logic for FiveFifteen */
+class CRM_Upgrade_Incremental_php_FiveFifteen extends CRM_Upgrade_Incremental_Base {
+
+  /**
+   * Compute any messages which should be displayed beforeupgrade.
+   *
+   * Note: This function is called iteratively for each upcoming
+   * revision to the database.
+   *
+   * @param string $preUpgradeMessage
+   * @param string $rev
+   *   a version number, e.g. '4.4.alpha1', '4.4.beta3', '4.4.0'.
+   * @param null $currentVer
+   */
+  public function setPreUpgradeMessage(&$preUpgradeMessage, $rev, $currentVer = NULL) {
+    // Example: Generate a pre-upgrade message.
+    // if ($rev == '5.12.34') {
+    //   $preUpgradeMessage .= '<p>' . ts('A new permission, "%1", has been added. This permission is now used to control access to the Manage Tags screen.', array(1 => ts('manage tags'))) . '</p>';
+    // }
+  }
+
+  /**
+   * Compute any messages which should be displayed after upgrade.
+   *
+   * @param string $postUpgradeMessage
+   *   alterable.
+   * @param string $rev
+   *   an intermediate version; note that setPostUpgradeMessage is called repeatedly with different $revs.
+   */
+  public function setPostUpgradeMessage(&$postUpgradeMessage, $rev) {
+    // Example: Generate a post-upgrade message.
+    // if ($rev == '5.12.34') {
+    //   $postUpgradeMessage .= '<br /><br />' . ts("By default, CiviCRM now disables the ability to import directly from SQL. To use this feature, you must explicitly grant permission 'import SQL datasource'.");
+    // }
+  }
+
+  /*
+   * Important! All upgrade functions MUST add a 'runSql' task.
+   * Uncomment and use the following template for a new upgrade version
+   * (change the x in the function name):
+   */
+
+  //  /**
+  //   * Upgrade function.
+  //   *
+  //   * @param string $rev
+  //   */
+  //  public function upgrade_5_0_x($rev) {
+  //    $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
+  //    $this->addTask('Do the foo change', 'taskFoo', ...);
+  //    // Additional tasks here...
+  //    // Note: do not use ts() in the addTask description because it adds unnecessary strings to transifex.
+  //    // The above is an exception because 'Upgrade DB to %1: SQL' is generic & reusable.
+  //  }
+
+  // public static function taskFoo(CRM_Queue_TaskContext $ctx, ...) {
+  //   return TRUE;
+  // }
+
+}
index ad58a8a853ced0039ad7942ef70acc4ceca65230..97bca1d3700aec8132c7f742f793d529e6ac5135 100644 (file)
@@ -67,21 +67,40 @@ class CRM_Upgrade_Incremental_php_FiveFourteen extends CRM_Upgrade_Incremental_B
    * (change the x in the function name):
    */
 
-  //  /**
-  //   * Upgrade function.
-  //   *
-  //   * @param string $rev
-  //   */
-  //  public function upgrade_5_0_x($rev) {
-  //    $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
-  //    $this->addTask('Do the foo change', 'taskFoo', ...);
-  //    // Additional tasks here...
-  //    // Note: do not use ts() in the addTask description because it adds unnecessary strings to transifex.
-  //    // The above is an exception because 'Upgrade DB to %1: SQL' is generic & reusable.
-  //  }
+  /**
+   * Upgrade function.
+   *
+   * @param string $rev
+   */
+  public function upgrade_5_14_alpha1($rev) {
+    $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
+
+    // Only need to rebuild view if CiviCase is enabled: otherwise will be
+    // rebuilt when component is enabled
+    $config = CRM_Core_Config::singleton();
+    if (in_array('CiviCase', $config->enableComponents)) {
+      $this->addTask('Rebuild case activity views', 'rebuildCaseActivityView', $rev);
+    }
+    // Additional tasks here...
+    // Note: do not use ts() in the addTask description because it adds unnecessary strings to transifex.
+    // The above is an exception because 'Upgrade DB to %1: SQL' is generic & reusable.
+  }
 
-  // public static function taskFoo(CRM_Queue_TaskContext $ctx, ...) {
-  //   return TRUE;
-  // }
+  /**
+   * Rebuild the view of recent and upcoming case activities
+   *
+   * See https://github.com/civicrm/civicrm-core/pull/14086 and
+   * https://lab.civicrm.org/dev/core/issues/832
+   *
+   * @param CRM_Queue_TaskContext $ctx
+   * @return bool
+   */
+  public static function rebuildCaseActivityView($ctx) {
+    if (!CRM_Case_BAO_Case::createCaseViews()) {
+      CRM_Core_Error::debug_log_message(ts("Could not create the MySQL views for CiviCase. Your mysql user needs to have the 'CREATE VIEW' permission"));
+      return FALSE;
+    }
+    return TRUE;
+  }
 
 }
diff --git a/CRM/Upgrade/Incremental/sql/5.14.beta1.mysql.tpl b/CRM/Upgrade/Incremental/sql/5.14.beta1.mysql.tpl
new file mode 100644 (file)
index 0000000..2e796c9
--- /dev/null
@@ -0,0 +1 @@
+{* file to handle db changes in 5.14.beta1 during upgrade *}
diff --git a/CRM/Upgrade/Incremental/sql/5.15.alpha1.mysql.tpl b/CRM/Upgrade/Incremental/sql/5.15.alpha1.mysql.tpl
new file mode 100644 (file)
index 0000000..8832251
--- /dev/null
@@ -0,0 +1 @@
+{* file to handle db changes in 5.15.alpha1 during upgrade *}
index b641a6b8849022d3494a660462e0c4404fd514ea..d8a435d004ab51c476bedf692a323a2e321fc8fa 100644 (file)
@@ -35,8 +35,8 @@ class CRM_Utils_Check_Component_FinancialTypeAcls extends CRM_Utils_Check_Compon
   public static function checkFinancialAclReport() {
     $messages = [];
     $ftAclSetting = Civi::settings()->get('acl_financial_type');
-    $financialAclExtension = civicrm_api3('extension', 'get', ['key' => 'biz.jmaconsulting.financialaclreport']);
-    if ($ftAclSetting && (($financialAclExtension['count'] == 1 && $financialAclExtension['status'] != 'Installed') || $financialAclExtension['count'] !== 1)) {
+    $financialAclExtension = civicrm_api3('extension', 'get', ['key' => 'biz.jmaconsulting.financialaclreport', 'sequential' => 1]);
+    if ($ftAclSetting && (($financialAclExtension['count'] == 1 && $financialAclExtension['values'][0]['status'] != 'Installed') || $financialAclExtension['count'] !== 1)) {
       $messages[] = new CRM_Utils_Check_Message(
         __FUNCTION__,
         ts('CiviCRM will in the future require the extension %1 for CiviCRM Reports to work correctly with the Financial Type ACLs. The extension can be downloaded <a href="%2">here</a>', [
index a47f3076d7f7fb8b10009033570498125f853c82..9a48148b9f1b81f42013f887814da337e4e1c893 100644 (file)
@@ -2217,6 +2217,24 @@ abstract class CRM_Utils_Hook {
     Civi::dispatcher()->dispatch('hook_civicrm_alterAngular', $event);
   }
 
+  /**
+   * This hook is called when building a link to a semi-static asset.
+   *
+   * @param string $asset
+   *   The name of the asset.
+   *   Ex: 'angular.json'
+   * @param array $params
+   *   List of optional arguments which influence the content.
+   * @return null
+   *   the return value is ignored
+   */
+  public static function getAssetUrl(&$asset, &$params) {
+    return self::singleton()->invoke(['asset', 'params'],
+      $asset, $params, self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject,
+      'civicrm_getAssetUrl'
+    );
+  }
+
   /**
    * This hook is called whenever the system builds a new copy of
    * semi-static asset.
@@ -2386,9 +2404,6 @@ abstract class CRM_Utils_Hook {
    * @param string $region
    */
   public static function coreResourceList(&$list, $region) {
-    // First allow the cms integration to add to the list
-    CRM_Core_Config::singleton()->userSystem->appendCoreResources($list);
-
     self::singleton()->invoke(['list', 'region'], $list, $region,
       self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject,
       'civicrm_coreResourceList'
index 5433b17c416b14be12196782cd561306d6efb6a9..ad4cc452542ff3a811a37603ebcf41e5dbd15c04 100644 (file)
@@ -54,7 +54,7 @@
  *
  * Example 3: Create an empty temp table with list of columns.
  *
- * $tmpTbl = CRM_Utils_SQL_TempTable::build()->setDurable()->setUtf8()->createWithColumns('id int(10, name varchar(64)');
+ * $tmpTbl = CRM_Utils_SQL_TempTable::build()->setDurable()->createWithColumns('id int(10, name varchar(64)');
  *
  * Example 4: Drop a table that you previously created.
  *
@@ -105,8 +105,7 @@ class CRM_Utils_SQL_TempTable {
     $t->id = md5(uniqid('', TRUE));
     // The constant CIVICRM_TEMP_FORCE_DURABLE is for local debugging.
     $t->durable = CRM_Utils_Constant::value('CIVICRM_TEMP_FORCE_DURABLE', FALSE);
-    // @deprecated This constant is deprecated and will be removed.
-    $t->utf8 = CRM_Utils_Constant::value('CIVICRM_TEMP_FORCE_UTF8', TRUE);
+    $t->utf8 = TRUE;
     $t->autodrop = FALSE;
     $t->memory = FALSE;
     return $t;
@@ -319,7 +318,9 @@ class CRM_Utils_SQL_TempTable {
   /**
    * Set table collation to UTF8.
    *
-   * This would make sense as a default but cautiousness during phasing in has made it opt-in.
+   * @deprecated This method is deprecated as tables should be assumed to have
+   * UTF-8 as the default character set and collation; some other character set
+   * or collation may be specified in the column definition.
    *
    * @param bool $value
    *
index 0aa8fe3e67d54ed0ed5714d9cda3291d120f33e9..cdb29038368502df0ef4b20601d1cbae6ef3e136 100644 (file)
@@ -51,6 +51,8 @@
  * @method static int getLoggedInUfID() Get current logged in user id.
  * @method static setHttpHeader(string $name, string $value) Set http header.
  * @method static array synchronizeUsers() Create CRM contacts for all existing CMS users.
+ * @method static appendCoreResources(\Civi\Core\Event\GenericHookEvent $e) Callback for hook_civicrm_coreResourceList.
+ * @method static alterAssetUrl(\Civi\Core\Event\GenericHookEvent $e) Callback for hook_civicrm_getAssetUrl.
  */
 class CRM_Utils_System {
 
@@ -214,8 +216,7 @@ class CRM_Utils_System {
     $print = FALSE,
     $maintenance = FALSE
   ) {
-    $config = &CRM_Core_Config::singleton();
-    return $config->userSystem->theme($content, $print, $maintenance);
+    return CRM_Core_Config::singleton()->userSystem->theme($content, $print, $maintenance);
   }
 
   /**
@@ -1612,8 +1613,7 @@ class CRM_Utils_System {
     $addLanguagePart = TRUE,
     $removeLanguagePart = FALSE
   ) {
-    $config = &CRM_Core_Config::singleton();
-    return $config->userSystem->languageNegotiationURL($url, $addLanguagePart, $removeLanguagePart);
+    return CRM_Core_Config::singleton()->userSystem->languageNegotiationURL($url, $addLanguagePart, $removeLanguagePart);
   }
 
   /**
index 7a3589a250a6ed37f5e4fba32a78f17adf0263b4..9c22b6b86b332ba3e7008d38b945df1f89dadddd 100644 (file)
@@ -1042,11 +1042,11 @@ AND    u.status = 1
   /**
    * Append Backdrop CSS and JS to coreResourcesList.
    *
-   * @param array $list
+   * @param \Civi\Core\Event\GenericHookEvent $e
    */
-  public function appendCoreResources(&$list) {
-    $list[] = 'css/backdrop.css';
-    $list[] = 'js/crm.backdrop.js';
+  public function appendCoreResources(\Civi\Core\Event\GenericHookEvent $e) {
+    $e->list[] = 'css/backdrop.css';
+    $e->list[] = 'js/crm.backdrop.js';
   }
 
 }
index bf6830d8e49f4c77c7a18e7e675adcc3afec0e20..2d8a81ca66f2a555d2b5ee74bade14d37a102e10 100644 (file)
@@ -254,10 +254,9 @@ abstract class CRM_Utils_System_Base {
     }
     $out = $content;
 
-    $config = &CRM_Core_Config::singleton();
     if (
       !$print &&
-      $config->userFramework == 'WordPress'
+      CRM_Core_Config::singleton()->userFramework == 'WordPress'
     ) {
       if (!function_exists('is_admin')) {
         throw new \Exception('Function "is_admin()" is missing, even though WordPress is the user framework.');
@@ -914,9 +913,17 @@ abstract class CRM_Utils_System_Base {
   /**
    * Append to coreResourcesList.
    *
-   * @param array $list
+   * @param \Civi\Core\Event\GenericHookEvent $e
    */
-  public function appendCoreResources(&$list) {
+  public function appendCoreResources(\Civi\Core\Event\GenericHookEvent $e) {
+  }
+
+  /**
+   * Modify dynamic assets.
+   *
+   * @param \Civi\Core\Event\GenericHookEvent $e
+   */
+  public function alterAssetUrl(\Civi\Core\Event\GenericHookEvent $e) {
   }
 
   /**
index d34007e5478a70174d8439b8bbf5fec9c003b55c..e280a40ba76f7db806c9150250eb0b9ea299cbd4 100644 (file)
@@ -667,10 +667,10 @@ class CRM_Utils_System_Drupal8 extends CRM_Utils_System_DrupalBase {
   /**
    * Append Drupal8 js to coreResourcesList.
    *
-   * @param array $list
+   * @param \Civi\Core\Event\GenericHookEvent $e
    */
-  public function appendCoreResources(&$list) {
-    $list[] = 'js/crm.drupal8.js';
+  public function appendCoreResources(\Civi\Core\Event\GenericHookEvent $e) {
+    $e->list[] = 'js/crm.drupal8.js';
   }
 
 }
index a188cff50138da129756af4b7224843a06893aa3..a1a9c64fd3442faa8604b7f8f3f29e993cf585eb 100644 (file)
@@ -472,9 +472,6 @@ class CRM_Utils_System_WordPress extends CRM_Utils_System_Base {
 
     $name = CRM_Utils_Array::value('name', $params);
     $pass = CRM_Utils_Array::value('pass', $params);
-    if (isset($params['uid'])) {
-      throw new \RuntimeException("Not implemented WordPress::loadBootStrap([uid=>\$num]))");
-    }
 
     if (!defined('WP_USE_THEMES')) {
       define('WP_USE_THEMES', FALSE);
@@ -500,7 +497,7 @@ class CRM_Utils_System_WordPress extends CRM_Utils_System_Base {
       CRM_Core_Config::singleton()->userSystem->setMySQLTimeZone();
     }
     require_once $cmsRootPath . DIRECTORY_SEPARATOR . 'wp-includes/pluggable.php';
-    $uid = CRM_Utils_Array::value('uid', $name);
+    $uid = CRM_Utils_Array::value('uid', $params);
     if (!$uid) {
       $name = $name ? $name : trim(CRM_Utils_Array::value('name', $_REQUEST));
       $pass = $pass ? $pass : trim(CRM_Utils_Array::value('pass', $_REQUEST));
@@ -801,10 +798,20 @@ class CRM_Utils_System_WordPress extends CRM_Utils_System_Base {
   /**
    * Append WP js to coreResourcesList.
    *
-   * @param array $list
+   * @param \Civi\Core\Event\GenericHookEvent $e
    */
-  public function appendCoreResources(&$list) {
-    $list[] = 'js/crm.wordpress.js';
+  public function appendCoreResources(\Civi\Core\Event\GenericHookEvent $e) {
+    $e->list[] = 'js/crm.wordpress.js';
+  }
+
+  /**
+   * @inheritDoc
+   */
+  public function alterAssetUrl(\Civi\Core\Event\GenericHookEvent $e) {
+    // Set menubar breakpoint to match WP admin theme
+    if ($e->asset == 'crm-menubar.css') {
+      $e->params['breakpoint'] = 783;
+    }
   }
 
   /**
index b60f41e20bcc10c58c531b4d4b42767106618c9a..a53be59402aacd8783be82c73e45c79f1e3f3453 100644 (file)
@@ -125,6 +125,8 @@ class AssetBuilder {
    *   Ex: 'http://example.org/files/civicrm/dyn/angular.abcd1234abcd1234.json'.
    */
   public function getUrl($name, $params = []) {
+    \CRM_Utils_Hook::getAssetUrl($name, $params);
+
     if (!$this->isValidName($name)) {
       throw new \RuntimeException("Invalid dynamic asset name");
     }
index 201111773ad0fa6a036d7e7c91bb37fad6c5814e..9ce531d1bb776fc3ad3994afe6e9c98a2435afdf 100644 (file)
@@ -321,6 +321,8 @@ class Container {
     $dispatcher->addListener('hook_civicrm_buildAsset', ['\CRM_Utils_VisualBundle', 'buildAssetJs']);
     $dispatcher->addListener('hook_civicrm_buildAsset', ['\CRM_Utils_VisualBundle', 'buildAssetCss']);
     $dispatcher->addListener('hook_civicrm_buildAsset', ['\CRM_Core_Resources', 'renderMenubarStylesheet']);
+    $dispatcher->addListener('hook_civicrm_coreResourceList', ['\CRM_Utils_System', 'appendCoreResources']);
+    $dispatcher->addListener('hook_civicrm_getAssetUrl', ['\CRM_Utils_System', 'alterAssetUrl']);
     $dispatcher->addListener('civi.dao.postInsert', ['\CRM_Core_BAO_RecurringEntity', 'triggerInsert']);
     $dispatcher->addListener('civi.dao.postUpdate', ['\CRM_Core_BAO_RecurringEntity', 'triggerUpdate']);
     $dispatcher->addListener('civi.dao.postDelete', ['\CRM_Core_BAO_RecurringEntity', 'triggerDelete']);
index 7d8fd3821c4ecacaa2595cb6be6eb027b10b39bb..e7c9581106cbbe902167211a8b4d886d4c28ea43 100644 (file)
@@ -613,6 +613,7 @@ class Requirements {
       return $results;
     }
 
+    mysqli_query($conn, 'DROP TABLE IF EXISTS civicrm_utf8mb4_test');
     $r = mysqli_query($conn, 'CREATE TABLE civicrm_utf8mb4_test (id VARCHAR(255), PRIMARY KEY(id(255))) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC ENGINE=INNODB');
     if (!$r) {
       $results['severity'] = $this::REQUIREMENT_WARNING;
@@ -620,7 +621,7 @@ class Requirements {
       mysqli_close($conn);
       return $results;
     }
-    mysqli_query('DROP TABLE civicrm_utf8mb4_test');
+    mysqli_query($conn, 'DROP TABLE civicrm_utf8mb4_test');
 
     // Ensure that the MySQL driver supports utf8mb4 encoding.
     $version = mysqli_get_client_info($conn);
index aac6f77a391b7bef32c9b9bd2e9ffb38b2d851e7..f378f641c7f49a5c20401d69d581ded98f07dfd2 100644 (file)
           text: ts('Submit final mailing'),
           icons: {primary: 'fa-paper-plane'},
           click: function() {
-            crmMailingMgr.mergeInto(abtest.mailings.c, abtest.mailings[mailingName], [
-              'name',
-              'recipients',
-              'scheduled_date'
-            ]);
-            crmStatus({start: ts('Saving...'), success: ''}, abtest.save())
-              .then(function() {
-                return crmStatus({start: ts('Submitting...'), success: ts('Submitted')},
-                  abtest.submitFinal().then(function(r) {
-                    delete abtest.$CrmMailingABReportCnt;
-                    return r;
-                  }));
-              })
-              .then(function() {
+            crmStatus({start: ts('Submitting...'), success: ts('Submitted')},
+              abtest.submitFinal(abtest.mailings[mailingName].id).then(function (r) {
+                delete abtest.$CrmMailingABReportCnt;
+              }))
+              .then(function () {
                 dialogService.close('selectWinnerDialog', abtest);
               });
           }
index 447909c4a30d9956c6bb10c9dffd0dfe30bd767c..2e9fa9260bd0233ee78dcfe40aef114c00e51f3d 100644 (file)
       // Schedule the final mailing
       // @return Promise CrmMailingAB
       // Note: Submission may cause the server state to change. Consider abtest.submit().then(...abtest.load()...)
-      submitFinal: function submitFinal() {
+      submitFinal: function submitFinal(winner_id) {
         var crmMailingAB = this;
         var params = {
           id: this.ab.id,
           status: 'Final',
+          winner_id: winner_id,
           approval_date: 'now',
           scheduled_date: this.mailings.c.scheduled_date ? this.mailings.c.scheduled_date : 'now'
         };
index ff9ac1258c5bdb18d4644c059a356f9bd612988c..89402415080ab20af25349c347c453849845280f 100644 (file)
@@ -300,6 +300,7 @@ function _civicrm_api3_activity_get_spec(&$params) {
 function civicrm_api3_activity_get($params) {
   $options = _civicrm_api3_get_options_from_params($params, FALSE, 'Activity', 'get');
   $sql = CRM_Utils_SQL_Select::fragment();
+  _civicrm_activity_get_handleSourceContactNameOrderBy($params, $options, $sql);
 
   _civicrm_api3_activity_get_extraFilters($params, $sql);
 
@@ -336,6 +337,41 @@ function civicrm_api3_activity_get($params) {
   return civicrm_api3_create_success($activities, $params, 'Activity', 'get');
 }
 
+/**
+ * Handle source_contact_name as a sort parameter.
+ *
+ * This is passed from the activity selector - e.g search results or contact tab.
+ *
+ * It's a non-standard handling but this api already handles variations on handling source_contact
+ * as a filter & as a field so it's in keeping with that. Source contact has a one-one relationship
+ * with activity table.
+ *
+ * Test coverage in CRM_Activity_BAO_ActivtiyTest::testGetActivitiesforContactSummaryWithSortOptions
+ *
+ * @param array $params
+ * @param array $options
+ * @param CRM_Utils_SQL_Select $sql
+ */
+function _civicrm_activity_get_handleSourceContactNameOrderBy(&$params, &$options, $sql) {
+  $sourceContactID = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_ActivityContact', 'record_type_id', 'Activity Source');
+  if (!empty($options['sort']) && in_array($options['sort'], [
+      'source_contact_name',
+      'source_contact_name desc',
+      'source_contact_name asc'
+    ])) {
+    $order = substr($options['sort'], -4) === 'desc' ? 'desc' : 'asc';
+    $sql->join(
+      'source_contact',
+      "LEFT JOIN
+      civicrm_activity_contact ac ON (ac.activity_id = a.id AND record_type_id = #sourceContactID)
+       LEFT JOIN civicrm_contact c ON c.id = ac.contact_id",
+      ['sourceContactID' => $sourceContactID]
+    );
+    $sql->orderBy("c.display_name $order");
+    unset($options['sort'], $params['options']['sort']);
+  }
+}
+
 /**
  * Support filters beyond what basic_get can do.
  *
index 86139b2d2fee7f0531dba33a4ef695fac5acda6d..aec00c43d0cd076583867ea5f1645d554d42c9ec 100644 (file)
@@ -573,18 +573,26 @@ function civicrm_api3_mailing_preview($params) {
   $returnProperties = $mailing->getReturnProperties();
   $contactID = CRM_Utils_Array::value('contact_id', $params);
   if (!$contactID) {
-    $contactID = $session->get('userID');
+    // If we still don't have a userID in a session because we are annon then set contactID to be 0
+    $contactID = empty($session->get('userID')) ? 0 : $session->get('userID');
   }
   $mailingParams = ['contact_id' => $contactID];
 
-  $details = CRM_Utils_Token::getTokenDetails($mailingParams, $returnProperties, TRUE, TRUE, NULL, $mailing->getFlattenedTokens());
+  if (!$contactID) {
+    $details = CRM_Utils_Token::getAnonymousTokenDetails($mailingParams, $returnProperties, TRUE, TRUE, NULL, $mailing->getFlattenedTokens());
+    $details = CRM_Utils_Array::value(0, $details[0]);
+  }
+  else {
+    $details = CRM_Utils_Token::getTokenDetails($mailingParams, $returnProperties, TRUE, TRUE, NULL, $mailing->getFlattenedTokens());
+    $details = $details[0][$contactID];
+  }
 
-  $mime = $mailing->compose(NULL, NULL, NULL, $session->get('userID'), $fromEmail, $fromEmail,
-    TRUE, $details[0][$contactID], $attachments
+  $mime = $mailing->compose(NULL, NULL, NULL, $contactID, $fromEmail, $fromEmail,
+    TRUE, $details, $attachments
   );
 
   return civicrm_api3_create_success([
-    'id' => $params['id'],
+    'id' => $mailingID,
     'contact_id' => $contactID,
     'subject' => $mime->headers()['Subject'],
     'body_html' => $mime->getHTMLBody(),
index 077b8bf2d44a1aa987c35e7cf327e7920aab3101..ab3bafe58456f105ddd3c96ebc9ff2ed009290e5 100644 (file)
@@ -93,6 +93,13 @@ function _civicrm_api3_mailing_a_b_submit_spec(&$spec) {
   $spec['approval_date'] = $mailingFields['approval_date'];
   $spec['approval_status_id'] = $mailingFields['approval_status_id'];
   $spec['approval_note'] = $mailingFields['approval_note'];
+  $spec['winner_id'] = [
+    'name' => 'winner_id',
+    'type' => 1,
+    'title' => 'Winner ID',
+    'description' => 'The experimental mailing with the best results. If specified, values are copied to the final mailing.',
+    'localizable' => 0,
+  ];
   // Note: we'll pass through approval_* fields to the underlying mailing, but they may be ignored
   // if the user doesn't have suitable permission. If separate approvals are required, they must be provided
   // outside the A/B Test UI.
@@ -149,6 +156,9 @@ function civicrm_api3_mailing_a_b_submit($params) {
       if ($dao->status != 'Testing') {
         throw new API_Exception("Cannot transition to state 'Final'");
       }
+      if (!empty($params['winner_id'])) {
+        _civicrm_api3_mailing_a_b_fill_winner($params['winner_id'], $dao->mailing_id_c);
+      }
       civicrm_api3('Mailing', 'submit', $submitParams + [
         'id' => $dao->mailing_id_c,
         '_skip_evil_bao_auto_recipients_' => 1,
@@ -168,6 +178,56 @@ function civicrm_api3_mailing_a_b_submit($params) {
   ]);
 }
 
+/**
+ * @param int $winner_id
+ *   The experimental mailing chosen as the "winner".
+ * @param int $final_id
+ *   The final mailing which should imitate the "winner".
+ * @throws \API_Exception
+ */
+function _civicrm_api3_mailing_a_b_fill_winner($winner_id, $final_id) {
+  $copyFields = [
+    // 'id',
+    // 'name',
+    'campaign_id',
+    'from_name',
+    'from_email',
+    'replyto_email',
+    'subject',
+    'dedupe_email',
+    // 'recipients',
+    'body_html',
+    'body_text',
+    'footer_id',
+    'header_id',
+    'visibility',
+    'url_tracking',
+    'dedupe_email',
+    'forward_replies',
+    'auto_responder',
+    'open_tracking',
+    'override_verp',
+    'optout_id',
+    'reply_id',
+    'resubscribe_id',
+    'unsubscribe_id'
+  ];
+  $f = CRM_Utils_SQL_Select::from('civicrm_mailing')
+    ->where('id = #id', ['id' => $winner_id])
+    ->select($copyFields)
+    ->execute()
+    ->fetchAll();
+  if (count($f) !== 1) {
+    throw new API_Exception('Invalid winner_id');
+  }
+  foreach ($f as $winner) {
+    civicrm_api3('Mailing', 'create', $winner + [
+      'id' => $final_id,
+      '_skip_evil_bao_auto_recipients_' => 1,
+    ]);
+  }
+}
+
 /**
  * Adjust Metadata for graph_stats action.
  *
index 69367bf6f0878c6ee49e1b4d0c5a53c80e15c6bd..bab232ab49453c767b99a2feb32fbc62c648f395 100644 (file)
@@ -104,15 +104,20 @@ function civicrm_api3_payment_cancel(&$params) {
     'financial_trxn_id' => $params['id'],
   ];
   $entity = civicrm_api3('EntityFinancialTrxn', 'getsingle', $eftParams);
-  $contributionId = $entity['entity_id'];
-  $params['total_amount'] = $entity['amount'];
-  unset($params['id']);
 
-  $trxn = CRM_Contribute_BAO_Contribution::recordAdditionalPayment($contributionId, $params, 'refund', NULL, FALSE);
+  $paymentParams = [
+    'total_amount' => -$entity['amount'],
+    'contribution_id' => $entity['entity_id'],
+    'trxn_date' => CRM_Utils_Array::value('trxn_date', $params, 'now'),
+  ];
 
-  $values = [];
-  _civicrm_api3_object_to_array_unique_fields($trxn, $values[$trxn->id]);
-  return civicrm_api3_create_success($values, $params, 'Payment', 'cancel', $trxn);
+  foreach (['trxn_id', 'payment_instrument_id'] as $permittedParam) {
+    if (isset($params[$permittedParam])) {
+      $paymentParams[$permittedParam] = $params[$permittedParam];
+    }
+  }
+  $result = civicrm_api3('Payment', 'create', $paymentParams);
+  return civicrm_api3_create_success($result['values'], $params, 'Payment', 'cancel');
 }
 
 /**
@@ -169,6 +174,10 @@ function _civicrm_api3_payment_create_spec(&$params) {
       'type' => CRM_Utils_Type::T_INT,
       'api.aliases' => ['payment_id'],
     ],
+    'trxn_date' => [
+      'title' => 'Cancel Date',
+      'type' => CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME,
+    ],
   ];
 }
 
@@ -233,6 +242,10 @@ function _civicrm_api3_payment_cancel_spec(&$params) {
       'type' => CRM_Utils_Type::T_INT,
       'api.aliases' => ['payment_id'],
     ],
+    'trxn_date' => [
+      'title' => 'Cancel Date',
+      'type' => CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME,
+    ],
   ];
 }
 
index aa609d30807205321e430b329d4f2fd56a87a7e2..8cdcc9e8e7c101e1b0fe151881a0b3e7ebaf2f01 100644 (file)
@@ -146,7 +146,7 @@ class civicrm_cli {
     // of this script
     array_shift($args);
 
-    while (list($k, $arg) = each($args)) {
+    foreach ($args as $k => $arg) {
       // sanitize all user input
       $arg = $this->_sanitize($arg);
 
index 04f67c359e1d9791d4b19f4a9c9e95363c77a60c..19ec87f44c513e8e1226d1f040b65d152436e2d2 100644 (file)
 
 - github      : demeritcowboy
   name        : Dave D
-  jira        : demeritcowboy
+  jira        : Dave D
 
 - github      : dereklewis123
   name        : Derek Lewis
   organization: Greenleaf Advancement
   jira        : guyiac
 
+- github      : GValFr35
+
+- github      : kewljuice
+  name        : Wouter Hechtermans
+  organization: Calibrate
+
+- github      : khorporative
+  name        : Aivars
+
 - github      : h-c-c
   name        : Peter Hartmann
   organization: Hartmann Computer Consulting
   organization: Web Access
   jira        : pratiksha
 
+- github      : prondubuisi
+  name        : Onyemenam Ndubuisi
+
 - name        : Richard Edgar
   jira        : redgar
 
index 89b486963e872b54b53d406649d14ae1d1dad6ea..dc2a4e7937116fb9734a60a776eb21d90d2a9a0c 100644 (file)
@@ -131,7 +131,7 @@ input#crm-qsearch-input {
   border: 1px solid #ccc;
   margin: 4px 4px 0;
   padding: 2px 8px;
-  height: 30px;
+  height: calc($menubarHeight - 10px);
   width: 30px;
   transition: width .5s .05s, background-color .3s .05s;
   color: black;
@@ -183,7 +183,7 @@ body.crm-menubar-over-cms-menu #crm-menubar-toggle-position a i {
   transform: rotate(180deg);
 }
 
-@media (min-width: 768px) {
+@media (min-width: $breakMin) {
 
   /* Switch to desktop layout
   -----------------------------------------------
@@ -219,12 +219,25 @@ body.crm-menubar-over-cms-menu #crm-menubar-toggle-position a i {
   }
 
   #civicrm-menu li a {
-    background-color: $semiTransparentMenuColor;
+    background-color: $menuItemColor;
     color: $textColor;
   }
 
   #civicrm-menu > li > a {
-    height: 40px;
+    height: $menubarHeight;
+    padding: 0 8px;
+  }
+
+  #civicrm-menu > li > a > * {
+    vertical-align: middle;
+  }
+
+  /* Pseudo-element to ensure vertical alignment */
+  #civicrm-menu > li > a:after {
+    content: '';
+    display: inline-block;
+    height: 100%;
+    vertical-align: middle;
   }
 
   #civicrm-menu > li > a.highlighted {
@@ -250,7 +263,7 @@ body.crm-menubar-over-cms-menu #crm-menubar-toggle-position a i {
   }
 }
 
-@media (max-width: 768px) {
+@media (max-width: $breakMax) {
   /* hide the menu in mobile view */
   #crm-menubar-state:not(:checked) ~ #civicrm-menu {
     display: none;
index b238c51f40e1a51cc0628aa0be3eee90b93cdaa0..ef980b240b1624ef4c15eec0546cb217d3b9ff33 100644 (file)
@@ -1,11 +1,11 @@
-@media (min-width: 768px) {
+@media (min-width: $breakMin) {
 
   body.crm-menubar-visible.crm-menubar-over-cms-menu {
     border-top: 0 none !important;
-    margin-top: 40px;
+    margin-top: $menubarHeight;
   }
   body.crm-menubar-visible.crm-menubar-over-cms-menu.crm-menubar-wrapped {
-    margin-top: 80px;
+    margin-top: calc($menubarHeight * 2);
   }
   body.crm-menubar-visible.crm-menubar-over-cms-menu #admin-bar {
     visibility: hidden;
@@ -28,7 +28,7 @@
   }
 
 }
-@media (max-width: 768px) {
+@media (max-width: $breakMax) {
 
   body.backdrop-admin-bar-position-absolute #civicrm-menu-nav {
     position: absolute;
index 8317feb0220533e7d15fd924855786d17e251cb5..f5c663160b8e5ea679f4fdd21c13bd1c213ec395 100644 (file)
@@ -1,14 +1,14 @@
-@media (min-width: 768px) {
+@media (min-width: $breakMin) {
 
   body.crm-menubar-visible.crm-menubar-over-cms-menu #toolbar {
     display: none;
   }
 
   body.crm-menubar-visible.crm-menubar-over-cms-menu {
-    padding-top: 40px !important;
+    padding-top: $menubarHeight !important;
   }
   body.crm-menubar-visible.crm-menubar-over-cms-menu.crm-menubar-wrapped {
-    padding-top: 80px !important;
+    padding-top: calc($menubarHeight * 2) !important;
   }
 
   body.crm-menubar-visible.crm-menubar-over-cms-menu #toolbar .toolbar-drawer {
     min-height: 30px;
   }
   body.crm-menubar-visible.crm-menubar-below-cms-menu.admin-menu {
-    padding-top: 40px !important;
+    padding-top: $menubarHeight !important;
   }
   body.crm-menubar-visible.crm-menubar-below-cms-menu.crm-menubar-wrapped.admin-menu {
-    padding-top: 80px !important;
+    padding-top: calc($menubarHeight * 2) !important;
   }
   body.crm-menubar-visible.crm-menubar-over-cms-menu #admin-menu {
     display: none;
@@ -67,7 +67,7 @@
 }
 
 /* For adminimal_admin_menu */
-@media (min-width: 768px) and (max-width: 1024px) {
+@media (min-width: $breakMin) and (max-width: 1024px) {
 
   body.crm-menubar-visible.crm-menubar-over-cms-menu.admin-menu.adminimal-menu > .slicknav_menu {
     display: none;
@@ -80,7 +80,7 @@
   }
 }
 
-@media (max-width: 768px) {
+@media (max-width: $breakMax) {
 
   body.toolbar.crm-menubar-visible #toolbar-home {
     visibility: hidden;
index 868a7864dad005731fadb6116131b286f7bf90c3..c143dc967f130e30c4501f7c61df07c73bcd4dfc 100644 (file)
@@ -24,21 +24,24 @@ nav#civicrm-menu-nav .crm-menubar-toggle-btn-icon {
   left: 44px;
 }
 
-@media (min-width: 768px) {
+@media (min-width: $breakMin) {
 
-  body.crm-menubar-visible.crm-menubar-over-cms-menu #toolbar-administration  {
+  body.crm-menubar-visible.crm-menubar-over-cms-menu #toolbar-administration {
     display: none;
   }
 
   body.crm-menubar-visible.crm-menubar-over-cms-menu {
-    padding-top: 40px !important;
+    padding-top: $menubarHeight !important;
   }
-  body.crm-menubar-visible.crm-menubar-over-cms-menu.crm-menubar-wrapped,
+  body.crm-menubar-visible.crm-menubar-over-cms-menu.crm-menubar-wrapped {
+    padding-top: calc($menubarHeight * 2) !important;
+  }
+  /* The Drupal menu is 40px tall so we add that to our menubar height */
   body.crm-menubar-visible.crm-menubar-below-cms-menu {
-    padding-top: 80px !important;
+    padding-top: calc($menubarHeight + 40px) !important;
   }
   body.crm-menubar-visible.crm-menubar-below-cms-menu.crm-menubar-wrapped {
-    padding-top: 120px !important;
+    padding-top: calc($menubarHeight * 2 + 40px) !important;
   }
 
   body.crm-menubar-below-cms-menu > #civicrm-menu-nav ul#civicrm-menu {
index 482f8c2ac643b9f7324a2add0e65bfded763d848..48422b5e38d52b0beff4a0ebe7cbf39305f2cc38 100644 (file)
@@ -1,21 +1,21 @@
-@media (min-width: 768px) {
+@media (min-width: $breakMin) {
 
   body.crm-menubar-over-cms-menu.crm-menubar-visible {
-    padding-top: 40px;
+    padding-top: $menubarHeight;
   }
   body.crm-menubar-over-cms-menu.crm-menubar-visible.crm-menubar-wrapped {
-    padding-top: 80px;
+    padding-top: calc($menubarHeight * 2);
   }
 
   body.crm-menubar-below-cms-menu.crm-menubar-visible {
-    margin-top: 40px;
+    margin-top: $menubarHeight;
   }
   body.crm-menubar-below-cms-menu.crm-menubar-visible.crm-menubar-wrapped {
-    margin-top: 80px;
+    margin-top: calc($menubarHeight * 2);
   }
 
 }
-@media (max-width: 768px) {
+@media (max-width: $breakMax) {
 
   body #civicrm-menu-nav {
     position: absolute;
index 792b59e7dfbee94b5ffa55597ba8ba4945e6d0e2..e87fc6e5271735458f8a40d85d76cc4a43930139 100644 (file)
@@ -1,4 +1,4 @@
-@media (min-width: 768px) {
+@media (min-width: $breakMin) {
 
   body.crm-menubar-over-cms-menu.crm-menubar-visible #wpbody {
     padding-top: 8px;
   }
 
   body.crm-menubar-below-cms-menu.crm-menubar-visible #wpbody {
-    padding-top: 40px;
+    padding-top: $menubarHeight;
   }
   body.crm-menubar-below-cms-menu.crm-menubar-visible.crm-menubar-wrapped #wpbody {
-    padding-top: 80px;
+    padding-top: calc($menubarHeight * 2);
   }
   body.crm-menubar-over-cms-menu.crm-menubar-visible.crm-menubar-wrapped #adminmenuwrap {
-    margin-top: 40px;
+    margin-top: $menubarHeight;
   }
 
 }
-@media (min-width: 768px) and (max-width: 960px) {
+@media (min-width: $breakMin) and (max-width: 960px) {
 
   /* For the auto-fold toolbar */
   .wp-toolbar body.crm-menubar-below-cms-menu.auto-fold > #civicrm-menu-nav #civicrm-menu {
@@ -42,7 +42,7 @@
   }
 
 }
-@media (max-width: 768px) {
+@media (max-width: $breakMax) {
 
   body #civicrm-menu-nav .crm-menubar-toggle-btn {
     position: absolute;
index 6e1c581f178c6fedef836a4921cd187da971e4da..503de82ce77c83d33da77c8b73fe199564ab61dc 100644 (file)
@@ -31,7 +31,6 @@ $config = CRM_Core_Config::singleton();
 if (defined('PANTHEON_ENVIRONMENT')) {
   ini_set('session.save_handler', 'files');
 }
-session_start();
 $rest = new CRM_Utils_REST();
 
 // Json-appropriate header will be set by CRM_Utils_Rest
index ad91a49e1b8a458d877f3f5f1bcc46787f0eface..f3b98afc7267d426c29c2783e9e8ea5a1fedbb3c 100644 (file)
@@ -78,7 +78,7 @@
             })
             .on('show.smapi', function(e, menu) {
               // Focus menu when opened with an accesskey
-              $(menu).siblings('a[accesskey]:not(:hover)').focus();
+              $(menu).siblings('a[accesskey]').focus();
             })
             .smartmenus(CRM.menubar.settings);
           initialized = true;
index 9d85e58ec898e2777786df37d8f41e8e663e1194..caaac6a198a8bf03bf3cefdf60acdf36b7ca9f8a 100644 (file)
@@ -14,6 +14,75 @@ Other resources for identifying changes are:
     * https://github.com/civicrm/civicrm-joomla
     * https://github.com/civicrm/civicrm-wordpress
 
+## CiviCRM 5.13.2
+
+Released May 6, 2019
+
+- **[Synopsis](release-notes/5.13.2.md#synopsis)**
+- **[Features](release-notes/5.13.2.md#features)**
+- **[Bugs resolved](release-notes/5.13.2.md#bugs)**
+- **[Miscellany](release-notes/5.13.2.md#misc)**
+- **[Credits](release-notes/5.13.2.md#credits)**
+- **[Feedback](release-notes/5.13.2.md#feedback)**
+
+## CiviCRM 5.13.1
+
+Released May 2, 2019
+
+- **[Synopsis](release-notes/5.13.1.md#synopsis)**
+- **[Features](release-notes/5.13.1.md#features)**
+- **[Bugs resolved](release-notes/5.13.1.md#bugs)**
+- **[Miscellany](release-notes/5.13.1.md#misc)**
+- **[Credits](release-notes/5.13.1.md#credits)**
+- **[Feedback](release-notes/5.13.1.md#feedback)**
+
+## CiviCRM 5.13.0
+
+Released May 1, 2019
+
+- **[Synopsis](release-notes/5.13.0.md#synopsis)**
+- **[Features](release-notes/5.13.0.md#features)**
+- **[Bugs resolved](release-notes/5.13.0.md#bugs)**
+- **[Miscellany](release-notes/5.13.0.md#misc)**
+- **[Credits](release-notes/5.13.0.md#credits)**
+- **[Feedback](release-notes/5.13.0.md#feedback)**
+
+## CiviCRM 5.12.4
+
+Released April 25, 2019
+
+- **[Synopsis](release-notes/5.12.4.md#synopsis)**
+- **[Bugs resolved](release-notes/5.12.4.md#bugs)**
+- **[Credits](release-notes/5.12.4.md#credits)**
+- **[Feedback](release-notes/5.12.4.md#feedback)**
+
+## CiviCRM 5.12.3
+
+Released April 20, 2019
+
+- **[Synopsis](release-notes/5.12.3.md#synopsis)**
+- **[Bugs resolved](release-notes/5.12.3.md#bugs)**
+- **[Credits](release-notes/5.12.3.md#credits)**
+- **[Feedback](release-notes/5.12.3.md#feedback)**
+
+## CiviCRM 5.12.2
+
+Released April 19, 2019
+
+- **[Synopsis](release-notes/5.12.2.md#synopsis)**
+- **[Bugs resolved](release-notes/5.12.2.md#bugs)**
+- **[Credits](release-notes/5.12.2.md#credits)**
+- **[Feedback](release-notes/5.12.2.md#feedback)**
+
+## CiviCRM 5.12.1
+
+Released April 15, 2019
+
+- **[Synopsis](release-notes/5.12.1.md#synopsis)**
+- **[Bugs resolved](release-notes/5.12.1.md#bugs)**
+- **[Credits](release-notes/5.12.1.md#credits)**
+- **[Feedback](release-notes/5.12.1.md#feedback)**
+
 ## CiviCRM 5.12.0
 
 Released April 3, 2019
diff --git a/release-notes/5.12.4.md b/release-notes/5.12.4.md
new file mode 100644 (file)
index 0000000..dfc9c2a
--- /dev/null
@@ -0,0 +1,39 @@
+# CiviCRM 5.12.4
+
+Released April 25, 2019
+
+- **[Synopsis](#synopsis)**
+- **[Bugs resolved](#bugs)**
+- **[Credits](#credits)**
+- **[Feedback](#feedback)**
+
+## <a name="synopsis"></a>Synopsis
+
+| *Does this version...?*                                         |         |
+|:--------------------------------------------------------------- |:-------:|
+| Fix security vulnerabilities?                                   |   no    |
+| Change the database schema?                                     |   no    |
+| Alter the API?                                                  |   no    |
+| Require attention to configuration options?                     |   no    |
+| Fix problems installing or upgrading to a previous version?     |   no    |
+| Introduce features?                                             |   no    |
+| **Fix bugs?**                                                   | **yes** |
+
+## <a name="bugs"></a>Bugs resolved
+
+- **CiviMail - Fix "Preview" action when using `viewUrl` tokens and mailing hashes. ([dev/core#891](https://lab.civicrm.org/dev/core/issues/891): [14124](https://github.com/civicrm/civicrm-core/pull/14124))**
+
+- **Installer - Fix diagnostic for MySQL `utf8mb4` support. ([dev/core#880](https://lab.civicrm.org/dev/core/issues/880): [14129](https://github.com/civicrm/civicrm-core/pull/14129))**
+
+## <a name="credits"></a>Credits
+
+This release was developed by the following authors and reviewers:
+
+Wikimedia Foundation - Eileen McNaughton; Australian Greens - Seamus Lee;
+Lighthouse Design and Consulting - Brian Shaughnessy; Electronic Frontier Foundation - Mark Burdett
+
+## <a name="feedback"></a>Feedback
+
+These release notes are edited by Tim Otten and Andrew Hunt.  If you'd like to
+provide feedback on them, please login to https://chat.civicrm.org/civicrm and
+contact `@agh1`.
diff --git a/release-notes/5.13.0.md b/release-notes/5.13.0.md
new file mode 100644 (file)
index 0000000..38172b6
--- /dev/null
@@ -0,0 +1,1095 @@
+# CiviCRM 5.13.0
+
+Released May 1, 2019
+
+- **[Synopsis](#synopsis)**
+- **[Features](#features)**
+- **[Bugs resolved](#bugs)**
+- **[Miscellany](#misc)**
+- **[Credits](#credits)**
+- **[Feedback](#feedback)**
+
+## <a name="synopsis"></a>Synopsis
+
+| *Does this version...?*                                         |         |
+|:--------------------------------------------------------------- |:-------:|
+| Fix security vulnerabilities?                                   |   no    |
+| **Change the database schema?**                                 | **yes** |
+| **Alter the API?**                                              | **yes** |
+| **Require attention to configuration options?**                 | **yes** |
+| **Fix problems installing or upgrading to a previous version?** | **yes** |
+| **Introduce features?**                                         | **yes** |
+| **Fix bugs?**                                                   | **yes** |
+
+## <a name="features"></a>Features
+
+### Core CiviCRM
+
+- **Configurable menubar color
+  ([13996](https://github.com/civicrm/civicrm-core/pull/13996))**
+
+  v5.12 introduced a new menu bar. The change also revised the default color
+  scheme (applying a more contemporary palette), but this created stress for
+  some users who were trained to recognize the old menu color. This exposes a
+  new setting for customizing the color scheme, and it changes the default to
+  match previous scheme (be black instead of beige).
+
+- **Menu config screen improvements
+  ([14002](https://github.com/civicrm/civicrm-core/pull/14002))**
+
+  Improves the Menu configuration screen by: making changes to the menu (adding
+  or editing menu items) on the admin screen be reflected immediately, adding
+  links to the related settings pages to reduce confusion about how to configure
+  various aspects of the menu bar and fixing the broken icon picker and missing
+  CiviCRM icon.
+
+- **What to do with the merge screen
+  ([dev/core#824](https://lab.civicrm.org/dev/core/issues/824):
+  [13898](https://github.com/civicrm/civicrm-core/pull/13898) and
+  [13895](https://github.com/civicrm/civicrm-core/pull/13895)) CONTINUES WORK**
+
+  Continues work to clean up the Merge screen by moving toward
+  using contact type icons in a standard way instead of the contact type names
+  and cleaning up alignment.
+
+- **Mutliple activity type filters on activity tab on contact records
+  ([13873](https://github.com/civicrm/civicrm-core/pull/13873))**
+
+  Change include/exclude activity type filters to be multiple select2 widgets so
+  that users can filter my multiple activity types rather than only permitting
+  users to select one activity type with a traditional select field.
+
+- **Added a DB check to prevent deleting exisiting CiviCRM data from database.
+  ([13944](https://github.com/civicrm/civicrm-core/pull/13944))**
+
+  When installing CiviCRM this change adds a check to see if there are existing
+  CiviCRM tables and requires users to manually remove any CiviCRM tables
+  before continuing to prevent users from accidentally deleting tables.
+
+- **Encourage developers to use .then instead of .done
+  ([13982](https://github.com/civicrm/civicrm-core/pull/13982))**
+
+  This change makes it so the Api Explorer generates js code using `.then()`
+  (instead of `.done`) and demonstrates proper errQor handling to encourage
+  developers to use `.then()`.
+
+- **Replace jcalendar instances with datepicker
+  ([dev/core#561](https://lab.civicrm.org/dev/core/issues/561):
+  [13919](https://github.com/civicrm/civicrm-core/pull/13919),
+  [13855](https://github.com/civicrm/civicrm-core/pull/13855),
+  [13965](https://github.com/civicrm/civicrm-core/pull/13965),
+  [13950](https://github.com/civicrm/civicrm-core/pull/13950) and
+  [13918](https://github.com/civicrm/civicrm-core/pull/13918)) CONTINUES WORK**
+
+  Moves from jcalendar to datepicker in the following places: the fulfilled date
+  on the premium tab on back end contribution add/edit screens, the activity
+  tab, the receive_date and the renewal_date fields in Membership forms and the
+  transaction date field on the update pending status task. And updates tests to
+  reflect progress getting rid of jcalendar.
+
+- **Expose sort_name as a dedupe-matchable field
+  ([13864](https://github.com/civicrm/civicrm-core/pull/13864))**
+
+  Allow sort_name to be used in dedupe rules.
+
+- **Standardise setTitle method on forms
+  ([13781](https://github.com/civicrm/civicrm-core/pull/13781))**
+
+  Makes the title of a form available in the buildForm hook.
+
+- **Send action links on any page that extends CRM_Core_Page_Basic thru
+  hook_civicrm_links
+  ([13068](https://github.com/civicrm/civicrm-core/pull/13068))**
+
+  Makes it so extension developers can use hook_civicrm_links to add or remove
+  links from the Relationship Types Administration Page (CiviCRM Navigation
+  Menu->Administer->Customize Data and Screens->Relationship Types) and any
+  other page that extends CRM_Core_Page_Basic.
+
+- **Improve lock handling for mysql 5.7.5+
+  ([CRM-18011](https://issues.civicrm.org/jira/browse/CRM-18011):
+  [13854](https://github.com/civicrm/civicrm-core/pull/13854))**
+
+  Ensures mysql locks are supported on mysql 5.7.5+ and MariaDB '10.0.2'+.
+
+- **Deploy PEAR Log package and upgrade to latest version in the process
+  ([13835](https://github.com/civicrm/civicrm-core/pull/13835))**
+
+  Upgrades the PEAR Log package version and deploys it via
+  composer.
+
+- **Make cacheCode optional in CRM.loadScript
+  ([13824](https://github.com/civicrm/civicrm-core/pull/13824))**
+
+  A cacheCode was recently added to script urls fetched by CRM.getScript(). This
+  is not always desirable e.g. for scripts fetched from an external source, this
+  change makes it so the cacheCode is added by default but can be disabled.
+
+- **Load hooks during upgrade mode
+  ([13551](https://github.com/civicrm/civicrm-core/pull/13551))**
+
+  Allow extensions to load hooks during an upgrade.
+
+- **Checkbox to explicitly change employer when sharing address
+  ([CRM-21008](https://issues.civicrm.org/jira/browse/CRM-21008):
+  [13700](https://github.com/civicrm/civicrm-core/pull/13700))**
+
+  Before this change when an individual was set to share an address with an
+  organization, that organization was set as its current employer. This change
+  adds a checkbox that allows users to explicitly tell civicrm whether the
+  organization is the current employer or not when sharing an address.
+
+- **Report improvements
+  ([CRM-21677](https://issues.civicrm.org/jira/browse/CRM-21677):
+  [13792](https://github.com/civicrm/civicrm-core/pull/13792),
+  [13790](https://github.com/civicrm/civicrm-core/pull/13790) and
+  [13780](https://github.com/civicrm/civicrm-core/pull/13780))**
+
+  These changes improve reports by removing redundant birth date and gender
+  evaluation code.
+
+- **Contact Subtype field at Reports does not support contacts with multiple
+  subtypes ([dev/core/544](https://lab.civicrm.org/dev/core/issues/544):
+  [13158](https://github.com/civicrm/civicrm-core/pull/13158) and
+  [13908](https://github.com/civicrm/civicrm-core/pull/13908))**
+
+  Makes reports support filtering on multiple contact subtypes.
+
+- **Replace all instances of CRM_Core_Fatal with throw new CRM_Core_Exception
+  ([dev/core#560](https://lab.civicrm.org/dev/core/issues/560):
+  [13850](https://github.com/civicrm/civicrm-core/pull/13850)) CONTINUES WORK**
+
+  Updates Cancel Billing & Update Billing screens to use status bounce rather
+  than throw a fatal error.
+
+- **Activity tab performance fix - switch to faster getActivities &
+  getActivitiesCount
+  ([13768](https://github.com/civicrm/civicrm-core/pull/13768))**
+
+  Performance improvement when loading the activity tab for a contact.
+
+- **Add hook findDuplicates
+  ([13234](https://github.com/civicrm/civicrm-core/pull/13234))**
+
+  Adds the hook findDuplicates which provides the ability for extensions to
+  intercept and/or override core duplicate checking when
+  registering/contributing.
+
+- **Deadlocks and performance issues when using smartgroups / ACLs extensively
+  ([dev/core#748](https://lab.civicrm.org/dev/core/issues/748):
+  [13772](https://github.com/civicrm/civicrm-core/pull/13772)) CONTINUES WORK**
+
+  Improves performance by switching the alphabetQuery to use new
+  getSearchSQLParts() function.
+
+- **Improve data when known time-dependent-failing test fails
+  ([13964](https://github.com/civicrm/civicrm-core/pull/13964))**
+
+  Improves output data when time dependent tests fail.
+
+- **Use TempTable methods.
+  ([13880](https://github.com/civicrm/civicrm-core/pull/13880),
+  [13865](https://github.com/civicrm/civicrm-core/pull/13865),
+  [13819](https://github.com/civicrm/civicrm-core/pull/13819),
+  [13848](https://github.com/civicrm/civicrm-core/pull/13848),
+  [13847](https://github.com/civicrm/civicrm-core/pull/13847) and
+  [13703](https://github.com/civicrm/civicrm-core/pull/13703))**
+
+  These changes move towards using the TempTable class to improve
+  naming standards, including but not limited to the following places: when
+  creating the dedupe table, on the contribution detail report, on the
+  bookkeeping report and when debugging.
+
+- **Allow extensions to enable validate.tpl
+  ([13961](https://github.com/civicrm/civicrm-core/pull/13961))**
+
+  This change makes it possible for extensions to add a validate.tpl which
+  provides front end javascript validation, which improves user experience by
+  making it so users do not have to refresh the page to see validation issues.
+
+- **Promise polyfill for older browsers
+  ([13955](https://github.com/civicrm/civicrm-core/pull/13955))**
+
+  Loads a polyfill for IE aQnd other outdated browsers so developers can use
+  native js Promises in our code.
+
+### CiviCase
+
+- **Case Activity Assignment Restriction
+  ([dev/core#641](https://lab.civicrm.org/dev/core/issues/641):
+  [13541](https://github.com/civicrm/civicrm-core/pull/13541))**
+
+  Makes it possible to restrict the assignment of case activities to
+  a group or to contacts having user accounts.
+
+### CiviContribute
+
+- **Add cancel_reason field to civicrm_contribution_recur table
+  ([dev/core#830](https://lab.civicrm.org/dev/core/issues/830):
+  [13930](https://github.com/civicrm/civicrm-core/pull/13930),
+  [13999](https://github.com/civicrm/civicrm-core/pull/13999), and
+  [14164](https://github.com/civicrm/civicrm-core/pull/14164))**
+
+  Adds a recur cancel reason field `civicrm_contribution_recur.cancel_reason
+  field`.
+
+- **Add ID / Test ID for payment processors to list - makes setup of IPNs much
+  easier! ([13869](https://github.com/civicrm/civicrm-core/pull/13869))**
+
+  Adds a column for payment processor id and test payment processor id to the
+  table of "Settings - Payment Processors" page so that users can more easily
+  access these ids.
+
+- **Add payment_processor column/filter to recurring contribution report
+  ([13699](https://github.com/civicrm/civicrm-core/pull/13699))**
+
+  On the "Recurring Contribution" report, this adds "Payment Processor" as an
+  option to the Column and Filter tabs enabling users to filter this report by
+  "Payment Processor" and/or include a column for "Payment Processor".
+
+- **Payment processor names: separate internal and external usage
+  ([dev/financial#2](https://lab.civicrm.org/dev/financial/issues/2):
+  [13995](https://github.com/civicrm/civicrm-core/pull/13995) and
+  [13954](https://github.com/civicrm/civicrm-core/pull/13954))**
+
+  Adds the field `payment_processor.title` to the schema and makes it
+  translatable.
+
+- **Support paying refunds
+  ([dev/financial#38](https://lab.civicrm.org/dev/financial/issues/38):
+  [13952](https://github.com/civicrm/civicrm-core/pull/13952)) BEGINS WORK**
+
+  Adds a PaymentProcessor.refund API which makes it possible for payment
+  processor extension authors to have their extensions issue refund payments.
+
+- **Add minimal PaymentProcessor.pay api
+  ([13953](https://github.com/civicrm/civicrm-core/pull/13953))**
+
+  Adds a new api PaymentProcessor.pay.
+
+- **Include lower level data when throwing an exception on payment processor.pay
+  ([14006](https://github.com/civicrm/civicrm-core/pull/14006))**
+
+  Improves error processing when using the PaymentProcessor.pay api.
+
+- **Add billingblock region to event registration thankyou to match contribution
+  thankyou ([13762](https://github.com/civicrm/civicrm-core/pull/13762))**
+
+  This change makes it so one can use the same method to
+  replace billingblock for both event and contribution thankyou workflows.
+
+- **CQ: Refactor Recurring Contribution Forms
+  ([dev/core#846](https://lab.civicrm.org/dev/core/issues/846):
+  [13940](https://github.com/civicrm/civicrm-core/pull/13940)) BEGINS WORK**
+
+  Begins work to refactor recurring contribution forms specifically by
+  rationalizing url variables into shared parent for recurring contribution
+  forms.
+
+- **Use label not name for payment processor type
+  ([13885](https://github.com/civicrm/civicrm-core/pull/13885))**
+
+  On the "Settings - Payment Processor" page changes the "Processor Type" column
+  to use the label instead of the name.
+
+- **Improve ContributionPage.validate api
+  ([13798](https://github.com/civicrm/civicrm-core/pull/13798))**
+
+  Makes it so that one can use the ContributionPage validate api on POST, for
+  example when using Paypal Checkout which calls a Promise, the
+  ContributionPage.validate api could be called to determine whether to proceed
+  after the button is pushed.
+
+- **Add pseudoconstant support for payment_processor_id on ContributionRecur
+  ([13698](https://github.com/civicrm/civicrm-core/pull/13698))**
+
+- **Allow payment processor to determine the text around 'continue'
+  ([13787](https://github.com/civicrm/civicrm-core/pull/13787))**
+
+
+### CiviEvent
+
+- **Expose Registered by Participant Name field to participant report
+  ([dev/core#835](https://lab.civicrm.org/dev/core/issues/835):
+  [13936](https://github.com/civicrm/civicrm-core/pull/13936))**
+
+  Exposes "Registered by Participant Name" field to participant reports.
+
+### CiviMail
+
+- **Report results don't show inactive campaigns
+  ([dev/core#491](https://lab.civicrm.org/dev/core/issues/491):
+  [13383](https://github.com/civicrm/civicrm-core/pull/13383))**
+
+  Standardizes the way campaign fields are added to the "Mailing Summary"
+  report.
+
+- **Use Mailing.preview API to display mailing in browser
+  ([14163](https://github.com/civicrm/civicrm-core/pull/14163))**
+
+  This resolves an error on sites with Flexmailer when an anonymous visitor
+  views a mailing in the browser.
+
+### CiviMember
+
+- **Membership form address fields for payment processors
+  ([13802](https://github.com/civicrm/civicrm-core/pull/13802))**
+
+  Standardizes processing and validating address parameters on the
+  Membership form.
+
+### Wordpress Integration
+
+- **Cleaner front-end URLs
+  ([144](https://github.com/civicrm/civicrm-wordpress/pull/144))**
+
+  Makes Wordpress URLs have the same structure as Drupal URLs ex:
+  `https://domain.tld/civicrm/contribute/transact/?reset=1&id=1 as opposed to
+  old` Wordpress URLs that looked like
+  `https://domain.tld/civicrm/?page=CiviCRM&q=civicrm/contribute/transact&reset=1&id=1`
+
+## <a name="bugs"></a>Bugs resolved
+
+### Core CiviCRM
+
+- **Add a test matrix for E2E tests on each CMS
+  ([infra/ops#878](https://lab.civicrm.org/infra/ops/issues/878):
+  [13810](https://github.com/civicrm/civicrm-core/pull/13810),
+  [13826](https://github.com/civicrm/civicrm-core/pull/13826) and
+  [13811](https://github.com/civicrm/civicrm-core/pull/13811)) CONTINUES WORK**
+
+  These changes resolve bugs when running E2E tests on WordPress moving the
+  project towards the goal of having a test matrix for E2E tests for each CMS
+  that CiviCRM is compatible with.
+
+- **Use the correct membership date for the notification that appear after
+  completing the membership payment in case pre hook is used
+  ([dev/core#288](https://lab.civicrm.org/dev/core/issues/288):
+  [12583](https://github.com/civicrm/civicrm-core/pull/12583))**
+
+  This change ensures that any changes made to the membership dates using
+  hook_civicrm_pre are taken into account when generating the membership payment
+  notification.
+
+- **Custom Field checkbox value renders empty if the values are randomly sorted
+  ([dev/core#499](https://lab.civicrm.org/dev/core/issues/499):
+  [13051](https://github.com/civicrm/civicrm-core/pull/13051))**
+
+  This change ensures that the values selected by a user for alphanumeric
+  checkbox custom fields render properly in view mode.
+
+- **New Organisation: "Check For Matching Contact (S)" button does not find
+  matching records ([dev/core#570](https://lab.civicrm.org/dev/core/issues/570):
+  [13398](https://github.com/civicrm/civicrm-core/pull/13398))**
+
+  This change ensures that "Check For Matching Contact(s)" retrieves
+  contacts for users with limited permissions.
+
+- **Soft Credits Multiply GIft Amount in Contribution Detail Report
+  ([dev/core#655](https://lab.civicrm.org/dev/core/issues/655):
+  [13906](https://github.com/civicrm/civicrm-core/pull/13906))**
+
+  This change updates the Contribution Detail report so that the "Total Amount"
+  field is not summed because the summing of the "Total Amount" field was
+  leading to the "Total Amount" field for contributions with multiple soft
+  credits to be multiplied by the number of soft credits.
+
+- **Add new indexes when updating log table schema regardless of engine change
+  ([dev/core#664](https://lab.civicrm.org/dev/core/issues/664):
+  [13462](https://github.com/civicrm/civicrm-core/pull/13462))**
+
+  This change makes it so that when the alterLogTables hook defines a new index
+  it is applied regardless of the engine.
+
+- **Contacts -> New Email give Unknown Error in Smarty when Allow Mail to be
+  sent from logged in contact's email address disabled
+  ([dev/core#688](https://lab.civicrm.org/dev/core/issues/688):
+  [13508](https://github.com/civicrm/civicrm-core/pull/13508))**
+
+  This change fixes an error "Warning: Smarty error" when attempting to send an
+  email from Contacts -> New Email for sites with "Allow Mail to be sent from
+  logged in user" disabled.
+
+- **Edit contribution : wrong decimal separator on total_amount for
+  participant(s) ([dev/core#706](https://lab.civicrm.org/dev/core/issues/706):
+  [13554](https://github.com/civicrm/civicrm-core/pull/13554))**
+
+  This change ensures that the decimal separator on total_amount field for
+  participant(s) is displayed as it is configured on the site.
+
+- **Contact Report: The filter by the custom datetime field with "Today" option
+  doesn't find matching contacts
+  ([dev/core#709](https://lab.civicrm.org/dev/core/issues/709):
+  [13567](https://github.com/civicrm/civicrm-core/pull/13567))**
+
+  This change ensures that on the Contact Report, when using a filter for a
+  custom datetime field the "Today" option properly filters results.
+
+- **Address API incorrectly sets state_province_id if multiple countries have
+  same state name / abbreviation
+  ([dev/core#725](https://lab.civicrm.org/dev/core/issues/725):
+  [13938](https://github.com/civicrm/civicrm-core/pull/13938))**
+
+  This change fixes a regression so that the Address API country_id parameter
+  works with an abbreviation or numeric id.
+
+- **Advanced Search: There is an Internal Server Error (500) when the user tries
+  to search by the "Mailing List" group type
+  ([dev/core#726](https://lab.civicrm.org/dev/core/issues/726):
+  [13603](https://github.com/civicrm/civicrm-core/pull/13603) and
+  [13888](https://github.com/civicrm/civicrm-core/pull/13888))**
+
+  Fixes a bug where searching by a group type (ex: Mailing List) on the Advanced
+  Search form would result in a fatal error so that this search runs as
+  expected.
+
+- **Notes: It isn't possible to edit note if the user uploaded an image larger
+  than 3 MByte(s) ([dev/core#740](https://lab.civicrm.org/dev/core/issues/740):
+  [13640](https://github.com/civicrm/civicrm-core/pull/13640))**
+
+  This change makes it so that it is possible to edit a note field
+  that includes images larger than  3 MByte(s).
+
+- **Custom field caching is not group-specific
+  ([dev/core#755](https://lab.civicrm.org/dev/core/issues/755):
+  [13900](https://github.com/civicrm/civicrm-core/pull/13900))**
+
+  Adds the $groupTitle parameter to the cache key for custom fields, so field
+  names that exist in multiple groups will be cached separately.
+
+- **Warning: A non-numeric value encountered in ...
+  ([dev/core#788](https://lab.civicrm.org/dev/core/issues/788):
+  [13795](https://github.com/civicrm/civicrm-core/pull/13795))**
+
+  This change fixes several warnings "Warning: A non-numeric value encountered
+  in ..." on contribution pages & event registrations forms.
+
+- **PHP Warning "explode() expects parameter 2 to be string, array given" for
+  multi-value country fields
+  ([dev/core#795](https://lab.civicrm.org/dev/core/issues/795):
+  [13858](https://github.com/civicrm/civicrm-core/pull/13858))**
+
+  Fixes a PHP warning when updating a multiselect country field.
+
+- **Prefix/suffix select2 renders oddly on public-facing pages
+  ([dev/core#798](https://lab.civicrm.org/dev/core/issues/798):
+  [13816](https://github.com/civicrm/civicrm-core/pull/13816))**
+
+  This change makes the Prefix/suffix select2's render full height (as opposed
+  to squished) in contribution/event profiles.
+
+- **DB Error:: Already exists during renewing membership automatically
+  ([dev/core#806](https://lab.civicrm.org/dev/core/issues/806):
+  [13852](https://github.com/civicrm/civicrm-core/pull/13852))**
+
+  Fixes a DB error "already exists" when recording recurring payments with taxes
+  enabled.
+
+- **Autocomplete select list disabled options
+  ([dev/core#811](https://lab.civicrm.org/dev/core/issues/811):
+  [13859](https://github.com/civicrm/civicrm-core/pull/13859))**
+
+  This change ensures that for select fields with autocomplete, only enabled
+  options autocomplete.
+
+- **Search results: Actions: Export contacts: DB Error: Syntax error occurs when
+  not all necessary fields are selected
+  ([dev/core#819](https://lab.civicrm.org/dev/core/issues/819):
+  [13889](https://github.com/civicrm/civicrm-core/pull/13889))**
+
+  Resolves a fatal database error when attempting to export contacts without
+  selecting any fields to be exported.
+
+- **Value in the "Contact Type" field disappears when the user tries to edit
+  Contact Details ([dev/core#823](https://lab.civicrm.org/dev/core/issues/823):
+  [13945](https://github.com/civicrm/civicrm-core/pull/13945))**
+
+  Ensures that when a user uses a profile with a contact sub type field to
+  update a contact that the contact sub type field pre-populates as expected.
+
+- **Notice error while creating smart group using Contribution Aggregate custom
+  search ([dev/core#837](https://lab.civicrm.org/dev/core/issues/837):
+  [13921](https://github.com/civicrm/civicrm-core/pull/13921))**
+
+  Resolves "Notice: Undefined index:" errors when creating a smart group using
+  Contribution Aggregate custom search.
+
+- **Notice error when deleting profile
+  ([dev/core#840](https://lab.civicrm.org/dev/core/issues/840):
+  [13926](https://github.com/civicrm/civicrm-core/pull/13926))**
+
+  Resolves a "Undefined property" notice when deleting a profile.
+
+- **CQ: Use Guzzle as our preferred way to retrieve via http
+  ([dev/core#849](https://lab.civicrm.org/dev/core/issues/849):
+  [13946](https://github.com/civicrm/civicrm-core/pull/13946))**
+
+  Replaces get_headers functions call with Guzzle HTTP request to prevent timing
+  out.
+
+- **Queries combining multiple text labels using REGEXP do not escape regular
+  expression metacharacters
+  ([dev/core#433](https://lab.civicrm.org/dev/core/issues/433):
+  [12998](https://github.com/civicrm/civicrm-core/pull/12998))**
+
+  Ensures that querying for fee levels that contain regex metacharacters will
+  match.
+
+- **Fix status type (error, not fail) for CRM_Core_Session::setStatus
+  ([13943](https://github.com/civicrm/civicrm-core/pull/13943))**
+
+  Fixes an incorrect status for setMessage which was using 'fail' (which is not
+  a valid status) instead of 'error'.
+
+- **Covert the CRM_Core_Error::fatal calls to exceptions when trying to access
+  Contact Photos ([13917](https://github.com/civicrm/civicrm-core/pull/13917))**
+
+  Cleaner errors when attempting to access contact photos fails.
+
+- **CiviCRM API, lookup state_province_id options based on country parameter if
+  present, or default country
+  ([13596](https://github.com/civicrm/civicrm-core/pull/13596))**
+
+  Ensures the CiviCRM Address API correctly sets state_province_id for states
+  whose name/abbreviation exist in multiple countries.
+
+- **Fix php 7.2 count notice
+  ([13877](https://github.com/civicrm/civicrm-core/pull/13877))**
+
+  Fixes a "Warning: count()" error on the "Import Contacts" Summary step screen.
+
+- **New Organisation: "Contact Type" dropdown disappears when fields validation
+  occurs ([dev/core#699](https://lab.civicrm.org/dev/core/issues/699):
+  [13545](https://github.com/civicrm/civicrm-core/pull/13545))**
+
+  Fixes a bug where when creating a new organization, if the form fails
+  validation the "Contact Sub Type" dropdown disappears.
+
+- **Fix contact.merge api to pass check_permissions parameter through to the
+  deeper layer ([13807](https://github.com/civicrm/civicrm-core/pull/13807))**
+
+  Fixes a bug where calling Contact.merge from php will leave the merged contact
+  unmerged if the logged in user does not have the delete contacts permission
+
+- **checkEditInboundEmailsPermissions should be a static function
+  ([13805](https://github.com/civicrm/civicrm-core/pull/13805))**
+
+- **DB error "no such field" when executing actions on a sorted contact search
+  result with search profile
+  ([dev/core#502](https://lab.civicrm.org/dev/core/issues/502):
+  [13884](https://github.com/civicrm/civicrm-core/pull/13884))**
+
+- **Transfer picks up the deleted contact ID basically transferring to the wrong
+  contact ([dev/core#314](https://lab.civicrm.org/dev/core/issues/314):
+  [12639](https://github.com/civicrm/civicrm-core/pull/12639))**
+
+- **Fix bug whereby sorting by state province gives an error in search builder
+  ([13748](https://github.com/civicrm/civicrm-core/pull/13748))**
+
+- **Fix Contact.create calls to respect passed in variables & variables set via
+  hook for sort_name & display_name
+  ([13863](https://github.com/civicrm/civicrm-core/pull/13863))**
+
+- **Do not cause a fatal error if no contact_id field for a note is filled in
+  when viewing contact notes
+  ([13910](https://github.com/civicrm/civicrm-core/pull/13910))**
+
+- **Disable phpcs checking in the Crypt files where mcrypt functions are
+  ([14031](https://github.com/civicrm/civicrm-core/pull/14031))**
+
+- **Fix 4.7.31 Upgrade in multilingual mode
+  ([14003](https://github.com/civicrm/civicrm-core/pull/14003))**
+
+- **Optimise the loading of the CiviCRM Deduplication Exception page
+  ([13435](https://github.com/civicrm/civicrm-core/pull/13435))**
+
+- **Unfork Zetacomponents mail and use patch to apply differences
+  ([13934](https://github.com/civicrm/civicrm-core/pull/13934))**
+
+- **Update lockfile to take into account of civicrm/zetacomponents-mail#4 being
+  merged ([13822](https://github.com/civicrm/civicrm-core/pull/13822))**
+
+- **Upgrade zetacomponents/base and zetacomponents/mail
+  ([13799](https://github.com/civicrm/civicrm-core/pull/13799))**
+
+- **Smart group with uf_group_id does not load contacts with same search profile
+  ([dev/core#771](https://lab.civicrm.org/dev/core/issues/771):
+  [13742](https://github.com/civicrm/civicrm-core/pull/13742))**
+
+- **Fix Deprecation notice for use of `while` in PHP7.2 in bin/cli.class.php
+  ([dev/core#907](https://lab.civicrm.org/dev/core/issues/907):
+  [14155](https://github.com/civicrm/civicrm-core/pull/14155))**
+
+### CiviCase
+
+- **PR 13333 breaks the Save and New button on a new case
+  ([dev/core#904](https://lab.civicrm.org/dev/core/issues/904):
+  [14145](https://github.com/civicrm/civicrm-core/pull/14145))**
+
+  This reverts a change making the Save and New button `submitOnce`, as that
+  prevented the button from opening a new case form after saving.
+
+- **Creating a new relationship type while editing case type definition adds a
+  blank row in the roles section
+  ([dev/core#784](https://lab.civicrm.org/dev/core/issues/784):
+  [13785](https://github.com/civicrm/civicrm-core/pull/13785))**
+
+- **PHP warnings on Case Dashboard and Find Cases
+  ([13998](https://github.com/civicrm/civicrm-core/pull/13998))**
+
+### CiviContribute
+
+- **Can't self-service cancel a recurring contribution made while you're logged
+  in ([dev/core#571](https://lab.civicrm.org/dev/core/issues/571):
+  [13237](https://github.com/civicrm/civicrm-core/pull/13237))**
+
+  This change makes it so that users without "edit contributions" permission can
+  edit their own recurring contribution subscriptions if they are logged in,
+  before this change they could only edit their own contribution subscriptions
+  thru a checksum link.
+
+- **Possible paypal fix to avoid sending 500 errors from ipn triggerred by
+  one-off payment
+  ([13867](https://github.com/civicrm/civicrm-core/pull/13867))**
+
+  Fixes paypal system sending a warning email when there is a failed IPN call
+  (500 errors from ipn triggered by non-recurring payment).
+
+- **Missing links to cancel recurring payments (regression .. sorta)
+  ([dev/core#704](https://lab.civicrm.org/dev/core/issues/704):
+  [13935](https://github.com/civicrm/civicrm-core/pull/13935))**
+
+  Fixes a 5.8 regression where the cancel link became unavailable on recurring
+  contributions with no attached payment processor id.
+
+- **Improve flushing after creating a processor so it can be used for a
+  recurring in the same run
+  ([14009](https://github.com/civicrm/civicrm-core/pull/14009))**
+
+  This change ensures tests run properly by flushing caches when creating a
+  payment processor.
+
+- **Flush ContributionRecur static cache when flushing processors
+  ([13962](https://github.com/civicrm/civicrm-core/pull/13962))**
+
+  Ensures a (new) static cache is flushed when creating a processor, mostly
+  useful for unit testing.
+
+- **Display test contributions when viewing contributions related to a test
+  recurring contribution
+  ([13779](https://github.com/civicrm/civicrm-core/pull/13779))**
+
+### CiviEvent
+
+- **Cancelling or An Error during event registration payment should cancel all
+  additional participates
+  ([dev/core#253](https://lab.civicrm.org/dev/core/issues/253):
+  [12457](https://github.com/civicrm/civicrm-core/pull/12457))**
+
+  This fixes a bug where if a user was registering for an event with additional
+  participants, and for some reason the payment failed or the user decided to
+  cancel the payment, only the main user participant record was set to
+  "canceled", the rest of the additional participants would have the status
+  "pending incomplete transaction" so that all participant statuses are changed
+  to "canceled".
+
+- **Event Cart: Fix PHP 7.2 fatal error (pass by ref)
+  ([13927](https://github.com/civicrm/civicrm-core/pull/13927))**
+
+  Fixes a Fatal error when using Event cart and PHP 7.2, specifically when
+  checking out.
+
+- **CRM/Event - Fix participant note search parameter being ignored
+  ([13697](https://github.com/civicrm/civicrm-core/pull/13697))**
+
+  This change ensures that when searching by "Participant Note" on the "Search
+  Builder form the filter is applied.
+
+- **BAO_Participant - Use default status if not specified for create
+  ([13875](https://github.com/civicrm/civicrm-core/pull/13875))**
+
+  This change fixes a api4 test failure by ensuring that the default value of
+  'status_id' is respected by the Participant BAO. Before this change the
+  'status_id' had a default value and thus was not required but the BAO would
+  not work correctly if a 'status_id' was not supplied. After this change the
+  'status_id' default is respected and the BAO works regardless of whether the
+  'status_id' is supplied.
+
+### CiviGrant
+
+- **PHP Error on Grant Detail Report
+  ([13883](https://github.com/civicrm/civicrm-core/pull/13883))**
+
+  Fixes a PHP error when viewing the "Grant Detail Report" for sites running PHP
+  7.2.
+
+### CiviMail
+
+- **Do not track CSS URLs
+  ([dev/core#836](https://lab.civicrm.org/dev/core/issues/836):
+  [13920](https://github.com/civicrm/civicrm-core/pull/13920))**
+
+  Ensures CiviMail does not convert css URLs into trackable URLs.
+
+- **Restore support for preview of "mailing"/"action" tokens via
+  TokenProcessor/Flexmailer
+  ([14156](https://github.com/civicrm/civicrm-core/pull/14156))**
+
+### CiviMember
+
+- **Disabling or deleting Expired status breaks membership status update
+  ([13259](https://github.com/civicrm/civicrm-core/pull/13259))**
+
+  This change ensures that deleting, disabling or renaming the "Expired"
+  membership status does not cause issues when running the "Membership status
+  processor" scheduled job. Before this change deleting, disabling or renaming
+  the "Expired" membership status would result in the  "Membership status
+  processor" scheduled job failing with the message `Finished execution of
+  Membership status processor with result: Failure, Error message: A fatal error
+  was triggered: One of parameters (value: ) is not of the type Integer`.
+
+- **Fatal error to exception on Membership BAO
+  ([13774](https://github.com/civicrm/civicrm-core/pull/13774))**
+
+  This change improves experience by throwing an exception instead of a fatal
+  error.
+
+### Backdrop Integration
+
+- **civicrm/admin/setting/uf - Fix advice about Backdrop Views
+  ($database_prefix)
+  ([13803](https://github.com/civicrm/civicrm-core/pull/13803))**
+
+  This change updates the advice for configuring views on the
+  `civicrm/admin/setting/uf` form so that it works for Backdrop sites.
+
+### Drupal Integration
+
+- **Drupal8: Can't upload images via CKEditor/kcfinder
+  ([dev/drupal#42](https://lab.civicrm.org/dev/drupal/issues/42):
+  [242](https://github.com/civicrm/civicrm-packages/pull/242))**
+
+   Makes it so on Drupal 8 sites users can upload and browse images in KCFinder.
+
+## <a name="misc"></a>Miscellany
+
+- **Fix e-notice in IDS
+  ([247](https://github.com/civicrm/civicrm-packages/pull/247))**
+
+- **Update 7.x Drupal code to be that of the new coder style
+  ([571](https://github.com/civicrm/civicrm-drupal/pull/571))**
+
+- **Fix up to newer coder style
+  ([69](https://github.com/civicrm/civicrm-backdrop/pull/69))**
+
+- **Remove now-obsolete additionalFromClause parameter from prepareOrderBy
+  ([13874](https://github.com/civicrm/civicrm-core/pull/13874))**
+
+- **Remove switch statement that no longer switches
+  ([13886](https://github.com/civicrm/civicrm-core/pull/13886))**
+
+- **Add unit test for exporting with incomplete data
+  ([13904](https://github.com/civicrm/civicrm-core/pull/13904))**
+
+- **Delete webtests
+  ([13861](https://github.com/civicrm/civicrm-core/pull/13861))**
+
+- **Add a class to handle test entities consistently
+  ([13814](https://github.com/civicrm/civicrm-core/pull/13814))**
+
+- **Fix up composer for composer 2.0 compatibility
+  ([13872](https://github.com/civicrm/civicrm-core/pull/13872))**
+
+- **Remove log files as now supplied by composer
+  ([244](https://github.com/civicrm/civicrm-packages/pull/244), [245](https://github.com/civicrm/civicrm-packages/pull/245))**
+
+- **Remove htmlpurifier from within the IDS to facilitate it being provided by
+  composer ([246](https://github.com/civicrm/civicrm-packages/pull/246))**
+
+- **Remove Log.php require_once statements
+  ([13842](https://github.com/civicrm/civicrm-core/pull/13842))**
+  
+- **Remove amavisd now that it is removed from the packages repository
+  ([243](https://github.com/civicrm/civicrm-packages/pull/243), [13841](https://github.com/civicrm/civicrm-core/pull/13841))**
+
+- **Upgrade htmlpurifier to 4.10 to support PHP7.2 and install via composer
+  ([13840](https://github.com/civicrm/civicrm-core/pull/13840))**
+
+- **Refactor CRM_Contact_Form_Task_PDFLetterCommon
+  ([13892](https://github.com/civicrm/civicrm-core/pull/13892))**
+
+- **Reformat test files for array format
+  ([13862](https://github.com/civicrm/civicrm-core/pull/13862))**
+
+- **Logging - attempt to fix tests
+  ([13832](https://github.com/civicrm/civicrm-core/pull/13832))**
+
+- **Try Reverting commit removing require once to see if it fixes the problem
+  for api4 ([13870](https://github.com/civicrm/civicrm-core/pull/13870))**
+
+- **Import date test
+  ([13823](https://github.com/civicrm/civicrm-core/pull/13823))**
+
+- **Add shared parent for ContributionRecur forms
+  ([13931](https://github.com/civicrm/civicrm-core/pull/13931))**
+
+- **Update PHPWord Patches to match the latest versions of their code
+  ([13923](https://github.com/civicrm/civicrm-core/pull/13923))**
+
+- **Extract assignPaymentFields
+  ([13957](https://github.com/civicrm/civicrm-core/pull/13957))**
+
+- **Move code to assign tax information into shared parent
+  ([13899](https://github.com/civicrm/civicrm-core/pull/13899))**
+
+- **Update test to reflect recently merged PR lower permission to access
+  dedupecheck ([13866](https://github.com/civicrm/civicrm-core/pull/13866))**
+
+- **Test fix ([13856](https://github.com/civicrm/civicrm-core/pull/13856))**
+
+- **Add unit testing for activity creation when cancelling a recurring, related
+  cleanup ([14000](https://github.com/civicrm/civicrm-core/pull/14000))**
+
+- **Improve test coverage for CRM_Utils_Color::getRgb()
+  ([14007](https://github.com/civicrm/civicrm-core/pull/14007))**
+
+- **Add in tests of purifying HTML output
+  ([13845](https://github.com/civicrm/civicrm-core/pull/13845))**
+
+- **Remove more instances of ->free()
+  ([dev/core#562](https://lab.civicrm.org/dev/core/issues/562):
+  [13786](https://github.com/civicrm/civicrm-core/pull/13786)) CONTINUES WORK**
+
+- **(NFC) Ensure phpcs ignores eval notice in these files as it is required
+  ([14032](https://github.com/civicrm/civicrm-core/pull/14032))**
+
+- **(NFC) Lint additional php files up to the new coder standard
+  ([14025](https://github.com/civicrm/civicrm-core/pull/14025))**
+
+- **Port code style fixes to 5.13 from master
+  ([14026](https://github.com/civicrm/civicrm-core/pull/14026))**
+
+- **(NFC) Update CRM/Core CRM/Custom CRM/Dedupe to match the new coder style
+  ([14023](https://github.com/civicrm/civicrm-core/pull/14023))**
+
+- **(NFC) Update CRM/Event folder for the new coder style
+  ([14019](https://github.com/civicrm/civicrm-core/pull/14019))**
+
+- **(NFC) update CRM/Contribute to be the new coder standard
+  ([14021](https://github.com/civicrm/civicrm-core/pull/14021))**
+
+- **(NFC) Update CRM/Friend CRM/Grant CRM/Group CRM/Mailing to be up to d…
+  ([14016](https://github.com/civicrm/civicrm-core/pull/14016))**
+
+- **(NFC) Update CRM/Badge CRM/Campaign CRM/Case to be up to date with a â€¦
+  ([14017](https://github.com/civicrm/civicrm-core/pull/14017))**
+
+- **(NFC) Update CRM/Cxn CRM/Dashlet CRM/Export CRM/Extension and CRM/Fin…
+  ([14018](https://github.com/civicrm/civicrm-core/pull/14018))**
+
+- **[NFC] Short array syntax - auto convert settings dir
+  ([14005](https://github.com/civicrm/civicrm-core/pull/14005))**
+
+- **(NFC) SchemaStructure.php - Fix up mismatch between stored+generated code
+  ([14046](https://github.com/civicrm/civicrm-core/pull/14046))**
+
+- **Arg I put these fixes in 5.12 & master while trying for 5.13
+  ([14036](https://github.com/civicrm/civicrm-core/pull/14036))**
+
+- **(NFC) Update CRM/Member CRM/Note CRM/Logging CRM/Import and CRM/Price…
+  ([13992](https://github.com/civicrm/civicrm-core/pull/13992))**
+
+- **(REF) CRM_Core_Resources - Move hook declaration from addCoreResources() to
+  Container.php ([14008](https://github.com/civicrm/civicrm-core/pull/14008))**
+
+- **(NFC) Update CRM/Activity CRM/Admin and CRM/Batch folders to be the f…
+  ([13990](https://github.com/civicrm/civicrm-core/pull/13990))**
+
+- **(NFC) Update coding style in PCP, Pledge, Profile, Queue, Report folders
+  ([13987](https://github.com/civicrm/civicrm-core/pull/13987))**
+
+- **(NFC) Update CRM/SMS/ CRM/UF/ CRM/Upgrade/ CRM/Tag/ to be up to speed…
+  ([13986](https://github.com/civicrm/civicrm-core/pull/13986))**
+
+- **(NFC) Bring CRM/Utils folder up to future coder standards
+  ([13985](https://github.com/civicrm/civicrm-core/pull/13985))**
+
+- **(NFC) Set _log and _tableName variables to be public
+  ([13988](https://github.com/civicrm/civicrm-core/pull/13988))**
+
+- **Grammar fixes
+  ([13960](https://github.com/civicrm/civicrm-core/pull/13960))**
+
+- **Update Unit test styling to cover the future coder version
+  ([13983](https://github.com/civicrm/civicrm-core/pull/13983))**
+
+- **(NFC) Fix location of comment to match future coder version
+  ([13984](https://github.com/civicrm/civicrm-core/pull/13984))**
+
+- **(NFC) Bring up API folder to style of future coder checker
+  ([13980](https://github.com/civicrm/civicrm-core/pull/13980))**
+
+- **(NFC) Upgrade Civi Folder to the new coder version
+  ([13981](https://github.com/civicrm/civicrm-core/pull/13981))**
+
+- **(NFC) Update various files to pass future civicrm/coder ruleset
+  ([13979](https://github.com/civicrm/civicrm-core/pull/13979))**
+
+- **(NFC) Update various files to pass current phpcs
+  ([13978](https://github.com/civicrm/civicrm-core/pull/13978))**
+
+- **[NFC] Reformat tricksy file CRM_Mailing_BAO_Mailing
+  ([13973](https://github.com/civicrm/civicrm-core/pull/13973))**
+
+- **[NFC] Reformat tricksy file CRM/Contribute/Import/Form/MapField
+  ([13974](https://github.com/civicrm/civicrm-core/pull/13974))**
+
+- **[NFC] short array syntax Autoformat - just  the tricksy bits of CRM/Activity
+  ([13969](https://github.com/civicrm/civicrm-core/pull/13969))**
+
+- **[NFC] array format tricksie file  CRM/Admin/Form/MessageTemplates
+  ([13970](https://github.com/civicrm/civicrm-core/pull/13970))**
+
+- **[NFC] array format tricksie file CRM_Utils_Rest
+  ([13971](https://github.com/civicrm/civicrm-core/pull/13971))**
+
+- **[NFC] array formatting tricksy tricksie file (another CRM/UF/Form/Group.php)
+  ([13972](https://github.com/civicrm/civicrm-core/pull/13972))**
+
+- **[NFC] short array syntax Autoformat - just CRM/ACL dir
+  ([13968](https://github.com/civicrm/civicrm-core/pull/13968))**
+
+- **[NFC] Short array syntax - auto-format CRM directory
+  ([13915](https://github.com/civicrm/civicrm-core/pull/13915))**
+
+- **[REF] extract token functions
+  ([13967](https://github.com/civicrm/civicrm-core/pull/13967))**
+
+- **Test fix ([13949](https://github.com/civicrm/civicrm-core/pull/13949))**
+
+- **Payment test cleanup
+  ([13924](https://github.com/civicrm/civicrm-core/pull/13924))**
+
+- **(NFC) Fix mode on files
+  ([13933](https://github.com/civicrm/civicrm-core/pull/13933))**
+
+- **[NFC] Cleanup DAO factory classes for code standards
+  ([13922](https://github.com/civicrm/civicrm-core/pull/13922))**
+
+- **NFC - Short array syntax - auto-convert ang dir
+  ([13912](https://github.com/civicrm/civicrm-core/pull/13912))**
+
+- **NFC - Short array syntax - auto-convert Civi dir
+  ([13911](https://github.com/civicrm/civicrm-core/pull/13911))**
+
+- **[NFC] Short array syntax - auto-convert api dir
+  ([13909](https://github.com/civicrm/civicrm-core/pull/13909))**
+
+- **Minor code cleanup
+  ([13839](https://github.com/civicrm/civicrm-core/pull/13839))**
+
+- **Minor code cleanup - remove unnecessary ids declaration
+  ([13838](https://github.com/civicrm/civicrm-core/pull/13838))**
+
+- **Code cleanup on membership block loop
+  ([13851](https://github.com/civicrm/civicrm-core/pull/13851))**
+
+- **[NFC] IDE formatting only
+  ([13896](https://github.com/civicrm/civicrm-core/pull/13896))**
+
+- **Minor code cleanups around invoicing assignment
+  ([13857](https://github.com/civicrm/civicrm-core/pull/13857))**
+
+- **[nfc] Reset entire session object between tests
+  ([13878](https://github.com/civicrm/civicrm-core/pull/13878))**
+
+- **Fixing formatting of contributors section
+  ([13860](https://github.com/civicrm/civicrm-core/pull/13860))**
+
+- **[NFC] code formatting only
+  ([13846](https://github.com/civicrm/civicrm-core/pull/13846))**
+
+- **[NFC] Code reformatting
+  ([13849](https://github.com/civicrm/civicrm-core/pull/13849))**
+
+- **Add comments about usage for doPayment() function
+  ([13812](https://github.com/civicrm/civicrm-core/pull/13812))**
+
+- **[nfc] Attempt to improve false negatives on Logging test
+  ([13829](https://github.com/civicrm/civicrm-core/pull/13829))**
+
+- **[NFC] remove unnecessary variable
+  ([13836](https://github.com/civicrm/civicrm-core/pull/13836))**
+
+- **REF Extract case action links into a separate function to facilitate
+  refactoring ([13793](https://github.com/civicrm/civicrm-core/pull/13793))**
+
+- **NFC Whitespace cleanup MembershipBlock.tpl
+  ([13830](https://github.com/civicrm/civicrm-core/pull/13830))**
+
+- **Further cleanup on getRelatedMemberships - just get them with the api
+  ([13797](https://github.com/civicrm/civicrm-core/pull/13797))**
+
+- **[REF] small cleanups on payment.create flow.
+  ([13778](https://github.com/civicrm/civicrm-core/pull/13778))**
+
+- **[NFC] reformat Contact api file to switch to new array formatting
+  ([13806](https://github.com/civicrm/civicrm-core/pull/13806))**
+
+- **[REF] minor code simplification - remove over-handling of amount comp with
+  zero ([13783](https://github.com/civicrm/civicrm-core/pull/13783))**
+
+- **Attempted test fix
+  ([13791](https://github.com/civicrm/civicrm-core/pull/13791))**
+
+- **Remove reference to google checkout
+  ([13784](https://github.com/civicrm/civicrm-core/pull/13784))**
+
+- **[NFC] template whitespace cleanup
+  ([13782](https://github.com/civicrm/civicrm-core/pull/13782))**
+
+- **(NFC) Update for compliance with next phpcs standard
+  ([577](https://github.com/civicrm/civicrm-drupal/pull/577))**
+
+- **Lint .inc files in Drupal module folder to match newer coder standard
+  ([574](https://github.com/civicrm/civicrm-drupal/pull/574))**
+
+- **(NFC) Get phpcs to ignore the use of eval in this file as it is required
+  ([575](https://github.com/civicrm/civicrm-drupal/pull/575))**
+
+- **(NFC) Update for compliance with next phpcs standard
+  ([72](https://github.com/civicrm/civicrm-backdrop/pull/72))**
+
+- **(NFC) Lint .inc files and ensure that the eval usage in tests/phpunit…
+  ([71](https://github.com/civicrm/civicrm-backdrop/pull/71))**
+
+## <a name="credits"></a>Credits
+
+This release was developed by the following code authors:
+
+AGH Strategies - Alice Frumin, Andrew Hunt, Eli Lisseck; Agileware - Alok Patel,
+Francis Whittle; Australian Greens - Seamus Lee; calibrate - Wouter Hechtermans;
+Christian Wach; CiviCRM - Coleman Watts, Tim Otten; CiviDesk - Yashodha Chaku;
+CompuCorp - Omar Abu Hussein; Coop SymbioTIC - Mathieu Lutfy; Dave D; Electronic
+Frontier Foundation - Mark Burdett; Freeform Solutions - Herb van den Dool;
+Fuzion - Jitendra Purohit; GreenPeace Central and Eastern Europe - Patrick
+Figel; JMA Consulting - Monish Deb; Megaphone Technology Consulting - Jon
+Goldberg; MJW Consulting - Matthew Wire; Pradeep Nayak; Skvare - Mark Hanna;
+Squiffle Consulting - Aidan Saunders; Stephen Palmstrom; Timbsoft Technologies -
+Tunbola Ogunwande; Wikimedia Foundation - Eileen McNaughton
+
+Most authors also reviewed code for this release; in addition, the following
+reviewers contributed their comments:
+
+Agileware - Justin Freeman; Aniessh Sethh; Artful Robot - Rich Lott; British
+Humanist Association - Andrew West; Circle Interactive - Dave Jenkins; Shitij
+Gugnani; Coop SymbioTIC - Samuel Vanhove; GValFr35; JMA Consulting - Joe Murray;
+Joinery - Allen Shaw; Aivars; Korlon - Stuart Gaston; Lighthouse Design and
+Consulting - Brian Shaughnessy; mcuradoc; Onyemenam Ndubuisi; Tadpole
+Collective - Kevin Cristiano
+
+## <a name="feedback"></a>Feedback
+
+These release notes are edited by Alice Frumin and Andrew Hunt.  If you'd like
+to provide feedback on them, please log in to https://chat.civicrm.org/civicrm
+and contact `@agh1`.
diff --git a/release-notes/5.13.1.md b/release-notes/5.13.1.md
new file mode 100644 (file)
index 0000000..1dca67e
--- /dev/null
@@ -0,0 +1,39 @@
+# CiviCRM 5.13.1
+
+Released May 2, 2019
+
+- **[Synopsis](#synopsis)**
+- **[Bugs resolved](#bugs)**
+- **[Credits](#credits)**
+- **[Feedback](#feedback)**
+
+## <a name="synopsis"></a>Synopsis
+
+| *Does this version...?*                                         |         |
+|:--------------------------------------------------------------- |:-------:|
+| Fix security vulnerabilities?                                   |   no    |
+| Change the database schema?                                     |   no    |
+| Alter the API?                                                  |   no    |
+| Require attention to configuration options?                     |   no    |
+| Fix problems installing or upgrading to a previous version?     |   no    |
+| Introduce features?                                             |   no    |
+| **Fix bugs?**                                                   | **yes** |
+
+## <a name="bugs"></a>Bugs resolved
+
+- **Fix upgrade failure on multilingual sites ([dev/core#931](https://lab.civicrm.org/dev/core/issues/931): [14187](https://github.com/civicrm/civicrm-core/pull/14187))**
+
+- **Fix regression in REST endpoint on WordPress ([dev/wordpress#26](https://lab.civicrm.org/dev/wordpress/issues/26): [14186](https://github.com/civicrm/civicrm-core/pull/14186))**
+
+## <a name="credits"></a>Credits
+
+This release was developed by the following authors and reviewers:
+
+Australian Greens - Seamus Lee; Megaphone Technology Consulting - Jon Goldberg;
+Tadpole Collective - Kevin Cristiano;
+
+## <a name="feedback"></a>Feedback
+
+These release notes are edited by Tim Otten and Andrew Hunt.  If you'd like to
+provide feedback on them, please login to https://chat.civicrm.org/civicrm and
+contact `@agh1`.
diff --git a/release-notes/5.13.2.md b/release-notes/5.13.2.md
new file mode 100644 (file)
index 0000000..487b778
--- /dev/null
@@ -0,0 +1,41 @@
+# CiviCRM 5.13.2
+
+Released May 6, 2019
+
+- **[Synopsis](#synopsis)**
+- **[Bugs resolved](#bugs)**
+- **[Credits](#credits)**
+- **[Feedback](#feedback)**
+
+## <a name="synopsis"></a>Synopsis
+
+| *Does this version...?*                                         |         |
+|:--------------------------------------------------------------- |:-------:|
+| Fix security vulnerabilities?                                   |   no    |
+| Change the database schema?                                     |   no    |
+| Alter the API?                                                  |   no    |
+| Require attention to configuration options?                     |   no    |
+| Fix problems installing or upgrading to a previous version?     |   no    |
+| Introduce features?                                             |   no    |
+| **Fix bugs?**                                                   | **yes** |
+
+## <a name="bugs"></a>Bugs resolved
+
+- **Fix regression in sorting "Activities" tab by "source_name" ([dev/core#934](https://lab.civicrm.org/dev/core/issues/934):
+  [14194](https://github.com/civicrm/civicrm-core/pull/14194), [14204](https://github.com/civicrm/civicrm-core/pull/14204))**
+
+- **Fix regression in which inbound email attachments were saved as `.unknown`" ([dev/core#940](https://lab.civicrm.org/dev/core/issues/940):
+  [14207](https://github.com/civicrm/civicrm-core/pull/14207)**
+
+## <a name="credits"></a>Credits
+
+This release was developed by the following authors and reviewers:
+
+Wikimedia Foundation - Eileen McNaughton; CiviCRM - Tim Otten; Australian Greens - Seamus Lee;
+Dave D;
+
+## <a name="feedback"></a>Feedback
+
+These release notes are edited by Tim Otten and Andrew Hunt.  If you'd like to
+provide feedback on them, please login to https://chat.civicrm.org/civicrm and
+contact `@agh1`.
index 3305a0d4efc773e571d085e1c8f3ed89e9e5b54a..54141a87d5b45b6d366e32e4519db2bfda1daccd 100644 (file)
@@ -399,7 +399,7 @@ UNLOCK TABLES;
 
 LOCK TABLES `civicrm_domain` WRITE;
 /*!40000 ALTER TABLE `civicrm_domain` DISABLE KEYS */;
-INSERT INTO `civicrm_domain` (`id`, `name`, `description`, `config_backend`, `version`, `contact_id`, `locales`, `locale_custom_strings`) VALUES (1,'Default Domain Name',NULL,NULL,'5.14.alpha1',1,NULL,'a:1:{s:5:\"en_US\";a:0:{}}');
+INSERT INTO `civicrm_domain` (`id`, `name`, `description`, `config_backend`, `version`, `contact_id`, `locales`, `locale_custom_strings`) VALUES (1,'Default Domain Name',NULL,NULL,'5.15.alpha1',1,NULL,'a:1:{s:5:\"en_US\";a:0:{}}');
 /*!40000 ALTER TABLE `civicrm_domain` ENABLE KEYS */;
 UNLOCK TABLES;
 
index 315f6cd34e153105bd63956f84365213d5e741e4..e9ac9139fa3ef882b4d372eb6faf2d3c6e931239 100644 (file)
@@ -89,9 +89,8 @@
 </tr>
 
 <tr>
-  <td>
-    {include file="CRM/Core/DatePickerRange.tpl" fieldName="activity_date_time"}
-  </td>
+  {include file="CRM/Core/DatePickerRangeWrapper.tpl" fieldName="activity_date_time" colspan="2"}
+  <td>&nbsp;</td>
 </tr>
 <tr>
   <td>
index 7a88582f2990be715f1eff28ec73428d2fd3b20e..d16b96871497b7f4367d6ac3ecaf242227300273 100644 (file)
 
             <tr>
               <td>{$form.start_date.label}<br/>
-                {include file="CRM/common/jcalendar.tpl" elementName=start_date}
+                {$form.start_date.html}
               </td>
               <td>{$form.end_date.label}<br/>
-                {include file="CRM/common/jcalendar.tpl" elementName=end_date}
+                {$form.end_date.html}
               </td>
             </tr>
 
diff --git a/templates/CRM/Core/DatePickerRangeWrapper.tpl b/templates/CRM/Core/DatePickerRangeWrapper.tpl
new file mode 100644 (file)
index 0000000..9396375
--- /dev/null
@@ -0,0 +1,29 @@
+{*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 5                                                  |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2018                                |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM.                                    |
+ |                                                                    |
+ | CiviCRM is free software; you can copy, modify, and distribute it  |
+ | under the terms of the GNU Affero General Public License           |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
+ |                                                                    |
+ | CiviCRM is distributed in the hope that it will be useful, but     |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of         |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
+ | See the GNU Affero General Public License for more details.        |
+ |                                                                    |
+ | You should have received a copy of the GNU Affero General Public   |
+ | License and the CiviCRM Licensing Exception along                  |
+ | with this program; if not, contact CiviCRM LLC                     |
+ | at info[AT]civicrm[DOT]org. If you have questions about the        |
+ | GNU Affero General Public License or the licensing of CiviCRM,     |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
+ +--------------------------------------------------------------------+
+*}
+{* Wrapper around DatePickerRange TPL file *}
+<td {if $colspan} colspan="{$colspan}" {else} colspan="2" {/if} {if $class} class="{$class}" {/if}>
+    {include file="CRM/Core/DatePickerRange.tpl" fieldName=$fieldName}
+</td>
index fb0a114c630c190b80be82f4bacde1baaf2d6873..1c9555bd4605f502f2de7b3866665d7d0444a411 100644 (file)
@@ -21,7 +21,7 @@
     {foreach from=$line_items item=line_item}
       <tr class="event-line-item {$line_item.class}">
   <td class="event-title">
-    {$line_item.event->title} ({$line_item.event->start_date})
+    {$line_item.event->title} ({$line_item.event->start_date|crmDate})
   </td>
   <td class="participants-column">
     {$line_item.num_participants}<br/>
index bb7bb1d17911ab2f02c889e887dace7d3313d63d..1febb52fc654f6f316710834b4c18dd3db4d1a06 100644 (file)
@@ -98,7 +98,7 @@
         });
       }
       else {
-        if (elementId.is('select') === true && firstElement.parent().find(':input').select().index() >= 1 && firstElement.parent().find('select').select().index < 1) {
+        if (elementId.is('select') === true && firstElement.parent().find(':input').select().index() >= 1 && firstElement.parent().find('select').select().length > 1) {
           // its a multiselect case
           firstElement.parent().find(':input').select().each( function(count) {
             var firstElementValue = $(this).val();
index 1f49256bb887c08bbec5813a9105500fed453206..71e1e8eac60ecbf8dd9d5186b4714a9353aafcf6 100644 (file)
@@ -331,12 +331,7 @@ class CRM_Activity_BAO_ActivityTest extends CiviUnitTestCase {
    * Test getActivities BAO method for getting count
    */
   public function testGetActivitiesCountforNonAdminDashboard() {
-    $op = new PHPUnit_Extensions_Database_Operation_Insert();
-    $op->execute($this->_dbconn,
-      $this->createFlatXMLDataSet(
-        dirname(__FILE__) . '/activities_for_dashboard_count.xml'
-      )
-    );
+    $this->createTestActivities();
 
     $params = array(
       'contact_id' => 9,
@@ -360,12 +355,7 @@ class CRM_Activity_BAO_ActivityTest extends CiviUnitTestCase {
    * Test getActivities BAO method for getting count
    */
   public function testGetActivitiesCountforContactSummary() {
-    $op = new PHPUnit_Extensions_Database_Operation_Insert();
-    $op->execute($this->_dbconn,
-      $this->createFlatXMLDataSet(
-        dirname(__FILE__) . '/activities_for_dashboard_count.xml'
-      )
-    );
+    $this->createTestActivities();
 
     $params = array(
       'contact_id' => 9,
@@ -387,12 +377,7 @@ class CRM_Activity_BAO_ActivityTest extends CiviUnitTestCase {
    * CRM-18706 - Test Include/Exclude Activity Filters
    */
   public function testActivityFilters() {
-    $op = new PHPUnit_Extensions_Database_Operation_Insert();
-    $op->execute($this->_dbconn,
-      $this->createFlatXMLDataSet(
-        dirname(__FILE__) . '/activities_for_dashboard_count.xml'
-      )
-    );
+    $this->createTestActivities();
     Civi::settings()->set('preserve_activity_tab_filter', 1);
     $this->createLoggedInUser();
 
@@ -429,12 +414,7 @@ class CRM_Activity_BAO_ActivityTest extends CiviUnitTestCase {
    * Test getActivities BAO method for getting count
    */
   public function testGetActivitiesCountforContactSummaryWithNoActivities() {
-    $op = new PHPUnit_Extensions_Database_Operation_Insert();
-    $op->execute($this->_dbconn,
-      $this->createFlatXMLDataSet(
-        dirname(__FILE__) . '/activities_for_dashboard_count.xml'
-      )
-    );
+    $this->createTestActivities();
 
     $params = array(
       'contact_id' => 17,
@@ -501,12 +481,7 @@ class CRM_Activity_BAO_ActivityTest extends CiviUnitTestCase {
    * Test getActivities BAO method.
    */
   public function testGetActivitiesforNonAdminDashboard() {
-    $op = new PHPUnit_Extensions_Database_Operation_Insert();
-    $op->execute($this->_dbconn,
-      $this->createFlatXMLDataSet(
-        dirname(__FILE__) . '/activities_for_dashboard_count.xml'
-      )
-    );
+    $this->createTestActivities();
 
     $contactID = 9;
     $params = array(
@@ -572,16 +547,35 @@ class CRM_Activity_BAO_ActivityTest extends CiviUnitTestCase {
 
   }
 
+  /**
+   * Test getActivities BAO method.
+   */
+  public function testGetActivitiesforContactSummaryWithSortOptions() {
+    $this->createTestActivities();
+    $params = [
+      'contact_id' => 9,
+      'admin' => FALSE,
+      'caseId' => NULL,
+      'context' => 'activity',
+      'activity_type_id' => NULL,
+      'offset' => 0,
+      'rowCount' => 0,
+      'sort' => 'source_contact_name desc',
+    ];
+
+    $activities = CRM_Activity_BAO_Activity::getActivities($params);
+    $alphaOrder = ['Test Contact 11', 'Test Contact 12', 'Test Contact 3', 'Test Contact 4', 'Test Contact 9'];
+    foreach ($activities as $activity) {
+      $this->assertEquals(array_pop($alphaOrder), $activity['source_contact_name']);
+    }
+
+  }
+
   /**
    * Test getActivities BAO method.
    */
   public function testGetActivitiesforContactSummary() {
-    $op = new PHPUnit_Extensions_Database_Operation_Insert();
-    $op->execute($this->_dbconn,
-      $this->createFlatXMLDataSet(
-        dirname(__FILE__) . '/activities_for_dashboard_count.xml'
-      )
-    );
+    $this->createTestActivities();
 
     $contactID = 9;
     $params = array(
@@ -592,7 +586,6 @@ class CRM_Activity_BAO_ActivityTest extends CiviUnitTestCase {
       'activity_type_id' => NULL,
       'offset' => 0,
       'rowCount' => 0,
-      'sort' => NULL,
     );
 
     //since we are loading activities from dataset, we know total number of activities for this contact
@@ -633,12 +626,7 @@ class CRM_Activity_BAO_ActivityTest extends CiviUnitTestCase {
    * Test getActivities BAO method.
    */
   public function testGetActivitiesforContactSummaryWithActivities() {
-    $op = new PHPUnit_Extensions_Database_Operation_Insert();
-    $op->execute($this->_dbconn,
-      $this->createFlatXMLDataSet(
-        dirname(__FILE__) . '/activities_for_dashboard_count.xml'
-      )
-    );
+    $this->createTestActivities();
 
     // parameters for different test cases, check each array key for the specific test-case
     $testCases = array(
@@ -763,12 +751,7 @@ class CRM_Activity_BAO_ActivityTest extends CiviUnitTestCase {
    */
   public function testByActivityDateAndStatus() {
     CRM_Core_Config::singleton()->userPermissionClass->permissions = ['view all contacts', 'access CiviCRM'];
-    $op = new PHPUnit_Extensions_Database_Operation_Insert();
-    $op->execute($this->_dbconn,
-      $this->createFlatXMLDataSet(
-        dirname(__FILE__) . '/activities_for_dashboard_count.xml'
-      )
-    );
+    $this->createTestActivities();
 
     // activity IDs catagorised by date
     $lastWeekActivities = array(1, 2, 3);
@@ -1030,12 +1013,7 @@ class CRM_Activity_BAO_ActivityTest extends CiviUnitTestCase {
    * Set up for testing activity queries.
    */
   protected function setUpForActivityDashboardTests() {
-    $op = new PHPUnit_Extensions_Database_Operation_Insert();
-    $op->execute($this->_dbconn,
-      $this->createFlatXMLDataSet(
-        dirname(__FILE__) . '/activities_for_dashboard_count.xml'
-      )
-    );
+    $this->createTestActivities();
 
     $this->_params = array(
       'contact_id' => NULL,
@@ -1163,8 +1141,7 @@ $text
   public function testSendSMSWithoutPermission() {
     $dummy = NULL;
     $session = CRM_Core_Session::singleton();
-    $config = &CRM_Core_Config::singleton();
-    $config->userPermissionClass->permissions = array('access CiviCRM');
+    CRM_Core_Config::singleton()->userPermissionClass->permissions = array('access CiviCRM');
 
     CRM_Activity_BAO_Activity::sendSMS(
       $dummy,
@@ -1335,4 +1312,13 @@ $text
     return array($sent, $activityId, $success);
   }
 
+  protected function createTestActivities() {
+    $op = new PHPUnit_Extensions_Database_Operation_Insert();
+    $op->execute($this->_dbconn,
+      $this->createFlatXMLDataSet(
+        dirname(__FILE__) . '/activities_for_dashboard_count.xml'
+      )
+    );
+  }
+
 }
index 7c8f1ed47f8ba97b734e660d07bef8e30c7a9662..0d1c270d5fb6a7331d01bb15e80f6daa3751c761 100644 (file)
@@ -31,6 +31,28 @@ class CRM_Case_BAO_CaseTest extends CiviUnitTestCase {
     CRM_Core_BAO_ConfigSetting::enableComponent('CiviCase');
   }
 
+  /**
+   * Make sure that the latest case activity works accurately.
+   */
+  public function testCaseActivity() {
+    $userID = $this->createLoggedInUser();
+
+    $addTimeline = civicrm_api3('Case', 'addtimeline', [
+      'case_id' => 1,
+      'timeline' => "standard_timeline",
+    ]);
+
+    $query = CRM_Case_BAO_Case::getCaseActivityQuery('recent', $userID, ' civicrm_case.id IN( 1 )');
+    $res = CRM_Core_DAO::executeQuery($query);
+    $openCaseType = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Open Case');
+    while ($res->fetch()) {
+      $message = 'Failed asserting that the case activity query has a activity_type_id property:';
+      $this->assertObjectHasAttribute('activity_type_id', $res, $message . PHP_EOL . print_r($res, TRUE));
+      $message = 'Failed asserting that the latest activity from Case ID 1 was "Open Case":';
+      $this->assertEquals($openCaseType, $res->activity_type_id, $message . PHP_EOL . print_r($res, TRUE));
+    }
+  }
+
   protected function tearDown() {
     parent::tearDown();
     $this->quickCleanup($this->tablesToTruncate, TRUE);
index 823b91aa2cd887b9592cac0e42cced350d65f839..2ab4aaf85cb3df66bf50f4524c2f6724244a8fc0 100644 (file)
@@ -37,7 +37,7 @@
  * @group headless
  */
 class CRM_Contact_Import_Parser_ContactTest extends CiviUnitTestCase {
-  protected $_tablesToTruncate = ['civicrm_address', 'civicrm_phone'];
+  protected $_tablesToTruncate = ['civicrm_address', 'civicrm_phone', 'civicrm_email'];
 
   /**
    * Setup function.
@@ -241,15 +241,16 @@ class CRM_Contact_Import_Parser_ContactTest extends CiviUnitTestCase {
     $contactValues['external_identifier'] = 'android';
     $contactValues['street_address'] = 'Big Mansion';
     $contactValues['phone'] = 12334;
-    $this->runImport($contactValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID, array(0 => NULL, 1 => NULL, 2 => NULL, 3 => NULL, 4 => NULL, 5 => 'Primary', 6 => 'Primary'));
+    $this->runImport($contactValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID, array(0 => NULL, 1 => NULL, 2 => 'Primary', 3 => NULL, 4 => NULL, 5 => 'Primary', 6 => 'Primary'));
     $address = $this->callAPISuccessGetSingle('Address', array('street_address' => 'Big Mansion'));
     $this->assertEquals(1, $address['location_type_id']);
     $this->assertEquals(1, $address['is_primary']);
 
-    $this->markTestIncomplete('phone actually doesn\'t work');
     $phone = $this->callAPISuccessGetSingle('Phone', array('phone' => '12334'));
     $this->assertEquals(1, $phone['location_type_id']);
 
+    $this->callAPISuccessGetSingle('Email', array('email' => 'bill.gates@microsoft.com'));
+
     $contact = $this->callAPISuccessGetSingle('Contact', $contactValues);
     $this->callAPISuccess('Contact', 'delete', array('id' => $contact['id']));
   }
@@ -315,7 +316,6 @@ class CRM_Contact_Import_Parser_ContactTest extends CiviUnitTestCase {
     $this->assertEquals(1, $address['values'][1]['is_primary']);
     $this->assertEquals('Big Mansion', $address['values'][1]['street_address']);
 
-    $this->markTestIncomplete('phone import primary actually IS broken');
     $phone = $this->callAPISuccess('Phone', 'get', array('contact_id' => $contact['id'], 'sequential' => 1));
     $this->assertEquals(1, $phone['values'][0]['location_type_id']);
     $this->assertEquals(1, $phone['values'][0]['is_primary']);
@@ -355,8 +355,7 @@ class CRM_Contact_Import_Parser_ContactTest extends CiviUnitTestCase {
     $this->assertEquals(0, $address[0]['is_primary']);
     $this->assertEquals('Big Mansion', $address[0]['street_address']);
 
-    $this->markTestIncomplete('phone import primary actually IS broken');
-    $phone = $this->callAPISuccess('Phone', 'get', array('contact_id' => $contact['id'], 'sequential' => 1))['values'];
+    $phone = $this->callAPISuccess('Phone', 'get', ['contact_id' => $contact['id'], 'sequential' => 1, 'options' => ['sort' => 'is_primary DESC']])['values'];
     $this->assertEquals(3, $phone[1]['location_type_id']);
     $this->assertEquals(0, $phone[1]['is_primary']);
     $this->assertEquals(12334, $phone[1]['phone']);
@@ -374,13 +373,19 @@ class CRM_Contact_Import_Parser_ContactTest extends CiviUnitTestCase {
    */
   public function testImportPrimaryAddressUpdate() {
     list($contactValues) = $this->setUpBaseContact(array('external_identifier' => 'android'));
-    $contactValues['nick_name'] = 'Old Bill';
+    $contactValues['email'] = 'melinda.gates@microsoft.com';
+    $contactValues['phone'] = '98765';
     $contactValues['external_identifier'] = 'android';
     $contactValues['street_address'] = 'Big Mansion';
     $contactValues['city'] = 'Big City';
     $contactID = $this->callAPISuccessGetValue('Contact', array('external_identifier' => 'android', 'return' => 'id'));
     $originalAddress = $this->callAPISuccess('Address', 'create', array('location_type_id' => 2, 'street_address' => 'small house', 'contact_id' => $contactID));
-    $this->runImport($contactValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID, array(0 => NULL, 1 => NULL, 2 => NULL, 3 => NULL, 4 => NULL, 5 => 'Primary', 6 => 'Primary'));
+    $originalPhone = $this->callAPISuccess('phone', 'create', array('location_type_id' => 2, 'phone' => '1234', 'contact_id' => $contactID));
+    $this->runImport($contactValues, CRM_Import_Parser::DUPLICATE_UPDATE, CRM_Import_Parser::VALID, array(0 => NULL, 1 => NULL, 2 => 'Primary', 3 => NULL, 4 => NULL, 5 => 'Primary', 6 => 'Primary', 7 => 'Primary'));
+    $phone = $this->callAPISuccessGetSingle('Phone', ['phone' => '98765']);
+    $this->assertEquals(2, $phone['location_type_id']);
+    $this->assertEquals($originalPhone['id'], $phone['id']);
+    $email = $this->callAPISuccess('Email', 'getsingle', ['contact_id' => $contactID]);
     $address = $this->callAPISuccessGetSingle('Address', array('street_address' => 'Big Mansion'));
     $this->assertEquals(2, $address['location_type_id']);
     $this->assertEquals($originalAddress['id'], $address['id']);
index 362dc43875de297db32011cffb01995f988c4887..7143f3b4062cfe0148e5f8bcf5c88ccae6f5b3e6 100644 (file)
@@ -179,6 +179,15 @@ class CRM_Contribute_Form_AdditionalPaymentTest extends CiviUnitTestCase {
     // pay additional amount
     $this->submitPayment(20);
     $this->checkResults(array(30, 50, 20), 3);
+    $activities = $this->callAPISuccess('Activity', 'get', [
+      'source_record_id' => $this->_contributionId,
+      'activity_type_id' => 'Payment',
+      'options' => ['sort' => 'id'],
+      'sequential' => 1,
+    ])['values'];
+    $this->assertEquals(2, count($activities));
+    $this->assertEquals('$ 50.00 - Offline Payment for Contribution', $activities[0]['subject']);
+    $this->assertEquals('$ 20.00 - Offline Payment for Contribution', $activities[1]['subject']);
   }
 
   /**
index 89d65f22eb96b61901abf7545454796e0b637174..f773d1dd5ba16c73779a8ee7e18aab0c4c599ef5 100644 (file)
@@ -409,7 +409,7 @@ class CRM_Contribute_Form_SearchTest extends CiviUnitTestCase {
    *
    * @dataProvider getSearchData
    */
-  public function testContributionRecurStatusFilter($formValues, $expectedCount, $expectedContact, $expectedQill) {
+  public function testContributionRecurSearchFilters($formValues, $expectedCount, $expectedContact, $expectedQill) {
     $this->setUpRecurringContributions();
 
     $query = new CRM_Contact_BAO_Query(CRM_Contact_BAO_Query::convertFormValues($formValues));
@@ -553,12 +553,14 @@ class CRM_Contribute_Form_SearchTest extends CiviUnitTestCase {
       'sequential' => 1,
       'contact_id' => $this->ids['Contact']['contactID2'],
       'frequency_interval' => 1,
-      'frequency_unit' => "month",
+      'frequency_unit' => 'month',
       'amount' => 22,
       'currency' => "CAD",
       'payment_instrument_id' => 1,
       'contribution_status_id' => 1,
-      'financial_type_id' => "Donation",
+      'financial_type_id' => 'Donation',
+      'trxn_id' => 'a transaction',
+      'processor_id' => 'a processor',
     ]);
     $Contribution2 = $this->callAPISuccess('Contribution', 'create', [
       'financial_type_id' => 'Donation',
@@ -607,6 +609,18 @@ class CRM_Contribute_Form_SearchTest extends CiviUnitTestCase {
         'expected_contact' => [],
         'expected_qill' => "Recurring Contribution Status = 'Cancelled'",
       ],
+      'trxn_id_search' => [
+        'form_value' => ['contribution_recur_trxn_id' => 'a transaction'],
+        'expected_count' => 1,
+        'expected_contact' => ['Mr. Terrence Smith II'],
+        'expected_qill' => "Recurring Contribution Transaction ID = 'a transaction'",
+      ],
+      'processor_id_search' => [
+        'form_value' => ['contribution_recur_processor_id' => 'a processor'],
+        'expected_count' => 1,
+        'expected_contact' => ['Mr. Terrence Smith II'],
+        'expected_qill' => "Recurring Contribution Processor ID = 'a processor'",
+      ],
     ];
     return $useCases;
   }
index 7452e2cab1f5a74ed5a4a6786da609adb30b6511..73943396a39da974a8d20f7f312c6c6b136ff2bc 100644 (file)
@@ -318,4 +318,84 @@ class CRM_Core_BAO_RecurringEntityTest extends CiviUnitTestCase {
     $this->assertDBCompareValues('CRM_Friend_DAO_Friend', $searchActParams, $compareActParams);
   }
 
+  /**
+   * Testing Activity Generation through Entity Recursion with Custom Data and Tags.
+   */
+  public function testRecurringEntityGenerationWithCustomDataAndTags() {
+
+    // Create custom group and field
+    $customGroup = $this->customGroupCreate([
+      'extends' => 'Activity',
+    ]);
+    $customField = $this->customFieldCreate([
+        'custom_group_id' => $customGroup['id'],
+        'default_value' => '',
+      ]
+    );
+
+    // Create activity Tag
+    $tag = $this->tagCreate([
+      'used_for' => 'Activities',
+    ]);
+
+    // Create original activity
+    $customFieldValue = 'Custom Value';
+    $activityDateTime = date('YmdHis');
+    $activityId = $this->activityCreate([
+      'activity_date_time' => $activityDateTime,
+      'custom_' . $customField['id'] => $customFieldValue,
+    ]);
+
+    $activityId = $activityId['id'];
+
+    // Assign tag to a activity.
+    $this->callAPISuccess('EntityTag', 'create', [
+      'entity_table' => 'civicrm_activity',
+      'entity_id' => $activityId,
+      'tag_id' => $tag['id'],
+    ]);
+
+    // Create recurring activities.
+    $recursion = new CRM_Core_BAO_RecurringEntity();
+    $recursion->entity_id = $activityId;
+    $recursion->entity_table = 'civicrm_activity';
+    $recursion->dateColumns = ['activity_date_time'];
+    $recursion->schedule = [
+      'entity_value' => $activityId,
+      'start_action_date' => $activityDateTime,
+      'entity_status' => 'fourth saturday',
+      'repetition_frequency_unit' => 'month',
+      'repetition_frequency_interval' => 3,
+      'start_action_offset' => 3,
+      'used_for' => 'activity',
+    ];
+
+    $generatedEntities = $recursion->generate();
+    $generatedActivities = $generatedEntities['civicrm_activity'];
+
+    $this->assertEquals(3, count($generatedActivities), "Check if number of iterations are 3");
+
+    foreach ($generatedActivities as $generatedActivityId) {
+
+      /* Validate tag in recurring activity
+      // @todo - refer https://github.com/civicrm/civicrm-core/pull/13470
+      $this->callAPISuccess('EntityTag', 'getsingle', [
+      'entity_table' => 'civicrm_activity',
+      'entity_id' => $generatedActivityId,
+      ]);
+       */
+
+      // Validate custom data in recurring activity
+      $activity = $this->callAPISuccess('activity', 'getsingle', [
+        'return' => [
+          'custom_' . $customField['id'],
+        ],
+        'id' => $generatedActivityId,
+      ]);
+
+      $this->assertEquals($customFieldValue, $activity['custom_' . $customField['id']], 'Custom field value should be ' . $customFieldValue);
+
+    }
+  }
+
 }
index 721f87f7c087a3466140b6009d569f390d34d1cc..8b31fe906e198da38afe3bbc5a5bbf2d6f5506b5 100644 (file)
@@ -102,16 +102,25 @@ class CRM_Mailing_TokensTest extends \CiviUnitTestCase {
     $this->assertEquals(1, $count);
   }
 
+  public function getExampleTokensForUseWithoutMailingJob() {
+    $cases = [];
+    $cases[] = ['text/plain', 'To opt out: {action.optOutUrl}!', '@To opt out: .*civicrm/mailing/optout.*&jid=&qid=@'];
+    $cases[] = ['text/html', 'To opt out: <a href="{action.optOutUrl}">click here</a>!', '@To opt out: <a href=".*civicrm/mailing/optout.*&amp;jid=&amp;qid=.*">click@'];
+    return $cases;
+  }
+
   /**
-   * Check the behavior in the erroneous situation where someone uses
-   * a mailing-related token without providing a mailing ID.
+   * When previewing a mailing, there is no active mailing job, so one cannot
+   * generate fully formed URLs which reference the job. The current behavior
+   * is to link to a placeholder URL which has blank values for key fields
+   * like `jid` and `qid`.
+   *
+   * This current behavior may be wise or unwise - either way, having ensures
+   * that changes are intentional.
+   *
+   * @dataProvider getExampleTokensForUseWithoutMailingJob
    */
-  public function testTokensWithoutMailing() {
-    // We only need one case to see that the mailing-object works as
-    // an alternative to the mailing-id.
-    $inputTemplateFormat = 'text/plain';
-    $inputTemplate = 'To optout: {action.optOutUrl}!';
-
+  public function testTokensWithoutMailingJob($inputTemplateFormat, $inputTemplateText, $expectRegex) {
     $mailing = CRM_Core_DAO::createTestObject('CRM_Mailing_DAO_Mailing', array(
       'name' => 'Example Name',
     ));
@@ -120,17 +129,23 @@ class CRM_Mailing_TokensTest extends \CiviUnitTestCase {
     $p = new \Civi\Token\TokenProcessor(Civi::service('dispatcher'), array(
       'mailing' => $mailing,
     ));
-    $p->addMessage('example', $inputTemplate, $inputTemplateFormat);
+    $p->addMessage('example', $inputTemplateText, $inputTemplateFormat);
     $p->addRow()->context(array(
       'contactId' => $contact->id,
     ));
-    try {
-      $p->evaluate();
-      $this->fail('TokenProcessor::evaluate() should have thrown an exception');
-    }
-    catch (CRM_Core_Exception $e) {
-      $this->assertRegExp(';Cannot use action tokens unless context defines mailingJobId and mailingActionTarget;', $e->getMessage());
-    }
+    //    try {
+    //      $p->evaluate();
+    //      $this->fail('TokenProcessor::evaluate() should have thrown an exception');
+    //    }
+    //    catch (CRM_Core_Exception $e) {
+    //      $this->assertRegExp(';Cannot use action tokens unless context defines mailingJobId and mailingActionTarget;', $e->getMessage());
+    //    }
+
+    $p->evaluate();
+
+    // FIXME: For compatibility with
+    $actual = $p->getRow(0)->render('example');
+    $this->assertRegExp($expectRegex, $actual);
   }
 
 }
index 61f089c35002a8d189f78b79fa85930963d02be5..98e6952ee1a05bc960901426e44d8f5cb3e7837a 100644 (file)
@@ -42,9 +42,18 @@ class api_v3_MailingABTest extends CiviUnitTestCase {
     parent::setUp();
     $this->useTransaction(TRUE);
     $this->createLoggedInUser();
-    $this->_mailingID_A = $this->createMailing();
-    $this->_mailingID_B = $this->createMailing();
-    $this->_mailingID_C = $this->createMailing();
+    $this->_mailingID_A = $this->createMailing([
+      'subject' => 'subject a ' . time(),
+      'body_text' => 'body_text a ' . time(),
+    ]);
+    $this->_mailingID_B = $this->createMailing([
+      'subject' => 'subject b ' . time(),
+      'body_text' => 'body_text b ' . time(),
+    ]);
+    $this->_mailingID_C = $this->createMailing([
+      'subject' => 'not yet ' . time(),
+      'body_text' => 'not yet ' . time(),
+    ]);
     $this->_groupID = $this->groupCreate();
 
     $this->_params = array(
@@ -154,6 +163,65 @@ class api_v3_MailingABTest extends CiviUnitTestCase {
     $this->assertJobCounts(1, 1, 1);
   }
 
+  /**
+   * Create a test. Declare the second mailing a winner. Ensure that key
+   * fields propagate to the final mailing.
+   */
+  public function testSubmitWinnderId() {
+    $checkSyncFields = ['subject', 'body_text'];
+
+    $result = $this->groupContactCreate($this->_groupID, 20, TRUE);
+    $this->assertEquals(20, $result['added'], "in line " . __LINE__);
+
+    $params = $this->_params;
+    $params['group_percentage'] = 10;
+    $result = $this->callAPISuccess($this->_entity, 'create', $params);
+
+    $this->callAPISuccess('Mailing', 'create', [
+      'id' => $this->_mailingID_A,
+      'groups' => ['include' => [$this->_groupID]],
+    ]);
+    $this->assertJobCounts(0, 0, 0);
+
+    $this->callAPISuccess('MailingAB', 'submit', [
+      'id' => $result['id'],
+      'status' => 'Testing',
+      'scheduled_date' => 'now',
+      'approval_date' => 'now',
+    ]);
+    $this->assertJobCounts(1, 1, 0);
+
+    $b = $this->getApiValues('Mailing', ['id' => $this->_mailingID_B], $checkSyncFields);
+    $c = $this->getApiValues('Mailing', ['id' => $this->_mailingID_C], $checkSyncFields);
+    $this->assertNotEquals($b, $c);
+
+    $this->callAPISuccess('MailingAB', 'submit', [
+      'id' => $result['id'],
+      'status' => 'Final',
+      'winner_id' => $this->_mailingID_B,
+      'scheduled_date' => 'now',
+      'approval_date' => 'now',
+    ]);
+    $this->assertJobCounts(1, 1, 1);
+
+    $b = $this->getApiValues('Mailing', ['id' => $this->_mailingID_B], $checkSyncFields);
+    $c = $this->getApiValues('Mailing', ['id' => $this->_mailingID_C], $checkSyncFields);
+    $this->assertEquals($b, $c);
+  }
+
+  /**
+   * Lookup a record via API. Return *only* the expected values.
+   *
+   * @param $entity
+   * @param $filter
+   * @param $return
+   * @return array
+   */
+  protected function getApiValues($entity, $filter, $return) {
+    $rec = $this->callAPISuccess($entity, 'getsingle', $filter + ['return' => $return]);
+    return CRM_Utils_Array::subset($rec, $return);
+  }
+
   /**
    * @param $expectedCountA
    * @param $expectedCountB
index d543a2919ca0d34adfead88c4734a280ccf09615..e72fc5097e39991fbb02f745b776bd875cf75ee3 100644 (file)
@@ -55,7 +55,7 @@ class api_v3_MailingTest extends CiviUnitTestCase {
     $this->_params = array(
       'subject' => 'Hello {contact.display_name}',
       'body_text' => "This is {contact.display_name}.\nhttps://civicrm.org\n{domain.address}{action.optOutUrl}",
-      'body_html' => "<link href='https://fonts.googleapis.com/css?family=Roboto+Condensed:400,700|Zilla+Slab:500,700' rel='stylesheet' type='text/css'><p>This is {contact.display_name}.</p><p><a href='https://civicrm.org/'>CiviCRM.org</a></p><p>{domain.address}{action.optOutUrl}</p>",
+      'body_html' => "<link href='https://fonts.googleapis.com/css?family=Roboto+Condensed:400,700|Zilla+Slab:500,700' rel='stylesheet' type='text/css'><p><a href=\"http://{action.forward}\">Forward this email</a><a href=\"{action.forward}\">Forward this email with no protocol</a></p<p>This is {contact.display_name}.</p><p><a href='https://civicrm.org/'>CiviCRM.org</a></p><p>{domain.address}{action.optOutUrl}</p>",
       'name' => 'mailing name',
       'created_id' => $this->_contactID,
       'header_id' => '',
@@ -269,11 +269,30 @@ class api_v3_MailingTest extends CiviUnitTestCase {
     $this->assertDBQuery($maxIDs['group'], 'SELECT MAX(id) FROM civicrm_mailing_group');
     // 'Preview should not create any mailing_recipient records'
     $this->assertDBQuery($maxIDs['recipient'], 'SELECT MAX(id) FROM civicrm_mailing_recipients');
-
+    $baseurl = CRM_Utils_System::baseCMSURL();
     $previewResult = $result['values'][$result['id']]['api.Mailing.preview'];
     $this->assertEquals("Hello $displayName", $previewResult['values']['subject']);
     $this->assertContains("This is $displayName", $previewResult['values']['body_text']);
     $this->assertContains("<p>This is $displayName.</p>", $previewResult['values']['body_html']);
+    $this->assertContains('<a href="' . $baseurl . 'index.php?q=civicrm/mailing/forward&amp;amp;reset=1&amp;jid=&amp;qid=&amp;h=">Forward this email with no protocol</a>', $previewResult['values']['body_html']);
+    $this->assertNotContains("http://http://", $previewResult['values']['body_html']);
+  }
+
+  public function testMailerPreviewUnknownContact() {
+    $params = $this->_params;
+    $params['api.Mailing.preview'] = array(
+      'id' => '$value.id',
+    );
+
+    $result = $this->callAPISuccess('mailing', 'create', $params);
+
+    // NOTE: It's highly debatable what's best to do with contact-tokens for an
+    // unknown-contact. However, changes should be purposeful, so we'll test
+    // for the current behavior (i.e. returning blanks).
+    $previewResult = $result['values'][$result['id']]['api.Mailing.preview'];
+    $this->assertEquals("Hello ", $previewResult['values']['subject']);
+    $this->assertContains("This is .", $previewResult['values']['body_text']);
+    $this->assertContains("<p>This is .</p>", $previewResult['values']['body_html']);
   }
 
   public function testMailerPreviewRecipients() {
index 129495aa785575400e9300278efd3174bb6947b5..932a9a8ad5e20639949c0edff06aa4783d54a1ff 100644 (file)
@@ -202,7 +202,7 @@ class api_v3_PaymentTest extends CiviUnitTestCase {
       'from_financial_account_id' => 7,
       'to_financial_account_id' => 6,
       'total_amount' => -30,
-      'status_id' => 1,
+      'status_id' => CRM_Core_PseudoConstant::getKey('CRM_Core_BAO_FinancialTrxn', 'status_id', 'Refunded'),
       'is_payment' => 1,
     ];
     foreach ($expected as $key => $value) {
@@ -315,7 +315,7 @@ class api_v3_PaymentTest extends CiviUnitTestCase {
    */
   public function checkPaymentResult($payment, $expectedResult) {
     foreach ($expectedResult[$payment['id']] as $key => $value) {
-      $this->assertEquals($payment['values'][$payment['id']][$key], $value);
+      $this->assertEquals($payment['values'][$payment['id']][$key], $value, 'mismatch on ' . $key);
     }
   }
 
index 95c0ac018ac31a3d69b891687969b99fbcc88374..df222ccaadecdcf0dad271f35a8d186c1020f072 100644 (file)
@@ -24,8 +24,7 @@
 */
 
 
-
-require_once ('bin/cli.php');
+require_once('bin/cli.php');
 require_once 'CRM/Core/BAO/Tag.php';
 
 /**
@@ -41,7 +40,7 @@ class tagsImporter extends civicrm_cli {
       die("you need to profide a csv file (1st column parent name, 2nd tag name");
     }
     $this->file = $this->args[0];
-    $this->tags = array_flip(CRM_Core_PseudoConstant::get('CRM_Core_DAO_EntityTag', 'tag_id', array('onlyActive' => FALSE)));
+    $this->tags = array_flip(CRM_Core_PseudoConstant::get('CRM_Core_DAO_EntityTag', 'tag_id', ['onlyActive' => FALSE]));
   }
 
   //format expected: parent name, tag
@@ -70,12 +69,17 @@ class tagsImporter extends civicrm_cli {
       echo "\n- exists already: " . $param['name'];
       return;
     }
-    $key = array('tag' => '');
+    $key = ['tag' => ''];
     if ($param['parent']) {
       if (array_key_exists($param['parent'], $this->tags)) {
         $param['parent_id'] = $this->tags[$param['parent']];
       }
-      else $param['parent_id'] = $this->addTag(array(parent => '', name => $param['parent']));
+      else {
+        $param['parent_id'] = $this->addTag([
+          parent => '',
+          name => $param['parent'],
+        ]);
+      }
       $tag = CRM_Core_BAO_Tag::add($param, $key);
       echo "\n" . $tag->id . ": create " . $param['name'] . " below " . $param['parent'];
     }
index 331e3a6bad5c9bc13faaabb6c7bac0a9f661f8be..f4bfaf16f0f16b096b7585735a6cb2af54dde4ec 100644 (file)
@@ -44,7 +44,7 @@ function run() {
 
   require_once 'Console/Getopt.php';
   $shortOptions = "n:p:k:pre";
-  $longOptions = array('name=', 'pass=', 'key=', 'prefix=');
+  $longOptions = ['name=', 'pass=', 'key=', 'prefix='];
 
   $getopt = new Console_Getopt();
   $args = $getopt->readPHPArgv();
@@ -52,12 +52,12 @@ function run() {
   array_shift($args);
   list($valid, $dontCare) = $getopt->getopt2($args, $shortOptions, $longOptions);
 
-  $vars = array(
+  $vars = [
     'name' => 'n',
     'pass' => 'p',
     'key' => 'k',
     'prefix' => 'pre',
-  );
+  ];
 
   foreach ($vars as $var => $short) {
     $$var = NULL;
@@ -100,9 +100,10 @@ AND        phone NOT REGEXP '^[[:digit:]]{3}-[[:digit:]]{3}-[[:digit:]]{4}$'
   $dao = &CRM_Core_DAO::executeQuery($query);
 
   $updateQuery = "UPDATE civicrm_phone SET phone = %1 where id = %2";
-  $params = array(1 => array('', 'String'),
-    2 => array(0, 'Integer'),
-  );
+  $params = [
+    1 => ['', 'String'],
+    2 => [0, 'Integer'],
+  ];
   $totalPhone = $validPhone = $nonPrefixedPhone = 0;
   while ($dao->fetch()) {
     $newPhone = processPhone($dao->phone, $prefix);
index e95a66552b42b60d308a52cb8b6af09c2b083404..ba95cfb4a152366d879d2079fcb49fb9b2f859b5 100644 (file)
@@ -3,14 +3,14 @@
  * Scrape all config options from the CKEditor documentation site.
  */
 $content = file_get_contents('http://docs.ckeditor.com/?print=/api/CKEDITOR.config');
-$matches = $output = array();
+$matches = $output = [];
 preg_match_all("#name expandable'>([^<]+)</a>\s?:\s?(.*)<span.*'short'>([\s\S]*?)</div>#", $content, $matches);
 foreach ($matches[1] as $i => $name) {
-  $output[] = array(
+  $output[] = [
     'id' => $name,
     'type' => strip_tags($matches[2][$i]),
-    'description' => str_replace(array("\n", '. ...'), array(' ', '.'), $matches[3][$i]),
-  );
+    'description' => str_replace(["\n", '. ...'], [' ', '.'], $matches[3][$i]),
+  ];
 }
 if ($output) {
   $location = str_replace('tools/bin/scripts', '', __DIR__);
index 29b8704da0954d24240033a194e7567af9c6cef6..823e82ee713d8752d5e74cf548bc2b4e2e19fc78 100644 (file)
 
 /**
  * A PHP shell script
-
- On drupal if you have a symlink to your civi module, don't forget to create a new file - settings_location.php
- Enter the following code (substitute the actual location of your <drupal root>/sites directory)
- <?php
- define( 'CIVICRM_CONFDIR', '/var/www/drupal.6/sites' );
- ?>
-
+ *
+ * On drupal if you have a symlink to your civi module, don't forget to create a new file - settings_location.php
+ * Enter the following code (substitute the actual location of your <drupal root>/sites directory)
+ * <?php
+ * define( 'CIVICRM_CONFDIR', '/var/www/drupal.6/sites' );
+ * ?>
  */
 $include_path = "../packages/:" . get_include_path();
 set_include_path($include_path);
@@ -49,19 +48,19 @@ class civicrm_CLI {
     // set_include_path( $include_path );
     require_once 'Console/Getopt.php';
     $shortOptions = "s:u:p:k:";
-    $longOptions = array('site=', 'user', 'pass');
+    $longOptions = ['site=', 'user', 'pass'];
 
     $getopt = new Console_Getopt();
     $args = $getopt->readPHPArgv();
     array_shift($args);
     list($valid, $this->args) = $getopt->getopt2($args, $shortOptions, $longOptions);
 
-    $vars = array(
+    $vars = [
       'user' => 'u',
       'pass' => 'p',
       'key' => 'k',
       'site' => 's',
-    );
+    ];
 
     foreach ($vars as $var => $short) {
       $$var = NULL;
@@ -88,8 +87,8 @@ class civicrm_CLI {
   function authenticate($user, $pass) {
     session_start();
     require_once 'CRM/Core/Config.php';
-
-    $config = &CRM_Core_Config::singleton();
+    // Does calling this do anything here?
+    CRM_Core_Config::singleton();
 
     // this does not return on failure
     // require_once 'CRM/Utils/System.php';
@@ -102,7 +101,7 @@ class civicrm_CLI {
     $_SERVER['PHP_SELF'] = "/index.php";
     $_SERVER['HTTP_HOST'] = $this->site;
     $_REQUEST['key'] = $this->key;
-    require_once ("./civicrm.config.php");
+    require_once("./civicrm.config.php");
   }
 }
 
index c341602256666a4e033c91fc674a29457784118a..a7dff160fde32d2afcbcae5980f31566e18e57ac 100644 (file)
@@ -5,9 +5,9 @@ require_once 'CRM/Utils/Cache.php';
 
 define('CIVICRM_USE_MEMCACHE', 1);
 
-$config = &CRM_Core_Config::singleton();
-$cache = &CRM_Utils_Cache::singleton();
+$config = CRM_Core_Config::singleton();
+$cache = CRM_Utils_Cache::singleton();
 
-$cache->set('CRM_Core_Config' .CRM_Core_Config::domainID(), $config);
+$cache->set('CRM_Core_Config' . CRM_Core_Config::domainID(), $config);
 CRM_Core_Error::debug('get', $cache->get('CRM_Core_Config' . CRM_Core_Config::domainID()));
 
index 711c196483c3f8ba97646c41506223b93f612a40..4b7a6d60713c0ce8675a405e09d6f1115d2ce687 100755 (executable)
@@ -44,7 +44,7 @@ switch (@$argv[2]) {
 echo "Changing version from $oldVersion to $newVersion...\n";
 
 $verName = makeVerName($newVersion);
-$phpFile = initFile("CRM/Upgrade/Incremental/php/{$verName}.php", function() use ($verName) {
+$phpFile = initFile("CRM/Upgrade/Incremental/php/{$verName}.php", function () use ($verName) {
   ob_start();
   global $camelNumber;
   $camelNumber = $verName;
@@ -53,7 +53,7 @@ $phpFile = initFile("CRM/Upgrade/Incremental/php/{$verName}.php", function() use
   return ob_get_clean();
 });
 
-$sqlFile = initFile("CRM/Upgrade/Incremental/sql/{$newVersion}.mysql.tpl", function() use ($newVersion) {
+$sqlFile = initFile("CRM/Upgrade/Incremental/sql/{$newVersion}.mysql.tpl", function () use ($newVersion) {
   return "{* file to handle db changes in $newVersion during upgrade *}\n";
 });
 
index ecfc0f9f6ae0a2b2822f3ef59eaa0fe7a219fe7c..077836aa983fb74770fe0211f7e58c2cf6a4601e 100644 (file)
@@ -1,5 +1,6 @@
 <?php
-require_once '../civicrm.config.php'; require_once 'CRM/Core/Config.php';
+require_once '../civicrm.config.php';
+require_once 'CRM/Core/Config.php';
 require_once 'CRM/Core/Error.php';
 $config = CRM_Core_Config::singleton();
 
@@ -10,13 +11,14 @@ CRM_Core_Error::debug($report);
 exit();
 
 $xmlProcessor->run(104, 1, 'Substance Abuse', '15 Day Review');
-$params = array('clientID' => 104,
+$params = [
+  'clientID' => 104,
   'creatorID' => 108,
   'standardTimeline' => 1,
   'activityTypeName' => 'Open Case',
   'dueDateTime' => time(),
   'caseID' => 1,
-);
+];
 require_once 'CRM/Case/XMLProcessor/Process.php';
 $xmlProcessor = new CRM_Case_XMLProcessor_Process();
 
index f47685e1d4d2435ac9e88ad62f88ec9c534142d0..6d2f8fc20d3f87270396263cfa106f2af5d4f64a 100644 (file)
@@ -26,7 +26,6 @@
 */
 
 
-
 /*
  * This script recaches the display_name and sort_name values
  *
@@ -42,7 +41,7 @@ class CRM_UpdateNameCache {
   function __construct() {
     // you can run this program either from an apache command, or from the cli
     if (php_sapi_name() == "cli") {
-      require_once ("cli.php");
+      require_once("cli.php");
       $cli = new civicrm_cli();
       //if it doesn't die, it's authenticated
     }
@@ -81,9 +80,9 @@ class CRM_UpdateNameCache {
     $prefixes = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'prefix_id');
     $suffixes = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'suffix_id');
 
-    $tokens = array();
+    $tokens = [];
     CRM_Utils_Hook::tokens($tokens);
-    $tokenFields = array();
+    $tokenFields = [];
     foreach ($tokens as $category => $catTokens) {
       foreach ($catTokens as $token) {
         $tokenFields[] = $token;
@@ -100,12 +99,13 @@ class CRM_UpdateNameCache {
 
     while ($dao->fetch()) {
       $contactID = $dao->id;
-      $params = array('first_name' => $dao->first_name,
+      $params = [
+        'first_name' => $dao->first_name,
         'middle_name' => $dao->middle_name,
         'last_name' => $dao->last_name,
         'prefix_id' => $dao->prefix_id,
         'suffix_id' => $dao->suffix_id,
-      );
+      ];
       $params['individual_prefix'] = $prefixes[$dao->prefix_id];
       $params['individual_suffix'] = $suffixes[$dao->suffix_id];
 
index cba6b799f2ac1cd26fea2ab948ad5325ad59f458..9e4ae1695e699fcaef50b06a5db9267d6e874fae 100644 (file)
@@ -4,7 +4,7 @@
  * Implementation of hook_enable
  */
 function civicrm_webtest_enable() {
-  user_role_grant_permissions(1, array(
+  user_role_grant_permissions(1, [
     'access CiviMail subscribe/unsubscribe pages',
     'access all custom data',
     'access uploaded files',
@@ -12,7 +12,7 @@ function civicrm_webtest_enable() {
     'profile create',
     'profile view',
     'register for events',
-  ));
+  ]);
 
   $roles = user_roles();
   if (!in_array('civicrm_webtest_user', $roles)) {
@@ -20,87 +20,88 @@ function civicrm_webtest_enable() {
     $role->name = 'civicrm_webtest_user';
     user_role_save($role);
     $rid = $role->rid;
-  } else {
+  }
+  else {
     $rid = array_search('civicrm_webtest_user', $roles);
   }
 
-  user_role_grant_permissions($rid, array(
+  user_role_grant_permissions($rid, [
     // FIXME: whoa, why do we bother with users if both need admin rights?
-   'access AJAX API',
+    'access AJAX API',
     // 'access all cases and activities',
-   'access all custom data',
-   'access CiviContribute',
-   'access CiviCRM',
-   'access CiviEvent',
-   // 'access CiviGrant',
-   'access CiviMail',
-   'access CiviMail subscribe/unsubscribe pages',
-   'access CiviMember',
-   'access CiviPledge',
-   'access CiviReport',
-   'access Contact Dashboard',
-   'access contact reference fields',
-   'access deleted contacts',
-   // 'access my cases and activities',
-   'access Report Criteria',
-   'save Report Criteria',
-   'access uploaded files',
-   // 'add cases',
-   'add contacts',
-   // 'administer CiviCase',
-   'administer CiviCRM',
-   'administer dedupe rules',
-   'administer Reports',
-   'administer reserved groups',
-   'administer reserved reports',
-   'administer reserved tags',
-   'administer Tagsets',
-   'delete activities',
-   'delete contacts',
-   // 'delete in CiviCase',
-   'delete in CiviContribute',
-   'delete in CiviEvent',
-   // 'delete in CiviGrant',
-   'delete in CiviMail',
-   'delete in CiviMember',
-   'delete in CiviPledge',
-   'edit all contacts',
-   'view my contact',
-   'edit my contact',
-   'edit all events',
-   'edit contributions',
-   'edit event participants',
-   'edit message templates',
-   // 'edit grants',
-   'edit groups',
-   'edit memberships',
-   'edit pledges',
-   'import contacts',
-   'make online contributions',
-   'manage tags',
-   'merge duplicate contacts',
-   'profile create',
-   'profile edit',
-   'profile listings',
-   'profile listings and forms',
-   'profile view',
-   'register for events',
-   'translate CiviCRM',
-   'view all activities',
-   'view all contacts',
-   'view all notes',
-   'view event info',
-   'view event participants',
-   'view public CiviMail content',
-   'administer payment processors',
-   'create manual batch',
-   'edit own manual batches',
-   'edit all manual batches',
-   'view own manual batches',
-   'view all manual batches',
-   'delete own manual batches',
-   'delete all manual batches',
-   'export own manual batches',
-   'export all manual batches',
-  ));
+    'access all custom data',
+    'access CiviContribute',
+    'access CiviCRM',
+    'access CiviEvent',
+    // 'access CiviGrant',
+    'access CiviMail',
+    'access CiviMail subscribe/unsubscribe pages',
+    'access CiviMember',
+    'access CiviPledge',
+    'access CiviReport',
+    'access Contact Dashboard',
+    'access contact reference fields',
+    'access deleted contacts',
+    // 'access my cases and activities',
+    'access Report Criteria',
+    'save Report Criteria',
+    'access uploaded files',
+    // 'add cases',
+    'add contacts',
+    // 'administer CiviCase',
+    'administer CiviCRM',
+    'administer dedupe rules',
+    'administer Reports',
+    'administer reserved groups',
+    'administer reserved reports',
+    'administer reserved tags',
+    'administer Tagsets',
+    'delete activities',
+    'delete contacts',
+    // 'delete in CiviCase',
+    'delete in CiviContribute',
+    'delete in CiviEvent',
+    // 'delete in CiviGrant',
+    'delete in CiviMail',
+    'delete in CiviMember',
+    'delete in CiviPledge',
+    'edit all contacts',
+    'view my contact',
+    'edit my contact',
+    'edit all events',
+    'edit contributions',
+    'edit event participants',
+    'edit message templates',
+    // 'edit grants',
+    'edit groups',
+    'edit memberships',
+    'edit pledges',
+    'import contacts',
+    'make online contributions',
+    'manage tags',
+    'merge duplicate contacts',
+    'profile create',
+    'profile edit',
+    'profile listings',
+    'profile listings and forms',
+    'profile view',
+    'register for events',
+    'translate CiviCRM',
+    'view all activities',
+    'view all contacts',
+    'view all notes',
+    'view event info',
+    'view event participants',
+    'view public CiviMail content',
+    'administer payment processors',
+    'create manual batch',
+    'edit own manual batches',
+    'edit all manual batches',
+    'view own manual batches',
+    'view all manual batches',
+    'delete own manual batches',
+    'delete all manual batches',
+    'export own manual batches',
+    'export all manual batches',
+  ]);
 }
index 79958c9e4000dd56f574a62a4caedc94d1feecb0..69dee259d3dc1d6980562ad452e388133fff82af 100644 (file)
  */
 function _angularex_civix_civicrm_config(&$config = NULL) {
   static $configured = FALSE;
-  if ($configured) return;
+  if ($configured) {
+    return;
+  }
   $configured = TRUE;
 
   $template =& CRM_Core_Smarty::singleton();
 
-  $extRoot = dirname( __FILE__ ) . DIRECTORY_SEPARATOR;
+  $extRoot = dirname(__FILE__) . DIRECTORY_SEPARATOR;
   $extDir = $extRoot . 'templates';
 
-  if ( is_array( $template->template_dir ) ) {
-      array_unshift( $template->template_dir, $extDir );
-  } else {
-      $template->template_dir = array( $extDir, $template->template_dir );
+  if (is_array($template->template_dir)) {
+    array_unshift($template->template_dir, $extDir);
+  }
+  else {
+    $template->template_dir = [$extDir, $template->template_dir];
   }
 
-  $include_path = $extRoot . PATH_SEPARATOR . get_include_path( );
-  set_include_path( $include_path );
+  $include_path = $extRoot . PATH_SEPARATOR . get_include_path();
+  set_include_path($include_path);
 }
 
 /**
@@ -72,7 +75,7 @@ function _angularex_civix_civicrm_uninstall() {
 function _angularex_civix_civicrm_enable() {
   _angularex_civix_civicrm_config();
   if ($upgrader = _angularex_civix_upgrader()) {
-    if (is_callable(array($upgrader, 'onEnable'))) {
+    if (is_callable([$upgrader, 'onEnable'])) {
       return $upgrader->onEnable();
     }
   }
@@ -86,7 +89,7 @@ function _angularex_civix_civicrm_enable() {
 function _angularex_civix_civicrm_disable() {
   _angularex_civix_civicrm_config();
   if ($upgrader = _angularex_civix_upgrader()) {
-    if (is_callable(array($upgrader, 'onDisable'))) {
+    if (is_callable([$upgrader, 'onDisable'])) {
       return $upgrader->onDisable();
     }
   }
@@ -113,9 +116,10 @@ function _angularex_civix_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) {
  * @return CRM_Angularex_Upgrader
  */
 function _angularex_civix_upgrader() {
-  if (!file_exists(__DIR__.'/CRM/Angularex/Upgrader.php')) {
+  if (!file_exists(__DIR__ . '/CRM/Angularex/Upgrader.php')) {
     return NULL;
-  } else {
+  }
+  else {
     return CRM_Angularex_Upgrader_Base::instance();
   }
 }
@@ -131,12 +135,12 @@ function _angularex_civix_upgrader() {
  * @return array(string)
  */
 function _angularex_civix_find_files($dir, $pattern) {
-  if (is_callable(array('CRM_Utils_File', 'findFiles'))) {
+  if (is_callable(['CRM_Utils_File', 'findFiles'])) {
     return CRM_Utils_File::findFiles($dir, $pattern);
   }
 
-  $todos = array($dir);
-  $result = array();
+  $todos = [$dir];
+  $result = [];
   while (!empty($todos)) {
     $subdir = array_shift($todos);
     foreach (_angularex_civix_glob("$subdir/$pattern") as $match) {
@@ -148,7 +152,8 @@ function _angularex_civix_find_files($dir, $pattern) {
       while (FALSE !== ($entry = readdir($dh))) {
         $path = $subdir . DIRECTORY_SEPARATOR . $entry;
         if ($entry{0} == '.') {
-        } elseif (is_dir($path)) {
+        }
+        elseif (is_dir($path)) {
           $todos[] = $path;
         }
       }
@@ -202,11 +207,11 @@ function _angularex_civix_civicrm_caseTypes(&$caseTypes) {
       CRM_Core_Error::fatal($errorMessage);
       // throw new CRM_Core_Exception($errorMessage);
     }
-    $caseTypes[$name] = array(
+    $caseTypes[$name] = [
       'module' => 'org.civicrm.angularex',
       'name' => $name,
       'file' => $file,
-    );
+    ];
   }
 }
 
@@ -224,7 +229,7 @@ function _angularex_civix_civicrm_caseTypes(&$caseTypes) {
  */
 function _angularex_civix_glob($pattern) {
   $result = glob($pattern);
-  return is_array($result) ? $result : array();
+  return is_array($result) ? $result : [];
 }
 
 /**
@@ -245,25 +250,30 @@ function _angularex_civix_insert_navigation_menu(&$menu, $path, $item, $parentId
 
   // If we are done going down the path, insert menu
   if (empty($path)) {
-    if (!$navId) $navId = CRM_Core_DAO::singleValueQuery("SELECT max(id) FROM civicrm_navigation");
-    $navId ++;
-    $menu[$navId] = array (
-      'attributes' => array_merge($item, array(
-        'label'      => CRM_Utils_Array::value('name', $item),
-        'active'     => 1,
-        'parentID'   => $parentId,
-        'navID'      => $navId,
-      ))
-    );
-    return true;
-  } else {
+    if (!$navId) {
+      $navId = CRM_Core_DAO::singleValueQuery("SELECT max(id) FROM civicrm_navigation");
+    }
+    $navId++;
+    $menu[$navId] = [
+      'attributes' => array_merge($item, [
+        'label' => CRM_Utils_Array::value('name', $item),
+        'active' => 1,
+        'parentID' => $parentId,
+        'navID' => $navId,
+      ]),
+    ];
+    return TRUE;
+  }
+  else {
     // Find an recurse into the next level down
-    $found = false;
+    $found = FALSE;
     $path = explode('/', $path);
     $first = array_shift($path);
     foreach ($menu as $key => &$entry) {
       if ($entry['attributes']['name'] == $first) {
-        if (!$entry['child']) $entry['child'] = array();
+        if (!$entry['child']) {
+          $entry['child'] = [];
+        }
         $found = _angularex_civix_insert_navigation_menu($entry['child'], implode('/', $path), $item, $key);
       }
     }
@@ -279,11 +289,13 @@ function _angularex_civix_insert_navigation_menu(&$menu, $path, $item, $parentId
  */
 function _angularex_civix_civicrm_alterSettingsFolders(&$metaDataFolders = NULL) {
   static $configured = FALSE;
-  if ($configured) return;
+  if ($configured) {
+    return;
+  }
   $configured = TRUE;
 
   $settingsDir = __DIR__ . DIRECTORY_SEPARATOR . 'settings';
-  if(is_dir($settingsDir) && !in_array($settingsDir, $metaDataFolders)) {
+  if (is_dir($settingsDir) && !in_array($settingsDir, $metaDataFolders)) {
     $metaDataFolders[] = $settingsDir;
   }
 }
index 064f725453311ebd296e8522bb6429e9a882b109..225edb358a79145a276dbb72ebe7f6549e58bad6 100644 (file)
@@ -115,9 +115,9 @@ function angularex_civicrm_alterSettingsFolders(&$metaDataFolders = NULL) {
  * @param $angularModule
  */
 function angularex_civicrm_angularModules(&$angularModule) {
-  $angularModule['example'] = array(
+  $angularModule['example'] = [
     'ext' => 'org.civicrm.angularex',
-    'js' => array('js/*.js'),
-    'partials' => array('partials'),
-  );
+    'js' => ['js/*.js'],
+    'partials' => ['partials'],
+  ];
 }
index df73fb08ba5057042ff34ec549407c3c757cba1d..a63c4eea01d10e16eeaf1a782868e1064ecf54c8 100644 (file)
@@ -9,33 +9,33 @@ class CRM_Demoqueue_Page_DemoQueue extends CRM_Core_Page {
   const QUEUE_NAME = 'demo-queue';
 
   function run() {
-    $queue = CRM_Queue_Service::singleton()->create(array(
+    $queue = CRM_Queue_Service::singleton()->create([
       'type' => 'Sql',
       'name' => self::QUEUE_NAME,
       'reset' => TRUE,
-    ));
+    ]);
 
     for ($i = 0; $i < 5; $i++) {
       $queue->createItem(new CRM_Queue_Task(
-        array('CRM_Demoqueue_Page_DemoQueue', 'doMyWork'), // callback
-        array($i, "Task $i takes $i second(s)"), // arguments
+        ['CRM_Demoqueue_Page_DemoQueue', 'doMyWork'], // callback
+        [$i, "Task $i takes $i second(s)"], // arguments
         "Task $i" // title
       ));
       if ($i == 2) {
         $queue->createItem(new CRM_Queue_Task(
-          array('CRM_Demoqueue_Page_DemoQueue', 'addMoreWork'), // callback
-          array(), // arguments
+          ['CRM_Demoqueue_Page_DemoQueue', 'addMoreWork'], // callback
+          [], // arguments
           "Add More Work" // title
         ));
       }
     }
 
-    $runner = new CRM_Queue_Runner(array(
+    $runner = new CRM_Queue_Runner([
       'title' => ts('Demo Queue Runner'),
       'queue' => $queue,
-      'onEnd' => array('CRM_Demoqueue_Page_DemoQueue', 'onEnd'),
+      'onEnd' => ['CRM_Demoqueue_Page_DemoQueue', 'onEnd'],
       'onEndUrl' => CRM_Utils_System::url('civicrm/demo-queue/done'),
-    ));
+    ]);
     $runner->runAllViaWeb(); // does not return
   }
 
@@ -65,12 +65,12 @@ class CRM_Demoqueue_Page_DemoQueue extends CRM_Core_Page {
     sleep(1);
     for ($i = 0; $i < 5; $i++) {
       $ctx->queue->createItem(new CRM_Queue_Task(
-        array('CRM_Demoqueue_Page_DemoQueue', 'doMyWork'), // callback
-        array($i, "Extra task $i takes $i second(s)"), // arguments
+        ['CRM_Demoqueue_Page_DemoQueue', 'doMyWork'], // callback
+        [$i, "Extra task $i takes $i second(s)"], // arguments
         "Extra Task $i" // title
-      ), array(
+      ), [
         'weight' => -1,
-      ));
+      ]);
     }
     return TRUE; // success
   }
index 6f1eb17782e5abff66f83c69ab85956bf7986297..3f9fd4e427f7b47807ebda31b8d308aaa21a0bc0 100644 (file)
@@ -6,9 +6,9 @@ require_once 'CRM/Core/Page.php';
  * Class CRM_Demoqueue_Page_DemoQueueDone
  */
 class CRM_Demoqueue_Page_DemoQueueDone extends CRM_Core_Page {
-    function run() {
-        // Example: Set the page-title dynamically; alternatively, declare a static title in xml/Menu/*.xml
-        CRM_Utils_System::setTitle(ts('DemoQueueDone'));
-        parent::run();
-    }
+  function run() {
+    // Example: Set the page-title dynamically; alternatively, declare a static title in xml/Menu/*.xml
+    CRM_Utils_System::setTitle(ts('DemoQueueDone'));
+    parent::run();
+  }
 }
index cfc2973f96640caf8fd2d8bf61bfb5d9c4fe56b6..2f643279ded3e7b1b0b4e2c96454c96a8543a2c1 100644 (file)
@@ -9,17 +9,18 @@
 function _demoqueue_civix_civicrm_config(&$config) {
   $template =& CRM_Core_Smarty::singleton();
 
-  $extRoot = dirname( __FILE__ ) . DIRECTORY_SEPARATOR;
+  $extRoot = dirname(__FILE__) . DIRECTORY_SEPARATOR;
   $extDir = $extRoot . 'templates';
 
-  if ( is_array( $template->template_dir ) ) {
-      array_unshift( $template->template_dir, $extDir );
-  } else {
-      $template->template_dir = array( $extDir, $template->template_dir );
+  if (is_array($template->template_dir)) {
+    array_unshift($template->template_dir, $extDir);
+  }
+  else {
+    $template->template_dir = [$extDir, $template->template_dir];
   }
 
-  $include_path = $extRoot . PATH_SEPARATOR . get_include_path( );
-  set_include_path( $include_path );
+  $include_path = $extRoot . PATH_SEPARATOR . get_include_path();
+  set_include_path($include_path);
 }
 
 /**
index b0d44d3003a9def28aeea923471e8219a3fd2b50..79a97aa097c641f3b7902b82f00f37c1fba404b3 100755 (executable)
@@ -5,7 +5,7 @@ eval(`cv php:boot`);
 global $civicrm_root;
 $realArgs = $argv;
 $diffCmd = FALSE;
-$files = array();
+$files = [];
 
 array_shift($realArgs);
 foreach ($realArgs as $arg) {
@@ -52,7 +52,7 @@ function compareFile($file, $diffCmd) {
     echo "File \"$file\" appears to have consistency issues. Created $newFile.\n";
     file_put_contents($newFile, $newMarkup);
     if ($diffCmd) {
-      passthru($diffCmd . ' '  . escapeshellarg($file) . ' ' . escapeshellarg($newFile));
+      passthru($diffCmd . ' ' . escapeshellarg($file) . ' ' . escapeshellarg($newFile));
     }
   }
-}
\ No newline at end of file
+}
index 63bb5a83a5e90ff6aaff6c0eb63b3e62964a37ff..8c79fb8c796ecb69f7c6802725bf2f274b2398c7 100644 (file)
@@ -1,5 +1,6 @@
 <?php
-$options = getopt('bc:ht:'); if (isset($options['h'])) {
+$options = getopt('bc:ht:');
+if (isset($options['h'])) {
   print ("\nUsage: php civimail-spooler.php [-bh] [-c <config>] [-t <period>]\n");
   print ("   -b  Run this process continuously\n");
   print ("   -c  Path to CiviCRM civicrm.settings.php\n");
@@ -17,7 +18,7 @@ require_once "$config_file";
 require_once "CRM/Core/Config.php";
 ');
 
-$config = &CRM_Core_Config::singleton();
+$config = CRM_Core_Config::singleton();
 
 /* Temporary permissioning hack for now */
 
@@ -34,7 +35,6 @@ if (isset($options['b'])) {
          * process into the background and provide init.d scripts */
 
 
-
     CRM_Mailing_BAO_MailingJob::runJobs();
     sleep($config->mailerPeriod);
   }
index effecbdbb02e322eef025157b54b41f2a1bfc2b3..42c1f39dd5b92ebe60e89a7200a34fb5ab32f90a 100644 (file)
@@ -23,3 +23,20 @@ index 3acadc3..06f1e71 100644
  /**
   * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
   * @version //autogentag//
+diff --git a/src/parser/interfaces/part_parser.php b/src/parser/interfaces/part_parser.php
+index a81378b..6c59e5a 100644
+--- a/src/parser/interfaces/part_parser.php
++++ b/src/parser/interfaces/part_parser.php
+@@ -168,7 +168,11 @@ abstract class ezcMailPartParser
+                 break;
+             case 'text':
+-                if ( ezcMailPartParser::$parseTextAttachmentsAsFiles === true )
++                // dev/core#940 Ensure that emails are not processed as .unknown attachments by checking
++                // for Filename or name in the content-disposition and content-type headers.
++                if ( (ezcMailPartParser::$parseTextAttachmentsAsFiles === true)                   &&
++                     (preg_match('/\s*filename="?([^;"]*);?/i', $headers['Content-Disposition']) ||
++                      preg_match( '/\s*name="?([^;"]*);?/i'   , $headers['Content-Type'])        )  )
+                 {
+                     $bodyParser = new ezcMailFileParser( $mainType, $subType, $headers );
+                 }
index bbe6eeae6c10f50448e0090920188501d595cecd..d567aa6991a6aa466c29e4f19a350f4684a64f67 100644 (file)
@@ -42,10 +42,10 @@ define('CHUNK_SIZE', 128);
 function &splitContactIDs(&$contactIDs) {
   // contactIDs could be a real large array, so we split it up into
   // smaller chunks and then general xml for each chunk
-  $chunks           = array();
-  $current          = 0;
-  $chunks[$current] = array();
-  $count            = 0;
+  $chunks = [];
+  $current = 0;
+  $chunks[$current] = [];
+  $count = 0;
 
   foreach ($contactIDs as $cid) {
     $chunks[$current][] = $cid;
@@ -53,7 +53,7 @@ function &splitContactIDs(&$contactIDs) {
 
     if ($count == CHUNK_SIZE) {
       $current++;
-      $chunks[$current] = array();
+      $chunks[$current] = [];
       $count = 0;
     }
   }
@@ -81,7 +81,7 @@ function &generateSolrJSON($values) {
 
     foreach ($tokens as $n => $v) {
       if (is_array($v)) {
-        $str = array();
+        $str = [];
         foreach ($v as $el) {
           $el = escapeJsonString($el);
           $str[] = "\"$el\"";
@@ -115,8 +115,8 @@ function &generateSolrJSON($values) {
  * @return mixed
  */
 function escapeJsonString($value) {
-  $escapers = array("\\", "/", "\"", "\n", "\r", "\t", "\x08", "\x0c");
-  $replacements = array("\\\\", "\\/", "\\\"", "\\n", "\\r", "\\t", "\\f", "\\b");
+  $escapers = ["\\", "/", "\"", "\n", "\r", "\t", "\x08", "\x0c"];
+  $replacements = ["\\\\", "\\/", "\\\"", "\\n", "\\r", "\\t", "\\f", "\\b"];
   return str_replace($escapers, $replacements, $value);
 }
 
@@ -127,10 +127,10 @@ function escapeJsonString($value) {
  * @return array
  */
 function getValues(&$contactIDs, &$values) {
-  $values = array();
+  $values = [];
 
   foreach ($contactIDs as $cid) {
-    $values[$cid] = array();
+    $values[$cid] = [];
   }
 
   getContactInfo($contactIDs, $values);
@@ -178,7 +178,8 @@ SELECT $selectString, $whereField as contact_id
  * @param $values
  */
 function getContactInfo(&$contactIDs, &$values) {
-  $fields = array('sort_name' => NULL,
+  $fields = [
+    'sort_name' => NULL,
     'display_name' => NULL,
     'contact_type' => NULL,
     'legal_identifier' => NULL,
@@ -190,7 +191,7 @@ function getContactInfo(&$contactIDs, &$values) {
     'organization_name' => NULL,
     'legal_name' => NULL,
     'job_title' => NULL,
-  );
+  ];
   getTableInfo($contactIDs, $values, 'civicrm_contact', $fields, 'id');
 }
 
@@ -312,10 +313,17 @@ LEFT  JOIN civicrm_country        co ON a.country_id        = co.id
 WHERE c.id IN ( $ids )
 ";
 
-  $fields = array('location_type', 'street_address', 'supplemental_address_1',
-    'supplemental_address_2', 'supplemental_address_3', 'city', 'postal_code',
-    'state', 'country',
-  );
+  $fields = [
+    'location_type',
+    'street_address',
+    'supplemental_address_1',
+    'supplemental_address_2',
+    'supplemental_address_3',
+    'city',
+    'postal_code',
+    'state',
+    'country',
+  ];
   $dao = &CRM_Core_DAO::executeQuery($sql);
   while ($dao->fetch()) {
     $address = '';
@@ -352,7 +360,7 @@ function appendValue(&$values, $contactID, $name, $value) {
   else {
     if (!is_array($values[$contactID][$name])) {
       $save = $values[$contactID][$name];
-      $values[$contactID][$name] = array();
+      $values[$contactID][$name] = [];
       $values[$contactID][$name][] = $save;
     }
     $values[$contactID][$name][] = $value;
@@ -366,14 +374,14 @@ function run(&$contactIDs) {
   $chunks = &splitContactIDs($contactIDs);
 
   foreach ($chunks as $chunk) {
-    $values = array();
+    $values = [];
     getValues($chunk, $values);
     $xml = &generateSolrJSON($values);
     echo $xml;
   }
 }
 
-$config = &CRM_Core_Config::singleton();
+$config = CRM_Core_Config::singleton();
 $config->userFramework = 'Soap';
 $config->userFrameworkClass = 'CRM_Utils_System_Soap';
 $config->userHookClass = 'CRM_Utils_Hook_Soap';
@@ -385,7 +393,7 @@ EOT;
 $dao = &CRM_Core_DAO::executeQuery($sql);
 
 
-$contactIDs = array();
+$contactIDs = [];
 while ($dao->fetch()) {
   $contactIDs[] = $dao->id;
 }
index a00b15a4bfa0edd169b819067a45f49734f6287a..b0f207dc31166f8fa2f3f728f52be52cfe3ff08a 100644 (file)
@@ -42,10 +42,10 @@ define('CHUNK_SIZE', 128);
 function &splitContactIDs(&$contactIDs) {
   // contactIDs could be a real large array, so we split it up into
   // smaller chunks and then general xml for each chunk
-  $chunks           = array();
-  $current          = 0;
-  $chunks[$current] = array();
-  $count            = 0;
+  $chunks = [];
+  $current = 0;
+  $chunks[$current] = [];
+  $count = 0;
 
   foreach ($contactIDs as $cid) {
     $chunks[$current][] = $cid;
@@ -53,7 +53,7 @@ function &splitContactIDs(&$contactIDs) {
 
     if ($count == CHUNK_SIZE) {
       $current++;
-      $chunks[$current] = array();
+      $chunks[$current] = [];
       $count = 0;
     }
   }
@@ -103,10 +103,10 @@ EOT;
  * @return array
  */
 function getValues(&$contactIDs, &$values) {
-  $values = array();
+  $values = [];
 
   foreach ($contactIDs as $cid) {
-    $values[$cid] = array();
+    $values[$cid] = [];
   }
 
   getContactInfo($contactIDs, $values);
@@ -146,7 +146,7 @@ SELECT $selectString, $whereField as contact_id
       if (!$name) {
         $name = $fld;
       }
-      $values[$dao->contact_id][] = array($name, $dao->$fld);
+      $values[$dao->contact_id][] = [$name, $dao->$fld];
     }
   }
 }
@@ -156,34 +156,38 @@ SELECT $selectString, $whereField as contact_id
  * @param $values
  */
 function getContactInfo(&$contactIDs, &$values) {
-  $fields = array('sort_name' => NULL,
+  $fields = [
+    'sort_name' => NULL,
     'display_name' => NULL,
     'contact_type' => NULL,
     'legal_identifier' => NULL,
     'external_identifier' => NULL,
     'source' => 'contact_source',
-  );
+  ];
   getTableInfo($contactIDs, $values, 'civicrm_contact', $fields, 'id');
 
-  $fields = array('first_name' => NULL,
+  $fields = [
+    'first_name' => NULL,
     'last_name' => NULL,
     'middle_name' => NULL,
     'job_title' => NULL,
-  );
+  ];
   getTableInfo($contactIDs, $values, 'civicrm_individual', $fields, 'contact_id');
 
-  $fields = array('household_name' => NULL);
+  $fields = ['household_name' => NULL];
   getTableInfo($contactIDs, $values, 'civicrm_household', $fields, 'contact_id');
 
-  $fields = array('organization_name' => NULL,
+  $fields = [
+    'organization_name' => NULL,
     'legal_name' => NULL,
     'sic_code' => NULL,
-  );
+  ];
   getTableInfo($contactIDs, $values, 'civicrm_organization', $fields, 'contact_id');
 
-  $fields = array('note' => 'note_body',
+  $fields = [
+    'note' => 'note_body',
     'subject' => 'note_subject',
-  );
+  ];
   getTableInfo($contactIDs, $values, 'civicrm_note', $fields, 'entity_id', "entity_table = 'civicrm_contact'");
 }
 
@@ -215,17 +219,28 @@ WHERE l.entity_table = 'civicrm_contact'
   AND l.entity_id IN ( $ids )
 ";
 
-  $fields = array('location_name', 'street_address', 'supplemental_address_1',
-    'supplemental_address_2', 'supplemental_address_3', 'city', 'postal_code', 'county', 'state',
-    'country', 'email', 'phone', 'im',
-  );
+  $fields = [
+    'location_name',
+    'street_address',
+    'supplemental_address_1',
+    'supplemental_address_2',
+    'supplemental_address_3',
+    'city',
+    'postal_code',
+    'county',
+    'state',
+    'country',
+    'email',
+    'phone',
+    'im',
+  ];
   $dao = CRM_Core_DAO::executeQuery($sql);
   while ($dao->fetch()) {
     foreach ($fields as $fld) {
       if (empty($dao->$fld)) {
         continue;
       }
-      $values[$dao->contact_id][] = array($fld, $dao->$fld);
+      $values[$dao->contact_id][] = [$fld, $dao->$fld];
     }
   }
 }
@@ -237,14 +252,14 @@ function run(&$contactIDs) {
   $chunks = &splitContactIDs($contactIDs);
 
   foreach ($chunks as $chunk) {
-    $values = array();
+    $values = [];
     getValues($chunk, $values);
     $xml = &generateSolrXML($values);
     echo $xml;
   }
 }
 
-$config = &CRM_Core_Config::singleton();
+$config = CRM_Core_Config::singleton();
 $config->userFramework = 'Soap';
 $config->userFrameworkClass = 'CRM_Utils_System_Soap';
 $config->userHookClass = 'CRM_Utils_Hook_Soap';
@@ -255,7 +270,7 @@ FROM civicrm_contact
 EOT;
 $dao = CRM_Core_DAO::executeQuery($sql);
 
-$contactIDs = array();
+$contactIDs = [];
 while ($dao->fetch()) {
   $contactIDs[] = $dao->id;
 }
index 540978056c07fd635fc5cb4eafa1b67c4f1e317c..95d4fac75fffc867855038d0a964b0b944cf8235 100644 (file)
@@ -42,10 +42,10 @@ define('CHUNK_SIZE', 128);
 function &splitContactIDs(&$contactIDs) {
   // contactIDs could be a real large array, so we split it up into
   // smaller chunks and then general xml for each chunk
-  $chunks           = array();
-  $current          = 0;
-  $chunks[$current] = array();
-  $count            = 0;
+  $chunks = [];
+  $current = 0;
+  $chunks[$current] = [];
+  $count = 0;
 
   foreach ($contactIDs as $k => $v) {
     $chunks[$current][$k] = $v;
@@ -53,7 +53,7 @@ function &splitContactIDs(&$contactIDs) {
 
     if ($count == CHUNK_SIZE) {
       $current++;
-      $chunks[$current] = array();
+      $chunks[$current] = [];
       $count = 0;
     }
   }
@@ -74,7 +74,7 @@ function &splitContactIDs(&$contactIDs) {
  * @return array
  */
 function getValues(&$contactIDs, &$values, &$allContactIDs, &$addditionalContactIDs) {
-  $values = array();
+  $values = [];
 
   getContactInfo($contactIDs, $values);
   getAddressInfo($contactIDs, $values);
@@ -103,8 +103,8 @@ function getValues(&$contactIDs, &$values, &$allContactIDs, &$addditionalContact
  * @param bool $flat
  */
 function getTableInfo(&$contactIDs, &$values, $tableName, &$fields,
-  $whereField, $additionalWhereCond = NULL,
-  $flat = FALSE
+                      $whereField, $additionalWhereCond = NULL,
+                      $flat = FALSE
 ) {
   $selectString = implode(',', array_keys($fields));
   $idString = implode(',', $contactIDs);
@@ -121,7 +121,7 @@ SELECT $selectString, $whereField as contact_id
 
   $dao = &CRM_Core_DAO::executeQuery($sql);
   while ($dao->fetch()) {
-    $contact = array();
+    $contact = [];
     foreach ($fields as $fld => $name) {
       $name = $name ? $name : $fld;
       if (empty($dao->$fld)) {
@@ -141,7 +141,8 @@ SELECT $selectString, $whereField as contact_id
  * @param $values
  */
 function getContactInfo(&$contactIDs, &$values) {
-  $fields = array('id' => NULL,
+  $fields = [
+    'id' => NULL,
     'sort_name' => NULL,
     'display_name' => NULL,
     'contact_type' => NULL,
@@ -154,7 +155,7 @@ function getContactInfo(&$contactIDs, &$values) {
     'organization_name' => NULL,
     'legal_name' => NULL,
     'job_title' => NULL,
-  );
+  ];
   getTableInfo($contactIDs, $values, 'civicrm_contact', $fields, 'id', NULL, TRUE);
 }
 
@@ -177,11 +178,12 @@ AND   entity_table = 'civicrm_contact'
 
   $dao = &CRM_Core_DAO::executeQuery($sql);
   while ($dao->fetch()) {
-    $note = array('id' => $dao->id,
+    $note = [
+      'id' => $dao->id,
       'contact_id' => $dao->contact_id,
       'subject' => empty($dao->subject) ? NULL : $dao->subject,
       'note' => empty($dao->note) ? NULL : $dao->note,
-    );
+    ];
 
     appendValue($values, $dao->id, 'note', $note);
   }
@@ -213,12 +215,13 @@ AND        p.phone IS NOT NULL
 
   $dao = &CRM_Core_DAO::executeQuery($sql);
   while ($dao->fetch()) {
-    $phone = array('id' => $dao->id,
+    $phone = [
+      'id' => $dao->id,
       'contact_id' => $dao->contact_id,
       'location_type' => empty($dao->location_type) ? NULL : $dao->location_type,
       'phone' => $dao->phone,
       'phone_type' => empty($dao->phone_type) ? NULL : $dao->phone_type,
-    );
+    ];
 
     appendValue($values, $dao->id, 'phone', $phone);
   }
@@ -247,11 +250,12 @@ AND        e.email IS NOT NULL
 
   $dao = &CRM_Core_DAO::executeQuery($sql);
   while ($dao->fetch()) {
-    $email = array('id' => $dao->id,
+    $email = [
+      'id' => $dao->id,
       'contact_id' => $dao->contact_id,
       'location_type' => empty($dao->location_type) ? NULL : $dao->location_type,
       'email' => $dao->email,
-    );
+    ];
     appendValue($values, $dao->id, 'email', $email);
   }
   $dao->free();
@@ -279,14 +283,22 @@ LEFT  JOIN civicrm_country        co ON a.country_id        = co.id
 WHERE c.id IN ( $ids )
 ";
 
-  $fields = array('id', 'contact_id',
-    'location_type', 'street_address', 'supplemental_address_1',
-    'supplemental_address_2', 'supplemental_address_3', 'city', 'postal_code',
-    'state', 'country',
-  );
+  $fields = [
+    'id',
+    'contact_id',
+    'location_type',
+    'street_address',
+    'supplemental_address_1',
+    'supplemental_address_2',
+    'supplemental_address_3',
+    'city',
+    'postal_code',
+    'state',
+    'country',
+  ];
   $dao = &CRM_Core_DAO::executeQuery($sql);
   while ($dao->fetch()) {
-    $address = array();
+    $address = [];
     foreach ($fields as $fld) {
       if (empty($dao->$fld)) {
         $address[$fld] = NULL;
@@ -308,7 +320,7 @@ WHERE c.id IN ( $ids )
  */
 function getRelationshipInfo(&$contactIDs, &$values, &$allContactIDs, &$additionalContacts) {
   // handle relationships only once
-  static $_relationshipsHandled = array();
+  static $_relationshipsHandled = [];
 
   $ids = implode(',', $contactIDs);
 
@@ -324,15 +336,15 @@ function getRelationshipInfo(&$contactIDs, &$values, &$allContactIDs, &$addition
 ";
 
   $relationshipFields = getDBFields('CRM_Contact_DAO_Relationship');
-  $fields             = array_keys($relationshipFields);
-  $dao                = &CRM_Core_DAO::executeQuery($sql);
+  $fields = array_keys($relationshipFields);
+  $dao = &CRM_Core_DAO::executeQuery($sql);
   while ($dao->fetch()) {
     if (isset($_relationshipsHandled[$dao->id])) {
       continue;
     }
     $_relationshipsHandled[$dao->id] = $dao->id;
 
-    $relationship = array();
+    $relationship = [];
     foreach ($fields as $fld) {
       if (empty($dao->$fld)) {
         $relationship[$fld] = NULL;
@@ -343,9 +355,10 @@ function getRelationshipInfo(&$contactIDs, &$values, &$allContactIDs, &$addition
     }
     appendValue($values, $dao->id, 'relationship', $relationship);
 
-    addAdditionalContacts(array($dao->contact_id_a,
-        $dao->contact_id_b,
-      ),
+    addAdditionalContacts([
+      $dao->contact_id_a,
+      $dao->contact_id_b,
+    ],
       $allContactIDs, $additionalContacts
     );
   }
@@ -359,7 +372,7 @@ function getRelationshipInfo(&$contactIDs, &$values, &$allContactIDs, &$addition
  * @param $additionalContacts
  */
 function getActivityInfo(&$contactIDs, &$values, &$allContactIDs, &$additionalContacts) {
-  static $_activitiesHandled = array();
+  static $_activitiesHandled = [];
 
   $ids = implode(',', $contactIDs);
 
@@ -381,7 +394,7 @@ function getActivityInfo(&$contactIDs, &$values, &$allContactIDs, &$additionalCo
   $activityFields = &getDBFields('CRM_Activity_DAO_Activity');
   $fields = array_keys($activityFields);
 
-  $activityIDs = array();
+  $activityIDs = [];
   $dao = &CRM_Core_DAO::executeQuery($sql);
   while ($dao->fetch()) {
     if (isset($_activitiesHandled[$dao->id])) {
@@ -390,7 +403,7 @@ function getActivityInfo(&$contactIDs, &$values, &$allContactIDs, &$additionalCo
     $_activitiesHandled[$dao->id] = $dao->id;
     $activityIDs[] = $dao->id;
 
-    $activity = array();
+    $activity = [];
     foreach ($fields as $fld) {
       if (empty($dao->$fld)) {
         $activity[$fld] = NULL;
@@ -401,7 +414,7 @@ function getActivityInfo(&$contactIDs, &$values, &$allContactIDs, &$additionalCo
     }
 
     appendValue($values, $dao->id, 'activity', $activity);
-    addAdditionalContacts(array($dao->source_contact_id),
+    addAdditionalContacts([$dao->source_contact_id],
       $allContactIDs, $additionalContacts
     );
   }
@@ -414,14 +427,15 @@ function getActivityInfo(&$contactIDs, &$values, &$allContactIDs, &$additionalCo
   $activityIDString = implode(",", $activityIDs);
 
   // now get all assignee contact ids and target contact ids for this activity
-  $sql              = "SELECT * FROM civicrm_activity_assignment WHERE activity_id IN ($activityIDString)";
-  $aaDAO            = &CRM_Core_DAO::executeQuery($sql);
-  $activityContacts = array();
+  $sql = "SELECT * FROM civicrm_activity_assignment WHERE activity_id IN ($activityIDString)";
+  $aaDAO = &CRM_Core_DAO::executeQuery($sql);
+  $activityContacts = [];
   while ($aaDAO->fetch()) {
-    $activityAssignee = array('id' => $aaDAO->id,
+    $activityAssignee = [
+      'id' => $aaDAO->id,
       'assignee_contact_id' => $aaDAO->assignee_contact_id,
       'activity_id' => $aaDAO->activity_id,
-    );
+    ];
     appendValue($values, $aaDAO->id, 'activity_assignment', $activityAssignee);
     $activityContacts[] = $aaDAO->assignee_contact_id;
   }
@@ -430,10 +444,11 @@ function getActivityInfo(&$contactIDs, &$values, &$allContactIDs, &$additionalCo
   $sql = "SELECT * FROM civicrm_activity_target WHERE activity_id IN ($activityIDString)";
   $atDAO = &CRM_Core_DAO::executeQuery($sql);
   while ($atDAO->fetch()) {
-    $activityTarget = array('id' => $atDAO->id,
+    $activityTarget = [
+      'id' => $atDAO->id,
       'target_contact_id' => $atDAO->target_contact_id,
       'activity_id' => $atDAO->activity_id,
-    );
+    ];
     appendValue($values, $atDAO->id, 'activity_target', $activityTarget);
     $activityContacts[] = $atDAO->target_contact_id;
   }
@@ -455,7 +470,7 @@ function appendValue(&$values, $id, $name, $value, $ignored = FALSE) {
   }
 
   if (!isset($values[$name])) {
-    $values[$name] = array();
+    $values[$name] = [];
     $values[$name][] = array_keys($value);
   }
   $values[$name][] = array_values($value);
@@ -467,24 +482,25 @@ function appendValue(&$values, $id, $name, $value, $ignored = FALSE) {
  * @return mixed
  */
 function getDBFields($daoName) {
-  static $_fieldsRetrieved = array();
+  static $_fieldsRetrieved = [];
 
   if (!isset($_fieldsRetrieved[$daoName])) {
-    $_fieldsRetrieved[$daoName] = array();
+    $_fieldsRetrieved[$daoName] = [];
     $daoFile = str_replace('_',
-      DIRECTORY_SEPARATOR,
-      $daoName
-    ) . '.php';
-    include_once ($daoFile);
+        DIRECTORY_SEPARATOR,
+        $daoName
+      ) . '.php';
+    include_once($daoFile);
 
     $daoFields = &$daoName::fields();
     require_once 'CRM/Utils/Array.php';
 
     foreach ($daoFields as $key => & $value) {
-      $_fieldsRetrieved[$daoName][$value['name']] = array('uniqueName' => $key,
+      $_fieldsRetrieved[$daoName][$value['name']] = [
+        'uniqueName' => $key,
         'type' => $value['type'],
         'title' => CRM_Utils_Array::value('title', $value, NULL),
-      );
+      ];
     }
   }
   return $_fieldsRetrieved[$daoName];
@@ -514,7 +530,7 @@ function addAdditionalContacts($contactIDs, &$allContactIDs, &$additionalContact
 function run(&$values, &$contactIDs, &$allContactIDs) {
   $chunks = &splitContactIDs($contactIDs);
 
-  $additionalContactIDs = array();
+  $additionalContactIDs = [];
 
   foreach ($chunks as $chunk) {
     getValues($chunk, $values, $allContactIDs, $additionalContactIDs);
@@ -526,7 +542,7 @@ function run(&$values, &$contactIDs, &$allContactIDs) {
   }
 }
 
-$config = &CRM_Core_Config::singleton();
+$config = CRM_Core_Config::singleton();
 $config->userFramework = 'Soap';
 $config->userFrameworkClass = 'CRM_Utils_System_Soap';
 $config->userHookClass = 'CRM_Utils_Hook_Soap';
@@ -539,12 +555,12 @@ LIMIT 10
 $dao = &CRM_Core_DAO::executeQuery($sql);
 
 
-$contactIDs = array();
+$contactIDs = [];
 while ($dao->fetch()) {
   $contactIDs[$dao->id] = $dao->id;
 }
 
-$values = array();
+$values = [];
 run($values, $contactIDs, $contactIDs);
 
 $json = json_encode($values);
index 4fe5925e2cddf15871b52992260d35605f29c103..04b6f856754ea73f15e0786d7085aba632e092a3 100755 (executable)
@@ -3,7 +3,7 @@
 
 // FIXME: Make this a proper app with unit-tests
 
-$civi_pkgs_dir = dirname( dirname( dirname( __FILE__ ) ) ) .   DIRECTORY_SEPARATOR . 'packages';
+$civi_pkgs_dir = dirname(dirname(dirname(__FILE__))) . DIRECTORY_SEPARATOR . 'packages';
 require_once $civi_pkgs_dir . DIRECTORY_SEPARATOR . 'simple_html_dom.php';
 exit(main($argv));
 
@@ -19,7 +19,7 @@ function main($argv) {
   $files = $argv;
   array_shift($files); // skip program name
   foreach ($files as $file) {
-    check_tpl($file, function($code, $message) use ($file) {
+    check_tpl($file, function ($code, $message) use ($file) {
       printf("[%s] %s\n", $file, $message);
     });
   }
index 4deea9bf9639c99e2e4e652cfbe7cfd1989c8e2a..330e1a42dbc35b86bcdca5c8e9ca165b7c03d22e 100644 (file)
@@ -35,6 +35,9 @@
     <localizable>true</localizable>
     <comment>Name of Group.</comment>
     <add>1.1</add>
+    <html>
+      <type>Text</type>
+    </html>
   </field>
   <field>
     <name>description</name>
index b492bd9453056aa70554dcb93d4278178ddee8cd..1e3a211e07b0ad1d408c971a08e112432a784c45 100644 (file)
@@ -7,6 +7,7 @@
   <log>true</log>
   <field>
     <name>id</name>
+    <uniqueName>contribution_recur_id</uniqueName>
     <title>Recurring Contribution ID</title>
     <type>int unsigned</type>
     <required>true</required>
   </field>
   <field>
     <name>processor_id</name>
+    <uniqueName>contribution_recur_processor_id</uniqueName>
     <title>Processor ID</title>
     <type>varchar</type>
     <length>255</length>
   </foreignKey>
   <field>
     <name>trxn_id</name>
+    <uniqueName>contribution_recur_trxn_id</uniqueName>
     <title>Transaction ID</title>
     <type>varchar</type>
     <length>255</length>
   </index>
   <field>
     <name>contribution_status_id</name>
+    <uniqueName>contribution_recur_contribution_status_id</uniqueName>
     <title>Status</title>
     <type>int unsigned</type>
     <default>1</default>
   <field>
     <name>payment_processor_id</name>
     <title>Payment Processor</title>
+    <uniqueName>contribution_recur_payment_processor_id</uniqueName>
     <type>int unsigned</type>
     <comment>Foreign key to civicrm_payment_processor.id</comment>
     <add>3.3</add>
index 07d0df45b4058051a642a98ed5f12a4bfb7cd6c6..3f79cb6a6ba5b668ea92cc63b57bc438a34688dc 100644 (file)
@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="iso-8859-1" ?>
 <version>
-  <version_no>5.14.alpha1</version_no>
+  <version_no>5.15.alpha1</version_no>
 </version>