Merge pull request #16574 from civicrm/5.23
authorEileen McNaughton <emcnaughton@wikimedia.org>
Mon, 17 Feb 2020 20:52:44 +0000 (09:52 +1300)
committerGitHub <noreply@github.com>
Mon, 17 Feb 2020 20:52:44 +0000 (09:52 +1300)
5.23

149 files changed:
CRM/Activity/BAO/Activity.php
CRM/Activity/Form/Activity.php
CRM/Activity/Form/Task/Batch.php
CRM/Activity/Selector/Activity.php
CRM/Activity/Selector/Search.php
CRM/Activity/Tokens.php
CRM/Admin/Form/Generic.php
CRM/Admin/Form/Job.php
CRM/Admin/Form/Preferences/Contribute.php
CRM/Admin/Form/Setting/Case.php
CRM/Admin/Form/Setting/Smtp.php
CRM/Admin/Form/SettingTrait.php
CRM/Api4/Page/AJAX.php
CRM/Case/BAO/Case.php
CRM/Case/Form/Report.php
CRM/Case/Info.php
CRM/Case/XMLProcessor/Report.php
CRM/Contact/Form/Task/Label.php
CRM/Contact/Page/AJAX.php
CRM/Contact/Page/Inline/CommunicationPreferences.php
CRM/Contact/Page/Inline/OpenID.php
CRM/Contact/Page/Inline/Phone.php
CRM/Contact/Page/Inline/Website.php
CRM/Contribute/BAO/Contribution.php
CRM/Contribute/Form/AbstractEditPayment.php
CRM/Contribute/Form/AdditionalPayment.php
CRM/Contribute/Form/CancelSubscription.php
CRM/Contribute/Form/Task/Invoice.php
CRM/Core/BAO/ConfigSetting.php
CRM/Core/BAO/CustomField.php
CRM/Core/BAO/Log.php
CRM/Core/BAO/Note.php
CRM/Core/Exception/ResourceConflictException.php
CRM/Core/Form.php
CRM/Core/Page/AJAX/Location.php
CRM/Core/Payment.php
CRM/Core/Payment/Dummy.php
CRM/Core/Payment/Manual.php
CRM/Core/TokenTrait.php [new file with mode: 0644]
CRM/Core/xml/Menu/Admin.xml
CRM/Dedupe/BAO/Rule.php
CRM/Dedupe/BAO/RuleGroup.php
CRM/Dedupe/Finder.php
CRM/Dedupe/Merger.php
CRM/Event/BAO/Participant.php
CRM/Event/Form/Participant.php
CRM/Extension/Container/Interface.php
CRM/Extension/Info.php
CRM/Extension/Mapper.php
CRM/Financial/BAO/Payment.php
CRM/Financial/BAO/PaymentProcessor.php
CRM/Logging/Schema.php
CRM/Member/BAO/Membership.php
CRM/Report/Form/Contact/Detail.php
CRM/Report/Form/Contact/Relationship.php
CRM/Report/Form/Contribute/Summary.php
CRM/Report/Form/Member/ContributionDetail.php
CRM/SMS/Controller/Send.php
CRM/Upgrade/Incremental/General.php
CRM/Upgrade/Incremental/php/FiveTwentyFour.php [new file with mode: 0644]
CRM/Upgrade/Incremental/sql/5.24.alpha1.mysql.tpl [new file with mode: 0644]
CRM/Utils/Mail.php
CRM/Utils/Mail/FilteredPearMailer.php [new file with mode: 0644]
CRM/Utils/Mail/Logger.php [new file with mode: 0644]
CRM/Utils/Money.php
CRM/Utils/Request.php
CRM/Utils/System/Drupal8.php
Civi/API/Kernel.php
Civi/API/Request.php
Civi/API/Subscriber/ChainSubscriber.php
Civi/API/Subscriber/DynamicFKAuthorization.php
Civi/Api4/Action/GetActions.php
Civi/Api4/Generic/AbstractAction.php
Civi/Api4/Generic/BasicGetFieldsAction.php
Civi/Api4/Generic/BasicReplaceAction.php
Civi/Api4/Generic/BasicSaveAction.php
Civi/Api4/Generic/DAOGetFieldsAction.php
Civi/Api4/Service/Spec/Provider/PaymentProcessorTypeCreationSpecProvider.php
Civi/Api4/Utils/ActionUtil.php [deleted file]
Civi/Test.php
Civi/Test/ContactTestTrait.php
ang/crmCaseType/list.html
api/api.php
api/v3/Attachment.php
api/v3/Contact.php
api/v3/Participant.php
api/v3/utils.php
composer.json
composer.lock
js/Common.js
js/jquery/jquery.dashboard.js
release-notes/5.21.1.md
settings/Case.setting.php
settings/Contribute.setting.php
sql/civicrm_generated.mysql
templates/CRM/Activity/Form/ActivityView.tpl
templates/CRM/Activity/Form/Task/Print.tpl
templates/CRM/Activity/Page/UserDashboard.tpl
templates/CRM/Activity/Selector/Selector.tpl
templates/CRM/Admin/Form/Setting/Case.tpl
templates/CRM/Admin/Form/Setting/Localization.tpl
templates/CRM/Case/Audit/Report.tpl
templates/CRM/Contact/Form/Search/Custom/FullText.tpl
templates/CRM/Contribute/Form/Contribution/Main.tpl
templates/CRM/Contribute/Form/ContributionView.tpl
templates/CRM/Event/Form/Registration/Register.tpl
templates/CRM/Group/Form/Search.tpl
templates/CRM/Mailing/Page/Tab.tpl
templates/CRM/Price/Form/Calculate.tpl
templates/CRM/Tag/Form/Edit.tpl
templates/CRM/common/civicrm.settings.php.template
tests/extensions/test.extension.manager.moduletest/info.xml
tests/extensions/test.extension.manager.paymenttest/info.xml
tests/karma/unit/crmCaseTypeSpec.js
tests/phpunit/CRM/Activity/BAO/ActivityTest.php
tests/phpunit/CRM/Activity/Selector/SearchTest.php
tests/phpunit/CRM/Case/XMLProcessor/ReportTest.php
tests/phpunit/CRM/Contribute/BAO/ContributionTest.php
tests/phpunit/CRM/Contribute/Import/Parser/ContributionTest.php
tests/phpunit/CRM/Core/FormTest.php [new file with mode: 0644]
tests/phpunit/CRM/Dedupe/DedupeFinderTest.php
tests/phpunit/CRM/Event/Form/ParticipantTest.php
tests/phpunit/CRM/Extension/MapperTest.php
tests/phpunit/CRM/Financial/BAO/PaymentProcessorTest.php
tests/phpunit/CRM/Member/BAO/MembershipTest.php
tests/phpunit/CRM/Utils/Mail/FilteredPearMailerTest.php [new file with mode: 0644]
tests/phpunit/CRM/Utils/MoneyTest.php
tests/phpunit/CRMTraits/ACL/PermissionTrait.phpx [deleted file]
tests/phpunit/Civi/API/Event/PrepareEventTest.php
tests/phpunit/Civi/API/KernelTest.php
tests/phpunit/Civi/API/RequestTest.php
tests/phpunit/Civi/API/Subscriber/DynamicFKAuthorizationTest.php
tests/phpunit/Civi/API/Subscriber/WhitelistSubscriberTest.php
tests/phpunit/E2E/Extern/CliRunnerTest.php
tests/phpunit/api/v3/ExtensionTest.php
tests/phpunit/api/v3/UtilsTest.php
tests/phpunit/api/v4/Entity/ContactInterchangeTest.php
tools/scripts/composer/dompdf-cleanup.sh
tools/scripts/composer/net-smtp-fix.sh
tools/scripts/composer/patches/civicrm-custom-patches-zetacompoents-mail.patch [deleted file]
tools/scripts/composer/patches/dompdf_no_block_level_parent_fix.patch [deleted file]
tools/scripts/composer/patches/net-smtp-patch.txt [deleted file]
tools/scripts/composer/patches/net-smtp-php7-patch.txt [deleted file]
tools/scripts/composer/patches/net-smtp-ref-patch.txt [deleted file]
tools/scripts/composer/patches/net-smtp-tls-patch.txt [deleted file]
tools/scripts/composer/patches/pear-mail.patch.txt
tools/scripts/composer/patches/phpoffice-common-xml-entity-fix.patch [deleted file]
tools/scripts/composer/patches/phpword-libxml-fix-global-handling.patch [deleted file]
xml/version.xml

index 1f0e7a4fe8f95cf7f433aa3ce84322f9ca1f0ac1..59b9d813667d7ac209731957077d9e9777567b5c 100644 (file)
@@ -697,6 +697,9 @@ class CRM_Activity_BAO_Activity extends CRM_Activity_DAO_Activity {
       'case_id',
       'campaign_id',
     ];
