Merge pull request #12576 from colemanw/userPerm
authorMonish Deb <monish.deb@jmaconsulting.biz>
Sat, 11 Aug 2018 14:00:55 +0000 (19:30 +0530)
committerGitHub <noreply@github.com>
Sat, 11 Aug 2018 14:00:55 +0000 (19:30 +0530)
Fix CRM_ACL_API::whereClause to respect $contactId param

120 files changed:
CONTRIBUTORS.txt
CRM/ACL/BAO/ACL.php
CRM/ACL/BAO/EntityRole.php
CRM/ACL/Form/WordPress/Permissions.php
CRM/Activity/BAO/Activity.php
CRM/Activity/Page/AJAX.php
CRM/Activity/Selector/Activity.php
CRM/Admin/Form/Options.php
CRM/Badge/BAO/Layout.php
CRM/Campaign/BAO/Campaign.php
CRM/Campaign/BAO/Survey.php
CRM/Campaign/Selector/Search.php
CRM/Case/BAO/Case.php
CRM/Case/Form/Activity.php
CRM/Contact/BAO/Contact.php
CRM/Contact/BAO/Contact/Utils.php
CRM/Contact/BAO/ContactType.php
CRM/Contact/BAO/Group.php
CRM/Contact/BAO/Query.php
CRM/Contact/BAO/RelationshipType.php
CRM/Contact/Form/Search.php
CRM/Contact/Form/Task/EmailCommon.php
CRM/Contact/Page/View.php
CRM/Contact/Selector.php
CRM/Contribute/BAO/ContributionPage.php
CRM/Contribute/BAO/Premium.php
CRM/Contribute/Form/AbstractEditPayment.php
CRM/Contribute/Page/Tab.php
CRM/Core/BAO/ActionSchedule.php
CRM/Core/BAO/Cache.php
CRM/Core/BAO/ConfigSetting.php
CRM/Core/BAO/CustomField.php
CRM/Core/BAO/CustomGroup.php
CRM/Core/BAO/CustomValueTable.php
CRM/Core/BAO/Job.php
CRM/Core/BAO/LocationType.php
CRM/Core/BAO/MessageTemplate.php
CRM/Core/BAO/Navigation.php
CRM/Core/BAO/OptionGroup.php
CRM/Core/BAO/OptionValue.php
CRM/Core/BAO/SchemaHandler.php
CRM/Core/BAO/UFField.php
CRM/Core/BAO/UFGroup.php
CRM/Core/DAO.php
CRM/Core/DAO/AllCoreTables.php
CRM/Core/DAO/Phone.php
CRM/Core/Form.php
CRM/Core/I18n/Schema.php
CRM/Core/Menu.php
CRM/Core/PrevNextCache/Interface.php
CRM/Core/PrevNextCache/Sql.php
CRM/Core/Resources.php
CRM/Event/BAO/Event.php
CRM/Event/BAO/ParticipantStatusType.php
CRM/Event/Form/Participant.php
CRM/Export/BAO/Export.php
CRM/Export/BAO/ExportProcessor.php
CRM/Financial/BAO/FinancialAccount.php
CRM/Financial/BAO/PaymentProcessor.php
CRM/Financial/BAO/PaymentProcessorType.php
CRM/Financial/Form/SalesTaxTrait.php [new file with mode: 0644]
CRM/Mailing/BAO/Component.php
CRM/Member/BAO/MembershipStatus.php
CRM/Member/BAO/MembershipType.php
CRM/Member/DAO/MembershipType.php
CRM/Member/Form.php
CRM/Member/Form/Membership.php
CRM/Member/Form/MembershipRenewal.php
CRM/Member/Form/MembershipType.php
CRM/PCP/BAO/PCP.php
CRM/Price/BAO/PriceField.php
CRM/Price/BAO/PriceFieldValue.php
CRM/Price/BAO/PriceSet.php
CRM/Upgrade/Incremental/General.php
CRM/Upgrade/Incremental/php/FiveSix.php [new file with mode: 0644]
CRM/Upgrade/Incremental/php/FourSeven.php
CRM/Upgrade/Incremental/php/FourThree.php
CRM/Upgrade/Incremental/sql/5.5.beta1.mysql.tpl [new file with mode: 0644]
CRM/Upgrade/Incremental/sql/5.6.alpha1.mysql.tpl [new file with mode: 0644]
CRM/Upgrade/Snapshot/V4p2/Price/BAO/Field.php
CRM/Upgrade/Snapshot/V4p2/Price/BAO/FieldValue.php
CRM/Upgrade/Snapshot/V4p2/Price/BAO/Set.php
CRM/Utils/Cache.php
CRM/Utils/Check/Component/Env.php
CRM/Utils/GeocodeProvider.php
CRM/Utils/System.php
CRM/Utils/System/Joomla.php
Civi/Core/SettingsBag.php
Civi/Core/SqlTrigger/StaticTriggers.php
Civi/Core/SqlTrigger/TimestampTriggers.php
Civi/Test/Api3TestTrait.php
Civi/Token/TokenCompatSubscriber.php
README.md
ang/crmRouteBinder.js
api/v3/CustomValue.php
api/v3/PaymentProcessor.php
api/v3/PaymentProcessorType.php
composer.json
composer.lock
contributor-key.yml
js/Common.js
js/crm.datepicker.js [new file with mode: 0644]
karma.conf.js
release-notes.md
release-notes/5.4.0.md [new file with mode: 0644]
sql/civicrm_generated.mysql
templates/CRM/Case/Form/CaseView.tpl
templates/CRM/Contribute/Page/Tab.tpl
templates/CRM/Core/Form/Field.tpl
templates/CRM/Member/Form/MembershipType.tpl
tests/phpunit/CRM/Core/BAO/CacheTest.php
tests/phpunit/CRM/Core/BAO/CustomValueTableMultipleTest.php
tests/phpunit/CRM/Core/ComposerConfigTest.php
tests/phpunit/CRM/Export/BAO/ExportTest.php
tests/phpunit/CRM/Member/Form/MembershipTest.php
tests/phpunit/api/v3/CustomValueTest.php
tests/phpunit/api/v3/ReportTemplateTest.php
xml/schema/Core/Phone.xml
xml/schema/Member/MembershipType.xml
xml/version.xml

index 60a8f1ac4e325eb1ceb0d511acf37563bf79e95d..6af5bf8853ca5a881aa645b290a1a82f0f115456 100644 (file)
@@ -9,17 +9,28 @@ CiviCRM - Coleman Watts, Tim Otten
 AGH Strategies - Alice Frumin, Andrew Hunt, Eli Lisseck
 Agileware - Alok Patel, Francis Whittle, Justin Freeman
 Andrew Thompson
+applicado
 Australian Greens - Seamus Lee
-CiviDesk - Yashodha Chaku
-CompuCorp - Michael Devery, Mukesh Ram, Omar Abu Hussein, René Olivo, Vinu
-    Varshith Sekar
-Coop SymbioTIC - Samuel Vanhove
+Bastien Ho
+Blackfly Solutions - Alan Dixon
+Caltha - Tomasz Pietrzkowski
+CEDC - Laryn Kragt Bakker
+Chris Burgess
+CiviCoop - Jaap Jansma
+CiviDesk - Sunil Pawar, Yashodha Chaku
+CompuCorp - Camilo Rodriguez, Davi Alexandre, Debarshi Bhaumik, Michael Devery,
+    Mukesh Ram, Omar Abu Hussein, René Olivo, Vinu Varshith Sekar
+Coop SymbioTIC - Mathieu Lutfy, Samuel Vanhove
 Davis Media Access - Darrick Servis
+Electronic Frontier Foundation - Mark Burdett
 Fuzion - Jitendra Purohit
 Ginkgo Street Labs - Frank Gómez
+Hossein Amin
 JMA Consulting - Monish Deb
+Johan Vervloet
 John Kingsnorth
 Joinery - Allen Shaw
+Kanzu Code - Carl Andrew Lema
 Kompetenzzentrum Technik-Diversity-Chancengleichheit - Niels Heinemann
 Left Join Labs - Sean Madsen
 Lighthouse Design and Consulting - Brian Shaughnessy
@@ -30,11 +41,17 @@ myDropWizard - David Snopek
 Naomi Rosenberg
 Olivier Tétard
 Oxfam Germany - Thomas Schüttler, Yuliyana Liyana
+Pradeep Nayak
 Progressive Technology Project - Jamie McClelland
+Romain Thouvenin
+Squiffle Consulting - Aidan Saunders
 Systopia - Björn Endres
 Tadpole Collective - Kevin Cristiano
 Third Sector Design - Michael McAndrew
+Tom Bloor
 Wikimedia Foundation - Eileen McNaughton
+Wildsight - Lars Sanders-Green
+Will Long
 
 ************************************************
 Key Contributors and Sponsors for 4.7
