Merge pull request #15117 from eileenmcnaughton/member_renew
authorSeamus Lee <seamuslee001@gmail.com>
Thu, 5 Sep 2019 21:55:20 +0000 (07:55 +1000)
committerGitHub <noreply@github.com>
Thu, 5 Sep 2019 21:55:20 +0000 (07:55 +1000)
[REF] extract send receipt in MembershipRenewal fn

141 files changed:
.gitignore
CRM/ACL/BAO/Cache.php
CRM/ACL/DAO/ACLCache.php [moved from CRM/ACL/DAO/Cache.php with 91% similarity]
CRM/Activity/BAO/Activity.php
CRM/Activity/Page/AJAX.php
CRM/Admin/Form/Setting/Smtp.php
CRM/Batch/BAO/Batch.php
CRM/Batch/Form/Entry.php
CRM/Case/BAO/Query.php
CRM/Case/Form/Activity/ChangeCaseStatus.php
CRM/Case/XMLProcessor/Process.php
CRM/Contact/BAO/Contact/Utils.php
CRM/Contact/BAO/Query.php
CRM/Contact/BAO/Relationship.php
CRM/Contact/BAO/SavedSearch.php
CRM/Contact/DAO/Contact.php
CRM/Contact/Form/Contact.php
CRM/Contact/Form/Merge.php
CRM/Contact/Import/Form/MapField.php
CRM/Contact/Import/Parser.php
CRM/Contact/Page/AJAX.php
CRM/Contact/Page/DedupeFind.php
CRM/Contact/Page/DedupeMerge.php
CRM/Contact/Page/View.php
CRM/Contribute/BAO/Contribution.php
CRM/Contribute/BAO/ContributionRecur.php
CRM/Contribute/Form/AdditionalPayment.php
CRM/Contribute/Form/Contribution/Confirm.php
CRM/Core/BAO/Address.php
CRM/Core/BAO/CustomField.php
CRM/Core/BAO/Dashboard.php
CRM/Core/BAO/PrevNextCache.php
CRM/Core/BAO/SchemaHandler.php
CRM/Core/Config.php
CRM/Core/DAO/AllCoreTables.data.php
CRM/Core/DAO/Cache.php
CRM/Core/DAO/Dashboard.php
CRM/Core/Error.php
CRM/Core/Page/AJAX/Location.php
CRM/Core/Payment/BaseIPN.php
CRM/Core/Payment/PayPalIPN.php
CRM/Core/Payment/PayPalImpl.php
CRM/Core/Permission.php
CRM/Core/PseudoConstant.php
CRM/Dedupe/Finder.php
CRM/Dedupe/Merger.php
CRM/Event/BAO/Event.php
CRM/Event/Cart/Form/Checkout/Payment.php
CRM/Export/BAO/ExportProcessor.php
CRM/Financial/BAO/ExportFormat.php
CRM/Financial/BAO/Payment.php
CRM/Grant/Form/Grant.php
CRM/Import/ImportProcessor.php
CRM/Mailing/Form/Search.php
CRM/Mailing/Selector/Browse.php
CRM/Member/BAO/Membership.php
CRM/Member/BAO/Query.php
CRM/Member/DAO/Membership.php
CRM/Member/Form/Membership.php
CRM/Member/Form/MembershipRenewal.php
CRM/Member/Form/Search.php
CRM/Member/Form/Task/Batch.php
CRM/Member/Selector/Search.php
CRM/Pledge/BAO/Query.php
CRM/Pledge/DAO/Pledge.php
CRM/Pledge/DAO/PledgePayment.php
CRM/Pledge/Form/Search.php
CRM/Price/BAO/LineItem.php
CRM/Price/BAO/PriceSet.php
CRM/Report/Form/Member/ContributionDetail.php
CRM/Report/Form/Member/Detail.php
CRM/Report/Form/Member/Summary.php
CRM/Report/Form/Membership/Summary.php
CRM/Upgrade/Incremental/SmartGroups.php
CRM/Upgrade/Incremental/php/FiveEighteen.php
CRM/Utils/JS.php
CRM/Utils/System.php
CRM/Utils/System/Joomla.php
api/v3/Batch.php
api/v3/Contribution.php
api/v3/Dedupe.php
api/v3/Event.php
api/v3/Job.php
api/v3/MembershipType.php
api/v3/Payment.php
bin/setup.sh
bower.json [deleted file]
composer.json
composer.lock
distmaker/distmaker.conf.dist
distmaker/distmaker.sh
distmaker/dists/common.sh
distmaker/dists/repo-report.sh
distmaker/utils/repo-report.php
release-notes.md
release-notes/5.16.4.md [new file with mode: 0644]
release-notes/5.17.0.md
sql/civicrm_generated.mysql
templates/CRM/Grant/Form/Grant.tpl
templates/CRM/Mailing/Form/Search.tpl
templates/CRM/Member/Form/Search/Common.tpl
templates/CRM/Member/Form/Selector.tpl
templates/CRM/Pledge/Form/Search/Common.tpl
templates/CRM/Price/Form/Calculate.tpl
templates/CRM/Report/Form/Contact/Detail.tpl
templates/CRM/common/fatal.tpl
tests/phpunit/CRM/Batch/BAO/BatchTest.php
tests/phpunit/CRM/Batch/Form/EntryTest.php
tests/phpunit/CRM/Case/XMLProcessor/ProcessTest.php
tests/phpunit/CRM/Contact/BAO/RelationshipTest.php
tests/phpunit/CRM/Contact/BAO/SavedSearchTest.php
tests/phpunit/CRM/Contact/Import/Form/MapFieldTest.php
tests/phpunit/CRM/Contact/Import/Parser/ContactTest.php
tests/phpunit/CRM/Core/BAO/UFFieldTest.php
tests/phpunit/CRM/Core/Payment/PayPalIPNTest.php
tests/phpunit/CRM/Dedupe/BAO/RuleGroupTest.php
tests/phpunit/CRM/Dedupe/MergerTest.php
tests/phpunit/CRM/Event/BAO/ChangeFeeSelectionTest.php
tests/phpunit/CRM/Event/Form/ParticipantTest.php
tests/phpunit/CRM/Export/BAO/ExportTest.php
tests/phpunit/CRM/Member/BAO/MembershipTest.php
tests/phpunit/CRM/Member/Form/MembershipTest.php
tests/phpunit/CRM/Member/Selector/SearchTest.php
tests/phpunit/CRM/Upgrade/Incremental/BaseTest.php
tests/phpunit/CRM/Utils/JSTest.php
tests/phpunit/CiviTest/CiviUnitTestCase.php
tests/phpunit/api/v3/AttachmentTest.php
tests/phpunit/api/v3/CaseTypeTest.php
tests/phpunit/api/v3/EventTest.php
tests/phpunit/api/v3/GroupNestingTest.php
tests/phpunit/api/v3/GroupOrganizationTest.php
tests/phpunit/api/v3/JobTest.php
tests/phpunit/api/v3/UtilsTest.php
xml/schema/ACL/Cache.xml
xml/schema/Contact/Contact.xml
xml/schema/Core/Cache.xml
xml/schema/Core/Dashboard.xml
xml/schema/Member/Membership.xml
xml/schema/Pledge/Pledge.xml
xml/schema/Pledge/PledgePayment.xml
xml/templates/civicrm_data.tpl

index 95f9b09cd8245b1ddc829a62ada311ff91e004b9..fd86ffe726cee93135cbe60ef4d7aa62701534dd 100644 (file)
@@ -25,7 +25,8 @@ tests/phpunit/CiviTest/CiviSeleniumSettings.php
 tests/phpunit/CiviTest/civicrm.settings.php
 tools/stats/config.php
 authors.txt
-drupal/
+/drupal/
+/drupal-8/
 WordPress
 joomla
 packages/
index 921adfeaf6c08c03e4c94238af36bde567b793a9..c165e940c0d69357574b7063acddbe378f07182a 100644 (file)
@@ -34,7 +34,7 @@
 /**
  *  Access Control Cache.
  */