+    // Q. What does the code below achieve? case_id and campaign_id are already
+    // in the array, defined above, and this code adds them in again if their
+    // component is enabled? @fixme remove case_id and campaign_id from the array above?
     foreach (['case_id' => 'CiviCase', 'campaign_id' => 'CiviCampaign'] as $attr => $component) {
       if (in_array($component, self::activityComponents())) {
         $activityParams['return'][] = $attr;
@@ -780,6 +783,7 @@ class CRM_Activity_BAO_Activity extends CRM_Activity_DAO_Activity {
 
     // Eventually this second iteration should just handle the target contacts. It's a bit muddled at
     // the moment as the bulk activity stuff needs unravelling & test coverage.
+    $caseIds = [];
     foreach ($result as $id => $activity) {
       $isBulkActivity = (!$bulkActivityTypeID || ($bulkActivityTypeID === $activity['activity_type_id']));
       foreach ($mappingParams as $apiKey => $expectedName) {
@@ -804,10 +808,9 @@ class CRM_Activity_BAO_Activity extends CRM_Activity_DAO_Activity {
 
           // fetch case subject for case ID found
           if (!empty($activity['case_id'])) {
-            $activities[$id]['case_subject'] = civicrm_api3('Case', 'getvalue', [
-              'return' => 'subject',
-              'id' => reset($activity['case_id']),
-            ]);
+            // Store cases; we'll look them up in one query below. We convert
+            // to int here so we can trust it for SQL.
+            $caseIds[$id] = (int) current($activity['case_id']);
           }
         }
         else {
@@ -827,6 +830,15 @@ class CRM_Activity_BAO_Activity extends CRM_Activity_DAO_Activity {
       $activities[$id]['is_recurring_activity'] = CRM_Core_BAO_RecurringEntity::getParentFor($id, 'civicrm_activity');
     }
 
+    // Look up any case subjects we need in a single query and add them in the relevant activities under 'case_subject'
+    if ($caseIds) {
+      $subjects = CRM_Core_DAO::executeQuery('SELECT id, subject FROM civicrm_case WHERE id IN (' . implode(',', array_unique($caseIds)) . ')')
+        ->fetchMap('id', 'subject');
+      foreach ($caseIds as $activityId => $caseId) {
+        $result[$activityId]['case_subject'] = $subjects[$caseId];
+      }
+    }
+
     return $activities;
   }
 
@@ -2526,6 +2538,9 @@ INNER JOIN  civicrm_option_group grp ON (grp.id = option_group_id AND grp.name =
     // Format params and add links.
     $contactActivities = [];
 
+    // View-only activity types
+    $viewOnlyCaseActivityTypeIDs = array_flip(CRM_Activity_BAO_Activity::getViewOnlyActivityTypeIDs());
+
     if (!empty($activities)) {
       $activityStatus = CRM_Core_PseudoConstant::activityStatus();
 
@@ -2538,6 +2553,7 @@ INNER JOIN  civicrm_option_group grp ON (grp.id = option_group_id AND grp.name =
       }
 
       $mask = CRM_Core_Action::mask($permissions);
+      $userID = CRM_Core_Session::getLoggedInContactID();
 
       foreach ($activities as $activityId => $values) {
         $activity = ['source_contact_name' => '', 'target_contact_name' => ''];
@@ -2663,29 +2679,83 @@ INNER JOIN  civicrm_option_group grp ON (grp.id = option_group_id AND grp.name =
           $accessMailingReport = TRUE;
         }
 
-        $actionLinks = CRM_Activity_Selector_Activity::actionLinks(
-          CRM_Utils_Array::value('activity_type_id', $values),
-          CRM_Utils_Array::value('source_record_id', $values),
-          $accessMailingReport,
-          CRM_Utils_Array::value('activity_id', $values)
-        );
+        // Get action links.
+
+        // If this is a case activity, then we hand off to Case's actionLinks instead.
+        if (!empty($values['case_id']) && Civi::settings()->get('civicaseShowCaseActivities')) {
+          // This activity belongs to a case.
+          $caseId = current($values['case_id']);
+
+          $activity['subject'] = $values['subject'];
+
+          // Get the view and edit (update) links:
+          $caseActionLinks =
+            $actionLinks = array_intersect_key(
+              CRM_Case_Selector_Search::actionLinks(),
+              array_fill_keys([CRM_Core_Action::VIEW, CRM_Core_Action::UPDATE], NULL));
+
+          // Create a Manage Case link (using ADVANCED as can't use two VIEW ones)
+          $actionLinks[CRM_Core_Action::ADVANCED] = [
+            "name"  => 'Manage Case',
+            "url"   => 'civicrm/contact/view/case',
+            'qs'    => 'reset=1&id=%%caseid%%&cid=%%cid%%&action=view&context=&selectedChild=case',
+            "title" => ts('Manage Case %1', [1 => $caseId]),
+            'class' => 'no-popup',
+          ];
+
+          $caseLinkValues = [
+            'aid'    => $activityId,
+            'caseid' => $caseId,
+            'cid'    => current(CRM_Case_BAO_Case::getCaseClients($caseId) ?? []),
+            // Unlike other 'context' params, this 'ctx' param is appended raw to the URL.
+            'cxt'    => '',
+          ];
+
+          $caseActivityPermissions = CRM_Core_Action::VIEW | CRM_Core_Action::ADVANCED;
+          // Allow Edit link if:
+          // 1. Activity type is NOT view-only type. CRM-5871
+          // 2. User has edit permission.
+          if (!isset($viewOnlyCaseActivityTypeIDs[$values['activity_type_id']])
+            && CRM_Case_BAO_Case::checkPermission($activityId, 'edit', $values['activity_type_id'], $userID)) {
+            // We're allowed to edit.
+            $caseActivityPermissions |= CRM_Core_Action::UPDATE;
+          }
 
-        $actionMask = array_sum(array_keys($actionLinks)) & $mask;
-
-        $activity['links'] = CRM_Core_Action::formLink($actionLinks,
-          $actionMask,
-          [
-            'id' => $values['activity_id'],
-            'cid' => $params['contact_id'],
-            'cxt' => $context,
-            'caseid' => CRM_Utils_Array::value('case_id', $values),
-          ],
-          ts('more'),
-          FALSE,
-          'activity.tab.row',
-          'Activity',
-          $values['activity_id']
-        );
+          $activity['links'] = CRM_Core_Action::formLink($actionLinks,
+            $caseActivityPermissions,
+            $caseLinkValues,
+            ts('more'),
+            FALSE,
+            'activity.tab.row',
+            'Activity',
+            $values['activity_id']
+          );
+        }
+        else {
+          // Non-case activity
+          $actionLinks = CRM_Activity_Selector_Activity::actionLinks(
+            CRM_Utils_Array::value('activity_type_id', $values),
+            CRM_Utils_Array::value('source_record_id', $values),
+            $accessMailingReport,
+            CRM_Utils_Array::value('activity_id', $values)
+          );
+          $actionMask = array_sum(array_keys($actionLinks)) & $mask;
+
+          $activity['links'] = CRM_Core_Action::formLink($actionLinks,
+            $actionMask,
+            [
+              'id' => $values['activity_id'],
+              'cid' => $params['contact_id'],
+              'cxt' => $context,
+              'caseid' => NULL,
+            ],
+            ts('more'),
+            FALSE,
+            'activity.tab.row',
+            'Activity',
+            $values['activity_id']
+          );
+        }
 
         if ($values['is_recurring_activity']) {
           $activity['is_recurring_activity'] = CRM_Core_BAO_RecurringEntity::getPositionAndCount($values['activity_id'], 'civicrm_activity');
index a3d6f4a5d6f8332b82352274dfe4e447163b3647..84880f2c020db52be9b3841a275e16767374b365 100644 (file)
@@ -179,7 +179,7 @@ class CRM_Activity_Form_Activity extends CRM_Contact_Form_Task {
       ],
       'source_contact_id' => [
         'type' => 'entityRef',
-        'label' => ts('Added By'),
+        'label' => ts('Added by'),
         'required' => FALSE,
       ],
       'target_contact_id' => [
index f83b17e37b5368d0cd079198e2d1a3951be930ec..ce68c080d95e6a0fa4f6173a96b8c447c374acc9 100644 (file)
@@ -48,7 +48,7 @@ class CRM_Activity_Form_Task_Batch extends CRM_Activity_Form_Task {
     parent::preProcess();
 
     // Get the contact read only fields to display.
-    $readOnlyFields = array_merge(['sort_name' => ts('Added By'), 'target_sort_name' => ts('With Contact')],
+    $readOnlyFields = array_merge(['sort_name' => ts('Added by'), 'target_sort_name' => ts('With Contact')],
       CRM_Core_BAO_Setting::valueOptions(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
         'contact_autocomplete_options',
         TRUE, NULL, FALSE, 'name', TRUE
index 744ee580bd53daac690ed8f7ec13de7a532b66d3..5f7aa426fdd7e37f31b2ef8e65e753588adf7953 100644 (file)
@@ -459,7 +459,7 @@ class CRM_Activity_Selector_Activity extends CRM_Core_Selector_Base implements C
             'id' => $row['activity_id'],
             'cid' => $this->_contactId,
             'cxt' => $this->_context,
-            'caseid' => CRM_Utils_Array::value('case_id', $row),
+            'caseid' => isset($row['case_id']) ? current($row['case_id']) : NULL,
           ],
           ts('more'),
           FALSE,
@@ -508,7 +508,7 @@ class CRM_Activity_Selector_Activity extends CRM_Core_Selector_Base implements C
           'direction' => CRM_Utils_Sort::DONTCARE,
         ],
         [
-          'name' => ts('Added By'),
+          'name' => ts('Added by'),
           'sort' => 'source_contact_name',
           'direction' => CRM_Utils_Sort::DONTCARE,
         ],
index 8fa745c600130b4406554bb316462335907f2371..e2d38c551d9efa2915e72968ac8ca54707c918d7 100644 (file)
@@ -394,7 +394,7 @@ class CRM_Activity_Selector_Search extends CRM_Core_Selector_Base implements CRM
           'direction' => CRM_Utils_Sort::DONTCARE,
         ],
         [
-          'name' => ts('Added By'),
+          'name' => ts('Added by'),
           'sort' => 'source_contact',
           'direction' => CRM_Utils_Sort::DONTCARE,
         ],
index 825c120c9890e085260a3c64825b1dc33df1747e..fff8e6224a507fe684cf1465cbf0881d7365ca91 100644 (file)
  */
 class CRM_Activity_Tokens extends \Civi\Token\AbstractTokenSubscriber {
 
-  private $basicTokens;
-  private $customFieldTokens;
+  use CRM_Core_TokenTrait;
 
   /**
-   * Mapping from tokenName to api return field
-   * Use lists since we might need multiple fields
-   *
-   * @var array
+   * @return string
    */
-  private static $fieldMapping = [
-    'activity_id' => ['id'],
-    'activity_type' => ['activity_type_id'],
-    'status' => ['status_id'],
-    'campaign' => ['campaign_id'],
-  ];
+  private function getEntityName(): string {
+    return 'activity';
+  }
 
   /**
-   * CRM_Activity_Tokens constructor.
+   * @return string
    */
-  public function __construct() {
-    parent::__construct('activity', array_merge(
-      $this->getBasicTokens(),
-      $this->getCustomFieldTokens()
-    ));
+  private function getEntityTableName(): string {
+    return 'civicrm_activity';
   }
 
   /**
-   * @inheritDoc
+   * @return string
    */
-  public function checkActive(\Civi\Token\TokenProcessor $processor) {
-    return in_array('activityId', $processor->context['schema']) ||
-      (!empty($processor->context['actionMapping'])
-      && $processor->context['actionMapping']->getEntity() === 'civicrm_activity');
+  private function getEntityContextSchema(): string {
+    return 'activityId';
   }
 
   /**
-   * @inheritDoc
+   * Mapping from tokenName to api return field
+   * Use lists since we might need multiple fields
+   *
+   * @var array
    */
-  public function getActiveTokens(\Civi\Token\Event\TokenValueEvent $e) {
-    $messageTokens = $e->getTokenProcessor()->getMessageTokens();
-    if (!isset($messageTokens[$this->entity])) {
-      return NULL;
-    }
-
-    $activeTokens = [];
-    // if message token contains '_\d+_', then treat as '_N_'
-    foreach ($messageTokens[$this->entity] as $msgToken) {
-      if (array_key_exists($msgToken, $this->tokenNames)) {
-        $activeTokens[] = $msgToken;
-      }
-      else {
-        $altToken = preg_replace('/_\d+_/', '_N_', $msgToken);
-        if (array_key_exists($altToken, $this->tokenNames)) {
-          $activeTokens[] = $msgToken;
-        }
-      }
-    }
-    return array_unique($activeTokens);
-  }
+  private static $fieldMapping = [
+    'activity_id' => ['id'],
+    'activity_type' => ['activity_type_id'],
+    'status' => ['status_id'],
+    'campaign' => ['campaign_id'],
+  ];
 
   /**
    * @inheritDoc
    */
   public function alterActionScheduleQuery(\Civi\ActionSchedule\Event\MailingQueryEvent $e) {
-    if ($e->mapping->getEntity() !== 'civicrm_activity') {
+    if ($e->mapping->getEntity() !== $this->getEntityTableName()) {
       return;
     }
 
@@ -105,44 +81,22 @@ class CRM_Activity_Tokens extends \Civi\Token\AbstractTokenSubscriber {
     $e->query->param('casEntityJoinExpr', 'e.id = reminder.entity_id AND e.is_current_revision = 1 AND e.is_deleted = 0');
   }
 
-  /**
-   * Find the fields that we need to get to construct the tokens requested.
-   * @param  array $tokens list of tokens
-   * @return array         list of fields needed to generate those tokens
-   */
-  public function getReturnFields($tokens) {
-    // Make sure we always return something
-    $fields = ['id'];
-
-    foreach (array_intersect($tokens,
-      array_merge(array_keys(self::getBasicTokens()), array_keys(self::getCustomFieldTokens()))
-      ) as $token) {
-      if (isset(self::$fieldMapping[$token])) {
-        $fields = array_merge($fields, self::$fieldMapping[$token]);
-      }
-      else {
-        $fields[] = $token;
-      }
-    }
-    return array_unique($fields);
-  }
-
   /**
    * @inheritDoc
    */
   public function prefetch(\Civi\Token\Event\TokenValueEvent $e) {
-    // Find all the activity IDs
-    $activityIds
+    // Find all the entity IDs
+    $entityIds
       = $e->getTokenProcessor()->getContextValues('actionSearchResult', 'entityID')
-      + $e->getTokenProcessor()->getContextValues('activityId');
+      + $e->getTokenProcessor()->getContextValues($this->getEntityContextSchema());
 
-    if (!$activityIds) {
-      return;
+    if (!$entityIds) {
+      return NULL;
     }
 
     // Get data on all activities for basic and customfield tokens
     $activities = civicrm_api3('Activity', 'get', [
-      'id' => ['IN' => $activityIds],
+      'id' => ['IN' => $entityIds],
       'options' => ['limit' => 0],
       'return' => self::getReturnFields($this->activeTokens),
     ]);
@@ -176,9 +130,7 @@ class CRM_Activity_Tokens extends \Civi\Token\AbstractTokenSubscriber {
     ];
 
     // Get ActivityID either from actionSearchResult (for scheduled reminders) if exists
-    $activityId = isset($row->context['actionSearchResult']->entityID)
-      ? $row->context['actionSearchResult']->entityID
-      : $row->context['activityId'];
+    $activityId = $row->context['actionSearchResult']->entityID ?? $row->context[$this->getEntityContextSchema()];
 
     $activity = (object) $prefetch['activity'][$activityId];
 
@@ -243,15 +195,4 @@ class CRM_Activity_Tokens extends \Civi\Token\AbstractTokenSubscriber {
     return $this->basicTokens;
   }
 
-  /**
-   * Get the tokens for custom fields
-   * @return array token name => token label
-   */
-  protected function getCustomFieldTokens() {
-    if (!isset($this->customFieldTokens)) {
-      $this->customFieldTokens = \CRM_Utils_Token::getCustomFieldTokens('Activity');
-    }
-    return $this->customFieldTokens;
-  }
-
 }
index 00a4e3d3a4e86b622d5ef1f91f7c6bb9874eb5f6..2c23019a6af81885d15adadb288810791d674d9e 100644 (file)
@@ -50,14 +50,6 @@ class CRM_Admin_Form_Generic extends CRM_Core_Form {
    * Build the form object.
    */
   public function buildQuickForm() {
-    $filter = $this->getSettingPageFilter();
-    $settings = civicrm_api3('Setting', 'getfields', [])['values'];
-    foreach ($settings as $key => $setting) {
-      if (isset($setting['settings_pages'][$filter])) {
-        $this->_settings[$key] = $setting;
-      }
-    }
-
     $this->addFieldsDefinedInSettingsMetadata();
 
     // @todo look at sharing the code below in the settings trait.
index f0bc3fefd2f9985941679dfa6dd717ede425a4ca..8a8679b5b444a2ce54091a2faffcefc887ae2d58 100644 (file)
@@ -107,7 +107,7 @@ class CRM_Admin_Form_Job extends CRM_Admin_Form {
 
     /** @var \Civi\API\Kernel $apiKernel */
     $apiKernel = \Civi::service('civi_api_kernel');
-    $apiRequest = \Civi\API\Request::create($fields['api_entity'], $fields['api_action'], ['version' => 3], NULL);
+    $apiRequest = \Civi\API\Request::create($fields['api_entity'], $fields['api_action'], ['version' => 3]);
     try {
       $apiKernel->resolve($apiRequest);
     }
index 69fa149cb0be8af77132b1d6730f817c17b5a0c9..e835e335e80218a3f12bd4f5a7fd4ace94fa7a6e 100644 (file)
  * This class generates form components for the display preferences.
  */
 class CRM_Admin_Form_Preferences_Contribute extends CRM_Admin_Form_Preferences {
-  protected $_settings = [
-    'cvv_backoffice_required' => CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME,
-    'update_contribution_on_membership_type_change' => CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME,
-    'acl_financial_type' => CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME,
-    'always_post_to_accounts_receivable' => CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME,
-    'deferred_revenue_enabled' => CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME,
-    'default_invoice_page' => CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME,
-    'invoicing' => CRM_Core_BAO_Setting::CONTRIBUTE_PREFERENCES_NAME,
-  ];
 
   /**
    * Our standards for settings are to have a setting per value with defined metadata.
@@ -35,7 +26,10 @@ class CRM_Admin_Form_Preferences_Contribute extends CRM_Admin_Form_Preferences {
    * Unfortunately the 'contribution_invoice_settings' has been added in non-compliance.
    * We use this array to hack-handle.
    *
-   * I think the best way forwards would be to covert to multiple individual settings.
+   * These are now stored as individual settings but this form still does weird & wonderful things.
+   *
+   * Note the 'real' settings on this form are added via metadata definition - ie
+   * 'settings_pages' => ['contribute' => ['weight' => 1]], in their metadata.
    *
    * @var array
    */
@@ -43,10 +37,12 @@ class CRM_Admin_Form_Preferences_Contribute extends CRM_Admin_Form_Preferences {
 
   /**
    * Build the form object.
+   *
+   * @throws \CiviCRM_API3_Exception
+   * @throws \CRM_Core_Exception
    */
   public function buildQuickForm() {
     parent::buildQuickForm();
-    $config = CRM_Core_Config::singleton();
     $this->invoiceSettings = [
       'invoice_prefix' => [
         'html_type' => 'text',
@@ -54,12 +50,6 @@ class CRM_Admin_Form_Preferences_Contribute extends CRM_Admin_Form_Preferences {
         'weight' => 1,
         'description' => ts('Enter prefix to be display on PDF for invoice'),
       ],
-      'credit_notes_prefix' => [
-        'html_type' => 'text',
-        'title' => ts('Credit Notes Prefix'),
-        'weight' => 2,
-        'description' => ts('Enter prefix to be display on PDF for credit notes.'),
-      ],
       'due_date' => [
         'html_type' => 'text',
         'title' => ts('Due Date'),
index 38331609214e3e1dbd86523b841f07c02217ebde..58331a8b2f95bfda4ff84271a96dffda92c9d1a1 100644 (file)
@@ -25,6 +25,7 @@ class CRM_Admin_Form_Setting_Case extends CRM_Admin_Form_Setting {
     'civicaseAllowMultipleClients' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
     'civicaseNaturalActivityTypeSort' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
     'civicaseActivityRevisions' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
+    'civicaseShowCaseActivities' => CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
   ];
 
   /**
index 87d30761cfa47fca814c8c705063658c730bac23..a3590b3ca2e61c48c8a7043f2946c632ffb762e2 100644 (file)
@@ -165,7 +165,7 @@ class CRM_Admin_Form_Setting_Smtp extends CRM_Admin_Form_Setting {
           'Subject' => $subject,
         ];
 
-        $mailer = Mail::factory($mailerName, $params);
+        $mailer = CRM_Utils_Mail::_createMailer($mailerName, $params);
 
         $errorScope = CRM_Core_TemporaryErrorScope::ignoreException();
         $result = $mailer->send($toEmail, $headers, $message);
index 840461009c300b197e49b6ff3d9cb3458cd37372..a4b59e523f353a0aa85b6e7469f523cb4e8a21de 100644 (file)
@@ -153,8 +153,10 @@ trait CRM_Admin_Form_SettingTrait {
    * Add fields in the metadata to the template.
    *
    * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
    */
   protected function addFieldsDefinedInSettingsMetadata() {
+    $this->addSettingsToFormFromMetadata();
     $settingMetaData = $this->getSettingsMetaData();
     $descriptions = [];
     foreach ($settingMetaData as $setting => $props) {
@@ -174,7 +176,7 @@ trait CRM_Admin_Form_SettingTrait {
         }
 
         //Load input as readonly whose values are overridden in civicrm.settings.php.
-        if (Civi::settings()->getMandatory($setting)) {
+        if (Civi::settings()->getMandatory($setting) !== NULL) {
           $props['html_attributes']['readonly'] = TRUE;
           $this->includesReadOnlyFields = TRUE;
         }
@@ -222,7 +224,7 @@ trait CRM_Admin_Form_SettingTrait {
           $this->$add($setting, $props['title'], $props['entity_reference_options']);
         }
         elseif ($add === 'addYesNo' && ($props['type'] === 'Boolean')) {
-          $this->addRadio($setting, $props['title'], [1 => 'Yes', 0 => 'No'], NULL, '&nbsp;&nbsp;');
+          $this->addRadio($setting, $props['title'], [1 => 'Yes', 0 => 'No'], CRM_Utils_Array::value('html_attributes', $props), '&nbsp;&nbsp;');
         }
         elseif ($add === 'add') {
           $this->add($props['html_type'], $setting, $props['title'], $options);
@@ -372,4 +374,19 @@ trait CRM_Admin_Form_SettingTrait {
     return array_intersect($order, $settingValueKeys);
   }
 
+  /**
+   * Add settings to form if the metadata designates they should be on the page.
+   *
+   * @throws \CiviCRM_API3_Exception
+   */
+  protected function addSettingsToFormFromMetadata() {
+    $filter = $this->getSettingPageFilter();
+    $settings = civicrm_api3('Setting', 'getfields', [])['values'];
+    foreach ($settings as $key => $setting) {
+      if (isset($setting['settings_pages'][$filter])) {
+        $this->_settings[$key] = $setting;
+      }
+    }
+  }
+
 }
index da37b04682985781db5a365fc20da5a20abb79d2..94f9c329c788b4e81c44e70a778281cff276ed47 100644 (file)
@@ -65,7 +65,7 @@ class CRM_Api4_Page_AJAX extends CRM_Core_Page {
     try {
       // Call multiple
       if (empty($this->urlPath[3])) {
-        $calls = CRM_Utils_Request::retrieve('calls', 'String', CRM_Core_DAO::$_nullObject, TRUE, NULL, 'POST', TRUE);
+        $calls = CRM_Utils_Request::retrieve('calls', 'String', CRM_Core_DAO::$_nullObject, TRUE, NULL, 'POST');
         $calls = json_decode($calls, TRUE);
         $response = [];
         foreach ($calls as $index => $call) {
index f481c016f0cf879c753df9354da8fadcabc65b97..f24066c6fbb8cf7efd4ddf775ad44037c35c192f 100644 (file)
@@ -15,6 +15,7 @@
  * @copyright CiviCRM LLC https://civicrm.org/licensing
  */
 
+
 /**
  * This class contains the functions for Case Management.
  */
@@ -284,7 +285,7 @@ WHERE civicrm_case.id = %1";
    *
    * @param int $activityId
    *
-   * @return int, case ID
+   * @return int|null, case ID
    */
   public static function getCaseIdByActivityId($activityId) {
     $originalId = CRM_Core_DAO::singleValueQuery(
index 21a44c5977a0ed19bdf016a5e815a8bcce9af951..d2864843150dcd97c20f7ea0e60f2b66b1493805 100644 (file)
@@ -106,13 +106,20 @@ class CRM_Case_Form_Report extends CRM_Core_Form {
     // store the submitted values in an array
     $params = $this->controller->exportValues($this->_name);
 
-    $xmlProcessor = new CRM_Case_XMLProcessor_Report();
-    $contents = $xmlProcessor->run($this->_clientID,
-      $this->_caseID,
-      $this->_activitySetName,
-      $params
+    // this is either a 1 or a 2, but the url expects a 1 or 0
+    $all = ($params['include_activities'] == 1) ? 1 : 0;
+
+    // similar but comes from a checkbox that's either 1 or not present
+    $is_redact = empty($params['is_redact']) ? 0 : 1;
+
+    $asn = rawurlencode($this->_activitySetName);
+
+    CRM_Utils_System::redirect(
+      CRM_Utils_System::url(
+        'civicrm/case/report/print',
+        "caseID={$this->_caseID}&cid={$this->_clientID}&asn={$asn}&redact={$is_redact}&all={$all}"
+      )
     );
-    $this->set('report', $contents);
   }
 
 }
index c25af90a00795e1920d1ac1491a899c324d94aba..0f996ee0c890116dd80d19f72e9ea8fd796bfc33 100644 (file)
@@ -36,7 +36,7 @@ class CRM_Case_Info extends CRM_Core_Component_Info {
       'translatedName' => ts('CiviCase'),
       'title' => ts('CiviCase Engine'),
       'search' => 1,
-      'showActivitiesInCore' => 0,
+      'showActivitiesInCore' => Civi::settings()->get('civicaseShowCaseActivities') ?? 0,
     ];
   }
 
index b240b3c77cf125272209600756d5eaf31cceae2f..fc4d6a2d3ecefa716e50a5a8642d8312b03d77f5 100644 (file)
@@ -131,7 +131,7 @@ class CRM_Case_XMLProcessor_Report extends CRM_Case_XMLProcessor {
       foreach ($activitySetsXML->ActivitySet as $activitySetXML) {
         if ((string ) $activitySetXML->name == $activitySetName) {
           $activityTypes = array();
-          $allActivityTypes = &$this->allActivityTypes();
+          $allActivityTypes = CRM_Case_PseudoConstant::caseActivityType(TRUE, TRUE);
           foreach ($activitySetXML->ActivityTypes as $activityTypesXML) {
             foreach ($activityTypesXML as $activityTypeXML) {
               $activityTypeName = (string ) $activityTypeXML->name;
@@ -752,7 +752,7 @@ LIMIT  1
     $case = $form->caseInfo($clientID, $caseID);
     $template->assign_by_ref('case', $case);
 
-    if ($params['include_activities'] == 1) {
+    if (CRM_Utils_Array::value('include_activities', $params) == 1) {
       $template->assign('includeActivities', 'All');
     }
     else {
index 5fa92afb0029655dd61a548af3d4e3fab61535cf..c297cd3a07ddb9371f37d35b34a182cd8df7b011 100644 (file)
@@ -163,9 +163,11 @@ class CRM_Contact_Form_Task_Label extends CRM_Contact_Form_Task {
       $location = ['location' => ["{$locName}" => $address]];
       $returnProperties = array_merge($returnProperties, $location);
       $params[] = ['location_type', '=', [1 => $fv['location_type_id']], 0, 0];
+      $primaryLocationOnly = FALSE;
     }
     else {
       $returnProperties = array_merge($returnProperties, $address);
+      $primaryLocationOnly = TRUE;
     }
 
     $rows = [];
@@ -198,7 +200,7 @@ class CRM_Contact_Form_Task_Label extends CRM_Contact_Form_Task {
     //get the total number of contacts to fetch from database.
     $numberofContacts = count($this->_contactIds);
     $query = new CRM_Contact_BAO_Query($params, $returnProperties);
-    $details = $query->apiQuery($params, $returnProperties, NULL, NULL, 0, $numberofContacts);
+    $details = $query->apiQuery($params, $returnProperties, NULL, NULL, 0, $numberofContacts, TRUE, FALSE, TRUE, CRM_Contact_BAO_Query::MODE_CONTACTS, NULL, $primaryLocationOnly);
 
     $messageToken = CRM_Utils_Token::getTokens($mailingFormat);
 
index 444d3f96db1a16613f40093b44316da47b958049..334925e6af939e7fde784749714312d81b5845fa 100644 (file)
@@ -346,111 +346,51 @@ class CRM_Contact_Page_AJAX {
    *  Function to get email address of a contact.
    */
   public static function getContactEmail() {
-    if (!empty($_REQUEST['contact_id'])) {
-      $contactID = CRM_Utils_Type::escape($_REQUEST['contact_id'], 'Positive');
-      if (!CRM_Contact_BAO_Contact_Permission::allow($contactID, CRM_Core_Permission::EDIT)) {
-        return;
+    $queryStrings = [];
+    $name = CRM_Utils_Array::value('name', $_GET);
+    if ($name) {
+      $name = CRM_Utils_Type::escape($name, 'String');
+      $wildCard = Civi::settings()->get('includeWildCardInName') ? '%' : '';
+      foreach (['cc.sort_name', 'ce.email'] as $column) {
+        $queryStrings[] = "{$column} LIKE '{$wildCard}{$name}%'";
       }
-      list($displayName,
-        $userEmail
-        ) = CRM_Contact_BAO_Contact_Location::getEmailDetails($contactID);
+      $result = [];
+      $rowCount = Civi::settings()->get('search_autocomplete_count');
 
-      CRM_Utils_System::setHttpHeader('Content-Type', 'text/plain');
-      if ($userEmail) {
-        echo $userEmail;
-      }
-    }
-    else {
-      $noemail = CRM_Utils_Array::value('noemail', $_GET);
-      $queryString = NULL;
-      $name = CRM_Utils_Array::value('name', $_GET);
-      if ($name) {
-        $name = CRM_Utils_Type::escape($name, 'String');
-        if ($noemail) {
-          $queryString = " cc.sort_name LIKE '%$name%'";
-        }
-        else {
-          $queryString = " ( cc.sort_name LIKE '%$name%' OR ce.email LIKE '%$name%' ) ";
-        }
-      }
-      else {
-        $cid = CRM_Utils_Array::value('cid', $_GET);
-        if ($cid) {
-          //check cid for integer
-          $contIDS = explode(',', $cid);
-          foreach ($contIDS as $contID) {
-            CRM_Utils_Type::escape($contID, 'Integer');
-          }
-          $queryString = " cc.id IN ( $cid )";
-        }
+      // add acl clause here
+      list($aclFrom, $aclWhere) = CRM_Contact_BAO_Contact_Permission::cacheClause('cc');
+      if ($aclWhere) {
+        $aclWhere = "AND {$aclWhere}";
       }
-
-      if ($queryString) {
-        $result = [];
-        $offset = CRM_Utils_Array::value('offset', $_GET, 0);
-        $rowCount = Civi::settings()->get('search_autocomplete_count');
-
-        $offset = CRM_Utils_Type::escape($offset, 'Int');
-
-        // add acl clause here
-        list($aclFrom, $aclWhere) = CRM_Contact_BAO_Contact_Permission::cacheClause('cc');
-        if ($aclWhere) {
-          $aclWhere = " AND $aclWhere";
-        }
-        if ($noemail) {
-          $query = "
-SELECT sort_name name, cc.id
-FROM civicrm_contact cc
-     {$aclFrom}
-WHERE cc.is_deceased = 0 AND {$queryString}
-      {$aclWhere}
-LIMIT {$offset}, {$rowCount}
-";
-
-          // send query to hook to be modified if needed
-          CRM_Utils_Hook::contactListQuery($query,
-            $name,
-            CRM_Utils_Request::retrieve('context', 'Alphanumeric'),
-            CRM_Utils_Request::retrieve('cid', 'Positive')
-          );
-
-          $dao = CRM_Core_DAO::executeQuery($query);
-          while ($dao->fetch()) {
-            $result[] = [
-              'id' => $dao->id,
-              'text' => $dao->name,
-            ];
-          }
-        }
-        else {
-          $query = "
+      foreach ($queryStrings as &$queryString) {
+        $queryString = "(
 SELECT sort_name name, ce.email, cc.id
 FROM   civicrm_email ce INNER JOIN civicrm_contact cc ON cc.id = ce.contact_id
        {$aclFrom}
 WHERE  ce.on_hold = 0 AND cc.is_deceased = 0 AND cc.do_not_email = 0 AND {$queryString}
        {$aclWhere}
-LIMIT {$offset}, {$rowCount}
-";
+LIMIT {$rowCount}
+)";
+      }
+      $query = implode(' UNION ', $queryStrings) . " LIMIT {$rowCount}";
 
-          // send query to hook to be modified if needed
-          CRM_Utils_Hook::contactListQuery($query,
-            $name,
-            CRM_Utils_Request::retrieve('context', 'Alphanumeric'),
-            CRM_Utils_Request::retrieve('cid', 'Positive')
-          );
-
-          $dao = CRM_Core_DAO::executeQuery($query);
-
-          while ($dao->fetch()) {
-            //working here
-            $result[] = [
-              'text' => '"' . $dao->name . '" <' . $dao->email . '>',
-              'id' => (CRM_Utils_Array::value('id', $_GET)) ? "{$dao->id}::{$dao->email}" : '"' . $dao->name . '" <' . $dao->email . '>',
-            ];
-          }
-        }
-        CRM_Utils_JSON::output($result);
+      // send query to hook to be modified if needed
+      CRM_Utils_Hook::contactListQuery($query,
+        $name,
+        CRM_Utils_Request::retrieve('context', 'Alphanumeric'),
+        CRM_Utils_Request::retrieve('cid', 'Positive')
+      );
+
+      $dao = CRM_Core_DAO::executeQuery($query);
+
+      while ($dao->fetch()) {
+        //working here
+        $result[] = [
+          'text' => '"' . $dao->name . '" <' . $dao->email . '>',
+          'id' => (CRM_Utils_Array::value('id', $_GET)) ? "{$dao->id}::{$dao->email}" : '"' . $dao->name . '" <' . $dao->email . '>',
+        ];
       }
+      CRM_Utils_JSON::output($result);
     }
     CRM_Utils_System::civiExit();
   }
index a5648cdd677024a4af397bd676313ce8fe1393d5..9b95964b0191e8dc02cd7b413d8e33453d067b1d 100644 (file)
@@ -24,10 +24,12 @@ class CRM_Contact_Page_Inline_CommunicationPreferences extends CRM_Core_Page {
    * Run the page.
    *
    * This method is called after the page is created.
+   *
+   * @throws \CRM_Core_Exception
    */
   public function run() {
     // get the emails for this contact
-    $contactId = CRM_Utils_Request::retrieve('cid', 'Positive', CRM_Core_DAO::$_nullObject, TRUE, NULL, $_REQUEST);
+    $contactId = CRM_Utils_Request::retrieve('cid', 'Positive', CRM_Core_DAO::$_nullObject, TRUE);
 
     $params = ['id' => $contactId];
 
index 50897e0bc65a4ab39b2041966e09966950d9ef55..53e93e9f5617cc5f878ab3263f90c4b487ae5b35 100644 (file)
@@ -24,10 +24,12 @@ class CRM_Contact_Page_Inline_OpenID extends CRM_Core_Page {
    * Run the page.
    *
    * This method is called after the page is created.
+   *
+   * @throws \CRM_Core_Exception
    */
   public function run() {
     // get the emails for this contact
-    $contactId = CRM_Utils_Request::retrieve('cid', 'Positive', CRM_Core_DAO::$_nullObject, TRUE, NULL, $_REQUEST);
+    $contactId = CRM_Utils_Request::retrieve('cid', 'Positive', CRM_Core_DAO::$_nullObject, TRUE);
 
     $locationTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id', ['labelColumn' => 'display_name']);
 
index 478d1592ace1db4b54863d4046f24b40a037b1c6..714c1c039dd715a6132b5e524bd62453bc980c15 100644 (file)
@@ -24,10 +24,12 @@ class CRM_Contact_Page_Inline_Phone extends CRM_Core_Page {
    * Run the page.
    *
    * This method is called after the page is created.
+   *
+   * @throws \CRM_Core_Exception
    */
   public function run() {
     // get the emails for this contact
-    $contactId = CRM_Utils_Request::retrieve('cid', 'Positive', CRM_Core_DAO::$_nullObject, TRUE, NULL, $_REQUEST);
+    $contactId = CRM_Utils_Request::retrieve('cid', 'Positive', CRM_Core_DAO::$_nullObject, TRUE);
 
     $locationTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id', ['labelColumn' => 'display_name']);
     $phoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id');
index e1402c96775781ecbcd4f49d6e7a4fea88ed9653..de416295df8da6c15cd918882ecc0771719c17fc 100644 (file)
@@ -24,10 +24,12 @@ class CRM_Contact_Page_Inline_Website extends CRM_Core_Page {
    * Run the page.
    *
    * This method is called after the page is created.
+   *
+   * @throws \CRM_Core_Exception
    */
   public function run() {
     // get the emails for this contact
-    $contactId = CRM_Utils_Request::retrieve('cid', 'Positive', CRM_Core_DAO::$_nullObject, TRUE, NULL, $_REQUEST);
+    $contactId = CRM_Utils_Request::retrieveValue('cid', 'Positive');
 
     $websiteTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Website', 'website_type_id');
 
index 4cc044b85c147073298edc14f649ae1b9f49c98b..edf648b09856038889835b423ac86dd5f4d97d98 100644 (file)
@@ -180,6 +180,7 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
     $setPrevContribution = TRUE;
     // CRM-13964 partial payment
     if (!empty($params['partial_payment_total']) && !empty($params['partial_amount_to_pay'])) {
+      CRM_Core_Error::deprecatedFunctionWarning('partial_amount params are deprecated from Contribution.create - use Payment.create');
       $partialAmtTotal = $params['partial_payment_total'];
       $partialAmtPay = $params['partial_amount_to_pay'];
       $params['total_amount'] = $partialAmtTotal;
@@ -3489,6 +3490,7 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
     if ($contributionStatus == 'Partially paid'
       && !empty($params['partial_payment_total']) && !empty($params['partial_amount_to_pay'])
     ) {
+      CRM_Core_Error::deprecatedFunctionWarning('partial_amount params are deprecated from Contribution.create - use Payment.create');
       $partialAmtPay = CRM_Utils_Rule::cleanMoney($params['partial_amount_to_pay']);
       $partialAmtTotal = CRM_Utils_Rule::cleanMoney($params['partial_payment_total']);
 
@@ -4135,7 +4137,12 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
             [
               'id' => $resultDAO->id,
               'contribution_id' => $contributionId,
-            ]
+            ],
+            ts('more'),
+            FALSE,
+            'Payment.edit.action',
+            'Payment',
+            $resultDAO->id
           );
         }
 
@@ -4840,40 +4847,6 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
     return '';
   }
 
-  /**
-   * Function to add payments for contribution for Partially Paid status
-   *
-   * @deprecated this is known to be flawed and possibly buggy.
-   *
-   * Replace with Order.create->Payment.create flow.
-   *
-   * @param array $contribution
-   *
-   * @throws \CiviCRM_API3_Exception
-   */
-  public static function addPayments($contribution) {
-    // get financial trxn which is a payment
-    $ftSql = "SELECT ft.id, ft.total_amount
-      FROM civicrm_financial_trxn ft
-      INNER JOIN civicrm_entity_financial_trxn eft ON eft.financial_trxn_id = ft.id AND eft.entity_table = 'civicrm_contribution'
-      WHERE eft.entity_id = %1 AND ft.is_payment = 1 ORDER BY ft.id DESC LIMIT 1";
-
-    $ftDao = CRM_Core_DAO::executeQuery($ftSql, [
-      1 => [
-        $contribution->id,
-        'Integer',
-      ],
-    ]);
-    $ftDao->fetch();
-
-    // store financial item Proportionaly.
-    $trxnParams = [
-      'total_amount' => $ftDao->total_amount,
-      'contribution_id' => $contribution->id,
-    ];
-    self::assignProportionalLineItems($trxnParams, $ftDao->id, $contribution->total_amount);
-  }
-
   /**
    * Function use to store line item proportionally in in entity financial trxn table
    *
index 04be631bb13810d842ab22bbbae5b12b9e5b7a15..7469609f7fbcaf2fc35f40f3e8a639005888a976 100644 (file)
@@ -372,19 +372,12 @@ WHERE  contribution_id = {$id}
     }
     $this->_processors = [];
     foreach ($this->_paymentProcessors as $id => $processor) {
-      // @todo review this. The inclusion of this IF was to address test processors being incorrectly loaded.
-      // However the function $this->getValidProcessors() is expected to only return the processors relevant
-      // to the mode (using the actual id - ie. the id of the test processor for the test processor).
-      // for some reason there was a need to filter here per commit history - but this indicates a problem
-      // somewhere else.
-      if ($processor['is_test'] == ($this->_mode == 'test')) {
-        $this->_processors[$id] = $processor['name'];
-        if (!empty($processor['description'])) {
-          $this->_processors[$id] .= ' : ' . $processor['description'];
-        }
-        if ($processor['is_recur']) {
-          $this->_recurPaymentProcessors[$id] = $this->_processors[$id];
-        }
+      $this->_processors[$id] = $processor['name'];
+      if (!empty($processor['description'])) {
+        $this->_processors[$id] .= ' : ' . $processor['description'];
+      }
+      if ($processor['is_recur']) {
+        $this->_recurPaymentProcessors[$id] = $this->_processors[$id];
       }
     }
     // CRM-21002: pass the default payment processor ID whose credit card type icons should be populated first
index ee860de148faacef9a46c178cacb3336b98f096a..cf387bf9444c5898cd3acac6b83eefeeaa2d9508 100644 (file)
@@ -167,6 +167,8 @@ class CRM_Contribute_Form_AdditionalPayment extends CRM_Contribute_Form_Abstract
 
   /**
    * Build the form object.
+   *
+   * @throws \CRM_Core_Exception
    */
   public function buildQuickForm() {
     if ($this->_view == 'transaction' && ($this->_action & CRM_Core_Action::BROWSE)) {
index e02ae64bb5860f1c211cf476dd5a5b2de209cfc8..4cbac2cfb6cac0533e45cf399ded972a1d1be75b 100644 (file)
@@ -68,7 +68,7 @@ class CRM_Contribute_Form_CancelSubscription extends CRM_Contribute_Form_Contrib
 
     if ($this->_coid) {
       if (CRM_Contribute_BAO_Contribution::isSubscriptionCancelled($this->_coid)) {
-        CRM_Core_Error::fatal(ts('The recurring contribution looks to have been cancelled already.'));
+        CRM_Core_Error::statusBounce(ts('The recurring contribution looks to have been cancelled already.'));
       }
       $this->_paymentProcessorObj = CRM_Financial_BAO_PaymentProcessor::getProcessorForEntity($this->_coid, 'contribute', 'obj');
 
index 9ff683534ce741ff4ede8d5ce4001dd347f63cd9..54171aba75defd8613c65aac7e5c8efc33a80b30 100644 (file)
@@ -286,24 +286,13 @@ class CRM_Contribute_Form_Task_Invoice extends CRM_Contribute_Form_Task {
       $invoiceDate = date("F j, Y");
       $dueDate = date('F j, Y', strtotime($contributionReceiveDate . "+" . $prefixValue['due_date'] . "" . $prefixValue['due_date_period']));
 
-      $lineItem = CRM_Price_BAO_LineItem::getLineItemsByContributionID($contribID);
-
-      $resultPayments = civicrm_api3('Payment', 'get', [
-        'sequential' => 1,
-        'contribution_id' => $contribID,
-      ]);
-      $amountPaid = 0;
-      foreach ($resultPayments['values'] as $singlePayment) {
-        // Only count payments that have been (status =) completed.
-        if ($singlePayment['status_id'] == 1) {
-          $amountPaid += $singlePayment['total_amount'];
-        }
-      }
+      $amountPaid = CRM_Core_BAO_FinancialTrxn::getTotalPayments($contribID, TRUE);
       $amountDue = ($input['amount'] - $amountPaid);
 
       // retrieving the subtotal and sum of same tax_rate
       $dataArray = [];
       $subTotal = 0;
+      $lineItem = CRM_Price_BAO_LineItem::getLineItemsByContributionID($contribID);
       foreach ($lineItem as $taxRate) {
         if (isset($dataArray[(string) $taxRate['tax_rate']])) {
           $dataArray[(string) $taxRate['tax_rate']] = $dataArray[(string) $taxRate['tax_rate']] + CRM_Utils_Array::value('tax_amount', $taxRate);
index 359685a8cf12a0605ff8d970403e709fe21332d6..e011e4e884eb28fa895bfa2f28957a4857c9211b 100644 (file)
@@ -263,8 +263,7 @@ class CRM_Core_BAO_ConfigSetting {
       'Boolean',
       CRM_Core_DAO::$_nullArray,
       FALSE,
-      FALSE,
-      'REQUEST'
+      FALSE
     );
     if ($config->userSystem->is_drupal &&
       $resetSessionTable
index 1f21c3e80edcf701a797f0363062f312cdf3007b..0c314495ff4ffc264000e4d589dd3c4592689856 100644 (file)
@@ -738,7 +738,6 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField {
       }
 
       // Add data for popup link. Normally this is handled by CRM_Core_Form->addSelect
-      $isSupportedWidget = in_array($widget, ['Select', 'Radio']);
       $canEditOptions = CRM_Core_Permission::check('administer CiviCRM');
       if ($field->option_group_id && !$search && $isSelect && $canEditOptions) {
         $customFieldAttributes += array(
index 4fe04b8f1d0315522d164f9ea8512b8a49dcdd45..382fbb5c31678dd07d96bdc5aa5b4d63f80b897c 100644 (file)
@@ -70,6 +70,8 @@ class CRM_Core_BAO_Log extends CRM_Core_DAO_Log {
    * @param string $tableName
    * @param int $tableID
    * @param int $userID
+   *
+   * @throws \CRM_Core_Exception
    */
   public static function register(
     $contactID,
index ce27f69cb6d3e3f1dd45b36e2dbd3bad375a0c22..1e839357c2329322dd323dc3bcea7cb4d22bf852 100644 (file)
@@ -84,7 +84,7 @@ class CRM_Core_BAO_Note extends CRM_Core_DAO_Note {
 
     CRM_Utils_Hook::notePrivacy($noteValues);
 
-    if (!$noteValues['privacy']) {
+    if (empty($noteValues['privacy'])) {
       return FALSE;
     }
     elseif (isset($noteValues['notePrivacy_hidden'])) {
index c72232029558ef83226eba825d1bb62746eeff60..73f40cc77b8c437b8b08360a5f973821452b933d 100644 (file)
@@ -3,7 +3,7 @@
  +--------------------------------------------------------------------+
  | CiviCRM version 5                                                  |
  +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2019                                |
+ | Copyright CiviCRM LLC (c) 2004-2020                                |
  +--------------------------------------------------------------------+
  | This file is a part of CiviCRM.                                    |
  |                                                                    |
index 5eb5167b312547b67ee642697452616bf82392e9..782f72ca44f03096bb47e9381f02e232a94bd9c5 100644 (file)
@@ -776,10 +776,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
    * @throws \CRM_Core_Exception
    */
   protected function assignPaymentProcessor($isPayLaterEnabled) {
-    $this->_paymentProcessors = CRM_Financial_BAO_PaymentProcessor::getPaymentProcessors(
-      [ucfirst($this->_mode) . 'Mode'],
-      $this->_paymentProcessorIDs
-    );
+    $this->_paymentProcessors = CRM_Financial_BAO_PaymentProcessor::getPaymentProcessors([ucfirst($this->_mode) . 'Mode'], $this->_paymentProcessorIDs);
     if ($isPayLaterEnabled) {
       $this->_paymentProcessors[0] = CRM_Financial_BAO_PaymentProcessor::getPayment(0);
     }
index 5f0eeb5063c4b3a24e51d9f5b834fb6abae41143..60a11fdd6789f63ee1d72097c68f7dabfd73bbfe 100644 (file)
@@ -28,6 +28,8 @@ class CRM_Core_Page_AJAX_Location {
    * obtain the location of given contact-id.
    * This method is used by on-behalf-of form to dynamically generate poulate the
    * location field values for selected permissioned contact.
+   *
+   * @throws \CRM_Core_Exception
    */
   public static function getPermissionedLocation() {
     $cid = CRM_Utils_Request::retrieve('cid', 'Integer', CRM_Core_DAO::$_nullObject, TRUE);
index 1af72a2301f03e52b8dbd79952d03d886dea4fe9..18d89d958920eb4b93b6f78707671c6228ae2520 100644 (file)
@@ -354,7 +354,7 @@ abstract class CRM_Core_Payment {
    * @return bool
    */
   protected function supportsLiveMode() {
-    return TRUE;
+    return empty($this->_paymentProcessor['is_test']) ? TRUE : FALSE;
   }
 
   /**
@@ -363,7 +363,7 @@ abstract class CRM_Core_Payment {
    * @return bool
    */
   protected function supportsTestMode() {
-    return TRUE;
+    return empty($this->_paymentProcessor['is_test']) ? FALSE : TRUE;
   }
 
   /**
index d7c39838ee89103cc69cb64e701f3d0378b2c339..e0a079a8f1b8b48218c9811bdc6e9354531e7d66 100644 (file)
@@ -132,17 +132,6 @@ class CRM_Core_Payment_Dummy extends CRM_Core_Payment {
     return $params;
   }
 
-  /**
-   * Are back office payments supported.
-   *
-   * E.g paypal standard won't permit you to enter a credit card associated with someone else's login.
-   *
-   * @return bool
-   */
-  protected function supportsLiveMode() {
-    return TRUE;
-  }
-
   /**
    * Does this payment processor support refund?
    *
index be4a171c966765259bbf8eea14ef528f87cec236..fe267437f904fde2ac1f097565db67d8e00e3f6e 100644 (file)
@@ -160,6 +160,24 @@ class CRM_Core_Payment_Manual extends CRM_Core_Payment {
     return CRM_Core_PseudoConstant::getLabel('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', $this->getPaymentInstrumentID());
   }
 
+  /**
+   * Are live payments supported - e.g dummy doesn't support this.
+   *
+   * @return bool
+   */
+  protected function supportsLiveMode() {
+    return TRUE;
+  }
+
+  /**
+   * Are test payments supported.
+   *
+   * @return bool
+   */
+  protected function supportsTestMode() {
+    return TRUE;
+  }
+
   /**
    * Declare that more than one payment can be processed at once.
    *
diff --git a/CRM/Core/TokenTrait.php b/CRM/Core/TokenTrait.php
new file mode 100644 (file)
index 0000000..2611015
--- /dev/null
@@ -0,0 +1,85 @@
+<?php
+
+trait CRM_Core_TokenTrait {
+
+  private $basicTokens;
+  private $customFieldTokens;
+
+  /**
+   * CRM_Entity_Tokens constructor.
+   */
+  public function __construct() {
+    parent::__construct($this->getEntityName(), array_merge(
+      $this->getBasicTokens(),
+      $this->getCustomFieldTokens()
+    ));
+  }
+
+  /**
+   * @inheritDoc
+   */
+  public function checkActive(\Civi\Token\TokenProcessor $processor) {
+    return in_array($this->getEntityContextSchema(), $processor->context['schema']) ||
+      (!empty($processor->context['actionMapping'])
+        && $processor->context['actionMapping']->getEntity() === $this->getEntityTableName());
+  }
+
+  /**
+   * @inheritDoc
+   */
+  public function getActiveTokens(\Civi\Token\Event\TokenValueEvent $e) {
+    $messageTokens = $e->getTokenProcessor()->getMessageTokens();
+    if (!isset($messageTokens[$this->entity])) {
+      return NULL;
+    }
+
+    $activeTokens = [];
+    // if message token contains '_\d+_', then treat as '_N_'
+    foreach ($messageTokens[$this->entity] as $msgToken) {
+      if (array_key_exists($msgToken, $this->tokenNames)) {
+        $activeTokens[] = $msgToken;
+      }
+      else {
+        $altToken = preg_replace('/_\d+_/', '_N_', $msgToken);
+        if (array_key_exists($altToken, $this->tokenNames)) {
+          $activeTokens[] = $msgToken;
+        }
+      }
+    }
+    return array_unique($activeTokens);
+  }
+
+  /**
+   * Find the fields that we need to get to construct the tokens requested.
+   * @param  array $tokens list of tokens
+   * @return array         list of fields needed to generate those tokens
+   */
+  public function getReturnFields($tokens) {
+    // Make sure we always return something
+    $fields = ['id'];
+
+    foreach (array_intersect($tokens,
+      array_merge(array_keys(self::getBasicTokens()), array_keys(self::getCustomFieldTokens()))
+             ) as $token) {
+      if (isset(self::$fieldMapping[$token])) {
+        $fields = array_merge($fields, self::$fieldMapping[$token]);
+      }
+      else {
+        $fields[] = $token;
+      }
+    }
+    return array_unique($fields);
+  }
+
+  /**
+   * Get the tokens for custom fields
+   * @return array token name => token label
+   */
+  protected function getCustomFieldTokens() {
+    if (!isset($this->customFieldTokens)) {
+      $this->customFieldTokens = \CRM_Utils_Token::getCustomFieldTokens(ucfirst($this->getEntityName()));
+    }
+    return $this->customFieldTokens;
+  }
+
+}
index be9c335de5bc457c3b26e5f793c58045b1e7aba1..c68150360683c54a604ea2ac806aee24a32c69d6 100644 (file)
   <item>
      <path>civicrm/ajax/recipientListing</path>
      <page_callback>CRM_Admin_Page_AJAX::recipientListing</page_callback>
-     <access_arguments>administer CiviCRM,access CiviCRM</access_arguments>
+     <access_arguments>access CiviEvent,access CiviCRM</access_arguments>
   </item>
   <item>
      <path>civicrm/admin/sms/provider</path>
index 6ff97260ee6dca097d4d160f1cfc9d61dfc3fa68..73048c846c610e9db08ebfb689991c68922d9045 100644 (file)
@@ -41,6 +41,9 @@ class CRM_Dedupe_BAO_Rule extends CRM_Dedupe_DAO_Rule {
    *
    * @return string
    *   SQL query performing the search
+   *
+   * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
    */
   public function sql() {
     if ($this->params &&
@@ -126,7 +129,7 @@ class CRM_Dedupe_BAO_Rule extends CRM_Dedupe_DAO_Rule {
           $id = 'entity_id';
         }
         else {
-          CRM_Core_Error::fatal("Unsupported rule_table for civicrm_dedupe_rule.id of {$this->id}");
+          throw new CRM_Core_Exception("Unsupported rule_table for civicrm_dedupe_rule.id of {$this->id}");
         }
         break;
     }
@@ -211,7 +214,11 @@ class CRM_Dedupe_BAO_Rule extends CRM_Dedupe_DAO_Rule {
     $ruleBao->find();
     $ruleFields = [];
     while ($ruleBao->fetch()) {
-      $ruleFields[] = $ruleBao->rule_field;
+      $field_name = $ruleBao->rule_field;
+      if ($field_name == 'phone_numeric') {
+        $field_name = 'phone';
+      }
+      $ruleFields[] = $field_name;
     }
     return $ruleFields;
   }
index 08533684468f5053fca3c2ae21aca503d12cf21d..773e9ac1869080298ccd005b917994ea5309e2a0 100644 (file)
@@ -431,7 +431,11 @@ class CRM_Dedupe_BAO_RuleGroup extends CRM_Dedupe_DAO_RuleGroup {
     $ruleBao->find();
     $ruleFields = [];
     while ($ruleBao->fetch()) {
-      $ruleFields[$ruleBao->rule_field] = $ruleBao->rule_weight;
+      $field_name = $ruleBao->rule_field;
+      if ($field_name == 'phone_numeric') {
+        $field_name = 'phone';
+      }
+      $ruleFields[$field_name] = $ruleBao->rule_weight;
     }
 
     return [$ruleFields, $rgBao->threshold];
index 25fd1adbeaaadec3664f596896f31c51ce26dd5b..f2626bcb328ed8eebeb8cf7edf87d3552b90426b 100644 (file)
@@ -38,7 +38,7 @@ class CRM_Dedupe_Finder {
    * @return array
    *   Array of (cid1, cid2, weight) dupe triples
    *
-   * @throws Exception
+   * @throws \CRM_Core_Exception
    */
   public static function dupes($rgid, $cids = [], $checkPermissions = TRUE) {
     $rgBao = new CRM_Dedupe_BAO_RuleGroup();
@@ -152,7 +152,8 @@ class CRM_Dedupe_Finder {
    *
    * @return array
    *   array of (cid1, cid2, weight) dupe triples
-   * @throws \CiviCRM_API3_Exception
+   *
+   * @throws \CRM_Core_Exception
    */
   public static function dupesInGroup($rgid, $gid, $searchLimit = 0) {
     $cids = array_keys(CRM_Contact_BAO_Group::getMember($gid, TRUE, $searchLimit));
@@ -263,7 +264,7 @@ class CRM_Dedupe_Finder {
     $supportedFields = CRM_Dedupe_BAO_RuleGroup::supportedFields($ctype);
     if (is_array($supportedFields)) {
       foreach ($supportedFields as $table => $fields) {
-        if ($table == 'civicrm_address') {
+        if ($table === 'civicrm_address') {
           // for matching on civicrm_address fields, we also need the location_type_id
           $fields['location_type_id'] = '';
           // FIXME: we also need to do some hacking for id and name fields, see CRM-3902’s comments
index 12ec5faaa539e8ebf1d0838d31e026a8750fc369..c5f063d1dfd42c5845138ac3a6291ba8f6bd6057 100644 (file)
@@ -1357,7 +1357,7 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
       'id' => $otherId,
       'return' => ['created_date'],
     ])['created_date'];
-    if ($otherCreatedDate < $mainCreatedDate) {
+    if ($otherCreatedDate < $mainCreatedDate && !empty($otherCreatedDate)) {
       CRM_Core_DAO::executeQuery("UPDATE civicrm_contact SET created_date = %1 WHERE id = %2", [
         1 => [$otherCreatedDate, 'String'],
         2 => [$mainId, 'Positive'],
index f134201cc436ff695a0f6d89943ca0fc1c058163..b24c279aa80455fedab47a4f5fdc81036e049252 100644 (file)
@@ -1058,82 +1058,6 @@ WHERE cpf.price_set_id = %1 AND cpfv.label LIKE %2";
     return CRM_Core_DAO::singleValueQuery($query, $params);
   }
 
-  /**
-   * Get the event fee info for given participant ids
-   * either from line item table / participant table.
-   *
-   * @param array $participantIds
-   *   Participant ids.
-   * @param bool $hasLineItems
-   *   Do fetch from line items.
-   *
-   * @return array
-   */
-  public function getFeeDetails($participantIds, $hasLineItems = FALSE) {
-    $feeDetails = [];
-    if (!is_array($participantIds) || empty($participantIds)) {
-      return $feeDetails;
-    }
-
-    $select = '
-SELECT  participant.id         as id,
-        participant.fee_level  as fee_level,
-        participant.fee_amount as fee_amount';
-    $from = 'FROM civicrm_participant participant';
-    if ($hasLineItems) {
-      $select .= ' ,
-lineItem.id          as lineId,
-lineItem.label       as label,
-lineItem.qty         as qty,
-lineItem.unit_price  as unit_price,
-lineItem.line_total  as line_total,
-field.label          as field_title,
-field.html_type      as html_type,
-field.id             as price_field_id,
-value.id             as price_field_value_id,
-value.description    as description,
-IF( value.count, value.count, 0 ) as participant_count';
-      $from .= "
-INNER JOIN civicrm_line_item lineItem      ON ( lineItem.entity_table = 'civicrm_participant'
-                                                AND lineItem.entity_id = participant.id )
-INNER JOIN civicrm_price_field field ON ( field.id = lineItem.price_field_id )
-INNER JOIN civicrm_price_field_value value ON ( value.id = lineItem.price_field_value_id )
-";
-    }
-    $where = 'WHERE participant.id IN ( ' . implode(', ', $participantIds) . ' )';
-    $query = "$select $from  $where";
-
-    $feeInfo = CRM_Core_DAO::executeQuery($query);
-    $feeProperties = ['fee_level', 'fee_amount'];
-    $lineProperties = [
-      'lineId',
-      'label',
-      'qty',
-      'unit_price',
-      'line_total',
-      'field_title',
-      'html_type',
-      'price_field_id',
-      'participant_count',
-      'price_field_value_id',
-      'description',
-    ];
-    while ($feeInfo->fetch()) {
-      if ($hasLineItems) {
-        foreach ($lineProperties as $property) {
-          $feeDetails[$feeInfo->id][$feeInfo->lineId][$property] = $feeInfo->$property;
-        }
-      }
-      else {
-        foreach ($feeProperties as $property) {
-          $feeDetails[$feeInfo->id][$property] = $feeInfo->$property;
-        }
-      }
-    }
-
-    return $feeDetails;
-  }
-
   /**
    * Retrieve additional participants display-names and URL to view their participant records.
    * (excludes cancelled participants automatically)
index d1d5a95861b2ac879c94b844915c761285911ae0..57cbdae214b5fd1bc8cc7c4c9630655b1677de88 100644 (file)
@@ -119,13 +119,6 @@ class CRM_Event_Form_Participant extends CRM_Contribute_Form_AbstractEditPayment
    */
   public $_action;
 
-  /**
-   * Role Id.
-   *
-   * @var int
-   */
-  protected $_roleId = NULL;
-
   /**
    * Event Type Id.
    *
@@ -226,6 +219,31 @@ class CRM_Event_Form_Participant extends CRM_Contribute_Form_AbstractEditPayment
    */
   protected $participantRecord;
 
+  /**
+   * Params for creating a payment to add to the contribution.
+   *
+   * @var array
+   */
+  protected $createPaymentParams = [];
+
+  /**
+   * Get params to create payments.
+   *
+   * @return array
+   */
+  public function getCreatePaymentParams(): array {
+    return $this->createPaymentParams;
+  }
+
+  /**
+   * Set params to create payments.
+   *
+   * @param array $createPaymentParams
+   */
+  public function setCreatePaymentParams(array $createPaymentParams) {
+    $this->createPaymentParams = $createPaymentParams;
+  }
+
   /**
    * Explicitly declare the entity api name.
    */
@@ -392,7 +410,6 @@ class CRM_Event_Form_Participant extends CRM_Contribute_Form_AbstractEditPayment
     if ($this->_id) {
       // assign participant id to the template
       $this->assign('participantId', $this->_id);
-      $this->_roleId = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_Participant', $this->_id, 'role_id');
     }
 
     // when fee amount is included in form
@@ -1360,10 +1377,10 @@ class CRM_Event_Form_Participant extends CRM_Contribute_Form_AbstractEditPayment
           // CRM-13964 partial_payment_total
           if ($amountOwed > $params['total_amount']) {
             // the owed amount
-            $contributionParams['partial_payment_total'] = $amountOwed;
-            // the actual amount paid
-            $contributionParams['partial_amount_to_pay'] = $params['total_amount'];
-            $this->assign('balanceAmount', $contributionParams['partial_payment_total'] - $contributionParams['partial_amount_to_pay']);
+            $contributionParams['total_amount'] = $amountOwed;
+            $contributionParams['contribution_status_id'] = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Pending');
+            $this->assign('balanceAmount', $amountOwed - $params['total_amount']);
+            $this->storePaymentCreateParams($params);
           }
         }
 
@@ -1429,8 +1446,8 @@ class CRM_Event_Form_Participant extends CRM_Contribute_Form_AbstractEditPayment
         }
       }
       foreach ($contributions as $contribution) {
-        if ('Partially paid' === CRM_Core_PseudoConstant::getName('CRM_Contribute_BAO_Contribution', 'contribution_status_id', $contribution->contribution_status_id)) {
-          CRM_Contribute_BAO_Contribution::addPayments($contribution);
+        if (!empty($this->getCreatePaymentParams())) {
+          civicrm_api3('Payment', 'create', array_merge(['contribution_id' => $contribution->id], $this->getCreatePaymentParams()));
         }
       }
     }
@@ -1467,7 +1484,7 @@ class CRM_Event_Form_Participant extends CRM_Contribute_Form_AbstractEditPayment
           }
         }
 
-        $this->assign('totalAmount', $contributionParams['total_amount']);
+        $this->assign('totalAmount', $params['total_amount'] ?? $contributionParams['total_amount']);
         $this->assign('isPrimary', 1);
         $this->assign('checkNumber', CRM_Utils_Array::value('check_number', $params));
       }
@@ -1868,9 +1885,7 @@ class CRM_Event_Form_Participant extends CRM_Contribute_Form_AbstractEditPayment
       if (CRM_Event_BAO_Participant::isPrimaryParticipant($this->_id)) {
         $additionalIds = CRM_Event_BAO_Participant::getAdditionalParticipantIds($this->_id);
         $hasLineItems = CRM_Utils_Array::value('priceSetId', $params, FALSE);
-        $additionalParticipantDetails = CRM_Event_BAO_Participant::getFeeDetails($additionalIds,
-          $hasLineItems
-        );
+        $additionalParticipantDetails = $this->getFeeDetails($additionalIds, $hasLineItems);
       }
     }
     else {
@@ -2236,4 +2251,102 @@ class CRM_Event_Form_Participant extends CRM_Contribute_Form_AbstractEditPayment
     return '';
   }
 
+  /**
+   * Store the parameters to create a payment, if approprite, on the form.
+   *
+   * @param array $params
+   *   Params as submitted.
+   */
+  protected function storePaymentCreateParams($params) {
+    if ('Completed' === CRM_Core_PseudoConstant::getName('CRM_Contribute_BAO_Contribution', 'contribution_status_id', $params['contribution_status_id'])) {
+      $this->setCreatePaymentParams([
+        'total_amount' => $params['total_amount'],
+        'is_send_contribution_notification' => FALSE,
+        'payment_instrument_id' => $params['payment_instrument_id'],
+        'trxn_date' => $params['receive_date'] ?? date('Y-m-d'),
+        'trxn_id' => $params['trxn_id'],
+        'pan_truncation' => $params['pan_truncation'] ?? '',
+        'card_type_id' => $params['card_type_id'] ?? '',
+        'check_number' => $params['check_number'] ?? '',
+        'skipCleanMoney' => TRUE,
+      ]);
+    }
+  }
+
+  /**
+   * Get the event fee info for given participant ids
+   * either from line item table / participant table.
+   *
+   * @param array $participantIds
+   *   Participant ids.
+   * @param bool $hasLineItems
+   *   Do fetch from line items.
+   *
+   * @return array
+   */
+  public function getFeeDetails($participantIds, $hasLineItems = FALSE) {
+    $feeDetails = [];
+    if (!is_array($participantIds) || empty($participantIds)) {
+      return $feeDetails;
+    }
+
+    $select = '
+SELECT  participant.id         as id,
+        participant.fee_level  as fee_level,
+        participant.fee_amount as fee_amount';
+    $from = 'FROM civicrm_participant participant';
+    if ($hasLineItems) {
+      $select .= ' ,
+lineItem.id          as lineId,
+lineItem.label       as label,
+lineItem.qty         as qty,
+lineItem.unit_price  as unit_price,
+lineItem.line_total  as line_total,
+field.label          as field_title,
+field.html_type      as html_type,
+field.id             as price_field_id,
+value.id             as price_field_value_id,
+value.description    as description,
+IF( value.count, value.count, 0 ) as participant_count';
+      $from .= "
+INNER JOIN civicrm_line_item lineItem      ON ( lineItem.entity_table = 'civicrm_participant'
+                                                AND lineItem.entity_id = participant.id )
+INNER JOIN civicrm_price_field field ON ( field.id = lineItem.price_field_id )
+INNER JOIN civicrm_price_field_value value ON ( value.id = lineItem.price_field_value_id )
+";
+    }
+    $where = 'WHERE participant.id IN ( ' . implode(', ', $participantIds) . ' )';
+    $query = "$select $from  $where";
+
+    $feeInfo = CRM_Core_DAO::executeQuery($query);
+    $feeProperties = ['fee_level', 'fee_amount'];
+    $lineProperties = [
+      'lineId',
+      'label',
+      'qty',
+      'unit_price',
+      'line_total',
+      'field_title',
+      'html_type',
+      'price_field_id',
+      'participant_count',
+      'price_field_value_id',
+      'description',
+    ];
+    while ($feeInfo->fetch()) {
+      if ($hasLineItems) {
+        foreach ($lineProperties as $property) {
+          $feeDetails[$feeInfo->id][$feeInfo->lineId][$property] = $feeInfo->$property;
+        }
+      }
+      else {
+        foreach ($feeProperties as $property) {
+          $feeDetails[$feeInfo->id][$property] = $feeInfo->$property;
+        }
+      }
+    }
+
+    return $feeDetails;
+  }
+
 }
index 01c66c249ecd2e3a739ad0a4767a1f6fe8d25757..f55c5687e4163ceeea7d57f11c84fec16dc72cf5 100644 (file)
@@ -43,6 +43,8 @@ interface CRM_Extension_Container_Interface {
    *
    * @param string $key
    *   Fully-qualified extension name.
+   *
+   * @throws \CRM_Extension_Exception_MissingException
    */
   public function getResUrl($key);
 
index fddd975f496cea5c003a0d2c89f16cac00e649a7..43e185d3264fb0eb5daa8d8a78d5e147be745304 100644 (file)
@@ -44,6 +44,12 @@ class CRM_Extension_Info {
    */
   public $requires = [];
 
+  /**
+   * @var array
+   *   List of strings (tag-names).
+   */
+  public $tags = [];
+
   /**
    * Load extension info an XML file.
    *
@@ -155,6 +161,12 @@ class CRM_Extension_Info {
           ];
         }
       }
+      elseif ($attr === 'tags') {
+        $this->tags = [];
+        foreach ($val->tag as $tag) {
+          $this->tags[] = (string) $tag;
+        }
+      }
       elseif ($attr === 'requires') {
         $this->requires = $this->filterRequirements($val);
       }
index a21af4d43b7e2c7458014fd216043fac14abbc5c..4a34a79117b6b49a4e2a83f633be035a40a917bf 100644 (file)
@@ -236,9 +236,11 @@ class CRM_Extension_Mapper {
    *
    * @return string
    *   url for resources in this extension
+   *
+   * @throws \CRM_Extension_Exception_MissingException
    */
   public function keyToUrl($key) {
-    if ($key == 'civicrm') {
+    if ($key === 'civicrm') {
       // CRM-12130 Workaround: If the domain's config_backend is NULL at the start of the request,
       // then the Mapper is wrongly constructed with an empty value for $this->civicrmUrl.
       if (empty($this->civicrmUrl)) {
@@ -257,7 +259,7 @@ class CRM_Extension_Mapper {
    * @param bool $fresh
    *   whether to forcibly reload extensions list from canonical store.
    * @return array
-   *   array(array('prefix' => $, 'file' => $))
+   *   array(array('prefix' => $, 'fullName' => $, 'filePath' => $))
    */
   public function getActiveModuleFiles($fresh = FALSE) {
     if (!defined('CIVICRM_DSN')) {
@@ -265,11 +267,26 @@ class CRM_Extension_Mapper {
       return [];
     }
 
+    // The list of module files is cached in two tiers. The tiers are slightly
+    // different:
+    //
+    // 1. The persistent tier (cache) stores
+    // names WITHOUT absolute paths.
+    // 2. The ephemeral/thread-local tier (statics) stores names
+    // WITH absolute paths.
+    // Return static value instead of re-running query
+    if (isset(Civi::$statics[__CLASS__]['moduleExtensions']) && !$fresh) {
+      return Civi::$statics[__CLASS__]['moduleExtensions'];
+    }
+
     $moduleExtensions = NULL;
+
+    // Checked if it's stored in the persistent cache.
     if ($this->cache && !$fresh) {
       $moduleExtensions = $this->cache->get($this->cacheKey . '_moduleFiles');
     }
 
+    // If cache is empty we build it from database.
     if (!is_array($moduleExtensions)) {
       $compat = CRM_Extension_System::getCompatibilityInfo();
 
@@ -286,28 +303,36 @@ class CRM_Extension_Mapper {
         if (!empty($compat[$dao->full_name]['force-uninstall'])) {
           continue;
         }
-        try {
-          $moduleExtensions[] = [
-            'prefix' => $dao->file,
-            'filePath' => $this->keyToPath($dao->full_name),
-          ];
-        }
-        catch (CRM_Extension_Exception $e) {
-          // Putting a stub here provides more consistency
-          // in how getActiveModuleFiles when racing between
-          // dirty file-removals and cache-clears.
-          CRM_Core_Session::setStatus($e->getMessage(), '', 'error');
-          $moduleExtensions[] = [
-            'prefix' => $dao->file,
-            'filePath' => NULL,
-          ];
-        }
+        $moduleExtensions[] = [
+          'prefix' => $dao->file,
+          'fullName' => $dao->full_name,
+          'filePath' => NULL,
+        ];
       }
 
       if ($this->cache) {
         $this->cache->set($this->cacheKey . '_moduleFiles', $moduleExtensions);
       }
     }
+
+    // Since we're not caching the full path we add it now.
+    array_walk($moduleExtensions, function(&$value, $key) {
+      try {
+        if (!$value['filePath']) {
+          $value['filePath'] = $this->keyToPath($value['fullName']);
+        }
+      }
+      catch (CRM_Extension_Exception $e) {
+        // Putting a stub here provides more consistency
+        // in how getActiveModuleFiles when racing between
+        // dirty file-removals and cache-clears.
+        CRM_Core_Session::setStatus($e->getMessage(), '', 'error');
+        $value['filePath'] = NULL;
+      }
+    });
+
+    Civi::$statics[__CLASS__]['moduleExtensions'] = $moduleExtensions;
+
     return $moduleExtensions;
   }
 
@@ -316,6 +341,8 @@ class CRM_Extension_Mapper {
    *
    * @return array
    *   (string $extKey => string $baseUrl)
+   *
+   * @throws \CRM_Extension_Exception_MissingException
    */
   public function getActiveModuleUrls() {
     // TODO optimization/caching
@@ -324,7 +351,12 @@ class CRM_Extension_Mapper {
     foreach ($this->getModules() as $module) {
       /** @var $module CRM_Core_Module */
       if ($module->is_active) {
-        $urls[$module->name] = $this->keyToUrl($module->name);
+        try {
+          $urls[$module->name] = $this->keyToUrl($module->name);
+        }
+        catch (CRM_Extension_Exception_MissingException $e) {
+          CRM_Core_Session::setStatus(ts('An enabled extension is missing from the extensions directory') . ':' . $module->name);
+        }
       }
     }
     return $urls;
@@ -365,6 +397,42 @@ class CRM_Extension_Mapper {
     return $keys;
   }
 
+  /**
+   * Get a list of extensions which match a given tag.
+   *
+   * @param string $tag
+   *   Ex: 'foo'
+   * @return array
+   *   Array(string $key).
+   *   Ex: array("org.foo.bar").
+   */
+  public function getKeysByTag($tag) {
+    $allTags = $this->getAllTags();
+    return $allTags[$tag] ?? [];
+  }
+
+  /**
+   * Get a list of extension tags.
+   *
+   * @return array
+   *   Ex: ['form-building' => ['org.civicrm.afform-gui', 'org.civicrm.afform-html']]
+   */
+  public function getAllTags() {
+    $tags = Civi::cache('short')->get('extension_tags', NULL);
+    if ($tags !== NULL) {
+      return $tags;
+    }
+
+    $tags = [];
+    $allInfos = $this->getAllInfos();
+    foreach ($allInfos as $key => $info) {
+      foreach ($info->tags as $tag) {
+        $tags[$tag][] = $key;
+      }
+    }
+    return $tags;
+  }
+
   /**
    * @return array
    *   Ex: $result['org.civicrm.foobar'] = new CRM_Extension_Info(...).
index 122f13cb918ec4cbe2fecc230e74d92faa3fe18d..7cd09259cc78d89a4f583ed3358097559691252f 100644 (file)
@@ -45,6 +45,8 @@ class CRM_Financial_BAO_Payment {
     $whiteList = ['check_number', 'payment_processor_id', 'fee_amount', 'total_amount', 'contribution_id', 'net_amount', 'card_type_id', 'pan_truncation', 'trxn_result_code', 'payment_instrument_id', 'trxn_id', 'trxn_date'];
     $paymentTrxnParams = array_intersect_key($params, array_fill_keys($whiteList, 1));
     $paymentTrxnParams['is_payment'] = 1;
+    // Really we should have a DB default.
+    $paymentTrxnParams['fee_amount'] = $paymentTrxnParams['fee_amount'] ?? 0;
 
     if (isset($paymentTrxnParams['payment_processor_id']) && empty($paymentTrxnParams['payment_processor_id'])) {
       // Don't pass 0 - ie the Pay Later processor as it is  a pseudo-processor.
@@ -148,6 +150,13 @@ class CRM_Financial_BAO_Payment {
     }
     elseif ($contributionStatus === 'Pending' && $params['total_amount'] > 0) {
       self::updateContributionStatus($contribution['id'], 'Partially Paid');
+      $participantPayments = civicrm_api3('ParticipantPayment', 'get', [
+        'contribution_id' => $contribution['id'],
+        'participant_id.status_id' => ['IN' => ['Pending from pay later', 'Pending from incomplete transaction']],
+      ])['values'];
+      foreach ($participantPayments as $participantPayment) {
+        civicrm_api3('Participant', 'create', ['id' => $participantPayment['participant_id'], 'status_id' => 'Partially paid']);
+      }
     }
     elseif ($contributionStatus === 'Completed' && ((float) CRM_Core_BAO_FinancialTrxn::getTotalPayments($contribution['id'], TRUE) === 0.0)) {
       // If the contribution has previously been completed (fully paid) and now has total payments adding up to 0
index 65dae3da36241ca4ec63b36b561654afa8705904..b2508ec8653427b978c45ec31b27c1ec2f887b8f 100644 (file)
@@ -379,8 +379,8 @@ class CRM_Financial_BAO_PaymentProcessor extends CRM_Financial_DAO_PaymentProces
    *   available processors
    */
   public static function getPaymentProcessors($capabilities = [], $ids = FALSE) {
-    $testProcessors = in_array('TestMode', $capabilities) ? self::getAllPaymentProcessors('test') : [];
     if (is_array($ids)) {
+      $testProcessors = in_array('TestMode', $capabilities) ? self::getAllPaymentProcessors('test') : [];
       $processors = self::getAllPaymentProcessors('all', FALSE, FALSE);
       if (in_array('TestMode', $capabilities)) {
         $possibleLiveIDs = array_diff($ids, array_keys($testProcessors));
index 9a8e7133a216cb1f42fa2cf31ec8c0c4fcdd991a..cd8ee48acb9a7eee6a1f292add5a4987ba006eab 100644 (file)
@@ -75,7 +75,7 @@ class CRM_Logging_Schema {
     $domain = new CRM_Core_DAO_Domain();
     $domain->find(TRUE);
     if (!(CRM_Core_DAO::checkTriggerViewPermission(FALSE)) && $value) {
-      throw new API_Exception("In order to use this functionality, the installation's database user must have privileges to create triggers (in MySQL 5.0 â€“ and in MySQL 5.1 if binary logging is enabled â€“ this means the SUPER privilege). This install either does not seem to have the required privilege enabled.");
+      throw new API_Exception(ts("In order to use this functionality, the installation's database user must have privileges to create triggers and views (if binary logging is enabled â€“ this means the SUPER privilege). This install does not have the required privilege(s) enabled."));
     }
     return TRUE;
   }
index 8386983c67646cb7b9b03a68a2cb4067f57af704..9b184d93ccc78712c510edfcf6725f79f3380d35 100644 (file)
@@ -641,6 +641,7 @@ INNER JOIN  civicrm_membership_type type ON ( type.id = membership.membership_ty
       CRM_Activity_BAO_Activity::deleteActivity($params);
     }
     self::deleteMembershipPayment($membershipId, $preserveContrib);
+    CRM_Price_BAO_LineItem::deleteLineItems($membershipId, 'civicrm_membership');
 
     $results = $membership->delete();
     $transaction->commit();
@@ -2227,7 +2228,7 @@ WHERE      civicrm_membership.is_test = 0
       self::processOverriddenUntilDateMembership($dao1);
     }
 
-    $query = $baseQuery . " AND (civicrm_membership.is_override = 0 OR civicrm_membership.is_override IS NULL) 
+    $query = $baseQuery . " AND (civicrm_membership.is_override = 0 OR civicrm_membership.is_override IS NULL)
      AND civicrm_membership.status_id NOT IN (%1, %2, %3, %4)
      AND civicrm_membership.owner_membership_id IS NULL ";
     $params = [
index b761bc7dd52ace085fe5bbc0b88fb5d54aa70586..56acf7e3347895d6d29b35a2b8b53927843529f3 100644 (file)
@@ -39,6 +39,17 @@ class CRM_Report_Form_Contact_Detail extends CRM_Report_Form {
    */
   protected $groupFilterNotOptimised = TRUE;
 
+  /**
+   * Store the joins for civicrm_activity_contact
+   *
+   * Activities are retrieved by a union of four queries in order to catch
+   * activities where the contact is the source, target, assignee, or case
+   * contact.
+   *
+   * @var array
+   */
+  protected $activityContactJoin = [];
+
   /**
    * Class constructor.
    */
@@ -331,7 +342,7 @@ class CRM_Report_Form_Contact_Detail extends CRM_Report_Form {
         'dao' => 'CRM_Activity_DAO_ActivityContact',
         'fields' => [
           'source_contact_id' => [
-            'title' => ts('Added By'),
+            'title' => ts('Added by'),
             'name' => 'contact_id',
             'default' => TRUE,
           ],
@@ -453,71 +464,136 @@ class CRM_Report_Form_Contact_Detail extends CRM_Report_Form {
     $this->_selectedTables = array_diff($this->_selectedTables, $componentTables);
 
     if (!empty($this->_selectComponent['contribution_civireport'])) {
-      $this->_formComponent['contribution_civireport'] = " FROM
+      $this->_formComponent['contribution_civireport'] = <<<HERESQL
+      FROM
         civicrm_contact {$this->_aliases['civicrm_contact']}
         INNER JOIN civicrm_contribution {$this->_aliases['civicrm_contribution']}
           ON {$this->_aliases['civicrm_contact']}.id = {$this->_aliases['civicrm_contribution']}.contact_id
-      ";
+HERESQL;
     }
     if (!empty($this->_selectComponent['membership_civireport'])) {
-      $this->_formComponent['membership_civireport'] = " FROM
+      $this->_formComponent['membership_civireport'] = <<<HERESQL
+      FROM
         civicrm_contact {$this->_aliases['civicrm_contact']}
         INNER JOIN civicrm_membership {$this->_aliases['civicrm_membership']}
           ON {$this->_aliases['civicrm_contact']}.id = {$this->_aliases['civicrm_membership']}.contact_id
-      ";
+HERESQL;
     }
     if (!empty($this->_selectComponent['participant_civireport'])) {
-      $this->_formComponent['participant_civireport'] = " FROM
+      $this->_formComponent['participant_civireport'] = <<<HERESQL
+      FROM
         civicrm_contact {$this->_aliases['civicrm_contact']}
         INNER JOIN civicrm_participant {$this->_aliases['civicrm_participant']}
         ON {$this->_aliases['civicrm_contact']}.id = {$this->_aliases['civicrm_participant']}.contact_id
-      ";
+HERESQL;
     }
 
     if (!empty($this->_selectComponent['activity_civireport'])) {
+
+      // First, prepare all the joins to filter activities by contact
       $activityContacts = CRM_Activity_BAO_ActivityContact::buildOptions('record_type_id', 'validate');
-      $assigneeID = CRM_Utils_Array::key('Activity Assignees', $activityContacts);
-      $targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts);
-      $sourceID = CRM_Utils_Array::key('Activity Source', $activityContacts);
 
-      $this->_formComponent['activity_civireport'] = "FROM
+      $aliasMap = [
+        'Activity Assignees' => 'civicrm_activity_assignment',
+        'Activity Targets' => 'civicrm_activity_target',
+        'Activity Source' => 'civicrm_activity_source',
+      ];
+
+      $this->activityContactJoin['case'] = <<<HERESQL
+        JOIN civicrm_case_activity
+          ON civicrm_case_activity.activity_id = activity_civireport.id
+        JOIN civicrm_case
+          ON civicrm_case_activity.case_id = civicrm_case.id
+        JOIN civicrm_case_contact
+          ON civicrm_case_contact.case_id = civicrm_case.id
+          AND civicrm_case_contact.contact_id IN ([FILTERCONTACTSHERE])
+HERESQL;
+
+      // Collect the joins for civicrm_contact to each of the activity contact joins
+      $contactJoins = [];
+
+      foreach ($activityContacts as $recordTypeId => $label) {
+        if (empty($aliasMap[$label])) {
+          continue;
+        }
+
+        // Inner join on this record type
+        $this->activityContactJoin[$recordTypeId] = <<<HERESQL
+          JOIN civicrm_activity_contact {$aliasMap[$label]}
+            ON activity_civireport.id = {$aliasMap[$label]}.activity_id
+              AND {$aliasMap[$label]}.record_type_id = $recordTypeId
+              AND {$aliasMap[$label]}.contact_id IN ([FILTERCONTACTSHERE])
+HERESQL;
+
+        // Cycle through other record types to add left joins
+        foreach ($activityContacts as $recordTypeIdX => $labelX) {
+          if ($recordTypeIdX == $recordTypeId || empty($aliasMap[$labelX])) {
+            continue;
+          }
+          $this->activityContactJoin[$recordTypeId] .= <<<HERESQL
+            LEFT JOIN civicrm_activity_contact {$aliasMap[$labelX]}
+              ON activity_civireport.id = {$aliasMap[$labelX]}.activity_id
+                AND {$aliasMap[$labelX]}.record_type_id = $recordTypeIdX
+HERESQL;
+        }
+
+        // Add to the joins for case activities
+        $this->activityContactJoin['case'] .= <<<HERESQL
+          LEFT JOIN civicrm_activity_contact {$aliasMap[$label]}
+            ON activity_civireport.id = {$aliasMap[$label]}.activity_id
+              AND {$aliasMap[$label]}.record_type_id = $recordTypeId
+HERESQL;
+
+        // Each activity_contact join gets joined to civicrm_contact
+        $contactJoins[] = <<<HERESQL
+        LEFT JOIN civicrm_contact {$this->_aliases[$aliasMap[$label]]}
+          ON $aliasMap[$label].contact_id = {$this->_aliases[$aliasMap[$label]]}.id
+HERESQL;
+      }
+
+      // civicrm_contact joins into a single string
+      $contactJoins = implode(PHP_EOL, $contactJoins);
+
+      // Now filter out component activities that should be suppressed
+      $compInfo = CRM_Core_Component::getEnabledComponents();
+      $componentsList = [];
+      foreach ($compInfo as $compObj) {
+        if ($compObj->info['showActivitiesInCore']) {
+          $componentsList[] = $compObj->componentID;
+        }
+      }
+      $componentClause = "civicrm_option_value.component_id IS NULL";
+      if (!empty($componentsList)) {
+        $componentsIn = implode(', ', $componentsList);
+        $componentClause = <<<HERESQL
+        ( $componentClause
+          OR civicrm_option_value.component_id IN ($componentsIn) )
+HERESQL;
+      }
+
+      $this->_formComponent['activity_civireport'] = <<<HERESQL
+      FROM
           civicrm_activity {$this->_aliases['civicrm_activity']}
-          LEFT JOIN civicrm_activity_contact civicrm_activity_target
-            ON {$this->_aliases['civicrm_activity']}.id = civicrm_activity_target.activity_id
-            AND civicrm_activity_target.record_type_id = {$targetID}
-          LEFT JOIN civicrm_activity_contact civicrm_activity_assignment
-            ON {$this->_aliases['civicrm_activity']}.id = civicrm_activity_assignment.activity_id
-            AND civicrm_activity_assignment.record_type_id = {$assigneeID}
-          LEFT JOIN civicrm_activity_contact civicrm_activity_source
-            ON {$this->_aliases['civicrm_activity']}.id = civicrm_activity_source.activity_id
-            AND civicrm_activity_source.record_type_id = {$sourceID}
-          LEFT JOIN civicrm_contact {$this->_aliases['civicrm_activity_target']}
-            ON civicrm_activity_target.contact_id = {$this->_aliases['civicrm_activity_target']}.id
-          LEFT JOIN civicrm_contact {$this->_aliases['civicrm_activity_assignment']}
-            ON civicrm_activity_assignment.contact_id = {$this->_aliases['civicrm_activity_assignment']}.id
-          LEFT JOIN civicrm_contact {$this->_aliases['civicrm_activity_source']}
-            ON civicrm_activity_source.contact_id = {$this->_aliases['civicrm_activity_source']}.id
-          LEFT JOIN civicrm_option_value
-            ON ( {$this->_aliases['civicrm_activity']}.activity_type_id = civicrm_option_value.value )
-          LEFT JOIN civicrm_option_group
+          [ACTIVITYCONTACTJOINSHERE]
+          $contactJoins
+          JOIN civicrm_option_value
+            ON {$this->_aliases['civicrm_activity']}.activity_type_id = civicrm_option_value.value
+            AND $componentClause
+          JOIN civicrm_option_group
             ON civicrm_option_group.id = civicrm_option_value.option_group_id
-          LEFT JOIN civicrm_case_activity
-            ON civicrm_case_activity.activity_id = {$this->_aliases['civicrm_activity']}.id
-          LEFT JOIN civicrm_case
-            ON civicrm_case_activity.case_id = civicrm_case.id
-          LEFT JOIN civicrm_case_contact
-            ON civicrm_case_contact.case_id = civicrm_case.id
-      ";
+            AND civicrm_option_group.name = 'activity_type'
+HERESQL;
     }
 
     if (!empty($this->_selectComponent['relationship_civireport'])) {
-      $this->_formComponent['relationship_civireport'] = "FROM
+      $this->_formComponent['relationship_civireport'] = <<<HERESQL
+      FROM
         civicrm_relationship {$this->_aliases['civicrm_relationship']}
         LEFT JOIN civicrm_contact  {$this->_aliases['civicrm_contact']}
           ON {$this->_aliases['civicrm_contact']}.id = {$this->_aliases['civicrm_relationship']}.contact_id_b
         LEFT JOIN civicrm_contact  contact_a
           ON contact_a.id = {$this->_aliases['civicrm_relationship']}.contact_id_a
-      ";
+HERESQL;
     }
   }
 
@@ -575,9 +651,10 @@ class CRM_Report_Form_Contact_Detail extends CRM_Report_Form {
       if (!empty($this->_selectComponent[$val]) &&
         ($val != 'activity_civireport' && $val != 'relationship_civireport')
       ) {
-        $sql = "{$this->_selectComponent[$val]} {$this->_formComponent[$val]}
-                         WHERE    {$this->_aliases['civicrm_contact']}.id IN ( $selectedContacts )
-                          ";
+        $sql = <<<HERESQL
+        {$this->_selectComponent[$val]} {$this->_formComponent[$val]}
+        WHERE {$this->_aliases['civicrm_contact']}.id IN ( $selectedContacts )
+HERESQL;
 
         $dao = CRM_Core_DAO::executeQuery($sql);
         while ($dao->fetch()) {
@@ -606,14 +683,15 @@ class CRM_Report_Form_Contact_Detail extends CRM_Report_Form {
 
       $val = 'relationship_civireport';
       $eligibleResult[$val] = $val;
-      $sql = "{$this->_selectComponent[$val]},{$this->_aliases['civicrm_contact']}.display_name as contact_b_name,  contact_a.id as contact_a_id , contact_a.display_name  as contact_a_name  {$this->_formComponent[$val]}
-                         WHERE    ({$this->_aliases['civicrm_contact']}.id IN ( $selectedContacts )
-                                  OR
-                                  contact_a.id IN ( $selectedContacts ) ) AND
-                                  {$this->_aliases['civicrm_relationship']}.is_active = 1 AND
-                                  contact_a.is_deleted = 0 AND
-                                  {$this->_aliases['civicrm_contact']}.is_deleted = 0
-                         ";
+      $sql = <<<HERESQL
+      {$this->_selectComponent[$val]},{$this->_aliases['civicrm_contact']}.display_name as contact_b_name, contact_a.id as contact_a_id, contact_a.display_name as contact_a_name
+      {$this->_formComponent[$val]}
+      WHERE ({$this->_aliases['civicrm_contact']}.id IN ( $selectedContacts )
+          OR contact_a.id IN ( $selectedContacts ) )
+        AND {$this->_aliases['civicrm_relationship']}.is_active = 1
+        AND contact_a.is_deleted = 0
+        AND {$this->_aliases['civicrm_contact']}.is_deleted = 0
+HERESQL;
 
       $dao = CRM_Core_DAO::executeQuery($sql);
       while ($dao->fetch()) {
@@ -643,35 +721,35 @@ class CRM_Report_Form_Contact_Detail extends CRM_Report_Form {
     }
 
     if (!empty($this->_selectComponent['activity_civireport'])) {
-
-      $componentClause = "civicrm_option_value.component_id IS NULL";
-      $componentsIn = NULL;
-      $compInfo = CRM_Core_Component::getEnabledComponents();
-      foreach ($compInfo as $compObj) {
-        if ($compObj->info['showActivitiesInCore']) {
-          $componentsIn = $componentsIn ? ($componentsIn . ', ' .
-            $compObj->componentID) : $compObj->componentID;
-        }
-      }
-      if ($componentsIn) {
-        $componentClause = "( $componentClause OR
-                                      civicrm_option_value.component_id IN ($componentsIn) )";
-      }
-
       $val = 'activity_civireport';
       $eligibleResult[$val] = $val;
-      $sql = "{$this->_selectComponent[$val]} ,
-                 {$this->_aliases['civicrm_activity_source']}.display_name as added_by {$this->_formComponent[$val]}
-
-                 WHERE ( civicrm_activity_source.contact_id IN ($selectedContacts) OR
-                         civicrm_activity_target.contact_id IN ($selectedContacts) OR
-                         civicrm_activity_assignment.contact_id IN ($selectedContacts) OR
-                         civicrm_case_contact.contact_id IN ($selectedContacts) ) AND
-                         civicrm_option_group.name = 'activity_type' AND
-                         {$this->_aliases['civicrm_activity']}.is_test = 0 AND
-                         ($componentClause)
-                 ORDER BY {$this->_aliases['civicrm_activity']}.activity_date_time desc  ";
 
+      // The activities we want to show are those where the contact is the
+      // target, assignee, source, or the client on a case.  Since the vast
+      // majority of activities will not involve the client, it's impractical to
+      // retrieve all activities and use OR clauses in the WHERE.  Instead, we
+      // use a union of subqueries for each of the four ways activities might
+      // join to the contact.
+      $unionParts = [];
+      foreach ($this->activityContactJoin as $activityContactJoinClauses) {
+        $fromClauses = str_replace(
+          '[ACTIVITYCONTACTJOINSHERE]',
+          str_replace('[FILTERCONTACTSHERE]', $selectedContacts, $activityContactJoinClauses),
+          $this->_formComponent[$val]
+        );
+        $unionParts[] = <<<HERESQL
+        (
+          {$this->_selectComponent[$val]},
+          {$this->_aliases['civicrm_activity_source']}.display_name as added_by,
+          {$this->_aliases['civicrm_activity']}.activity_date_time as date_time_for_sort
+          $fromClauses
+
+          WHERE {$this->_aliases['civicrm_activity']}.is_test = 0
+        )
+HERESQL;
+      }
+
+      $sql = implode(' UNION ', $unionParts) . ' ORDER BY date_time_for_sort DESC';
       $dao = CRM_Core_DAO::executeQuery($sql);
       while ($dao->fetch()) {
         foreach ($this->_columnHeadersComponent[$val] as $key => $value) {
index 8703ce8b8e62d58d840d03a608574ee04281442e..f2756c3e65a34e17eac7cb21a96a0c10868148f4 100644 (file)
@@ -248,6 +248,9 @@ class CRM_Report_Form_Contact_Relationship extends CRM_Report_Form {
           'description' => [
             'title' => ts('Description'),
           ],
+          'is_active' => [
+            'title' => ts('Is active?'),
+          ],
           'relationship_id' => [
             'title' => ts('Rel ID'),
             'name' => 'id',
@@ -311,6 +314,10 @@ class CRM_Report_Form_Contact_Relationship extends CRM_Report_Form {
             'title' => ts('Start Date'),
             'name' => 'start_date',
           ],
+          'end_date' => [
+            'title' => ts('End Date'),
+            'name' => 'end_date',
+          ],
         ],
         'grouping' => 'relation-fields',
       ],
@@ -765,6 +772,8 @@ class CRM_Report_Form_Contact_Relationship extends CRM_Report_Form {
         $entryFound = TRUE;
       }
 
+      $rows[$rowNum]['civicrm_relationship_is_active'] = $row['civicrm_relationship_is_active'] ? ts('Yes') : '';
+
       // skip looking further in rows, if first row itself doesn't
       // have the column we need
       if (!$entryFound) {
index ab65d97d302abc0a2c9bd766e108c737c6c56197..c1ae2db6286ac2eded48ca564041df9350096b90 100644 (file)
  */
 class CRM_Report_Form_Contribute_Summary extends CRM_Report_Form {
 
-  protected $_charts = array(
+  protected $_charts = [
     '' => 'Tabular',
     'barChart' => 'Bar Chart',
     'pieChart' => 'Pie Chart',
-  );
-  protected $_customGroupExtends = array('Contribution', 'Contact', 'Individual');
+  ];
+  protected $_customGroupExtends = ['Contribution', 'Contact', 'Individual'];
   protected $_customGroupGroupBy = TRUE;
 
-  public $_drilldownReport = array('contribute/detail' => 'Link to Detail Report');
+  public $_drilldownReport = ['contribute/detail' => 'Link to Detail Report'];
 
   /**
    * To what frequency group-by a date column
    *
    * @var array
    */
-  protected $_groupByDateFreq = array(
+  protected $_groupByDateFreq = [
     'MONTH' => 'Month',
     'YEARWEEK' => 'Week',
     'DATE' => 'Day',
     'QUARTER' => 'Quarter',
     'YEAR' => 'Year',
     'FISCALYEAR' => 'Fiscal Year',
-  );
+  ];
 
   /**
    * This report has been optimised for group filtering.
@@ -60,256 +60,256 @@ class CRM_Report_Form_Contribute_Summary extends CRM_Report_Form {
    * Class constructor.
    */
   public function __construct() {
-    $this->_columns = array(
-      'civicrm_contact' => array(
+    $this->_columns = [
+      'civicrm_contact' => [
         'dao' => 'CRM_Contact_DAO_Contact',
         'fields' => array_merge(
           $this->getBasicContactFields(),
-          array(
-            'sort_name' => array(
+          [
+            'sort_name' => [
               'title' => ts('Contact Name'),
               'no_repeat' => TRUE,
-            ),
-          )
+            ],
+          ]
         ),
-        'filters' => $this->getBasicContactFilters(array('deceased' => NULL)),
+        'filters' => $this->getBasicContactFilters(['deceased' => NULL]),
         'grouping' => 'contact-fields',
-        'group_bys' => array(
-          'id' => array('title' => ts('Contact ID')),
-          'sort_name' => array(
+        'group_bys' => [
+          'id' => ['title' => ts('Contact ID')],
+          'sort_name' => [
             'title' => ts('Contact Name'),
-          ),
-        ),
-      ),
-      'civicrm_email' => array(
+          ],
+        ],
+      ],
+      'civicrm_email' => [
         'dao' => 'CRM_Core_DAO_Email',
-        'fields' => array(
-          'email' => array(
+        'fields' => [
+          'email' => [
             'title' => ts('Email'),
             'no_repeat' => TRUE,
-          ),
-        ),
+          ],
+        ],
         'grouping' => 'contact-fields',
-      ),
-      'civicrm_line_item' => array(
+      ],
+      'civicrm_line_item' => [
         'dao' => 'CRM_Price_DAO_LineItem',
-      ),
-      'civicrm_phone' => array(
+      ],
+      'civicrm_phone' => [
         'dao' => 'CRM_Core_DAO_Phone',
-        'fields' => array(
-          'phone' => array(
+        'fields' => [
+          'phone' => [
             'title' => ts('Phone'),
             'no_repeat' => TRUE,
-          ),
-        ),
+          ],
+        ],
         'grouping' => 'contact-fields',
-      ),
-      'civicrm_financial_type' => array(
+      ],
+      'civicrm_financial_type' => [
         'dao' => 'CRM_Financial_DAO_FinancialType',
-        'fields' => array('financial_type' => NULL),
+        'fields' => ['financial_type' => NULL],
         'grouping' => 'contri-fields',
-        'group_bys' => array(
-          'financial_type' => array('title' => ts('Financial Type')),
-        ),
-      ),
-      'civicrm_contribution' => array(
+        'group_bys' => [
+          'financial_type' => ['title' => ts('Financial Type')],
+        ],
+      ],
+      'civicrm_contribution' => [
         'dao' => 'CRM_Contribute_DAO_Contribution',
           //'bao'           => 'CRM_Contribute_BAO_Contribution',
-        'fields' => array(
-          'contribution_status_id' => array(
+        'fields' => [
+          'contribution_status_id' => [
             'title' => ts('Contribution Status'),
-          ),
-          'contribution_source' => array('title' => ts('Source')),
-          'currency' => array(
+          ],
+          'contribution_source' => ['title' => ts('Source')],
+          'currency' => [
             'required' => TRUE,
             'no_display' => TRUE,
-          ),
-          'contribution_page_id' => array(
+          ],
+          'contribution_page_id' => [
             'title' => ts('Contribution Page'),
-          ),
-          'total_amount' => array(
+          ],
+          'total_amount' => [
             'title' => ts('Contribution Amount Stats'),
             'default' => TRUE,
-            'statistics' => array(
+            'statistics' => [
               'count' => ts('Contributions'),
               'sum' => ts('Contribution Aggregate'),
               'avg' => ts('Contribution Avg'),
-            ),
-          ),
-          'non_deductible_amount' => array(
+            ],
+          ],
+          'non_deductible_amount' => [
             'title' => ts('Non-deductible Amount'),
-          ),
-        ),
+          ],
+        ],
         'grouping' => 'contri-fields',
-        'filters' => array(
-          'receive_date' => array('operatorType' => CRM_Report_Form::OP_DATE),
-          'thankyou_date' => array('operatorType' => CRM_Report_Form::OP_DATE),
-          'contribution_status_id' => array(
+        'filters' => [
+          'receive_date' => ['operatorType' => CRM_Report_Form::OP_DATE],
+          'thankyou_date' => ['operatorType' => CRM_Report_Form::OP_DATE],
+          'contribution_status_id' => [
             'title' => ts('Contribution Status'),
             'operatorType' => CRM_Report_Form::OP_MULTISELECT,
             'options' => CRM_Contribute_BAO_Contribution::buildOptions('contribution_status_id', 'search'),
-            'default' => array(1),
+            'default' => [1],
             'type' => CRM_Utils_Type::T_INT,
-          ),
-          'contribution_page_id' => array(
+          ],
+          'contribution_page_id' => [
             'title' => ts('Contribution Page'),
             'operatorType' => CRM_Report_Form::OP_MULTISELECT,
             'options' => CRM_Contribute_PseudoConstant::contributionPage(),
             'type' => CRM_Utils_Type::T_INT,
-          ),
-          'currency' => array(
+          ],
+          'currency' => [
             'title' => ts('Currency'),
             'operatorType' => CRM_Report_Form::OP_MULTISELECT,
             'options' => CRM_Core_OptionGroup::values('currencies_enabled'),
             'default' => NULL,
             'type' => CRM_Utils_Type::T_STRING,
-          ),
-          'financial_type_id' => array(
+          ],
+          'financial_type_id' => [
             'title' => ts('Financial Type'),
             'operatorType' => CRM_Report_Form::OP_MULTISELECT,
             'options' => CRM_Financial_BAO_FinancialType::getAvailableFinancialTypes(),
             'type' => CRM_Utils_Type::T_INT,
-          ),
-          'contribution_page_id' => array(
+          ],
+          'contribution_page_id' => [
             'title' => ts('Contribution Page'),
             'operatorType' => CRM_Report_Form::OP_MULTISELECT,
             'options' => CRM_Contribute_PseudoConstant::contributionPage(),
             'type' => CRM_Utils_Type::T_INT,
-          ),
-          'total_amount' => array(
+          ],
+          'total_amount' => [
             'title' => ts('Contribution Amount'),
-          ),
-          'non_deductible_amount' => array(
+          ],
+          'non_deductible_amount' => [
             'title' => ts('Non-deductible Amount'),
-          ),
-          'total_sum' => array(
+          ],
+          'total_sum' => [
             'title' => ts('Contribution Aggregate'),
             'type' => CRM_Report_Form::OP_INT,
             'dbAlias' => 'civicrm_contribution_total_amount_sum',
             'having' => TRUE,
-          ),
-          'total_count' => array(
+          ],
+          'total_count' => [
             'title' => ts('Contribution Count'),
             'type' => CRM_Report_Form::OP_INT,
             'dbAlias' => 'civicrm_contribution_total_amount_count',
             'having' => TRUE,
-          ),
-          'total_avg' => array(
+          ],
+          'total_avg' => [
             'title' => ts('Contribution Avg'),
             'type' => CRM_Report_Form::OP_INT,
             'dbAlias' => 'civicrm_contribution_total_amount_avg',
             'having' => TRUE,
-          ),
-        ),
-        'group_bys' => array(
-          'receive_date' => array(
+          ],
+        ],
+        'group_bys' => [
+          'receive_date' => [
             'frequency' => TRUE,
             'default' => TRUE,
             'chart' => TRUE,
-          ),
+          ],
           'contribution_source' => NULL,
-          'contribution_status_id' => array(
+          'contribution_status_id' => [
             'title' => ts('Contribution Status'),
             'operatorType' => CRM_Report_Form::OP_MULTISELECT,
             'options' => CRM_Contribute_BAO_Contribution::buildOptions('contribution_status_id', 'search'),
-            'default' => array(1),
+            'default' => [1],
             'type' => CRM_Utils_Type::T_INT,
-          ),
-          'contribution_page_id' => array(
+          ],
+          'contribution_page_id' => [
             'title' => ts('Contribution Page'),
             'operatorType' => CRM_Report_Form::OP_MULTISELECT,
             'options' => CRM_Contribute_PseudoConstant::contributionPage(),
             'type' => CRM_Utils_Type::T_INT,
-          ),
-        ),
-      ),
-      'civicrm_financial_trxn' => array(
+          ],
+        ],
+      ],
+      'civicrm_financial_trxn' => [
         'dao' => 'CRM_Financial_DAO_FinancialTrxn',
-        'fields' => array(
-          'card_type_id' => array(
+        'fields' => [
+          'card_type_id' => [
             'title' => ts('Credit Card Type'),
             'dbAlias' => 'GROUP_CONCAT(financial_trxn_civireport.card_type_id SEPARATOR ",")',
-          ),
-        ),
-        'filters' => array(
-          'card_type_id' => array(
+          ],
+        ],
+        'filters' => [
+          'card_type_id' => [
             'title' => ts('Credit Card Type'),
             'operatorType' => CRM_Report_Form::OP_MULTISELECT,
             'options' => CRM_Financial_DAO_FinancialTrxn::buildOptions('card_type_id'),
             'default' => NULL,
             'type' => CRM_Utils_Type::T_STRING,
-          ),
-        ),
-      ),
-      'civicrm_batch' => array(
+          ],
+        ],
+      ],
+      'civicrm_batch' => [
         'dao' => 'CRM_Batch_DAO_EntityBatch',
         'grouping' => 'contri-fields',
-        'fields' => array(
-          'batch_id' => array(
+        'fields' => [
+          'batch_id' => [
             'name' => 'batch_id',
             'title' => ts('Batch Title'),
             'dbAlias' => 'GROUP_CONCAT(DISTINCT batch_civireport.batch_id
                                     ORDER BY batch_civireport.batch_id SEPARATOR ",")',
-          ),
-        ),
-        'filters' => array(
-          'batch_id' => array(
+          ],
+        ],
+        'filters' => [
+          'batch_id' => [
             'title' => ts('Batch Title'),
             'operatorType' => CRM_Report_Form::OP_MULTISELECT,
             'options' => CRM_Batch_BAO_Batch::getBatches(),
             'type' => CRM_Utils_Type::T_INT,
-          ),
-        ),
-        'group_bys' => array(
-          'batch_id' => array('title' => ts('Batch Title')),
-        ),
-      ),
-      'civicrm_contribution_soft' => array(
+          ],
+        ],
+        'group_bys' => [
+          'batch_id' => ['title' => ts('Batch Title')],
+        ],
+      ],
+      'civicrm_contribution_soft' => [
         'dao' => 'CRM_Contribute_DAO_ContributionSoft',
-        'fields' => array(
-          'soft_amount' => array(
+        'fields' => [
+          'soft_amount' => [
             'title' => ts('Soft Credit Amount Stats'),
             'name' => 'amount',
-            'statistics' => array(
+            'statistics' => [
               'count' => ts('Soft Credits'),
               'sum' => ts('Soft Credit Aggregate'),
               'avg' => ts('Soft Credit Avg'),
-            ),
-          ),
-        ),
+            ],
+          ],
+        ],
         'grouping' => 'contri-fields',
-        'filters' => array(
-          'amount' => array(
+        'filters' => [
+          'amount' => [
             'title' => ts('Soft Credit Amount'),
-          ),
-          'soft_credit_type_id' => array(
+          ],
+          'soft_credit_type_id' => [
             'title' => ts('Soft Credit Type'),
             'operatorType' => CRM_Report_Form::OP_MULTISELECT,
             'options' => CRM_Core_OptionGroup::values('soft_credit_type'),
             'default' => NULL,
             'type' => CRM_Utils_Type::T_STRING,
-          ),
-          'soft_sum' => array(
+          ],
+          'soft_sum' => [
             'title' => ts('Soft Credit Aggregate'),
             'type' => CRM_Report_Form::OP_INT,
             'dbAlias' => 'civicrm_contribution_soft_soft_amount_sum',
             'having' => TRUE,
-          ),
-          'soft_count' => array(
+          ],
+          'soft_count' => [
             'title' => ts('Soft Credits Count'),
             'type' => CRM_Report_Form::OP_INT,
             'dbAlias' => 'civicrm_contribution_soft_soft_amount_count',
             'having' => TRUE,
-          ),
-          'soft_avg' => array(
+          ],
+          'soft_avg' => [
             'title' => ts('Soft Credit Avg'),
             'type' => CRM_Report_Form::OP_INT,
             'dbAlias' => 'civicrm_contribution_soft_soft_amount_avg',
             'having' => TRUE,
-          ),
-        ),
-      ),
-    ) + $this->addAddressFields();
+          ],
+        ],
+      ],
+    ] + $this->addAddressFields();
 
     $this->addCampaignFields('civicrm_contribution', TRUE);
 
@@ -323,8 +323,8 @@ class CRM_Report_Form_Contribute_Summary extends CRM_Report_Form {
    * Set select clause.
    */
   public function select() {
-    $select = array();
-    $this->_columnHeaders = array();
+    $select = [];
+    $this->_columnHeaders = [];
     foreach ($this->_columns as $tableName => $table) {
       if (array_key_exists('group_bys', $table)) {
         foreach ($table['group_bys'] as $fieldName => $field) {
@@ -383,8 +383,8 @@ class CRM_Report_Form_Contribute_Summary extends CRM_Report_Form {
               // just to make sure these values are transferred to rows.
               // since we need that for calculation purpose,
               // e.g making subtotals look nicer or graphs
-              $this->_columnHeaders["{$tableName}_{$fieldName}_interval"] = array('no_display' => TRUE);
-              $this->_columnHeaders["{$tableName}_{$fieldName}_subtotal"] = array('no_display' => TRUE);
+              $this->_columnHeaders["{$tableName}_{$fieldName}_interval"] = ['no_display' => TRUE];
+              $this->_columnHeaders["{$tableName}_{$fieldName}_subtotal"] = ['no_display' => TRUE];
             }
           }
         }
@@ -443,15 +443,15 @@ class CRM_Report_Form_Contribute_Summary extends CRM_Report_Form {
   public static function formRule($fields, $files, $self) {
     // Check for searching combination of display columns and
     // grouping criteria
-    $ignoreFields = array('total_amount', 'sort_name');
+    $ignoreFields = ['total_amount', 'sort_name'];
     $errors = $self->customDataFormRule($fields, $ignoreFields);
 
     if (empty($fields['fields']['total_amount'])) {
-      foreach (array(
+      foreach ([
         'total_count_value',
         'total_sum_value',
         'total_avg_value',
-      ) as $val) {
+      ] as $val) {
         if (!empty($fields[$val])) {
           $errors[$val] = ts("Please select the Amount Statistics");
         }
@@ -518,7 +518,7 @@ class CRM_Report_Form_Contribute_Summary extends CRM_Report_Form {
    */
   public function groupBy() {
     $this->_groupBy = "";
-    $groupByColumns = array();
+    $groupByColumns = [];
     $append = FALSE;
     if (!empty($this->_params['group_bys']) &&
       is_array($this->_params['group_bys'])
@@ -537,7 +537,7 @@ class CRM_Report_Form_Contribute_Summary extends CRM_Report_Form {
 
                 $append = "YEAR({$field['dbAlias']});;";
                 if (in_array(strtolower($this->_params['group_bys_freq'][$fieldName]),
-                  array('year')
+                  ['year']
                 )) {
                   $append = '';
                 }
@@ -563,7 +563,7 @@ class CRM_Report_Form_Contribute_Summary extends CRM_Report_Form {
       ) {
         $this->_rollup = " WITH ROLLUP";
       }
-      $groupBy = array();
+      $groupBy = [];
       foreach ($groupByColumns as $key => $val) {
         if (strpos($val, ';;') !== FALSE) {
           $groupBy = array_merge($groupBy, explode(';;', $val));
@@ -608,7 +608,12 @@ class CRM_Report_Form_Contribute_Summary extends CRM_Report_Form {
 
     $softCredit = CRM_Utils_Array::value('soft_amount', $this->_params['fields']);
     $onlySoftCredit = $softCredit && !CRM_Utils_Array::value('total_amount', $this->_params['fields']);
-    $group = "\nGROUP BY {$this->_aliases['civicrm_contribution']}.currency";
+    if (empty($this->_groupBy)) {
+      $group = "\nGROUP BY {$this->_aliases['civicrm_contribution']}.currency";
+    }
+    else {
+      $group = "\n {$this->_groupBy}, {$this->_aliases['civicrm_contribution']}.currency";
+    }
 
     $this->from('contribution');
     if ($softCredit) {
@@ -639,14 +644,38 @@ ROUND(AVG({$this->_aliases['civicrm_contribution_soft']}.amount), 2) as civicrm_
     $contriSQL = "SELECT {$contriQuery} {$group} {$this->_having}";
     $contriDAO = CRM_Core_DAO::executeQuery($contriSQL);
     $this->addToDeveloperTab($contriSQL);
-    $totalAmount = $average = $mode = $median = $softTotalAmount = $softAverage = array();
-    $count = $softCount = 0;
+    $currencies = $currAmount = $currAverage = $currCount = [];
+    $totalAmount = $average = $mode = $median = [];
+    $softTotalAmount = $softAverage = $averageCount = $averageSoftCount = [];
+    $softCount = $count = 0;
     while ($contriDAO->fetch()) {
-      $totalAmount[]
-        = CRM_Utils_Money::format($contriDAO->civicrm_contribution_total_amount_sum, $contriDAO->currency) .
-        " (" . $contriDAO->civicrm_contribution_total_amount_count . ")";
-      $average[] = CRM_Utils_Money::format($contriDAO->civicrm_contribution_total_amount_avg, $contriDAO->currency);
+      if (!isset($currAmount[$contriDAO->currency])) {
+        $currAmount[$contriDAO->currency] = 0;
+      }
+      if (!isset($currCount[$contriDAO->currency])) {
+        $currCount[$contriDAO->currency] = 0;
+      }
+      if (!isset($currAverage[$contriDAO->currency])) {
+        $currAverage[$contriDAO->currency] = 0;
+      }
+      if (!isset($averageCount[$contriDAO->currency])) {
+        $averageCount[$contriDAO->currency] = 0;
+      }
+      $currAmount[$contriDAO->currency] += $contriDAO->civicrm_contribution_total_amount_sum;
+      $currCount[$contriDAO->currency] += $contriDAO->civicrm_contribution_total_amount_count;
+      $currAverage[$contriDAO->currency] += $contriDAO->civicrm_contribution_total_amount_avg;
+      $averageCount[$contriDAO->currency]++;
       $count += $contriDAO->civicrm_contribution_total_amount_count;
+
+      if (!in_array($contriDAO->currency, $currencies)) {
+        $currencies[] = $contriDAO->currency;
+      }
+    }
+
+    foreach ($currencies as $currency) {
+      $totalAmount[] = CRM_Utils_Money::format($currAmount[$currency], $currency) .
+        " (" . $currCount[$currency] . ")";
+      $average[] = CRM_Utils_Money::format(($currAverage[$currency] / $averageCount[$currency]), $currency);
     }
 
     $groupBy = "\n{$group}, {$this->_aliases['civicrm_contribution']}.total_amount";
@@ -660,59 +689,82 @@ ROUND(AVG({$this->_aliases['civicrm_contribution_soft']}.amount), 2) as civicrm_
     $mode = $this->calculateMode($modeSQL);
     $median = $this->calculateMedian();
 
+    $currencies = $currSoftAmount = $currSoftAverage = $currSoftCount = [];
     if ($softCredit) {
       $softDAO = CRM_Core_DAO::executeQuery($softSQL);
       $this->addToDeveloperTab($softSQL);
       while ($softDAO->fetch()) {
-        $softTotalAmount[]
-          = CRM_Utils_Money::format($softDAO->civicrm_contribution_soft_soft_amount_sum, $softDAO->currency) .
-          " (" . $softDAO->civicrm_contribution_soft_soft_amount_count . ")";
-        $softAverage[] = CRM_Utils_Money::format($softDAO->civicrm_contribution_soft_soft_amount_avg, $softDAO->currency);
+        if (!isset($currSoftAmount[$softDAO->currency])) {
+          $currSoftAmount[$softDAO->currency] = 0;
+        }
+        if (!isset($currSoftCount[$softDAO->currency])) {
+          $currSoftCount[$softDAO->currency] = 0;
+        }
+        if (!isset($currSoftAverage[$softDAO->currency])) {
+          $currSoftAverage[$softDAO->currency] = 0;
+        }
+        if (!isset($averageSoftCount[$softDAO->currency])) {
+          $averageSoftCount[$softDAO->currency] = 0;
+        }
+        $currSoftAmount[$softDAO->currency] += $softDAO->civicrm_contribution_soft_soft_amount_sum;
+        $currSoftCount[$softDAO->currency] += $softDAO->civicrm_contribution_soft_soft_amount_count;
+        $currSoftAverage[$softDAO->currency] += $softDAO->civicrm_contribution_soft_soft_amount_avg;
+        $averageSoftCount[$softDAO->currency]++;
         $softCount += $softDAO->civicrm_contribution_soft_soft_amount_count;
+
+        if (!in_array($softDAO->currency, $currencies)) {
+          $currencies[] = $softDAO->currency;
+        }
+      }
+
+      foreach ($currencies as $currency) {
+        $softTotalAmount[] = CRM_Utils_Money::format($currSoftAmount[$currency], $currency) .
+          " (" . $currSoftCount[$currency] . ")";
+        $softAverage[] = CRM_Utils_Money::format(($currSoftAverage[$currency] / $averageSoftCount[$currency]), $currency);
       }
     }
 
     if (!$onlySoftCredit) {
-      $statistics['counts']['amount'] = array(
+      $statistics['counts']['amount'] = [
         'title' => ts('Total Amount'),
         'value' => implode(',  ', $totalAmount),
         'type' => CRM_Utils_Type::T_STRING,
-      );
-      $statistics['counts']['count'] = array(
+      ];
+      $statistics['counts']['count'] = [
         'title' => ts('Total Contributions'),
         'value' => $count,
-      );
-      $statistics['counts']['avg'] = array(
+      ];
+      $statistics['counts']['avg'] = [
         'title' => ts('Average'),
         'value' => implode(',  ', $average),
         'type' => CRM_Utils_Type::T_STRING,
-      );
-      $statistics['counts']['mode'] = array(
+      ];
+      $statistics['counts']['mode'] = [
         'title' => ts('Mode'),
         'value' => implode(',  ', $mode),
         'type' => CRM_Utils_Type::T_STRING,
-      );
-      $statistics['counts']['median'] = array(
+      ];
+      $statistics['counts']['median'] = [
         'title' => ts('Median'),
         'value' => implode(',  ', $median),
         'type' => CRM_Utils_Type::T_STRING,
-      );
+      ];
     }
     if ($softCredit) {
-      $statistics['counts']['soft_amount'] = array(
+      $statistics['counts']['soft_amount'] = [
         'title' => ts('Total Soft Credit Amount'),
         'value' => implode(',  ', $softTotalAmount),
         'type' => CRM_Utils_Type::T_STRING,
-      );
-      $statistics['counts']['soft_count'] = array(
+      ];
+      $statistics['counts']['soft_count'] = [
         'title' => ts('Total Soft Credits'),
         'value' => $softCount,
-      );
-      $statistics['counts']['soft_avg'] = array(
+      ];
+      $statistics['counts']['soft_avg'] = [
         'title' => ts('Average Soft Credit'),
         'value' => implode(',  ', $softAverage),
         'type' => CRM_Utils_Type::T_STRING,
-      );
+      ];
     }
     return $statistics;
   }
@@ -731,7 +783,7 @@ ROUND(AVG({$this->_aliases['civicrm_contribution_soft']}.amount), 2) as civicrm_
    * @param array $rows
    */
   public function buildChart(&$rows) {
-    $graphRows = array();
+    $graphRows = [];
 
     if (!empty($this->_params['charts'])) {
       if (!empty($this->_params['group_bys']['receive_date'])) {
@@ -771,7 +823,7 @@ ROUND(AVG({$this->_aliases['civicrm_contribution_soft']}.amount), 2) as civicrm_
         // build the chart.
         $config = CRM_Core_Config::Singleton();
         $graphRows['xname'] = $this->_interval;
-        $graphRows['yname'] = ts('Amount (%1)', array(1 => $config->defaultCurrency));
+        $graphRows['yname'] = ts('Amount (%1)', [1 => $config->defaultCurrency]);
         CRM_Utils_Chart::chart($graphRows, $this->_params['charts'], $this->_interval);
         $this->assign('chartType', $this->_params['charts']);
       }
@@ -802,11 +854,11 @@ ROUND(AVG({$this->_aliases['civicrm_contribution_soft']}.amount), 2) as civicrm_
       $contriDAO = CRM_Core_DAO::executeQuery($contriSQL);
       CRM_Core_DAO::reenableFullGroupByMode();
       $this->addToDeveloperTab($contriSQL);
-      $contriFields = array(
+      $contriFields = [
         'civicrm_contribution_total_amount_sum',
         'civicrm_contribution_total_amount_avg',
         'civicrm_contribution_total_amount_count',
-      );
+      ];
       $count = 0;
       while ($contriDAO->fetch()) {
         foreach ($contriFields as $column) {
@@ -825,7 +877,7 @@ ROUND(AVG({$this->_aliases['civicrm_contribution_soft']}.amount), 2) as civicrm_
 
         $dateStart = CRM_Utils_Date::customFormat($row['civicrm_contribution_receive_date_start'], '%Y%m%d');
         $endDate = new DateTime($dateStart);
-        $dateEnd = array();
+        $dateEnd = [];
 
         list($dateEnd['Y'], $dateEnd['M'], $dateEnd['d']) = explode(':', $endDate->format('Y:m:d'));
 
index 425f7a433b267286ab713771c7dbb80f1ff50da1..6b4ae72b4f0b3953a6e0dcf374619f57143e13e7 100644 (file)
@@ -657,8 +657,8 @@ class CRM_Report_Form_Member_ContributionDetail extends CRM_Report_Form {
           if ($contactId = $row['civicrm_contact_id']) {
             if ($rowNum == 0) {
               $pcid = $contactId;
-              $fAmt = $row['first_donation_first_donation_amount'];
-              $fDate = $row['first_donation_first_donation_date'];
+              $fAmt = $row['first_donation_first_donation_amount'] ?? '';
+              $fDate = $row['first_donation_first_donation_date'] ?? '';
             }
             else {
               if ($pcid == $contactId) {
@@ -667,8 +667,8 @@ class CRM_Report_Form_Member_ContributionDetail extends CRM_Report_Form {
                 $pcid = $contactId;
               }
               else {
-                $fAmt = $row['first_donation_first_donation_amount'];
-                $fDate = $row['first_donation_first_donation_date'];
+                $fAmt = $row['first_donation_first_donation_amount'] ?? '';
+                $fDate = $row['first_donation_first_donation_date'] ?? '';
                 $pcid = $contactId;
               }
             }
index 116cc577ae38fb06027c9c81aa9399336b6b7ce4..92627d38e9ed6e43861e3cc3266f494cc0fc3893 100644 (file)
@@ -22,16 +22,16 @@ class CRM_SMS_Controller_Send extends CRM_Core_Controller {
    * @param string $title
    * @param bool|int $action
    * @param bool $modal
+   *
+   * @throws \CRM_Core_Exception
    */
   public function __construct($title = NULL, $action = CRM_Core_Action::NONE, $modal = TRUE) {
     parent::__construct($title, $modal, NULL, FALSE, TRUE);
 
-    $mailingID = CRM_Utils_Request::retrieve('mid', 'String', $this, FALSE, NULL);
+    $mailingID = CRM_Utils_Request::retrieve('mid', 'String', $this);
 
     // also get the text and html file
-    $txtFile = CRM_Utils_Request::retrieve('txtFile', 'String',
-      CRM_Core_DAO::$_nullObject, FALSE, NULL
-    );
+    $txtFile = CRM_Utils_Request::retrieveValue('txtFile', 'String');
 
     $config = CRM_Core_Config::singleton();
     if ($txtFile &&
index 52d49af4f0e8e05ff1959879140a495e7f464a6e..9c7144606ce9de4e5f6ec70b954a975b6370fe4d 100644 (file)
@@ -25,7 +25,7 @@ class CRM_Upgrade_Incremental_General {
   /**
    * The recommended PHP version.
    */
-  const RECOMMENDED_PHP_VER = '7.2';
+  const RECOMMENDED_PHP_VER = '7.3';
 
   /**
    * The previous recommended PHP version.
diff --git a/CRM/Upgrade/Incremental/php/FiveTwentyFour.php b/CRM/Upgrade/Incremental/php/FiveTwentyFour.php
new file mode 100644 (file)
index 0000000..b215e3c
--- /dev/null
@@ -0,0 +1,72 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved.                        |
+ |                                                                    |
+ | This work is published under the GNU AGPLv3 license with some      |
+ | permitted exceptions and without any warranty. For full license    |
+ | and copyright information, see https://civicrm.org/licensing       |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ * Upgrade logic for FiveTwentyFour */
+class CRM_Upgrade_Incremental_php_FiveTwentyFour 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', [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;
+  // }
+
+}
diff --git a/CRM/Upgrade/Incremental/sql/5.24.alpha1.mysql.tpl b/CRM/Upgrade/Incremental/sql/5.24.alpha1.mysql.tpl
new file mode 100644 (file)
index 0000000..cd099a7
--- /dev/null
@@ -0,0 +1 @@
+{* file to handle db changes in 5.24.alpha1 during upgrade *}
index b9aa6ef617e2662fd423a5872899e63d73cecffd..696ed860d27235b34de3473904a60418bda2e7ca 100644 (file)
@@ -124,6 +124,17 @@ class CRM_Utils_Mail {
     else {
       $mailer = Mail::factory($driver, $params);
     }
+
+    // Previously, CiviCRM bundled patches to change the behavior of 3 specific drivers. Use wrapper/filters to avoid patching.
+    $mailer = new CRM_Utils_Mail_FilteredPearMailer($driver, $params, $mailer);
+    if (in_array($driver, ['smtp', 'mail', 'sendmail'])) {
+      $mailer->addFilter('2000_log', ['CRM_Utils_Mail_Logger', 'filter']);
+      $mailer->addFilter('2100_validate', function ($mailer, &$recipients, &$headers, &$body) {
+        if (!is_array($headers)) {
+          return PEAR::raiseError('$headers must be an array');
+        }
+      });
+    }
     CRM_Utils_Hook::alterMailer($mailer, $driver, $params);
     return $mailer;
   }
@@ -268,7 +279,10 @@ class CRM_Utils_Mail {
     // * All other mailers require that all be recipients be listed in the $to array AND that
     //   the Bcc must not be present in $header as otherwise it will be shown to all recipients
     // ref: https://pear.php.net/bugs/bug.php?id=8047, full thread and answer [2011-04-19 20:48 UTC]
-    if (get_class($mailer) != "Mail_mail") {
+    // TODO: Refactor this quirk-handler as another filter in FilteredPearMailer. But that would merit review of impact on universe.
+    $driver = ($mailer instanceof CRM_Utils_Mail_FilteredPearMailer) ? $mailer->getDriver() : NULL;
+    $isPhpMail = (get_class($mailer) === "Mail_mail" || $driver === 'mail');
+    if (!$isPhpMail) {
       // get emails from headers, since these are
       // combination of name and email addresses.
       if (!empty($headers['Cc'])) {
@@ -326,34 +340,10 @@ class CRM_Utils_Mail {
    * @param $to
    * @param $headers
    * @param $message
+   * @deprecated
    */
   public static function logger(&$to, &$headers, &$message) {
-    if (is_array($to)) {
-      $toString = implode(', ', $to);
-      $fileName = $to[0];
-    }
-    else {
-      $toString = $fileName = $to;
-    }
-    $content = "To: " . $toString . "\n";
-    foreach ($headers as $key => $val) {
-      $content .= "$key: $val\n";
-    }
-    $content .= "\n" . $message . "\n";
-
-    if (is_numeric(CIVICRM_MAIL_LOG)) {
-      $config = CRM_Core_Config::singleton();
-      // create the directory if not there
-      $dirName = $config->configAndLogDir . 'mail' . DIRECTORY_SEPARATOR;
-      CRM_Utils_File::createDir($dirName);
-      $fileName = md5(uniqid(CRM_Utils_String::munge($fileName))) . '.txt';
-      file_put_contents($dirName . $fileName,
-        $content
-      );
-    }
-    else {
-      file_put_contents(CIVICRM_MAIL_LOG, $content, FILE_APPEND);
-    }
+    CRM_Utils_Mail_Logger::log($to, $headers, $message);
   }
 
   /**
diff --git a/CRM/Utils/Mail/FilteredPearMailer.php b/CRM/Utils/Mail/FilteredPearMailer.php
new file mode 100644 (file)
index 0000000..1c11e23
--- /dev/null
@@ -0,0 +1,112 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved.                        |
+ |                                                                    |
+ | This work is published under the GNU AGPLv3 license with some      |
+ | permitted exceptions and without any warranty. For full license    |
+ | and copyright information, see https://civicrm.org/licensing       |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ * The filtered-mailer is a utility to wrap an existing PEAR Mail class
+ * and apply extra filters. It is primarily intended for resolving
+ * quirks in the standard implementations.
+ *
+ * This wrapper acts a bit like a chameleon, passing-through properties
+ * from the underlying object. Consequently, internal properties are
+ * prefixed with `_` to avoid conflict.
+ *
+ * @package CRM
+ * @copyright CiviCRM LLC https://civicrm.org/licensing
+ */
+class CRM_Utils_Mail_FilteredPearMailer extends Mail {
+
+  /**
+   * @var string
+   *   Ex: 'smtp' or 'sendmail'
+   */
+  protected $_driver;
+
+  /**
+   * @var array
+   */
+  protected $_params;
+
+  /**
+   * @var Mail
+   */
+  protected $_delegate;
+
+  /**
+   * @var callable[]
+   */
+  protected $_filters = [];
+
+  /**
+   * CRM_Utils_Mail_FilteredPearMailer constructor.
+   * @param string $driver
+   * @param array $params
+   * @param Mail $mailer
+   */
+  public function __construct($driver, $params, $mailer) {
+    $this->_driver = $driver;
+    $this->_params = $params;
+    $this->_delegate = $mailer;
+  }
+
+  public function send($recipients, $headers, $body) {
+    $filterArgs = [$this, &$recipients, &$headers, &$body];
+    foreach ($this->_filters as $filter) {
+      $result = call_user_func_array($filter, $filterArgs);
+      if ($result !== NULL) {
+        return $result;
+      }
+    }
+
+    return $this->_delegate->send($recipients, $headers, $body);
+  }
+
+  /**
+   * @param string $id
+   *   Unique ID for this filter. Filters are sorted by ID.
+   *   Suggestion: '{nnnn}_{name}', where '{nnnn}' is a number.
+   *   Filters are sorted and executed in order.
+   * @param callable $func
+   *   function(FilteredPearMailer $mailer, mixed $recipients, array $headers, string $body).
+   *   The return value should generally be null/void. However, if you wish to
+   *   short-circuit execution of the filters, then return a concrete value.
+   * @return static
+   */
+  public function addFilter($id, $func) {
+    $this->_filters[$id] = $func;
+    ksort($this->_filters);
+    return $this;
+  }
+
+  /**
+   * @return string
+   *   Ex: 'smtp', 'sendmail', 'mail'.
+   */
+  public function getDriver() {
+    return $this->_driver;
+  }
+
+  public function &__get($name) {
+    return $this->_delegate->{$name};
+  }
+
+  public function __set($name, $value) {
+    return $this->_delegate->{$name} = $value;
+  }
+
+  public function __isset($name) {
+    return isset($this->_delegate->{$name});
+  }
+
+  public function __unset($name) {
+    unset($this->_delegate->{$name});
+  }
+
+}
diff --git a/CRM/Utils/Mail/Logger.php b/CRM/Utils/Mail/Logger.php
new file mode 100644 (file)
index 0000000..453554e
--- /dev/null
@@ -0,0 +1,76 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved.                        |
+ |                                                                    |
+ | This work is published under the GNU AGPLv3 license with some      |
+ | permitted exceptions and without any warranty. For full license    |
+ | and copyright information, see https://civicrm.org/licensing       |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ * An attachment to PEAR Mail which logs emails to files based on
+ * the CIVICRM_MAIL_LOG configuration.
+ *
+ * (Produced by refactoring; specifically, extracting log-related functions
+ * from CRM_Utils_Mail.)
+ *
+ * @package CRM
+ * @copyright CiviCRM LLC https://civicrm.org/licensing
+ */
+class CRM_Utils_Mail_Logger {
+
+  /**
+   * @param CRM_Utils_Mail_FilteredPearMailer $mailer
+   * @param mixed $recipients
+   * @param array $headers
+   * @param string $body
+   * @return mixed
+   *   Normally returns null/void. But if the filter process is to be
+   *   short-circuited, then returns a concrete value.
+   */
+  public static function filter($mailer, &$recipients, &$headers, &$body) {
+    if (defined('CIVICRM_MAIL_LOG')) {
+      static::log($recipients, $headers, $body);
+      if (!defined('CIVICRM_MAIL_LOG_AND_SEND') && !defined('CIVICRM_MAIL_LOG_AND SEND')) {
+        return TRUE;
+      }
+    }
+  }
+
+  /**
+   * @param $to
+   * @param $headers
+   * @param $message
+   */
+  public static function log(&$to, &$headers, &$message) {
+    if (is_array($to)) {
+      $toString = implode(', ', $to);
+      $fileName = $to[0];
+    }
+    else {
+      $toString = $fileName = $to;
+    }
+    $content = "To: " . $toString . "\n";
+    foreach ($headers as $key => $val) {
+      $content .= "$key: $val\n";
+    }
+    $content .= "\n" . $message . "\n";
+
+    if (is_numeric(CIVICRM_MAIL_LOG)) {
+      $config = CRM_Core_Config::singleton();
+      // create the directory if not there
+      $dirName = $config->configAndLogDir . 'mail' . DIRECTORY_SEPARATOR;
+      CRM_Utils_File::createDir($dirName);
+      $fileName = md5(uniqid(CRM_Utils_String::munge($fileName))) . '.txt';
+      file_put_contents($dirName . $fileName,
+        $content
+      );
+    }
+    else {
+      file_put_contents(CIVICRM_MAIL_LOG, $content, FILE_APPEND);
+    }
+  }
+
+}
index 0e8cd6d76cc9497462ee6eaf066d9ae67f8176a7..bbe8072a25aec4b4fa4956af0f994538e107f433 100644 (file)
@@ -138,18 +138,13 @@ class CRM_Utils_Money {
 
   /**
    * Tests if two currency values are equal, taking into account the currency's
-   * precision, so that if the difference between the two values is less than
-   * one more order of magnitude for the precision, then the values are
-   * considered as equal. So, if the currency has  precision of 2 decimal
-   * points, a difference of more than 0.001 will cause the values to be
-   * considered as different. Anything less than 0.001 will be considered as
-   * equal.
+   * precision, so that the two values are compared as integers after rounding.
    *
    * Eg.
    *
-   * 1.2312 == 1.2319 with a currency precision of 2 decimal points
-   * 1.2310 != 1.2320 with a currency precision of 2 decimal points
-   * 1.3000 != 1.2000 with a currency precision of 2 decimal points
+   * 1.231 == 1.232 with a currency precision of 2 decimal points
+   * 1.234 != 1.236 with a currency precision of 2 decimal points
+   * 1.300 != 1.200 with a currency precision of 2 decimal points
    *
    * @param $value1
    * @param $value2
@@ -158,14 +153,9 @@ class CRM_Utils_Money {
    * @return bool
    */
   public static function equals($value1, $value2, $currency) {
-    $precision = 1 / pow(10, self::getCurrencyPrecision($currency) + 1);
-    $difference = self::subtractCurrencies($value1, $value2, $currency);
+    $precision = pow(10, self::getCurrencyPrecision($currency));
 
-    if (abs($difference) > $precision) {
-      return FALSE;
-    }
-
-    return TRUE;
+    return (int) round($value1 * $precision) == (int) round($value2 * $precision);
   }
 
   /**
index 4b5d89fbcd06cb15b734dd64c3edb953d02fd173..731e43ffafe45b431696484e437ec4894a7ebcb1 100644 (file)
@@ -88,10 +88,8 @@ class CRM_Utils_Request {
         break;
     }
 
-    if (isset($value) &&
-      (CRM_Utils_Type::validate($value, $type, $abort, $name) === NULL)
-    ) {
-      $value = NULL;
+    if (isset($value)) {
+      $value = CRM_Utils_Type::validate($value, $type, $abort, $name);
     }
 
     if (!isset($value) && $store) {
index a548406ddf5c6e304d734904576e2c718d4777ab..072e012270525537fa473520c04dafde14c646f8 100644 (file)
@@ -137,17 +137,17 @@ class CRM_Utils_System_Drupal8 extends CRM_Utils_System_DrupalBase {
       // This checks for both username uniqueness and validity.
       $violations = iterator_to_array($user->validate());
       // We only care about violations on the username field; discard the rest.
-      $violations = array_filter($violations, function ($v) {
+      $violations = array_values(array_filter($violations, function ($v) {
         return $v->getPropertyPath() == 'name';
-      });
+      }));
       if (count($violations) > 0) {
         $errors['cms_name'] = (string) $violations[0]->getMessage();
       }
     }
 
     // And if we are given an email address, let's check to see if it already exists.
-    if (!empty($params[$emailName])) {
-      $mail = $params[$emailName];
+    if (!empty($params['mail'])) {
+      $mail = $params['mail'];
 
       $user = entity_create('user');
       $user->setEmail($mail);
@@ -155,9 +155,9 @@ class CRM_Utils_System_Drupal8 extends CRM_Utils_System_DrupalBase {
       // This checks for both email uniqueness.
       $violations = iterator_to_array($user->validate());
       // We only care about violations on the email field; discard the rest.
-      $violations = array_filter($violations, function ($v) {
+      $violations = array_values(array_filter($violations, function ($v) {
         return $v->getPropertyPath() == 'mail';
-      });
+      }));
       if (count($violations) > 0) {
         $errors[$emailName] = (string) $violations[0]->getMessage();
       }
index 9aaa03a274845fbebd510227aa71387f34c5d8a2..188e2c3acbfb431c6cab35a0f70ec20da37d3f8b 100644 (file)
@@ -44,20 +44,20 @@ class Kernel {
   }
 
   /**
-   * @deprecated
    * @param string $entity
-   *   Type of entities to deal with.
+   *   Name of entity: e.g. Contact, Activity, Event
    * @param string $action
-   *   Create, get, delete or some special action name.
+   *   Name of action: e.g. create, get, delete
    * @param array $params
    *   Array to be passed to API function.
-   * @param mixed $extra
-   *   Unused/deprecated.
+   *
    * @return array|int
+   * @throws \API_Exception
    * @see runSafe
+   * @deprecated
    */
-  public function run($entity, $action, $params, $extra = NULL) {
-    return $this->runSafe($entity, $action, $params, $extra);
+  public function run($entity, $action, $params) {
+    return $this->runSafe($entity, $action, $params);
   }
 
   /**
@@ -65,26 +65,26 @@ class Kernel {
    * normal format.
    *
    * @param string $entity
-   *   Type of entities to deal with.
+   *   Name of entity: e.g. Contact, Activity, Event
    * @param string $action
-   *   Create, get, delete or some special action name.
+   *   Name of action: e.g. create, get, delete
    * @param array $params
    *   Array to be passed to API function.
-   * @param mixed $extra
-   *   Unused/deprecated.
    *
    * @return array|int
    * @throws \API_Exception
    */
-  public function runSafe($entity, $action, $params, $extra = NULL) {
-    $apiRequest = Request::create($entity, $action, $params, $extra);
-
+  public function runSafe($entity, $action, $params) {
+    $apiRequest = [];
     try {
+      $apiRequest = Request::create($entity, $action, $params);
       $apiResponse = $this->runRequest($apiRequest);
       return $this->formatResult($apiRequest, $apiResponse);
     }
     catch (\Exception $e) {
-      $this->dispatcher->dispatch(Events::EXCEPTION, new ExceptionEvent($e, NULL, $apiRequest, $this));
+      if ($apiRequest) {
+        $this->dispatcher->dispatch(Events::EXCEPTION, new ExceptionEvent($e, NULL, $apiRequest, $this));
+      }
 
       if ($e instanceof \PEAR_Exception) {
         $err = $this->formatPearException($e, $apiRequest);
@@ -109,16 +109,14 @@ class Kernel {
    *   Create, get, delete or some special action name.
    * @param array $params
    *   Array to be passed to function.
-   * @param mixed $extra
-   *   Unused/deprecated.
    *
    * @return bool
    *   TRUE if authorization would succeed.
    * @throws \Exception
    */
-  public function runAuthorize($entity, $action, $params, $extra = NULL) {
+  public function runAuthorize($entity, $action, $params) {
     $apiProvider = NULL;
-    $apiRequest = Request::create($entity, $action, $params, $extra);
+    $apiRequest = Request::create($entity, $action, $params);
 
     try {
       $this->boot($apiRequest);
index d3379ab437285ac6880e4d6964e4530f134b5c4c..7a053e37c2abc101d4b08b65390b857ec6bee1a3 100644 (file)
@@ -26,51 +26,43 @@ class Request {
    *   API action name.
    * @param array $params
    *   API parameters.
-   * @param mixed $extra
-   *   Who knows? ...
    *
-   * @throws \API_Exception
-   * @return array
-   *   the request descriptor; keys:
-   *   - version: int
-   *   - entity: string
-   *   - action: string
-   *   - params: array (string $key => mixed $value) [deprecated in v4]
-   *   - extra: unspecified
-   *   - fields: NULL|array (string $key => array $fieldSpec)
-   *   - options: \CRM_Utils_OptionBag derived from params [v4-only]
-   *   - data: \CRM_Utils_OptionBag derived from params [v4-only]
-   *   - chains: unspecified derived from params [v4-only]
+   * @throws \Civi\API\Exception\NotImplementedException
+   * @return \Civi\Api4\Generic\AbstractAction|array
    */
-  public static function create($entity, $action, $params, $extra = NULL) {
-    $version = \CRM_Utils_Array::value('version', $params);
-    switch ($version) {
-      default:
-        $apiRequest = [];
-        $apiRequest['id'] = self::$nextId++;
-        $apiRequest['version'] = (int) $version;
-        $apiRequest['params'] = $params;
-        $apiRequest['extra'] = $extra;
-        $apiRequest['fields'] = NULL;
-        $apiRequest['entity'] = self::normalizeEntityName($entity, $apiRequest['version']);
-        $apiRequest['action'] = self::normalizeActionName($action, $apiRequest['version']);
-        return $apiRequest;
+  public static function create(string $entity, string $action, array $params) {
+    switch ($params['version'] ?? NULL) {
+      case 3:
+        return [
+          'id' => self::$nextId++,
+          'version' => 3,
+          'params' => $params,
+          'fields' => NULL,
+          'entity' => self::normalizeEntityName($entity),
+          'action' => self::normalizeActionName($action),
+        ];
 
       case 4:
-        $callable = ["Civi\\Api4\\$entity", $action];
-        if (!is_callable($callable)) {
-          throw new Exception\NotImplementedException("API ($entity, $action) does not exist (join the API team and implement it!)");
+        // For custom pseudo-entities
+        if (strpos($entity, 'Custom_') === 0) {
+          $apiRequest = \Civi\Api4\CustomValue::$action(substr($entity, 7));
+        }
+        else {
+          $callable = ["\\Civi\\Api4\\$entity", $action];
+          if (!is_callable($callable)) {
+            throw new \Civi\API\Exception\NotImplementedException("API ($entity, $action) does not exist (join the API team and implement it!)");
+          }
+          $apiRequest = call_user_func($callable);
         }
-        $apiCall = call_user_func($callable);
-        $apiRequest['id'] = self::$nextId++;
-        unset($params['version']);
         foreach ($params as $name => $param) {
           $setter = 'set' . ucfirst($name);
-          $apiCall->$setter($param);
+          $apiRequest->$setter($param);
         }
-        return $apiCall;
-    }
+        return $apiRequest;
 
+      default:
+        throw new \Civi\API\Exception\NotImplementedException("Unknown api version");
+    }
   }
 
   /**
@@ -79,10 +71,9 @@ class Request {
    * APIv1-v3 munges entity/action names, and accepts any mixture of case and underscores.
    *
    * @param string $entity
-   * @param int $version
    * @return string
    */
-  public static function normalizeEntityName($entity, $version) {
+  public static function normalizeEntityName($entity) {
     return \CRM_Utils_String::convertStringToCamel(\CRM_Utils_String::munge($entity));
   }
 
@@ -95,7 +86,7 @@ class Request {
    * @param $version
    * @return string
    */
-  public static function normalizeActionName($action, $version) {
+  public static function normalizeActionName($action) {
     return strtolower(\CRM_Utils_String::munge($action));
   }
 
index 42baa4062ec4a65e5b9c1c7546dac044de3d29de..37c8688a4c86b73fec14eb660cc01ef497c28634 100644 (file)
@@ -183,7 +183,7 @@ class ChainSubscriber implements EventSubscriberInterface {
             foreach ($newparams as $entityparams) {
               $subParams = array_merge($genericParams, $entityparams);
               _civicrm_api_replace_variables($subParams, $result['values'][$idIndex], $separator);
-              $result['values'][$idIndex][$field][] = $apiKernel->run($subEntity, $subaction, $subParams);
+              $result['values'][$idIndex][$field][] = $apiKernel->runSafe($subEntity, $subaction, $subParams);
               if ($result['is_error'] === 1) {
                 throw new \Exception($subEntity . ' ' . $subaction . 'call failed with' . $result['error_message']);
               }
@@ -193,7 +193,7 @@ class ChainSubscriber implements EventSubscriberInterface {
 
             $subParams = array_merge($subParams, $newparams);
             _civicrm_api_replace_variables($subParams, $result['values'][$idIndex], $separator);
-            $result['values'][$idIndex][$field] = $apiKernel->run($subEntity, $subaction, $subParams);
+            $result['values'][$idIndex][$field] = $apiKernel->runSafe($subEntity, $subaction, $subParams);
             if (!empty($result['is_error'])) {
               throw new \Exception($subEntity . ' ' . $subaction . 'call failed with' . $result['error_message']);
             }
index 7747d0a6285ecfbdcfbbf9e256c27bfb7dda31ce..ecaf5ff428ecb8719090530fead9281366a65b5d 100644 (file)
@@ -230,7 +230,7 @@ class DynamicFKAuthorization implements EventSubscriberInterface {
         'id' => $entityId,
       ];
 
-      $result = $self->kernel->run($entity, $self->getDelegatedAction($action), $params);
+      $result = $self->kernel->runSafe($entity, $self->getDelegatedAction($action), $params);
       if ($result['is_error'] || empty($result['values'])) {
         $exception = new \Civi\API\Exception\UnauthorizedException("Authorization failed on ($entity,$entityId)", [
           'cause' => $result,
index b16fb0a285a49835341c1741f7a11b5a00c305e1..a1d2b9413272de35726087aa09c69418add302b2 100644 (file)
@@ -23,7 +23,6 @@ namespace Civi\Api4\Action;
 
 use Civi\API\Exception\NotImplementedException;
 use Civi\Api4\Generic\BasicGetAction;
-use Civi\Api4\Utils\ActionUtil;
 use Civi\Api4\Utils\ReflectionUtils;
 
 /**
@@ -84,7 +83,7 @@ class GetActions extends BasicGetAction {
   private function loadAction($actionName, $method = NULL) {
     try {
       if (!isset($this->_actions[$actionName]) && (!$this->_actionsToGet || in_array($actionName, $this->_actionsToGet))) {
-        $action = ActionUtil::getAction($this->getEntityName(), $actionName);
+        $action = \Civi\API\Request::create($this->getEntityName(), $actionName, ['version' => 4]);
         if (is_object($action)) {
           $this->_actions[$actionName] = ['name' => $actionName];
           if ($this->_isFieldSelected('description', 'comment', 'see')) {
index 531f11aace52d3b418446174d23831854585793a..0de9856f6380333a2af2134fc87820017fa1df7b 100644 (file)
@@ -21,7 +21,6 @@
 namespace Civi\Api4\Generic;
 
 use Civi\Api4\Utils\ReflectionUtils;
-use Civi\Api4\Utils\ActionUtil;
 
 /**
  * Base class for all api actions.
@@ -424,15 +423,14 @@ abstract class AbstractAction implements \ArrayAccess {
    */
   public function entityFields() {
     if (!$this->_entityFields) {
-      $getFields = ActionUtil::getAction($this->getEntityName(), 'getFields');
+      $getFields = \Civi\API\Request::create($this->getEntityName(), 'getFields', [
+        'version' => 4,
+        'checkPermissions' => $this->checkPermissions,
+        'action' => $this->getActionName(),
+        'includeCustom' => FALSE,
+      ]);
       $result = new Result();
-      if (method_exists($this, 'getBaoName')) {
-        $getFields->setIncludeCustom(FALSE);
-      }
-      $getFields
-        ->setCheckPermissions($this->checkPermissions)
-        ->setAction($this->getActionName())
-        ->_run($result);
+      $getFields->_run($result);
       $this->_entityFields = (array) $result->indexBy('name');
     }
     return $this->_entityFields;
index ae11f65f48269ed543cda5e12f14d2630eea5c24..553d5bed2208a024fd09345482112d2cb7349be9 100644 (file)
@@ -22,7 +22,6 @@
 namespace Civi\Api4\Generic;
 
 use Civi\API\Exception\NotImplementedException;
-use Civi\Api4\Utils\ActionUtil;
 
 /**
  * Lists information about fields for the $ENTITY entity.
@@ -78,7 +77,7 @@ class BasicGetFieldsAction extends BasicGetAction {
    */
   public function _run(Result $result) {
     try {
-      $actionClass = ActionUtil::getAction($this->getEntityName(), $this->getAction());
+      $actionClass = \Civi\API\Request::create($this->getEntityName(), $this->getAction(), ['version' => 4]);
     }
     catch (NotImplementedException $e) {
     }
@@ -143,6 +142,18 @@ class BasicGetFieldsAction extends BasicGetAction {
     return $this;
   }
 
+  /**
+   * @param bool $includeCustom
+   * @return $this
+   */
+  public function setIncludeCustom(bool $includeCustom) {
+    // Be forgiving if the param doesn't exist and don't throw an exception
+    if (property_exists($this, 'includeCustom')) {
+      $this->includeCustom = $includeCustom;
+    }
+    return $this;
+  }
+
   public function fields() {
     return [
       [
index b8e20285cd258ddce9d598d84a04de46d266120e..cb06ec096e096bd14bd89f968a6512d43892e352 100644 (file)
@@ -21,8 +21,6 @@
 
 namespace Civi\Api4\Generic;
 
-use Civi\Api4\Utils\ActionUtil;
-
 /**
  * Replaces an existing set of $ENTITIES with a new one.
  *
@@ -100,7 +98,7 @@ class BasicReplaceAction extends AbstractBatchAction {
     $idField = $this->getSelect()[0];
     $toDelete = array_diff_key(array_column($items, NULL, $idField), array_flip(array_filter(\CRM_Utils_Array::collect($idField, $this->records))));
 
-    $saveAction = ActionUtil::getAction($this->getEntityName(), 'save');
+    $saveAction = \Civi\API\Request::create($this->getEntityName(), 'save', ['version' => 4]);
     $saveAction
       ->setCheckPermissions($this->getCheckPermissions())
       ->setReload($this->reload)
index b5c998af5676bfca49281bdbca698f84f6e7c691..a080fa6d82c6b98cd4e694c42429af6ab6617055 100644 (file)
@@ -22,7 +22,6 @@
 namespace Civi\Api4\Generic;
 
 use Civi\API\Exception\NotImplementedException;
-use Civi\Api4\Utils\ActionUtil;
 
 /**
  * $ACTION one or more $ENTITIES.
@@ -68,7 +67,7 @@ class BasicSaveAction extends AbstractSaveAction {
     }
     if ($this->reload) {
       /** @var BasicGetAction $get */
-      $get = ActionUtil::getAction($this->getEntityName(), 'get');
+      $get = \Civi\API\Request::create($this->getEntityName(), 'get', ['version' => 4]);
       $get
         ->setCheckPermissions($this->getCheckPermissions())
         ->addWhere($this->getIdField(), 'IN', (array) $result->column($this->getIdField()));
index 992eca6707c8aced4b25ad808bcfb52be657b92b..7d7ac1849d0a0158340d92774b231b76b4ba32c8 100644 (file)
@@ -25,7 +25,6 @@ use Civi\Api4\Service\Spec\SpecFormatter;
 
 /**
  * @inheritDoc
- * @method $this setIncludeCustom(bool $value)
  * @method bool getIncludeCustom()
  */
 class DAOGetFieldsAction extends BasicGetFieldsAction {
index f0ed1edf8767aac9367a83042c5a6c123af63db7..5a3706056782b12b38684374c88b406164fd7b15 100644 (file)
@@ -3,7 +3,7 @@
  +--------------------------------------------------------------------+
  | CiviCRM version 5                                                  |
  +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2019                                |
+ | Copyright CiviCRM LLC (c) 2004-2020                                |
  +--------------------------------------------------------------------+
  | This file is a part of CiviCRM.                                    |
  |                                                                    |
@@ -27,7 +27,7 @@
 /**
  *
  * @package CRM
- * @copyright CiviCRM LLC (c) 2004-2019
+ * @copyright CiviCRM LLC (c) 2004-2020
  * $Id$
  *
  */
diff --git a/Civi/Api4/Utils/ActionUtil.php b/Civi/Api4/Utils/ActionUtil.php
deleted file mode 100644 (file)
index 614f4de..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-
-/*
- +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC. All rights reserved.                        |
- |                                                                    |
- | This work is published under the GNU AGPLv3 license with some      |
- | permitted exceptions and without any warranty. For full license    |
- | and copyright information, see https://civicrm.org/licensing       |
- +--------------------------------------------------------------------+
- */
-
-/**
- *
- * @package CRM
- * @copyright CiviCRM LLC https://civicrm.org/licensing
- * $Id$
- *
- */
-
-
-namespace Civi\Api4\Utils;
-
-class ActionUtil {
-
-  /**
-   * @param $entityName
-   * @param $actionName
-   * @return \Civi\Api4\Generic\AbstractAction
-   * @throws \Civi\API\Exception\NotImplementedException
-   */
-  public static function getAction($entityName, $actionName) {
-    // For custom pseudo-entities
-    if (strpos($entityName, 'Custom_') === 0) {
-      return \Civi\Api4\CustomValue::$actionName(substr($entityName, 7));
-    }
-    else {
-      $callable = ["\\Civi\\Api4\\$entityName", $actionName];
-      if (!is_callable($callable)) {
-        throw new \Civi\API\Exception\NotImplementedException("API ($entityName, $actionName) does not exist (join the API team and implement it!)");
-      }
-      return call_user_func($callable);
-    }
-  }
-
-}
index 7eb83cade19ad792b41ae8ab4c1ccca1e23a012f..50d6ebf31c4a39ee1d97fa1071b29516757eec2d 100644 (file)
@@ -163,7 +163,7 @@ class Test {
    */
   public static function codeGen() {
     if (!isset(self::$singletons['codeGen'])) {
-      $civiRoot = dirname(__DIR__);
+      $civiRoot = str_replace(DIRECTORY_SEPARATOR, '/', dirname(__DIR__));
       $codeGen = new \CRM_Core_CodeGen_Main("$civiRoot/CRM/Core/DAO", "$civiRoot/sql", $civiRoot, "$civiRoot/templates", NULL, "UnitTests", NULL, "$civiRoot/xml/schema/Schema.xml", NULL);
       $codeGen->init();
       self::$singletons['codeGen'] = $codeGen;
index cb64e989e38c9897ea5126f12304fbf455d545ab..03b28597adf6632dbdd69cc67f5ba0a7b50a0bf9 100644 (file)
@@ -156,16 +156,17 @@ trait ContactTestTrait {
    *   For civicrm_contact_add api function call.
    *
    * @return int
-   *   id of Household created
-   * @throws \CRM_Core_Exception
+   *   id of contact created
    *
+   * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
    */
   private function _contactCreate($params) {
     $result = civicrm_api3('contact', 'create', $params);
     if (!empty($result['is_error']) || empty($result['id'])) {
       throw new \CRM_Core_Exception('Could not create test contact, with message: ' . \CRM_Utils_Array::value('error_message', $result) . "\nBacktrace:" . \CRM_Utils_Array::value('trace', $result));
     }
-    return $result['id'];
+    return (int) $result['id'];
   }
 
   /**
index a9caecc34a2e12c3f110249468106327fa53446d..4ba06c96fe610ddc4cb4f2c3967a3e4e4dcd3405 100644 (file)
@@ -35,29 +35,30 @@ Required vars: caseTypes
         <span>
           <a class="action-item crm-hover-button" ng-href="#/caseType/{{caseType.id}}">{{ts('Edit')}}</a>
 
-          <span class="btn-slide crm-hover-button" ng-show="!caseType.is_reserved || (!caseType.is_active || caseType.is_forked)">
+          <!-- The variables used in ng-show below can take on any of the values from the set {0, 1, "0", "1", undefined}, so use explicit ==1 or !=1 to cover all possibilities properly. -->
+          <span class="more-panel btn-slide crm-hover-button" ng-show="caseType.is_reserved!=1 || (caseType.is_active!=1 || caseType.is_forked==1)">
             {{ts('more')}}
             <ul class="panel" style="display: none;">
-              <li ng-hide="caseType.is_active">
+              <li class="panel-item-enable" ng-hide="caseType.is_active==1">
                 <a class="action-item crm-hover-button" ng-click="toggleCaseType(caseType)">
                   {{ts('Enable')}}
                 </a>
               </li>
-              <li ng-show="caseType.is_active && !caseType.is_reserved">
+              <li class="panel-item-disable" ng-show="caseType.is_active==1 && caseType.is_reserved!=1">
                 <a class="action-item crm-hover-button"
                    crm-confirm="{type: 'disable', obj: caseType}"
                    on-yes="toggleCaseType(caseType)">
                   {{ts('Disable')}}
                 </a>
               </li>
-              <li ng-show="caseType.is_forked">
+              <li class="panel-item-revert" ng-show="caseType.is_forked==1">
                 <a class="action-item crm-hover-button"
                    crm-confirm="{type: 'revert', obj: caseType}"
                    on-yes="revertCaseType(caseType)">
                   {{ts('Revert')}}
                 </a>
               </li>
-              <li ng-show="!caseType.is_reserved">
+              <li class="panel-item-delete" ng-show="caseType.is_reserved!=1">
                 <a class="action-item crm-hover-button"
                    crm-confirm="{type: 'delete', obj: caseType}"
                    on-yes="deleteCaseType(caseType)">
index 1a70bc3921cb83182598e84da4c5e23a4d0702b8..4f6c4585c9ba7049f1637ac3f6b2b311893b261c 100644 (file)
@@ -19,7 +19,7 @@
  *
  * @return array|int
  */
-function civicrm_api(string $entity = NULL, string $action, array $params, $extra = NULL) {
+function civicrm_api(string $entity, string $action, array $params, $extra = NULL) {
   return \Civi::service('civi_api_kernel')->runSafe($entity, $action, $params, $extra);
 }
 
@@ -61,7 +61,6 @@ function civicrm_api(string $entity = NULL, string $action, array $params, $extr
  * @throws \Civi\API\Exception\NotImplementedException
  */
 function civicrm_api4(string $entity, string $action, array $params = [], $index = NULL) {
-  $apiCall = \Civi\Api4\Utils\ActionUtil::getAction($entity, $action);
   $indexField = $index && is_string($index) && !CRM_Utils_Rule::integer($index) ? $index : NULL;
   $removeIndexField = FALSE;
 
@@ -70,10 +69,7 @@ function civicrm_api4(string $entity, string $action, array $params = [], $index
     $params['select'][] = $indexField;
     $removeIndexField = TRUE;
   }
-  foreach ($params as $name => $param) {
-    $setter = 'set' . ucfirst($name);
-    $apiCall->$setter($param);
-  }
+  $apiCall = \Civi\API\Request::create($entity, $action, ['version' => 4] + $params);
 
   if ($index && is_array($index)) {
     $indexCol = reset($index);
index 5b8ff8a6b9c4d8953dbd3005db199b4cc75ac1b9..b2834091f8d3ccc164183b8e254efc1da3f15a76 100644 (file)
@@ -145,8 +145,10 @@ function civicrm_api3_attachment_create($params) {
   }
   elseif (is_string($moveFile)) {
     // CRM-17432 Do not use rename() since it will break file permissions.
-    // Also avoid move_uplaoded_file() because the API can use options.move-file.
-    copy($moveFile, $path);
+    // Also avoid move_uploaded_file() because the API can use options.move-file.
+    if (!copy($moveFile, $path)) {
+      throw new API_Exception("Cannot copy uploaded file $moveFile to $path");
+    }
     unlink($moveFile);
   }
 
index 680583cf1e78bba3edd7d110f7595d03158714db..00c0bebe1d53647f9a54134cbbdc100ae53d089c 100644 (file)
@@ -81,6 +81,9 @@ function civicrm_api3_contact_create($params) {
 
   if (empty($params['contact_type']) && $contactID) {
     $params['contact_type'] = CRM_Contact_BAO_Contact::getContactType($contactID);
+    if (!$params['contact_type']) {
+      throw new API_Exception('Contact id ' . $contactID . ' not found.');
+    }
   }
 
   if (!isset($params['contact_sub_type']) && $contactID) {
index 29b56ae4ceea3d670f6c7801c398a0e550f96fc3..e70bc067cdcdfdc002b67e3106811ee4f3e83be9 100644 (file)
@@ -23,6 +23,9 @@
  *
  * @return array
  *   API result array
+ *
+ * @throws \CiviCRM_API3_Exception
+ * @throws \CRM_Core_Exception
  */
 function civicrm_api3_participant_create($params) {
   // Check that event id is not an template - should be done @ BAO layer.
index fb3c509cb94e73dc3797251fe576a53bfc82ddaf..5b7ed126680a93ff998d96c72ad930c48bbcc33b 100644 (file)
@@ -171,7 +171,7 @@ function civicrm_api3_create_success($values = 1, $params = [], $entity = NULL,
     }
   }
 
-  if (is_array($params) && !empty($params['debug'])) {
+  if (is_array($params) && $entity && !empty($params['debug'])) {
     if (is_string($action) && $action !== 'getfields') {
       $apiFields = civicrm_api($entity, 'getfields', ['version' => 3, 'action' => $action] + $params);
     }
index 6c14e526a2ca69e015bf30d493febf4fec30ebc7..22db3a163983a11a6ca04f4d50892c67ed985fb4 100644 (file)
@@ -40,6 +40,7 @@
   },
   "require": {
     "php": "~7.0",
+    "cache/integration-tests": "~0.16.0",
     "dompdf/dompdf" : "0.8.*",
     "electrolinux/phpquery": "^0.9.6",
     "symfony/config": "^2.8.50 || ~3.0",
@@ -59,7 +60,7 @@
     "pear/validate_finance_creditcard": "dev-master",
     "civicrm/civicrm-cxn-rpc": "~0.19.01.08",
     "pear/auth_sasl": "1.1.0",
-    "pear/net_smtp": "1.6.*",
+    "pear/net_smtp": "1.9.*",
     "pear/net_socket": "1.0.*",
     "pear/mail": "^1.4",
     "civicrm/civicrm-setup": "~0.4.0",
@@ -73,9 +74,6 @@
     "tplaner/when": "~3.0.0",
     "xkerman/restricted-unserialize": "~1.1"
   },
-  "require-dev": {
-    "cache/integration-tests": "dev-master"
-  },
   "scripts": {
     "post-install-cmd": [
       "bash tools/scripts/composer/dompdf-cleanup.sh",
       }
     },
     "patches": {
+      "cache/integration-tests": {
+        "Allow adding tests": "https://github.com/php-cache/integration-tests/commit/05f97174c09364dc10c084a38ba0cfd5124f4cec.patch",
+        "Support PHPUnit 6+": "https://github.com/php-cache/integration-tests/commit/1ec7362962185df91d3d749bc3fa7e7b99cb9fc7.patch",
+        "Add tests for binary data round trip": "https://github.com/php-cache/integration-tests/commit/89cd7068e83aa776774bfc44f6bcba858c085616.patch"
+      },
+      "pear/net_smtp": {
+        "Add in CiviCRM custom error message for CRM-8744": "https://raw.githubusercontent.com/civicrm/civicrm-core/a6a0ff13d2a155ad962529595dceaef728116f96/tools/scripts/composer/patches/net-smtp-patch.patch"
+      },
       "phpoffice/common": {
-        "Fix handling of libxml_disable_entity_loader": "tools/scripts/composer/patches/phpoffice-common-xml-entity-fix.patch"
+        "Fix handling of libxml_disable_entity_loader": "https://raw.githubusercontent.com/civicrm/civicrm-core/9d93748a36c7c5d44422911db1c98fb2f7067b34/tools/scripts/composer/patches/phpoffice-common-xml-entity-fix.patch"
       },
       "phpoffice/phpword": {
-        "Fix handling of libxml_disable_entity_loader": "tools/scripts/composer/patches/phpword-libxml-fix-global-handling.patch"
+        "Fix handling of libxml_disable_entity_loader": "https://raw.githubusercontent.com/civicrm/civicrm-core/9d93748a36c7c5d44422911db1c98fb2f7067b34/tools/scripts/composer/patches/phpword-libxml-fix-global-handling.patch"
       },
       "zetacomponents/mail": {
-        "CiviCRM Custom Patches for ZetaCompoents mail": "tools/scripts/composer/patches/civicrm-custom-patches-zetacompoents-mail.patch"
+        "CiviCRM Custom Patches for ZetaCompoents mail": "https://raw.githubusercontent.com/civicrm/civicrm-core/9d93748a36c7c5d44422911db1c98fb2f7067b34/tools/scripts/composer/patches/civicrm-custom-patches-zetacompoents-mail.patch"
       }
     }
   }
index 240823ffed51ab36f9aacdf26ffc0d86a639d115..1443ab232447399f0ce1fa45cb2254c7d065eb0c 100644 (file)
@@ -4,8 +4,129 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "6b2ec4d9dc608f8b2e0def4af6d7bafb",
+    "content-hash": "705221f636824b774ef9fb35f3bfc987",
     "packages": [
+        {
+            "name": "cache/integration-tests",
+            "version": "0.16.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-cache/integration-tests.git",
+                "reference": "a8d9538a44ed5a70d551f9b87f534c98dfe6b0ee"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-cache/integration-tests/zipball/a8d9538a44ed5a70d551f9b87f534c98dfe6b0ee",
+                "reference": "a8d9538a44ed5a70d551f9b87f534c98dfe6b0ee",
+                "shasum": ""
+            },
+            "require": {
+                "cache/tag-interop": "^1.0",
+                "php": "^5.4|^7",
+                "psr/cache": "~1.0"
+            },
+            "require-dev": {
+                "cache/cache": "dev-master",
+                "illuminate/cache": "^5.0",
+                "madewithlove/illuminate-psr-cache-bridge": "^1.0",
+                "phpunit/phpunit": "^4.0|^5.0",
+                "symfony/cache": "^3.1",
+                "tedivm/stash": "dev-master"
+            },
+            "type": "library",
+            "extra": {
+                "patches_applied": {
+                    "Allow adding tests": "https://github.com/php-cache/integration-tests/commit/05f97174c09364dc10c084a38ba0cfd5124f4cec.patch",
+                    "Support PHPUnit 6+": "https://github.com/php-cache/integration-tests/commit/1ec7362962185df91d3d749bc3fa7e7b99cb9fc7.patch",
+                    "Add tests for binary data round trip": "https://github.com/php-cache/integration-tests/commit/89cd7068e83aa776774bfc44f6bcba858c085616.patch"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Cache\\IntegrationTests\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Aaron Scherer",
+                    "email": "aequasi@gmail.com",
+                    "homepage": "https://github.com/aequasi"
+                },
+                {
+                    "name": "Tobias Nyholm",
+                    "email": "tobias.nyholm@gmail.com",
+                    "homepage": "https://github.com/Nyholm"
+                }
+            ],
+            "description": "Integration tests for PSR-6 and PSR-16 cache implementations",
+            "homepage": "https://github.com/php-cache/integration-tests",
+            "keywords": [
+                "cache",
+                "psr16",
+                "psr6",
+                "test"
+            ],
+            "time": "2017-02-02T14:29:50+00:00"
+        },
+        {
+            "name": "cache/tag-interop",
+            "version": "1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-cache/tag-interop.git",
+                "reference": "c7496dd81530f538af27b4f2713cde97bc292832"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-cache/tag-interop/zipball/c7496dd81530f538af27b4f2713cde97bc292832",
+                "reference": "c7496dd81530f538af27b4f2713cde97bc292832",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.5 || ^7.0",
+                "psr/cache": "^1.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Cache\\TagInterop\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Tobias Nyholm",
+                    "email": "tobias.nyholm@gmail.com",
+                    "homepage": "https://github.com/Nyholm"
+                },
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com",
+                    "homepage": "https://github.com/nicolas-grekas"
+                }
+            ],
+            "description": "Framework interoperable interfaces for tags",
+            "homepage": "http://www.php-cache.com/en/latest/",
+            "keywords": [
+                "cache",
+                "psr",
+                "psr6",
+                "tag"
+            ],
+            "time": "2017-03-13T09:14:27+00:00"
+        },
         {
             "name": "civicrm/civicrm-cxn-rpc",
             "version": "v0.19.01.08",
         },
         {
             "name": "pear/net_smtp",
-            "version": "1.6.3",
+            "version": "1.9.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/pear/Net_SMTP.git",
-                "reference": "7b6240761adf6ee245098e238a25d5c35650d82c"
+                "reference": "f7fbc5808bfeba87c38e02ea4acc5243ffc9524e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/pear/Net_SMTP/zipball/7b6240761adf6ee245098e238a25d5c35650d82c",
-                "reference": "7b6240761adf6ee245098e238a25d5c35650d82c",
+                "url": "https://api.github.com/repos/pear/Net_SMTP/zipball/f7fbc5808bfeba87c38e02ea4acc5243ffc9524e",
+                "reference": "f7fbc5808bfeba87c38e02ea4acc5243ffc9524e",
                 "shasum": ""
             },
             "require": {
-                "pear/net_socket": "*",
-                "pear/pear_exception": "*",
-                "php": ">=4.0.5"
+                "pear/net_socket": "@stable",
+                "pear/pear-core-minimal": "@stable",
+                "php": ">=5.4.0"
             },
             "require-dev": {
                 "phpunit/phpunit": "*"
                 "pear/auth_sasl": "Install optionally via your project's composer.json"
             },
             "type": "library",
+            "extra": {
+                "patches_applied": {
+                    "Add in CiviCRM custom error message for CRM-8744": "https://raw.githubusercontent.com/civicrm/civicrm-core/a6a0ff13d2a155ad962529595dceaef728116f96/tools/scripts/composer/patches/net-smtp-patch.patch"
+                }
+            },
             "autoload": {
                 "psr-0": {
                     "Net": "./"
                 "./"
             ],
             "license": [
-                "PHP License"
+                "BSD-2-Clause"
             ],
             "authors": [
                 {
                     "name": "Jon Parise",
                     "email": "jon@php.net",
-                    "homepage": "http://www.indelible.org",
+                    "homepage": "https://www.indelible.org",
                     "role": "Lead"
                 },
                 {
                 }
             ],
             "description": "An implementation of the SMTP protocol",
-            "homepage": "http://pear.github.io/Net_SMTP/",
+            "homepage": "https://pear.github.io/Net_SMTP/",
             "keywords": [
                 "email",
                 "mail",
                 "smtp"
             ],
-            "time": "2015-08-02T17:20:17+00:00"
+            "time": "2019-11-30T23:40:31+00:00"
         },
         {
             "name": "pear/net_socket",
             "type": "library",
             "extra": {
                 "patches_applied": {
-                    "Fix handling of libxml_disable_entity_loader": "tools/scripts/composer/patches/phpoffice-common-xml-entity-fix.patch"
+                    "Fix handling of libxml_disable_entity_loader": "https://raw.githubusercontent.com/civicrm/civicrm-core/9d93748a36c7c5d44422911db1c98fb2f7067b34/tools/scripts/composer/patches/phpoffice-common-xml-entity-fix.patch"
                 }
             },
             "autoload": {
                     "dev-develop": "0.16-dev"
                 },
                 "patches_applied": {
-                    "Fix handling of libxml_disable_entity_loader": "tools/scripts/composer/patches/phpword-libxml-fix-global-handling.patch"
+                    "Fix handling of libxml_disable_entity_loader": "https://raw.githubusercontent.com/civicrm/civicrm-core/9d93748a36c7c5d44422911db1c98fb2f7067b34/tools/scripts/composer/patches/phpword-libxml-fix-global-handling.patch"
                 }
             },
             "autoload": {
             ],
             "time": "2017-06-05T06:30:30+00:00"
         },
+        {
+            "name": "psr/cache",
+            "version": "1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/cache.git",
+                "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8",
+                "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Cache\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for caching libraries",
+            "keywords": [
+                "cache",
+                "psr",
+                "psr-6"
+            ],
+            "time": "2016-08-06T20:24:11+00:00"
+        },
         {
             "name": "psr/http-message",
             "version": "1.0.1",
             "type": "library",
             "extra": {
                 "patches_applied": {
-                    "CiviCRM Custom Patches for ZetaCompoents mail": "tools/scripts/composer/patches/civicrm-custom-patches-zetacompoents-mail.patch"
+                    "CiviCRM Custom Patches for ZetaCompoents mail": "https://raw.githubusercontent.com/civicrm/civicrm-core/9d93748a36c7c5d44422911db1c98fb2f7067b34/tools/scripts/composer/patches/civicrm-custom-patches-zetacompoents-mail.patch"
                 }
             },
             "autoload": {
             "time": "2020-01-17T11:18:01+00:00"
         }
     ],
-    "packages-dev": [
-        {
-            "name": "cache/integration-tests",
-            "version": "dev-master",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/php-cache/integration-tests.git",
-                "reference": "b97328797ab199f0ac933e39842a86ab732f21f9"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/php-cache/integration-tests/zipball/b97328797ab199f0ac933e39842a86ab732f21f9",
-                "reference": "b97328797ab199f0ac933e39842a86ab732f21f9",
-                "shasum": ""
-            },
-            "require": {
-                "cache/tag-interop": "^1.0",
-                "php": "^5.4|^7",
-                "psr/cache": "~1.0"
-            },
-            "conflict": {
-                "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0"
-            },
-            "require-dev": {
-                "cache/cache": "^1.0",
-                "illuminate/cache": "^5.4|^5.5|^5.6",
-                "mockery/mockery": "^1.0",
-                "phpunit/phpunit": "^4.8.35|^5.4.3",
-                "symfony/cache": "^3.1|^4.0|^5.0",
-                "tedivm/stash": "^0.14"
-            },
-            "type": "library",
-            "autoload": {
-                "psr-4": {
-                    "Cache\\IntegrationTests\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Aaron Scherer",
-                    "email": "aequasi@gmail.com",
-                    "homepage": "https://github.com/aequasi"
-                },
-                {
-                    "name": "Tobias Nyholm",
-                    "email": "tobias.nyholm@gmail.com",
-                    "homepage": "https://github.com/nyholm"
-                }
-            ],
-            "description": "Integration tests for PSR-6 and PSR-16 cache implementations",
-            "homepage": "https://github.com/php-cache/integration-tests",
-            "keywords": [
-                "cache",
-                "psr16",
-                "psr6",
-                "test"
-            ],
-            "time": "2019-05-28T15:23:38+00:00"
-        },
-        {
-            "name": "cache/tag-interop",
-            "version": "1.0.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/php-cache/tag-interop.git",
-                "reference": "c7496dd81530f538af27b4f2713cde97bc292832"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/php-cache/tag-interop/zipball/c7496dd81530f538af27b4f2713cde97bc292832",
-                "reference": "c7496dd81530f538af27b4f2713cde97bc292832",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.5 || ^7.0",
-                "psr/cache": "^1.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "2.0-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Cache\\TagInterop\\": ""
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Tobias Nyholm",
-                    "email": "tobias.nyholm@gmail.com",
-                    "homepage": "https://github.com/Nyholm"
-                },
-                {
-                    "name": "Nicolas Grekas",
-                    "email": "p@tchwork.com",
-                    "homepage": "https://github.com/nicolas-grekas"
-                }
-            ],
-            "description": "Framework interoperable interfaces for tags",
-            "homepage": "http://www.php-cache.com/en/latest/",
-            "keywords": [
-                "cache",
-                "psr",
-                "psr6",
-                "tag"
-            ],
-            "time": "2017-03-13T09:14:27+00:00"
-        },
-        {
-            "name": "psr/cache",
-            "version": "1.0.1",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/php-fig/cache.git",
-                "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8",
-                "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.0.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Psr\\Cache\\": "src/"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "PHP-FIG",
-                    "homepage": "http://www.php-fig.org/"
-                }
-            ],
-            "description": "Common interface for caching libraries",
-            "keywords": [
-                "cache",
-                "psr",
-                "psr-6"
-            ],
-            "time": "2016-08-06T20:24:11+00:00"
-        }
-    ],
+    "packages-dev": [],
     "aliases": [],
     "minimum-stability": "stable",
     "stability-flags": {
-        "pear/validate_finance_creditcard": 20,
-        "cache/integration-tests": 20
+        "pear/validate_finance_creditcard": 20
     },
     "prefer-stable": false,
     "prefer-lowest": false,
index 47c6e48b18e095dd3950eaa92d0d0e7e034f8ca0..fca7ef9abc4fde8262eb39c3852b0bbd35bee783 100644 (file)
@@ -404,6 +404,7 @@ if (!CRM.vars) CRM.vars = {};
       return $(this).each(function() {
         $(this)
           .removeClass('crm-ajax-select')
+          .off('.crmSelect2')
           .select2('destroy');
       });
     }
@@ -439,6 +440,13 @@ if (!CRM.vars) CRM.vars = {};
         };
       }
 
+      // Use description as title for each option
+      $el.on('select2-loaded.crmSelect2', function() {
+        $('.crm-select2-row-description', '#select2-drop').each(function() {
+          $(this).closest('.select2-result-label').attr('title', $(this).text());
+        });
+      });
+
       // Defaults for single-selects
       if ($el.is('select:not([multiple])')) {
         settings.minimumResultsForSearch = 10;
@@ -671,7 +679,7 @@ if (!CRM.vars) CRM.vars = {};
       '</div>' +
       '<div class="crm-select2-row-description">';
     $.each(row.description || [], function(k, text) {
-      markup += '<p>' + _.escape(text) + '</p>';
+      markup += '<p>' + _.escape(text) + '</p> ';
     });
     markup += '</div></div></div>';
     return markup;
@@ -1598,25 +1606,6 @@ if (!CRM.vars) CRM.vars = {};
     return (yiq >= 128) ? 'black' : 'white';
   };
 
-  // based on https://github.com/janl/mustache.js/blob/master/mustache.js
-  // If you feel the need to use this function, consider whether assembling HTML
-  // via DOM might be a cleaner approach rather than using string concatenation.
-  CRM.utils.escapeHtml = function(string) {
-    var entityMap = {
-      '&': '&amp;',
-      '<': '&lt;',
-      '>': '&gt;',
-      '"': '&quot;',
-      "'": '&#39;',
-      '/': '&#x2F;',
-      '`': '&#x60;',
-      '=': '&#x3D;'
-    };
-    return String(string).replace(/[&<>"'`=\/]/g, function fromEntityMap (s) {
-      return entityMap[s];
-    });
-  }
-
   // CVE-2015-9251 - Prevent auto-execution of scripts when no explicit dataType was provided
   $.ajaxPrefilter(function(s) {
     if (s.crossDomain) {
index b87db357d16ade482d2938ce58436919a016d29f..b757e27f6c472c4f3c4afd33501cf34093658e5a 100644 (file)
@@ -1,7 +1,7 @@
 // https://civicrm.org/licensing
 /* global CRM, ts */
 /*jshint loopfunc: true */
-(function($) {
+(function($, _) {
   'use strict';
   // Constructor for dashboard object.
   $.fn.dashboard = function(options) {
         });
         CRM.alert(
           ts('You can re-add it by clicking the "Configure Your Dashboard" button.'),
-          ts('"%1" Removed', {1: CRM.utils.escapeHtml(widget.title)}),
+          ts('"%1" Removed', {1: _.escape(widget.title)}),
           'success'
         );
       };
       function widgetHTML() {
         var html = '';
         html += '<div class="widget-wrapper">';
-        html += '  <div class="widget-controls"><h3 class="widget-header">' + CRM.utils.escapeHtml(widget.title) + '</h3></div>';
+        html += '  <div class="widget-controls"><h3 class="widget-header">' + _.escape(widget.title) + '</h3></div>';
         html += '  <div class="widget-content"></div>';
         html += '</div>';
         return html;
       // id, url, fullscreenUrl, title, name, cacheMinutes
     }
   };
-})(jQuery);
+})(jQuery, CRM._);
index 7c0c8099b35499b4cfc53c86f3246ae0c1a88755..e742897b9def0b05dce48a9dde868199f09dd273 100644 (file)
@@ -1,6 +1,6 @@
 # CiviCRM 5.21.1
 
-Released January 10, 2019
+Released January 10, 2020
 
 - **[Synopsis](#synopsis)**
 - **[Bugs resolved](#bugs)**
index 23c793bdd3e7304a9d0b79187b29a61c38cf9d2b..44dc6055695280e93259af149bf0cc45b482cc5a 100644 (file)
@@ -99,4 +99,19 @@ return [
     'description' => ts('Enable tracking of activity revisions embedded within the "civicrm_activity" table. Alternatively, see "Administer => System Settings => Misc => Logging".'),
     'help_text' => '',
   ],
+  'civicaseShowCaseActivities' => [
+    'group_name' => 'CiviCRM Preferences',
+    'group' => 'core',
+    'name' => 'civicaseShowCaseActivities',
+    'type' => 'Boolean',
+    'quick_form_type' => 'YesNo',
+    'default' => FALSE,
+    'html_type' => 'radio',
+    'add' => '5.24',
+    'title' => ts('Include case activities in general activity views.'),
+    'is_domain' => 1,
+    'is_contact' => 0,
+    'description' => ts('e.g. the Contact form\'s Activity tab listing. Without this ticked, activities that belong to a case are hidden (default behavior). Warning: enabling this option means that all case activities relating to a contact will be listed which could result in users without "access all cases and activities" permission being able to see see the summarized details (date, subject, assignees, status etc.). Such users will still be prevented from managing the case and viewing/editing the activity.'),
+    'help_text' => '',
+  ],
 ];
index fb2170cc6ff4fa3e7e43b76730377b5e8030e55c..fe9175d8abceaae22142fb22c21a4a5e1425bf63 100644 (file)
@@ -32,6 +32,7 @@ return [
     'is_contact' => 0,
     'description' => ts('Is the CVV code required for back office credit card transactions'),
     'help_text' => 'If set it back-office credit card transactions will required a cvv code. Leave as required unless you have a very strong reason to change',
+    'settings_pages' => ['contribute' => ['weight' => 10]],
   ],
   'contribution_invoice_settings' => [
     // @todo our standard is to have a setting per item not to hide settings in an array with
@@ -70,6 +71,7 @@ return [
     'on_change' => [
       'CRM_Invoicing_Utils::onToggle',
     ],
+    'settings_pages' => ['contribute' => ['weight' => 90]],
   ],
   'credit_notes_prefix' => [
     'group_name' => 'Contribute Preferences',
@@ -85,6 +87,7 @@ return [
     'description' => ts('Prefix to be prepended to credit note ids'),
     'default' => 'CN_',
     'help_text' => ts('The credit note ID is generated when a contribution is set to Refunded, Cancelled or Chargeback. It is visible on invoices, if invoices are enabled'),
+    'settings_pages' => ['contribute' => ['weight' => 80]],
   ],
   'invoice_prefix' => [
     'html_type' => 'text',
@@ -176,6 +179,7 @@ return [
     'is_contact' => 0,
     'help_text' => NULL,
     'help' => ['id' => 'acl_financial_type'],
+    'settings_pages' => ['contribute' => ['weight' => 30]],
   ],
   'deferred_revenue_enabled' => [
     'group_name' => 'Contribute Preferences',
@@ -190,6 +194,7 @@ return [
     'is_domain' => 1,
     'is_contact' => 0,
     'help_text' => NULL,
+    'settings_pages' => ['contribute' => ['weight' => 50]],
   ],
   'default_invoice_page' => [
     'group_name' => 'Contribute Preferences',
@@ -208,6 +213,7 @@ return [
     'is_domain' => 1,
     'is_contact' => 0,
     'help_text' => NULL,
+    'settings_pages' => ['contribute' => ['weight' => 70]],
   ],
   'always_post_to_accounts_receivable' => [
     'group_name' => 'Contribute Preferences',
@@ -222,6 +228,7 @@ return [
     'is_domain' => 1,
     'is_contact' => 0,
     'help_text' => NULL,
+    'settings_pages' => ['contribute' => ['weight' => 40]],
   ],
   'update_contribution_on_membership_type_change' => [
     'group_name' => 'Contribute Preferences',
@@ -237,5 +244,6 @@ return [
     'is_contact' => 0,
     'description' => ts('Enabling this setting will update related contribution of membership(s) except if the membership is paid for with a recurring contribution.'),
     'help_text' => NULL,
+    'settings_pages' => ['contribute' => ['weight' => 20]],
   ],
 ];
index 316898f0d1820d3dfcedfa43bc5e45b96ce09269..275f4a59310b1e406589f5254eb6003b75753a97 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`, `version`, `contact_id`, `locales`, `locale_custom_strings`) VALUES (1,'Default Domain Name',NULL,'5.23.beta1',1,NULL,'a:1:{s:5:\"en_US\";a:0:{}}');
+INSERT INTO `civicrm_domain` (`id`, `name`, `description`, `version`, `contact_id`, `locales`, `locale_custom_strings`) VALUES (1,'Default Domain Name',NULL,'5.24.alpha1',1,NULL,'a:1:{s:5:\"en_US\";a:0:{}}');
 /*!40000 ALTER TABLE `civicrm_domain` ENABLE KEYS */;
 UNLOCK TABLES;
 
index 5edd94951002c78bb888b43f4233607e764960e6..b19a243c02ab15aa6de62d50d250f951038ba4d6 100644 (file)
@@ -13,7 +13,7 @@
       {/if}
       <table class="crm-info-panel">
         <tr>
-            <td class="label">{ts}Added By{/ts}</td><td class="view-value">{$values.source_contact}</td>
+            <td class="label">{ts}Added by{/ts}</td><td class="view-value">{$values.source_contact}</td>
         </tr>
        {if $values.target_contact_value}
            <tr>
index b986c82f936b8c56fd5dafb5479b65fc11a64a8f..7fd288217c7d480ad1e43e417b5df9c84ef8bfd3 100644 (file)
@@ -20,7 +20,7 @@
   <tr class="columnheader">
     <td>{ts}Type{/ts}</td>
     <td>{ts}Subject{/ts}</td>
-    <td>{ts}Added By{/ts}</td>
+    <td>{ts}Added by{/ts}</td>
     <td>{ts}With{/ts}</td>
     <td>{ts}Assigned to{/ts}</td>
     <td>{ts}Date{/ts}</td>
index d06073ac6f77faf7ccd291745497ff19c9df63c2..8fb1f85f2b9370cd38d23467500c66cc48c2c7b1 100644 (file)
@@ -19,7 +19,7 @@
                 <tr class="columnheader">
                     <th>{ts}Type{/ts}</th>
                     <th>{ts}Subject{/ts}</th>
-                    <th>{ts}Added By{/ts}</th>
+                    <th>{ts}Added by{/ts}</th>
                     <th>{ts}With{/ts}</th>
                     <th>{ts}Date{/ts}</th>
                     <th>{ts}Status{/ts}</th>
index 63d0de4ae0f5640d3f68fd3374b985b3b59fdb88..ffb235266b9b01db7122fd5960f86b4778fa30fb 100644 (file)
@@ -38,7 +38,7 @@
     <tr>
       <th data-data="activity_type" class="crm-contact-activity-activity_type">{ts}Type{/ts}</th>
       <th data-data="subject" cell-class="crmf-subject crm-editable" class="crm-contact-activity_subject">{ts}Subject{/ts}</th>
-      <th data-data="source_contact_name" class="crm-contact-activity-source_contact">{ts}Added By{/ts}</th>
+      <th data-data="source_contact_name" class="crm-contact-activity-source_contact">{ts}Added by{/ts}</th>
       <th data-data="target_contact_name" data-orderable="false" class="crm-contact-activity-target_contact">{ts}With{/ts}</th>
       <th data-data="assignee_contact_name" data-orderable="false" class="crm-contact-activity-assignee_contact">{ts}Assigned{/ts}</th>
       <th data-data="activity_date_time" class="crm-contact-activity-activity_date_time">{ts}Date{/ts}</th>
index 5df543574fc8fce9b32821341e341909fc20b16f..825826c6aadfc82ce1e11a451aa93fb3857a8153 100644 (file)
         <span class="description">{ts}Enable embedded tracking to activity revisions within the "civicrm_activity" table. Alternatively, see "Administer => System Settings => Misc => Logging".{/ts}</span>
       </td>
     </tr>
+    <tr class="crm-case-form-block-civicaseShowCaseActivities">
+      <td class="label">{$form.civicaseShowCaseActivities.label}</td>
+      <td>{$form.civicaseShowCaseActivities.html}<br />
+        <span class="description">{$civicaseShowCaseActivities_description}</span>
+      </td>
+    </tr>
   </table>
   <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
 </div>
index 9f244ff36701aa6b8f4e19a292817def573d14db..ce5c162e089711c5027ec354a2dfeb5d5ef015b7 100644 (file)
         {else}
           <tr class="crm-localization-form-block-description">
               <td>
-              <span class="description">{ts}In order to use this functionality, the installation's database user must have privileges to create triggers and views (in MySQL 5.0 â€“ and in MySQL 5.1 if binary logging is enabled â€“ this means the SUPER privilege). This install either does not seem to have the required privilege enabled.{/ts} {ts}(Multilingual support currently cannot be enabled on installations with enabled logging.){/ts}</span><br /><br />
+              <span class="description">{ts}In order to use this functionality, the installation's database user must have privileges to create triggers and views (if binary logging is enabled â€“ this means the SUPER privilege). This install does not have the required privilege(s) enabled.{/ts} {ts}(Multilingual support currently cannot be enabled on installations with enabled logging.){/ts}</span><br /><br />
               <span class="description font-red">{$warning}</span></td>
           </tr>
         {/if}
index be43122c55c5928be1a610c9908a2b6559a9ad0b..fb28c7034daae09b47e08aaf53db0fcb43786ed0 100644 (file)
 <div id="crm-container" class="crm-container">
 <h1>{$pageTitle}</h1>
 <div id="report-date">{$reportDate}</div>
-<h2>{ts}Case Summary{/ts}</h2>
-<table class="report-layout">
+{if $case}
+  <h2>{ts}Case Summary{/ts}</h2>
+  <table class="report-layout">
     <tr>
       <th class="reports-header">{ts}Client{/ts}</th>
       <th class="reports-header">{ts}Case Type{/ts}</th>
-         <th class="reports-header">{ts}Status{/ts}</th>
-        <th class="reports-header">{ts}Start Date{/ts}</th>
+      <th class="reports-header">{ts}Status{/ts}</th>
+      <th class="reports-header">{ts}Start Date{/ts}</th>
       <th class="reports-header">{ts}Case ID{/ts}</th>
     </tr>
     <tr>
-        <td class="crm-case-report-clientName">{$case.clientName}</td>
-        <td class="crm-case-report-caseType">{$case.caseType}</td>
-        <td class="crm-case-report-status">{$case.status}</td>
-        <td class="crm-case-report-start_date">{$case.start_date}</td>
-        <td class="crm-case-report-{$caseId}">{$caseId}</td>
+      <td class="crm-case-report-clientName">{$case.clientName}</td>
+      <td class="crm-case-report-caseType">{$case.caseType}</td>
+      <td class="crm-case-report-status">{$case.status}</td>
+      <td class="crm-case-report-start_date">{$case.start_date}</td>
+      <td class="crm-case-report-{$caseId}">{$caseId}</td>
     </tr>
-</table>
-<h2>{ts}Case Roles{/ts}</h2>
-<table class ="report-layout">
+  </table>
+{/if}
+
+{if $caseRelationships}
+  <h2>{ts}Case Roles{/ts}</h2>
+  <table class ="report-layout">
     <tr>
       <th class="reports-header">{ts}Case Role{/ts}</th>
       <th class="reports-header">{ts}Name{/ts}</th>
-         <th class="reports-header">{ts}Phone{/ts}</th>
-        <th class="reports-header">{ts}Email{/ts}</th>
+      <th class="reports-header">{ts}Phone{/ts}</th>
+      <th class="reports-header">{ts}Email{/ts}</th>
     </tr>
 
     {foreach from=$caseRelationships item=row key=relId}
-       <tr>
-          <td class="crm-case-report-caserelationships-relation">{$row.relation}</td>
-          <td class="crm-case-report-caserelationships-name">{$row.name}</td>
-          <td class="crm-case-report-caserelationships-phone">{$row.phone}</td>
-          <td class="crm-case-report-caserelationships-email">{$row.email}</td>
-       </tr>
+      <tr>
+        <td class="crm-case-report-caserelationships-relation">{$row.relation}</td>
+        <td class="crm-case-report-caserelationships-name">{$row.name}</td>
+        <td class="crm-case-report-caserelationships-phone">{$row.phone}</td>
+        <td class="crm-case-report-caserelationships-email">{$row.email}</td>
+      </tr>
     {/foreach}
     {foreach from=$caseRoles item=relName key=relTypeID}
-         {if $relTypeID neq 'client'}
-           <tr>
-               <td>{$relName}</td>
-               <td>{ts}(not assigned){/ts}</td>
-               <td></td>
-               <td></td>
-           </tr>
-         {else}
-           <tr>
-               <td class="crm-case-report-caseroles-role">{$relName.role}</td>
-               <td class="crm-case-report-caseroles-sort_name">{$relName.sort_name}</td>
-               <td class="crm-case-report-caseroles-phone">{$relName.phone}</td>
-               <td class="crm-case-report-caseroles-email">{$relName.email}</td>
-           </tr>
-         {/if}
-  {/foreach}
-</table>
-<br />
-
+      {if $relTypeID neq 'client'}
+        <tr>
+          <td>{$relName}</td>
+          <td>{ts}(not assigned){/ts}</td>
+          <td></td>
+          <td></td>
+        </tr>
+      {else}
+        <tr>
+          <td class="crm-case-report-caseroles-role">{$relName.role}</td>
+          <td class="crm-case-report-caseroles-sort_name">{$relName.sort_name}</td>
+          <td class="crm-case-report-caseroles-phone">{$relName.phone}</td>
+          <td class="crm-case-report-caseroles-email">{$relName.email}</td>
+        </tr>
+      {/if}
+    {/foreach}
+  </table>
+  <br />
+{/if}
 {if $otherRelationships}
     <table  class ="report-layout">
          <tr>
   {/foreach}
 {/if}
 
-<h2>{ts}Case Activities{/ts}</h2>
-{foreach from=$activities item=activity key=key}
-  <table  class ="report-layout">
-       {foreach from=$activity item=field name=fieldloop}
-           <tr class="crm-case-report-activity-{$field.label}">
-             <th scope="row" class="label">{$field.label|escape}</th>
-             {if $field.label eq 'Activity Type' or $field.label eq 'Status'}
-                <td class="bold">{$field.value|escape}</td>
-             {elseif $field.label eq 'Details' or $field.label eq 'Subject'}
-                <td>{$field.value}</td>
-             {else}
-                <td>{$field.value|escape}</td>
-             {/if}
-           </tr>
-       {/foreach}
-  </table>
-  <br />
-{/foreach}
+{if $activities}
+  <h2>{ts}Case Activities{/ts}</h2>
+  {foreach from=$activities item=activity key=key}
+    <table  class ="report-layout">
+      {foreach from=$activity item=field name=fieldloop}
+        <tr class="crm-case-report-activity-{$field.label}">
+          <th scope="row" class="label">{$field.label|escape}</th>
+          {if $field.label eq 'Activity Type' or $field.label eq 'Status'}
+            <td class="bold">{$field.value|escape}</td>
+          {elseif $field.label eq 'Details' or $field.label eq 'Subject'}
+            <td>{$field.value}</td>
+          {else}
+            <td>{$field.value|escape}</td>
+          {/if}
+        </tr>
+      {/foreach}
+    </table>
+    <br />
+  {/foreach}
+{/if}
 </div>
 </body>
 </html>
-
-
-
-
-
index 3db496d8b11082f857618c53a62a55e7eb756614..6d15896a9a5bf40f6faabfa75350932c5537b06a 100644 (file)
@@ -84,7 +84,7 @@
           <th>{ts}Type{/ts}</th>
           <th>{ts}Subject{/ts}</th>
           <th>{ts}Details{/ts}</th>
-          <th class='link'>{ts}Added By{/ts}</th>
+          <th class='link'>{ts}Added by{/ts}</th>
           <th class='link'>{ts}With{/ts}</th>
           <th class='link'>{ts}Assignee{/ts}</th>
           {if $allowFileSearch}<th>{ts}File{/ts}</th>{/if}
index a16097cf01f3760fac2a3dd3a89885c199a349cd..6077fe49fdc4d4ed6422841ce2c9a6793905de3c 100644 (file)
   {/literal}
 </script>
 {/if}
-
-{* jQuery validate *}
-{* disabled because originally this caused problems with some credit cards.
-Likely it no longer has an problems but allowing conditional
- inclusion by extensions / payment processors for now in order to add in a conservative way *}
-{if $isJsValidate}
-  {include file="CRM/Form/validate.tpl"}
-{/if}
+{include file="CRM/Form/validate.tpl"}
index 5d543f9661f61a29de3da630ced7398e3907f669..439d97e6601cc54a805f0eaa807fbce723879a0a 100644 (file)
     <td class="label">{ts}Financial Type{/ts}</td>
     <td>{$financial_type}{if $is_test} {ts}(test){/ts} {/if}</td>
   </tr>
+  <tr>
+    <td class="label">{ts}Source{/ts}</td>
+    <td>{$source}</td>
+  </tr>
+  <tr>
+    <td class="label">{ts}Received{/ts}</td>
+    <td>{if $receive_date}{$receive_date|crmDate}{else}({ts}not available{/ts}){/if}</td>
+  </tr>
   {if $displayLineItems}
     <tr>
       <td class="label">{ts}Contribution Amount{/ts}</td>
       <td>{$revenue_recognition_date|crmDate:"%B, %Y"}</td>
     </tr>
   {/if}
-  <tr>
-    <td class="label">{ts}Received{/ts}</td>
-    <td>{if $receive_date}{$receive_date|crmDate}{else}({ts}not available{/ts}){/if}</td>
-  </tr>
   {if $to_financial_account }
     <tr>
       <td class="label">{ts}Received Into{/ts}</td>
       <td>{$check_number}</td>
     </tr>
   {/if}
-  <tr>
-    <td class="label">{ts}Source{/ts}</td>
-    <td>{$source}</td>
-  </tr>
 
   {if $campaign}
     <tr>
index 046d997e3d68902d7f98e0f3cf2a3bdfdeea74d9..cc2ccfdb340629eed94cdac7fa3597984f06aa6a 100644 (file)
 
 </script>
 {/literal}
+{include file="CRM/Form/validate.tpl"}
index c1a14bbbc4dbbc3a4fe2249402974c607a2938a9..d5a7a64e76cc6c4c0880c59ebdcb905c058ecede 100644 (file)
         "url": {/literal}'{crmURL p="civicrm/ajax/grouplist" h=0 q="snippet=4"}'{literal},
         "data": function (d) {
 
-          var groupTypes = ($('.crm-group-search-form-block #group_type_search_1').prop('checked')) ? '1' : '';
-          if (groupTypes) {
-            groupTypes = ($('.crm-group-search-form-block #group_type_search_2').prop('checked')) ? groupTypes + ',2' : groupTypes;
-          } else {
-            groupTypes = ($('.crm-group-search-form-block #group_type_search_2').prop('checked')) ? '2' : '';
-          }
+          var groupTypes = '';
+          $('input[id*="group_type_search_"]:checked').each(function(e) {
+            groupTypes += $(this).attr('id').replace(/group_type_search_/, groupTypes == '' ? '' : ',');
+          });
 
           var groupStatus = ($('.crm-group-search-form-block #group_status_1').prop('checked')) ? 1 : '';
           if (groupStatus) {
index 66904f8569cc4497f1904faab3e856a82e8b4db0..1a05e10bb859ca5a7e2d06fc01f9387cc7501366 100644 (file)
@@ -13,7 +13,7 @@
     <thead>
       <tr>
         <th data-data="subject" class="crm-mailing-contact-subject">{ts}Subject{/ts}</th>
-        <th data-data="creator_name" class="crm-mailing-contact_created">{ts}Added By{/ts}</th>
+        <th data-data="creator_name" class="crm-mailing-contact_created">{ts}Added by{/ts}</th>
         <th data-data="recipients" data-orderable="false" class="crm-contact-activity_contact">{ts}Recipients{/ts}</th>
         <th data-data="start_date" class="crm-mailing-contact-date">{ts}Date{/ts}</th>
         <th data-data="openstats" data-orderable="false" class="crm-mailing_openstats">{ts}Opens/ Clicks{/ts}</th>
index 5ef0a00c5ed1cee3e2b7faf85e4f1637e1c55d19..153fb4af448f55dd3c88ba8d4910b9b48b5a95f6 100644 (file)
@@ -154,33 +154,27 @@ function calculateTotalFee() {
  * Display calculated amount.
  */
 function display(totalfee) {
+  // totalfee is monetary, round it to 2 decimal points so it can
+  // go as a float - CRM-13491
+  totalfee = Math.round(totalfee*100)/100;
+  var totalFormattedFee = CRM.formatMoney(totalfee);
+  cj('#pricevalue').html(totalFormattedFee);
 
-    // totalfee is monetary, round it to 2 decimal points so it can
-    // go as a float - CRM-13491
-    totalfee = Math.round(totalfee*100)/100;
-    var totalEventFee  = formatMoney( totalfee, 2, separator, thousandMarker);
-    document.getElementById('pricevalue').innerHTML = "<b>"+symbol+"</b> "+totalEventFee;
+  cj('#total_amount').val( totalfee );
+  cj('#pricevalue').data('raw-total', totalfee).trigger('change');
 
-    cj('#total_amount').val( totalfee );
-    cj('#pricevalue').data('raw-total', totalfee).trigger('change');
-
-    ( totalfee < 0 ) ? cj('table#pricelabel').addClass('disabled') : cj('table#pricelabel').removeClass('disabled');
-    if (typeof skipPaymentMethod == 'function') {
-      // Advice to anyone who, like me, feels hatred towards this if construct ... if you remove the if you
-      // get an error on participant 2 of a event that requires approval & permits multiple registrants.
-      skipPaymentMethod();
-    }
-}
+  if (totalfee < 0) {
+    cj('table#pricelabel').addClass('disabled');
+  }
+  else {
+    cj('table#pricelabel').removeClass('disabled');
+  }
 
-//money formatting/localization
-function formatMoney (amount, c, d, t) {
-var n = amount,
-    c = isNaN(c = Math.abs(c)) ? 2 : c,
-    d = d == undefined ? "," : d,
-    t = t == undefined ? "." : t, s = n < 0 ? "-" : "",
-    i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "",
-    j = (j = i.length) > 3 ? j % 3 : 0;
-  return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
+  if (typeof skipPaymentMethod == 'function') {
+    // Advice to anyone who, like me, feels hatred towards this if construct ... if you remove the if you
+    // get an error on participant 2 of a event that requires approval & permits multiple registrants.
+    skipPaymentMethod();
+  }
 }
 
 {/literal}
index 70829c1100a97a48162227aa304759e006b37014..16c1032b4a69efc059f59d108179488a9897728f 100644 (file)
           </tr>
         {/if}
     </table>
-        {if $parent_tags|@count > 0}
-        <table class="form-layout-compressed">
-            <tr><td><label>{ts}Remove Parent?{/ts}</label></td></tr>
-            {foreach from=$parent_tags item=ctag key=tag_id}
-                {assign var="element_name" value="remove_parent_tag_"|cat:$tag_id}
-                <tr><td>&nbsp;&nbsp;{$form.$element_name.html}&nbsp;{$form.$element_name.label}</td></tr>
-            {/foreach}
-        </table><br />
-        {/if}
     {else}
         <div class="status">{ts 1=$delName}Are you sure you want to delete <b>%1</b>?{/ts}<br />{ts}This tag will be removed from any currently tagged contacts, and users will no longer be able to assign contacts to this tag.{/ts}</div>
     {/if}
index 65bbd8f920d3b400b2c029f45d34de23e8bbf83c..d00db87015612b4cf33a082719820829a00aed3b 100644 (file)
@@ -3,7 +3,7 @@
  +--------------------------------------------------------------------+
  | CiviCRM version 5                                                  |
  +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2018                                |
+ | Copyright CiviCRM LLC (c) 2004-2020                                |
  +--------------------------------------------------------------------+
  | This file is a part of CiviCRM.                                    |
  |                                                                    |
index 67b31e2e67f0480df39f8d21608adb09a8003b5d..c8c5f8d00830662bf9276d730c1c4603e0a89acf 100644 (file)
@@ -1,4 +1,7 @@
 <extension key='test.extension.manager.moduletest' type='module'>
   <file>moduletest</file>
   <name>test_extension_manager_moduletest</name>
+  <tags>
+    <tag>mock</tag>
+  </tags>
 </extension>
index 9e91db0e187b606c112950ccaead63c889487619..eb93e2705411c03fd78fb69470765462a22407e0 100644 (file)
@@ -19,4 +19,7 @@
     <isRecur>0</isRecur>
     <paymentType>1</paymentType>
   </typeInfo>
+  <tags>
+    <tag>mock</tag>
+  </tags>
 </extension>
index 502d1fdb41ab67f5050a3a4c49d2cecbbf6664d0..e63adf2f5f87e565f1a0a9d8bfbf468afab33b0b 100644 (file)
@@ -31,6 +31,7 @@ describe('crmCaseType', function() {
     $httpBackend = _$httpBackend_;
     $q = _$q_;
     $rootScope = _$rootScope_;
+    $rootScope.ts = CRM.ts(null);
     $timeout = _$timeout_;
   }));
 
@@ -1059,5 +1060,1488 @@ describe('crmCaseType', function() {
         });
       });
     });
+
+    // Test show/hide for the various dropdown actions
+    describe('showandtell', function() {
+      var templateCache;
+      var template;
+
+      // $templateCache is populated by the nghtml2js plugin. See karma.conf.js
+      // I'm not sure why it can't be injected higher up in the hierarchy. It doesn't seem to work?
+      beforeEach(inject(function($templateCache) {
+        scope = $rootScope.$new();
+        templateCache = $templateCache;
+        template = templateCache.get('~/crmCaseType/list.html');
+      }));
+
+      // Helper function which we call repeatedly. It can't be in beforeEach
+      // because then the timing is wrong because we need different caseTypes
+      // in each test, which happens of course after beforeEach.
+      var compileTemplate = function(scope) {
+        var element = $compile(template)(scope);
+        scope.$digest();
+        return element;
+      };
+
+      // This is the workhorse function that does the actual test, called
+      // repeatedly for each case type variation from the `it()` below.
+      var doTest = function(inputCaseType, expected) {
+        // Mock up our case types based on input, merging some static info
+        // with the variable input.
+        var caseType = {
+          id: 1,
+          title: 'Housing Support',
+          name: 'housing_support'
+        };
+        // PhantomJS at the moment doesn't support ES6, so do a loop.
+        for (var memberVar in inputCaseType) {
+          caseType[memberVar] = inputCaseType[memberVar];
+        }
+        scope.caseTypes = {
+          1: caseType
+        };
+
+        // Render the template in the context of our scope now that the scope
+        // contains our mock case types.
+        var element = compileTemplate(scope);
+        //console.debug(element);
+
+        //
+        // Now verify the expected values
+        //
+
+        // Useful variable for displaying the inputs that caused failure
+        // in readable form.
+        var inputStr = JSON.stringify(inputCaseType);
+
+        expect(element.find('span.more-panel').hasClass('ng-hide')).toBe(expected.more_hidden, 'More link should be ' +
+          (expected.more_hidden ? 'hidden' : 'visible') +
+          ' for ' + inputStr);
+
+        expect(element.find('li.panel-item-enable').hasClass('ng-hide')).toBe(expected.enable_hidden, 'Enable should be ' +
+          (expected.enable_hidden ? 'hidden' : 'visible') +
+          ' for ' + inputStr);
+
+        expect(element.find('li.panel-item-disable').hasClass('ng-hide')).toBe(expected.disable_hidden, 'Disable should be ' +
+          (expected.disable_hidden ? 'hidden' : 'visible') +
+          ' for ' + inputStr);
+
+        expect(element.find('li.panel-item-revert').hasClass('ng-hide')).toBe(expected.revert_hidden, 'Revert should be ' +
+          (expected.revert_hidden ? 'hidden' : 'visible') +
+          ' for ' + inputStr);
+
+        expect(element.find('li.panel-item-delete').hasClass('ng-hide')).toBe(expected.delete_hidden, 'Delete should be ' +
+          (expected.delete_hidden ? 'hidden' : 'visible') +
+          ' for ' + inputStr);
+      };
+
+      // Test show/hide for the various dropdown actions
+      //
+      // There's 625 assertions.
+      // Three variables: [is_active, is_forked, is_reserved],
+      // each with 5 possible values: [0, 1, "0", "1", undefined].
+      // Then, multiply that by 5 because there are 5 UI elements
+      // to be checked.
+      // So 125 possible input tuples, with 5 things to check in each test.
+      it('to be or not to be', function() {
+        var caseTypeSimulations = [
+          [
+            // input case type
+            {"is_active": "1", "is_reserved": "0"},
+            {
+              // should more link be hidden
+              "more_hidden": false,
+              // should enable choice be hidden
+              "enable_hidden": true,
+              // should disable choice be hidden
+              "disable_hidden": false,
+              // should revert choice be hidden
+              "revert_hidden": true,
+              // should delete choice be hidden
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":0,"is_reserved":0,"is_forked":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":0,"is_reserved":0,"is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":0,"is_reserved":0,"is_forked":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":0,"is_reserved":0,"is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":0,"is_reserved":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":0,"is_reserved":1,"is_forked":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":0,"is_reserved":1,"is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":0,"is_reserved":1,"is_forked":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":0,"is_reserved":1,"is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":0,"is_reserved":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":0,"is_reserved":"0","is_forked":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":0,"is_reserved":"0","is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":0,"is_reserved":"0","is_forked":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":0,"is_reserved":"0","is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":0,"is_reserved":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":0,"is_reserved":"1","is_forked":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":0,"is_reserved":"1","is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":0,"is_reserved":"1","is_forked":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":0,"is_reserved":"1","is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":0,"is_reserved":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":0,"is_forked":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":0,"is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":0,"is_forked":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":0,"is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":1,"is_reserved":0,"is_forked":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":1,"is_reserved":0,"is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":1,"is_reserved":0,"is_forked":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":1,"is_reserved":0,"is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":1,"is_reserved":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":1,"is_reserved":1,"is_forked":0},
+            {
+              "more_hidden": true,
+              "enable_hidden": true,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":1,"is_reserved":1,"is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":1,"is_reserved":1,"is_forked":"0"},
+            {
+              "more_hidden": true,
+              "enable_hidden": true,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":1,"is_reserved":1,"is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":1,"is_reserved":1},
+            {
+              "more_hidden": true,
+              "enable_hidden": true,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":1,"is_reserved":"0","is_forked":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":1,"is_reserved":"0","is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":1,"is_reserved":"0","is_forked":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":1,"is_reserved":"0","is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":1,"is_reserved":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":1,"is_reserved":"1","is_forked":0},
+            {
+              "more_hidden": true,
+              "enable_hidden": true,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":1,"is_reserved":"1","is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":1,"is_reserved":"1","is_forked":"0"},
+            {
+              "more_hidden": true,
+              "enable_hidden": true,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":1,"is_reserved":"1","is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":1,"is_reserved":"1"},
+            {
+              "more_hidden": true,
+              "enable_hidden": true,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":1,"is_forked":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":1,"is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":1,"is_forked":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":1,"is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"0","is_reserved":0,"is_forked":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"0","is_reserved":0,"is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"0","is_reserved":0,"is_forked":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"0","is_reserved":0,"is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"0","is_reserved":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"0","is_reserved":1,"is_forked":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":"0","is_reserved":1,"is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":"0","is_reserved":1,"is_forked":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":"0","is_reserved":1,"is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":"0","is_reserved":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":"0","is_reserved":"0","is_forked":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"0","is_reserved":"0","is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"0","is_reserved":"0","is_forked":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"0","is_reserved":"0","is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"0","is_reserved":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"0","is_reserved":"1","is_forked":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":"0","is_reserved":"1","is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":"0","is_reserved":"1","is_forked":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":"0","is_reserved":"1","is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":"0","is_reserved":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":"0","is_forked":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"0","is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"0","is_forked":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"0","is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"1","is_reserved":0,"is_forked":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"1","is_reserved":0,"is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"1","is_reserved":0,"is_forked":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"1","is_reserved":0,"is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"1","is_reserved":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"1","is_reserved":1,"is_forked":0},
+            {
+              "more_hidden": true,
+              "enable_hidden": true,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":"1","is_reserved":1,"is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":"1","is_reserved":1,"is_forked":"0"},
+            {
+              "more_hidden": true,
+              "enable_hidden": true,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":"1","is_reserved":1,"is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":"1","is_reserved":1},
+            {
+              "more_hidden": true,
+              "enable_hidden": true,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":"1","is_reserved":"0","is_forked":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"1","is_reserved":"0","is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"1","is_reserved":"0","is_forked":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"1","is_reserved":"0","is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"1","is_reserved":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"1","is_reserved":"1","is_forked":0},
+            {
+              "more_hidden": true,
+              "enable_hidden": true,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":"1","is_reserved":"1","is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":"1","is_reserved":"1","is_forked":"0"},
+            {
+              "more_hidden": true,
+              "enable_hidden": true,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":"1","is_reserved":"1","is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":"1","is_reserved":"1"},
+            {
+              "more_hidden": true,
+              "enable_hidden": true,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_active":"1","is_forked":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"1","is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"1","is_forked":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"1","is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_active":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": true,
+              "disable_hidden": false,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_reserved":0,"is_forked":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_reserved":0,"is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_reserved":0,"is_forked":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_reserved":0,"is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_reserved":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_reserved":1,"is_forked":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_reserved":1,"is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_reserved":1,"is_forked":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_reserved":1,"is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_reserved":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_reserved":"0","is_forked":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_reserved":"0","is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_reserved":"0","is_forked":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_reserved":"0","is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_reserved":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_reserved":"1","is_forked":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_reserved":"1","is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_reserved":"1","is_forked":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_reserved":"1","is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_reserved":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": true
+            }
+          ],
+
+          [
+            {"is_forked":0},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_forked":1},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_forked":"0"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {"is_forked":"1"},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": false,
+              "delete_hidden": false
+            }
+          ],
+
+          [
+            {},
+            {
+              "more_hidden": false,
+              "enable_hidden": false,
+              "disable_hidden": true,
+              "revert_hidden": true,
+              "delete_hidden": false
+            }
+          ],
+        ];
+        caseTypeSimulations.forEach(function(simulation) {
+          doTest(simulation[0], simulation[1]);
+        });
+      });
+    });
   });
+
 });
index 890a2854a8dcc6870fb4dc2a075d02206884b0c5..236be3c440f628a1bf98b52ecec3f4c7345d4be7 100644 (file)
@@ -331,18 +331,36 @@ class CRM_Activity_BAO_ActivityTest extends CiviUnitTestCase {
 
   /**
    * Test getActivities BAO method for getting count.
+   *
    */
   public function testGetActivitiesCountForAdminDashboard() {
+    // Reset to default
+    $this->setShowCaseActivitiesInCore(FALSE);
     $this->setUpForActivityDashboardTests();
+    $this->addCaseWithActivity();
+    CRM_Core_Config::singleton()->userPermissionClass->permissions[] = 'access all cases and activities';
+
     $activityCount = CRM_Activity_BAO_Activity::getActivitiesCount($this->_params);
     $this->assertEquals(8, $activityCount);
+
+    // If we're showing case activities, we exepct to see one more (the scheduled meeting)...
+    $this->setShowCaseActivitiesInCore(TRUE);
+    $activityCount = CRM_Activity_BAO_Activity::getActivitiesCount($this->_params);
+    $this->assertEquals(9, $activityCount);
+    // Reset to default
+    $this->setShowCaseActivitiesInCore(FALSE);
   }
 
   /**
    * Test getActivities BAO method for getting count
+   *
    */
   public function testGetActivitiesCountforNonAdminDashboard() {
+    // Reset to default
+    $this->setShowCaseActivitiesInCore(FALSE);
     $this->createTestActivities();
+    $this->addCaseWithActivity();
+    CRM_Core_Config::singleton()->userPermissionClass->permissions[] = 'access all cases and activities';
 
     $params = [
       'contact_id' => 9,
@@ -358,15 +376,27 @@ class CRM_Activity_BAO_ActivityTest extends CiviUnitTestCase {
     ];
 
     //since we are loading activities from dataset, we know total number of activities for this contact
-    // 5 activities ( 2 scheduled, 3 Completed ), note that dashboard shows only scheduled activities
+    // 5 activities ( 2 scheduled, 3 Completed, 1 Scheduled Case activity ),
+    // note that dashboard shows only scheduled activities
     $this->assertEquals(2, CRM_Activity_BAO_Activity::getActivitiesCount($params));
+
+    // If we're showing case activities, we exepct to see one more (the scheduled meeting)...
+    $this->setShowCaseActivitiesInCore(TRUE);
+    $this->assertEquals(3, CRM_Activity_BAO_Activity::getActivitiesCount($params));
+    // Reset to default
+    $this->setShowCaseActivitiesInCore(FALSE);
   }
 
   /**
    * Test getActivities BAO method for getting count
+   *
    */
   public function testGetActivitiesCountforContactSummary() {
+    // Reset to default
+    $this->setShowCaseActivitiesInCore(FALSE);
     $this->createTestActivities();
+    $this->addCaseWithActivity();
+    CRM_Core_Config::singleton()->userPermissionClass->permissions[] = 'access all cases and activities';
 
     $params = [
       'contact_id' => 9,
@@ -380,8 +410,14 @@ class CRM_Activity_BAO_ActivityTest extends CiviUnitTestCase {
     ];
 
     //since we are loading activities from dataset, we know total number of activities for this contact
-    // 5 activities, Contact Summary should show all activities
+    // 5 activities
     $this->assertEquals(5, CRM_Activity_BAO_Activity::getActivitiesCount($params));
+
+    // If we're showing case activities, we exepct to see one more (the scheduled meeting)...
+    $this->setShowCaseActivitiesInCore(TRUE);
+    $this->assertEquals(6, CRM_Activity_BAO_Activity::getActivitiesCount($params));
+    // Reset to default
+    $this->setShowCaseActivitiesInCore(FALSE);
   }
 
   /**
@@ -447,7 +483,11 @@ class CRM_Activity_BAO_ActivityTest extends CiviUnitTestCase {
    * Test getActivities BAO method.
    */
   public function testGetActivitiesForAdminDashboard() {
+    $this->setShowCaseActivitiesInCore(FALSE);
     $this->setUpForActivityDashboardTests();
+    $this->addCaseWithActivity();
+    CRM_Core_Config::singleton()->userPermissionClass->permissions[] = 'access all cases and activities';
+
     $activitiesNew = CRM_Activity_BAO_Activity::getActivities($this->_params);
     // $this->assertEquals($activities, $activitiesDeprecatedFn);
 
@@ -463,6 +503,16 @@ class CRM_Activity_BAO_ActivityTest extends CiviUnitTestCase {
         $this->assertEquals($value['status_id'], 1, 'Verify all activities are scheduled.');
       }
     }
+
+    // Now check that we get the scheduled meeting, if civicaseShowCaseActivities is set.
+    $this->setShowCaseActivitiesInCore(TRUE);
+    $activitiesNew = CRM_Activity_BAO_Activity::getActivities($this->_params);
+    $this->assertEquals(9, count($activitiesNew));
+    // Scan through to find the meeting.
+    $this->assertTrue(in_array('test meeting activity', array_column($activitiesNew, 'subject')),
+      "failed to find scheduled case Meeting activity");
+    // Reset to default
+    $this->setShowCaseActivitiesInCore(FALSE);
   }
 
   /**
@@ -492,7 +542,10 @@ class CRM_Activity_BAO_ActivityTest extends CiviUnitTestCase {
    * Test getActivities BAO method.
    */
   public function testGetActivitiesforNonAdminDashboard() {
+    $this->setShowCaseActivitiesInCore(FALSE);
     $this->createTestActivities();
+    $this->addCaseWithActivity();
+    CRM_Core_Config::singleton()->userPermissionClass->permissions[] = 'access all cases and activities';
 
     $contactID = 9;
     $params = [
@@ -527,6 +580,17 @@ class CRM_Activity_BAO_ActivityTest extends CiviUnitTestCase {
         }
       }
     }
+
+    // Now check that we get the scheduled meeting, if civicaseShowCaseActivities is set.
+    $this->setShowCaseActivitiesInCore(TRUE);
+    $activities = CRM_Activity_BAO_Activity::getActivities($params);
+    $this->assertEquals(3, count($activities));
+    // Scan through to find the meeting.
+    $this->assertTrue(in_array('test meeting activity', array_column($activities, 'subject')),
+      "failed to find scheduled case Meeting activity");
+
+    // Reset to default
+    $this->setShowCaseActivitiesInCore(FALSE);
   }
 
   /**
@@ -586,7 +650,11 @@ class CRM_Activity_BAO_ActivityTest extends CiviUnitTestCase {
    * Test getActivities BAO method.
    */
   public function testGetActivitiesForContactSummary() {
+    // Reset to default
+    $this->setShowCaseActivitiesInCore(FALSE);
     $this->createTestActivities();
+    $this->addCaseWithActivity();
+    CRM_Core_Config::singleton()->userPermissionClass->permissions[] = 'access all cases and activities';
 
     $contactID = 9;
     $params = [
@@ -635,12 +703,24 @@ class CRM_Activity_BAO_ActivityTest extends CiviUnitTestCase {
         $this->assertArrayHasKey($contactID, $value['assignee_contact_name']);
       }
     }
+
+    // Now check that we get the scheduled meeting, if civicaseShowCaseActivities is set.
+    $this->setShowCaseActivitiesInCore(TRUE);
+    $activities = CRM_Activity_BAO_Activity::getActivities($params);
+    $this->assertEquals(6, count($activities));
+    // Scan through to find the meeting.
+    $this->assertTrue(in_array('test meeting activity', array_column($activities, 'subject')),
+      "failed to find scheduled case Meeting activity");
+    // Reset to default
+    $this->setShowCaseActivitiesInCore(FALSE);
   }
 
   /**
    * Test getActivities BAO method.
    */
   public function testGetActivitiesforContactSummaryWithActivities() {
+    // Reset to default
+    $this->setShowCaseActivitiesInCore(FALSE);
     $this->createTestActivities();
 
     // parameters for different test cases, check each array key for the specific test-case
@@ -1417,4 +1497,95 @@ $text
     $mut->stop();
   }
 
+  /**
+   * Adds a case with one activity.
+   *
+   */
+  protected function addCaseWithActivity() {
+    // case is not enabled by default do that now.
+    $enableResult = CRM_Core_BAO_ConfigSetting::enableComponent('CiviCase');
+    $this->assertTrue($enableResult, 'Cannot enable CiviCase in line ' . __LINE__);
+
+    // We need a minimal case setup.
+    $case_type_id = civicrm_api3('CaseType', 'get', ['return' => 'id', 'name' => 'test_case_type'])['id'] ?? NULL;
+    if (!$case_type_id) {
+      $params = [
+        'name'  => 'test_case_type',
+        'title' => 'test_case_type',
+        "is_active" => "1",
+        "definition" => [
+          "activityTypes" => [
+            ["name" => "Open Case", "max_instances" => "1"],
+            ["name" => "Meeting"],
+          ],
+          "activitySets" => [
+            [
+              "name" => "standard_timeline",
+              "label" => "Standard Timeline",
+              "timeline" => "1",
+              "activityTypes" => [
+                [
+                  "name" => "Open Case",
+                  "status" => "Completed",
+                  "label" => "Open Case",
+                  "default_assignee_type" => "1",
+                ],
+              ],
+            ],
+          ],
+          "timelineActivityTypes" => [
+            [
+              "name" => "Open Case",
+              "status" => "Completed",
+              "label" => "Open Case",
+              "default_assignee_type" => "1",
+            ],
+          ],
+          "caseRoles" => [
+            [
+              "name" => "Case Coordinator",
+              "creator" => "1",
+              "manager" => "1",
+            ],
+          ],
+        ],
+      ];
+      $case_type_id = $this->callAPISuccess('CaseType', 'create', $params)['id'];
+    }
+
+    // Create a case with Contact #3 as the client.
+    $case_id = civicrm_api3('case', 'get', ['subject' => 'test case 1'])['id'] ?? NULL;
+    if (!$case_id) {
+      // Create case
+      $params = [
+        'subject'       => 'test case 1',
+        'contact_id'    => 3,
+        'status_id'     => 'Open',
+        'case_type_id'  => $case_type_id,
+        'creator_id'    => 3,
+      ];
+      $case_id = $this->callAPISuccess('case', 'create', $params)['id'];
+    }
+
+    // Create a scheduled 'Meeting' activity that belongs to this case, but is
+    // assigned to contact #9
+    $activity_id = $this->callAPISuccess('Activity', 'create', [
+      'activity_type_id' => 'Meeting',
+      'status_id' => 'Scheduled',
+      'case_id' => $case_id,
+      'source_contact_id' => 3,
+      'assignee_id' => [9],
+      'subject' => 'test meeting activity',
+    ])['id'] ?? NULL;
+  }
+
+  /**
+   * Change setting, and the cache of it.
+   */
+  protected function setShowCaseActivitiesInCore(bool $val) {
+    Civi::settings()->set('civicaseShowCaseActivities', $val ? 1 : 0);
+    CRM_Core_Component::getEnabledComponents();
+    Civi::$statics['CRM_Core_Component']['info']['CiviCase']->info['showActivitiesInCore'] = $val;
+  }
+
 }
index 7daf34e7eb032e5a80d07e2565844d245c6cba5e..ab28f9bd7ed2394d332bc4343542b7bad69ec06f 100644 (file)
@@ -55,7 +55,7 @@ class CRM_Activity_Selector_SearchTest extends CiviUnitTestCase {
         'name' => 'source_contact',
         'sort' => 'source_contact',
         'direction' => 4,
-        'title' => 'Added By',
+        'title' => 'Added by',
       ],
       5 => [
         'name' => 'activity_status',
index e199f656839c6cb05a33dd9e22e1e1394d1cefb9..78021056c904f96adb3b014e9ca8d47d05ae60c5 100644 (file)
@@ -71,6 +71,60 @@ class CRM_Case_XMLProcessor_ReportTest extends CiviCaseTestCase {
     }
   }
 
+  /**
+   * This is similar to testGetCaseReport but test with a timeline that
+   * does have Meeting in it.
+   */
+  public function testGetCaseReportWithMeetingInTimeline() {
+    $client_id = $this->individualCreate([
+      'first_name' => 'Casey',
+      'middle_name' => '',
+      'last_name' => 'Reportee',
+      'prefix_id' => NULL,
+      'suffix_id' => NULL,
+    ]);
+    $caseObj = $this->createCase($client_id, $this->_loggedInUser);
+    $case_id = $caseObj->id;
+
+    // Now update the timeline so it has Meeting in it.
+    $this->addMeetingToTimeline();
+
+    // Add a meeting activity to the case.
+    $meetingTypeId = $this->callAPISuccess('OptionValue', 'getsingle', [
+      'return' => ["value"],
+      'option_group_id' => 'activity_type',
+      'name' => 'Meeting',
+    ]);
+    $this->callAPISuccess('activity', 'create', [
+      'case_id' => $case_id,
+      'activity_type_id' => $meetingTypeId['value'],
+      'activity_date_time' => '20191114123456',
+      'subject' => 'Test Meeting',
+      'source_contact_id' => $this->_loggedInUser,
+      'target_contact_id' => $client_id,
+    ]);
+
+    $caseReportParams = [
+      'is_redact' => FALSE,
+      'include_activities' => 1,
+    ];
+
+    // run the thing we're testing and get the output vars
+    $template = CRM_Case_XMLProcessor_Report::populateCaseReportTemplate($client_id, $case_id, 'standard_timeline', $caseReportParams, $this->report);
+    $assigned_vars = $template->get_template_vars();
+
+    // We don't want to run all the data in the dataprovider but we know
+    // in this case it should be the same as the second one in the
+    // dataprovider so we can reuse it.
+    $expected = $this->caseReportDataProvider()[1][1];
+    $this->updateExpectedBecauseDataProviderEvaluatesBeforeEverything($expected, $client_id, $case_id);
+
+    foreach ($expected as $key => $value) {
+      // does the assigned template var match the expected value?
+      $this->assertEquals($value, $assigned_vars[$key], "$key does not match" . print_r($assigned_vars[$key], TRUE));
+    }
+  }
+
   /**
    * Data provider for testGetCaseReport
    * @return array
@@ -80,7 +134,9 @@ class CRM_Case_XMLProcessor_ReportTest extends CiviCaseTestCase {
       [
         // activity set name
         'standard_timeline',
-        // some expected assigned vars of CRM_Core_Smarty template
+        // Some expected assigned vars of CRM_Core_Smarty template.
+        // In particular we shouldn't have meeting in the output since it's
+        // not in the timeline.
         [
           'case' => [
             'clientName' => 'Casey Reportee',
@@ -219,7 +275,8 @@ class CRM_Case_XMLProcessor_ReportTest extends CiviCaseTestCase {
       [
         // activity set name is blank here, meaning don't filter the activities
         '',
-        // some expected assigned vars of CRM_Core_Smarty template
+        // Some expected assigned vars of CRM_Core_Smarty template.
+        // In particular now we will have Meeting in the output.
         [
           'case' => [
             'clientName' => 'Casey Reportee',
@@ -481,4 +538,20 @@ class CRM_Case_XMLProcessor_ReportTest extends CiviCaseTestCase {
     $this->callAPISuccess('CaseType', 'create', $caseType);
   }
 
+  /**
+   * Add Meeting to the standard timeline.
+   */
+  private function addMeetingToTimeline() {
+    $caseType = $this->callAPISuccess('CaseType', 'getsingle', ['id' => $this->caseTypeId]);
+    $activityTypes = $caseType['definition']['activitySets'][0]['activityTypes'];
+    // Make a copy of the second activity type and change the type.
+    $activityType = $activityTypes[1];
+    $activityType['name'] = 'Meeting';
+    $activityType['label'] = 'Meeting';
+
+    $activityTypes[] = $activityType;
+    $caseType['definition']['activitySets'][0]['activityTypes'] = $activityTypes;
+    $this->callAPISuccess('CaseType', 'create', $caseType);
+  }
+
 }
index 5c6d66f1a3e74459e2a15bab2f7c336262937c28..52be41042974b257ece1b7c5b06cfc4a7b8caf54 100644 (file)
@@ -672,21 +672,6 @@ class CRM_Contribute_BAO_ContributionTest extends CiviUnitTestCase {
     $this->assertEquals(2, $financialTrxn->N, 'Mismatch count for is payment flag.');
   }
 
-  /**
-   * addPayments() method (add and edit modes of participant).
-   *
-   * Add Payments is part of an old, flawed, code flow.
-   */
-  public function testAddPayments() {
-    $contribution = $this->addParticipantWithContribution();
-    // Delete existing financial_trxns. This is because we are testing a code flow we
-    // want to deprecate & remove & the test relies on bad data asa starting point.
-    // End goal is the Order.create->Payment.create flow.
-    CRM_Core_DAO::executeQuery('DELETE FROM civicrm_entity_financial_trxn WHERE entity_table = "civicrm_financial_item"');
-    CRM_Contribute_BAO_Contribution::addPayments($contribution);
-    $this->checkItemValues($contribution);
-  }
-
   /**
    * checks db values for financial item
    */
index 02e42c062b789819be8d47967f7526bce1c37179..753f684e71b4b67bb611bc372a661b87f886503f 100644 (file)
@@ -179,6 +179,41 @@ class CRM_Contribute_Import_Parser_ContributionTest extends CiviUnitTestCase {
     $this->assertEquals('20191020000000', $formatted[$this->getCustomFieldName('date')]);
   }
 
+  /**
+   * Test phone is included if it is part of dedupe rule.
+   *
+   * @throws \CRM_Core_Exception
+   */
+  public function testPhoneMatchOnContact() {
+    // Update existing unsupervised rule, change to general.
+    $unsupervisedRuleGroup = $this->callApiSuccess('RuleGroup', 'getsingle', [
+      'used' => 'Unsupervised',
+      'contact_type' => 'Individual',
+    ]);
+    $this->callApiSuccess('RuleGroup', 'create', [
+      'id' => $unsupervisedRuleGroup['id'],
+      'used' => 'General',
+    ]);
+
+    // Create new unsupervised rule with Phone field.
+    $ruleGroup = $this->callAPISuccess('RuleGroup', 'create', [
+      'contact_type' => 'Individual',
+      'threshold' => 10,
+      'used' => 'Unsupervised',
+      'name' => 'MatchingPhone',
+      'title' => 'Matching Phone',
+      'is_reserved' => 0,
+    ]);
+    $this->callAPISuccess('Rule', 'create', [
+      'dedupe_rule_group_id' => $ruleGroup['id'],
+      'rule_table' => 'civicrm_phone',
+      'rule_weight' => 10,
+      'rule_field' => 'phone_numeric',
+    ]);
+    $fields = CRM_Contribute_BAO_Contribution::importableFields();
+    $this->assertTrue(array_key_exists('phone', $fields));
+  }
+
   /**
    * Run the import parser.
    *
diff --git a/tests/phpunit/CRM/Core/FormTest.php b/tests/phpunit/CRM/Core/FormTest.php
new file mode 100644 (file)
index 0000000..39dc9fa
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @group headless
+ */
+class CRM_Core_FormTest extends CiviUnitTestCase {
+
+  /**
+   * Simulate opening various forms. All we're looking to do here is
+   * see if any warnings or notices come up, the equivalent of red boxes
+   * on the screen, but which are hidden when using popup forms.
+   * So no assertions required.
+   *
+   * @param string $classname
+   * @dataProvider formClassList
+   */
+  public function testOpeningForms(string $classname) {
+    $form = $this->getFormObject($classname);
+    $form->preProcess();
+    $form->buildQuickForm();
+    $form->setDefaultValues();
+    $form->assign('action', CRM_Core_Action::UPDATE);
+    $form->getTemplate()->fetch($form->getTemplateFileName());
+  }
+
+  /**
+   * Dataprovider for testOpeningForms().
+   * TODO: Add more forms! Use a descriptive array key so when it fails
+   * it will make it clearer what form it is, although you'll see the class
+   * anyway.
+   */
+  public function formClassList() {
+    return [
+      'Add New Tag' => ['CRM_Tag_Form_Edit'],
+    ];
+  }
+
+}
index 0666a70854c47071e023147ff864ed3e5970407b..0e5f599a35c31a3a924771629e0e172565bc516f 100644 (file)
@@ -22,6 +22,8 @@ class CRM_Dedupe_DedupeFinderTest extends CiviUnitTestCase {
 
   /**
    * Clean up after the test.
+   *
+   * @throws \CRM_Core_Exception
    */
   public function tearDown() {
 
@@ -60,6 +62,8 @@ class CRM_Dedupe_DedupeFinderTest extends CiviUnitTestCase {
 
   /**
    * Test duplicate contact retrieval with 2 email fields.
+   *
+   * @throws \CRM_Core_Exception
    */
   public function testUnsupervisedWithTwoEmailFields() {
     $this->setupForGroupDedupe();
@@ -84,6 +88,8 @@ class CRM_Dedupe_DedupeFinderTest extends CiviUnitTestCase {
    * Test that a rule set to is_reserved = 0 works.
    *
    * There is a different search used dependent on this variable.
+   *
+   * @throws \CRM_Core_Exception
    */
   public function testCustomRule() {
     $this->setupForGroupDedupe();
@@ -113,6 +119,8 @@ class CRM_Dedupe_DedupeFinderTest extends CiviUnitTestCase {
 
   /**
    * Test a custom rule with a non-default field.
+   *
+   * @throws \CRM_Core_Exception
    */
   public function testCustomRuleWithAddress() {
     $this->setupForGroupDedupe();
@@ -142,6 +150,8 @@ class CRM_Dedupe_DedupeFinderTest extends CiviUnitTestCase {
 
   /**
    * Test rule from Richard
+   *
+   * @throws \CRM_Core_Exception
    */
   public function testRuleThreeContactFieldsEqualWeightWIthThresholdtheTotalSumOfAllWeight() {
     $this->setupForGroupDedupe();
@@ -164,11 +174,13 @@ class CRM_Dedupe_DedupeFinderTest extends CiviUnitTestCase {
       ]);
     }
     $foundDupes = CRM_Dedupe_Finder::dupesInGroup($ruleGroup['id'], $this->groupID);
-    $this->assertEquals(1, count($foundDupes));
+    $this->assertCount(1, $foundDupes);
   }
 
   /**
    * Test a custom rule with a non-default field.
+   *
+   * @throws \CRM_Core_Exception
    */
   public function testInclusiveRule() {
     $this->setupForGroupDedupe();
@@ -191,7 +203,7 @@ class CRM_Dedupe_DedupeFinderTest extends CiviUnitTestCase {
       ]);
     }
     $foundDupes = CRM_Dedupe_Finder::dupesInGroup($ruleGroup['id'], $this->groupID);
-    $this->assertEquals(4, count($foundDupes));
+    $this->assertCount(4, $foundDupes);
     CRM_Dedupe_Finder::dupes($ruleGroup['id']);
   }
 
@@ -215,6 +227,8 @@ class CRM_Dedupe_DedupeFinderTest extends CiviUnitTestCase {
 
   /**
    * Test dupesByParams function.
+   *
+   * @throws \CRM_Core_Exception
    */
   public function testDupesByParams() {
     // make dupe checks based on based on following contact sets:
@@ -346,6 +360,8 @@ class CRM_Dedupe_DedupeFinderTest extends CiviUnitTestCase {
 
   /**
    * Set up a group of dedupable contacts.
+   *
+   * @throws \CRM_Core_Exception
    */
   protected function setupForGroupDedupe() {
     $params = [
index 399a8a927d76ab4a3dfb8c8a91d295dac266ed25..79f7ee481cd3b67859e3a08619de10d073786a93 100644 (file)
@@ -340,11 +340,11 @@ class CRM_Event_Form_ParticipantTest extends CiviUnitTestCase {
       $event = $this->eventCreate($eventParams);
     }
 
-    $contactID = $this->individualCreate();
+    $this->ids['contact']['event'] = (int) $this->individualCreate();
     /** @var CRM_Event_Form_Participant $form */
     $form = $this->getFormObject('CRM_Event_Form_Participant');
     $form->_single = TRUE;
-    $form->_contactID = $form->_contactId = $contactID;
+    $form->_contactID = $form->_contactId = $this->ids['contact']['event'];
     $form->setCustomDataTypes();
     $form->_eventId = $event['id'];
     if (!empty($eventParams['is_monetary'])) {
@@ -547,7 +547,6 @@ class CRM_Event_Form_ParticipantTest extends CiviUnitTestCase {
    * @param bool $isQuickConfig
    *
    * @throws \CRM_Core_Exception
-   * @throws \CiviCRM_API3_Exception
    */
   public function testSubmitPartialPayment($isQuickConfig) {
     $mut = new CiviMailUtils($this, TRUE);
@@ -573,7 +572,7 @@ class CRM_Event_Form_ParticipantTest extends CiviUnitTestCase {
       'hidden_custom' => '1',
       'hidden_custom_group_count' => ['' => 1],
       'custom_4_-1' => '',
-      'contact_id' => $form->_contactID,
+      'contact_id' => $this->getContactID(),
       'event_id' => $this->getEventID(),
       'campaign_id' => '',
       'register_date' => '2020-01-31 00:50:00',
@@ -584,12 +583,80 @@ class CRM_Event_Form_ParticipantTest extends CiviUnitTestCase {
       'MAX_FILE_SIZE' => '33554432',
     ];
     $form->submit($submitParams);
+    $this->assertPartialPaymentResult($isQuickConfig, $mut);
+  }
+
+  /**
+   * Test submitting a partially paid event registration, recording a pending contribution.
+   *
+   * This tests
+   *
+   * @dataProvider getBooleanDataProvider
+   *
+   * @param bool $isQuickConfig
+   *
+   * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
+   */
+  public function testSubmitPendingPartiallyPaidAddPayment($isQuickConfig) {
+    $mut = new CiviMailUtils($this, TRUE);
+    $form = $this->getForm(['is_monetary' => 1]);
+    $this->callAPISuccess('PriceSet', 'create', ['is_quick_config' => $isQuickConfig, 'id' => $this->getPriceSetID()]);
+    $paymentInstrumentID = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', 'Check');
+    $submitParams = $this->getRecordContributionParams('Partially paid', $form);
+    $form->submit($submitParams);
+    $this->callAPISuccess('Payment', 'create', [
+      'contribution_id' => $this->callAPISuccessGetValue('Contribution', ['return' => 'id']),
+      'total_amount'  => 20,
+      'check_number' => 879,
+      'payment_instrument_id' => $paymentInstrumentID,
+    ]);
+    $this->assertPartialPaymentResult($isQuickConfig, $mut);
+  }
+
+  /**
+   * Test submitting a partially paid event registration, recording a pending contribution.
+   *
+   * This tests
+   *
+   * @dataProvider getBooleanDataProvider
+   *
+   * @param bool $isQuickConfig
+   *
+   * @throws \CRM_Core_Exception
+   */
+  public function testSubmitPendingAddPayment($isQuickConfig) {
+    $mut = new CiviMailUtils($this, TRUE);
+    $form = $this->getForm(['is_monetary' => 1]);
+    $this->callAPISuccess('PriceSet', 'create', ['is_quick_config' => $isQuickConfig, 'id' => $this->getPriceSetID()]);
+    $paymentInstrumentID = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', 'Check');
+    $submitParams = $this->getRecordContributionParams('Pending from pay later', 'Pending');
+    // Create the pending contribution for the full amount to be paid.
+    $submitParams['total_amount'] = 1550.55;
+    $form->submit($submitParams);
+    $this->callAPISuccess('Payment', 'create', [
+      'contribution_id' => $this->callAPISuccessGetValue('Contribution', ['return' => 'id']),
+      'total_amount'  => 20,
+      'check_number' => 879,
+      'payment_instrument_id' => $paymentInstrumentID,
+    ]);
+    $this->assertPartialPaymentResult($isQuickConfig, $mut, FALSE);
+  }
+
+  /**
+   * @param bool $isQuickConfig
+   * @param \CiviMailUtils $mut
+   * @param bool $isAmountPaidOnForm
+   *   Was the amount paid entered on the form (if so this should be on the receipt)
+   */
+  protected function assertPartialPaymentResult($isQuickConfig, CiviMailUtils $mut, $isAmountPaidOnForm = TRUE) {
+    $paymentInstrumentID = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', 'Check');
     $contribution = $this->callAPISuccessGetSingle('Contribution', []);
     $expected = [
-      'contact_id' => $form->_contactID,
+      'contact_id' => $this->getContactID(),
       'total_amount' => '1550.55',
       'fee_amount' => '0.00',
-      'net_amount' => '20.00',
+      'net_amount' => '1550.55',
       'contribution_source' => 'I wrote this',
       'amount_level' => '',
       'is_template' => '0',
@@ -602,7 +669,7 @@ class CRM_Event_Form_ParticipantTest extends CiviUnitTestCase {
 
     $participant = $this->callAPISuccessGetSingle('Participant', []);
     $this->assertAttributesEquals([
-      'contact_id' => $form->_contactID,
+      'contact_id' => $this->getContactID(),
       'event_title' => 'Annual CiviCRM meet',
       'participant_fee_level' => [0 => 'big - 1'],
       'participant_fee_amount' => '1550.55',
@@ -630,18 +697,6 @@ class CRM_Event_Form_ParticipantTest extends CiviUnitTestCase {
       'tax_amount' => '0.00',
     ], $lineItem);
 
-    $financialTrxn = $this->callAPISuccessGetSingle('FinancialTrxn', ['is_payment' => 0]);
-    $this->assertAttributesEquals([
-      'to_financial_account_id' => '7',
-      'total_amount' => '1550.55',
-      'fee_amount' => '0.00',
-      'net_amount' => '1550.55',
-      'currency' => 'USD',
-      'status_id' => '1',
-      'payment_instrument_id' => $paymentInstrumentID,
-      'check_number' => '879',
-    ], $financialTrxn);
-
     $payment = $this->callAPISuccessGetSingle('FinancialTrxn', ['is_payment' => 1]);
     $this->assertAttributesEquals([
       'to_financial_account_id' => 6,
@@ -658,10 +713,10 @@ class CRM_Event_Form_ParticipantTest extends CiviUnitTestCase {
     $financialItem = $this->callAPISuccessGetSingle('FinancialItem', []);
     $this->assertAttributesEquals([
       'description' => 'big',
-      'contact_id' => $form->_contactID,
+      'contact_id' => $this->getContactID(),
       'amount' => 1550.55,
       'currency' => 'USD',
-      'status_id' => 2,
+      'status_id' => CRM_Core_PseudoConstant::getKey('CRM_Financial_BAO_FinancialItem', 'status_id', 'Unpaid'),
       'entity_table' => 'civicrm_line_item',
       'entity_id' => $lineItem['id'],
       'financial_account_id' => 4,
@@ -676,7 +731,7 @@ class CRM_Event_Form_ParticipantTest extends CiviUnitTestCase {
       'Annual CiviCRM meet',
       'Registered Email',
       $isQuickConfig ? $this->formatMoneyInput(1550.55) . ' big - 1' : 'Price Field - big',
-      'Total Paid: $ 20.00',
+      $isAmountPaidOnForm ? 'Total Paid: $ 20.00' : ' ',
       'Balance: $ 1,530.55',
       'Financial Type: Event Fee',
       'Paid By: Check',
@@ -720,6 +775,47 @@ class CRM_Event_Form_ParticipantTest extends CiviUnitTestCase {
     return (int) $this->_ids['price_field_value'][1];
   }
 
+  /**
+   * Get the parameters for recording a contribution.
+   *
+   * @param string $participantStatus
+   * @param string $contributionStatus
+   *
+   * @return array
+   */
+  protected function getRecordContributionParams($participantStatus, $contributionStatus): array {
+    $submitParams = [
+      'hidden_feeblock' => '1',
+      'hidden_eventFullMsg' => '',
+      'priceSetId' => $this->getPriceSetID(),
+      $this->getPriceFieldKey() => $this->getPriceFieldValueID(),
+      'check_number' => '879',
+      'record_contribution' => '1',
+      'financial_type_id' => '4',
+      'receive_date' => '2020-01-31 00:51:00',
+      'payment_instrument_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', 'Check'),
+      'trxn_id' => '',
+      'contribution_status_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', $contributionStatus),
+      'total_amount' => '20',
+      'send_receipt' => '1',
+      'from_email_address' => $this->getFromEmailAddress(),
+      'receipt_text' => 'Contact the Development Department if you need to make any changes to your registration.',
+      'hidden_custom' => '1',
+      'hidden_custom_group_count' => ['' => 1],
+      'custom_4_-1' => '',
+      'contact_id' => $this->getContactID(),
+      'event_id' => $this->getEventID(),
+      'campaign_id' => '',
+      'register_date' => '2020-01-31 00:50:00',
+      'role_id' => [0 => CRM_Core_PseudoConstant::getKey('CRM_Event_BAO_Participant', 'role_id', 'Attendee')],
+      'status_id' => CRM_Core_PseudoConstant::getKey('CRM_Event_BAO_Participant', 'status_id', $participantStatus),
+      'source' => 'I wrote this',
+      'note' => 'I wrote a note',
+      'MAX_FILE_SIZE' => '33554432',
+    ];
+    return $submitParams;
+  }
+
   /**
    * Get the id of the created event.
    *
@@ -729,4 +825,13 @@ class CRM_Event_Form_ParticipantTest extends CiviUnitTestCase {
     return $this->ids['event']['event'];
   }
 
+  /**
+   * Get created contact ID.
+   *
+   * @return int
+   */
+  protected function getContactID(): int {
+    return $this->ids['contact']['event'];
+  }
+
 }
index bbe4aeed1e88898e0b85e3b2a09979b486fe8e8b..da9ba2c61eaf497f6765b56375bd344198a55187 100644 (file)
@@ -124,6 +124,11 @@ class CRM_Extension_MapperTest extends CiviUnitTestCase {
     }
   }
 
+  public function testGetKeysByTag() {
+    $this->assertEquals([], $this->mapper->getKeysByTag('big-rock-candy-mountain'));
+    $this->assertEquals(['test.foo.bar'], $this->mapper->getKeysByTag('wakka'));
+  }
+
   /**
    * @param CRM_Utils_Cache_Interface $cache
    * @param null $cacheKey
@@ -143,7 +148,7 @@ class CRM_Extension_MapperTest extends CiviUnitTestCase {
     $basedir = rtrim($this->createTempDir('ext-'), '/');
     mkdir("$basedir/weird");
     mkdir("$basedir/weird/foobar");
-    file_put_contents("$basedir/weird/foobar/info.xml", "<extension key='test.foo.bar' type='report'><file>oddball</file></extension>");
+    file_put_contents("$basedir/weird/foobar/info.xml", "<extension key='test.foo.bar' type='report'><file>oddball</file><tags><tag>wakka</tag></tags></extension>");
     // not needed for now // file_put_contents("$basedir/weird/bar/oddball.php", "<?php\n");
     $c = new CRM_Extension_Container_Basic($basedir . $appendPathGarbage, 'http://example/basedir' . $appendPathGarbage, $cache, $cacheKey);
     return [$basedir, $c];
index 0a921a6ec4b7f6546aa2c974646e3d9c94a84ad5..675349f222c138c1f35331d93135279a467aa435 100644 (file)
@@ -58,7 +58,6 @@ class CRM_Financial_BAO_PaymentProcessorTest extends CiviUnitTestCase {
     $liveProcessorID = $testProcessorID + 1;
 
     $processors = CRM_Financial_BAO_PaymentProcessor::getPaymentProcessors(['BackOffice', 'TestMode']);
-    $this->markTestIncomplete('Not working yet :-(');
     $this->assertEquals([$testProcessorID, 0], array_keys($processors), 'Only the test processor and the manual processor should be returned');
 
     $processors = CRM_Financial_BAO_PaymentProcessor::getPaymentProcessors(['BackOffice', 'TestMode'], [$liveProcessorID]);
@@ -72,7 +71,6 @@ class CRM_Financial_BAO_PaymentProcessorTest extends CiviUnitTestCase {
 
     $processors = CRM_Financial_BAO_PaymentProcessor::getPaymentProcessors(['BackOffice', 'LiveMode'], [$liveProcessorID]);
     $this->assertEquals([$liveProcessorID], array_keys($processors), 'Only the Live processor should be returned');
-
   }
 
 }
index 08b49429396293337c6920c399844d783ed3c8e9..f8b57375eb664384dd7b869ba18a1d28b511a2bb 100644 (file)
@@ -291,6 +291,9 @@ class CRM_Member_BAO_MembershipTest extends CiviUnitTestCase {
     $this->assertDBNull('CRM_Member_BAO_Membership', $contactId, 'id',
       'contact_id', 'Database check for deleted membership.'
     );
+    $this->assertDBNull('CRM_Price_BAO_LineItem', $membershipId, 'id',
+      'entity_id', 'Database check for deleted line item.'
+    );
     $this->contactDelete($contactId);
   }
 
diff --git a/tests/phpunit/CRM/Utils/Mail/FilteredPearMailerTest.php b/tests/phpunit/CRM/Utils/Mail/FilteredPearMailerTest.php
new file mode 100644 (file)
index 0000000..56b257c
--- /dev/null
@@ -0,0 +1,54 @@
+<?php
+
+/**
+ * Class CRM_Utils_Mail_FilteredPearMailerTest
+ * @group headless
+ */
+class CRM_Utils_Mail_FilteredPearMailerTest extends CiviUnitTestCase {
+
+  public function testFilter() {
+    $mock = new class() extends \Mail {
+      public $buf = [];
+
+      public function send($recipients, $headers, $body) {
+        $this->buf['recipients'] = $recipients;
+        $this->buf['headers'] = $headers;
+        $this->buf['body'] = $body;
+        return 'all the fruits in the basket';
+      }
+
+    };
+
+    $fm = new CRM_Utils_Mail_FilteredPearMailer('mock', [], $mock);
+    $fm->addFilter('1000_apple', function ($mailer, &$recipients, &$headers, &$body) {
+      $body .= ' with apples!';
+    });
+    $fm->addFilter('1000_banana', function ($mailer, &$recipients, &$headers, &$body) {
+      $headers['Banana'] = 'Cavendish';
+    });
+    $r = $fm->send(['recip'], ['Subject' => 'Fruit loops'], 'body');
+
+    $this->assertEquals('Fruit loops', $mock->buf['headers']['Subject']);
+    $this->assertEquals('Cavendish', $mock->buf['headers']['Banana']);
+    $this->assertEquals('body with apples!', $mock->buf['body']);
+    $this->assertEquals('all the fruits in the basket', $r);
+  }
+
+  public function testFilter_shortCircuit() {
+    $mock = new class() extends \Mail {
+
+      public function send($recipients, $headers, $body) {
+        return 'all the fruits in the basket';
+      }
+
+    };
+
+    $fm = new CRM_Utils_Mail_FilteredPearMailer('mock', [], $mock);
+    $fm->addFilter('1000_short_circuit', function ($mailer, &$recipients, &$headers, &$body) {
+      return 'the triumph of veggies over fruits';
+    });
+    $r = $fm->send(['recip'], ['Subject' => 'Fruit loops'], 'body');
+    $this->assertEquals('the triumph of veggies over fruits', $r);
+  }
+
+}
index 41c5e7c9857061f740751d1a6d5aea5cf1849080..ba6a3dc8ba7320686ecc688ba2a2f7de59dd0926 100644 (file)
@@ -24,12 +24,12 @@ class CRM_Utils_MoneyTest extends CiviUnitTestCase {
   public function testEquals() {
     $testValue = 0.01;
 
-    for ($i = 0; $i <= 10; $i++) {
-      $equalValues = CRM_Utils_Money::equals($testValue, $testValue + ($i * 0.0001), 'USD');
-      $this->assertTrue($equalValues);
+    for ($i = 0; $i < 10; $i++) {
+      $equalValues = CRM_Utils_Money::equals($testValue, $testValue + ($i * 0.0005), 'USD');
+      $this->assertTrue($equalValues, 'Currency - USD' . $testValue . ' is equal to USD' . ($testValue + ($i * 0.0005)));
     }
 
-    $this->assertFalse(CRM_Utils_Money::equals($testValue, $testValue + 0.001000000001, 'USD'));
+    $this->assertFalse(CRM_Utils_Money::equals($testValue + 0.004, $testValue + 0.006, 'USD'), 'Currency - USD' . ($testValue + 0.004) . ' is different to USD' . ($testValue + 0.006));
   }
 
   /**
diff --git a/tests/phpunit/CRMTraits/ACL/PermissionTrait.phpx b/tests/phpunit/CRMTraits/ACL/PermissionTrait.phpx
deleted file mode 100644 (file)
index 356a19a..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-<?php
-/*
- +--------------------------------------------------------------------+
- | 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        |
- +--------------------------------------------------------------------+
- */
-
-/**
- * Trait ACL_Permission_Trait.
- *
- * Trait for working with ACLs in tests
- */
-trait CRMTraits_ACL_PermissionTrait {
-
-  protected $allowedContactId = 0;
-  protected $allowedContacts = [];
-
-  /**
-   * All results returned.
-   *
-   * @implements CRM_Utils_Hook::aclWhereClause
-   *
-   * @param string $type
-   * @param array $tables
-   * @param array $whereTables
-   * @param int $contactID
-   * @param string $where
-   */
-  public function aclWhereHookAllResults($type, &$tables, &$whereTables, &$contactID, &$where) {
-    $where = " (1) ";
-  }
-
-  /**
-   * All but first results returned.
-   *
-   * @implements CRM_Utils_Hook::aclWhereClause
-   *
-   * @param string $type
-   * @param array $tables
-   * @param array $whereTables
-   * @param int $contactID
-   * @param string $where
-   */
-  public function aclWhereOnlySecond($type, &$tables, &$whereTables, &$contactID, &$where) {
-    $where = " contact_a.id > 1";
-  }
-
-  /**
-   * Only specified contact returned.
-   *
-   * @implements CRM_Utils_Hook::aclWhereClause
-   *
-   * @param string $type
-   * @param array $tables
-   * @param array $whereTables
-   * @param int $contactID
-   * @param string $where
-   */
-  public function aclWhereOnlyOne($type, &$tables, &$whereTables, &$contactID, &$where) {
-    $where = " contact_a.id = " . $this->allowedContactId;
-  }
-
-}
index 824e03d59f88677dfb9f27e23bbc4703979ea022..258a7bf642126dd3ff1d666626df53b1a8d616a2 100644 (file)
@@ -47,7 +47,7 @@ class PrepareEventTest extends \CiviUnitTestCase {
   public function testOnPrepare($onPrepare, $inputApiCall, $expectResult) {
     $this->dispatcher->addListener(Events::PREPARE, [$this, $onPrepare]);
     $this->kernel->registerApiProvider($this->createWidgetFrobnicateProvider());
-    $result = call_user_func_array([$this->kernel, 'run'], $inputApiCall);
+    $result = call_user_func_array([$this->kernel, 'runSafe'], $inputApiCall);
     $this->assertEquals($expectResult, $result['values']);
   }
 
index 63944f2e6da10f67420c3420f819d6972915bef9..6d8829b01d652c0100b7d89a2b6493ccaa45c010 100644 (file)
@@ -34,7 +34,7 @@ class KernelTest extends \CiviUnitTestCase {
 
   public function testNormalEvents() {
     $this->kernel->registerApiProvider($this->createWidgetFrobnicateProvider());
-    $result = $this->kernel->run('Widget', 'frobnicate', [
+    $result = $this->kernel->runSafe('Widget', 'frobnicate', [
       'version' => self::MOCK_VERSION,
     ]);
 
@@ -58,7 +58,7 @@ class KernelTest extends \CiviUnitTestCase {
     });
 
     $this->kernel->registerApiProvider($this->createWidgetFrobnicateProvider());
-    $result = $this->kernel->run('Widget', 'frobnicate', [
+    $result = $this->kernel->runSafe('Widget', 'frobnicate', [
       'version' => self::MOCK_VERSION,
     ]);
 
index be0e6821c9657faebfa018a28c25d65581b42294..3434d2cad7ec43f9fe5e8cd365d1a12269439daa 100644 (file)
@@ -37,7 +37,7 @@ class RequestTest extends \CiviUnitTestCase {
    */
   public function testCreateRequest_EntityActionMunging($input, $expected) {
     list ($inEntity, $inAction, $inVersion) = $input;
-    $apiRequest = Request::create($inEntity, $inAction, ['version' => $inVersion], NULL);
+    $apiRequest = Request::create($inEntity, $inAction, ['version' => $inVersion]);
     $this->assertEquals($expected, [$apiRequest['entity'], $apiRequest['action'], $apiRequest['version']]);
   }
 
index e1a4902218518c7762f1c6c94848b1f3d3808fa0..0934a626d2f8f5de63cd342c95473ecbbc043d00 100644 (file)
@@ -186,7 +186,7 @@ class DynamicFKAuthorizationTest extends \CiviUnitTestCase {
     $params['version'] = 3;
     $params['debug'] = 1;
     $params['check_permissions'] = 1;
-    $result = $this->kernel->run($entity, $action, $params);
+    $result = $this->kernel->runSafe($entity, $action, $params);
     $this->assertFalse((bool) $result['is_error'], print_r([
       '$entity' => $entity,
       '$action' => $action,
@@ -206,7 +206,7 @@ class DynamicFKAuthorizationTest extends \CiviUnitTestCase {
     $params['version'] = 3;
     $params['debug'] = 1;
     $params['check_permissions'] = 1;
-    $result = $this->kernel->run($entity, $action, $params);
+    $result = $this->kernel->runSafe($entity, $action, $params);
     $this->assertTrue((bool) $result['is_error'], print_r([
       '$entity' => $entity,
       '$action' => $action,
@@ -231,12 +231,12 @@ class DynamicFKAuthorizationTest extends \CiviUnitTestCase {
       'check_permissions' => 1,
     ];
     // run with permission check
-    $result = $this->kernel->run('FakeFile', 'create', $params);
+    $result = $this->kernel->runSafe('FakeFile', 'create', $params);
     $this->assertTrue((bool) $result['is_error'], 'Undelegated entity with check_permissions = 1 should fail');
     $this->assertRegExp('/Unrecognized target entity table \(civicrm_membership\)/', $result['error_message']);
     // repeat without permission check
     $params['check_permissions'] = 0;
-    $result = $this->kernel->run('FakeFile', 'create', $params);
+    $result = $this->kernel->runSafe('FakeFile', 'create', $params);
     $this->assertFalse((bool) $result['is_error'], 'Undelegated entity with check_permissions = 0 should succeed');
   }
 
index 73407752866c7224d42027aac9697e6033b8d349..2ff64e595dbdac4a5d87b4b9de1029519487c7d9 100644 (file)
@@ -163,8 +163,6 @@ class WhitelistSubscriberTest extends \CiviUnitTestCase {
               0 => ['id' => 1, 'provider' => 'cosmo spacely'],
               1 => ['id' => 5, 'provider' => 'george jetson'],
             ],
-            // This is silly:
-            'undefined_fields' => ['entity_id', 'entity_table', 'widget_id', 'api.has_parent'],
           ],
         ],
       ],
@@ -384,9 +382,8 @@ class WhitelistSubscriberTest extends \CiviUnitTestCase {
     $dispatcher->addSubscriber(new WhitelistSubscriber($whitelist));
     $dispatcher->addSubscriber(new ChainSubscriber());
 
-    $apiRequest['params']['debug'] = 1;
     $apiRequest['params']['check_permissions'] = 'whitelist';
-    $result = $kernel->run($apiRequest['entity'], $apiRequest['action'], $apiRequest['params']);
+    $result = $kernel->runSafe($apiRequest['entity'], $apiRequest['action'], $apiRequest['params']);
 
     if ($expectSuccess) {
       $this->assertAPISuccess($result);
index ce23acc46a95fafee199d690e30ca0f7b57af45b..0b153dd98da0add8bfb7acb5c1b99e3b37d93514 100644 (file)
@@ -3,7 +3,7 @@
  +--------------------------------------------------------------------+
  | CiviCRM version 5                                                  |
  +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2019                                |
+ | Copyright CiviCRM LLC (c) 2004-2020                                |
  +--------------------------------------------------------------------+
  | This file is a part of CiviCRM.                                    |
  |                                                                    |
index 32aa99e6352f8862ae4fb3570259c17f43bf8d92..f804ce26f9e284667770af401913bb35063b6e91 100644 (file)
@@ -72,7 +72,9 @@ class api_v3_ExtensionTest extends CiviUnitTestCase {
   public function testExtensionGet() {
     $result = $this->callAPISuccess('extension', 'get', ['options' => ['limit' => 0]]);
     $testExtensionResult = $this->callAPISuccess('extension', 'get', ['key' => 'test.extension.manager.paymenttest']);
-    $this->assertNotNull($result['values'][$testExtensionResult['id']]['typeInfo']);
+    $ext = $result['values'][$testExtensionResult['id']];
+    $this->assertNotNull($ext['typeInfo']);
+    $this->assertEquals(['mock'], $ext['tags']);
     $this->assertTrue($result['count'] >= 6);
   }
 
index f11fa585ccb053b54d26d1d9efba7b00bb562308..9988575b956fd211811e09389411bbb95b4c5f23 100644 (file)
@@ -95,10 +95,11 @@ class api_v3_UtilsTest extends CiviUnitTestCase {
    *   TRUE or FALSE depending on the outcome of the authorization check
    */
   public function runPermissionCheck($entity, $action, $params, $throws = FALSE) {
+    $params['version'] = 3;
     $dispatcher = new \Symfony\Component\EventDispatcher\EventDispatcher();
     $dispatcher->addSubscriber(new \Civi\API\Subscriber\PermissionCheck());
     $kernel = new \Civi\API\Kernel($dispatcher);
-    $apiRequest = \Civi\API\Request::create($entity, $action, $params, NULL);
+    $apiRequest = \Civi\API\Request::create($entity, $action, $params);
     try {
       $kernel->authorize(NULL, $apiRequest);
       return TRUE;
@@ -366,18 +367,18 @@ class api_v3_UtilsTest extends CiviUnitTestCase {
     });
     $kernel->registerApiProvider($provider);
 
-    $r1 = $kernel->run('Widget', 'get', $params);
+    $r1 = $kernel->runSafe('Widget', 'get', $params);
     $this->assertEquals(count($resultIds), $r1['count']);
     $this->assertEquals($resultIds, array_keys($r1['values']));
     $this->assertEquals($resultIds, array_values(CRM_Utils_Array::collect('snack_id', $r1['values'])));
     $this->assertEquals($resultIds, array_values(CRM_Utils_Array::collect('id', $r1['values'])));
 
-    $r2 = $kernel->run('Widget', 'get', $params + ['sequential' => 1]);
+    $r2 = $kernel->runSafe('Widget', 'get', $params + ['sequential' => 1]);
     $this->assertEquals(count($resultIds), $r2['count']);
     $this->assertEquals($resultIds, array_values(CRM_Utils_Array::collect('snack_id', $r2['values'])));
     $this->assertEquals($resultIds, array_values(CRM_Utils_Array::collect('id', $r2['values'])));
 
-    $r3 = $kernel->run('Widget', 'get', $params + ['options' => ['offset' => 1, 'limit' => 2]]);
+    $r3 = $kernel->runSafe('Widget', 'get', $params + ['options' => ['offset' => 1, 'limit' => 2]]);
     $slice = array_slice($resultIds, 1, 2);
     $this->assertEquals(count($slice), $r3['count']);
     $this->assertEquals($slice, array_values(CRM_Utils_Array::collect('snack_id', $r3['values'])));
@@ -398,7 +399,7 @@ class api_v3_UtilsTest extends CiviUnitTestCase {
     });
     $kernel->registerApiProvider($provider);
 
-    $r1 = $kernel->run('Widget', 'get', [
+    $r1 = $kernel->runSafe('Widget', 'get', [
       'version' => 3,
       'snack_id' => 'b',
       'return' => 'fruit',
@@ -406,7 +407,7 @@ class api_v3_UtilsTest extends CiviUnitTestCase {
     $this->assertAPISuccess($r1);
     $this->assertEquals(['b' => ['id' => 'b', 'fruit' => 'grape']], $r1['values']);
 
-    $r2 = $kernel->run('Widget', 'get', [
+    $r2 = $kernel->runSafe('Widget', 'get', [
       'version' => 3,
       'snack_id' => 'b',
       'return' => ['fruit', 'cheese'],
@@ -414,7 +415,7 @@ class api_v3_UtilsTest extends CiviUnitTestCase {
     $this->assertAPISuccess($r2);
     $this->assertEquals(['b' => ['id' => 'b', 'fruit' => 'grape', 'cheese' => 'cheddar']], $r2['values']);
 
-    $r3 = $kernel->run('Widget', 'get', [
+    $r3 = $kernel->runSafe('Widget', 'get', [
       'version' => 3,
       'cheese' => 'cheddar',
       'return' => ['fruit'],
index 5f200582d59bd187dc653cfdbd2e7372ffcdf52e..57bc3fd12235973427381604a1306c1c27bc7168 100644 (file)
@@ -4,7 +4,7 @@
  +--------------------------------------------------------------------+
  | CiviCRM version 5                                                  |
  +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC (c) 2004-2019                                |
+ | Copyright CiviCRM LLC (c) 2004-2020                                |
  +--------------------------------------------------------------------+
  | This file is a part of CiviCRM.                                    |
  |                                                                    |
@@ -29,7 +29,7 @@
 /**
  *
  * @package CRM
- * @copyright CiviCRM LLC (c) 2004-2019
+ * @copyright CiviCRM LLC (c) 2004-2020
  * $Id$
  *
  */
index bfe79d6ebd277eebee6a1156a6df50f9b751720d..9ee2e377e22a8201b94c10bbd8485a72ce38d56d 100755 (executable)
@@ -129,7 +129,3 @@ make_font_readme > vendor/dompdf/dompdf/lib/fonts/README.DejaVuFonts.txt
 
 # Remove debug_print_backtrace(), which can leak system details. Put backtrace in log.
 simple_replace vendor/dompdf/dompdf/lib/html5lib/TreeBuilder.php 'debug_print_backtrace();' 'CRM_Core_Error::backtrace("backTrace", TRUE);'
-
-if ! grep -q 'CRM-21395' vendor/dompdf/dompdf/src/Dompdf.php; then
-  patch vendor/dompdf/dompdf/src/Dompdf.php < tools/scripts/composer/patches/dompdf_no_block_level_parent_fix.patch
-fi
index aef79b3e305f18da8e765f522d447d1de46fd190..de72c24a7015ec0620a8346b6b2267a0e1d47906 100755 (executable)
@@ -23,20 +23,4 @@ function safe_delete() {
   done
 }
 
-
-##############################################################################
-# Add in CiviCRM custom error message for CRM-8744.
-if ! grep -q 'CRM-8744' vendor/pear/net_smtp/Net/SMTP.php; then
-  patch vendor/pear/net_smtp/Net/SMTP.php < tools/scripts/composer/patches/net-smtp-patch.txt
-fi
-if ! grep -q '@STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT' vendor/pear/net_smtp/Net/SMTP.php; then
-  patch vendor/pear/net_smtp/Net/SMTP.php < tools/scripts/composer/patches/net-smtp-tls-patch.txt
-fi
-if ! grep -q 'function __construct' vendor/pear/net_smtp/Net/SMTP.php; then
-  patch vendor/pear/net_smtp/Net/SMTP.php < tools/scripts/composer/patches/net-smtp-php7-patch.txt
-fi
-if grep -q '&Auth_SASL::factory' vendor/pear/net_smtp/Net/SMTP.php; then
-  patch vendor/pear/net_smtp/Net/SMTP.php < tools/scripts/composer/patches/net-smtp-ref-patch.txt
-fi
-
 safe_delete vendor/pear/net_smtp/{README.rst,examples,phpdoc.sh,tests}
diff --git a/tools/scripts/composer/patches/civicrm-custom-patches-zetacompoents-mail.patch b/tools/scripts/composer/patches/civicrm-custom-patches-zetacompoents-mail.patch
deleted file mode 100644 (file)
index e55de1d..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-diff --git a/tests/tutorial_examples.php b/tests/tutorial_examples.php
-index 3acadc3..06f1e71 100644
---- a/tests/tutorial_examples.php
-+++ b/tests/tutorial_examples.php
-@@ -1,5 +1,4 @@
- <?php
--declare(encoding="latin1");
- /**
-  * @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 );
-                 }
diff --git a/tools/scripts/composer/patches/dompdf_no_block_level_parent_fix.patch b/tools/scripts/composer/patches/dompdf_no_block_level_parent_fix.patch
deleted file mode 100644 (file)
index 29dd309..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-From 226061647fc7e30f99855c8b481a88f5d78f455b Mon Sep 17 00:00:00 2001
-From: Ed Preston <epreston@prestonsoft.com>
-Date: Mon, 9 Oct 2017 20:29:46 +1100
-Subject: [PATCH] Fix: Uncaught Dompdf\Exception: No block-level parent found.
- Not good
-
-Fatal error: Uncaught Dompdf\Exception: No block-level parent found.
-Not good
----
- src/Dompdf.php | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
-diff --git a/src/Dompdf.php b/src/Dompdf.php
-index 40329063..bfb1c2b1 100644
---- a/src/Dompdf.php
-+++ b/src/Dompdf.php
-@@ -490,6 +490,16 @@ public function loadHtml($str, $encoding = 'UTF-8')
-             $doc->loadHTML($str);
-             $doc->encoding = $encoding;
-+            // Remove #text children nodes in nodes that shouldn't have #CRM-21395
-+            $tag_names = array("html", "table", "tbody", "thead", "tfoot", "tr");
-+            foreach ($tag_names as $tag_name) {
-+                $nodes = $doc->getElementsByTagName($tag_name);
-+
-+                foreach ($nodes as $node) {
-+                    self::removeTextNodes($node);
-+                }
-+            }
-+
-             // If some text is before the doctype, we are in quirksmode
-             if (preg_match("/^(.+)<!doctype/i", ltrim($str), $matches)) {
-                 $quirksmode = true;
diff --git a/tools/scripts/composer/patches/net-smtp-patch.txt b/tools/scripts/composer/patches/net-smtp-patch.txt
deleted file mode 100644 (file)
index 6b12048..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
---- SMTP.php   2017-01-15 05:19:55.000000000 +1100
-+++ SMTP.php.new       2017-05-20 09:01:52.832373840 +1000
-@@ -368,8 +368,10 @@
-             return true;
-         }
-
--        return PEAR::raiseError('Invalid response code received from server',
--                                $this->_code, PEAR_ERROR_RETURN);
-+        // CRM-8744
-+        $errorMessage = 'Invalid response code received from SMTP server while sending email.  This is often caused by a misconfiguration in Outbound Email settings. Please verify the settings at Administer CiviCRM >> Global Settings >> Outbound Email (SMTP).';
-+        return PEAR::raiseError($errorMessage, $this->_code, PEAR_ERROR_RETURN);
-+
-     }
-
-     /**
diff --git a/tools/scripts/composer/patches/net-smtp-php7-patch.txt b/tools/scripts/composer/patches/net-smtp-php7-patch.txt
deleted file mode 100644 (file)
index 6ed1605..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
---- SMTP.php    2017-05-20 11:50:53.716664059 +1000
-+++ SMTP.php.new        2017-05-20 12:38:36.271530119 +1000
-@@ -167,7 +167,7 @@
-      * @access  public
-      * @since   1.0
-      */
--    function Net_SMTP($host = null, $port = null, $localhost = null,
-+    function __construct($host = null, $port = null, $localhost = null,
-         $pipelining = false, $timeout = 0, $socket_options = null)
-     {
-         if (isset($host)) {
diff --git a/tools/scripts/composer/patches/net-smtp-ref-patch.txt b/tools/scripts/composer/patches/net-smtp-ref-patch.txt
deleted file mode 100644 (file)
index 84f080d..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
---- SMTP.php   2017-06-15 20:08:34.696988543 -0700
-+++ SMTP.php.new       2017-06-15 20:08:25.951703778 -0700
-@@ -732,7 +732,8 @@
-         }
-         $challenge = base64_decode($this->_arguments[0]);
--        $digest = &Auth_SASL::factory('digest-md5');
-+        // CRM-8597
-+        $digest = Auth_SASL::factory('digest-md5');
-         $auth_str = base64_encode($digest->getResponse($uid, $pwd, $challenge,
-                                                        $this->host, "smtp",
-                                                        $authz));
-@@ -784,7 +785,8 @@
-         }
-         $challenge = base64_decode($this->_arguments[0]);
--        $cram = &Auth_SASL::factory('cram-md5');
-+        // CRM-8597
-+        $cram = Auth_SASL::factory('cram-md5');
-         $auth_str = base64_encode($cram->getResponse($uid, $pwd, $challenge));
-         if (PEAR::isError($error = $this->_put($auth_str))) {
diff --git a/tools/scripts/composer/patches/net-smtp-tls-patch.txt b/tools/scripts/composer/patches/net-smtp-tls-patch.txt
deleted file mode 100644 (file)
index 3eb2122..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-diff --git a/Net/SMTP.php b/Net/SMTP.php
-index 28eae8c..8f4e92b 100644
---- a/Net/SMTP.php
-+++ b/Net/SMTP.php
-@@ -602,7 +602,17 @@
-             if (PEAR::isError($result = $this->_parseResponse(220))) {
-                 return $result;
-             }
--            if (PEAR::isError($result = $this->_socket->enableCrypto(true, STREAM_CRYPTO_METHOD_TLS_CLIENT))) {
-+            if (isset($this->_socket_options['ssl']['crypto_method'])) {
-+                $crypto_method = $this->_socket_options['ssl']['crypto_method'];
-+            } else {
-+                /* STREAM_CRYPTO_METHOD_TLS_ANY_CLIENT constant does not exist
-+                 * and STREAM_CRYPTO_METHOD_SSLv23_CLIENT constant is
-+                 * inconsistent across PHP versions. */
-+                $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT
-+                                 | @STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT
-+                                 | @STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
-+            }
-+            if (PEAR::isError($result = $this->_socket->enableCrypto(true, $crypto_method))) {
-                 return $result;
-             } elseif ($result !== true) {
-                 return PEAR::raiseError('STARTTLS failed');
index e2f488dd33105a782adbba3ac24052c790aab623..23fa638c9d40e9a2c186211ec8ef29faa4256c67 100644 (file)
@@ -17,21 +17,6 @@ diff --git a/Mail/mail.php b/Mail/mail.php
 index ee1ecef..ae6e2e8 100644
 --- a/Mail/mail.php
 +++ b/Mail/mail.php
-@@ -114,6 +114,14 @@ class Mail_mail extends Mail {
-      */
-     public function send($recipients, $headers, $body)
-     {
-+        if (defined('CIVICRM_MAIL_LOG')) {
-+            CRM_Utils_Mail::logger($recipients, $headers, $body);
-+            // Note: "CIVICRM_MAIL_LOG_AND SEND" (space not underscore) was a typo that existed for some years, so kept here for compatibility, but it should not be used.
-+            if (!defined('CIVICRM_MAIL_LOG_AND_SEND') && !defined('CIVICRM_MAIL_LOG_AND SEND')) {
-+                return true;
-+            }
-+        }
-+
-         if (!is_array($headers)) {
-             return PEAR::raiseError('$headers must be an array');
-         }
 @@ -145,7 +153,12 @@ class Mail_mail extends Mail {
          if (is_a($headerElements, 'PEAR_Error')) {
              return $headerElements;
@@ -46,41 +31,3 @@ index ee1ecef..ae6e2e8 100644
  
          // We only use mail()'s optional fifth parameter if the additional
          // parameters have been provided and we're not running in safe mode.
-diff --git a/Mail/sendmail.php b/Mail/sendmail.php
-index 7e8f804..e0300a0 100644
---- a/Mail/sendmail.php
-+++ b/Mail/sendmail.php
-@@ -132,6 +132,14 @@ class Mail_sendmail extends Mail {
-      */
-     public function send($recipients, $headers, $body)
-     {
-+        if (defined('CIVICRM_MAIL_LOG')) {
-+            CRM_Utils_Mail::logger($recipients, $headers, $body);
-+            // Note: "CIVICRM_MAIL_LOG_AND SEND" (space not underscore) was a typo that existed for some years, so kept here for compatibility, but it should not be used.
-+            if (!defined('CIVICRM_MAIL_LOG_AND_SEND') && !defined('CIVICRM_MAIL_LOG_AND SEND')) {
-+                return true;
-+            }
-+        }
-+
-         if (!is_array($headers)) {
-             return PEAR::raiseError('$headers must be an array');
-         }
-diff --git a/Mail/smtp.php b/Mail/smtp.php
-index 5e698fe..5f057e2 100644
---- a/Mail/smtp.php
-+++ b/Mail/smtp.php
-@@ -255,6 +255,14 @@ class Mail_smtp extends Mail {
-      */
-     public function send($recipients, $headers, $body)
-     {
-+        if (defined('CIVICRM_MAIL_LOG')) {
-+            CRM_Utils_Mail::logger($recipients, $headers, $body);
-+            // Note: "CIVICRM_MAIL_LOG_AND SEND" (space not underscore) was a typo that existed for some years, so kept here for compatibility, but it should not be used.
-+            if (!defined('CIVICRM_MAIL_LOG_AND_SEND') && !defined('CIVICRM_MAIL_LOG_AND SEND')) {
-+                return true;
-+            }
-+        }
-+
-         $result = $this->send_or_fail($recipients, $headers, $body);
-         /* If persistent connections are disabled, destroy our SMTP object. */
diff --git a/tools/scripts/composer/patches/phpoffice-common-xml-entity-fix.patch b/tools/scripts/composer/patches/phpoffice-common-xml-entity-fix.patch
deleted file mode 100644 (file)
index 47b211e..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
---- src/Common/XMLReader.php   2019-02-24 13:35:42.895637978 +1100
-+++ src/Common/XMLReader.php   2019-02-24 11:41:29.462449569 +1100
-@@ -71,10 +71,11 @@
-      */
-     public function getDomFromString($content)
-     {
--        libxml_disable_entity_loader(true);
-+        $originalLibXMLEntityValue = libxml_disable_entity_loader(true);
-         $this->dom = new \DOMDocument();
-         $this->dom->loadXML($content);
--
-+        libxml_disable_entity_loader($originalLibXMLEntityValue);
-+
-         return $this->dom;
-     }
diff --git a/tools/scripts/composer/patches/phpword-libxml-fix-global-handling.patch b/tools/scripts/composer/patches/phpword-libxml-fix-global-handling.patch
deleted file mode 100644 (file)
index cc3673f..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-From 27ee4bef48def2e3b966b6d5ff8cc8c56b1fac2c Mon Sep 17 00:00:00 2001
-From: Seamus Lee <seamuslee001@gmail.com>
-Date: Sun, 24 Feb 2019 09:06:51 +1100
-Subject: [PATCH] Ensure that entity_loader disable variable is re-set back to
- the original setting
-
----
- src/PhpWord/Shared/Html.php             | 2 ++
- src/PhpWord/TemplateProcessor.php       | 2 ++
- 3 files changed, 6 insertions(+), 1 deletion(-)
-
-diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php
-index 89881822ca..f2710ea168 100644
---- a/src/PhpWord/Shared/Html.php
-+++ b/src/PhpWord/Shared/Html.php
-@@ -72,7 +72,7 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit
-         }
-         // Load DOM
--        libxml_disable_entity_loader(true);
-+        $orignalLibEntityLoader = libxml_disable_entity_loader(true);
-         $dom = new \DOMDocument();
-         $dom->preserveWhiteSpace = $preserveWhiteSpace;
-         $dom->loadXML($html);
-@@ -80,6 +80,7 @@ public static function addHtml($element, $html, $fullHTML = false, $preserveWhit
-         $node = $dom->getElementsByTagName('body');
-         self::parseNode($node->item(0), $element);
-+        libxml_disable_entity_loader($orignalLibEntityLoader);
-     }
-     /**
-diff --git a/src/PhpWord/TemplateProcessor.php b/src/PhpWord/TemplateProcessor.php
-index 0f685bc45b..7efc0f1ac8 100644
---- a/src/PhpWord/TemplateProcessor.php
-+++ b/src/PhpWord/TemplateProcessor.php
-@@ -170,7 +170,7 @@ protected function readPartWithRels($fileName)
-      */
-     protected function transformSingleXml($xml, $xsltProcessor)
-     {
--        libxml_disable_entity_loader(true);
-+        $orignalLibEntityLoader = libxml_disable_entity_loader(true);
-         $domDocument = new \DOMDocument();
-         if (false === $domDocument->loadXML($xml)) {
-             throw new Exception('Could not load the given XML document.');
-@@ -180,6 +180,7 @@ protected function transformSingleXml($xml, $xsltProcessor)
-         if (false === $transformedXml) {
-             throw new Exception('Could not transform the given XML document.');
-         }
-+        libxml_disable_entity_loader($orignalLibEntityLoader);
-         return $transformedXml;
-     }
index 642dc54b41f121c0cb0a4b252ef11a6943737df6..c5a64105a35996043de14874bd8b634f263f6d6f 100644 (file)
@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="iso-8859-1" ?>
 <version>
-  <version_no>5.23.beta1</version_no>
+  <version_no>5.24.alpha1</version_no>
 </version>