index 15221f74565ead4bc8a0177ce0147f34df3c4c6a..2723f0f61e8eced30a4468ada4bdf7cb0de0e934 100644 (file)
@@ -680,8 +680,8 @@ SELECT $acl.*
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     // note this also resets any ACL cache
@@ -777,7 +777,7 @@ SELECT g.*
         $staticGroupIDs = array();
         $cachedGroupIDs = array();
         while ($dao->fetch()) {
-          // currently operation is restrcited to VIEW/EDIT
+          // currently operation is restricted to VIEW/EDIT
           if ($dao->where_clause) {
             if ($dao->select_tables) {
               $tmpTables = array();
index 757edce1cf10123c1b43a3dbe2ecbf56432f5c3a..42dd9167bc995efd481cc4ad53051c7f00c45826 100644 (file)
@@ -80,8 +80,8 @@ class CRM_ACL_BAO_EntityRole extends CRM_ACL_DAO_EntityRole {
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_ACL_DAO_EntityRole', $id, 'is_active', $is_active);
index 8310106827ac2c3d360bd5bfe00edcea55439ec8..580886435761a7242c0d34ed47ad10ad13fa6592 100644 (file)
@@ -191,7 +191,7 @@ class CRM_ACL_Form_WordPress_Permissions extends CRM_Core_Form {
 
     CRM_Core_Session::setStatus("", ts('Wordpress Access Control Updated'), "success");
 
-    // rebuild the menus to comply with the new permisssions/capabilites
+    // rebuild the menus to comply with the new permissions/capabilites
     CRM_Core_Invoke::rebuildMenuAndCaches();
 
     CRM_Utils_System::redirect('admin.php?page=CiviCRM&q=civicrm/admin/access&reset=1');
index 61568a96edf6b1015148e96479e651858ea6e46b..b5cdf13fd4c77b418b157d4c81394ab6c93d1620 100644 (file)
@@ -780,7 +780,7 @@ class CRM_Activity_BAO_Activity extends CRM_Activity_DAO_Activity {
         continue;
       }
 
-      $isBulkActivity = (!$bulkActivityTypeID || ($bulkActivityTypeID != $activity['activity_type_id']));
+      $isBulkActivity = (!$bulkActivityTypeID || ($bulkActivityTypeID === $activity['activity_type_id']));
       foreach ($mappingParams as $apiKey => $expectedName) {
         if (in_array($apiKey, array('assignee_contact_name', 'target_contact_name'))) {
           $activities[$id][$expectedName] = CRM_Utils_Array::value($apiKey, $activity, array());
@@ -2876,7 +2876,7 @@ INNER JOIN  civicrm_option_group grp ON ( grp.id = val.option_group_id AND grp.n
     }
 
     // Get contact activities.
-    $activities = CRM_Activity_BAO_Activity::deprecatedGetActivities($params);
+    $activities = CRM_Activity_BAO_Activity::getActivities($params);
 
     // Add total.
     $params['total'] = CRM_Activity_BAO_Activity::deprecatedGetActivitiesCount($params);
@@ -2946,19 +2946,19 @@ INNER JOIN  civicrm_option_group grp ON ( grp.id = val.option_group_id AND grp.n
         }
         elseif (isset($values['target_contact_counter']) && $values['target_contact_counter']) {
           $activity['target_contact_name'] = '';
-          foreach ($values['target_contact_name'] as $tcID => $tcName) {
-            $targetTypeImage = "";
-            $targetLink = CRM_Utils_System::href($tcName, 'civicrm/contact/view', "reset=1&cid={$tcID}");
-            if ($showContactOverlay) {
-              $targetTypeImage = CRM_Contact_BAO_Contact_Utils::getImage(
-                CRM_Contact_BAO_Contact::getContactType($tcID),
-                FALSE,
-                $tcID);
-              $activity['target_contact_name'] .= "<div>$targetTypeImage  $targetLink";
-            }
-            else {
-              $activity['target_contact_name'] .= $targetLink;
-            }
+          $firstTargetName = reset($values['target_contact_name']);
+          $firstTargetContactID = key($values['target_contact_name']);
+
+          $targetLink = CRM_Utils_System::href($firstTargetName, 'civicrm/contact/view', "reset=1&cid={$firstTargetContactID}");
+          if ($showContactOverlay) {
+            $targetTypeImage = CRM_Contact_BAO_Contact_Utils::getImage(
+              CRM_Contact_BAO_Contact::getContactType($firstTargetContactID),
+              FALSE,
+              $firstTargetContactID);
+            $activity['target_contact_name'] .= "<div>$targetTypeImage  $targetLink";
+          }
+          else {
+            $activity['target_contact_name'] .= $targetLink;
           }
 
           if ($extraCount = $values['target_contact_counter'] - 1) {
index 63d342f291178d4ab0ace57142157fb3b262bf44..4a53288813e26499bc25a0d86d354b681c7d4ff6 100644 (file)
@@ -302,8 +302,8 @@ class CRM_Activity_Page_AJAX {
     $mainActivity->activity_date_time = $actDateTime;
     // Make sure this is current revision.
     $mainActivity->is_current_revision = TRUE;
-    // Drop all relations.
-    $mainActivity->parent_id = $mainActivity->original_id = NULL;
+    $mainActivity->original_id = $otherActivity->id;
+    $otherActivity->is_current_revision = FALSE;
 
     $mainActivity->save();
     $mainActivityId = $mainActivity->id;
@@ -327,7 +327,6 @@ class CRM_Activity_Page_AJAX {
           1 => $params['caseID'],
         )) . ' ' . $otherActivity->subject;
       }
-      $otherActivity->activity_date_time = $actDateTime;
       $otherActivity->save();
 
       $caseActivity->free();
index 8182c6409cf52f491db92bf17f3e633e6c72c1e6..9c279843ea913d5d29b33526525185a1ef2e78fd 100644 (file)
@@ -393,7 +393,7 @@ class CRM_Activity_Selector_Activity extends CRM_Core_Selector_Base implements C
       'sort' => $sort,
     );
     $config = CRM_Core_Config::singleton();
-    $rows = CRM_Activity_BAO_Activity::deprecatedGetActivities($params);
+    $rows = CRM_Activity_BAO_Activity::getActivities($params);
 
     if (empty($rows)) {
       return $rows;
index 1f2821d399d694ddc4c3fefe8c143cd432c80fc4..fd4aa9dfa18a1964884db831b91ca20f78e28e01 100644 (file)
@@ -486,18 +486,6 @@ class CRM_Admin_Form_Options extends CRM_Admin_Form {
 
       $optionValue = CRM_Core_OptionValue::addOptionValue($params, $this->_gName, $this->_action, $this->_id);
 
-      // CRM-11516
-      if (!empty($params['financial_account_id'])) {
-        $relationTypeId = key(CRM_Core_PseudoConstant::accountOptionValues('account_relationship', NULL, " AND v.name LIKE 'Asset Account is' "));
-        $params = array(
-          'entity_table' => 'civicrm_option_value',
-          'entity_id' => $optionValue->id,
-          'account_relationship' => $relationTypeId,
-          'financial_account_id' => $params['financial_account_id'],
-        );
-        CRM_Financial_BAO_FinancialTypeAccount::add($params);
-      }
-
       CRM_Core_Session::setStatus(ts('The %1 \'%2\' has been saved.', array(
             1 => $this->_gLabel,
             2 => $optionValue->label,
index 1c5ce8021952440623d7fd47ccb0642fc3257e38..db9dd0de0b456bf3e6382e4980314af25145158d 100644 (file)
@@ -70,9 +70,8 @@ class CRM_Badge_BAO_Layout extends CRM_Core_DAO_PrintLabel {
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
-   *
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_PrintLabel', $id, 'is_active', $is_active);
index 8345d7fac404bcc4256c24c8989928de0f68706c..7cc0e111c8b770cfdfef755c1f07bd1d7d4453b5 100644 (file)
@@ -551,8 +551,8 @@ INNER JOIN  civicrm_group grp ON ( grp.id = campgrp.entity_id )
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return CRM_Campaign_DAO_Campaign|null
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Campaign_DAO_Campaign', $id, 'is_active', $is_active);
index df9b49022b8318bf037a85598343c53b97485343..a7e9f8ea08ecffb97fed939cfb8206b64e4a07ac 100644 (file)
@@ -391,8 +391,8 @@ SELECT  survey.id    as id,
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Campaign_DAO_Survey', $id, 'is_active', $is_active);
index 08b233be673a1ba5537b66445ee0a6d416dfea38..28c2b15b6d7961c6899021582a5765012b16e5fc 100644 (file)
@@ -271,7 +271,7 @@ class CRM_Campaign_Selector_Search extends CRM_Core_Selector_Base implements CRM
 
     if (!$crmPID) {
       $cacheKey = "civicrm search {$this->_key}";
-      CRM_Core_BAO_PrevNextCache::deleteItem(NULL, $cacheKey, 'civicrm_contact');
+      Civi::service('prevnext')->deleteItem(NULL, $cacheKey, 'civicrm_contact');
 
       $sql = $this->_query->searchQuery(0, 0, $sort,
         FALSE, FALSE,
index 4eeebfed00844c1f94b7ffbcfa64bb813286055e..797867c23e8a923d94b116e3358c8da52e8aca94 100644 (file)
@@ -684,7 +684,7 @@ LEFT JOIN civicrm_option_group aog ON aog.name='activity_type'
 
       $casesList[$key]['activity_list'] = sprintf('<a title="%s" class="crm-expand-row" href="%s"></a>',
         ts('Activities'),
-        CRM_Utils_System::url('civicrm/case/details', array('caseid' => $case['case_id'], 'cid' => $case['contact_id'], 'type' => $type))
+        CRM_Utils_System::url('civicrm/case/details', array('caseId' => $case['case_id'], 'cid' => $case['contact_id'], 'type' => $type))
       );
 
       $phone = empty($case['phone']) ? '' : '<br /><span class="description">' . $case['phone'] . '</span>';
@@ -725,7 +725,7 @@ LEFT JOIN civicrm_option_group aog ON aog.name='activity_type'
         }
         if (self::checkPermission($actId, 'edit', $case['activity_type_id'], $userID)) {
           $casesList[$key]['date'] .= sprintf('<a class="action-item crm-hover-button" href="%s" title="%s"><i class="crm-i fa-pencil"></i></a>',
-            CRM_Utils_System::url('civicrm/case/activity', array('reset' => 1, 'cid' => $case['contact_id'], 'caseid' => $case['case_id'], 'action' => 'update')),
+            CRM_Utils_System::url('civicrm/case/activity', array('reset' => 1, 'cid' => $case['contact_id'], 'caseid' => $case['case_id'], 'action' => 'update', 'id' => $actId)),
             ts('Edit activity')
           );
         }
@@ -909,15 +909,13 @@ SELECT case_status.label AS case_status, status_id, civicrm_case_type.title AS c
    *
    * @param null $context
    * @param int $userID
-   * @param null $type
+   * @param null $type (deprecated)
    *
    * @return array
    *   Array of case activities
    *
    */
   public static function getCaseActivity($caseID, &$params, $contactID, $context = NULL, $userID = NULL, $type = NULL) {
-    $values = array();
-
     $activityContacts = CRM_Activity_BAO_ActivityContact::buildOptions('record_type_id', 'validate');
     $assigneeID = CRM_Utils_Array::key('Activity Assignees', $activityContacts);
     $sourceID = CRM_Utils_Array::key('Activity Source', $activityContacts);
@@ -1088,9 +1086,6 @@ SELECT case_status.label AS case_status, status_id, civicrm_case_type.title AS c
       CRM_Activity_BAO_Activity::getStatusesByType(CRM_Activity_BAO_Activity::CANCELLED)
     );
 
-    $contactViewUrl = CRM_Utils_System::url("civicrm/contact/view", "reset=1&cid=", FALSE, NULL, FALSE);
-    $hasViewContact = CRM_Core_Permission::giveMeAllACLs();
-
     if (!$userID) {
       $session = CRM_Core_Session::singleton();
       $userID = $session->get('userID');
@@ -1112,75 +1107,74 @@ SELECT case_status.label AS case_status, status_id, civicrm_case_type.title AS c
         continue;
       }
 
-      $caseActivity['DT_RowId'] = $caseActivityId;
+      $caseActivities[$caseActivityId]['DT_RowId'] = $caseActivityId;
       //Add classes to the row, via DataTables syntax
-      $caseActivity['DT_RowClass'] = "crm-entity status-id-$dao->status";
+      $caseActivities[$caseActivityId]['DT_RowClass'] = "crm-entity status-id-$dao->status";
 
       if (CRM_Utils_Array::crmInArray($dao->status, $compStatusValues)) {
-        $caseActivity['DT_RowClass'] .= " status-completed";
+        $caseActivities[$caseActivityId]['DT_RowClass'] .= " status-completed";
       }
       else {
         if (CRM_Utils_Date::overdue($dao->display_date)) {
-          $caseActivity['DT_RowClass'] .= " status-overdue";
+          $caseActivities[$caseActivityId]['DT_RowClass'] .= " status-overdue";
         }
         else {
-          $caseActivity['DT_RowClass'] .= " status-scheduled";
+          $caseActivities[$caseActivityId]['DT_RowClass'] .= " status-scheduled";
         }
       }
 
       if (!empty($dao->priority)) {
         if ($dao->priority == CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'priority_id', 'Urgent')) {
-          $caseActivity['DT_RowClass'] .= " priority-urgent ";
+          $caseActivities[$caseActivityId]['DT_RowClass'] .= " priority-urgent ";
         }
         elseif ($dao->priority == CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'priority_id', 'Low')) {
-          $caseActivity['DT_RowClass'] .= " priority-low ";
+          $caseActivities[$caseActivityId]['DT_RowClass'] .= " priority-low ";
         }
       }
 
       //Add data to the row for inline editing, via DataTable syntax
-      $caseActivity['DT_RowAttr'] = array();
-      $caseActivity['DT_RowAttr']['data-entity'] = 'activity';
-      $caseActivity['DT_RowAttr']['data-id'] = $caseActivityId;
+      $caseActivities[$caseActivityId]['DT_RowAttr'] = array();
+      $caseActivities[$caseActivityId]['DT_RowAttr']['data-entity'] = 'activity';
+      $caseActivities[$caseActivityId]['DT_RowAttr']['data-id'] = $caseActivityId;
 
       //Activity Date and Time
-      $caseActivity['activity_date_time'] = CRM_Utils_Date::customFormat($dao->display_date);
+      $caseActivities[$caseActivityId]['activity_date_time'] = CRM_Utils_Date::customFormat($dao->display_date);
 
       //Activity Subject
-      $caseActivity['subject'] = $dao->subject;
+      $caseActivities[$caseActivityId]['subject'] = $dao->subject;
 
       //Activity Type
-      $caseActivity['type'] = (!empty($activityTypes[$dao->type]['icon']) ? '<span class="crm-i ' . $activityTypes[$dao->type]['icon'] . '"></span> ' : '')
+      $caseActivities[$caseActivityId]['type'] = (!empty($activityTypes[$dao->type]['icon']) ? '<span class="crm-i ' . $activityTypes[$dao->type]['icon'] . '"></span> ' : '')
         . $activityTypes[$dao->type]['label'];
 
-      //Activity Target (With)
-      $targetContact = '';
-      if (isset($dao->target_contact_id)) {
-        $targetContact = $dao->target_contact_name;
-        if ($hasViewContact) {
-          $targetContact = '<a href="' . $contactViewUrl . $dao->target_contact_id . '">' . $dao->target_contact_name . '</a>';
+      // Activity Target (With Contact) (There can be more than one)
+      $targetContact = self::formatContactLink($dao->target_contact_id, $dao->target_contact_name);
+      if (empty($caseActivities[$caseActivityId]['target_contact_name'])) {
+        $caseActivities[$caseActivityId]['target_contact_name'] = $targetContact;
+      }
+      else {
+        if (strpos($caseActivities[$caseActivityId]['target_contact_name'], $targetContact) === FALSE) {
+          $caseActivities[$caseActivityId]['target_contact_name'] .= '; ' . $targetContact;
         }
       }
-      $caseActivity['target_contact_name'] = $targetContact;
 
-      //Activity Source Contact (Reporter)
-      $sourceContact = $dao->source_contact_name;
-      if ($hasViewContact) {
-        $sourceContact = '<a href="' . $contactViewUrl . $dao->source_contact_id . '">' . $dao->source_contact_name . '</a>';
-      }
-      $caseActivity['source_contact_name'] = $sourceContact;
+      // Activity Source Contact (Reporter) (There can only be one)
+      $sourceContact = self::formatContactLink($dao->source_contact_id, $dao->source_contact_name);
+      $caseActivities[$caseActivityId]['source_contact_name'] = $sourceContact;
 
-      //Activity Assignee. CRM-4485.
-      $assigneeContact = '';
-      if (isset($dao->assignee_contact_id)) {
-        $assigneeContact = $dao->assignee_contact_name;
-        if ($hasViewContact) {
-          $assigneeContact = '<a href="' . $contactViewUrl . $dao->assignee_contact_id . '">' . $dao->assignee_contact_name . '</a>';
+      // Activity Assignee (There can be more than one)
+      $assigneeContact = self::formatContactLink($dao->assignee_contact_id, $dao->assignee_contact_name);
+      if (empty($caseActivities[$caseActivityId]['assignee_contact_name'])) {
+        $caseActivities[$caseActivityId]['assignee_contact_name'] = $assigneeContact;
+      }
+      else {
+        if (strpos($caseActivities[$caseActivityId]['assignee_contact_name'], $assigneeContact) === FALSE) {
+          $caseActivities[$caseActivityId]['assignee_contact_name'] .= '; ' . $assigneeContact;
         }
       }
-      $caseActivity['assignee_contact_name'] = $assigneeContact;
 
       //Activity Status
-      $caseActivity['status_id'] = $activityStatuses[$dao->status];
+      $caseActivities[$caseActivityId]['status_id'] = $activityStatuses[$dao->status];
 
       // FIXME: Why are we not using CRM_Core_Action for these links? This is too much manual work and likely to get out-of-sync with core markup.
       $url = "";
@@ -1204,7 +1198,7 @@ SELECT case_status.label AS case_status, status_id, civicrm_case_type.title AS c
       }
       elseif (!$caseDeleted) {
         $url = ' <a ' . $css . ' href="' . $restoreUrl . $additionalUrl . '">' . ts('Restore') . '</a>';
-        $caseActivity['status_id'] = $caseActivity['status_id'] . '<br /> (deleted)';
+        $caseActivities[$caseActivityId]['status_id'] = $caseActivities[$caseActivityId]['status_id'] . '<br /> (deleted)';
       }
 
       //check for operations.
@@ -1217,24 +1211,46 @@ SELECT case_status.label AS case_status, status_id, civicrm_case_type.title AS c
       // if there are file attachments we will return how many and, if only one, add a link to it
       if (!empty($dao->attachment_ids)) {
         $attachmentIDs = array_unique(explode(',', $dao->attachment_ids));
-        $caseActivity['no_attachments'] = count($attachmentIDs);
+        $caseActivities[$caseActivityId]['no_attachments'] = count($attachmentIDs);
         $url .= implode(' ', CRM_Core_BAO_File::paperIconAttachment('civicrm_activity', $caseActivityId));
       }
 
-      $caseActivity['links'] = $url;
-
-      array_push($caseActivities, $caseActivity);
+      $caseActivities[$caseActivityId]['links'] = $url;
     }
     $dao->free();
 
     $caseActivitiesDT = array();
-    $caseActivitiesDT['data'] = $caseActivities;
+    $caseActivitiesDT['data'] = array_values($caseActivities);
     $caseActivitiesDT['recordsTotal'] = $caseCount;
     $caseActivitiesDT['recordsFiltered'] = $caseCount;
 
     return $caseActivitiesDT;
   }
 
+  /**
+   * Helper function to generate a formatted contact link/name for display in the Case activities tab
+   *
+   * @param $contactId
+   * @param $contactName
+   *
+   * @return string
+   */
+  private static function formatContactLink($contactId, $contactName) {
+    if (empty($contactId)) {
+      return NULL;
+    }
+
+    $hasViewContact = CRM_Contact_BAO_Contact_Permission::allow($contactId);
+
+    if ($hasViewContact) {
+      $contactViewUrl = CRM_Utils_System::url("civicrm/contact/view", "reset=1&cid={$contactId}");
+      return "<a href=\"{$contactViewUrl}\">" . $contactName . "</a>";
+    }
+    else {
+      return $contactName;
+    }
+  }
+
   /**
    * Get Case Related Contacts.
    *
index d12b8716cc5b242a7b3e442ce97dd654b2d67d1d..7fd6f54d7de6e32d2f0d21cc21ef1eeca86ba13a 100644 (file)
@@ -178,10 +178,9 @@ class CRM_Case_Form_Activity extends CRM_Activity_Form_Activity {
                 $atArray,
                 $this->_currentUserId
               );
-              $activities = array_keys($activities);
-              $activities = $activities[0];
+              $activityId = CRM_Utils_Array::first(array_keys($activities['data']));
               $editUrl = CRM_Utils_System::url('civicrm/case/activity',
-                "reset=1&cid={$this->_currentlyViewedContactId}&caseid={$caseId}&action=update&id={$activities}"
+                "reset=1&cid={$this->_currentlyViewedContactId}&caseid={$caseId}&action=update&id={$activityId}"
               );
             }
             CRM_Core_Error::statusBounce(ts("You can not add another '%1' activity to this case. %2",
index f222e19594a8f976f2e5586bcbbab2f45aa45af4..9e4488208c0e76eff1f000620f945a3ee5d25eec 100644 (file)
@@ -1013,7 +1013,10 @@ WHERE     civicrm_contact.id = " . CRM_Utils_Type::escape($id, 'Integer');
     CRM_Utils_Recent::delContact($id);
     self::updateContactCache($id, empty($restore));
 
-    // delete any dupe cache entry
+    // delete any prevnext/dupe cache entry
+    // These two calls are redundant in default deployments, but they're
+    // meaningful if "prevnext" is memory-backed.
+    Civi::service('prevnext')->deleteItem($id);
     CRM_Core_BAO_PrevNextCache::deleteItem($id);
 
     $transaction->commit();
index f3b391362afdd66216f7449110c66723b74003c1..2cee6e99dcb3b9e584bc7fcdb25c47f481157aa2 100644 (file)
@@ -917,6 +917,9 @@ INNER JOIN civicrm_contact contact_target ON ( contact_target.id = act.contact_i
       return;
     }
     if ($isEmptyPrevNextTable) {
+      // These two calls are redundant in default deployments, but they're
+      // meaningful if "prevnext" is memory-backed.
+      Civi::service('prevnext')->deleteItem();
       CRM_Core_BAO_PrevNextCache::deleteItem();
     }
     // clear acl cache if any.
index cb13346f556a1bd91fa98d7b7010b056757c2b17..d7a211ebac47f93b8f1dd82af3677c586fb37843 100644 (file)
@@ -694,8 +694,8 @@ WHERE name = %1";
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     $params = array('id' => $id);
index 8c08654256d78acd477d7017d4c70506a31a3d0b..a5374fe7a68f22a222d37627518621b6b9e49773 100644 (file)
@@ -539,8 +539,8 @@ class CRM_Contact_BAO_Group extends CRM_Contact_DAO_Group {
    * @param bool $isActive
    *   Value we want to set the is_active field.
    *
-   * @return CRM_Core_DAO|null
-   *   DAO object on success, NULL otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $isActive) {
     return CRM_Core_DAO::setFieldValue('CRM_Contact_DAO_Group', $id, 'is_active', $isActive);
index f515564998a6e3e6a4b7added11863b1b46f8a52..57643ede2677b99a55f8c1474a4c7f0d7dc59fdc 100644 (file)
@@ -2235,6 +2235,7 @@ class CRM_Contact_BAO_Query {
       $this->_qill[$grouping][] = "$field[title] $op \"$value\"";
     }
     elseif ($name === 'email_greeting') {
+      CRM_Core_Error::deprecatedFunctionWarning('pass in email_greeting_id or email_greeting_display');
       $filterCondition = array('greeting_type' => 'email_greeting');
       $this->optionValueQuery(
         $name, $op, $value, $grouping,
@@ -2244,6 +2245,7 @@ class CRM_Contact_BAO_Query {
       );
     }
     elseif ($name === 'postal_greeting') {
+      CRM_Core_Error::deprecatedFunctionWarning('pass in postal_greeting_id or postal_greeting_display');
       $filterCondition = array('greeting_type' => 'postal_greeting');
       $this->optionValueQuery(
         $name, $op, $value, $grouping,
@@ -2253,6 +2255,7 @@ class CRM_Contact_BAO_Query {
       );
     }
     elseif ($name === 'addressee') {
+      CRM_Core_Error::deprecatedFunctionWarning('pass in addressee_id or addressee_display');
       $filterCondition = array('greeting_type' => 'addressee');
       $this->optionValueQuery(
         $name, $op, $value, $grouping,
@@ -5965,8 +5968,8 @@ AND   displayRelType.is_active = 1
       }
     }
     else {
-      // LOWER roughly translates to 'hurt my database without deriving any benefit' See CRM-19811.
-      $wc = self::caseImportant($op) ? "LOWER({$field['where']})" : "{$field['where']}";
+      CRM_Core_Error::deprecatedFunctionWarning('pass $ids to this method');
+      $wc = "{$field['where']}";
     }
     if (in_array($name, $pseudoFields)) {
       if (!in_array($name, array('gender_id', 'prefix_id', 'suffix_id', 'communication_style_id'))) {
index 55e32582ff55d1cabff8f0c9803338754c3a1e12..346131b9f3ddb1c07a0a8a36efdd65f571076617 100644 (file)
@@ -68,8 +68,8 @@ class CRM_Contact_BAO_RelationshipType extends CRM_Contact_DAO_RelationshipType
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Contact_DAO_RelationshipType', $id, 'is_active', $is_active);
index eadf418b4d015b245773ba27f6e98f025d5e3ff4..a9ea4d57d990b53345201ee0ac0fbfdf236ed135 100644 (file)
@@ -782,7 +782,7 @@ class CRM_Contact_Form_Search extends CRM_Core_Form_Search {
     ) {
       //reset the cache table for new search
       $cacheKey = "civicrm search {$this->controller->_key}";
-      CRM_Core_BAO_PrevNextCache::deleteItem(NULL, $cacheKey);
+      Civi::service('prevnext')->deleteItem(NULL, $cacheKey);
     }
 
     //get the button name
index 3f12ee333a4d11a9239ff9eb8255c803978c2b7a..889adc25abb2f752ea2b142d2f981e8e5510db01 100644 (file)
@@ -89,7 +89,11 @@ class CRM_Contact_Form_Task_EmailCommon {
     }
 
     $form->_emails = $fromEmailValues;
+    $defaults = array();
     $form->_fromEmails = $fromEmailValues;
+    if (!Civi::settings()->get('allow_mail_from_logged_in_contact')) {
+      $defaults['from_email_address'] = current(CRM_Core_BAO_Domain::getNameAndEmail(FALSE, TRUE));
+    }
     if (is_numeric(key($form->_fromEmails))) {
       // Add signature
       $defaultEmail = civicrm_api3('email', 'getsingle', array('id' => key($form->_fromEmails)));
@@ -100,8 +104,8 @@ class CRM_Contact_Form_Task_EmailCommon {
       if (!empty($defaultEmail['signature_text'])) {
         $defaults['text_message'] = "\n\n--\n" . $defaultEmail['signature_text'];
       }
-      $form->setDefaults($defaults);
     }
+    $form->setDefaults($defaults);
   }
 
   /**
index 4da77a244a8551831ac29fc50254fd366d7686ba..f7e0057eefa53549ea64c6488ccd933c7cef97ed 100644 (file)
@@ -117,7 +117,7 @@ class CRM_Contact_Page_View extends CRM_Core_Page {
       'nextPrevError' => 0,
     );
     if ($qfKey) {
-      $pos = CRM_Core_BAO_PrevNextCache::getPositions("civicrm search $qfKey",
+      $pos = Civi::service('prevnext')->getPositions("civicrm search $qfKey",
         $this->_contactId,
         $this->_contactId
       );
index a3c270231cab5a2b6c0a74756776d8e213efd5a9..066e4a4476fd22a14557c37bc9f35f32aa960cb2 100644 (file)
@@ -881,7 +881,7 @@ class CRM_Contact_Selector extends CRM_Core_Selector_Base implements CRM_Core_Se
     // check for current != previous to ensure cache is not reset if paging is done without changing
     // sort criteria
     if (!$pageNum || (!empty($currentSortID) && $currentSortID != $previousSortID)) {
-      CRM_Core_BAO_PrevNextCache::deleteItem(NULL, $cacheKey, 'civicrm_contact');
+      Civi::service('prevnext')->deleteItem(NULL, $cacheKey, 'civicrm_contact');
       // this means it's fresh search, so set pageNum=1
       if (!$pageNum) {
         $pageNum = 1;
@@ -900,7 +900,7 @@ class CRM_Contact_Selector extends CRM_Core_Selector_Base implements CRM_Core_Se
     $sortByCharacter = CRM_Utils_Request::retrieve('sortByCharacter', 'String');
 
     //for text field pagination selection save
-    $countRow = CRM_Core_BAO_PrevNextCache::getCount($cacheKey, NULL, "entity_table = 'civicrm_contact'");
+    $countRow = Civi::service('prevnext')->getCount($cacheKey);
     // $sortByCharacter triggers a refresh in the prevNext cache
     if ($sortByCharacter && $sortByCharacter != 'all') {
       $cacheKey .= "_alphabet";
index 0197f65cdcbfc50962151ca824ce34bd1d746cd1..c8a63a5adcda062816338e7f949878b043b61164 100644 (file)
@@ -74,8 +74,8 @@ class CRM_Contribute_BAO_ContributionPage extends CRM_Contribute_DAO_Contributio
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Contribute_DAO_ContributionPage', $id, 'is_active', $is_active);
index a7db1d5efd48f604cc84d6f87509bdca837b4060..5a8063925e85e8d3954071cd69068fcd0ea31246 100644 (file)
@@ -74,8 +74,8 @@ class CRM_Contribute_BAO_Premium extends CRM_Contribute_DAO_Premium {
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Contribute_DAO_Premium', $id, 'premiums_active ', $is_active);
index 62295f1c70ca7db182413be80c62fe7e7cac52be..9e59495c619241253100f6422578fb684f702b4a 100644 (file)
@@ -46,6 +46,9 @@
  *
  */
 class CRM_Contribute_Form_AbstractEditPayment extends CRM_Contact_Form_Task {
+
+  use CRM_Financial_Form_SalesTaxTrait;
+
   public $_mode;
 
   public $_action;
index 5317697fe72b8e08915f2688870af6d7b8c706b6..fa80f7d728fd7f3ab686a62d407bf8ed63e08c96 100644 (file)
@@ -168,13 +168,14 @@ class CRM_Contribute_Page_Tab extends CRM_Core_Page {
    * Get all the recurring contribution information and assign to the template
    */
   private function addRecurringContributionsBlock() {
-    $activeContributions = $this->getActiveRecurringContributions();
-    $inactiveRecurringContributions = $this->getInactiveRecurringContributions();
+    list($activeContributions, $activeContributionsCount) = $this->getActiveRecurringContributions();
+    list($inactiveRecurringContributions, $inactiveContributionsCount) = $this->getInactiveRecurringContributions();
 
     if (!empty($activeContributions) || !empty($inactiveRecurringContributions)) {
       // assign vars to templates
       $this->assign('action', $this->_action);
       $this->assign('activeRecurRows', $activeContributions);
+      $this->assign('contributionRecurCount', $activeContributionsCount + $inactiveContributionsCount);
       $this->assign('inactiveRecurRows', $inactiveRecurringContributions);
       $this->assign('recur', TRUE);
     }
@@ -191,7 +192,7 @@ class CRM_Contribute_Page_Tab extends CRM_Core_Page {
       $contributionRecurResult = civicrm_api3('ContributionRecur', 'get', array(
         'contact_id' => $this->_contactId,
         'contribution_status_id' => array('NOT IN' => CRM_Contribute_BAO_ContributionRecur::getInactiveStatuses()),
-        'options' => array('limit' => 0, 'sort' => 'start_date ASC'),
+        'options' => ['limit' => 0, 'sort' => 'is_test, start_date DESC'],
       ));
       $recurContributions = CRM_Utils_Array::value('values', $contributionRecurResult);
     }
@@ -213,7 +214,7 @@ class CRM_Contribute_Page_Tab extends CRM_Core_Page {
       $contributionRecurResult = civicrm_api3('ContributionRecur', 'get', array(
         'contact_id' => $this->_contactId,
         'contribution_status_id' => array('IN' => CRM_Contribute_BAO_ContributionRecur::getInactiveStatuses()),
-        'options' => array('limit' => 0, 'sort' => 'start_date ASC'),
+        'options' => ['limit' => 0, 'sort' => 'is_test, start_date DESC'],
       ));
       $recurContributions = CRM_Utils_Array::value('values', $contributionRecurResult);
     }
@@ -230,11 +231,16 @@ class CRM_Contribute_Page_Tab extends CRM_Core_Page {
    * @return mixed
    */
   private function buildRecurringContributionsArray($recurContributions) {
+    $liveRecurringContributionCount = 0;
     foreach ($recurContributions as $recurId => $recurDetail) {
       $action = array_sum(array_keys($this->recurLinks($recurId)));
       // no action allowed if it's not active
       $recurContributions[$recurId]['is_active'] = (!CRM_Contribute_BAO_Contribution::isContributionStatusNegative($recurDetail['contribution_status_id']));
 
+      if (empty($recurDetail['is_test'])) {
+        $liveRecurringContributionCount++;
+      }
+
       // Get the name of the payment processor
       if (!empty($recurDetail['payment_processor_id'])) {
         $recurContributions[$recurId]['payment_processor'] = CRM_Financial_BAO_PaymentProcessor::getPaymentProcessorName($recurDetail['payment_processor_id']);
@@ -267,7 +273,7 @@ class CRM_Contribute_Page_Tab extends CRM_Core_Page {
       }
     }
 
-    return $recurContributions;
+    return [$recurContributions, $liveRecurringContributionCount];
   }
 
   /**
index e783523e0a003616cb5ace50f0f168e87fdc36cb..b7cb0b2c3f7118592edba146aedfcac423842c20 100644 (file)
@@ -259,8 +259,8 @@ FROM civicrm_action_schedule cas
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_ActionSchedule', $id, 'is_active', $is_active);
index ce1d63ede35a9a3106ea2f10f13963330fc5645d..d1f97f63f661a483becb6e05016fece69d483e3c 100644 (file)
@@ -73,7 +73,8 @@ class CRM_Core_BAO_Cache extends CRM_Core_DAO_Cache {
     $argString = "CRM_CT_{$group}_{$path}_{$componentID}";
     if (!array_key_exists($argString, self::$_cache)) {
       $cache = CRM_Utils_Cache::singleton();
-      self::$_cache[$argString] = $cache->get(self::cleanKey($argString));
+      $cleanKey = self::cleanKey($argString);
+      self::$_cache[$argString] = $cache->get($cleanKey);
       if (!self::$_cache[$argString]) {
         $table = self::getTableName();
         $where = self::whereCache($group, $path, $componentID);
@@ -81,7 +82,7 @@ class CRM_Core_BAO_Cache extends CRM_Core_DAO_Cache {
         $data = $rawData ? self::decode($rawData) : NULL;
 
         self::$_cache[$argString] = $data;
-        $cache->set(self::cleanKey($argString), self::$_cache[$argString]);
+        $cache->set($cleanKey, self::$_cache[$argString]);
       }
     }
     return self::$_cache[$argString];
@@ -106,7 +107,8 @@ class CRM_Core_BAO_Cache extends CRM_Core_DAO_Cache {
     $argString = "CRM_CT_CI_{$group}_{$componentID}";
     if (!array_key_exists($argString, self::$_cache)) {
       $cache = CRM_Utils_Cache::singleton();
-      self::$_cache[$argString] = $cache->get(self::cleanKey($argString));
+      $cleanKey = self::cleanKey($argString);
+      self::$_cache[$argString] = $cache->get($cleanKey);
       if (!self::$_cache[$argString]) {
         $table = self::getTableName();
         $where = self::whereCache($group, NULL, $componentID);
@@ -119,7 +121,7 @@ class CRM_Core_BAO_Cache extends CRM_Core_DAO_Cache {
         $dao->free();
 
         self::$_cache[$argString] = $result;
-        $cache->set(self::cleanKey($argString), self::$_cache[$argString]);
+        $cache->set($cleanKey, self::$_cache[$argString]);
       }
     }
 
@@ -448,7 +450,7 @@ class CRM_Core_BAO_Cache extends CRM_Core_DAO_Cache {
       return $escape . md5($key);
     }
 
-    $r = preg_replace_callback(';[^A-Za-z0-9_\. ];', function($m) use ($escape) {
+    $r = preg_replace_callback(';[^A-Za-z0-9_\.];', function($m) use ($escape) {
       return $escape . dechex(ord($m[0]));
     }, $key);
 
index bb5340bbec4ab108cc6bd7687128cfe81121e25d..4b5f3111e80fdc882809dc02ea6a01ebd5c1f53e 100644 (file)
@@ -96,7 +96,7 @@ class CRM_Core_BAO_ConfigSetting {
       $urlVar = 'task';
     }
 
-    if ($isUpgrade && CRM_Core_DAO::checkFieldExists('civicrm_domain', 'config_backend')) {
+    if ($isUpgrade && CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_domain', 'config_backend')) {
       $domain->selectAdd('config_backend');
     }
     else {
index 8dd1a491fc3acb6a9f5d95e0bd2cdbe26faa3693..6fc3fe7d49e7b014b058d60f7e2da1a98afe97e7 100644 (file)
@@ -363,8 +363,8 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField {
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
 
index 17d089d656ec96947024d6072cc881795970830e..f4b61a577722c92001815064b75be7b8f994f1a9 100644 (file)
@@ -253,8 +253,8 @@ class CRM_Core_BAO_CustomGroup extends CRM_Core_DAO_CustomGroup {
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     // reset the cache
index 9455b06a4fa3cabc91315e1f4e16d0858aabd5d6..73a431065a898d73f8c5e80fee96c2db3ba9996d 100644 (file)
@@ -637,6 +637,10 @@ AND    cf.id IN ( $fieldIDList )
           'extends' => $dao->extends,
         );
 
+        if (!empty($params['id'])) {
+          $cvParam['id'] = $params['id'];
+        }
+
         if ($cvParam['type'] == 'File') {
           $cvParam['file_id'] = $fieldValue['value'];
         }
index a67ffaa5b07f852b00472ad51a2d54f9b1b7680f..dfd28028a0e52b3d531853a4d0768f3ccc67ce5a 100644 (file)
@@ -90,9 +90,8 @@ class CRM_Core_BAO_Job extends CRM_Core_DAO_Job {
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
-   *
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_Job', $id, 'is_active', $is_active);
index d75cb632f18fa942d15b1f38bc1edbe7486bbed3..6362f126aaa355674b73c7e76bc4751d7fd9fc2b 100644 (file)
@@ -76,9 +76,8 @@ class CRM_Core_BAO_LocationType extends CRM_Core_DAO_LocationType {
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
-   *
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_LocationType', $id, 'is_active', $is_active);
index 871ca35427d77a8f9c2639e67a7e5921b262fe74..9d2b002aacb47a656edda85d4a6315f3fd5e82d9 100644 (file)
@@ -66,8 +66,8 @@ class CRM_Core_BAO_MessageTemplate extends CRM_Core_DAO_MessageTemplate {
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, NULL otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_MessageTemplate', $id, 'is_active', $is_active);
index 9b5f50a00c5350acea1780ec7773e962127e0607..1637c14dffaaa1747a5c10f7256c0a69c6af0502 100644 (file)
@@ -50,8 +50,8 @@ class CRM_Core_BAO_Navigation extends CRM_Core_DAO_Navigation {
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return CRM_Core_DAO_Navigation|NULL
-   *   DAO object on success, NULL otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_Navigation', $id, 'is_active', $is_active);
index bbabcef8bd42e1fcc265e20d6e3a3159b2749375..4c1ccc9dfb9a856dd54afd4bbd7b435a108224f6 100644 (file)
@@ -69,8 +69,8 @@ class CRM_Core_BAO_OptionGroup extends CRM_Core_DAO_OptionGroup {
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_OptionGroup', $id, 'is_active', $is_active);
index cfb4b45dce48838c9d9b53720e6db4b26fd80fc7..5c3c2dfd26c5d6c4b519390f5c40815c769b4ee0 100644 (file)
@@ -151,8 +151,8 @@ class CRM_Core_BAO_OptionValue extends CRM_Core_DAO_OptionValue {
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_OptionValue', $id, 'is_active', $is_active);
@@ -243,6 +243,29 @@ class CRM_Core_BAO_OptionValue extends CRM_Core_DAO_OptionValue {
     $optionValue->id = $id;
     $optionValue->save();
     CRM_Core_PseudoConstant::flush();
+
+    // Create relationship for payment intrument options
+    if (!empty($params['financial_account_id'])) {
+      $optionName = civicrm_api3('OptionGroup', 'getvalue', [
+        'return' => 'name',
+        'id' => $params['option_group_id'],
+      ]);
+      // Only create relationship for payment intrument options
+      if ($optionName == 'payment_instrument') {
+        $relationTypeId = civicrm_api3('OptionValue', 'getvalue', [
+          'return' => 'value',
+          'option_group_id' => 'account_relationship',
+          'name' => 'Asset Account is',
+        ]);
+        $params = [
+          'entity_table' => 'civicrm_option_value',
+          'entity_id' => $optionValue->id,
+          'account_relationship' => $relationTypeId,
+          'financial_account_id' => $params['financial_account_id'],
+        ];
+        CRM_Financial_BAO_FinancialTypeAccount::add($params);
+      }
+    }
     return $optionValue;
   }
 
index ab58a8aa4b25f6efa0d77af505661b3d9e16430a..1a926044fff0f335e97ee941a7a9b18c43513b88 100644 (file)
@@ -627,18 +627,17 @@ MODIFY      {$columnName} varchar( $length )
    *
    * @param string $tableName
    * @param string $columnName
+   * @param bool $i18nRewrite
+   *   Whether to rewrite the query on multilingual setups.
    *
    * @return bool
    */
-  public static function checkIfFieldExists($tableName, $columnName) {
-    $result = CRM_Core_DAO::executeQuery(
-      "SHOW COLUMNS FROM $tableName LIKE %1",
-      array(1 => array($columnName, 'String'))
-    );
-    if ($result->fetch()) {
-      return TRUE;
-    }
-    return FALSE;
+  public static function checkIfFieldExists($tableName, $columnName, $i18nRewrite = TRUE) {
+    $query = "SHOW COLUMNS FROM $tableName LIKE '%1'";
+    $dao = CRM_Core_DAO::executeQuery($query, [1 => [$columnName, 'Alphanumeric']], TRUE, NULL, FALSE, $i18nRewrite);
+    $result = $dao->fetch() ? TRUE : FALSE;
+    $dao->free();
+    return $result;
   }
 
   /**
index e3ce7a46b557c23ee8dc17f1dcd5fe2450f9e860..9629d21e1a536717554805027aab06c8e88bbe9e 100644 (file)
@@ -158,8 +158,8 @@ class CRM_Core_BAO_UFField extends CRM_Core_DAO_UFField {
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     //check if custom data profile field is disabled
index 722fc4b9dfc6d05a8d8fce2ccc4c5902d788a8f1..8e294147d973d9fb27f7cb57584fba617607f932 100644 (file)
@@ -116,8 +116,8 @@ class CRM_Core_BAO_UFGroup extends CRM_Core_DAO_UFGroup {
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   CRM_Core_DAO_UFGroup object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Core_DAO_UFGroup', $id, 'is_active', $is_active);
@@ -1673,12 +1673,12 @@ AND    ( entity_id IS NULL OR entity_id <= 0 )
   public static function getModuleUFGroup($moduleName = NULL, $count = 0, $skipPermission = TRUE, $op = CRM_Core_Permission::VIEW, $returnFields = NULL) {
     $selectFields = array('id', 'title', 'created_id', 'is_active', 'is_reserved', 'group_type');
 
-    if (CRM_Core_DAO::checkFieldExists('civicrm_uf_group', 'description')) {
+    if (CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_uf_group', 'description')) {
       // CRM-13555, since description field was added later (4.4), and to avoid any problems with upgrade
       $selectFields[] = 'description';
     }
 
-    if (CRM_Core_DAO::checkFieldExists('civicrm_uf_group', 'frontend_title')) {
+    if (CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_uf_group', 'frontend_title')) {
       $selectFields[] = 'frontend_title';
     }
 
index 3416e61a70d662aa47f4f5ae51f663c8ffcf06af..c6a495b61db5a68c2838401527d680e23c72e8a1 100644 (file)
@@ -849,6 +849,9 @@ class CRM_Core_DAO extends DB_DataObject {
   /**
    * Check if there is a given column in a specific table.
    *
+   * @deprecated
+   * @see CRM_Core_BAO_SchemaHandler::checkIfFieldExists
+   *
    * @param string $tableName
    * @param string $columnName
    * @param bool $i18nRewrite
@@ -858,16 +861,7 @@ class CRM_Core_DAO extends DB_DataObject {
    *   true if exists, else false
    */
   public static function checkFieldExists($tableName, $columnName, $i18nRewrite = TRUE) {
-    $query = "
-SHOW COLUMNS
-FROM $tableName
-LIKE %1
-";
-    $params = array(1 => array($columnName, 'String'));
-    $dao = CRM_Core_DAO::executeQuery($query, $params, TRUE, NULL, FALSE, $i18nRewrite);
-    $result = $dao->fetch() ? TRUE : FALSE;
-    $dao->free();
-    return $result;
+    return CRM_Core_BAO_SchemaHandler::checkIfFieldExists($tableName, $columnName, $i18nRewrite);
   }
 
   /**
index 6be5be07f763499ac0ec58febc8a082e08e2518f..2bfbf0aeeb9ccc43092bc65d1a5e949b0fe0badd 100644 (file)
@@ -126,7 +126,7 @@ class CRM_Core_DAO_AllCoreTables {
   /**
    * Modify indices to account for localization options.
    *
-   * @param CRM_Core_DAO $class DAO class
+   * @param string $class DAO class
    * @param array $originalIndices index definitions before localization
    *
    * @return array
index 034f0d54af1eedefd73245e9b5aec7dd4dd963a7..660ca3f05276703975d18f3b733d91e917217c4d 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Phone.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:661faad4886dd1a40784d465b906f447)
+ * (GenCodeChecksum:22802e5d7d8dfce93626004aaf6cd2e2)
  */
 
 /**
@@ -258,6 +258,10 @@ class CRM_Core_DAO_Phone extends CRM_Core_DAO {
           'type' => CRM_Utils_Type::T_INT,
           'title' => ts('Phone Type'),
           'description' => 'Which type of phone does this number belongs.',
+          'export' => TRUE,
+          'where' => 'civicrm_phone.phone_type_id',
+          'headerPattern' => '',
+          'dataPattern' => '',
           'table_name' => 'civicrm_phone',
           'entity' => 'Phone',
           'bao' => 'CRM_Core_BAO_Phone',
index abfbcdfcd44236ebd000ba53e94106db9beea29a..70e560494a7a23b1cf1d056d20073c3c42f9c2d5 100644 (file)
@@ -1589,6 +1589,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
         return $this->addEntityRef($name, $label, $props, $required);
 
       case 'Password':
+        $props['size'] = isset($props['size']) ? $props['size'] : 60;
         return $this->add('password', $name, $label, $props, $required);
 
       // Check datatypes of fields
index 9d72908401ea76c739ae6a16bcad9dbc0ca11aac..71627d76d4b039d71cbf821889ec4b00944363b5 100644 (file)
@@ -265,7 +265,7 @@ class CRM_Core_I18n_Schema {
       // add new columns
       foreach ($hash as $column => $type) {
         // CRM-7854: skip existing columns
-        if (CRM_Core_DAO::checkFieldExists($table, "{$column}_{$locale}", FALSE)) {
+        if (CRM_Core_BAO_SchemaHandler::checkIfFieldExists($table, "{$column}_{$locale}", FALSE)) {
           continue;
         }
         $queries[] = "ALTER TABLE {$table} ADD {$column}_{$locale} {$type}";
index c7c0904355069c8ce6dcc3d801dd0fb692196622..58c9904d061f38ced85e153df7c0604f2da16671 100644 (file)
@@ -317,7 +317,7 @@ class CRM_Core_Menu {
       $menu->find(TRUE);
 
       if (!CRM_Core_Config::isUpgradeMode() ||
-        CRM_Core_DAO::checkFieldExists('civicrm_menu', 'module_data', FALSE)
+        CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_menu', 'module_data', FALSE)
       ) {
         // Move unrecognized fields to $module_data.
         $module_data = array();
index 364e0b402b96b05c81678595edf63fec71829067..c71b57ed24f05c0afb07f9adc9c1993205cde1a3 100644 (file)
@@ -84,4 +84,32 @@ interface CRM_Core_PrevNextCache_Interface {
    */
   public function getSelection($cacheKey, $action = 'get');
 
+  /**
+   * Get the previous and next keys.
+   *
+   * @param string $cacheKey
+   * @param int $id1
+   * @param int $id2
+   *
+   * @return array
+   */
+  public function getPositions($cacheKey, $id1, $id2);
+
+  /**
+   * Delete an item from the prevnext cache table based on the entity.
+   *
+   * @param int $id
+   * @param string $cacheKey
+   * @param string $entityTable
+   */
+  public function deleteItem($id = NULL, $cacheKey = NULL, $entityTable = 'civicrm_contact');
+
+  /**
+   * Get count of matching rows.
+   *
+   * @param string $cacheKey
+   * @return int
+   */
+  public function getCount($cacheKey);
+
 }
index 5febfe2fedc47abe7f055f95459031198b3e26a5..2f20a63ba96721e126d86dd3a44091f9436de45e 100644 (file)
@@ -175,4 +175,41 @@ ORDER BY id
     }
   }
 
+  /**
+   * Get the previous and next keys.
+   *
+   * @param string $cacheKey
+   * @param int $id1
+   * @param int $id2
+   *
+   * NOTE: I don't really get why there are two ID columns, but we'll
+   * keep passing them through as a matter of safe-refactoring.
+   *
+   * @return array
+   */
+  public function getPositions($cacheKey, $id1, $id2) {
+    return CRM_Core_BAO_PrevNextCache::getPositions($cacheKey, $id1, $id2);
+  }
+
+  /**
+   * Delete an item from the prevnext cache table based on the entity.
+   *
+   * @param int $id
+   * @param string $cacheKey
+   * @param string $entityTable
+   */
+  public function deleteItem($id = NULL, $cacheKey = NULL, $entityTable = 'civicrm_contact') {
+    CRM_Core_BAO_PrevNextCache::deleteItem($id, $cacheKey, $entityTable);
+  }
+
+  /**
+   * Get count of matching rows.
+   *
+   * @param string $cacheKey
+   * @return int
+   */
+  public function getCount($cacheKey) {
+    return CRM_Core_BAO_PrevNextCache::getCount($cacheKey, NULL, "entity_table = 'civicrm_contact'");
+  }
+
 }
index 7be010ab6bb151c63538569e20f06813219d62ea..e24e36ff5c9959f7467e304859e816ce8d002d9d 100644 (file)
@@ -725,6 +725,7 @@ class CRM_Core_Resources {
       "bower_components/datatables/media/css/jquery.dataTables.min.css",
       "bower_components/jquery-validation/dist/jquery.validate.min.js",
       "packages/jquery/plugins/jquery.ui.datepicker.validation.min.js",
+      "js/crm.datepicker.js",
       "js/Common.js",
       "js/crm.ajax.js",
       "js/wysiwyg/crm.wysiwyg.js",
index 30ca5ffaf6d4abe8b573ac85396deddd789baa31..203c47f4c20b5b2fa6dca2cc93328c5af9812033 100644 (file)
@@ -67,8 +67,8 @@ class CRM_Event_BAO_Event extends CRM_Event_DAO_Event {
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Event_DAO_Event', $id, 'is_active', $is_active);
index 53f2720e9ca6f3fb9ed16cb3e5ee283e2fe294b8..b41b3693ccbb59d2cd907e2d27955886cfc6c664 100644 (file)
@@ -125,7 +125,6 @@ class CRM_Event_BAO_ParticipantStatusType extends CRM_Event_DAO_ParticipantStatu
 
     $returnMessages = array();
 
-    $participantRole = CRM_Event_PseudoConstant::participantRole();
     $pendingStatuses = CRM_Event_PseudoConstant::participantStatus(NULL, "class = 'Pending'");
     $expiredStatuses = CRM_Event_PseudoConstant::participantStatus(NULL, "class = 'Negative'");
     $waitingStatuses = CRM_Event_PseudoConstant::participantStatus(NULL, "class = 'Waiting'");
@@ -137,8 +136,6 @@ class CRM_Event_BAO_ParticipantStatusType extends CRM_Event_DAO_ParticipantStatu
     $expiredParticipantCount = $waitingConfirmCount = $waitingApprovalCount = 0;
 
     //get all participant who's status in class pending and waiting
-    $query = "SELECT * FROM civicrm_participant WHERE status_id IN {$statusIds} ORDER BY register_date";
-
     $query = "
    SELECT  participant.id,
            participant.contact_id,
index 5897aff52bb954058040b74c9a3fca7d9b996686..ec7863ccac2a4982ac34282bd8dda7febc9c161a 100644 (file)
@@ -1692,7 +1692,7 @@ class CRM_Event_Form_Participant extends CRM_Contribute_Form_AbstractEditPayment
               }
             }
             $this->assign('totalTaxAmount', $totalTaxAmount);
-            $this->assign('taxTerm', CRM_Utils_Array::value('tax_term', $invoiceSettings));
+            $this->assign('taxTerm', $this->getSalesTaxTerm());
             $this->assign('dataArray', $dataArray);
           }
           if (!empty($additionalParticipantDetails)) {
index 8822076944f387cdaaf4a7e0ae78e6eff8cfdfbc..baaacb4b92f85efde12dfd2b965036779cee0d37 100644 (file)
@@ -246,9 +246,6 @@ class CRM_Export_BAO_Export {
 
     $processor = new CRM_Export_BAO_ExportProcessor($exportMode, $fields, $queryOperator);
     $returnProperties = array();
-    $selectedPaymentFields = FALSE;
-    // @todo - this variable is overwritten later - it should be wholly definable in the processor fn.
-    $paymentTableId = $processor->getPaymentTableID();
 
     $phoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id');
     // Warning - this imProviders var is used in a somewhat fragile way - don't rename it
@@ -292,14 +289,6 @@ class CRM_Export_BAO_Export {
           if ($fieldName == 'event_id') {
             $returnProperties['event_id'] = 1;
           }
-          elseif (
-            $exportMode == CRM_Export_Form_Select::EVENT_EXPORT &&
-            array_key_exists($fieldName, self::componentPaymentFields())
-          ) {
-            $selectedPaymentFields = TRUE;
-            $paymentTableId = 'participant_id';
-            $returnProperties[$fieldName] = 1;
-          }
           else {
             $returnProperties[$fieldName] = 1;
           }
@@ -313,6 +302,9 @@ class CRM_Export_BAO_Export {
     else {
       $returnProperties = $processor->getDefaultReturnProperties();
     }
+    // @todo - we are working towards this being entirely a property of the processor
+    $processor->setReturnProperties($returnProperties);
+    $paymentTableId = $processor->getPaymentTableID();
 
     if ($mergeSameAddress) {
       //make sure the addressee fields are selected
@@ -463,14 +455,14 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
     $addPaymentHeader = FALSE;
 
     $paymentDetails = array();
-    if ($processor->isExportPaymentFields() || $selectedPaymentFields) {
+    if ($processor->isExportPaymentFields()) {
 
       // get payment related in for event and members
       $paymentDetails = CRM_Contribute_BAO_Contribution::getContributionDetails($exportMode, $ids);
       //get all payment headers.
       // If we haven't selected specific payment fields, load in all the
       // payment headers.
-      if (!$selectedPaymentFields) {
+      if (!$processor->isExportSpecifiedPaymentFields()) {
         $paymentHeaders = self::componentPaymentFields();
         if (!empty($paymentDetails)) {
           $addPaymentHeader = TRUE;
@@ -498,7 +490,7 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
     // for CRM-3157 purposes
     $i18n = CRM_Core_I18n::singleton();
 
-    list($outputColumns, $headerRows, $sqlColumns, $metadata) = self::getExportStructureArrays($returnProperties, $processor, $relationQuery, $selectedPaymentFields);
+    list($outputColumns, $headerRows, $sqlColumns, $metadata) = self::getExportStructureArrays($returnProperties, $processor);
 
     $limitReached = FALSE;
     while (!$limitReached) {
@@ -549,7 +541,7 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
             self::fetchRelationshipDetails($relDAO, $value, $field, $row);
           }
           else {
-            $row[$field] = self::getTransformedFieldValue($field, $iterationDAO, $fieldValue, $i18n, $metadata, $selectedPaymentFields, $paymentDetails, $paymentTableId);
+            $row[$field] = self::getTransformedFieldValue($field, $iterationDAO, $fieldValue, $i18n, $metadata, $paymentDetails, $processor);
           }
         }
 
@@ -574,7 +566,7 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
         // data will already be in $row. Otherwise, add payment related
         // information, if appropriate.
         if ($addPaymentHeader) {
-          if (!$selectedPaymentFields) {
+          if (!$processor->isExportSpecifiedPaymentFields()) {
             if ($processor->isExportPaymentFields()) {
               $paymentData = CRM_Utils_Array::value($row[$paymentTableId], $paymentDetails);
               if (!is_array($paymentData) || empty($paymentData)) {
@@ -642,7 +634,7 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
       }
       else {
         // return tableName and sqlColumns in test context
-        return array($exportTempTable, $sqlColumns);
+        return array($exportTempTable, $sqlColumns, $headerRows);
       }
 
       // delete the export temp table and component table
@@ -795,120 +787,8 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
     if (substr($field, -4) == '_a_b' || substr($field, -4) == '_b_a') {
       return;
     }
-    $queryFields = $processor->getQueryFields();
-
-    $fieldName = CRM_Utils_String::munge(strtolower($field), '_', 64);
-    if ($fieldName == 'id') {
-      $fieldName = 'civicrm_primary_id';
-    }
-
-    // early exit for master_id, CRM-12100
-    // in the DB it is an ID, but in the export, we retrive the display_name of the master record
-    // also for current_employer, CRM-16939
-    if ($fieldName == 'master_id' || $fieldName == 'current_employer') {
-      $sqlColumns[$fieldName] = "$fieldName varchar(128)";
-      return;
-    }
 
-    if (substr($fieldName, -11) == 'campaign_id') {
-      // CRM-14398
-      $sqlColumns[$fieldName] = "$fieldName varchar(128)";
-      return;
-    }
-
-    $lookUp = array('prefix_id', 'suffix_id');
-    // set the sql columns
-    if (isset($queryFields[$field]['type'])) {
-      switch ($queryFields[$field]['type']) {
-        case CRM_Utils_Type::T_INT:
-        case CRM_Utils_Type::T_BOOLEAN:
-          if (in_array($field, $lookUp)) {
-            $sqlColumns[$fieldName] = "$fieldName varchar(255)";
-          }
-          else {
-            $sqlColumns[$fieldName] = "$fieldName varchar(16)";
-          }
-          break;
-
-        case CRM_Utils_Type::T_STRING:
-          if (isset($queryFields[$field]['maxlength'])) {
-            $sqlColumns[$fieldName] = "$fieldName varchar({$queryFields[$field]['maxlength']})";
-          }
-          else {
-            $sqlColumns[$fieldName] = "$fieldName varchar(255)";
-          }
-          break;
-
-        case CRM_Utils_Type::T_TEXT:
-        case CRM_Utils_Type::T_LONGTEXT:
-        case CRM_Utils_Type::T_BLOB:
-        case CRM_Utils_Type::T_MEDIUMBLOB:
-          $sqlColumns[$fieldName] = "$fieldName longtext";
-          break;
-
-        case CRM_Utils_Type::T_FLOAT:
-        case CRM_Utils_Type::T_ENUM:
-        case CRM_Utils_Type::T_DATE:
-        case CRM_Utils_Type::T_TIME:
-        case CRM_Utils_Type::T_TIMESTAMP:
-        case CRM_Utils_Type::T_MONEY:
-        case CRM_Utils_Type::T_EMAIL:
-        case CRM_Utils_Type::T_URL:
-        case CRM_Utils_Type::T_CCNUM:
-        default:
-          $sqlColumns[$fieldName] = "$fieldName varchar(32)";
-          break;
-      }
-    }
-    else {
-      if (substr($fieldName, -3, 3) == '_id') {
-        $sqlColumns[$fieldName] = "$fieldName varchar(255)";
-      }
-      elseif (substr($fieldName, -5, 5) == '_note') {
-        $sqlColumns[$fieldName] = "$fieldName text";
-      }
-      else {
-        $changeFields = array(
-          'groups',
-          'tags',
-          'notes',
-        );
-
-        if (in_array($fieldName, $changeFields)) {
-          $sqlColumns[$fieldName] = "$fieldName text";
-        }
-        else {
-          // set the sql columns for custom data
-          if (isset($queryFields[$field]['data_type'])) {
-
-            switch ($queryFields[$field]['data_type']) {
-              case 'String':
-                // May be option labels, which could be up to 512 characters
-                $length = max(512, CRM_Utils_Array::value('text_length', $queryFields[$field]));
-                $sqlColumns[$fieldName] = "$fieldName varchar($length)";
-                break;
-
-              case 'Country':
-              case 'StateProvince':
-              case 'Link':
-                $sqlColumns[$fieldName] = "$fieldName varchar(255)";
-                break;
-
-              case 'Memo':
-                $sqlColumns[$fieldName] = "$fieldName text";
-                break;
-
-              default:
-                $sqlColumns[$fieldName] = "$fieldName varchar(255)";
-                break;
-            }
-          }
-          else {
-            $sqlColumns[$fieldName] = "$fieldName text";
-          }
-        }
-      }
-    }
+    $sqlColumns[$processor->getMungedFieldName($field)] = $processor->getSqlColumnDefinition($field);
   }
 
   /**
@@ -916,7 +796,7 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
    * @param $details
    * @param $sqlColumns
    */
-  public static function writeDetailsToTable($tableName, &$details, &$sqlColumns) {
+  public static function writeDetailsToTable($tableName, $details, $sqlColumns) {
     if (empty($details)) {
       return;
     }
@@ -933,10 +813,10 @@ FROM   $tableName
 
     $sqlClause = array();
 
-    foreach ($details as $dontCare => $row) {
+    foreach ($details as $row) {
       $id++;
       $valueString = array($id);
-      foreach ($row as $dontCare => $value) {
+      foreach ($row as $value) {
         if (empty($value)) {
           $valueString[] = "''";
         }
@@ -963,7 +843,7 @@ VALUES $sqlValueString
    *
    * @return string
    */
-  public static function createTempTable(&$sqlColumns) {
+  public static function createTempTable($sqlColumns) {
     //creating a temporary table for the search result that need be exported
     $exportTempTable = CRM_Utils_SQL_TempTable::build()->setDurable()->setCategory('export')->getName();
 
@@ -1525,36 +1405,28 @@ WHERE  {$whereClause}";
    *   Columns to go in the temp table.
    * @param \CRM_Export_BAO_ExportProcessor $processor
    * @param array|string $value
-   * @param array $phoneTypes
-   * @param array $imProviders
-   * @param string $relationQuery
-   * @param array $selectedPaymentFields
+   *
    * @return array
    */
-  public static function setHeaderRows($field, $headerRows, $sqlColumns, $processor, $value, $phoneTypes, $imProviders, $relationQuery, $selectedPaymentFields) {
+  public static function setHeaderRows($field, $headerRows, $sqlColumns, $processor, $value) {
 
     $queryFields = $processor->getQueryFields();
-    // Split campaign into 2 fields for id and title
-    if (substr($field, -14) == 'campaign_title') {
-      $headerRows[] = ts('Campaign Title');
-    }
-    elseif (substr($field, -11) == 'campaign_id') {
+    if (substr($field, -11) == 'campaign_id') {
+      // @todo - set this correctly in the xml rather than here.
       $headerRows[] = ts('Campaign ID');
     }
     elseif (isset($queryFields[$field]['title'])) {
       $headerRows[] = $queryFields[$field]['title'];
     }
-    elseif ($field == 'phone_type_id') {
-      $headerRows[] = ts('Phone Type');
-    }
     elseif ($field == 'provider_id') {
+      // @todo - set this correctly in the xml rather than here.
       $headerRows[] = ts('IM Service Provider');
     }
     elseif ($processor->isRelationshipTypeKey($field)) {
       foreach ($value as $relationField => $relationValue) {
         // below block is same as primary block (duplicate)
-        if (isset($relationQuery[$field]->_fields[$relationField]['title'])) {
-          if ($relationQuery[$field]->_fields[$relationField]['name'] == 'name') {
+        if (isset($queryFields[$relationField]['title'])) {
+          if ($queryFields[$relationField]['name'] == 'name') {
             $headerName = $field . '-' . $relationField;
           }
           else {
@@ -1562,7 +1434,7 @@ WHERE  {$whereClause}";
               $headerName = $field . '-' . 'current_employer';
             }
             else {
-              $headerName = $field . '-' . $relationQuery[$field]->_fields[$relationField]['name'];
+              $headerName = $field . '-' . $queryFields[$relationField]['name'];
             }
           }
 
@@ -1591,14 +1463,14 @@ WHERE  {$whereClause}";
             foreach (array_keys($val) as $fld) {
               $type = explode('-', $fld);
 
-              $hdr = "{$ltype}-" . $relationQuery[$field]->_fields[$type[0]]['title'];
+              $hdr = "{$ltype}-" . $queryFields[$type[0]]['title'];
 
               if (!empty($type[1])) {
                 if (CRM_Utils_Array::value(0, $type) == 'phone') {
-                  $hdr .= "-" . CRM_Utils_Array::value($type[1], $phoneTypes);
+                  $hdr .= "-" . CRM_Core_PseudoConstant::getLabel('CRM_Core_BAO_Phone', 'phone_type_id', $type[1]);
                 }
                 elseif (CRM_Utils_Array::value(0, $type) == 'im') {
-                  $hdr .= "-" . CRM_Utils_Array::value($type[1], $imProviders);
+                  $hdr .= "-" . CRM_Core_PseudoConstant::getLabel('CRM_Core_BAO_IM', 'provider_id', $type[1]);
                 }
               }
               $headerName = $field . '-' . $hdr;
@@ -1610,7 +1482,7 @@ WHERE  {$whereClause}";
       }
       self::manipulateHeaderRows($headerRows);
     }
-    elseif ($selectedPaymentFields && array_key_exists($field, self::componentPaymentFields())) {
+    elseif ($processor->isExportPaymentFields() && array_key_exists($field, self::componentPaymentFields())) {
       $headerRows[] = CRM_Utils_Array::value($field, self::componentPaymentFields());
     }
     else {
@@ -1633,8 +1505,7 @@ WHERE  {$whereClause}";
    *
    * @param array $returnProperties
    * @param \CRM_Export_BAO_ExportProcessor $processor
-   * @param string $relationQuery
-   * @param array $selectedPaymentFields
+   *
    * @return array
    *   - outputColumns Array of columns to be exported. The values don't matter but the key must match the
    *   alias for the field generated by BAO_Query object.
@@ -1651,16 +1522,15 @@ WHERE  {$whereClause}";
    *    - b) this code is old & outdated. Submit your answers to circular bin or better
    *       yet find a way to comment them for posterity.
    */
-  public static function getExportStructureArrays($returnProperties, $processor, $relationQuery, $selectedPaymentFields) {
+  public static function getExportStructureArrays($returnProperties, $processor) {
     $metadata = $headerRows = $outputColumns = $sqlColumns = array();
     $phoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id');
     $imProviders = CRM_Core_PseudoConstant::get('CRM_Core_DAO_IM', 'provider_id');
-
     $queryFields = $processor->getQueryFields();
     foreach ($returnProperties as $key => $value) {
       if ($key != 'location' || !is_array($value)) {
         $outputColumns[$key] = $value;
-        list($headerRows, $sqlColumns) = self::setHeaderRows($key, $headerRows, $sqlColumns, $processor, $value, $phoneTypes, $imProviders, $relationQuery, $selectedPaymentFields);
+        list($headerRows, $sqlColumns) = self::setHeaderRows($key, $headerRows, $sqlColumns, $processor, $value);
       }
       else {
         foreach ($value as $locationType => $locationFields) {
@@ -1685,7 +1555,7 @@ WHERE  {$whereClause}";
               $metadata[$daoFieldName]['pseudoconstant']['var'] = 'imProviders';
             }
             self::sqlColumnDefn($processor, $sqlColumns, $outputFieldName);
-            list($headerRows, $sqlColumns) = self::setHeaderRows($outputFieldName, $headerRows, $sqlColumns, $processor, $value, $phoneTypes, $imProviders, $relationQuery, $selectedPaymentFields);
+            list($headerRows, $sqlColumns) = self::setHeaderRows($outputFieldName, $headerRows, $sqlColumns, $processor, $value);
             if ($actualDBFieldName == 'country' || $actualDBFieldName == 'world_region') {
               $metadata[$daoFieldName] = array('context' => 'country');
             }
@@ -1920,12 +1790,13 @@ WHERE  {$whereClause}";
    * @param $fieldValue
    * @param $i18n
    * @param $metadata
-   * @param $selectedPaymentFields
    * @param $paymentDetails
-   * @param string $paymentTableId
+   *
+   * @param \CRM_Export_BAO_ExportProcessor $processor
+   *
    * @return string
    */
-  protected static function getTransformedFieldValue($field, $iterationDAO, $fieldValue, $i18n, $metadata, $selectedPaymentFields, $paymentDetails, $paymentTableId) {
+  protected static function getTransformedFieldValue($field, $iterationDAO, $fieldValue, $i18n, $metadata, $paymentDetails, $processor) {
 
     if ($field == 'id') {
       return $iterationDAO->contact_id;
@@ -2002,7 +1873,8 @@ WHERE  {$whereClause}";
         }
       }
     }
-    elseif ($selectedPaymentFields && array_key_exists($field, self::componentPaymentFields())) {
+    elseif ($processor->isExportSpecifiedPaymentFields() && array_key_exists($field, self::componentPaymentFields())) {
+      $paymentTableId = $processor->getPaymentTableID();
       $paymentData = CRM_Utils_Array::value($iterationDAO->$paymentTableId, $paymentDetails);
       $payFieldMapper = array(
         'componentPaymentField_total_amount' => 'total_amount',
index 8efc7102551c7b3893d8c16b8ef9d7bb61103633..d25fefcb8df01cb09d955c1a95f12adcea3e703e 100644 (file)
@@ -88,6 +88,11 @@ class CRM_Export_BAO_ExportProcessor {
    */
   protected $relationshipReturnProperties = [];
 
+  /**
+   * @var array
+   */
+  protected $returnProperties = [];
+
   /**
    * CRM_Export_BAO_ExportProcessor constructor.
    *
@@ -117,6 +122,21 @@ class CRM_Export_BAO_ExportProcessor {
     $this->requestedFields = $requestedFields;
   }
 
+
+  /**
+   * @return array
+   */
+  public function getReturnProperties() {
+    return $this->returnProperties;
+  }
+
+  /**
+   * @param array $returnProperties
+   */
+  public function setReturnProperties($returnProperties) {
+    $this->returnProperties = $returnProperties;
+  }
+
   /**
    * @return array
    */
@@ -310,9 +330,25 @@ class CRM_Export_BAO_ExportProcessor {
       ])) {
       return TRUE;
     }
+    elseif ($this->isExportSpecifiedPaymentFields()) {
+      return TRUE;
+    }
     return FALSE;
   }
 
+  /**
+   * Has specific payment fields been requested (as opposed to via all fields).
+   *
+   * If specific fields have been requested then they get added at various points.
+   *
+   * @return bool
+   */
+  public function isExportSpecifiedPaymentFields() {
+    if ($this->getRequestedFields() !== NULL && $this->hasRequestedComponentPaymentFields()) {
+      return TRUE;
+    }
+  }
+
   /**
    * Get the name of the id field in the table that connects contributions to the export entity.
    */
@@ -325,9 +361,42 @@ class CRM_Export_BAO_ExportProcessor {
       ];
       return isset($mapping[$this->getQueryMode()]) ? $mapping[$this->getQueryMode()] : '';
     }
+    elseif ($this->hasRequestedComponentPaymentFields()) {
+      return 'participant_id';
+    }
+    return FALSE;
+  }
+
+  /**
+   * Have component payment fields been requested.
+   *
+   * @return bool
+   */
+  protected function hasRequestedComponentPaymentFields() {
+    if ($this->getQueryMode() === CRM_Contact_BAO_Query::MODE_EVENT) {
+      $participantPaymentFields = array_intersect_key($this->getComponentPaymentFields(), $this->getReturnProperties());
+      if (!empty($participantPaymentFields)) {
+        return TRUE;
+      }
+    }
     return FALSE;
   }
 
+  /**
+   * Get fields that indicate payment fields have been requested for a component.
+   *
+   * @return array
+   */
+  protected function getComponentPaymentFields() {
+    return [
+      'componentPaymentField_total_amount' => ts('Total Amount'),
+      'componentPaymentField_contribution_status' => ts('Contribution Status'),
+      'componentPaymentField_received_date' => ts('Date Received'),
+      'componentPaymentField_payment_instrument' => ts('Payment Method'),
+      'componentPaymentField_transaction_id' => ts('Transaction ID'),
+    ];
+  }
+
   /**
    * Get the default properties when not specified.
    *
@@ -437,4 +506,128 @@ class CRM_Export_BAO_ExportProcessor {
     ];
   }
 
+  /**
+   * Get the sql column definition for the given field.
+   *
+   * @param $field
+   *
+   * @return mixed
+   */
+  public function getSqlColumnDefinition($field) {
+    $fieldName = $this->getMungedFieldName($field);
+
+    // early exit for master_id, CRM-12100
+    // in the DB it is an ID, but in the export, we retrive the display_name of the master record
+    // also for current_employer, CRM-16939
+    if ($fieldName == 'master_id' || $fieldName == 'current_employer') {
+      return "$fieldName varchar(128)";
+    }
+
+    if (substr($fieldName, -11) == 'campaign_id') {
+      // CRM-14398
+      return "$fieldName varchar(128)";
+    }
+
+    $queryFields = $this->getQueryFields();
+    $lookUp = ['prefix_id', 'suffix_id'];
+    // set the sql columns
+    if (isset($queryFields[$field]['type'])) {
+      switch ($queryFields[$field]['type']) {
+        case CRM_Utils_Type::T_INT:
+        case CRM_Utils_Type::T_BOOLEAN:
+          if (in_array($field, $lookUp)) {
+            return "$fieldName varchar(255)";
+          }
+          else {
+            return "$fieldName varchar(16)";
+          }
+
+        case CRM_Utils_Type::T_STRING:
+          if (isset($queryFields[$field]['maxlength'])) {
+            return "$fieldName varchar({$queryFields[$field]['maxlength']})";
+          }
+          else {
+            return "$fieldName varchar(255)";
+          }
+
+        case CRM_Utils_Type::T_TEXT:
+        case CRM_Utils_Type::T_LONGTEXT:
+        case CRM_Utils_Type::T_BLOB:
+        case CRM_Utils_Type::T_MEDIUMBLOB:
+          return "$fieldName longtext";
+
+        case CRM_Utils_Type::T_FLOAT:
+        case CRM_Utils_Type::T_ENUM:
+        case CRM_Utils_Type::T_DATE:
+        case CRM_Utils_Type::T_TIME:
+        case CRM_Utils_Type::T_TIMESTAMP:
+        case CRM_Utils_Type::T_MONEY:
+        case CRM_Utils_Type::T_EMAIL:
+        case CRM_Utils_Type::T_URL:
+        case CRM_Utils_Type::T_CCNUM:
+        default:
+          return "$fieldName varchar(32)";
+      }
+    }
+    else {
+      if (substr($fieldName, -3, 3) == '_id') {
+        return "$fieldName varchar(255)";
+      }
+      elseif (substr($fieldName, -5, 5) == '_note') {
+        return "$fieldName text";
+      }
+      else {
+        $changeFields = [
+          'groups',
+          'tags',
+          'notes',
+        ];
+
+        if (in_array($fieldName, $changeFields)) {
+          return "$fieldName text";
+        }
+        else {
+          // set the sql columns for custom data
+          if (isset($queryFields[$field]['data_type'])) {
+
+            switch ($queryFields[$field]['data_type']) {
+              case 'String':
+                // May be option labels, which could be up to 512 characters
+                $length = max(512, CRM_Utils_Array::value('text_length', $queryFields[$field]));
+                return "$fieldName varchar($length)";
+
+              case 'Country':
+              case 'StateProvince':
+              case 'Link':
+                return "$fieldName varchar(255)";
+
+              case 'Memo':
+                return "$fieldName text";
+
+              default:
+                return "$fieldName varchar(255)";
+            }
+          }
+          else {
+            return "$fieldName text";
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Get the munged field name.
+   *
+   * @param string $field
+   * @return string
+   */
+  public function getMungedFieldName($field) {
+    $fieldName = CRM_Utils_String::munge(strtolower($field), '_', 64);
+    if ($fieldName == 'id') {
+      $fieldName = 'civicrm_primary_id';
+    }
+    return $fieldName;
+  }
+
 }
index e171ee9a48bd943685a795e1d81eeffde2a5599a..9e37d4ceaf4db9f34c7ede44bcde362ab9ba4930 100644 (file)
@@ -67,8 +67,8 @@ class CRM_Financial_BAO_FinancialAccount extends CRM_Financial_DAO_FinancialAcco
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return CRM_Core_DAO|null
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Financial_DAO_FinancialAccount', $id, 'is_active', $is_active);
index 3054bb464989e11fb7ce2c35a8ea0af17a533842..e312d2ebc94feeff3312138ed093699420efe7ef 100644 (file)
@@ -150,9 +150,8 @@ class CRM_Financial_BAO_PaymentProcessor extends CRM_Financial_DAO_PaymentProces
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return CRM_Financial_DAO_PaymentProcessor|null
-   *   DAO object on success, null otherwise
-   *
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Financial_DAO_PaymentProcessor', $id, 'is_active', $is_active);
@@ -273,7 +272,7 @@ class CRM_Financial_BAO_PaymentProcessor extends CRM_Financial_DAO_PaymentProces
    */
   public static function getAllPaymentProcessors($mode = 'all', $reset = FALSE, $isCurrentDomainOnly = TRUE) {
 
-    $cacheKey = 'CRM_Financial_BAO_Payment_Processor_' . $mode . '_' . CRM_Core_Config::domainID();
+    $cacheKey = 'CRM_Financial_BAO_Payment_Processor_' . $mode . '_' . $isCurrentDomainOnly . '_' . CRM_Core_Config::domainID();
     if (!$reset) {
       $processors = CRM_Utils_Cache::singleton()->get($cacheKey);
       if (!empty($processors)) {
@@ -370,10 +369,10 @@ class CRM_Financial_BAO_PaymentProcessor extends CRM_Financial_DAO_PaymentProces
   public static function getPaymentProcessors($capabilities = array(), $ids = FALSE) {
     $testProcessors = in_array('TestMode', $capabilities) ? self::getAllPaymentProcessors('test') : array();
     if (is_array($ids)) {
-      $processors = self::getAllPaymentProcessors('all', TRUE, FALSE);
+      $processors = self::getAllPaymentProcessors('all', FALSE, FALSE);
     }
     else {
-      $processors = self::getAllPaymentProcessors('all', TRUE);
+      $processors = self::getAllPaymentProcessors('all');
     }
 
     if (in_array('TestMode', $capabilities) && is_array($ids)) {
index 6667d8bab7d92f7ade1ab0a013f2c91256ca00fb..70d99b4c555f335b5aa40da3b60d2f09a349fe95 100644 (file)
@@ -73,9 +73,8 @@ class CRM_Financial_BAO_PaymentProcessorType extends CRM_Financial_DAO_PaymentPr
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
-   *
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Financial_DAO_PaymentProcessorType', $id, 'is_active', $is_active);
diff --git a/CRM/Financial/Form/SalesTaxTrait.php b/CRM/Financial/Form/SalesTaxTrait.php
new file mode 100644 (file)
index 0000000..072126a
--- /dev/null
@@ -0,0 +1,90 @@
+<?php
+/*
+  +--------------------------------------------------------------------+
+  | CiviCRM version 4.7                                                |
+  +--------------------------------------------------------------------+
+  | 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        |
+  +--------------------------------------------------------------------+
+ */
+
+/**
+ *
+ * @package CRM
+ * @copyright CiviCRM LLC (c) 2004-2018
+ */
+
+trait CRM_Financial_Form_SalesTaxTrait {
+
+  /**
+   * Assign the sales tax term to the template.
+   */
+  public function assignSalesTaxTermToTemplate() {
+    $this->assign('taxTerm', $this->getSalesTaxTerm());
+  }
+
+  /**
+   * Assign sales tax rates to the template.
+   */
+  public function assignSalesTaxRates() {
+    $this->assign('taxRates', json_encode(CRM_Core_PseudoConstant::getTaxRates()));
+  }
+
+  /**
+   * Return the string to be assigned to the template for sales tax - e.g GST, VAT.
+   *
+   * @return string
+   */
+  public function getSalesTaxTerm() {
+    $invoiceSettings = Civi::settings()->get('contribution_invoice_settings');
+    $invoicing = CRM_Utils_Array::value('invoicing', $invoiceSettings);
+    if (!$invoicing) {
+      return '';
+    }
+    return CRM_Utils_Array::value('tax_term', $invoiceSettings);
+  }
+
+  /**
+   * Assign information to the template required for sales tax purposes.
+   */
+  public function assignSalesTaxMetadataToTemplate() {
+    $this->assignSalesTaxRates();
+    $this->assignSalesTaxTermToTemplate();
+  }
+
+  /**
+   * Get sales tax rates.
+   *
+   * @return array
+   */
+  public function getTaxRatesForFinancialTypes() {
+    return CRM_Core_PseudoConstant::getTaxRates();
+  }
+
+  /**
+   * @param int $financialTypeID
+   *
+   * @return string
+   */
+  public function getTaxRateForFinancialType($financialTypeID) {
+    return CRM_Utils_Array::value($financialTypeID, $this->getTaxRatesForFinancialTypes());
+  }
+
+}
index 969d4b57e0471e04e922554ab57c36807030100a..6840e3edeee9b0e15f5af408e71c20a9a9f63049 100644 (file)
@@ -67,8 +67,8 @@ class CRM_Mailing_BAO_Component extends CRM_Mailing_DAO_Component {
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Mailing_DAO_Component', $id, 'is_active', $is_active);
index 2fa7203cc157b07e4c189b567a8047086638aff3..7c7d4518648272d70d23115f68202e1bd098deeb 100644 (file)
@@ -74,8 +74,8 @@ class CRM_Member_BAO_MembershipStatus extends CRM_Member_DAO_MembershipStatus {
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Member_DAO_MembershipStatus', $id, 'is_active', $is_active);
index 796e047a0731b3b474d446b7240f668795a69e39..9c0a4e683a2bbeb1cfd231244e6ab3ce3b173d33 100644 (file)
@@ -76,8 +76,8 @@ class CRM_Member_BAO_MembershipType extends CRM_Member_DAO_MembershipType {
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Member_DAO_MembershipType', $id, 'is_active', $is_active);
index 8b7301f8194de737cedff2c0c9a6797d001b4a91..275933dc11e694ec934074ab98b06b0da101cebc 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Member/MembershipType.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:51b478b01b1ef20a54b1039ccc29d0ab)
+ * (GenCodeChecksum:b36330fa029a5c1467441e89b7c45c63)
  */
 
 /**
@@ -490,6 +490,9 @@ class CRM_Member_DAO_MembershipType extends CRM_Core_DAO {
           'entity' => 'MembershipType',
           'bao' => 'CRM_Member_BAO_MembershipType',
           'localizable' => 0,
+          'html' => [
+            'type' => 'Radio',
+          ],
           'pseudoconstant' => [
             'callback' => 'CRM_Core_SelectValues::memberAutoRenew',
           ]
index 4c41ab201f61d56b1619bca66fe50aed72309700..2d2a757264135909b5722b58ae41c452a82d441d 100644 (file)
@@ -189,6 +189,7 @@ class CRM_Member_Form extends CRM_Contribute_Form_AbstractEditPayment {
    * Build the form object.
    */
   public function buildQuickForm() {
+    $this->assignSalesTaxMetadataToTemplate();
 
     $this->addPaymentProcessorSelect(TRUE, FALSE, TRUE);
     CRM_Core_Payment_Form::buildPaymentForm($this, $this->_paymentProcessor, FALSE, TRUE, $this->getDefaultPaymentInstrumentId());
index b81bc5ec3bb6c1bd5736a8a6999d14fdf7764986..62afa07d483b62f4d338d52edfc2ed1dd2e628ec 100644 (file)
@@ -396,14 +396,8 @@ class CRM_Member_Form_Membership extends CRM_Member_Form {
    */
   public function buildQuickForm() {
 
-    $this->assign('taxRates', json_encode(CRM_Core_PseudoConstant::getTaxRates()));
-
     $this->assign('currency', CRM_Core_Config::singleton()->defaultCurrencySymbol);
-    $invoiceSettings = Civi::settings()->get('contribution_invoice_settings');
-    $invoicing = CRM_Utils_Array::value('invoicing', $invoiceSettings);
-    if (isset($invoicing)) {
-      $this->assign('taxTerm', CRM_Utils_Array::value('tax_term', $invoiceSettings));
-    }
+
     // build price set form.
     $buildPriceSet = FALSE;
     if ($this->_priceSetId || !empty($_POST['price_set_id'])) {
@@ -1685,7 +1679,8 @@ class CRM_Member_Form_Membership extends CRM_Member_Form {
         }
         if ($taxAmount) {
           $this->assign('totalTaxAmount', $totalTaxAmount);
-          $this->assign('taxTerm', CRM_Utils_Array::value('tax_term', $invoiceSettings));
+          // Not sure why would need this on Submit.... unless it's being used when sending mails in which case this is the wrong place
+          $this->assign('taxTerm', $this->getSalesTaxTerm());
         }
         $this->assign('dataArray', $dataArray);
       }
index 25c90c49699081035d74b470da92e6f3c26e01f6..d5eb08968a686c0ae65cb3bfb70c8abcbdc1b320 100644 (file)
@@ -244,10 +244,7 @@ class CRM_Member_Form_MembershipRenewal extends CRM_Member_Form {
     }
 
     //CRM-16950
-    $taxRates = CRM_Core_PseudoConstant::getTaxRates();
-    $taxRate = CRM_Utils_Array::value($this->allMembershipTypeDetails[$defaults['membership_type_id']]['financial_type_id'], $taxRates);
-
-    $invoiceSettings = Civi::settings()->get('contribution_invoice_settings');
+    $taxRate = $this->getTaxRateForFinancialType($this->allMembershipTypeDetails[$defaults['membership_type_id']]['financial_type_id']);
 
     // auto renew options if enabled for the membership
     $options = CRM_Core_SelectValues::memberAutoRenew();
@@ -276,7 +273,8 @@ class CRM_Member_Form_MembershipRenewal extends CRM_Member_Form {
         //CRM-16950
         $taxAmount = NULL;
         $totalAmount = CRM_Utils_Array::value('minimum_fee', $values);
-        if (CRM_Utils_Array::value($values['financial_type_id'], $taxRates)) {
+        // @todo - feels a bug - we use taxRate from the form default rather than from the specified type?!?
+        if ($this->getTaxRateForFinancialType($values['financial_type_id'])) {
           $taxAmount = ($taxRate / 100) * CRM_Utils_Array::value('minimum_fee', $values);
           $totalAmount = $totalAmount + $taxAmount;
         }
@@ -287,7 +285,7 @@ class CRM_Member_Form_MembershipRenewal extends CRM_Member_Form {
           'financial_type_id' => CRM_Utils_Array::value('financial_type_id', $values),
           'total_amount' => CRM_Utils_Money::format($totalAmount, NULL, '%a'),
           'total_amount_numeric' => $totalAmount,
-          'tax_message' => $taxAmount ? ts("Includes %1 amount of %2", array(1 => CRM_Utils_Array::value('tax_term', $invoiceSettings), 2 => CRM_Utils_Money::format($taxAmount))) : $taxAmount,
+          'tax_message' => $taxAmount ? ts("Includes %1 amount of %2", array(1 => $this->getSalesTaxTerm(), 2 => CRM_Utils_Money::format($taxAmount))) : $taxAmount,
         );
 
         if (!empty($values['auto_renew'])) {
index 726f3191e05d040d343d59810cd0ec6746f718b9..3a5d4926bc9361288e8174521b7388bba370e464 100644 (file)
@@ -62,9 +62,77 @@ class CRM_Member_Form_MembershipType extends CRM_Member_Form_MembershipConfig {
    * Set entity fields to be assigned to the form.
    */
   protected function setEntityFields() {
-    // TODO: Add fields here per CRM/Admin/Form/RelationshipType.php.
-    // ... It's not as easy because MembershipType has multiple conditional fields/javascript etc.
-    $this->entityFields = [];
+    $this->entityFields = [
+      'name' => [
+        'required' => 'TRUE',
+        'name' => 'name',
+        'description' => ts("e.g. 'Student', 'Senior', 'Honor Society'..."),
+      ],
+      'description' => [
+        'name' => 'description',
+        'description' => ts("Description of this membership type for internal use. May include eligibility, benefits, terms, etc."),
+      ],
+      'member_of_contact_id' => [
+        'name' => 'member_of_contact_id',
+        'description' => ts("Members assigned this membership type belong to which organization (e.g. this is for membership in 'Save the Whales - Northwest Chapter'). NOTE: This organization/group/chapter must exist as a CiviCRM Organization type contact."),
+      ],
+      'minimum_fee' => [
+        'name' => 'minimum_fee',
+        'description' => ts('Minimum fee required for this membership type. For free/complimentary memberships - set minimum fee to zero (0). NOTE: When using CiviCRM to process sales taxes this should be the tax exclusive amount.'),
+        'formatter' => 'crmMoney',
+      ],
+      'financial_type_id' => [
+        'name' => 'financial_type_id',
+        'description' => ts('Select the financial type assigned to fees for this membership type (for example \'Membership Fees\'). This is required for all membership types - including free or complimentary memberships.'),
+      ],
+      'auto_renew' => [
+        'name' => 'auto_renew',
+        'options' => CRM_Core_SelectValues::memberAutoRenew(),
+        'place_holder' => ts('You will need to select and configure a supported payment processor (currently Authorize.Net, PayPal Pro, or PayPal Website Standard) in order to offer automatically renewing memberships.'),
+      ],
+      'duration_interval' => [
+        'name' => 'duration_interval',
+      ],
+      'duration_unit' => [
+        'name' => 'duration_unit',
+        'description' => ts('Duration of this membership (e.g. 30 days, 2 months, 5 years, 1 lifetime)'),
+      ],
+      'period_type' => [
+        'name' => 'period_type',
+        'description' => ts("Select 'rolling' if membership periods begin at date of signup. Select 'fixed' if membership periods begin on a set calendar date."),
+        'help' => ['id' => 'period-type', 'file' => "CRM/Member/Page/MembershipType.hlp"],
+      ],
+      'fixed_period_start_day' => [
+        'name' => 'fixed_period_start_day',
+        'description' => ts("Month and day on which a <strong>fixed</strong> period membership or subscription begins. Example: A fixed period membership with Start Day set to Jan 01 means that membership periods would be 1/1/06 - 12/31/06 for anyone signing up during 2006."),
+      ],
+      'fixed_period_rollover_day' => [
+        'name' => 'fixed_period_rollover_day',
+        'description' => ts('Membership signups on or after this date cover the following calendar year as well. Example: If the rollover day is November 30, membership period for signups during December will cover the following year.'),
+      ],
+      'relationship_type_id' => [
+        'name' => 'relationship_type_id',
+      ],
+      'max_related' => [
+        'name' => 'max_related',
+        'description' => ts('Maximum number of related memberships (leave blank for unlimited).'),
+      ],
+      'visibility' => [
+        'name' => 'visibility',
+        'description' => ts("Can this membership type be used for self-service signups ('Public'), or is it only for CiviCRM users with 'Edit Contributions' permission ('Admin')."),
+      ],
+      'weight' => [
+        'name' => 'weight',
+      ],
+      'is_active' => [
+        'name' => 'is_active',
+      ],
+    ];
+
+    if (!CRM_Financial_BAO_PaymentProcessor::hasPaymentProcessorSupporting(array('Recurring'))) {
+      $this->entityFields['auto_renew']['not-auto-addable'] = TRUE;
+      $this->entityFields['auto_renew']['documentation_link'] = ['page' => 'user/contributions/payment-processors'];
+    }
   }
 
   /**
@@ -176,26 +244,17 @@ class CRM_Member_Form_MembershipType extends CRM_Member_Form_MembershipConfig {
     if ($this->_action & CRM_Core_Action::DELETE) {
       return;
     }
-
-    $this->applyFilter('__ALL__', 'trim');
-    $this->addField('name', [], TRUE);
-    $this->addField('description');
-    $this->addField('minimum_fee');
-    $this->addField('duration_unit', [], TRUE);
-    $this->addField('period_type', [], TRUE);
-    $this->addField('is_active');
-    $this->addField('weight');
-    $this->addField('max_related');
+    // This is a temporary variable as we work towards moving over towards using the EntityField.tpl.
+    // Fields in this array have been tested & in the tpl have been switched over to metadata.
+    // Note this kinda 'works from the top' - ie. once we hit a field that needs some thought we need
+    // to stop & make that one work.
+    $this->assign('tpl_standardised_fields', ['name', 'description', 'member_of_contact_id', 'minimum_fee']);
 
     $this->addRule('name', ts('A membership type with this name already exists. Please select another name.'),
       'objectExists', array('CRM_Member_DAO_MembershipType', $this->_id)
     );
     $this->addRule('minimum_fee', ts('Please enter a monetary value for the Minimum Fee.'), 'money');
 
-    $this->add('text', 'duration_interval', ts('Duration Interval'),
-      CRM_Core_DAO::getAttribute('CRM_Member_DAO_MembershipType', 'duration_interval')
-    );
-
     $props = array('api' => array('params' => array('contact_type' => 'Organization')));
     $this->addEntityRef('member_of_contact_id', ts('Membership Organization'), $props, TRUE);
 
index b21a3a21469cc6e41f9883519557d8336fa74413..eaea71fbde4bd7f98f449ba55bc2cabb50798407 100644 (file)
@@ -709,7 +709,9 @@ WHERE pcp.id = %1 AND cc.contribution_status_id =1 AND cc.is_test = 0";
    *   Campaign page id.
    *
    * @param bool $is_active
-   * @return null
+   *
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setDisable($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_PCP_DAO_PCP', $id, 'is_active', $is_active);
index 0dd12fd66c55bc3038cda89a903e86ad903515fb..4e63f49f59a578e97c1add4b40d3871c6667f547 100644 (file)
@@ -225,8 +225,8 @@ class CRM_Price_BAO_PriceField extends CRM_Price_DAO_PriceField {
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise.
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Price_DAO_PriceField', $id, 'is_active', $is_active);
index b309facc0816caddf6b97f2fbacafee3ec99cff5..a8c0b1b587ffe87af76bce1e015567d015c31cdb 100644 (file)
@@ -223,9 +223,8 @@ class CRM_Price_BAO_PriceFieldValue extends CRM_Price_DAO_PriceFieldValue {
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
-   *
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Price_DAO_PriceFieldValue', $id, 'is_active', $is_active);
index 1f8d2fe79bf6acf189714a2e22e9b6c26c5550d4..922653857d8f5264384f966e71c77ad992266b09 100644 (file)
@@ -105,10 +105,8 @@ class CRM_Price_BAO_PriceSet extends CRM_Price_DAO_PriceSet {
    *   Id of the database record.
    * @param $isActive
    *
-   * @internal param bool $is_active value we want to set the is_active field
-   *
-   * @return Object
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $isActive) {
     return CRM_Core_DAO::setFieldValue('CRM_Price_DAO_PriceSet', $id, 'is_active', $isActive);
@@ -1473,8 +1471,8 @@ GROUP BY     mt.member_of_contact_id ";
    * @param bool $isQuickConfig we want to set the is_quick_config field.
    *   Value we want to set the is_quick_config field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsQuickConfig($id, $isQuickConfig) {
     return CRM_Core_DAO::setFieldValue('CRM_Price_DAO_PriceSet', $id, 'is_quick_config', $isQuickConfig);
index 3575ce91c9aa66407d601bbdb33938abe8c89eec..289f8d15dffd256c1867dfa3bc6b7133231b502d 100644 (file)
@@ -41,12 +41,12 @@ class CRM_Upgrade_Incremental_General {
   /**
    * The recommended PHP version.
    */
-  const RECOMMENDED_PHP_VER = '7.0';
+  const RECOMMENDED_PHP_VER = '7.1';
 
   /**
    * The previous recommended PHP version.
    */
-  const MIN_RECOMMENDED_PHP_VER = '5.6';
+  const MIN_RECOMMENDED_PHP_VER = '7.0';
 
   /**
    * The minimum PHP version required to install Civi.
diff --git a/CRM/Upgrade/Incremental/php/FiveSix.php b/CRM/Upgrade/Incremental/php/FiveSix.php
new file mode 100644 (file)
index 0000000..94f0d4c
--- /dev/null
@@ -0,0 +1,87 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 5                                                  |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2017                                |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM.                                    |
+ |                                                                    |
+ | CiviCRM is free software; you can copy, modify, and distribute it  |
+ | under the terms of the GNU Affero General Public License           |
+ | Version 3, 19 November 2007.                                       |
+ |                                                                    |
+ | CiviCRM is distributed in the hope that it will be useful, but     |
+ | WITHOUT ANY WARRANTY; without even the implied warranty of         |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |
+ | See the GNU Affero General Public License for more details.        |
+ |                                                                    |
+ | You should have received a copy of the GNU Affero General Public   |
+ | License along with this program; if not, contact CiviCRM LLC       |
+ | at info[AT]civicrm[DOT]org. If you have questions about the        |
+ | GNU Affero General Public License or the licensing of CiviCRM,     |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ * Upgrade logic for FiveSix */
+class CRM_Upgrade_Incremental_php_FiveSix 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 has been added called %1 This Permission is now used to control access to the Manage Tags screen', array(1 => 'manage tags')) . '</p>';
+    // }
+  }
+
+  /**
+   * Compute any messages which should be displayed after upgrade.
+   *
+   * @param string $postUpgradeMessage
+   *   alterable.
+   * @param string $rev
+   *   an intermediate version; note that setPostUpgradeMessage is called repeatedly with different $revs.
+   */
+  public function setPostUpgradeMessage(&$postUpgradeMessage, $rev) {
+    // Example: Generate a post-upgrade message.
+    // if ($rev == '5.12.34') {
+    //   $postUpgradeMessage .= '<br /><br />' . ts("By default, CiviCRM now disables the ability to import directly from SQL. To use this feature, you must explicitly grant permission 'import SQL datasource'.");
+    // }
+  }
+
+  /*
+   * Important! All upgrade functions MUST add a 'runSql' task.
+   * Uncomment and use the following template for a new upgrade version
+   * (change the x in the function name):
+   */
+
+  //  /**
+  //   * Upgrade function.
+  //   *
+  //   * @param string $rev
+  //   */
+  //  public function upgrade_5_0_x($rev) {
+  //    $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev);
+  //    $this->addTask('Do the foo change', 'taskFoo', ...);
+  //    // Additional tasks here...
+  //    // Note: do not use ts() in the addTask description because it adds unnecessary strings to transifex.
+  //    // The above is an exception because 'Upgrade DB to %1: SQL' is generic & reusable.
+  //  }
+
+  // public static function taskFoo(CRM_Queue_TaskContext $ctx, ...) {
+  //   return TRUE;
+  // }
+
+}
index 0f667a7c919ff74bc03008beda9439e66db1ef98..2fa54ff1d459fcd1ae0995d6b149f983ddfa442f 100644 (file)
@@ -1140,7 +1140,7 @@ FROM `civicrm_dashboard_contact` JOIN `civicrm_contact` WHERE civicrm_dashboard_
    * @return bool
    */
   public static function addMailingTemplateType() {
-    if (!CRM_Core_DAO::checkFieldExists('civicrm_mailing', 'template_type', FALSE)) {
+    if (!CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_mailing', 'template_type', FALSE)) {
       CRM_Core_DAO::executeQuery('
         ALTER TABLE civicrm_mailing
         ADD COLUMN `template_type` varchar(64)  NOT NULL DEFAULT \'traditional\' COMMENT \'The language/processing system used for email templates.\',
index e224cac48a71262f6f5981fc274f000182e38a14..f1030b546175b6a61f847445318cd8b1d1bb8da7 100644 (file)
@@ -277,7 +277,7 @@ WHERE ccp.financial_type_id IS NULL and cp.cost > 0');
    */
   public function upgrade_4_3_alpha2($rev) {
     //CRM-11847
-    $isColumnPresent = CRM_Core_DAO::checkFieldExists('civicrm_dedupe_rule_group', 'is_default');
+    $isColumnPresent = CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_dedupe_rule_group', 'is_default');
     if ($isColumnPresent) {
       CRM_Core_DAO::executeQuery('ALTER TABLE civicrm_dedupe_rule_group DROP COLUMN is_default');
     }
@@ -300,7 +300,7 @@ WHERE ccp.financial_type_id IS NULL and cp.cost > 0');
     // CRM-12002
     if (
       CRM_Core_DAO::checkTableExists('log_civicrm_line_item') &&
-      CRM_Core_DAO::checkFieldExists('log_civicrm_line_item', 'label')
+      CRM_Core_BAO_SchemaHandler::checkIfFieldExists('log_civicrm_line_item', 'label')
     ) {
       CRM_Core_DAO::executeQuery('ALTER TABLE `log_civicrm_line_item` CHANGE `label` `label` VARCHAR(255) NULL DEFAULT NULL');
     }
@@ -335,7 +335,7 @@ WHERE ccp.financial_type_id IS NULL and cp.cost > 0');
     // CRM-12205
     if (
       CRM_Core_DAO::checkTableExists('log_civicrm_financial_trxn') &&
-      CRM_Core_DAO::checkFieldExists('log_civicrm_financial_trxn', 'trxn_id')
+      CRM_Core_BAO_SchemaHandler::checkIfFieldExists('log_civicrm_financial_trxn', 'trxn_id')
     ) {
       CRM_Core_DAO::executeQuery('ALTER TABLE `log_civicrm_financial_trxn` CHANGE `trxn_id` `trxn_id` VARCHAR(255) NULL DEFAULT NULL');
     }
@@ -343,7 +343,7 @@ WHERE ccp.financial_type_id IS NULL and cp.cost > 0');
     // CRM-12367 - add this column to single lingual sites only
     $upgrade = new CRM_Upgrade_Form();
     if (!$upgrade->multilingual &&
-      !CRM_Core_DAO::checkFieldExists('civicrm_premiums', 'premiums_nothankyou_label')
+      !CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_premiums', 'premiums_nothankyou_label')
     ) {
       $query = "
 ALTER TABLE civicrm_premiums
@@ -925,7 +925,7 @@ AND TABLE_SCHEMA = %1
       }
     }
     // check if column contact_id is present or not in civicrm_financial_account
-    $fieldExists = CRM_Core_DAO::checkFieldExists('civicrm_financial_account', 'contact_id', FALSE);
+    $fieldExists = CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_financial_account', 'contact_id', FALSE);
     if (!$fieldExists) {
       $query = "
 ALTER TABLE civicrm_financial_account
diff --git a/CRM/Upgrade/Incremental/sql/5.5.beta1.mysql.tpl b/CRM/Upgrade/Incremental/sql/5.5.beta1.mysql.tpl
new file mode 100644 (file)
index 0000000..236a53f
--- /dev/null
@@ -0,0 +1 @@
+{* file to handle db changes in 5.5.beta1 during upgrade *}
diff --git a/CRM/Upgrade/Incremental/sql/5.6.alpha1.mysql.tpl b/CRM/Upgrade/Incremental/sql/5.6.alpha1.mysql.tpl
new file mode 100644 (file)
index 0000000..7e2f820
--- /dev/null
@@ -0,0 +1 @@
+{* file to handle db changes in 5.6.alpha1 during upgrade *}
index 0abb97f3a7a94a6ffb92fa35b20844517953da6a..8f7ef8c62a504fdf181856ff9376d6a2890aa6ce 100644 (file)
@@ -172,8 +172,8 @@ class CRM_Upgrade_Snapshot_V4p2_Price_BAO_Field extends CRM_Upgrade_Snapshot_V4p
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Upgrade_Snapshot_V4p2_Price_DAO_Field', $id, 'is_active', $is_active);
index 0bc631b35fdccc69dfecf55c7d1b771e4dfef7c9..10b6c2cd93615541b0ac585f0e4595f89e24dcb2 100644 (file)
@@ -177,9 +177,8 @@ class CRM_Upgrade_Snapshot_V4p2_Price_BAO_FieldValue extends CRM_Upgrade_Snapsho
    * @param bool $is_active
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
-   *
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $is_active) {
     return CRM_Core_DAO::setFieldValue('CRM_Upgrade_Snapshot_V4p2_Price_DAO_FieldValue', $id, 'is_active', $is_active);
index 080524203a1c96e2892f63ec2c0d916aa22e2e4a..4b0d898963075d326204d48fcc6cce4dbd627146 100644 (file)
@@ -82,8 +82,8 @@ class CRM_Upgrade_Snapshot_V4p2_Price_BAO_Set extends CRM_Upgrade_Snapshot_V4p2_
    * @param bool $isActive
    *   Value we want to set the is_active field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsActive($id, $isActive) {
     return CRM_Core_DAO::setFieldValue('CRM_Upgrade_Snapshot_V4p2_Price_DAO_Set', $id, 'is_active', $isActive);
@@ -1134,8 +1134,8 @@ GROUP BY     mt.member_of_contact_id";
    * @param bool $isQuickConfig we want to set the is_quick_config field.
    *   Value we want to set the is_quick_config field.
    *
-   * @return Object
-   *   DAO object on success, null otherwise
+   * @return bool
+   *   true if we found and updated the object, else false
    */
   public static function setIsQuickConfig($id, $isQuickConfig) {
     return CRM_Core_DAO::setFieldValue('CRM_Upgrade_Snapshot_V4p2_Price_DAO_Set', $id, 'is_quick_config', $isQuickConfig);
index 358f260181e9b593e44d967613c5f26141bd5893..0ce1128c83ba2019c878996d45845742c7923f81 100644 (file)
@@ -160,6 +160,9 @@ class CRM_Utils_Cache {
    * @param array $params
    *   Array with keys:
    *   - name: string, unique symbolic name.
+   *     For a naming convention, use `snake_case` or `CamelCase` to maximize
+   *     portability/cleanliness. Any other punctuation or whitespace
+   *     should function correctly, but it can be harder to inspect/debug.
    *   - type: array|string, list of acceptable cache types, in order of preference.
    *   - prefetch: bool, whether to prefetch all data in cache (if possible).
    * @return CRM_Utils_Cache_Interface
@@ -169,6 +172,10 @@ class CRM_Utils_Cache {
   public static function create($params = array()) {
     $types = (array) $params['type'];
 
+    if (!empty($params['name'])) {
+      $params['name'] = CRM_Core_BAO_Cache::cleanKey($params['name']);
+    }
+
     foreach ($types as $type) {
       switch ($type) {
         case '*memory*':
index a253716e42f30e6b639bcb4157153a31006d8be1..0615165c4c49e213cbdfc8fcc713353e87371196 100644 (file)
@@ -68,7 +68,7 @@ class CRM_Utils_Check_Component_Env extends CRM_Utils_Check_Component {
     elseif (version_compare($phpVersion, CRM_Upgrade_Incremental_General::MIN_INSTALL_PHP_VER) >= 0) {
       $messages[] = new CRM_Utils_Check_Message(
         __FUNCTION__,
-        ts('This system uses PHP version %1. This meets the minimum requirements for CiviCRM to function but is not recommended. At least PHP version %2 is recommended; the preferrred version is %3.',
+        ts('This system uses PHP version %1. This meets the minimum requirements for CiviCRM to function but is not recommended. At least PHP version %2 is recommended; the preferred version is %3.',
           array(
             1 => $phpVersion,
             2 => CRM_Upgrade_Incremental_General::MIN_RECOMMENDED_PHP_VER,
index f87c8eac1150f8102a1136e4be7bbba8af49888d..e11a2eb67ad98627a5c9f3a2758c01e2a6d3b367 100644 (file)
@@ -84,7 +84,7 @@ class CRM_Utils_GeocodeProvider {
       // or extend a base class. While we identify and implement a geocoding
       // abstraction library (rather than continue to roll our own), we settle for
       // this check.
-      if (!method_exists($provider, 'format')) {
+      if (!method_exists($provider, 'format') && $provider !== FALSE) {
         Civi::log()->error('Configured geocoder is invalid, must provide a format method', ['geocode_class' => $provider]);
         $provider = FALSE;
       }
index e88076c21735a520bf9440825df4d50f55421673..fb5bb879ea4e173673bc3672a59e41d4a1f95651 100644 (file)
@@ -1417,7 +1417,14 @@ class CRM_Utils_System {
     // flush out all cache entries so we can reload new data
     // a bit aggressive, but livable for now
     CRM_Utils_Cache::singleton()->flush();
-    if (Civi\Core\Container::isContainerBooted()) {
+
+    // Traditionally, systems running on memory-backed caches were quite
+    // zealous about destroying *all* memory-backed caches during a flush().
+    // These flushes simulate that legacy behavior. However, they should probably
+    // be removed at some point.
+    $localDrivers = ['CRM_Utils_Cache_Arraycache', 'CRM_Utils_Cache_NoCache'];
+    if (Civi\Core\Container::isContainerBooted()
+      && !in_array(get_class(CRM_Utils_Cache::singleton()), $localDrivers)) {
       Civi::cache('settings')->flush();
       Civi::cache('js_strings')->flush();
       Civi::cache('community_messages')->flush();
index 2b8ec1a31a83da2fedcf0bbf7fe758b9985949a7..64bb31d7787efc56613f90af32fcb911c8682d52 100644 (file)
@@ -589,6 +589,14 @@ class CRM_Utils_System_Joomla extends CRM_Utils_System_Base {
       define('JDEBUG', FALSE);
     }
 
+    // Set timezone for Joomla on Cron
+    $config = JFactory::getConfig();
+    $timezone = $config->get('offset');
+    if ($timezone) {
+      date_default_timezone_set($timezone);
+      CRM_Core_Config::singleton()->userSystem->setMySQLTimeZone();
+    }
+
     // CRM-14281 Joomla wasn't available during bootstrap, so hook_civicrm_config never executes.
     $config = CRM_Core_Config::singleton();
     CRM_Utils_Hook::config($config);
index e3fcd7adb8232715c62cd8a4d1db30ce5e6bf8ab..167be544c39140d388019fb899e0364a286a4f76 100644 (file)
@@ -139,7 +139,7 @@ class SettingsBag {
 
     $isUpgradeMode = \CRM_Core_Config::isUpgradeMode();
 
-    if ($isUpgradeMode && empty($this->contactId) && \CRM_Core_DAO::checkFieldExists('civicrm_domain', 'config_backend', FALSE)) {
+    if ($isUpgradeMode && empty($this->contactId) && \CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_domain', 'config_backend', FALSE)) {
       $config_backend = \CRM_Core_DAO::singleValueQuery('SELECT config_backend FROM civicrm_domain WHERE id = %1',
         array(1 => array($this->domainId, 'Positive')));
       $oldSettings = \CRM_Upgrade_Incremental_php_FourSeven::convertBackendToSettings($this->domainId, $config_backend);
@@ -373,7 +373,7 @@ class SettingsBag {
     if (!isset(\Civi::$statics[__CLASS__]['upgradeMode'])) {
       \Civi::$statics[__CLASS__]['upgradeMode'] = \CRM_Core_Config::isUpgradeMode();
     }
-    if (\Civi::$statics[__CLASS__]['upgradeMode'] && \CRM_Core_DAO::checkFieldExists('civicrm_setting', 'group_name')) {
+    if (\Civi::$statics[__CLASS__]['upgradeMode'] && \CRM_Core_BAO_SchemaHandler::checkIfFieldExists('civicrm_setting', 'group_name')) {
       $dao->group_name = 'placeholder';
     }
 
index 40cd3a57ba5851da35ae0dbb71b3e16b5ce6d024..30a02a8fa1385635f76a5bacc9bf4d659d961f3e 100644 (file)
@@ -89,7 +89,7 @@ class StaticTriggers {
 
       if (\CRM_Core_Config::isUpgradeMode() && isset($trigger['upgrade_check'])) {
         $uc = $trigger['upgrade_check'];
-        if (!\CRM_Core_DAO::checkFieldExists($uc['table'], $uc['column'])
+        if (!\CRM_Core_BAO_SchemaHandler::checkIfFieldExists($uc['table'], $uc['column'])
         ) {
           continue;
         }
index c7e1127322b519ca12eb10407d0b4ac96c711917..dcce0e39307713ba5fe7d6cc38512c01978d840f 100644 (file)
@@ -145,7 +145,7 @@ class TimestampTriggers {
     // In the past, this was a version-based check, but checkFieldExists()
     // seems more robust.
     if (\CRM_Core_Config::isUpgradeMode()) {
-      if (!\CRM_Core_DAO::checkFieldExists($this->getTableName(),
+      if (!\CRM_Core_BAO_SchemaHandler::checkIfFieldExists($this->getTableName(),
         $this->getCreatedDate())
       ) {
         return;
index 1efcd13ce693246853128e091e7ee156058b8b78..2a10abf7e7357f7fc2a13c7dbbba3c7618ab6e4e 100644 (file)
@@ -235,6 +235,9 @@ trait Api3TestTrait {
       'debug' => 1,
     );
     $result = $this->civicrm_api($entity, 'getvalue', $params);
+    if (is_array($result) && (!empty($result['is_error']) || isset($result['values']))) {
+      throw new \Exception('Invalid getvalue result' . print_r($result, TRUE));
+    }
     if ($type) {
       if ($type == 'integer') {
         // api seems to return integers as strings
index d00acd75092236e8466f963130f1b1304ee6ff02..8e2ac735ba1b176cb5216da295183ec7733282b9 100644 (file)
@@ -90,7 +90,7 @@ class TokenCompatSubscriber implements EventSubscriberInterface {
       // less randomly.
       \CRM_Utils_Hook::tokenValues($contactArray,
         (array) $contactId,
-        empty($row->context['mailingJob']) ? NULL : $row->context['mailingJob']->id,
+        empty($row->context['mailingJobId']) ? NULL : $row->context['mailingJobId'],
         $messageTokens,
         $row->context['controller']
       );
index cf7462f47dbafa953a7d85ffb913094dac170e35..69835a0b75c5673aec371dc992413c960d38d3bf 100644 (file)
--- a/README.md
+++ b/README.md
@@ -46,5 +46,5 @@ questions and ideas in the [Developer Discussion room](https://chat.civicrm.org/
 
 Installing the latest developmental code requires some [special steps](http://wiki.civicrm.org/confluence/display/CRMDOC/Contributing+to+CiviCRM+using+GitHub). 
 
-Report all issues to CiviCRM via JIRA:
-https://issues.civicrm.org
+Report all issues to CiviCRM via GitLab:
+https://lab.civicrm.org
index 16947a3d79dc0d65e38238789fccc9f2ec1b4332..0dd232dd637c5a56f2060f80b4b9eb5ce19e99f0 100644 (file)
@@ -66,7 +66,7 @@
           value = fmt.decode($route.current.params[options.param]);
         }
         else {
-          value = _.isObject(options.default) ? angular.extend({}, options.default) : options.default;
+          value = _.cloneDeep(options.default);
           ignorable[options.param] = fmt.encode(options.default);
         }
         $parse(options.expr).assign(_scope, value);
index e53b39d88a7013c0676cd738c8d50b730ed3012d..3a855d21f3106ac1e27d6bbc8f12269efc096db7 100644 (file)
@@ -149,7 +149,10 @@ function civicrm_api3_custom_value_get($params) {
       if (!empty(substr($id, 7))) {
         $returnVal = substr($id, 7);
       }
-      foreach ((array) $returnVal as $value) {
+      if (!is_array($returnVal)) {
+        $returnVal = explode(',', $returnVal);
+      }
+      foreach ($returnVal as $value) {
         list($c, $i) = CRM_Utils_System::explode('_', $value, 2);
         if ($c == 'custom' && is_numeric($i)) {
           $names['custom_' . $i] = 'custom_' . $i;
index 2f51ca951dee70058c560379740406b2b4b04ee8..20a7e0a510cea02ae6f6f215add173c02f2ccc87 100644 (file)
@@ -61,6 +61,7 @@ function _civicrm_api3_payment_processor_create_spec(&$params) {
   $params['payment_processor_type_id']['api.required'] = 1;
   $params['is_default']['api.default'] = 0;
   $params['is_test']['api.default'] = 0;
+  $params['domain_id']['api.default'] = CRM_Core_Config::domainID();
 }
 
 /**
index 337839693525beb7a6acb5f48c826d3037627b1c..b6d678318dbe552f5c8b611bf1f102383040cc03 100644 (file)
@@ -56,7 +56,6 @@ function _civicrm_api3_payment_processor_type_create_spec(&$params) {
   $params['class_name']['api.required'] = 1;
   $params['is_active']['api.default'] = 1;
   $params['is_recur']['api.default'] = FALSE;
-  // FIXME bool support // $params['is_recur']['api.required'] = 1;
   $params['name']['api.required'] = 1;
   $params['title']['api.required'] = 1;
   $params['payment_instrument_id']['api.default'] = 'Credit Card';
index 1078ccf3d30346eefb791349eebd4dd61199eefb..0988e0cd99530c697b8e7673e32eb7cecfbe860e 100644 (file)
   "require": {
     "dompdf/dompdf" : "0.8.*",
     "electrolinux/phpquery": "^0.9.6",
-    "symfony/config": "^2.6.13 || ~3.0",
-    "symfony/dependency-injection": "^2.6.13 || ~3.0",
-    "symfony/event-dispatcher": "^2.6.13 || ~3.0",
-    "symfony/filesystem": "^2.6.13 || ~3.0",
-    "symfony/process": "^2.6.13 || ~3.0",
+    "symfony/config": "^2.8.44 || ~3.0",
+    "symfony/polyfill-iconv": "~1.0",
+    "symfony/dependency-injection": "^2.8.44 || ~3.0",
+    "symfony/event-dispatcher": "^2.8.44 || ~3.0",
+    "symfony/filesystem": "^2.8.44 || ~3.0",
+    "symfony/process": "^2.8.44 || ~3.0",
     "psr/log": "~1.0.0",
-    "symfony/finder": "^2.6.13 || ~3.0",
+    "symfony/finder": "^2.8.44 || ~3.0",
     "tecnickcom/tcpdf" : "6.2.*",
     "totten/ca-config": "~17.05",
     "zetacomponents/base": "1.7.*",
index 8f3e4d2659e99894ff0300d04addd2785b5eb1e3..7b5f352c9f7c94faaf2c80911a625dfb9ff3e1e1 100644 (file)
@@ -1,10 +1,10 @@
 {
     "_readme": [
         "This file locks the dependencies of your project to a known state",
-        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "233f9c457d9e7d49a6d96c356e1035f1",
+    "content-hash": "38f5450ab72f881008f5cd10bb588b6f",
     "packages": [
         {
             "name": "civicrm/civicrm-cxn-rpc",
             "extra": {
                 "branch-alias": {
                     "dev-develop": "0.7-dev"
+                },
+                "patches_applied": {
+                    "Fix Fatal error: Uncaught Dompdf Exception: No block-level parent found.": "tools/scripts/composer/patches/dompdf_no_block_level_parent_fix.patch"
                 }
             },
             "autoload": {
                 "pear/auth_sasl": "Install optionally via your project's composer.json"
             },
             "type": "library",
+            "extra": {
+                "patches_applied": {
+                    "CRM-8744 Display CiviCRM Specific error message": "tools/scripts/composer/patches/net-smtp-patch.patch",
+                    "Fix PHP7 Compliance": "tools/scripts/composer/patches/net-smtp-php7-patch.patch",
+                    "Fix Pass by reference issues": "tools/scripts/composer/patches/net-smtp-ref-patch.patch",
+                    "Fix TLS support issue in PHP5.6": "tools/scripts/composer/patches/net-smtp-tls-patch.patch"
+                }
+            },
             "autoload": {
                 "psr-0": {
                     "Net": "./"
         },
         {
             "name": "symfony/config",
-            "version": "v2.6.13",
-            "target-dir": "Symfony/Component/Config",
+            "version": "v2.8.44",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/config.git",
-                "reference": "0ca496cbe208fc37c4cf3415ebb3056e0963115b"
+                "reference": "06c0be4cdd8363f3ec8d592c9a4d1b981d5052af"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/config/zipball/0ca496cbe208fc37c4cf3415ebb3056e0963115b",
-                "reference": "0ca496cbe208fc37c4cf3415ebb3056e0963115b",
+                "url": "https://api.github.com/repos/symfony/config/zipball/06c0be4cdd8363f3ec8d592c9a4d1b981d5052af",
+                "reference": "06c0be4cdd8363f3ec8d592c9a4d1b981d5052af",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.3",
-                "symfony/filesystem": "~2.3"
+                "php": ">=5.3.9",
+                "symfony/filesystem": "~2.3|~3.0.0",
+                "symfony/polyfill-ctype": "~1.8"
             },
             "require-dev": {
-                "symfony/phpunit-bridge": "~2.7"
+                "symfony/yaml": "~2.7|~3.0.0"
+            },
+            "suggest": {
+                "symfony/yaml": "To use the yaml reference dumper"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.6-dev"
+                    "dev-master": "2.8-dev"
                 }
             },
             "autoload": {
-                "psr-0": {
+                "psr-4": {
                     "Symfony\\Component\\Config\\": ""
-                }
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
             ],
             "description": "Symfony Config Component",
             "homepage": "https://symfony.com",
-            "time": "2015-07-08T05:59:48+00:00"
+            "time": "2018-07-26T11:13:39+00:00"
         },
         {
             "name": "symfony/dependency-injection",
-            "version": "v2.6.13",
-            "target-dir": "Symfony/Component/DependencyInjection",
+            "version": "v2.8.44",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/dependency-injection.git",
-                "reference": "d9fe6837d74aed11e5ee741cd6b6dfe45e0af78e"
+                "reference": "ad2446d39d11c3daaa7f147d957941a187e47357"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/d9fe6837d74aed11e5ee741cd6b6dfe45e0af78e",
-                "reference": "d9fe6837d74aed11e5ee741cd6b6dfe45e0af78e",
+                "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/ad2446d39d11c3daaa7f147d957941a187e47357",
+                "reference": "ad2446d39d11c3daaa7f147d957941a187e47357",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.3"
+                "php": ">=5.3.9"
             },
             "conflict": {
                 "symfony/expression-language": "<2.6"
             },
             "require-dev": {
-                "symfony/config": "~2.2",
-                "symfony/expression-language": "~2.6",
-                "symfony/phpunit-bridge": "~2.7",
-                "symfony/yaml": "~2.1"
+                "symfony/config": "~2.2|~3.0.0",
+                "symfony/expression-language": "~2.6|~3.0.0",
+                "symfony/yaml": "~2.3.42|~2.7.14|~2.8.7|~3.0.7"
             },
             "suggest": {
                 "symfony/config": "",
+                "symfony/expression-language": "For using expressions in service container configuration",
                 "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them",
                 "symfony/yaml": ""
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.6-dev"
+                    "dev-master": "2.8-dev"
                 }
             },
             "autoload": {
-                "psr-0": {
+                "psr-4": {
                     "Symfony\\Component\\DependencyInjection\\": ""
-                }
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
             ],
             "description": "Symfony DependencyInjection Component",
             "homepage": "https://symfony.com",
-            "time": "2015-07-22T10:08:40+00:00"
+            "time": "2018-07-26T11:13:39+00:00"
         },
         {
             "name": "symfony/event-dispatcher",
-            "version": "v2.6.13",
-            "target-dir": "Symfony/Component/EventDispatcher",
+            "version": "v2.8.44",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/event-dispatcher.git",
-                "reference": "672593bc4b0043a0acf91903bb75a1c82d8f2e02"
+                "reference": "84ae343f39947aa084426ed1138bb96bf94d1f12"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/672593bc4b0043a0acf91903bb75a1c82d8f2e02",
-                "reference": "672593bc4b0043a0acf91903bb75a1c82d8f2e02",
+                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/84ae343f39947aa084426ed1138bb96bf94d1f12",
+                "reference": "84ae343f39947aa084426ed1138bb96bf94d1f12",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.3"
+                "php": ">=5.3.9"
             },
             "require-dev": {
                 "psr/log": "~1.0",
-                "symfony/config": "~2.0,>=2.0.5",
-                "symfony/dependency-injection": "~2.6",
-                "symfony/expression-language": "~2.6",
-                "symfony/phpunit-bridge": "~2.7",
-                "symfony/stopwatch": "~2.3"
+                "symfony/config": "^2.0.5|~3.0.0",
+                "symfony/dependency-injection": "~2.6|~3.0.0",
+                "symfony/expression-language": "~2.6|~3.0.0",
+                "symfony/stopwatch": "~2.3|~3.0.0"
             },
             "suggest": {
                 "symfony/dependency-injection": "",
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.6-dev"
+                    "dev-master": "2.8-dev"
                 }
             },
             "autoload": {
-                "psr-0": {
+                "psr-4": {
                     "Symfony\\Component\\EventDispatcher\\": ""
-                }
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
             ],
             "description": "Symfony EventDispatcher Component",
             "homepage": "https://symfony.com",
-            "time": "2015-05-02T15:18:45+00:00"
+            "time": "2018-07-26T09:03:18+00:00"
         },
         {
             "name": "symfony/filesystem",
-            "version": "v2.6.13",
-            "target-dir": "Symfony/Component/Filesystem",
+            "version": "v2.8.44",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/filesystem.git",
-                "reference": "823c035b1a5c13a4924e324d016eb07e70f94735"
+                "reference": "2d6a4deccdfa2e4e9f113138b93457b2d0886c15"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/filesystem/zipball/823c035b1a5c13a4924e324d016eb07e70f94735",
-                "reference": "823c035b1a5c13a4924e324d016eb07e70f94735",
+                "url": "https://api.github.com/repos/symfony/filesystem/zipball/2d6a4deccdfa2e4e9f113138b93457b2d0886c15",
+                "reference": "2d6a4deccdfa2e4e9f113138b93457b2d0886c15",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.3"
-            },
-            "require-dev": {
-                "symfony/phpunit-bridge": "~2.7"
+                "php": ">=5.3.9",
+                "symfony/polyfill-ctype": "~1.8"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.6-dev"
+                    "dev-master": "2.8-dev"
                 }
             },
             "autoload": {
-                "psr-0": {
+                "psr-4": {
                     "Symfony\\Component\\Filesystem\\": ""
-                }
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
             ],
             "description": "Symfony Filesystem Component",
             "homepage": "https://symfony.com",
-            "time": "2015-07-08T05:59:48+00:00"
+            "time": "2018-07-26T11:13:39+00:00"
         },
         {
             "name": "symfony/finder",
-            "version": "v2.6.13",
-            "target-dir": "Symfony/Component/Finder",
+            "version": "v2.8.44",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/finder.git",
-                "reference": "203a10f928ae30176deeba33512999233181dd28"
+                "reference": "f0de0b51913eb2caab7dfed6413b87e14fca780e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/finder/zipball/203a10f928ae30176deeba33512999233181dd28",
-                "reference": "203a10f928ae30176deeba33512999233181dd28",
+                "url": "https://api.github.com/repos/symfony/finder/zipball/f0de0b51913eb2caab7dfed6413b87e14fca780e",
+                "reference": "f0de0b51913eb2caab7dfed6413b87e14fca780e",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.3"
-            },
-            "require-dev": {
-                "symfony/phpunit-bridge": "~2.7"
+                "php": ">=5.3.9"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.6-dev"
+                    "dev-master": "2.8-dev"
                 }
             },
             "autoload": {
-                "psr-0": {
+                "psr-4": {
                     "Symfony\\Component\\Finder\\": ""
-                }
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
             ],
             "description": "Symfony Finder Component",
             "homepage": "https://symfony.com",
-            "time": "2015-07-09T16:02:48+00:00"
+            "time": "2018-07-26T11:13:39+00:00"
         },
         {
-            "name": "symfony/process",
-            "version": "v2.6.13",
-            "target-dir": "Symfony/Component/Process",
+            "name": "symfony/polyfill-ctype",
+            "version": "v1.8.0",
             "source": {
                 "type": "git",
-                "url": "https://github.com/symfony/process.git",
-                "reference": "57f1e88bb5dafa449b83f9f265b11d52d517b3e9"
+                "url": "https://github.com/symfony/polyfill-ctype.git",
+                "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/process/zipball/57f1e88bb5dafa449b83f9f265b11d52d517b3e9",
-                "reference": "57f1e88bb5dafa449b83f9f265b11d52d517b3e9",
+                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/7cc359f1b7b80fc25ed7796be7d96adc9b354bae",
+                "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae",
                 "shasum": ""
             },
             "require": {
                 "php": ">=5.3.3"
             },
-            "require-dev": {
-                "symfony/phpunit-bridge": "~2.7"
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.8-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Ctype\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                },
+                {
+                    "name": "Gert de Pagter",
+                    "email": "BackEndTea@gmail.com"
+                }
+            ],
+            "description": "Symfony polyfill for ctype functions",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "ctype",
+                "polyfill",
+                "portable"
+            ],
+            "time": "2018-04-30T19:57:29+00:00"
+        },
+        {
+            "name": "symfony/polyfill-iconv",
+            "version": "v1.9.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-iconv.git",
+                "reference": "bcc0cd69185b8a5d8b4a5400c489ed3333bf9bb2"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/bcc0cd69185b8a5d8b4a5400c489ed3333bf9bb2",
+                "reference": "bcc0cd69185b8a5d8b4a5400c489ed3333bf9bb2",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "suggest": {
+                "ext-iconv": "For best performance"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.6-dev"
+                    "dev-master": "1.9-dev"
                 }
             },
             "autoload": {
-                "psr-0": {
-                    "Symfony\\Component\\Process\\": ""
+                "psr-4": {
+                    "Symfony\\Polyfill\\Iconv\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
                 }
+            ],
+            "description": "Symfony polyfill for the Iconv extension",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "iconv",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "time": "2018-08-06T14:22:27+00:00"
+        },
+        {
+            "name": "symfony/process",
+            "version": "v2.8.44",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/process.git",
+                "reference": "cc83afdb5ac99147806b3bb65a3ff1227664f596"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/process/zipball/cc83afdb5ac99147806b3bb65a3ff1227664f596",
+                "reference": "cc83afdb5ac99147806b3bb65a3ff1227664f596",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.9"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.8-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Process\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
             ],
             "description": "Symfony Process Component",
             "homepage": "https://symfony.com",
-            "time": "2015-06-30T16:10:16+00:00"
+            "time": "2018-07-26T11:13:39+00:00"
         },
         {
             "name": "tecnickcom/tcpdf",
index 567ac1f9f20674717c17815d4b2e7dc6c62fc2dd..167a9c9d4fbb56903f91f9ccb75c7641efb557b2 100644 (file)
 - name        : Matthias Bärnthaler
   jira        : baerm
 
+- github      : baernm
+
+- github      : bastienho
+  name        : Bastien Ho
+
 - github      : bhahumanists
   name        : Andrew West
   organization: British Humanist Association
   organization: Jvillage Network
   jira        : dinalondon
 
+- name        : Lizz Trudeau
+  organization: Drupal Association
+  jira        : drupal_lizz
+
 - github      : dsnopek
   name        : David Snopek
   organization: myDropWizard
   organization: AGH Strategies
   jira        : hollyhanks
 
+- name        : Hugo do Carmo
+  jira        : hugo.carmo
+
 - name        : Anthony Colombo
   organization: DreamSpace
   jira        : Hunabku
   organization: Coop SymbioTIC
   jira        : mlutfy
 
-- name        : Michal Mach
+- github      : michau
+  name        : Michal Mach
+  organization: Caltha
   jira        : mover
 
+- github      : MikeyMJCO
+  name        : Mikey O'Toole
+  organization: MJCO
+  jira        : MikeyMJCO
+
 - github      : mmauroy
   name        : Matthias de Mauroy
   organization: CYIM
   organization: Botanical Society of America
   jira        : robbrandt
 
+- github      : robfenwickuk
+  name        : Robin Fenwick
+
 - name        : Robert Lang
   jira        : rjlang
 
 
 - github      : scardinius
   name        : Tomasz Pietrzkowski
-  organization: We Move Europe/Caltha
+  organization: Caltha
   jira        : scardinius
 
 - github      : seamuslee001
index 8a5306763778e4b27059c4a0e07e57a9bd870545..985e7d616ccb76c2b00e8e7ece334ce64aa42167 100644 (file)
@@ -646,153 +646,12 @@ if (!CRM.vars) CRM.vars = {};
     return combined;
   }
 
-  function copyAttributes($source, $target, attributes) {
+  CRM.utils.copyAttributes = function ($source, $target, attributes) {
     _.each(attributes, function(name) {
       if ($source.attr(name) !== undefined) {
         $target.attr(name, $source.attr(name));
       }
     });
-  }
-
-  /**
-   * @see http://wiki.civicrm.org/confluence/display/CRMDOC/crmDatepicker
-   */
-  $.fn.crmDatepicker = function(options) {
-    return $(this).each(function() {
-      if ($(this).is('.crm-form-date-wrapper .crm-hidden-date')) {
-        // Already initialized - destroy
-        $(this)
-          .off('.crmDatepicker')
-          .css('display', '')
-          .removeClass('crm-hidden-date')
-          .siblings().remove();
-        $(this).unwrap();
-      }
-      if (options === 'destroy') {
-        return;
-      }
-      var
-        $dataField = $(this).wrap('<span class="crm-form-date-wrapper" />'),
-        settings = _.cloneDeep(options || {}),
-        $dateField = $(),
-        $timeField = $(),
-        $clearLink = $(),
-        hasDatepicker = settings.date !== false && settings.date !== 'yy',
-        type = hasDatepicker ? 'text' : 'number';
-
-      if (settings.allowClear !== undefined ? settings.allowClear : !$dataField.is('.required, [required]')) {
-        $clearLink = $('<a class="crm-hover-button crm-clear-link" title="'+ _.escape(ts('Clear')) +'"><i class="crm-i fa-times"></i></a>')
-          .insertAfter($dataField);
-      }
-      if (settings.time !== false) {
-        $timeField = $('<input>').insertAfter($dataField);
-        copyAttributes($dataField, $timeField, ['class', 'disabled']);
-        $timeField
-          .addClass('crm-form-text crm-form-time')
-          .attr('placeholder', $dataField.attr('time-placeholder') === undefined ? ts('Time') : $dataField.attr('time-placeholder'))
-          .attr('aria-label', $dataField.attr('time-placeholder') === undefined ? ts('Time') : $dataField.attr('time-placeholder'))
-          .change(updateDataField)
-          .timeEntry({
-            spinnerImage: '',
-            show24Hours: settings.time === true || settings.time === undefined ? CRM.config.timeIs24Hr : settings.time == '24'
-          });
-      }
-      if (settings.date !== false) {
-        // Render "number" field for year-only format, calendar popup for all other formats
-        $dateField = $('<input type="' + type + '">').insertAfter($dataField);
-        copyAttributes($dataField, $dateField, ['placeholder', 'style', 'class', 'disabled', 'aria-label']);
-        $dateField.addClass('crm-form-' + type);
-        if (hasDatepicker) {
-          settings.minDate = settings.minDate ? CRM.utils.makeDate(settings.minDate) : null;
-          settings.maxDate = settings.maxDate ? CRM.utils.makeDate(settings.maxDate) : null;
-          settings.dateFormat = typeof settings.date === 'string' ? settings.date : CRM.config.dateInputFormat;
-          settings.changeMonth = _.includes(settings.dateFormat, 'm');
-          settings.changeYear = _.includes(settings.dateFormat, 'y');
-          if (!settings.yearRange && settings.minDate !== null && settings.maxDate !== null) {
-            settings.yearRange = '' + CRM.utils.formatDate(settings.minDate, 'yy') + ':' + CRM.utils.formatDate(settings.maxDate, 'yy');
-          }
-          $dateField.addClass('crm-form-date').datepicker(settings);
-        } else {
-          $dateField.attr('min', settings.minDate ? CRM.utils.formatDate(settings.minDate, 'yy') : '1000');
-          $dateField.attr('max', settings.maxDate ? CRM.utils.formatDate(settings.maxDate, 'yy') : '4000');
-        }
-        $dateField.change(updateDataField);
-      }
-      // Rudimentary validation. TODO: Roll into use of jQUery validate and ui.datepicker.validation
-      function isValidDate() {
-        // FIXME: parseDate doesn't work with incomplete date formats; skip validation if no month, day or year in format
-        var lowerFormat = settings.dateFormat.toLowerCase();
-        if (lowerFormat.indexOf('y') < 0 || lowerFormat.indexOf('m') < 0 || !dateHasDay()) {
-          return true;
-        }
-        try {
-          $.datepicker.parseDate(settings.dateFormat, $dateField.val());
-          return true;
-        } catch (e) {
-          return false;
-        }
-      }
-
-      /**
-       * Does the date format contain the day.
-       *
-       * @returns {boolean}
-       */
-      function dateHasDay() {
-        var lowerFormat = settings.dateFormat.toLowerCase();
-        if (lowerFormat.indexOf('d') < 0) {
-          return false;
-        }
-        return true;
-      }
-      function updateInputFields(e, context) {
-        var val = $dataField.val(),
-          time = null;
-        if (context !== 'userInput' && context !== 'crmClear') {
-          if (hasDatepicker) {
-            $dateField.datepicker('setDate', _.includes(val, '-') ? $.datepicker.parseDate('yy-mm-dd', val) : null);
-          } else if ($dateField.length) {
-            $dateField.val(val.slice(0, 4));
-          }
-          if ($timeField.length) {
-            if (val.length === 8) {
-              time = val;
-            } else if (val.length === 19) {
-              time = val.split(' ')[1];
-            }
-            $timeField.timeEntry('setTime', time);
-          }
-        }
-        $clearLink.css('visibility', val ? 'visible' : 'hidden');
-      }
-      function updateDataField(e, context) {
-        // The crmClear event wipes all the field values anyway, so no need to respond
-        if (context !== 'crmClear') {
-          var val = '';
-          if ($dateField.val()) {
-            if (hasDatepicker && isValidDate() && dateHasDay()) {
-              val = $.datepicker.formatDate('yy-mm-dd', $dateField.datepicker('getDate'));
-              $dateField.removeClass('crm-error');
-            } else if (!hasDatepicker) {
-              val = $dateField.val() + '-01-01';
-            }
-            else if (!dateHasDay()) {
-              // This would be a Year-month date (yyyy-mm)
-              // it could be argued it should not use a datepicker....
-              val = $dateField.val() + '-01';
-            } else {
-              $dateField.addClass('crm-error');
-            }
-          }
-          if ($timeField.val()) {
-            val += (val ? ' ' : '') + $timeField.timeEntry('getTime').toTimeString().substr(0, 8);
-          }
-          $dataField.val(val).trigger('change', ['userInput']);
-        }
-      }
-      $dataField.hide().addClass('crm-hidden-date').on('change.crmDatepicker', updateInputFields);
-      updateInputFields();
-    });
   };
 
   CRM.utils.formatSelect2Result = function (row) {
diff --git a/js/crm.datepicker.js b/js/crm.datepicker.js
new file mode 100644 (file)
index 0000000..cfef977
--- /dev/null
@@ -0,0 +1,144 @@
+(function($, CRM, _) {
+  "use strict";
+
+  /**
+   * @see http://wiki.civicrm.org/confluence/display/CRMDOC/crmDatepicker
+   */
+  $.fn.crmDatepicker = function(options) {
+    return $(this).each(function() {
+      if ($(this).is('.crm-form-date-wrapper .crm-hidden-date')) {
+        // Already initialized - destroy
+        $(this)
+          .off('.crmDatepicker')
+          .css('display', '')
+          .removeClass('crm-hidden-date')
+          .siblings().remove();
+        $(this).unwrap();
+      }
+      if (options === 'destroy') {
+        return;
+      }
+      var
+        $dataField = $(this).wrap('<span class="crm-form-date-wrapper" />'),
+        settings = CRM._.cloneDeep(options || {}),
+        $dateField = $(),
+        $timeField = $(),
+        $clearLink = $(),
+        hasDatepicker = settings.date !== false && settings.date !== 'yy',
+        type = hasDatepicker ? 'text' : 'number';
+
+      if (settings.allowClear !== undefined ? settings.allowClear : !$dataField.is('.required, [required]')) {
+        $clearLink = $('<a class="crm-hover-button crm-clear-link" title="'+ CRM._.escape(ts('Clear')) +'"><i class="crm-i fa-times"></i></a>')
+          .insertAfter($dataField);
+      }
+      if (settings.time !== false) {
+        $timeField = $('<input>').insertAfter($dataField);
+        CRM.utils.copyAttributes($dataField, $timeField, ['class', 'disabled']);
+        $timeField
+          .addClass('crm-form-text crm-form-time')
+          .attr('placeholder', $dataField.attr('time-placeholder') === undefined ? ts('Time') : $dataField.attr('time-placeholder'))
+          .attr('aria-label', $dataField.attr('time-placeholder') === undefined ? ts('Time') : $dataField.attr('time-placeholder'))
+          .change(updateDataField)
+          .timeEntry({
+            spinnerImage: '',
+            show24Hours: settings.time === true || settings.time === undefined ? CRM.config.timeIs24Hr : settings.time == '24'
+          });
+      }
+      if (settings.date !== false) {
+        // Render "number" field for year-only format, calendar popup for all other formats
+        $dateField = $('<input type="' + type + '">').insertAfter($dataField);
+        CRM.utils.copyAttributes($dataField, $dateField, ['placeholder', 'style', 'class', 'disabled', 'aria-label']);
+        $dateField.addClass('crm-form-' + type);
+        if (hasDatepicker) {
+          settings.minDate = settings.minDate ? CRM.utils.makeDate(settings.minDate) : null;
+          settings.maxDate = settings.maxDate ? CRM.utils.makeDate(settings.maxDate) : null;
+          settings.dateFormat = typeof settings.date === 'string' ? settings.date : CRM.config.dateInputFormat;
+          settings.changeMonth = CRM._.includes(settings.dateFormat, 'm');
+          settings.changeYear = CRM._.includes(settings.dateFormat, 'y');
+          if (!settings.yearRange && settings.minDate !== null && settings.maxDate !== null) {
+            settings.yearRange = '' + CRM.utils.formatDate(settings.minDate, 'yy') + ':' + CRM.utils.formatDate(settings.maxDate, 'yy');
+          }
+          $dateField.addClass('crm-form-date').datepicker(settings);
+        } else {
+          $dateField.attr('min', settings.minDate ? CRM.utils.formatDate(settings.minDate, 'yy') : '1000');
+          $dateField.attr('max', settings.maxDate ? CRM.utils.formatDate(settings.maxDate, 'yy') : '4000');
+        }
+        $dateField.change(updateDataField);
+      }
+      // Rudimentary validation. TODO: Roll into use of jQUery validate and ui.datepicker.validation
+      function isValidDate() {
+        // FIXME: parseDate doesn't work with incomplete date formats; skip validation if no month, day or year in format
+        var lowerFormat = settings.dateFormat.toLowerCase();
+        if (lowerFormat.indexOf('y') < 0 || lowerFormat.indexOf('m') < 0 || !dateHasDay()) {
+          return true;
+        }
+        try {
+          $.datepicker.parseDate(settings.dateFormat, $dateField.val());
+          return true;
+        } catch (e) {
+          return false;
+        }
+      }
+
+      /**
+       * Does the date format contain the day.
+       *
+       * @returns {boolean}
+       */
+      function dateHasDay() {
+        var lowerFormat = settings.dateFormat.toLowerCase();
+        if (lowerFormat.indexOf('d') < 0) {
+          return false;
+        }
+        return true;
+      }
+      function updateInputFields(e, context) {
+        var val = $dataField.val(),
+          time = null;
+        if (context !== 'userInput' && context !== 'crmClear') {
+          if (hasDatepicker) {
+            $dateField.datepicker('setDate', CRM._.includes(val, '-') ? $.datepicker.parseDate('yy-mm-dd', val) : null);
+          } else if ($dateField.length) {
+            $dateField.val(val.slice(0, 4));
+          }
+          if ($timeField.length) {
+            if (val.length === 8) {
+              time = val;
+            } else if (val.length === 19) {
+              time = val.split(' ')[1];
+            }
+            $timeField.timeEntry('setTime', time);
+          }
+        }
+        $clearLink.css('visibility', val ? 'visible' : 'hidden');
+      }
+      function updateDataField(e, context) {
+        // The crmClear event wipes all the field values anyway, so no need to respond
+        if (context !== 'crmClear') {
+          var val = '';
+          if ($dateField.val()) {
+            if (hasDatepicker && isValidDate() && dateHasDay()) {
+              val = $.datepicker.formatDate('yy-mm-dd', $dateField.datepicker('getDate'));
+              $dateField.removeClass('crm-error');
+            } else if (!hasDatepicker) {
+              val = $dateField.val() + '-01-01';
+            }
+            else if (!dateHasDay()) {
+              // This would be a Year-month date (yyyy-mm)
+              // it could be argued it should not use a datepicker....
+              val = $dateField.val() + '-01';
+            } else {
+              $dateField.addClass('crm-error');
+            }
+          }
+          if ($timeField.val()) {
+            val += (val ? ' ' : '') + $timeField.timeEntry('getTime').toTimeString().substr(0, 8);
+          }
+          $dataField.val(val).trigger('change', ['userInput']);
+        }
+      }
+      $dataField.hide().addClass('crm-hidden-date').on('change.crmDatepicker', updateInputFields);
+      updateInputFields();
+    });
+  };
+})(jQuery, CRM, CRM._);
index d1c9cd3487fd92e2c41ff3800a554f3e608a7bb0..2915dc7814fe5020a03f613abe5ce5eaf923edc5 100644 (file)
@@ -32,6 +32,7 @@ module.exports = function(config) {
       'bower_components/jquery-validation/dist/jquery.validate.min.js',
       'packages/jquery/plugins/jquery.timeentry.js',
       'js/Common.js',
+      'js/crm.datepicker.js',
       'bower_components/angular/angular.js',
       'js/crm.angular.js',
       angularTempFile,
index b9971abd35814d7b63d85915c8cee75e54f880f4..f32d8821676e367f109cb0b28b29818ecf96cba3 100644 (file)
@@ -14,6 +14,36 @@ Other resources for identifying changes are:
     * https://github.com/civicrm/civicrm-joomla
     * https://github.com/civicrm/civicrm-wordpress
 
+## CiviCRM 5.4.0
+
+Released August 1, 2018
+
+- **[Synopsis](release-notes/5.4.0.md#synopsis)**
+- **[Features](release-notes/5.4.0.md#features)**
+- **[Bugs resolved](release-notes/5.4.0.md#bugs)**
+- **[Miscellany](release-notes/5.4.0.md#misc)**
+- **[Credits](release-notes/5.4.0.md#credits)**
+- **[Feedback](release-notes/5.4.0.md#feedback)**
+
+## CiviCRM 5.3.2
+
+Released July 25, 2018
+
+- **[Synopsis](release-notes/5.3.2.md#synopsis)**
+- **[Bugs resolved](release-notes/5.3.2.md#bugs)**
+- **[Credits](release-notes/5.3.2.md#credits)**
+- **[Feedback](release-notes/5.3.2.md#feedback)**
+
+## CiviCRM 5.3.1
+
+Released July 18, 2018
+
+- **[Security advisories](release-notes/5.3.1.md#security)**
+- **[Features](release-notes/5.3.1.md#features)**
+- **[Bugs resolved](release-notes/5.3.1.md#bugs)**
+- **[Miscellany](release-notes/5.3.1.md#misc)**
+- **[Credits](release-notes/5.3.1.md#credits)**
+
 ## CiviCRM 5.3.0
 
 Released July 3, 2018
diff --git a/release-notes/5.4.0.md b/release-notes/5.4.0.md
new file mode 100644 (file)
index 0000000..c24fe77
--- /dev/null
@@ -0,0 +1,667 @@
+# CiviCRM 5.4.0
+
+Released August 1, 2018
+
+- **[Synopsis](#synopsis)**
+- **[Features](#features)**
+- **[Bugs resolved](#bugs)**
+- **[Miscellany](#misc)**
+- **[Credits](#credits)**
+- **[Feedback](#feedback)**
+
+## <a name="synopsis"></a>Synopsis
+
+| *Does this version...?*                                         |         |
+|:--------------------------------------------------------------- |:-------:|
+| Fix security vulnerabilities?                                   |   no    |
+| **Change the database schema?**                                 | **yes** |
+| **Alter the API?**                                              | **yes** |
+| **Require attention to configuration options?**                 | **yes** |
+| **Fix problems installing or upgrading to a previous version?** | **yes** |
+| **Introduce features?**                                         | **yes** |
+| **Fix bugs?**                                                   | **yes** |
+
+## <a name="features"></a>Features
+
+### Core CiviCRM
+
+- **[CRM-20430](https://issues.civicrm.org/jira/browse/CRM-20430) A permission
+  'save Report Criteria'
+  ([12107](https://github.com/civicrm/civicrm-core/pull/12107))**
+
+  Permission to edit the criteria for saved reports is now separate from the
+  permission to access and preview modifications of report criteria.  This will
+  prevent non-privileged users from modifying the criteria of an organization's
+  standard reports.  However when upgrading, site administrators will need to
+  grant the Save Report Criteria permission to roles that need that capability.
+
+- **[dev/core#174](https://lab.civicrm.org/dev/core/issues/174) Consistently use
+  swappable cache interfaces
+  ([12321](https://github.com/civicrm/civicrm-core/pull/12321),
+  [12322](https://github.com/civicrm/civicrm-core/pull/12322),
+  [12323](https://github.com/civicrm/civicrm-core/pull/12323),
+  [12330](https://github.com/civicrm/civicrm-core/pull/12330),
+  [12331](https://github.com/civicrm/civicrm-core/pull/12331),
+  [12336](https://github.com/civicrm/civicrm-core/pull/12336),
+  [12342](https://github.com/civicrm/civicrm-core/pull/12342),
+  [12348](https://github.com/civicrm/civicrm-core/pull/12348),
+  [12354](https://github.com/civicrm/civicrm-core/pull/12354),
+  [12362](https://github.com/civicrm/civicrm-core/pull/12362),
+  [12368](https://github.com/civicrm/civicrm-core/pull/12368),
+  [12376](https://github.com/civicrm/civicrm-core/pull/12376),
+  [12378](https://github.com/civicrm/civicrm-core/pull/12378),
+  [12379](https://github.com/civicrm/civicrm-core/pull/12379),
+  [12380](https://github.com/civicrm/civicrm-core/pull/12380),
+  [12381](https://github.com/civicrm/civicrm-core/pull/12381),
+  [12389](https://github.com/civicrm/civicrm-core/pull/12389), and
+  [215](https://github.com/civicrm/civicrm-packages/pull/215))**
+
+  Sites using Redis or Memcache for caches and sessions will now use those
+  facilities exclusively rather than retaining the `civicrm_cache` table as
+  a backstop.  This improves performance for these sites, especially those
+  using multiple MySQL servers.
+
+  As a precaution, Redis or Memcache administrators with very active sites
+  may wish to double-check that they have ample capacity for their caches and
+  sessions.
+
+  For developers, the `CRM_Utils_Cache` APIs now support expiration/TTL
+  times and [PSR-16 CacheInterface](https://www.php-fig.org/psr/psr-16/).
+  The Civi implementation is slightly more permissive than the PSR-16
+  specification; for full compliance, enable `CIVICRM_PSR16_STRICT`.
+
+- **[CRM-21574](https://issues.civicrm.org/jira/browse/CRM-21574) Allow to
+  disable sending of email from source contact for tell a friend on pcp
+  ([12355](https://github.com/civicrm/civicrm-core/pull/12355)) (preliminary
+  work)**
+
+  Emails from the "tell a friend" feature are sent as if they are from the
+  donor's address.  This can cause delivery failures as the site may not be a
+  valid source for the donor's email domain.  Changes here are preliminary
+  cleanup.
+
+- **[dev/core#32](https://lab.civicrm.org/dev/core/issues/32) Add option to
+  disable cancel button on a profile form
+  ([11883](https://github.com/civicrm/civicrm-core/pull/11883))**
+
+  The Cancel button is now optional on profile forms.
+
+- **[CRM-21392](https://issues.civicrm.org/jira/browse/CRM-21392) Allow viewing
+  groups/smartgroups as as other entities (eg. memberships, events)
+  ([11241](https://github.com/civicrm/civicrm-core/pull/11241))**
+
+  The Find Groups page now has a similar "View Results As" feature as the
+  Advanced Search: you can choose to view memberships, events, activities, etc.
+  of group subscribers rather than the contacts themselves.
+
+- **[CRM-21622](https://issues.civicrm.org/jira/browse/CRM-21622) Make the Add
+  Parent Groups on Group Settings be a multiselect
+  ([11481](https://github.com/civicrm/civicrm-core/pull/11481))**
+
+  The New Group form now allows you to set multiple parent groups for a single
+  group.
+
+- **[CRM-21460](https://issues.civicrm.org/jira/browse/CRM-21460) Programmatic
+  access to job execution status
+  ([11337](https://github.com/civicrm/civicrm-core/pull/11337))**
+
+  Extension developers can implement two new hooks, `hook_civicrm_preJob` and
+  `hook_civicrm_postJob`, which are invoked before and after executing a
+  scheduled job.
+
+- **Change default for `CIVICRM_CONTAINER_CACHE` to simplify admin/developer
+  experience ([12426](https://github.com/civicrm/civicrm-core/pull/12426))**
+
+- **[dev/core#223](https://lab.civicrm.org/dev/core/issues/223) Expose prefix
+  and suffix in reports
+  ([12394](https://github.com/civicrm/civicrm-core/pull/12394))**
+
+  Individuals' prefix and suffix fields are now available as columns and filters
+  among the contact fields in most reports.
+
+- **[dev/core#101](https://lab.civicrm.org/dev/core/issues/101) Allow further
+  customization of search form in hooks
+  ([12078](https://github.com/civicrm/civicrm-core/pull/12078))**
+
+  Fields are no longer explicitly included in the search form template since
+  that makes it hard to add or remove fields.  Instead, the fields are listed in
+  template variables, and the template iterates over the list to render the
+  field elements.
+
+- **[dev/core#183](https://lab.civicrm.org/dev/core/issues/183) Temporary tables
+  should follow consistent naming convention
+  ([12311](https://github.com/civicrm/civicrm-core/pull/12311)) (partially
+  completed)**
+
+  This moves towards naming temporary tables--both true temporary tables in
+  MySQL and regular tables created for temporary use--in a consistent manner in
+  order to help database administrators employ replication policies based upon
+  table names.
+
+- **[dev/core#144](https://lab.civicrm.org/dev/core/issues/144)
+  `getCustomFieldID` switch to API, add caching, add full string return option
+  ([12218](https://github.com/civicrm/civicrm-core/pull/12218) and
+  [12283](https://github.com/civicrm/civicrm-core/pull/12283))**
+
+  The function to retrieve a custom field ID now relies upon APIv3 rather than
+  an *ad hoc* SQL query.  It also contains an option to return the ID preceded
+  by `custom_`.  Finally, the function caches the result and attempts to return
+  the cached value rather than looking it up each time.
+
+- **[dev/core#47](https://lab.civicrm.org/dev/core/issues/47) Add "clone"
+  functionality to scheduled jobs
+  ([11945](https://github.com/civicrm/civicrm-core/pull/11945))**
+
+  Scheduled jobs can now be copied, including their parameters, both from the
+  Scheduled Jobs page and through a new `Job.clone` API method.
+
+### CiviCase
+
+- **[dev/core#107](https://lab.civicrm.org/dev/core/issues/107) After creating a
+  new case, the assignee for each activity must be selected manually
+  ([11998](https://github.com/civicrm/civicrm-core/pull/11998))**
+
+  You can now select the default assignee for each activity in the standard
+  timeline for a case type.  This may be defined according to a relationship
+  with the client, a single specific contact, or the contact who created the
+  case.
+
+- **CiviCase, added reference of activities from different timelines.
+  ([12236](https://github.com/civicrm/civicrm-core/pull/12236))**
+
+  From an activity on a case timeline, you can now reference any activity
+  available to the case--not just those on that case timeline.
+
+### CiviContribute
+
+- **Add support for hidden fields in general (and 'token' specifically) on the
+  payment form. ([12332](https://github.com/civicrm/civicrm-core/pull/12332)
+  and [12391](https://github.com/civicrm/civicrm-core/pull/12391))**
+
+  A new authorization token field is added to the payment form to support
+  token-based payment processors.
+
+- **[CRM-21808](https://issues.civicrm.org/jira/browse/CRM-21808) Install custom
+  group for Contribution or ContributioRecur subtypes based on XML file
+  ([11726](https://github.com/civicrm/civicrm-core/pull/11726))**
+
+  Extensions created custom data sets for contributions can now specify the
+  custom data to apply only to a single financial type.
+
+- **(dev/core/50) and
+  [dev/core#195](https://lab.civicrm.org/dev/core/issues/195) Add Separate
+  Sub-tabs for Contributions and Recurring  Contributions
+  ([11956](https://github.com/civicrm/civicrm-core/pull/11956) and
+  [12345](https://github.com/civicrm/civicrm-core/pull/12345))**
+
+  The Contributions tab on a contact now contains two sub-tabs--one for single
+  contributions, and the other for recurring contribution series--instead of
+  displaying one after the other.
+
+- **[dev/core#96](https://lab.civicrm.org/dev/core/issues/96) Expose source
+  column in booking report
+  ([12374](https://github.com/civicrm/civicrm-core/pull/12374))**
+
+  The contribution Source field is now available as a column and filter on the
+  Bookkeeping Transactions report.
+
+- **Use html5 color input for contribution page widget
+  ([12339](https://github.com/civicrm/civicrm-core/pull/12339))**
+
+### CiviMail
+
+- **[dev/mail#1](https://lab.civicrm.org/dev/mail/issues/1) Add pause/resume
+  functionality to civicrm bulk mailing.
+  ([11803](https://github.com/civicrm/civicrm-core/pull/11803) and
+  [12284](https://github.com/civicrm/civicrm-core/pull/12284))**
+
+  A CiviMail mailing that is scheduled or in progress can now be paused in order
+  to allow an urgent message to go out first.
+
+- **Add in bootstrap button classes to CiviMail interface
+  ([12013](https://github.com/civicrm/civicrm-core/pull/12013) and
+  [12338](https://github.com/civicrm/civicrm-core/pull/12338))**
+
+  This allows the interfaces to be themed more easily by Bootstrap-based themes.
+
+## <a name="bugs"></a>Bugs resolved
+
+### Core CiviCRM
+
+- **[dev/core#222](https://lab.civicrm.org/dev/core/issues/222) Importing
+  contacts with dedupe rule does not use the rule
+  ([12393](https://github.com/civicrm/civicrm-core/pull/12393))**
+
+- **[dev/core#284](https://lab.civicrm.org/dev/core/issues/284) Aggressive cache
+  clearing significantly increases test time
+  ([12590](https://github.com/civicrm/civicrm-core/pull/12590))**
+
+  Settings, compiled Javascript, extension, and other caches are now only
+  flushed along with the `default` CiviCRM cache if an external cache like Redis or
+  Memcache is in use. (This reproduces the `5.3` behavior.)
+
+- **[dev/core#279](https://lab.civicrm.org/dev/core/issues/279) When Merging two
+  contacts, Flip between original and duplicate link not working in WordPress
+  ([12568](https://github.com/civicrm/civicrm-core/pull/12568))**
+
+- **Handle 'Check for Matching Contact(s)' button with ajax
+  ([12552](https://github.com/civicrm/civicrm-core/pull/12552))**
+
+  This resolves a bug where the "Check for Matching Contact(s)" button would not
+  work if AJAX Deduping is enabled.
+
+- **[dev/core#131](https://lab.civicrm.org/dev/core/issues/131) Add in missing
+  UK shire Monmouthshire
+  ([12538](https://github.com/civicrm/civicrm-core/pull/12538)) (follow-up on
+  previous work)**
+
+  Many individual sites had manually added the county of Monmouthshire in Wales
+  to the `civicrm_state_province` table, and upgrading to 5.3.0, which added the
+  missing record, would cause them a database error.
+
+- **[dev/core#258](https://lab.civicrm.org/dev/core/issues/258) Possible
+  unreleased regression - message template update altered customised template
+  ([12492](https://github.com/civicrm/civicrm-core/pull/12492))**
+
+- **[dev/core#249](https://lab.civicrm.org/dev/core/issues/249) Contact Export
+  fails in 5.4 when trying to export using the All radio button
+  ([12447](https://github.com/civicrm/civicrm-core/pull/12447))**
+
+- **[dev/core#234](https://lab.civicrm.org/dev/core/issues/234) Upgrade Steps in
+  5.3.alpha1 may not have been run
+  ([12419](https://github.com/civicrm/civicrm-core/pull/12419),
+  [12420](https://github.com/civicrm/civicrm-core/pull/12420), and
+  [12425](https://github.com/civicrm/civicrm-core/pull/12425))**
+
+- **[dev/core#155](https://lab.civicrm.org/dev/core/issues/155) Improvements and
+  bugfixes to Option Groups UI
+  ([12233](https://github.com/civicrm/civicrm-core/pull/12233) and
+  [12411](https://github.com/civicrm/civicrm-core/pull/12411))**
+
+  The Option Groups page now displays whether each option group is reserved or
+  enabled.  In addition, sites using sample data no longer have the sample
+  custom fields reserved.
+
+- **[CRM-20184](https://issues.civicrm.org/jira/browse/CRM-20184) Some System
+  Workflow templates still miss {contact.email_greeting}
+  ([12296](https://github.com/civicrm/civicrm-core/pull/12296))**
+
+  This makes receipt templates more consistent in using the contact's email
+  greeting when sent to individuals.
+
+- **[dev/core#41](https://lab.civicrm.org/dev/core/issues/41) Search Builder:
+  Not empty with date or integer custom fields gives a sql warning
+  ([12351](https://github.com/civicrm/civicrm-core/pull/12351) and
+  [12363](https://github.com/civicrm/civicrm-core/pull/12363))**
+
+- **Make all form tasks inherit from `CRM_Core_Form_Task`
+  ([12318](https://github.com/civicrm/civicrm-core/pull/12318))**
+
+  This addresses some export problems caused by tasks lacking certain properties
+  because their classes did not extend `CRM_Core_Form_Task`.
+
+- **[dev/core#178](https://lab.civicrm.org/dev/core/issues/178) Redis driver -
+  Error messages are invisible
+  ([12303](https://github.com/civicrm/civicrm-core/pull/12303))**
+
+  The log now contains error messages passed from Redis.
+
+- **[dev/core#180](https://lab.civicrm.org/dev/core/issues/180) Deleting custom
+  values and custom_hook parameter `$entity_id` empty
+  ([12309](https://github.com/civicrm/civicrm-core/pull/12309))**
+
+  The ID of the affected entity is now passed to `hook_civicrm_custom` when a
+  value is deleted from a custom field.
+
+- **Fix access to scheduled reminders for admins without event access
+  ([11733](https://github.com/civicrm/civicrm-core/pull/11733))**
+
+  Users with Administer CiviCRM permission but lacking Manage Events permission
+  would get an error when trying to create a non-event scheduled reminder.
+
+- **Only treat a request as a get request (and hence use GET) if it starts with
+  get ([12308](https://github.com/civicrm/civicrm-core/pull/12308))**
+
+- **[dev/core#179](https://lab.civicrm.org/dev/core/issues/179) Redis driver -
+  Allow anonymous connections
+  ([12304](https://github.com/civicrm/civicrm-core/pull/12304))**
+
+  Redis no longer attempts to authenticate when no password is set, such as on
+  local development environments.
+
+- **[dev/core#177](https://lab.civicrm.org/dev/core/issues/177) Redis driver -
+  Reports incorrect value for cache-miss
+  ([12302](https://github.com/civicrm/civicrm-core/pull/12302))**
+
+  When a cache key is undefined, Redis now returns `NULL` rather than `FALSE`.
+
+- **[dev/core#175](https://lab.civicrm.org/dev/core/issues/175) Smart group
+  involving relationship type filter display incorrect results.
+  ([12301](https://github.com/civicrm/civicrm-core/pull/12301))**
+
+- **Make Send SMS permission independent of Edit Contact permission
+  ([12067](https://github.com/civicrm/civicrm-core/pull/12067))**
+
+  You no longer need the permission to edit a contact (in addition to the Send
+  SMS permission) to send the contact a SMS message.
+
+- **[dev/core#134](https://lab.civicrm.org/dev/core/issues/134) Search Builder
+  broken filter for Source Contact ID
+  ([12181](https://github.com/civicrm/civicrm-core/pull/12181))**
+
+- **[dev/core#140](https://lab.civicrm.org/dev/core/issues/140) add missing
+  pseudoconstant for `option_group_id` in CustomField.xml
+  ([12195](https://github.com/civicrm/civicrm-core/pull/12195))**
+
+  Extensions creating custom fields can now refer to option groups by name
+  rather than ID.
+
+- **[dev/accessiblity#3](https://lab.civicrm.org/dev/accessibility/issues/3) Add
+  aria-label (and label?) to form elements missing them
+  ([12209](https://github.com/civicrm/civicrm-core/pull/12209) and
+  [213](https://github.com/civicrm/civicrm-packages/pull/213)) (partial work)**
+
+  Besides adding `aria-label` attributes to sub-elements of the Quickform
+  date field, event info pages no longer wrap basic information labels in
+  `<label>` tags.
+
+- **[CRM-20711](https://issues.civicrm.org/jira/browse/CRM-20711) Error - DB
+  Constraint Violation - GroupContact, get API
+  ([12408](https://github.com/civicrm/civicrm-core/pull/12408))**
+
+  This adds the `location_id` field to the `civicrm_group_contact` table on
+  older sites that lack it.
+
+- **[dev/core#152](https://lab.civicrm.org/dev/core/issues/152) -
+  AdvMulti-Select cleanup
+  ([531](https://github.com/civicrm/civicrm-drupal/pull/531)) (follow-up work)**
+
+  This removes a couple of references to the now-removed "Advanced Multi-select"
+  custom field type
+
+- **Upgrade Mime_mail to fix issues with PHP7.2
+  ([205](https://github.com/civicrm/civicrm-packages/pull/205))**
+
+- **Apply fixes to have DB package support PHP7.2
+  ([207](https://github.com/civicrm/civicrm-packages/pull/207))**
+
+- **[dev/core#117](https://lab.civicrm.org/dev/core/issues/117) Remove usage of
+  `each()` This is deprecated in php7.2
+  ([211](https://github.com/civicrm/civicrm-packages/pull/211)) (follow-up
+  work)**
+
+- **Declare Subparts as array in mimePart to support PHP7.2
+  ([210](https://github.com/civicrm/civicrm-packages/pull/210))**
+
+- **[CRM-19798](https://issues.civicrm.org/jira/browse/CRM-19798) Memory leak in
+  API3 EntityTag get operations
+  ([12276](https://github.com/civicrm/civicrm-core/pull/12276))**
+
+### CiviCase
+
+- **Fix regression on case export from recent export fix
+  ([12588](https://github.com/civicrm/civicrm-core/pull/12588))**
+
+  This resolves undefined property PHP notices when exporting cases.
+
+- **[dev/core#24](https://lab.civicrm.org/dev/core/issues/24) Passing an array
+  for contact_id/client_id to Case.Create API when updating an existing case
+  causes case to be "reassigned"
+  ([11830](https://github.com/civicrm/civicrm-core/pull/11830))**
+
+- **[CRM-21815](https://issues.civicrm.org/jira/browse/CRM-21815) On re-opening
+  a civicase - Case Coordinator (and other roles) are not reinstated
+  ([11736](https://github.com/civicrm/civicrm-core/pull/11736))**
+
+- **[dev/core#165](https://lab.civicrm.org/dev/core/issues/165) Bad link in
+  civicrm/case/activity/view breadcrumb
+  ([12279](https://github.com/civicrm/civicrm-core/pull/12279))**
+
+### CiviContribute
+
+- **[CRM-21637](https://issues.civicrm.org/jira/browse/CRM-21637) Search
+  Criteria for Card Type ID and Card Number not respected in Batch
+  ([11495](https://github.com/civicrm/civicrm-core/pull/11495))**
+
+  The card type and card number filters for financial transactions in the
+  accounting batch interface now work as expected.
+
+- **[CRM-21854](https://issues.civicrm.org/jira/browse/CRM-21854) Contribution
+  start date and end dates are not respected
+  ([11881](https://github.com/civicrm/civicrm-core/pull/11881) and
+  [12504](https://github.com/civicrm/civicrm-core/pull/12504))**
+
+- **[dev/core#264](https://lab.civicrm.org/dev/core/issues/264) Fatal Error on
+  editing Financial Transaction
+  ([12502](https://github.com/civicrm/civicrm-core/pull/12502))**
+
+- **[dev/core#220](https://lab.civicrm.org/dev/core/issues/220) State
+  province/country doesn't show properly in the report
+  ([12390](https://github.com/civicrm/civicrm-core/pull/12390))**
+
+  This resolves a bug in the Contribution History by Relationship report where
+  strange values would appear for the State/Province and Country fields.
+
+- **[dev/core#202](https://lab.civicrm.org/dev/core/issues/202) Empty row under
+  currency drop down
+  ([12356](https://github.com/civicrm/civicrm-core/pull/12356))**
+
+  A warning now appears when a site has a disabled currency that is set as
+  default.
+
+- **[dev/core#88](https://lab.civicrm.org/dev/core/issues/88) Make sure
+  `financial_type_id` is set when a contribution is created
+  ([11907](https://github.com/civicrm/civicrm-core/pull/11907))**
+
+  This resolves a bug where the financial type would not be set on a one-time
+  contribution made through a contribution page.
+
+- **[dev/core#170](https://lab.civicrm.org/dev/core/issues/170) contribution
+  detail report errors when soft credits column is exposed
+  ([12281](https://github.com/civicrm/civicrm-core/pull/12281) and
+  [12282](https://github.com/civicrm/civicrm-core/pull/12282))**
+
+- **Fix e-notice, remove legacy code pattern
+  ([12298](https://github.com/civicrm/civicrm-core/pull/12298))**
+
+  This resolves a PHP notice when printing contribution receipts in bulk.
+
+- **[dev/core#56](https://lab.civicrm.org/dev/core/issues/56) Cancel Recurring
+  Contribution activity should have a source record id
+  ([11964](https://github.com/civicrm/civicrm-core/pull/11964))**
+
+  The activity created when cancelling a recurring contribution now has the
+  recurring contribution ID as the `source_record_id`.
+
+- **[dev/financial#14](https://lab.civicrm.org/dev/financial/issues/14) PayPal
+  Express recurring payment causes warning messages
+  ([12091](https://github.com/civicrm/civicrm-core/pull/12091))**
+
+- **[CRM-20697](https://issues.civicrm.org/jira/browse/CRM-20697) Online pay now
+  anomalies (contribution transfer to new contact)
+  ([11578](https://github.com/civicrm/civicrm-core/pull/11578))**
+
+  The Pay Now form now uses contact ID and checksum to validate the
+  contribution's contact to avoid creating new contacts when an anonymous
+  visitor fulfills a pending contribution.
+
+### CiviEvent
+
+- **[dev/core#272](https://lab.civicrm.org/dev/core/issues/272) Fatal Error
+  (Regression) on PCP pages associated with Events
+  ([12533](https://github.com/civicrm/civicrm-core/pull/12533))**
+
+- **[dev/core#124](https://lab.civicrm.org/dev/core/issues/124) Registration
+  approval issues ([12160](https://github.com/civicrm/civicrm-core/pull/12160)
+  and [12417](https://github.com/civicrm/civicrm-core/pull/12417))**
+
+  This resolves a PHP warning and some confusing aspects of handling event
+  registration approvals.
+
+### CiviGrant
+
+- **[dev/core#187](https://lab.civicrm.org/dev/core/issues/187) Fix typo in
+  `CRM_Grant_Form_Task` that prevents retrieving session key from URL
+  ([12317](https://github.com/civicrm/civicrm-core/pull/12317))**
+
+### CiviMail
+
+- **[dev/core#133](https://lab.civicrm.org/dev/core/issues/133) Reply-to field
+  with empty string get saved in DB as `NULL`
+  ([12176](https://github.com/civicrm/civicrm-core/pull/12176))**
+
+- **[CRM-20320](https://issues.civicrm.org/jira/browse/CRM-20320) Error in PEAR
+  SMTP causes mailing job to fail when an error occurs during one connection
+  ([11840](https://github.com/civicrm/civicrm-core/pull/11840))**
+
+  CiviMail will now disconnect the SMTP connection when a connection error is
+  detected and record the group of messages as not delivered.  This allows it to
+  reconnect later and send the messages.
+
+- **[CRM-17753](https://issues.civicrm.org/jira/browse/CRM-17753) Newsletter
+  confirmation emails shouldn't use do-not-reply@yourdomain.org
+  ([12270](https://github.com/civicrm/civicrm-core/pull/12270)) (preliminary
+  work)**
+
+- **[CRM-21779](https://issues.civicrm.org/jira/browse/CRM-21779) Civimail
+  allows adding current draft mailing recipients to recipients field
+  ([11724](https://github.com/civicrm/civicrm-core/pull/11724))**
+
+### CiviMember
+
+- **[dev/membership#4](https://lab.civicrm.org/dev/membership/issues/4) Admin
+  Membership type is displayed on Public contribution page.
+  ([12178](https://github.com/civicrm/civicrm-core/pull/12178))**
+
+- **[dev/core#276](https://lab.civicrm.org/dev/core/issues/276) Undefined index:
+  is_override on submit credit card membership
+  ([12563](https://github.com/civicrm/civicrm-core/pull/12563))**
+
+- **[dev/core#151](https://lab.civicrm.org/dev/core/issues/151) Action to Update
+  Recurring Contributions From Membership View is Never Shown
+  ([12228](https://github.com/civicrm/civicrm-core/pull/12228))**
+
+  The table to view recurring contributions on a membership now displays the
+  Edit action where appropriate.
+
+- **[CRM-21682](https://issues.civicrm.org/jira/browse/CRM-21682) Automatic
+  membership renewal fixes
+  ([12313](https://github.com/civicrm/civicrm-core/pull/12313) and
+  [12314](https://github.com/civicrm/civicrm-core/pull/12314)) (preliminary
+  work)**
+
+- **[CRM-21177](https://issues.civicrm.org/jira/browse/CRM-21177) Wrong interval
+  of recurring payment for auto-renewing membership
+  ([12289](https://github.com/civicrm/civicrm-core/pull/12289)) (preliminary
+  work)**
+
+### Joomla Integration
+
+- **[dev/joomla#1](https://lab.civicrm.org/dev/joomla/issues/1) CiviEvent menu
+  listing showing old events
+  ([46](https://github.com/civicrm/civicrm-joomla/pull/46))**
+
+### WordPress Integration
+
+- **[dev/wordpress#1](https://lab.civicrm.org/dev/wordpress/issues/1)
+  CiviCRM-WordPress - Gutenberg Compatibility: Do not parse shortcodes in REST
+  context ([130](https://github.com/civicrm/civicrm-wordpress/pull/130))**
+
+- **[CRM-21565](https://issues.civicrm.org/jira/browse/CRM-21565) Change mkdir
+  to use correct and more secure mode numbers
+  ([120](https://github.com/civicrm/civicrm-wordpress/pull/120))**
+
+## <a name="misc"></a>Miscellany
+
+- **(NFC) Convert files to use linux line endings not windows
+  ([12531](https://github.com/civicrm/civicrm-core/pull/12531))**
+
+- **Move DAO function to DAO class, call it from Merge class
+  ([12340](https://github.com/civicrm/civicrm-core/pull/12340))**
+
+- **NFC code cleanup for AuthNet, Paypal, PaypalPro IPNs
+  ([12386](https://github.com/civicrm/civicrm-core/pull/12386))**
+
+- **[dev/core#203](https://lab.civicrm.org/dev/core/issues/203) Cruft code in
+  `CRM_Core_BAO_OptionGroup::add()`
+  ([12357](https://github.com/civicrm/civicrm-core/pull/12357))**
+
+- **Remove unused instances of usedTable
+  ([12341](https://github.com/civicrm/civicrm-core/pull/12341) and
+  [12349](https://github.com/civicrm/civicrm-core/pull/12349))**
+
+- **(NFC) CiviUnitTestCase - Fix edge-case for mis-reported error
+  ([12347](https://github.com/civicrm/civicrm-core/pull/12347))**
+
+- **NFC Code cleanup to core task class
+  ([12316](https://github.com/civicrm/civicrm-core/pull/12316))**
+
+- **[NFC] Stop passing no-longer-part-of-signature variable
+  ([12329](https://github.com/civicrm/civicrm-core/pull/12329))**
+
+- **Fix typo in api explorer sample code
+  ([12324](https://github.com/civicrm/civicrm-core/pull/12324))**
+
+- **Remove unused code variable
+  ([12299](https://github.com/civicrm/civicrm-core/pull/12299))**
+
+- **Confirm & lock in group.get handling of is_active
+  ([12295](https://github.com/civicrm/civicrm-core/pull/12295))**
+
+- **Remove unused function getRecuringTransactionStatus from PayflowPro c…
+  ([12294](https://github.com/civicrm/civicrm-core/pull/12294))**
+
+- **Add upgrade function for message templates that does not involve copying the
+  whole template ([12224](https://github.com/civicrm/civicrm-core/pull/12224))**
+
+- **Function extraction BAO_Export class
+  ([12288](https://github.com/civicrm/civicrm-core/pull/12288))**
+
+- **Partial refactor of completeMembershipFromContribution
+  ([12271](https://github.com/civicrm/civicrm-core/pull/12271))**
+
+- **[NFC] Fix line endings (Jenkins where were you)
+  ([12280](https://github.com/civicrm/civicrm-core/pull/12280))**
+
+- **Towards fixing household merge export, extract function, add test, fix prev
+  ([12272](https://github.com/civicrm/civicrm-core/pull/12272))**
+
+- **Standardise line endings away from windows line endings to linux
+  ([212](https://github.com/civicrm/civicrm-packages/pull/212))**
+
+## <a name="credits"></a>Credits
+
+This release was developed by the following code authors:
+
+AGH Strategies - Alice Frumin, Andrew Hunt; Agileware - Alok Patel; Australian
+Greens - Seamus Lee; Bastien Ho; Caltha - Tomasz Pietrzkowski; CiviCoop - Jaap
+Jansma; CiviCRM - Coleman Watts, Tim Otten; CiviDesk - Yashodha Chaku; CompuCorp -
+Camilo Rodriguez, Michael Devery, René Olivo, Vinu Varshith Sekar; Electronic
+Frontier Foundation - Mark Burdett; Fuzion - Jitendra Purohit; Ginkgo Street
+Labs - Frank Gómez; JMA Consulting - Monish Deb; Johan Vervloet; John
+Kingsnorth; Kanzu Code - Carl Andrew Lema; Left Join Labs - Sean Madsen; MJW
+Consulting - Matthew Wire; Pradeep Nayak; Romain Thouvenin; Squiffle Consulting -
+Aidan Saunders; Tadpole Collective - Kevin Cristiano; Third Sector Design -
+Michael McAndrew; Tom Bloor; Wikimedia Foundation - Eileen McNaughton
+
+Most authors also reviewed code for this release; in addition, the following
+reviewers contributed their comments:
+
+Agileware - Justin Freeman; baernm; Blackfly Solutions - Alan Dixon; Bob
+Silvern; Borislav Zlatanov; Caltha - Michal Mach; cartbar; Christian Wach;
+Circle Interactive - Dave Jenkins; CiviCoop - Erik Hommel; Community Builders -
+Andrew Perry; CompuCorp - Guanhuan Chen, Omar Abu Hussein; Coop SymbioTIC -
+Mathieu Lutfy; Drupal Association - Lizz Trudeau; Evan Chute; Forest CRM
+Consulting - Tamar Meir; Freeform Solutions - Herb van den Dool; Ginkgo Street
+Labs - Dan O'Brien; Hugo do Carmo; JMA Consulting - Joe Murray; Lemniscus - Noah
+Miller; Lighthouse Design and Consulting - Brian Shaughnessy; Megaphone
+Technology Consulting - Jon Goldberg; MJCO - Mikey O'Toole; Oxfam Germany -
+Thomas Schüttler; Richard van Oosterhout; Robin Fenwick; Semper IT - Karin
+Gerritsen; Stephen Palmstrom; Tech To The People - Xavier Dutoit; Timbsoft
+Technologies - Tunbola Ogunwande
+
+## <a name="feedback"></a>Feedback
+
+These release notes are edited by Andrew Hunt.  If you'd like to provide
+feedback on them, please log in to https://chat.civicrm.org/civicrm and contact
+`@agh1`.
index f3a4e5f2eeb7ebe388945d7ae9f086aec6dc47ae..aa19c5efb1de67125f44fef14db166b829250f2e 100644 (file)
@@ -399,7 +399,7 @@ UNLOCK TABLES;
 
 LOCK TABLES `civicrm_domain` WRITE;
 /*!40000 ALTER TABLE `civicrm_domain` DISABLE KEYS */;
-INSERT INTO `civicrm_domain` (`id`, `name`, `description`, `config_backend`, `version`, `contact_id`, `locales`, `locale_custom_strings`) VALUES (1,'Default Domain Name',NULL,NULL,'5.5.alpha1',1,NULL,'a:1:{s:5:\"en_US\";a:0:{}}');
+INSERT INTO `civicrm_domain` (`id`, `name`, `description`, `config_backend`, `version`, `contact_id`, `locales`, `locale_custom_strings`) VALUES (1,'Default Domain Name',NULL,NULL,'5.6.alpha1',1,NULL,'a:1:{s:5:\"en_US\";a:0:{}}');
 /*!40000 ALTER TABLE `civicrm_domain` ENABLE KEYS */;
 UNLOCK TABLES;
 
index f15819318a3ca021d6fb780b8b6ca1b832f48b5b..14dd2bd8d483766e00832fa32c7ec744197ae453 100644 (file)
@@ -60,7 +60,9 @@
           <table class="form-layout-compressed">
             {foreach from=$caseRoles.client item=client}
               <tr class="crm-case-caseview-display_name">
-                <td class="label-left bold" style="padding: 0px; border: none;">{$client.display_name}</td>
+                <td class="label-left bold" style="padding: 0px; border: none;">
+                  <a href="{crmURL p='civicrm/contact/view' q="action=view&reset=1&cid=`$client.contact_id`"}" title="{ts}View contact record{/ts}">{$client.display_name}</a>
+                </td>
               </tr>
               {if $client.phone}
                 <tr class="crm-case-caseview-phone">
index c4a9bc2adaa4ffb74357e91b67482e7a09256d3e..4f989cdf6e6db9c423e9978125e83ba1fe88a443 100644 (file)
@@ -51,7 +51,7 @@
           </li>
           <li id="tab_recurring" class="crm-tab-button ui-corner-all ui-tabs-tab ui-corner-top ui-state-default ui-tab">
             <a href="#recurring-subtab" title="{ts}Recurring Contributions{/ts}">
-              {ts}Recurring Contributions{/ts} <em>{$activeRecurRows|@count}</em>
+              {ts}Recurring Contributions{/ts} <em>{$contributionRecurCount}</em>
             </a>
           </li>
         </ul>
index 79d68bda40cd6320b1a82848405b883d93c434fd..026a009d1a358e1d41145fa0a74a9f2d8dd8ff45 100644 (file)
@@ -35,5 +35,6 @@
   </td>
   <td>{if $form.$fieldName.html}{if $fieldSpec.formatter === 'crmMoney'}{$form.$fieldName.html|crmMoney}{else}{$form.$fieldName.html}{/if}{else}{$fieldSpec.place_holder}{/if}<br />
     {if $fieldSpec.description}<span class="description">{$fieldSpec.description}</span>{/if}
+    {if $fieldSpec.documentation_link}{docURL page=$fieldSpec.documentation_link.page}{/if}
   </td>
 {/if}
index b9eabe52386c07c79363b83ab4ced7477f991386..2fee1d365533c295c56128ae527c100f610f39a4 100644 (file)
   <div class="form-item" id="membership_type_form">
     <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
     <table class="form-layout-compressed">
-      <tr class="crm-membership-type-form-block-name">
-        <td class="label">{$form.name.label} {if $action == 2}{include file='CRM/Core/I18n/Dialog.tpl' table='civicrm_membership_type' field='name' id=$membershipTypeId}{/if}
-        </td>
-        <td>{$form.name.html}<br />
-          <span class="description">{ts}e.g. 'Student', 'Senior', 'Honor Society'...{/ts}</span>
-        </td>
-      </tr>
-      <tr class="crm-membership-type-form-block-description">
-        <td class="label">{$form.description.label} {if $action == 2}{include file='CRM/Core/I18n/Dialog.tpl' table='civicrm_membership_type' field='description' id=$membershipTypeId}{/if}
-        </td>
-        <td>{$form.description.html}<br />
-          <span class="description">{ts}Description of this membership type for internal use. May include eligibility, benefits, terms, etc.{/ts}</span>
-        </td>
-      </tr>
-
-      <tr class="crm-membership-type-form-block-member_org">
-        <td class="label">{$form.member_of_contact_id.label}</td>
-        <td>{$form.member_of_contact_id.html}<br />
-          <span class="description">{ts}Members assigned this membership type belong to which organization (e.g. this is for membership in 'Save the Whales - Northwest Chapter'). NOTE: This organization/group/chapter must exist as a CiviCRM Organization type contact.{/ts}</span>
-        </td>
-      </tr>
-
-      <tr class="crm-membership-type-form-block-minimum_fee">
-        <td class="label">{$form.minimum_fee.label}</td>
-        <td>{$form.minimum_fee.html|crmMoney}<br />
-          <span  class="description">{ts}Minimum fee required for this membership type. For free/complimentary memberships - set minimum fee to zero (0). NOTE: When using CiviCRM to process sales taxes this should be the tax exclusive amount.{/ts}</span>
-        </td>
-      </tr>
+      {foreach from=$tpl_standardised_fields item=fieldName}
+       {assign var=fieldSpec value=$entityFields.$fieldName}
+       <tr class="crm-{$entityInClassFormat}-form-block-{$fieldName}">
+          {include file="CRM/Core/Form/Field.tpl"}
+        </tr>
+      {/foreach}
       <tr class="crm-membership-type-form-block-financial_type_id">
         <td class="label">{$form.financial_type_id.label}</td>
         <td>{$form.financial_type_id.html}<br />
index 900b96dc17e0c1da2cb1a8b34567f87cfbe55b04..51c4d537e5f19e781c238bd228ff5217cb9f5f37 100644 (file)
@@ -84,11 +84,14 @@ class CRM_Core_BAO_CacheTest extends CiviUnitTestCase {
 
   public function getCleanKeyExamples() {
     $es = [];
-    $es[] = ['hello_world and other.planets', 'hello_world and other.planets']; // allowed chars
+    $es[] = ['hello_world and/other.planets', 'hello_world-20and-2fother.planets']; // allowed chars
     $es[] = ['hello/world+-#@{}', 'hello-2fworld-2b-2d-23-40-7b-7d']; // escaped chars
-    $es[] = ['123456789 123456789 123456789 123456789 123456789 123456789 123', '123456789 123456789 123456789 123456789 123456789 123456789 123']; // long but allowed
-    $es[] = ['123456789 123456789 123456789 123456789 123456789 123456789 1234', '-2a008e182a4dcd1a78f405f30119e5f2']; // too long, md5 fallback
-    $es[] = ['123456789 /23456789 +23456789 -23456789 123456789 123456789', '-1b6baab5961431ed443ab321f5dfa0fb']; // too long, md5 fallback
+    $es[] = ["LF-\nTAB-\tCR-\remojiskull💀", 'LF-2d-aTAB-2d-9CR-2d-demojiskull-f0-9f-92-80']; // short with emoji
+    $es[] = ["LF-\nTAB-\tCR-\remojibomb💣emojiskull💀", '-5d9324e052f6e10240dce5029c5e8525']; // long with emoji
+    $es[] = ['123456789 123456789 123456789 123456789 123456789 123', '123456789-20123456789-20123456789-20123456789-20123456789-20123']; // spaces are escaped
+    $es[] = ['123456789_123456789_123456789_123456789_123456789_123456789_123', '123456789_123456789_123456789_123456789_123456789_123456789_123']; // long but allowed
+    $es[] = ['123456789_123456789_123456789_123456789_123456789_123456789_1234', '-e02b981aff954fdcc9a81c25f5ec9681']; // too long, md5 fallback
+    $es[] = ['123456789-/23456789-+23456789--23456789_123456789_123456789', '-43b6dec1026187ae6f6a8fe4d56ab22e']; // too long, md5 fallback
     return $es;
   }
 
index 8d7255a5bd31c077755741a9eb265f34bc9faeaa..ad6e0d86bdc6c9267761289d7ebd8fc42a3e9cdd 100644 (file)
@@ -35,6 +35,20 @@ class CRM_Core_BAO_CustomValueTableMultipleTest extends CiviUnitTestCase {
     $this->assertEquals($params["custom_{$customField['id']}_-1"], $result["custom_{$customField['id']}_1"]);
     $this->assertEquals($params['entityID'], $result['entityID']);
 
+    $updateParams = array(
+      'id' => 1,
+      'entityID' => $contactID,
+      "custom_{$customField['id']}" => 2,
+    );
+    CRM_Core_BAO_CustomValueTable::setValues($updateParams);
+
+    $criteria = array(
+      'id' => 1,
+      'entityID' => $contactID,
+    );
+    $result = CRM_Core_BAO_CustomValueTable::getValues($criteria);
+    $this->assertEquals(2, $result["custom_{$customField['id']}_1"]);
+
     $this->customFieldDelete($customField['id']);
     $this->customGroupDelete($customGroup['id']);
     $this->contactDelete($contactID);
index e62c907b243dd0d62691b98edb90a5c7ffb8c63c..9166688b86e7bfd1fa470681245d962eec2ce05d 100644 (file)
@@ -21,12 +21,12 @@ class CRM_Core_ComposerConfigTest extends \PHPUnit_Framework_TestCase {
    */
   public function testHardLocks() {
     $hardLocks = array(
-      'symfony/config' => '/^v2\.6\./',
-      'symfony/dependency-injection' => '/^v2\.6\./',
-      'symfony/event-dispatcher' => '/^v2\.6\./',
-      'symfony/filesystem' => '/^v2\.6\./',
-      'symfony/finder' => '/^v2\.6\./',
-      'symfony/process' => '/^v2\.6\./',
+      'symfony/config' => '/^v2\.8\./',
+      'symfony/dependency-injection' => '/^v2\.8\./',
+      'symfony/event-dispatcher' => '/^v2\.8\./',
+      'symfony/filesystem' => '/^v2\.8\./',
+      'symfony/finder' => '/^v2\.8\./',
+      'symfony/process' => '/^v2\.8\./',
     );
 
     $lockFile = Civi::paths()->getPath('[civicrm.root]/composer.lock');
index 1a0418413a47ef52980850525be449fada2602d5..4d1631b72c6cb71656886f40ae8e24c6c73e154c 100644 (file)
@@ -843,9 +843,11 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
    * @param $selectedFields
    * @param int $id
    *
+   * @param int $exportMode
+   *
    * @return array
    */
-  protected function doExport($selectedFields, $id) {
+  protected function doExport($selectedFields, $id, $exportMode = CRM_Export_Form_Select::CONTACT_EXPORT) {
     list($tableName, $sqlColumns) = CRM_Export_BAO_Export::exportComponents(
       TRUE,
       array($id),
@@ -853,7 +855,7 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       NULL,
       $selectedFields,
       NULL,
-      CRM_Export_Form_Select::CONTACT_EXPORT,
+      $exportMode,
       "contact_a.id IN ({$id})",
       NULL,
       FALSE,
@@ -1325,12 +1327,13 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
   /**
    * Test the column definition when 'all' fields defined.
    *
-   * @param $exportMode
-   * @param $expected
+   * @param int $exportMode
+   * @param array $expected
+   * @param array $expectedHeaders
    *
    * @dataProvider getSqlColumnsOutput
    */
-  public function testGetSQLColumns($exportMode, $expected) {
+  public function testGetSQLColumnsAndHeaders($exportMode, $expected, $expectedHeaders) {
     $this->ensureComponentIsEnabled($exportMode);
     // We need some data so that we can get to the end of the export
     // function. Hopefully one day that won't be required to get metadata info out.
@@ -1356,6 +1359,267 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       )
     );
     $this->assertEquals($expected, $result[1]);
+    $this->assertEquals($expectedHeaders, $result[2]);
+  }
+
+  /**
+   * Test exported with fields to output specified.
+   *
+   * @dataProvider getAllSpecifiableReturnFields
+   *
+   * @param int $exportMode
+   * @param array $selectedFields
+   * @param array $expected
+   */
+  public function testExportSpecifyFields($exportMode, $selectedFields, $expected) {
+    $this->ensureComponentIsEnabled($exportMode);
+    $this->setUpContributionExportData();
+    list($tableName, $sqlColumns) = $this->doExport($selectedFields, $this->contactIDs[1], $exportMode);
+    $this->assertEquals($expected, $sqlColumns);
+  }
+
+  /**
+   * Test export fields when no payment fields to be exported.
+   */
+  public function textExportParticipantSpecifyFieldsNoPayment() {
+    $selectedFields = $this->getAllSpecifiableParticipantReturnFields();
+    foreach ($selectedFields as $index => $field) {
+      if (substr($field[1], 0, 22) === 'componentPaymentField_') {
+        unset ($selectedFields[$index]);
+      }
+    }
+
+    $expected = $this->getAllSpecifiableParticipantReturnFields();
+    foreach ($expected as $index => $field) {
+      if (substr($index, 0, 22) === 'componentPaymentField_') {
+        unset ($expected[$index]);
+      }
+    }
+
+    list($tableName, $sqlColumns) = $this->doExport($selectedFields, $this->contactIDs[1], CRM_Export_Form_Select::EVENT_EXPORT);
+    $this->assertEquals($expected, $sqlColumns);
+  }
+  /**
+   * Get all return fields (@todo - still being built up.
+   *
+   * @return array
+   */
+  public function getAllSpecifiableReturnFields() {
+    return [
+      [
+        CRM_Export_Form_Select::EVENT_EXPORT,
+        $this->getAllSpecifiableParticipantReturnFields(),
+        $this->getAllSpecifiableParticipantReturnColumns(),
+      ],
+    ];
+  }
+
+  /**
+   * Get expected return column output for participant mode return all columns.
+   *
+   * @return array
+   */
+  public function getAllSpecifiableParticipantReturnColumns() {
+    return [
+      'participant_campaign_id' => 'participant_campaign_id varchar(128)',
+      'participant_contact_id' => 'participant_contact_id varchar(16)',
+      'componentpaymentfield_contribution_status' => 'componentpaymentfield_contribution_status text',
+      'currency' => 'currency varchar(3)',
+      'componentpaymentfield_received_date' => 'componentpaymentfield_received_date text',
+      'default_role_id' => 'default_role_id varchar(16)',
+      'participant_discount_name' => 'participant_discount_name varchar(16)',
+      'event_id' => 'event_id varchar(16)',
+      'event_end_date' => 'event_end_date varchar(32)',
+      'event_start_date' => 'event_start_date varchar(32)',
+      'template_title' => 'template_title varchar(255)',
+      'event_title' => 'event_title varchar(255)',
+      'participant_fee_amount' => 'participant_fee_amount varchar(32)',
+      'participant_fee_currency' => 'participant_fee_currency varchar(3)',
+      'fee_label' => 'fee_label varchar(255)',
+      'participant_fee_level' => 'participant_fee_level longtext',
+      'participant_is_pay_later' => 'participant_is_pay_later varchar(16)',
+      'participant_id' => 'participant_id varchar(16)',
+      'participant_note' => 'participant_note text',
+      'participant_role_id' => 'participant_role_id varchar(128)',
+      'participant_role' => 'participant_role varchar(255)',
+      'participant_source' => 'participant_source varchar(128)',
+      'participant_status_id' => 'participant_status_id varchar(16)',
+      'participant_status' => 'participant_status varchar(255)',
+      'participant_register_date' => 'participant_register_date varchar(32)',
+      'participant_registered_by_id' => 'participant_registered_by_id varchar(16)',
+      'participant_is_test' => 'participant_is_test varchar(16)',
+      'componentpaymentfield_total_amount' => 'componentpaymentfield_total_amount text',
+      'componentpaymentfield_transaction_id' => 'componentpaymentfield_transaction_id varchar(255)',
+      'transferred_to_contact_id' => 'transferred_to_contact_id varchar(16)',
+    ];
+  }
+
+  /**
+   * @return array
+   */
+  public function getAllSpecifiableParticipantReturnFields() {
+    return [
+      0 =>
+        [
+          0 => 'Participant',
+          1 => '',
+        ],
+      1 =>
+        [
+          0 => 'Participant',
+          1 => 'participant_campaign_id',
+        ],
+      2 =>
+        [
+          0 => 'Participant',
+          1 => 'participant_contact_id',
+        ],
+      3 =>
+        [
+          0 => 'Participant',
+          1 => 'componentPaymentField_contribution_status',
+        ],
+      4 =>
+        [
+          0 => 'Participant',
+          1 => 'currency',
+        ],
+      5 =>
+        [
+          0 => 'Participant',
+          1 => 'componentPaymentField_received_date',
+        ],
+      6 =>
+        [
+          0 => 'Participant',
+          1 => 'default_role_id',
+        ],
+      7 =>
+        [
+          0 => 'Participant',
+          1 => 'participant_discount_name',
+        ],
+      8 =>
+        [
+          0 => 'Participant',
+          1 => 'event_id',
+        ],
+      9 =>
+        [
+          0 => 'Participant',
+          1 => 'event_end_date',
+        ],
+      10 =>
+        [
+          0 => 'Participant',
+          1 => 'event_start_date',
+        ],
+      11 =>
+        [
+          0 => 'Participant',
+          1 => 'template_title',
+        ],
+      12 =>
+        [
+          0 => 'Participant',
+          1 => 'event_title',
+        ],
+      13 =>
+        [
+          0 => 'Participant',
+          1 => 'participant_fee_amount',
+        ],
+      14 =>
+        [
+          0 => 'Participant',
+          1 => 'participant_fee_currency',
+        ],
+      15 =>
+        [
+          0 => 'Participant',
+          1 => 'fee_label',
+        ],
+      16 =>
+        [
+          0 => 'Participant',
+          1 => 'participant_fee_level',
+        ],
+      17 =>
+        [
+          0 => 'Participant',
+          1 => 'participant_is_pay_later',
+        ],
+      18 =>
+        [
+          0 => 'Participant',
+          1 => 'participant_id',
+        ],
+      19 =>
+        [
+          0 => 'Participant',
+          1 => 'participant_note',
+        ],
+      20 =>
+        [
+          0 => 'Participant',
+          1 => 'participant_role_id',
+        ],
+      21 =>
+        [
+          0 => 'Participant',
+          1 => 'participant_role',
+        ],
+      22 =>
+        [
+          0 => 'Participant',
+          1 => 'participant_source',
+        ],
+      23 =>
+        [
+          0 => 'Participant',
+          1 => 'participant_status_id',
+        ],
+      24 =>
+        [
+          0 => 'Participant',
+          1 => 'participant_status',
+        ],
+      25 =>
+        [
+          0 => 'Participant',
+          1 => 'participant_status',
+        ],
+      26 =>
+        [
+          0 => 'Participant',
+          1 => 'participant_register_date',
+        ],
+      27 =>
+        [
+          0 => 'Participant',
+          1 => 'participant_registered_by_id',
+        ],
+      28 =>
+        [
+          0 => 'Participant',
+          1 => 'participant_is_test',
+        ],
+      29 =>
+        [
+          0 => 'Participant',
+          1 => 'componentPaymentField_total_amount',
+        ],
+      30 =>
+        [
+          0 => 'Participant',
+          1 => 'componentPaymentField_transaction_id',
+        ],
+      31 =>
+        [
+          0 => 'Participant',
+          1 => 'transferred_to_contact_id',
+        ],
+    ];
   }
 
   /**
@@ -1387,35 +1651,340 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       [
         'anything that will then be defaulting ton contact',
         $this->getBasicSqlColumnDefinition(TRUE),
+        $this->getBasicHeaderDefinition(TRUE),
       ],
       [
         CRM_Export_Form_Select::ACTIVITY_EXPORT,
         array_merge($this->getBasicSqlColumnDefinition(FALSE), $this->getActivitySqlColumns()),
+        array_merge($this->getBasicHeaderDefinition(FALSE), $this->getActivityHeaderDefinition()),
       ],
       [
         CRM_Export_Form_Select::CASE_EXPORT,
         array_merge($this->getBasicSqlColumnDefinition(FALSE), $this->getCaseSqlColumns()),
+        array_merge($this->getBasicHeaderDefinition(FALSE), $this->getCaseHeaderDefinition()),
       ],
       [
         CRM_Export_Form_Select::CONTRIBUTE_EXPORT,
         array_merge($this->getBasicSqlColumnDefinition(FALSE), $this->getContributionSqlColumns()),
+        array_merge($this->getBasicHeaderDefinition(FALSE), $this->getContributeHeaderDefinition()),
       ],
       [
         CRM_Export_Form_Select::EVENT_EXPORT,
         array_merge($this->getBasicSqlColumnDefinition(FALSE), $this->getParticipantSqlColumns()),
+        array_merge($this->getBasicHeaderDefinition(FALSE), $this->getParticipantHeaderDefinition()),
       ],
       [
         CRM_Export_Form_Select::MEMBER_EXPORT,
         array_merge($this->getBasicSqlColumnDefinition(FALSE), $this->getMembershipSqlColumns()),
+        array_merge($this->getBasicHeaderDefinition(FALSE), $this->getMemberHeaderDefinition()),
       ],
       [
         CRM_Export_Form_Select::PLEDGE_EXPORT,
         array_merge($this->getBasicSqlColumnDefinition(FALSE), $this->getPledgeSqlColumns()),
+        array_merge($this->getBasicHeaderDefinition(FALSE), $this->getPledgeHeaderDefinition()),
       ],
 
     ];
   }
 
+  /**
+   * Get the header definition for exports.
+   *
+   * @param bool $isContactExport
+   *
+   * @return array
+   */
+  protected function getBasicHeaderDefinition($isContactExport) {
+    $headers = [
+        0 => 'Contact ID',
+        1 => 'Contact Type',
+        2 => 'Contact Subtype',
+        3 => 'Do Not Email',
+        4 => 'Do Not Phone',
+        5 => 'Do Not Mail',
+        6 => 'Do Not Sms',
+        7 => 'Do Not Trade',
+        8 => 'No Bulk Emails (User Opt Out)',
+        9 => 'Legal Identifier',
+        10 => 'External Identifier',
+        11 => 'Sort Name',
+        12 => 'Display Name',
+        13 => 'Nickname',
+        14 => 'Legal Name',
+        15 => 'Image Url',
+        16 => 'Preferred Communication Method',
+        17 => 'Preferred Language',
+        18 => 'Preferred Mail Format',
+        19 => 'Contact Hash',
+        20 => 'Contact Source',
+        21 => 'First Name',
+        22 => 'Middle Name',
+        23 => 'Last Name',
+        24 => 'Individual Prefix',
+        25 => 'Individual Suffix',
+        26 => 'Formal Title',
+        27 => 'Communication Style',
+        28 => 'Email Greeting ID',
+        29 => 'Postal Greeting ID',
+        30 => 'Addressee ID',
+        31 => 'Job Title',
+        32 => 'Gender',
+        33 => 'Birth Date',
+        34 => 'Deceased',
+        35 => 'Deceased Date',
+        36 => 'Household Name',
+        37 => 'Organization Name',
+        38 => 'Sic Code',
+        39 => 'Unique ID (OpenID)',
+        40 => 'Current Employer ID',
+        41 => 'Contact is in Trash',
+        42 => 'Created Date',
+        43 => 'Modified Date',
+        44 => 'Addressee',
+        45 => 'Email Greeting',
+        46 => 'Postal Greeting',
+        47 => 'Current Employer',
+        48 => 'Location Type',
+        49 => 'Street Address',
+        50 => 'Street Number',
+        51 => 'Street Number Suffix',
+        52 => 'Street Name',
+        53 => 'Street Unit',
+        54 => 'Supplemental Address 1',
+        55 => 'Supplemental Address 2',
+        56 => 'Supplemental Address 3',
+        57 => 'City',
+        58 => 'Postal Code Suffix',
+        59 => 'Postal Code',
+        60 => 'Latitude',
+        61 => 'Longitude',
+        62 => 'Address Name',
+        63 => 'Master Address Belongs To',
+        64 => 'County',
+        65 => 'State',
+        66 => 'Country',
+        67 => 'Phone',
+        68 => 'Phone Extension',
+        69 => 'Phone Type',
+        70 => 'Email',
+        71 => 'On Hold',
+        72 => 'Use for Bulk Mail',
+        73 => 'Signature Text',
+        74 => 'Signature Html',
+        75 => 'IM Provider',
+        76 => 'IM Screen Name',
+        77 => 'OpenID',
+        78 => 'World Region',
+        79 => 'Website',
+        80 => 'Group(s)',
+        81 => 'Tag(s)',
+        82 => 'Note(s)',
+        83 => 'IM Service Provider',
+      ];
+    if (!$isContactExport) {
+      unset($headers[80]);
+      unset($headers[81]);
+      unset($headers[82]);
+    }
+    return $headers;
+  }
+
+  /**
+   * Get the definition for activity headers.
+   *
+   * @return array
+   */
+  protected function getActivityHeaderDefinition() {
+    return [
+      81 => 'Activity ID',
+      82 => 'Activity Type',
+      83 => 'Activity Type ID',
+      84 => 'Subject',
+      85 => 'Activity Date',
+      86 => 'Duration',
+      87 => 'Location',
+      88 => 'Details',
+      89 => 'Activity Status',
+      90 => 'Activity Priority',
+      91 => 'Source Contact',
+      92 => 'source_record_id',
+      93 => 'Test',
+      94 => 'Campaign ID',
+      95 => 'result',
+      96 => 'Engagement Index',
+      97 => 'parent_id',
+    ];
+  }
+
+  /**
+   * Get the definition for case headers.
+   *
+   * @return array
+   */
+  protected function getCaseHeaderDefinition() {
+    return [
+      81 => 'contact_id',
+      82 => 'Case ID',
+      83 => 'case_activity_subject',
+      84 => 'Case Subject',
+      85 => 'Case Status',
+      86 => 'Case Type',
+      87 => 'Role in Case',
+      88 => 'Case is in the Trash',
+      89 => 'case_recent_activity_date',
+      90 => 'case_recent_activity_type',
+      91 => 'case_scheduled_activity_date',
+      92 => 'Case Start Date',
+      93 => 'Case End Date',
+      94 => 'case_source_contact_id',
+      95 => 'case_activity_status',
+      96 => 'case_activity_duration',
+      97 => 'case_activity_medium_id',
+      98 => 'case_activity_details',
+      99 => 'case_activity_is_auto',
+    ];
+  }
+
+  /**
+   * Get the definition for contribute headers.
+   *
+   * @return array
+   */
+  protected function getContributeHeaderDefinition() {
+    return [
+      81 => 'Financial Type',
+      82 => 'Contribution Source',
+      83 => 'Date Received',
+      84 => 'Thank-you Date',
+      85 => 'Cancel Date',
+      86 => 'Total Amount',
+      87 => 'Accounting Code',
+      88 => 'payment_instrument',
+      89 => 'Payment Method ID',
+      90 => 'Check Number',
+      91 => 'Non-deductible Amount',
+      92 => 'Fee Amount',
+      93 => 'Net Amount',
+      94 => 'Transaction ID',
+      95 => 'Invoice Reference',
+      96 => 'Invoice Number',
+      97 => 'Currency',
+      98 => 'Cancel Reason',
+      99 => 'Receipt Date',
+      100 => 'Product Name',
+      101 => 'SKU',
+      102 => 'Product Option',
+      103 => 'Fulfilled Date',
+      104 => 'Start date for premium',
+      105 => 'End date for premium',
+      106 => 'Test',
+      107 => 'Is Pay Later',
+      108 => 'contribution_status',
+      109 => 'Recurring Contribution ID',
+      110 => 'Amount Label',
+      111 => 'Contribution Note',
+      112 => 'Batch Name',
+      113 => 'Campaign Title',
+      114 => 'Campaign ID',
+      115 => 'Premium',
+      116 => 'Soft Credit For',
+      117 => 'Soft Credit Amount',
+      118 => 'Soft Credit Type',
+      119 => 'Soft Credit For Contact ID',
+      120 => 'Soft Credit For Contribution ID',
+    ];
+  }
+
+  /**
+   * Get the definition for event headers.
+   *
+   * @return array
+   */
+  protected function getParticipantHeaderDefinition() {
+    return [
+      81 => 'Event',
+      82 => 'Event Title',
+      83 => 'Event Start Date',
+      84 => 'Event End Date',
+      85 => 'Event Type',
+      86 => 'Participant ID',
+      87 => 'Participant Status',
+      88 => 'Participant Status Id',
+      89 => 'Participant Role',
+      90 => 'Participant Role Id',
+      91 => 'Participant Note',
+      92 => 'Register date',
+      93 => 'Participant Source',
+      94 => 'Fee level',
+      95 => 'Test',
+      96 => 'Is Pay Later',
+      97 => 'Fee Amount',
+      98 => 'Discount Name',
+      99 => 'Fee Currency',
+      100 => 'Registered By ID',
+      101 => 'Campaign ID',
+    ];
+  }
+
+  /**
+   * Get the definition for member headers.
+   *
+   * @return array
+   */
+  protected function getMemberHeaderDefinition() {
+    return [
+      81 => 'Membership Type',
+      82 => 'Test',
+      83 => 'Is Pay Later',
+      84 => 'Member Since',
+      85 => 'Membership Start Date',
+      86 => 'Membership Expiration Date',
+      87 => 'Source',
+      88 => 'Membership Status',
+      89 => 'Membership ID',
+      90 => 'Primary Member ID',
+      91 => 'max_related',
+      92 => 'membership_recur_id',
+      93 => 'Campaign ID',
+      94 => 'member_is_override',
+      95 => 'member_auto_renew',
+    ];
+  }
+
+  /**
+   * Get the definition for pledge headers.
+   *
+   * @return array
+   */
+  protected function getPledgeHeaderDefinition() {
+    return [
+      81 => 'Pledge ID',
+      82 => 'Total Pledged',
+      83 => 'Total Paid',
+      84 => 'Pledge Made',
+      85 => 'pledge_start_date',
+      86 => 'Next Payment Date',
+      87 => 'Next Payment Amount',
+      88 => 'Pledge Status',
+      89 => 'Test',
+      90 => 'Pledge Contribution Page Id',
+      91 => 'pledge_financial_type',
+      92 => 'Pledge Frequency Interval',
+      93 => 'Pledge Frequency Unit',
+      94 => 'pledge_currency',
+      95 => 'Campaign ID',
+      96 => 'Balance Amount',
+      97 => 'Payment ID',
+      98 => 'Scheduled Amount',
+      99 => 'Scheduled Date',
+      100 => 'Paid Amount',
+      101 => 'Paid Date',
+      102 => 'Last Reminder',
+      103 => 'Reminders Sent',
+      104 => 'Pledge Payment Status',
+    ];
+  }
+
   /**
    * Get the column definition for exports.
    *
@@ -1494,6 +2063,7 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       'country' => 'country varchar(64)',
       'phone' => 'phone varchar(32)',
       'phone_ext' => 'phone_ext varchar(16)',
+      'phone_type_id' => 'phone_type_id varchar(16)',
       'email' => 'email varchar(254)',
       'on_hold' => 'on_hold varchar(16)',
       'is_bulkmail' => 'is_bulkmail varchar(16)',
@@ -1507,7 +2077,6 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       'groups' => 'groups text',
       'tags' => 'tags text',
       'notes' => 'notes text',
-      'phone_type_id' => 'phone_type_id varchar(255)',
       'provider_id' => 'provider_id varchar(255)',
     ];
     if (!$isContactExport) {
@@ -1691,7 +2260,7 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       'openid' => 'openid varchar(255)',
       'world_region' => 'world_region varchar(128)',
       'url' => 'url varchar(128)',
-      'phone_type_id' => 'phone_type_id varchar(255)',
+      'phone_type_id' => 'phone_type_id varchar(16)',
       'provider_id' => 'provider_id varchar(255)',
       'financial_type' => 'financial_type varchar(64)',
       'contribution_source' => 'contribution_source varchar(255)',
index 14fcde188382d5f6b412979662a29b72c3b722c4..6f977f4a137c320aa248d82342d518ed17bceb23 100644 (file)
@@ -1281,10 +1281,12 @@ Expires: ',
   }
 
   /**
-   * CRM-21656: Test the submit function of the membership form if Sale Tax is enabled.
-   *  Check that the tax rate isn't reapplied to line item's unit price and total amount
+   * CRM-21656: Test the submit function of the membership form if Sales Tax is enabled.
+   * This test simulates what happens when one hits Edit on a Contribution that has both LineItems and Sales Tax components
+   * Without making any Edits -> check that the LineItem data remain the same
+   * In addition (a data-integrity check) -> check that the LineItem data add up to the data at the Contribution level
    */
-  public function testLineItemAmountOnSaleTax() {
+  public function testLineItemAmountOnSalesTax() {
     $this->enableTaxAndInvoicing();
     $this->relationForFinancialTypeWithFinancialAccount(2);
     $form = $this->getForm();
@@ -1293,6 +1295,8 @@ Expires: ',
     $this->createLoggedInUser();
     $priceSet = $this->callAPISuccess('PriceSet', 'Get', array("extends" => "CiviMember"));
     $form->set('priceSetId', $priceSet['id']);
+    // we are simulating the creation of a Price Set in Administer -> CiviContribute -> Manage Price Sets so set is_quick_config = 0
+    $this->callAPISuccess('PriceSet', 'Create', array("id" => $priceSet['id'], 'is_quick_config' => 0));
     // clean the price options static variable to repopulate the options, in order to fetch tax information
     \Civi::$statics['CRM_Price_BAO_PriceField']['priceOptions'] = NULL;
     CRM_Price_BAO_PriceSet::buildPriceSet($form);
@@ -1336,10 +1340,22 @@ Expires: ',
     ),
     CRM_Core_Action::UPDATE);
 
-    // ensure that the line-item values got unaffected
+    // ensure that the LineItem data remain the same
     $lineItem = $this->callAPISuccessGetSingle('LineItem', array('entity_id' => $membership['id'], 'entity_table' => 'civicrm_membership'));
     $this->assertEquals(1, $lineItem['qty']);
-    $this->assertEquals(5.00, $lineItem['tax_amount']); // ensure that tax amount is not changed
+    $this->assertEquals(50.00, $lineItem['unit_price']);
+    $this->assertEquals(50.00, $lineItem['line_total']);
+    $this->assertEquals(5.00, $lineItem['tax_amount']);
+
+    // ensure that the LineItem data add up to the data at the Contribution level
+    $contribution = $this->callAPISuccessGetSingle('Contribution',
+      array(
+        'contribution_id' => 1,
+        'return' => array('tax_amount', 'total_amount'),
+      )
+    );
+    $this->assertEquals($contribution['total_amount'], $lineItem['line_total'] + $lineItem['tax_amount']);
+    $this->assertEquals($contribution['tax_amount'], $lineItem['tax_amount']);
 
     // reset the price options static variable so not leave any dummy data, that might hamper other unit tests
     \Civi::$statics['CRM_Price_BAO_PriceField']['priceOptions'] = NULL;
index 133a9f812add8d1cb24f42cb57f27d3bfb239f1a..d50a684e53c357b94bbc093f1176c2a21ae62e0a 100644 (file)
@@ -552,4 +552,72 @@ class api_v3_CustomValueTest extends CiviUnitTestCase {
 
   }
 
+  /**
+   * Creates a multi-valued custom field set and creates a contact with mutliple values for it.
+   *
+   * @return array
+   */
+  private function _testGetCustomValueMultiple() {
+    $fieldIDs = $this->CustomGroupMultipleCreateWithFields();
+    $customFieldValues = [];
+    foreach ($fieldIDs['custom_field_id'] as $id) {
+      $customFieldValues["custom_{$id}"] = "field_{$id}_value_1";
+    }
+    $this->assertNotEmpty($customFieldValues);
+    $contactParams = [
+      'first_name' => 'Jane',
+      'last_name' => 'Doe',
+      'contact_type' => 'Individual',
+    ];
+    $contact = $this->callAPISuccess('Contact', 'create', array_merge($contactParams, $customFieldValues));
+    foreach ($fieldIDs['custom_field_id'] as $id) {
+      $customFieldValues["custom_{$id}"] = "field_{$id}_value_2";
+    }
+    $result = $this->callAPISuccess('Contact', 'create', array_merge(['id' => $contact['id']], $customFieldValues));
+    return [
+      $contact['id'],
+      $customFieldValues,
+    ];
+  }
+
+  /**
+   * Test that specific custom values can be retrieved while using return with comma separated values as genererated by the api explorer.
+   * ['return' => 'custom_1,custom_2']
+   */
+  public function testGetCustomValueReturnMultipleApiExplorer() {
+    list($cid, $customFieldValues) = $this->_testGetCustomValueMultiple();
+    $result = $this->callAPISuccess('CustomValue', 'get', [
+      'return' => implode(',', array_keys($customFieldValues)),
+      'entity_id' => $cid,
+    ]);
+    $this->assertEquals(count($customFieldValues), $result['count']);
+  }
+
+  /**
+   * Test that specific custom values can be retrieved while using return with array style syntax.
+   * ['return => ['custom_1', 'custom_2']]
+   */
+  public function testGetCustomValueReturnMultipleArray() {
+    list($cid, $customFieldValues) = $this->_testGetCustomValueMultiple();
+    $result = $this->callAPISuccess('CustomValue', 'get', [
+      'return' => array_keys($customFieldValues),
+      'entity_id' => $cid,
+    ]);
+    $this->assertEquals(count($customFieldValues), $result['count']);
+  }
+
+  /**
+   * Test that specific custom values can be retrieved while using a list of return parameters.
+   * [['return.custom_1' => '1'], ['return.custom_2' => '1']]
+   */
+  public function testGetCustomValueReturnMultipleList() {
+    list($cid, $customFieldValues) = $this->_testGetCustomValueMultiple();
+    $returnArray = [];
+    foreach ($customFieldValues as $field => $value) {
+      $returnArray["return.{$field}"] = 1;
+    }
+    $result = $this->callAPISuccess('CustomValue', 'get', array_merge($returnArray, ['entity_id' => $cid]));
+    $this->assertEquals(count($customFieldValues), $result['count']);
+  }
+
 }
index 30b999f80ff05b5d85430e04eec4371c90a7c85f..95c9e550d076ce16ce5aefd43ee7d1f9b6423599 100644 (file)
@@ -849,7 +849,7 @@ class api_v3_ReportTemplateTest extends CiviUnitTestCase {
       'civicrm_activity_source_record_id' => NULL,
       'civicrm_activity_activity_type_id' => 'Meeting',
       'civicrm_activity_activity_subject' => 'Very secret meeting',
-      'civicrm_activity_activity_date_time' => '2018-07-16 03:42:32',
+      'civicrm_activity_activity_date_time' => date('Y-m-d 23:59:58', strtotime('now')),
       'civicrm_activity_status_id' => 'Scheduled',
       'civicrm_activity_duration' => '120',
       'civicrm_activity_location' => 'Pennsylvania',
@@ -872,7 +872,6 @@ class api_v3_ReportTemplateTest extends CiviUnitTestCase {
       'civicrm_contact_contact_source_link' => '/index.php?q=civicrm/contact/view&amp;reset=1&amp;cid=' . $this->contactIDs[2],
       'civicrm_contact_contact_source_hover' => 'View Contact Summary for this Contact',
       'civicrm_activity_activity_type_id_hover' => 'View Activity Record',
-      'class' => 'status-overdue',
     ];
     $row = $rows[0];
     // This link is not relative - skip for now
@@ -895,7 +894,7 @@ class api_v3_ReportTemplateTest extends CiviUnitTestCase {
 
     $this->callAPISuccess('Activity', 'create', [
       'subject' => 'Very secret meeting',
-      'activity_date_time' => '2018-07-16 03:42:32',
+      'activity_date_time' => date('Y-m-d 23:59:58', strtotime('now')),
       'duration' => 120,
       'location' => 'Pennsylvania',
       'details' => 'a test activity',
index 29b17c1df38aa935d4c2b7acb08f5cdf5b960829..f3703dc8f585ef43dd683a96d850c261ab3170b3 100644 (file)
     <name>phone_type_id</name>
     <title>Phone Type</title>
     <type>int unsigned</type>
+    <export>true</export>
     <comment>Which type of phone does this number belongs.</comment>
     <pseudoconstant>
       <optionGroupName>phone_type</optionGroupName>
index 0286b74680659a91c4fb6ca94ee9300b4baa306a..a71afd51a7fa530b8eb6d29bcb535b690fe503d4 100644 (file)
     <name>auto_renew</name>
     <type>boolean</type>
     <default>0</default>
+    <html>
+      <type>Radio</type>
+    </html>
     <pseudoconstant>
       <callback>CRM_Core_SelectValues::memberAutoRenew</callback>
     </pseudoconstant>
index 2d6ffca87ee222e5521bfbd931a2912716913ee7..b348d6acac62503b568c6eb65b5ed4d2920f6328 100644 (file)
@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="iso-8859-1" ?>
 <version>
-  <version_no>5.5.alpha1</version_no>
+  <version_no>5.6.alpha1</version_no>
 </version>