-class CRM_ACL_BAO_Cache extends CRM_ACL_DAO_Cache {
+class CRM_ACL_BAO_Cache extends CRM_ACL_DAO_ACLCache {
 
   public static $_cache = NULL;
 
@@ -96,7 +96,7 @@ SELECT acl_id
    */
   public static function store($id, &$cache) {
     foreach ($cache as $aclID => $data) {
-      $dao = new CRM_ACL_DAO_Cache();
+      $dao = new CRM_ACL_BAO_Cache();
       if ($id) {
         $dao->contact_id = $id;
       }
similarity index 91%
rename from CRM/ACL/DAO/Cache.php
rename to CRM/ACL/DAO/ACLCache.php
index 34a3e7360b56f9727e26ea3315146edf437e8daf..cbf774e4b27641421418c2d22ded5507ad8ec856 100644 (file)
@@ -4,15 +4,15 @@
  * @package CRM
  * @copyright CiviCRM LLC (c) 2004-2019
  *
- * Generated from xml/schema/CRM/ACL/Cache.xml
+ * Generated from xml/schema/CRM/ACL/ACLCache.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:6180a43e0d4bd8f2008286be6683d0ba)
+ * (GenCodeChecksum:a7bccfc35714fdcf0fdb6f4cd24842bd)
  */
 
 /**
- * Database access object for the Cache entity.
+ * Database access object for the ACLCache entity.
  */
-class CRM_ACL_DAO_Cache extends CRM_Core_DAO {
+class CRM_ACL_DAO_ACLCache extends CRM_Core_DAO {
 
   /**
    * Static instance to hold the table name.
@@ -96,8 +96,8 @@ class CRM_ACL_DAO_Cache extends CRM_Core_DAO {
           'required' => TRUE,
           'where' => 'civicrm_acl_cache.id',
           'table_name' => 'civicrm_acl_cache',
-          'entity' => 'Cache',
-          'bao' => 'CRM_ACL_BAO_Cache',
+          'entity' => 'ACLCache',
+          'bao' => 'CRM_ACL_DAO_ACLCache',
           'localizable' => 0,
         ],
         'contact_id' => [
@@ -107,8 +107,8 @@ class CRM_ACL_DAO_Cache extends CRM_Core_DAO {
           'description' => ts('Foreign Key to Contact'),
           'where' => 'civicrm_acl_cache.contact_id',
           'table_name' => 'civicrm_acl_cache',
-          'entity' => 'Cache',
-          'bao' => 'CRM_ACL_BAO_Cache',
+          'entity' => 'ACLCache',
+          'bao' => 'CRM_ACL_DAO_ACLCache',
           'localizable' => 0,
           'FKClassName' => 'CRM_Contact_DAO_Contact',
         ],
@@ -120,8 +120,8 @@ class CRM_ACL_DAO_Cache extends CRM_Core_DAO {
           'required' => TRUE,
           'where' => 'civicrm_acl_cache.acl_id',
           'table_name' => 'civicrm_acl_cache',
-          'entity' => 'Cache',
-          'bao' => 'CRM_ACL_BAO_Cache',
+          'entity' => 'ACLCache',
+          'bao' => 'CRM_ACL_DAO_ACLCache',
           'localizable' => 0,
           'FKClassName' => 'CRM_ACL_DAO_ACL',
         ],
@@ -133,8 +133,8 @@ class CRM_ACL_DAO_Cache extends CRM_Core_DAO {
           'required' => FALSE,
           'where' => 'civicrm_acl_cache.modified_date',
           'table_name' => 'civicrm_acl_cache',
-          'entity' => 'Cache',
-          'bao' => 'CRM_ACL_BAO_Cache',
+          'entity' => 'ACLCache',
+          'bao' => 'CRM_ACL_DAO_ACLCache',
           'localizable' => 0,
         ],
       ];
index d0ac8f4ada30fcb6a3f144bf51de03dc53b8ffb3..2a999323cd61bc5da88bf96daabff9eee4474ea1 100644 (file)
@@ -987,6 +987,56 @@ class CRM_Activity_BAO_Activity extends CRM_Activity_DAO_Activity {
     return civicrm_api3('Activity', 'getcount', $activityParams);
   }
 
+  /**
+   * @param int $userID
+   * @param string $subject
+   * @param string $html
+   * @param string $text
+   * @param string $additionalDetails
+   * @param int $campaignID
+   * @param array $attachments
+   *
+   * @return int
+   *   The created activity ID
+   * @throws \CRM_Core_Exception
+   */
+  public static function createEmailActivity($userID, $subject, $html, $text, $additionalDetails, $campaignID, $attachments) {
+    $activityTypeID = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Email');
+
+    // CRM-6265: save both text and HTML parts in details (if present)
+    if ($html and $text) {
+      $details = "-ALTERNATIVE ITEM 0-\n$html$additionalDetails\n-ALTERNATIVE ITEM 1-\n$text$additionalDetails\n-ALTERNATIVE END-\n";
+    }
+    else {
+      $details = $html ? $html : $text;
+      $details .= $additionalDetails;
+    }
+
+    $activityParams = [
+      'source_contact_id' => $userID,
+      'activity_type_id' => $activityTypeID,
+      'activity_date_time' => date('YmdHis'),
+      'subject' => $subject,
+      'details' => $details,
+      // FIXME: check for name Completed and get ID from that lookup
+      'status_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'status_id', 'Completed'),
+      'campaign_id' => $campaignID,
+    ];
+
+    // CRM-5916: strip [case #…] before saving the activity (if present in subject)
+    $activityParams['subject'] = preg_replace('/\[case #([0-9a-h]{7})\] /', '', $activityParams['subject']);
+
+    // add the attachments to activity params here
+    if ($attachments) {
+      // first process them
+      $activityParams = array_merge($activityParams, $attachments);
+    }
+
+    $activity = self::create($activityParams);
+
+    return $activity->id;
+  }
+
   /**
    * Send the message to all the contacts.
    *
@@ -1018,6 +1068,8 @@ class CRM_Activity_BAO_Activity extends CRM_Activity_DAO_Activity {
    *
    * @return array
    *   ( sent, activityId) if any email is sent and activityId
+   * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
    */
   public static function sendEmail(
     &$contactDetails,
@@ -1061,45 +1113,8 @@ class CRM_Activity_BAO_Activity extends CRM_Activity_DAO_Activity {
     }
 
     //create the meta level record first ( email activity )
-    $activityTypeID = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Email');
+    $activityID = self::createEmailActivity($userID, $subject, $html, $text, $additionalDetails, $campaignId, $attachments);
 
-    // CRM-6265: save both text and HTML parts in details (if present)
-    if ($html and $text) {
-      $details = "-ALTERNATIVE ITEM 0-\n$html$additionalDetails\n-ALTERNATIVE ITEM 1-\n$text$additionalDetails\n-ALTERNATIVE END-\n";
-    }
-    else {
-      $details = $html ? $html : $text;
-      $details .= $additionalDetails;
-    }
-
-    $activityParams = [
-      'source_contact_id' => $userID,
-      'activity_type_id' => $activityTypeID,
-      'activity_date_time' => date('YmdHis'),
-      'subject' => $subject,
-      'details' => $details,
-      // FIXME: check for name Completed and get ID from that lookup
-      'status_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'status_id', 'Completed'),
-      'campaign_id' => $campaignId,
-    ];
-
-    // CRM-5916: strip [case #…] before saving the activity (if present in subject)
-    $activityParams['subject'] = preg_replace('/\[case #([0-9a-h]{7})\] /', '', $activityParams['subject']);
-
-    // add the attachments to activity params here
-    if ($attachments) {
-      // first process them
-      $activityParams = array_merge($activityParams,
-        $attachments
-      );
-    }
-
-    $activity = self::create($activityParams);
-
-    // get the set of attachments from where they are stored
-    $attachments = CRM_Core_BAO_File::getEntityFile('civicrm_activity',
-      $activity->id
-    );
     $returnProperties = [];
     if (isset($messageToken['contact'])) {
       foreach ($messageToken['contact'] as $key => $value) {
@@ -1207,8 +1222,9 @@ class CRM_Activity_BAO_Activity extends CRM_Activity_DAO_Activity {
         $tokenText,
         $tokenHtml,
         $emailAddress,
-        $activity->id,
-        $attachments,
+        $activityID,
+        // get the set of attachments from where they are stored
+        CRM_Core_BAO_File::getEntityFile('civicrm_activity', $activityID),
         $cc,
         $bcc
       )
@@ -1217,7 +1233,7 @@ class CRM_Activity_BAO_Activity extends CRM_Activity_DAO_Activity {
       }
     }
 
-    return [$sent, $activity->id];
+    return [$sent, $activityID];
   }
 
   /**
index 6c78fb59c5b1d879c5f267da09a7487c6d6b6905..5688dd5093fd1d97c7fd6e35cdbb002da11e9e26 100644 (file)
@@ -185,7 +185,7 @@ class CRM_Activity_Page_AJAX {
       else {
         foreach ($value as $clientRole) {
           $relClient = [];
-          $relClient['relation'] = 'Client';
+          $relClient['relation'] = ts('Client');
           $relClient['name'] = $clientRole['sort_name'];
           $relClient['phone'] = $clientRole['phone'];
           $relClient['email'] = $clientRole['email'];
index cebf70c8ca4d739a60e2168019cdbaf6d5d0a77d..45dc52dccedea26c90685175b930922f458d37da 100644 (file)
@@ -105,8 +105,8 @@ class CRM_Admin_Form_Setting_Smtp extends CRM_Admin_Form_Setting {
         list($domainEmailName, $domainEmailAddress) = CRM_Core_BAO_Domain::getNameAndEmail();
 
         if (!$domainEmailAddress || $domainEmailAddress == 'info@EXAMPLE.ORG') {
-          $fixUrl = CRM_Utils_System::url("civicrm/admin/domain", 'action=update&reset=1');
-          CRM_Core_Error::statusBounce(ts('The site administrator needs to enter a valid email address in <a href="%1">Administer CiviCRM &raquo; Communications &raquo; Organization Address and Contact Info</a>. The email address used may need to be a valid mail account with your email service provider.', [1 => $fixUrl]));
+          $fixUrl = CRM_Utils_System::url("civicrm/admin/options/from_email_address", 'action=update&reset=1');
+          CRM_Core_Error::statusBounce(ts('The site administrator needs to enter a valid \'FROM Email Address\' in <a href="%1">Administer CiviCRM &raquo; System Settings &raquo; Option Groups &raquo; From Email Address</a>. The email address used may need to be a valid mail account with your email service provider.', [1 => $fixUrl]));
         }
         if (!$toEmail) {
           CRM_Core_Error::statusBounce(ts('Cannot send a test email because your user record does not have a valid email address.'));
index 771c0cc412138cf9f5d28344e4e5d0a684893066..93bb4b6c3e9f7399412fa265c2a9113fb0c47e30 100644 (file)
@@ -334,9 +334,14 @@ class CRM_Batch_BAO_Batch extends CRM_Batch_DAO_Batch {
         $aid = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Export Accounting Batch');
         $activityParams = ['source_record_id' => $values['id'], 'activity_type_id' => $aid];
         $exportActivity = CRM_Activity_BAO_Activity::retrieve($activityParams, $val);
-        $fid = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_EntityFile', $exportActivity->id, 'file_id', 'entity_id');
-        $fileHash = CRM_Core_BAO_File::generateFileHash($exportActivity->id, $fid);
-        $tokens = array_merge(['eid' => $exportActivity->id, 'fid' => $fid, 'fcs' => $fileHash], $tokens);
+        if ($exportActivity) {
+          $fid = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_EntityFile', $exportActivity->id, 'file_id', 'entity_id');
+          $fileHash = CRM_Core_BAO_File::generateFileHash($exportActivity->id, $fid);
+          $tokens = array_merge(['eid' => $exportActivity->id, 'fid' => $fid, 'fcs' => $fileHash], $tokens);
+        }
+        else {
+          CRM_Utils_Array::remove($newLinks, 'export', 'download');
+        }
       }
       $values['action'] = CRM_Core_Action::formLink(
         $newLinks,
index 038f32094446fa57932af70f5732988569719df6..5d98871c54b81d288a7769f3dfc4636fd524bcf4 100644 (file)
@@ -395,7 +395,7 @@ class CRM_Batch_Form_Entry extends CRM_Core_Form {
 
       $completeStatus = CRM_Contribute_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
       $specialFields = [
-        'join_date' => date('Y-m-d'),
+        'membership_join_date' => date('Y-m-d'),
         'receive_date' => $currentDate,
         'contribution_status_id' => $completeStatus,
       ];
@@ -825,7 +825,7 @@ class CRM_Batch_Form_Entry extends CRM_Core_Form {
         }
         else {
           $dateTypes = [
-            'join_date' => 'joinDate',
+            'membership_join_date' => 'joinDate',
             'membership_start_date' => 'startDate',
             'membership_end_date' => 'endDate',
           ];
index 321118bf96e74613625e82dd299eff8ff4338cfe..3db0adee600152aefe70f4492b3de3d6f7d55cdd 100644 (file)
@@ -481,7 +481,14 @@ class CRM_Case_BAO_Query extends CRM_Core_BAO_Query {
         $tags = CRM_Core_PseudoConstant::get('CRM_Core_DAO_EntityTag', 'tag_id', ['onlyActive' => FALSE]);
 
         if (!empty($value)) {
-          $val = explode(',', $value);
+          if (is_array($value)) {
+            // Search tag(s) are part of a tag set
+            $val = array_keys($value);
+          }
+          else {
+            // Search tag(s) are part of the tag tree
+            $val = explode(',', $value);
+          }
           foreach ($val as $v) {
             if ($v) {
               $names[] = $tags[$v];
index 6316f3a223c58c710faee75ef7e44781113b2481..aa4a6ce43fd484a60aa93a320d0fa2264bfeb99f 100644 (file)
@@ -165,7 +165,6 @@ class CRM_Case_Form_Activity_ChangeCaseStatus {
    * @param CRM_Activity_BAO_Activity $activity
    */
   public static function endPostProcess(&$form, &$params, $activity) {
-
     $groupingValues = CRM_Core_OptionGroup::values('case_status', FALSE, TRUE, FALSE, NULL, 'value');
 
     // Set case end_date if we're closing the case. Clear end_date if we're (re)opening it.
@@ -175,14 +174,14 @@ class CRM_Case_Form_Activity_ChangeCaseStatus {
       // End case-specific relationships (roles)
       foreach ($params['target_contact_id'] as $cid) {
         $rels = CRM_Case_BAO_Case::getCaseRoles($cid, $params['case_id']);
-        // FIXME: Is there an existing function to close a relationship?
-        $query = 'UPDATE civicrm_relationship SET end_date=%2 WHERE id=%1';
         foreach ($rels as $relId => $relData) {
-          $relParams = [
-            1 => [$relId, 'Integer'],
-            2 => [$params['end_date'], 'Timestamp'],
+          $relationshipParams = [
+            'id' => $relId,
+            'end_date' => $params['end_date'],
           ];
-          CRM_Core_DAO::executeQuery($query, $relParams);
+          // @todo we can't switch directly to api because there is too much business logic and it breaks closing cases with organisations as client relationships
+          //civicrm_api3('Relationship', 'create', $relationshipParams);
+          CRM_Contact_BAO_Relationship::add($relationshipParams);
         }
       }
     }
@@ -192,11 +191,14 @@ class CRM_Case_Form_Activity_ChangeCaseStatus {
       // Reopen case-specific relationships (roles)
       foreach ($params['target_contact_id'] as $cid) {
         $rels = CRM_Case_BAO_Case::getCaseRoles($cid, $params['case_id'], NULL, FALSE);
-        // FIXME: Is there an existing function?
-        $query = 'UPDATE civicrm_relationship SET end_date=NULL WHERE id=%1';
         foreach ($rels as $relId => $relData) {
-          $relParams = [1 => [$relId, 'Integer']];
-          CRM_Core_DAO::executeQuery($query, $relParams);
+          $relationshipParams = [
+            'id' => $relId,
+            'end_date' => 'null',
+          ];
+          // @todo we can't switch directly to api because there is too much business logic and it breaks closing cases with organisations as client relationships
+          //civicrm_api3('Relationship', 'create', $relationshipParams);
+          CRM_Contact_BAO_Relationship::add($relationshipParams);
         }
       }
     }
index 4cfb5c8d7e1abcf6142a5e97ab2acc580d1663c3..1b96b2e152485abeec18c83236471e043dea6240 100644 (file)
@@ -105,7 +105,7 @@ class CRM_Case_XMLProcessor_Process extends CRM_Case_XMLProcessor {
       foreach ($xml->CaseRoles as $caseRoleXML) {
         foreach ($caseRoleXML->RelationshipType as $relationshipTypeXML) {
           if ((int ) $relationshipTypeXML->creator == 1) {
-            if (!$this->createRelationships((string ) $relationshipTypeXML->name,
+            if (!$this->createRelationships($this->locateNameOrLabel($relationshipTypeXML),
               $params
             )
             ) {
@@ -846,4 +846,34 @@ AND        a.is_deleted = 0
     return $default;
   }
 
+  /**
+   * At some point name and label got mixed up for case roles.
+   * Check for higher priority tag <machineName> first which represents name, then fall back to the <name> tag which somehow became label.
+   * We do this to avoid requiring people to update their xml files which can be stored in external files.
+   *
+   * Note this is different than doing something like comparing the <name> tag against name in the database and then falling back to comparing label in the database, which is subject to an edge case where you would get the wrong one (where the label of one relationship type is the same as the name of another). Here there are two tags with explicit single meanings.
+   *
+   * @param SimpleXMLElement $xml
+   *
+   * @return string
+   */
+  public function locateNameOrLabel($xml) {
+    /* While it's unlikely, it's possible somebody is using '0' as their machineName, so we should let them.
+     * Specifically if machineName is:
+     * missing - use name
+     * null - use name
+     * blank - use name
+     * the string '0' - use machineName
+     * the number 0 - use machineName (but can't really have number 0 in simplexml unless cast to number)
+     * the word 'null' - use machineName and best not to think about it
+     */
+    if (isset($xml->machineName)) {
+      $machineName = (string) $xml->machineName;
+      if ($machineName !== '') {
+        return $machineName;
+      }
+    }
+    return (string) $xml->name;
+  }
+
 }
index 41659ba38acc3ca3c917c4edf1820e0f501b8ac3..28f380249093a9fd91665141bfd39241fbda55bb 100644 (file)
@@ -442,9 +442,6 @@ WHERE id={$contactId}; ";
    *
    */
   public static function buildOnBehalfForm(&$form, $contactType, $countryID, $stateID, $title) {
-
-    $config = CRM_Core_Config::singleton();
-
     $form->assign('contact_type', $contactType);
     $form->assign('fieldSetTitle', $title);
     $form->assign('contactEditMode', TRUE);
@@ -482,7 +479,7 @@ WHERE id={$contactId}; ";
         );
     }
 
-    $addressSequence = $config->addressSequence();
+    $addressSequence = CRM_Utils_Address::sequence(\Civi::settings()->get('address_format'));
     $form->assign('addressSequence', array_fill_keys($addressSequence, 1));
 
     //Primary Phone
index 7a6b045758774cedddb9442314c96b9bf647d5a4..d62f6279d24cf5909516e9068f1d99e8121edaa6 100644 (file)
@@ -1584,7 +1584,17 @@ class CRM_Contact_BAO_Query {
 
     self::filterCountryFromValuesIfStateExists($formValues);
     // We shouldn't have to whitelist fields to not hack but here we are, for now.
-    $nonLegacyDateFields = ['participant_register_date_relative', 'receive_date_relative'];
+    $nonLegacyDateFields = [
+      'participant_register_date_relative',
+      'receive_date_relative',
+      'pledge_end_date_relative',
+      'pledge_create_date_relative',
+      'pledge_start_date_relative',
+      'pledge_payment_scheduled_date_relative',
+      'membership_join_date_relative',
+      'membership_start_date_relative',
+      'membership_end_date_relative',
+    ];
     // Handle relative dates first
     foreach (array_keys($formValues) as $id) {
       if (
@@ -1815,6 +1825,7 @@ class CRM_Contact_BAO_Query {
       $this->buildRelativeDateQuery($values);
       return;
     }
+    // @todo also handle _low, _high generically here with if ($query->buildDateRangeQuery($values)) {return}
 
     // do not process custom fields or prefixed contact ids or component params
     if (CRM_Core_BAO_CustomField::getKeyID($values[0]) ||
@@ -5257,7 +5268,7 @@ civicrm_relationship.start_date > {$today}
    * @param string $dateFormat
    */
   public function dateQueryBuilder(
-    &$values, $tableName, $fieldName,
+    $values, $tableName, $fieldName,
     $dbFieldName, $fieldTitle,
     $appendTimeStamp = TRUE,
     $dateFormat = 'YmdHis'
@@ -6943,6 +6954,47 @@ AND   displayRelType.is_active = 1
     return isset($this->_fields[$realField]);
   }
 
+  /**
+   * Get the specifications for the field, if available.
+   *
+   * @param string $fieldName
+   *   Fieldname as displayed on the form.
+   *
+   * @return array
+   */
+  public function getFieldSpec($fieldName) {
+    if (isset($this->_fields[$fieldName])) {
+      return $this->_fields[$fieldName];
+    }
+    $lowFieldName = str_replace('_low', '', $fieldName);
+    if (isset($this->_fields[$lowFieldName])) {
+      return array_merge($this->_fields[$lowFieldName], ['field_name' => $lowFieldName]);
+    }
+    $highFieldName = str_replace('_high', '', $fieldName);
+    if (isset($this->_fields[$highFieldName])) {
+      return array_merge($this->_fields[$highFieldName], ['field_name' => $highFieldName]);
+    }
+    return [];
+  }
+
+  public function buildWhereForDate() {
+
+  }
+
+  /**
+   * Is the field a relative date field.
+   *
+   * @param string $fieldName
+   *
+   * @return bool
+   */
+  protected function isADateRangeField($fieldName) {
+    if (substr($fieldName, -4, 4) !== '_low' && substr($fieldName, -5, 5) !== '_high') {
+      return FALSE;
+    }
+    return !empty($this->getFieldSpec($fieldName));
+  }
+
   /**
    * @param $values
    */
@@ -6988,6 +7040,23 @@ AND   displayRelType.is_active = 1
     }
   }
 
+  /**
+   * Build the query for a date field if it is a _high or _low field.
+   *
+   * @param $values
+   *
+   * @return bool
+   */
+  public function buildDateRangeQuery($values) {
+    if ($this->isADateRangeField($values[0])) {
+      $fieldSpec = $this->getFieldSpec($values[0]);
+      $title = empty($fieldSpec['unique_title']) ? $fieldSpec['title'] : $fieldSpec['unique_title'];
+      $this->dateQueryBuilder($values, $fieldSpec['table_name'], $fieldSpec['field_name'], $fieldSpec['name'], $title);
+      return TRUE;
+    }
+    return FALSE;
+  }
+
   /**
    * Add the address table into the query.
    *
index f9a49f68ca13f6e03d4721369b87dec99362edfe..b210da587acac3c2dc8eb687a85c1a3b45bb5637 100644 (file)
@@ -181,6 +181,7 @@ class CRM_Contact_BAO_Relationship extends CRM_Contact_DAO_Relationship {
       $hook = 'edit';
     }
 
+    // @todo pre hook is called from add - remove it from here
     CRM_Utils_Hook::pre($hook, 'Relationship', $relationshipId, $params);
 
     if (!$relationshipId) {
@@ -295,33 +296,55 @@ class CRM_Contact_BAO_Relationship extends CRM_Contact_DAO_Relationship {
     if ($params['id']) {
       $hook = 'edit';
     }
-    //@todo hook are called from create and add - remove one
     CRM_Utils_Hook::pre($hook, 'Relationship', $params['id'], $params);
 
     $relationshipTypes = CRM_Utils_Array::value('relationship_type_id', $params);
-
     // explode the string with _ to get the relationship type id
     // and to know which contact has to be inserted in
     // contact_id_a and which one in contact_id_b
-    list($type) = explode('_', $relationshipTypes);
+    list($relationshipTypeID) = explode('_', $relationshipTypes);
+
+    $relationship = new CRM_Contact_BAO_Relationship();
+    if (!empty($params['id'])) {
+      $relationship->id = $params['id'];
+      // Only load the relationship if we're missing required params
+      $requiredParams = ['contact_id_a', 'contact_id_b', 'relationship_type_id'];
+      foreach ($requiredParams as $requiredKey) {
+        if (!isset($params[$requiredKey])) {
+          $relationship->find(TRUE);
+          break;
+        }
+      }
+
+    }
+    $relationship->copyValues($params);
+    // @todo we could probably set $params['relationship_type_id'] above but it's unclear
+    //   what that would do with the code below this. So for now be conservative and set it manually.
+    if (!empty($relationshipTypeID)) {
+      $relationship->relationship_type_id = $relationshipTypeID;
+    }
+
+    $params['contact_id_a'] = $relationship->contact_id_a;
+    $params['contact_id_b'] = $relationship->contact_id_b;
 
     // check if the relationship type is Head of Household then update the
     // household's primary contact with this contact.
-    if ($type == 6) {
-      CRM_Contact_BAO_Household::updatePrimaryContact($params['contact_id_b'], $params['contact_id_a']);
+    try {
+      $headOfHouseHoldID = civicrm_api3('RelationshipType', 'getvalue', [
+        'return' => "id",
+        'name_a_b' => "Head of Household for",
+      ]);
+      if ($relationshipTypeID == $headOfHouseHoldID) {
+        CRM_Contact_BAO_Household::updatePrimaryContact($relationship->contact_id_b, $relationship->contact_id_a);
+      }
     }
-    if (!empty($params['id']) && self::isCurrentEmployerNeedingToBeCleared($params, $params['id'], $type)) {
-      CRM_Contact_BAO_Contact_Utils::clearCurrentEmployer($params['contact_id_a']);
+    catch (Exception $e) {
+      // No "Head of Household" relationship found so we skip specific processing
     }
 
-    $relationship = new CRM_Contact_BAO_Relationship();
-    //@todo this code needs to be updated for the possibility that not all fields are set
-    // by using $relationship->copyValues($params);
-    // (update)
-    $relationship->contact_id_b = $params['contact_id_b'];
-    $relationship->contact_id_a = $params['contact_id_a'];
-    $relationship->relationship_type_id = $type;
-    $relationship->id = $params['id'];
+    if (!empty($params['id']) && self::isCurrentEmployerNeedingToBeCleared($relationship->toArray(), $params['id'], $relationshipTypeID)) {
+      CRM_Contact_BAO_Contact_Utils::clearCurrentEmployer($relationship->contact_id_a);
+    }
 
     $dateFields = ['end_date', 'start_date'];
 
@@ -1512,6 +1535,7 @@ LEFT JOIN  civicrm_country ON (civicrm_address.country_id = civicrm_country.id)
    * @param bool $active
    *
    * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
    */
   public static function relatedMemberships($contactId, &$params, $ids, $action = CRM_Core_Action::ADD, $active = TRUE) {
     // Check the end date and set the status of the relationship
@@ -1668,6 +1692,12 @@ LEFT JOIN  civicrm_country ON (civicrm_address.country_id = civicrm_country.id)
       $mainRelatedContactId = reset($relatedContacts);
 
       foreach ($details['memberships'] as $membershipId => $membershipValues) {
+        $membershipInherittedFromContactID = NULL;
+        if (!empty($membershipValues['owner_membership_id'])) {
+          // Use get not getsingle so that we get e-notice noise but not a fatal is the membership has already been deleted.
+          $inheritedFromMembership = civicrm_api3('Membership', 'get', ['id' => $membershipValues['owner_membership_id'], 'sequential' => 1])['values'][0];
+          $membershipInherittedFromContactID = (int) $inheritedFromMembership['contact_id'];
+        }
         $relTypeIds = [];
         if ($action & CRM_Core_Action::DELETE) {
           // @todo don't return relTypeId here - but it seems to be used later in a cryptic way (hint cryptic is not a complement).
@@ -1746,17 +1776,10 @@ LEFT JOIN  civicrm_country ON (civicrm_address.country_id = civicrm_country.id)
             if (!empty($membershipValues['status_id']) && $membershipValues['status_id'] == $pendingStatusId) {
               $membershipValues['skipStatusCal'] = TRUE;
             }
-
-            // check whether we have some related memberships still available
-            $query = "
-SELECT count(*)
-  FROM civicrm_membership
-    LEFT JOIN civicrm_membership_status ON (civicrm_membership_status.id = civicrm_membership.status_id)
- WHERE membership_type_id = {$membershipValues['membership_type_id']} AND owner_membership_id = {$membershipValues['owner_membership_id']}
-    AND is_current_member = 1";
-            $result = CRM_Core_DAO::singleValueQuery($query);
-            if ($result < CRM_Utils_Array::value('max_related', $membershipValues, PHP_INT_MAX)) {
-              CRM_Member_BAO_Membership::create($membershipValues);
+            // As long as the membership itself was not created by inheritance from the same contact
+            // that stands to inherit the membership we add an inherited membership.
+            if ($membershipInherittedFromContactID !== (int) $membershipValues['contact_id']) {
+              $membershipValues = self::addInheritedMembership($membershipValues);
             }
           }
         }
@@ -2335,4 +2358,27 @@ AND cc.sort_name LIKE '%$name%'";
     return [implode(',', $relTypeIds), $isDeletable];
   }
 
+  /**
+   * Add an inherited membership, provided max related not exceeded.
+   *
+   * @param array $membershipValues
+   *
+   * @return array
+   * @throws \CRM_Core_Exception
+   */
+  protected static function addInheritedMembership($membershipValues) {
+    $query = "
+SELECT count(*)
+  FROM civicrm_membership
+    LEFT JOIN civicrm_membership_status ON (civicrm_membership_status.id = civicrm_membership.status_id)
+ WHERE membership_type_id = {$membershipValues['membership_type_id']}
+           AND owner_membership_id = {$membershipValues['owner_membership_id']}
+    AND is_current_member = 1";
+    $result = CRM_Core_DAO::singleValueQuery($query);
+    if ($result < CRM_Utils_Array::value('max_related', $membershipValues, PHP_INT_MAX)) {
+      CRM_Member_BAO_Membership::create($membershipValues);
+    }
+    return $membershipValues;
+  }
+
 }
index b3561a72fed2ab933d3e6386e5958bab7adcd1c9..749a716a4938d7b3cfc6ba298d49ffd311afe2b8 100644 (file)
@@ -437,9 +437,22 @@ LEFT JOIN civicrm_email ON (contact_a.id = civicrm_email.contact_id AND civicrm_
     // This is required only until all fields are converted to datepicker fields as the new format is truer to the
     // form format and simply saves (e.g) custom_3_relative => "this.year"
     $relativeDates = ['relative_dates' => []];
-    $specialDateFields = ['event_relative', 'case_from_relative', 'case_to_relative', 'participant_relative'];
+    $specialDateFields = [
+      'event_relative',
+      'case_from_relative',
+      'case_to_relative',
+      'participant_relative',
+      'log_date_relative',
+      'birth_date_relative',
+      'deceased_date_relative',
+      'mailing_date_relative',
+      'relation_date_relative',
+      'relation_start_date_relative',
+      'relation_end_date_relative',
+      'relation_action_date_relative',
+    ];
     foreach ($formValues as $id => $value) {
-      if ((preg_match('/_date$/', $id) || in_array($id, $specialDateFields)) && !empty($value)) {
+      if (in_array($id, $specialDateFields) && !empty($value)) {
         $entityName = strstr($id, '_date', TRUE);
         if (empty($entityName)) {
           $entityName = strstr($id, '_relative', TRUE);
index 5bc2b38a3b2a2ec5b9aeee63d4d97e0019bbe476..a7da4e718e994db88e2fbf0bb70d0a7c9f1393c6 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Contact/Contact.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:bd37bd31a0ac8ba4fd5f411fddef080b)
+ * (GenCodeChecksum:ee3bf9f2d1faed5a4de439ecf0537ac6)
  */
 
 /**
@@ -963,7 +963,9 @@ class CRM_Contact_DAO_Contact extends CRM_Core_DAO {
           'type' => CRM_Utils_Type::T_INT,
           'title' => ts('Communication Style'),
           'description' => ts('Communication style (e.g. formal vs. familiar) to use with this contact. FK to communication styles in civicrm_option_value.'),
+          'import' => TRUE,
           'where' => 'civicrm_contact.communication_style_id',
+          'headerPattern' => '/style/i',
           'export' => TRUE,
           'table_name' => 'civicrm_contact',
           'entity' => 'Contact',
@@ -1589,6 +1591,22 @@ class CRM_Contact_DAO_Contact extends CRM_Core_DAO {
         'localizable' => FALSE,
         'sig' => 'civicrm_contact::0::is_deleted::sort_name::id',
       ],
+      'index_created_date' => [
+        'name' => 'index_created_date',
+        'field' => [
+          0 => 'created_date',
+        ],
+        'localizable' => FALSE,
+        'sig' => 'civicrm_contact::0::created_date',
+      ],
+      'index_modified_date' => [
+        'name' => 'index_modified_date',
+        'field' => [
+          0 => 'modified_date',
+        ],
+        'localizable' => FALSE,
+        'sig' => 'civicrm_contact::0::modified_date',
+      ],
     ];
     return ($localize && !empty($indices)) ? CRM_Core_DAO_AllCoreTables::multilingualize(__CLASS__, $indices) : $indices;
   }
index f275cfa377f43641cc2fd4b88682ca8de9fa1ad5..11bef4a62927e7901ab37ba52ab0abe3a6f3ef30 100644 (file)
@@ -227,7 +227,7 @@ class CRM_Contact_Form_Contact extends CRM_Core_Form {
 
         $displayName = CRM_Contact_BAO_Contact::displayName($this->_contactId);
         if ($defaults['is_deceased']) {
-          $displayName .= '  <span class="crm-contact-deceased">(deceased)</span>';
+          $displayName .= '  <span class="crm-contact-deceased">(' . ts('deceased') . ')</span>';
         }
         $displayName = ts('Edit %1', [1 => $displayName]);
 
index 91f282f6bb4ea9fc1cdb35c340119b0a1daa65da..da804021ea2ce1ab7eafde17ca6349518af0f62f 100644 (file)
@@ -114,7 +114,7 @@ class CRM_Contact_Form_Merge extends CRM_Core_Form {
         CRM_Core_Session::singleton()->pushUserContext($browseUrl);
       }
 
-      $cacheKey = CRM_Dedupe_Merger::getMergeCacheKeyString($this->_rgid, $gid, json_decode($this->criteria, TRUE));
+      $cacheKey = CRM_Dedupe_Merger::getMergeCacheKeyString($this->_rgid, $gid, json_decode($this->criteria, TRUE), TRUE, $this->limit);
 
       $join = CRM_Dedupe_Merger::getJoinOnDedupeTable();
       $where = "de.id IS NULL";
@@ -331,7 +331,7 @@ class CRM_Contact_Form_Merge extends CRM_Core_Form {
     }
 
     if ($this->next && $this->_mergeId) {
-      $cacheKey = CRM_Dedupe_Merger::getMergeCacheKeyString($this->_rgid, $this->_gid, json_decode($this->criteria, TRUE));
+      $cacheKey = CRM_Dedupe_Merger::getMergeCacheKeyString($this->_rgid, $this->_gid, json_decode($this->criteria, TRUE), TRUE, $this->limit);
 
       $join = CRM_Dedupe_Merger::getJoinOnDedupeTable();
       $where = "de.id IS NULL";
index 8c0ef827acb92e406f6bdb47ecae46cb2a01db8f..69f111bbc267181d89cece750396a27762ec1e4d 100644 (file)
@@ -209,13 +209,10 @@ class CRM_Contact_Import_Form_MapField extends CRM_Import_Form_MapField {
     else {
       $savedMapping = $this->get('savedMapping');
 
-      list($mappingName, $mappingContactType, $mappingLocation, $mappingPhoneType, $mappingImProvider, $mappingRelation, $mappingOperator, $mappingValue, $mappingWebsiteType) = CRM_Core_BAO_Mapping::getMappingFields($savedMapping, TRUE);
+      list($mappingName) = CRM_Core_BAO_Mapping::getMappingFields($savedMapping, TRUE);
 
       //get loaded Mapping Fields
       $mappingName = CRM_Utils_Array::value(1, $mappingName);
-      $mappingLocation = CRM_Utils_Array::value(1, $mappingLocation);
-      $mappingRelation = CRM_Utils_Array::value(1, $mappingRelation);
-      $mappingWebsiteType = CRM_Utils_Array::value(1, $mappingWebsiteType);
 
       $this->assign('loadedMapping', $savedMapping);
       $this->set('loadedMapping', $savedMapping);
@@ -402,12 +399,14 @@ class CRM_Contact_Import_Form_MapField extends CRM_Import_Form_MapField {
     $processor->setMappingID($savedMappingID);
     $processor->setFormName($formName);
     $processor->setMetadata($this->getContactImportMetadata());
+    $processor->setContactTypeByConstant($this->get('contactType'));
+    $processor->setContactSubType($this->get('contactSubType'));
 
     for ($i = 0; $i < $this->_columnCount; $i++) {
       $sel = &$this->addElement('hierselect', "mapper[$i]", ts('Mapper for Field %1', [1 => $i]), NULL);
 
       if ($this->get('savedMapping')) {
-        list($defaults, $js) = $this->loadSavedMapping($processor, $mappingName, $i, $mappingRelation, $mappingWebsiteType, $mappingLocation, $defaults, $js, $hasColumnNames, $dataPatterns, $columnPatterns);
+        list($defaults, $js) = $this->loadSavedMapping($processor, $mappingName, $i, $defaults, $js, $hasColumnNames, $dataPatterns, $columnPatterns);
       }
       else {
         $js .= "swapOptions($formName, 'mapper[$i]', 0, 3, 'hs_mapper_0_');\n";
@@ -700,7 +699,7 @@ class CRM_Contact_Import_Form_MapField extends CRM_Import_Form_MapField {
             elseif (CRM_Utils_Array::value('1', $mapperKeys[$i]) == 'im') {
               $updateMappingFields->im_provider_id = isset($mapperKeys[$i][3]) ? $mapperKeys[$i][3] : NULL;
             }
-            $updateMappingFields->location_type_id = isset($mapperKeys[$i][2]) ? $mapperKeys[$i][2] : NULL;
+            $updateMappingFields->location_type_id = isset($mapperKeys[$i][2]) && is_numeric($mapperKeys[$i][2]) ? $mapperKeys[$i][2] : NULL;
           }
         }
         else {
@@ -849,9 +848,6 @@ class CRM_Contact_Import_Form_MapField extends CRM_Import_Form_MapField {
    * @param \CRM_Import_ImportProcessor $processor
    * @param $mappingName
    * @param int $i
-   * @param $mappingRelation
-   * @param $mappingWebsiteType
-   * @param $mappingLocation
    * @param array $defaults
    * @param string $js
    * @param bool $hasColumnNames
@@ -861,122 +857,15 @@ class CRM_Contact_Import_Form_MapField extends CRM_Import_Form_MapField {
    * @return array
    * @throws \CiviCRM_API3_Exception
    */
-  public function loadSavedMapping($processor, $mappingName, $i, $mappingRelation, $mappingWebsiteType, $mappingLocation, $defaults, $js, $hasColumnNames, $dataPatterns, $columnPatterns) {
-    $jsSet = FALSE;
+  public function loadSavedMapping($processor, $mappingName, $i, $defaults, $js, $hasColumnNames, $dataPatterns, $columnPatterns) {
     $formName = $processor->getFormName();
     if (isset($mappingName[$i])) {
       if ($mappingName[$i] != ts('- do not import -')) {
-
-        if (isset($mappingRelation[$i])) {
-          // relationship mapping
-          switch ($this->get('contactType')) {
-            case CRM_Import_Parser::CONTACT_INDIVIDUAL:
-              $contactType = 'Individual';
-              break;
-
-            case CRM_Import_Parser::CONTACT_HOUSEHOLD:
-              $contactType = 'Household';
-              break;
-
-            case CRM_Import_Parser::CONTACT_ORGANIZATION:
-              $contactType = 'Organization';
-          }
-          //CRM-5125
-          $contactSubType = NULL;
-          if ($this->get('contactSubType')) {
-            $contactSubType = $this->get('contactSubType');
-          }
-
-          $relations = CRM_Contact_BAO_Relationship::getContactRelationshipType(NULL, NULL, NULL, $contactType,
-            FALSE, 'label', TRUE, $contactSubType
-          );
-
-          foreach ($relations as $key => $var) {
-            if ($key == $mappingRelation[$i]) {
-              $relation = $key;
-              break;
-            }
-          }
-
-          $contactDetails = strtolower(str_replace(" ", "_", $mappingName[$i]));
-          $websiteTypeId = isset($mappingWebsiteType[$i]) ? $mappingWebsiteType[$i] : NULL;
-          $locationId = isset($mappingLocation[$i]) ? $mappingLocation[$i] : 0;
-          $phoneType = $processor->getPhoneTypeID($i);
-          $imProvider = $processor->getIMProviderID($i);
-
-          if ($websiteTypeId) {
-            $defaults["mapper[$i]"] = [$relation, $contactDetails, $websiteTypeId];
-            if (!$websiteTypeId) {
-              $js .= "{$formName}['mapper[$i][2]'].style.display = 'none';\n";
-            }
-          }
-          else {
-            // default for IM/phone when mapping with relation is true
-            $typeId = NULL;
-            if (isset($phoneType)) {
-              $typeId = $phoneType;
-            }
-            elseif (isset($imProvider)) {
-              $typeId = $imProvider;
-            }
-            $defaults["mapper[$i]"] = [$relation, $contactDetails, $locationId, $typeId];
-            if (!$locationId) {
-              $js .= "{$formName}['mapper[$i][2]'].style.display = 'none';\n";
-            }
-          }
-          // fix for edge cases, CRM-4954
-          if ($contactDetails == 'image_url') {
-            $contactDetails = str_replace('url', 'URL', $contactDetails);
-          }
-
-          if (!$contactDetails) {
-            $js .= "{$formName}['mapper[$i][1]'].style.display = 'none';\n";
-          }
-
-          if ((!$phoneType) && (!$imProvider)) {
-            $js .= "{$formName}['mapper[$i][3]'].style.display = 'none';\n";
-          }
-          //$js .= "{$formName}['mapper[$i][3]'].style.display = 'none';\n";
-          $jsSet = TRUE;
-        }
-        else {
-          $mappingHeader = array_keys((array) $this->_mapperFields, $mappingName[$i]);
-          $websiteTypeId = isset($mappingWebsiteType[$i]) ? $mappingWebsiteType[$i] : NULL;
-          $locationId = isset($mappingLocation[$i]) ? $mappingLocation[$i] : 0;
-          $phoneType = $processor->getPhoneTypeID($i);
-          $imProvider = $processor->getIMProviderID($i);
-
-          if ($websiteTypeId) {
-            $defaults["mapper[$i]"] = [$mappingHeader[0], $websiteTypeId];
-          }
-          else {
-            if (!$locationId) {
-              $js .= "{$formName}['mapper[$i][1]'].style.display = 'none';\n";
-            }
-            //default for IM/phone without related contact
-            $typeId = NULL;
-            if (isset($phoneType)) {
-              $typeId = $phoneType;
-            }
-            elseif (isset($imProvider)) {
-              $typeId = $imProvider;
-            }
-            $defaults["mapper[$i]"] = [$mappingHeader[0] ?? '', $locationId, $typeId];
-          }
-
-          if ((!$phoneType) && (!$imProvider)) {
-            $js .= "{$formName}['mapper[$i][2]'].style.display = 'none';\n";
-          }
-
-          $js .= "{$formName}['mapper[$i][3]'].style.display = 'none';\n";
-
-          $jsSet = TRUE;
-        }
+        $defaults["mapper[$i]"] = $processor->getSavedQuickformDefaultsForColumn($i);
+        $js .= $processor->getQuickFormJSForField($i);
       }
       else {
         $defaults["mapper[$i]"] = [];
-      }
-      if (!$jsSet) {
         for ($k = 1; $k < 4; $k++) {
           $js .= "{$formName}['mapper[$i][$k]'].style.display = 'none';\n";
         }
index c0fac2ee073fdaf05268afc9d0db450b2ee3cec2..7b7e027308d62f4bf3d3125daef3ddf63ebed564 100644 (file)
@@ -1207,6 +1207,7 @@ abstract class CRM_Contact_Import_Parser extends CRM_Import_Parser {
       if (!array_key_exists($blockFieldName, $values)) {
         continue;
       }
+      $blockIndex = $values['location_type_id'] . (!empty($values['phone_type_id']) ? '_' . $values['phone_type_id'] : '');
 
       // block present in value array.
       if (!array_key_exists($blockFieldName, $params) || !is_array($params[$blockFieldName])) {
@@ -1221,13 +1222,13 @@ abstract class CRM_Contact_Import_Parser extends CRM_Import_Parser {
       }
 
       _civicrm_api3_store_values($fields[$block], $values,
-        $params[$blockFieldName][$values['location_type_id']]
+        $params[$blockFieldName][$blockIndex]
       );
 
-      $this->fillPrimary($params[$blockFieldName][$values['location_type_id']], $values, $block, CRM_Utils_Array::value('id', $params));
+      $this->fillPrimary($params[$blockFieldName][$blockIndex], $values, $block, CRM_Utils_Array::value('id', $params));
 
       if (empty($params['id']) && (count($params[$blockFieldName]) == 1)) {
-        $params[$blockFieldName][$values['location_type_id']]['is_primary'] = TRUE;
+        $params[$blockFieldName][$blockIndex]['is_primary'] = TRUE;
       }
 
       // we only process single block at a time.
index 7dcedcc8cd5f3439b2dafe1fb7c63d9268de56d7..3ac0326cf743eecfef9239b012f5737c38486c86 100644 (file)
@@ -638,6 +638,7 @@ LIMIT {$offset}, {$rowCount}
 
     $gid = CRM_Utils_Request::retrieve('gid', 'Positive');
     $rgid = CRM_Utils_Request::retrieve('rgid', 'Positive');
+    $limit = CRM_Utils_Request::retrieveValue('limit', 'Positive', 0);
     $null = NULL;
     $criteria = CRM_Utils_Request::retrieve('criteria', 'Json', $null, FALSE, '{}');
     $selected = CRM_Utils_Request::retrieveValue('selected', 'Boolean');
@@ -646,7 +647,7 @@ LIMIT {$offset}, {$rowCount}
     }
 
     $whereClause = $orderByClause = '';
-    $cacheKeyString   = CRM_Dedupe_Merger::getMergeCacheKeyString($rgid, $gid, json_decode($criteria, TRUE));
+    $cacheKeyString   = CRM_Dedupe_Merger::getMergeCacheKeyString($rgid, $gid, json_decode($criteria, TRUE), TRUE, $limit);
 
     $searchRows = [];
 
index 8b22a7140d9286a084c5a455f079210133b1608a..b7a22ea66611a6c03b1a5d94b59289254333f04e 100644 (file)
@@ -105,13 +105,13 @@ class CRM_Contact_Page_DedupeFind extends CRM_Core_Page_Basic {
       'reset' => 1,
       'rgid' => $rgid,
       'gid' => $gid,
-      'limit' => $limit,
+      'limit' => (int) $limit,
       'criteria' => $criteria,
     ];
     $this->assign('urlQuery', CRM_Utils_System::makeQueryString($urlQry));
     $this->assign('isSelected', $this->isSelected());
     $criteria = json_decode($criteria, TRUE);
-    $cacheKeyString = CRM_Dedupe_Merger::getMergeCacheKeyString($rgid, $gid, $criteria);
+    $cacheKeyString = CRM_Dedupe_Merger::getMergeCacheKeyString($rgid, $gid, $criteria, TRUE, $limit);
     $this->assign('cacheKey', $cacheKeyString);
 
     if ($context == 'search') {
@@ -129,7 +129,7 @@ class CRM_Contact_Page_DedupeFind extends CRM_Core_Page_Basic {
     }
     elseif ($action & CRM_Core_Action::MAP) {
       // do a batch merge if requested
-      $result = CRM_Dedupe_Merger::batchMerge($rgid, $gid, 'safe', 75, 2, $criteria);
+      $result = CRM_Dedupe_Merger::batchMerge($rgid, $gid, 'safe', 75, 2, $criteria, TRUE, NULL, $limit);
 
       $skippedCount = CRM_Utils_Request::retrieve('skipped', 'Positive', $this, FALSE, 0);
       $skippedCount = $skippedCount + count($result['skipped']);
index 1dddf5619470e97e645661939532c1595ecb4bbf..348f65b1d8f8a4010ad3c813f5f85aa4de8ff9e8 100644 (file)
@@ -70,7 +70,7 @@ class CRM_Contact_Page_DedupeMerge extends CRM_Core_Page {
     ];
 
     $criteria = json_decode($criteria, TRUE);
-    $cacheKeyString = CRM_Dedupe_Merger::getMergeCacheKeyString($rgid, $gid, $criteria);
+    $cacheKeyString = CRM_Dedupe_Merger::getMergeCacheKeyString($rgid, $gid, $criteria, TRUE, $limit);
 
     if ($mode == 'aggressive' && !CRM_Core_Permission::check('force merge duplicate contacts')) {
       CRM_Core_Session::setStatus(ts('You do not have permission to force merge duplicate contact records'), ts('Permission Denied'), 'error');
@@ -98,7 +98,7 @@ class CRM_Contact_Page_DedupeMerge extends CRM_Core_Page {
     for ($i = 1; $i <= ceil($total / self::BATCHLIMIT); $i++) {
       $task = new CRM_Queue_Task(
         ['CRM_Contact_Page_DedupeMerge', 'callBatchMerge'],
-        [$rgid, $gid, $mode, self::BATCHLIMIT, $onlyProcessSelected, $criteria],
+        [$rgid, $gid, $mode, self::BATCHLIMIT, $onlyProcessSelected, $criteria, $limit],
         "Processed " . $i * self::BATCHLIMIT . " pair of duplicates out of " . $total
       );
 
@@ -132,11 +132,15 @@ class CRM_Contact_Page_DedupeMerge extends CRM_Core_Page {
    * @param int $batchLimit
    * @param int $isSelected
    * @param array $criteria
+   * @param int $searchLimit
    *
    * @return int
+   *
+   * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
    */
-  public static function callBatchMerge(CRM_Queue_TaskContext $ctx, $rgid, $gid, $mode = 'safe', $batchLimit, $isSelected, $criteria) {
-    CRM_Dedupe_Merger::batchMerge($rgid, $gid, $mode, $batchLimit, $isSelected, $criteria, TRUE, FALSE);
+  public static function callBatchMerge(CRM_Queue_TaskContext $ctx, $rgid, $gid, $mode = 'safe', $batchLimit, $isSelected, $criteria, $searchLimit) {
+    CRM_Dedupe_Merger::batchMerge($rgid, $gid, $mode, $batchLimit, $isSelected, $criteria, TRUE, FALSE, $searchLimit);
     return CRM_Queue_Task::TASK_SUCCESS;
   }
 
index 8f7a78f214a50250d1dc0d8ce2731f1c2c25653f..52fb0683bb1d5a351f118b29a94c604352aa81e7 100644 (file)
@@ -323,7 +323,7 @@ class CRM_Contact_Page_View extends CRM_Core_Page {
     // set page title
     $title = "{$contactImage} {$displayName}";
     if ($contactDetails[$contactId]['isDeceased']) {
-      $title .= '  <span class="crm-contact-deceased">(deceased)</span>';
+      $title .= '  <span class="crm-contact-deceased">(' . ts('deceased') . ')</span>';
     }
     if ($isDeleted) {
       $title = "<del>{$title}</del>";
index 9dcc2224c29dfbb08ca57a731c078bd97b6705b4..33a350ef6ae8a7cb681e0d680d8ee762975bb9f1 100644 (file)
@@ -1016,6 +1016,7 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
    * @return array
    */
   protected static function cancel($processContributionObject, $memberships, $contributionId, $membershipStatuses, $updateResult, $participant, $oldStatus, $pledgePayment, $pledgeID, $pledgePaymentIDs, $contributionStatusId) {
+    // @fixme https://lab.civicrm.org/dev/core/issues/927 Cancelling membership etc is not desirable for all use-cases and we should be able to disable it
     $processContribution = FALSE;
     $participantStatuses = CRM_Event_PseudoConstant::participantStatus();
     if (is_array($memberships)) {
@@ -1205,6 +1206,27 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
     return [TRUE, $isARefund];
   }
 
+  /**
+   * It is possible to override the membership id that is updated from the payment processor.
+   *
+   * Historically Paypal does this & it still does if it determines data is messed up - see
+   * https://lab.civicrm.org/dev/membership/issues/13
+   *
+   * Read the comment block on repeattransaction for more information
+   * about how things should  work.
+   *
+   * @param int $contributionID
+   * @param array $input
+   *
+   * @throws \CiviCRM_API3_Exception
+   */
+  protected static function handleMembershipIDOverride($contributionID, $input) {
+    if (!empty($input['membership_id'])) {
+      Civi::log()->debug('The related membership id has been overridden - this may impact data - see  https://github.com/civicrm/civicrm-core/pull/15053');
+      civicrm_api3('MembershipPayment', 'create', ['contribution_id' => $contributionID, 'membership_id' => $input['membership_id']]);
+    }
+  }
+
   /**
    * @inheritDoc
    */
@@ -2400,11 +2422,35 @@ LEFT JOIN  civicrm_contribution contribution ON ( componentPayment.contribution_
   /**
    * Repeat a transaction as part of a recurring series.
    *
-   * Only call this via the api as it is being refactored. The intention is that the repeatTransaction function
-   * (possibly living on the ContributionRecur BAO) would be called first to create a pending contribution with a
-   * subsequent call to the contribution.completetransaction api.
-   *
-   * The completeTransaction functionality has historically been overloaded to both complete and repeat payments.
+   * The ideal flow is
+   * 1) Processor calls contribution.repeattransaction with contribution_status_id = Pending
+   * 2) The repeattransaction loads the 'template contribution' and calls a hook to allow altering of it .
+   * 3) Repeat transaction calls order.create to create the pending contribution with correct line items
+   *   and associated entities.
+   * 4) The  calling code calls Payment.create which in turn calls CompleteOrder (if completing)
+   *   which updates the various entities and sends appropriate emails.
+   *
+   * Gaps in the above (@todo)
+   *  1) many processors still call repeattransaction with contribution_status_id = Completed
+   *  2) repeattransaction code is current munged into completeTransaction code for historical bad coding reasons
+   *  3) Repeat transaction duplicates rather than calls Order.create
+   *  4) Use of payment.create still limited - completetransaction is more common.
+   *  5) the template transaction is tricky - historically we used the first contribution
+   *    linked to a recurring contribution. More recently that was changed to be the most recent.
+   *    Ideally it would be an actual template - not a contribution used as a template which
+   *    would give more appropriate flexibility. Note line_items have an entity so that table
+   *    could be used for the line item template - the difficulty is the custom fields...
+   * 6) the determination of the membership to be linked is tricksy. The prioritised method is
+   *   to load the membership(s) referred to via line items in the template transactions. Any other
+   *   method is likely to lead to incorrect line items & related entities being created (as the line_item
+   *   link is a required part of 'correct data'). However there are 3 other methods to determine it
+   *   - membership_payment record
+   *   - civicrm_membership.contribution_recur_id
+   *   - input override.
+   *   Passing in an input override WILL ensure the membership is extended to prevent regressions
+   *   of historical processors since this has been handled 'forever' - specifically for paypal.
+   *   albeit by an even nastier mechanism than the current input override.
+   *   The count is out on how correct related entities wind up in this case.
    *
    * @param CRM_Contribute_BAO_Contribution $contribution
    * @param array $input
@@ -2468,6 +2514,7 @@ LEFT JOIN  civicrm_contribution contribution ON ( componentPayment.contribution_
       $createContribution = civicrm_api3('Contribution', 'create', $contributionParams);
       $contribution->id = $createContribution['id'];
       CRM_Contribute_BAO_ContributionRecur::copyCustomValues($contributionParams['contribution_recur_id'], $contribution->id);
+      self::handleMembershipIDOverride($contribution->id, $input);
       return TRUE;
     }
   }
@@ -3901,40 +3948,6 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
     return FALSE;
   }
 
-  /**
-   * Function to record additional payment for partial and refund contributions.
-   *
-   * @param int $contributionId
-   *   is the invoice contribution id (got created after processing participant payment).
-   * @param array $trxnsData
-   *   to take user provided input of transaction details.
-   * @param string $paymentType
-   *   'owed' for purpose of recording partial payments, 'refund' for purpose of recording refund payments.
-   * @param int $participantId
-   * @param bool $updateStatus
-   *
-   * @return int
-   *
-   * @throws \CRM_Core_Exception
-   * @throws \CiviCRM_API3_Exception
-   */
-  public static function recordAdditionalPayment($contributionId, $trxnsData, $paymentType = 'owed', $participantId = NULL, $updateStatus = TRUE) {
-
-    if ($paymentType == 'owed') {
-      $financialTrxn = CRM_Financial_BAO_Payment::recordPayment($contributionId, $trxnsData, $participantId);
-      if (!empty($financialTrxn)) {
-        self::recordPaymentActivity($contributionId, $participantId, $financialTrxn->total_amount, $financialTrxn->currency, $financialTrxn->trxn_date);
-        return $financialTrxn->id;
-      }
-    }
-    elseif ($paymentType == 'refund') {
-      $trxnsData['total_amount'] = -$trxnsData['total_amount'];
-      $trxnsData['participant_id'] = $participantId;
-      $trxnsData['contribution_id'] = $contributionId;
-      return civicrm_api3('Payment', 'create', $trxnsData)['id'];
-    }
-  }
-
   /**
    * @param int $targetCid
    * @param $activityType
index c6197f14cef709f1d8b9da6bcc574018e48a25f0..233377eb157f9c29984fbc23b22bf1aed276822b 100644 (file)
@@ -284,6 +284,7 @@ class CRM_Contribute_BAO_ContributionRecur extends CRM_Contribute_DAO_Contributi
       $recur->cancel_date = date('YmdHis');
       $recur->save();
 
+      // @fixme https://lab.civicrm.org/dev/core/issues/927 Cancelling membership etc is not desirable for all use-cases and we should be able to disable it
       $dao = CRM_Contribute_BAO_ContributionRecur::getSubscriptionDetails($recurId);
       if ($dao && $dao->recur_id) {
         $details = CRM_Utils_Array::value('details', $activityParams);
index f34854f597859a9c326c1dc911fb96ce9d88b2da..fdb7c478f3a9c81eb86813aa1df0568dee07aaf0 100644 (file)
@@ -73,6 +73,11 @@ class CRM_Contribute_Form_AdditionalPayment extends CRM_Contribute_Form_Abstract
 
   public $_action = NULL;
 
+  /**
+   * Pre process form.
+   *
+   * @throws \CRM_Core_Exception
+   */
   public function preProcess() {
 
     $this->_id = CRM_Utils_Request::retrieve('id', 'Positive', $this, TRUE);
@@ -118,11 +123,11 @@ class CRM_Contribute_Form_AdditionalPayment extends CRM_Contribute_Form_Abstract
       $this->_paymentType = 'owed';
     }
     else {
-      CRM_Core_Error::fatal(ts('No payment information found for this record'));
+      throw new CRM_Core_Exception(ts('No payment information found for this record'));
     }
 
     if (!empty($this->_mode) && $this->_paymentType == 'refund') {
-      CRM_Core_Error::fatal(ts('Credit card payment is not for Refund payments use'));
+      throw new CRM_Core_Exception(ts('Credit card payment is not for Refund payments use'));
     }
 
     list($this->_contributorDisplayName, $this->_contributorEmail) = CRM_Contact_BAO_Contact_Location::getEmailDetails($this->_contactID);
@@ -139,6 +144,8 @@ class CRM_Contribute_Form_AdditionalPayment extends CRM_Contribute_Form_Abstract
    * Is this function being called from a datatable selector.
    *
    * If so we don't want to show the buttons.
+   *
+   * @throws \CRM_Core_Exception
    */
   protected function isBeingCalledFromSelectorContext() {
     return CRM_Utils_Request::retrieve('selector', 'Positive');
@@ -356,19 +363,16 @@ class CRM_Contribute_Form_AdditionalPayment extends CRM_Contribute_Form_Abstract
       $this->processCreditCard();
     }
 
-    $defaults = [];
-    $contribution = civicrm_api3('Contribution', 'getsingle', [
-      'return' => ["contribution_status_id"],
-      'id' => $this->_contributionId,
-    ]);
-    $contributionStatusId = CRM_Utils_Array::value('contribution_status_id', $contribution);
-    $paymentID = CRM_Contribute_BAO_Contribution::recordAdditionalPayment($this->_contributionId, $this->_params, $this->_paymentType, $participantId);
-    // Fetch the contribution & do proportional line item assignment
-    $params = ['id' => $this->_contributionId];
-    $contribution = CRM_Contribute_BAO_Contribution::retrieve($params, $defaults, $params);
-    // @todo - this line needs to be moved to the Payment.create api - it's not form layer appropriate.
-    // testing required.
-    CRM_Contribute_BAO_Contribution::addPayments([$contribution], $contributionStatusId);
+    $trxnsData = $this->_params;
+    if ($this->_paymentType == 'refund') {
+      $trxnsData['total_amount'] = -$trxnsData['total_amount'];
+    }
+    $trxnsData['participant_id'] = $participantId;
+    $trxnsData['contribution_id'] = $this->_contributionId;
+    // From the
+    $trxnsData['is_send_contribution_notification'] = FALSE;
+    $paymentID = civicrm_api3('Payment', 'create', $trxnsData)['id'];
+
     if ($this->_contributionId && CRM_Core_Permission::access('CiviMember')) {
       $membershipPaymentCount = civicrm_api3('MembershipPayment', 'getCount', ['contribution_id' => $this->_contributionId]);
       if ($membershipPaymentCount) {
index 25deceea7b02741ba3c8d7a20431a42e915057e3..95fddb2ce9c5a9ae853acf673d6f96ad012590fe 100644 (file)
@@ -1364,7 +1364,6 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
     $membershipTypeIDs = (array) $membershipParams['selectMembership'];
     $membershipTypes = CRM_Member_BAO_Membership::buildMembershipTypeValues($this, $membershipTypeIDs);
     $membershipType = empty($membershipTypes) ? [] : reset($membershipTypes);
-    $isPending = $this->getIsPending();
 
     $this->assign('membership_name', CRM_Utils_Array::value('name', $membershipType));
     $this->_values['membership_name'] = CRM_Utils_Array::value('name', $membershipType);
@@ -1392,7 +1391,7 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
 
     $this->postProcessMembership($membershipParams, $contactID,
       $this, $premiumParams, $customFieldsFormatted, $fieldTypes, $membershipType, $membershipTypeIDs, $isPaidMembership, $this->_membershipId, $isProcessSeparateMembershipTransaction, $financialTypeID,
-      $membershipLineItems, $isPending);
+      $membershipLineItems);
 
     $this->assign('membership_assign', TRUE);
     $this->set('membershipTypeID', $membershipParams['selectMembership']);
@@ -1424,14 +1423,15 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
    * @param int $financialTypeID
    * @param array $unprocessedLineItems
    *   Line items for payment options chosen on the form.
-   * @param bool $isPending
    *
    * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
+   * @throws \Civi\Payment\Exception\PaymentProcessorException
    */
   protected function postProcessMembership(
     $membershipParams, $contactID, &$form, $premiumParams,
     $customFieldsFormatted = NULL, $includeFieldTypes = NULL, $membershipDetails, $membershipTypeIDs, $isPaidMembership, $membershipID,
-    $isProcessSeparateMembershipTransaction, $financialTypeID, $unprocessedLineItems, $isPending) {
+    $isProcessSeparateMembershipTransaction, $financialTypeID, $unprocessedLineItems) {
 
     $membershipContribution = NULL;
     $isTest = CRM_Utils_Array::value('is_test', $membershipParams, FALSE);
@@ -1532,13 +1532,6 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
         }
         $i++;
         $numTerms = CRM_Utils_Array::value($memType, $typesTerms, 1);
-        if (!empty($membershipContribution)) {
-          $pendingStatus = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Pending');
-          $pending = ($membershipContribution->contribution_status_id == $pendingStatus) ? TRUE : FALSE;
-        }
-        else {
-          $pending = $isPending;
-        }
         $contributionRecurID = isset($form->_params['contributionRecurID']) ? $form->_params['contributionRecurID'] : NULL;
 
         $membershipSource = NULL;
@@ -1560,6 +1553,13 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
           }
         }
 
+        // @todo Move this into CRM_Member_BAO_Membership::processMembership
+        if (!empty($membershipContribution)) {
+          $pending = ($membershipContribution->contribution_status_id == array_search('Pending', CRM_Contribute_PseudoConstant::contributionStatus())) ? TRUE : FALSE;
+        }
+        else {
+          $pending = $this->getIsPending();
+        }
         list($membership, $renewalMode, $dates) = CRM_Member_BAO_Membership::processMembership(
           $contactID, $memType, $isTest,
           date('YmdHis'), CRM_Utils_Array::value('cms_contactID', $membershipParams),
index 71ebf132db34c44a174ddefc3c13721604488b0c..af3dbd233da196c559995eebd657617ca50f6bdd 100644 (file)
@@ -416,9 +416,9 @@ class CRM_Core_BAO_Address extends CRM_Core_DAO_Address {
         if (substr($name, 0, 7) == 'country') {
           // make sure its different from the default country
           // iso code
-          $defaultCountry = $config->defaultContactCountry();
+          $defaultCountry = CRM_Core_BAO_Country::defaultContactCountry();
           // full name
-          $defaultCountryName = $config->defaultContactCountryName();
+          $defaultCountryName = CRM_Core_BAO_Country::defaultContactCountryName();
 
           if ($defaultCountry) {
             if ($value == $defaultCountry ||
@@ -663,8 +663,7 @@ ORDER BY civicrm_address.is_primary DESC, civicrm_address.location_type_id DESC,
    *   Array of address sequence.
    */
   public static function addressSequence() {
-    $config = CRM_Core_Config::singleton();
-    $addressSequence = $config->addressSequence();
+    $addressSequence = CRM_Utils_Address::sequence(\Civi::settings()->get('address_format'));
 
     $countryState = $cityPostal = FALSE;
     foreach ($addressSequence as $key => $field) {
index 07530e3f5228135718df1b361cc8e8a480e0515e..26907960b8567e8038d5ef54fe9c532f1161ee4a 100644 (file)
@@ -1261,7 +1261,7 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField {
         if (!$value) {
           $config = CRM_Core_Config::singleton();
           if ($config->defaultContactCountry) {
-            $value = $config->defaultContactCountry();
+            $value = CRM_Core_BAO_Country::defaultContactCountry();
           }
         }
       }
index 8b61cf0c0d6605828586d26ce3dd2e54ea249c3d..8eef1432321fb40c383683ca6df78d6188f518c4 100644 (file)
@@ -109,6 +109,7 @@ class CRM_Core_BAO_Dashboard extends CRM_Core_DAO_Dashboard {
       'contact_id' => $contactID,
       'is_active' => 1,
       'dashboard_id.is_active' => 1,
+      'dashboard_id.domain_id' => CRM_Core_Config::domainID(),
       'options' => ['sort' => 'weight', 'limit' => 0],
       'return' => [
         'id',
@@ -143,7 +144,7 @@ class CRM_Core_BAO_Dashboard extends CRM_Core_DAO_Dashboard {
     // If empty, then initialize default dashlets for this user.
     if (!$results['count']) {
       // They may just have disabled all their dashlets. Check if any records exist for this contact.
-      if (!civicrm_api3('DashboardContact', 'getcount', ['contact_id' => $contactID])) {
+      if (!civicrm_api3('DashboardContact', 'getcount', ['contact_id' => $contactID, 'dashboard_id.domain_id' => CRM_Core_Config::domainID()])) {
         $dashlets = self::initializeDashlets();
       }
     }
@@ -388,7 +389,13 @@ class CRM_Core_BAO_Dashboard extends CRM_Core_DAO_Dashboard {
     $dashlet = new CRM_Core_DAO_Dashboard();
 
     if (!$dashboardID) {
-      // check url is same as exiting entries, if yes just update existing
+
+      // Assign domain before search to allow identical dashlets in different domains.
+      if (empty($params['domain_id'])) {
+        $dashlet->domain_id = CRM_Core_Config::domainID();
+      }
+
+      // Try and find an existing dashlet - it will be updated if found.
       if (!empty($params['name'])) {
         $dashlet->name = CRM_Utils_Array::value('name', $params);
         $dashlet->find(TRUE);
@@ -397,9 +404,7 @@ class CRM_Core_BAO_Dashboard extends CRM_Core_DAO_Dashboard {
         $dashlet->url = CRM_Utils_Array::value('url', $params);
         $dashlet->find(TRUE);
       }
-      if (empty($params['domain_id'])) {
-        $dashlet->domain_id = CRM_Core_Config::domainID();
-      }
+
     }
     else {
       $dashlet->id = $dashboardID;
index bcc8e650f8f0887d3799d95fbc3adaecf5067ae8..f217d874417f1d22551cff250d0e747f5fc039d2 100644 (file)
@@ -429,7 +429,7 @@ WHERE (pn.cachekey $op %1 OR pn.cachekey $op %2)
    * @throws \CiviCRM_API3_Exception
    */
   public static function refillCache($rgid, $gid, $criteria, $checkPermissions, $searchLimit = 0) {
-    $cacheKeyString = CRM_Dedupe_Merger::getMergeCacheKeyString($rgid, $gid, $criteria, $checkPermissions);
+    $cacheKeyString = CRM_Dedupe_Merger::getMergeCacheKeyString($rgid, $gid, $criteria, $checkPermissions, $searchLimit);
 
     // 1. Clear cache if any
     $sql = "DELETE FROM civicrm_prevnext_cache WHERE  cachekey LIKE %1";
@@ -450,15 +450,24 @@ WHERE (pn.cachekey $op %1 OR pn.cachekey $op %2)
       // would chain to a delete. Limiting to getfields for 'get' limits us to declared fields,
       // although we might wish to revisit later to allow joins.
       $validFieldsForRetrieval = civicrm_api3('Contact', 'getfields', ['action' => 'get'])['values'];
-      if (!empty($criteria)) {
+      $filteredCriteria = isset($criteria['contact']) ? array_intersect_key($criteria['contact'], $validFieldsForRetrieval) : [];
+
+      if (!empty($criteria) || !empty($searchLimit)) {
         $contacts = civicrm_api3('Contact', 'get', array_merge([
-          'options' => ['limit' => 0],
+          'options' => ['limit' => $searchLimit],
           'return' => 'id',
           'check_permissions' => TRUE,
-        ], array_intersect_key($criteria['contact'], $validFieldsForRetrieval)));
+          'contact_type' => civicrm_api3('RuleGroup', 'getvalue', ['id' => $rgid, 'return' => 'contact_type']),
+        ], $filteredCriteria));
         $contactIDs = array_keys($contacts['values']);
+
+        if (empty($contactIDs)) {
+          // If there is criteria but no contacts were found then we should return now
+          // since we have no contacts to match.
+          return [];
+        }
       }
-      $foundDupes = CRM_Dedupe_Finder::dupes($rgid, $contactIDs, $checkPermissions, $searchLimit);
+      $foundDupes = CRM_Dedupe_Finder::dupes($rgid, $contactIDs, $checkPermissions);
     }
 
     if (!empty($foundDupes)) {
index 004907fa127874aad356167f1ea4fbfa134a9a17..0b0ee3b5f9851af2fa2411972d93d2aeb8ff2abe 100644 (file)
@@ -626,7 +626,7 @@ MODIFY      {$columnName} varchar( $length )
       2 => [$table_name, 'String'],
       3 => [$constraint_name, 'String'],
     ];
-    $dao = CRM_Core_DAO::executeQuery($query, $params);
+    $dao = CRM_Core_DAO::executeQuery($query, $params, TRUE, NULL, FALSE, FALSE);
 
     if ($dao->fetch()) {
       return TRUE;
@@ -644,7 +644,7 @@ MODIFY      {$columnName} varchar( $length )
    */
   public static function safeRemoveFK($table_name, $constraint_name) {
     if (self::checkFKExists($table_name, $constraint_name)) {
-      CRM_Core_DAO::executeQuery("ALTER TABLE {$table_name} DROP FOREIGN KEY {$constraint_name}", []);
+      CRM_Core_DAO::executeQuery("ALTER TABLE {$table_name} DROP FOREIGN KEY {$constraint_name}", [], TRUE, NULL, FALSE, FALSE);
       return TRUE;
     }
     return FALSE;
index 4e3679fb6d4d305d38afedff0d4e7261fda28ada..f8952cf41928c30621be8a62829c05314df4f383 100644 (file)
@@ -471,6 +471,7 @@ class CRM_Core_Config extends CRM_Core_Config_MagicMerge {
    * @deprecated
    */
   public function addressSequence() {
+    CRM_Core_Error::deprecatedFunctionWarning('CRM_Utils_Address::sequence(Civi::settings()->get(\'address_format\')');
     return CRM_Utils_Address::sequence(Civi::settings()->get('address_format'));
   }
 
@@ -478,6 +479,7 @@ class CRM_Core_Config extends CRM_Core_Config_MagicMerge {
    * @deprecated
    */
   public function defaultContactCountry() {
+    CRM_Core_Error::deprecatedFunctionWarning('CRM_Core_BAO_Country::defaultContactCountry');
     return CRM_Core_BAO_Country::defaultContactCountry();
   }
 
@@ -485,6 +487,7 @@ class CRM_Core_Config extends CRM_Core_Config_MagicMerge {
    * @deprecated
    */
   public function defaultContactCountryName() {
+    CRM_Core_Error::deprecatedFunctionWarning('CRM_Core_BAO_Country::defaultContactCountryName');
     return CRM_Core_BAO_Country::defaultContactCountryName();
   }
 
index e42e08bf4eb9acc892c852ca700be1d69eae6ccc..8a366e7b077a3e59d654fcc72154048296459205 100644 (file)
@@ -397,9 +397,9 @@ return [
     'class' => 'CRM_Core_DAO_StatusPreference',
     'table' => 'civicrm_status_pref',
   ],
-  'CRM_ACL_DAO_Cache' => [
-    'name' => 'Cache',
-    'class' => 'CRM_ACL_DAO_Cache',
+  'CRM_ACL_DAO_ACLCache' => [
+    'name' => 'ACLCache',
+    'class' => 'CRM_ACL_DAO_ACLCache',
     'table' => 'civicrm_acl_cache',
   ],
   'CRM_Contact_DAO_Group' => [
index 01536dda8ed0c391031bdfc4ce548220362d65b9..15f2f222680cf3b16c2e93475ec07b8ac34485bc 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Cache.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:97df4edaa4829ea30a151dbb95ff754d)
+ * (GenCodeChecksum:4d3ccecb7d91aa67b8c78c3c39933ae8)
  */
 
 /**
@@ -29,6 +29,8 @@ class CRM_Core_DAO_Cache extends CRM_Core_DAO {
   public static $_log = FALSE;
 
   /**
+   * Unique table ID
+   *
    * @var int
    */
   public $id;
@@ -109,6 +111,8 @@ class CRM_Core_DAO_Cache extends CRM_Core_DAO {
         'id' => [
           'name' => 'id',
           'type' => CRM_Utils_Type::T_INT,
+          'title' => ts('Cache ID'),
+          'description' => ts('Unique table ID'),
           'required' => TRUE,
           'where' => 'civicrm_cache.id',
           'table_name' => 'civicrm_cache',
@@ -157,6 +161,7 @@ class CRM_Core_DAO_Cache extends CRM_Core_DAO {
         'component_id' => [
           'name' => 'component_id',
           'type' => CRM_Utils_Type::T_INT,
+          'title' => ts('Component ID'),
           'description' => ts('Component that this menu item belongs to'),
           'where' => 'civicrm_cache.component_id',
           'table_name' => 'civicrm_cache',
index 026937454c374d971e8aa6aeaefafe0fac900362..f772fef1082d4b9b4fd98c2368b02700ada75e68 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Core/Dashboard.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:2b085baa3414de05ee5c52a4d7d4f81f)
+ * (GenCodeChecksum:6fd1bfbecace855a159025ad31e37fb0)
  */
 
 /**
index ea1dc1d0e3b731a8b2786f985d996b20a25b9db8..e52e51515a22e94705dbb695b9903043718fb47d 100644 (file)
@@ -466,17 +466,12 @@ class CRM_Core_Error extends PEAR_ErrorStack {
     $template = CRM_Core_Smarty::singleton();
     $template->assign($vars);
     $content = $template->fetch('CRM/common/fatal.tpl');
+
     if ($config->backtrace) {
       $content = self::formatHtmlException($exception) . $content;
     }
-    if ($config->userFramework == 'Joomla' &&
-      class_exists('JError')
-    ) {
-      JError::raiseError('CiviCRM-001', $content);
-    }
-    else {
-      echo CRM_Utils_System::theme($content);
-    }
+
+    echo CRM_Utils_System::theme($content);
 
     // fin
     self::abend(CRM_Core_Error::FATAL_ERROR);
index 7a998fe2a523caa951764e81bd2b2c3808b8e6e3..f54c05d2c47345d4342ed2cd4548be0dc88ee60a 100644 (file)
@@ -67,8 +67,7 @@ class CRM_Core_Page_AJAX_Location {
     $entityBlock = ['contact_id' => $cid];
     $location = CRM_Core_BAO_Location::getValues($entityBlock);
 
-    $config = CRM_Core_Config::singleton();
-    $addressSequence = array_flip($config->addressSequence());
+    $addressSequence = array_flip(CRM_Utils_Address::sequence(\Civi::settings()->get('address_format')));
 
     $profileFields = CRM_Core_BAO_UFGroup::getFields($ufId, FALSE, CRM_Core_Action::VIEW, NULL, NULL, FALSE,
       NULL, FALSE, NULL, CRM_Core_Permission::CREATE, NULL
index 35af834bd575c67dc51e899a6223ab7b2b569d97..9e7ed420ba3c9330dd5a2255e866684838df229b 100644 (file)
@@ -213,6 +213,7 @@ class CRM_Core_Payment_BaseIPN {
    * @param array $input
    *
    * @return bool
+   * @throws \CiviCRM_API3_Exception
    */
   public function failed(&$objects, &$transaction, $input = []) {
     $contribution = &$objects['contribution'];
@@ -235,10 +236,10 @@ class CRM_Core_Payment_BaseIPN {
       'labelColumn' => 'name',
       'flip' => 1,
     ]);
+    $contribution->contribution_status_id = $contributionStatuses['Failed'];
     $contribution->receive_date = CRM_Utils_Date::isoToMysql($contribution->receive_date);
     $contribution->receipt_date = CRM_Utils_Date::isoToMysql($contribution->receipt_date);
     $contribution->thankyou_date = CRM_Utils_Date::isoToMysql($contribution->thankyou_date);
-    $contribution->contribution_status_id = $contributionStatuses['Failed'];
     $contribution->save();
 
     // Add line items for recurring payments.
@@ -255,33 +256,19 @@ class CRM_Core_Payment_BaseIPN {
 
     if (empty($input['IAmAHorribleNastyBeyondExcusableHackInTheCRMEventFORMTaskClassThatNeedsToBERemoved'])) {
       if (!empty($memberships)) {
-        // if transaction is failed then set "Cancelled" as membership status
-        $membershipStatuses = CRM_Core_PseudoConstant::get('CRM_Member_DAO_Membership', 'status_id', [
-          'labelColumn' => 'name',
-          'flip' => 1,
-        ]);
         foreach ($memberships as $membership) {
-          if ($membership) {
-            $membership->status_id = $membershipStatuses['Cancelled'];
-            $membership->save();
-
-            //update related Memberships.
-            $params = ['status_id' => $membershipStatuses['Cancelled']];
-            CRM_Member_BAO_Membership::updateRelatedMemberships($membership->id, $params);
-          }
+          // @fixme Should we cancel only Pending memberships? per cancelled()
+          $this->cancelMembership($membership, $membership->status_id, FALSE);
         }
       }
 
       if ($participant) {
-        $participantParams['id'] = $participant->id;
-        $participantParams['status_id'] = 'Cancelled';
-        civicrm_api3('Participant', 'create', $participantParams);
+        $this->cancelParticipant($participant->id);
       }
     }
 
     $transaction->commit();
-    CRM_Core_Error::debug_log_message("Setting contribution status to failed");
-    //echo "Success: Setting contribution status to failed<p>";
+    Civi::log()->debug("Setting contribution status to Failed");
     return TRUE;
   }
 
@@ -295,7 +282,7 @@ class CRM_Core_Payment_BaseIPN {
    */
   public function pending(&$objects, &$transaction) {
     $transaction->commit();
-    CRM_Core_Error::debug_log_message("returning since contribution status is pending");
+    Civi::log()->debug("Returning since contribution status is Pending");
     echo "Success: Returning since contribution status is pending<p>";
     return TRUE;
   }
@@ -308,32 +295,38 @@ class CRM_Core_Payment_BaseIPN {
    * @param array $input
    *
    * @return bool
+   * @throws \CiviCRM_API3_Exception
    */
   public function cancelled(&$objects, &$transaction, $input = []) {
     $contribution = &$objects['contribution'];
-    $memberships = &$objects['membership'];
-    if (is_numeric($memberships)) {
-      $memberships = [$objects['membership']];
+    $memberships = [];
+    if (!empty($objects['membership'])) {
+      $memberships = &$objects['membership'];
+      if (is_numeric($memberships)) {
+        $memberships = [$objects['membership']];
+      }
     }
 
-    $participant = &$objects['participant'];
     $addLineItems = FALSE;
     if (empty($contribution->id)) {
       $addLineItems = TRUE;
     }
+    $participant = &$objects['participant'];
+
+    // CRM-15546
     $contributionStatuses = CRM_Core_PseudoConstant::get('CRM_Contribute_DAO_Contribution', 'contribution_status_id', [
       'labelColumn' => 'name',
       'flip' => 1,
     ]);
     $contribution->contribution_status_id = $contributionStatuses['Cancelled'];
-    $contribution->cancel_date = self::$_now;
-    $contribution->cancel_reason = CRM_Utils_Array::value('reasonCode', $input);
     $contribution->receive_date = CRM_Utils_Date::isoToMysql($contribution->receive_date);
     $contribution->receipt_date = CRM_Utils_Date::isoToMysql($contribution->receipt_date);
     $contribution->thankyou_date = CRM_Utils_Date::isoToMysql($contribution->thankyou_date);
+    $contribution->cancel_date = self::$_now;
+    $contribution->cancel_reason = CRM_Utils_Array::value('reasonCode', $input);
     $contribution->save();
 
-    //add lineitems for recurring payments
+    // Add line items for recurring payments.
     if (!empty($objects['contributionRecur']) && $objects['contributionRecur']->id && $addLineItems) {
       CRM_Contribute_BAO_ContributionRecur::addRecurLineItems($objects['contributionRecur']->id, $contribution);
     }
@@ -347,34 +340,19 @@ class CRM_Core_Payment_BaseIPN {
 
     if (empty($input['IAmAHorribleNastyBeyondExcusableHackInTheCRMEventFORMTaskClassThatNeedsToBERemoved'])) {
       if (!empty($memberships)) {
-        $membershipStatuses = CRM_Core_PseudoConstant::get('CRM_Member_DAO_Membership', 'status_id', [
-          'labelColumn' => 'name',
-          'flip' => 1,
-        ]);
-        // Cancel only Pending memberships
-        // CRM-18688
-        $pendingStatusId = $membershipStatuses['Pending'];
         foreach ($memberships as $membership) {
-          if ($membership && ($membership->status_id == $pendingStatusId)) {
-            $membership->status_id = $membershipStatuses['Cancelled'];
-            $membership->save();
-
-            //update related Memberships.
-            $params = ['status_id' => $membershipStatuses['Cancelled']];
-            CRM_Member_BAO_Membership::updateRelatedMemberships($membership->id, $params);
+          if ($membership) {
+            $this->cancelMembership($membership, $membership->status_id);
           }
         }
       }
 
       if ($participant) {
-        $participantParams['id'] = $participant->id;
-        $participantParams['status_id'] = 'Cancelled';
-        civicrm_api3('Participant', 'create', $participantParams);
+        $this->cancelParticipant($participant->id);
       }
     }
     $transaction->commit();
-    CRM_Core_Error::debug_log_message("Setting contribution status to cancelled");
-    //echo "Success: Setting contribution status to cancelled<p>";
+    Civi::log()->debug("Setting contribution status to Cancelled");
     return TRUE;
   }
 
@@ -388,11 +366,60 @@ class CRM_Core_Payment_BaseIPN {
    */
   public function unhandled(&$objects, &$transaction) {
     $transaction->rollback();
-    CRM_Core_Error::debug_log_message("returning since contribution status: is not handled");
+    Civi::log()->debug("Returning since contribution status is not handled");
     echo "Failure: contribution status is not handled<p>";
     return FALSE;
   }
 
+  /**
+   * Logic to cancel a participant record when the related contribution changes to failed/cancelled.
+   * @todo This is part of a bigger refactor for dev/core/issues/927 - "duplicate" functionality exists in CRM_Contribute_BAO_Contribution::cancel()
+   *
+   * @param $participantID
+   *
+   * @throws \CiviCRM_API3_Exception
+   */
+  private function cancelParticipant($participantID) {
+    // @fixme https://lab.civicrm.org/dev/core/issues/927 Cancelling membership etc is not desirable for all use-cases and we should be able to disable it
+    $participantParams['id'] = $participantID;
+    $participantParams['status_id'] = 'Cancelled';
+    civicrm_api3('Participant', 'create', $participantParams);
+  }
+
+  /**
+   * Logic to cancel a membership record when the related contribution changes to failed/cancelled.
+   * @todo This is part of a bigger refactor for dev/core/issues/927 - "duplicate" functionality exists in CRM_Contribute_BAO_Contribution::cancel()
+   * @param \CRM_Member_BAO_Membership $membership
+   * @param int $membershipStatusID
+   * @param boolean $onlyCancelPendingMembership
+   *   Do we only cancel pending memberships? OR memberships in any status? (see CRM-18688)
+   * @fixme Historically failed() cancelled membership in any status, cancelled() cancelled only pending memberships so we retain that behaviour for now.
+   *
+   */
+  private function cancelMembership($membership, $membershipStatusID, $onlyCancelPendingMembership = TRUE) {
+    // @fixme https://lab.civicrm.org/dev/core/issues/927 Cancelling membership etc is not desirable for all use-cases and we should be able to disable it
+    // Cancel only Pending memberships
+    $pendingMembershipStatusId = CRM_Core_PseudoConstant::getKey('CRM_Member_BAO_Membership', 'status_id', 'Pending');
+    if (($membershipStatusID == $pendingMembershipStatusId) || ($onlyCancelPendingMembership == FALSE)) {
+      $cancelledMembershipStatusId = CRM_Core_PseudoConstant::getKey('CRM_Member_BAO_Membership', 'status_id', 'Cancelled');
+
+      $membership->status_id = $cancelledMembershipStatusId;
+      $membership->save();
+
+      $params = ['status_id' => $cancelledMembershipStatusId];
+      CRM_Member_BAO_Membership::updateRelatedMemberships($membership->id, $params);
+
+      // @todo Convert the above to API
+      // $membershipParams = [
+      //   'id' => $membership->id,
+      //   'status_id' => $cancelledMembershipStatusId,
+      // ];
+      // civicrm_api3('Membership', 'create', $membershipParams);
+      // CRM_Member_BAO_Membership::updateRelatedMemberships($membershipParams['id'], ['status_id' => $cancelledMembershipStatusId]);
+    }
+
+  }
+
   /**
    * @deprecated
    *
@@ -447,6 +474,9 @@ class CRM_Core_Payment_BaseIPN {
    * @param array $objects
    * @param CRM_Core_Transaction $transaction
    * @param bool $recur
+   *
+   * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
    */
   public function completeTransaction(&$input, &$ids, &$objects, &$transaction, $recur = FALSE) {
     $contribution = &$objects['contribution'];
@@ -493,6 +523,8 @@ class CRM_Core_Payment_BaseIPN {
    *   is because the function is also used to generate pdfs
    *
    * @return array
+   * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
    */
   public function sendMail(&$input, &$ids, &$objects, &$values, $recur = FALSE, $returnMessageText = FALSE) {
     return CRM_Contribute_BAO_Contribution::sendMail($input, $ids, $objects['contribution']->id, $values,
index 3ad4c74d27597804fffa4dc7c95db0f2dc055270..d7a13692b65f29a8d05c2d5cc21780c9467f2c2c 100644 (file)
@@ -313,7 +313,9 @@ class CRM_Core_Payment_PayPalIPN extends CRM_Core_Payment_BaseIPN {
     $input['component'] = $component;
 
     $ids['contact'] = $this->retrieve('contactID', 'Integer', TRUE);
-    $ids['contribution'] = $this->retrieve('contributionID', 'Integer', TRUE);
+    $contributionID = $ids['contribution'] = $this->retrieve('contributionID', 'Integer', TRUE);
+    $membershipID = $this->retrieve('membershipID', 'Integer', FALSE);
+    $contributionRecurID = $this->retrieve('contributionRecurID', 'Integer', FALSE);
 
     $this->getInput($input, $ids);
 
@@ -323,17 +325,48 @@ class CRM_Core_Payment_PayPalIPN extends CRM_Core_Payment_BaseIPN {
     }
     else {
       // get the optional ids
-      $ids['membership'] = $this->retrieve('membershipID', 'Integer', FALSE);
-      $ids['contributionRecur'] = $this->retrieve('contributionRecurID', 'Integer', FALSE);
+      $ids['membership'] = $membershipID;
+      $ids['contributionRecur'] = $contributionRecurID;
       $ids['contributionPage'] = $this->retrieve('contributionPageID', 'Integer', FALSE);
       $ids['related_contact'] = $this->retrieve('relatedContactID', 'Integer', FALSE);
       $ids['onbehalf_dupe_alert'] = $this->retrieve('onBehalfDupeAlert', 'Integer', FALSE);
     }
 
-    $paymentProcessorID = self::getPayPalPaymentProcessorID($input, $ids);
+    $paymentProcessorID = $this->getPayPalPaymentProcessorID($input, $ids);
 
     Civi::log()->debug('PayPalIPN: Received (ContactID: ' . $ids['contact'] . '; trxn_id: ' . $input['trxn_id'] . ').');
 
+    if ($this->retrieve('membershipID', 'Integer', FALSE)) {
+      $templateContribution = CRM_Contribute_BAO_ContributionRecur::getTemplateContribution($contributionRecurID);
+      $membershipPayment = civicrm_api3('MembershipPayment', 'get', [
+        'contribution_id' => $templateContribution['id'],
+        'membership_id' => $membershipID,
+      ]);
+      $lineItems  = civicrm_api3('LineItem', 'get', [
+        'contribution_id' => $templateContribution['id'],
+        'entity_id' => $membershipID,
+        'entity_table' => 'civicrm_membership',
+      ]);
+      Civi::log()->debug('PayPalIPN: Received payment for membership ' . (int) $membershipID
+        . '. Original contribution was ' . (int) $contributionID . '. The template for this contribution is '
+        . $templateContribution['id'] . ' it is linked to ' . $membershipPayment['count']
+        . 'payments for this membership. It has ' . $lineItems['count'] . ' line items linked to  this membership.'
+        . '  it is  expected the original contribution will be linked by both entities to the membership.'
+      );
+      if (empty($membershipPayment['count']) && empty($lineItems['count'])) {
+        Civi::log()->debug('PayPalIPN: Will attempt to compensate');
+        $input['membership_id'] = $this->retrieve('membershipID', 'Integer', FALSE);
+      }
+      if ($contributionRecurID) {
+        $recurLinks = civicrm_api3('ContributionRecur', 'get', [
+          'membership_id' => $membershipID,
+          'contribution_recur_id' => $contributionRecurID,
+        ]);
+        Civi::log()->debug('PayPalIPN: Membership should be  linked to  contribution recur  record ' . $contributionRecurID
+          . ' ' . $recurLinks['count'] . 'links found'
+        );
+      }
+    }
     if (!$this->validateData($input, $ids, $objects, TRUE, $paymentProcessorID)) {
       return;
     }
index 5b4a109802e07e5ace1ce6df9d114b741d029a0d..905e369a61b71dc2e4f2e5656df2416b57579118 100644 (file)
@@ -352,7 +352,6 @@ class CRM_Core_Payment_PayPalImpl extends CRM_Core_Payment {
    * @throws \Civi\Payment\Exception\PaymentProcessorException
    */
   public function doExpressCheckout(&$params) {
-    $statuses = CRM_Contribute_BAO_Contribution::buildOptions('contribution_status_id');
     if (!empty($params['is_recur'])) {
       return $this->createRecurringPayments($params);
     }
@@ -379,7 +378,6 @@ class CRM_Core_Payment_PayPalImpl extends CRM_Core_Payment {
     }
 
     /* Success */
-
     $params['trxn_id'] = $result['transactionid'];
     $params['gross_amount'] = $result['amt'];
     $params['fee_amount'] = $result['feeamt'];
@@ -391,10 +389,10 @@ class CRM_Core_Payment_PayPalImpl extends CRM_Core_Payment {
     $params['pending_reason'] = $result['pendingreason'];
     if (!empty($params['is_recur'])) {
       // See comment block.
-      $params['payment_status_id'] = array_search('Pending', $statuses);
+      $params['payment_status_id'] = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Pending');
     }
     else {
-      $params['payment_status_id'] = array_search('Completed', $statuses);
+      $params['payment_status_id'] = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
     }
     return $params;
   }
index 57d58ec7471762797882f9392fe05c4255a428f1..d5818d93ffe477245fb83aae03dd84f10c59044e 100644 (file)
@@ -81,48 +81,43 @@ class CRM_Core_Permission {
 
   /**
    * Given a permission string or array, check for access requirements
-   * @param string|array $permissions
-   *   The permission to check as an array or string -see examples.
-   *
-   * @param int $contactId
-   *   Contact id to check permissions for. Defaults to current logged-in user.
    *
-   *  Ex 1
+   * Ex 1: Must have 'access CiviCRM'
+   * (string) 'access CiviCRM'
    *
-   *  Must have 'access CiviCRM'
-   *  (string) 'access CiviCRM'
+   *  Ex 2: Must have 'access CiviCRM' and 'access Ajax API'
+   *    ['access CiviCRM', 'access Ajax API']
    *
+   * Ex 3: Must have 'access CiviCRM' or 'access Ajax API'
+   *   [
+   *     ['access CiviCRM', 'access Ajax API'],
+   *   ],
    *
-   *  Ex 2 Must have 'access CiviCRM' and 'access Ajax API'
-   *   array('access CiviCRM', 'access Ajax API')
+   * Ex 4: Must have 'access CiviCRM' or 'access Ajax API' AND 'access CiviEvent'
+   *   [
+   *     ['access CiviCRM', 'access Ajax API'],
+   *     'access CiviEvent',
+   *   ],
    *
-   *  Ex 3 Must have 'access CiviCRM' or 'access Ajax API'
-   *   array(
-   *      array('access CiviCRM', 'access Ajax API'),
-   *   ),
+   * Note that in permissions.php this is keyed by the action eg.
+   *   (access Civi || access AJAX) && (access CiviEvent || access CiviContribute)
+   *   'myaction' => [
+   *     ['access CiviCRM', 'access Ajax API'],
+   *     ['access CiviEvent', 'access CiviContribute']
+   *   ],
    *
-   *  Ex 4 Must have 'access CiviCRM' or 'access Ajax API' AND 'access CiviEvent'
-   *  array(
-   *    array('access CiviCRM', 'access Ajax API'),
-   *    'access CiviEvent',
-   *   ),
+   * @param string|array $permissions
+   *   The permission to check as an array or string -see examples.
    *
-   *  Note that in permissions.php this is keyed by the action eg.
-   *  (access Civi || access AJAX) && (access CiviEvent || access CiviContribute)
-   *  'myaction' => array(
-   *    array('access CiviCRM', 'access Ajax API'),
-   *    array('access CiviEvent', 'access CiviContribute')
-   *  ),
+   * @param int $contactId
+   *   Contact id to check permissions for. Defaults to current logged-in user.
    *
    * @return bool
-   *   true if yes, else false
+   *   true if contact has permission(s), else false
    */
   public static function check($permissions, $contactId = NULL) {
     $permissions = (array) $permissions;
-    $userId = NULL;
-    if ($contactId) {
-      $userId = CRM_Core_BAO_UFMatch::getUFId($contactId);
-    }
+    $userId = CRM_Core_BAO_UFMatch::getUFId($contactId);
 
     /** @var CRM_Core_Permission_Temp $tempPerm */
     $tempPerm = CRM_Core_Config::singleton()->userPermissionTemp;
@@ -976,6 +971,12 @@ class CRM_Core_Permission {
       'duplicatecheck' => [
         'access CiviCRM',
       ],
+      'merge' => ['merge duplicate contacts'],
+    ];
+
+    $permissions['dedupe'] = [
+      'getduplicates' => ['access CiviCRM'],
+      'getstatistics' => ['access CiviCRM'],
     ];
 
     // CRM-16963 - Permissions for country.
@@ -1179,6 +1180,13 @@ class CRM_Core_Permission {
         'edit all events',
       ],
     ];
+    // Exception refers to dedupe_exception.
+    $permissions['exception'] = [
+      'default' => ['merge duplicate contacts'],
+    ];
+    $permissions['job'] = [
+      'process_batch_merge' => ['merge duplicate contacts'],
+    ];
     // Loc block is only used for events
     $permissions['loc_block'] = $permissions['event'];
 
index c53c451d2d3785b9a9739fae6605ccbbed2b1972..14e2e7fcf220d826e9af4d437329f7fc442bc5cf 100644 (file)
@@ -836,9 +836,9 @@ WHERE  id = %1";
       self::populate(self::$country, 'CRM_Core_DAO_Country', TRUE, 'name', 'is_active', $whereClause);
 
       // if default country is set, percolate it to the top
-      if ($config->defaultContactCountry()) {
+      if (CRM_Core_BAO_Country::defaultContactCountry()) {
         $countryIsoCodes = self::countryIsoCode();
-        $defaultID = array_search($config->defaultContactCountry(), $countryIsoCodes);
+        $defaultID = array_search(CRM_Core_BAO_Country::defaultContactCountry(), $countryIsoCodes);
         if ($defaultID !== FALSE) {
           $default[$defaultID] = CRM_Utils_Array::value($defaultID, self::$country);
           self::$country = $default + self::$country;
index f3fa9a01b75ed8bd753d266f5cd57954648456d9..63725439a91682537e8bbe6a607bcfffb67bbb2c 100644 (file)
@@ -51,31 +51,17 @@ class CRM_Dedupe_Finder {
    * @param bool $checkPermissions
    *   Respect logged in user permissions.
    *
-   * @param int $searchLimit
-   *  Limit for the number of contacts to be used for comparison.
-   *  The search methodology finds all matches for the searchedContacts so this limits
-   *  the number of searched contacts, not the matches found.
-   *
    * @return array
    *   Array of (cid1, cid2, weight) dupe triples
    *
-   * @throws CiviCRM_API3_Exception
    * @throws Exception
    */
-  public static function dupes($rgid, $cids = [], $checkPermissions = TRUE, $searchLimit = 0) {
+  public static function dupes($rgid, $cids = [], $checkPermissions = TRUE) {
     $rgBao = new CRM_Dedupe_BAO_RuleGroup();
     $rgBao->id = $rgid;
     $rgBao->contactIds = $cids;
     if (!$rgBao->find(TRUE)) {
-      CRM_Core_Error::fatal("Dedupe rule not found for selected contacts");
-    }
-    if (empty($rgBao->contactIds) && !empty($searchLimit)) {
-      $limitedContacts = civicrm_api3('Contact', 'get', [
-        'return' => 'id',
-        'contact_type' => $rgBao->contact_type,
-        'options' => ['limit' => $searchLimit],
-      ]);
-      $rgBao->contactIds = array_keys($limitedContacts['values']);
+      throw new CRM_Core_Exception('Dedupe rule not found for selected contacts');
     }
 
     $rgBao->fillTable();
@@ -113,6 +99,7 @@ class CRM_Dedupe_Finder {
    *
    * @return array
    *   matching contact ids
+   * @throws \CRM_Core_Exception
    */
   public static function dupesByParams(
     $params,
@@ -144,7 +131,7 @@ class CRM_Dedupe_Finder {
       $rgBao->contact_type = $ctype;
       $rgBao->used = $used;
       if (!$rgBao->find(TRUE)) {
-        CRM_Core_Error::fatal("$used rule for $ctype does not exist");
+        throw new CRM_Core_Exception("$used rule for $ctype does not exist");
       }
     }
 
@@ -181,6 +168,7 @@ class CRM_Dedupe_Finder {
    *
    * @return array
    *   array of (cid1, cid2, weight) dupe triples
+   * @throws \CiviCRM_API3_Exception
    */
   public static function dupesInGroup($rgid, $gid, $searchLimit = 0) {
     $cids = array_keys(CRM_Contact_BAO_Group::getMember($gid, TRUE, $searchLimit));
@@ -201,6 +189,7 @@ class CRM_Dedupe_Finder {
    *
    * @return array
    *   valid $params array for dedupe
+   * @throws \CRM_Core_Exception
    */
   public static function formatParams($fields, $ctype) {
     $flat = [];
@@ -306,7 +295,7 @@ class CRM_Dedupe_Finder {
             }
           }
         }
-        if ($table == 'civicrm_phone') {
+        if ($table === 'civicrm_phone') {
           $fixes = [
             'phone' => 'phone_numeric',
           ];
@@ -340,8 +329,6 @@ class CRM_Dedupe_Finder {
    *   -dstName
    *   -weight
    *   -canMerge
-   *
-   * @throws CRM_Core_Exception
    */
   public static function parseAndStoreDupePairs($foundDupes, $cacheKeyString) {
     $cids = [];
index 9e501f35f60c2a07f11f11f03d049543429ea0f0..2e5d26cde7e2a3406a83930eec5c683e81297d70 100644 (file)
@@ -691,11 +691,21 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
    *  If not set explicitly this is calculated but it is preferred that it be set
    *  per comments on isSelected above.
    *
+   * @param int $searchLimit
+   *   Limit on number of contacts to search for duplicates for.
+   *   This means that if the limit is 1000 then only duplicates for the first 1000 contacts
+   *   matching criteria will be found and batchMerged (the number of merges could be less than or greater than 100)
+   *
    * @return array|bool
+   *
+   * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
    */
-  public static function batchMerge($rgid, $gid = NULL, $mode = 'safe', $batchLimit = 1, $isSelected = 2, $criteria = [], $checkPermissions = TRUE, $reloadCacheIfEmpty = NULL) {
+  public static function batchMerge($rgid, $gid = NULL, $mode = 'safe', $batchLimit = 1, $isSelected = 2, $criteria = [], $checkPermissions = TRUE, $reloadCacheIfEmpty = NULL, $searchLimit = 0) {
     $redirectForPerformance = ($batchLimit > 1) ? TRUE : FALSE;
-
+    if ($mode === 'aggressive' && $checkPermissions && !CRM_Core_Permission::check('force merge duplicate contacts')) {
+      throw new CRM_Core_Exception(ts('Insufficient permissions for aggressive mode batch merge'));
+    }
     if (!isset($reloadCacheIfEmpty)) {
       $reloadCacheIfEmpty = (!$redirectForPerformance && $isSelected == 2);
     }
@@ -706,7 +716,7 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
     $dupePairs = self::getDuplicatePairs($rgid, $gid, $reloadCacheIfEmpty, $batchLimit, $isSelected, ($mode == 'aggressive'), $criteria, $checkPermissions);
 
     $cacheParams = [
-      'cache_key_string' => self::getMergeCacheKeyString($rgid, $gid, $criteria, $checkPermissions),
+      'cache_key_string' => self::getMergeCacheKeyString($rgid, $gid, $criteria, $checkPermissions, $searchLimit),
       // @todo stop passing these parameters in & instead calculate them in the merge function based
       // on the 'real' params like $isRespectExclusions $batchLimit and $isSelected.
       'join' => self::getJoinOnDedupeTable(),
@@ -1833,20 +1843,23 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
    * @param int $searchLimit
    *   Limit to searching for matches against this many contacts.
    *
+   * @param int $isForceNewSearch
+   *   Should a new search be forced, bypassing any cache retrieval.
+   *
    * @return array
    *   Array of matches meeting the criteria.
    *
    * @throws \CRM_Core_Exception
    * @throws \CiviCRM_API3_Exception
    */
-  public static function getDuplicatePairs($rule_group_id, $group_id, $reloadCacheIfEmpty, $batchLimit, $isSelected, $includeConflicts = TRUE, $criteria = [], $checkPermissions = TRUE, $searchLimit = 0) {
-    $dupePairs = self::getCachedDuplicateMatches($rule_group_id, $group_id, $batchLimit, $isSelected, $includeConflicts, $criteria, $checkPermissions);
+  public static function getDuplicatePairs($rule_group_id, $group_id, $reloadCacheIfEmpty, $batchLimit, $isSelected, $includeConflicts = TRUE, $criteria = [], $checkPermissions = TRUE, $searchLimit = 0, $isForceNewSearch = 0) {
+    $dupePairs = $isForceNewSearch ? [] : self::getCachedDuplicateMatches($rule_group_id, $group_id, $batchLimit, $isSelected, $includeConflicts, $criteria, $checkPermissions, $searchLimit);
     if (empty($dupePairs) && $reloadCacheIfEmpty) {
       // If we haven't found any dupes, probably cache is empty.
       // Try filling cache and give another try. We don't need to specify include conflicts here are there will not be any
       // until we have done some processing.
       CRM_Core_BAO_PrevNextCache::refillCache($rule_group_id, $group_id, $criteria, $checkPermissions, $searchLimit);
-      return self::getCachedDuplicateMatches($rule_group_id, $group_id, $batchLimit, $isSelected, FALSE, $criteria, $checkPermissions);
+      return self::getCachedDuplicateMatches($rule_group_id, $group_id, $batchLimit, $isSelected, FALSE, $criteria, $checkPermissions, $searchLimit);
     }
     return $dupePairs;
   }
@@ -1859,17 +1872,21 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
    * @param array $criteria
    *   Additional criteria to narrow down the merge group.
    *   Currently we are only supporting the key 'contact' within it.
-   *
    * @param bool $checkPermissions
    *   Respect the users permissions.
+   * @param int $searchLimit
+   *   Number of contacts to seek dupes for (we need this because if
+   *   we change it the results won't be refreshed otherwise. Changing the limit
+   *   from 100 to 1000 SHOULD result in a new dedupe search).
    *
    * @return string
    */
-  public static function getMergeCacheKeyString($rule_group_id, $group_id, $criteria = [], $checkPermissions = TRUE) {
+  public static function getMergeCacheKeyString($rule_group_id, $group_id, $criteria, $checkPermissions, $searchLimit) {
     $contactType = CRM_Dedupe_BAO_RuleGroup::getContactTypeForRuleGroup($rule_group_id);
     $cacheKeyString = "merge_{$contactType}";
     $cacheKeyString .= $rule_group_id ? "_{$rule_group_id}" : '_0';
     $cacheKeyString .= $group_id ? "_{$group_id}" : '_0';
+    $cacheKeyString .= '_' . (int) $searchLimit;
     $cacheKeyString .= !empty($criteria) ? md5(serialize($criteria)) : '_0';
     if ($checkPermissions) {
       $contactID = CRM_Core_Session::getLoggedInContactID();
@@ -2487,12 +2504,13 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
    * @param bool $includeConflicts
    * @param array $criteria
    * @param int $checkPermissions
+   * @param int $searchLimit
    *
    * @return array
    */
-  protected static function getCachedDuplicateMatches($rule_group_id, $group_id, $batchLimit, $isSelected, $includeConflicts, $criteria, $checkPermissions) {
+  protected static function getCachedDuplicateMatches($rule_group_id, $group_id, $batchLimit, $isSelected, $includeConflicts, $criteria, $checkPermissions, $searchLimit = 0) {
     return CRM_Core_BAO_PrevNextCache::retrieve(
-      self::getMergeCacheKeyString($rule_group_id, $group_id, $criteria, $checkPermissions),
+      self::getMergeCacheKeyString($rule_group_id, $group_id, $criteria, $checkPermissions, $searchLimit),
       self::getJoinOnDedupeTable(),
       self::getWhereString($isSelected),
       0, $batchLimit,
index eb096487d0c27c84e4640b1b6b31e0cba8aa202a..09f06ac9cc7aee1d41bfcb315f06962558ff2c35 100644 (file)
@@ -83,7 +83,6 @@ class CRM_Event_BAO_Event extends CRM_Event_DAO_Event {
    * @return CRM_Event_DAO_Event
    */
   public static function add(&$params) {
-    CRM_Utils_System::flushCache();
     $financialTypeId = NULL;
     if (!empty($params['id'])) {
       CRM_Utils_Hook::pre('edit', 'Event', $params['id'], $params);
@@ -133,6 +132,13 @@ class CRM_Event_BAO_Event extends CRM_Event_DAO_Event {
         $params['created_id'] = $session->get('userID');
       }
       $params['created_date'] = date('YmdHis');
+
+      // Clone from template
+      if (!empty($params['template_id'])) {
+        $copy = self::copy($params['template_id']);
+        $params['id'] = $copy->id;
+        unset($params['template_id']);
+      }
     }
 
     $event = self::add($params);
@@ -948,6 +954,7 @@ WHERE civicrm_event.is_active = 1
 
     $blockCopyOfCustomValue = (!empty($params['custom']));
 
+    /** @var \CRM_Event_DAO_Event $copyEvent */
     $copyEvent = CRM_Core_DAO::copyGeneric('CRM_Event_DAO_Event',
       ['id' => $id],
       // since the location is sharable, lets use the same loc_block_id.
index b5b6b6fef0c2d8269d99508e656a3627cc190b53..ece09d61d1eabb66abccaac915b109f6ba226189 100644 (file)
@@ -714,7 +714,7 @@ class CRM_Event_Cart_Form_Checkout_Payment extends CRM_Event_Cart_Form_Cart {
 
     $config = CRM_Core_Config::singleton();
     $default_country = new CRM_Core_DAO_Country();
-    $default_country->iso_code = $config->defaultContactCountry();
+    $default_country->iso_code = CRM_Core_BAO_Country::defaultContactCountry();
     $default_country->find(TRUE);
     $defaults["billing_country_id-{$this->_bltID}"] = $default_country->id;
 
index bd9559bbe2a37bf5ffb9c0d09b1700a624b8b02e..4405a1aaeeac282b517a66c44aab053a933fa290 100644 (file)
@@ -602,6 +602,7 @@ class CRM_Export_BAO_ExportProcessor {
     $queryFields['country']['context'] = 'country';
     $queryFields['world_region']['context'] = 'country';
     $queryFields['state_province']['context'] = 'province';
+    $queryFields['contact_id'] = ['title' => ts('Contact ID'), 'type' => CRM_Utils_Type::T_INT];
     $this->queryFields = $queryFields;
   }
 
index b352f9bb84e092c4d5805e5f35acd695ffeb26dd..cf4111509608bbf7f49c647f3c5b84983b00905d 100644 (file)
@@ -209,11 +209,10 @@ abstract class CRM_Financial_BAO_ExportFormat {
 
     // create activity.
     $subject .= ' ' . ts('Batch') . '[' . $values['title'] . ']';
-    $activityTypes = CRM_Core_PseudoConstant::activityType(TRUE, FALSE, FALSE, 'name');
     $activityParams = [
-      'activity_type_id' => array_search('Export Accounting Batch', $activityTypes),
+      'activity_type_id' => 'Export Accounting Batch',
       'subject' => $subject,
-      'status_id' => 2,
+      'status_id' => 'Completed',
       'activity_date_time' => date('YmdHis'),
       'source_contact_id' => $session->get('userID'),
       'source_record_id' => $values['id'],
@@ -226,8 +225,7 @@ abstract class CRM_Financial_BAO_ExportFormat {
         'upload_date' => date('YmdHis'),
       ],
     ];
-
-    CRM_Activity_BAO_Activity::create($activityParams);
+    civicrm_api3('Activity', 'create', $activityParams);
   }
 
   /**
index 630f95915bc55b36e21e3469a80aec2dc53f6da1..5b641fec44529c9f0c6a867d8f4f0adb052c5ca8 100644 (file)
@@ -162,6 +162,7 @@ class CRM_Financial_BAO_Payment {
         civicrm_api3('Contribution', 'completetransaction', [
           'id' => $contribution['id'],
           'is_post_payment_create' => TRUE,
+          'is_email_receipt' => $params['is_send_contribution_notification'],
         ]);
         // Get the trxn
         $trxnId = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($contribution['id'], 'DESC');
@@ -360,8 +361,6 @@ class CRM_Financial_BAO_Payment {
    * @param $updateStatus
    *   - deprecate this param
    *
-   * @todo  - make this protected once recordAdditionalPayment no longer calls it.
-   *
    * @return CRM_Financial_DAO_FinancialTrxn
    */
   protected static function recordRefundPayment($contributionId, $trxnData, $updateStatus) {
index 36d7afa24fe8cc6b5e3cee3106d823a7fddad431..d03961fb02e19443f53861247a08c3bac066aef2 100644 (file)
@@ -224,8 +224,9 @@ class CRM_Grant_Form_Grant extends CRM_Core_Form {
       ],
     ]);
 
-    if ($this->_context == 'standalone') {
-      $this->addEntityRef('contact_id', ts('Applicant'), ['create' => TRUE], TRUE);
+    $contactField = $this->addEntityRef('contact_id', ts('Applicant'), ['create' => TRUE], TRUE);
+    if ($this->_context != 'standalone') {
+      $contactField->freeze();
     }
   }
 
index d7835714cd1f9789f7bfa27aefa79c92811d8bd9..929be2055159969b8549fe3feb4fe1a5b7d20fc9 100644 (file)
@@ -104,7 +104,7 @@ class CRM_Import_ImportProcessor {
    * @return string
    */
   public function getContactSubType(): string {
-    return $this->contactSubType;
+    return $this->contactSubType ?? '';
   }
 
   /**
@@ -170,6 +170,8 @@ class CRM_Import_ImportProcessor {
   }
 
   /**
+   * Get the contact type for the import.
+   *
    * @return string
    */
   public function getContactType(): string {
@@ -212,9 +214,27 @@ class CRM_Import_ImportProcessor {
   }
 
   /**
+   * Set mapping fields.
+   *
+   * We do a little cleanup here too.
+   *
+   * We ensure that column numbers are set and that the fields are ordered by them.
+   *
+   * This would mean the fields could be loaded unsorted.
+   *
    * @param array $mappingFields
    */
   public function setMappingFields(array $mappingFields) {
+    $i = 0;
+    foreach ($mappingFields as &$mappingField) {
+      if (!isset($mappingField['column_number'])) {
+        $mappingField['column_number'] = $i;
+      }
+      if ($mappingField['column_number'] > $i) {
+        $i = $mappingField['column_number'];
+      }
+      $i++;
+    }
     $this->mappingFields = $this->rekeyBySortedColumnNumbers($mappingFields);
   }
 
@@ -478,4 +498,63 @@ class CRM_Import_ImportProcessor {
     return !empty($this->getValidRelationships()[$key]) ? TRUE : FALSE;
   }
 
+  /**
+   * Get the relevant js for quickform.
+   *
+   * @param int $column
+   *
+   * @return string
+   * @throws \CiviCRM_API3_Exception
+   */
+  public function getQuickFormJSForField($column) {
+    $columnNumbersToHide = [];
+    if ($this->getRelationshipKey($column)) {
+      if (!$this->getWebsiteTypeID($column) && !$this->getLocationTypeID($column)) {
+        $columnNumbersToHide[] = 2;
+      }
+      if (!$this->getFieldName($column)) {
+        $columnNumbersToHide[] = 1;
+      }
+      if (!$this->getPhoneOrIMTypeID($column)) {
+        $columnNumbersToHide[] = 3;
+      }
+    }
+    else {
+      if (!$this->getLocationTypeID($column) && !$this->getWebsiteTypeID($column)) {
+        $columnNumbersToHide[] = 1;
+      }
+      if (!$this->getPhoneOrIMTypeID($column)) {
+        $columnNumbersToHide[] = 2;
+      }
+      $columnNumbersToHide[] = 3;
+    }
+
+    $jsClauses = [];
+    foreach ($columnNumbersToHide as $columnNumber) {
+      $jsClauses[] = $this->getFormName() . "['mapper[$column][" . $columnNumber . "]'].style.display = 'none';";
+    }
+    return empty($jsClauses) ? '' : implode("\n", $jsClauses) . "\n";
+  }
+
+  /**
+   * Get the defaults for the column from the saved mapping.
+   *
+   * @param int $column
+   *
+   * @return array
+   * @throws \CiviCRM_API3_Exception
+   */
+  public function getSavedQuickformDefaultsForColumn($column) {
+    if ($this->getValidRelationshipKey($column)) {
+      if ($this->getWebsiteTypeID($column)) {
+        return [$this->getValidRelationshipKey($column), $this->getFieldName($column), $this->getWebsiteTypeID($column)];
+      }
+      return [$this->getValidRelationshipKey($column), $this->getFieldName($column), $this->getLocationTypeID($column), $this->getPhoneOrIMTypeID($column)];
+    }
+    if ($this->getWebsiteTypeID($column)) {
+      return [$this->getFieldName($column), $this->getWebsiteTypeID($column)];
+    }
+    return [(string) $this->getFieldName($column), $this->getLocationTypeID($column), $this->getPhoneOrIMTypeID($column)];
+  }
+
 }
index d2d6af941ea9a9480943a371ef514369c4ed67b0..6c03b4e9ef0de4dc460b9e6e6bf86d9aeadd561d 100644 (file)
@@ -44,7 +44,8 @@ class CRM_Mailing_Form_Search extends CRM_Core_Form {
       CRM_Core_DAO::getAttribute('CRM_Mailing_DAO_Mailing', 'title')
     );
 
-    CRM_Core_Form_Date::buildDateRange($this, 'mailing', 1, '_from', '_to', ts('From'), FALSE);
+    $dateFieldLabel = ($parent->_sms) ? ts('SMS Date') : ts('Mailing Date');
+    $this->addDatePickerRange('mailing', $dateFieldLabel);
 
     $this->add('text', 'sort_name', ts('Created or Sent by'),
       CRM_Core_DAO::getAttribute('CRM_Contact_DAO_Contact', 'sort_name')
@@ -111,14 +112,20 @@ class CRM_Mailing_Form_Search extends CRM_Core_Form {
   public function postProcess() {
     $params = $this->controller->exportValues($this->_name);
 
-    CRM_Contact_BAO_Query::fixDateValues($params["mailing_relative"], $params['mailing_from'], $params['mailing_to']);
+    if (!empty($params['mailing_relative'])) {
+      list($params['mailing_low'], $params['mailing_high']) = CRM_Utils_Date::getFromTo($params['mailing_relative'], $params['mailing_low'], $params['mailing_high']);
+      unset($params['mailing_relative']);
+    }
+    elseif (!empty($params['mailing_high'])) {
+      $params['mailing_high'] .= ' ' . '23:59:59';
+    }
 
     $parent = $this->controller->getParent();
     if (!empty($params)) {
       $fields = [
         'mailing_name',
-        'mailing_from',
-        'mailing_to',
+        'mailing_low',
+        'mailing_high',
         'sort_name',
         'campaign_id',
         'mailing_status',
@@ -132,16 +139,7 @@ class CRM_Mailing_Form_Search extends CRM_Core_Form {
         if (isset($params[$field]) &&
           !CRM_Utils_System::isNull($params[$field])
         ) {
-          if (in_array($field, [
-            'mailing_from',
-            'mailing_to',
-          ]) && !$params["mailing_relative"]) {
-            $time = ($field == 'mailing_to') ? '235959' : NULL;
-            $parent->set($field, CRM_Utils_Date::processDate($params[$field], $time));
-          }
-          else {
-            $parent->set($field, $params[$field]);
-          }
+          $parent->set($field, $params[$field]);
         }
         else {
           $parent->set($field, NULL);
index a0ae8f5b656ecd48e891a260e3de5921e7fd0676..9440a77bb18419d66abef44bd41a43dc5bb15c94 100644 (file)
@@ -522,7 +522,7 @@ LEFT JOIN  civicrm_contact scheduledContact ON ( $mailing.scheduled_id = schedul
     }
 
     $dateClause1 = $dateClause2 = [];
-    $from = $this->_parent->get('mailing_from');
+    $from = $this->_parent->get('mailing_low');
     if (!CRM_Utils_System::isNull($from)) {
       if ($this->_parent->get('unscheduled')) {
         $dateClause1[] = 'civicrm_mailing.created_date >= %2';
@@ -534,7 +534,7 @@ LEFT JOIN  civicrm_contact scheduledContact ON ( $mailing.scheduled_id = schedul
       $params[2] = [$from, 'String'];
     }
 
-    $to = $this->_parent->get('mailing_to');
+    $to = $this->_parent->get('mailing_high');
     if (!CRM_Utils_System::isNull($to)) {
       if ($this->_parent->get('unscheduled')) {
         $dateClause1[] = ' civicrm_mailing.created_date <= %3 ';
index 46c1f0ddafd8aa2266a2d2d4d4acb53156f1cd2e..2e22a1d836380d137e3231697761c5ed157e9cca 100644 (file)
@@ -255,13 +255,13 @@ class CRM_Member_BAO_Membership extends CRM_Member_DAO_Membership {
    *   (reference ) an assoc array of name/value pairs.
    * @param array $ids
    *   Deprecated parameter The array that holds all the db ids.
-   * @param bool $skipRedirect
-   *
-   * @throws CRM_Core_Exception
    *
    * @return CRM_Member_BAO_Membership|CRM_Core_Error
+   * @throws \CiviCRM_API3_Exception
+   *
+   * @throws CRM_Core_Exception
    */
-  public static function create(&$params, &$ids = [], $skipRedirect = FALSE) {
+  public static function create(&$params, &$ids = []) {
     // always calculate status if is_override/skipStatusCal is not true.
     // giving respect to is_override during import.  CRM-4012
 
@@ -1874,7 +1874,7 @@ INNER JOIN  civicrm_contact contact ON ( contact.id = membership.contact_id AND
           $memParams['contribution_recur_id'] = $contributionRecurID;
         }
         // @todo stop passing $ids - it is empty
-        $membership = self::create($memParams, $ids, FALSE);
+        $membership = self::create($memParams, $ids);
         return array($membership, $renewalMode, $dates);
       }
 
@@ -2048,7 +2048,7 @@ INNER JOIN  civicrm_contact contact ON ( contact.id = membership.contact_id AND
     // Relevant tests in api_v3_ContributionPageTest.
     $memParams['line_item'] = $lineItems;
     // @todo stop passing $ids (membership and userId may be set by this point)
-    $membership = self::create($memParams, $ids, FALSE);
+    $membership = self::create($memParams, $ids);
 
     // not sure why this statement is here, seems quite odd :( - Lobo: 12/26/2010
     // related to: http://forum.civicrm.org/index.php/topic,11416.msg49072.html#msg49072
index a681a449c78e23c9db9c7b831efe04582126facc..d8e0d9b9ea4211ed61f45c617cd84af0a0e5dfd3 100644 (file)
@@ -67,9 +67,9 @@ class CRM_Member_BAO_Query extends CRM_Core_BAO_Query {
       }
 
       //add join date
-      if (!empty($query->_returnProperties['join_date'])) {
-        $query->_select['join_date'] = "civicrm_membership.join_date as join_date";
-        $query->_element['join_date'] = 1;
+      if (!empty($query->_returnProperties['membership_join_date'])) {
+        $query->_select['membership_join_date'] = "civicrm_membership.join_date as membership_join_date";
+        $query->_element['membership_join_date'] = 1;
       }
 
       //add source
@@ -161,12 +161,22 @@ class CRM_Member_BAO_Query extends CRM_Core_BAO_Query {
    * @param CRM_Contact_BAO_Query $query
    */
   public static function whereClauseSingle(&$values, &$query) {
+    if ($query->buildDateRangeQuery($values)) {
+      // @todo - move this to Contact_Query in or near the call to
+      // $this->buildRelativeDateQuery($values);
+      return;
+    }
     list($name, $op, $value, $grouping) = $values;
     switch ($name) {
       case 'member_join_date_low':
       case 'member_join_date_high':
+        Civi::log()->warning(
+          'member_join_date field is deprecated please use membership_join_date field instead',
+          ['civi.tag' => 'deprecated']
+        );
+        $fldName = str_replace(['_low', '_high'], '', $name);
         $query->dateQueryBuilder($values,
-          'civicrm_membership', 'member_join_date', 'join_date',
+          'civicrm_membership', $fldName, 'join_date',
           'Member Since'
         );
         return;
@@ -174,6 +184,10 @@ class CRM_Member_BAO_Query extends CRM_Core_BAO_Query {
       case 'membership_start_date':
       case 'member_start_date_low':
       case 'member_start_date_high':
+        Civi::log()->warning(
+          'member_start_date field is deprecated please use membership_start_date field instead',
+          ['civi.tag' => 'deprecated']
+        );
         $fldName = str_replace(['_low', '_high'], '', $name);
         $query->dateQueryBuilder($values,
           'civicrm_membership', $fldName, 'start_date',
@@ -184,6 +198,10 @@ class CRM_Member_BAO_Query extends CRM_Core_BAO_Query {
       case 'membership_end_date':
       case 'member_end_date_low':
       case 'member_end_date_high':
+        Civi::log()->warning(
+          'member_end_date field is deprecated please use membership_end_date field instead',
+          ['civi.tag' => 'deprecated']
+        );
         $fldName = str_replace(['_low', '_high'], '', $name);
         $query->dateQueryBuilder($values,
           'civicrm_membership', $fldName, 'end_date',
@@ -376,6 +394,7 @@ class CRM_Member_BAO_Query extends CRM_Core_BAO_Query {
         $query->_qill[$grouping][] = $value ? ts("Membership Status Is Overriden") : ts("Membership Status Is NOT Overriden");
         $query->_tables['civicrm_membership'] = $query->_whereTables['civicrm_membership'] = 1;
         return;
+
     }
   }
 
@@ -443,7 +462,7 @@ class CRM_Member_BAO_Query extends CRM_Core_BAO_Query {
         'membership_type' => 1,
         'member_is_test' => 1,
         'member_is_pay_later' => 1,
-        'join_date' => 1,
+        'membership_join_date' => 1,
         'membership_start_date' => 1,
         'membership_end_date' => 1,
         'membership_source' => 1,
@@ -470,12 +489,29 @@ class CRM_Member_BAO_Query extends CRM_Core_BAO_Query {
     return $properties;
   }
 
+  /**
+   * Get the metadata for fields to be included on the grant search form.
+   *
+   * @throws \CiviCRM_API3_Exception
+   */
+  public static function getSearchFieldMetadata() {
+    $fields = [
+      'membership_join_date',
+      'membership_start_date',
+      'membership_end_date',
+    ];
+    $metadata = civicrm_api3('Membership', 'getfields', [])['values'];
+    return array_intersect_key($metadata, array_flip($fields));
+  }
+
   /**
    * Build the search form.
    *
    * @param CRM_Core_Form $form
    */
   public static function buildSearchForm(&$form) {
+    $form->addSearchFieldMetadata(['Membership' => self::getSearchFieldMetadata()]);
+    $form->addFormFieldsFromMetadata();
     $membershipStatus = CRM_Member_PseudoConstant::membershipStatus(NULL, NULL, 'label', FALSE, FALSE);
     $form->add('select', 'membership_status_id', ts('Membership Status'), $membershipStatus, FALSE, [
       'id' => 'membership_status_id',
@@ -493,17 +529,6 @@ class CRM_Member_BAO_Query extends CRM_Core_BAO_Query {
     $form->addElement('text', 'member_source', ts('Source'));
     $form->add('number', 'membership_id', ts('Membership ID'), ['class' => 'four', 'min' => 1]);
 
-    CRM_Core_Form_Date::buildDateRange($form, 'member_join_date', 1, '_low', '_high', ts('From'), FALSE);
-    $form->addElement('hidden', 'member_join_date_range_error');
-
-    CRM_Core_Form_Date::buildDateRange($form, 'member_start_date', 1, '_low', '_high', ts('From'), FALSE);
-    $form->addElement('hidden', 'member_start_date_range_error');
-
-    CRM_Core_Form_Date::buildDateRange($form, 'member_end_date', 1, '_low', '_high', ts('From'), FALSE);
-    $form->addElement('hidden', 'member_end_date_range_error');
-
-    $form->addFormRule(['CRM_Member_BAO_Query', 'formRule'], $form);
-
     $form->addYesNo('membership_is_current_member', ts('Current Member?'), TRUE);
     $form->addYesNo('member_is_primary', ts('Primary Member?'), TRUE);
     $form->addYesNo('member_pay_later', ts('Pay Later?'), TRUE);
@@ -543,27 +568,4 @@ class CRM_Member_BAO_Query extends CRM_Core_BAO_Query {
     }
   }
 
-  /**
-   * Custom form rules.
-   *
-   * @param array $fields
-   * @param array $files
-   * @param CRM_Core_Form $form
-   *
-   * @return bool|array
-   */
-  public static function formRule($fields, $files, $form) {
-    $errors = [];
-
-    if ((empty($fields['member_join_date_low']) || empty($fields['member_join_date_high'])) && (empty($fields['member_start_date_low']) || empty($fields['member_start_date_high'])) && (empty($fields['member_end_date_low']) || empty($fields['member_end_date_high']))) {
-      return TRUE;
-    }
-
-    CRM_Utils_Rule::validDateRange($fields, 'member_join_date', $errors, ts('Member Since'));
-    CRM_Utils_Rule::validDateRange($fields, 'member_start_date', $errors, ts('Start Date'));
-    CRM_Utils_Rule::validDateRange($fields, 'member_end_date', $errors, ts('End Date'));
-
-    return empty($errors) ? TRUE : $errors;
-  }
-
 }
index 59580c356fe69a8fbc071ffd2d696ae8501d034f..d9948efa77c02183ffc035747993dd4fa11b5e8a 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Member/Membership.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:40f3b0813c1e13fab544ae1f8fa2ebb3)
+ * (GenCodeChecksum:97d01bc13256a1dd315a86fb5faea1dc)
  */
 
 /**
@@ -229,7 +229,7 @@ class CRM_Member_DAO_Membership extends CRM_Core_DAO {
             'labelColumn' => 'name',
           ],
         ],
-        'join_date' => [
+        'membership_join_date' => [
           'name' => 'join_date',
           'type' => CRM_Utils_Type::T_DATE,
           'title' => ts('Member Since'),
index 151ac140320108f79249054b5f489e24392bf1fe..bdc9c861101e8bcdd05d732aed3365902efd38a6 100644 (file)
@@ -1162,6 +1162,12 @@ class CRM_Member_Form_Membership extends CRM_Member_Form {
 
     $lineItem = [$this->_priceSetId => []];
 
+    // BEGIN Fix for dev/core/issues/860
+    // Prepare fee block and call buildAmount hook - based on CRM_Price_BAO_PriceSet::buildPriceSet().
+    CRM_Price_BAO_PriceSet::applyACLFinancialTypeStatusToFeeBlock($this->_priceSet['fields']);
+    CRM_Utils_Hook::buildAmount('membership', $this, $this->_priceSet['fields']);
+    // END Fix for dev/core/issues/860
+
     CRM_Price_BAO_PriceSet::processAmount($this->_priceSet['fields'],
       $formValues, $lineItem[$this->_priceSetId], NULL, $this->_priceSetId);
 
index d4067cc897997654405ea234d38a5bbdaedf9fff..2553d1f1fb2af84f67369f7b1d7443bb1675d4c0 100644 (file)
@@ -587,12 +587,12 @@ class CRM_Member_Form_MembershipRenewal extends CRM_Member_Form {
       $membershipSource = $this->_params['membership_source'];
     }
 
-    $isPending = ($this->_params['contribution_status_id'] == 2) ? TRUE : FALSE;
-
+    // @todo Move this into CRM_Member_BAO_Membership::processMembership
+    $pending = ($this->_params['contribution_status_id'] == array_search('Pending', CRM_Contribute_PseudoConstant::contributionStatus())) ? TRUE : FALSE;
     list($membership) = CRM_Member_BAO_Membership::processMembership(
       $this->_contactID, $this->_params['membership_type_id'][1], $isTestMembership,
       $renewalDate, NULL, $customFieldsFormatted, $numRenewTerms, $this->_membershipId,
-      $isPending,
+      $pending,
       $contributionRecurID, $membershipSource, $this->_params['is_pay_later'], CRM_Utils_Array::value('campaign_id',
       $this->_params)
     );
index 8eba67bfa9c7d76d365568febfe240dd125a6696..3d7afe8ffcd6d50cd2a82621249ff62d51be8d7c 100644 (file)
@@ -95,6 +95,8 @@ class CRM_Member_Form_Search extends CRM_Core_Form_Search {
     }
 
     if ($this->_force) {
+      $this->addSearchFieldMetadata(['Membership' => CRM_Member_BAO_Query::getSearchFieldMetadata()]);
+      $this->addFormFieldsFromMetadata();
       $this->postProcess();
       $this->set('force', 0);
     }
@@ -227,8 +229,7 @@ class CRM_Member_Form_Search extends CRM_Core_Form_Search {
     }
 
     $this->_done = TRUE;
-
-    $this->_formValues = $this->controller->exportValues($this->_name);
+    $this->setFormValues();
 
     $this->fixFormValues();
 
@@ -292,17 +293,6 @@ class CRM_Member_Form_Search extends CRM_Core_Form_Search {
     $controller->run();
   }
 
-  /**
-   * Set default values.
-   *
-   * @todo - can this function override be removed?
-   *
-   * @return array
-   */
-  public function setDefaultValues() {
-    return $this->_defaults;
-  }
-
   /**
    * If this search has been forced then see if there are any get values, and if so over-ride the post values.
    *
index 99d6af35a4e6f8585288ed65a9a9989195eb3508..35cc5a6b0988f78f15a6152c5b89085bb4d64ffe 100644 (file)
@@ -212,7 +212,7 @@ class CRM_Member_Form_Task_Batch extends CRM_Member_Form_Task {
     // extend CRM_Event_Form_Task_BatchTest::testSubmit with a data provider to test
     // handling of custom data, specifically checkbox fields.
     $dates = [
-      'join_date',
+      'membership_join_date',
       'membership_start_date',
       'membership_end_date',
     ];
index 7c94dafc070edad45397e4335390ca87776a8885..0189535ece080ffb749dc5c7a7355e1599697125 100644 (file)
@@ -62,7 +62,7 @@ class CRM_Member_Selector_Search extends CRM_Core_Selector_Base implements CRM_C
     'contact_type',
     'sort_name',
     'membership_type',
-    'join_date',
+    'membership_join_date',
     'membership_start_date',
     'membership_end_date',
     'membership_source',
@@ -493,7 +493,7 @@ class CRM_Member_Selector_Search extends CRM_Core_Selector_Base implements CRM_C
         ],
         [
           'name' => ts('Member Since'),
-          'sort' => 'join_date',
+          'sort' => 'membership_join_date',
           'direction' => CRM_Utils_Sort::DESCENDING,
         ],
         [
index 1b3779060efd029774b8d3ff0df36b2f2467cc7b..1859eb7e06f3e26a1a4782720331fe6199d98975 100644 (file)
@@ -82,6 +82,12 @@ class CRM_Pledge_BAO_Query extends CRM_Core_BAO_Query {
       $query->_tables['civicrm_pledge'] = $query->_whereTables['civicrm_pledge'] = 1;
     }
 
+    if (!empty($query->_returnProperties['pledge_end_date'])) {
+      $query->_select['pledge_end_date'] = 'civicrm_pledge.end_date as pledge_end_date';
+      $query->_element['pledge_end_date'] = 1;
+      $query->_tables['civicrm_pledge'] = $query->_whereTables['civicrm_pledge'] = 1;
+    }
+
     if (!empty($query->_returnProperties['pledge_start_date'])) {
       $query->_select['pledge_start_date'] = 'civicrm_pledge.start_date as pledge_start_date';
       $query->_element['pledge_start_date'] = 1;
@@ -239,43 +245,24 @@ class CRM_Pledge_BAO_Query extends CRM_Core_BAO_Query {
   }
 
   /**
-   * @param $values
-   * @param $query
+   * Get where clause for field.
+   *
+   * @todo most of this could be replaced by using metadata.
+   *
+   * @param array $values
+   * @param \CRM_Contact_BAO_Query $query
+   *
+   * @throws \CRM_Core_Exception
    */
   public static function whereClauseSingle(&$values, &$query) {
+    if ($query->buildDateRangeQuery($values)) {
+      // @todo - move this to Contact_Query in or near the call to
+      // $this->buildRelativeDateQuery($values);
+      return;
+    }
     list($name, $op, $value, $grouping, $wildcard) = $values;
 
     switch ($name) {
-      case 'pledge_create_date_low':
-      case 'pledge_create_date_high':
-        // process to / from date
-        $query->dateQueryBuilder($values,
-          'civicrm_pledge', 'pledge_create_date', 'create_date', 'Pledge Made'
-        );
-      case 'pledge_start_date_low':
-      case 'pledge_start_date_high':
-        // process to / from date
-        $query->dateQueryBuilder($values,
-          'civicrm_pledge', 'pledge_start_date', 'start_date', 'Pledge Start Date'
-        );
-        return;
-
-      case 'pledge_end_date_low':
-      case 'pledge_end_date_high':
-        // process to / from date
-        $query->dateQueryBuilder($values,
-          'civicrm_pledge', 'pledge_end_date', 'end_date', 'Pledge End Date'
-        );
-        return;
-
-      case 'pledge_payment_date_low':
-      case 'pledge_payment_date_high':
-        // process to / from date
-        $query->dateQueryBuilder($values,
-          'civicrm_pledge_payment', 'pledge_payment_date', 'scheduled_date', 'Payment Scheduled'
-        );
-        return;
-
       case 'pledge_amount':
       case 'pledge_amount_low':
       case 'pledge_amount_high':
@@ -531,11 +518,27 @@ class CRM_Pledge_BAO_Query extends CRM_Core_BAO_Query {
   public static function getSearchFieldMetadata() {
     $fields = [
       'pledge_status_id',
+      'pledge_start_date',
+      'pledge_end_date',
+      'pledge_create_date',
     ];
     $metadata = civicrm_api3('Pledge', 'getfields', [])['values'];
     return array_intersect_key($metadata, array_flip($fields));
   }
 
+  /**
+   * Get the metadata for fields to be included on the grant search form.
+   *
+   * @throws \CiviCRM_API3_Exception
+   */
+  public static function getPledgePaymentSearchFieldMetadata() {
+    $fields = [
+      'pledge_payment_scheduled_date',
+    ];
+    $metadata = civicrm_api3('PledgePayment', 'getfields', [])['values'];
+    return array_intersect_key($metadata, array_flip($fields));
+  }
+
   /**
    * Build the search for for pledges.
    *
@@ -547,13 +550,8 @@ class CRM_Pledge_BAO_Query extends CRM_Core_BAO_Query {
   public static function buildSearchForm(&$form) {
     // pledge related dates
     $form->addSearchFieldMetadata(['Pledge' => self::getSearchFieldMetadata()]);
+    $form->addSearchFieldMetadata(['PledgePayment' => self::getPledgePaymentSearchFieldMetadata()]);
     $form->addFormFieldsFromMetadata();
-    CRM_Core_Form_Date::buildDateRange($form, 'pledge_start_date', 1, '_low', '_high', ts('From'), FALSE);
-    CRM_Core_Form_Date::buildDateRange($form, 'pledge_end_date', 1, '_low', '_high', ts('From'), FALSE);
-    CRM_Core_Form_Date::buildDateRange($form, 'pledge_create_date', 1, '_low', '_high', ts('From'), FALSE);
-
-    // pledge payment related dates
-    CRM_Core_Form_Date::buildDateRange($form, 'pledge_payment_date', 1, '_low', '_high', ts('From'), FALSE);
 
     $form->addYesNo('pledge_test', ts('Pledge is a Test?'), TRUE);
     $form->add('text', 'pledge_amount_low', ts('From'), ['size' => 8, 'maxlength' => 8]);
index fe6abc9014b7a22588b9981699c21be87d56fc3f..76d0e11dd292c4cd7cc87d086ab06d9984de46a0 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Pledge/Pledge.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:5e5bb725caa46ae10f0c5d039a03c675)
+ * (GenCodeChecksum:a25cc68d8392b1d60d7179ca484b604a)
  */
 
 /**
@@ -420,17 +420,19 @@ class CRM_Pledge_DAO_Pledge extends CRM_Core_DAO {
             'type' => 'Text',
           ],
         ],
-        'start_date' => [
+        'pledge_start_date' => [
           'name' => 'start_date',
           'type' => CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME,
           'title' => ts('Pledge Start Date'),
           'description' => ts('The date the first scheduled pledge occurs.'),
           'required' => TRUE,
           'where' => 'civicrm_pledge.start_date',
+          'export' => TRUE,
           'table_name' => 'civicrm_pledge',
           'entity' => 'Pledge',
           'bao' => 'CRM_Pledge_BAO_Pledge',
           'localizable' => 0,
+          'unique_title' => ts('Payments Start Date'),
           'html' => [
             'type' => 'Select Date',
           ],
@@ -491,16 +493,18 @@ class CRM_Pledge_DAO_Pledge extends CRM_Core_DAO {
             'type' => 'Select Date',
           ],
         ],
-        'end_date' => [
+        'pledge_end_date' => [
           'name' => 'end_date',
           'type' => CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME,
           'title' => ts('Pledge End Date'),
           'description' => ts('Date this pledge finished successfully (total pledge payments equal to or greater than pledged amount).'),
           'where' => 'civicrm_pledge.end_date',
+          'export' => TRUE,
           'table_name' => 'civicrm_pledge',
           'entity' => 'Pledge',
           'bao' => 'CRM_Pledge_BAO_Pledge',
           'localizable' => 0,
+          'unique_title' => ts('Payments Ended Date'),
           'html' => [
             'type' => 'Select Date',
           ],
index 5e1da56ae5f8280d2f433f6ee5e54658b55d5978..879a6fa973d2fb0cd1fd738d36e63ed983995bcc 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Generated from xml/schema/CRM/Pledge/PledgePayment.xml
  * DO NOT EDIT.  Generated by CRM_Core_CodeGen
- * (GenCodeChecksum:7dfb4f8000b79fa8b1abab1de3712fc1)
+ * (GenCodeChecksum:563e2926d00b9fe0c4919bfd9a0a05e7)
  */
 
 /**
@@ -236,6 +236,7 @@ class CRM_Pledge_DAO_PledgePayment extends CRM_Core_DAO {
           'entity' => 'PledgePayment',
           'bao' => 'CRM_Pledge_BAO_PledgePayment',
           'localizable' => 0,
+          'unique_title' => ts('Payment Scheduled'),
           'html' => [
             'type' => 'Select Date',
             'formatType' => 'activityDate',
index ecf8f503e4645e2a62320be59b044a6265667ded..1f735e48af4f46b8b505dffc6d47b97fd9c663ed 100644 (file)
@@ -98,6 +98,10 @@ class CRM_Pledge_Form_Search extends CRM_Core_Form_Search {
     }
 
     if ($this->_force) {
+      // pledge related dates
+      $this->addSearchFieldMetadata(['Pledge' => CRM_Pledge_BAO_Query::getSearchFieldMetadata()]);
+      $this->addSearchFieldMetadata(['PledgePayment' => CRM_Pledge_BAO_Query::getPledgePaymentSearchFieldMetadata()]);
+      $this->addFormFieldsFromMetadata();
       $this->postProcess();
       $this->set('force', 0);
     }
@@ -230,7 +234,7 @@ class CRM_Pledge_Form_Search extends CRM_Core_Form_Search {
 
     $this->_done = TRUE;
 
-    $this->_formValues = $this->controller->exportValues($this->_name);
+    $this->setFormValues();
 
     $this->fixFormValues();
 
@@ -321,19 +325,6 @@ class CRM_Pledge_Form_Search extends CRM_Core_Form_Search {
     $this->addFormRule(['CRM_Pledge_Form_Search', 'formRule']);
   }
 
-  /**
-   * Set the default form values.
-   *
-   *
-   * @return array
-   *   the default array reference
-   */
-  public function setDefaultValues() {
-    $defaults = [];
-    $defaults = $this->_formValues;
-    return $defaults;
-  }
-
   public function fixFormValues() {
     if (!$this->_force) {
       return;
index 04c5a5d3e25c0fee5e4feabb403060af53c5bd13..0c88ab14d9bb459f2eeb3c77879e43548052cb85 100644 (file)
@@ -769,21 +769,18 @@ WHERE li.contribution_id = %1";
           ]);
           unset($updateFinancialItemInfoValues['financialTrxn']);
         }
-        elseif (!empty($updateFinancialItemInfoValues['link-financial-trxn']) && $newFinancialItem->amount != 0) {
+        elseif ($trxn && $newFinancialItem->amount != 0) {
           civicrm_api3('EntityFinancialTrxn', 'create', [
             'entity_id' => $newFinancialItem->id,
             'entity_table' => 'civicrm_financial_item',
             'financial_trxn_id' => $trxn->id,
             'amount' => $newFinancialItem->amount,
           ]);
-          unset($updateFinancialItemInfoValues['link-financial-trxn']);
         }
       }
     }
 
-    // @todo - it may be that trxn_id is always empty - flush out scenarios. Add tests.
-    $trxnId = !empty($trxn->id) ? ['id' => $trxn->id] : [];
-    $lineItemObj->addFinancialItemsOnLineItemsChange(array_merge($requiredChanges['line_items_to_add'], $requiredChanges['line_items_to_resurrect']), $entityID, $entityTable, $contributionId, $trxnId);
+    $lineItemObj->addFinancialItemsOnLineItemsChange(array_merge($requiredChanges['line_items_to_add'], $requiredChanges['line_items_to_resurrect']), $entityID, $entityTable, $contributionId, $trxn->id ?? NULL);
 
     // update participant fee_amount column
     $lineItemObj->updateEntityRecordOnChangeFeeSelection($params, $entityID, $entity);
@@ -842,8 +839,6 @@ WHERE li.contribution_id = %1";
         if ($amountChangeOnTextLineItem !== (float) 0) {
           // calculate the amount difference, considered as financial item amount
           $updateFinancialItemInfoValues['amount'] = $amountChangeOnTextLineItem;
-          // add a flag, later used to link financial trxn and this new financial item
-          $updateFinancialItemInfoValues['link-financial-trxn'] = TRUE;
           if ($previousLineItems[$updateFinancialItemInfoValues['entity_id']]['tax_amount']) {
             $updateFinancialItemInfoValues['tax']['amount'] = $lineItemsToUpdate[$updateFinancialItemInfoValues['entity_id']]['tax_amount'] - $previousLineItems[$updateFinancialItemInfoValues['entity_id']]['tax_amount'];
             $updateFinancialItemInfoValues['tax']['description'] = $this->getSalesTaxTerm();
@@ -1033,13 +1028,14 @@ WHERE li.contribution_id = %1";
    * @param int $entityID
    * @param string $entityTable
    * @param int $contributionID
-   * @param bool $isCreateAdditionalFinancialTrxn
+   * @param bool $trxnID
    *   Is there a change to the total balance requiring additional transactions to be created.
    */
-  protected function addFinancialItemsOnLineItemsChange($lineItemsToAdd, $entityID, $entityTable, $contributionID, $isCreateAdditionalFinancialTrxn) {
+  protected function addFinancialItemsOnLineItemsChange($lineItemsToAdd, $entityID, $entityTable, $contributionID, $trxnID) {
     $updatedContribution = new CRM_Contribute_BAO_Contribution();
     $updatedContribution->id = $contributionID;
     $updatedContribution->find(TRUE);
+    $trxnArray = $trxnID ? ['id' => $trxnID] : NULL;
 
     foreach ($lineItemsToAdd as $priceFieldValueID => $lineParams) {
       $lineParams = array_merge($lineParams, [
@@ -1047,7 +1043,14 @@ WHERE li.contribution_id = %1";
         'entity_id' => $entityID,
         'contribution_id' => $contributionID,
       ]);
-      $this->addFinancialItemsOnLineItemChange($isCreateAdditionalFinancialTrxn, $lineParams, $updatedContribution);
+      $financialTypeChangeTrxnID = $this->addFinancialItemsOnLineItemChange($trxnID, $lineParams, $updatedContribution);
+      $lineObj = CRM_Price_BAO_LineItem::retrieve($lineParams);
+      // insert financial items
+      // ensure entity_financial_trxn table has a linking of it.
+      CRM_Financial_BAO_FinancialItem::add($lineObj, $updatedContribution, NULL, $trxnArray);
+      if (isset($lineObj->tax_amount)) {
+        CRM_Financial_BAO_FinancialItem::add($lineObj, $updatedContribution, TRUE, $trxnArray);
+      }
     }
   }
 
@@ -1253,15 +1256,13 @@ WHERE li.contribution_id = %1";
     $tempFinancialTrxnID = NULL;
     // don't add financial item for cancelled line item
     if ($lineParams['qty'] == 0) {
-      return;
+      return NULL;
     }
     elseif ($isCreateAdditionalFinancialTrxn) {
       // This routine & the return below is super uncomfortable.
-      // I have refactored to here but don't understand how this would be hit
-      // and it is how it would be a good thing, given the odd return below which
-      // does not seem consistent with what is going on.
-      // I'm tempted to add an e-deprecated into it to confirm my suspicion it only exists to
-      // cause mental anguish.
+      // I have refactored to here and it is hit from
+      // testSubmitUnpaidPriceChangeWhileStillPending
+      // but I'm still skeptical it's not covered elsewhere.
       // original comment : add financial item if ONLY financial type is changed
       if ($lineParams['financial_type_id'] != $updatedContribution->financial_type_id) {
         $changedFinancialTypeID = (int) $lineParams['financial_type_id'];
@@ -1279,16 +1280,9 @@ WHERE li.contribution_id = %1";
           'currency' => $updatedContribution->currency,
         ];
         $adjustedTrxn = CRM_Core_BAO_FinancialTrxn::create($adjustedTrxnValues);
-        $tempFinancialTrxnID = ['id' => $adjustedTrxn->id];
+        return $adjustedTrxn->id;
       }
     }
-    $lineObj = CRM_Price_BAO_LineItem::retrieve($lineParams);
-    // insert financial items
-    // ensure entity_financial_trxn table has a linking of it.
-    CRM_Financial_BAO_FinancialItem::add($lineObj, $updatedContribution, NULL, $tempFinancialTrxnID);
-    if (isset($lineObj->tax_amount)) {
-      CRM_Financial_BAO_FinancialItem::add($lineObj, $updatedContribution, TRUE, $tempFinancialTrxnID);
-    }
   }
 
   /**
index 7055bab12f29cf2c54be498084a2eb84f36d796f..c7d9ebe7079ec8f5b958ee4568fc1f964cec60ac 100644 (file)
@@ -1014,19 +1014,9 @@ WHERE  id = %1";
     else {
       $feeBlock = &$form->_priceSet['fields'];
     }
-    if (CRM_Financial_BAO_FinancialType::isACLFinancialTypeStatus()) {
-      foreach ($feeBlock as $key => $value) {
-        foreach ($value['options'] as $k => $options) {
-          if (!CRM_Core_Permission::check('add contributions of type ' . CRM_Contribute_PseudoConstant::financialType($options['financial_type_id']))) {
-            unset($feeBlock[$key]['options'][$k]);
-          }
-        }
-        if (empty($feeBlock[$key]['options'])) {
-          unset($feeBlock[$key]);
-        }
-      }
-    }
-    // call the hook.
+
+    self::applyACLFinancialTypeStatusToFeeBlock($feeBlock);
+    // Call the buildAmount hook.
     CRM_Utils_Hook::buildAmount($component, $form, $feeBlock);
 
     // CRM-14492 Admin price fields should show up on event registration if user has 'administer CiviCRM' permissions
@@ -1080,6 +1070,29 @@ WHERE  id = %1";
     }
   }
 
+  /**
+   * Apply ACLs on Financial Type to the price options in a fee block.
+   *
+   * @param array $feeBlock
+   *   Fee block: array of price fields.
+   *
+   * @return void
+   */
+  public static function applyACLFinancialTypeStatusToFeeBlock(&$feeBlock) {
+    if (CRM_Financial_BAO_FinancialType::isACLFinancialTypeStatus()) {
+      foreach ($feeBlock as $key => $value) {
+        foreach ($value['options'] as $k => $options) {
+          if (!CRM_Core_Permission::check('add contributions of type ' . CRM_Contribute_PseudoConstant::financialType($options['financial_type_id']))) {
+            unset($feeBlock[$key]['options'][$k]);
+          }
+        }
+        if (empty($feeBlock[$key]['options'])) {
+          unset($feeBlock[$key]);
+        }
+      }
+    }
+  }
+
   /**
    * Check the current Membership having end date null.
    *
index 3b92f9b633f4a128091d4a16ad80da7c82d917cd..a1c5d33850c9897e80832f66c75e3511ea756c3d 100644 (file)
@@ -311,7 +311,7 @@ class CRM_Report_Form_Member_ContributionDetail extends CRM_Report_Form {
           'source' => ['title' => ts('Membership Source')],
         ],
         'filters' => [
-          'join_date' => ['operatorType' => CRM_Report_Form::OP_DATE],
+          'membership_join_date' => ['operatorType' => CRM_Report_Form::OP_DATE],
           'membership_start_date' => ['operatorType' => CRM_Report_Form::OP_DATE],
           'membership_end_date' => ['operatorType' => CRM_Report_Form::OP_DATE],
           'owner_membership_id' => [
index cdb100c8f28703ac391929e4ef6bf77e2dcf80a7..92cd8f40e9322f488eef6bb623cec7806e374491 100644 (file)
@@ -115,7 +115,7 @@ class CRM_Report_Form_Member_Detail extends CRM_Report_Form {
           'source' => ['title' => ts('Source')],
         ],
         'filters' => [
-          'join_date' => ['operatorType' => CRM_Report_Form::OP_DATE],
+          'membership_join_date' => ['operatorType' => CRM_Report_Form::OP_DATE],
           'membership_start_date' => ['operatorType' => CRM_Report_Form::OP_DATE],
           'membership_end_date' => ['operatorType' => CRM_Report_Form::OP_DATE],
           'owner_membership_id' => [
index e4fb27ac9b995c02c2dc8d5a6c14486053cd6b33..386150e4bcc549d11034fa48a80ee4c258066ad2 100644 (file)
@@ -595,7 +595,7 @@ GROUP BY    {$this->_aliases['civicrm_contribution']}.currency
             implode(",", $this->_params['status_id_value']);
         }
         $url = CRM_Report_Utils_Report::getNextUrl('member/detail',
-          "reset=1&force=1&join_date_from={$dateStart}&join_date_to={$dateEnd}{$typeUrl}{$statusUrl}",
+          "reset=1&force=1&membership_join_date_from={$dateStart}&membership_join_date_to={$dateEnd}{$typeUrl}{$statusUrl}",
           $this->_absoluteUrl, $this->_id, $this->_drilldownReport
         );
         $row['civicrm_membership_join_date_start'] = CRM_Utils_Date::format($row['civicrm_membership_join_date_start']);
index 1a25d456039c62afeaa7c168845f98ac1d4ff21d..9ab478c0846ae746ae44c57f12c4aaaa89370705 100644 (file)
@@ -100,7 +100,7 @@ class CRM_Report_Form_Membership_Summary extends CRM_Report_Form {
           'membership_type_id' => ['title' => ts('Membership Type')],
         ],
         'filters' => [
-          'join_date' => ['type' => CRM_Utils_Type::T_DATE],
+          'membership_join_date' => ['type' => CRM_Utils_Type::T_DATE],
         ],
       ],
       'civicrm_address' => [
index feb9c6438a103a369505f9eeb991f9ab0e498108..2ff9287b826695a0c7bc0c72eb75cf627bc0907e 100644 (file)
@@ -56,20 +56,26 @@ class CRM_Upgrade_Incremental_SmartGroups {
    */
   public function datePickerConversion($fields) {
     $fieldPossibilities = $relativeFieldNames = [];
-    foreach ($fields as $field) {
-      $fieldPossibilities[] = $field;
-      $fieldPossibilities[] = $field . '_high';
-      $fieldPossibilities[] = $field . '_low';
-    }
     $relativeDateMappings = [
       'activity_date_time' => 'activity',
       'participant_register_date' => 'participant',
       'receive_date' => 'contribution',
       'contribution_cancel_date' => 'contribution_cancel',
+      'membership_join_date' => 'member_join',
+      'membership_start_date' => 'member_start',
+      'membership_end_date' => 'member_end',
+      'pledge_payment_scheduled_date' => 'pledge_payment',
+      'pledge_create_date' => 'pledge_create',
+      'pledge_end_date' => 'pledge_end',
+      'pledge_start_date' => 'pledge_start',
     ];
 
     foreach ($fields as $field) {
       foreach ($this->getSearchesWithField($field) as $savedSearch) {
+        // Only populate field possibilities as we go to convert each field
+        $fieldPossibilities[] = $field;
+        $fieldPossibilities[] = $field . '_high';
+        $fieldPossibilities[] = $field . '_low';
         $formValues = $savedSearch['form_values'];
         $isRelative = $hasRelative = FALSE;
         $relativeFieldName = $field . '_relative';
index 5d535d234f463a243c369341db6a8687b555c624..5fb3adce2c1edacbf6164a2989b88ff721f3ae97 100644 (file)
@@ -79,6 +79,95 @@ class CRM_Upgrade_Incremental_php_FiveEighteen extends CRM_Upgrade_Incremental_B
         ['old' => 'is_override', 'new' => 'member_is_override'],
       ],
     ]);
+    $this->addTask('Remove Foreign Key from civicrm_dashboard on domain_id if exists', 'removeDomainIDFK');
+    $this->addTask('Remove Index on domain_id that might have been randomly added in the same format as FK', 'dropIndex', 'civicrm_dashboard', 'FK_civicrm_dashboard_domain_id');
+    $this->addTask('Re-Create Foreign key between civicrm_dashboard and civicrm_domain correctly', 'recreateDashboardFK');
+    $this->addTask('Update smart groups to rename filters on pledge_payment_date to pledge_payment_scheduled_date', 'updateSmartGroups', [
+      'renameField' => [
+        ['old' => 'pledge_payment_date_relative', 'new' => 'pledge_payment_scheduled_date_relative'],
+        ['old' => 'pledge_payment_date_high', 'new' => 'pledge_payment_scheduled_date_high'],
+        ['old' => 'pledge_payment_date_low', 'new' => 'pledge_payment_scheduled_date_low'],
+        ['old' => 'member_join_date_relative', 'new' => 'membership_join_date_relative'],
+        ['old' => 'member_join_date_high', 'new' => 'membership_join_date_high'],
+        ['old' => 'member_join_date_low', 'new' => 'membership_join_date_low'],
+        ['old' => 'member_start_date_relative', 'new' => 'membership_start_date_relative'],
+        ['old' => 'member_start_date_high', 'new' => 'membership_start_date_high'],
+        ['old' => 'member_start_date_low', 'new' => 'membership_start_date_low'],
+        ['old' => 'member_end_date_relative', 'new' => 'membership_end_date_relative'],
+        ['old' => 'member_end_date_high', 'new' => 'membership_end_date_high'],
+        ['old' => 'member_end_date_low', 'new' => 'membership_end_date_low'],
+      ],
+    ]);
+    $this->addTask('Update smart groups where jcalendar fields have been converted to datepicker', 'updateSmartGroups', [
+      'datepickerConversion' => [
+        'pledge_payment_scheduled_date',
+        'pledge_create_date',
+        'pledge_end_date',
+        'pledge_start_date',
+        'membership_join_date',
+        'membership_end_date',
+        'membership_start_date',
+      ],
+    ]);
+    $this->addTask('Update civicrm_mapping_field and civicrm_uf_field for change in join_date name', 'updateJoinDateMappingUF');
+    $this->addTask('Update civicrm_report_instances for change in filter from join_date to membership_join_date', 'joinDateReportUpdate');
+  }
+
+  public static function removeDomainIDFK() {
+    CRM_Core_BAO_SchemaHandler::safeRemoveFK('civicrm_dashboard', 'FK_civicrm_dashboard_domain_id');
+    return TRUE;
+  }
+
+  public static function recreateDashboardFK() {
+    $sql = CRM_Core_BAO_SchemaHandler::buildForeignKeySQL([
+      'fk_table_name' => 'civicrm_domain',
+      'fk_field_name' => 'id',
+      'name' => 'domain_id',
+      'fk_attributes' => ' ON DELETE CASCADE',
+    ], "\n", " ADD ", 'civicrm_dashboard');
+    CRM_Core_DAO::executeQuery("ALTER TABLE civicrm_dashboard " . $sql, [], TRUE, NULL, FALSE, FALSE);
+    return TRUE;
+  }
+
+  public static function updateJoinDateMappingUF() {
+    CRM_Core_DAO::executeQuery("UPDATE civicrm_mapping_field SET name = 'membership_join_date' WHERE name = 'join_date' AND contact_type = 'Membership'");
+    CRM_Core_DAO::executeQuery("UPDATE civicrm_uf_field SET field_name = 'membership_join_date' WHERE field_name = 'join_date' AND field_type = 'Membership'");
+    return TRUE;
+  }
+
+  public static function joinDateReportUpdate() {
+    $report_templates = ['member/contributionDetail', 'member/Detail', 'member/Summary'];
+    $substitutions = [
+      'join_date_relative' => 'membership_join_date_relative',
+      'join_date_from' => 'membership_join_date_from',
+      'join_date_to' => 'membership_join_date_to',
+    ];
+    foreach ($report_templates as $report_template) {
+      $reports = civicrm_api3('ReportInstance', 'get', [
+        'report_id' => $report_template,
+        'options' => ['limit' => 0],
+      ])['values'];
+      foreach ($reports as $report) {
+        if (!is_array($report['form_values'])) {
+          $form_values = unserialize($report['form_values']);
+        }
+        else {
+          $form_values = $report['form_values'];
+        }
+        foreach ($form_values as $key => $value) {
+          if (array_key_exists($key, $substitutions)) {
+            $form_values[$substitutions[$key]] = $value;
+            unset($form_values[$key]);
+          }
+        }
+        $form_values = serialize($form_values);
+        CRM_Core_DAO::executeQuery("UPDATE civicrm_report_instance SET form_values = %1 WHERE id = %2", [
+          1 => [$form_values, 'String'],
+          2 => [$report['id'], 'Positive'],
+        ]);
+      }
+    }
+    return TRUE;
   }
 
   // public static function taskFoo(CRM_Queue_TaskContext $ctx, ...) {
index 06331b5a2c343b32f68cf200b58ee02b2a4da0e6..718afc457654066932b05e1db3ccfcefa52700bb 100644 (file)
@@ -143,11 +143,13 @@ class CRM_Utils_JS {
    */
   public static function decode($js) {
     $js = trim($js);
-    if ($js[0] === "'" || $js[0] === '"') {
+    $first = substr($js, 0, 1);
+    $last = substr($js, -1);
+    if ($last === $first && ($first === "'" || $first === '"')) {
       // Use a temp placeholder for escaped backslashes
       return str_replace(['\\\\', "\\'", '\\"', '\\&', '\\/', '**backslash**'], ['**backslash**', "'", '"', '&', '/', '\\'], substr($js, 1, -1));
     }
-    if ($js[0] === '{' || $js[0] === '[') {
+    if (($first === '{' && $last === '}') || ($first === '[' && $last === ']')) {
       $obj = self::getRawProps($js);
       foreach ($obj as $idx => $item) {
         $obj[$idx] = self::decode($item);
index dc3b5466f65c278c1d2ca62b1427277c7a7b2589..b52932368805f2c7f3579531484d4921059661bf 100644 (file)
@@ -53,7 +53,6 @@
  * @method static array synchronizeUsers() Create CRM contacts for all existing CMS users.
  * @method static appendCoreResources(\Civi\Core\Event\GenericHookEvent $e) Callback for hook_civicrm_coreResourceList.
  * @method static alterAssetUrl(\Civi\Core\Event\GenericHookEvent $e) Callback for hook_civicrm_getAssetUrl.
- * @method static sendResponse(\Psr\Http\Message\ResponseInterface $response) function to handle RepsoseInterface for delivering HTTP Responses.
  */
 class CRM_Utils_System {
 
index 030b73cc6c80bf3d1c24c286d2537d71876307ad..4fd07e84d0c053332909337efa0468e395da7a4f 100644 (file)
@@ -833,23 +833,6 @@ class CRM_Utils_System_Joomla extends CRM_Utils_System_Base {
     }
   }
 
-  /**
-   * Output code from error function.
-   * @param string $content
-   */
-  public function outputError($content) {
-    if (class_exists('JErrorPage')) {
-      $error = new Exception($content);
-      JErrorPage::render($error);
-    }
-    elseif (class_exists('JError')) {
-      JError::raiseError('CiviCRM-001', $content);
-    }
-    else {
-      parent::outputError($content);
-    }
-  }
-
   /**
    * @inheritDoc
    */
index 36b5ee35df53ca7868aae8e1b67d04bb74426bd5..9e93ad9f4e1fe12df8dd18f8b30f17adbd09254f 100644 (file)
@@ -37,6 +37,8 @@
  * @param array $params
  *
  * @return array
+ * @throws \API_Exception
+ * @throws \Civi\API\Exception\UnauthorizedException
  */
 function civicrm_api3_batch_create($params) {
   return _civicrm_api3_basic_create(_civicrm_api3_get_BAO(__FUNCTION__), $params, 'Batch');
@@ -56,8 +58,10 @@ function _civicrm_api3_batch_create_spec(&$params) {
   $params['entity_table']['api.default'] = "civicrm_batch";
   $params['entity_table']['type'] = CRM_Utils_Type::T_STRING;
   $params['entity_table']['title'] = 'Batch Entity Table - remove?';
-
-  $params['modified_date']['api.default'] = "now";
+  $params['created_id']['api.default'] = 'user_contact_id';
+  $params['created_date']['api.default'] = 'now';
+  $params['modified_id']['api.default'] = 'user_contact_id';
+  $params['modified_date']['api.default'] = 'now';
   $params['status_id']['api.required'] = 1;
   $params['title']['api.required'] = 1;
   $params['status_id']['api.required'] = 1;
@@ -82,6 +86,8 @@ function civicrm_api3_batch_get($params) {
  *
  * @return array
  *   Array of deleted values.
+ * @throws \API_Exception
+ * @throws \Civi\API\Exception\UnauthorizedException
  */
 function civicrm_api3_batch_delete($params) {
   return _civicrm_api3_basic_delete(_civicrm_api3_get_BAO(__FUNCTION__), $params);
index 5bcd435b577954192fe46249528c85846d76078f..f190f3eb3222994ed2e745eb924a73b852553250 100644 (file)
@@ -678,6 +678,7 @@ function civicrm_api3_contribution_repeattransaction($params) {
       'fee_amount',
       'financial_type_id',
       'contribution_status_id',
+      'membership_id',
     ];
     $input = array_intersect_key($params, array_fill_keys($passThroughParams, NULL));
 
index 00992069184055a2c76082a58ee96c3aa41189c9..6762af43c68896d96a527e60446a25b8378e704f 100644 (file)
@@ -107,7 +107,8 @@ function civicrm_api3_dedupe_getstatistics($params) {
     $params['rule_group_id'],
     CRM_Utils_Array::value('group_id', $params),
     CRM_Utils_Array::value('criteria', $params, []),
-    CRM_Utils_Array::value('check_permissions', $params, [])
+    !empty($params['check_permissions']),
+    CRM_Utils_Array::value('search_limit', $params, 0)
   ));
   return civicrm_api3_create_success($stats);
 }
@@ -135,6 +136,11 @@ function _civicrm_api3_dedupe_getstatistics_spec(&$params) {
     'title' => ts('Criteria'),
     'description' => ts('Dedupe search criteria, as parsable by v3 Contact.get api'),
   ];
+  $spec['search_limit'] = [
+    'title' => ts('Number of contacts to look for matches for.'),
+    'type' => CRM_Utils_Type::T_INT,
+    'api.default' => (int) Civi::settings()->get('dedupe_default_limit'),
+  ];
 
 }
 
@@ -150,7 +156,7 @@ function _civicrm_api3_dedupe_getstatistics_spec(&$params) {
  */
 function civicrm_api3_dedupe_getduplicates($params) {
   $options = _civicrm_api3_get_options_from_params($params);
-  $dupePairs = CRM_Dedupe_Merger::getDuplicatePairs($params['rule_group_id'], NULL, TRUE, $options['limit'], FALSE, TRUE, $params['criteria'], CRM_Utils_Array::value('check_permissions', $params), CRM_Utils_Array::value('search_limit', $params, 0));
+  $dupePairs = CRM_Dedupe_Merger::getDuplicatePairs($params['rule_group_id'], NULL, TRUE, $options['limit'], FALSE, TRUE, $params['criteria'], CRM_Utils_Array::value('check_permissions', $params), CRM_Utils_Array::value('search_limit', $params, 0), CRM_Utils_Array::value('is_force_new_search', $params));
   return civicrm_api3_create_success($dupePairs);
 }
 
@@ -178,5 +184,9 @@ function _civicrm_api3_dedupe_getduplicates_spec(&$params) {
     'type' => CRM_Utils_Type::T_INT,
     'api.default' => (int) Civi::settings()->get('dedupe_default_limit'),
   ];
+  $spec['is_force_new_search'] = [
+    'title' => ts('Force a new search, refreshing any cached search'),
+    'type' => CRM_Utils_Type::T_BOOLEAN,
+  ];
 
 }
index b3dbd7adcddc5658a359fdf6978eb76d6c5aff23..f99d9a0430e40dcf1566e4fbe5bbb64a2d009842 100644 (file)
@@ -40,6 +40,8 @@
  *
  * @return array
  *   API result Array.
+ * @throws \CRM_Core_Exception
+ * @throws \API_Exception
  */
 function civicrm_api3_event_create($params) {
   // Required fields for creating an event
@@ -57,13 +59,6 @@ function civicrm_api3_event_create($params) {
     ]);
   }
 
-  // Clone event from template
-  if (!empty($params['template_id']) && empty($params['id'])) {
-    $copy = CRM_Event_BAO_Event::copy($params['template_id']);
-    $params['id'] = $copy->id;
-    unset($params['template_id']);
-  }
-
   _civicrm_api3_event_create_legacy_support_42($params);
   return _civicrm_api3_basic_create(_civicrm_api3_get_BAO(__FUNCTION__), $params, 'Event');
 }
index 86cfa253d27f0c514b90e0bee397023197f34b64..4a4b0eca75f0729fd2e85161aed74c5d67015b2c 100644 (file)
@@ -541,7 +541,7 @@ function civicrm_api3_job_process_batch_merge($params) {
   $gid = CRM_Utils_Array::value('gid', $params);
   $mode = CRM_Utils_Array::value('mode', $params, 'safe');
 
-  $result = CRM_Dedupe_Merger::batchMerge($rule_group_id, $gid, $mode, 1, 2, CRM_Utils_Array::value('criteria', $params, []), CRM_Utils_Array::value('check_permissions', $params));
+  $result = CRM_Dedupe_Merger::batchMerge($rule_group_id, $gid, $mode, 1, 2, CRM_Utils_Array::value('criteria', $params, []), CRM_Utils_Array::value('check_permissions', $params), NULL, $params['search_limit']);
 
   return civicrm_api3_create_success($result, $params);
 }
@@ -571,6 +571,12 @@ function _civicrm_api3_job_process_batch_merge_spec(&$params) {
     'description' => 'let the api decide which contact to retain and which to delete?',
     'type' => CRM_Utils_Type::T_BOOLEAN,
   ];
+  $params['search_limit'] = [
+    'title' => ts('Number of contacts to look for matches for.'),
+    'type' => CRM_Utils_Type::T_INT,
+    'api.default' => (int) Civi::settings()->get('dedupe_default_limit'),
+  ];
+
 }
 
 /**
index c0247f45f02217c4ef86e715843c353d638322f7..cf4bccf62ea8d24abc10e1d8134fea8b7148dda9 100644 (file)
@@ -96,6 +96,18 @@ function civicrm_api3_membership_type_get($params) {
   return $results;
 }
 
+/**
+ * Adjust Metadata for Get action.
+ *
+ * The metadata is used for setting defaults, documentation & validation.
+ *
+ * @param array $params
+ *   Array of parameters determined by getfields.
+ */
+function _civicrm_api3_membership_type_get_spec(&$params) {
+  $params['domain_id']['api.default'] = CRM_Core_Config::domainID();
+}
+
 /**
  * Adjust input for getlist action.
  *
index 6114835fa267a0b2b7a522817a5bb0796cd4b387..4ac10c070fc8714e0f2984ee44ba7ae22b6e8fd8 100644 (file)
@@ -178,6 +178,12 @@ function _civicrm_api3_payment_create_spec(&$params) {
       'title' => ts('Cancel Date'),
       'type' => CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME,
     ],
+    'is_send_contribution_notification' => [
+      'title' => ts('Send out notifications based on contribution status change?'),
+      'description' => ts('Most commonly this equates to emails relating to the contribution, event, etcwhen a payment completes a contribution'),
+      'type' => CRM_Utils_Type::T_BOOLEAN,
+      'api.default' => TRUE,
+    ],
   ];
 }
 
index f71e7a6d74f615491a8648c0ca4ad83d37a24764..2badb46673d68eafbc7d647b88bf289a0f51e82c 100755 (executable)
@@ -144,32 +144,12 @@ if [ -n "$DO_DOWNLOAD" ]; then
     COMPOSER=$(pickcmd composer composer.phar)
     $COMPOSER install
 
-    if has_commands bower karma ; then
+    if has_commands karma ; then
       ## dev dependencies have been installed globally; don't force developer to redownload
       npm install --production
     else
       npm install
     fi
-
-    BOWER=$(pickcmd node_modules/bower/bin/bower bower)
-    if [ -f "$BOWER" ]; then
-      NODE=$(pickcmd node nodejs)
-      BOWER="$NODE $BOWER"
-    fi
-    # Without the force flag, bower may not check for new versions or verify that installed software matches version specified in bower.json
-    # With the force flag, bower will ignore all caches and download all deps.
-    if [ -n "$OFFLINE" ]; then
-      BOWER_OPT=
-    elif [ ! -f "bower_components/.setupsh.ts" ]; then
-      ## First run -- or cleanup from failed run
-      BOWER_OPT=-f
-    elif [ "bower.json" -nt "bower_components/.setupsh.ts" ]; then
-      ## Bower.json has changed since last run
-      BOWER_OPT=-f
-    fi
-    [ -f "bower_components/.setupsh.ts" ] && rm -f "bower_components/.setupsh.ts"
-    $BOWER install $BOWER_OPT
-    touch bower_components/.setupsh.ts
   popd
 fi
 
diff --git a/bower.json b/bower.json
deleted file mode 100644 (file)
index f4159c2..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-{
-  "name": "civicrm",
-  "description": "CiviCRM",
-  "version": "5.0.0",
-  "license": "AGPL-3.0",
-  "private": true,
-  "dependencies": {
-    "angular": "~1.5.0",
-    "angular-file-upload": ">=1.1.5 <=1.1.6",
-    "angular-jquery-dialog-service": "totten/angular-jquery-dialog-service#civicrm",
-    "angular-mocks": "~1.5.0",
-    "angular-route": "~1.5.0",
-    "angular-ui-sortable": "0.12.x",
-    "angular-ui-utils": "0.1.x",
-    "angular-unsavedChanges": "~0.1.1",
-    "qunit": "~1.10",
-    "d3": "3.4.11",
-    "d3-3.5.x": "d3#~3.5.17",
-    "dc-2.1.x": "dc.js#~2.1.8",
-    "crossfilter-1.3.x": "crossfilter2#~1.3.11",
-    "jquery": "civicrm/jquery#1.12.4-civicrm-1.2",
-    "jquery-ui": "~1.12",
-    "lodash-compat": "~3.0",
-    "google-code-prettify": "~1.0",
-    "select2": "colemanw/select2#v3.5-civicrm-1.0",
-    "jquery-validation": "~1.13",
-    "datatables": "~1.10",
-    "jstree": "~3",
-    "ckeditor": "~4.9",
-    "font-awesome": "~4",
-    "angular-bootstrap": "^2.5.0",
-    "angular-sanitize": "~1.5.0",
-    "smartmenus": "~1.1",
-    "phantomjs-polyfill": "^0.0.2",
-    "es6-promise": "^4.2.4",
-    "angular-xeditable": "^0.9.0",
-    "checklist-model": "~1",
-    "css-color-names": "~1"
-  },
-  "resolutions": {
-    "angular": "~1.5.11",
-    "jquery": "1.12.4-civicrm-1.2"
-  }
-}
index f5dfe176013a6710f60c3d8d15f77ed20ae044f6..b298a5c9baebd2f2c26493abea016c50179dc766 100644 (file)
@@ -63,6 +63,7 @@
     "cweagans/composer-patches": "~1.0",
     "pear/log": "1.13.1",
     "katzien/php-mime-type": "2.1.0",
+    "civicrm/composer-downloads-plugin": "^2.0",
     "league/csv": "^9.2"
   },
   "require-dev": {
     ]
   },
   "extra": {
+    "downloads": {
+      "*": {
+        "path": "bower_components/{$id}"
+      },
+      "angular": {
+        "url": "https://github.com/angular/bower-angular/archive/v1.5.11.zip"
+      },
+      "angular-bootstrap": {
+        "url": "https://github.com/angular-ui/bootstrap-bower/archive/2.5.0.zip"
+      },
+      "angular-file-upload": {
+        "url": "https://github.com/nervgh/angular-file-upload/archive/v1.1.6.zip",
+        "ignore": ["examples"]
+      },
+      "angular-jquery-dialog-service": {
+        "url": "https://github.com/totten/angular-jquery-dialog-service/archive/v0.8.0-civicrm-1.0.zip"
+      },
+      "angular-mocks": {
+        "url": "https://github.com/angular/bower-angular-mocks/archive/v1.5.11.zip"
+      },
+      "angular-route": {
+        "url": "https://github.com/angular/bower-angular-route/archive/v1.5.11.zip"
+      },
+      "angular-sanitize": {
+        "url": "https://github.com/angular/bower-angular-sanitize/archive/v1.5.11.zip"
+      },
+      "angular-ui-sortable": {
+        "url": "https://github.com/angular-ui/ui-sortable/archive/v0.12.11.zip"
+      },
+      "angular-ui-utils": {
+        "url": "https://github.com/angular-ui/ui-utils/archive/v0.1.1.zip"
+      },
+      "angular-unsavedChanges": {
+        "url": "https://github.com/facultymatt/angular-unsavedChanges/archive/v0.1.1.zip",
+        "ignore": [".*", "node_modules", "bower_components", "test", "tests"]
+      },
+      "angular-xeditable": {
+        "url": "https://github.com/vitalets/angular-xeditable/archive/0.9.0.zip",
+        "ignore": [".*", "node_modules", "bower_components", "playground", "test", "libs", "docs", "zip", "src", "starter", "Gruntfile.js", "index.html", "jsdoc.conf.json", "package.json"]
+      },
+      "checklist-model": {
+        "url": "https://github.com/vitalets/checklist-model/archive/1.0.0.zip",
+        "ignore": [".*", "node_modules", "docs", "Gruntfile.js", "index.html", "package.json", "test"]
+      },
+      "ckeditor": {
+        "url": "https://github.com/ckeditor/ckeditor-releases/archive/4.9.2.zip"
+      },
+      "crossfilter-1.3.x": {
+        "url": "https://github.com/crossfilter/crossfilter/archive/1.3.14.zip",
+        "ignore": [".*", "node_modules", "bower_components", "src", "lib", "test", "component.json", "package.json", "index.js", "Makefile"]
+      },
+      "crossfilter2": {
+        "url": "https://github.com/crossfilter/crossfilter/archive/1.4.7.zip",
+        "ignore": [".*", "node_modules", "bower_components", "package.json", "index.js", "src", "component.json", "media", "test", "tests"]
+      },
+      "css-color-names": {
+        "url": "https://github.com/bahamas10/css-color-names/archive/v1.0.1.zip"
+      },
+      "d3": {
+        "url": "https://github.com/mbostock-bower/d3-bower/archive/v3.4.11.zip",
+        "ignore": [".DS_Store", ".git", ".gitignore", ".npmignore", ".travis.yml", "Makefile", "bin", "component.json", "index.js", "lib", "node_modules", "package.json", "src", "test"]
+      },
+      "d3-3.5.x": {
+        "url": "https://github.com/mbostock-bower/d3-bower/archive/v3.5.17.zip"
+      },
+      "datatables": {
+        "url": "https://github.com/DataTables/DataTables/archive/1.10.19.zip",
+        "ignore": ["/.*", "examples", "media/unit_testing", "composer.json", "dataTables.jquery.json", "package.json"]
+      },
+      "dc-2.1.x": {
+        "url": "https://github.com/NickQiZhu/dc.js/archive/2.1.10.zip",
+        "ignore": [".*", "style", "web", "*.json", "regression", "scripts", "spec", "src", "docs", "grunt", "Gruntfile.js", "Changelog.md", "welcome.md", "class-hierarchy.dot", "index.js", "CONTRIBUTING.md", "LICENSE_BANNER", "AUTHORS"]
+      },
+      "es6-promise": {
+        "url": "https://github.com/components/es6-promise/archive/v4.2.4.zip"
+      },
+      "font-awesome": {
+        "url": "https://github.com/FortAwesome/Font-Awesome/archive/v4.7.0.zip",
+        "ignore": ["*/.*", "*.json", "src", "*.yml", "Gemfile", "Gemfile.lock", "*.md"]
+      },
+      "google-code-prettify": {
+        "url": "https://github.com/tcollard/google-code-prettify/archive/v1.0.5.zip",
+        "ignore": ["closure-compiler", "js-modules", "tests", "yui-compressor", "Makefile"]
+      },
+      "jquery": {
+        "url": "https://github.com/civicrm/jquery/archive/1.12.4-civicrm-1.2.zip"
+      },
+      "jquery-ui": {
+        "url": "https://github.com/components/jqueryui/archive/1.12.1.zip"
+      },
+      "jquery-validation": {
+        "url": "https://github.com/jquery-validation/jquery-validation/archive/1.13.1.zip",
+        "ignore": [".*", "node_modules", "bower_components", "test", "demo", "lib"]
+      },
+      "jstree": {
+        "url": "https://github.com/vakata/jstree/archive/3.3.8.zip",
+        "ignore": [".*", "docs", "demo", "libs", "node_modules", "test", "libs", "jstree.jquery.json", "gruntfile.js", "package.json", "bower.json", "component.json", "LICENCE-MIT", "README.md"]
+      },
+      "lodash-compat": {
+        "url": "https://github.com/lodash/lodash-compat/archive/3.0.1.zip",
+        "ignore": [".*", "*.log", "*.md", "component.json", "package.json", "node_modules"]
+      },
+      "phantomjs-polyfill": {
+        "url": "https://github.com/conversocial/phantomjs-polyfill/archive/v0.0.2.zip"
+      },
+      "qunit": {
+        "url": "https://github.com/jquery/qunit/archive/v1.10.0.zip"
+      },
+      "select2": {
+        "url": "https://github.com/colemanw/select2/archive/v3.5-civicrm-1.0.zip"
+      },
+      "smartmenus": {
+        "url": "https://github.com/vadikom/smartmenus/archive/1.1.0.zip",
+        "ignore": [".gitignore", "Gruntfile.js"]
+      }
+    },
     "patches": {
       "phpoffice/common": {
         "Fix handling of libxml_disable_entity_loader": "tools/scripts/composer/patches/phpoffice-common-xml-entity-fix.patch"
index db621338827172b2a5bc505edce33ebf358711f7..ab0f88ec85c2107011c5f89251960cf47f8d1db6 100644 (file)
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "ffdac3f93564fe6edb467d3ac43c4869",
+    "content-hash": "195f60bb40e72b390be3211fcc870a38",
     "packages": [
         {
             "name": "civicrm/civicrm-cxn-rpc",
             "description": "CiviCRM installation library",
             "time": "2018-01-23T06:26:55+00:00"
         },
+        {
+            "name": "civicrm/composer-downloads-plugin",
+            "version": "v2.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/civicrm/composer-downloads-plugin.git",
+                "reference": "869b7a12f57b2d912f0ea77d5c33c1518b8de27d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/civicrm/composer-downloads-plugin/zipball/869b7a12f57b2d912f0ea77d5c33c1518b8de27d",
+                "reference": "869b7a12f57b2d912f0ea77d5c33c1518b8de27d",
+                "shasum": ""
+            },
+            "require": {
+                "composer-plugin-api": "^1.1",
+                "php": ">=5.6",
+                "togos/gitignore": "~1.1.1"
+            },
+            "require-dev": {
+                "composer/composer": "~1.0",
+                "friendsofphp/php-cs-fixer": "^2.3",
+                "phpunit/phpunit": "^5.7",
+                "totten/process-helper": "^1.0.1"
+            },
+            "type": "composer-plugin",
+            "extra": {
+                "class": "LastCall\\DownloadsPlugin\\Plugin"
+            },
+            "autoload": {
+                "psr-4": {
+                    "LastCall\\DownloadsPlugin\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Rob Bayliss",
+                    "email": "rob@lastcallmedia.com"
+                },
+                {
+                    "name": "Tim Otten",
+                    "email": "totten@civicrm.org"
+                }
+            ],
+            "description": "Composer plugin for downloading additional files within any composer package.",
+            "time": "2019-08-22T10:56:51+00:00"
+        },
         {
             "name": "cweagans/composer-patches",
             "version": "1.6.5",
             ],
             "time": "2018-10-16T17:24:05+00:00"
         },
+        {
+            "name": "togos/gitignore",
+            "version": "1.1.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/TOGoS/PHPGitIgnore.git",
+                "reference": "32bc0830e4123f670adcbf5ddda5bef362f4f4d4"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/TOGoS/PHPGitIgnore/zipball/32bc0830e4123f670adcbf5ddda5bef362f4f4d4",
+                "reference": "32bc0830e4123f670adcbf5ddda5bef362f4f4d4",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.2"
+            },
+            "require-dev": {
+                "togos/simpler-test": "1.1.1"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "TOGoS_GitIgnore_": "src/main/php/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "description": "Parser for .gitignore (and sparse-checkout, and anything else using the same format) files",
+            "time": "2019-04-19T19:16:58+00:00"
+        },
         {
             "name": "totten/ca-config",
             "version": "v17.05.0",
index 2d6fd480514bafb89f8f8bbdc41988a047f7ae3e..452ea2e50baadd2c3e4deec562876f795bbd0f7f 100644 (file)
@@ -19,6 +19,7 @@ DM_REF_CORE=master
 DM_REF_BACKDROP=1.x-${DM_REF_CORE}
 DM_REF_DRUPAL=7.x-${DM_REF_CORE}
 DM_REF_DRUPAL6=6.x-${DM_REF_CORE}
+DM_REF_DRUPAL8=${DM_REF_CORE}
 DM_REF_JOOMLA=${DM_REF_CORE}
 DM_REF_WORDPRESS=${DM_REF_CORE}
 DM_REF_PACKAGES=${DM_REF_CORE}
index 5471d6ae0dc8fe16524455c3a5a355ee11279746..e1d3541292df91fd203c4ef6aecaf994b22eda54 100755 (executable)
@@ -123,7 +123,7 @@ check_conf()
     echo "Current directory is : $THIS_DIR";
     exit 1
   else
-    export DM_SOURCEDIR DM_GENFILESDIR DM_TMPDIR DM_TARGETDIR DM_PHP DM_RSYNC DM_ZIP DM_VERSION DM_REF_CORE DM_REF_DRUPAL DM_REF_DRUPAL6 DM_REF_JOOMLA DM_REF_WORDPRESS DM_REF_PACKAGES
+    export DM_SOURCEDIR DM_GENFILESDIR DM_TMPDIR DM_TARGETDIR DM_PHP DM_RSYNC DM_ZIP DM_VERSION DM_REF_CORE DM_REF_DRUPAL DM_REF_DRUPAL6 DM_REF_DRUPAL8 DM_REF_JOOMLA DM_REF_WORDPRESS DM_REF_PACKAGES
     if [ ! -d "$DM_SOURCEDIR" ]; then
       echo; echo "ERROR! " DM_SOURCEDIR "directory not found!"; echo "(if you get empty directory name, it might mean that one of necessary variables is not set)"; echo;
     fi
@@ -234,14 +234,14 @@ if [ -d "$DM_SOURCEDIR/drupal" ]; then
   dm_git_checkout "$DM_SOURCEDIR/drupal" "$DM_REF_DRUPAL"
   GENCODE_CMS=Drupal
 fi
+if [ -d "$DM_SOURCEDIR/drupal-8" ]; then
+  dm_git_checkout "$DM_SOURCEDIR/drupal-8" "$DM_REF_DRUPAL8"
+fi
 
-## Get latest dependencies
+## Get fresh dependencies
+[ -d "$DM_SOURCEDIR/vendor" ] && rm -rf $DM_SOURCEDIR/vendor
+[ -d "$DM_SOURCEDIR/bower_components" ] && rm -rf $DM_SOURCEDIR/bower_components
 dm_generate_vendor "$DM_SOURCEDIR"
-## if we already have a bower_compoents dir empty it.
-if [ -d "$DM_SOURCEDIR/bower_components" ]; then
-  rm -rf $DM_SOURCEDIR/bower_components/* 
-fi
-dm_generate_bower "$DM_SOURCEDIR"
 
 # Before anything - regenerate DAOs
 
index 2b12fa2a02fa195fca2485b900cb316719019eba..0ae2ef8c62a21d6981f9197bd00c216305ce9857 100644 (file)
@@ -70,7 +70,7 @@ function dm_install_core() {
   done
 
   dm_install_files "$repo" "$to" {agpl-3.0,agpl-3.0.exception,gpl,CONTRIBUTORS}.txt
-  dm_install_files "$repo" "$to" composer.json composer.lock bower.json package.json Civi.php README.md release-notes.md extension-compatibility.json
+  dm_install_files "$repo" "$to" composer.json composer.lock package.json Civi.php README.md release-notes.md extension-compatibility.json
 
   mkdir -p "$to/sql"
   pushd "$repo" >> /dev/null
@@ -192,17 +192,6 @@ function dm_install_wordpress() {
   dm_preg_edit '/^Version: [0-9\.]+/m' "Version: $DM_VERSION" "$to/civicrm.php"
 }
 
-
-## Generate the "bower_components" folder.
-## usage: dm_generate_bower <repo_path>
-function dm_generate_bower() {
-  local repo="$1"
-  pushd "$repo"
-    ${DM_NPM:-npm} install
-    ${DM_NODE:-node} node_modules/bower/bin/bower install
-  popd
-}
-
 ## Generate the composer "vendor" folder
 ## usage: dm_generate_vendor <repo_path>
 function dm_generate_vendor() {
index 411ede8e3327f7f8ebcb4b40c357e767fe743392..32402bb570d60710d3d702cb07cb5388ac52ca61 100755 (executable)
@@ -21,6 +21,7 @@ env \
   DM_REF_BACKDROP="$DM_REF_BACKDROP" \
   DM_REF_DRUPAL6="$DM_REF_DRUPAL6" \
   DM_REF_DRUPAL="$DM_REF_DRUPAL" \
+  DM_REF_DRUPAL8="$DM_REF_DRUPAL8" \
   DM_REF_JOOMLA="$DM_REF_JOOMLA" \
   DM_REF_WORDPRESS="$DM_REF_WORDPRESS" \
   DM_REF_PACKAGES="$DM_REF_PACKAGES" \
index 27feb512e6763d540991ec1b17d0d4517bfac86f..7c3d51279b367edbebb0b09954465e93985e9ce4 100644 (file)
@@ -37,7 +37,7 @@ $data = array(
     'civicrm-core' => repo("$DM_SOURCEDIR", getenv('DM_REF_CORE')),
     'civicrm-drupal@6.x' => repo("$DM_SOURCEDIR/drupal", getenv('DM_REF_DRUPAL6')),
     'civicrm-drupal@7.x' => repo("$DM_SOURCEDIR/drupal", getenv('DM_REF_DRUPAL')),
-    //'civicrm-drupal@8.x' => repo("$DM_SOURCEDIR/drupal", getenv('DM_REF_DRUPAL8')),
+    'civicrm-drupal-8' => repo("$DM_SOURCEDIR/drupal-8", getenv('DM_REF_DRUPAL8')),
     'civicrm-joomla' => repo("$DM_SOURCEDIR/joomla", getenv('DM_REF_JOOMLA')),
     'civicrm-packages' => repo("$DM_SOURCEDIR/packages", getenv('DM_REF_PACKAGES')),
     'civicrm-wordpress' => repo("$DM_SOURCEDIR/WordPress", getenv('DM_REF_WORDPRESS')),
index ff3acd4cc989ddb8c9e683992fbc83c8d841234c..a35dc34a517c11cb28bf5e47e17c94a6b0872c21 100644 (file)
@@ -26,6 +26,15 @@ Released September 4, 2019
 - **[Credits](release-notes/5.17.0.md#credits)**
 - **[Feedback](release-notes/5.17.0.md#feedback)**
 
+## CiviCRM 5.16.4
+
+Released September 3, 2019
+
+- **[Synopsis](release-notes/5.16.4.md#synopsis)**
+- **[Bugs resolved](release-notes/5.16.4.md#bugs)**
+- **[Credits](release-notes/5.16.4.md#credits)**
+- **[Feedback](release-notes/5.16.4.md#feedback)**
+
 ## CiviCRM 5.16.3
 
 Released August 22, 2019
diff --git a/release-notes/5.16.4.md b/release-notes/5.16.4.md
new file mode 100644 (file)
index 0000000..84d0573
--- /dev/null
@@ -0,0 +1,44 @@
+# CiviCRM 5.16.4
+
+Released September 3, 2019
+
+- **[Synopsis](#synopsis)**
+- **[Bugs resolved](#bugs)**
+- **[Credits](#credits)**
+- **[Feedback](#feedback)**
+
+## <a name="synopsis"></a>Synopsis
+
+| *Does this version...?*                                         |         |
+|:--------------------------------------------------------------- |:-------:|
+| Fix security vulnerabilities?                                   |   no    |
+| Change the database schema?                                     |   no    |
+| Alter the API?                                                  |   no    |
+| **Require attention to configuration options?**                 | **yes** |
+| Fix problems installing or upgrading to a previous version?     |   no    |
+| Introduce features?                                             |   no    |
+| **Fix bugs?**                                                   | **yes** |
+
+## <a name="bugs"></a>Bugs resolved
+
+- **_Smart Groups_: Relative date filters saved incorrectly ([dev/core#1226](https://lab.civicrm.org/dev/core/issues/1226):
+  [#15201](https://github.com/civicrm/civicrm-core/pull/15201), [#15169](https://github.com/civicrm/civicrm-core/pull/15169))**
+
+  On 5.16.0 - 5.16.3, if you saved a smart-group with a relative date
+  filter, it would incorrectly save the configuration.  
+  
+  If you recently created or modified a smart-group with a date-filter, please update it.
+  For discussion of cleanup tips, please use [dev/core#1226](https://lab.civicrm.org/dev/core/issues/1226).
+
+## <a name="credits"></a>Credits
+
+This release was developed by the following authors and reviewers:
+
+Wikimedia Foundation - Eileen McNaughton; Pradeep Nayak; CiviCRM - Tim
+Otten; Australian Greens - Seamus Lee;
+
+## <a name="feedback"></a>Feedback
+
+These release notes are edited by Tim Otten and Andrew Hunt.  If you'd like to
+provide feedback on them, please login to https://chat.civicrm.org/civicrm and
+contact `@agh1`.
index 90668908eabda99a67cb336121fa14c3f1640b25..57c4f6b216ae2c0056af0a015df2fbf79f285d27 100644 (file)
@@ -13,13 +13,13 @@ Released September 4, 2019
 
 | *Does this version...?*                                         |         |
 |:--------------------------------------------------------------- |:-------:|
-| Fix security vulnerabilities?                                   |         |
-| Change the database schema?                                     | **yes** |
-| Alter the API?                                                  | **yes** |
-| Require attention to configuration options?                     |         |
-| Fix problems installing or upgrading to a previous version?     | **yes** |
-| Introduce features?                                             | **yes** |
-| Fix bugs?                                                       | **yes** |
+| Fix security vulnerabilities?                                   |   no    |
+| **Change the database schema?**                                 | **yes** |
+| **Alter the API?**                                              | **yes** |
+| Require attention to configuration options?                     |   no    |
+| **Fix problems installing or upgrading to a previous version?** | **yes** |
+| **Introduce features?**                                         | **yes** |
+| **Fix bugs?**                                                   | **yes** |
 
 ## <a name="features"></a>Features
 
@@ -580,13 +580,15 @@ Released September 4, 2019
   Fixes a call to `languageNegotiationURL` that was causing cv to fail on Drupal
   8 sites.
 
-- **Error when upgrading to 5.16.0
+- **Fail more gracefully when attempting to install on PHP 5.x
   ([dev/drupal#79](https://lab.civicrm.org/dev/drupal/issues/79):
-  [15082](https://github.com/civicrm/civicrm-core/pull/15082))**
+  [15082](https://github.com/civicrm/civicrm-core/pull/15082) and
+  [15089](https://github.com/civicrm/civicrm-core/pull/15089))**
 
   Raises the `MINIMUM_PHP_VERSION` from 5.6 to 7.0 in the metadata because when
   upgrading via drush or Drupal web UI to Civi 5.16+ on PHP 5.6, the Civi
-  class-loader fails to initialize.
+  class-loader fails to initialize.  The installer is also updated to check the
+  PHP version before proceeding with the class loader.
 
 - **Migrate CivicrmHelper::parseUrl() to CRM_Utils_System_Drupal8::parseUrl().
   ([14696](https://github.com/civicrm/civicrm-core/pull/14696))**
@@ -978,6 +980,9 @@ Released September 4, 2019
 - **[NFC] comment fixes, function mis-casing fix
   ([14906](https://github.com/civicrm/civicrm-core/pull/14906))**
 
+- **[NFC] comment
+  fixes([15197](https://github.com/civicrm/civicrm-core/pull/15197))**
+
 ## <a name="credits"></a>Credits
 
 This release was developed by the following code authors:
index 72ec8450c09c9248daacae484902e3dd42b442f5..4654f7fadc1c2fdb93bbec34a6992cf04d428489 100644 (file)
@@ -1402,7 +1402,7 @@ UNLOCK TABLES;
 
 LOCK TABLES `civicrm_uf_field` WRITE;
 /*!40000 ALTER TABLE `civicrm_uf_field` DISABLE KEYS */;
-INSERT INTO `civicrm_uf_field` (`id`, `uf_group_id`, `field_name`, `is_active`, `is_view`, `is_required`, `weight`, `help_post`, `help_pre`, `visibility`, `in_selector`, `is_searchable`, `location_type_id`, `phone_type_id`, `website_type_id`, `label`, `field_type`, `is_reserved`, `is_multi_summary`) VALUES (1,1,'first_name',1,0,1,1,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'First Name','Individual',0,0),(2,1,'last_name',1,0,1,2,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Last Name','Individual',0,0),(3,1,'street_address',1,0,0,3,NULL,NULL,'User and User Admin Only',0,0,1,NULL,NULL,'Street Address (Home)','Contact',0,0),(4,1,'city',1,0,0,4,NULL,NULL,'User and User Admin Only',0,0,1,NULL,NULL,'City (Home)','Contact',0,0),(5,1,'postal_code',1,0,0,5,NULL,NULL,'User and User Admin Only',0,0,1,NULL,NULL,'Postal Code (Home)','Contact',0,0),(6,1,'country',1,0,0,6,NULL,NULL,'User and User Admin Only',0,0,1,NULL,NULL,'Country (Home)','Contact',0,0),(7,1,'state_province',1,0,0,7,NULL,NULL,'User and User Admin Only',0,0,1,NULL,NULL,'State (Home)','Contact',0,0),(8,2,'first_name',1,0,1,1,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'First Name','Individual',0,0),(9,2,'last_name',1,0,1,2,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Last Name','Individual',0,0),(10,2,'email',1,0,1,3,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Email Address','Contact',0,0),(11,3,'participant_status',1,0,1,1,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Participant Status','Participant',1,0),(12,4,'first_name',1,0,1,1,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'First Name','Individual',0,0),(13,4,'last_name',1,0,1,2,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Last Name','Individual',0,0),(14,4,'email',1,0,0,3,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Email Address','Contact',0,0),(15,5,'organization_name',1,0,1,2,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Organization Name','Organization',0,0),(16,5,'email',1,0,0,3,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Email Address','Contact',0,0),(17,6,'household_name',1,0,1,2,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Household Name','Household',0,0),(18,6,'email',1,0,0,3,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Email Address','Contact',0,0),(19,7,'phone',1,0,1,1,NULL,NULL,'User and User Admin Only',0,0,1,1,NULL,'Home Phone','Contact',0,0),(20,7,'phone',1,0,1,2,NULL,NULL,'User and User Admin Only',0,0,1,2,NULL,'Home Mobile','Contact',0,0),(21,7,'street_address',1,0,1,3,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Primary Address','Contact',0,0),(22,7,'city',1,0,1,4,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'City','Contact',0,0),(23,7,'state_province',1,0,1,5,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'State','Contact',0,0),(24,7,'postal_code',1,0,1,6,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Postal Code','Contact',0,0),(25,7,'email',1,0,1,7,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Primary Email','Contact',0,0),(26,7,'group',1,0,1,8,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Groups','Contact',0,0),(27,7,'tag',1,0,1,9,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Tags','Contact',0,0),(28,7,'gender_id',1,0,1,10,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Gender','Individual',0,0),(29,7,'birth_date',1,0,1,11,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Date of Birth','Individual',0,0),(30,8,'street_address',1,0,1,1,NULL,NULL,'User and User Admin Only',0,0,1,NULL,NULL,'Street Address (Home)','Contact',1,0),(31,8,'city',1,0,1,2,NULL,NULL,'User and User Admin Only',0,0,1,NULL,NULL,'City (Home)','Contact',1,0),(32,8,'postal_code',1,0,0,3,NULL,NULL,'User and User Admin Only',0,0,1,NULL,NULL,'Postal Code (Home)','Contact',0,0),(33,8,'country',1,0,0,4,NULL,NULL,'User and User Admin Only',0,0,1,NULL,NULL,'Country (Home)','Contact',0,0),(34,8,'state_province',1,0,0,5,NULL,NULL,'User and User Admin Only',0,0,1,NULL,NULL,'State (Home)','Contact',0,0),(35,9,'organization_name',1,0,1,1,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Organization Name','Organization',0,0),(36,9,'phone',1,0,1,2,NULL,NULL,'User and User Admin Only',0,0,3,1,NULL,'Phone (Main) ','Contact',0,0),(37,9,'email',1,0,1,3,NULL,NULL,'User and User Admin Only',0,0,3,NULL,NULL,'Email (Main) ','Contact',0,0),(38,9,'street_address',1,0,1,4,NULL,NULL,'User and User Admin Only',0,0,3,NULL,NULL,'Street Address','Contact',0,0),(39,9,'city',1,0,1,5,NULL,NULL,'User and User Admin Only',0,0,3,NULL,NULL,'City','Contact',0,0),(40,9,'postal_code',1,0,1,6,NULL,NULL,'User and User Admin Only',0,0,3,NULL,NULL,'Postal Code','Contact',0,0),(41,9,'country',1,0,1,7,NULL,NULL,'User and User Admin Only',0,0,3,NULL,NULL,'Country','Contact',0,0),(42,9,'state_province',1,0,1,8,NULL,NULL,'User and User Admin Only',0,0,3,NULL,NULL,'State/Province','Contact',0,0),(43,10,'financial_type',1,0,0,1,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Financial Type','Contribution',1,0),(44,10,'total_amount',1,0,0,2,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Amount','Contribution',1,0),(45,10,'contribution_status_id',1,0,1,3,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Status','Contribution',1,0),(46,10,'receive_date',1,0,1,4,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Received','Contribution',1,0),(47,10,'contribution_source',1,0,0,5,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Source','Contribution',0,0),(48,10,'payment_instrument',1,0,0,6,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Payment Method','Contribution',0,0),(49,10,'contribution_check_number',1,0,0,7,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Check Number','Contribution',0,0),(50,10,'send_receipt',1,0,0,8,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Send Receipt','Contribution',0,0),(51,10,'invoice_id',1,0,0,9,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Invoice ID','Contribution',0,0),(52,10,'soft_credit',1,0,0,10,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Soft Credit','Contribution',0,0),(53,10,'soft_credit_type',1,0,0,11,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Soft Credit Type','Contribution',0,0),(54,11,'membership_type',1,0,1,1,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Membership Type','Membership',1,0),(55,11,'join_date',1,0,1,2,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Member Since','Membership',1,0),(56,11,'membership_start_date',1,0,0,3,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Start Date','Membership',1,0),(57,11,'membership_end_date',1,0,0,4,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'End Date','Membership',1,0),(58,11,'membership_source',1,0,0,5,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Source','Membership',0,0),(59,11,'send_receipt',1,0,0,6,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Send Receipt','Membership',0,0),(60,11,'financial_type',1,0,0,7,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Financial Type','Membership',1,0),(61,11,'total_amount',1,0,0,8,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Amount','Membership',1,0),(62,11,'receive_date',1,0,1,9,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Received','Membership',1,0),(63,11,'payment_instrument',1,0,0,10,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Payment Method','Membership',0,0),(64,11,'contribution_check_number',1,0,0,11,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Check Number','Membership',0,0),(65,11,'contribution_status_id',1,0,1,12,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Payment Status','Membership',1,0),(66,11,'soft_credit',1,0,0,13,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Soft Credit','Membership',0,0),(67,11,'soft_credit_type',1,0,0,14,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Soft Credit Type','Membership',0,0),(68,12,'first_name',1,0,1,1,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'First Name','Individual',0,0),(69,12,'last_name',1,0,1,2,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Last Name','Individual',0,0),(70,12,'email',1,0,1,3,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Email Address','Contact',0,0),(71,13,'prefix_id',1,0,0,1,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Individual Prefix','Individual',1,0),(72,13,'first_name',1,0,1,2,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'First Name','Individual',1,0),(73,13,'last_name',1,0,1,3,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Last Name','Individual',1,0),(74,13,'email',1,0,0,4,NULL,NULL,'User and User Admin Only',0,0,1,NULL,NULL,'Email Address','Contact',1,0);
+INSERT INTO `civicrm_uf_field` (`id`, `uf_group_id`, `field_name`, `is_active`, `is_view`, `is_required`, `weight`, `help_post`, `help_pre`, `visibility`, `in_selector`, `is_searchable`, `location_type_id`, `phone_type_id`, `website_type_id`, `label`, `field_type`, `is_reserved`, `is_multi_summary`) VALUES (1,1,'first_name',1,0,1,1,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'First Name','Individual',0,0),(2,1,'last_name',1,0,1,2,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Last Name','Individual',0,0),(3,1,'street_address',1,0,0,3,NULL,NULL,'User and User Admin Only',0,0,1,NULL,NULL,'Street Address (Home)','Contact',0,0),(4,1,'city',1,0,0,4,NULL,NULL,'User and User Admin Only',0,0,1,NULL,NULL,'City (Home)','Contact',0,0),(5,1,'postal_code',1,0,0,5,NULL,NULL,'User and User Admin Only',0,0,1,NULL,NULL,'Postal Code (Home)','Contact',0,0),(6,1,'country',1,0,0,6,NULL,NULL,'User and User Admin Only',0,0,1,NULL,NULL,'Country (Home)','Contact',0,0),(7,1,'state_province',1,0,0,7,NULL,NULL,'User and User Admin Only',0,0,1,NULL,NULL,'State (Home)','Contact',0,0),(8,2,'first_name',1,0,1,1,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'First Name','Individual',0,0),(9,2,'last_name',1,0,1,2,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Last Name','Individual',0,0),(10,2,'email',1,0,1,3,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Email Address','Contact',0,0),(11,3,'participant_status',1,0,1,1,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Participant Status','Participant',1,0),(12,4,'first_name',1,0,1,1,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'First Name','Individual',0,0),(13,4,'last_name',1,0,1,2,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Last Name','Individual',0,0),(14,4,'email',1,0,0,3,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Email Address','Contact',0,0),(15,5,'organization_name',1,0,1,2,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Organization Name','Organization',0,0),(16,5,'email',1,0,0,3,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Email Address','Contact',0,0),(17,6,'household_name',1,0,1,2,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Household Name','Household',0,0),(18,6,'email',1,0,0,3,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Email Address','Contact',0,0),(19,7,'phone',1,0,1,1,NULL,NULL,'User and User Admin Only',0,0,1,1,NULL,'Home Phone','Contact',0,0),(20,7,'phone',1,0,1,2,NULL,NULL,'User and User Admin Only',0,0,1,2,NULL,'Home Mobile','Contact',0,0),(21,7,'street_address',1,0,1,3,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Primary Address','Contact',0,0),(22,7,'city',1,0,1,4,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'City','Contact',0,0),(23,7,'state_province',1,0,1,5,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'State','Contact',0,0),(24,7,'postal_code',1,0,1,6,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Postal Code','Contact',0,0),(25,7,'email',1,0,1,7,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Primary Email','Contact',0,0),(26,7,'group',1,0,1,8,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Groups','Contact',0,0),(27,7,'tag',1,0,1,9,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Tags','Contact',0,0),(28,7,'gender_id',1,0,1,10,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Gender','Individual',0,0),(29,7,'birth_date',1,0,1,11,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Date of Birth','Individual',0,0),(30,8,'street_address',1,0,1,1,NULL,NULL,'User and User Admin Only',0,0,1,NULL,NULL,'Street Address (Home)','Contact',1,0),(31,8,'city',1,0,1,2,NULL,NULL,'User and User Admin Only',0,0,1,NULL,NULL,'City (Home)','Contact',1,0),(32,8,'postal_code',1,0,0,3,NULL,NULL,'User and User Admin Only',0,0,1,NULL,NULL,'Postal Code (Home)','Contact',0,0),(33,8,'country',1,0,0,4,NULL,NULL,'User and User Admin Only',0,0,1,NULL,NULL,'Country (Home)','Contact',0,0),(34,8,'state_province',1,0,0,5,NULL,NULL,'User and User Admin Only',0,0,1,NULL,NULL,'State (Home)','Contact',0,0),(35,9,'organization_name',1,0,1,1,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Organization Name','Organization',0,0),(36,9,'phone',1,0,1,2,NULL,NULL,'User and User Admin Only',0,0,3,1,NULL,'Phone (Main) ','Contact',0,0),(37,9,'email',1,0,1,3,NULL,NULL,'User and User Admin Only',0,0,3,NULL,NULL,'Email (Main) ','Contact',0,0),(38,9,'street_address',1,0,1,4,NULL,NULL,'User and User Admin Only',0,0,3,NULL,NULL,'Street Address','Contact',0,0),(39,9,'city',1,0,1,5,NULL,NULL,'User and User Admin Only',0,0,3,NULL,NULL,'City','Contact',0,0),(40,9,'postal_code',1,0,1,6,NULL,NULL,'User and User Admin Only',0,0,3,NULL,NULL,'Postal Code','Contact',0,0),(41,9,'country',1,0,1,7,NULL,NULL,'User and User Admin Only',0,0,3,NULL,NULL,'Country','Contact',0,0),(42,9,'state_province',1,0,1,8,NULL,NULL,'User and User Admin Only',0,0,3,NULL,NULL,'State/Province','Contact',0,0),(43,10,'financial_type',1,0,0,1,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Financial Type','Contribution',1,0),(44,10,'total_amount',1,0,0,2,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Amount','Contribution',1,0),(45,10,'contribution_status_id',1,0,1,3,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Status','Contribution',1,0),(46,10,'receive_date',1,0,1,4,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Received','Contribution',1,0),(47,10,'contribution_source',1,0,0,5,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Source','Contribution',0,0),(48,10,'payment_instrument',1,0,0,6,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Payment Method','Contribution',0,0),(49,10,'contribution_check_number',1,0,0,7,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Check Number','Contribution',0,0),(50,10,'send_receipt',1,0,0,8,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Send Receipt','Contribution',0,0),(51,10,'invoice_id',1,0,0,9,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Invoice ID','Contribution',0,0),(52,10,'soft_credit',1,0,0,10,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Soft Credit','Contribution',0,0),(53,10,'soft_credit_type',1,0,0,11,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Soft Credit Type','Contribution',0,0),(54,11,'membership_type',1,0,1,1,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Membership Type','Membership',1,0),(55,11,'membership_join_date',1,0,1,2,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Member Since','Membership',1,0),(56,11,'membership_start_date',1,0,0,3,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Start Date','Membership',1,0),(57,11,'membership_end_date',1,0,0,4,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'End Date','Membership',1,0),(58,11,'membership_source',1,0,0,5,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Source','Membership',0,0),(59,11,'send_receipt',1,0,0,6,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Send Receipt','Membership',0,0),(60,11,'financial_type',1,0,0,7,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Financial Type','Membership',1,0),(61,11,'total_amount',1,0,0,8,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Amount','Membership',1,0),(62,11,'receive_date',1,0,1,9,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Received','Membership',1,0),(63,11,'payment_instrument',1,0,0,10,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Payment Method','Membership',0,0),(64,11,'contribution_check_number',1,0,0,11,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Check Number','Membership',0,0),(65,11,'contribution_status_id',1,0,1,12,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Payment Status','Membership',1,0),(66,11,'soft_credit',1,0,0,13,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Soft Credit','Membership',0,0),(67,11,'soft_credit_type',1,0,0,14,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Soft Credit Type','Membership',0,0),(68,12,'first_name',1,0,1,1,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'First Name','Individual',0,0),(69,12,'last_name',1,0,1,2,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Last Name','Individual',0,0),(70,12,'email',1,0,1,3,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Email Address','Contact',0,0),(71,13,'prefix_id',1,0,0,1,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Individual Prefix','Individual',1,0),(72,13,'first_name',1,0,1,2,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'First Name','Individual',1,0),(73,13,'last_name',1,0,1,3,NULL,NULL,'User and User Admin Only',0,0,NULL,NULL,NULL,'Last Name','Individual',1,0),(74,13,'email',1,0,0,4,NULL,NULL,'User and User Admin Only',0,0,1,NULL,NULL,'Email Address','Contact',1,0);
 /*!40000 ALTER TABLE `civicrm_uf_field` ENABLE KEYS */;
 UNLOCK TABLES;
 
index a3385f6929edd5a93d52c82bc5d2709e77df5089..6deac7d975d4eb2ed97f3d9ff27d7e057ad4eefa 100644 (file)
   {else}
      <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
       <table class="form-layout-compressed">
-      {if $context eq 'standalone'}
         <tr class="crm-grant-form-block-contact_id">
           <td class="label">{$form.contact_id.label}</td>
           <td>{$form.contact_id.html}</td>
         </tr>
-      {/if}
       <tr class="crm-grant-form-block-status_id">
          <td class="label">{$form.status_id.label}</td>
          <td>{$form.status_id.html}</td>
index c726adf719088e672f4d9c58dfcf25eb6adae783..467e174b938750217cf9d815e4de9d6c35e1f5bb 100644 (file)
  +--------------------------------------------------------------------+
 *}
 <div class="crm-block crm-form-block crm-search-form-block">
-<table class="form-layout">
+  <table class="form-layout">
     <tr>
-        <td>{$form.mailing_name.label} {help id="id-mailing_name"}<br />
-            {$form.mailing_name.html|crmAddClass:big}
-        </td>
-    </tr>
-    <tr>
-        <td>
-      <label>{if $sms eq 1}{ts}SMS Date{/ts}{else}{ts}Mailing Date{/ts}{/if}</label>
-  </td>
+       <td>{$form.mailing_name.label} {help id="id-mailing_name"}<br />
+        {$form.mailing_name.html|crmAddClass:big}
+      </td>
     </tr>
     <tr>
-  {include file="CRM/Core/DateRange.tpl" fieldName="mailing" from='_from' to='_to'}
+      {include file="CRM/Core/DatePickerRangeWrapper.tpl" fieldName="mailing" colspan='2'}
     </tr>
     <tr>
-        <td colspan="1">{$form.sort_name.label} {help id="id-create_sort_name"}<br />
-            {$form.sort_name.html|crmAddClass:big}
-            <br/><br/>
-            <div class="crm-search-form-block-is_archive">
-            {$form.is_archived.label} {help id="is_archived"}<br/>
-            {$form.is_archived.html}
-            </div>
-        </td>
-        {if $form.mailing_status}
-           <td width="100%"><label>{if $sms eq 1}{ts}SMS Status{/ts}{else}{ts}Mailing Status{/ts}{/if}</label><br />
+      <td colspan="1">{$form.sort_name.label} {help id="id-create_sort_name"}<br />
+        {$form.sort_name.html|crmAddClass:big}
+        <br/><br/>
+        <div class="crm-search-form-block-is_archive">
+          {$form.is_archived.label} {help id="is_archived"}<br/>
+          {$form.is_archived.html}
+        </div>
+      </td>
+      {if $form.mailing_status}
+         <td width="100%"><label>{if $sms eq 1}{ts}SMS Status{/ts}{else}{ts}Mailing Status{/ts}{/if}</label><br />
            <div class="listing-box" style="height: auto">
              {foreach from=$form.mailing_status item="mailing_status_val"}
-             <div class="{cycle values="odd-row,even-row"}">
-               {$mailing_status_val.html}
-             </div>
+               <div class="{cycle values="odd-row,even-row"}">
+                 {$mailing_status_val.html}
+               </div>
             {/foreach}
             <div class="{cycle values="odd-row,even-row"}">
               {$form.status_unscheduled.html}
             </div>
-           </div><br />
-           </td>
-        {/if}
+          </div><br />
+        </td>
+      {/if}
     </tr>
 
     {* language *}
     {if $form.language}
       <tr>
         <td>{$form.language.label} {help id="id-language"}<br />
-            {$form.language.html|crmAddClass:big}
+          {$form.language.html|crmAddClass:big}
         </td>
       </tr>
     {/if}
 
     {* campaign in mailing search *}
     {include file="CRM/Campaign/Form/addCampaignToComponent.tpl"
-    campaignContext="componentSearch" campaignTrClass='' campaignTdClass=''}
+      campaignContext="componentSearch" campaignTrClass='' campaignTdClass=''}
 
     <tr>
-        <td>{$form.buttons.html}</td><td colspan="2"></td>
+      <td>{$form.buttons.html}</td><td colspan="2"></td>
     </tr>
-</table>
+  </table>
 </div>
 
 {literal}
index 38d8b78b37773faf1f0b1b183e4df12862420b0b..79592f98597fa5344d305cd5975b364c38082f96 100644 (file)
 </tr>
 
 <tr>
-  <td>
-  {$form.member_source.label}
-    <br />{$form.member_source.html}
-    <p>
-    {$form.member_test.label} {help id="is-test" file="CRM/Contact/Form/Search/Advanced"} &nbsp;{$form.member_test.html}
-    </p>
+  <td>{$form.member_source.label}<br />
+    {$form.member_source.html}
   </td>
   <td>
-    <p>
-    {$form.membership_is_current_member.label}
+    {$form.membership_is_current_member.label}<br />
     {$form.membership_is_current_member.html}
-    </p>
-    <p>
-    {$form.member_is_primary.label}
-    {help id="id-member_is_primary" file="CRM/Member/Form/Search.hlp"}
-    {$form.member_is_primary.html}
-    </p>
-    <p>
-    {$form.member_pay_later.label}&nbsp;{$form.member_pay_later.html}
-    </p>
-    <p>
-      {if $form.member_auto_renew}
-          <label>{$form.member_auto_renew.label}</label>
-          {help id="id-member_auto_renew" file="CRM/Member/Form/Search.hlp"}
-          <br/>
-          {$form.member_auto_renew.html}
-        {/if}
-    </p>
-    <p>
-    {$form.member_is_override.label}
-    {help id="id-member_is_override" file="CRM/Member/Form/Search.hlp"}
-    {$form.member_is_override.html}
-    </p>
   </td>
 </tr>
-
+<tr>
+  <td>{$form.member_test.label} {help id="is-test" file="CRM/Contact/Form/Search/Advanced"} &nbsp;{$form.member_test.html}
+  </td>
+  <td>
+    {$form.member_is_primary.label} {help id="id-member_is_primary" file="CRM/Member/Form/Search.hlp"} {$form.member_is_primary.html}
+  </td>
+</tr>
 <tr><td><label>{$form.membership_id.label}</label> {$form.membership_id.html}</td>
+  <td>{$form.member_pay_later.label}&nbsp;{$form.member_pay_later.html}</td>
 </tr>
-
-<tr><td><label>{ts}Member Since{/ts}</label></td></tr>
 <tr>
-{include file="CRM/Core/DateRange.tpl" fieldName="member_join_date" from='_low' to='_high'}
+  <td>
+    {if $form.member_auto_renew}
+      <label>{$form.member_auto_renew.label}</label>
+      {help id="id-member_auto_renew" file="CRM/Member/Form/Search.hlp"}
+      <br/>
+      {$form.member_auto_renew.html}
+    {/if}
+  </td>
+  <td>{$form.member_is_override.label}{help id="id-member_is_override" file="CRM/Member/Form/Search.hlp"}{$form.member_is_override.html}</td>
 </tr>
-
-<tr><td><label>{ts}Start Date{/ts}</label></td></tr>
 <tr>
-{include file="CRM/Core/DateRange.tpl" fieldName="member_start_date" from='_low' to='_high'}
+  {include file="CRM/Core/DatePickerRangeWrapper.tpl" fieldName="membership_join_date" colspan='2'}
+</tr>
+<tr>
+  {include file="CRM/Core/DatePickerRangeWrapper.tpl" fieldName="membership_start_date" colspan='2'}
 </tr>
-
-<tr><td><label>{ts}End Date{/ts}</label></td></tr>
 <tr>
-{include file="CRM/Core/DateRange.tpl" fieldName="member_end_date" from='_low' to='_high'}
+  {include file="CRM/Core/DatePickerRangeWrapper.tpl" fieldName="membership_end_date" colspan='2'}
 </tr>
 
 {* campaign in membership search *}
index cfd4dc1ff9d4afd9d27c5a2790589d308a69abb5..f33db8e4a6eda8471eccc350fc9fc0fd3b26578c 100644 (file)
@@ -62,7 +62,7 @@
         {$row.membership_type}{if $row.is_test} ({ts}test{/ts}){/if}
         {if $row.owner_membership_id}<br />({ts}by relationship{/ts}){/if}
     </td>
-    <td class="crm-membership-join_date">{$row.join_date|truncate:10:''|crmDate}</td>
+    <td class="crm-membership-join_date">{$row.membership_join_date|truncate:10:''|crmDate}</td>
     <td class="crm-membership-start_date">{$row.membership_start_date|truncate:10:''|crmDate}</td>
     <td class="crm-membership-end_date">{$row.membership_end_date|truncate:10:''|crmDate}</td>
     <td class="crm-membership-source">{$row.membership_source}</td>
index dbd5cc6d6cedabb1b118bb169e739d98b53196cd..9168c503b3476d4c045c29c2c919ad4a3fd57c35 100644 (file)
@@ -25,7 +25,7 @@
 *}
 
 <tr>
-{include file="CRM/Core/DateRange.tpl" fieldName="pledge_payment_date" from='_low' to='_high' label="<label>Payment Scheduled</label>"}
+{include file="CRM/Core/DatePickerRangeWrapper.tpl" fieldName="pledge_payment_scheduled_date" colspan="2"}
 </tr>
 <tr>
   <td colspan="2">
   </td>
 </tr>
 <tr>
-{include file="CRM/Core/DateRange.tpl" fieldName="pledge_create_date" from='_low' to='_high' label="<label>Pledge Made</label>"}
+{include file="CRM/Core/DatePickerRangeWrapper.tpl" fieldName="pledge_create_date" colspan="2"}
 </tr>
 <tr>
-{include file="CRM/Core/DateRange.tpl" fieldName="pledge_start_date" from='_low' to='_high' label="<label>Payments Start Date</label>"}
+{include file="CRM/Core/DatePickerRangeWrapper.tpl" fieldName="pledge_start_date" colspan="2"}
 </tr>
 <tr>
-{include file="CRM/Core/DateRange.tpl" fieldName="pledge_end_date" from='_low' to='_high' label="<label>Payments Ended Date</label>"}
+{include file="CRM/Core/DatePickerRangeWrapper.tpl" fieldName="pledge_end_date" colspan="2"}
 </tr>
 <tr>
   <td>
index 268ce89acf0e0b930e71580a3606f5bf1aa0d27f..ec93545237f8df3010c105b7514587f00f363779 100644 (file)
 *}
 
 {assign var='hideTotal' value=$quickConfig+$noCalcValueDisplay}
+
 <div id="pricesetTotal" class="crm-section section-pricesetTotal">
-  <div class="label
-{if $hideTotal},  hiddenElement{/if}" id="pricelabel">
-    {if ( $extends eq 'Contribution' ) || ( $extends eq 'Membership' )}
-    <span id='amount_sum_label'>{ts}Total Amount{/ts}{else}{ts}Total Fee(s){/ts}</span>
-     {if $isAdditionalParticipants} {ts}for this participant{/ts}{/if}
+  <div id="pricelabel" class="label {if $hideTotal}hiddenElement{/if}">
+    {if ($extends eq 'Contribution') || ($extends eq 'Membership')}
+      <span id='amount_sum_label'>{ts}Total Amount{/ts}</span>
+    {else}
+      <span id='amount_sum_label'>{ts}Total Fee(s){/ts}{if $isAdditionalParticipants} {ts}for this participant{/ts}{/if}</span>
     {/if}
   </div>
-  <div class="content calc-value" {if $hideTotal}style="display:none;"{/if} id="pricevalue" ></div>
+  <div class="content calc-value" {if $hideTotal}style="display:none;"{/if} id="pricevalue"></div>
 </div>
 
 <script type="text/javascript">
@@ -44,25 +45,23 @@ var separator      = '{/literal}{$config->monetaryDecimalPoint}{literal}';
 var symbol         = '{/literal}{$currencySymbol}{literal}';
 var optionSep      = '|';
 
+// Recalculate the total fees based on user selection
 cj("#priceset [price]").each(function () {
+  var elementType = cj(this).attr('type');
+  if (this.tagName == 'SELECT') {
+    elementType = 'select-one';
+  }
 
-    var elementType =  cj(this).attr('type');
-    if ( this.tagName == 'SELECT' ) {
-      elementType = 'select-one';
-    }
-
-    switch(elementType) {
-      case 'checkbox':
-        //event driven calculation of element.
-        cj(this).click(function(){
-          calculateCheckboxLineItemValue(this);
-          display(calculateTotalFee());
-        });
+  switch(elementType) {
+    case 'checkbox':
+      cj(this).click(function(){
         calculateCheckboxLineItemValue(this);
+        display(calculateTotalFee());
+      });
+      calculateCheckboxLineItemValue(this);
       break;
 
     case 'radio':
-      //event driven calculation of element.
       cj(this).click( function(){
         calculateRadioLineItemValue(this);
         display(calculateTotalFee());
@@ -70,32 +69,26 @@ cj("#priceset [price]").each(function () {
       calculateRadioLineItemValue(this);
       break;
 
-  case 'text':
-
-    //event driven calculation of element.
-    cj(this).bind( 'keyup', function() {
-      calculateText(this);
-    }).bind( 'blur' , function() {
+    case 'text':
+      cj(this).bind( 'keyup', function() {
+        calculateText(this);
+      }).bind( 'blur' , function() {
+        calculateText(this);
+      });
+      //default calculation of element.
       calculateText(this);
-    });
-    //default calculation of element.
-    calculateText(this);
-
-    break;
-
-  case 'select-one':
-    calculateSelectLineItemValue(this);
+      break;
 
-    //event driven calculation of element.
-    cj(this).change( function() {
+    case 'select-one':
       calculateSelectLineItemValue(this);
-      display(calculateTotalFee());
-    });
-
-
-    break;
 
+      cj(this).change(function() {
+        calculateSelectLineItemValue(this);
+        display(calculateTotalFee());
+      });
+      break;
   }
+
   display(calculateTotalFee());
 });
 
index a3e05682d586c39937d48c171218054e4cefce3b..83560773dd675662e5dd3bc3c621adfec2a44a24 100644 (file)
     {/if}
     {include file="CRM/Report/Form/ErrorMessage.tpl"}
 </div>
+
+
+{if $outputMode == 'print'}
+  <script type="text/javascript">
+    window.print();
+  </script>
+{/if}
\ No newline at end of file
index 321402ac84bfd21ac3a2f6c98bc224e59b7fc03a..61ba067007e8e4a433f5e2282f560640e7a2ff76 100644 (file)
@@ -24,7 +24,7 @@
  +--------------------------------------------------------------------+
 *}
 {* error.tpl: Display page for fatal errors. Provides complete HTML doc.*}
-{if $config->userFramework != 'Joomla' and $config->userFramework != 'WordPress'}
+{if $config->userFramework != 'WordPress'}
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
 
@@ -89,7 +89,7 @@ function toggle( element ) {
 }
 </script>
 {/literal}
-{if $config->userFramework != 'Joomla' and $config->userFramework != 'WordPress'}
+{if $config->userFramework != 'WordPress'}
 </body>
 </html>
 {/if}
index c6b57a81d6ab53f2b29e87df7fce188953881d1e..0bda3569ccab07f0892184510770f48aec08dbfe 100644 (file)
  */
 class CRM_Batch_BAO_BatchTest extends CiviUnitTestCase {
 
+  /**
+   * Cleanup after test.
+   *
+   * @throws \CRM_Core_Exception
+   */
+  public function tearDown() {
+    parent::tearDown();
+    $this->quickCleanup(['civicrm_batch']);
+  }
+
   /**
    * This test checks that a batch search
    * by payment method works.
@@ -42,6 +52,8 @@ class CRM_Batch_BAO_BatchTest extends CiviUnitTestCase {
    * card and one with payment method check.  After performing a
    * search by payment method for checks, it makes sure that the
    * results are only contributions made by check.
+   *
+   * @throws \CRM_Core_Exception
    */
   public function testGetBatchFinancialItems() {
 
@@ -104,4 +116,15 @@ class CRM_Batch_BAO_BatchTest extends CiviUnitTestCase {
     $this->assertEquals(count($result), 1, 'In line' . __LINE__);
   }
 
+  /**
+   * Test testExportFinancialBatch.
+   */
+  public function testExportFinancialBatch() {
+    $this->createLoggedInUser();
+    $batchParams = ['title' => 'Test Batch'];
+    $batchParams['status_id'] = CRM_Core_PseudoConstant::getKey('CRM_Batch_BAO_Batch', 'status_id', 'Exported');
+    $batch = $this->callAPISuccess('Batch', 'create', $batchParams);
+    CRM_Batch_BAO_Batch::exportFinancialBatch([$batch['id']], 'CSV', NULL);
+  }
+
 }
index 47b0336f193cd8d15e115e6b86ab5afab82ce9dc..9967cebfdecbb27ff72eacb3f7f5789cfeb1d17b 100644 (file)
@@ -289,7 +289,7 @@ class CRM_Batch_Form_EntryTest extends CiviUnitTestCase {
       'field' => [
         1 => [
           'membership_type' => [0 => $this->_orgContactID, 1 => $this->_membershipTypeID],
-          'join_date' => '2013-07-22',
+          'membership_join_date' => '2013-07-22',
           'membership_start_date' => NULL,
           'membership_end_date' => NULL,
           'membership_source' => NULL,
@@ -304,7 +304,7 @@ class CRM_Batch_Form_EntryTest extends CiviUnitTestCase {
         ],
         2 => [
           'membership_type' => [0 => $this->_orgContactID, 1 => $this->_membershipTypeID],
-          'join_date' => '2013-07-03',
+          'membership_join_date' => '2013-07-03',
           'membership_start_date' => '2013-02-03',
           'membership_end_date' => NULL,
           'membership_source' => NULL,
@@ -320,7 +320,7 @@ class CRM_Batch_Form_EntryTest extends CiviUnitTestCase {
         // no join date, coded end date
         3 => [
           'membership_type' => [0 => $this->_orgContactID, 1 => $this->_membershipTypeID],
-          'join_date' => NULL,
+          'membership_join_date' => NULL,
           'membership_start_date' => NULL,
           'membership_end_date' => '2013-12-01',
           'membership_source' => NULL,
index 53dcd83690acdd2d87a4addeb77e4f0daa3a0cd0..e7c04f6dc4476ac1daabf2c21c7242606b29010c 100644 (file)
@@ -239,4 +239,32 @@ class CRM_Case_XMLProcessor_ProcessTest extends CiviCaseTestCase {
     $this->assertEquals($expectedContact, $activity['assignee_contact_id'], 'Activity is not assigned to expected contact');
   }
 
+  /**
+   * Test that locateNameOrLabel does the right things.
+   *
+   * @dataProvider xmlDataProvider
+   */
+  public function testLocateNameOrLabel($xmlString, $expected) {
+    $xmlObj = new SimpleXMLElement($xmlString);
+    $this->assertEquals($expected, $this->process->locateNameOrLabel($xmlObj));
+  }
+
+  /**
+   * Data provider for testLocateNameOrLabel
+   * @return array
+   */
+  public function xmlDataProvider() {
+    return [
+      ['<RelationshipType><name>Senior Services Coordinator</name><creator>1</creator><manager>1</manager></RelationshipType>', 'Senior Services Coordinator'],
+      ['<RelationshipType><name>Senior Services Coordinator</name></RelationshipType>', 'Senior Services Coordinator'],
+      ['<RelationshipType><name>Lion Tamer&#39;s Obituary Writer</name></RelationshipType>', "Lion Tamer's Obituary Writer"],
+      ['<RelationshipType><machineName>BP1234</machineName><name>Banana Peeler</name></RelationshipType>', 'BP1234'],
+      ['<RelationshipType><machineName>BP1234</machineName><name>Banana Peeler</name><creator>1</creator><manager>1</manager></RelationshipType>', 'BP1234'],
+      ['<RelationshipType><machineName>0</machineName><name>Assistant Level 0</name></RelationshipType>', '0'],
+      ['<RelationshipType><machineName></machineName><name>Banana Peeler</name></RelationshipType>', 'Banana Peeler'],
+      // hopefully nobody would do this
+      ['<RelationshipType><machineName>null</machineName><name>Annulled Relationship</name></RelationshipType>', 'null'],
+    ];
+  }
+
 }
index ddde7bc94d6568c9377615616110c3cf9cb42b4c..dde4de9d7f787c0d550bb8a9bca4277a8af54e4f 100644 (file)
@@ -250,7 +250,7 @@ class CRM_Contact_BAO_RelationshipTest extends CiviUnitTestCase {
     ]);
 
     $this->callAPISuccessGetCount('Membership', ['contact_id' => $individualID], 1);
-
+    $this->callAPISuccessGetCount('Membership', ['contact_id' => $organisationID], 1);
     // Disable the relationship & check the membership is removed.
     $relationshipOne['is_active'] = 0;
     $this->callAPISuccess('Relationship', 'create', array_merge($relationshipOne, ['is_active' => 0]));
@@ -274,4 +274,51 @@ class CRM_Contact_BAO_RelationshipTest extends CiviUnitTestCase {
      */
   }
 
+  /**
+   * Test CRM_Contact_BAO_Relationship::add() function directly.
+   *
+   * In general it's preferred to use the Relationship-create api since it does
+   * checks and such before calling add(). There are already some good tests
+   * for the api, but since it does some more business logic after too the
+   * tests might not be checking exactly the same thing.
+   */
+  public function testBAOAdd() {
+    // add a new type
+    $relationship_type_id_1 = $this->relationshipTypeCreate([
+      'name_a_b' => 'Food poison tester is',
+      'name_b_a' => 'Food poison tester for',
+      'contact_type_a' => 'Individual',
+      'contact_type_b' => 'Individual',
+    ]);
+
+    // add some people
+    $contact_id_1 = $this->individualCreate();
+    $contact_id_2 = $this->individualCreate([], 1);
+
+    // create new relationship (using BAO)
+    $params = [
+      'relationship_type_id' => $relationship_type_id_1,
+      'contact_id_a' => $contact_id_1,
+      'contact_id_b' => $contact_id_2,
+    ];
+    $relationshipObj = CRM_Contact_BAO_Relationship::add($params);
+    $this->assertEquals($relationshipObj->relationship_type_id, $relationship_type_id_1);
+    $this->assertEquals($relationshipObj->contact_id_a, $contact_id_1);
+    $this->assertEquals($relationshipObj->contact_id_b, $contact_id_2);
+    $this->assertEquals($relationshipObj->is_active, 1);
+
+    // demonstrate PR 15103 - should fail before the patch and pass after
+    $today = date('Ymd');
+    $params = [
+      'id' => $relationshipObj->id,
+      'end_date' => $today,
+    ];
+    $relationshipObj = CRM_Contact_BAO_Relationship::add($params);
+    $this->assertEquals($relationshipObj->relationship_type_id, $relationship_type_id_1);
+    $this->assertEquals($relationshipObj->contact_id_a, $contact_id_1);
+    $this->assertEquals($relationshipObj->contact_id_b, $contact_id_2);
+    $this->assertEquals($relationshipObj->is_active, 1);
+    $this->assertEquals($relationshipObj->end_date, $today);
+  }
+
 }
index 52965533db0bbc5faf522c909afaeaed935b3b66..01b45fc6f0fff87cbbc3e9f3ef2a8e43db740efc 100644 (file)
@@ -202,6 +202,30 @@ class CRM_Contact_BAO_SavedSearchTest extends CiviUnitTestCase {
     $this->checkArrayEquals($result['relative_dates'], $expectedResult);
   }
 
+  /**
+   * Test if change log relative dates are stored correctly
+   * in civicrm_saved_search table.
+   */
+  public function testRelativeDateChangeLog() {
+    $savedSearch = new CRM_Contact_BAO_SavedSearch();
+    $formValues = [
+      'operator' => 'AND',
+      'log_date_relative' => 'this.month',
+      'radio_ts' => 'ts_all',
+    ];
+    $queryParams = [];
+    CRM_Contact_BAO_SavedSearch::saveRelativeDates($queryParams, $formValues);
+    CRM_Contact_BAO_SavedSearch::saveSkippedElement($queryParams, $formValues);
+    $savedSearch->form_values = serialize($queryParams);
+    $savedSearch->save();
+
+    $result = CRM_Contact_BAO_SavedSearch::getFormValues(CRM_Core_DAO::singleValueQuery('SELECT LAST_INSERT_ID()'));
+    $expectedResult = [
+      'log' => 'this.month',
+    ];
+    $this->checkArrayEquals($result['relative_dates'], $expectedResult);
+  }
+
   /**
    * Test relative dates
    *
index 88cfdd1b9737fddf4bdddda64c611512ebdf971f..50ebd39fcb30099c2cd2f22ea4815032500b22a3 100644 (file)
@@ -166,17 +166,19 @@ class CRM_Contact_Import_Form_MapFieldTest extends CiviUnitTestCase {
    *
    * @param array $fieldSpec
    * @param string $expectedJS
+   * @param array $expectedDefaults
    *
    * @throws \CRM_Core_Exception
    * @throws \CiviCRM_API3_Exception
    */
-  public function testLoadSavedMapping($fieldSpec, $expectedJS) {
+  public function testLoadSavedMapping($fieldSpec, $expectedJS, $expectedDefaults) {
     $this->setUpMapFieldForm();
 
     $mapping = $this->callAPISuccess('Mapping', 'create', ['name' => 'my test']);
     $this->callAPISuccess('MappingField', 'create', array_merge(['mapping_id' => $mapping['id']], $fieldSpec));
     $result = $this->loadSavedMapping($this->form, $mapping['id'], $fieldSpec['column_number']);
     $this->assertEquals($expectedJS, $result['js']);
+    $this->assertEquals($expectedDefaults, $result['defaults']);
   }
 
   /**
@@ -288,14 +290,34 @@ class CRM_Contact_Import_Form_MapFieldTest extends CiviUnitTestCase {
         "document.forms.MapField['mapper[1][1]'].style.display = 'none';
 document.forms.MapField['mapper[1][2]'].style.display = 'none';
 document.forms.MapField['mapper[1][3]'].style.display = 'none';\n",
+        ['mapper[1]' => ['first_name', 0, NULL]],
       ],
       [
         ['name' => 'Phone', 'contact_type' => 'Individual', 'column_number' => 8, 'phone_type_id' => 1, 'location_type_id' => 2],
         "document.forms.MapField['mapper[8][3]'].style.display = 'none';\n",
+        ['mapper[8]' => ['phone', 2, 1]],
       ],
       [
-        ['name' => 'Phone', 'contact_type' => 'Individual', 'column_number' => 0, 'im_provider_id' => 1, 'location_type_id' => 2],
+        ['name' => 'IM Screen Name', 'contact_type' => 'Individual', 'column_number' => 0, 'im_provider_id' => 1, 'location_type_id' => 2],
         "document.forms.MapField['mapper[0][3]'].style.display = 'none';\n",
+        ['mapper[0]' => ['im', 2, 1]],
+      ],
+      [
+        ['name' => 'Website', 'contact_type' => 'Individual', 'column_number' => 0, 'website_type_id' => 1],
+        "document.forms.MapField['mapper[0][2]'].style.display = 'none';
+document.forms.MapField['mapper[0][3]'].style.display = 'none';\n",
+        ['mapper[0]' => ['url', 1]],
+      ],
+      [
+        // Yes, the relationship mapping really does use url whereas non relationship uses website because... legacy
+        ['name' => 'Url', 'contact_type' => 'Individual', 'column_number' => 0, 'website_type_id' => 1, 'relationship_type_id' => 1, 'relationship_direction' => 'a_b'],
+        "document.forms.MapField['mapper[0][3]'].style.display = 'none';\n",
+        ['mapper[0]' => ['1_a_b', 'url', 1]],
+      ],
+      [
+        ['name' => 'Phone', 'contact_type' => 'Individual', 'column_number' => 0, 'phone_type_id' => 1, 'relationship_type_id' => 1, 'relationship_direction' => 'b_a'],
+        '',
+        ['mapper[0]' => ['1_b_a', 'phone', 'Primary', 1]],
       ],
     ];
   }
@@ -315,15 +337,10 @@ document.forms.MapField['mapper[1][3]'].style.display = 'none';\n",
    * @throws \CiviCRM_API3_Exception
    */
   protected function loadSavedMapping($form, $mappingID, $columnNumber) {
-    list($mappingName, $mappingContactType, $mappingLocation, $mappingPhoneType, $mappingImProvider, $mappingRelation, $mappingOperator, $mappingValue, $mappingWebsiteType) = CRM_Core_BAO_Mapping::getMappingFields($mappingID, TRUE);
+    list($mappingName) = CRM_Core_BAO_Mapping::getMappingFields($mappingID, TRUE);
 
     //get loaded Mapping Fields
     $mappingName = CRM_Utils_Array::value(1, $mappingName);
-    $mappingLocation = CRM_Utils_Array::value(1, $mappingLocation);
-    $mappingPhoneType = CRM_Utils_Array::value(1, $mappingPhoneType);
-    $mappingImProvider = CRM_Utils_Array::value(1, $mappingImProvider);
-    $mappingRelation = CRM_Utils_Array::value(1, $mappingRelation);
-    $mappingWebsiteType = CRM_Utils_Array::value(1, $mappingWebsiteType);
     $defaults = [];
 
     $js = '';
@@ -335,8 +352,9 @@ document.forms.MapField['mapper[1][3]'].style.display = 'none';\n",
     $processor->setMappingID($mappingID);
     $processor->setFormName('document.forms.MapField');
     $processor->setMetadata($this->getContactImportMetadata());
+    $processor->setContactTypeByConstant(CRM_Import_Parser::CONTACT_INDIVIDUAL);
 
-    $return = $form->loadSavedMapping($processor, $mappingName, $columnNumber, $mappingRelation, $mappingWebsiteType, $mappingLocation, $defaults, $js, $hasColumnNames, $dataPatterns, $columnPatterns);
+    $return = $form->loadSavedMapping($processor, $mappingName, $columnNumber, $defaults, $js, $hasColumnNames, $dataPatterns, $columnPatterns);
     return ['defaults' => $return[0], 'js' => $return[1]];
   }
 
index 22325812f5b1d2a84f384824d9f0f0ca8001179b..92619e0480375535085ab215de17088e8b3f315e 100644 (file)
@@ -463,6 +463,32 @@ class CRM_Contact_Import_Parser_ContactTest extends CiviUnitTestCase {
     $this->callAPISuccess('Contact', 'delete', ['id' => $contact['id']]);
   }
 
+  /**
+   * Test importing 2 phones of different types.
+   *
+   * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
+   */
+  public function testImportTwoPhonesDifferentTypes() {
+    $processor = new CRM_Import_ImportProcessor();
+    $processor->setContactType('Individual');
+    $processor->setMappingFields(
+      [
+        ['name' => 'first_name'],
+        ['name' => 'last_name'],
+        ['name' => 'email'],
+        ['name' => 'phone', 'location_type_id' => 1, 'phone_type_id' => 2],
+        ['name' => 'phone', 'location_type_id' => 1, 'phone_type_id' => 1],
+      ]
+    );
+    $importer = $processor->getImporterObject();
+    $fields = ['First Name', 'new last name', 'bob@example.com', '1234', '5678'];
+    $importer->import(CRM_Import_Parser::DUPLICATE_UPDATE, $fields);
+    $contact = $this->callAPISuccessGetSingle('Contact', ['last_name' => 'new last name']);
+    $phones = $this->callAPISuccess('Phone', 'get', ['contact_id' => $contact['id']])['values'];
+    $this->assertCount(2, $phones);
+  }
+
   /**
    * Test that the import parser adds the address to the primary location.
    *
index f5dc72b4b8b1ab6512373caec5326b41cf932299..ba369748cd0cb480e42b30e111923d44b7a1a122 100644 (file)
@@ -34,7 +34,7 @@ class CRM_Core_BAO_UFFieldTest extends CiviUnitTestCase {
         'field_type' => 'Participant',
       ],
       [
-        'field_name' => 'join_date',
+        'field_name' => 'membership_join_date',
         'field_type' => 'Membership',
       ],
       [
@@ -65,7 +65,7 @@ class CRM_Core_BAO_UFFieldTest extends CiviUnitTestCase {
     $this->assertEquals('participant_role', $fields['Participant']['participant_role']['name']);
 
     // already used
-    $this->assertFalse(isset($fields['Membership']['join_date']));
+    $this->assertFalse(isset($fields['Membership']['membership_join_date']));
     $this->assertEquals('end_date', $fields['Membership']['membership_end_date']['name']);
 
     // already used
@@ -130,7 +130,7 @@ class CRM_Core_BAO_UFFieldTest extends CiviUnitTestCase {
     $this->assertEquals('participant_note', $fields['Participant']['participant_note']['name']);
     $this->assertEquals('participant_role', $fields['Participant']['participant_role']['name']);
 
-    $this->assertEquals('join_date', $fields['Membership']['join_date']['name']);
+    $this->assertEquals('join_date', $fields['Membership']['membership_join_date']['name']);
     $this->assertEquals('end_date', $fields['Membership']['membership_end_date']['name']);
 
     $this->assertEquals('activity_date_time', $fields['Activity']['activity_date_time']['name']);
@@ -167,7 +167,7 @@ class CRM_Core_BAO_UFFieldTest extends CiviUnitTestCase {
     $this->assertEquals('Participant', $fields['participant_note']['field_type']);
     $this->assertEquals('Participant', $fields['participant_role']['field_type']);
 
-    $this->assertEquals('Membership', $fields['join_date']['field_type']);
+    $this->assertEquals('Membership', $fields['membership_join_date']['field_type']);
     $this->assertEquals('Membership', $fields['membership_end_date']['field_type']);
 
     $this->assertEquals('Activity', $fields['activity_date_time']['field_type']);
index 05d1694d13e1926bc4f5ec7b06a8ecd8858dc00b..71d93aa8049eea794596ccc7bb0ceca018fbf80c 100644 (file)
@@ -157,6 +157,9 @@ class CRM_Core_Payment_PayPalIPNTest extends CiviUnitTestCase {
 
   /**
    * Test IPN response updates contribution_recur & contribution for first & second contribution.
+   *
+   * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
    */
   public function testIPNPaymentMembershipRecurSuccess() {
     $durationUnit = 'year';
@@ -169,7 +172,7 @@ class CRM_Core_Payment_PayPalIPNTest extends CiviUnitTestCase {
     $this->assertEquals(1, $contribution['contribution_status_id']);
     $this->assertEquals('8XA571746W2698126', $contribution['trxn_id']);
     // source gets set by processor
-    $this->assertTrue(substr($contribution['contribution_source'], 0, 20) == "Online Contribution:");
+    $this->assertTrue(substr($contribution['contribution_source'], 0, 20) === "Online Contribution:");
     $contributionRecur = $this->callAPISuccess('contribution_recur', 'getsingle', ['id' => $this->_contributionRecurID]);
     $this->assertEquals(5, $contributionRecur['contribution_status_id']);
     $paypalIPN = new CRM_Core_Payment_PaypalIPN($this->getPaypalRecurSubsequentTransaction());
@@ -191,7 +194,48 @@ class CRM_Core_Payment_PayPalIPNTest extends CiviUnitTestCase {
       'entity_table' => 'civicrm_membership',
     ]);
     $this->callAPISuccessGetSingle('membership_payment', ['contribution_id' => $contribution['values'][1]['id']]);
+  }
 
+  /**
+   * Test IPN that we can force membership when the membership payment has been deleted.
+   *
+   * https://lab.civicrm.org/dev/membership/issues/13
+   *
+   * In this scenario the membership payment record was deleted (or not created) for the first contribution but we
+   * 'recover' by using the input  membership id.
+   *
+   * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
+   */
+  public function testIPNPaymentInputMembershipRecurSuccess() {
+    $durationUnit = 'year';
+    $this->setupMembershipRecurringPaymentProcessorTransaction(['duration_unit' => $durationUnit, 'frequency_unit' => $durationUnit]);
+    $membershipPayment = $this->callAPISuccessGetSingle('membership_payment', []);
+    $paypalIPN = new CRM_Core_Payment_PayPalIPN(array_merge($this->getPaypalRecurTransaction(), ['membershipID' => $membershipPayment['membership_id']]));
+    $paypalIPN->main();
+    $membershipEndDate = $this->callAPISuccessGetValue('membership', ['return' => 'end_date']);
+    CRM_Core_DAO::executeQuery('DELETE FROM civicrm_membership_payment WHERE id = ' . $membershipPayment['id']);
+    CRM_Core_DAO::executeQuery("UPDATE civicrm_line_item SET entity_table = 'civicrm_contribution' WHERE entity_table = 'civicrm_membership'");
+
+    $paypalIPN = new CRM_Core_Payment_PaypalIPN(array_merge($this->getPaypalRecurSubsequentTransaction(), ['membershipID' => $membershipPayment['membership_id']]));
+    $paypalIPN->main();
+    $renewedMembershipEndDate = $this->membershipRenewalDate($durationUnit, $membershipEndDate);
+    $this->assertEquals($renewedMembershipEndDate, $this->callAPISuccessGetValue('membership', ['return' => 'end_date']));
+    $contribution = $this->callAPISuccess('contribution', 'get', [
+      'contribution_recur_id' => $this->_contributionRecurID,
+      'sequential' => 1,
+    ]);
+    $this->assertEquals(2, $contribution['count']);
+    $this->assertEquals('secondone', $contribution['values'][1]['trxn_id']);
+    $this->callAPISuccessGetCount('line_item', [
+      'entity_id' => $this->ids['membership'],
+      'entity_table' => 'civicrm_membership',
+    ], 1);
+    $this->callAPISuccessGetSingle('line_item', [
+      'contribution_id' => $contribution['values'][1]['id'],
+      'entity_table' => 'civicrm_membership',
+    ]);
+    $this->callAPISuccessGetSingle('membership_payment', ['contribution_id' => $contribution['values'][1]['id']]);
   }
 
   /**
index 461e3b0f3e9bb782e4405e5374b23d89329505e5..9acefc7eea450282bddecc017cbf435f685d2668 100644 (file)
@@ -68,6 +68,7 @@ class CRM_Dedupe_BAO_RuleGroupTest extends CiviUnitTestCase {
           'sic_code' => 'Sic Code',
           'user_unique_id' => 'Unique ID (OpenID)',
           'sort_name' => 'Sort Name',
+          'communication_style_id' => 'Communication Style',
         ],
       'civicrm_email' =>
         [
index a5e3c8c67a249ecd8fb8053590b988caa5625991..37e4f8ba21b69abfa3a544293d4029e16d69b260 100644 (file)
@@ -11,6 +11,15 @@ class CRM_Dedupe_MergerTest extends CiviUnitTestCase {
 
   protected $_contactIds = [];
 
+  /**
+   * Contacts created for the test.
+   *
+   * Overlaps contactIds....
+   *
+   * @var array
+   */
+  protected $contacts = [];
+
   /**
    * Tear down.
    *
@@ -21,6 +30,7 @@ class CRM_Dedupe_MergerTest extends CiviUnitTestCase {
       'civicrm_contact',
       'civicrm_group_contact',
       'civicrm_group',
+      'civicrm_prevnext_cache',
     ]);
     parent::tearDown();
   }
@@ -175,7 +185,7 @@ class CRM_Dedupe_MergerTest extends CiviUnitTestCase {
 
     // Retrieve pairs from prev next cache table
     $select = ['pn.is_selected' => 'is_selected'];
-    $cacheKeyString = CRM_Dedupe_Merger::getMergeCacheKeyString($dao->id, $this->_groupId);
+    $cacheKeyString = CRM_Dedupe_Merger::getMergeCacheKeyString($dao->id, $this->_groupId, [], TRUE, 0);
     $pnDupePairs = CRM_Core_BAO_PrevNextCache::retrieve($cacheKeyString, NULL, NULL, 0, 0, $select);
     $this->assertEquals(count($foundDupes), count($pnDupePairs), 'Check number of dupe pairs in prev next cache.');
 
@@ -245,7 +255,7 @@ class CRM_Dedupe_MergerTest extends CiviUnitTestCase {
 
     // Retrieve pairs from prev next cache table
     $select = ['pn.is_selected' => 'is_selected'];
-    $cacheKeyString = CRM_Dedupe_Merger::getMergeCacheKeyString($dao->id, $this->_groupId);
+    $cacheKeyString = CRM_Dedupe_Merger::getMergeCacheKeyString($dao->id, $this->_groupId, [], TRUE, 0);
     $pnDupePairs = CRM_Core_BAO_PrevNextCache::retrieve($cacheKeyString, NULL, NULL, 0, 0, $select);
 
     $this->assertEquals(count($foundDupes), count($pnDupePairs), 'Check number of dupe pairs in prev next cache.');
@@ -321,6 +331,79 @@ class CRM_Dedupe_MergerTest extends CiviUnitTestCase {
     ], $pairs);
   }
 
+  /**
+   * Test results are returned when criteria are passed in.
+   */
+  public function testGetMatchesCriteriaMatched() {
+    $this->setupMatchData();
+    $pairs = $this->callAPISuccess('Dedupe', 'getduplicates', [
+      'rule_group_id' => 1,
+      'criteria' => ['contact' => ['id' => ['>' => 1]]],
+    ])['values'];
+    $this->assertCount(2, $pairs);
+  }
+
+  /**
+   * Test results are returned when criteria are passed in & limit is  respected.
+   */
+  public function testGetMatchesCriteriaMatchedWithLimit() {
+    $this->setupMatchData();
+    $pairs = $this->callAPISuccess('Dedupe', 'getduplicates', [
+      'rule_group_id' => 1,
+      'criteria' => ['contact' => ['id' => ['>' => 1]]],
+      'options' => ['limit' => 1],
+    ])['values'];
+    $this->assertCount(1, $pairs);
+  }
+
+  /**
+   * Test results are returned when criteria are passed in & limit is  respected.
+   */
+  public function testGetMatchesCriteriaMatchedWithSearchLimit() {
+    $this->setupMatchData();
+    $pairs = $this->callAPISuccess('Dedupe', 'getduplicates', [
+      'rule_group_id' => 1,
+      'criteria' => ['contact' => ['id' => ['>' => 1]]],
+      'search_limit' => 1,
+    ])['values'];
+    $this->assertCount(1, $pairs);
+  }
+
+  /**
+   * Test getting matches where there are  no criteria.
+   */
+  public function testGetMatchesNoCriteria() {
+    $this->setupMatchData();
+    $pairs = $this->callAPISuccess('Dedupe', 'getduplicates', [
+      'rule_group_id' => 1,
+    ])['values'];
+    $this->assertCount(2, $pairs);
+  }
+
+  /**
+   * Test getting matches with a limit in play.
+   */
+  public function testGetMatchesNoCriteriaButLimit() {
+    $this->setupMatchData();
+    $pairs = $this->callAPISuccess('Dedupe', 'getduplicates', [
+      'rule_group_id' => 1,
+      'options' => ['limit' => 1],
+    ])['values'];
+    $this->assertCount(1, $pairs);
+  }
+
+  /**
+   * Test that if criteria are passed and there are no matching contacts no matches are returned.
+   */
+  public function testGetMatchesCriteriaNotMatched() {
+    $this->setupMatchData();
+    $pairs = $this->callAPISuccess('Dedupe', 'getduplicates', [
+      'rule_group_id' => 1,
+      'criteria' => ['contact' => ['id' => ['>' => 100000]]],
+    ])['values'];
+    $this->assertCount(0, $pairs);
+  }
+
   /**
    * Test function that gets organization pairs.
    *
index 5a7322b745d035f64e5eb01dc3976897b9820b52..622d37612a82f4776d6176d7411f928898ad5c72 100644 (file)
@@ -538,4 +538,75 @@ class CRM_Event_BAO_ChangeFeeSelectionTest extends CiviUnitTestCase {
     }
   }
 
+  /**
+   * dev-financial-40: Test that partial payment entries in entity-financial-trxn table to ensure that reverse transaction is entered
+   */
+  public function testPartialPaymentEntries() {
+    $this->registerParticipantAndPay($this->_expensiveFee);
+    $priceSetParams['price_' . $this->priceSetFieldID] = $this->veryExpensiveFeeValueID;
+    $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->participantID, 'participant');
+    CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem);
+    $actualResults = $this->callAPISuccess('EntityFinancialTrxn', 'get', ['sequential' => 1, 'entity_table' => 'civicrm_financial_item'])['values'];
+    $this->assertCount(3, $actualResults);
+    $expectedResults = [
+      [
+        'id' => 2,
+        'amount' => 100.0,
+        'entity_id' => 1,
+        'financial_trxn_id' => 1,
+        'entity_table' => 'civicrm_financial_item',
+      ],
+      [
+        'id' => 4,
+        // ensure that reverse entry is entered in the EntityFinancialTrxn table on fee change to greater amount
+        'amount' => -100.0,
+        'entity_id' => 2,
+        'financial_trxn_id' => 2,
+        'entity_table' => 'civicrm_financial_item',
+      ],
+      [
+        'id' => 5,
+        'amount' => 120.00,
+        'entity_id' => 3,
+        'financial_trxn_id' => 2,
+        'entity_table' => 'civicrm_financial_item',
+      ],
+    ];
+    foreach ($expectedResults as $key => $expectedResult) {
+      $this->checkArrayEquals($expectedResult, $actualResults[$key]);
+    }
+  }
+
+  /**
+   * dev-financial-40: Test that refund payment entries in entity-financial-trxn table to ensure that reverse transaction is entered on fee change to lesser amount
+   */
+  public function testRefundPaymentEntries() {
+    $this->registerParticipantAndPay($this->_expensiveFee);
+    $priceSetParams['price_' . $this->priceSetFieldID] = $this->cheapFeeValueID;
+    $lineItem = CRM_Price_BAO_LineItem::getLineItems($this->participantID, 'participant');
+    CRM_Price_BAO_LineItem::changeFeeSelections($priceSetParams, $this->_participantId, 'participant', $this->_contributionId, $this->_feeBlock, $lineItem);
+    $actualResults = $this->callAPISuccess('EntityFinancialTrxn', 'get', ['sequential' => 1, 'entity_table' => 'civicrm_financial_item', 'return' => ['amount', 'entity_id']])['values'];
+    $expectedResults = [
+      [
+        'id' => 2,
+        'amount' => 100.00,
+        'entity_id' => 1,
+      ],
+      [
+        'id' => 4,
+        // ensure that reverse entry is entered in the EntityFinancialTrxn table
+        'amount' => -100.00,
+        'entity_id' => 2,
+      ],
+      [
+        'id' => 5,
+        'amount' => 80.00,
+        'entity_id' => 3,
+      ],
+    ];
+    foreach ($expectedResults as $key => $expectedResult) {
+      $this->checkArrayEquals($expectedResult, $actualResults[$key]);
+    }
+  }
+
 }
index cd57dbd88e029e2a96deadcd67fec0f2e57317ad..4cb83a0935c3a40bd8b9cbb8f0ee4019153ec8d8 100644 (file)
@@ -82,6 +82,7 @@ class CRM_Event_Form_ParticipantTest extends CiviUnitTestCase {
       'financial_type_id' => 1,
       'contribution_status_id' => 2,
       'payment_instrument_id' => 1,
+      'receive_date' => date('Y-m-d'),
     ]);
     $participants = $this->callAPISuccess('Participant', 'get', []);
     $this->assertEquals(1, $participants['count']);
index 71f8d5b068d50bcedc9abbfc991489e1f82c8f97..ad220feff66b16f2c17d43a449a9b6fc22bc3d01 100644 (file)
@@ -780,7 +780,7 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
     $this->doExportTest(['fields' => $mappedFields, 'ids' => [$this->contactIDs[0]]]);
 
     foreach ($this->csv->getRecords() as $row) {
-      $id = $row['contact_id'];
+      $id = $row['Contact ID'];
       $this->assertEquals('AIM', $row['Billing-IM Provider']);
       $this->assertEquals('AIM', $row['Whare Kai-IM Provider']);
       $this->assertEquals('BillingJabber' . $id, $row['Billing-IM Screen Name-Jabber']);
@@ -955,17 +955,18 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
     $this->doExportTest(['fields' => $fields]);
 
     foreach ($this->csv as $row) {
-      $this->assertEquals('Méin' . $row['contact_id'] . 'city', $row['Main-City']);
-      $this->assertEquals('Billing' . $row['contact_id'] . 'street_address', $row['Billing-Street Address']);
-      $this->assertEquals('Whare Kai' . $row['contact_id'] . 'postal_code', $row['Whare Kai-Postal Code']);
+      $contactID = (int) $row['Contact ID'];
+      $this->assertEquals('Méin' . $contactID . 'city', $row['Main-City']);
+      $this->assertEquals('Billing' . $contactID . 'street_address', $row['Billing-Street Address']);
+      $this->assertEquals('Whare Kai' . $contactID . 'postal_code', $row['Whare Kai-Postal Code']);
       foreach ($relationships as $relatedContactID => $relationship) {
-        $value = ((int) $row['contact_id'] === $this->contactIDs[0]) ? 'Méin' . $relatedContactID . 'city' : '';
+        $value = ($contactID === $this->contactIDs[0]) ? 'Méin' . $relatedContactID . 'city' : '';
         $this->assertEquals($value, $row[$relationship['label'] . '-Main-City'], 'checking ' . $relationship['label'] . '-Main-City');
       }
     }
 
     $this->assertEquals([
-      'contact_id' => 'contact_id varchar(255)',
+      'contact_id' => 'contact_id varchar(16)',
       'billing_city' => 'billing_city varchar(64)',
       'billing_street_address' => 'billing_street_address varchar(96)',
       'billing_postal_code' => 'billing_postal_code varchar(64)',
@@ -1549,7 +1550,7 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       'membership_type' => 1,
       'member_is_test' => 1,
       'member_is_pay_later' => 1,
-      'join_date' => 1,
+      'membership_join_date' => 1,
       'membership_start_date' => 1,
       'membership_end_date' => 1,
       'membership_source' => 1,
@@ -2217,7 +2218,7 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
    */
   protected function getCaseHeaderDefinition() {
     return [
-      81 => 'contact_id',
+      81 => 'Contact ID',
       82 => 'Case ID',
       83 => 'case_activity_subject',
       84 => 'Case Subject',
@@ -2348,7 +2349,7 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       82 => 'Total Pledged',
       83 => 'Total Paid',
       84 => 'Pledge Made',
-      85 => 'pledge_start_date',
+      85 => 'Pledge Start Date',
       86 => 'Next Payment Date',
       87 => 'Next Payment Amount',
       88 => 'Pledge Status',
@@ -2489,7 +2490,7 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       'case_activity_medium_id' => 'case_activity_medium_id varchar(255)',
       'case_activity_details' => 'case_activity_details text',
       'case_activity_is_auto' => 'case_activity_is_auto text',
-      'contact_id' => 'contact_id varchar(255)',
+      'contact_id' => 'contact_id varchar(16)',
       'case_id' => 'case_id varchar(16)',
       'case_activity_subject' => 'case_activity_subject text',
       'case_status' => 'case_status text',
@@ -2694,7 +2695,7 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       'pledge_amount' => 'pledge_amount varchar(32)',
       'pledge_total_paid' => 'pledge_total_paid text',
       'pledge_create_date' => 'pledge_create_date varchar(32)',
-      'pledge_start_date' => 'pledge_start_date text',
+      'pledge_start_date' => 'pledge_start_date varchar(32)',
       'pledge_next_pay_date' => 'pledge_next_pay_date text',
       'pledge_next_pay_amount' => 'pledge_next_pay_amount text',
       'pledge_status' => 'pledge_status varchar(255)',
@@ -2727,7 +2728,7 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       'membership_type' => 'membership_type varchar(128)',
       'member_is_test' => 'member_is_test varchar(16)',
       'member_is_pay_later' => 'member_is_pay_later varchar(16)',
-      'join_date' => 'join_date varchar(32)',
+      'membership_join_date' => 'membership_join_date varchar(32)',
       'membership_start_date' => 'membership_start_date varchar(32)',
       'membership_end_date' => 'membership_end_date varchar(32)',
       'membership_source' => 'membership_source varchar(128)',
index cf50231bbab9bd8c59bdc0386d69500df7c38821..1d516932bd88ece0b495557a7bad6ea74b0e9f5d 100644 (file)
@@ -548,6 +548,13 @@ class CRM_Member_BAO_MembershipTest extends CiviUnitTestCase {
 
   /**
    * Renew membership with change in membership type.
+   *
+   * @fixme Note that this test fails when today is August 29 2019 (and maybe other years?):
+   *   Verify correct end date is calculated after membership renewal
+   *   Failed asserting that two strings are equal.
+   *   Expected-'2021-03-01'
+   *   Actual+'2021-02-28'
+   *   /home/jenkins/bknix-dfl/build/core-15165-73etc/web/sites/all/modules/civicrm/tests/phpunit/CRM/Member/BAO/MembershipTest.php:609
    */
   public function testRenewMembership() {
     $contactId = $this->individualCreate();
index c42b52a06f5d536629a4e5f7b41b8ada5beb5f99..d70cee2413273bad27f48a5b4cae972520ba96ec 100644 (file)
@@ -1085,6 +1085,57 @@ Expires: ',
     $this->assertEquals(1, $contributionResultAfterRelationshipDelete['count'], "Contribution has been wrongly deleted.");
   }
 
+  /**
+   * dev/core/issues/860:
+   * Test creating two memberships via price set in the back end with a discount,
+   * checking that the line items have correct amounts.
+   */
+  public function testTwoMembershipsViaPriceSetInBackendWithDiscount() {
+    // Register buildAmount hook to apply discount.
+    $this->hookClass->setHook('civicrm_buildAmount', [$this, 'buildAmountMembershipDiscount']);
+
+    // Create two memberships for individual $this->_individualId, via a price set in the back end.
+    $this->createTwoMembershipsViaPriceSetInBackEnd($this->_individualId);
+    $contribution = $this->callAPISuccessGetSingle('Contribution', [
+      'contact_id' => $this->_individualId,
+    ]);
+    // Note: we can't check for the contribution total being discounted, because the total is set
+    // when the contribution is created via $form->testSubmit(), but buildAmount isn't called
+    // until testSubmit() runs. Fixing that might involve making testSubmit() more sophisticated,
+    // or just hacking total_amount for this case.
+
+    $lineItemResult = $this->callAPISuccess('LineItem', 'get', [
+      'contribution_id' => $contribution['id'],
+    ]);
+    $this->assertEquals(2, $lineItemResult['count']);
+    $discountedItems = 0;
+    foreach ($lineItemResult['values'] as $lineItem) {
+      if (CRM_Utils_String::startsWith($lineItem['label'], 'Long Haired Goat')) {
+        $this->assertEquals(15.0, $lineItem['line_total']);
+        $this->assertEquals('Long Haired Goat - one leg free!', $lineItem['label']);
+        $discountedItems++;
+      }
+    }
+    $this->assertEquals(1, $discountedItems);
+  }
+
+  /**
+   * Implements hook_civicrm_buildAmount() for testTwoMembershipsViaPriceSetInBackendWithDiscount().
+   */
+  public function buildAmountMembershipDiscount($pageType, &$form, &$amount) {
+    foreach ($amount as $id => $priceField) {
+      if (is_array($priceField['options'])) {
+        foreach ($priceField['options'] as $optionId => $option) {
+          if ($option['membership_type_id'] == 15) {
+            // Long Haired Goat membership discount.
+            $amount[$id]['options'][$optionId]['amount'] = $option['amount'] * 0.75;
+            $amount[$id]['options'][$optionId]['label'] = $option['label'] . ' - one leg free!';
+          }
+        }
+      }
+    }
+  }
+
   /**
    * Get a membership form object.
    *
index ee3f3604cab03bc0cdc645e20d95bb6368adc90c..d1d6aa8027355796c10850a30416ced1a80a1e1d 100644 (file)
@@ -54,7 +54,7 @@ class CRM_Member_Selector_SearchTest extends CiviUnitTestCase {
       'contact_type' => '<a href="/index.php?q=civicrm/profile/view&amp;reset=1&amp;gid=7&amp;id=' . $this->_contactID . '&amp;snippet=4" class="crm-summary-link"><div class="icon crm-icon Individual-icon"></div></a>',
       'sort_name' => 'Anderson, Anthony',
       'membership_type' => 'General',
-      'join_date' => date('Y-m-d'),
+      'membership_join_date' => date('Y-m-d'),
       'membership_start_date' => date('Y-m-d'),
       'membership_end_date' => $membership['end_date'],
       'membership_source' => 'Payment',
index a990e124fcedf3b3ec81d83853bfbadc8ec092ce..be60f5ff4c2364b3a2d9ccd69a2093e70bce18e8 100644 (file)
@@ -117,6 +117,45 @@ class CRM_Upgrade_Incremental_BaseTest extends CiviUnitTestCase {
     $this->assertEquals(TRUE, $hasRelative);
   }
 
+  /**
+   * Test Multiple Relative Date conversions
+   */
+  public function testSmartGroupMultipleRelatvieDateConversions() {
+    $this->callAPISuccess('SavedSearch', 'create', [
+      'form_values' => [
+        ['membership_join_date_low', '=', '20190903000000'],
+        ['membership_join_date_high', '=', '20190903235959'],
+        ['membership_start_date_low', '=' , '20190901000000'],
+        ['membership_start_date_high', '=', '20190907235959'],
+        ['membership_end_date_low', '=', '20190901000000'],
+        ['membership_end_date_high', '=', '20190907235959'],
+        'relative_dates' => [
+          'member_join' => 'this.day',
+          'member_start' => 'this.week',
+          'member_end' => 'this.week',
+        ],
+      ],
+    ]);
+    $smartGroupConversionObject = new CRM_Upgrade_Incremental_SmartGroups();
+    $smartGroupConversionObject->updateGroups([
+      'datepickerConversion' => [
+        'membership_join_date',
+        'membership_start_date',
+        'membership_end_date',
+      ],
+    ]);
+    $savedSearch = $this->callAPISuccessGetSingle('SavedSearch', []);
+    $this->assertContains('6', array_keys($savedSearch['form_values']));
+    $this->assertEquals('membership_join_date_relative', $savedSearch['form_values'][6][0]);
+    $this->assertEquals('this.day', $savedSearch['form_values'][6][2]);
+    $this->assertContains('7', array_keys($savedSearch['form_values']));
+    $this->assertEquals('membership_start_date_relative', $savedSearch['form_values'][7][0]);
+    $this->assertEquals('this.week', $savedSearch['form_values'][7][2]);
+    $this->assertContains('8', array_keys($savedSearch['form_values']));
+    $this->assertEquals('membership_end_date_relative', $savedSearch['form_values'][8][0]);
+    $this->assertEquals('this.week', $savedSearch['form_values'][8][2]);
+  }
+
   /**
    * Test conversion of on hold group.
    */
index 98a119fd748da449d03b8ae89c865c85917f723d..8517f568b914fbc7e7d809ccc9810f301210ab21 100644 (file)
@@ -203,6 +203,7 @@ class CRM_Utils_JSTest extends CiviUnitTestCase {
     return [
       ['{a: \'Apple\', \'b\': "Banana", c: [1, 2, 3]}', ['a' => 'Apple', 'b' => 'Banana', 'c' => [1, 2, 3]]],
       ['true', TRUE],
+      [' ', NULL],
       ['false', FALSE],
       ['null', NULL],
       ['"true"', 'true'],
@@ -212,6 +213,10 @@ class CRM_Utils_JSTest extends CiviUnitTestCase {
       ["{  }", []],
       [" [   ]", []],
       [" [ 2   ]", [2]],
+      [
+        '{a: "parse error no closing bracket"',
+        NULL,
+      ],
       [
         '{a: ["foo", \'bar\'], "b": {a: [\'foo\', "bar"], b: {\'a\': ["foo", "bar"], b: {}}}}',
         ['a' => ['foo', 'bar'], 'b' => ['a' => ['foo', 'bar'], 'b' => ['a' => ['foo', 'bar'], 'b' => []]]],
index 1343cffa1b4297b55fe44511b9798e202bb41302..0b685ffe69109429942a3401c61fb2634e5ba516 100644 (file)
@@ -1374,7 +1374,7 @@ class CiviUnitTestCase extends PHPUnit\Framework\TestCase {
     if (!isset($params['target_contact_id'])) {
       $params['target_contact_id'] = $this->individualCreate(array(
         'first_name' => 'Julia',
-        'Last_name' => 'Anderson',
+        'last_name' => 'Anderson',
         'prefix' => 'Ms.',
         'email' => 'julia_anderson@civicrm.org',
         'contact_type' => 'Individual',
index 33bc8ec269194c4f61d10f9beb986f533986fc34..4d9833829ccc280882f67fe0578a790564612d8b 100644 (file)
@@ -349,8 +349,16 @@ class api_v3_AttachmentTest extends CiviUnitTestCase {
       'return' => ['content'],
     ]);
     $this->assertEquals($expectedContent, $getResult2['values'][$fileId]['content']);
+    // Do this again even though we just tested above to demonstrate that these fields should be returned even if you only ask to return 'content'.
     foreach (['id', 'entity_table', 'entity_id', 'url'] as $field) {
-      $this->assertEquals($createResult['values'][$fileId][$field], $getResult['values'][$fileId][$field], "Expect field $field to match");
+      if ($field == 'url') {
+        $this->assertEquals(substr($createResult['values'][$fileId][$field], 0, -15), substr($getResult2['values'][$fileId][$field], 0, -15));
+        $this->assertEquals(substr($createResult['values'][$fileId][$field], -3), substr($getResult2['values'][$fileId][$field], -3));
+        $this->assertApproxEquals(substr($createResult['values'][$fileId][$field], -14, 10), substr($getResult2['values'][$fileId][$field], -14, 10), 2);
+      }
+      else {
+        $this->assertEquals($createResult['values'][$fileId][$field], $getResult2['values'][$fileId][$field], "Expect field $field to match");
+      }
     }
   }
 
index 995d8ae8fe62626060ed0e202c05484862a30198..f82c6612a6d911d11d531e48eca507d8a9cb9d8d 100644 (file)
@@ -241,7 +241,6 @@ class api_v3_CaseTypeTest extends CiviCaseTestCase {
    * @throws \Exception
    */
   public function testCaseStatusByCaseType() {
-    $this->markTestIncomplete('Cannot figure out why this passes locally but fails on Jenkins.');
     $statusName = md5(mt_rand());
     $template = $this->callAPISuccess('CaseType', 'getsingle', ['id' => $this->caseTypeId]);
     unset($template['id']);
index 5422b5223c747a72a741a063d0832765ec5a2800..46efb5e8b78b1bd2a42dc8a3e06ad30f5d54891e 100644 (file)
@@ -945,7 +945,7 @@ class api_v3_EventTest extends CiviUnitTestCase {
     ]);
     $eventResult = $this->callAPISuccess('Event', 'getsingle', ['id' => $eventResult['id']]);
     foreach ($templateParams as $param => $value) {
-      $this->assertEquals($value, $eventResult[$param]);
+      $this->assertEquals($value, $eventResult[$param], print_r($eventResult, 1));
     }
   }
 
index dba8e5779374a76be12121638166ace0e57121b8..ca3516b360f6e5066fcc13298b74336835e7769d 100644 (file)
@@ -87,6 +87,8 @@ class api_v3_GroupNestingTest extends CiviUnitTestCase {
 
   /**
    * Test civicrm_group_nesting_get.
+   *
+   * @dataProvider versionThreeAndFour
    */
   public function testGet() {
     $params = [
@@ -108,6 +110,8 @@ class api_v3_GroupNestingTest extends CiviUnitTestCase {
 
   /**
    * Test civicrm_group_nesting_get with just one param (child_group_id).
+   *
+   * @dataProvider versionThreeAndFour
    */
   public function testGetWithChildGroupId() {
     $params = [
@@ -135,6 +139,8 @@ class api_v3_GroupNestingTest extends CiviUnitTestCase {
 
   /**
    * Test civicrm_group_nesting_get with just one param (parent_group_id).
+   *
+   * @dataProvider versionThreeAndFour
    */
   public function testGetWithParentGroupId() {
     $params = [
@@ -169,7 +175,9 @@ class api_v3_GroupNestingTest extends CiviUnitTestCase {
    * Test civicrm_group_nesting_get for no records results.
    *
    * Success expected. (these tests are of marginal value as are in syntax conformance,
-   * don't copy & paste
+   * don't copy & paste.
+   *
+   * @dataProvider versionThreeAndFour
    */
   public function testGetEmptyResults() {
     $params = [
@@ -183,6 +191,8 @@ class api_v3_GroupNestingTest extends CiviUnitTestCase {
    * Test civicrm_group_nesting_create.
    *
    * @throws \Exception
+   *
+   * @dataProvider versionThreeAndFour
    */
   public function testCreate() {
     $params = [
@@ -196,6 +206,8 @@ class api_v3_GroupNestingTest extends CiviUnitTestCase {
 
   /**
    * Test civicrm_group_nesting_remove.
+   *
+   * @dataProvider versionThreeAndFour
    */
   public function testDelete() {
     $params = [
@@ -213,6 +225,8 @@ class api_v3_GroupNestingTest extends CiviUnitTestCase {
    * Test civicrm_group_nesting_remove with empty parameter array.
    *
    * Error expected.
+   *
+   * @dataProvider versionThreeAndFour
    */
   public function testDeleteWithEmptyParams() {
     $this->callAPIFailure('group_nesting', 'delete', []);
index a3c26cff5fa2f379b1fb70b47e5b3f5bbf906595..cd30a2ac84c7a6472c8e77897f5bbd0d300be7fd 100644 (file)
@@ -51,6 +51,8 @@ class api_v3_GroupOrganizationTest extends CiviUnitTestCase {
 
   /**
    * Test civicrm_group_organization_get with valid params.
+   *
+   * @dataProvider versionThreeAndFour
    */
   public function testGroupOrganizationGet() {
 
@@ -67,6 +69,8 @@ class api_v3_GroupOrganizationTest extends CiviUnitTestCase {
 
   /**
    * Test civicrm_group_organization_get with group_id.
+   *
+   * @dataProvider versionThreeAndFour
    */
   public function testGroupOrganizationGetWithGroupId() {
     $createParams = [
@@ -85,6 +89,8 @@ class api_v3_GroupOrganizationTest extends CiviUnitTestCase {
 
   /**
    * Test civicrm_group_organization_get with empty params.
+   *
+   * @dataProvider versionThreeAndFour
    */
   public function testGroupOrganizationGetWithEmptyParams() {
     $params = [];
@@ -95,6 +101,8 @@ class api_v3_GroupOrganizationTest extends CiviUnitTestCase {
 
   /**
    * Test civicrm_group_organization_get with wrong params.
+   *
+   * @dataProvider versionThreeAndFour
    */
   public function testGroupOrganizationGetWithWrongParams() {
     $params = 'groupOrg';
@@ -104,6 +112,8 @@ class api_v3_GroupOrganizationTest extends CiviUnitTestCase {
 
   /**
    * Test civicrm_group_organization_get invalid keys.
+   *
+   * @dataProvider versionThreeAndFour
    */
   public function testGroupOrganizationGetWithInvalidKeys() {
     $params = [
@@ -118,6 +128,8 @@ class api_v3_GroupOrganizationTest extends CiviUnitTestCase {
 
   /**
    * Check with valid params.
+   *
+   * @dataProvider versionThreeAndFour
    */
   public function testGroupOrganizationCreate() {
     $params = [
@@ -129,6 +141,8 @@ class api_v3_GroupOrganizationTest extends CiviUnitTestCase {
 
   /**
    * CRM-13841 - Load Group Org before save
+   *
+   * @dataProvider versionThreeAndFour
    */
   public function testGroupOrganizationCreateTwice() {
     $params = [
@@ -142,6 +156,8 @@ class api_v3_GroupOrganizationTest extends CiviUnitTestCase {
 
   /**
    * Check with empty params array.
+   *
+   * @dataProvider versionThreeAndFour
    */
   public function testGroupOrganizationCreateWithEmptyParams() {
     $params = [];
@@ -151,6 +167,8 @@ class api_v3_GroupOrganizationTest extends CiviUnitTestCase {
 
   /**
    * Check with invalid params.
+   *
+   * @dataProvider versionThreeAndFour
    */
   public function testGroupOrganizationCreateParamsNotArray() {
     $params = 'group_org';
@@ -160,6 +178,8 @@ class api_v3_GroupOrganizationTest extends CiviUnitTestCase {
 
   /**
    * Check with invalid params keys.
+   *
+   * @dataProvider versionThreeAndFour
    */
   public function testGroupOrganizationCreateWithInvalidKeys() {
     $params = [
@@ -173,6 +193,8 @@ class api_v3_GroupOrganizationTest extends CiviUnitTestCase {
 
   /**
    * Test civicrm_group_organization_remove with params not an array.
+   *
+   * @dataProvider versionThreeAndFour
    */
   public function testGroupOrganizationDeleteParamsNotArray() {
     $params = 'delete';
@@ -182,6 +204,8 @@ class api_v3_GroupOrganizationTest extends CiviUnitTestCase {
 
   /**
    * Test civicrm_group_organization_remove with empty params.
+   *
+   * @dataProvider versionThreeAndFour
    */
   public function testGroupOrganizationDeleteWithEmptyParams() {
     $params = [];
@@ -191,6 +215,8 @@ class api_v3_GroupOrganizationTest extends CiviUnitTestCase {
 
   /**
    * Test civicrm_group_organization_remove with valid params.
+   *
+   * @dataProvider versionThreeAndFour
    */
   public function testGroupOrganizationDelete() {
     $paramsC = [
@@ -207,6 +233,8 @@ class api_v3_GroupOrganizationTest extends CiviUnitTestCase {
 
   /**
    * Test civicrm_group_organization_remove with invalid params key.
+   *
+   * @dataProvider versionThreeAndFour
    */
   public function testGroupOrganizationDeleteWithInvalidKey() {
     $paramsDelete = [
index bc5adbd8a8890ed2ec14e3cfe523b72000a5d693..c9ebda053c25e95697272f7b0448ddc2569ac2ca 100644 (file)
@@ -1112,7 +1112,7 @@ class api_v3_JobTest extends CiviUnitTestCase {
    * @param $dataSet
    */
   public function testBatchMergeWorksCheckPermissionsTrue($dataSet) {
-    CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM', 'administer CiviCRM'];
+    CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM', 'administer CiviCRM', 'merge duplicate contacts', 'force merge duplicate contacts'];
     foreach ($dataSet['contacts'] as $params) {
       $this->callAPISuccess('Contact', 'create', $params);
     }
index e6b3a7947efa2503983bb80cf4f7b7eadda41e81..14a7710f48d8141b76e0b18676f8a8b78ec36ffe 100644 (file)
@@ -254,7 +254,7 @@ class api_v3_UtilsTest extends CiviUnitTestCase {
       'start_date' => '2010-12-20',
       'end_date' => '',
       'membership_end_date' => '0',
-      'join_date' => '2010-12-20',
+      'membership_join_date' => '2010-12-20',
       'membership_start_date' => '2010-12-20',
     ];
     $fields = civicrm_api3('Membership', 'getfields', ['action' => 'get']);
@@ -262,7 +262,7 @@ class api_v3_UtilsTest extends CiviUnitTestCase {
     $this->assertEquals('2010-12-20', $params['start_date']);
     $this->assertEquals('20101220000000', $params['membership_start_date']);
     $this->assertEquals('', $params['end_date']);
-    $this->assertEquals('20101220000000', $params['join_date'], 'join_date not set in line ' . __LINE__);
+    $this->assertEquals('20101220000000', $params['membership_join_date'], 'join_date not set in line ' . __LINE__);
   }
 
   public function test_civicrm_api3_validate_fields_event() {
@@ -283,14 +283,14 @@ class api_v3_UtilsTest extends CiviUnitTestCase {
 
   public function test_civicrm_api3_validate_fields_exception() {
     $params = [
-      'join_date' => 'abc',
+      'membership_join_date' => 'abc',
     ];
     try {
       $fields = civicrm_api3('Membership', 'getfields', ['action' => 'get']);
       _civicrm_api3_validate_fields('Membership', 'get', $params, $fields['values']);
     }
     catch (Exception$expected) {
-      $this->assertEquals('join_date is not a valid date: abc', $expected->getMessage());
+      $this->assertEquals('membership_join_date is not a valid date: abc', $expected->getMessage());
     }
   }
 
index d73ea8a08a583363516aae81d92e4d05af3c7595..38c9df70bb819a94e7efe151c0ee1da9912ed3f8 100644 (file)
@@ -2,7 +2,7 @@
 
 <table>
   <base>CRM/ACL</base>
-  <class>Cache</class>
+  <class>ACLCache</class>
   <name>civicrm_acl_cache</name>
   <comment>Cache for acls and contacts</comment>
   <add>1.6</add>
index 1539d0c6e8b3289e7d950b61c57a87bf3d9f312d..14965f9ffcb4f6960bac163b6b6b2f2d8d5a0315 100644 (file)
       <optionGroupName>communication_style</optionGroupName>
     </pseudoconstant>
     <export>true</export>
+    <import>true</import>
+    <headerPattern>/style/i</headerPattern>
     <comment>Communication style (e.g. formal vs. familiar) to use with this contact. FK to communication styles in civicrm_option_value.</comment>
     <add>4.4</add>
     <html>
     <default>NULL</default>
     <add>4.3</add>
   </field>
+  <index>
+    <name>index_created_date</name>
+    <fieldName>created_date</fieldName>
+    <add>5.18</add>
+  </index>
   <field>
     <name>modified_date</name>
     <type>timestamp</type>
     <default>CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP</default>
     <add>4.3</add>
   </field>
+  <index>
+    <name>index_modified_date</name>
+    <fieldName>modified_date</fieldName>
+    <add>5.18</add>
+  </index>
 </table>
index 29445f1aa986b8f6acec3992cb96539f75838e02..564a2773292b117051960462feca88bf7ecf1e89 100644 (file)
@@ -8,8 +8,10 @@
   <add>2.1</add>
   <field>
     <name>id</name>
+    <title>Cache ID</title>
     <type>int unsigned</type>
     <required>true</required>
+    <comment>Unique table ID</comment>
     <add>2.1</add>
   </field>
   <primaryKey>
@@ -18,6 +20,7 @@
   </primaryKey>
   <field>
     <name>group_name</name>
+    <title>Group Name</title>
     <type>varchar</type>
     <length>32</length>
     <required>true</required>
@@ -26,6 +29,7 @@
   </field>
   <field>
     <name>path</name>
+    <title>Path</title>
     <type>varchar</type>
     <length>255</length>
     <comment>Unique path name for cache element</comment>
   </index>
   <field>
     <name>data</name>
+    <title>Data</title>
     <type>longtext</type>
     <comment>data associated with this path</comment>
     <add>2.1</add>
   </field>
   <field>
     <name>component_id</name>
+    <title>Component ID</title>
     <type>int unsigned</type>
     <comment>Component that this menu item belongs to</comment>
     <add>2.1</add>
@@ -75,6 +81,7 @@
   </foreignKey>
   <field>
     <name>created_date</name>
+    <title>Created Date</title>
     <type>timestamp</type>
     <default>CURRENT_TIMESTAMP</default>
     <comment>When was the cache item created</comment>
@@ -82,6 +89,7 @@
   </field>
   <field>
     <name>expired_date</name>
+    <title>Expired Date</title>
     <type>timestamp</type>
     <default>NULL</default>
     <required>false</required>
index 41ed111374447b1832f6041175f96f27f025dc00..96da590e28381ff6c25bf6b7f7f4972270dcc950 100644 (file)
@@ -35,6 +35,7 @@
     <table>civicrm_domain</table>
     <key>id</key>
     <add>3.1</add>
+    <onDelete>CASCADE</onDelete>
   </foreignKey>
   <field>
     <name>name</name>
index e46f4d634e41e672d916dae7c8f0f16c0026e63f..9522592d80db54634e6e87b6bf9167a979abd7dd 100644 (file)
@@ -84,6 +84,7 @@
       <type>Select Date</type>
       <formatType>activityDate</formatType>
     </html>
+    <uniqueName>membership_join_date</uniqueName>
   </field>
   <field>
     <name>start_date</name>
index 50ecd9c2261b391c4ae8f46a650cb85368b180d2..7fd1cf35cc2c5c8e74100cafb2d7f1d0c11de829 100644 (file)
     <type>datetime</type>
     <title>Pledge Start Date</title>
     <required>true</required>
+    <export>true</export>
     <comment>The date the first scheduled pledge occurs.</comment>
     <add>2.1</add>
     <html>
-        <type>Select Date</type>
-      </html>
+      <type>Select Date</type>
+    </html>
+    <uniqueName>pledge_start_date</uniqueName>
+    <uniqueTitle>Payments Start Date</uniqueTitle>
   </field>
   <field>
     <name>create_date</name>
     <title>Pledge Made</title>
     <required>true</required>
     <import>true</import>
+    <export>true</export>
     <comment>When this pledge record was created.</comment>
     <add>2.1</add>
     <html>
     <comment>When a pledge acknowledgement message was sent to the contributor.</comment>
     <add>2.1</add>
     <html>
-        <type>Select Date</type>
+      <type>Select Date</type>
     </html>
   </field>
   <field>
     <comment>Date this pledge was cancelled by contributor.</comment>
     <add>2.1</add>
     <html>
-        <type>Select Date</type>
+      <type>Select Date</type>
     </html>
   </field>
   <field>
     <name>end_date</name>
     <type>datetime</type>
     <title>Pledge End Date</title>
+    <export>true</export>
     <comment>Date this pledge finished successfully (total pledge payments equal to or greater than pledged amount).</comment>
     <add>2.1</add>
     <html>
-        <type>Select Date</type>
+      <type>Select Date</type>
     </html>
+    <uniqueName>pledge_end_date</uniqueName>
+    <uniqueTitle>Payments Ended Date</uniqueTitle>
   </field>
   <field>
     <name>max_reminders</name>
     <default>1</default>
     <comment>The maximum number of payment reminders to send for any given payment.</comment>
     <html>
-         <type>Text</type>
-       </html>
+       <type>Text</type>
+     </html>
     <add>2.1</add>
   </field>
   <field>
     <comment>Send initial reminder this many days prior to the payment due date.</comment>
     <add>2.1</add>
     <html>
-          <type>Select</type>
-        </html>
+      <type>Select</type>
+    </html>
   </field>
   <field>
     <name>additional_reminder_day</name>
     <comment>Send additional reminder this many days after last one sent, up to maximum number of reminders.</comment>
     <add>2.1</add>
     <html>
-         <type>Text</type>
-       </html>
+      <type>Text</type>
+    </html>
   </field>
   <field>
     <name>status_id</name>
index e13eb9e16b7d5466ce3a1c61ad1c2124494d2d31..bc711aef4394fd04152892edc891341556206c58 100644 (file)
@@ -60,6 +60,7 @@
     <uniqueName>pledge_payment_scheduled_amount</uniqueName>
     <title>Scheduled Amount</title>
     <import>true</import>
+    <export>true</export>
     <type>decimal</type>
     <required>true</required>
     <comment>Pledged amount for this payment (the actual contribution amount might be different).</comment>
@@ -98,6 +99,7 @@
     <uniqueName>pledge_payment_scheduled_date</uniqueName>
     <title>Scheduled Date</title>
     <import>true</import>
+    <export>true</export>
     <type>datetime</type>
     <required>true</required>
     <comment>The date the pledge payment is supposed to happen.</comment>
       <type>Select Date</type>
       <formatType>activityDate</formatType>
     </html>
+    <uniqueTitle>Payment Scheduled</uniqueTitle>
   </field>
   <field>
     <name>reminder_date</name>
index f921cc8c44599092a86aa33a0fe2d58a7c53d204..42eff2a277c96b61f9e01dc2df12dcf1c9711310 100644 (file)
@@ -1603,7 +1603,7 @@ INSERT INTO civicrm_uf_field
        ( 10,     'soft_credit',                 0, 0, 10, 'User and User Admin Only', 0, 0, NULL, '{ts escape="sql"}Soft Credit{/ts}', 'Contribution', NULL, NULL ),
        ( 10,     'soft_credit_type',            0, 0, 11, 'User and User Admin Only', 0, 0, NULL, '{ts escape="sql"}Soft Credit Type{/ts}', 'Contribution', NULL, NULL ),
        ( 11,     'membership_type',             1, 1, 1, 'User and User Admin Only', 0, 0, NULL, '{ts escape="sql"}Membership Type{/ts}', 'Membership', NULL, NULL ),
-       ( 11,     'join_date',                   1, 1, 2, 'User and User Admin Only', 0, 0, NULL, '{ts escape="sql"}Member Since{/ts}', 'Membership', NULL, NULL ),
+       ( 11,     'membership_join_date',        1, 1, 2, 'User and User Admin Only', 0, 0, NULL, '{ts escape="sql"}Member Since{/ts}', 'Membership', NULL, NULL ),
        ( 11,     'membership_start_date',       0, 1, 3, 'User and User Admin Only', 0, 0, NULL, '{ts escape="sql"}Start Date{/ts}', 'Membership', NULL, NULL ),
        ( 11,     'membership_end_date',         0, 1, 4, 'User and User Admin Only', 0, 0, NULL, '{ts escape="sql"}End Date{/ts}', 'Membership', NULL, NULL ),
        ( 11,     'membership_source',           0, 0, 5, 'User and User Admin Only', 0, 0, NULL, '{ts escape="sql"}Source{/ts}', 'Membership', NULL, NULL ),