Merge pull request #17981 from eileenmcnaughton/merge_form
authorEileen McNaughton <emcnaughton@wikimedia.org>
Wed, 5 Aug 2020 12:18:52 +0000 (00:18 +1200)
committerGitHub <noreply@github.com>
Wed, 5 Aug 2020 12:18:52 +0000 (00:18 +1200)
[REF] Move handling of form elements back to the Form

314 files changed:
CRM/Activity/BAO/Activity.php
CRM/Admin/Form/Setting/Localization.php
CRM/Admin/Page/Job.php
CRM/Case/BAO/Query.php
CRM/Contact/BAO/Contact/Permission.php
CRM/Contact/BAO/Query.php
CRM/Contact/Form/Search/Advanced.php
CRM/Contact/Form/Task/Useradd.php
CRM/Contribute/BAO/Contribution.php
CRM/Contribute/BAO/ContributionRecur.php
CRM/Contribute/Form/AbstractEditPayment.php
CRM/Contribute/Form/Contribution.php
CRM/Contribute/Form/Contribution/Confirm.php
CRM/Contribute/Form/Task/Invoice.php
CRM/Contribute/Form/Task/PDF.php
CRM/Contribute/Form/Task/Status.php
CRM/Contribute/Task.php
CRM/Core/BAO/Cache.php
CRM/Core/BAO/Cache/Psr16.php [deleted file]
CRM/Core/BAO/ConfigSetting.php
CRM/Core/Config.php
CRM/Core/Controller.php
CRM/Core/DAO.php
CRM/Core/Error.php
CRM/Core/Form.php
CRM/Core/Key.php
CRM/Core/Payment.php
CRM/Core/Payment/AuthorizeNetIPN.php
CRM/Core/Payment/BaseIPN.php
CRM/Core/Payment/Manual.php
CRM/Core/Payment/PayPalIPN.php
CRM/Core/Payment/PayPalProIPN.php
CRM/Core/Payment/PaymentExpress.php [deleted file]
CRM/Core/Payment/PaymentExpressUtils.php [deleted file]
CRM/Core/Smarty/plugins/block.crmButton.php
CRM/Dedupe/Merger.php
CRM/Event/BAO/Participant.php
CRM/Event/Form/Registration/Register.php
CRM/Event/Form/SelfSvcTransfer.php
CRM/Event/Form/SelfSvcUpdate.php
CRM/Export/BAO/Export.php
CRM/Export/BAO/ExportProcessor.php
CRM/Financial/BAO/Payment.php
CRM/Mailing/BAO/Mailing.php
CRM/Mailing/Event/BAO/Reply.php
CRM/Mailing/Event/BAO/Resubscribe.php
CRM/Mailing/Event/BAO/Subscribe.php
CRM/Mailing/Event/BAO/Unsubscribe.php
CRM/Mailing/Form/Subscribe.php
CRM/Member/BAO/Membership.php
CRM/Member/BAO/MembershipStatus.php
CRM/Member/Form/Membership.php
CRM/PCP/BAO/PCP.php
CRM/Price/BAO/PriceSet.php
CRM/SMS/Form/Provider.php
CRM/UF/Page/ProfileEditor.php
CRM/Upgrade/Incremental/php/FiveTwentyEight.php
CRM/Upgrade/Incremental/sql/5.29.alpha1.mysql.tpl
CRM/Utils/Check.php
CRM/Utils/Check/Component.php
CRM/Utils/Check/Component/Env.php
CRM/Utils/Hook.php
CRM/Utils/Mail.php
CRM/Utils/REST.php
CRM/Utils/SQL/TempTable.php
CRM/Utils/System.php
CRM/Utils/System/Drupal8.php
CRM/Utils/System/WordPress.php
Civi/Api4/Action/System/Check.php
Civi/Api4/Generic/AbstractGetAction.php
Civi/Api4/Generic/AbstractSaveAction.php
Civi/Api4/Generic/BasicSaveAction.php
Civi/Api4/Generic/DAOSaveAction.php
Civi/Api4/Generic/Traits/ArrayQueryActionTrait.php
Civi/Core/Container.php
Civi/Install/Requirements.php
ang/crmMailingAB/EditCtrl/report.html
ang/crmUi.js
api/v3/Contribution.php
api/v3/Order.php
css/civicrm.css
ext/flexmailer/info.xml
i/crm-button-bg.gif [deleted file]
js/Common.js
js/crm.ajax.js
release-notes.md
release-notes/5.27.4.md [new file with mode: 0644]
sql/civicrm_generated.mysql
templates/CRM/ACL/Form/ACL.tpl
templates/CRM/ACL/Form/ACLBasic.tpl
templates/CRM/ACL/Form/EntityRole.tpl
templates/CRM/Activity/Form/Search/EmptyResults.tpl
templates/CRM/Activity/Form/Task/Delete.tpl
templates/CRM/Activity/Form/Task/Print.tpl
templates/CRM/Activity/Form/Task/SearchTaskHookSample.tpl
templates/CRM/Activity/Page/UserDashboard.tpl
templates/CRM/Admin/Form/ContactType.tpl
templates/CRM/Admin/Form/Extensions.tpl
templates/CRM/Admin/Form/Job.tpl
templates/CRM/Admin/Form/LabelFormats.tpl
templates/CRM/Admin/Form/LocationType.tpl
templates/CRM/Admin/Form/MailSettings.tpl
templates/CRM/Admin/Form/Mapping.tpl
templates/CRM/Admin/Form/MessageTemplates.tpl
templates/CRM/Admin/Form/OptionGroup.tpl
templates/CRM/Admin/Form/Options.tpl
templates/CRM/Admin/Form/ParticipantStatusType.tpl
templates/CRM/Admin/Form/PaymentProcessor.tpl
templates/CRM/Admin/Form/PaymentProcessorType.tpl
templates/CRM/Admin/Form/PdfFormats.tpl
templates/CRM/Admin/Form/Preferences/Display.tpl
templates/CRM/Admin/Form/ScheduleReminders.tpl
templates/CRM/Admin/Page/APIExplorer.tpl
templates/CRM/Admin/Page/CKEditorConfig.tpl
templates/CRM/Admin/Page/EventTemplate.tpl
templates/CRM/Admin/Page/Extensions/AddNew.tpl
templates/CRM/Admin/Page/Extensions/AddNewReq.tpl
templates/CRM/Admin/Page/Extensions/Main.tpl
templates/CRM/Admin/Page/Job.tpl
templates/CRM/Admin/Page/JobLog.tpl
templates/CRM/Admin/Page/LabelFormats.tpl
templates/CRM/Admin/Page/MessageTemplates.tpl
templates/CRM/Admin/Page/PaymentProcessor.tpl
templates/CRM/Admin/Page/PdfFormats.tpl
templates/CRM/Admin/Page/ScheduleReminders.tpl
templates/CRM/Badge/Form/Layout.tpl
templates/CRM/Batch/Form/Batch.tpl
templates/CRM/Campaign/Form/Campaign.tpl
templates/CRM/Campaign/Form/Gotv.tpl
templates/CRM/Campaign/Form/Petition.tpl
templates/CRM/Campaign/Form/Search/Campaign.tpl
templates/CRM/Campaign/Form/Search/EmptyResults.tpl
templates/CRM/Campaign/Form/Search/Petition.tpl
templates/CRM/Campaign/Form/Search/Survey.tpl
templates/CRM/Campaign/Form/Survey/Delete.tpl
templates/CRM/Campaign/Form/Task/Interview.tpl
templates/CRM/Campaign/Form/Task/Print.tpl
templates/CRM/Campaign/Form/Task/Release.tpl
templates/CRM/Campaign/Form/Task/Reserve.tpl
templates/CRM/Campaign/Page/Petition.tpl
templates/CRM/Campaign/Page/Petition/Confirm.tpl
templates/CRM/Campaign/Page/SurveyType.tpl
templates/CRM/Campaign/Page/Vote.tpl
templates/CRM/Case/Form/Case.tpl
templates/CRM/Case/Form/EditClient.tpl
templates/CRM/Case/Form/Search/EmptyResults.tpl
templates/CRM/Case/Form/Task/Delete.tpl
templates/CRM/Case/Form/Task/Print.tpl
templates/CRM/Case/Form/Task/Restore.tpl
templates/CRM/Case/Form/Task/SearchTaskHookSample.tpl
templates/CRM/Case/Page/ConfigureError.tpl
templates/CRM/Case/Page/Tab.tpl
templates/CRM/Contact/Form/Edit/Address.tpl
templates/CRM/Contact/Form/Merge.tpl
templates/CRM/Contact/Form/Search/Custom/EmptyResults.tpl
templates/CRM/Contact/Form/Search/Custom/FullText.tpl
templates/CRM/Contact/Form/Search/EmptyResults.tpl
templates/CRM/Contact/Form/Task/Delete.tpl
templates/CRM/Contact/Form/Task/HookSample.tpl
templates/CRM/Contact/Form/Task/Print.tpl
templates/CRM/Contact/Form/Task/Unhold.tpl
templates/CRM/Contact/Page/View/ContactSmartGroup.tpl
templates/CRM/Contact/Page/View/Delete.tpl
templates/CRM/Contact/Page/View/Group.tpl
templates/CRM/Contact/Page/View/GroupContact.tpl
templates/CRM/Contact/Page/View/Log.tpl
templates/CRM/Contact/Page/View/Note.tpl
templates/CRM/Contact/Page/View/UserDashBoard/GroupContact.tpl
templates/CRM/Contribute/Form/AcceptCreditCard.tpl
templates/CRM/Contribute/Form/AdditionalPayment.tpl
templates/CRM/Contribute/Form/CancelSubscription.tpl
templates/CRM/Contribute/Form/Contribution.tpl
templates/CRM/Contribute/Form/Contribution/Main.tpl
templates/CRM/Contribute/Form/ContributionPage/AddProduct.tpl
templates/CRM/Contribute/Form/ContributionPage/Amount.tpl
templates/CRM/Contribute/Form/ContributionPage/Delete.tpl
templates/CRM/Contribute/Form/ContributionPage/Widget.tpl
templates/CRM/Contribute/Form/ManagePremiums.tpl
templates/CRM/Contribute/Form/PCP/Delete.tpl
templates/CRM/Contribute/Form/PaymentInstrument.tpl
templates/CRM/Contribute/Form/Search/EmptyResults.tpl
templates/CRM/Contribute/Form/Task/Delete.tpl
templates/CRM/Contribute/Form/Task/Invoice.tpl
templates/CRM/Contribute/Form/Task/PDF.tpl
templates/CRM/Contribute/Form/Task/Print.tpl
templates/CRM/Contribute/Form/Task/SearchTaskHookSample.tpl
templates/CRM/Contribute/Form/Task/Status.tpl
templates/CRM/Contribute/Form/UpdateBilling.tpl
templates/CRM/Contribute/Page/ContributionPage.tpl
templates/CRM/Contribute/Page/ContributionRecurPayments.tpl
templates/CRM/Contribute/Page/ContributionType.tpl
templates/CRM/Contribute/Page/PcpUserDashboard.tpl
templates/CRM/Contribute/Page/Premium.tpl
templates/CRM/Contribute/Page/Tab.tpl
templates/CRM/Contribute/Page/UserDashboard.tpl
templates/CRM/Core/Form/EntityForm.tpl
templates/CRM/Custom/Form/ChangeFieldType.tpl
templates/CRM/Custom/Form/DeleteField.tpl
templates/CRM/Custom/Form/DeleteFile.tpl
templates/CRM/Custom/Form/DeleteGroup.tpl
templates/CRM/Custom/Form/Option.tpl
templates/CRM/Custom/Page/Option.tpl
templates/CRM/Dashlet/Page/Blog.tpl
templates/CRM/Event/Form/ManageEvent/Delete.tpl
templates/CRM/Event/Form/Participant.tpl
templates/CRM/Event/Form/ParticipantFeeSelection.tpl
templates/CRM/Event/Form/Registration/Register.tpl
templates/CRM/Event/Form/Search/EmptyResults.tpl
templates/CRM/Event/Form/Task/Cancel.tpl
templates/CRM/Event/Form/Task/Delete.tpl
templates/CRM/Event/Form/Task/Print.tpl
templates/CRM/Event/Form/Task/SearchTaskHookSample.tpl
templates/CRM/Event/Page/DashBoard.tpl
templates/CRM/Event/Page/ManageEvent.tpl
templates/CRM/Event/Page/ParticipantListing/Name.tpl
templates/CRM/Event/Page/ParticipantListing/NameAndEmail.tpl
templates/CRM/Event/Page/ParticipantListing/NameStatusAndDate.tpl
templates/CRM/Event/Page/Tab.tpl
templates/CRM/Event/Page/UserDashboard.tpl
templates/CRM/Financial/Form/Export.tpl
templates/CRM/Financial/Form/FinancialAccount.tpl
templates/CRM/Financial/Form/FinancialBatch.tpl
templates/CRM/Financial/Form/FinancialTypeAccount.tpl
templates/CRM/Financial/Page/FinancialAccount.tpl
templates/CRM/Financial/Page/FinancialType.tpl
templates/CRM/Financial/Page/FinancialTypeAccount.tpl
templates/CRM/Grant/Form/Grant.tpl
templates/CRM/Grant/Form/Search/EmptyResults.tpl
templates/CRM/Grant/Form/Task/Delete.tpl
templates/CRM/Grant/Form/Task/Print.tpl
templates/CRM/Grant/Form/Task/SearchTaskHookSample.tpl
templates/CRM/Grant/Page/Tab.tpl
templates/CRM/Logging/ReportDetail.tpl
templates/CRM/Mailing/Form/Task/Print.tpl
templates/CRM/Mailing/Page/Browse.tpl
templates/CRM/Mailing/Page/Confirm.tpl
templates/CRM/Mailing/Page/Event.tpl
templates/CRM/Mailing/Page/Resubscribe.tpl
templates/CRM/Member/Form/Membership.tpl
templates/CRM/Member/Form/MembershipRenewal.tpl
templates/CRM/Member/Form/MembershipStatus.tpl
templates/CRM/Member/Form/MembershipType.tpl
templates/CRM/Member/Form/Search/EmptyResults.tpl
templates/CRM/Member/Form/Task/Delete.tpl
templates/CRM/Member/Form/Task/SearchTaskHookSample.tpl
templates/CRM/Member/Page/MembershipType.tpl
templates/CRM/Member/Page/Tab.tpl
templates/CRM/Member/Page/UserDashboard.tpl
templates/CRM/PCP/Form/PCP/Delete.tpl
templates/CRM/PCP/Page/PCP.tpl
templates/CRM/PCP/Page/PCPInfo.tpl
templates/CRM/Pledge/Form/Pledge.tpl
templates/CRM/Pledge/Form/PledgeView.tpl
templates/CRM/Pledge/Form/Search/EmptyResults.tpl
templates/CRM/Pledge/Form/Task/Delete.tpl
templates/CRM/Pledge/Form/Task/Print.tpl
templates/CRM/Pledge/Form/Task/SearchTaskHookSample.tpl
templates/CRM/Pledge/Page/Tab.tpl
templates/CRM/Pledge/Page/UserDashboard.tpl
templates/CRM/Price/Form/DeleteField.tpl
templates/CRM/Price/Form/Option.tpl
templates/CRM/Price/Form/PriceSet.tpl
templates/CRM/Price/Page/Field.tpl
templates/CRM/Price/Page/Option.tpl
templates/CRM/Price/Page/Set.tpl
templates/CRM/Profile/Form/Dynamic.tpl
templates/CRM/Profile/Form/Search.tpl
templates/CRM/Profile/Page/Listings.tpl
templates/CRM/Profile/Page/MultipleRecordFieldsListing.tpl
templates/CRM/Report/Form/Actions.tpl
templates/CRM/Report/Form/ErrorMessage.tpl
templates/CRM/Report/Form/Register.tpl
templates/CRM/Report/Page/InstanceList.tpl
templates/CRM/Report/Page/TemplateList.tpl
templates/CRM/SMS/Form/Group.tpl
templates/CRM/SMS/Form/Provider.tpl
templates/CRM/SMS/Page/Provider.tpl
templates/CRM/Tag/Page/Tag.tpl
templates/CRM/UF/Form/Field.tpl
templates/CRM/UF/Form/Group.tpl
templates/CRM/UF/Page/Field.tpl
templates/CRM/UF/Page/Group.tpl
templates/CRM/common/civicrm.settings.php.template
templates/CRM/common/formButtons.tpl
templates/CRM/common/info.tpl
templates/CRM/common/l10n.js.tpl
tests/phpunit/CRM/Case/BAO/QueryTest.php
tests/phpunit/CRM/Contact/Form/Task/UseraddTest.php [new file with mode: 0644]
tests/phpunit/CRM/Contact/SelectorTest.php
tests/phpunit/CRM/Contribute/BAO/ContributionRecurTest.php
tests/phpunit/CRM/Contribute/BAO/ContributionTest.php
tests/phpunit/CRM/Contribute/Form/ContributionTest.php
tests/phpunit/CRM/Contribute/Form/Task/InvoiceTest.php
tests/phpunit/CRM/Core/BAO/CacheTest.php
tests/phpunit/CRM/Core/Payment/AuthorizeNetIPNTest.php
tests/phpunit/CRM/Core/Payment/BaseIPNTest.php
tests/phpunit/CRM/Event/BAO/EventPermissionsTest.php
tests/phpunit/CRM/Event/BAO/ParticipantTest.php
tests/phpunit/CRM/Event/Form/ParticipantTest.php
tests/phpunit/CRM/Event/Form/Task/ParticipantStatusTest.php [new file with mode: 0644]
tests/phpunit/CRM/Export/BAO/ExportTest.php
tests/phpunit/CRM/Member/BAO/MembershipStatusTest.php
tests/phpunit/CRM/PCP/BAO/PCPTest.php
tests/phpunit/CRM/SMS/ProviderTest.php
tests/phpunit/CRM/UF/Page/ProfileEditorTest.php
tests/phpunit/CRMTraits/ACL/PermissionTrait.php
tests/phpunit/CiviTest/CiviUnitTestCase.php
tests/phpunit/api/v3/ContactTest.php
tests/phpunit/api/v3/ContributionTest.php
tests/phpunit/api/v3/MailingGroupTest.php
tests/phpunit/api/v3/MembershipTest.php
tests/phpunit/api/v3/PaymentTest.php
tests/phpunit/api/v4/Entity/SystemTest.php [new file with mode: 0644]
xml/templates/civicrm_data.tpl

index a4065942ca0985398024d3802cbd6e94b9a0ace2..3c8a0eb1551f2ee1c10baf75e16ccdfbd2b2d205 100644 (file)
@@ -1783,16 +1783,14 @@ WHERE      activity.id IN ($activityIds)";
    *   particular component object.
    *
    * @return string
+   * @throws \CRM_Core_Exception
    */
   public static function getActivitySubject($entityObj) {
+    // @todo determine the subject on the appropriate entity rather than from the activity.
     switch ($entityObj->__table) {
       case 'civicrm_membership':
-        $membershipType = CRM_Member_PseudoConstant::membershipType($entityObj->membership_type_id);
-        $subject = $membershipType ? $membershipType : ts('Membership');
-
-        if (is_array($subject)) {
-          $subject = implode(", ", $subject);
-        }
+        $membershipType = CRM_Core_PseudoConstant::getLabel('CRM_Member_BAO_Membership', 'membership_type_id', $entityObj->membership_type_id);
+        $subject = $membershipType ?: ts('Membership');
 
         if (!CRM_Utils_System::isNull($entityObj->source)) {
           $subject .= " - {$entityObj->source}";
@@ -1803,7 +1801,7 @@ WHERE      activity.id IN ($activityIds)";
           $subject .= sprintf(' (by %s)', $displayName);
         }
 
-        $subject .= " - Status: " . CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipStatus', $entityObj->status_id, 'label');
+        $subject .= ' - Status: ' . CRM_Core_PseudoConstant::getLabel('CRM_Member_BAO_Membership', 'status_id', $entityObj->status_id);
         return $subject;
 
       case 'civicrm_participant':
@@ -2132,91 +2130,75 @@ AND cl.modified_id  = c.id
     self::$_exportableFields[$name] = [];
 
     // TODO: ideally we should retrieve all fields from xml, in this case since activity processing is done
-    // my case hence we have defined fields as case_*
-    if ($name === 'Activity') {
-      $exportableFields = CRM_Activity_DAO_Activity::export();
-      $exportableFields['source_contact_id'] = [
-        'title' => ts('Source Contact ID'),
-        'type' => CRM_Utils_Type::T_INT,
-      ];
-      $exportableFields['source_contact'] = [
-        'title' => ts('Source Contact'),
+    $exportableFields = CRM_Activity_DAO_Activity::export();
+    $exportableFields['source_contact_id'] = [
+      'title' => ts('Source Contact ID'),
+      'type' => CRM_Utils_Type::T_INT,
+    ];
+    $exportableFields['source_contact'] = [
+      'title' => ts('Source Contact'),
+      'type' => CRM_Utils_Type::T_STRING,
+    ];
+
+    // @todo - remove these - they are added by CRM_Core_DAO::appendPseudoConstantsToFields
+    // below. That search label stuff is referenced in search builder but is likely just
+    // a hack that duplicates, maybe differently, other functionality.
+    $activityFields = [
+      'activity_type' => [
+        'title' => ts('Activity Type'),
+        'name' => 'activity_type',
         'type' => CRM_Utils_Type::T_STRING,
-      ];
+        'searchByLabel' => TRUE,
+      ],
+      'activity_status' => [
+        'title' => ts('Activity Status'),
+        'name' => 'activity_status',
+        'type' => CRM_Utils_Type::T_STRING,
+        'searchByLabel' => TRUE,
+      ],
+      'activity_priority' => [
+        'title' => ts('Activity Priority'),
+        'name' => 'activity_priority',
+        'type' => CRM_Utils_Type::T_STRING,
+        'searchByLabel' => TRUE,
+      ],
+    ];
+    $fields = array_merge($activityFields, $exportableFields);
+    $fields['activity_type_id']['title'] = ts('Activity Type ID');
+    $fields['activity_priority_id'] = $fields['priority_id'];
 
-      // @todo - remove these - they are added by CRM_Core_DAO::appendPseudoConstantsToFields
-      // below. That search label stuff is referenced in search builder but is likely just
-      // a hack that duplicates, maybe differently, other functionality.
-      $Activityfields = [
-        'activity_type' => [
-          'title' => ts('Activity Type'),
-          'name' => 'activity_type',
-          'type' => CRM_Utils_Type::T_STRING,
-          'searchByLabel' => TRUE,
-        ],
-        'activity_status' => [
-          'title' => ts('Activity Status'),
-          'name' => 'activity_status',
-          'type' => CRM_Utils_Type::T_STRING,
-          'searchByLabel' => TRUE,
-        ],
-        'activity_priority' => [
-          'title' => ts('Activity Priority'),
-          'name' => 'activity_priority',
-          'type' => CRM_Utils_Type::T_STRING,
-          'searchByLabel' => TRUE,
-        ],
-      ];
-      $fields = array_merge($Activityfields, $exportableFields);
-      $fields['activity_type_id']['title'] = ts('Activity Type ID');
-    }
-    else {
+    if ($name === 'Case') {
+      // Now add "case_activity" fields
       // Set title to activity fields.
-      $fields = [
-        'case_activity_subject' => [
-          'title' => ts('Activity Subject'),
-          'type' => CRM_Utils_Type::T_STRING,
-        ],
+      $caseActivityFields = [
         'case_source_contact_id' => [
           'title' => ts('Activity Reporter'),
           'type' => CRM_Utils_Type::T_STRING,
         ],
-        'case_recent_activity_date' => [
-          'title' => ts('Activity Actual Date'),
+        'case_activity_date_time' => [
+          'title' => ts('Activity Date'),
           'type' => CRM_Utils_Type::T_DATE,
         ],
-        'case_scheduled_activity_date' => [
-          'title' => ts('Activity Scheduled Date'),
-          'type' => CRM_Utils_Type::T_DATE,
-        ],
-        'case_recent_activity_type' => [
+        'case_activity_type' => [
           'title' => ts('Activity Type'),
           'type' => CRM_Utils_Type::T_STRING,
         ],
-        'case_activity_status' => [
-          'title' => ts('Activity Status'),
-          'type' => CRM_Utils_Type::T_STRING,
-        ],
-        'case_activity_duration' => [
-          'title' => ts('Activity Duration'),
-          'type' => CRM_Utils_Type::T_INT,
-        ],
         'case_activity_medium_id' => [
           'title' => ts('Activity Medium'),
           'type' => CRM_Utils_Type::T_INT,
         ],
-        'case_activity_details' => [
-          'title' => ts('Activity Details'),
-          'type' => CRM_Utils_Type::T_TEXT,
-        ],
         'case_activity_is_auto' => [
           'title' => ts('Activity Auto-generated?'),
           'type' => CRM_Utils_Type::T_BOOLEAN,
         ],
       ];
+      $caseStandardFields = ['activity_subject', 'activity_status', 'activity_duration', 'activity_details'];
+      foreach ($caseStandardFields as $key) {
+        $caseActivityFields['case_' . $key] = $fields[$key];
+      }
+      $fields = $caseActivityFields;
     }
-
-    // add custom data for case activities
+    // Add custom data
     $fields = array_merge($fields, CRM_Core_BAO_CustomField::getFieldsForImport('Activity'));
     CRM_Core_DAO::appendPseudoConstantsToFields($fields);
     self::$_exportableFields[$name] = $fields;
index 83194effcea58fc1f2add936301dffa0c33d932f..d33ebb369df1096f9e78358b8119c1438f0b516b 100644 (file)
@@ -325,8 +325,6 @@ class CRM_Admin_Form_Setting_Localization extends CRM_Admin_Form_Setting {
       $ufm = new CRM_Core_DAO_UFMatch();
       $ufm->contact_id = $session->get('userID');
       if ($newLocale && $ufm->find(TRUE)) {
-        $ufm->language = $newLocale;
-        $ufm->save();
         $session->set('lcMessages', $newLocale);
       }
     }
index e8ba06d9d549feddc6523d1bfb01834c7c1a3b4c..2164d2b7cefa57fd7c6531b9b6243d2933abf7cd 100644 (file)
@@ -142,6 +142,17 @@ class CRM_Admin_Page_Job extends CRM_Core_Page_Basic {
     if (CRM_Core_Config::environment() != 'Production') {
       CRM_Core_Session::setStatus(ts('Execution of scheduled jobs has been turned off by default since this is a non-production environment. You can override this for particular jobs by adding runInNonProductionEnvironment=TRUE as a parameter.'), ts("Non-production Environment"), "warning", array('expires' => 0));
     }
+    else {
+      $cronError = Civi\Api4\System::check(FALSE)
+        ->addWhere('name', '=', 'checkLastCron')
+        ->addWhere('severity_id', '>', 1)
+        ->setIncludeDisabled(TRUE)
+        ->execute()
+        ->first();
+      if ($cronError) {
+        CRM_Core_Session::setStatus($cronError['message'], $cronError['title'], 'alert', ['expires' => 0]);
+      }
+    }
 
     $sj = new CRM_Core_JobManager();
     $rows = $temp = [];
index 71a5e0f1473f5d564daed5b428fd74b68bb765d2..6958dc66740d48098149e40dceb22adba2d16b0c 100644 (file)
@@ -100,9 +100,9 @@ class CRM_Case_BAO_Query extends CRM_Core_BAO_Query {
       $query->_tables['case_relation_type'] = $query->_whereTables['case_relation_type'] = 1;
     }
 
-    if (!empty($query->_returnProperties['case_recent_activity_date'])) {
-      $query->_select['case_recent_activity_date'] = "case_activity.activity_date_time as case_recent_activity_date";
-      $query->_element['case_recent_activity_date'] = 1;
+    if (!empty($query->_returnProperties['case_activity_date_time'])) {
+      $query->_select['case_activity_date_time'] = "case_activity.activity_date_time as case_activity_date_time";
+      $query->_element['case_activity_date_time'] = 1;
       $query->_tables['case_activity'] = $query->_whereTables['case_activity'] = 1;
     }
 
@@ -121,6 +121,7 @@ class CRM_Case_BAO_Query extends CRM_Core_BAO_Query {
       $query->_tables['civicrm_case'] = 1;
     }
 
+    // @todo switch to a more standard case_source_contact as the key where we want the name not the id.
     if (!empty($query->_returnProperties['case_source_contact_id'])) {
       $query->_select['case_source_contact_id'] = "civicrm_case_reporter.sort_name as case_source_contact_id";
       $query->_element['case_source_contact_id'] = 1;
@@ -134,7 +135,7 @@ class CRM_Case_BAO_Query extends CRM_Core_BAO_Query {
       $query->_select['case_activity_status_id'] = "rec_activity_status.id as case_activity_status_id";
       $query->_element['case_activity_status_id'] = 1;
       $query->_tables['case_activity'] = 1;
-      $query->_tables['recent_activity_status'] = 1;
+      $query->_tables['case_activity_status'] = 1;
       $query->_tables['civicrm_case_contact'] = 1;
       $query->_tables['civicrm_case'] = 1;
     }
@@ -143,7 +144,7 @@ class CRM_Case_BAO_Query extends CRM_Core_BAO_Query {
       $query->_select['case_activity_status'] = "rec_activity_status.label as case_activity_status";
       $query->_element['case_activity_status'] = 1;
       $query->_tables['case_activity'] = 1;
-      $query->_tables['recent_activity_status'] = 1;
+      $query->_tables['case_activity_status'] = 1;
       $query->_tables['civicrm_case_contact'] = 1;
       $query->_tables['civicrm_case'] = 1;
     }
@@ -157,7 +158,7 @@ class CRM_Case_BAO_Query extends CRM_Core_BAO_Query {
     }
 
     if (!empty($query->_returnProperties['case_activity_medium_id'])) {
-      $query->_select['case_activity_medium_id'] = "recent_activity_medium.label as case_activity_medium_id";
+      $query->_select['case_activity_medium_id'] = "case_activity_medium.label as case_activity_medium_id";
       $query->_element['case_activity_medium_id'] = 1;
       $query->_tables['case_activity'] = 1;
       $query->_tables['case_activity_medium'] = 1;
@@ -181,16 +182,16 @@ class CRM_Case_BAO_Query extends CRM_Core_BAO_Query {
       $query->_tables['civicrm_case'] = 1;
     }
 
-    if (!empty($query->_returnProperties['case_scheduled_activity_date'])) {
-      $query->_select['case_scheduled_activity_date'] = "case_activity.activity_date_time as case_scheduled_activity_date";
-      $query->_element['case_scheduled_activity_date'] = 1;
+    if (!empty($query->_returnProperties['case_activity_date_time'])) {
+      $query->_select['case_activity_date_time'] = "case_activity.activity_date_time as case_activity_date_time";
+      $query->_element['case_activity_date_time'] = 1;
       $query->_tables['case_activity'] = 1;
       $query->_tables['civicrm_case_contact'] = 1;
       $query->_tables['civicrm_case'] = 1;
     }
-    if (!empty($query->_returnProperties['case_recent_activity_type'])) {
-      $query->_select['case_recent_activity_type'] = "rec_activity_type.label as case_recent_activity_type";
-      $query->_element['case_recent_activity_type'] = 1;
+    if (!empty($query->_returnProperties['case_activity_type'])) {
+      $query->_select['case_activity_type'] = "rec_activity_type.label as case_activity_type";
+      $query->_element['case_activity_type'] = 1;
       $query->_tables['case_activity'] = 1;
       $query->_tables['case_activity_type'] = 1;
       $query->_tables['civicrm_case_contact'] = 1;
@@ -320,6 +321,7 @@ class CRM_Case_BAO_Query extends CRM_Core_BAO_Query {
         $query->handleWhereFromMetadata($fieldSpec, $name, $value, $op);
         return;
 
+      // @todo switch to a more standard case_source_contact as the key where we want the name not the id.
       case 'case_source_contact_id':
         $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("civicrm_case_reporter.sort_name", $op, $value, 'String');
         $query->_qill[$grouping][] = ts("Activity Reporter %1 '%2'", [1 => $op, 2 => $value]);
@@ -329,31 +331,19 @@ class CRM_Case_BAO_Query extends CRM_Core_BAO_Query {
         $query->_tables['civicrm_case_contact'] = $query->_whereTables['civicrm_case_contact'] = 1;
         return;
 
-      case 'case_recent_activity_date':
+      case 'case_activity_date_time':
         $date = CRM_Utils_Date::format($value);
         $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("case_activity.activity_date_time", $op, $date, 'Date');
         if ($date) {
           $date = CRM_Utils_Date::customFormat($date);
-          $query->_qill[$grouping][] = ts("Activity Actual Date %1 %2", [1 => $op, 2 => $date]);
+          $query->_qill[$grouping][] = ts("Activity Date %1 %2", [1 => $op, 2 => $date]);
         }
         $query->_tables['case_activity'] = $query->_whereTables['case_activity'] = 1;
         $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1;
         $query->_tables['civicrm_case_contact'] = $query->_whereTables['civicrm_case_contact'] = 1;
         return;
 
-      case 'case_scheduled_activity_date':
-        $date = CRM_Utils_Date::format($value);
-        $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("case_activity.activity_date_time", $op, $date, 'Date');
-        if ($date) {
-          $date = CRM_Utils_Date::customFormat($date);
-          $query->_qill[$grouping][] = ts("Activity Schedule Date %1 %2", [1 => $op, 2 => $date]);
-        }
-        $query->_tables['case_activity'] = $query->_whereTables['case_activity'] = 1;
-        $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1;
-        $query->_tables['civicrm_case_contact'] = $query->_whereTables['civicrm_case_contact'] = 1;
-        return;
-
-      case 'case_recent_activity_type':
+      case 'case_activity_type':
         $names = $value;
         if (($activityType = CRM_Core_PseudoConstant::getLabel('CRM_Activity_BAO_Activity', 'activity_type_id', $value)) != FALSE) {
           $names = $activityType;
@@ -374,7 +364,7 @@ class CRM_Case_BAO_Query extends CRM_Core_BAO_Query {
         }
 
         $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause("case_activity.status_id", $op, $value, 'Int');
-        $query->_qill[$grouping][] = ts("Activity Type %1 %2", [1 => $op, 2 => $names]);
+        $query->_qill[$grouping][] = ts("Activity Status %1 %2", [1 => $op, 2 => $names]);
         $query->_tables['case_activity'] = $query->_whereTables['case_activity'] = 1;
         $query->_tables['civicrm_case'] = $query->_whereTables['civicrm_case'] = 1;
         $query->_tables['case_activity_status'] = 1;
@@ -537,7 +527,7 @@ class CRM_Case_BAO_Query extends CRM_Core_BAO_Query {
         $from .= " $side JOIN civicrm_option_value rec_activity_type ON (case_activity.activity_type_id = rec_activity_type.value AND option_group_activity_type.id = rec_activity_type.option_group_id ) ";
         break;
 
-      case 'recent_activity_status':
+      case 'case_activity_status':
         $from .= " $side JOIN civicrm_option_group option_group_activity_status ON (option_group_activity_status.name = 'activity_status')";
         $from .= " $side JOIN civicrm_option_value rec_activity_status ON (case_activity.status_id = rec_activity_status.value AND option_group_activity_status.id = rec_activity_status.option_group_id ) ";
         break;
@@ -555,7 +545,7 @@ case_relation_type.id = case_relationship.relationship_type_id )";
 
       case 'case_activity_medium':
         $from .= " $side JOIN civicrm_option_group option_group_activity_medium ON (option_group_activity_medium.name = 'encounter_medium')";
-        $from .= " $side JOIN civicrm_option_value recent_activity_medium ON (case_activity.medium_id = recent_activity_medium.value AND option_group_activity_medium.id = recent_activity_medium.option_group_id ) ";
+        $from .= " $side JOIN civicrm_option_value case_activity_medium ON (case_activity.medium_id = case_activity_medium.value AND option_group_activity_medium.id = case_activity_medium.option_group_id ) ";
         break;
 
       case 'case_activity':
@@ -607,11 +597,9 @@ case_relation_type.id = case_relationship.relationship_type_id )";
         'case_type' => 1,
         'case_role' => 1,
         'case_deleted' => 1,
-        'case_recent_activity_date' => 1,
-        'case_recent_activity_type' => 1,
-        'case_scheduled_activity_date' => 1,
+        'case_activity_date_time' => 1,
+        'case_activity_type' => 1,
         'phone' => 1,
-        // 'case_scheduled_activity_type'=>      1
       ];
 
       if ($includeCustomFields) {
@@ -643,6 +631,7 @@ case_relation_type.id = case_relationship.relationship_type_id )";
         'case_start_date' => 1,
         'case_end_date' => 1,
         'case_subject' => 1,
+        // @todo switch to a more standard case_source_contact as the key where we want the name not the id.
         'case_source_contact_id' => 1,
         'case_activity_status' => 1,
         'case_activity_duration' => 1,
index 964fc47295c245859ff2242eeb7d324301ac8770..1aae3cea9a7d54ad6f626ebe88f3a5d375454ae4 100644 (file)
@@ -307,17 +307,16 @@ AND    $operationClause
     if (CRM_Core_Permission::check('view all contacts') ||
       CRM_Core_Permission::check('edit all contacts')
     ) {
-      if (is_array($contactAlias)) {
+      if (!CRM_Core_Permission::check('access deleted contacts')) {
         $wheres = [];
-        foreach ($contactAlias as $alias) {
+        foreach ((array) $contactAlias as $alias) {
           // CRM-6181
           $wheres[] = "$alias.is_deleted = 0";
         }
         return [NULL, '(' . implode(' AND ', $wheres) . ')'];
       }
       else {
-        // CRM-6181
-        return [NULL, "$contactAlias.is_deleted = 0"];
+        return [NULL, '( 1 )'];
       }
     }
 
@@ -332,14 +331,17 @@ AND    $operationClause
       }
 
       $fromClause = implode(" ", $clauses);
-      $whereClase = NULL;
+      $whereClause = NULL;
     }
     else {
       $fromClause = " INNER JOIN civicrm_acl_contact_cache aclContactCache ON {$contactAlias}.id = aclContactCache.contact_id ";
-      $whereClase = " aclContactCache.user_id = $contactID AND $contactAlias.is_deleted = 0";
+      $whereClause = " aclContactCache.user_id = $contactID";
+      if (!CRM_Core_Permission::check('access deleted contacts')) {
+        $whereClause .= " AND $contactAlias.is_deleted = 0";
+      }
     }
 
-    return [$fromClause, $whereClase];
+    return [$fromClause, $whereClause];
   }
 
   /**
index 648fd5d95738ad737edaccec399052a00f115339..a6b2545d8bfc72265a4d1feaa3992befbc5771c6 100644 (file)
@@ -517,6 +517,7 @@ class CRM_Contact_BAO_Query {
 
       // add activity fields
       $this->_fields = array_merge($this->_fields, CRM_Activity_BAO_Activity::exportableFields());
+      $this->_fields = array_merge($this->_fields, CRM_Activity_BAO_Activity::exportableFields('Case'));
       // Add hack as no unique name is defined for the field but the search form is in denial.
       $this->_fields['activity_priority_id'] = $this->_fields['priority_id'];
 
@@ -1487,6 +1488,9 @@ class CRM_Contact_BAO_Query {
     }
 
     if (!empty($this->_permissionWhereClause) && empty($this->_displayRelationshipType)) {
+      if (!empty($this->_permissionFromClause)) {
+        $from .= " $this->_permissionFromClause";
+      }
       if (empty($where)) {
         $where = "WHERE $this->_permissionWhereClause";
       }
@@ -4603,6 +4607,9 @@ civicrm_relationship.start_date > {$today}
 
     $options = $query->_options;
     if (!empty($query->_permissionWhereClause)) {
+      if (!empty($query->_permissionFromClause) && !stripos($from, 'aclContactCache')) {
+        $from .= " $query->_permissionFromClause";
+      }
       if (empty($where)) {
         $where = "WHERE $query->_permissionWhereClause";
       }
@@ -4982,10 +4989,7 @@ civicrm_relationship.start_date > {$today}
     $sqlParts = $this->getSearchSQLParts(NULL, NULL, NULL, FALSE, FALSE, TRUE);
     $query = "SELECT DISTINCT LEFT(contact_a.sort_name, 1) as sort_name
       {$sqlParts['from']}
-      {$sqlParts['where']}
-      {$sqlParts['having']}
-      GROUP BY sort_name
-      ORDER BY sort_name asc";
+      {$sqlParts['where']}";
     $dao = CRM_Core_DAO::executeQuery($query);
     return $dao;
   }
@@ -5051,17 +5055,22 @@ civicrm_relationship.start_date > {$today}
    */
   public function generatePermissionClause($onlyDeleted = FALSE, $count = FALSE) {
     if (!$this->_skipPermission) {
-      $this->_permissionWhereClause = CRM_ACL_API::whereClause(
-        CRM_Core_Permission::VIEW,
-        $this->_tables,
-        $this->_whereTables,
-        NULL,
-        $onlyDeleted,
-        $this->_skipDeleteClause
-      );
+      $permissionClauses = CRM_Contact_BAO_Contact_Permission::cacheClause();
+      $this->_permissionWhereClause = $permissionClauses[1];
+      $this->_permissionFromClause = $permissionClauses[0];
 
-      if (!$onlyDeleted && CRM_Core_Permission::check('access deleted contacts')) {
-        $this->_permissionWhereClause = str_replace(' ( 1 ) ', '(contact_a.is_deleted = 0)', $this->_permissionWhereClause);
+      if (CRM_Core_Permission::check('access deleted contacts')) {
+        if (!$onlyDeleted) {
+          $this->_permissionWhereClause = str_replace('( 1 )', '(contact_a.is_deleted = 0)', $this->_permissionWhereClause);
+        }
+        else {
+          if ($this->_permissionWhereClause === '( 1 )') {
+            $this->_permissionWhereClause = str_replace('( 1 )', '(contact_a.is_deleted)', $this->_permissionWhereClause);
+          }
+          else {
+            $this->_permissionWhereClause .= " AND (contact_a.is_deleted) ";
+          }
+        }
       }
 
       if (isset($this->_tables['civicrm_activity'])) {
@@ -5085,19 +5094,6 @@ civicrm_relationship.start_date > {$today}
           $this->_permissionWhereClause .= '(' . implode(' AND ', $clauses) . ')';
         }
       }
-
-      // regenerate fromClause since permission might have added tables
-      if ($this->_permissionWhereClause) {
-        //fix for row count in qill (in contribute/membership find)
-        if (!$count) {
-          $this->_useDistinct = TRUE;
-        }
-        //CRM-15231
-        $this->_fromClause = self::fromClause($this->_tables, NULL, NULL, $this->_primaryLocation, $this->_mode);
-        $this->_simpleFromClause = self::fromClause($this->_whereTables, NULL, NULL, $this->_primaryLocation, $this->_mode);
-        // note : this modifies _fromClause and _simpleFromClause
-        $this->includePseudoFieldsJoin($this->_sort);
-      }
     }
     else {
       // add delete clause if needed even if we are skipping permission
@@ -5129,6 +5125,9 @@ civicrm_relationship.start_date > {$today}
    */
   public function summaryContribution($context = NULL) {
     list($innerselect, $from, $where, $having) = $this->query(TRUE);
+    if (!empty($this->_permissionFromClause) && !stripos($from, 'aclContactCache')) {
+      $from .= " $this->_permissionFromClause";
+    }
     if ($this->_permissionWhereClause) {
       $where .= " AND " . $this->_permissionWhereClause;
     }
@@ -5832,6 +5831,9 @@ AND   displayRelType.is_active = 1
       $from = str_replace("INNER JOIN", "LEFT JOIN", $from);
       $from .= $qcache['from'];
       $where = $qcache['where'];
+      if (!empty($this->_permissionFromClause) && !stripos($from, 'aclContactCache')) {
+        $from .= " $this->_permissionFromClause";
+      }
       if (!empty($this->_permissionWhereClause)) {
         $where .= "AND $this->_permissionWhereClause";
       }
index f517389c4dcecc16e2d969fc31b4edd0a7d11894..e579c743316625c7ba92096d5ce68b0b44eed638 100644 (file)
@@ -189,7 +189,7 @@ class CRM_Contact_Form_Search_Advanced extends CRM_Contact_Form_Search {
       'privacy_toggle' => 1,
       'operator' => 'AND',
     ], $defaults);
-    $this->normalizeDefaultValues($defaults);
+    $defaults = $this->normalizeDefaultValues($defaults);
 
     //991/Subtypes not respected when editing smart group criteria
     if (!empty($defaults['contact_type']) && !empty($this->_formValues['contact_sub_type'])) {
index b9a8056721633f1ef63090d42907d43f36ec653c..385405c6a2e145d57e34e170e1fa532c926591fc 100644 (file)
@@ -73,6 +73,7 @@ class CRM_Contact_Form_Task_Useradd extends CRM_Core_Form {
     $this->addRule('cms_pass', 'Password is required', 'required');
     $this->addRule(['cms_pass', 'cms_confirm_pass'], 'ERROR: Password mismatch', 'compare');
     $this->add('text', 'email', ts('Email:'), ['class' => 'huge'])->freeze();
+    $this->addRule('email', 'Email is required', 'required');
     $this->add('hidden', 'contactID');
 
     //add a rule to check username uniqueness
@@ -101,8 +102,12 @@ class CRM_Contact_Form_Task_Useradd extends CRM_Core_Form {
     // store the submitted values in an array
     $params = $this->exportValues();
 
-    CRM_Core_BAO_CMSUser::create($params, 'email');
-    CRM_Core_Session::setStatus('', ts('User Added'), 'success');
+    if (CRM_Core_BAO_CMSUser::create($params, 'email') === FALSE) {
+      CRM_Core_Error::statusBounce(ts('Error creating CMS user account.'));
+    }
+    else {
+      CRM_Core_Session::setStatus(ts('User Added'), '', 'success');
+    }
   }
 
   /**
index 6c5df3c357a030ada804df5718fa5bc677192f51..e5d83dd6cfeb24d22509b38c493b2a54a3339bc8 100644 (file)
@@ -10,6 +10,8 @@
  */
 
 use Civi\Api4\Activity;
+use Civi\Api4\ContributionPage;
+use Civi\Api4\ContributionRecur;
 
 /**
  *
@@ -1345,6 +1347,38 @@ class CRM_Contribute_BAO_Contribution extends CRM_Contribute_DAO_Contribution {
     return $rows;
   }
 
+  /**
+   * Should an email receipt be sent for this contribution on completion.
+   *
+   * @param array $input
+   * @param int $contributionPageID
+   * @param int $recurringContributionID
+   *
+   * @return bool
+   * @throws \API_Exception
+   * @throws \Civi\API\Exception\UnauthorizedException
+   */
+  protected static function isEmailReceipt(array $input, $contributionPageID, $recurringContributionID): bool {
+    if (isset($input['is_email_receipt'])) {
+      return (bool) $input['is_email_receipt'];
+    }
+    if ($recurringContributionID) {
+      //CRM-13273 - is_email_receipt setting on recurring contribution should take precedence over contribution page setting
+      // but CRM-16124 if $input['is_email_receipt'] is set then that should not be overridden.
+      // dev/core#1245 this maybe not the desired effect because the default value for is_email_receipt is set to 0 rather than 1 in
+      // Instance that had the table added via an upgrade in 4.1
+      // see also https://github.com/civicrm/civicrm-svn/commit/7f39befd60bc735408d7866b02b3ac7fff1d4eea#diff-9ad8e290180451a2d6eacbd3d1ca7966R354
+      // https://lab.civicrm.org/dev/core/issues/1245
+      return (bool) ContributionRecur::get(FALSE)->addWhere('id', '=', $recurringContributionID)->addSelect('is_email_receipt')->execute()->first()['is_email_receipt'];
+    }
+    if ($contributionPageID) {
+      return (bool) ContributionPage::get(FALSE)->addWhere('id', '=', $contributionPageID)->addSelect('is_email_receipt')->execute()->first()['is_email_receipt'];
+    }
+    // This would be the case for backoffice (where is_email_receipt is not passed in) or events, where Event::sendMail will filter
+    // again anyway.
+    return TRUE;
+  }
+
   /**
    * @inheritDoc
    */
@@ -2575,12 +2609,11 @@ LEFT JOIN  civicrm_contribution contribution ON ( componentPayment.contribution_
    * @param CRM_Contribute_BAO_Contribution $contribution
    * @param array $input
    * @param array $contributionParams
-   * @param int $paymentProcessorID
    *
-   * @return bool
+   * @return bool|array
    * @throws CiviCRM_API3_Exception
    */
-  protected static function repeatTransaction(&$contribution, &$input, $contributionParams, $paymentProcessorID) {
+  protected static function repeatTransaction(&$contribution, &$input, $contributionParams) {
     if (!empty($contribution->id)) {
       return FALSE;
     }
@@ -2611,17 +2644,21 @@ LEFT JOIN  civicrm_contribution contribution ON ( componentPayment.contribution_
         ])
       );
       $input['line_item'] = $contributionParams['line_item'] = $templateContribution['line_item'];
-
       $contributionParams['status_id'] = 'Pending';
-      if (isset($contributionParams['financial_type_id'])) {
-        // Give precedence to passed in type.
+
+      if (isset($contributionParams['financial_type_id']) && count($input['line_item']) === 1) {
+        // We permit the financial type to be overridden for single line items.
+        // More comments on this are in getTemplateTransaction.
         $contribution->financial_type_id = $contributionParams['financial_type_id'];
       }
       else {
         $contributionParams['financial_type_id'] = $templateContribution['financial_type_id'];
       }
-      $contributionParams['contact_id'] = $templateContribution['contact_id'];
-      $contributionParams['source'] = empty($templateContribution['source']) ? ts('Recurring contribution') : $templateContribution['source'];
+      foreach (['contact_id', 'currency', 'source'] as $fieldName) {
+        $contributionParams[$fieldName] = $templateContribution[$fieldName];
+      }
+
+      $contributionParams['source'] = $contributionParams['source'] ?: ts('Recurring contribution');
 
       //CRM-18805 -- Contribution page not recorded on recurring transactions, Recurring contribution payments
       //do not create CC or BCC emails or profile notifications.
@@ -2636,9 +2673,9 @@ 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);
+      $contribution->copyCustomFields($templateContribution['id'], $contribution->id);
       self::handleMembershipIDOverride($contribution->id, $input);
-      return TRUE;
+      return $createContribution;
     }
   }
 
@@ -2927,7 +2964,7 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
 
     //not really sure what params might be passed in but lets merge em into values
     $values = array_merge($this->_gatherMessageValues($input, $values, $ids), $values);
-    $values['is_email_receipt'] = $this->isEmailReceipt($input, $values);
+    $values['is_email_receipt'] = !$returnMessageText;
     if (!empty($input['receipt_date'])) {
       $values['receipt_date'] = $input['receipt_date'];
     }
@@ -3109,7 +3146,11 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
       //get soft contributions
       $softContributions = CRM_Contribute_BAO_ContributionSoft::getSoftContribution($this->id, TRUE);
       if (!empty($softContributions)) {
-        $values['softContributions'] = $softContributions['soft_credit'];
+        // For pcp soft credit, there is no 'soft_credit' member it comes
+        // back in different array members, but shortly after returning from
+        // this function it calls _assignMessageVariablesToTemplate which does
+        // its own lookup of any pcp soft credit, so we can skip it here.
+        $values['softContributions'] = $softContributions['soft_credit'] ?? NULL;
       }
       if (isset($this->contribution_page_id)) {
         // This is a call we want to use less, in favour of loading related objects.
@@ -3925,6 +3966,7 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
       'Refunded' => ['Cancelled', 'Completed'],
       'Partially paid' => ['Completed'],
       'Pending refund' => ['Completed', 'Refunded'],
+      'Failed' => ['Pending'],
     ];
 
     if (!in_array($contributionStatuses[$fields['contribution_status_id']],
@@ -4401,8 +4443,6 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
    * @param array $input
    * @param array $ids
    * @param array $objects
-   * @param CRM_Core_Transaction $transaction
-   *   It is not recommended to pass this in. The calling function handle it's own roll back if it wants it.
    * @param bool $isPostPaymentCreate
    *   Is this being called from the payment.create api. If so the api has taken care of financial entities.
    *   Note that our goal is that this would only ever be called from payment.create and never handle financials (only
@@ -4412,10 +4452,8 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
    * @throws \CRM_Core_Exception
    * @throws \CiviCRM_API3_Exception
    */
-  public static function completeOrder($input, &$ids, $objects, $transaction = NULL, $isPostPaymentCreate = FALSE) {
-    if (!$transaction) {
-      $transaction = new CRM_Core_Transaction();
-    }
+  public static function completeOrder($input, &$ids, $objects, $isPostPaymentCreate = FALSE) {
+    $transaction = new CRM_Core_Transaction();
     $contribution = $objects['contribution'];
     $primaryContributionID = $contribution->id ?? $objects['first_contribution']->id;
     // The previous details are used when calculating line items so keep it before any code that 'does something'
@@ -4435,10 +4473,8 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
       'contribution_status_id',
       'card_type_id',
       'pan_truncation',
+      'financial_type_id',
     ];
-    if (self::isSingleLineItem($primaryContributionID)) {
-      $inputContributionWhiteList[] = 'financial_type_id';
-    }
 
     $participant = $objects['participant'] ?? NULL;
     $recurContrib = $objects['contributionRecur'] ?? NULL;
@@ -4463,11 +4499,6 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
     ], array_intersect_key($input, array_fill_keys($inputContributionWhiteList, 1)
     ));
 
-    // CRM-20678 Ensure that the currency is correct in subseqent transcations.
-    if (empty($contributionParams['currency']) && isset($objects['first_contribution']->currency)) {
-      $contributionParams['currency'] = $objects['first_contribution']->currency;
-    }
-
     $contributionParams['payment_processor'] = $input['payment_processor'] = $paymentProcessorId;
 
     // If paymentProcessor is not set then the payment_instrument_id would not be correct.
@@ -4481,41 +4512,12 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
     }
     $changeDate = CRM_Utils_Array::value('trxn_date', $input, date('YmdHis'));
 
-    if (empty($contributionParams['receive_date']) && $changeDate) {
-      $contributionParams['receive_date'] = $changeDate;
-    }
-
-    self::repeatTransaction($contribution, $input, $contributionParams, $paymentProcessorId);
-    $contributionParams['financial_type_id'] = $contribution->financial_type_id;
-
-    $values = [];
+    $contributionResult = self::repeatTransaction($contribution, $input, $contributionParams);
 
     if ($input['component'] == 'contribute') {
-      if ($contribution->contribution_page_id) {
-        // Figure out what we gain from this.
-        // Note that we may have overwritten the is_email_receipt input, fix that below.
-        CRM_Contribute_BAO_ContributionPage::setValues($contribution->contribution_page_id, $values);
-      }
-      elseif ($recurContrib && $recurringContributionID) {
-        $values['amount'] = $recurContrib->amount;
-        $values['financial_type_id'] = $objects['contributionType']->id;
-        $values['title'] = $source = ts('Offline Recurring Contribution');
-      }
-
-      if ($recurContrib && $recurringContributionID) {
-        //CRM-13273 - is_email_receipt setting on recurring contribution should take precedence over contribution page setting
-        // but CRM-16124 if $input['is_email_receipt'] is set then that should not be overridden.
-        // dev/core#1245 this maybe not the desired effect because the default value for is_email_receipt is set to 0 rather than 1 in
-        // Instance that had the table added via an upgrade in 4.1
-        // see also https://github.com/civicrm/civicrm-svn/commit/7f39befd60bc735408d7866b02b3ac7fff1d4eea#diff-9ad8e290180451a2d6eacbd3d1ca7966R354
-        // https://lab.civicrm.org/dev/core/issues/1245
-        $values['is_email_receipt'] = $recurContrib->is_email_receipt;
-      }
-
       if ($contributionParams['contribution_status_id'] === $completedContributionStatusID) {
         self::updateMembershipBasedOnCompletionOfContribution(
           $contribution,
-          $primaryContributionID,
           $changeDate
         );
       }
@@ -4535,10 +4537,9 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
     $contributionParams['id'] = $contribution->id;
     $contributionParams['is_post_payment_create'] = $isPostPaymentCreate;
 
-    // CRM-19309 - if you update the contribution here with financial_type_id it can/will mess with $lineItem
-    // unsetting it here does NOT cause any other contribution test to fail!
-    unset($contributionParams['financial_type_id']);
-    $contributionResult = civicrm_api3('Contribution', 'create', $contributionParams);
+    if (!$contributionResult) {
+      $contributionResult = civicrm_api3('Contribution', 'create', $contributionParams);
+    }
 
     // Add new soft credit against current $contribution.
     if (!empty($objects['contributionRecur']) && $objects['contributionRecur']->id) {
@@ -4556,10 +4557,12 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
     CRM_Core_Error::debug_log_message('Contribution record updated successfully');
     $transaction->commit();
 
+    // @todo - check if Contribution::create does this, test, remove.
     CRM_Contribute_BAO_ContributionRecur::updateRecurLinkedPledge($contribution->id, $recurringContributionID,
       $contributionParams['contribution_status_id'], $input['amount']);
 
     // create an activity record
+    // @todo - check if Contribution::create does this, test, remove.
     if ($input['component'] == 'contribute') {
       //CRM-4027
       $targetContactID = NULL;
@@ -4570,13 +4573,7 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
       CRM_Activity_BAO_Activity::addActivity($contribution, NULL, $targetContactID);
     }
 
-    $isEmailReceipt = !array_key_exists('is_email_receipt', $values) || $values['is_email_receipt'] == 1;
-    if (isset($input['is_email_receipt'])) {
-      $isEmailReceipt = $input['is_email_receipt'];
-    }
-    // CRM-9132 legacy behaviour was that receipts were sent out in all instances. Still sending
-    // when array_key 'is_email_receipt doesn't exist in case some instances where is needs setting haven't been set
-    if ($isEmailReceipt) {
+    if (self::isEmailReceipt($input, $contribution->contribution_page_id, $recurringContributionID)) {
       civicrm_api3('Contribution', 'sendconfirmation', [
         'id' => $contribution->id,
         'payment_processor_id' => $paymentProcessorId,
@@ -4601,8 +4598,6 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
    * @param array $ids
    *   Related object IDs.
    * @param int $contributionID
-   * @param array $values
-   *   Values related to objects that have already been loaded.
    * @param bool $returnMessageText
    *   Should text be returned instead of sent. This.
    *   is because the function is also used to generate pdfs
@@ -4612,9 +4607,8 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
    * @throws \CiviCRM_API3_Exception
    * @throws \Exception
    */
-  public static function sendMail(&$input, &$ids, $contributionID, &$values,
-                                  $returnMessageText = FALSE) {
-
+  public static function sendMail($input, $ids, $contributionID, $returnMessageText = FALSE) {
+    $values = [];
     $contribution = new CRM_Contribute_BAO_Contribution();
     $contribution->id = $contributionID;
     if (!$contribution->find(TRUE)) {
@@ -5216,13 +5210,12 @@ LEFT JOIN  civicrm_contribution on (civicrm_contribution.contact_id = civicrm_co
    * load them in this function. Code clean up would compensate for any minor performance implication.
    *
    * @param \CRM_Contribute_BAO_Contribution $contribution
-   * @param int $primaryContributionID
    * @param string $changeDate
    *
    * @throws \CRM_Core_Exception
    * @throws \CiviCRM_API3_Exception
    */
-  public static function updateMembershipBasedOnCompletionOfContribution($contribution, $primaryContributionID, $changeDate) {
+  public static function updateMembershipBasedOnCompletionOfContribution($contribution, $changeDate) {
     $memberships = self::getRelatedMemberships($contribution->id);
     foreach ($memberships as $membership) {
       $membershipParams = [
@@ -5259,10 +5252,11 @@ LIMIT 1;";
         // Passing num_terms to the api triggers date calculations, but for pending memberships these may be already calculated.
         // sigh - they should  be  consistent but removing the end date check causes test failures & maybe UI too?
         // The api assumes num_terms is a special sauce for 'is_renewal' so we need to not pass it when updating a pending to completed.
+        // ... except testCompleteTransactionMembershipPriceSetTwoTerms hits this line so the above is obviously not true....
         // @todo once apiv4 ships with core switch to that & find sanity.
         $membershipParams['num_terms'] = $contribution->getNumTermsByContributionAndMembershipType(
           $membershipParams['membership_type_id'],
-          $primaryContributionID
+          $contribution->id
         );
       }
       // @todo remove all this stuff in favour of letting the api call further down handle in
@@ -5278,6 +5272,8 @@ LIMIT 1;";
          * In BAO/Membership.php(renewMembership function), we skip the extend membership date and status
          * when Contribution mode is notify and membership is for renewal )
          */
+        // Test cover for this is in testRepeattransactionRenewMembershipOldMembership
+        // Be afraid.
         CRM_Member_BAO_Membership::fixMembershipStatusBeforeRenew($currentMembership, $changeDate);
 
         // @todo - we should pass membership_type_id instead of null here but not
@@ -5712,23 +5708,6 @@ LIMIT 1;";
     }
   }
 
-  /**
-   * Should an email receipt be sent for this contribution when complete.
-   *
-   * @param array $input
-   *
-   * @return mixed
-   */
-  protected function isEmailReceipt($input) {
-    if (isset($input['is_email_receipt'])) {
-      return $input['is_email_receipt'];
-    }
-    if (!empty($this->_relatedObjects['contribution_page_id'])) {
-      return $this->_relatedObjects['contribution_page_id']->is_email_receipt;
-    }
-    return TRUE;
-  }
-
   /**
    * Function to replace contribution tokens.
    *
index c1985a3f1b9249fe3f099c03799f6839e410326e..63d7799768d38a08042dd551330d69ca35be5fdd 100644 (file)
@@ -442,8 +442,15 @@ INNER JOIN civicrm_contribution       con ON ( con.id = mp.contribution_id )
     }
     if ($templateContributions->count()) {
       $templateContribution = $templateContributions->first();
-      $result = array_merge($templateContribution, $overrides);
       $lineItems = CRM_Price_BAO_LineItem::getLineItemsByContributionID($templateContribution['id']);
+      // We only permit the financial type to be overridden for single line items.
+      // Otherwise we need to figure out a whole lot of extra complexity.
+      // It's not UI-possible to alter financial_type_id for recurring contributions
+      // with more than one line item.
+      if (count($lineItems) > 1 && isset($overrides['financial_type_id'])) {
+        unset($overrides['financial_type_id']);
+      }
+      $result = array_merge($templateContribution, $overrides);
       $result['line_item'] = self::reformatLineItemsForRepeatContribution($result['total_amount'], $result['financial_type_id'], $lineItems, (array) $templateContribution);
       return $result;
     }
@@ -545,6 +552,8 @@ INNER JOIN civicrm_contribution       con ON ( con.id = mp.contribution_id )
   /**
    * Copy custom data of the initial contribution into its recurring contributions.
    *
+   * @deprecated
+   *
    * @param int $recurId
    * @param int $targetContributionId
    */
index 435c2398139c5005500f97b51c2df4de5616b3e6..cdf5b2f6a1e95ead61d4e2096086438533373826 100644 (file)
@@ -718,7 +718,7 @@ WHERE  contribution_id = {$id}
       $title .= " - {$info['title']}";
     }
     $this->assign('transaction', TRUE);
-    $this->assign('payments', $paymentInfo['transaction']);
+    $this->assign('payments', $paymentInfo['transaction'] ?? NULL);
     $this->assign('paymentLinks', $paymentInfo['payment_links']);
     return $title;
   }
index 09f05ba0bd490aa1c03efc9f388c2703bcca65ff..d453df3a7c9e482fbf5ab3310130541979402172 100644 (file)
@@ -951,30 +951,7 @@ class CRM_Contribute_Form_Contribution extends CRM_Contribute_Form_AbstractEditP
 
       CRM_Core_Error::statusBounce($e->getMessage(), $urlParams, ts('Payment Processor Error'));
     }
-    $session = CRM_Core_Session::singleton();
-    $buttonName = $this->controller->getButtonName();
-    if ($this->_context == 'standalone') {
-      if ($buttonName == $this->getButtonName('upload', 'new')) {
-        $session->replaceUserContext(CRM_Utils_System::url('civicrm/contribute/add',
-          'reset=1&action=add&context=standalone'
-        ));
-      }
-      else {
-        $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view',
-          "reset=1&cid={$this->_contactID}&selectedChild=contribute"
-        ));
-      }
-    }
-    elseif ($this->_context == 'contribution' && $this->_mode && $buttonName == $this->getButtonName('upload', 'new')) {
-      $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view/contribution',
-        "reset=1&action=add&context={$this->_context}&cid={$this->_contactID}&mode={$this->_mode}"
-      ));
-    }
-    elseif ($buttonName == $this->getButtonName('upload', 'new')) {
-      $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view/contribution',
-        "reset=1&action=add&context={$this->_context}&cid={$this->_contactID}"
-      ));
-    }
+    $this->setUserContext();
 
     //store contribution ID if not yet set (on create)
     if (empty($this->_id) && !empty($contribution->id)) {
@@ -1814,4 +1791,34 @@ class CRM_Contribute_Form_Contribution extends CRM_Contribute_Form_AbstractEditP
     }
   }
 
+  /**
+   * Set context in session
+   */
+  public function setUserContext(): void {
+    $session = CRM_Core_Session::singleton();
+    $buttonName = $this->controller->getButtonName();
+    if ($this->_context == 'standalone') {
+      if ($buttonName == $this->getButtonName('upload', 'new')) {
+        $session->replaceUserContext(CRM_Utils_System::url('civicrm/contribute/add',
+          'reset=1&action=add&context=standalone'
+        ));
+      }
+      else {
+        $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view',
+          "reset=1&cid={$this->_contactID}&selectedChild=contribute"
+        ));
+      }
+    }
+    elseif ($this->_context == 'contribution' && $this->_mode && $buttonName == $this->getButtonName('upload', 'new')) {
+      $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view/contribution',
+        "reset=1&action=add&context={$this->_context}&cid={$this->_contactID}&mode={$this->_mode}"
+      ));
+    }
+    elseif ($buttonName == $this->getButtonName('upload', 'new')) {
+      $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view/contribution',
+        "reset=1&action=add&context={$this->_context}&cid={$this->_contactID}"
+      ));
+    }
+  }
+
 }
index a1da2697a6227557b62ff44418b486bc9b836acf..228e285dfdee18ffeef735d6bf931e6d444bc852 100644 (file)
@@ -954,7 +954,7 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
         }
         $smarty = CRM_Core_Smarty::singleton();
         $smarty->assign('dataArray', $dataArray);
-        $smarty->assign('totalTaxAmount', $params['tax_amount']);
+        $smarty->assign('totalTaxAmount', $params['tax_amount'] ?? NULL);
       }
 
       // lets store it in the form variable so postProcess hook can get to this and use it
index d189158cd8a0402c128c2309da5751b33bc0e47c..b2087a6474622c69e45469aa23d3e36017085efd 100644 (file)
@@ -9,9 +9,6 @@
  +--------------------------------------------------------------------+
  */
 
-use Dompdf\Dompdf;
-use Dompdf\Options;
-
 /**
  *
  * @package CRM
@@ -479,7 +476,11 @@ class CRM_Contribute_Form_Task_Invoice extends CRM_Contribute_Form_Task {
           'metric' => 'px',
         ]);
         // functions call for adding activity with attachment
-        $fileName = self::putFile($html, $pdfFileName);
+        $fileName = self::putFile($html, $pdfFileName, [
+          'margin_top' => 10,
+          'margin_left' => 65,
+          'metric' => 'px',
+        ]);
         self::addActivities($subject, $contactIds, $fileName, $params);
 
         CRM_Utils_System::civiExit();
@@ -554,22 +555,13 @@ class CRM_Contribute_Form_Task_Invoice extends CRM_Contribute_Form_Task {
    *   Content for pdf in html format.
    *
    * @param string $name
+   * @param array $format
    *
    * @return string
    *   Name of file which is in pdf format
    */
-  public static function putFile($html, $name = 'Invoice.pdf') {
-    $options = new Options();
-    $options->set('isRemoteEnabled', TRUE);
-
-    $doc = new DOMPDF($options);
-    $doc->load_html($html);
-    $doc->render();
-    $html = $doc->output();
-    $config = CRM_Core_Config::singleton();
-    $fileName = $config->uploadDir . $name;
-    file_put_contents($fileName, $html);
-    return $fileName;
+  public static function putFile($html, $name = 'Invoice.pdf', $format = NULL) {
+    return CRM_Utils_Mail::appendPDF($name, $html, $format)['fullPath'] ?? '';
   }
 
   /**
index 76dac1989fb10104e73d07fed177da16684294bb..e05ebab9d5a8b5619228e67cda7e7dc9f7a21df0 100644 (file)
@@ -184,7 +184,6 @@ AND    {$this->_componentClause}";
       // CRM_Contribute_BAO_Contribution::composeMessageArray expects mysql formatted date
       $objects['contribution']->receive_date = CRM_Utils_Date::isoToMysql($objects['contribution']->receive_date);
 
-      $values = [];
       if (isset($params['from_email_address']) && !$elements['createPdf']) {
         // If a logged in user from email is used rather than a domain wide from email address
         // the from_email_address params key will be numerical and we need to convert it to be
@@ -196,8 +195,7 @@ AND    {$this->_componentClause}";
         $input['receipt_from_name'] = str_replace('"', '', $fromDetails[0]);
       }
 
-      $mail = CRM_Contribute_BAO_Contribution::sendMail($input, $ids, $objects['contribution']->id, $values,
-        $elements['createPdf']);
+      $mail = CRM_Contribute_BAO_Contribution::sendMail($input, $ids, $objects['contribution']->id, $elements['createPdf']);
 
       if ($mail['html']) {
         $message[] = $mail['html'];
@@ -253,7 +251,7 @@ AND    {$this->_componentClause}";
 
     $pdfElements['contribIDs'] = implode(',', $contribIds);
 
-    $pdfElements['details'] = CRM_Contribute_Form_Task_Status::getDetails($pdfElements['contribIDs']);
+    $pdfElements['details'] = self::getDetails($pdfElements['contribIDs']);
 
     $pdfElements['baseIPN'] = new CRM_Core_Payment_BaseIPN();
 
@@ -295,4 +293,47 @@ AND    {$this->_componentClause}";
     return $pdfElements;
   }
 
+  /**
+   * @param string $contributionIDs
+   *
+   * @return array
+   */
+  private static function getDetails($contributionIDs) {
+    if (empty($contributionIDs)) {
+      return [];
+    }
+    $query = "
+SELECT    c.id              as contribution_id,
+          c.contact_id      as contact_id     ,
+          mp.membership_id  as membership_id  ,
+          pp.participant_id as participant_id ,
+          p.event_id        as event_id
+FROM      civicrm_contribution c
+LEFT JOIN civicrm_membership_payment  mp ON mp.contribution_id = c.id
+LEFT JOIN civicrm_participant_payment pp ON pp.contribution_id = c.id
+LEFT JOIN civicrm_participant         p  ON pp.participant_id  = p.id
+WHERE     c.id IN ( $contributionIDs )";
+
+    $rows = [];
+    $dao = CRM_Core_DAO::executeQuery($query);
+
+    while ($dao->fetch()) {
+      $rows[$dao->contribution_id]['component'] = $dao->participant_id ? 'event' : 'contribute';
+      $rows[$dao->contribution_id]['contact'] = $dao->contact_id;
+      if ($dao->membership_id) {
+        if (!array_key_exists('membership', $rows[$dao->contribution_id])) {
+          $rows[$dao->contribution_id]['membership'] = [];
+        }
+        $rows[$dao->contribution_id]['membership'][] = $dao->membership_id;
+      }
+      if ($dao->participant_id) {
+        $rows[$dao->contribution_id]['participant'] = $dao->participant_id;
+      }
+      if ($dao->event_id) {
+        $rows[$dao->contribution_id]['event'] = $dao->event_id;
+      }
+    }
+    return $rows;
+  }
+
 }
index e3c2a6e7daa1b769f2e689ddc4efc3b55755c9dc..b501327a88f5757e27a1e0f25b5f9eab757cd832 100644 (file)
@@ -68,21 +68,6 @@ AND    {$this->_componentClause}";
    * Build the form object.
    */
   public function buildQuickForm() {
-    $status = CRM_Contribute_BAO_Contribution_Utils::getContributionStatuses(
-      'contribution', $this->_contributionIds[0]
-    );
-    $byName = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
-    // FIXME: if it's invalid to transition from Pending to
-    // In Progress or Overdue, we should move that logic to
-    // CRM_Contribute_BAO_Contribution_Utils::getContributionStatuses.
-    foreach (['Pending', 'In Progress', 'Overdue'] as $suppress) {
-      unset($status[CRM_Utils_Array::key($suppress, $byName)]);
-    }
-    $this->add('select', 'contribution_status_id',
-      ts('Contribution Status'),
-      $status,
-      TRUE
-    );
     $this->add('checkbox', 'is_email_receipt', ts('Send e-mail receipt'));
     $this->setDefaults(['is_email_receipt' => 1]);
 
@@ -198,7 +183,7 @@ AND    co.id IN ( $contribIDs )";
     // submit the form with values.
     self::processForm($this, $params);
 
-    CRM_Core_Session::setStatus(ts('Contribution status has been updated for selected record(s).'), ts('Status Updated'), 'success');
+    CRM_Core_Session::setStatus(ts('Payments have been recorded for selected record(s).'), ts('Payments recorded'), 'success');
   }
 
   /**
@@ -212,124 +197,26 @@ AND    co.id IN ( $contribIDs )";
    * @throws \Exception
    */
   public static function processForm($form, $params) {
-    $statusID = $params['contribution_status_id'] ?? NULL;
-    $baseIPN = new CRM_Core_Payment_BaseIPN();
-
-    // get the missing pieces for each contribution
-    $contribIDs = implode(',', $form->_contributionIds);
-    $details = self::getDetails($contribIDs);
-    $template = CRM_Core_Smarty::singleton();
-
-    // for each contribution id, we just call the baseIPN stuff
     foreach ($form->_rows as $row) {
-      $input = $ids = $objects = [];
-      $input['component'] = $details[$row['contribution_id']]['component'];
-
-      $ids['contact'] = $row['contact_id'];
-      $ids['contribution'] = $row['contribution_id'];
-      $ids['contributionRecur'] = NULL;
-      $ids['contributionPage'] = NULL;
-      $ids['membership'] = $details[$row['contribution_id']]['membership'] ?? NULL;
-      $ids['participant'] = $details[$row['contribution_id']]['participant'] ?? NULL;
-      $ids['event'] = $details[$row['contribution_id']]['event'] ?? NULL;
-
-      if (!$baseIPN->validateData($input, $ids, $objects, FALSE)) {
-        CRM_Core_Error::statusBounce('Supplied data was not able to be validated');
-      }
-
-      $contribution = &$objects['contribution'];
-
-      $contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL,
-        'name'
-      );
-
-      if ($statusID == array_search('Cancelled', $contributionStatuses)) {
-        $transaction = new CRM_Core_Transaction();
-        $baseIPN->cancelled($objects, $transaction);
-        $transaction->commit();
-        continue;
-      }
-      elseif ($statusID == array_search('Failed', $contributionStatuses)) {
-        $transaction = new CRM_Core_Transaction();
-        $baseIPN->failed($objects, $transaction);
-        $transaction->commit();
-        continue;
-      }
-
-      // status is not pending
-      if ($contribution->contribution_status_id != array_search('Pending',
-          $contributionStatuses
-        )
-      ) {
-        continue;
-      }
-
-      // set some fake input values so we can reuse IPN code
-      $input['amount'] = $contribution->total_amount;
-      $input['is_test'] = $contribution->is_test;
-      $input['fee_amount'] = $params["fee_amount_{$row['contribution_id']}"];
-      $input['check_number'] = $params["check_number_{$row['contribution_id']}"];
-      $input['payment_instrument_id'] = $params["payment_instrument_id_{$row['contribution_id']}"];
-      $input['net_amount'] = $contribution->total_amount - $input['fee_amount'];
-
-      if (!empty($params["trxn_id_{$row['contribution_id']}"])) {
-        $input['trxn_id'] = trim($params["trxn_id_{$row['contribution_id']}"]);
-      }
-      else {
-        $input['trxn_id'] = $contribution->invoice_id;
-      }
-      $input['trxn_date'] = $params["trxn_date_{$row['contribution_id']}"] . ' ' . date('H:i:s');
-      $input['is_email_receipt'] = !empty($params['is_email_receipt']);
-
-      // @todo calling CRM_Contribute_BAO_Contribution::completeOrder like this is a pattern in it's last gasps. Call contribute.completetransaction api.
-      CRM_Contribute_BAO_Contribution::completeOrder($input, $ids, $objects);
-
-      // reset template values before processing next transactions
-      $template->clearTemplateVars();
-    }
-  }
-
-  /**
-   * @param string $contributionIDs
-   *
-   * @return array
-   */
-  public static function &getDetails($contributionIDs) {
-    if (empty($contributionIDs)) {
-      return [];
-    }
-    $query = "
-SELECT    c.id              as contribution_id,
-          c.contact_id      as contact_id     ,
-          mp.membership_id  as membership_id  ,
-          pp.participant_id as participant_id ,
-          p.event_id        as event_id
-FROM      civicrm_contribution c
-LEFT JOIN civicrm_membership_payment  mp ON mp.contribution_id = c.id
-LEFT JOIN civicrm_participant_payment pp ON pp.contribution_id = c.id
-LEFT JOIN civicrm_participant         p  ON pp.participant_id  = p.id
-WHERE     c.id IN ( $contributionIDs )";
-
-    $rows = [];
-    $dao = CRM_Core_DAO::executeQuery($query);
-
-    while ($dao->fetch()) {
-      $rows[$dao->contribution_id]['component'] = $dao->participant_id ? 'event' : 'contribute';
-      $rows[$dao->contribution_id]['contact'] = $dao->contact_id;
-      if ($dao->membership_id) {
-        if (!array_key_exists('membership', $rows[$dao->contribution_id])) {
-          $rows[$dao->contribution_id]['membership'] = [];
-        }
-        $rows[$dao->contribution_id]['membership'][] = $dao->membership_id;
-      }
-      if ($dao->participant_id) {
-        $rows[$dao->contribution_id]['participant'] = $dao->participant_id;
-      }
-      if ($dao->event_id) {
-        $rows[$dao->contribution_id]['event'] = $dao->event_id;
-      }
+      $contribData = civicrm_api3('Contribution', 'getSingle', ['id' => $row['contribution_id']]);
+      $trxnParams = [
+        'contribution_id' => $row['contribution_id'],
+        // We are safe assuming that payments will be for the total amount of
+        // the contribution because the contributions must be in "Pending"
+        // status.
+        'total_amount' => $contribData['total_amount'],
+        'fee_amount' => $params["fee_amount_{$row['contribution_id']}"],
+        'check_number' => $params["check_number_{$row['contribution_id']}"],
+        'payment_instrument_id' => $params["payment_instrument_id_{$row['contribution_id']}"],
+        'net_amount' => $contribData['total_amount'] - $params["fee_amount_{$row['contribution_id']}"],
+        // Not sure why to default to invoice_id, but that's what the form has
+        // been doing historically
+        'trxn_id' => $params["trxn_id_{$row['contribution_id']}"] ?? $contribData['invoice_id'],
+        'trxn_date' => $params["trxn_date_{$row['contribution_id']}"] ?? 'now',
+        'is_send_contribution_notification' => !empty($params['is_email_receipt']),
+      ];
+      $result = civicrm_api3('Payment', 'create', $trxnParams);
     }
-    return $rows;
   }
 
 }
index 9a88cfc6d51ad802e97268955d6a8e6e82d02a0b..24feae8a8797bf4ffe93389c0a468782a6e46544 100644 (file)
@@ -81,7 +81,7 @@ class CRM_Contribute_Task extends CRM_Core_Task {
           'result' => TRUE,
         ],
         self::UPDATE_STATUS => [
-          'title' => ts('Update pending contribution status'),
+          'title' => ts('Record payments for contributions'),
           'class' => 'CRM_Contribute_Form_Task_Status',
           'result' => TRUE,
         ],
index a13a6fee8588cfa91a32a185e93cc35e45477f6a..c7534119308217a3588a0a93000e25b9706d70f3 100644 (file)
@@ -33,225 +33,10 @@ class CRM_Core_BAO_Cache extends CRM_Core_DAO_Cache {
    */
   const DEFAULT_SESSION_TTL = 172800;
 
-  /**
-   * Cache.
-   *
-   * Format is ($cacheKey => $cacheValue)
-   *
-   * @var array
-   */
-  public static $_cache = NULL;
-
-  /**
-   * Retrieve an item from the DB cache.
-   *
-   * @param string $group
-   *   (required) The group name of the item.
-   * @param string $path
-   *   (required) The path under which this item is stored.
-   * @param int $componentID
-   *   The optional component ID (so componenets can share the same name space).
-   *
-   * @return object
-   *   The data if present in cache, else null
-   * @deprecated
-   */
-  public static function &getItem($group, $path, $componentID = NULL) {
-    CRM_Core_Error::deprecatedFunctionWarning(
-      'CRM_Core_BAO_Cache::getItem is deprecated and will be removed from core soon, use Civi::cache() facade or define cache group using hook_civicrm_container'
-    );
-    if (($adapter = CRM_Utils_Constant::value('CIVICRM_BAO_CACHE_ADAPTER')) !== NULL) {
-      $value = $adapter::getItem($group, $path, $componentID);
-      return $value;
-    }
-
-    if (self::$_cache === NULL) {
-      self::$_cache = [];
-    }
-
-    $argString = "CRM_CT_{$group}_{$path}_{$componentID}";
-    if (!array_key_exists($argString, self::$_cache)) {
-      $cache = CRM_Utils_Cache::singleton();
-      $cleanKey = self::cleanKey($argString);
-      self::$_cache[$argString] = $cache->get($cleanKey);
-      if (self::$_cache[$argString] === NULL) {
-        $table = self::getTableName();
-        $where = self::whereCache($group, $path, $componentID);
-        $rawData = CRM_Core_DAO::singleValueQuery("SELECT data FROM $table WHERE $where");
-        $data = $rawData ? self::decode($rawData) : NULL;
-
-        self::$_cache[$argString] = $data;
-        if ($data !== NULL) {
-          // Do not cache 'null' as that is most likely a cache miss & we shouldn't then cache it.
-          $cache->set($cleanKey, self::$_cache[$argString]);
-        }
-      }
-    }
-    return self::$_cache[$argString];
-  }
-
-  /**
-   * Retrieve all items in a group.
-   *
-   * @param string $group
-   *   (required) The group name of the item.
-   * @param int $componentID
-   *   The optional component ID (so componenets can share the same name space).
-   *
-   * @return object
-   *   The data if present in cache, else null
-   * @deprecated
-   */
-  public static function &getItems($group, $componentID = NULL) {
-    CRM_Core_Error::deprecatedFunctionWarning(
-      'CRM_Core_BAO_Cache::getItems is deprecated and will be removed from core soon, use Civi::cache() facade or define cache group using hook_civicrm_container'
-    );
-    if (($adapter = CRM_Utils_Constant::value('CIVICRM_BAO_CACHE_ADAPTER')) !== NULL) {
-      return $adapter::getItems($group, $componentID);
-    }
-
-    if (self::$_cache === NULL) {
-      self::$_cache = [];
-    }
-
-    $argString = "CRM_CT_CI_{$group}_{$componentID}";
-    if (!array_key_exists($argString, self::$_cache)) {
-      $cache = CRM_Utils_Cache::singleton();
-      $cleanKey = self::cleanKey($argString);
-      self::$_cache[$argString] = $cache->get($cleanKey);
-      if (!self::$_cache[$argString]) {
-        $table = self::getTableName();
-        $where = self::whereCache($group, NULL, $componentID);
-        $dao = CRM_Core_DAO::executeQuery("SELECT path, data FROM $table WHERE $where");
-
-        $result = [];
-        while ($dao->fetch()) {
-          $result[$dao->path] = self::decode($dao->data);
-        }
-
-        self::$_cache[$argString] = $result;
-        $cache->set($cleanKey, self::$_cache[$argString]);
-      }
-    }
-
-    return self::$_cache[$argString];
-  }
-
-  /**
-   * Store an item in the DB cache.
-   *
-   * @param object $data
-   *   (required) A reference to the data that will be serialized and stored.
-   * @param string $group
-   *   (required) The group name of the item.
-   * @param string $path
-   *   (required) The path under which this item is stored.
-   * @param int $componentID
-   *   The optional component ID (so componenets can share the same name space).
-   * @deprecated
-   * @throws CRM_Core_Exception
-   */
-  public static function setItem(&$data, $group, $path, $componentID = NULL) {
-    CRM_Core_Error::deprecatedFunctionWarning(
-      'CRM_Core_BAO_Cache::setItem is deprecated and will be removed from core soon, use Civi::cache() facade or define cache group using hook_civicrm_container'
-    );
-    if (($adapter = CRM_Utils_Constant::value('CIVICRM_BAO_CACHE_ADAPTER')) !== NULL) {
-      return $adapter::setItem($data, $group, $path, $componentID);
-    }
-
-    if (self::$_cache === NULL) {
-      self::$_cache = [];
-    }
-
-    // get a lock so that multiple ajax requests on the same page
-    // dont trample on each other
-    // CRM-11234
-    $lock = Civi::lockManager()->acquire("cache.{$group}_{$path}._{$componentID}");
-    if (!$lock->isAcquired()) {
-      throw new CRM_Core_Exception('Cannot acquire database lock');
-    }
-
-    $table = self::getTableName();
-    $where = self::whereCache($group, $path, $componentID);
-    $dataExists = CRM_Core_DAO::singleValueQuery("SELECT COUNT(*) FROM $table WHERE {$where}");
-    // FIXME - Use SQL NOW() or CRM_Utils_Time?
-    $now = date('Y-m-d H:i:s');
-    $dataSerialized = self::encode($data);
-
-    // This table has a wonky index, so we cannot use REPLACE or
-    // "INSERT ... ON DUPE". Instead, use SELECT+(INSERT|UPDATE).
-    if ($dataExists) {
-      $sql = "UPDATE $table SET data = %1, created_date = %2 WHERE {$where}";
-      $args = [
-        1 => [$dataSerialized, 'String'],
-        2 => [$now, 'String'],
-      ];
-      $dao = CRM_Core_DAO::executeQuery($sql, $args, TRUE, NULL, FALSE, FALSE);
-    }
-    else {
-      $insert = CRM_Utils_SQL_Insert::into($table)
-        ->row([
-          'group_name' => $group,
-          'path' => $path,
-          'component_id' => $componentID,
-          'data' => $dataSerialized,
-          'created_date' => $now,
-        ]);
-      $dao = CRM_Core_DAO::executeQuery($insert->toSQL(), [], TRUE, NULL, FALSE, FALSE);
-    }
-
-    $lock->release();
-
-    // cache coherency - refresh or remove dependent caches
-
-    $argString = "CRM_CT_{$group}_{$path}_{$componentID}";
-    $cache = CRM_Utils_Cache::singleton();
-    $data = self::decode($dataSerialized);
-    self::$_cache[$argString] = $data;
-    $cache->set(self::cleanKey($argString), $data);
-
-    $argString = "CRM_CT_CI_{$group}_{$componentID}";
-    unset(self::$_cache[$argString]);
-    $cache->delete(self::cleanKey($argString));
-  }
-
-  /**
-   * Delete all the cache elements that belong to a group OR delete the entire cache if group is not specified.
-   *
-   * @param string $group
-   *   The group name of the entries to be deleted.
-   * @param string $path
-   *   Path of the item that needs to be deleted.
-   * @param bool $clearAll clear all caches
-   * @deprecated
-   */
-  public static function deleteGroup($group = NULL, $path = NULL, $clearAll = TRUE) {
-    CRM_Core_Error::deprecatedFunctionWarning(
-      'CRM_Core_BAO_Cache::deleteGroup is deprecated and will be removed from core soon, use Civi::cache() facade or define cache group using hook_civicrm_container'
-    );
-    if (($adapter = CRM_Utils_Constant::value('CIVICRM_BAO_CACHE_ADAPTER')) !== NULL) {
-      return $adapter::deleteGroup($group, $path);
-    }
-    else {
-      $table = self::getTableName();
-      $where = self::whereCache($group, $path, NULL);
-      CRM_Core_DAO::executeQuery("DELETE FROM $table WHERE $where");
-    }
-
-    if ($clearAll) {
-      self::resetCaches();
-    }
-  }
-
   /**
    * Cleanup ACL and System Level caches
    */
   public static function resetCaches() {
-    // also reset ACL Cache
-    // @todo why is this called when CRM_Utils_System::flushCache() does it as well.
-    CRM_ACL_BAO_Cache::resetCache();
-
-    // also reset memory cache if any
     CRM_Utils_System::flushCache();
   }
 
@@ -476,6 +261,7 @@ class CRM_Core_BAO_Cache extends CRM_Core_DAO_Cache {
    * @see CRM_Utils_Cache::cleanKey()
    */
   public static function cleanKey($key) {
+    CRM_Core_Error::deprecatedFunctionWarning('CRM_Utils_Cache::cleanKey');
     return CRM_Utils_Cache::cleanKey($key);
   }
 
diff --git a/CRM/Core/BAO/Cache/Psr16.php b/CRM/Core/BAO/Cache/Psr16.php
deleted file mode 100644 (file)
index 1255f6d..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-<?php
-
-/*
- +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC. All rights reserved.                        |
- |                                                                    |
- | This work is published under the GNU AGPLv3 license with some      |
- | permitted exceptions and without any warranty. For full license    |
- | and copyright information, see https://civicrm.org/licensing       |
- +--------------------------------------------------------------------+
- */
-
-/**
- * Class CRM_Core_BAO_Cache_Psr16
- *
- * This optional adapter to help phase-out CRM_Core_BAO_Cache.
- *
- * In effect, it changes the default behavior of legacy cache-consumers
- * (CRM_Core_BAO_Cache) so that they store in the best-available tier
- * (Reds/Memcache or SQL or array) rather than being hard-coded to SQL.
- *
- * It basically just calls "CRM_Utils_Cache::create()" for each $group and
- * maps the getItem/setItem to get()/set().
- */
-class CRM_Core_BAO_Cache_Psr16 {
-
-  /**
-   * Original BAO behavior did not do expiration. PSR-16 providers have
-   * diverse defaults. To provide some consistency, we'll pick a long(ish)
-   * TTL for everything that goes through the adapter.
-   */
-  const TTL = 86400;
-
-  /**
-   * @param string $group
-   * @return CRM_Utils_Cache_Interface
-   */
-  protected static function getGroup($group) {
-    if (!isset(Civi::$statics[__CLASS__][$group])) {
-      if (!in_array($group, self::getLegacyGroups())) {
-        Civi::log()
-          ->warning('Unrecognized BAO cache group ({group}). This should work generally, but data may not be flushed in some edge-cases. Consider migrating explicitly to PSR-16.', [
-            'group' => $group,
-          ]);
-      }
-
-      $cache = CRM_Utils_Cache::create([
-        'name' => "bao_$group",
-        'type' => ['*memory*', 'SqlGroup', 'ArrayCache'],
-        // We're replacing CRM_Core_BAO_Cache, which traditionally used a front-cache
-        // that was not aware of TTLs. So it seems more consistent/performant to
-        // use 'fast' here.
-        'withArray' => 'fast',
-      ]);
-      Civi::$statics[__CLASS__][$group] = $cache;
-    }
-    return Civi::$statics[__CLASS__][$group];
-  }
-
-  /**
-   * Retrieve an item from the DB cache.
-   *
-   * @param string $group
-   *   (required) The group name of the item.
-   * @param string $path
-   *   (required) The path under which this item is stored.
-   * @param int $componentID
-   *   The optional component ID (so componenets can share the same name space).
-   *
-   * @return object
-   *   The data if present in cache, else null
-   */
-  public static function getItem($group, $path, $componentID = NULL) {
-    // TODO: Generate a general deprecation notice.
-    if ($componentID) {
-      Civi::log()
-        ->warning('getItem({group},{path},...) uses unsupported componentID. Consider migrating explicitly to PSR-16.', [
-          'group' => $group,
-          'path' => $path,
-        ]);
-    }
-    return self::getGroup($group)->get(CRM_Utils_Cache::cleanKey($path));
-  }
-
-  /**
-   * Retrieve all items in a group.
-   *
-   * @param string $group
-   *   (required) The group name of the item.
-   * @param int $componentID
-   *   The optional component ID (so componenets can share the same name space).
-   *
-   * @throws CRM_Core_Exception
-   */
-  public static function &getItems($group, $componentID = NULL) {
-    // Based on grepping universe, this function is not currently used.
-    // Moreover, it's hard to implement in PSR-16. (We'd have to extend the
-    // interface.) Let's wait and see if anyone actually needs this...
-    throw new \CRM_Core_Exception('Not implemented: CRM_Core_BAO_Cache_Psr16::getItems');
-  }
-
-  /**
-   * Store an item in the DB cache.
-   *
-   * @param object $data
-   *   (required) A reference to the data that will be serialized and stored.
-   * @param string $group
-   *   (required) The group name of the item.
-   * @param string $path
-   *   (required) The path under which this item is stored.
-   * @param int $componentID
-   *   The optional component ID (so componenets can share the same name space).
-   */
-  public static function setItem(&$data, $group, $path, $componentID = NULL) {
-    // TODO: Generate a general deprecation notice.
-
-    if ($componentID) {
-      Civi::log()
-        ->warning('setItem({group},{path},...) uses unsupported componentID. Consider migrating explicitly to PSR-16.', [
-          'group' => $group,
-          'path' => $path,
-        ]);
-    }
-    self::getGroup($group)
-      ->set(CRM_Utils_Cache::cleanKey($path), $data, self::TTL);
-  }
-
-  /**
-   * Delete all the cache elements that belong to a group OR delete the entire cache if group is not specified.
-   *
-   * @param string $group
-   *   The group name of the entries to be deleted.
-   * @param string $path
-   *   Path of the item that needs to be deleted.
-   */
-  public static function deleteGroup($group = NULL, $path = NULL) {
-    // FIXME: Generate a general deprecation notice.
-
-    if ($path) {
-      self::getGroup($group)->delete(CRM_Utils_Cache::cleanKey($path));
-    }
-    else {
-      self::getGroup($group)->clear();
-    }
-  }
-
-  /**
-   * Cleanup any caches that we've mapped.
-   *
-   * Traditional SQL-backed caches are cleared as a matter of course during a
-   * system flush (by way of "TRUNCATE TABLE civicrm_cache"). This provides
-   * a spot where the adapter can
-   */
-  public static function clearDBCache() {
-    foreach (self::getLegacyGroups() as $groupName) {
-      $group = self::getGroup($groupName);
-      $group->clear();
-    }
-  }
-
-  /**
-   * Get a list of known cache-groups
-   *
-   * @return array
-   */
-  public static function getLegacyGroups() {
-    $groups = [
-      // Universe
-
-      // biz.jmaconsulting.lineitemedit
-      'lineitem-editor',
-
-      // civihr/uk.co.compucorp.civicrm.hrcore
-      'HRCore_Info',
-
-    ];
-    // Handle Legacy Multisite caching group.
-    $extensions = CRM_Extension_System::singleton()->getManager();
-    $multisiteExtensionStatus = $extensions->getStatus('org.civicrm.multisite');
-    if ($multisiteExtensionStatus == $extensions::STATUS_INSTALLED) {
-      $extension_version = civicrm_api3('Extension', 'get', ['key' => 'org.civicrm.multisite'])['values'][0]['version'];
-      if (version_compare($extension_version, '2.7', '<')) {
-        Civi::log()->warning(
-          'CRM_Core_BAO_Cache_PSR is deprecated for multisite extension, you should upgrade to the latest version to avoid this warning, this code will be removed at the end of 2019',
-          ['civi.tag' => 'deprecated']
-        );
-        $groups[] = 'descendant groups for an org';
-      }
-    }
-    $entitySettingExtensionStatus = $extensions->getStatus('nz.co.fuzion.entitysetting');
-    if ($multisiteExtensionStatus == $extensions::STATUS_INSTALLED) {
-      $extension_version = civicrm_api3('Extension', 'get', ['key' => 'nz.co.fuzion.entitysetting'])['values'][0]['version'];
-      if (version_compare($extension_version, '1.3', '<')) {
-        Civi::log()->warning(
-          'CRM_Core_BAO_Cache_PSR is deprecated for entity setting extension, you should upgrade to the latest version to avoid this warning, this code will be removed at the end of 2019',
-          ['civi.tag' => 'deprecated']
-        );
-        $groups[] = 'CiviCRM setting Spec';
-      }
-    }
-    $atomFeedsSettingExtensionStatus = $extensions->getStatus('be.chiro.civi.atomfeeds');
-    if ($atomFeedsSettingExtensionStatus == $extensions::STATUS_INSTALLED) {
-      $extension_version = civicrm_api3('Extension', 'get', ['key' => 'be.chiro.civi.atomfeeds'])['values'][0]['version'];
-      if (version_compare($extension_version, '0.1-alpha2', '<')) {
-        Civi::log()->warning(
-          'CRM_Core_BAO_Cache_PSR is deprecated for Atomfeeds extension, you should upgrade to the latest version to avoid this warning, this code will be removed at the end of 2019',
-          ['civi.tag' => 'deprecated']
-        );
-        $groups[] = 'dashboard';
-      }
-    }
-    return $groups;
-  }
-
-}
index c462bae66426c3692bd8010734eee1752b5dc3b1..45e0378974903192132872b49f14eaaffaa01525 100644 (file)
@@ -119,105 +119,120 @@ class CRM_Core_BAO_ConfigSetting {
   }
 
   /**
-   * Evaluate locale preferences and activate a chosen locale by
-   * updating session+global variables.
+   * Activate a chosen locale.
+   *
+   * The locale is set by updating the session and global variables.
+   *
+   * When there is a choice of permitted languages (set on the "Administer" ->
+   * "Localisation" -> "Languages, Currency, Locations" screen) the locale to
+   * be applied can come from a variety of sources. The list below is the order
+   * of priority for deciding which of the sources "wins":
+   *
+   * - The request - when the "lcMessages" query variable is present in the URL.
+   * - The session - when the "lcMessages" session variable has been set.
+   * - Inherited from the CMS - when the "inheritLocale" setting is set.
+   * - CiviCRM settings - the fallback when none of the above set the locale.
+   *
+   * Single-language installs skip this and always set the default locale.
    *
    * @param \Civi\Core\SettingsBag $settings
    * @param string $activatedLocales
    *   Imploded list of locales which are supported in the DB.
    */
   public static function applyLocale($settings, $activatedLocales) {
-    // are we in a multi-language setup?
-    $multiLang = (bool) $activatedLocales;
 
-    // set the current language
-    $chosenLocale = NULL;
+    // Declare access to locale globals.
+    global $dbLocale, $tsLocale;
 
+    // Grab session reference.
     $session = CRM_Core_Session::singleton();
 
-    $permittedLanguages = CRM_Core_I18n::uiLanguages(TRUE);
+    // Set flag for multi-language setup.
+    $multiLang = (bool) $activatedLocales;
+
+    // Initialise the default and chosen locales.
+    $defaultLocale = $settings->get('lcMessages');
+    $chosenLocale = NULL;
 
-    // The locale to be used can come from various places:
-    // - the request (url)
-    // - the session
-    // - civicrm_uf_match
-    // - inherited from the CMS
-    // Only look at this if there is actually a choice of permitted languages
+    // When there is a choice of permitted languages.
+    $permittedLanguages = CRM_Core_I18n::uiLanguages(TRUE);
     if (count($permittedLanguages) >= 2) {
+
+      // Is the "lcMessages" query variable present in the URL?
       $requestLocale = CRM_Utils_Request::retrieve('lcMessages', 'String');
       if (in_array($requestLocale, $permittedLanguages)) {
         $chosenLocale = $requestLocale;
-
-        //CRM-8559, cache navigation do not respect locale if it is changed, so reseting cache.
-        // Ed: This doesn't sound good.
-        // Civi::cache('navigation')->flush();
-      }
-      else {
-        $requestLocale = NULL;
       }
 
-      if (!$requestLocale) {
+      // Check the session if the chosen locale hasn't been set yet.
+      if (empty($chosenLocale)) {
         $sessionLocale = $session->get('lcMessages');
         if (in_array($sessionLocale, $permittedLanguages)) {
           $chosenLocale = $sessionLocale;
         }
-        else {
-          $sessionLocale = NULL;
-        }
       }
 
-      if ($requestLocale) {
-        $ufm = new CRM_Core_DAO_UFMatch();
-        $ufm->contact_id = $session->get('userID');
-        if ($ufm->find(TRUE)) {
-          $ufm->language = $chosenLocale;
-          $ufm->save();
+      /*
+       * Maybe inherit the language from the CMS.
+       *
+       * If the language is specified via "lcMessages" we skip this, since the
+       * intention of the URL query var is to override all other sources.
+       */
+      if ($settings->get('inheritLocale') && empty($chosenLocale)) {
+
+        /*
+         * FIXME: On multi-language installs, CRM_Utils_System::getUFLocale() in
+         * many cases returns nothing if $dbLocale is not set, so set it to the
+         * default - even if it's overridden later.
+         */
+        $dbLocale = $multiLang && $defaultLocale ? "_{$defaultLocale}" : '';
+
+        // Retrieve locale as reported by CMS.
+        $cmsLocale = CRM_Utils_System::getUFLocale();
+        if (in_array($cmsLocale, $permittedLanguages)) {
+          $chosenLocale = $cmsLocale;
         }
-        $session->set('lcMessages', $chosenLocale);
-      }
 
-      if (!$chosenLocale and $session->get('userID')) {
-        $ufm = new CRM_Core_DAO_UFMatch();
-        $ufm->contact_id = $session->get('userID');
-        if ($ufm->find(TRUE) &&
-          in_array($ufm->language, $permittedLanguages)
-        ) {
-          $chosenLocale = $ufm->language;
+        // Clear chosen locale if not activated in multi-language CiviCRM.
+        if ($activatedLocales && !in_array($chosenLocale, explode(CRM_Core_DAO::VALUE_SEPARATOR, $activatedLocales))) {
+          $chosenLocale = NULL;
         }
-        $session->set('lcMessages', $chosenLocale);
+
       }
-    }
-    global $dbLocale;
-
-    // try to inherit the language from the hosting CMS
-    // If the language is specified in the session (ie. via lcMessages) we still allow it to be overridden.
-    if ($settings->get('inheritLocale') && empty($sessionLocale)) {
-      // FIXME: On multilanguage installs, CRM_Utils_System::getUFLocale() in many cases returns nothing if $dbLocale is not set
-      $lcMessages = $settings->get('lcMessages');
-      $dbLocale = $multiLang && $lcMessages ? "_{$lcMessages}" : '';
-      $chosenLocale = CRM_Utils_System::getUFLocale();
-      if ($activatedLocales and !in_array($chosenLocale, explode(CRM_Core_DAO::VALUE_SEPARATOR, $activatedLocales))) {
-        $chosenLocale = NULL;
+
+      // Assign the system default if the chosen locale hasn't been set.
+      if (empty($chosenLocale)) {
+        $chosenLocale = $defaultLocale;
       }
+
+      // Always assign the chosen locale to the session.
+      $session->set('lcMessages', $chosenLocale);
+
     }
+    else {
+
+      // CRM-11993 - Use default when it's a single-language install.
+      $chosenLocale = $defaultLocale;
 
-    if (empty($chosenLocale)) {
-      //CRM-11993 - if a single-lang site, use default
-      $chosenLocale = $settings->get('lcMessages');
     }
 
-    // set suffix for table names - use views if more than one language
+    /*
+     * Set suffix for table names in multi-language installs.
+     * Use views if more than one language.
+     */
     $dbLocale = $multiLang && $chosenLocale ? "_{$chosenLocale}" : '';
 
-    // FIXME: an ugly hack to fix CRM-4041
-    global $tsLocale;
+    // FIXME: an ugly hack to fix CRM-4041.
     $tsLocale = $chosenLocale;
 
-    // FIXME: as bad aplace as any to fix CRM-5428
-    // (to be moved to a sane location along with the above)
+    /*
+     * FIXME: as bad a place as any to fix CRM-5428.
+     * (to be moved to a sane location along with the above)
+     */
     if (function_exists('mb_internal_encoding')) {
       mb_internal_encoding('UTF-8');
     }
+
   }
 
   /**
index 3243ebb2a36e4f82d1883e2a4dc5dc5f4d8b32ae..1785fa9a93ad020da9ca3443db1328e031cab589 100644 (file)
@@ -349,10 +349,6 @@ class CRM_Core_Config extends CRM_Core_Config_MagicMerge {
       CRM_Core_DAO::executeQuery($query);
     }
 
-    if ($adapter = CRM_Utils_Constant::value('CIVICRM_BAO_CACHE_ADAPTER')) {
-      return $adapter::clearDBCache();
-    }
-
     // also delete all the import and export temp tables
     self::clearTempTables();
   }
index 4a4254c25505eab19aecbaf5105742fe943f76cc..68c653185855e6a0c726458358ef90da6addef69 100644 (file)
@@ -568,8 +568,8 @@ class CRM_Core_Controller extends HTML_QuickForm_Controller {
   public function addWizardStyle(&$wizard) {
     $wizard['style'] = [
       'barClass' => '',
-      'stepPrefixCurrent' => '<i class="crm-i fa-chevron-right" aria-hidden="true"></i>&nbsp;',
-      'stepPrefixPast' => '<i class="crm-i fa-check" aria-hidden="true"></i>&nbsp;',
+      'stepPrefixCurrent' => '<i class="crm-i fa-chevron-right" aria-hidden="true"></i> ',
+      'stepPrefixPast' => '<i class="crm-i fa-check" aria-hidden="true"></i> ',
       'stepPrefixFuture' => ' ',
       'subStepPrefixCurrent' => '&nbsp;&nbsp;',
       'subStepPrefixPast' => '&nbsp;&nbsp;',
index 430005a894f974f06fc203a57edd2540933b097d..a1cd6f7498915e29b1919cb62dd88662533a633a 100644 (file)
@@ -163,6 +163,11 @@ class CRM_Core_DAO extends DB_DataObject {
     $options = &PEAR::getStaticProperty('DB_DataObject', 'options');
     $options['database'] = $dsn;
     $options['quote_identifiers'] = TRUE;
+    if (self::isSSLDSN($dsn)) {
+      // There are two different options arrays.
+      $other_options = &PEAR::getStaticProperty('DB', 'options');
+      $other_options['ssl'] = TRUE;
+    }
     if (defined('CIVICRM_DAO_DEBUG')) {
       self::DebugLevel(CIVICRM_DAO_DEBUG);
     }
@@ -3106,4 +3111,21 @@ SELECT contact_id
     }
   }
 
+  /**
+   * Does the DSN indicate the connection should use ssl.
+   *
+   * @param string $dsn
+   *
+   * @return bool
+   */
+  public static function isSSLDSN(string $dsn):bool {
+    // Note that ssl= below is not an official PEAR::DB option. It doesn't know
+    // what to do with it. We made it up because it's not required
+    // to have client-side certificates to use ssl, so here you can specify
+    // you want that by putting ssl=1 in the DSN string.
+    //
+    // Cast to bool in case of error which we interpret as no ssl.
+    return (bool) preg_match('/[\?&](key|cert|ca|capath|cipher|ssl)=/', $dsn);
+  }
+
 }
index d23b83d959bdff3c90ce1cca86520b391e8a5b25..04f7e8cd39fadc2d311ac8824c73b51340ca4034 100644 (file)
@@ -358,7 +358,7 @@ class CRM_Core_Error extends PEAR_ErrorStack {
     if (CRM_Utils_Array::value('snippet', $_REQUEST) === CRM_Core_Smarty::PRINT_JSON) {
       $out = [
         'status' => 'fatal',
-        'content' => '<div class="messages status no-popup"><div class="icon inform-icon"></div>' . ts('Sorry but we are not able to provide this at the moment.') . '</div>',
+        'content' => '<div class="messages status no-popup">' . CRM_Core_Page::crmIcon('fa-info-circle') . ' ' . ts('Sorry but we are not able to provide this at the moment.') . '</div>',
       ];
       if ($config->backtrace && CRM_Core_Permission::check('view debug output')) {
         $out['backtrace'] = self::parseBacktrace(debug_backtrace());
@@ -573,18 +573,6 @@ class CRM_Core_Error extends PEAR_ErrorStack {
     }
     $file_log->close();
 
-    // Use the custom fatalErrorHandler if defined
-    if (in_array($priority, [PEAR_LOG_EMERG, PEAR_LOG_ALERT, PEAR_LOG_CRIT, PEAR_LOG_ERR])) {
-      if ($config->fatalErrorHandler && function_exists($config->fatalErrorHandler)) {
-        $name = $config->fatalErrorHandler;
-        $vars = [
-          'debugLogMessage' => $message,
-          'priority' => $priority,
-        ];
-        $name($vars);
-      }
-    }
-
     if (!isset(\Civi::$statics[__CLASS__]['userFrameworkLogging'])) {
       // Set it to FALSE first & then try to set it. This is to prevent a loop as calling
       // $config->userFrameworkLogging can trigger DB queries & under log mode this
index 7bd57e0dd7a0722496ae5adf59b66825f1ef1e06..ae4391a37170d64d861b28f26e8920b19fc05e8d 100644 (file)
@@ -366,6 +366,9 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
     $type, $name, $label = '',
     $attributes = '', $required = FALSE, $extra = NULL
   ) {
+    if ($type === 'radio') {
+      CRM_Core_Error::deprecatedFunctionWarning('CRM_Core_Form::addRadio');
+    }
     // Fudge some extra types that quickform doesn't support
     $inputType = $type;
     if ($type == 'wysiwyg' || in_array($type, self::$html5Types)) {
@@ -1202,7 +1205,11 @@ class CRM_Core_Form extends HTML_QuickForm_Page {
           }
         }
       }
-      $options[] = $this->createElement('radio', NULL, NULL, $var, $key, $optAttributes);
+      $element = $this->createElement('radio', NULL, NULL, $var, $key, $optAttributes);
+      if ($required) {
+        $element->setAttribute('required', TRUE);
+      }
+      $options[] = $element;
     }
     $group = $this->addGroup($options, $name, $title, $separator);
 
index 637a3a61476f79d43f57c5295c5020c19df46cef..3e4ee1235b1cff4be2c0ee1aeb6d0adf21e73fa9 100644 (file)
@@ -110,30 +110,19 @@ class CRM_Core_Key {
   }
 
   /**
-   * @param $key
+   * The original version of this function, added circa 2010 and untouched
+   * since then, seemed intended to check for a 32-digit hex string followed
+   * optionally by an underscore and 4-digit number. But it had a bug where
+   * the optional part was never checked ever. So have decided to remove that
+   * second check to keep it simple since it seems like pseudo-security.
+   *
+   * @param string $key
    *
    * @return bool
    */
   public static function valid($key) {
-    // a valid key is a 32 digit hex number
-    // followed by an optional _ and a number between 1 and 10000
-    if (strpos('_', $key) !== FALSE) {
-      list($hash, $seq) = explode('_', $key);
-
-      // ensure seq is between 1 and 10000
-      if (!is_numeric($seq) ||
-        $seq < 1 ||
-        $seq > 10000
-      ) {
-        return FALSE;
-      }
-    }
-    else {
-      $hash = $key;
-    }
-
-    // ensure that hash is a 32 digit hex number
-    return (bool) preg_match('#[0-9a-f]{32}#i', $hash);
+    // ensure that key contains a 32 digit hex string
+    return (bool) preg_match('#[0-9a-f]{32}#i', $key);
   }
 
 }
index 277c5346115181dffab1ecf8bc84dee65d98951e..9c998dc66d604dd2dde9ee5c848cd572f2068688 100644 (file)
@@ -1504,7 +1504,8 @@ abstract class CRM_Core_Payment {
     catch (CRM_Core_Exception $e) {
       Civi::log()->error('ipn_payment_callback_exception', [
         'context' => [
-          'backtrace' => CRM_Core_Error::formatBacktrace(debug_backtrace()),
+          'backtrace' => $e->getTraceAsString(),
+          'message' => $e->getMessage(),
         ],
       ]);
     }
index 7946ecacbe493b3d2a2089b57f176b752385fd7c..83697bd338fa7f7da2e3aa99bbc420a78e136ae7 100644 (file)
@@ -100,22 +100,20 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
    *
    * @return bool
    */
-  public function recur(&$input, &$ids, &$objects, $first) {
+  public function recur($input, $ids, $objects, $first) {
     $this->_isRecurring = TRUE;
     $recur = &$objects['contributionRecur'];
     $paymentProcessorObject = $objects['contribution']->_relatedObjects['paymentProcessor']['object'];
 
     // do a subscription check
     if ($recur->processor_id != $input['subscription_id']) {
-      CRM_Core_Error::debug_log_message("Unrecognized subscription.");
-      echo "Failure: Unrecognized subscription<p>";
+      CRM_Core_Error::debug_log_message('Unrecognized subscription.');
+      echo 'Failure: Unrecognized subscription<p>';
       return FALSE;
     }
 
     $contributionStatus = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name');
 
-    $transaction = new CRM_Core_Transaction();
-
     $now = date('YmdHis');
 
     //load new contribution object if required.
@@ -148,18 +146,17 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
         $recur->trxn_id = $recur->processor_id;
         $isFirstOrLastRecurringPayment = CRM_Core_Payment::RECURRING_PAYMENT_START;
       }
-      $statusName = 'In Progress';
+
       if (($recur->installments > 0) &&
         ($input['subscription_paynum'] >= $recur->installments)
       ) {
         // this is the last payment
-        $statusName = 'Completed';
         $recur->end_date = $now;
         $isFirstOrLastRecurringPayment = CRM_Core_Payment::RECURRING_PAYMENT_END;
+        // This end date update should occur in ContributionRecur::updateOnNewPayment
+        // testIPNPaymentRecurNoReceipt has test cover.
+        $recur->save();
       }
-      $recur->modified_date = $now;
-      $recur->contribution_status_id = array_search($statusName, $contributionStatus);
-      $recur->save();
     }
     else {
       // Declined
@@ -168,7 +165,7 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
       $recur->cancel_date = $now;
       $recur->save();
 
-      $message = ts("Subscription payment failed - %1", [1 => htmlspecialchars($input['response_reason_text'])]);
+      $message = ts('Subscription payment failed - %1', [1 => htmlspecialchars($input['response_reason_text'])]);
       CRM_Core_Error::debug_log_message($message);
 
       // the recurring contribution has declined a payment or has failed
@@ -180,13 +177,12 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
 
     // check if contribution is already completed, if so we ignore this ipn
     if ($objects['contribution']->contribution_status_id == 1) {
-      $transaction->commit();
       CRM_Core_Error::debug_log_message("Returning since contribution has already been handled.");
-      echo "Success: Contribution has already been handled<p>";
+      echo 'Success: Contribution has already been handled<p>';
       return TRUE;
     }
 
-    $this->completeTransaction($input, $ids, $objects, $transaction, $recur);
+    $this->completeTransaction($input, $ids, $objects);
 
     // Only Authorize.net does this so it is on the a.net class. If there is a need for other processors
     // to do this we should make it available via the api, e.g as a parameter, changing the nuance
@@ -203,11 +199,10 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
    * Get the input from passed in fields.
    *
    * @param array $input
-   * @param array $ids
    *
    * @throws \CRM_Core_Exception
    */
-  public function getInput(&$input, &$ids) {
+  public function getInput(&$input) {
     $input['amount'] = $this->retrieve('x_amount', 'String');
     $input['subscription_id'] = $this->retrieve('x_subscription_id', 'Integer');
     $input['response_code'] = $this->retrieve('x_response_code', 'Integer');
@@ -216,7 +211,6 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
     $input['response_reason_text'] = $this->retrieve('x_response_reason_text', 'String', FALSE);
     $input['subscription_paynum'] = $this->retrieve('x_subscription_paynum', 'Integer', FALSE, 0);
     $input['trxn_id'] = $this->retrieve('x_trans_id', 'String', FALSE);
-    $input['trxn_id'] = $this->retrieve('x_trans_id', 'String', FALSE);
     $input['receive_date'] = $this->retrieve('receive_date', 'String', FALSE, date('YmdHis', strtotime('now')));
 
     if ($input['trxn_id']) {
@@ -229,7 +223,7 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
       $input['trxn_id'] = md5(uniqid(rand(), TRUE));
     }
 
-    $billingID = $ids['billing'] = CRM_Core_BAO_LocationType::getBilling();
+    $billingID = CRM_Core_BAO_LocationType::getBilling();
     $params = [
       'first_name' => 'x_first_name',
       'last_name' => 'x_last_name',
index 973fbd988894b02582d1d483917c7ee91e3e86f8..27b0074814464f3a29b549dff6981386bdb2a272 100644 (file)
@@ -214,7 +214,7 @@ class CRM_Core_Payment_BaseIPN {
    * @return bool
    * @throws \CiviCRM_API3_Exception
    */
-  public function failed(&$objects, &$transaction, $input = []) {
+  public function failed(&$objects, $transaction = NULL, $input = []) {
     $contribution = &$objects['contribution'];
     $memberships = [];
     if (!empty($objects['membership'])) {
@@ -224,21 +224,9 @@ class CRM_Core_Payment_BaseIPN {
       }
     }
 
-    $addLineItems = FALSE;
-    if (empty($contribution->id)) {
-      $addLineItems = TRUE;
-    }
+    $addLineItems = empty($contribution->id);
     $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['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 = CRM_Core_PseudoConstant::getKey('CRM_Contribute_DAO_Contribution', 'contribution_status_id', 'Failed');
     $contribution->save();
 
     // Add line items for recurring payments.
@@ -266,7 +254,9 @@ class CRM_Core_Payment_BaseIPN {
       }
     }
 
-    $transaction->commit();
+    if ($transaction) {
+      $transaction->commit();
+    }
     Civi::log()->debug("Setting contribution status to Failed");
     return TRUE;
   }
@@ -299,7 +289,7 @@ class CRM_Core_Payment_BaseIPN {
    * @return bool
    * @throws \CiviCRM_API3_Exception
    */
-  public function cancelled(&$objects, &$transaction, $input = []) {
+  public function cancelled(&$objects, $transaction = NULL, $input = []) {
     $contribution = &$objects['contribution'];
     $memberships = [];
     if (!empty($objects['membership'])) {
@@ -353,7 +343,9 @@ class CRM_Core_Payment_BaseIPN {
         $this->cancelParticipant($participant->id);
       }
     }
-    $transaction->commit();
+    if ($transaction) {
+      $transaction->commit();
+    }
     Civi::log()->debug("Setting contribution status to Cancelled");
     return TRUE;
   }
@@ -477,13 +469,12 @@ class CRM_Core_Payment_BaseIPN {
    * @param array $input
    * @param array $ids
    * @param array $objects
-   * @param CRM_Core_Transaction $transaction
    *
    * @throws \CRM_Core_Exception
    * @throws \CiviCRM_API3_Exception
    */
-  public function completeTransaction(&$input, &$ids, &$objects, $transaction = NULL) {
-    CRM_Contribute_BAO_Contribution::completeOrder($input, $ids, $objects, $transaction);
+  public function completeTransaction(&$input, &$ids, &$objects) {
+    CRM_Contribute_BAO_Contribution::completeOrder($input, $ids, $objects);
   }
 
   /**
@@ -518,21 +509,14 @@ class CRM_Core_Payment_BaseIPN {
    * @param array $ids
    *   Related object IDs.
    * @param array $objects
-   * @param array $values
-   *   Values related to objects that have already been loaded.
-   * @param bool $recur
-   *   Is it part of a recurring contribution.
-   * @param bool $returnMessageText
-   *   Should text be returned instead of sent. This.
-   *   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,
-      $returnMessageText);
+  public function sendMail($input, $ids, $objects) {
+    CRM_Core_Error::deprecatedFunctionWarning('this should be done via completetransaction api');
+    civicrm_api3('Contribution', 'sendconfirmation', [
+      'id' => $objects['contribution']->id,
+    ]);
   }
 
 }
index a2c7c5dd2593a0d65a0b9f9833a37007cd2a72c9..4c254691cc83d8964223a95717ff3a561423a14c 100644 (file)
@@ -238,25 +238,6 @@ class CRM_Core_Payment_Manual extends CRM_Core_Payment {
     return TRUE;
   }
 
-  /**
-   * Submit a manual payment.
-   *
-   * @param array $params
-   *   Assoc array of input parameters for this transaction.
-   *
-   * @return array
-   */
-  public function doDirectPayment(&$params) {
-    $statuses = CRM_Contribute_BAO_Contribution::buildOptions('contribution_status_id');
-    if ($params['is_pay_later']) {
-      $result['payment_status_id'] = array_search('Pending', $statuses);
-    }
-    else {
-      $result['payment_status_id'] = array_search('Completed', $statuses);
-    }
-    return $result;
-  }
-
   /**
    * Should a receipt be sent out for a pending payment.
    *
index 0e87056c8755bde0a2d8c017730632d2eafeffc4..b6948ddbd47b2f10cbea78e55e9e9a6daeff99e6 100644 (file)
@@ -229,8 +229,10 @@ class CRM_Core_Payment_PayPalIPN extends CRM_Core_Payment_BaseIPN {
    * @param bool $first
    *
    * @return void
+   * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
    */
-  public function single(&$input, &$ids, &$objects, $recur = FALSE, $first = FALSE) {
+  public function single($input, $ids, $objects, $recur = FALSE, $first = FALSE) {
     $contribution = &$objects['contribution'];
 
     // make sure the invoice is valid and matches what we have in the contribution record
@@ -256,18 +258,18 @@ class CRM_Core_Payment_PayPalIPN extends CRM_Core_Payment_BaseIPN {
       $contribution->total_amount = $input['amount'];
     }
 
-    $transaction = new CRM_Core_Transaction();
-
     $status = $input['paymentStatus'];
-    if ($status == 'Denied' || $status == 'Failed' || $status == 'Voided') {
-      return $this->failed($objects, $transaction);
+    if ($status === 'Denied' || $status === 'Failed' || $status === 'Voided') {
+      $this->failed($objects);
+      return;
     }
     if ($status === 'Pending') {
       Civi::log()->debug('Returning since contribution status is Pending');
       return;
     }
-    elseif ($status == 'Refunded' || $status == 'Reversed') {
-      return $this->cancelled($objects, $transaction);
+    elseif ($status === 'Refunded' || $status === 'Reversed') {
+      $this->cancelled($objects);
+      return;
     }
     elseif ($status !== 'Completed') {
       Civi::log()->debug('Returning since contribution status is not handled');
@@ -277,13 +279,12 @@ class CRM_Core_Payment_PayPalIPN extends CRM_Core_Payment_BaseIPN {
     // check if contribution is already completed, if so we ignore this ipn
     $completedStatusId = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
     if ($contribution->contribution_status_id == $completedStatusId) {
-      $transaction->commit();
       Civi::log()->debug('PayPalIPN: Returning since contribution has already been handled. (ID: ' . $contribution->id . ').');
       echo 'Success: Contribution has already been handled<p>';
       return;
     }
 
-    $this->completeTransaction($input, $ids, $objects, $transaction, $recur);
+    $this->completeTransaction($input, $ids, $objects);
   }
 
   /**
@@ -302,7 +303,7 @@ class CRM_Core_Payment_PayPalIPN extends CRM_Core_Payment_BaseIPN {
     $membershipID = $this->retrieve('membershipID', 'Integer', FALSE);
     $contributionRecurID = $this->retrieve('contributionRecurID', 'Integer', FALSE);
 
-    $this->getInput($input, $ids);
+    $this->getInput($input);
 
     if ($component == 'event') {
       $ids['event'] = $this->retrieve('eventID', 'Integer', TRUE);
@@ -370,17 +371,16 @@ class CRM_Core_Payment_PayPalIPN extends CRM_Core_Payment_BaseIPN {
         return;
       }
     }
-    $this->single($input, $ids, $objects, FALSE, FALSE);
+    $this->single($input, $ids, $objects);
   }
 
   /**
    * @param array $input
-   * @param array $ids
    *
    * @throws \CRM_Core_Exception
    */
-  public function getInput(&$input, &$ids) {
-    $billingID = $ids['billing'] = CRM_Core_BAO_LocationType::getBilling();
+  public function getInput(&$input) {
+    $billingID = CRM_Core_BAO_LocationType::getBilling();
     $input['txnType'] = $this->retrieve('txn_type', 'String', FALSE);
     $input['paymentStatus'] = $this->retrieve('payment_status', 'String', FALSE);
     $input['invoice'] = $this->retrieve('invoice', 'String', TRUE);
index d249aa0bef30b2d2a494358eda818db76a3c80e2..e5c58d3de7ec8045dbb6e4187fd822b114853a43 100644 (file)
@@ -145,16 +145,19 @@ class CRM_Core_Payment_PayPalProIPN extends CRM_Core_Payment_BaseIPN {
 
   /**
    * Process recurring contributions.
+   *
    * @param array $input
    * @param array $ids
    * @param array $objects
    * @param bool $first
-   * @return void
+   *
+   * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
    */
-  public function recur(&$input, &$ids, &$objects, $first) {
+  public function recur($input, $ids, $objects, $first) {
     if (!isset($input['txnType'])) {
       Civi::log()->debug('PayPalProIPN: Could not find txn_type in input request.');
-      echo "Failure: Invalid parameters<p>";
+      echo 'Failure: Invalid parameters<p>';
       return;
     }
 
@@ -165,7 +168,7 @@ class CRM_Core_Payment_PayPalProIPN extends CRM_Core_Payment_BaseIPN {
     // the contribution record
     if ($recur->invoice_id != $input['invoice']) {
       Civi::log()->debug('PayPalProIPN: Invoice values dont match between database and IPN request recur is ' . $recur->invoice_id . ' input is ' . $input['invoice']);
-      echo "Failure: Invoice values dont match between database and IPN request recur is " . $recur->invoice_id . " input is " . $input['invoice'];
+      echo 'Failure: Invoice values dont match between database and IPN request recur is ' . $recur->invoice_id . " input is " . $input['invoice'];
       return;
     }
 
@@ -344,19 +347,17 @@ class CRM_Core_Payment_PayPalProIPN extends CRM_Core_Payment_BaseIPN {
       $contribution->total_amount = $input['amount'];
     }
 
-    $transaction = new CRM_Core_Transaction();
-
     $status = $input['paymentStatus'];
-    if ($status == 'Denied' || $status == 'Failed' || $status == 'Voided') {
-      $this->failed($objects, $transaction);
+    if ($status === 'Denied' || $status === 'Failed' || $status === 'Voided') {
+      $this->failed($objects);
       return;
     }
     if ($status === 'Pending') {
       Civi::log()->debug('Returning since contribution status is Pending');
       return;
     }
-    elseif ($status == 'Refunded' || $status == 'Reversed') {
-      $this->cancelled($objects, $transaction);
+    elseif ($status === 'Refunded' || $status === 'Reversed') {
+      $this->cancelled($objects);
       return;
     }
     elseif ($status !== 'Completed') {
@@ -367,13 +368,12 @@ class CRM_Core_Payment_PayPalProIPN extends CRM_Core_Payment_BaseIPN {
     // check if contribution is already completed, if so we ignore this ipn
     $completedStatusId = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed');
     if ($contribution->contribution_status_id == $completedStatusId) {
-      $transaction->commit();
       Civi::log()->debug('PayPalProIPN: Returning since contribution has already been handled.');
       echo 'Success: Contribution has already been handled<p>';
       return;
     }
 
-    $this->completeTransaction($input, $ids, $objects, $transaction, $recur);
+    $this->completeTransaction($input, $ids, $objects);
   }
 
   /**
@@ -423,7 +423,7 @@ class CRM_Core_Payment_PayPalProIPN extends CRM_Core_Payment_BaseIPN {
     $ids['contact'] = self::getValue('c', TRUE);
     $ids['contribution'] = self::getValue('b', TRUE);
 
-    $this->getInput($input, $ids);
+    $this->getInput($input);
 
     if ($this->_component == 'event') {
       $ids['event'] = self::getValue('e', TRUE);
@@ -487,13 +487,12 @@ INNER JOIN civicrm_membership_payment mp ON m.id = mp.membership_id AND mp.contr
 
   /**
    * @param array $input
-   * @param array $ids
    *
    * @return void
    * @throws CRM_Core_Exception
    */
-  public function getInput(&$input, &$ids) {
-    $billingID = $ids['billing'] = CRM_Core_BAO_LocationType::getBilling();
+  public function getInput(&$input) {
+    $billingID = CRM_Core_BAO_LocationType::getBilling();
 
     $input['txnType'] = self::retrieve('txn_type', 'String', 'POST', FALSE);
     $input['paymentStatus'] = self::retrieve('payment_status', 'String', 'POST', FALSE);
diff --git a/CRM/Core/Payment/PaymentExpress.php b/CRM/Core/Payment/PaymentExpress.php
deleted file mode 100644 (file)
index 2315f59..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-<?php
-/*
- +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC. All rights reserved.                        |
- |                                                                    |
- | This work is published under the GNU AGPLv3 license with some      |
- | permitted exceptions and without any warranty. For full license    |
- | and copyright information, see https://civicrm.org/licensing       |
- +--------------------------------------------------------------------+
- */
-
-
-/*
- * PxPay Functionality Copyright (C) 2008 Lucas Baker, Logistic Information Systems Limited (Logis)
- * PxAccess Functionality Copyright (C) 2008 Eileen McNaughton
- * Licensed to CiviCRM under the Academic Free License version 3.0.
- *
- * Grateful acknowledgements go to Donald Lobo for invaluable assistance
- * in creating this payment processor module
- */
-
-/**
- * Class CRM_Core_Payment_PaymentExpress
- */
-class CRM_Core_Payment_PaymentExpress extends CRM_Core_Payment {
-  const CHARSET = 'iso-8859-1';
-
-  protected $_mode = NULL;
-
-  /**
-   * Constructor.
-   *
-   * @param string $mode
-   *   The mode of operation: live or test.
-   *
-   * @param $paymentProcessor
-   *
-   * @return \CRM_Core_Payment_PaymentExpress
-   */
-  public function __construct($mode, &$paymentProcessor) {
-
-    $this->_mode = $mode;
-    $this->_paymentProcessor = $paymentProcessor;
-  }
-
-  /**
-   * This function checks to see if we have the right config values.
-   *
-   * @internal param string $mode the mode we are operating in (live or test)
-   *
-   * @return string
-   *   the error message if any
-   */
-  public function checkConfig() {
-    $config = CRM_Core_Config::singleton();
-
-    $error = [];
-
-    if (empty($this->_paymentProcessor['user_name'])) {
-      $error[] = ts('UserID is not set in the Administer &raquo; System Settings &raquo; Payment Processors');
-    }
-
-    if (empty($this->_paymentProcessor['password'])) {
-      $error[] = ts('pxAccess / pxPay Key is not set in the Administer &raquo; System Settings &raquo; Payment Processors');
-    }
-
-    if (!empty($error)) {
-      return implode('<p>', $error);
-    }
-    else {
-      return NULL;
-    }
-  }
-
-  /**
-   * This function collects all the information from a web/api form and invokes
-   * the relevant payment processor specific functions to perform the transaction
-   *
-   * @param array $params
-   *   Assoc array of input parameters for this transaction.
-   */
-  public function doDirectPayment(&$params) {
-    throw new CRM_Core_Exception(ts('This function is not implemented'));
-  }
-
-  /**
-   * Main transaction function.
-   *
-   * @param array $params
-   *   Name value pair of contribution data.
-   *
-   * @param $component
-   */
-  public function doTransferCheckout(&$params, $component) {
-    // This is broken - in 2015 this commit broke it... https://github.com/civicrm/civicrm-core/commit/204c86d59f0cfc4c4d917cc245fb41633d36916e#diff-b00e65c9829c27da8b34e35f2e64d9b6L114
-    $component = strtolower($component);
-    $config = CRM_Core_Config::singleton();
-    if ($component != 'contribute' && $component != 'event') {
-      throw new CRM_Core_Exception(ts('Component is invalid'));
-    }
-
-    $url = CRM_Utils_System::externUrl('extern/pxIPN');
-
-    if ($component == 'event') {
-      $cancelURL = CRM_Utils_System::url('civicrm/event/register',
-        "_qf_Confirm_display=true&qfKey={$params['qfKey']}",
-        FALSE, NULL, FALSE
-      );
-    }
-    elseif ($component == 'contribute') {
-      $cancelURL = CRM_Utils_System::url('civicrm/contribute/transact',
-        "_qf_Confirm_display=true&qfKey={$params['qfKey']}",
-        FALSE, NULL, FALSE
-      );
-    }
-
-    /*
-     * Build the private data string to pass to DPS, which they will give back to us with the
-     *
-     * transaction result.  We are building this as a comma-separated list so as to avoid long URLs.
-     *
-     * Parameters passed: a=contactID, b=contributionID,c=contributionTypeID,d=invoiceID,e=membershipID,f=participantID,g=eventID
-     */
-
-    $privateData = "a={$params['contactID']},b={$params['contributionID']},c={$params['contributionTypeID']},d={$params['invoiceID']}";
-
-    if ($component == 'event') {
-      $merchantRef = substr($params['contactID'] . "-" . $params['contributionID'] . " " . substr($params['description'], 27, 20), 0, 24);
-      $privateData .= ",f={$params['participantID']},g={$params['eventID']}";
-    }
-    elseif ($component == 'contribute') {
-      $membershipID = $params['membershipID'] ?? NULL;
-      if ($membershipID) {
-        $privateData .= ",e=$membershipID";
-      }
-      $merchantRef = substr($params['contactID'] . "-" . $params['contributionID'] . " " . substr($params['description'], 20, 20), 0, 24);
-
-    }
-
-    $dpsParams = [
-      'AmountInput' => str_replace(",", "", number_format($params['amount'], 2)),
-      'CurrencyInput' => $params['currencyID'],
-      'MerchantReference' => $merchantRef,
-      'TxnData1' => $params['qfKey'],
-      'TxnData2' => $privateData,
-      'TxnData3' => $component . "," . $this->_paymentProcessor['id'],
-      'TxnType' => 'Purchase',
-      // Leave this empty for now, causes an error with DPS if we populate it
-      'TxnId' => '',
-      'UrlFail' => $url,
-      'UrlSuccess' => $url,
-    ];
-    // Allow further manipulation of params via custom hooks
-    CRM_Utils_Hook::alterPaymentProcessorParams($this, $params, $dpsParams);
-
-    /*
-     *  determine whether method is pxaccess or pxpay by whether signature (mac key) is defined
-     */
-
-    if (empty($this->_paymentProcessor['signature'])) {
-      /*
-       * Processor is pxpay
-       *
-       * This contains the XML/Curl functions we'll need to generate the XML request
-       */
-
-      $dpsParams['PxPayUserId'] = $this->_paymentProcessor['user_name'];
-      $dpsParams['PxPayKey'] = $this->_paymentProcessor['password'];
-      // Build a valid XML string to pass to DPS
-      $generateRequest = CRM_Core_Payment_PaymentExpressUtils::_valueXml($dpsParams);
-
-      $generateRequest = CRM_Core_Payment_PaymentExpressUtils::_valueXml('GenerateRequest', $generateRequest);
-      // Get the special validated URL back from DPS by sending them the XML we've generated
-      $curl = CRM_Core_Payment_PaymentExpressUtils::_initCURL($generateRequest, $this->_paymentProcessor['url_site']);
-      $success = FALSE;
-
-      if ($response = curl_exec($curl)) {
-        curl_close($curl);
-        $valid = CRM_Core_Payment_PaymentExpressUtils::_xmlAttribute($response, 'valid');
-        if (1 == $valid) {
-          // the request was validated, so we'll get the URL and redirect to it
-          $uri = CRM_Core_Payment_PaymentExpressUtils::_xmlElement($response, 'URI');
-          CRM_Utils_System::redirect($uri);
-        }
-        else {
-          // redisplay confirmation page
-          CRM_Utils_System::redirect($cancelURL);
-        }
-      }
-      else {
-        // calling DPS failed
-        throw new CRM_Core_Exception(ts('Unable to establish connection to the payment gateway.'));
-      }
-    }
-    else {
-      $processortype = "pxaccess";
-      require_once 'PaymentExpress/pxaccess.inc.php';
-      // URL
-      $PxAccess_Url = $this->_paymentProcessor['url_site'];
-      // User ID
-      $PxAccess_Userid = $this->_paymentProcessor['user_name'];
-      // Your DES Key from DPS
-      $PxAccess_Key = $this->_paymentProcessor['password'];
-      // Your MAC key from DPS
-      $Mac_Key = $this->_paymentProcessor['signature'];
-
-      $pxaccess = new PxAccess($PxAccess_Url, $PxAccess_Userid, $PxAccess_Key, $Mac_Key);
-      $request = new PxPayRequest();
-      $request->setAmountInput($dpsParams['AmountInput']);
-      $request->setTxnData1($dpsParams['TxnData1']);
-      $request->setTxnData2($dpsParams['TxnData2']);
-      $request->setTxnData3($dpsParams['TxnData3']);
-      $request->setTxnType($dpsParams['TxnType']);
-      $request->setInputCurrency($dpsParams['InputCurrency']);
-      $request->setMerchantReference($dpsParams['MerchantReference']);
-      $request->setUrlFail($dpsParams['UrlFail']);
-      $request->setUrlSuccess($dpsParams['UrlSuccess']);
-      $request_string = $pxaccess->makeRequest($request);
-      CRM_Utils_System::redirect($request_string);
-    }
-  }
-
-}
diff --git a/CRM/Core/Payment/PaymentExpressUtils.php b/CRM/Core/Payment/PaymentExpressUtils.php
deleted file mode 100644 (file)
index 015207e..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-<?php
-/*
- +--------------------------------------------------------------------+
- | Copyright CiviCRM LLC. All rights reserved.                        |
- |                                                                    |
- | This work is published under the GNU AGPLv3 license with some      |
- | permitted exceptions and without any warranty. For full license    |
- | and copyright information, see https://civicrm.org/licensing       |
- +--------------------------------------------------------------------+
- */
-
-
-/*
- * PxPay Functionality Copyright (C) 2008 Lucas Baker, Logistic Information Systems Limited (Logis)
- * PxAccess Functionality Copyright (C) 2008 Eileen McNaughton
- * Licensed to CiviCRM under the Academic Free License version 3.0.
- *
- * Grateful acknowledgements go to Donald Lobo for invaluable assistance
- * in creating this payment processor module
- */
-
-/**
- * Class CRM_Core_Payment_PaymentExpressUtils
- */
-class CRM_Core_Payment_PaymentExpressUtils {
-
-  /**
-   * @param $element
-   * @param null $value
-   *
-   * @return string
-   */
-  public static function _valueXml($element, $value = NULL) {
-    $nl = "\n";
-
-    if (is_array($element)) {
-      $xml = '';
-      foreach ($element as $elem => $value) {
-        $xml .= self::_valueXml($elem, $value);
-      }
-      return $xml;
-    }
-    return "<" . $element . ">" . $value . "</" . $element . ">" . $nl;
-  }
-
-  /**
-   * @param $xml
-   * @param string $name
-   *
-   * @return mixed
-   */
-  public static function _xmlElement($xml, $name) {
-    $value = preg_replace('/.*<' . $name . '[^>]*>(.*)<\/' . $name . '>.*/', '\1', $xml);
-    return $value;
-  }
-
-  /**
-   * @param $xml
-   * @param string $name
-   *
-   * @return mixed|null
-   */
-  public static function _xmlAttribute($xml, $name) {
-    $value = preg_replace('/<.*' . $name . '="([^"]*)".*>/', '\1', $xml);
-    return $value != $xml ? $value : NULL;
-  }
-
-  /**
-   * @param $query
-   * @param $url
-   *
-   * @return resource
-   */
-  public static function &_initCURL($query, $url) {
-    $curl = curl_init();
-
-    curl_setopt($curl, CURLOPT_URL, $url);
-    curl_setopt($curl, CURLOPT_FRESH_CONNECT, TRUE);
-    curl_setopt($curl, CURLOPT_POST, TRUE);
-    curl_setopt($curl, CURLOPT_POSTFIELDS, $query);
-    curl_setopt($curl, CURLOPT_TIMEOUT, 30);
-    curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
-    if (ini_get('open_basedir') == '' && ini_get('safe_mode') == 'Off') {
-      curl_setopt($curl, CURLOPT_FOLLOWLOCATION, FALSE);
-    }
-    curl_setopt($curl, CURLOPT_HEADER, 0);
-    curl_setopt($curl, CURLOPT_SSLVERSION, 0);
-
-    if (strtoupper(substr(@php_uname('s'), 0, 3)) === 'WIN') {
-      curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, Civi::settings()->get('verifySSL'));
-      curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, Civi::settings()->get('verifySSL') ? 2 : 0);
-    }
-    return $curl;
-  }
-
-}
index 390a8e73030e4d039daa89eff48c6c9c05a0502d..64543d5957683dbbf5d193dda100261bd8f42140 100644 (file)
@@ -47,7 +47,7 @@ function smarty_block_crmButton($params, $text, &$smarty) {
     if (strpos($icon, 'fa-') !== 0) {
       $icon = "fa-$icon";
     }
-    $iconMarkup = "<i class='crm-i $icon' aria-hidden=\"true\"></i>&nbsp; ";
+    $iconMarkup = "<i class='crm-i $icon' aria-hidden=\"true\"></i> ";
   }
   // All other params are treated as html attributes
   CRM_Utils_Array::remove($params, 'icon', 'p', 'q', 'a', 'f', 'h', 'fb', 'fe');
index 0bab319abba78892d3e4e7297d15ae32b080eb07..ca548fba2d0da350c02cab17e292be22d7cadf14 100644 (file)
@@ -935,7 +935,8 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
           unset($dupePairs[$index]);
           continue;
         }
-        if (($result = self::dedupePair($dupes, $mode, $checkPermissions, $cacheKeyString)) === FALSE) {
+        CRM_Utils_Hook::merge('flip', $dupes, $dupes['dstID'], $dupes['srcID']);
+        if (($result = self::dedupePair((int) $dupes['dstID'], (int) $dupes['srcID'], $mode, $checkPermissions, $cacheKeyString)) === FALSE) {
           unset($dupePairs[$index]);
           continue;
         }
@@ -1005,7 +1006,11 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
   }
 
   /**
-   * Compare 2 addresses to see if they are the same.
+   * Compare 2 addresses to see if they are the effectively the same.
+   *
+   * Being the same would mean same location type and any populated fields that describe the locationn match.
+   *
+   * Metadata fields such as is_primary, on_hold, manual_geocode may differ.
    *
    * @param array $mainAddress
    * @param array $comparisonAddress
@@ -1025,6 +1030,39 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
     return TRUE;
   }
 
+  /**
+   * Does the location array have valid data.
+   *
+   * While not UI-creatable some sites wind up with email or address rows with no actual email or address
+   * through non core-UI processes.
+   *
+   * @param array $location
+   *
+   * @return bool
+   */
+  public static function locationHasData($location) {
+    return !empty(self::getLocationDataFields($location));
+  }
+
+  /**
+   * Get the location data from a location array, filtering out metadata.
+   *
+   * This returns data like street_address but not metadata like is_primary, on_hold etc.
+   *
+   * @param array $location
+   *
+   * @return mixed
+   */
+  public static function getLocationDataFields($location) {
+    $keysToIgnore = array_merge(self::ignoredFields(), ['display', 'location_type_id']);
+    foreach ($location as $field => $value) {
+      if (in_array($field, $keysToIgnore, TRUE)) {
+        unset($location[$field]);
+      }
+    }
+    return $location;
+  }
+
   /**
    * A function to build an array of information about location blocks that is
    * required when merging location fields
@@ -1862,26 +1900,22 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
   /**
    * Dedupe a pair of contacts.
    *
-   * @param array $dupes
+   * @param int $mainId Id of contact to keep.
+   * @param int $otherId Id of contact to delete.
    * @param string $mode
    * @param bool $checkPermissions
    * @param string $cacheKeyString
    *
    * @return bool|array
+   * @throws \API_Exception
    * @throws \CRM_Core_Exception
+   * @throws \CRM_Core_Exception_ResourceConflictException
    * @throws \CiviCRM_API3_Exception
-   * @throws \API_Exception
+   * @throws \Civi\API\Exception\UnauthorizedException
    */
-  protected static function dedupePair($dupes, $mode = 'safe', $checkPermissions = TRUE, $cacheKeyString = NULL) {
-    CRM_Utils_Hook::merge('flip', $dupes, $dupes['dstID'], $dupes['srcID']);
-    $mainId = $dupes['dstID'];
-    $otherId = $dupes['srcID'];
+  protected static function dedupePair(int $mainId, int $otherId, $mode = 'safe', $checkPermissions = TRUE, $cacheKeyString = NULL) {
     $resultStats = [];
 
-    if (!$mainId || !$otherId) {
-      // return error
-      return FALSE;
-    }
     $migrationInfo = [];
     $conflicts = [];
     // Try to lock the contacts before we load the data as we don't want it changing under us.
@@ -2144,13 +2178,19 @@ INNER JOIN  civicrm_membership membership2 ON membership1.membership_type_id = m
           // If it exists on the 'main' contact already, skip it. Otherwise
           // if the location type exists already, log a conflict.
           foreach ($migrationInfo['main_details']['location_blocks'][$fieldName] as $mainAddressKey => $mainAddressRecord) {
+            if (!self::locationHasData($mainAddressRecord)) {
+              // Go ahead & overwrite the main address - it has no data in it.
+              // if it is the primary address then pass that honour to the address that actually has data.
+              $migrationInfo['location_blocks'][$fieldName][$mainAddressKey]['set_other_primary'] = $mainAddressRecord['is_primary'];
+              continue;
+            }
             if (self::locationIsSame($addressRecord, $mainAddressRecord)) {
               unset($migrationInfo[$key]);
-              break;
+              continue;
             }
-            elseif ($addressRecordLocTypeId == $mainAddressRecord['location_type_id']) {
+            if ($addressRecordLocTypeId == $mainAddressRecord['location_type_id']) {
               $conflicts[$key] = NULL;
-              break;
+              continue;
             }
           }
         }
index aa0aaf61706a2a030c5bee788b305d9f75aa730c..1f19c32f74b48ffa0907baad6f8910d97578b107 100644 (file)
@@ -1877,19 +1877,15 @@ WHERE    civicrm_participant.contact_id = {$contactID} AND
    * Evaluate whether a participant record is eligible for self-service transfer/cancellation.  If so,
    * return additional participant/event details.
    *
-   * TODO: BAO-level functions shouldn't set a redirect, and it should be possible to return "false" to the
-   * calling function.  The next refactor will add a fourth param $errors, which can be passed by reference
-   * from the calling function.  Instead of redirecting, we will return the error.
-   * TODO: This function should always return FALSE when self-service has been disabled on an event.
-   * TODO: This function fails when the "hours until self-service" is greater than 24 or less than zero.
+   * TODO: This function fails when the "hours until self-service" is less than zero.
    * @param int $participantId
    * @param string $url
    * @param bool $isBackOffice
    */
-  public static function getSelfServiceEligibility($participantId, $url, $isBackOffice) {
+  public static function getSelfServiceEligibility(int $participantId, string $url, bool $isBackOffice) : array {
     $optionGroupId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionGroup', 'participant_role', 'id', 'name');
     $query = "
-      SELECT cpst.name as status, cov.name as role, cp.fee_level, cp.fee_amount, cp.register_date, cp.status_id, ce.start_date, ce.title, cp.event_id
+      SELECT cpst.name as status, cov.name as role, cp.fee_level, cp.fee_amount, cp.register_date, cp.status_id, ce.start_date, ce.title, cp.event_id, ce.allow_selfcancelxfer
       FROM civicrm_participant cp
       LEFT JOIN civicrm_participant_status_type cpst ON cpst.id = cp.status_id
       LEFT JOIN civicrm_option_value cov ON cov.value = cp.role_id and cov.option_group_id = {$optionGroupId}
@@ -1897,40 +1893,44 @@ WHERE    civicrm_participant.contact_id = {$contactID} AND
       WHERE cp.id = {$participantId}";
     $dao = CRM_Core_DAO::executeQuery($query);
     while ($dao->fetch()) {
+      $details['eligible'] = TRUE;
       $details['status']  = $dao->status;
       $details['role'] = $dao->role;
       $details['fee_level'] = trim($dao->fee_level, CRM_Core_DAO::VALUE_SEPARATOR);
       $details['fee_amount'] = $dao->fee_amount;
       $details['register_date'] = $dao->register_date;
       $details['event_start_date'] = $dao->start_date;
+      $details['allow_selfcancelxfer'] = $dao->allow_selfcancelxfer;
       $eventTitle = $dao->title;
       $eventId = $dao->event_id;
     }
+    if (!$details['allow_selfcancelxfer']) {
+      $details['eligible'] = FALSE;
+      $details['ineligible_message'] = ts('This event registration can not be transferred or cancelled. Contact the event organizer if you have questions.');
+      return $details;
+    }
     //verify participant status is still Registered
     if ($details['status'] != 'Registered') {
-      $status = "You cannot transfer or cancel your registration for " . $eventTitle . ' as you are not currently registered for this event.';
-      CRM_Core_Session::setStatus($status, ts('Sorry'), 'alert');
-      CRM_Utils_System::redirect($url);
+      $details['eligible'] = FALSE;
+      $details['ineligible_message'] = "You cannot transfer or cancel your registration for " . $eventTitle . ' as you are not currently registered for this event.';
+      return $details;
     }
+    // Determine if it's too late to self-service cancel/transfer.
     $query = "select start_date as start, selfcancelxfer_time as time from civicrm_event where id = " . $eventId;
     $dao = CRM_Core_DAO::executeQuery($query);
     while ($dao->fetch()) {
       $time_limit  = $dao->time;
       $start_date = $dao->start;
     }
-    $start_time = new Datetime($start_date);
     $timenow = new Datetime();
-    if (!$isBackOffice && !empty($start_time) && $start_time < $timenow) {
-      $status = ts('Registration for this event cannot be cancelled or transferred once the event has begun. Contact the event organizer if you have questions.');
-      CRM_Core_Error::statusBounce($status, $url, ts('Sorry'));
-    }
-    if (!$isBackOffice && !empty($time_limit) && $time_limit > 0) {
-      $interval = $timenow->diff($start_time);
-      $days = $interval->format('%d');
-      $hours   = $interval->format('%h');
-      if ($hours <= $time_limit && $days < 1) {
-        $status = ts("Registration for this event cannot be cancelled or transferred less than %1 hours prior to the event's start time. Contact the event organizer if you have questions.", [1 => $time_limit]);
-        CRM_Core_Error::statusBounce($status, $url, ts('Sorry'));
+    if (!$isBackOffice && !empty($time_limit)) {
+      $cancelHours = abs($time_limit);
+      $cancelInterval = new DateInterval("PT${cancelHours}H");
+      $cancelInterval->invert = $time_limit < 0 ? 1 : 0;
+      $cancelDeadline = (new Datetime($start_date))->sub($cancelInterval);
+      if ($timenow > $cancelDeadline) {
+        $details['eligible'] = FALSE;
+        $details['ineligible_message'] = ts("Registration for this event cannot be cancelled or transferred less than %1 hours prior to the event's start time. Contact the event organizer if you have questions.", [1 => $time_limit]);
       }
     }
     return $details;
index 0bb56e3e0e798643ff86a1150724cbfc2e001890..e44c213172e634a4e817eb5e348849d1e915880a 100644 (file)
@@ -629,6 +629,7 @@ class CRM_Event_Form_Registration_Register extends CRM_Event_Form_Registration {
           }
         }
       }
+      $form->_priceSet['id'] = $form->_priceSet['id'] ?? $form->_priceSetId;
       $form->assign('priceSet', $form->_priceSet);
     }
     else {
index 5d72f2aaa34e02be3e7fc568179372c36fdb8f42..1d5ac36d72101f2f6ed0a37b0db4ec2f93f52984 100644 (file)
@@ -137,7 +137,7 @@ class CRM_Event_Form_SelfSvcTransfer extends CRM_Core_Form {
     $this->_userContext = $session->readUserContext();
     $this->_from_participant_id = CRM_Utils_Request::retrieve('pid', 'Positive', $this, FALSE, NULL, 'REQUEST');
     $this->_userChecksum = CRM_Utils_Request::retrieve('cs', 'String', $this, FALSE, NULL, 'REQUEST');
-    $this->isBackoffice = CRM_Utils_Request::retrieve('is_backoffice', 'String', $this, FALSE, NULL, 'REQUEST');
+    $this->isBackoffice = CRM_Utils_Request::retrieve('is_backoffice', 'String', $this, FALSE, NULL, 'REQUEST') ?? FALSE;
     $params = ['id' => $this->_from_participant_id];
     $participant = $values = [];
     $this->_participant = CRM_Event_BAO_Participant::getValues($params, $values, $participant);
@@ -165,6 +165,9 @@ class CRM_Event_Form_SelfSvcTransfer extends CRM_Core_Form {
 
     $details = CRM_Event_BAO_Participant::participantDetails($this->_from_participant_id);
     $selfServiceDetails = CRM_Event_BAO_Participant::getSelfServiceEligibility($this->_from_participant_id, $url, $this->isBackoffice);
+    if (!$selfServiceDetails['eligible']) {
+      CRM_Core_Error::statusBounce($selfServiceDetails['ineligible_message'], $url, ts('Sorry'));
+    }
     $details = array_merge($details, $selfServiceDetails);
     $this->assign('details', $details);
     //This participant row will be cancelled.  Get line item(s) to cancel
index 33b9f7f3f87853a0893000e80b1d61ed736e7d97..a87d7aff27c305acd112bbd447e431a5f34a8112 100644 (file)
@@ -110,7 +110,7 @@ class CRM_Event_Form_SelfSvcUpdate extends CRM_Core_Form {
     $participant = $values = [];
     $this->_participant_id = CRM_Utils_Request::retrieve('pid', 'Positive', $this, FALSE, NULL, 'REQUEST');
     $this->_userChecksum = CRM_Utils_Request::retrieve('cs', 'String', $this, FALSE, NULL, 'REQUEST');
-    $this->isBackoffice = CRM_Utils_Request::retrieve('is_backoffice', 'String', $this, FALSE, NULL, 'REQUEST');
+    $this->isBackoffice = CRM_Utils_Request::retrieve('is_backoffice', 'String', $this, FALSE, FALSE, 'REQUEST') ?? FALSE;
     $params = ['id' => $this->_participant_id];
     $this->_participant = CRM_Event_BAO_Participant::getValues($params, $values, $participant);
     $this->_part_values = $values[$this->_participant_id];
@@ -140,6 +140,9 @@ class CRM_Event_Form_SelfSvcUpdate extends CRM_Core_Form {
     $contributionId = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_ParticipantPayment', $this->_participant_id, 'contribution_id', 'participant_id');
     $this->assign('contributionId', $contributionId);
     $selfServiceDetails = CRM_Event_BAO_Participant::getSelfServiceEligibility($this->_participant_id, $url, $this->isBackoffice);
+    if (!$selfServiceDetails['eligible']) {
+      CRM_Core_Error::statusBounce($selfServiceDetails['ineligible_message'], $url, ts('Sorry'));
+    }
     $details = array_merge($details, $selfServiceDetails);
     $this->assign('details', $details);
     $this->selfsvcupdateUrl = CRM_Utils_System::url('civicrm/event/selfsvcupdate', "reset=1&id={$this->_participant_id}&id=0");
index 83e2fa5ba2c1ff95472ead42199669bbe68dab58..575aa9af24cd371605850266ca71f8e0ec607566 100644 (file)
@@ -132,7 +132,7 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
 
     $addPaymentHeader = FALSE;
 
-    list($outputColumns, $metadata) = $processor->getExportStructureArrays();
+    list($outputColumns) = $processor->getExportStructureArrays();
 
     if ($processor->isMergeSameAddress()) {
       foreach (array_keys($processor->getAdditionalFieldsForSameAddressMerge()) as $field) {
@@ -185,7 +185,7 @@ INSERT INTO {$componentTable} SELECT distinct gc.contact_id FROM civicrm_group_c
       while ($iterationDAO->fetch()) {
         $count++;
         $rowsThisIteration++;
-        $row = $processor->buildRow($query, $iterationDAO, $outputColumns, $metadata, $paymentDetails, $addPaymentHeader);
+        $row = $processor->buildRow($query, $iterationDAO, $outputColumns, $paymentDetails, $addPaymentHeader);
         if ($row === FALSE) {
           continue;
         }
index 58aa78ba168a6bfe98bb09182a356613ee2a37a2..1dc733d9fd534a65a9c23826f4612458fc15e9b9 100644 (file)
@@ -870,8 +870,8 @@ class CRM_Export_BAO_ExportProcessor {
     // These oddly constructed keys are for legacy reasons. Altering them will affect test success
     // but in time it may be good to rationalise them.
     $label = $this->getOutputSpecificationLabel($key, $relationshipType, $locationType, $entityLabel);
-    $index = $this->getOutputSpecificationIndex($key, $relationshipType, $locationType, $entityLabel);
-    $fieldKey = $this->getOutputSpecificationFieldKey($key, $relationshipType, $locationType, $entityLabel);
+    $index = $this->getOutputSpecificationIndex($key, $relationshipType, $locationType, $entityTypeID);
+    $fieldKey = $this->getOutputSpecificationFieldKey($key, $relationshipType, $locationType, $entityTypeID);
 
     $this->outputSpecification[$index]['header'] = $label;
     $this->outputSpecification[$index]['sql_columns'] = $this->getSqlColumnDefinition($fieldKey, $key);
@@ -961,13 +961,12 @@ class CRM_Export_BAO_ExportProcessor {
    * @param \CRM_Contact_BAO_Query $query
    * @param CRM_Core_DAO $iterationDAO
    * @param array $outputColumns
-   * @param $metadata
    * @param $paymentDetails
    * @param $addPaymentHeader
    *
    * @return array|bool
    */
-  public function buildRow($query, $iterationDAO, $outputColumns, $metadata, $paymentDetails, $addPaymentHeader) {
+  public function buildRow($query, $iterationDAO, $outputColumns, $paymentDetails, $addPaymentHeader) {
     $paymentTableId = $this->getPaymentTableID();
     if ($this->isHouseholdToSkip($iterationDAO->contact_id)) {
       return FALSE;
@@ -1021,7 +1020,7 @@ class CRM_Export_BAO_ExportProcessor {
         $this->buildRelationshipFieldsForRow($row, $iterationDAO->contact_id, $value, $field);
       }
       else {
-        $row[$field] = $this->getTransformedFieldValue($field, $iterationDAO, $fieldValue, $metadata, $paymentDetails);
+        $row[$field] = $this->getTransformedFieldValue($field, $iterationDAO, $fieldValue, $paymentDetails);
       }
     }
 
@@ -1083,12 +1082,13 @@ class CRM_Export_BAO_ExportProcessor {
    * @param $field
    * @param $iterationDAO
    * @param $fieldValue
-   * @param $metadata
    * @param $paymentDetails
    *
    * @return string
+   * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
    */
-  public function getTransformedFieldValue($field, $iterationDAO, $fieldValue, $metadata, $paymentDetails) {
+  public function getTransformedFieldValue($field, $iterationDAO, $fieldValue, $paymentDetails) {
 
     $i18n = CRM_Core_I18n::singleton();
     if ($field == 'id') {
@@ -1146,31 +1146,27 @@ class CRM_Export_BAO_ExportProcessor {
             return $i18n->crm_translate($fieldValue);
 
           default:
-            $fieldSpec = $metadata[$field] ?? [];
+            $fieldSpec = $this->outputSpecification[$this->getMungedFieldName($field)]['metadata'];
             // No I don't know why we do it this way & whether we could
             // make better use of pseudoConstants.
             if (!empty($fieldSpec['context'])) {
               return $i18n->crm_translate($fieldValue, $fieldSpec);
             }
-            if (!empty($fieldSpec['pseudoconstant'])) {
+            if (!empty($fieldSpec['pseudoconstant']) && !empty($fieldSpec['hasLocationType'])) {
               if (!empty($fieldSpec['bao'])) {
-                return CRM_Core_PseudoConstant::getLabel($fieldSpec['bao'], $fieldSpec['name'], $fieldValue);
+                $transformedValue = CRM_Core_PseudoConstant::getLabel($fieldSpec['bao'], $fieldSpec['name'], $fieldValue);
+                if ($transformedValue) {
+                  return $transformedValue;
+                }
+                return $fieldValue;
               }
-              // This is not our normal syntax for pseudoconstants but I am a bit loath to
-              // call an external function until sure it is not increasing php processing given this
-              // may be iterated 100,000 times & we already have the $imProvider var loaded.
-              // That can be next refactor...
               // Yes - definitely feeling hatred for this bit of code - I know you will beat me up over it's awfulness
               // but I have to reach a stable point....
               $varName = $fieldSpec['pseudoconstant']['var'];
               if ($varName === 'imProviders') {
                 return CRM_Core_PseudoConstant::getLabel('CRM_Core_DAO_IM', 'provider_id', $fieldValue);
               }
-              if ($varName === 'phoneTypes') {
-                return CRM_Core_PseudoConstant::getLabel('CRM_Core_DAO_Phone', 'phone_type_id', $fieldValue);
-              }
             }
-
             return $fieldValue;
         }
       }
@@ -1692,7 +1688,7 @@ class CRM_Export_BAO_ExportProcessor {
    *       yet find a way to comment them for posterity.
    */
   public function getExportStructureArrays() {
-    $outputColumns = $metadata = [];
+    $outputColumns = [];
     $queryFields = $this->getQueryFields();
     foreach ($this->getReturnProperties() as $key => $value) {
       if (($key != 'location' || !is_array($value)) && !$this->isRelationshipTypeKey($key)) {
@@ -1729,13 +1725,12 @@ class CRM_Export_BAO_ExportProcessor {
               $daoFieldName .= "-" . $type[1];
             }
             $this->addOutputSpecification($actualDBFieldName, NULL, $locationType, CRM_Utils_Array::value(1, $type));
-            $metadata[$daoFieldName] = $this->getMetaDataForField($actualDBFieldName);
             $outputColumns[$daoFieldName] = TRUE;
           }
         }
       }
     }
-    return [$outputColumns, $metadata];
+    return [$outputColumns];
   }
 
   /**
@@ -2070,13 +2065,13 @@ WHERE  id IN ( $deleteIDString )
    */
   public function getPreview($limit) {
     $rows = [];
-    list($outputColumns, $metadata) = $this->getExportStructureArrays();
+    list($outputColumns) = $this->getExportStructureArrays();
     $query = $this->runQuery([], '');
     CRM_Core_DAO::disableFullGroupByMode();
     $result = CRM_Core_DAO::executeQuery($query[1] . ' LIMIT ' . (int) $limit);
     CRM_Core_DAO::reenableFullGroupByMode();
     while ($result->fetch()) {
-      $rows[] = $this->buildRow($query[0], $result, $outputColumns, $metadata, [], []);
+      $rows[] = $this->buildRow($query[0], $result, $outputColumns, [], []);
     }
     return $rows;
   }
index 1101aab35ed3d9242f0cdaf1f536e5eebf9397a9..f841363f141ff6c8979f67f86e37fb8a99146c80 100644 (file)
@@ -79,6 +79,21 @@ class CRM_Financial_BAO_Payment {
       $paymentTrxnParams['status_id'] = CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Refunded');
     }
 
+    //If Payment is recorded on Failed contribution, update it to Pending.
+    if ($contributionStatus === 'Failed' && $params['total_amount'] > 0) {
+      //Enter a financial trxn to record a payment in receivable account
+      //as failed transaction does not insert any trxn values. Hence, if Payment is
+      //recorded on a failed contribution, the transition happens from Failed -> Pending -> Completed.
+      $ftParams = array_merge($paymentTrxnParams, [
+        'from_financial_account_id' => NULL,
+        'to_financial_account_id' => $accountsReceivableAccount,
+        'is_payment' => 0,
+        'status_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Pending'),
+      ]);
+      CRM_Core_BAO_FinancialTrxn::create($ftParams);
+      $contributionStatus = 'Pending';
+      self::updateContributionStatus($contribution['id'], $contributionStatus);
+    }
     $trxn = CRM_Core_BAO_FinancialTrxn::create($paymentTrxnParams);
 
     if ($params['total_amount'] < 0 && !empty($params['cancelled_payment_id'])) {
index 8169513e89a136a0bba1ebb65f9b2fe2240ba900..8a1e9529096e79d8cee9ad72191469f7686b6299 100644 (file)
@@ -1528,6 +1528,12 @@ ORDER BY   civicrm_email.is_bulkmail DESC
       \Civi::log('Parameter $ids is no longer used by Mailing::create. Use the api or just pass $params', ['civi.tag' => 'deprecated']);
     }
 
+    // CRM-#1843
+    // If it is a mass sms, set url_tracking to false
+    if (!empty($params['sms_provider_id'])) {
+      $params['url_tracking'] = 0;
+    }
+
     // CRM-12430
     // Do the below only for an insert
     // for an update, we should not set the defaults
index 25fb8f4fff5739ce1404faace421c45f2aeaebbe..ed240b720f23ae333b46a82dc23900667d9a6568 100644 (file)
@@ -227,17 +227,15 @@ class CRM_Mailing_Event_BAO_Reply extends CRM_Mailing_Event_DAO_Reply {
     $component->id = $mailing->reply_id;
     $component->find(TRUE);
 
-    $message = new Mail_Mime("\n");
-
     $domain = CRM_Core_BAO_Domain::getDomain();
     list($domainEmailName, $_) = CRM_Core_BAO_Domain::getNameAndEmail();
 
-    $headers = [
-      'Subject' => $component->subject,
-      'To' => $to,
-      'From' => "\"$domainEmailName\" <" . CRM_Core_BAO_Domain::getNoReplyEmailAddress() . '>',
-      'Reply-To' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
-      'Return-Path' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
+    $params = [
+      'subject' => $component->subject,
+      'toEmail' => $to,
+      'from' => "\"$domainEmailName\" <" . CRM_Core_BAO_Domain::getNoReplyEmailAddress() . '>',
+      'replyTo' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
+      'returnPath' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
     ];
 
     // TODO: do we need reply tokens?
@@ -257,24 +255,19 @@ class CRM_Mailing_Event_BAO_Reply extends CRM_Mailing_Event_DAO_Reply {
     if ($eq->format == 'HTML' || $eq->format == 'Both') {
       $html = CRM_Utils_Token::replaceDomainTokens($html, $domain, TRUE, $tokens['html']);
       $html = CRM_Utils_Token::replaceMailingTokens($html, $mailing, NULL, $tokens['html']);
-      $message->setHTMLBody($html);
     }
     if (!$html || $eq->format == 'Text' || $eq->format == 'Both') {
       $text = CRM_Utils_Token::replaceDomainTokens($text, $domain, FALSE, $tokens['text']);
       $text = CRM_Utils_Token::replaceMailingTokens($text, $mailing, NULL, $tokens['text']);
-      $message->setTxtBody($text);
     }
+    $params['html'] = $html;
+    $params['text'] = $text;
 
-    $b = CRM_Utils_Mail::setMimeParams($message);
-    $h = $message->headers($headers);
-    CRM_Mailing_BAO_Mailing::addMessageIdHeader($h, 'a', $eq->job_id, queue_id, $eq->hash);
-
-    $mailer = \Civi::service('pear_mail');
-    if (is_object($mailer)) {
-      $errorScope = CRM_Core_TemporaryErrorScope::ignoreException();
-      $mailer->send($to, $h, $b);
-      unset($errorScope);
+    CRM_Mailing_BAO_Mailing::addMessageIdHeader($params, 'a', $eq->job_id, queue_id, $eq->hash);
+    if (CRM_Core_BAO_MailSettings::includeMessageId()) {
+      $params['messageId'] = $params['Message-ID'];
     }
+    CRM_Utils_Mail::send($params);
   }
 
   /**
index e13ee159b613f07c1a69094fcaa331d2c07b538f..3468c533b17bd9c55e70a1730a3158495af315aa 100644 (file)
@@ -229,8 +229,6 @@ class CRM_Mailing_Event_BAO_Resubscribe {
       }
     }
 
-    $message = new Mail_mime("\n");
-
     list($addresses, $urls) = CRM_Mailing_BAO_Mailing::getVerpAndUrls($job, $queue_id, $eq->hash, $eq->email);
     $bao = new CRM_Mailing_BAO_Mailing();
     $bao->body_text = $text;
@@ -241,34 +239,28 @@ class CRM_Mailing_Event_BAO_Resubscribe {
       $html = CRM_Utils_Token::replaceResubscribeTokens($html, $domain, $groups, TRUE, $eq->contact_id, $eq->hash);
       $html = CRM_Utils_Token::replaceActionTokens($html, $addresses, $urls, TRUE, $tokens['html']);
       $html = CRM_Utils_Token::replaceMailingTokens($html, $dao, NULL, $tokens['html']);
-      $message->setHTMLBody($html);
     }
     if (!$html || $eq->format == 'Text' || $eq->format == 'Both') {
       $text = CRM_Utils_Token::replaceDomainTokens($text, $domain, TRUE, $tokens['text']);
       $text = CRM_Utils_Token::replaceResubscribeTokens($text, $domain, $groups, FALSE, $eq->contact_id, $eq->hash);
       $text = CRM_Utils_Token::replaceActionTokens($text, $addresses, $urls, FALSE, $tokens['text']);
       $text = CRM_Utils_Token::replaceMailingTokens($text, $dao, NULL, $tokens['text']);
-      $message->setTxtBody($text);
     }
 
-    $headers = [
-      'Subject' => $component->subject,
-      'From' => "\"$domainEmailName\" <" . CRM_Core_BAO_Domain::getNoReplyEmailAddress() . '>',
-      'To' => $eq->email,
-      'Reply-To' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
-      'Return-Path' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
+    $params = [
+      'subject' => $component->subject,
+      'from' => "\"$domainEmailName\" <" . CRM_Core_BAO_Domain::getNoReplyEmailAddress() . '>',
+      'toEmail' => $eq->email,
+      'replyTo' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
+      'returnPath' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
+      'html' => $html,
+      'text' => $text,
     ];
-    CRM_Mailing_BAO_Mailing::addMessageIdHeader($headers, 'e', $job, $queue_id, $eq->hash);
-    $b = CRM_Utils_Mail::setMimeParams($message);
-    $h = $message->headers($headers);
-
-    $mailer = \Civi::service('pear_mail');
-
-    if (is_object($mailer)) {
-      $errorScope = CRM_Core_TemporaryErrorScope::ignoreException();
-      $mailer->send($eq->email, $h, $b);
-      unset($errorScope);
+    CRM_Mailing_BAO_Mailing::addMessageIdHeader($params, 'e', $job, $queue_id, $eq->hash);
+    if (CRM_Core_BAO_MailSettings::includeMessageId()) {
+      $params['messageId'] = $params['Message-ID'];
     }
+    CRM_Utils_Mail::send($params);
   }
 
 }
index 1dfad54a4a4206537704cdb63df456097627c774..71baa417fe75bd3763ec9ad373d697adb801a527 100644 (file)
@@ -205,12 +205,12 @@ SELECT     civicrm_email.id as email_id
 
     $component->find(TRUE);
 
-    $headers = [
-      'Subject' => $component->subject,
-      'From' => "\"{$domainEmailName}\" <{$domainEmailAddress}>",
-      'To' => $email,
-      'Reply-To' => $confirm,
-      'Return-Path' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
+    $params = [
+      'subject' => $component->subject,
+      'from' => "\"{$domainEmailName}\" <{$domainEmailAddress}>",
+      'toEmail' => $email,
+      'replyTo' => $confirm,
+      'returnPath' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
     ];
 
     $url = CRM_Utils_System::url('civicrm/mailing/confirm',
@@ -246,24 +246,17 @@ SELECT     civicrm_email.id as email_id
     // render the &amp; entities in text mode, so that the links work
     $text = str_replace('&amp;', '&', $text);
 
-    $message = new Mail_mime("\n");
-
-    $message->setHTMLBody($html);
-    $message->setTxtBody($text);
-    $b = CRM_Utils_Mail::setMimeParams($message);
-    $h = $message->headers($headers);
-    CRM_Mailing_BAO_Mailing::addMessageIdHeader($h, 's',
+    CRM_Mailing_BAO_Mailing::addMessageIdHeader($params, 's',
       $this->contact_id,
       $this->id,
       $this->hash
     );
-    $mailer = \Civi::service('pear_mail');
-
-    if (is_object($mailer)) {
-      $errorScope = CRM_Core_TemporaryErrorScope::ignoreException();
-      $mailer->send($email, $h, $b);
-      unset($errorScope);
+    $params['html'] = $html;
+    $params['text'] = $text;
+    if (CRM_Core_BAO_MailSettings::includeMessageId()) {
+      $params['messageId'] = $params['Message-ID'];
     }
+    CRM_Utils_Mail::send($params);
   }
 
   /**
index 920ae7d3bcfe3c43c2da490d73d009e24d18b5e8..ce92b388e2604c1d55c32b00ba693ea32682ce3e 100644 (file)
@@ -365,8 +365,6 @@ WHERE  email = %2
       }
     }
 
-    $message = new Mail_mime("\n");
-
     list($addresses, $urls) = CRM_Mailing_BAO_Mailing::getVerpAndUrls($job, $queue_id, $eq->hash, $eq->email);
     $bao = new CRM_Mailing_BAO_Mailing();
     $bao->body_text = $text;
@@ -377,37 +375,30 @@ WHERE  email = %2
       $html = CRM_Utils_Token::replaceUnsubscribeTokens($html, $domain, $groups, TRUE, $eq->contact_id, $eq->hash);
       $html = CRM_Utils_Token::replaceActionTokens($html, $addresses, $urls, TRUE, $tokens['html']);
       $html = CRM_Utils_Token::replaceMailingTokens($html, $dao, NULL, $tokens['html']);
-      $message->setHTMLBody($html);
     }
     if (!$html || $eq->format == 'Text' || $eq->format == 'Both') {
       $text = CRM_Utils_Token::replaceDomainTokens($text, $domain, FALSE, $tokens['text']);
       $text = CRM_Utils_Token::replaceUnsubscribeTokens($text, $domain, $groups, FALSE, $eq->contact_id, $eq->hash);
       $text = CRM_Utils_Token::replaceActionTokens($text, $addresses, $urls, FALSE, $tokens['text']);
       $text = CRM_Utils_Token::replaceMailingTokens($text, $dao, NULL, $tokens['text']);
-      $message->setTxtBody($text);
     }
 
     $emailDomain = CRM_Core_BAO_MailSettings::defaultDomain();
 
-    $headers = [
-      'Subject' => $component->subject,
-      'From' => "\"$domainEmailName\" <" . CRM_Core_BAO_Domain::getNoReplyEmailAddress() . '>',
-      'To' => $eq->email,
-      'Reply-To' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
-      'Return-Path' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
+    $params = [
+      'subject' => $component->subject,
+      'from' => "\"$domainEmailName\" <" . CRM_Core_BAO_Domain::getNoReplyEmailAddress() . '>',
+      'toEmail' => $eq->email,
+      'replyTo' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
+      'returnPath' => CRM_Core_BAO_Domain::getNoReplyEmailAddress(),
+      'html' => $html,
+      'text' => $text,
     ];
-    CRM_Mailing_BAO_Mailing::addMessageIdHeader($headers, 'u', $job, $queue_id, $eq->hash);
-
-    $b = CRM_Utils_Mail::setMimeParams($message);
-    $h = $message->headers($headers);
-
-    $mailer = \Civi::service('pear_mail');
-
-    if (is_object($mailer)) {
-      $errorScope = CRM_Core_TemporaryErrorScope::ignoreException();
-      $mailer->send($eq->email, $h, $b);
-      unset($errorScope);
+    CRM_Mailing_BAO_Mailing::addMessageIdHeader($params, 'u', $job, $queue_id, $eq->hash);
+    if (CRM_Core_BAO_MailSettings::includeMessageId()) {
+      $params['messageId'] = $params['Message-ID'];
     }
+    CRM_Utils_Mail::send($params);
   }
 
   /**
index 1be92c12145af51379b8ca4348d67368ebb201d7..97405dce40716e93f8d11136826a457e92aff25c 100644 (file)
@@ -105,32 +105,11 @@ ORDER BY title";
       $this->addFormRule(['CRM_Mailing_Form_Subscribe', 'formRule']);
     }
 
-    $addCaptcha = TRUE;
-
-    // if recaptcha is not configured, then dont add it
-    // CRM-11316 Only enable ReCAPTCHA for anonymous visitors
-    $config = CRM_Core_Config::singleton();
+    // CRM-11316 Enable ReCAPTCHA for anonymous visitors
     $session = CRM_Core_Session::singleton();
     $contactID = $session->get('userID');
 
-    if (empty($config->recaptchaPublicKey) ||
-      empty($config->recaptchaPrivateKey) ||
-      $contactID
-    ) {
-      $addCaptcha = FALSE;
-    }
-    else {
-      // If this is POST request and came from a block,
-      // lets add recaptcha only if already present.
-      // Gross hack for now.
-      if (!empty($_POST) &&
-        !array_key_exists('recaptcha_challenge_field', $_POST)
-      ) {
-        $addCaptcha = FALSE;
-      }
-    }
-
-    if ($addCaptcha) {
+    if (!$contactID) {
       CRM_Utils_ReCAPTCHA::enableCaptchaOnForm($this);
     }
 
index 18cffb95a5a694196d3712cf5fa2671bd23eb8e1..6640b4b113f87e666feef366c63fb971ee2db92f 100644 (file)
@@ -403,8 +403,8 @@ class CRM_Member_BAO_Membership extends CRM_Member_DAO_Membership {
       // ie in an update situation.
       $membership->find(TRUE);
     }
-    $membershipTypes = CRM_Member_PseudoConstant::membershipType();
-    $title = CRM_Contact_BAO_Contact::displayName($membership->contact_id) . ' - ' . ts('Membership Type:') . ' ' . $membershipTypes[$membership->membership_type_id];
+    $title = CRM_Contact_BAO_Contact::displayName($membership->contact_id) . ' - ' . ts('Membership Type:')
+      . ' ' . CRM_Core_PseudoConstant::getLabel('CRM_Member_BAO_Membership', 'membership_type_id', $membership->membership_type_id);
 
     $recentOther = [];
     if (CRM_Core_Permission::checkActionPermission('CiviMember', CRM_Core_Action::UPDATE)) {
index c7ddc7636c9ef79683ff49ab36161d0577bdf4d9..fa4a7665f8d594544887808cc21cdc21d290e246 100644 (file)
@@ -197,61 +197,45 @@ class CRM_Member_BAO_MembershipStatus extends CRM_Member_DAO_MembershipStatus {
   /**
    * Find the membership status based on start date, end date, join date & status date.
    *
+   * Loop through all the membership status definitions, ordered by their
+   * weight. For each, we loop through all possible variations of the given
+   * start, end, and join dates and adjust the starts and ends based on that
+   * membership status's rules, where the last computed set of adjusted start
+   * and end becomes a candidate. Then we compare that candidate to either
+   * "today" or some other given date, and if it falls between the adjusted
+   * start and end we have a match and we stop looping through status
+   * definitions. Then we call a hook in case that wasn't enough loops.
+   *
    * @param string $startDate
    *   Start date of the member whose membership status is to be calculated.
    * @param string $endDate
    *   End date of the member whose membership status is to be calculated.
    * @param string $joinDate
    *   Join date of the member whose membership status is to be calculated.
-   * @param \date|string $statusDate status date of the member whose membership status is to be calculated.
-   * @param bool $excludeIsAdmin the statuses those having is_admin = 1.
-   *   Exclude the statuses those having is_admin = 1.
+   * @param string $statusDate
+   *   Either the string "today" or a date against which we compare the adjusted start and end based on the status rules.
+   * @param bool $excludeIsAdmin
+   *   Exclude the statuses having is_admin = 1.
    * @param int $membershipTypeID
+   *   Not used directly but gets passed to the hook.
    * @param array $membership
-   *   Membership params as available to calling function - passed to the hook.
+   *   Membership params as available to calling function - not used directly but passed to the hook.
    *
    * @return array
    */
   public static function getMembershipStatusByDate(
     $startDate, $endDate, $joinDate,
-    $statusDate = 'today', $excludeIsAdmin = FALSE, $membershipTypeID, $membership = []
+    $statusDate = 'today', $excludeIsAdmin = FALSE, $membershipTypeID = NULL, $membership = []
   ) {
     $membershipDetails = [];
 
     if (!$statusDate || $statusDate == 'today') {
-      $statusDate = getdate();
-      $statusDate = date('Ymd',
-        mktime($statusDate['hours'],
-          $statusDate['minutes'],
-          $statusDate['seconds'],
-          $statusDate['mon'],
-          $statusDate['mday'],
-          $statusDate['year']
-        )
-      );
+      $statusDate = date('Ymd');
     }
     else {
       $statusDate = CRM_Utils_Date::customFormat($statusDate, '%Y%m%d');
     }
 
-    $dates = ['start', 'end', 'join'];
-    $events = ['start', 'end'];
-
-    foreach ($dates as $dat) {
-      if (${$dat . 'Date'} && ${$dat . 'Date'} != "null") {
-        ${$dat . 'Date'} = CRM_Utils_Date::customFormat(${$dat . 'Date'}, '%Y%m%d');
-
-        ${$dat . 'Year'} = substr(${$dat . 'Date'}, 0, 4);
-
-        ${$dat . 'Month'} = substr(${$dat . 'Date'}, 4, 2);
-
-        ${$dat . 'Day'} = substr(${$dat . 'Date'}, 6, 2);
-      }
-      else {
-        ${$dat . 'Date'} = '';
-      }
-    }
-
     //fix for CRM-3570, if we have statuses with is_admin=1,
     //exclude these statuses from calculatation during import.
     $where = "is_active = 1";
@@ -266,48 +250,56 @@ class CRM_Member_BAO_MembershipStatus extends CRM_Member_DAO_MembershipStatus {
  ORDER BY weight ASC";
 
     $membershipStatus = CRM_Core_DAO::executeQuery($query);
-    $hour = $minute = $second = 0;
+
+    $dates = [
+      'start' => ($startDate && $startDate !== 'null') ? date('Ymd', strtotime($startDate)) : '',
+      'end' => ($endDate && $endDate !== 'null') ? date('Ymd', strtotime($endDate)) : '',
+      'join' => ($joinDate && $joinDate !== 'null') ? date('Ymd', strtotime($joinDate)) : '',
+    ];
 
     while ($membershipStatus->fetch()) {
       $startEvent = NULL;
       $endEvent = NULL;
-      foreach ($events as $eve) {
-        foreach ($dates as $dat) {
+      foreach (['start', 'end'] as $eve) {
+        foreach ($dates as $dat => $date) {
           // calculate start-event/date and end-event/date
-          if (($membershipStatus->{$eve . '_event'} == $dat . '_date') &&
-            ${$dat . 'Date'}
+          if (($membershipStatus->{$eve . '_event'} === $dat . '_date') &&
+            $date
           ) {
             if ($membershipStatus->{$eve . '_event_adjust_unit'} &&
               $membershipStatus->{$eve . '_event_adjust_interval'}
             ) {
+              $month = date('m', strtotime($date));
+              $day = date('d', strtotime($date));
+              $year = date('Y', strtotime($date));
               // add in months
-              if ($membershipStatus->{$eve . '_event_adjust_unit'} == 'month') {
-                ${$eve . 'Event'} = date('Ymd', mktime($hour, $minute, $second,
-                  ${$dat . 'Month'} + $membershipStatus->{$eve . '_event_adjust_interval'},
-                  ${$dat . 'Day'},
-                  ${$dat . 'Year'}
+              if ($membershipStatus->{$eve . '_event_adjust_unit'} === 'month') {
+                ${$eve . 'Event'} = date('Ymd', mktime(0, 0, 0,
+                  $month + $membershipStatus->{$eve . '_event_adjust_interval'},
+                  $day,
+                  $year
                 ));
               }
               // add in days
-              if ($membershipStatus->{$eve . '_event_adjust_unit'} == 'day') {
-                ${$eve . 'Event'} = date('Ymd', mktime($hour, $minute, $second,
-                  ${$dat . 'Month'},
-                  ${$dat . 'Day'} + $membershipStatus->{$eve . '_event_adjust_interval'},
-                  ${$dat . 'Year'}
+              if ($membershipStatus->{$eve . '_event_adjust_unit'} === 'day') {
+                ${$eve . 'Event'} = date('Ymd', mktime(0, 0, 0,
+                  $month,
+                  $day + $membershipStatus->{$eve . '_event_adjust_interval'},
+                  $year
                 ));
               }
               // add in years
-              if ($membershipStatus->{$eve . '_event_adjust_unit'} == 'year') {
-                ${$eve . 'Event'} = date('Ymd', mktime($hour, $minute, $second,
-                  ${$dat . 'Month'},
-                  ${$dat . 'Day'},
-                  ${$dat . 'Year'} + $membershipStatus->{$eve . '_event_adjust_interval'}
+              if ($membershipStatus->{$eve . '_event_adjust_unit'} === 'year') {
+                ${$eve . 'Event'} = date('Ymd', mktime(0, 0, 0,
+                  $month,
+                  $day,
+                  $year + $membershipStatus->{$eve . '_event_adjust_interval'}
                 ));
               }
               // if no interval and unit, present
             }
             else {
-              ${$eve . 'Event'} = ${$dat . 'Date'};
+              ${$eve . 'Event'} = $date;
             }
           }
         }
index 88e21e4025d76abb7b92eb87d08e932c1625ee9a..3c98b8570b9f71cd919120ca3ef7c79fc3e5421c 100644 (file)
@@ -1780,23 +1780,24 @@ class CRM_Member_Form_Membership extends CRM_Member_Form {
     $buttonName = $this->controller->getButtonName();
     $session = CRM_Core_Session::singleton();
 
-    if ($this->_context === 'standalone') {
-      if ($buttonName == $this->getButtonName('upload', 'new')) {
-        $session->replaceUserContext(CRM_Utils_System::url('civicrm/member/add',
+    if ($buttonName == $this->getButtonName('upload', 'new')) {
+      if ($this->_context === 'standalone') {
+        $url = CRM_Utils_System::url('civicrm/member/add',
           'reset=1&action=add&context=standalone'
-        ));
+        );
       }
       else {
-        $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view',
-          "reset=1&cid={$this->_contactID}&selectedChild=member"
-        ));
+        $url = CRM_Utils_System::url('civicrm/contact/view/membership',
+          "reset=1&action=add&context=membership&cid={$this->_contactID}"
+        );
       }
     }
-    elseif ($buttonName == $this->getButtonName('upload', 'new')) {
-      $session->replaceUserContext(CRM_Utils_System::url('civicrm/contact/view/membership',
-        "reset=1&action=add&context=membership&cid={$this->_contactID}"
-      ));
+    else {
+      $url = CRM_Utils_System::url('civicrm/contact/view',
+        "reset=1&cid={$this->_contactID}&selectedChild=member"
+      );
     }
+    $session->replaceUserContext($url);
   }
 
   /**
index 45c962f2fe825a5599032af89eb4e23624752ba2..e71609eccd31abec138687a9913c977ea0fdd0b3 100644 (file)
@@ -661,7 +661,7 @@ WHERE pcp.id = %1 AND cc.contribution_status_id = %2 AND cc.is_test = 0";
     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');
+      $fixUrl = CRM_Utils_System::url('civicrm/admin/options/from_email_address', 'reset=1');
       throw new CRM_Core_Exception(ts('The site administrator needs to enter a valid \'FROM Email Address\' in <a href="%1">Administer CiviCRM &raquo; Communications &raquo; FROM Email Addresses</a>. The email address used may need to be a valid mail account with your email service provider.', [1 => $fixUrl]));
     }
 
index 2ed80ff8ebe8c62285c5729f15f6055ec85ccf02..bc87b6e9fe53c44ffdab2645e7d17b3d58d6e313 100644 (file)
@@ -860,6 +860,7 @@ WHERE  id = %1";
         }
       }
     }
+    $form->_priceSet['id'] = $form->_priceSet['id'] ?? $priceSetId;
     $form->assign('priceSet', $form->_priceSet);
 
     $component = 'contribution';
index 9659e1a892c7720ea3a557b57392f2fa787cb032..68e64de811b8c3c83a2e1e3c7655e673a280d3ef 100644 (file)
@@ -114,7 +114,7 @@ class CRM_SMS_Form_Provider extends CRM_Core_Form {
     if ($name) {
       $defaults['name'] = $name;
       $provider = CRM_SMS_Provider::singleton(['provider' => $name]);
-      $defaults['api_url'] = $provider->_apiURL;
+      $defaults['api_url'] = $provider->_apiURL ?? '';
     }
 
     if (!$this->_id) {
index 466278a3fa460bd9860a9363fb660cb353f680d5..061b7ce742bc9082e922f67ce3c2d33bf5e6eeee 100644 (file)
@@ -192,7 +192,20 @@ class CRM_UF_Page_ProfileEditor extends CRM_Core_Page {
           break;
 
         default:
-          throw new CRM_Core_Exception("Unrecognized entity type: $entityType");
+          if (strpos($entityType, 'Model') !== FALSE) {
+            $entity = str_replace('Model', '', $entityType);
+            $backboneModel = self::convertCiviModelToBackboneModel(
+              $entity,
+              ts('%1', [1 => $entity]),
+              $availableFields
+            );
+            if (!empty($backboneModel['schema'])) {
+              $civiSchema[$entityType] = $backboneModel;
+            }
+          }
+          if (!isset($civiSchema[$entityType])) {
+            throw new CRM_Core_Exception("Unrecognized entity type: $entityType");
+          }
       }
     }
 
index 3c040d82b281bd4f78b8420af35927688822c506..2d10885877eedd1e3c1b5fff5b351b200a3ac5dc 100644 (file)
@@ -26,9 +26,9 @@ class CRM_Upgrade_Incremental_php_FiveTwentyEight extends CRM_Upgrade_Incrementa
    */
   public function setPreUpgradeMessage(&$preUpgradeMessage, $rev, $currentVer = NULL) {
     // Example: Generate a pre-upgrade message.
-    // if ($rev == '5.12.34') {
-    //   $preUpgradeMessage .= '<p>' . ts('A new permission, "%1", has been added. This permission is now used to control access to the Manage Tags screen.', array(1 => ts('manage tags'))) . '</p>';
-    // }
+    if ($rev == '5.28.alpha1') {
+      $preUpgradeMessage .= CRM_Upgrade_Incremental_php_FiveTwentyEight::createWpFilesMessage();
+    }
   }
 
   /**
@@ -40,10 +40,39 @@ class CRM_Upgrade_Incremental_php_FiveTwentyEight extends CRM_Upgrade_Incrementa
    *   an intermediate version; note that setPostUpgradeMessage is called repeatedly with different $revs.
    */
   public function setPostUpgradeMessage(&$postUpgradeMessage, $rev) {
-    // Example: Generate a post-upgrade message.
-    // if ($rev == '5.12.34') {
-    //   $postUpgradeMessage .= '<br /><br />' . ts("By default, CiviCRM now disables the ability to import directly from SQL. To use this feature, you must explicitly grant permission 'import SQL datasource'.");
-    // }
+    // Example: Generate a pre-upgrade message.
+    if ($rev == '5.28.alpha1') {
+      $postUpgradeMessage .= CRM_Upgrade_Incremental_php_FiveTwentyEight::createWpFilesMessage();
+    }
+  }
+
+  public static function createWpFilesMessage() {
+    if (!function_exists('civi_wp')) {
+      return '';
+    }
+
+    if (isset($GLOBALS['civicrm_paths']['civicrm.files']['path'])) {
+      // They've explicitly chosen to use a non-default path.
+      return '';
+    }
+
+    $table = '<table><tbody>'
+      . sprintf('<tr><th colspan="2">%s</th></tr>', ts('<b>[civicrm.files]</b> Path'))
+      . sprintf('<tr><td>%s</td><td><code>%s</code></td></tr>', ts('5.29 Default:'), wp_upload_dir()['basedir'] . DIRECTORY_SEPARATOR . 'civicrm' . DIRECTORY_SEPARATOR)
+      . sprintf('<tr><td>%s</td><td><code>%s</code></td></tr>', ts('5.28 Default:'), CRM_Core_Config::singleton()->userSystem->getDefaultFileStorage()['path'])
+      . sprintf('<tr><td>%s</td><td><code>%s</code></td></tr>', ts('Active Value:'), Civi::paths()->getVariable('civicrm.files', 'path'))
+      . sprintf('<tr><th colspan="2">%s</th></tr>', ts('<b>[civicrm.files]</b> URL'))
+      . sprintf('<tr><td>%s</td><td><code>%s</code></td></tr>', ts('5.29 Default:'), wp_upload_dir()['baseurl'] . '/civicrm/')
+      . sprintf('<tr><td>%s</td><td><code>%s</code></td></tr>', ts('5.28 Default:'), CRM_Core_Config::singleton()->userSystem->getDefaultFileStorage()['url'])
+      . sprintf('<tr><td>%s</td><td><code>%s</code></td></tr>', ts('Active Value:'), Civi::paths()->getVariable('civicrm.files', 'url'))
+      . '</tbody></table>';
+
+    return '<p>' . ts('Starting with version 5.29.0, CiviCRM on WordPress may make a subtle change in the calculation of <code>[civicrm.files]</code>.
+         To ensure a smooth upgrade, please review the following table. All paths and URLs should appear the same. If there is <strong><em>any</em></strong> discrepancy,
+         then consult <a href=\'%1\' target=\'_blank\'>the upgrade documentation</a>.', [
+           1 => 'https://docs.civicrm.org/sysadmin/en/latest/upgrade/version-specific/#civicrm-5.29',
+           2 => '...wp-content/uploads/civicrm',
+         ]) . '</p>' . $table;
   }
 
   /*
@@ -58,8 +87,8 @@ class CRM_Upgrade_Incremental_php_FiveTwentyEight extends CRM_Upgrade_Incrementa
    * @param string $rev
    */
   public function upgrade_5_28_alpha1($rev) {
-    $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
     $this->addTask('Populate missing Contact Type name fields', 'populateMissingContactTypeName');
+    $this->addTask(ts('Upgrade DB to %1: SQL', [1 => $rev]), 'runSql', $rev);
     $this->addTask('Add icon column to civicrm_custom_group', 'addColumn',
       'civicrm_custom_group', 'icon', "varchar(255) COMMENT 'crm-i icon class' DEFAULT NULL");
     $this->addTask('Remove index on medium_id from civicrm_activity', 'dropIndex', 'civicrm_activity', 'index_medium_id');
index 7508dec80c209a305d4ee1b0c326764ac6abc0a1..18b176d4b0f0de31ccc1b70281538caa5d8822ef 100644 (file)
@@ -1,5 +1,9 @@
 {* file to handle db changes in 5.29.alpha1 during upgrade *}
 
+{* https://github.com/civicrm/civicrm-core/pull/17824 *}
+UPDATE civicrm_status_pref SET name = 'checkExtensionsOk' WHERE name = 'extensionsOk';
+UPDATE civicrm_status_pref SET name = 'checkExtensionsUpdates' WHERE name = 'extensionUpdates';
+
 -- The RelationshipCache is a high-level index/cache for querying relationships.
 DROP TABLE IF EXISTS `civicrm_relationship_cache`;
 CREATE TABLE `civicrm_relationship_cache` (
@@ -24,3 +28,20 @@ CREATE TABLE `civicrm_relationship_cache` (
      CONSTRAINT FK_civicrm_relationship_cache_near_contact_id FOREIGN KEY (`near_contact_id`) REFERENCES `civicrm_contact`(`id`) ON DELETE CASCADE,
      CONSTRAINT FK_civicrm_relationship_cache_far_contact_id FOREIGN KEY (`far_contact_id`) REFERENCES `civicrm_contact`(`id`) ON DELETE CASCADE
 )  ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
+
+-- Fix missing resubscribeUrl token. There doesn't seem to be any precedent
+-- for doing an upgrade for these, since the last update was in 2009 when
+-- the token went missing and it had no upgrade script for it. Also unlike
+-- message templates, there doesn't seem to be a way to tell whether it's
+-- been changed. Using ts is a bit unreliable if the translation has changed
+-- but it would be no worse than now and just end up not updating it.
+-- Also, I'm drawing a blank on why the %3 is replaced differently during
+-- install than during upgrade, hence the OR clause.
+{capture assign=unsubgroup}{ldelim}unsubscribe.group{rdelim}{/capture}
+{capture assign=actresub}{ldelim}action.resubscribe{rdelim}{/capture}
+{capture assign=actresuburl}{ldelim}action.resubscribeUrl{rdelim}{/capture}
+UPDATE civicrm_mailing_component
+SET body_text = '{ts escape="sql" 1=$unsubgroup 2=$actresub 3=$actresuburl}You have been un-subscribed from the following groups: %1. You can re-subscribe by mailing %2 or clicking %3{/ts}'
+WHERE component_type  = 'Unsubscribe'
+AND (body_text = '{ts escape="sql" 1=$unsubgroup 2=$actresub}You have been un-subscribed from the following groups: %1. You can re-subscribe by mailing %2 or clicking %3{/ts}'
+  OR body_text = '{ts escape="sql" 1=$unsubgroup 2=$actresub}You have been un-subscribed from the following groups: %1. You can re-subscribe by mailing %2 or clicking {/ts}');
index e92bb9ec7c24180c7d9769b568d4ef4bb2ceb3f6..1e4d9f7df707bee0cd99aa5e5944f0ea89299cd7 100644 (file)
@@ -170,7 +170,7 @@ class CRM_Utils_Check {
   }
 
   /**
-   * Run all system checks.
+   * Run all enabled system checks.
    *
    * This functon is wrapped by the System.check api.
    *
@@ -180,21 +180,10 @@ class CRM_Utils_Check {
    * @param bool $max
    *   Whether to return just the maximum non-hushed severity
    *
-   * @return array
-   *   Array of CRM_Utils_Check_Message objects
+   * @return CRM_Utils_Check_Message[]
    */
   public static function checkAll($max = FALSE) {
-    $messages = [];
-    foreach (glob(__DIR__ . '/Check/Component/*.php') as $filePath) {
-      $className = 'CRM_Utils_Check_Component_' . basename($filePath, '.php');
-      /* @var CRM_Utils_Check_Component $check */
-      $check = new $className();
-      if ($check->isEnabled()) {
-        $messages = array_merge($messages, $check->checkAll());
-      }
-    }
-
-    CRM_Utils_Hook::check($messages);
+    $messages = self::checkStatus();
 
     uasort($messages, [__CLASS__, 'severitySort']);
 
@@ -212,6 +201,38 @@ class CRM_Utils_Check {
     return ($max) ? $maxSeverity : $messages;
   }
 
+  /**
+   * @param array $statusNames
+   *   Optionally specify the names of specific checks to run, or leave empty to run all
+   * @param bool $includeDisabled
+   *   Run checks that have been explicitly disabled (default false)
+   *
+   * @return CRM_Utils_Check_Message[]
+   */
+  public static function checkStatus($statusNames = [], $includeDisabled = FALSE) {
+    $messages = [];
+    $checksNeeded = $statusNames;
+    foreach (glob(__DIR__ . '/Check/Component/*.php') as $filePath) {
+      $className = 'CRM_Utils_Check_Component_' . basename($filePath, '.php');
+      /* @var CRM_Utils_Check_Component $component */
+      $component = new $className();
+      if ($includeDisabled || $component->isEnabled()) {
+        $messages = array_merge($messages, $component->checkAll($statusNames, $includeDisabled));
+      }
+      if ($statusNames) {
+        // Early return if we have already run (or skipped) all the requested checks.
+        $checksNeeded = array_diff($checksNeeded, $component->getAllChecks());
+        if (!$checksNeeded) {
+          return $messages;
+        }
+      }
+    }
+
+    CRM_Utils_Hook::check($messages, $statusNames, $includeDisabled);
+
+    return $messages;
+  }
+
   /**
    * @param int $level
    * @return string
index 3ecf8bd347bd5a987dbe40bd9da3c5261ac0252d..5b5dcc746258972805f8271062c29767e88aa369 100644 (file)
@@ -44,26 +44,60 @@ abstract class CRM_Utils_Check_Component {
     return TRUE;
   }
 
+  /**
+   * Get the names of all check functions in this class
+   *
+   * @return string[]
+   */
+  public function getAllChecks() {
+    return array_filter(get_class_methods($this), function($method) {
+      return $method !== 'checkAll' && strpos($method, 'check') === 0;
+    });
+  }
+
   /**
    * Run all checks in this class.
    *
-   * @return array
-   *   [CRM_Utils_Check_Message]
+   * @param array $requestedChecks
+   *   Optionally specify the names of specific checks requested, or leave empty to run all
+   * @param bool $includeDisabled
+   *   Run checks that have been explicitly disabled (default false)
    *
-   * @throws \API_Exception
+   * @return CRM_Utils_Check_Message[]
+   *
+   * @throws API_Exception
    * @throws \Civi\API\Exception\UnauthorizedException
    */
-  public function checkAll() {
+  public function checkAll($requestedChecks = [], $includeDisabled = FALSE) {
     $messages = [];
-    foreach (get_class_methods($this) as $method) {
+    foreach ($this->getAllChecks() as $method) {
       // Note that we should check if the test is disabled BEFORE running it in case it's disabled for performance.
-      if ($method !== 'checkAll' && strpos($method, 'check') === 0 && !$this->isDisabled($method)) {
-        $messages = array_merge($messages, $this->$method());
+      if ($this->isRequested($method, $requestedChecks) && ($includeDisabled || !$this->isDisabled($method))) {
+        $messages = array_merge($messages, $this->$method($includeDisabled));
       }
     }
     return $messages;
   }
 
+  /**
+   * Is this check one of those requested
+   *
+   * @param string $method
+   * @param array $requestedChecks
+   * @return bool
+   */
+  private function isRequested($method, $requestedChecks) {
+    if (!$requestedChecks) {
+      return TRUE;
+    }
+    foreach ($requestedChecks as $name) {
+      if (strpos($name, $method) === 0) {
+        return TRUE;
+      }
+    }
+    return FALSE;
+  }
+
   /**
    * Is the specified check disabled.
    *
index 76ae62ca5f782a1059ff91e7c09ef289a7e69e8b..f3a494ab95131c23f3490d7017c1ab6461a9f2ce 100644 (file)
@@ -157,13 +157,14 @@ class CRM_Utils_Check_Component_Env extends CRM_Utils_Check_Component {
   }
 
   /**
+   * @param bool $force
    * @return CRM_Utils_Check_Message[]
    */
-  public function checkOutboundMail() {
+  public function checkOutboundMail($force = FALSE) {
     $messages = [];
 
     // CiviMail doesn't work in non-production environments; skip.
-    if (CRM_Core_Config::environment() != 'Production') {
+    if (!$force && CRM_Core_Config::environment() != 'Production') {
       return $messages;
     }
 
@@ -188,13 +189,14 @@ class CRM_Utils_Check_Component_Env extends CRM_Utils_Check_Component {
 
   /**
    * Check that domain email and org name are set
+   * @param bool $force
    * @return CRM_Utils_Check_Message[]
    */
-  public function checkDomainNameEmail() {
+  public function checkDomainNameEmail($force = FALSE) {
     $messages = [];
 
     // CiviMail doesn't work in non-production environments; skip.
-    if (CRM_Core_Config::environment() != 'Production') {
+    if (!$force && CRM_Core_Config::environment() != 'Production') {
       return $messages;
     }
 
@@ -238,13 +240,14 @@ class CRM_Utils_Check_Component_Env extends CRM_Utils_Check_Component {
 
   /**
    * Checks if a default bounce handling mailbox is set up
+   * @param bool $force
    * @return CRM_Utils_Check_Message[]
    */
-  public function checkDefaultMailbox() {
+  public function checkDefaultMailbox($force = FALSE) {
     $messages = [];
 
     // CiviMail doesn't work in non-production environments; skip.
-    if (CRM_Core_Config::environment() != 'Production') {
+    if (!$force && CRM_Core_Config::environment() != 'Production') {
       return $messages;
     }
 
@@ -273,14 +276,15 @@ class CRM_Utils_Check_Component_Env extends CRM_Utils_Check_Component {
 
   /**
    * Checks if cron has run in the past hour (3600 seconds)
+   * @param bool $force
    * @return CRM_Utils_Check_Message[]
    * @throws CRM_Core_Exception
    */
-  public function checkLastCron() {
+  public function checkLastCron($force = FALSE) {
     $messages = [];
 
     // Cron doesn't work in non-production environments; skip.
-    if (CRM_Core_Config::environment() != 'Production') {
+    if (!$force && CRM_Core_Config::environment() != 'Production') {
       return $messages;
     }
 
@@ -321,7 +325,7 @@ class CRM_Utils_Check_Component_Env extends CRM_Utils_Check_Component {
         // After 1 day (86400 seconds) increase the error level
         $level = ($lastCron > $now - 86400) ? \Psr\Log\LogLevel::WARNING : \Psr\Log\LogLevel::ERROR;
       }
-      $msg .= '<p>' . ts('To enable scheduling support, please set up the cron job.') .
+      $msg .= '<p>' . ts('A cron job is required to execute scheduled jobs automatically.') .
        '<br />' . CRM_Utils_System::docURL2('sysadmin/setup/jobs/') . '</p>';
     }
 
@@ -655,7 +659,7 @@ class CRM_Utils_Check_Component_Env extends CRM_Utils_Check_Component {
 
     if (!$okextensions && !$updates && !$errors) {
       $messages[] = new CRM_Utils_Check_Message(
-        'extensionsOk',
+        __FUNCTION__ . 'Ok',
         ts('No extensions installed. <a %1>Browse available extensions</a>.', [
           1 => 'href="' . CRM_Utils_System::url('civicrm/admin/extensions', 'reset=1') . '"',
         ]),
@@ -677,7 +681,7 @@ class CRM_Utils_Check_Component_Env extends CRM_Utils_Check_Component {
 
     if ($updates) {
       $messages[] = new CRM_Utils_Check_Message(
-        'extensionUpdates',
+        __FUNCTION__ . 'Updates',
         '<ul><li>' . implode('</li><li>', $updates) . '</li></ul>',
         ts('Extension Update Available', ['plural' => '%count Extension Updates Available', 'count' => count($updates)]),
         \Psr\Log\LogLevel::WARNING,
@@ -693,7 +697,7 @@ class CRM_Utils_Check_Component_Env extends CRM_Utils_Check_Component {
         $message = ts('All extensions are up-to-date:');
       }
       $messages[] = new CRM_Utils_Check_Message(
-        'extensionsOk',
+        __FUNCTION__ . 'Ok',
         $message . '<ul><li>' . implode('</li><li>', $okextensions) . '</li></ul>',
         ts('Extensions'),
         \Psr\Log\LogLevel::INFO,
@@ -820,13 +824,14 @@ class CRM_Utils_Check_Component_Env extends CRM_Utils_Check_Component {
 
   /**
    * Ensure reply id is set to any default value
+   * @param bool $force
    * @return CRM_Utils_Check_Message[]
    */
-  public function checkReplyIdForMailing() {
+  public function checkReplyIdForMailing($force = FALSE) {
     $messages = [];
 
     // CiviMail doesn't work in non-production environments; skip.
-    if (CRM_Core_Config::environment() != 'Production') {
+    if (!$force && CRM_Core_Config::environment() != 'Production') {
       return $messages;
     }
 
index 5a5e612c057dfaf8ebf43be286ce47d80e732a8a..381b69f8f68521ce164e56ebf4fe05589a8130a8 100644 (file)
@@ -132,7 +132,7 @@ abstract class CRM_Utils_Hook {
    * but also accepts enough information to support Symfony Event
    * dispatching.
    *
-   * @param array|int $names
+   * @param array $names
    *   (Recommended) Array of parameter names, in order.
    *   Using an array is recommended because it enables full
    *   event-broadcasting behaviors.
@@ -155,15 +155,14 @@ abstract class CRM_Utils_Hook {
     if (!is_array($names)) {
       // We were called with the old contract wherein $names is actually an int.
       // Symfony dispatcher requires some kind of name.
-      // TODO: Emit a warning, eg
-      // error_log("Warning: hook_$fnSuffix does not give names for its parameters. It will present odd names to any Symfony event listeners.");
+      Civi::log()->warning("hook_$fnSuffix should be updated to pass an array of parameter names to CRM_Utils_Hook::invoke().", ['civi.tag' => 'deprecated']);
       $compatNames = ['arg1', 'arg2', 'arg3', 'arg4', 'arg5', 'arg6'];
       $names = array_slice($compatNames, 0, (int) $names);
     }
 
     $event = \Civi\Core\Event\GenericHookEvent::createOrdered(
       $names,
-      array(&$arg1, &$arg2, &$arg3, &$arg4, &$arg5, &$arg6)
+      [&$arg1, &$arg2, &$arg3, &$arg4, &$arg5, &$arg6]
     );
     \Civi::dispatcher()->dispatch('hook_' . $fnSuffix, $event);
     return $event->getReturnValues();
@@ -678,7 +677,7 @@ abstract class CRM_Utils_Hook {
    *   the return value is ignored
    */
   public static function activeTheme(&$theme, $context) {
-    return self::singleton()->invoke(array('theme', 'context'), $theme, $context,
+    return self::singleton()->invoke(['theme', 'context'], $theme, $context,
       self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject,
       'civicrm_activeTheme'
     );
@@ -869,7 +868,7 @@ abstract class CRM_Utils_Hook {
    * @return mixed
    */
   public static function alterAdminPanel(&$panels) {
-    return self::singleton()->invoke(array('panels'), $panels,
+    return self::singleton()->invoke(['panels'], $panels,
       self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject,
       'civicrm_alterAdminPanel'
     );
@@ -2411,13 +2410,20 @@ abstract class CRM_Utils_Hook {
   /**
    * Check system status.
    *
-   * @param array $messages
-   *   Array<CRM_Utils_Check_Message>. A list of messages regarding system status.
+   * @param CRM_Utils_Check_Message[] $messages
+   *   A list of messages regarding system status
+   * @param array $statusNames
+   *   If specified, only these checks are being requested and others should be skipped
+   * @param bool $includeDisabled
+   *   Run checks that have been explicitly disabled (default false)
    * @return mixed
    */
-  public static function check(&$messages) {
-    return self::singleton()
-      ->invoke(['messages'], $messages, self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject, self::$_nullObject, 'civicrm_check');
+  public static function check(&$messages, $statusNames = [], $includeDisabled = FALSE) {
+    return self::singleton()->invoke(['messages'],
+      $messages, $statusNames, $includeDisabled,
+      self::$_nullObject, self::$_nullObject, self::$_nullObject,
+      'civicrm_check'
+    );
   }
 
   /**
index a49cb27acd77f2a067807232d7def335d8d180ee..0ac404f1431498309f2eb2e2d5720e3da075b387 100644 (file)
@@ -152,6 +152,8 @@ class CRM_Utils_Mail {
    * text    : text of the message
    * html    : html version of the message
    * replyTo : reply-to header in the email
+   * returnpath : email address for bounces to be sent to
+   * messageId : Message ID for this email mesage
    * attachments: an associative array of
    *   fullPath : complete pathname to the file
    *   mime_type: mime type of the attachment
@@ -223,7 +225,7 @@ class CRM_Utils_Mail {
     }
     $headers['Date'] = date('r');
     if ($includeMessageId) {
-      $headers['Message-ID'] = '<' . uniqid('civicrm_', TRUE) . "@$emailDomain>";
+      $headers['Message-ID'] = $params['messageId'] ?? '<' . uniqid('civicrm_', TRUE) . "@$emailDomain>";
     }
     if (!empty($params['autoSubmitted'])) {
       $headers['Auto-Submitted'] = "Auto-Generated";
index 5b436c0f2016a983ea878377f1e9166390adb349..03c7c26d1c0db6530ec04308b7c4aa298b621934 100644 (file)
@@ -212,7 +212,7 @@ class CRM_Utils_REST {
     // interface can be disabled in more change to the configuration file.
     // first check for civicrm site key
     if (!CRM_Utils_System::authenticateKey(FALSE)) {
-      $docLink = CRM_Utils_System::docURL2("Managing Scheduled Jobs", TRUE, NULL, NULL, NULL, "wiki");
+      $docLink = CRM_Utils_System::docURL2('sysadmin/setup/jobs', TRUE);
       $key = $requestParams['key'] ?? NULL;
       if (empty($key)) {
         return self::error("FATAL: mandatory param 'key' missing. More info at: " . $docLink);
index 9d886dced3e6530c7ee8e5f25b16b7f47f22b155..f0024d7ef79a5a15728fa8b35687061d04ca5c3b 100644 (file)
@@ -148,8 +148,7 @@ class CRM_Utils_SQL_TempTable {
       return '';
     }
     $dbUTF = CRM_Core_BAO_SchemaHandler::getDBCollation();
-    if (in_array($dbUTF, ['utf8_unicode_ci', 'utf8mb4_unicode_ci'])
-      && in_array($dbUTF, ['utf8', 'utf8mb4'])) {
+    if (strpos($dbUTF, 'utf8') !== FALSE) {
       return '';
     }
     return self::UTF8;
@@ -168,7 +167,7 @@ class CRM_Utils_SQL_TempTable {
       $this->toSQL('CREATE'),
       $columns,
       $this->memory ? self::MEMORY : self::INNODB,
-      $this->utf8 ? self::UTF8 : ''
+      $this->getUtf8String()
     );
     CRM_Core_DAO::executeQuery($sql, [], TRUE, NULL, TRUE, FALSE);
     $this->createSql = $sql;
index 42b0960d2b9a74c15a2dff222dbf2ee393c23888..cedef4ca0d458ca83af785ebf097b81633d5dc58 100644 (file)
@@ -600,7 +600,7 @@ class CRM_Utils_System {
     // also make sure the key is sent and is valid
     $key = trim(CRM_Utils_Array::value('key', $_REQUEST));
 
-    $docAdd = "More info at:" . CRM_Utils_System::docURL2("Managing Scheduled Jobs", TRUE, NULL, NULL, NULL, "wiki");
+    $docAdd = "More info at: " . CRM_Utils_System::docURL2('sysadmin/setup/jobs', TRUE);
 
     if (!$key) {
       return self::authenticateAbort(
@@ -1497,7 +1497,7 @@ class CRM_Utils_System {
         = CRM_Contribute_BAO_Contribution::$_exportableFields
           = CRM_Pledge_BAO_Pledge::$_exportableFields
             = CRM_Core_BAO_CustomField::$_importFields
-              = CRM_Core_BAO_Cache::$_cache = CRM_Core_DAO::$_dbColumnValueCache = NULL;
+              = CRM_Core_DAO::$_dbColumnValueCache = NULL;
 
     CRM_Core_OptionGroup::flushAll();
     CRM_Utils_PseudoConstant::flushAll();
index 53e2a67dea34288231577164dc1f9bd4eebe686f..78479501e3ab79599f79ef9af85660070e571ea7 100644 (file)
@@ -56,6 +56,9 @@ class CRM_Utils_System_Drupal8 extends CRM_Utils_System_DrupalBase {
     // Validate the user object
     $violations = $account->validate();
     if (count($violations)) {
+      foreach ($violations as $violation) {
+        CRM_Core_Session::setStatus($violation->getPropertyPath() . ': ' . $violation->getMessage(), '', 'alert');
+      }
       return FALSE;
     }
 
index 134fa0ffb2b5057d6859d8ae8f104c89210aedc4..4e86eb89bf9f37a415b734a6ef2327ad5258b146 100644 (file)
@@ -54,13 +54,6 @@ class CRM_Utils_System_WordPress extends CRM_Utils_System_Base {
       };
       Civi::paths()->register('cms', $cmsRoot);
       Civi::paths()->register('cms.root', $cmsRoot);
-      Civi::paths()->register('civicrm.files', function () {
-        $upload_dir = wp_get_upload_dir();
-        return [
-          'path' => $upload_dir['basedir'] . DIRECTORY_SEPARATOR . 'civicrm' . DIRECTORY_SEPARATOR,
-          'url' => $upload_dir['baseurl'] . '/civicrm/',
-        ];
-      });
       Civi::paths()->register('civicrm.root', function () {
         return [
           'path' => CIVICRM_PLUGIN_DIR . 'civicrm' . DIRECTORY_SEPARATOR,
@@ -140,6 +133,9 @@ class CRM_Utils_System_WordPress extends CRM_Utils_System_Base {
    * Moved from CRM_Utils_System_Base
    */
   public function getDefaultFileStorage() {
+    // NOTE: On WordPress, this will be circumvented in the future. However,
+    // should retain it to allow transitional/upgrade code determine the old value.
+
     $config = CRM_Core_Config::singleton();
     $cmsUrl = CRM_Utils_System::languageNegotiationURL($config->userFrameworkBaseURL, FALSE, TRUE);
     $cmsPath = $this->cmsRootPath();
index 9080f60a8d4ec7ab28c8c1f196fd1575d957575e..19df2a2a1150c1a8d3fdebda38991d93d580ad09 100644 (file)
@@ -14,12 +14,39 @@ namespace Civi\Api4\Action\System;
 
 /**
  * Retrieve system notices, warnings, errors, etc.
+ * @method bool getIncludeDisabled()
  */
 class Check extends \Civi\Api4\Generic\BasicGetAction {
 
+  /**
+   * Run checks that have been explicitly disabled (default false)
+   * @var bool
+   */
+  protected $includeDisabled = FALSE;
+
+  /**
+   * @param bool $includeDisabled
+   * @return Check
+   */
+  public function setIncludeDisabled(bool $includeDisabled): Check {
+    $this->includeDisabled = $includeDisabled;
+    return $this;
+  }
+
   protected function getRecords() {
-    $messages = [];
-    foreach (\CRM_Utils_Check::checkAll() as $message) {
+    $messages = $names = [];
+
+    // Filtering by name relies on the component check rather than the api arrayQuery
+    // @see \CRM_Utils_Check_Component::isCheckable
+    foreach ($this->where as $i => $clause) {
+      if ($clause[0] == 'name' && !empty($clause[2]) && in_array($clause[1], ['=', 'IN'], TRUE)) {
+        $names = (array) $clause[2];
+        unset($this->where[$i]);
+        break;
+      }
+    }
+
+    foreach (\CRM_Utils_Check::checkStatus($names, $this->includeDisabled) as $message) {
       $messages[] = $message->toArray();
     }
     return $messages;
index aaea4ca3c2ef9b32ad0516ef1fd6b915fd6e95ce..153f2e60a072b2c265c301a3ab76cf21a6dcdeac 100644 (file)
@@ -105,7 +105,7 @@ abstract class AbstractGetAction extends AbstractQueryAction {
   protected function _itemsToGet($field) {
     foreach ($this->where as $clause) {
       // Look for exact-match operators (=, IN, or LIKE with no wildcard)
-      if ($clause[0] == $field && (in_array($clause[1], ['=', 'IN']) || ($clause[1] == 'LIKE' && !(is_string($clause[2]) && strpos($clause[2], '%') !== FALSE)))) {
+      if ($clause[0] == $field && (in_array($clause[1], ['=', 'IN'], TRUE) || ($clause[1] == 'LIKE' && !(is_string($clause[2]) && strpos($clause[2], '%') !== FALSE)))) {
         return (array) $clause[2];
       }
     }
index 953f6c59c90aa92e3ba765c563a77b11c2998eb3..b12dc332049fe5d19b49baac995ef6bc7a8dd49f 100644 (file)
 namespace Civi\Api4\Generic;
 
 /**
- * Base class for all `Save` api actions.
+ * Create or update one or more $ENTITIES.
+ *
+ * Pass an array of one or more $ENTITY to save in the `records` param.
+ *
+ * If creating more than one $ENTITY with similar values, use the `defaults` param.
+ *
+ * Set `reload` if you need the api to return complete records for each saved $ENTITY
+ * (including values that were unchanged in from updated $ENTITIES).
  *
  * @method $this setRecords(array $records) Set array of records to be saved.
  * @method array getRecords()
index 4ddb4234dff613c3096838cb7a59c536a879a0d0..c1316ede9707c4d38e834d94fa3945aed9fd221c 100644 (file)
@@ -22,11 +22,7 @@ namespace Civi\Api4\Generic;
 use Civi\API\Exception\NotImplementedException;
 
 /**
- * $ACTION one or more $ENTITIES.
- *
- * If saving more than one new $ENTITY with similar values, use the `defaults` parameter.
- *
- * Set `reload` if you need the api to return complete $ENTITY records.
+ * @inheritDoc
  */
 class BasicSaveAction extends AbstractSaveAction {
 
@@ -37,7 +33,7 @@ class BasicSaveAction extends AbstractSaveAction {
   private $setter;
 
   /**
-   * Basic Create constructor.
+   * Basic Save constructor.
    *
    * @param string $entityName
    * @param string $actionName
index c6d0d36aa815bc464df77c46cff2abe154765beb..a3d8a288f55a9861d30750b9cb36dee1e5f2e7d6 100644 (file)
 namespace Civi\Api4\Generic;
 
 /**
- * Create or update one or more $ENTITIES.
- *
- * If creating more than one $ENTITY with similar values, use the `defaults` param.
- *
- * Set `reload` if you need the api to return complete records for each saved $ENTITY.
+ * @inheritDoc
  */
 class DAOSaveAction extends AbstractSaveAction {
   use Traits\DAOActionTrait;
index 7f16a88e69d3ced37aa4a87ec68dc3bff9a158eb..4ae6096c503965784deff942f29420d785cf50a0 100644 (file)
@@ -60,7 +60,7 @@ trait ArrayQueryActionTrait {
    * @return bool
    */
   private function evaluateFilters($row) {
-    $where = $this->getWhere();
+    $where = array_values($this->getWhere());
     $allConditions = in_array($where[0], ['AND', 'OR', 'NOT']) ? $where : ['AND', $where];
     return $this->walkFilters($row, $allConditions);
   }
index 617b6dee2c4ac6ad8746d06deb76ab14db699585..5b96e40ef08e2588e0f1c3a641f0e1bc3bd002ad 100644 (file)
@@ -210,7 +210,7 @@ class Container {
       ->setFactory('CRM_Utils_Mail::createMailer');
 
     if (empty(\Civi::$statics[__CLASS__]['boot'])) {
-      throw new \RuntimeException("Cannot initialize container. Boot services are undefined.");
+      throw new \RuntimeException('Cannot initialize container. Boot services are undefined.');
     }
     foreach (\Civi::$statics[__CLASS__]['boot'] as $bootService => $def) {
       $container->setDefinition($bootService, new Definition())->setSynthetic(TRUE)->setPublic(TRUE);
@@ -461,20 +461,19 @@ class Container {
    */
   public static function createPrevNextCache($container) {
     $setting = \Civi::settings()->get('prevNextBackend');
-    if ($setting === 'default') {
-      // For initial release (5.8.x), continue defaulting to SQL.
-      $isTransitional = version_compare(\CRM_Utils_System::version(), '5.9.alpha1', '<');
+    if (!$setting || $setting === 'default') {
       $cacheDriver = \CRM_Utils_Cache::getCacheDriver();
       $service = 'prevnext.driver.' . strtolower($cacheDriver);
-      return $container->has($service) && !$isTransitional
+      return $container->has($service)
         ? $container->get($service)
         : $container->get('prevnext.driver.sql');
     }
-    else {
-      return $container->get('prevnext.driver.' . $setting);
-    }
+    return $container->get('prevnext.driver.' . $setting);
   }
 
+  /**
+   * @return \ArrayObject
+   */
   public static function createCacheConfig() {
     $driver = \CRM_Utils_Cache::getCacheDriver();
     $settings = \CRM_Utils_Cache::getCacheSettings($driver);
@@ -548,6 +547,11 @@ class Container {
     }
   }
 
+  /**
+   * @param string $name
+   *
+   * @return mixed
+   */
   public static function getBootService($name) {
     return \Civi::$statics[__CLASS__]['boot'][$name];
   }
index d5f3d648ebf242cd23a90146144b54c63c8f7d18..da7b2cc76597194238bff22058288b01ed11c268 100644 (file)
@@ -303,6 +303,9 @@ class Requirements {
    * @return array
    */
   public function checkMysqlVersion(array $db_config) {
+    if (!class_exists('\CRM_Upgrade_Incremental_General')) {
+      require_once dirname(__FILE__) . '/../../CRM/Upgrade/Incremental/General.php';
+    }
     $min = \CRM_Upgrade_Incremental_General::MIN_INSTALL_MYSQL_VER;
     $results = [
       'title' => 'CiviCRM MySQL Version',
index 18380923c1eeb28c1ab05bcb5d9e7bff04fa8b49..5e97ae964a5b9ef7a7436bc68346289e14ffa551 100644 (file)
@@ -83,7 +83,7 @@
           class="crm-hover-button action-item"
           ng-href="{{statUrl(am.mailing, statType, 'report')}}"
           title="{{ts('Reports for \'%1\'', {1: statType.title})}}"
-          crm-icon="clipboard"
+          crm-icon="fa-clipboard"
           ></a>
       </td>
       <td ng-show="abtest.ab.status == 'Testing'"></td>
index c6ba58b1464ef6d156cf5e3875a573b955a9f289..355939c2dcf71ec855ac2fdaadc0c26d73c7db47 100644 (file)
     })
 
     // Example for Font Awesome: <button crm-icon="fa-check">Save</button>
-    // Example for jQuery UI (deprecated): <button crm-icon="check">Save</button>
+    // Example for jQuery UI (deprecated): <button crm-icon="fa-check">Save</button>
     .directive('crmIcon', function() {
       return {
         restrict: 'EA',
index bbe016918144e5c0ad12852764d0970b6c4ff544..298980b4a74acced636044863de2b1cc57d0d902 100644 (file)
@@ -393,7 +393,7 @@ function _civicrm_api3_contribute_format_params($params, &$values) {
  * @throws Exception
  */
 function civicrm_api3_contribution_sendconfirmation($params) {
-  $ids = $values = [];
+  $ids = [];
   $allowedParams = [
     'receipt_from_email',
     'receipt_from_name',
@@ -404,8 +404,7 @@ function civicrm_api3_contribution_sendconfirmation($params) {
     'payment_processor_id',
   ];
   $input = array_intersect_key($params, array_flip($allowedParams));
-  $input['is_email_receipt'] = TRUE;
-  CRM_Contribute_BAO_Contribution::sendMail($input, $ids, $params['id'], $values);
+  CRM_Contribute_BAO_Contribution::sendMail($input, $ids, $params['id']);
 }
 
 /**
@@ -488,7 +487,8 @@ function civicrm_api3_contribution_completetransaction($params) {
   elseif ($contribution->contribution_status_id == CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed')) {
     throw new API_Exception(ts('Contribution already completed'), 'contribution_completed');
   }
-  $input['trxn_id'] = !empty($params['trxn_id']) ? $params['trxn_id'] : $contribution->trxn_id;
+  $input['trxn_id'] = $params['trxn_id'] ?? $contribution->trxn_id;
+
   if (!empty($params['fee_amount'])) {
     $input['fee_amount'] = $params['fee_amount'];
   }
@@ -682,7 +682,7 @@ function _ipn_process_transaction(&$params, $contribution, $input, $ids, $firstC
   }
   $input['card_type_id'] = $params['card_type_id'] ?? NULL;
   $input['pan_truncation'] = $params['pan_truncation'] ?? NULL;
-  return CRM_Contribute_BAO_Contribution::completeOrder($input, $ids, $objects, NULL,
+  return CRM_Contribute_BAO_Contribution::completeOrder($input, $ids, $objects,
     $params['is_post_payment_create'] ?? NULL);
 }
 
index 99b270ec29755882805bc62f9a2a9e4439f659b0..32d59a193954a62755d3afd6d7ba9d66a8834a97 100644 (file)
@@ -74,9 +74,9 @@ function civicrm_api3_order_create($params) {
   civicrm_api3_verify_one_mandatory($params, NULL, ['line_items', 'total_amount']);
   $entity = NULL;
   $entityIds = [];
-  $contributionStatus = $params['contribution_status_id'] ?? NULL;
-  if ($contributionStatus !== 'Pending' && 'Pending' !== CRM_Core_PseudoConstant::getName('CRM_Contribute_BAO_Contribution', 'contribution_status_id', $contributionStatus)) {
-    CRM_Core_Error::deprecatedFunctionWarning("Creating a Order with a status other than pending is deprecated. Currently empty defaults to 'Completed' so as a transition not passing in 'Pending' is deprecated. You can chain payment creation e.g civicrm_api3('Order', 'create', ['blah' => 'blah', 'contribution_status_id' => 'Pending', 'api.Payment.create => ['total_amount' => 5]]");
+  $params['contribution_status_id'] = $params['contribution_status_id'] ?? 'Pending';
+  if ($params['contribution_status_id'] !== 'Pending' && 'Pending' !== CRM_Core_PseudoConstant::getName('CRM_Contribute_BAO_Contribution', 'contribution_status_id', $params['contribution_status_id'])) {
+    CRM_Core_Error::deprecatedFunctionWarning("Creating a Order with a status other than pending is deprecated. Please do not set contribution_status_id, it will default to Pending. You can chain payment creation e.g civicrm_api3('Order', 'create', ['blah' => 'blah', 'contribution_status_id' => 'Pending', 'api.Payment.create => ['total_amount' => 5]]");
   }
 
   if (!empty($params['line_items']) && is_array($params['line_items'])) {
@@ -91,9 +91,7 @@ function civicrm_api3_order_create($params) {
       if ($entityParams) {
         if (in_array($entity, ['participant', 'membership'])) {
           $entityParams['skipLineItem'] = TRUE;
-          if ($contributionStatus === 'Pending') {
-            $entityParams['status_id'] = ($entity === 'participant' ? 'Pending from incomplete transaction' : 'Pending');
-          }
+          $entityParams['status_id'] = ($entity === 'participant' ? 'Pending from incomplete transaction' : 'Pending');
           $entityResult = civicrm_api3($entity, 'create', $entityParams);
           $params['contribution_mode'] = $entity;
           $entityIds[] = $params[$entity . '_id'] = $entityResult['id'];
index d260ee66abff2dc6b3800ea776856d237d6089c8..cf61ef5a7d057e2d95fd9235732a21d89f10b2d3 100644 (file)
@@ -1835,8 +1835,6 @@ input.crm-form-entityref {
 
 .crm-container .crm-button input {
   background: none;
-  _background: #6C6C6C;
-  /* IE6 only */
   border: medium none;
   color: #FFF;
   cursor: pointer;
@@ -1850,8 +1848,11 @@ input.crm-form-entityref {
 .crm-container .crm-button-type-back {
   margin-left: 20px;
 }
-.crm-container .crm-button-type-cancel input {
-  color: #E6E6DC!important;
+
+/* Reset WP backend min-height for buttons */
+
+.wp-core-ui .crm-container .button {
+  min-height: 0;
 }
 
 .crm-container a.button,
@@ -1862,7 +1863,7 @@ input.crm-form-entityref {
 .crm-container input[type=button],
 .crm-container .crm-button {
   text-shadow: 0 1px 0 black;
-  background: #70716B url(../i/crm-button-bg.gif) repeat-x top left;
+  background: #696969;
   color: #FFF;
   font-size: 13px;
   font-weight: normal;
@@ -1873,11 +1874,19 @@ input.crm-form-entityref {
   border: 1px solid #3e3e3e;
 }
 
+.crm-container a.button,
+.crm-container a.button:link,
+.crm-container a.button:visited,
 .crm-container span.crm-button {
   display: block;
-  float: left !important;
+  float: left;
   overflow: hidden;
-  padding: 1px;
+  line-height: 135%;
+}
+
+/* Preserving the important but not sure why */
+.crm-container span.crm-button {
+  float: left !important;
 }
 
 .crm-container button.crm-button {
@@ -1895,22 +1904,12 @@ input.crm-form-entityref {
 
 .crm-container .crm-button input[type=button],
 .crm-container .crm-button input.crm-form-submit {
-  padding: 3px 5px 2px;
+  padding: 0;
   margin: 0;
   background: none;
-  _background: #6C6C6C;
-  /* IE6 only */
   border: none;
 }
 
-.crm-container a.button,
-.crm-container a.button:link,
-.crm-container a.button:visited {
-  display: block;
-  float: left;
-  line-height: 135%;
-}
-
 .crm-container .crm-button:hover,
 .crm-container .crm-button:focus,
 .crm-container input[type=submit]:hover,
@@ -1919,7 +1918,7 @@ input.crm-form-entityref {
 .crm-container .ui-dialog-buttonset .ui-button:focus,
 .crm-container a.button:hover,
 .crm-container a.button:focus {
-  background-position: 0 -25px;
+  background: #3e3e3e;
 }
 
 .crm-container .crm-button-disabled,
@@ -1930,7 +1929,6 @@ input.crm-form-entityref {
 .crm-container .crm-button[disabled] {
   opacity: .6;
   cursor: default;
-  background-position: top left;
 }
 
 .crm-container .crm-button-disabled input[disabled] {
@@ -2050,31 +2048,6 @@ input.crm-form-entityref {
   margin-left: 3px;
 }
 
-.crm-container .crm-button.crm-icon-button {
-  padding: 2px 2px 1px 4px;
-}
-
-.crm-container .crm-button.crm-icon-button input {
-  padding-left: 18px;
-}
-
-.crm-container .crm-button.button-crm-i {
-  padding: 2px 0 1px 5px;
-}
-
-.crm-container .crm-button.button-crm-i input {
-  padding-left: 0;
-}
-
-.crm-container .crm-button-icon {
-  background-image: url("../i/icons/jquery-ui-FFFFFF.png");
-  height: 16px;
-  width: 16px;
-  display: block;
-  position: absolute;
-  pointer-events: none;
-}
-
 .crm-container .delete-icon {
   background-position: -176px -96px;
 }
@@ -2121,27 +2094,6 @@ a.crm-i:hover {
   color: #86c661;
 }
 
-.crm-i-button {
-  position: relative;
-}
-
-.crm-i-button>.crm-i {
-  position: absolute;
-  pointer-events: none;
-  top: .4em;
-  left: .4em;
-}
-
-.crm-container .crm-button.crm-i-button input[type="button"],
-.crm-container .crm-button.crm-i-button input.crm-form-submit {
-  padding-left: 1.6em;
-}
-
-.crm-container .inform-icon {
-  background-position: -16px -144px;
-  margin-right: 5px;
-}
-
 .crm-container a.helpicon {
   opacity: .8;
 }
@@ -3201,7 +3153,7 @@ span.crm-select-item-color {
   right: 0;
 }
 .crm-container .ui-dialog-titlebar.ui-widget-header {
-  background: url("../i/crm-button-bg.gif") repeat-x scroll left center #70716B;
+  background: #5D677B;
   color: #F5F6F1;
 }
 .crm-container .ui-dialog-title {
index f89dbd026e786fb9cb3761354b367cd04a45cf64..7317ae50277fa2619f025c77432495d1b96dee2a 100644 (file)
     <url desc="Support">http://civicrm.stackexchange.com/</url>
     <url desc="Licensing">http://www.gnu.org/licenses/agpl-3.0.html</url>
   </urls>
-  <releaseDate>2019-11-26</releaseDate>
-  <version>1.1.1</version>
-  <develStage>alpha</develStage>
+  <releaseDate>2020-08-05</releaseDate>
+  <version>1.1.2</version>
+  <develStage>stable</develStage>
   <comments>
     FlexMailer is an email delivery engine which replaces the internal guts
     of CiviMail.  It is a drop-in replacement which enables *other* extensions
     to provide richer email features.
   </comments>
   <compatibility>
-    <ver>5.13</ver>
+    <ver>5.29</ver>
   </compatibility>
   <classloader>
     <psr4 prefix="Civi\FlexMailer\" path="src"/>
diff --git a/i/crm-button-bg.gif b/i/crm-button-bg.gif
deleted file mode 100644 (file)
index 6aa345e..0000000
Binary files a/i/crm-button-bg.gif and /dev/null differ
index 6f41eab124869baf3ee596ba647ac4ff5e2d1e1d..88acc9ef4d4055e3916a1692940045f5f7a3dd75 100644 (file)
@@ -883,7 +883,7 @@ if (!CRM.vars) CRM.vars = {};
       var that = this;
       validator.settings = $.extend({}, validator.settings, CRM.validate._defaults, CRM.validate.params);
       // Call our custom validation handler.
-      $(validator.currentForm).on("invalid-form.validate", validator.settings.invalidHandler );
+      $(validator.currentForm).on("invalid-form.validate", validator.settings.invalidHandler);
       // Call any post-initialization callbacks
       if (CRM.validate.functions && CRM.validate.functions.length) {
         $.each(CRM.validate.functions, function(i, func) {
index 9a3c3f1ce572d21cec0c0012a9a4840d339c7a83..e65bd7b2a22c946265f100899d9b50b24a6b6a5c 100644 (file)
             added.push(identifier);
           }
           // display:none causes the form to not submit when pressing "enter"
-          $el.parents(buttonContainers).css({height: 0, padding: 0, margin: 0, overflow: 'hidden'}).find('.crm-button-icon').hide();
+          $el.parents(buttonContainers).css({height: 0, padding: 0, margin: 0, overflow: 'hidden'});
         });
         $el.dialog('option', 'buttons', buttons);
       }
index 8e17ff63b72e08c9335c4ab7cef9fa22ffe6c16e..a7c7f0ef3554e82154357e519d1f0316b78dc630 100644 (file)
@@ -26,6 +26,15 @@ Released August 5, 2020
 - **[Credits](release-notes/5.28.0.md#credits)**
 - **[Feedback](release-notes/5.28.0.md#feedback)**
 
+## CiviCRM 5.27.4
+
+Released August 3, 2020
+
+- **[Synopsis](release-notes/5.27.4.md#synopsis)**
+- **[Bugs resolved](release-notes/5.27.4.md#bugs)**
+- **[Credits](release-notes/5.27.4.md#credits)**
+- **[Feedback](release-notes/5.27.4.md#feedback)**
+
 ## CiviCRM 5.27.3
 
 Released July 23, 2020
diff --git a/release-notes/5.27.4.md b/release-notes/5.27.4.md
new file mode 100644 (file)
index 0000000..feaaaa0
--- /dev/null
@@ -0,0 +1,56 @@
+# CiviCRM 5.27.4
+
+Released August 3, 2020
+
+- **[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?** | **yes** |
+| Introduce features?                                             |   no    |
+| **Fix bugs?**                                                   | **yes** |
+
+## <a name="bugs"></a>Bugs resolved
+
+* **_CiviCase_: Action links are missing text labels ([dev/core#1899](https://lab.civicrm.org/dev/core/-/issues/1899):
+  [#17947](https://github.com/civicrm/civicrm-core/pull/17947))**
+* **_CiviContribute_: When editing "Amounts", default is mis-saved ([dev/core#1911](https://lab.civicrm.org/dev/core/-/issues/1911):
+  [#17960](https://github.com/civicrm/civicrm-core/pull/17960))**
+
+  If you recently edited any "Amounts", then please review and verify that the default is correct.
+  Mis-saved defaults can cause problems when submitting contributions.
+
+* **_CiviMail_: Blasts sent via Job Manager do not recover from errors ([dev/mail#72](https://lab.civicrm.org/dev/mail/-/issues/72):
+  [#18017](https://github.com/civicrm/civicrm-core/pull/18017))**
+* **_WordPress_: `[civicrm.files]` is incorrect on older sites ([dev/wordpress#66](https://lab.civicrm.org/dev/wordpress/-/issues/66):
+  [#17868](https://github.com/civicrm/civicrm-core/pull/17868))**
+
+  This fixes a regression affecting older WordPress deployments by partially reverting
+  [dev/wordpress#47](https://lab.civicrm.org/dev/wordpress/-/issues/47).  This means that some WordPress configurations
+  (eg Polylang) may return to being unsupported.  The issue is scheduled to be revisited circa 5.29.  
+
+## <a name="credits"></a>Credits
+
+<!-- X: TIP: In buildkit, the CLI command civicredits.php can help autocomplete contributor names with the typical formatting.  -->
+
+This release was developed by the following authors and reviewers:
+
+Wikimedia Foundation - Eileen McNaughton; Team Expansion - Greg Harris; Tadpole Collective - Kevin
+Cristiano; Megaphone Technology Consulting - Jon Goldberg; MJW Consulting - Matthew Wire; JMA
+Consulting - Seamus Lee; Dave D; CiviCRM - Tim Otten; Christian Wach; Agileware - Justin Freeman;
+AGH Strategies - Andrew Hunt
+
+## <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 3644a8387a7d7d8357d1c22e2943b3894ef0c814..b6dba3bf1a733409af7f639970a5f34c0042b075 100644 (file)
@@ -725,7 +725,7 @@ UNLOCK TABLES;
 
 LOCK TABLES `civicrm_mailing_component` WRITE;
 /*!40000 ALTER TABLE `civicrm_mailing_component` DISABLE KEYS */;
-INSERT INTO `civicrm_mailing_component` (`id`, `name`, `component_type`, `subject`, `body_html`, `body_text`, `is_default`, `is_active`) VALUES (1,'Mailing Header','Header','Descriptive Title for this Header','Sample Header for HTML formatted content.','Sample Header for TEXT formatted content.',1,1),(2,'Mailing Footer','Footer','Descriptive Title for this Footer.','Sample Footer for HTML formatted content<br/><a href=\"{action.optOutUrl}\">Unsubscribe</a>  <br/> {domain.address}','to unsubscribe: {action.optOutUrl}\n{domain.address}',1,1),(3,'Subscribe Message','Subscribe','Subscription Confirmation Request','You have a pending subscription to the {subscribe.group} mailing list. To confirm this subscription, reply to this email or click <a href=\"{subscribe.url}\">here</a>.','You have a pending subscription to the {subscribe.group} mailing list. To confirm this subscription, reply to this email or click on this link: {subscribe.url}',1,1),(4,'Welcome Message','Welcome','Your Subscription has been Activated','Welcome. Your subscription to the {welcome.group} mailing list has been activated.','Welcome. Your subscription to the {welcome.group} mailing list has been activated.',1,1),(5,'Unsubscribe Message','Unsubscribe','Un-subscribe Confirmation','You have been un-subscribed from the following groups: {unsubscribe.group}. You can re-subscribe by mailing {action.resubscribe} or clicking <a href=\"{action.resubscribeUrl}\">here</a>.','You have been un-subscribed from the following groups: {unsubscribe.group}. You can re-subscribe by mailing {action.resubscribe} or clicking ',1,1),(6,'Resubscribe Message','Resubscribe','Re-subscribe Confirmation','You have been re-subscribed to the following groups: {resubscribe.group}. You can un-subscribe by mailing {action.unsubscribe} or clicking <a href=\"{action.unsubscribeUrl}\">here</a>.','You have been re-subscribed to the following groups: {resubscribe.group}. You can un-subscribe by mailing {action.unsubscribe} or clicking {action.unsubscribeUrl}',1,1),(7,'Opt-out Message','OptOut','Opt-out Confirmation','Your email address has been removed from {domain.name} mailing lists.','Your email address has been removed from {domain.name} mailing lists.',1,1),(8,'Auto-responder','Reply','Please Send Inquiries to Our Contact Email Address','This is an automated reply from an un-attended mailbox. Please send any inquiries to the contact email address listed on our web-site.','This is an automated reply from an un-attended mailbox. Please send any inquiries to the contact email address listed on our web-site.',1,1);
+INSERT INTO `civicrm_mailing_component` (`id`, `name`, `component_type`, `subject`, `body_html`, `body_text`, `is_default`, `is_active`) VALUES (1,'Mailing Header','Header','Descriptive Title for this Header','Sample Header for HTML formatted content.','Sample Header for TEXT formatted content.',1,1),(2,'Mailing Footer','Footer','Descriptive Title for this Footer.','Sample Footer for HTML formatted content<br/><a href=\"{action.optOutUrl}\">Unsubscribe</a>  <br/> {domain.address}','to unsubscribe: {action.optOutUrl}\n{domain.address}',1,1),(3,'Subscribe Message','Subscribe','Subscription Confirmation Request','You have a pending subscription to the {subscribe.group} mailing list. To confirm this subscription, reply to this email or click <a href=\"{subscribe.url}\">here</a>.','You have a pending subscription to the {subscribe.group} mailing list. To confirm this subscription, reply to this email or click on this link: {subscribe.url}',1,1),(4,'Welcome Message','Welcome','Your Subscription has been Activated','Welcome. Your subscription to the {welcome.group} mailing list has been activated.','Welcome. Your subscription to the {welcome.group} mailing list has been activated.',1,1),(5,'Unsubscribe Message','Unsubscribe','Un-subscribe Confirmation','You have been un-subscribed from the following groups: {unsubscribe.group}. You can re-subscribe by mailing {action.resubscribe} or clicking <a href=\"{action.resubscribeUrl}\">here</a>.','You have been un-subscribed from the following groups: {unsubscribe.group}. You can re-subscribe by mailing {action.resubscribe} or clicking {action.resubscribeUrl}',1,1),(6,'Resubscribe Message','Resubscribe','Re-subscribe Confirmation','You have been re-subscribed to the following groups: {resubscribe.group}. You can un-subscribe by mailing {action.unsubscribe} or clicking <a href=\"{action.unsubscribeUrl}\">here</a>.','You have been re-subscribed to the following groups: {resubscribe.group}. You can un-subscribe by mailing {action.unsubscribe} or clicking {action.unsubscribeUrl}',1,1),(7,'Opt-out Message','OptOut','Opt-out Confirmation','Your email address has been removed from {domain.name} mailing lists.','Your email address has been removed from {domain.name} mailing lists.',1,1),(8,'Auto-responder','Reply','Please Send Inquiries to Our Contact Email Address','This is an automated reply from an un-attended mailbox. Please send any inquiries to the contact email address listed on our web-site.','This is an automated reply from an un-attended mailbox. Please send any inquiries to the contact email address listed on our web-site.',1,1);
 /*!40000 ALTER TABLE `civicrm_mailing_component` ENABLE KEYS */;
 UNLOCK TABLES;
 
index fbecd9fce887313c0e3e9a2e1ad50ac66b0c044b..5c8bf2cc6dcd679662b4f4c7540c8b0295e1d7d5 100644 (file)
@@ -11,7 +11,7 @@
 <div class="crm-block crm-form-block crm-acl-form-block">
 {if $action eq 8}
   <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>&nbsp;
+    {icon icon="fa-info-circle"}{/icon}
         {ts}WARNING: Delete will remove this permission from the specified ACL Role.{/ts} {ts}Do you want to continue?{/ts}
   </div>
 {else}
index f905c4d5835e7c937f839306668f33b9b908d6c0..764ebe85bdfc2908d1829366c2b16e7be3d29fc2 100644 (file)
@@ -14,7 +14,7 @@
 {if $action eq 8}
   <div class="messages status no-popup">
     <dl>
-      <dt><div class="icon inform-icon"></div></dt>
+      <dt>{icon icon="fa-info-circle"}{/icon}</dt>
       <dd>
         {ts}WARNING: Delete will remove this permission from the specified ACL Role.{/ts} {ts}Do you want to continue?{/ts}
       </dd>
index 75bf26e6a2d2f1047c540239b450d75b8301081f..a2a8799c982baddf239a2be986f3dbffcb0e11c5 100644 (file)
@@ -13,7 +13,7 @@
  <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
 {if $action eq 8}
   <div class="messages status no-popup">
-  <div class="icon inform-icon"></div>
+  {icon icon="fa-info-circle"}{/icon}
        {ts}WARNING: Deleting this option will remove this ACL Role Assignment.{/ts} {ts}Do you want to continue?{/ts}
   </div>
 {else}
index 19eaaefeb2d5b9bf9e190a92a343390806bf201a..1a4c04c1730a223a5612e5454f4fa7f2fc4315e9 100644 (file)
@@ -9,7 +9,7 @@
 *}
 {* No matches for submitted search request. *}
 <div class="messages status no-popup">
-  <div class="icon inform-icon"></div>  &nbsp;
+  {icon icon="fa-info-circle"}{/icon}
     {if $qill}{ts}No matches found for:{/ts}
         {include file="CRM/common/displaySearchCriteria.tpl"}
     {else}
index fa8c71b91547227fbbd7718f0b0c680eaefb60c9..d467db4b42a7da700b889196471407e494809d71 100644 (file)
@@ -11,7 +11,7 @@
 <div class="crm-block crm-form-block crm-activity_delete-form-block">
 <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
 <div class="messages status no-popup">
-     <div class="icon inform-icon"></div>
+     {icon icon="fa-info-circle"}{/icon}
           <p>{ts}Are you sure you want to delete the selected Activities?{/ts}</p>
         <p>{include file="CRM/Activity/Form/Task.tpl"}</p>
     </div>
index 7fd288217c7d480ad1e43e417b5df9c84ef8bfd3..d71d4408c463355897145535e0c61b6abb628bf6 100644 (file)
@@ -67,7 +67,7 @@
   {include file="CRM/common/formButtons.tpl" location="bottom"}
 {else}
    <div class="messages status no-popup">
-       <div class="icon inform-icon"></div>
+       {icon icon="fa-info-circle"}{/icon}
          {ts}There are no records selected for Print.{/ts}
     </div>
 {/if}
index 8456ac24b4c72644b01d4188c615922e5ee38de0..4f1d28038a95885f65f5344840af35857e82d448 100644 (file)
@@ -37,7 +37,7 @@
 
 {else}
    <div class="messages status no-popup">
-          <div class="icon inform-icon"></div>
+          {icon icon="fa-info-circle"}{/icon}
             {ts}There are no records selected.{/ts}
    </div>
 {/if}
index 8fb1f85f2b9370cd38d23467500c66cc48c2c7b1..14318c6eb741d6f4fac2a1da973d669e6af2735c 100644 (file)
@@ -47,7 +47,7 @@ q="action=view&reset=1&id=`$row.activity_id`&cid=`$row.contact_id`&context=dashb
         {/strip}
     {else}
         <div class="messages status no-popup">
-           <div class="icon inform-icon"></div>&nbsp;
+           {icon icon="fa-info-circle"}{/icon}
                  {ts}There are no scheduled activities assigned to you.{/ts}
 
         </div>
index ed5b54c53c595dfb6409bf18273715b3efea269e..90c1962d33c9aa4c0497d39604013d17e1283ee3 100644 (file)
@@ -12,7 +12,7 @@
 <div class="crm-block crm-form-block crm-contact-type-form-block">
 {if $action eq 8}
   <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
         {ts}WARNING: {ts}This action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}{/ts}
     </div>
 {else}
index bf114f4f699dbbeda7466a3016054b1c1d5ca0dc..6b9345faa6e08a64f4ecaa8d50b4af893e498e1d 100644 (file)
 <div class="crm-block crm-form-block crm-admin-optionvalue-form-block">
    {if $action eq 8}
       <div class="messages status no-popup">
-          <div class="icon inform-icon"></div>
-          {ts}WARNING: Uninstalling this extension might result in the loss of all records which use the extension.{/ts} {ts}This may mean the loss of a substantial amount of data, and the action cannot be undone. Please review the extension information below before you make final decision.{/ts} {ts}Do you want to continue?{/ts}
+        {icon icon="fa-info-circle"}{/icon}
+        {ts}WARNING: Uninstalling this extension might result in the loss of all records which use the extension.{/ts} {ts}This may mean the loss of a substantial amount of data, and the action cannot be undone. Please review the extension information below before you make final decision.{/ts} {ts}Do you want to continue?{/ts}
       </div>
    {/if}
    {if $action eq 1}
-      <div class="messages status no-popup">
-          <div class="icon inform-icon"></div>
-          {ts}Installing this extension will provide you with new functionality. Please make sure that the extension you're installing comes from a trusted source.{/ts} {ts}Do you want to continue?{/ts}
+     <div class="messages status no-popup">
+        {icon icon="fa-info-circle"}{/icon}
+        {ts}Installing this extension will provide you with new functionality. Please make sure that the extension you're installing comes from a trusted source.{/ts} {ts}Do you want to continue?{/ts}
       </div>
    {/if}
    {if $action eq 2}
-      <div class="messages status no-popup">
-          <div class="icon inform-icon"></div>
-          {ts}Downloading this extension will provide you with new functionality. Please make sure that the extension you're installing or upgrading comes from a trusted source.{/ts} {ts}Do you want to continue?{/ts}
+     <div class="messages status no-popup">
+        {icon icon="fa-info-circle"}{/icon}
+        {ts}Downloading this extension will provide you with new functionality. Please make sure that the extension you're installing or upgrading comes from a trusted source.{/ts} {ts}Do you want to continue?{/ts}
       </div>
    {/if}
    {if $action eq 8 or $action eq 1 or $action eq 2}
index 0fb95d4655da5cd1081b3a9733f16f1fcde2ec15..a4b78dda1d5fb5995d09160cceadfe745f0abc67 100644 (file)
 
 {if $action eq 8}
   <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
         {ts}WARNING: Deleting this Scheduled Job will cause some important site functionality to stop working.{/ts} {ts}Do you want to continue?{/ts}
   </div>
 {elseif $action eq 4}
   <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
         {ts 1=$jobName}Are you sure you would like to execute %1 job?{/ts}
   </div>
 {else}
index c370eabac61061901a980c65dfaf7f4eeb290791..d5bcc2a96b98548ecad14ee5f98e47205d3cf984 100644 (file)
 <div class="crm-block crm-form-block crm-labelFormat-form-block">
   {if $action eq 8}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
       {ts 1=$formatName}WARNING: You are about to delete the Label Format titled <strong>%1</strong>.{/ts} {ts}Do you want to continue?{/ts}
     </div>
   {elseif $action eq 16384}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
       {ts 1=$formatName}Are you sure you would like to make a copy of the Label Format titled <strong>%1</strong>?{/ts}
     </div>
   {else}
index 9e11f776654b294c573568ed96f8d587cae3e585..26895130804f0129a6b5fb05e34ce1b328cc37d3 100644 (file)
@@ -12,7 +12,7 @@
 <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
 {if $action eq 8}
   <div class="messages status no-popup">
-     <div class="icon inform-icon"></div>
+     {icon icon="fa-info-circle"}{/icon}
         {ts}WARNING: Deleting this option will result in the loss of all location type records which use the option.{/ts} {ts}This may mean the loss of a substantial amount of data, and the action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
       </div>
 {else}
index ee8987a22bafcc320e9846e06b026a86c2b6c956..361ffe09e187932ba91ed2b4adee24be4970f7a0 100644 (file)
@@ -12,7 +12,7 @@
 <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
 {if $action eq 8}
   <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
   {ts}WARNING: Deleting this option will result in the loss of mail settings data.{/ts} {ts}Do you want to continue?{/ts}
   </div>
     <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
index af99fa96a286833095c77cd94921381e4f6ba660..b943bfd881d81b5f8ca4ad8323906b4ca97003f3 100644 (file)
@@ -27,7 +27,7 @@
       </table>
     {else}
         <div class="messages status no-popup">
-            <div class="icon inform-icon"></div> &nbsp;
+            {icon icon="fa-info-circle"}{/icon}
             {ts 1=$mappingName}WARNING: Are you sure you want to delete mapping '<b>%1</b>'?{/ts} {ts}This action cannot be undone.{/ts}
         </div>
         <br />
index 28430b69e21c87b8445798cfd35dea1f2bcde8c6..537e567516e9712620e7fb1d0b43a12d2d79e72e 100644 (file)
@@ -22,7 +22,7 @@
 <div class="form-item" id="message_templates">
 {if $action eq 8}
    <div class="messages status no-popup">
-       <div class="icon inform-icon"></div>
+       {icon icon="fa-info-circle"}{/icon}
        {ts 1=$msg_title|escape}Do you want to delete the message template '%1'?{/ts}
    </div>
 {else}
index 60715a5e959061d758d8bded0fa4c6826c6d943f..13f6ddee5bef07efc42a76ed8a8210bc6ce9c29b 100644 (file)
@@ -12,7 +12,7 @@
   <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
    {if $action eq 8}
       <div class="messages status no-popup">
-          <div class="icon inform-icon"></div>
+          {icon icon="fa-info-circle"}{/icon}
           {ts}WARNING: Deleting this option gruop will result in the loss of all records which use the option.{/ts} {ts}This may mean the loss of a substantial amount of data, and the action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
       </div>
      {else}
index 2a566c9b653ada3c07fbfc7953d4d1af84b3e8e0..fa435bd63eaaf71844717e17d47193b9ac99754a 100644 (file)
@@ -12,7 +12,7 @@
 <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
   {if $action eq 8}
       <div class="messages status no-popup">
-        <div class="icon inform-icon"></div>
+        {icon icon="fa-info-circle"}{/icon}
              {ts 1=$gLabel}WARNING: Deleting this option will result in the loss of all %1 related records which use the option.{/ts} {ts}This may mean the loss of a substantial amount of data, and the action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
       </div>
     {else}
index a6c81f9b0d0b4dfbbcd40c0d5fbb5653ec93de91..6b159db7b2eddd562a9b8997bedb7080512ec326 100644 (file)
@@ -15,7 +15,7 @@
    <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
     {if $action eq 8}
       <div class="messages status no-popup">
-       <div class="icon inform-icon"></div>
+       {icon icon="fa-info-circle"}{/icon}
              {ts}WARNING: Deleting this Participant Status will remove all of its settings.{/ts} {ts}Do you want to continue?{/ts}
        </div>
       <div>{include file="CRM/common/formButtons.tpl"}
index 016fd7d846cf910121c819d0623cfa4e523e686a..67464d00e998a9b788325f1e042c2689ca1813c1 100644 (file)
@@ -14,7 +14,7 @@
 
 {if $action eq 8}
   <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
     {$deleteMessage|escape}
   </div>
 {else}
index ccb4a69705501f947ec4b3d23048885060dc9105..3807b2e9b21a1b404504ca1d1e02d015049aa446 100644 (file)
@@ -13,7 +13,7 @@
  <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
 {if $action eq 8}
   <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
       {ts}Do you want to continue?{/ts}
   </div>
 {else}
index 623c0252549c56621ec24049aa18da099bd1afe4..7b6386d5d1756c0f34967c5a97a0bb3ecf4d4571 100644 (file)
@@ -30,7 +30,7 @@
 
 {if $action eq 8}
   <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
         {ts 1=$formatName}WARNING: You are about to delete the PDF Page Format titled <strong>%1</strong>.{/ts}<p>{ts}This will remove the format from all Message Templates that use it. Do you want to continue?{/ts}</p>
   </div>
 {else}
index 049a5ebf9975f78a4a4fe002de5724784583f32b..44ff0ba7aabb548929087fe8bd7763ed6f52833f 100644 (file)
       <td>
         {$form.editor_id.html}
         &nbsp;
-        <span class="crm-button crm-icon-button" style="display:inline-block;vertical-align:middle;float:none!important;">
-          <i class="crm-i fa-wrench" style="margin: 0 -18px 0 2px;" aria-hidden="true"></i>
+        <span class="crm-button" style="display:inline-block;vertical-align:middle;float:none!important;">
+          <i class="crm-i fa-wrench" aria-hidden="true"></i>
           {$form.ckeditor_config.html}
         </span>
       </td>
index 0807cfffd2a4bd316ef572405b55a16ab451b656..b8bb250a0f46aeb146da0fbccb7bd6a3452c6c3a 100644 (file)
@@ -13,7 +13,7 @@
 
 {if $action eq 8}
   <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
         {ts 1=$reminderName}WARNING: You are about to delete the Reminder titled <strong>%1</strong>.{/ts} {ts}Do you want to continue?{/ts}
   </div>
 {else}
index 1e1b8eb497da1501bbc2e14e17dc516a28516f9e..9c127fcb6fca890238e62db6f5eae51953bad866 100644 (file)
         </table>
       </div>
       <div class="crm-submit-buttons">
-        <span class="crm-button crm-i-button">
-          <i class="crm-i fa-bolt" aria-hidden="true"></i><input type="submit" value="{ts}Execute{/ts}" class="crm-form-submit" accesskey="S" title="{ts}Execute API call and display results{/ts}"/>
+        <span class="crm-button">
+          <i class="crm-i fa-bolt" aria-hidden="true"></i> <input type="submit" value="{ts}Execute{/ts}" class="crm-form-submit" accesskey="S" title="{ts}Execute API call and display results{/ts}"/>
         </span>
       </div>
 
index 14af566be27a39197e590abce48a285869c94c5e..ad179df5ab7afbbfb83d2a7fbf01d69c61e41fe7 100644 (file)
     </div>
 
     <div class="crm-submit-buttons">
-      <span class="crm-button crm-i-button">
+      <span class="crm-button">
         <i class="crm-i fa-wrench" aria-hidden="true"></i> <input type="submit" value="{ts}Save{/ts}" name="save" class="crm-form-submit" accesskey="S"/>
       </span>
-      <span class="crm-button crm-i-button">
+      <span class="crm-button">
         <i class="crm-i fa-times" aria-hidden="true"></i> <input type="submit" value="{ts}Revert to Default{/ts}" name="revert" class="crm-form-submit" onclick="return confirm('{$revertConfirm}');"/>
       </span>
     </div>
index 72d50d871f44896f38635c926d41fe82148f615b..b7a091b84706773bcbfc13dadb00be9a37e57095 100644 (file)
@@ -56,7 +56,7 @@
 
 {else}
     <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
     {capture assign=crmURL}{crmURL p='civicrm/event/add' q="action=add&is_template=1&reset=1"}{/capture}
         {ts 1=$crmURL}There are no Event Templates present. You can <a href='%1'>add one</a>.{/ts}
     </div>
index 3e025ac6a39f3fee5be02985dac82542566e15c9..04df4239eb70290014817202e78249079a68d000 100644 (file)
@@ -41,7 +41,7 @@ Depends: CRM/common/enableDisableApi.tpl and CRM/common/jsortable.tpl
   </div>
 {else}
   <div class="messages status no-popup">
-       <div class="icon inform-icon"></div>
+       {icon icon="fa-info-circle"}{/icon}
       {ts}There are no extensions to display. Please click "Refresh" to update information about available extensions.{/ts}
   </div>
 {/if}
index 1afe59b4f25045ea44c5617c8c4ed2960193eb81..c400f940b5d3f6a3e47d918714d53116e092ee66 100644 (file)
@@ -1,7 +1,7 @@
 <div class="crm-content-block crm-block">
   {foreach from=$extAddNewReqs item=req}
   <div class="messages status no-popup">
-       <div class="icon inform-icon"></div>
+       {icon icon="fa-info-circle"}{/icon}
        {$req.title}<br/>
        {$req.message}
   </div>
index e23977a984ecee21407fb4235e106a3c246d1482..88875c8573ee805c7b93d12fcea959cd6bc1fdd7 100644 (file)
@@ -45,7 +45,7 @@ Depends: CRM/common/enableDisableApi.tpl and CRM/common/jsortable.tpl
   </div>
 {else}
   <div class="messages status no-popup">
-       <div class="icon inform-icon"></div>
+       {icon icon="fa-info-circle"}{/icon}
       {ts 1="https://civicrm.org/extensions"}There are no extensions to display. Click the "Add New" tab to browse and install extensions posted on the <a href="%1">public CiviCRM Extensions Directory</a>. If you have downloaded extensions manually and don't see them here, try clicking the "Refresh" button.{/ts}
   </div>
 {/if}
index cb2d310b7c79c87a85b3a02fb4b322bac321a9bd..2738a86b94f33031bdb68587b7a753853cd605f6 100644 (file)
@@ -63,7 +63,7 @@
 </div>
 {elseif $action ne 1}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
         {ts}There are no jobs configured.{/ts}
      </div>
      <div class="action-link">
index 12b1b687b778d8174d5a7df13a4bf8b775fa4a28..367b0f5b1b113bd9d63029dcd56bc8dcb12cd4da 100644 (file)
@@ -49,7 +49,7 @@
   </div>
 {elseif $action ne 1}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>&nbsp;
+      {icon icon="fa-info-circle"}{/icon}
       {if $jobId}
         {ts}This scheduled job does not have any log entries.{/ts}
       {else}
index d2dd488eea672277a83b3552d3aff4dbce9deab2..e2ddf676bda4a38a86b589499821f5a5c982302a 100644 (file)
@@ -68,7 +68,7 @@
     </div>
   {else}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
       {capture assign=crmURL}{crmURL p='civicrm/admin/labelFormats' q="action=add&reset=1"}{/capture}
       {ts 1=$crmURL}There are no Label Formats configured. You can<a href='%1'>add one</a>.{/ts}
     </div>
index 2d704fdd963e7ea6b05c3d55b62f3366183821a6..b60355dede5c249e9e019fda75ca156a4cd1332b 100644 (file)
 
             {if empty( $template_row) }
                 <div class="messages status no-popup">
-                    <div class="icon inform-icon"></div>&nbsp;
+                    {icon icon="fa-info-circle"}{/icon}
                     {ts 1=$crmURL}There are no User-driven Message Templates entered. You can <a href='%1'>add one</a>.{/ts}
                 </div>
             {/if}
index ba6d55da20f0a335cea327f70853104b13596bc2..2323dffa9c2d1cde2b50d9fd88425b18bf89d891 100644 (file)
@@ -58,7 +58,7 @@
 </div>
 {elseif $action ne 1}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
         {ts}There are no Payment Processors entered.{/ts}
      </div>
      <div class="action-link">
index 1b419c5752bdd62eabb55d024a971e9ac2eb8849..063a160ff1d127689e289a86e95bc1d273607fc9 100644 (file)
@@ -60,7 +60,7 @@
     </div>
 {else}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
       {ts}None found.{/ts}
     </div>
 {/if}
index b5c9506544026c8e68ced7975cdf8efd08f8d988..0e004c2c88a9b8745597a8c4dd913670ecee56bb 100644 (file)
@@ -29,7 +29,7 @@
     </div>
   {else}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
       {ts}None found.{/ts}
     </div>
   {/if}
index 3aeda9184fc8fece5461cd7729b77bcab7ca6a32..00805e2e238157c8b109d83ed7fc94b28e12137b 100644 (file)
@@ -13,7 +13,7 @@
   <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
   {if $action eq 8}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
       {ts}This may mean the loss of a substantial amount of data, and the action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
     </div>
   {else}
index 56e8d5bd9dd5f15987d55859417aa356fc1cb52d..df8b0720894ea63a1079e846e8bfba3c000e2d3a 100644 (file)
@@ -19,7 +19,7 @@
 <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
 {if $action eq 8}
   <div class="messages status no-popup">
-     <div class="icon inform-icon"></div>
+     {icon icon="fa-info-circle"}{/icon}
         {ts}WARNING: Deleting this batch will result in the loss of all data entered for the batch.{/ts} {ts}This may mean the loss of a substantial amount of data, and the action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
       </div>
 {else}
index ba17c99e82d9d8a762011cbedf29f67716c05434..a56b9df3b71cce2bc1052a2b7612a32605173149 100644 (file)
@@ -14,7 +14,7 @@
   <table class="form-layout">
     <tr>
       <td colspan="2">
-        <div class="status"><div class="icon inform-icon"></div>&nbsp;{ts}Are you sure you want to delete this Campaign?{/ts}</div>
+        <div class="status">{icon icon="fa-info-circle"}{/icon}{ts}Are you sure you want to delete this Campaign?{/ts}</div>
       </td>
     </tr>
   </table>
index daa157e60d6be4ea5bc5b417928110f6d8f313c4..c11c028724167c8742ee29bda33d27d555b6d373 100644 (file)
@@ -10,7 +10,7 @@
 
 {if $errorMessages}
   <div class="messages status crm-error no-popup">
-     <div class="icon inform-icon"></div>
+     {icon icon="fa-info-circle"}{/icon}
         <ul>
           {foreach from=$errorMessages item=errorMsg}
             <li>{ts}{$errorMsg}{/ts}</li>
index 2220c9d1f90e22d0dbf72e3a09cac9265be71239..8b60e03238d63fa662cdb989b3e5d95717addb2b 100644 (file)
@@ -15,7 +15,7 @@
       <tr>
         <td colspan="2">
           <div class="status">
-            <div class="icon inform-icon"></div>
+            {icon icon="fa-info-circle"}{/icon}
             &nbsp;{ts}Are you sure you want to delete this Petition?{/ts}</div>
         </td>
       </tr>
index ec68d2770f9ab8ebe5d9172a6f8d5a8b5947f63f..f9fc2a79d46e75486e4c4d393c987cf8d5e543ee 100644 (file)
@@ -10,7 +10,7 @@
 
 {if !$hasCampaigns}
   <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
     &nbsp;
     {ts}None found.{/ts}
   </div>
index 0b2ef45f212c5faec6f7872eabcd7467bd432fa9..bfeb44999d3b46c066594b02a12be90754abbf22 100644 (file)
@@ -9,7 +9,7 @@
 *}
 {* No matches for submitted search request. *}
 <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
         {if $qill}{ts}No matches found for:{/ts}
             {include file="CRM/common/displaySearchCriteria.tpl"}
         {else}
index 35414668910eb632810b12329866e5d553edae60..afb84dde628a2237a9bec38de489e8727ef39d22 100644 (file)
@@ -10,7 +10,7 @@
 
 {if !$hasPetitions}
     <div class="messages status no-popup">
-        <div class="icon inform-icon"></div> &nbsp;
+        {icon icon="fa-info-circle"}{/icon}
         {ts}None found.{/ts}
     </div>
 
index 09a53a4ecea0fb293d4327f6d1ba3b51a0dff730..324f403a040cc20e491dc5ce219e7efa935ef2d7 100644 (file)
@@ -10,7 +10,7 @@
 
 {if !$hasSurveys}
     <div class="messages status no-popup">
-        <div class="icon inform-icon"></div> &nbsp;
+        {icon icon="fa-info-circle"}{/icon}
         {ts}None found.{/ts}
     </div>
 
index 1510b7bb4d6c4f98d302bcf5c794be7d1d8216bb..9c879e40983cbcec14b6405eb3b5ef8519466882 100644 (file)
@@ -11,7 +11,7 @@
   <table class="form-layout">
     <tr>
       <td colspan="2">
-        <div class="status"><div class="icon inform-icon"></div>&nbsp;{ts 1=$surveyTitle}Are you sure you want to delete the %1 survey?{/ts}</div>
+        <div class="status">{icon icon="fa-info-circle"}{/icon}{ts 1=$surveyTitle}Are you sure you want to delete the %1 survey?{/ts}</div>
       </td>
     </tr>
   </table>
index 9c927d7b4cc295242060c07da56debdf731fc616..2987636b71467589ec7c8c2c009494a67db313d6 100644 (file)
@@ -9,7 +9,7 @@
 *}
 {if $votingTab and $errorMessages}
   <div class='messages status'>
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
     <ul>
       {foreach from=$errorMessages item=errorMsg}
         <li>{ts}{$errorMsg}{/ts}</li>
index fd17756a31a0812f8b253a6076481b960fa82545..9c7023da1e96065f419dc256225c0844ab60ca1d 100644 (file)
@@ -21,7 +21,7 @@
 
 {else}
    <div class="messages status no-popup">
-     <div class="icon inform-icon"/>
+     {icon icon="fa-info-circle"}{/icon}
         {ts}There are no records selected for Print.{/ts}
    </div>
 {/if}
index cd992494304b95d29e5795b4ec0ac5985c7bac88..618af12e3fdbd21a414302eb30d49ca5e7912175 100644 (file)
@@ -16,7 +16,7 @@
   <tr class="crm-campaign-task-release-form-block-surveytitle">
     <td colspan=2>
       <div class="status">
-        <div class="icon inform-icon"></div>&nbsp;{ts 1=$surveyTitle}Do you want to release respondents for '%1' ?{/ts}
+        {icon icon="fa-info-circle"}{/icon}{ts 1=$surveyTitle}Do you want to release respondents for '%1' ?{/ts}
       </div>
     </td>
   </tr>
index a4ccaf412ea1a87671e22ba2c827faf57a3826ef..38fe35ac7e2b6c375cf954a1595a46df2e3ef6b5 100644 (file)
@@ -16,7 +16,7 @@
   <tr class="crm-campaign-task-reserve-form-block-surveytitle">
     <td colspan=2>
       <div class="status">
-        <div class="icon inform-icon"></div>&nbsp;{ts 1=$surveyTitle}Do you want to reserve respondents for '%1' ?{/ts}
+        {icon icon="fa-info-circle"}{/icon}{ts 1=$surveyTitle}Do you want to reserve respondents for '%1' ?{/ts}
       </div>
     </td>
   </tr>
index 595c8582e74ca29c6a3c38d6b8b62c2b0b5fb006..160ae236ed7e7144a98d205fcc43b342010e37d0 100644 (file)
@@ -50,7 +50,7 @@
 
 {else}
   <div class="status">
-    <div class="icon inform-icon"></div>&nbsp;{ts}None found.{/ts}
+    {icon icon="fa-info-circle"}{/icon}{ts}None found.{/ts}
   </div>
 {/if}
 <div class="action-link">
index b207cf1d0354a53e788ef2addc55e0a066caec91..193b0aa4ff46260b0fa5f15f3e5e347de31c8167 100644 (file)
@@ -8,7 +8,7 @@
  +--------------------------------------------------------------------+
 *}
 <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>&nbsp;
+    {icon icon="fa-info-circle"}{/icon}
     {if $success}
         {ts 1=$display_name 2=$email}<strong>%1 - your email address '%2' has been successfully verified.</strong>{/ts}
     {else}
index 6f1308bc10618615fc56e2baeff81bace0dba055..c7ac2f45889af7f8ec5c776b3a3d834d2a2d9d73 100644 (file)
@@ -47,8 +47,8 @@
 </div>
 {else}
     <div class="messages status no-popup">
-         <div class="icon inform-icon"> &nbsp;
-         {ts p=$addSurveyType.0 q=$addSurveyType.1}There are no survey types entered. You can <a href='%1'>add one</a>.{/ts}</div>
+      {icon icon="fa-info-circle"}{/icon}
+      {ts p=$addSurveyType.0 q=$addSurveyType.1}There are no survey types entered. You can <a href='%1'>add one</a>.{/ts}
     </div>
 {/if}
 {/if}
index ff305b93c9838220ea9f71c8319f835f02963ed8..b4a4a13db76d4036a31439804cc28d197f3dd6fc 100644 (file)
@@ -33,7 +33,7 @@
 
 {else}
  <div class="messages status no-popup">
-     <div class="icon inform-icon"></div>
+     {icon icon="fa-info-circle"}{/icon}
      {ts}You are not authorized to access this page.{/ts}
  </div>
 {/if}
index d96b5cb26b7fd7a514acee464d8eb1570b66a554..2edb838293da536e1f3bc278184d46f57f0ac272 100644 (file)
@@ -20,7 +20,7 @@
 <h3>{if $action eq 8}{ts}Delete Case{/ts}{elseif $action eq 32768}{ts}Restore Case{/ts}{/if}</h3>
 {if $action eq 8 or $action eq 32768 }
       <div class="messages status no-popup">
-        <div class="icon inform-icon"></div>
+        {icon icon="fa-info-circle"}{/icon}
           {if $action eq 8}
             {ts}Click Delete to move this case and all associated activities to the Trash.{/ts}
           {else}
index d1108cc1a4a9468313072a0265eea630711d2831..fea5368eb1b0dccea664b555bb75b13197257fb1 100644 (file)
@@ -10,7 +10,7 @@
 {* template for assigning the current case to another client*}
 <div class="crm-block crm-form-block crm-case-editclient-form-block">
   <div class="messages status no-popup">
-    <div class="icon inform-icon"></div> {ts 1=$currentClientName}This is case is currently assigned to %1.{/ts}
+    {icon icon="fa-info-circle"}{/icon} {ts 1=$currentClientName}This is case is currently assigned to %1.{/ts}
   </div>
   <div class="crm-form-block">
     <table class="form-layout-compressed">
index 05bfa282cea5fbb86bcee54ba249f393cd906ad7..f3924aa8797ccc789dbb8966be5fd17c006c4614 100644 (file)
@@ -9,7 +9,7 @@
 *}
 {* No matches for submitted search request. *}
 <div class="messages status no-popup">
-  <div class="icon inform-icon"></div>  &nbsp;
+  {icon icon="fa-info-circle"}{/icon}  &nbsp;
         {if $qill}{ts}No matches found for:{/ts}
             {include file="CRM/common/displaySearchCriteria.tpl"}
         {else}
index d94f86eb03cd384ab7ae7019821f6ec55652ce64..e24d21d749dc14df00c04a377876b17a5e9c5efb 100644 (file)
@@ -9,7 +9,7 @@
 *}
 {* Confirmation of contribution deletes  *}
 <div class="messages status no-popup">
-  <div class="icon inform-icon"></div>
+  {icon icon="fa-info-circle"}{/icon}
         &nbsp;{ts}Are you sure you want to delete the selected cases? This will move the case(s) and all associated activities to the Trash.{/ts}<br/>
         <p>{include file="CRM/Case/Form/Task.tpl"}</p>
 
index 31b56ebd7d6b01cea813d0c07ea83d4a429caafc..e15d076c6fe012b8a51ce977342a1f2614e935c9 100644 (file)
@@ -46,7 +46,7 @@
 
 {else}
    <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
         {ts}There are no records selected for Print.{/ts}
     </div>
 {/if}
index 88f3f554564061c2e7153f09cc7f7d79c385c3e6..790eb360dd3c81937d8c3e4dde948fb09277a693 100644 (file)
@@ -9,7 +9,7 @@
 *}
 {* Confirmation of contribution deletes  *}
 <div class="messages status no-popup">
-  <div class="icon inform-icon"></div>
+  {icon icon="fa-info-circle"}{/icon}
         &nbsp;{ts}Are you sure you want to restore the selected cases? This operation will retrieve the case(s) and all associated activities from Trash.{/ts}</p>
         <p>{include file="CRM/Case/Form/Task.tpl"}</p>
   </div>
index b146b79927ef0242e5680013be49ce359c579068..cff2cc5fb09855f0cf2ec5a7d47add753452e0df 100644 (file)
@@ -30,7 +30,7 @@
 
 {else}
    <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
           {ts}There are no records selected.{/ts}
       </div>
 {/if}
index 762ca73196e3d3ae44cca3c1a6ea579b57d3db0f..b2c69e68b767d314e3e4609ae71a5d85889e90a2 100644 (file)
@@ -12,7 +12,7 @@
 {capture assign=docLink}{docURL page="user/case-management/set-up" text="CiviCase Setup documentation"}{/capture}
 
 <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>&nbsp;
+      {icon icon="fa-info-circle"}{/icon}
       <strong>{ts}You need to setup and load Case and Activity configuration files before you can begin using the CiviCase component.{/ts}</strong>
       {ts 1=$docLink}Refer to the %1 to learn about this process.{/ts}
 </div>
index 047fd3dc379b92a4b5e4a276e6d63526f5c8ea56..66ec5e72b0a7fdbbf534e8a4d299d7e50332c660 100644 (file)
@@ -12,7 +12,7 @@
 
 {elseif $redirectToCaseAdmin}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>&nbsp;
+      {icon icon="fa-info-circle"}{/icon}
          <strong>{ts}Oops, It looks like there are no active case types.{/ts}</strong>
            {if call_user_func(array('CRM_Core_Permission','check'), ' administer CiviCase')}
              {capture assign=adminCaseTypeURL}{crmURL p='civicrm/a/#/caseType'}
@@ -52,7 +52,7 @@
           {include file="CRM/Case/Form/Selector.tpl"}
     {else}
        <div class="messages status no-popup">
-          <div class="icon inform-icon"></div>
+          {icon icon="fa-info-circle"}{/icon}
             {ts}There are no case records for this contact.{/ts}
           </div>
     {/if}
index 0181f55f956f7b38638a57a67e82555dcb03cf07..f83b4cb7bfb7a54a4416551e81a7c9b82b595e1e 100644 (file)
@@ -23,7 +23,7 @@
   {if $blockId gt 1}<fieldset><legend>{ts}Supplemental Address{/ts}</legend>{/if}
   <table class="form-layout-compressed crm-edit-address-form">
      {if $masterAddress.$blockId gt 0 }
-        <tr><td><div class="message status"><div class="icon inform-icon"></div>&nbsp; {ts 1=$masterAddress.$blockId}This address is shared with %1 contact record(s). Modifying this address will automatically update the shared address for these contacts.{/ts}</div></td></tr>
+        <tr><td><div class="message status">{icon icon="fa-info-circle"}{/icon} {ts 1=$masterAddress.$blockId}This address is shared with %1 contact record(s). Modifying this address will automatically update the shared address for these contacts.{/ts}</div></td></tr>
      {/if}
 
    {if $className eq 'CRM_Contact_Form_Contact'}
index 6c2902a06bb1eee8f53c4d7b7b73229caa9b6d9c..dce608c1b8e501b951d3f09ece4b112cb996539b 100644 (file)
   </div>
 
   <div class="message status">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
     <strong>{ts}WARNING: The duplicate contact record WILL BE DELETED after the merge is complete.{/ts}</strong>
   </div>
 
   {if $user}
     <div class="message status">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
       <strong>{ts 1=$config->userFramework}WARNING: There are %1 user accounts associated with both the original and duplicate contacts. Ensure that the %1 user you want to retain is on the right - if necessary use the 'Flip between original and duplicate contacts.' option at top to swap the positions of the two records before doing the merge.
   The user record associated with the duplicate contact will not be deleted, but will be unlinked from the associated contact record (which will be deleted).
   You will need to manually delete that user (click on the link to open the %1 user account in new screen). You may need to give thought to how you handle any content or contents associated with that user.{/ts}</strong>
index 6a9308dbde9ceec2080357b0404879370e70094b..d27e0e76973a68cfde31b4fa1a29ff1e9836e979 100644 (file)
@@ -9,7 +9,7 @@
 *}
 {* Custom searches. Default template for NO MATCHES on submitted search request. *}
 <div class="messages status no-popup">
-  <div class="icon inform-icon"></div>&nbsp;
+  {icon icon="fa-info-circle"}{/icon}
   {if $qill}
     {ts}No matches found for:{/ts}
     {include file="CRM/common/displaySearchCriteria.tpl"}
index 6a7d8b516a80234db780089d3708ffa7d1fc7d83..51a3c91956d8b96f243496c06062b4865605cd98 100644 (file)
@@ -62,7 +62,7 @@
     {if !$table and $summary.addShowAllLink.Contact}
       <div class="crm-section full-text-view-all-section">
         <a href="{crmURL p='civicrm/contact/search/custom' q="csid=`$csID`&reset=1&force=1&table=Contact&text=$text"}"
-        title="{ts}View all results for contacts{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i>&nbsp;{ts}View all results for contacts{/ts}</a>
+        title="{ts}View all results for contacts{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i> {ts}View all results for contacts{/ts}</a>
       </div>{/if}
     {* note we using location="below" because we don't want to use rows per page for now. And therefore don't put location="bottom" for now. *}
     {if $table}{include file="CRM/common/pager.tpl" location="below"}{/if}
     {if !$table and $summary.addShowAllLink.Activity}
       <div class="crm-section full-text-view-all-section">
         <a href="{crmURL p='civicrm/contact/search/custom' q="csid=`$csID`&reset=1&force=1&table=Activity&text=$text"}"
-        title="{ts}View all results for activities{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i>&nbsp;{ts}View all results for activities{/ts}</a>
+        title="{ts}View all results for activities{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i> {ts}View all results for activities{/ts}</a>
       </div>
     {/if}
     {if $table}{include file="CRM/common/pager.tpl" location="below"}{/if}
     {if !$table and $summary.addShowAllLink.Case}
       <div class="crm-section full-text-view-all-section">
         <a href="{crmURL p='civicrm/contact/search/custom' q="csid=`$csID`&reset=1&force=1&table=Case&text=$text"}"
-        title="{ts}View all results for cases{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i>&nbsp;{ts}View all results for cases{/ts}</a>
+        title="{ts}View all results for cases{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i> {ts}View all results for cases{/ts}</a>
       </div>
     {/if}
     {if $table}{include file="CRM/common/pager.tpl" location="below"}{/if}
     {if !$table and $summary.addShowAllLink.Contribution}
       <div class="crm-section full-text-view-all-section">
         <a href="{crmURL p='civicrm/contact/search/custom' q="csid=`$csID`&reset=1&force=1&table=Contribution&text=$text"}"
-        title="{ts}View all results for contributions{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i>&nbsp;{ts}View all results for contributions{/ts}</a>
+        title="{ts}View all results for contributions{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i> {ts}View all results for contributions{/ts}</a>
       </div>
     {/if}
     {if $table}{include file="CRM/common/pager.tpl" location="below"}{/if}
     {if !$table and $summary.addShowAllLink.Participant}
       <div class="crm-section full-text-view-all-section"><a
         href="{crmURL p='civicrm/contact/search/custom' q="csid=`$csID`&reset=1&force=1&table=Participant&text=$text"}"
-        title="{ts}View all results for participants{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i>&nbsp;{ts}View all results for participants{/ts}</a>
+        title="{ts}View all results for participants{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i> {ts}View all results for participants{/ts}</a>
       </div>{/if}
     {if $table}{include file="CRM/common/pager.tpl" location="below"}{/if}
     {* END Actions/Results section *}
     {if !$table and $summary.addShowAllLink.Membership}
       <div class="crm-section full-text-view-all-section">
         <a href="{crmURL p='civicrm/contact/search/custom' q="csid=`$csID`&reset=1&force=1&table=Membership&text=$text"}"
-        title="{ts}View all results for memberships{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i>&nbsp;{ts}View all results for memberships{/ts}</a>
+        title="{ts}View all results for memberships{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i> {ts}View all results for memberships{/ts}</a>
       </div>
     {/if}
     {if $table}{include file="CRM/common/pager.tpl" location="below"}{/if}
   {if !$table and $summary.addShowAllLink.File}
   <div class="crm-section full-text-view-all-section">
     <a href="{crmURL p='civicrm/contact/search/custom' q="csid=`$csID`&reset=1&force=1&table=File&text=$text"}"
-          title="{ts}View all results for files{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i>&nbsp;{ts}View all results for files{/ts}</a>
+          title="{ts}View all results for files{/ts}"><i class="crm-i fa-chevron-right" aria-hidden="true"></i> {ts}View all results for files{/ts}</a>
   </div>{/if}
   {if $table}{include file="CRM/common/pager.tpl" location="below"}{/if}
 {* END Actions/Results section *}
index 87e236eb97f745f4342dbd8bff5202a2dbd3b96f..c880ac595279cc174e98e3c4747ce4a5dd5ba060 100644 (file)
@@ -9,7 +9,7 @@
 *}
 {* No matches for submitted search request or viewing an empty group. *}
 <div class="messages status no-popup">
-  <div class="icon inform-icon"></div>&nbsp;
+  {icon icon="fa-info-circle"}{/icon}
         {if $context EQ 'smog'}
             {capture assign=crmURL}{crmURL q="context=amtg&amtgID=`$group.id`&reset=1"}{/capture}{ts 1=$group.title 2=$crmURL}%1 has no contacts which match your search criteria. You can <a href='%2'>add contacts here.</a>{/ts}
         {else}
index b24a66566fbacf456980f6ef221cc2a7d32d9f56..436464f40e34b17c4c47b789a0244a533e3541b2 100644 (file)
@@ -10,7 +10,7 @@
 {* Confirmation of contact deletes  *}
 <div class="crm-block crm-form-block crm-contact-task-delete-form-block">
 <div class="messages status no-popup">
-  <div class="icon inform-icon"></div>&nbsp;
+  {icon icon="fa-info-circle"}{/icon}
       {if $restore}
     {ts}Are you sure you want to restore the selected contact(s)? The contact(s) and all related data will be fully restored.{/ts}
       {elseif $trash}
index bea1556df673eff06b24fb03abe23f8a3b6de73a..2808e89f3a02e49882c0812cdcb6b5d7c01f1bdf 100644 (file)
@@ -38,7 +38,7 @@
 </div>
 {else}
    <div class="messages status no-popup">
-  <div class="icon inform-icon"></div>
+  {icon icon="fa-info-circle"}{/icon}
        {ts}There are no records selected for Print.{/ts}
      </div>
 {/if}
index 6b2966928996de50d6d7cef81b9a7c38c2eb73ee..b91d92ce9f60ef8685cc8c5a46846fcf3b4edc34 100644 (file)
 
 {else}
    <div class="messages status no-popup">
-  <div class="icon inform-icon"></div>
+  {icon icon="fa-info-circle"}{/icon}
        {ts}There are no records selected for Print.{/ts}
   </div>
 {/if}
index 2b2534f8abb19423d6a13014213afdab1ba71f43..e2f019db575d167bd4991f8d450a2a71bdb6341c 100644 (file)
@@ -10,7 +10,7 @@
 <div class="crm-block crm-form-block crm-unhold-form-block">
 <div class="spacer"></div>
 <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
           <p>{ts}Are you sure you want to unhold email of selected contact(s)?.{/ts} {ts}This action cannot be undone.{/ts}</p>
       <p>{include file="CRM/Contact/Form/Task.tpl"}</p>
     </div>
index 1cc375c9d49f3dff8e9324f9d3785be2f4f03b8a..e1248deb55eb0a00fc19ff88132aa33312ced18c 100644 (file)
@@ -10,7 +10,7 @@
 <div class="section-shown">
   {if !$groupSmart AND !$groupParent}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
       &nbsp;{ts}This contact does not currently belong to any smart groups.{/ts}
     </div>
   {/if}
index 14a773024077f2ef9e586bec7ad6fdc333d53f76..5b8c5115776ef71135a80470174500b8fb20c11d 100644 (file)
@@ -9,7 +9,7 @@
 *}
 {* Confirmation of contact deletes  *}
 <div class="messages status no-popup">
-<div class="icon inform-icon"></div>
+{icon icon="fa-info-circle"}{/icon}
         <p>{ts  1=$displayName}Are you sure you want to delete the contact record and all related information for <strong>%1</strong>?{/ts}</p>
         <p>{ts}This action cannot be undone.{/ts}</p>
 </div>
index ba78dff8db0a9916b7f0d979d74fcc96e80b090a..bc3343b56c7c4e8eac599f0fae2bedfa419a04ee 100644 (file)
@@ -30,7 +30,7 @@
        </table>
      {else}
      <div class="messages status no-popup">
-     <div class="icon inform-icon"></div> &nbsp;
+     {icon icon="fa-info-circle"}{/icon}
       {ts}This contact does not belong to any groups.{/ts}
      </div>
      {/if}
index 77bfdf27bb1f017b93789e3752449a0401fc88c2..4e5162643a982b5cc45826068a7c210b145dde1c 100644 (file)
@@ -10,7 +10,7 @@
 <div class="view-content view-contact-groups">
   {if $groupCount eq 0}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
       &nbsp;{ts}This contact does not currently belong to any groups.{/ts}
     </div>
   {else}
index 3849b211956aa669d05f3a114b95645da549d7b5..11b21f7555341d8866b46bb5f76c666e9f2ab1fd 100644 (file)
@@ -27,7 +27,7 @@
        </table>
      {else}
      <div class="messages status no-popup">
-      <div class="icon inform-icon"></div> &nbsp;
+      {icon icon="fa-info-circle"}{/icon}
       {ts}None found.{/ts}
      </div>
      {/if}
index 6e8c11ab7f8a34cdee08f591558f9134341cff6d..8cdf82cfd7a035174b9f72992c6d9461d0432d4e 100644 (file)
 </div>
 {elseif ($action eq 16)}
    <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
       {ts}There are no Notes for this contact.{/ts}
    </div>
 {/if}
index 94d8cd08e700d9e56e0e806f0bbf7c5a315e2e71..7306c342a0b63f3123693cec32e2147b58153663 100644 (file)
@@ -16,7 +16,7 @@
     <div class="view-content">
         {if $groupCount eq 0 }
             <div class="messages status no-popup">
-                    <div class="icon inform-icon"></div>
+                    {icon icon="fa-info-circle"}{/icon}
                     {ts}You are not currently subscribed to any Groups.{/ts}
             </div>
         {/if}
index 95204a53968d6d1ccc201d87db1ed8115f41f225..004070019d2e8b5de18fd03f11db47d343f7f036 100644 (file)
@@ -13,7 +13,7 @@
 
    {if $action eq 8}
       <div class="messages status no-popup">
-        <div class="icon inform-icon"></div>
+        {icon icon="fa-info-circle"}{/icon}
           {ts}WARNING: If you delete this option, contributors will not be able to use this credit card type on your Online Contribution pages.{/ts} {ts}Do you want to continue?{/ts}
       </div>
      {else}
index 08a41ddfa144d94084910f592fd714860c4a1fc5..40049945e7227d721490a436e576f6b12ce649cc 100644 (file)
@@ -20,7 +20,7 @@
 
   {if !$email}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>&nbsp;{ts}You will not be able to send an automatic email receipt for this payment because there is no email address recorded for this contact. If you want a receipt to be sent when this payment is recorded, click Cancel and then click Edit from the Summary tab to add an email address before recording the payment.{/ts}
+      {icon icon="fa-info-circle"}{/icon}{ts}You will not be able to send an automatic email receipt for this payment because there is no email address recorded for this contact. If you want a receipt to be sent when this payment is recorded, click Cancel and then click Edit from the Summary tab to add an email address before recording the payment.{/ts}
     </div>
   {/if}
   {if $newCredit AND $contributionMode EQ null}
index c193513b621c196485a25791a05b835b89032e9b..d93037432aa57888bda2938715b00af2efce69a4 100644 (file)
@@ -10,7 +10,7 @@
 
 <div class="crm-block crm-form-block crm-auto-renew-membership-cancellation">
 <div class="help">
-  <div class="icon inform-icon"></div>&nbsp;
+  {icon icon="fa-info-circle"}{/icon}
   {$cancelRecurDetailText}
   {if $cancelRecurNotSupportedText}
     <div class="status-warning">{$cancelRecurNotSupportedText}</div>
index f3674420c14f564fe6499fb0f41158fb4cc5bab8..9ab874819b1f2142bb6439e31c633bd49f0ad8bb 100644 (file)
 
     {if !$email and $action neq 8 and $context neq 'standalone'}
       <div class="messages status no-popup">
-        <div class="icon inform-icon"></div>&nbsp;{ts}You will not be able to send an automatic email receipt for this contribution because there is no email address recorded for this contact. If you want a receipt to be sent when this contribution is recorded, click Cancel and then click Edit from the Summary tab to add an email address before recording the contribution.{/ts}
+        {icon icon="fa-info-circle"}{/icon}{ts}You will not be able to send an automatic email receipt for this contribution because there is no email address recorded for this contact. If you want a receipt to be sent when this contribution is recorded, click Cancel and then click Edit from the Summary tab to add an email address before recording the contribution.{/ts}
       </div>
     {/if}
 
     {if $action eq 8}
       <div class="messages status no-popup">
-        <div class="icon inform-icon"></div>
+        {icon icon="fa-info-circle"}{/icon}
         {ts}WARNING: Deleting this contribution will result in the loss of the associated financial transactions (if any).{/ts} {ts}Do you want to continue?{/ts}
       </div>
     {else}
index c56308b119893fa2025c2afe7e1f52130196d6aa..5e7e66e467e59e31e010d2f4ebd841a682f7fe97 100644 (file)
     </div>
   {/if}
 
+  {if call_user_func(array('CRM_Core_Permission','check'), 'administer CiviCRM') }
+    {capture assign="buttonTitle"}{ts}Configure Contribution Page{/ts}{/capture}
+    {crmButton target="_blank" p="civicrm/admin/contribute/settings" q="reset=1&action=update&id=`$contributionPageID`" title="$buttonTitle" icon="fa-wrench"}{ts}Configure{/ts}{/crmButton}
+    <div class='clear'></div>
+  {/if}
   {include file="CRM/common/TrackingFields.tpl"}
 
   <div class="crm-contribution-page-id-{$contributionPageID} crm-block crm-contribution-main-form-block">
index eb0b41ccc97389a59bef36f7712fd103dfda85a8..3d282628fa6e1072ab9e6ecbbb128a47b6fb8e65 100644 (file)
@@ -21,7 +21,7 @@
 
   {if $action eq 8}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
       {ts}Are you sure you want to remove this premium product from this Contribution page?{/ts}
     </div>
   {elseif $action eq 1024}
index 496907832785ef4cb81d591001c40476481ffa8a..8be7d88e7b2d33784fa4ab9692fb3a77a72c5d11 100644 (file)
             <tr id="minMaxFields" class="crm-contribution-form-block-minMaxFields"><td>&nbsp;</td><td>
                <table class="form-layout-compressed">
                 <tr class="crm-contribution-form-block-min_amount"><th scope="row" class="label">{$form.min_amount.label}</th>
-                <td>{$form.min_amount.html|crmMoney}</td></tr>
+                <td>{$form.min_amount.html}</td></tr>
                 <tr class="crm-contribution-form-block-max_amount"><th scope="row" class="label">{$form.max_amount.label}</th>
-                <td>{$form.max_amount.html|crmMoney}<br />
+                <td>{$form.max_amount.html}<br />
                 <span class="description">{ts 1=5|crmMoney}If you have chosen to <strong>Allow Other Amounts</strong>, you can use the fields above to control minimum and/or maximum acceptable values (e.g. don't allow contribution amounts less than %1).{/ts}</span></td></tr>
                </table>
             </td></tr>
                         <tr class="columnheader" ><th scope="column">{ts}Contribution Label{/ts}</th><th scope="column">{ts}Amount{/ts}</th><th scope="column">{ts}Default?{/ts}<br />{$form.default.0.html}</th></tr>
                         {section name=loop start=1 loop=11}
                             {assign var=idx value=$smarty.section.loop.index}
-                            <tr><td class="even-row">{$form.label.$idx.html}</td><td>{$form.value.$idx.html|crmMoney}</td><td class="even-row">{$form.default.$idx.html}</td></tr>
+                            <tr><td class="even-row">{$form.label.$idx.html}</td><td>{$form.value.$idx.html}</td><td class="even-row">{$form.default.$idx.html}</td></tr>
                         {/section}
                     </table>
               </fieldset>
index bffeb24bfaffe49e4074a4310cf03d6656887ac7..98544852fb0cca2747f23deab17bb667adbff758 100644 (file)
@@ -9,7 +9,7 @@
 *}
 {* this template is used for confirmation of delete for a group  *}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
           {if $relatedContributions}
            {ts 1=$title}You cannot delete this Contribution Page because it has already been used to submit a contribution or membership payment. It is recommended that your disable the page instead of deleting it, to preserve the integrity of your contribution records. If you do want to completely delete this contribution page, you first need to search for and delete all of the contribution transactions associated with this page in CiviContribute.{/ts}
           {else}
index 2f8eb100310c18730d1a6586fed2653094a59261..9ae6af80260c697be87ceb83ac07eda5bc8f9df9 100644 (file)
@@ -11,7 +11,7 @@
 <h3>{ts}Configure Widget{/ts}</h3>
 {if $showStatus}
 <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
     {ts}It looks like you may have posted and / or distributed the flash version of the Contribution widget. We won't be supporting the flash version in next release. You should try and get all sites using the flash widget to update to the improved HTML widget code below as soon as possible.{/ts}
 </div>
 {/if}
index 415206b4f3f1051f076eec8627c8154fc618992b..c688678b938ccf5211d6739ca794950337440290 100644 (file)
@@ -11,7 +11,7 @@
 <div class="crm-block crm-form-block crm-contribution-manage_premiums-form-block">
    {if $action eq 8}
       <div class="messages status no-popup">
-          <div class="icon inform-icon"></div>
+          {icon icon="fa-info-circle"}{/icon}
           {ts}Are you sure you want to delete this premium?{/ts} {ts}This action cannot be undone.{/ts} {ts}This will also remove the premium from any contribution pages that currently include it.{/ts}
       </div>
   {elseif $action eq 1024}
index 8ca432991eefa9a793d513c765029f1c4a79b9ee..9ebac095e2639c84e164af8db946e3ea66f9b1c3 100644 (file)
@@ -10,7 +10,7 @@
 {* this template is used for confirmation of delete for a group *}
 <fieldset><legend>{ts}Delete Campaign Page {/ts}</legend>
 <div class="messages status no-popup">
-   <div class="icon inform-icon"></div>
+   {icon icon="fa-info-circle"}{/icon}
   {ts 1=$title}Are you sure you want to delete Campaign Page '%1'?{/ts}<br />
   {ts}This action cannot be undone.{/ts}
 </div>
index 4b43f2b097189a7126126fdd197c22a6877f5650..113c9483c0a6d980e826c0475b32e9fbe3197afb 100644 (file)
@@ -13,7 +13,7 @@
   <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
    {if $action eq 8}
       <div class="messages status no-popup">
-           <div class="icon inform-icon"></div>
+           {icon icon="fa-info-circle"}{/icon}
           {ts}WARNING: Deleting this option will result in the loss of all contribution records which use this option.{/ts} {ts}This may mean the loss of a substantial amount of data, and the action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
       </div>
      {else}
index 8b8cea760be105559184d383c58d7a110f8b5bfd..8ce4069f415fa46b2711f282c157ffa968efe38f 100644 (file)
@@ -9,7 +9,7 @@
 *}
 {* No matches for submitted search request. *}
 <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>  &nbsp;
+    {icon icon="fa-info-circle"}{/icon}  &nbsp;
         {if $qill}{ts}No matches found for:{/ts}
             {include file="CRM/common/displaySearchCriteria.tpl"}
         {else}
index bd63906c08decb97e324bccc458e39ca0f44dc11..0b4dfc49aaf51560b857f3189fdf8f7c57e7a476 100644 (file)
@@ -9,7 +9,7 @@
 *}
 {* Confirmation of contribution deletes  *}
 <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
         <p>{ts}Are you sure you want to delete the selected contributions? This delete operation cannot be undone and will delete all transactions and activity associated with these contributions.{/ts}</p>
         <p>{include file="CRM/Contribute/Form/Task.tpl"}</p>
 </div>
index 7fb22b7d123ea75ad5f19dc9905d810e95caa36c..9f3dde88890e677c073220468e56780eb4634a16 100644 (file)
@@ -8,7 +8,7 @@
  +--------------------------------------------------------------------+
 *}
 <div class="messages status no-popup">
-  <div class="icon inform-icon"></div>
+  {icon icon="fa-info-circle"}{/icon}
   {include file="CRM/Contribute/Form/Task.tpl"}
 </div>
 {if $selectedOutput ne 'email'}
index eebec04694b3b2edc40588fc5c49568b7d6119d4..ca5b3e1228a0dc580eef5311464280d0850475af 100644 (file)
@@ -8,7 +8,7 @@
  +--------------------------------------------------------------------+
 *}
 <div class="messages status no-popup">
-  <div class="icon inform-icon"></div>
+  {icon icon="fa-info-circle"}{/icon}
       {include file="CRM/Contribute/Form/Task.tpl"}
 </div>
 <div class="help">
index b4c4deda2f20626a7e6a0be0d6b6ca74f9832632..6625f15eaa67a619a476b004ef361dc230228d96 100644 (file)
@@ -52,7 +52,7 @@
 
 {else}
    <div class="messages status no-popup">
-     <div class="icon inform-icon"/>
+     {icon icon="fa-info-circle"}{/icon}
         {ts}There are no records selected for Print.{/ts}
    </div>
 {/if}
index 2fa8f7d0ad3f1d94627bd417ef320696fa659101..a14a183b17747d6640f09e8ac445f48a06a5c7ee 100644 (file)
@@ -32,7 +32,7 @@
 
 {else}
    <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
     {ts}There are no records selected.{/ts}
    </div>
 {/if}
index 635c4890d754714b33b4f0cd98b697a7a999e0e6..9d16b90aeb7f2741d9e6b1c8932c838042a6ef8d 100644 (file)
@@ -8,50 +8,49 @@
  +--------------------------------------------------------------------+
 *}
 <div class="form-item crm-block crm-form-block crm-contribution-form-block">
-<div class="help">
-    {ts}Use this form to record received payments for 'pay later' online contributions, membership signups and event registrations. You can use the Transaction ID field to record account+check number, bank transfer identifier, or other unique payment identifier.{/ts}
-</div>
-<fieldset>
-    <legend>{ts}Update Contribution Status{/ts}</legend>
-     <table class="form-layout-compressed">
-     <tr class="crm-contribution-form-block-contribution_status_id"><td class="label">{$form.contribution_status_id.label}</td><td class="html-adjust">{$form.contribution_status_id.html}<br />
-            <span class="description">{ts}Assign the selected status to all contributions listed below.{/ts}</td></tr>
-       <tr class="crm-contribution-form-block-is_email_receipt"><td class="label">{$form.is_email_receipt.label}</td>
-         <td class="html-adjust">{$form.is_email_receipt.html}<br />
-           <span class="description">{ts}When checked CiviCRM will send an e-mail receipt to the donor. Leave unchecked when you don't want to send an e-mail.{/ts}
-         </td>
-       </tr>
-     </table>
-<table>
-<tr class="columnheader">
-    <th>{ts}Name{/ts}</th>
-    <th class="right">{ts}Amount{/ts}&nbsp;&nbsp;</th>
-    <th>{ts}Source{/ts}</th>
-    <th>{ts}Fee Amount{/ts}</th>
-    <th>{ts}Payment Method{/ts}</th>
-    <th>{ts}Check{/ts} #</th>
-    <th>{ts}Transaction ID{/ts}</th>
-    <th>{ts}Transaction Date{/ts}</th>
-</tr>
+  <h3>{ts}Record payments for contributions{/ts}</h3>
+  <div class="help">
+    <p>{ts}Use this form to record received payments for "pay later" online contributions, membership signups and event registrations. You can use the Transaction ID field to record account+check number, bank transfer identifier, or other unique payment identifier.{/ts}</p>
+    <p>{ts}The contribution status will be updated as appropriate.  To update contribution statuses directly, return to the search results and select "Update multiple contributions".{/ts}</p>
+  </div>
+
+  <table class="form-layout-compressed">
+    <tr class="crm-contribution-form-block-is_email_receipt">
+      <td class="label">{$form.is_email_receipt.label}</td>
+      <td class="html-adjust">{$form.is_email_receipt.html}<br />
+        <span class="description">{ts}When checked CiviCRM will send an e-mail receipt to the donor. Leave unchecked when you don't want to send an e-mail.{/ts}</span>
+      </td>
+    </tr>
+  </table>
+  <table>
+    <tr class="columnheader">
+      <th>{ts}Name{/ts}</th>
+      <th class="right">{ts}Amount{/ts}&nbsp;&nbsp;</th>
+      <th>{ts}Source{/ts}</th>
+      <th>{ts}Fee Amount{/ts}</th>
+      <th>{ts}Payment Method{/ts}</th>
+      <th>{ts}Check{/ts} #</th>
+      <th>{ts}Transaction ID{/ts}</th>
+      <th>{ts}Transaction Date{/ts}</th>
+    </tr>
 
-{foreach from=$rows item=row}
-<tr class="{cycle values="odd-row,even-row"}">
-    <td>{$row.display_name}</td>
-    <td class="right nowrap">{$row.amount|crmMoney}&nbsp;&nbsp;</td>
-    <td>{$row.source}</td>
-    {assign var="element_name" value="fee_amount_"|cat:$row.contribution_id}
-    <td>{$form.$element_name.html}</td>
-    {assign var="element_name" value="payment_instrument_id_"|cat:$row.contribution_id}
-    <td class="form-text four">{$form.$element_name.html}</td>
-    {assign var="element_name" value="check_number_"|cat:$row.contribution_id}
-    <td class="form-text four">{$form.$element_name.html|crmAddClass:four}</td>
-    {assign var="element_name" value="trxn_id_"|cat:$row.contribution_id}
-    <td>{$form.$element_name.html|crmAddClass:eight}</td>
-    {assign var="element_name" value="trxn_date_"|cat:$row.contribution_id}
-    <td>{$form.$element_name.html}</td>
-</tr>
-{/foreach}
-</table>
+    {foreach from=$rows item=row}
+    <tr class="{cycle values="odd-row,even-row"}">
+      <td>{$row.display_name}</td>
+      <td class="right nowrap">{$row.amount|crmMoney}&nbsp;&nbsp;</td>
+      <td>{$row.source}</td>
+      {assign var="element_name" value="fee_amount_"|cat:$row.contribution_id}
+      <td>{$form.$element_name.html}</td>
+      {assign var="element_name" value="payment_instrument_id_"|cat:$row.contribution_id}
+      <td class="form-text four">{$form.$element_name.html}</td>
+      {assign var="element_name" value="check_number_"|cat:$row.contribution_id}
+      <td class="form-text four">{$form.$element_name.html|crmAddClass:four}</td>
+      {assign var="element_name" value="trxn_id_"|cat:$row.contribution_id}
+      <td>{$form.$element_name.html|crmAddClass:eight}</td>
+      {assign var="element_name" value="trxn_date_"|cat:$row.contribution_id}
+      <td>{$form.$element_name.html}</td>
+    </tr>
+    {/foreach}
+  </table>
   <div class="crm-submit-buttons">{$form.buttons.html}</div>
-</fieldset>
 </div>
index 8c819d0f108807b5a507367bf6f92d49eb31dc56..72d13b28f657097772141073e89f490ab3d5390d 100644 (file)
@@ -8,7 +8,7 @@
  +--------------------------------------------------------------------+
 *}
 <div class="help">
-  <div class="icon inform-icon"></div>&nbsp;
+  {icon icon="fa-info-circle"}{/icon}
   {if $mode eq 'auto_renew'}
       {ts}Use this form to update the credit card and billing name and address used with the auto-renewal option for your {$membershipType} membership.{/ts}
   {else}
index a4665f8026cb79b6f82f65c670ce145e7ea74d11..f39728a087a2a14f2f3ae0398a016b6d9f2138ef 100644 (file)
@@ -99,7 +99,7 @@
       </div>
       {else}
       <div class="messages status no-popup">
-             <div class="icon inform-icon"></div> &nbsp;
+             {icon icon="fa-info-circle"}{/icon}
              {ts 1=$newPageURL}No contribution pages have been created yet. Click <a accesskey="N" href='%1'>here</a> to create a new contribution page.{/ts}
       </div>
         {/if}
index 16873b7b8359a1b22a46b997f1c05aa5593e09c4..8867ffe409e5252411cc57152c822281f549bb47 100644 (file)
@@ -36,7 +36,7 @@
   </div>
 {else}
   <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
     {ts}No contributions have been recorded for this recurring contribution.{/ts}
   </div>
 {/if}
index fd1b6befbdce88f6e367341505cf7885b9d8faa0..25103e624d3c19f593748c6cff1b573ae89cbdff 100644 (file)
@@ -49,7 +49,7 @@
 </div>
 {else}
     <div class="messages status no-popup">
-        <div class="icon inform-icon"></div>
+        {icon icon="fa-info-circle"}{/icon}
       {ts}None found.{/ts}
     </div>
 {/if}
index 919e854cb0eed4a0f4e521e62eaef04c5ee62fcd..43e62b4ebf042bf8d855259f950241e4de7a4291 100644 (file)
@@ -40,7 +40,7 @@
 </div>
 {else}
 <div class="messages status no-popup">
-  <div class="icon inform-icon"></div>
+  {icon icon="fa-info-circle"}{/icon}
   {ts}You do not have any active Personal Campaign pages.{/ts}
 </div>
 {/if}
index 3737acf5ae1650792317e466867776d82f7b51c2..5dd5aa91579ac900fe81be5a085fc269365f2abf 100644 (file)
   {if $showForm eq false}
     <div class="messages status no-popup">
       {if $products ne null }
-        <div class="icon inform-icon"></div>
+        {icon icon="fa-info-circle"}{/icon}
         {capture assign=crmURL}{crmURL p='civicrm/admin/contribute/addProductToPage' q="reset=1&action=update&id=$id"}{/capture}
         {ts 1=$crmURL}There are no premiums offered on this contribution page yet. You can <a href='%1'>add one</a>.{/ts}
       {else}
-        <div class="icon inform-icon"></div>
+        {icon icon="fa-info-circle"}{/icon}
         {ts 1=$managePremiumsURL}There are no active premiums for your site. You can <a href='%1'>create and/or enable premiums here</a>.{/ts}
       {/if}
     </div>
index 8e17896d6080b2fa6fa17adb6be6d99a82d94414..e6b2ce8d71b1b3a0ea94e134ecf369105f0eca11 100644 (file)
@@ -63,7 +63,7 @@
             {include file="CRM/Contribute/Form/Selector.tpl"}
           {else}
             <div class="messages status no-popup">
-              <div class="icon inform-icon"></div>
+              {icon icon="fa-info-circle"}{/icon}
               {ts}No contributions have been recorded from this contact.{/ts}
             </div>
           {/if}
index 29ae828479a8da79ab473e73a0af67d16471e652..0520ebc1a300c60db90d00034a93b8ffb92a9f4c 100644 (file)
@@ -71,7 +71,7 @@
         {/if}
     {else}
         <div class="messages status no-popup">
-            <div class="icon inform-icon"></div>
+            {icon icon="fa-info-circle"}{/icon}
             {ts}There are no contributions on record for you.{/ts}
         </div>
     {/if}
index a14bd7686c90a7889c9c2e5a512e7857ea6db409..903eb96bb3ea9a19edaefbeac0b3830d52a74eb5 100644 (file)
@@ -12,7 +12,7 @@
   <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
   {if $action eq 8}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
       {$deleteMessage|escape}
     </div>
   {else}
index d3ddb9aef6f859c74731956f650384d40af3eaff..e87067ea84472e86d4ecdc61b52161eab91c1548 100644 (file)
@@ -9,7 +9,7 @@
 *}
 <div class="crm-block crm-form-block crm-custom-field-form-block">
 <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
-    <div class='status'><div class="icon inform-icon"></div>
+    <div class='status'>{icon icon="fa-info-circle"}{/icon}
         &nbsp;{ts}Warning: This functionality is currently in beta stage. Consider backing up your database before using it. Click "Cancel" to return to the "edit custom field" form without making changes.{/ts}
     </div>
     <table class="form-layout">
index 60a3e2ee3158703c0d6eca9a89fce8f87d207114..fbb546d19a5a6d7e530a998ff9750f0991da8ff7 100644 (file)
@@ -10,7 +10,7 @@
 {* this template is used for confirmation of delete for a Fields  *}
 <div class="crm-block crm-form-block crm-custom-deletefield-form-block">
     <div class="messages status no-popup">
-         <div class="icon inform-icon"></div>
+         {icon icon="fa-info-circle"}{/icon}
             {ts 1=$title}WARNING: Deleting this custom field will result in the loss of all '%1' data. Any Profile form and listings field(s) linked with '%1' will also be deleted.{/ts} {ts}This action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
          </div>
  <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
index 7507bc1d55c9251f7e0d07b9093cd6daec15d083..9bd7c6fdb5026daf91a6444b10b38e646058bbdc 100644 (file)
@@ -11,7 +11,7 @@
 <fieldset><legend>{ts}Delete Attached File{/ts}</legend>
     <div class="status">
       <dl>
-        <dt><div class="icon inform-icon"></div></dt>
+        <dt>{icon icon="fa-info-circle"}{/icon}</dt>
         <dd>
           {ts}WARNING: Are you sure you want to delete the attached file?{/ts}
         </dd>
index e6f4831401ef363e8e13200d701e147ceb619223..cd77148e29b58b8cf431bc180470c3373faeb5c3 100644 (file)
@@ -14,7 +14,7 @@
    {include file="CRM/common/formButtons.tpl" location="top"}
 </div>
     <div class="messages status no-popup">
-           <div class="icon inform-icon"></div>
+           {icon icon="fa-info-circle"}{/icon}
           {ts 1=$title}WARNING: Deleting this custom field set will result in the loss of all '%1' data.{/ts} {ts}This action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
     </div>
 <div class="crm-submit-buttons">
index 5a1fb626aae5a7a5a76c4e35361e1bd289b65d82..f45cb95e8b42e121663b734ca2c34bb3de861661 100644 (file)
@@ -14,7 +14,7 @@
     {/if} {* $action ne view *}
     {if $action eq 8}
       <div class="messages status no-popup">
-          <div class="icon inform-icon"></div>
+          {icon icon="fa-info-circle"}{/icon}
           {ts}WARNING: Deleting this custom field option will result in the loss of all related data.{/ts} {ts}This action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
       </div>
     {else}
index 41b49ac784904ad6e6fca788dcbcc08ee15e53bc..2aec75a532bf5bb088d958ddcdb3b44fcfab7e32 100644 (file)
@@ -12,7 +12,7 @@
 {else}
   {if $reusedNames}
       <div class="message status">
-        <div class="icon inform-icon"></div> &nbsp; {ts 1=$reusedNames}These Multiple Choice Options are shared by the following custom fields: %1{/ts}
+        {icon icon="fa-info-circle"}{/icon} {ts 1=$reusedNames}These Multiple Choice Options are shared by the following custom fields: %1{/ts}
       </div>
   {/if}
 
index 16d33ff2dea2497459703acd1769ee86d48df5d0..be40890a773f602767492aa060b32652fd824901 100644 (file)
@@ -60,7 +60,7 @@
   {/foreach}
   {if !$feeds}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
       {ts}Sorry but we are not able to provide this at the moment.{/ts}
     </div>
   {/if}
index 4ef9efa2be2d425d5c543eab2004635823fa06a5..55030635957ad5a36211d0f687abe3d57a29944f 100644 (file)
@@ -13,7 +13,7 @@
     {include file="CRM/common/formButtons.tpl" location="top"}
 </div>
 <div class="messages status no-popup">
-   <div class="icon inform-icon"></div>
+   {icon icon="fa-info-circle"}{/icon}
    <div>
        {if $isTemplate}
          {ts}Warning: Deleting this event template will also delete associated Event Registration Page and Event Fee configurations.{/ts} {ts}This action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
index 069ad4e2872acd2eecae19c08de7bf340df9b210..bf8a4c4fdfd6104daf6ae7b8444ac378a923371e 100644 (file)
       {if $action eq 8} {* If action is Delete *}
         <div class="crm-participant-form-block-delete messages status no-popup">
           <div class="crm-content">
-            <div class="icon inform-icon"></div> &nbsp;
+            {icon icon="fa-info-circle"}{/icon}
             {ts}WARNING: Deleting this registration will result in the loss of related payment records (if any).{/ts} {ts}Do you want to continue?{/ts}
           </div>
           {if $additionalParticipant}
index 02246d54cba6681f43f14049d85aa8d8b2d3a687..f9d3364dae5a56b7985b7e8e6a6cac028bfdbe94 100644 (file)
@@ -87,7 +87,7 @@ CRM.$(function($) {
   <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
   {if !$email}
   <div class="messages status no-popup">
-    <i class="crm-i fa-info-circle" aria-hidden="true"></i>&nbsp;{ts}You will not be able to send an automatic email receipt for this payment because there is no email address recorded for this contact. If you want a receipt to be sent when this payment is recorded, click Cancel and then click Edit from the Summary tab to add an email address before recording the payment.{/ts}
+    <i class="crm-i fa-info-circle" aria-hidden="true"></i> {ts}You will not be able to send an automatic email receipt for this payment because there is no email address recorded for this contact. If you want a receipt to be sent when this payment is recorded, click Cancel and then click Edit from the Summary tab to add an email address before recording the payment.{/ts}
   </div>
   {/if}
   <table class="form-layout">
index 59fd872132863273f3e79d8f410d790da73753da..80df777fe9d5c44f13b8ca8aa85cd0045e148c27 100644 (file)
@@ -7,6 +7,11 @@
  | and copyright information, see https://civicrm.org/licensing       |
  +--------------------------------------------------------------------+
 *}
+{if call_user_func(array('CRM_Core_Permission','check'), 'administer CiviCRM') }
+  {capture assign="buttonTitle"}{ts}Configure Event{/ts}{/capture}
+  {crmButton target="_blank" p="civicrm/event/manage/settings" q="reset=1&action=update&id=`$event.id`" title="$buttonTitle" icon="fa-wrench"}{ts}Configure{/ts}{/crmButton}
+  <div class='clear'></div>
+{/if}
 {* Callback snippet: Load payment processor *}
   {if $action & 1024}
     {include file="CRM/Event/Form/Registration/PreviewHeader.tpl"}
index d71c6369d308036edd6850b3634722ac5889b18e..593f14522c56558e0cd4c25a08c4caa67bca288e 100644 (file)
@@ -9,7 +9,7 @@
 *}
 {* No matches for submitted search request. *}
 <div class="messages status no-popup">
-  <div class="icon inform-icon"></div> &nbsp;
+  {icon icon="fa-info-circle"}{/icon}
     {if $qill}{ts}No matches found for:{/ts}
         {include file="CRM/common/displaySearchCriteria.tpl"}
     {else}
index acf605096e97aca744cba5b23b8b3e139cb00e3c..d7badca1f97da7350545e6ce3e308a60de4de10b 100644 (file)
@@ -10,7 +10,7 @@
 {* Confirmation of Cancel Registration *}
 <div class="crm-block crm-form-block crm-event-cancel-form-block">
 <div class="messages status no-popup">
-  <div class="icon inform-icon"></div>
+  {icon icon="fa-info-circle"}{/icon}
   <div>
       <p>{ts}Are you sure you want to set status to Cancelled for the selected participants?{/ts}</p>
       <p>{include file="CRM/Event/Form/Task.tpl"}</p>
index eb35a19794c60a416cfbb08becb2e4701d9ed997..b99fa017eebdad3b4e24b2e6a9c0c35c3b5d3781 100644 (file)
@@ -10,7 +10,7 @@
 {* Confirmation of participation deletes  *}
 <div class="crm-block crm-form-block crm-event-delete-form-block">
 <div class="messages status no-popup">
-  <div class="icon inform-icon"></div>
+  {icon icon="fa-info-circle"}{/icon}
   <div>
     <p>{ts}Are you sure you want to delete the selected participations? This delete operation cannot be undone and will delete all transactions and activity associated with these participations.{/ts}</p>
         <p>{include file="CRM/Event/Form/Task.tpl"}</p>
index f80be344b95081e6e75b2cb18cdfc395aee8856b..013cf6fd28a31913babfee65ee6192a90f474b71 100644 (file)
@@ -59,6 +59,6 @@
 
 {else}
 <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>&nbsp;{ts}There are no records selected for Print.{/ts}
+    {icon icon="fa-info-circle"}{/icon}{ts}There are no records selected for Print.{/ts}
 </div>
 {/if}
index 339070156c7245981650eb9ee68dd1fb1c80f05d..9cfdab00089337a72adc283cbecf25afade2b3fc 100644 (file)
@@ -31,6 +31,6 @@
 
 {else}
    <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>&nbsp;{ts}There are no records selected.{/ts}
+      {icon icon="fa-info-circle"}{/icon}{ts}There are no records selected.{/ts}
    </div>
 {/if}
index b5db9cad5ec587cfcd92b90f003643aa2e409f4b..d01250ee681b22c8fcb00e666ae0ec3a4e18b2d9 100644 (file)
@@ -87,7 +87,7 @@
       {if $actionColumn}
         <td class="crm-event-isMap">
           {if $values.isMap}
-            <a href="{$values.isMap}" title="{ts}Map event location{/ts}"><i class="crm-i fa-map-marker" aria-hidden="true"></i>&nbsp;{ts}Map{/ts}</a>
+            <a href="{$values.isMap}" title="{ts}Map event location{/ts}"><i class="crm-i fa-map-marker" aria-hidden="true"></i> {ts}Map{/ts}</a>
             &nbsp;|&nbsp;
           {/if}
           {if $values.configure}
     <br />
     <div class="messages status no-popup">
         <table>
-            <tr><div class="icon inform-icon"></div></tr>
+            <tr>{icon icon="fa-info-circle"}{/icon}</tr>
             <tr>
                 {ts}There are no active Events to display.{/ts}
                 {ts 1=$newEventURL}You can <a href="%1">Create a New Event</a> now.{/ts}
index 0f4a98d4aa2c8c71928c862c8b78f55b03208dac..099221a5af288465bd88a18be0a10b031fb85c18 100644 (file)
 {else}
   {if $isSearch eq 1}
   <div class="status messages">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
     {capture assign=browseURL}{crmURL p='civicrm/event/manage' q="reset=1"}{/capture}
     {ts}No available Events match your search criteria. Suggestions:{/ts}
     <div class="spacer"></div>
   </div>
     {else}
   <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
     {ts 1=$newEventURL}There are no events scheduled for the date range. You can <a href='%1'>add one</a>.{/ts}
   </div>
   {/if}
index ec1fde1a1263629ed1421c2db0816004a41704c5..695f53bebe4f618c3fa5646e8fcd5987bc9c4518 100644 (file)
@@ -33,7 +33,7 @@
 {else}
     <div class='spacer'></div>
     <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
         {ts}There are currently no participants registered for this event.{/ts}
     </div>
 {/if}
index 362f678fa71e3963b9658c1c7420950b7ba2ddcc..0626d6d15df44420c55447be33505b40070c39e3 100644 (file)
@@ -34,7 +34,7 @@
 {else}
     <div class='spacer'></div>
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
         {ts}There are currently no participants registered for this event.{/ts}
     </div>
 {/if}
index 6e875175c9567ff028d44266f896570be066442f..650dee0deab9e51f73aff9ada02a4589c0cf7111 100644 (file)
@@ -35,7 +35,7 @@
 {else}
     <div class='spacer'></div>
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
         {ts}There are currently no participants registered for this event.{/ts}
       </div>
 {/if}
index a85621d558f0e5a091d1558faeccb3f11e2c58e4..56f95044a633532ee2713850e8fd3ecc5201b072 100644 (file)
@@ -43,7 +43,7 @@
     {else}
        <div class="messages status no-popup">
            <table class="form-layout">
-             <tr><div class="icon inform-icon"></div>
+             <tr>{icon icon="fa-info-circle"}{/icon}
                    {ts}No event registrations have been recorded for this contact.{/ts}
              </tr>
            </table>
index 037ab085a4271d00dda42da81b0918e8910c5b32..5da7e3a430f51d51e5a8ebeb4e8c5090335cd1bc 100644 (file)
@@ -50,7 +50,7 @@
         {/strip}
     {else}
         <div class="messages status no-popup">
-           <div class="icon inform-icon"></div>
+           {icon icon="fa-info-circle"}{/icon}
            {ts}You are not registered for any current or upcoming Events.{/ts}
         </div>
     {/if}
index 5b974eb2a6408bfed68d79d5a7ea124a26a18a36..4b1bf47f1d5c1e62323bd5fd8428a0de6af04499 100644 (file)
@@ -10,7 +10,7 @@
 {* Confirmation of Export Batch(s)  *}
 <h3>{ts}Export Batch{/ts}</h3>
 <div class="messages status">
-  <div class="icon inform-icon"></div>
+  {icon icon="fa-info-circle"}{/icon}
   {ts}Warning: You will not be able to reopen or change the batch after it is exported. Are you sure you want to export?{/ts}
 </div>
 <div class="crm-block crm-form-block crm-export_batch-form-block">
index efa70c635e6e844d97d06f21ecccec3cfbbcf222..87026e64e22e175d1887fc6c255f09ad1ec28115 100644 (file)
@@ -11,7 +11,7 @@
 <div class="crm-block crm-form-block crm-contribution_type-form-block crm-financial_type-form-block">
 {if $action eq 8}
   <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
     {ts}WARNING: You cannot delete a {$delName} Financial Account if it is currently used by any Financial Types. Consider disabling this option instead.{/ts} {ts}Deleting a financial type cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
   </div>
 {else}
index 55a48bcee18153521a9e15e179993bd2465e1b91..6dbaef87879069f7024c9f0ddceb1b59d46cbdf9 100644 (file)
@@ -11,7 +11,7 @@
 <div class="crm-block crm-form-block crm-financial_type-form-block">
 {if $action eq 8}
   <div class="messages status">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
     {ts}WARNING: You cannot delete a financial type if it is currently used by any Contributions, Contribution Pages or Membership Types. Consider disabling this option instead.{/ts} {ts}Deleting a financial type cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
   </div>
 {else}
index 0ed2b3d5a6fe70af0458ad1a7f0176136880fd7e..498460aa74cb7f28965fe6ef546600f592154f79 100644 (file)
@@ -11,7 +11,7 @@
 <div class="crm-block crm-form-block crm-financial_type-form-block">
   {if $action eq 8}
     <div class="messages status">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
       {ts}WARNING: You cannot delete a financial type if it is currently used by any Contributions, Contribution Pages or Membership Types. Consider disabling this option instead.{/ts} {ts}Deleting a financial type cannot be undone. Unbalanced transactions may be created if you delete this account.{/ts} {ts}Do you want to continue?{/ts}
       </div>
   {else}
index 711003614e412ec271a9f225603afbaaf6b01d59..646255fe294fe5129eaaec8a56a7a58659fef539 100644 (file)
@@ -69,7 +69,7 @@
     </div>
   {else}
     <div class="messages status">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
       {capture assign=crmURL}{crmURL q="action=add&reset=1"}{/capture}
       {ts 1=$crmURL}There are no Financial Account entered. You can <a href='%1'>add one</a>.{/ts}
     </div>
index 59851127e8888886df24c45793e3d36ee52cd302..d42ca6f53b05634eb307abe9b3888a5438e9022f 100644 (file)
@@ -53,7 +53,7 @@
 </div>
 {else}
     <div class="messages status no-popup">
-        <div class="icon inform-icon"></div>
+        {icon icon="fa-info-circle"}{/icon}
       {ts}None found.{/ts}
     </div>
 {/if}
index 59732c8231b503aea7b116cb2fcf5f43b856ea45..5bc79434833235354eaf17a03d86fe4b585afe1c 100644 (file)
@@ -56,7 +56,7 @@
   </div>
   {else}
       <div class="messages status no-popup">
-          <div class="icon inform-icon"></div>
+          {icon icon="fa-info-circle"}{/icon}
           {capture assign=crmURL}{crmURL q="action=add&reset=1&aid=$aid"}{/capture}
           {ts 1=$crmURL}There are no financial accounts assigned to this financial type. You can <a href='%1'>assign one</a>.{/ts}
       </div>
index 7361b97e3cb3b43678bfb9f16123ea9749a5b63a..6fa4d9f9ac1f5aa423c08dd957056003d1f34cdc 100644 (file)
@@ -12,7 +12,7 @@
 <div class="crm-block crm-form-block crm-grant-form-block">
   {if $action eq 8}
      <div class="messages status">
-         <p><div class="icon inform-icon"></div>&nbsp;
+         <p>{icon icon="fa-info-circle"}{/icon}
          {ts}Are you sure you want to delete this Grant?{/ts} {ts}This action cannot be undone.{/ts}</p>
          <p>{include file="CRM/Grant/Form/Task.tpl"}</p>
      </div>
index dafc9136269acca7be644e5d443442fa2df2ab32..5237c908d6c3254547b08d4c2e209f80b6b88cd2 100644 (file)
@@ -9,7 +9,7 @@
 *}
 {* No matches for submitted search request. *}
 <div class="messages status">
-    <div class="icon inform-icon"></div>&nbsp;
+    {icon icon="fa-info-circle"}{/icon}
         {if $qill}{ts}No matches found for:{/ts}
             {include file="CRM/common/displaySearchCriteria.tpl"}
         {else}
index 3016c073f9a55fc004d0c3665915b61632ca9046..85f3168b06616895e3f11805c6d416f0f76523e7 100644 (file)
@@ -10,7 +10,7 @@
 {* Confirmation of Grant delete  *}
 <div class="crm-block crm-form-block crm-grant-task-delete-form-block">
   <div class="messages status no-popup">
-          <div class="icon inform-icon"></div>&nbsp;
+          {icon icon="fa-info-circle"}{/icon}
           {ts}Are you sure you want to delete the selected Grants? This delete operation cannot be undone and will delete all transactions associated with these grants.{/ts}
           <p>{include file="CRM/Grant/Form/Task.tpl"}</p>
   </div>
index 43e7f35ddb91782138c488394386b2a5411df356..98e16d5d4a4c0d408b3efc2247818a3f9c498ae4 100644 (file)
@@ -43,7 +43,7 @@
 
 {else}
    <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>&nbsp;
+    {icon icon="fa-info-circle"}{/icon}
         {ts}There are no records selected for Print.{/ts}
    </div>
 {/if}
index 6520e0845c75499fac49b571a8f69918f55ebc57..144ad174ca59449da14e34b38f9cc0b319058bc2 100644 (file)
@@ -28,7 +28,7 @@
 
 {else}
    <div class="messages status no-popup">
-          <div class="icon inform-icon"></div>
+          {icon icon="fa-info-circle"}{/icon}
             {ts}There are no records selected.{/ts}
    </div>
 {/if}
index 8ad006617459c11d839729310a1004e34fe7f8bb..bbebe0592e9c97fc958d82d8d59f66eac626f2ba 100644 (file)
@@ -35,7 +35,7 @@
         {include file="CRM/Grant/Form/Selector.tpl"}
     {else}
         <div class="messages status">
-             <div class="icon inform-icon"></div>&nbsp;
+             {icon icon="fa-info-circle"}{/icon}
              {ts}No grants have been recorded for this contact.{/ts}
        </div>
     {/if}
index 63b3e7c1a0dd58e3c2eb66d8947f49ed3c045e49..9f647186b761a351a2ebd816601718365e5110b8 100644 (file)
@@ -12,7 +12,7 @@
     {if $raw}
       <div class="status">
         <dl>
-          <dt><div class="icon inform-icon"></div></dt>
+          <dt>{icon icon="fa-info-circle"}{/icon}</dt>
           <dd>
             {ts}WARNING: Are you sure you want to revert the below changes?{/ts}
           </dd>
@@ -27,7 +27,7 @@
     {/if}
   {else}
     <div class='messages status'>
-        <div class='icon inform-icon'></div>&nbsp; {ts}This report can not be displayed because there are no relevant entries in the logging tables.{/ts}
+      {icon icon="fa-info-circle"}{/icon}{ts}This report can not be displayed because there are no relevant entries in the logging tables.{/ts}
     </div>
   {/if}
   {if $layout neq 'overlay'}
index b5a7c10110de11a3befda293f14c107b4be2b6b2..de38e6e8f6613bad6c1f879be47c8a22b6485165 100644 (file)
@@ -43,7 +43,7 @@
 
 {else}
    <div class="messages status no-popup">
-     <div class="icon inform-icon"/>
+     {icon icon="fa-info-circle"}{/icon}
         {ts}There are no records selected for Print.{/ts}
    </div>
 {/if}
index 7abb827f0a99bf96a1fa70c661219981e12f8b30..448cd77bdb467fe9bfc1ad6a6dd811c2a1e1e2e8 100644 (file)
@@ -97,7 +97,7 @@
     {/if}
     <div class="status messages">
         <table class="form-layout">
-            <tr><div class="icon inform-icon"></div>
+            <tr>{icon icon="fa-info-circle"}{/icon}
                {ts 1=$componentName}No %1 match your search criteria. Suggestions:{/ts}
       </tr>
                 <div class="spacer"></div>
 {elseif $unscheduled}
 
     <div class="messages status no-popup">
-            <div class="icon inform-icon"></div>&nbsp;
+            {icon icon="fa-info-circle"}{/icon}
             {capture assign=crmURL}{crmURL p=$newMassUrl q='reset=1'}{/capture}
             {ts 1=$componentName}There are no Unscheduled %1.{/ts}
       {if $showLinks}{ts 1=$crmURL}You can <a href='%1'>create and send one</a>.{/ts}{/if}
 
 {elseif $archived}
     <div class="messages status no-popup">
-            <div class="icon inform-icon"></div>&nbsp
+            {icon icon="fa-info-circle"}{/icon}&nbsp
             {capture assign=crmURL}{crmURL p='civicrm/mailing/browse/scheduled' q='scheduled=true&reset=1'}{$qVal}{/capture}
             {ts 1=$crmURL 2=$componentName}There are no Archived %2. You can archive %2 from <a href='%1'>Scheduled or Sent %2</a>.{/ts}
    </div>
 {else}
     <div class="messages status no-popup">
-            <div class="icon inform-icon"></div>&nbsp;
+            {icon icon="fa-info-circle"}{/icon}
             {capture assign=crmURL}{crmURL p=$newMassUrl q='reset=1'}{/capture}
             {capture assign=archiveURL}{crmURL p='civicrm/mailing/browse/archived' q='reset=1'}{$qVal}{/capture}
             {ts 1=$componentName}There are no Scheduled or Sent %1.{/ts}
index d84fca88fe5f75ee967add290ae265f1f4ea2737..d466cf7d42385739ecd09af30e6aa7125fb67a88 100644 (file)
@@ -8,7 +8,7 @@
  +--------------------------------------------------------------------+
 *}
 <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>&nbsp;
+      {icon icon="fa-info-circle"}{/icon}
 {if $success}
       {ts 1=$display_name 2=$email 3=$group}<strong>%1 (%2)</strong> has been successfully subscribed to the <strong>%3</strong> mailing list.{/ts}
 {else}
index 7c66c8be0e2fe428a738c63a11c7e57de73db8c5..4636f96d5e1217fa3cbdff9fec5afa6e359c11ea 100644 (file)
@@ -39,7 +39,7 @@
   {/strip}
 {else}
   <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
     &nbsp;
     {ts 1=$title}There are currently no %1.{/ts}
   </div>
index 95a6fd117543e3d7f651c47fe47781d4ef732979..47b413d078af6abc0ca1c9be8b891d9131b45b19 100644 (file)
@@ -9,7 +9,7 @@
 *}
 {if $confirm}
 <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>&nbsp;
+      {icon icon="fa-info-circle"}{/icon}
       <label>{$display_name} ({$email})</label> {ts}has been successfully resubscribed.{/ts}
 </div>
 {else}
index 36e5d8678f75780173fe9f4a2622ccd4e8460475..78d49280a15ef5b0c24f276b1524429db063b8b8 100644 (file)
@@ -10,7 +10,7 @@
 {* this template is used for adding/editing/deleting memberships for a contact  *}
 {if $isRecur}
   <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
     <p>{ts}This membership is set to renew automatically {if $endDate}on {$endDate|crmDate}{/if}. Please be aware that any changes that you make here may not be reflected in the payment processor. Please ensure that you alter the related subscription at the payment processor.{/ts}</p>
     {if $cancelAutoRenew}<p>{ts 1=$cancelAutoRenew}To stop the automatic renewal:
       <a href="%1">Cancel auto-renew</a>
@@ -42,7 +42,7 @@
   {/if}
   {if !$emailExists and $action neq 8 and $context neq 'standalone'}
   <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
     <p>{ts}You will not be able to send an automatic email receipt for this Membership because there is no email address recorded for this contact. If you want a receipt to be sent when this Membership is recorded, click Cancel and then click Edit from the Summary tab to add an email address before recording the Membership.{/ts}</p>
   </div>
   {/if}
@@ -65,7 +65,7 @@
     <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
     {if $action eq 8}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>&nbsp;
+      {icon icon="fa-info-circle"}{/icon}
       {$deleteMessage}
     </div>
     {else}
index bfaf1acc9298f6e4f2121bd0abc9b773b968be88..73b1b6850a4b8570057736960de48ec954459562 100644 (file)
@@ -15,7 +15,7 @@
   {/if}
   {if !$email}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
       <p>{ts}You will not be able to send an automatic email receipt for this Renew Membership because there is no email address recorded for this contact. If you want a receipt to be sent when this Membership is recorded, click Cancel and then click Edit from the Summary tab to add an email address before Renewal the Membership.{/ts}</p>
     </div>
   {/if}
@@ -29,7 +29,7 @@
   {if $action eq 32768}
     {if $cancelAutoRenew}
       <div class="messages status no-popup">
-        <div class="icon inform-icon"></div>
+        {icon icon="fa-info-circle"}{/icon}
         <p>{ts 1=$cancelAutoRenew}This membership is set to renew automatically {if $renewalDate}on {$renewalDate|crmDate}{/if}. You will need to cancel the auto-renew option if you want to modify the Membership Type, End Date or Membership Status.
             <a href="%1">Click here</a>
             if you want to cancel the automatic renewal option.{/ts}</p>
index 0ae925ddfd37edba051a55c811b29775c703ed10..0994cd02517c4d90a47cb50e339076acde48261e 100644 (file)
@@ -13,7 +13,7 @@
  <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
   {if $action eq 8}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
       {$deleteMessage|escape}
     </div>
   {else}
index c5ff09011be7c37a2374aa13f80523b1c0a48faf..8be9e23fd9c7fa9a8484d8d9cd937c2be3e4cf07 100644 (file)
     <fieldset><legend>{ts}Renewal Reminders{/ts}</legend>
       <div class="help">
         {capture assign=reminderLink}{crmURL p='civicrm/admin/scheduleReminders' q='reset=1'}{/capture}
-        <div class="icon inform-icon"></div>&nbsp;
+        {icon icon="fa-info-circle"}{/icon}
         {ts 1=$reminderLink}Configure membership renewal reminders using <a href="%1">Schedule Reminders</a>. If you have previously configured renewal reminder templates, you can re-use them with your new scheduled reminders.{/ts} {docURL page="user/email/scheduled-reminders"}
       </div>
     </fieldset>
index ec880d3b1e9a24a57c6c94a9b3f1d397c5f3bdf4..fb2e3984f09e8cb58acd854c5fae15ca2b02c984 100644 (file)
@@ -9,7 +9,7 @@
 *}
 {* No matches for submitted search request. *}
 <div class="messages status no-popup"> &nbsp;
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
         {if $qill}{ts}No matches found for:{/ts}
             {include file="CRM/common/displaySearchCriteria.tpl"}
         {else}
index cabc7be1e927d669b1cdbf5d07258b952b8f3754..585f457ee431f3d4fb20d6355a47581b37e14870 100644 (file)
@@ -10,7 +10,7 @@
 {* Confirmation of membership deletes  *}
 <div class="crm-block crm-form-block crm-member-task-delete-form-block">
   <div class="messages status no-popup">
-     <div class="icon inform-icon"></div>
+     {icon icon="fa-info-circle"}{/icon}
         <span>{ts}Are you sure you want to delete the selected memberships? This delete operation cannot be undone and will delete all transactions and activity associated with these memberships.{/ts}</span>
         <p>{include file="CRM/Member/Form/Task.tpl"}</p>
   </div>
index 170001ab8f8a3f10e6cea1eac84aeac928f6ef22..c906f807d0cd152e2a2ad20f12c6f4ea434b294f 100644 (file)
@@ -30,7 +30,7 @@
 </div>
 {else}
    <div class="messages status no-popup">
-            <div class="icon inform-icon"></div>
+            {icon icon="fa-info-circle"}{/icon}
                {ts}There are no records selected.{/ts}
    </div>
 {/if}
index cea515a485bbde06544799141b0e8b886265502c..04dc38cc7df9ad2cad73e874bd3e784db409b5be 100644 (file)
@@ -10,7 +10,7 @@
 
 {capture assign=reminderLink}{crmURL p='civicrm/admin/scheduleReminders' q='reset=1'}{/capture}
 <div class="help">
-  <p><div class="icon inform-icon"></div>&nbsp;{ts}Membership types are used to categorize memberships. You can define an unlimited number of types. Each type incorporates a 'name' (Gold Member, Honor Society Member...), a description, a minimum fee (can be $0), and a duration (can be 'lifetime'). Each member type is specifically linked to the membership entity (organization) - e.g. Bay Area Chapter.{/ts} {docURL page="user/membership/defining-memberships/"}</p>
+  <p>{icon icon="fa-info-circle"}{/icon}{ts}Membership types are used to categorize memberships. You can define an unlimited number of types. Each type incorporates a 'name' (Gold Member, Honor Society Member...), a description, a minimum fee (can be $0), and a duration (can be 'lifetime'). Each member type is specifically linked to the membership entity (organization) - e.g. Bay Area Chapter.{/ts} {docURL page="user/membership/defining-memberships/"}</p>
   <p>{ts 1=$reminderLink}Configure membership renewal reminders using <a href="%1">Schedule Reminders</a>.{/ts} {docURL page="user/email/scheduled-reminders"}</p>
 </div>
 
index d4abafedf555116edd78e618c773bd88b2aca491..249634931c3a587f045942e00ffb46aa26723239 100644 (file)
@@ -44,7 +44,7 @@
     {/if}
     {if NOT ($activeMembers or $inActiveMembers) and $action ne 2 and $action ne 1 and $action ne 8 and $action ne 4 and $action ne 32768}
          <div class="messages status no-popup">
-          <div class="icon inform-icon"></div>
+          {icon icon="fa-info-circle"}{/icon}
               {ts}No memberships have been recorded for this contact.{/ts}
          </div>
     {/if}
index 1e3cd972d1b8468184ae7f46e58e36970c45a0c7..084b6a22e08a826e2f3d10f555dcd91c8e4ee897 100644 (file)
@@ -73,7 +73,7 @@
 
 {if NOT ($activeMembers or $inActiveMembers)}
    <div class="messages status no-popup">
-       <div class="icon inform-icon"></div></dt>
+       {icon icon="fa-info-circle"}{/icon}</dt>
            {ts}There are no memberships on record for you.{/ts}
    </div>
 {/if}
index 8ca432991eefa9a793d513c765029f1c4a79b9ee..9ebac095e2639c84e164af8db946e3ea66f9b1c3 100644 (file)
@@ -10,7 +10,7 @@
 {* this template is used for confirmation of delete for a group *}
 <fieldset><legend>{ts}Delete Campaign Page {/ts}</legend>
 <div class="messages status no-popup">
-   <div class="icon inform-icon"></div>
+   {icon icon="fa-info-circle"}{/icon}
   {ts 1=$title}Are you sure you want to delete Campaign Page '%1'?{/ts}<br />
   {ts}This action cannot be undone.{/ts}
 </div>
index e16b55ffe4cfc100db76545dff4ab0b19af0556f..9aca301ba37c5feff9fec06b9e45e92eb6fa9d23 100644 (file)
@@ -53,7 +53,7 @@
 </div>
 {else}
 <div class="messages status no-popup">
-<div class="icon inform-icon"></div>
+{icon icon="fa-info-circle"}{/icon}
     {if $isSearch}
         {ts}There are no Personal Campaign Pages which match your search criteria.{/ts}
     {else}
index 450f685bf560e8f0b65bca4d8e0ad9af6f48ea8d..866402fbfdb3fceda47cf7fa2a7e70d2cb40b8cd 100644 (file)
@@ -10,7 +10,7 @@
 {* this template is used for displaying PCP information *}
 {if $owner}
 <div class="messages status no-popup">
-  <div class="icon inform-icon"></div>
+  {icon icon="fa-info-circle"}{/icon}
   <p><strong>{ts}Personal Campaign Preview{/ts}</strong> - {ts}This is a preview of your Personal Campaign Page in support of{/ts} <a href="{$parentURL}"><strong>{$pageName}</strong></a>.</p>
         {ts}The current status of your page is{/ts}: <strong {if $pcp.status_id NEQ 2}class=disabled {/if}>{$owner.status}</strong>.
         {if $pcp.status_id NEQ 2}<br /><span class="description">{ts}You will receive an email notification when your page is Approved and you can begin promoting your campaign.{/ts}</span>{/if}
index 81cd2afe3bc45c7967f0027d3b48187a4a42778f..82c7e770874325c0eede6fb4275da773cac8d8e1 100644 (file)
@@ -13,7 +13,7 @@
 {else}
 {if !$email and $action neq 8 and $context neq 'standalone'}
 <div class="messages status no-popup">
-  <div class="icon inform-icon"></div>
+  {icon icon="fa-info-circle"}{/icon}
   <p>{ts}You will not be able to send an acknowledgment for this pledge because there is no email address recorded for this contact. If you want a acknowledgment to be sent when this pledge is recorded, click Cancel and then click Edit from the Summary tab to add an email address before recording the pledge.{/ts}</p>
 </div>
 {/if}
@@ -29,7 +29,7 @@
  <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="top"}</div>
    {if $action eq 8}
     <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>&nbsp;
+    {icon icon="fa-info-circle"}{/icon}
     <span class="font-red bold">{ts}WARNING: Deleting this pledge will also delete any related pledge payments.{/ts} {ts}This action cannot be undone.{/ts}</span>
     <p>{ts}Consider cancelling the pledge instead if you want to maintain an audit trail and avoid losing payment data. To set the pledge status to Cancelled and cancel any not-yet-paid pledge payments, first click Cancel on this form. Then click the more &gt; link from the pledge listing, and select the Cancel action.{/ts}</p>
     </div>
@@ -43,7 +43,7 @@
             <td class="label">{$form.amount.label}</td>
             <td>
               <span>{$form.currency.html|crmAddClass:eight}&nbsp;{$form.amount.html|crmAddClass:eight}</span>
-              {if $originalPledgeAmount}<div class="messages status no-popup"><div class="icon inform-icon"></div>&nbsp;{ts 1=$originalPledgeAmount|crmMoney:$currency} Pledge total has changed due to payment adjustments. Original pledge amount was %1.{/ts}</div>{/if}
+              {if $originalPledgeAmount}<div class="messages status no-popup">{icon icon="fa-info-circle"}{/icon}{ts 1=$originalPledgeAmount|crmMoney:$currency} Pledge total has changed due to payment adjustments. Original pledge amount was %1.{/ts}</div>{/if}
             </td>
           </tr>
           <tr class="crm-pledge-form-block-installments">
index a9276b3ac81efdb44d445689c279ee8433ab3a14..742e47a4bd9862a25226b36011fae6bd4aa13a56 100644 (file)
@@ -20,7 +20,7 @@
      <tr class="crm-pledge-form-block-amount">
         <td class="label">{ts}Total Pledge Amount{/ts}</td>
         <td><span class="bold">{$amount|crmMoney:$currency}</span>
-            {if $originalPledgeAmount}<div class="messages status no-popup"><div class="icon inform-icon"></div>{ts 1=$originalPledgeAmount|crmMoney:$currency} Pledge total has changed due to payment adjustments. Original pledge amount was %1.{/ts}</div>{/if}
+            {if $originalPledgeAmount}<div class="messages status no-popup">{icon icon="fa-info-circle"}{/icon}{ts 1=$originalPledgeAmount|crmMoney:$currency} Pledge total has changed due to payment adjustments. Original pledge amount was %1.{/ts}</div>{/if}
         </td>
      </tr>
      <tr class="crm-pledge-form-block-installments"><td class="label">{ts}To be paid in{/ts}</td><td>{$installments} {ts}installments of{/ts} {$original_installment_amount|crmMoney:$currency} {ts}every{/ts} {$frequency_interval} {$frequencyUnit}</td></tr>
index df7b7dcd61cdc413764a1ab3f68f1694cf23b6c6..5a1812a2f160831ecc936b2bfaeda51a07c917c1 100644 (file)
@@ -9,7 +9,7 @@
 *}
 {* No matches for submitted search request. *}
 <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
         {if $qill}{ts}No matches found for:{/ts}
             {include file="CRM/common/displaySearchCriteria.tpl"}
         {else}
index bfc15a2ffc0d2cf4352bb1ced5a2a6865609bb6c..2a027be5d77185dfa12558f21dd69a955a341c12 100644 (file)
@@ -9,7 +9,7 @@
 *}
 {* Confirmation of participation deletes  *}
 <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
         <p>{ts}Are you sure you want to delete the selected pledges? This delete operation cannot be undone and will delete all transactions associated with these pledges.{/ts}</p>
         <p>{include file="CRM/Pledge/Form/Task.tpl"}</p>
 </div>
index a9a5995533bea2b2276db68a2a27307328efeb61..32d88291006d90d1b839dddfb50e5f46a172d39b 100644 (file)
@@ -43,7 +43,7 @@
 
 {else}
    <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
         {ts}There are no records selected for Print.{/ts}
    </div>
 {/if}
index d75e3879d28538eec592f7c579d4ad1de7cab399..7bf90eecb09d6a79fb3abde70a5e5a6f8de94073 100644 (file)
@@ -30,7 +30,7 @@
 
 {else}
    <div class="messages status no-popup">
-          <dt><div class="icon inform-icon"></div>
+          <dt>{icon icon="fa-info-circle"}{/icon}
             {ts}There are no records selected.{/ts}
       </dl>
    </div>
index 38740278c9f3e8d61a6b1cb6309c9a4e3313b0d3..98e5a5c622290d449ec1f9111304a13609b7b6e8 100644 (file)
@@ -36,7 +36,7 @@
 
 {else}
    <div class="messages status no-popup">
-       <div class="icon inform-icon"></div>
+       {icon icon="fa-info-circle"}{/icon}
             {ts}No pledges have been recorded from this contact.{/ts}
        </div>
 {/if}
index f67db5d0311e84f4c657f53feceb4d7102316efa..97ff8596d2d9f2f463a23d81fc3af3788db4e99d 100644 (file)
@@ -45,7 +45,7 @@
 {crmScript file='js/crm.expandRow.js'}
 {else}
 <div class="messages status no-popup">
-         <div class="icon inform-icon"></div>
+         {icon icon="fa-info-circle"}{/icon}
              {ts}There are no Pledges for your record.{/ts}
          </div>
 {/if}
index 236f1125dc311b7c2b4f1bee35cec38d1f0a4944..3259d4d282a5250070595c4b9dfb819c5129638a 100644 (file)
@@ -10,7 +10,7 @@
 {* this template is used for confirmation of delete for a Fields  *}
 <div class="crm-block crm-form-block crm-price_field_delete-form-block">
     <div class="messages status no-popup">
-        <div class="icon inform-icon"></div>
+        {icon icon="fa-info-circle"}{/icon}
           {ts 1=$title}WARNING: Deleting this price field will result in the loss of all '%1' data.{/ts} {ts}This action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
     </div>
     <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
index e65c52bd7939f163b9df0d7818fd0b11029fbabf..18b72acd55d3ab744019d3fcf918f0c736039f6f 100644 (file)
@@ -10,7 +10,7 @@
 <div class="crm-form-block">
   {if $action eq 8}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
       {ts}WARNING: Deleting this option will result in the loss of all data.{/ts} {ts}This action cannot be undone.{/ts} {ts}Do you want to continue?{/ts}
     </div>
   {else}
index e41bdb7b1ef503a5a18acf2bbb8fa22cd2497f63..480f9b9e3f11f4e2aa13f70f5f7a2db81c430d23 100644 (file)
     {assign var='adminFld' value=false}
     {if call_user_func(array('CRM_Core_Permission','check'), 'administer CiviCRM') }
       {assign var='adminFld' value=true}
+      {if $priceSet.id && !$priceSet.is_quick_config}
+        <div class='float-right'>
+          <a class="crm-hover-button" target="_blank" href="{crmURL p="civicrm/admin/price/field" q="reset=1&action=browse&sid=`$priceSet.id`"}">
+            {icon icon="fa-wrench"}{ts}Edit Price Set{/ts}{/icon}
+          </a>
+        </div>
+      {/if}
     {/if}
 
     {foreach from=$priceSet.fields item=element key=field_id}
index 9a3b9e1add88c4e4ba7b2a46bfd9d1ca0d4f2704..88ec508d58c9d1df04ae5f488a6da3d8627aebdd 100644 (file)
@@ -15,7 +15,7 @@
   {include file="CRM/Price/Form/Preview.tpl"}
 {elseif ($usedBy and $action eq 8) or $usedBy.civicrm_event or $usedBy.civicrm_contribution_page}
   <div id="price_set_used_by" class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
     {if $action eq 8}
       {ts 1=$usedPriceSetTitle}Unable to delete the '%1' Price Field - it is currently in use by one or more active events or contribution pages or contributions  or event templates.{/ts}
     {/if}
@@ -89,7 +89,7 @@
 {else}
   {if $action eq 16}
     <div class="messages status no-popup crm-empty-table">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
       {ts}None found.{/ts}
     </div>
     <div class="action-link">
index 22f82229a419147ca6c31249985a95f4ab93461c..0f4a5b079ae6fc3354d8c4889342cdb0b47c61c2 100644 (file)
@@ -13,7 +13,7 @@
 {elseif $usedBy}
   <div class='spacer'></div>
   <div id="price_set_used_by" class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
     {if $action eq 8}
       {ts 1=$usedPriceSetTitle}Unable to delete the '%1' Price Field Option - it is currently in use by one or more active events  or contribution pages or contributions.{/ts}
     {/if}
index d57b2e437a25d3de939d995fb203c25712e78045..e145781fe9ac1aa7ecda1c21313e96b8cccf5624 100644 (file)
@@ -21,7 +21,7 @@
     {if $usedBy}
     <div class='spacer'></div>
     <div id="price_set_used_by" class="messages status no-popup">
-       <div class="icon inform-icon"></div>
+       {icon icon="fa-info-circle"}{/icon}
         {if $action eq 8}
             {ts 1=$usedPriceSetTitle}Unable to delete the '%1' price set - it is currently in use by one or more active events or contribution pages or contributions or event templates.{/ts}
         {/if}
index 206ec5444d68e2f5e1c1861eb0fb18950e6018a8..2d0240fb886bb3f1ad93a97671dc7f714daa73a0 100644 (file)
@@ -14,7 +14,7 @@
     cms account edit (mode=8) or civicrm/profile (mode=4) pages *}
 {if $deleteRecord}
 <div class="messages status no-popup">
-  <div class="icon inform-icon"></div>&nbsp;
+  {icon icon="fa-info-circle"}{/icon}
         {ts}Are you sure you want to delete this record?{/ts}
   </div>
 
 
     {if ($action eq 1 and $mode eq 4 ) or ($action eq 2) or ($action eq 8192)}
       {if $action eq 2 and $multiRecordFieldListing}
-      {include file="CRM/Profile/Page/MultipleRecordFieldsListing.tpl" showListing=true}
-        {assign var=floatStyle value='float:right'}
+        <div class="crm-multi-record-custom-field-listing">
+          {include file="CRM/Profile/Page/MultipleRecordFieldsListing.tpl" showListing=true}
+          {assign var=floatStyle value='float:right'}
+        </div>
       {/if}
       <div class="crm-submit-buttons" style='{$floatStyle}'>
         {include file="CRM/common/formButtons.tpl"}{if $isDuplicate}<span class="crm-button">{$form._qf_Edit_upload_duplicate.html}</span>{/if}
@@ -250,7 +252,7 @@ invert              = 0
 }
 {elseif $statusMessage}
 <div class="messages status no-popup">
-  <div class="icon inform-icon"></div>
+  {icon icon="fa-info-circle"}{/icon}
   {$statusMessage}
 </div>
 {/if}
index d09429a17a30ec3ff021d265e4e43e68b810edae..0b093ea4504798e77fa6334a8024d2df5db49ef4 100644 (file)
 
 {elseif $statusMessage}
   <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
     {$statusMessage}
   </div>
 {else} {* empty fields *}
   <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
     {ts}No fields in this Profile have been configured as searchable. Ask the site administrator to check the Profile setup.{/ts}
   </div>
 {/if}
index bd02d534e232b5615cedcc118df4e56e323da41c..e3b3e23becb9212593217498cc6245aefa433c3d 100644 (file)
@@ -77,7 +77,7 @@
 
 {else}
     <div class="messages status no-popup">
-        <div class="icon inform-icon"></div>
+        {icon icon="fa-info-circle"}{/icon}
         {ts}No fields in this Profile have been configured to display as a result column in the search results table. Ask the site administrator to check the Profile setup.{/ts}
     </div>
 {/if}
index bd740966b6c2819479df69a42cb52e6437ad0e19..dc185e6d1d97a9a0da52a6570d9f72472f6cb1ea 100644 (file)
@@ -91,7 +91,7 @@
     <div id='{$dialogId}' class="hiddenElement"></div>
   {elseif !$records}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
       &nbsp;
       {ts 1=$customGroupTitle}No records of type '%1' found.{/ts}
     </div>
index 9aee8f669585f0588cf03036c71760727fb3a19a..34690c1d916d416587aa5a160b1df58d91d2302f 100644 (file)
@@ -20,7 +20,7 @@
               <tr>
                 {include file="CRM/common/tasks.tpl" location="botton"}
                 {if $instanceUrl}
-                  <td>&nbsp;&nbsp;<i class="crm-i fa-chevron-right" aria-hidden="true"></i>&nbsp;<a href="{$instanceUrl}">{ts}Existing report(s) from this template{/ts}</a></td>
+                  <td>&nbsp;&nbsp;<i class="crm-i fa-chevron-right" aria-hidden="true"></i> <a href="{$instanceUrl}">{ts}Existing report(s) from this template{/ts}</a></td>
                 {/if}
               </tr>
             </table>
index 79f2c59f1062814f83d4c4f942de899017841a72..800544e8edfda7b91ba9ecd5c9886280d225a48c 100644 (file)
@@ -9,6 +9,6 @@
 *}
 {if $outputMode eq 'html' && !$rows}
   <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>&nbsp; {ts}None found.{/ts}
+    {icon icon="fa-info-circle"}{/icon} {ts}None found.{/ts}
   </div>
 {/if}
index 15f9ce53a22b386422d04f828e4eaa5999a24ef7..49f8ff0d5c741f885cd140dc14eb3d3bf498d4ba 100644 (file)
@@ -25,7 +25,7 @@
     <tr>
       <td colspan=2>
         <div class="messages status no-popup">
-          <div class="icon inform-icon"></div> &nbsp;
+          {icon icon="fa-info-circle"}{/icon}
           {ts}WARNING: Deleting this option will result in the loss of all Report related records which use the option. This may mean the loss of a substantial amount of data, and the action cannot be undone. Do you want to continue?{/ts}
         </div>
       </td>
index 354edd5444ff91c8cb26eddaa2445ff7425e290e..1727e199071561a4de6633c15a66fcce8c106b79 100644 (file)
@@ -64,7 +64,7 @@
   {else}
     <div class="crm-content-block">
       <div class="messages status no-popup">
-        <div class="icon inform-icon"></div>&nbsp;
+        {icon icon="fa-info-circle"}{/icon}
         {if $myReports}
           {ts}You do not have any private reports. To add a report to this section, edit the Report Settings for a report and set 'Add to My Reports' to Yes.{/ts} &nbsp;
         {else}
index 497157d07432908dc46cc7300a061f8642a198bb..fe677c0dd79aa497558256dca37625641230c6ea 100644 (file)
@@ -46,7 +46,7 @@
       {/foreach}
     {else}
       <div class="messages status no-popup">
-        <div class="icon inform-icon"></div>&nbsp; {ts}There are currently no Report Templates.{/ts}
+        {icon icon="fa-info-circle"}{/icon} {ts}There are currently no Report Templates.{/ts}
       </div>
     {/if}
   {/strip}
index da6aa95bfb3b93c41967754c50e20b92d821834c..2ce5486d8c75d96b3c9557c023c64dfeb506324b 100644 (file)
@@ -9,7 +9,7 @@
 *}
 {if $groupCount == 0 and $mailingCount == 0}
   <div class="status">
-  <div class="icon inform-icon"></div>
+  {icon icon="fa-info-circle"}{/icon}
         {ts}To send a Mass SMS, you must have a valid group of recipients - either at least one group that's a Mailing List{/ts}
   </div>
 {else}
index 7995a794b7474caa776519487a7f29ee357eff9f..183d5a20c06770219a79ca6cd14ded1f075d2c7b 100644 (file)
 
 {if $action eq 8}
   <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
         {ts}Do you want to continue?{/ts}
   </div>
 {elseif $action eq 128}
   <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
         {ts}Are you sure you would like to execute this job?{/ts}
   </div>
 {else}
index 3c27c157c4592345e86eddb637d5fecbefc140e9..9a9deac2c2a177da4e601cc9d6bd0150ca8a5ea1 100644 (file)
@@ -46,7 +46,7 @@
   </div>
   {else}
     <div class="messages status no-popup">
-      <div class="icon inform-icon"></div>
+      {icon icon="fa-info-circle"}{/icon}
         {ts}None found.{/ts}
      </div>
 
index e59f24246a76710c5df727c464d88f4dab7a628a..e0ded1e4bcb40847c81b4cc746ce6609a2cb1191 100644 (file)
   <% {rdelim} %>
   <div class="crm-submit-buttons">
     <a href="{crmURL p="civicrm/tag/edit" q="action=add&parent_id="}<%= tagset || '' %>" class="button crm-popup">
-      <span><i class="crm-i fa-plus" aria-hidden="true"></i>&nbsp; {ts}Add Tag{/ts}</span>
+      <span><i class="crm-i fa-plus" aria-hidden="true"></i> {ts}Add Tag{/ts}</span>
     </a>
     <% if(tagset && adminTagsets) {ldelim} %>
       <a href="{crmURL p="civicrm/tag/edit" q="action=update&id="}<%= tagset %>" class="button crm-popup tagset-action-update">
-        <span><i class="crm-i fa-pencil" aria-hidden="true"></i>&nbsp; {ts}Edit Set{/ts}</span>
+        <span><i class="crm-i fa-pencil" aria-hidden="true"></i> {ts}Edit Set{/ts}</span>
       </a>
     <% {rdelim} %>
     <% if(tagset && !length && adminTagsets && (!is_reserved || adminReserved)) {ldelim} %>
       <a href="{crmURL p="civicrm/tag/edit" q="action=delete&id="}<%= tagset %>" class="button crm-popup small-popup tagset-action-delete">
-        <span><i class="crm-i fa-trash" aria-hidden="true"></i>&nbsp; {ts}Delete Set{/ts}</span>
+        <span><i class="crm-i fa-trash" aria-hidden="true"></i> {ts}Delete Set{/ts}</span>
       </a>
     <% {rdelim} %>
   </div>
   <div class="crm-submit-buttons">
     <% if(!tagset) {ldelim} %>
       <a href="{crmURL p="civicrm/tag/edit" q="action=add&parent_id="}<%= id %>" class="button crm-popup" title="{ts}Create new tag under this one{/ts}">
-        <span><i class="crm-i fa-plus" aria-hidden="true"></i>&nbsp; {ts}Add Child{/ts}</span>
+        <span><i class="crm-i fa-plus" aria-hidden="true"></i> {ts}Add Child{/ts}</span>
       </a>
     <% {rdelim} %>
     <a href="{crmURL p="civicrm/tag/edit" q="action=add&clone_from="}<%= id %>" class="button crm-popup" title="{ts}Duplicate this tag{/ts}">
-      <span><i class="crm-i fa-copy" aria-hidden="true"></i>&nbsp; {ts}Clone Tag{/ts}</span>
+      <span><i class="crm-i fa-copy" aria-hidden="true"></i> {ts}Clone Tag{/ts}</span>
     </a>
     <% if(!data.is_reserved || adminReserved) {ldelim} %>
       <% if(tagsetCount) {ldelim} %>
         <a href="#move" class="button move-tag-button" title="{ts}Move to a different tagset{/ts}">
-          <span><i class="crm-i fa-share-square-o" aria-hidden="true"></i>&nbsp; {ts}Move Tag{/ts}</span>
+          <span><i class="crm-i fa-share-square-o" aria-hidden="true"></i> {ts}Move Tag{/ts}</span>
         </a>
       <% {rdelim} %>
       <% if(!hasChildren) {ldelim} %>
         <a href="{crmURL p="civicrm/tag/edit" q="action=delete&id="}<%= id %>" class="button crm-popup small-popup">
-          <span><i class="crm-i fa-trash" aria-hidden="true"></i>&nbsp; {ts}Delete{/ts}</span>
+          <span><i class="crm-i fa-trash" aria-hidden="true"></i> {ts}Delete{/ts}</span>
         </a>
       <% {rdelim} %>
     <% {rdelim} %>
   <div class="crm-submit-buttons">
     <% if(!reserved || adminReserved) {ldelim} %>
       <a href="{crmURL p="civicrm/tag/merge" q="id="}<%= items.join() %>" class="button crm-popup small-popup" title="{ts}Combine tags into one{/ts}">
-        <span><i class="crm-i fa-compress" aria-hidden="true"></i>&nbsp; {ts}Merge Tags{/ts}</span>
+        <span><i class="crm-i fa-compress" aria-hidden="true"></i> {ts}Merge Tags{/ts}</span>
       </a>
       <% if(tagsetCount) {ldelim} %>
         <a href="#move" class="button move-tag-button" title="{ts}Move to a different tagset{/ts}">
-          <span><i class="crm-i fa-share-square-o" aria-hidden="true"></i>&nbsp; {ts}Move Tags{/ts}</span>
+          <span><i class="crm-i fa-share-square-o" aria-hidden="true"></i> {ts}Move Tags{/ts}</span>
         </a>
       <% {rdelim} %>
       <% if(!hasChildren) {ldelim} %>
         <a href="{crmURL p="civicrm/tag/edit" q="action=delete&id="}<%= items.join() %>" class="button crm-popup small-popup">
-          <span><i class="crm-i fa-trash" aria-hidden="true"></i>&nbsp; {ts}Delete All{/ts}</span>
+          <span><i class="crm-i fa-trash" aria-hidden="true"></i> {ts}Delete All{/ts}</span>
         </a>
       <% {rdelim} %>
     <% {rdelim} %>
index 447732e86790cf1f3eeda4cf8a98b9caa750625a..83a5056f7a06d3a38ef33b46695307dbcef1c15b 100644 (file)
@@ -10,7 +10,7 @@
 <div class="crm-block crm-form-block crm-uf-field-form-block">
 {if $action eq 8}
   <div class="messages status no-popup">
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
     {ts}WARNING: Deleting this profile field will remove it from Profile forms and listings. If this field is used in any 'stand-alone' Profile forms, you will need to update those forms to remove this field.{/ts} {ts}Do you want to continue?{/ts}
   </div>
 {else}
index 77a8c35d5853496843cd2e5299b521d9cb04fbcc..24c97000be23873404f39b3068c6a8f9d178a17f 100644 (file)
@@ -25,7 +25,7 @@
 
 {if $action eq 8 or $action eq 64}
     <div class="messages status no-popup">
-           <div class="icon inform-icon"></div>
+           {icon icon="fa-info-circle"}{/icon}
            {$message}
     </div>
 {else}
index 6c90c9482a273626f190107888d8a6c5b5b3477d..75229e7bc671a4f928b6227772b097563503f128 100644 (file)
@@ -70,7 +70,7 @@
         {if $action eq 16}
         {capture assign=crmURL}{crmURL p="civicrm/admin/uf/group/field/add" q="reset=1&action=add&gid=$gid"}{/capture}
         <div class="messages status no-popup crm-empty-table">
-          <div class="icon inform-icon"></div>
+          {icon icon="fa-info-circle"}{/icon}
           {ts}None found.{/ts}
         </div>
         <div class="action-link">
index 1eb5ee8ef0a9a609f65ad607f1a9578e417017de..a59a5a34457ce2f6aa4bab27b25cfcba7ad2443a 100644 (file)
     {else}
     {if $action ne 1} {* When we are adding an item, we should not display this message *}
        <div class="messages status no-popup">
-         <div class="icon inform-icon"></div> &nbsp;
+         {icon icon="fa-info-circle"}{/icon}
          {capture assign=crmURL}{crmURL p='civicrm/admin/uf/group/add' q='action=add&reset=1'}{/capture}{ts 1=$crmURL}No CiviCRM Profiles have been created yet. You can <a href='%1'>add one now</a>.{/ts}
        </div>
     {/if}
index 49ef5c02dc5ed1aee1f06c5bb285bbd5bf3b44a7..46ed344835d7c5594701862e047c5dc55f7826e7 100644 (file)
@@ -472,12 +472,6 @@ define('CIVICRM_DEADLOCK_RETRIES', 3);
 // define('CIVICRM_MYSQL_STRICT', TRUE );
 // }
 
-/**
- * Specify whether the CRM_Core_BAO_Cache should use the legacy
- * direct-to-SQL-mode or the interim PSR-16 adapter.
- */
-// define('CIVICRM_BAO_CACHE_ADAPTER', 'CRM_Core_BAO_Cache_Psr16');
-
 if (CIVICRM_UF === 'UnitTests') {
   if (!defined('CIVICRM_CONTAINER_CACHE')) define('CIVICRM_CONTAINER_CACHE', 'auto');
   if (!defined('CIVICRM_MYSQL_STRICT')) define('CIVICRM_MYSQL_STRICT', true);
index 92b41f4dff0dae94968c7160b2faea3e8693db64..7af01e646bec483f29db5b938c76eeeea01635b1 100644 (file)
     {crmGetAttribute html=$html attr='crm-icon' assign='icon'}
     {capture assign=iconPrefix}{$icon|truncate:3:"":true}{/capture}
     {if $icon && $iconPrefix eq 'fa-'}
-      {assign var='buttonClass' value=' crm-i-button'}
       {capture assign=iconDisp}<i class="crm-i {$icon}" aria-hidden="true"></i>{/capture}
-    {elseif $icon}
-      {assign var='buttonClass' value=' crm-icon-button'}
-      {capture assign=iconDisp}<span class="crm-button-icon ui-icon-{$icon}"> </span>{/capture}
     {/if}
     {crmGetAttribute html=$html attr='disabled' assign='disabled'}
-    <span class="crm-button crm-button-type-{$key|crmBtnType} crm-button{$key}{$buttonClass}{if $disabled} crm-button-disabled{/if}"{if $buttonStyle} style="{$buttonStyle}"{/if}>
+    <span class="crm-button crm-button-type-{$key|crmBtnType} crm-button{$key}{if $disabled} crm-button-disabled{/if}"{if $buttonStyle} style="{$buttonStyle}"{/if}>
       {$iconDisp}
       {$html}
     </span>
index 002f88f31aabf35fcb7db1e3f72a02d93dd9eac4..de02a23e78fe95cbc8e6a0d9c83bbda4b3d78b0c 100644 (file)
@@ -10,7 +10,7 @@
 {* Handles display of passed $infoMessage. *}
 {if $infoMessage or $infoTitle}
   <div class="messages status {$infoType}"{if $infoOptions} data-options='{$infoOptions}'{/if}>
-    <div class="icon inform-icon"></div>
+    {icon icon="fa-info-circle"}{/icon}
     <span class="msg-title">{$infoTitle}</span>
     <span class="msg-text">{$infoMessage}</span>
   </div>
index bba775f40a56419549d40d3d61cb88067a58f1f6..f6eec45ea639be217183bad72b124618e2ede8ca 100644 (file)
     errorClass: 'crm-inline-error alert-danger',
     messages: {},
     ignore: '.select2-offscreen, [readonly], :hidden:not(.crm-select2), .crm-no-validate',
-    ignoreTitle: true
+    ignoreTitle: true,
+    errorPlacement: function(error, element) {
+      if (element.prop('type') === 'radio') {
+        error.appendTo(element.parent('div.content'));
+      }
+      else {
+        error.insertAfter(element);
+      }
+    }
   };
 
   // use civicrm notifications when there are errors
index 1a4cc92cd6af7e5ebf0eb6c2f5c8403ea4513fff..da4c8b47f55fdb48805c027de1f0d427722bd065 100644 (file)
@@ -4,17 +4,7 @@
  *  Include dataProvider for tests
  * @group headless
  */
-class CRM_Case_BAO_QueryTest extends CiviUnitTestCase {
-
-  /**
-   * Set up function.
-   *
-   * Ensure CiviCase is enabled.
-   */
-  public function setUp() {
-    parent::setUp();
-    CRM_Core_BAO_ConfigSetting::enableComponent('CiviCase');
-  }
+class CRM_Case_BAO_QueryTest extends CiviCaseTestCase {
 
   /**
    * Check that Qill is calculated correctly.
@@ -22,20 +12,17 @@ class CRM_Case_BAO_QueryTest extends CiviUnitTestCase {
    * CRM-17120 check the qill is still calculated after changing function used
    * to retrieve function.
    *
-   * Note that the Qill doesn't actually appear to have the correct labels to
-   * start with. I didn't attempt to fix that. I just prevented regression.
-   *
    * I could not find anyway to actually do this search with the relevant fields
    * as parameters & don't know if they exist as legitimate code or code cruft so
    * this test was the only way I could verify the change.
-   *  - case_recent_activity_type
+   *  - case_activity_type
    *  - case_activity_status_id
    *  - case_activity_medium_id
    */
   public function testWhereClauseSingle() {
     $params = [
       0 => [
-        0 => 'case_recent_activity_type',
+        0 => 'case_activity_type',
         1 => '=',
         2 => 6,
         3 => 1,
@@ -61,11 +48,72 @@ class CRM_Case_BAO_QueryTest extends CiviUnitTestCase {
     $this->assertEquals(
       [
         0 => 'Activity Type = Contribution',
-        1 => 'Activity Type = Scheduled',
+        1 => 'Activity Status = Scheduled',
         2 => 'Activity Medium = In Person',
       ],
       $queryObj->_qill[1]
     );
   }
 
+  /**
+   * Test the qill for a find cases search.
+   */
+  public function testFindCasesQuery() {
+    $params = [
+      [
+        0 => 'case_type_id',
+        1 => 'IN',
+        2 => [1],
+        3 => 0,
+        4 => 0,
+      ],
+      [
+        0 => 'case_status_id',
+        1 => 'IN',
+        2 => [1],
+        3 => 0,
+        4 => 0,
+      ],
+      [
+        0 => 'case_deleted',
+        1 => '=',
+        2 => 0,
+        3 => 0,
+        4 => 0,
+      ],
+      [
+        0 => 'case_owner',
+        1 => '=',
+        2 => 1,
+        3 => 0,
+        4 => 0,
+      ],
+    ];
+
+    $query = new CRM_Contact_BAO_Query($params, NULL, NULL, FALSE, FALSE, CRM_Contact_BAO_Query::MODE_CASE);
+
+    $this->assertEquals(
+      [
+        0 => [
+          0 => 'Case Type(s) In Housing Support',
+          1 => 'Case Status(s) In Ongoing',
+          2 => 'Case = All Cases',
+        ],
+      ],
+      $query->_qill
+    );
+
+    $this->assertEquals(
+      [
+        0 => [
+          0 => 'civicrm_case.case_type_id IN ("1")',
+          1 => 'civicrm_case.status_id IN ("1")',
+          2 => 'civicrm_case.is_deleted = 0',
+          3 => 'civicrm_case_contact.contact_id = contact_a.id',
+        ],
+      ],
+      $query->_where
+    );
+  }
+
 }
diff --git a/tests/phpunit/CRM/Contact/Form/Task/UseraddTest.php b/tests/phpunit/CRM/Contact/Form/Task/UseraddTest.php
new file mode 100644 (file)
index 0000000..714a228
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved.                        |
+ |                                                                    |
+ | This work is published under the GNU AGPLv3 license with some      |
+ | permitted exceptions and without any warranty. For full license    |
+ | and copyright information, see https://civicrm.org/licensing       |
+ +--------------------------------------------------------------------+
+ */
+
+ /**
+  * @group headless
+  */
+class CRM_Contact_Form_Task_UseraddTest extends CiviUnitTestCase {
+
+  /**
+   * Test postProcess failure.
+   *
+   * In unit tests, the CMS user creation will always fail, but that's
+   * ok because that's what we're testing here.
+   */
+  public function testUserCreateFail() {
+    $form = new CRM_Contact_Form_Task_Useradd();
+    // We don't need to set params or anything because we're testing fail,
+    // which the user creation will do in unit tests no matter what we set.
+    // But before the patch, the status messages were always success no
+    // matter what.
+    try {
+      $form->postProcess();
+    }
+    catch (CRM_Core_Exception_PrematureExitException $e) {
+    }
+    $statuses = CRM_Core_Session::singleton()->getStatus(TRUE);
+    $this->assertEquals('alert', $statuses[0]['type']);
+  }
+
+}
index fd10b18eeb1487f6917e7e24e45c9091958444e5..bb103b9c123c832f5c0b0b3554b36e51987cde31 100644 (file)
@@ -32,6 +32,12 @@ class CRM_Contact_SelectorTest extends CiviUnitTestCase {
    * @throws \Exception
    */
   public function testSelectorQuery($dataSet) {
+    if (!empty($dataSet['limitedPermissions'])) {
+      CRM_Core_Config::singleton()->userPermissionClass->permissions = [
+        'access CiviCRM',
+        'access deleted contacts',
+      ];
+    }
     $params = CRM_Contact_BAO_Query::convertFormValues($dataSet['form_values'], 0, FALSE, NULL, []);
     $isDeleted = in_array(['deleted_contacts', '=', 1, 0, 0], $params);
     foreach ($dataSet['settings'] as $setting) {
@@ -90,6 +96,9 @@ class CRM_Contact_SelectorTest extends CiviUnitTestCase {
         $selector->getQueryObject()->getCachedContacts([$contactID], FALSE);
       }
     }
+    if (!empty($dataSet['limitedPermissions'])) {
+      $this->cleanUpAfterACLs();
+    }
   }
 
   /**
@@ -314,6 +323,28 @@ class CRM_Contact_SelectorTest extends CiviUnitTestCase {
             2 => "WHERE  ( civicrm_email.email LIKE 'mickey@mouseville.com%'  AND ( ( ( contact_a.sort_name LIKE 'Mouse%' ) OR ( civicrm_email.email LIKE 'Mouse%' ) ) ) ) AND (contact_a.is_deleted)",
           ],
         ],
+      ],
+      [
+        [
+          'description' => 'Ensure that the Join to the acl contact cache is correct and that if we are searching in deleted contacts appropriate where clause is added',
+          'class' => 'CRM_Contact_Selector',
+          'settings' => [['name' => 'includeWildCardInName', 'value' => FALSE]],
+          'form_values' => ['email' => 'mickey@mouseville.com', 'sort_name' => 'Mouse', 'deleted_contacts' => 1],
+          'params' => [],
+          'return_properties' => NULL,
+          'context' => 'advanced',
+          'action' => CRM_Core_Action::ADVANCED,
+          'includeContactIds' => NULL,
+          'searchDescendentGroups' => FALSE,
+          'limitedPermissions' => TRUE,
+          'expected_query' => [
+            0 => 'default',
+            1 => 'FROM civicrm_contact contact_a LEFT JOIN civicrm_address ON ( contact_a.id = civicrm_address.contact_id AND civicrm_address.is_primary = 1 ) LEFT JOIN civicrm_country ON ( civicrm_address.country_id = civicrm_country.id ) LEFT JOIN civicrm_email ON (contact_a.id = civicrm_email.contact_id AND civicrm_email.is_primary = 1) LEFT JOIN civicrm_phone ON (contact_a.id = civicrm_phone.contact_id AND civicrm_phone.is_primary = 1) LEFT JOIN civicrm_im ON (contact_a.id = civicrm_im.contact_id AND civicrm_im.is_primary = 1) LEFT JOIN civicrm_worldregion ON civicrm_country.region_id = civicrm_worldregion.id INNER JOIN civicrm_acl_contact_cache aclContactCache ON contact_a.id = aclContactCache.contact_id',
+            2 => "WHERE  ( civicrm_email.email LIKE 'mickey@mouseville.com%'  AND ( ( ( contact_a.sort_name LIKE 'Mouse%' ) OR ( civicrm_email.email LIKE 'Mouse%' ) ) ) ) AND  aclContactCache.user_id = 0 AND (contact_a.is_deleted)",
+          ],
+        ],
+      ],
+      [
         [
           'description' => 'Use of quotes for exact string',
           'use_case_comments' => 'This is something that was in the code but seemingly not working. No UI info on it though!',
index 12d68ea8554a826a48a39d5e452fca6831059a46..d34f23c2ee228cc90f415a892415016c84f8d13f 100644 (file)
@@ -225,8 +225,9 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
       'contribution_recur_id' => $contributionRecur['id'],
       'total_amount' => '3.00',
       'financial_type_id' => 1,
+      'source' => 'Template Contribution',
       'payment_instrument_id' => 1,
-      'currency' => 'USD',
+      'currency' => 'AUD',
       'contact_id' => $this->individualCreate(),
       'contribution_status_id' => 1,
       'receive_date' => 'yesterday',
@@ -237,6 +238,7 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
       'contribution_recur_id' => $contributionRecur['id'],
       'total_amount' => '3.00',
       'financial_type_id' => 1,
+      'source' => 'Non-template Contribution',
       'payment_instrument_id' => 1,
       'currency' => 'USD',
       'contact_id' => $this->individualCreate(),
@@ -246,6 +248,13 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
     $fetchedTemplate = CRM_Contribute_BAO_ContributionRecur::getTemplateContribution($contributionRecur['id']);
     // Fetched template should be the is_template, not the latest contrib
     $this->assertEquals($fetchedTemplate['id'], $templateContrib['id']);
+
+    $repeatContribution = $this->callAPISuccess('Contribution', 'repeattransaction', [
+      'contribution_status_id' => 'Completed',
+      'contribution_recur_id' => $contributionRecur['id'],
+    ]);
+    $this->assertEquals('Template Contribution', $repeatContribution['values'][$repeatContribution['id']]['source']);
+    $this->assertEquals('AUD', $repeatContribution['values'][$repeatContribution['id']]['currency']);
   }
 
   /**
@@ -304,7 +313,6 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
       'contact_id' => $contactId1,
       'receive_date' => '2010-01-20',
       'financial_type_id' => 'Member Dues',
-      'contribution_status_id' => 'Pending',
       'contribution_recur_id' => $contributionRecurId,
       'total_amount' => 150,
       'api.Payment.create' => ['total_amount' => 150],
@@ -331,8 +339,8 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
           'contact_id' => $contactId,
           'membership_type_id' => $priceField['membership_type_id'],
           'source' => 'Payment',
-          'join_date' => '2020-04-28',
-          'start_date' => '2020-04-28',
+          'join_date' => date('Y-m', strtotime('1 month ago')) . '-28',
+          'start_date' => date('Y-m') . '-28',
           'contribution_recur_id' => $contributionRecurId,
           'status_id' => 'Pending',
           'is_override' => 1,
@@ -372,13 +380,14 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
     $this->validateAllCounts($membershipId1, 4);
     $this->validateAllCounts($membershipId2, 4);
 
+    $expectedDate = $this->getYearAndMonthFromOffset(4);
     // check membership end date.
     foreach ([$membershipId1, $membershipId2] as $mId) {
       $endDate = $this->callAPISuccessGetValue('Membership', [
         'id' => $mId,
         'return' => 'end_date',
       ]);
-      $this->assertEquals($endDate, '2020-08-27', ts('End date incorrect.'));
+      $this->assertEquals("{$expectedDate['year']}-{$expectedDate['month']}-27", $endDate, ts('End date incorrect.'));
     }
 
     // At this moment Contact 2 is deceased, but we wait until payment is recorded in civi before marking the contact deceased.
@@ -445,7 +454,8 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
       'id' => $membershipId1,
       'return' => 'end_date',
     ]);
-    $this->assertEquals($endDate, '2020-10-27', ts('End date incorrect.'));
+    $expectedDate = $this->getYearAndMonthFromOffset(6);
+    $this->assertEquals("{$expectedDate['year']}-{$expectedDate['month']}-27", $endDate, ts('End date incorrect.'));
     // check line item and membership payment count.
     $this->validateAllCounts($membershipId1, 6);
     $this->validateAllCounts($membershipId2, 4);
@@ -478,4 +488,80 @@ class CRM_Contribute_BAO_ContributionRecurTest extends CiviUnitTestCase {
     $this->callAPISuccessGetCount('MembershipPayment', $memPayParams, $count);
   }
 
+  /**
+   * Given a number of months offset, get the year and month.
+   * Note the way php arithmetic works, using strtotime('+x months') doesn't
+   * work because it will roll over the day accounting for different number
+   * of days in the month, but we want the same day of the month, x months
+   * from now.
+   * e.g. July 31 + 4 months will return Dec 1 if using php functions, but
+   * we want Nov 31.
+   *
+   * @param int $offset
+   * @param int $year Optional input year to start
+   * @param int $month Optional input month to start
+   *
+   * @return array
+   *   ['year' => int, 'month' => int]
+   */
+  private function getYearAndMonthFromOffset(int $offset, int $year = NULL, int $month = NULL) {
+    $dateInfo = [
+      'year' => $year ?? date('Y'),
+      'month' => ($month ?? date('m')) + $offset,
+    ];
+    if ($dateInfo['month'] > 12) {
+      $dateInfo['year']++;
+      $dateInfo['month'] -= 12;
+    }
+    if ($dateInfo['month'] < 10) {
+      $dateInfo['month'] = "0{$dateInfo['month']}";
+    }
+
+    return $dateInfo;
+  }
+
+  /**
+   * Test getYearAndMonthFromOffset
+   * @dataProvider yearMonthProvider
+   *
+   * @param array $input
+   * @param array $expected
+   */
+  public function testGetYearAndMonthFromOffset($input, $expected) {
+    $this->assertEquals($expected, $this->getYearAndMonthFromOffset($input[0], $input[1], $input[2]));
+  }
+
+  /**
+   * data provider for testGetYearAndMonthFromOffset
+   */
+  public function yearMonthProvider() {
+    return [
+      // input = offset, year, current month
+      ['input' => [4, 2020, 1], 'output' => ['year' => '2020', 'month' => '05']],
+      ['input' => [6, 2020, 1], 'output' => ['year' => '2020', 'month' => '07']],
+      ['input' => [4, 2020, 2], 'output' => ['year' => '2020', 'month' => '06']],
+      ['input' => [6, 2020, 2], 'output' => ['year' => '2020', 'month' => '08']],
+      ['input' => [4, 2020, 3], 'output' => ['year' => '2020', 'month' => '07']],
+      ['input' => [6, 2020, 3], 'output' => ['year' => '2020', 'month' => '09']],
+      ['input' => [4, 2020, 4], 'output' => ['year' => '2020', 'month' => '08']],
+      ['input' => [6, 2020, 4], 'output' => ['year' => '2020', 'month' => '10']],
+      ['input' => [4, 2020, 5], 'output' => ['year' => '2020', 'month' => '09']],
+      ['input' => [6, 2020, 5], 'output' => ['year' => '2020', 'month' => '11']],
+      ['input' => [4, 2020, 6], 'output' => ['year' => '2020', 'month' => '10']],
+      ['input' => [6, 2020, 6], 'output' => ['year' => '2020', 'month' => '12']],
+      ['input' => [4, 2020, 7], 'output' => ['year' => '2020', 'month' => '11']],
+      ['input' => [6, 2020, 7], 'output' => ['year' => '2021', 'month' => '01']],
+      ['input' => [4, 2020, 8], 'output' => ['year' => '2020', 'month' => '12']],
+      ['input' => [6, 2020, 8], 'output' => ['year' => '2021', 'month' => '02']],
+      ['input' => [4, 2020, 9], 'output' => ['year' => '2021', 'month' => '01']],
+      ['input' => [6, 2020, 9], 'output' => ['year' => '2021', 'month' => '03']],
+      ['input' => [4, 2020, 10], 'output' => ['year' => '2021', 'month' => '02']],
+      ['input' => [6, 2020, 10], 'output' => ['year' => '2021', 'month' => '04']],
+      ['input' => [4, 2020, 11], 'output' => ['year' => '2021', 'month' => '03']],
+      ['input' => [6, 2020, 11], 'output' => ['year' => '2021', 'month' => '05']],
+      ['input' => [4, 2020, 12], 'output' => ['year' => '2021', 'month' => '04']],
+      ['input' => [6, 2020, 12], 'output' => ['year' => '2021', 'month' => '06']],
+    ];
+  }
+
 }
index a9cbb37184448d9c9856175cdee38fdde8c49b0c..1a06b3df1ff778fa78ce98e4406201c9981d5dd9 100644 (file)
@@ -685,7 +685,7 @@ WHERE eft.entity_id = %1 AND ft.to_financial_account_id <> %2";
   /**
    * Add participant with contribution
    *
-   * @return array
+   * @return CRM_Contribute_BAO_Contribution
    *
    * @throws \CRM_Core_Exception
    * @throws \CiviCRM_API3_Exception
@@ -695,7 +695,7 @@ WHERE eft.entity_id = %1 AND ft.to_financial_account_id <> %2";
     $this->_contactId = $this->individualCreate();
     $event = $this->eventCreatePaid([]);
     $this->_eventId = $event['id'];
-    $priceSetId = $this->priceSetID;
+    $priceSetID = $this->ids['PriceSet']['event'];
     $paramsField = [
       'label' => 'Price Field',
       'name' => CRM_Utils_String::titleToVar('Price Field'),
@@ -709,7 +709,7 @@ WHERE eft.entity_id = %1 AND ft.to_financial_account_id <> %2";
       'weight' => 1,
       'options_per_line' => 1,
       'is_active' => ['1' => 1, '2' => 1],
-      'price_set_id' => $this->priceSetID,
+      'price_set_id' => $priceSetID,
       'is_enter_qty' => 1,
       'financial_type_id' => CRM_Core_DAO::getFieldValue('CRM_Financial_DAO_FinancialType', 'Event Fee', 'id', 'name'),
     ];
@@ -720,7 +720,7 @@ WHERE eft.entity_id = %1 AND ft.to_financial_account_id <> %2";
       'is_monetary' => 1,
     ];
     CRM_Event_BAO_Event::create($eventParams);
-    CRM_Price_BAO_PriceSet::addTo('civicrm_event', $this->_eventId, $priceSetId);
+    CRM_Price_BAO_PriceSet::addTo('civicrm_event', $this->_eventId, $priceSetID);
 
     $priceFields = $this->callAPISuccess('PriceFieldValue', 'get', ['price_field_id' => $priceField->id]);
     $participantParams = [
index 358a8bf4867e12b6104701aabdd10736f8a0246c..bb5e440731bf5b0c9cd2048e7dbbce6b373aa5b0 100644 (file)
@@ -1696,4 +1696,29 @@ Price Field - Price Field 1        1   $ 100.00      $ 100.00
     $this->membershipDelete($membership['id']);
   }
 
+  /**
+   * Test no warnings or errors during preProcess when editing.
+   */
+  public function testPreProcessContributionEdit() {
+    // Simulate a contribution in pending status
+    $contribution = $this->callAPISuccess(
+      'Contribution',
+      'create',
+      array_merge($this->_params, ['contribution_status_id' => 'Pending'])
+    );
+
+    // set up the form to edit the contribution and call preProcess
+    $form = $this->getFormObject('CRM_Contribute_Form_Contribution');
+    $_REQUEST['cid'] = $this->_individualId;
+    $_REQUEST['id'] = $contribution['id'];
+    $form->_action = CRM_Core_Action::UPDATE;
+    $form->preProcess();
+
+    // Check something while we're here
+    $this->assertEquals($contribution['id'], $form->_values['contribution_id']);
+
+    unset($_REQUEST['cid']);
+    unset($_REQUEST['id']);
+  }
+
 }
index a38b8a2e958e76b727d47b2a1f3dbe8b9a60257a..01172c613359889fd893bfbd85a6f5d7cbf73086 100644 (file)
@@ -136,7 +136,6 @@ class CRM_Contribute_Form_Task_InvoiceTest extends CiviUnitTestCase {
         return $total;
       }),
       'financial_type_id' => $priceFieldValues['values'][0]['financial_type_id'],
-      'contribution_status_id' => 'Pending',
       'currency' => 'USD',
       'line_items' => $lineItemParams,
     ];
index a7db1889cea2ba1614a06c09daee085307726dbc..a34da16c816975064121b44e6d735e6a5720de85 100644 (file)
@@ -75,7 +75,6 @@ class CRM_Core_BAO_CacheTest extends CiviUnitTestCase {
     // Wipe out any in-memory copies of the cache. Check to see if the SQL
     // read is correct.
 
-    CRM_Core_BAO_Cache::$_cache = NULL;
     CRM_Utils_Cache::$_singleton = NULL;
     $this->a->values = [];
     $return_2 = $this->a->get('testSetGetItem');
index b402fbab73c727a514c21d6943dff5cbc8a652ff..269e3d519dbc5854065f7f2f1699fffc056f05b9 100644 (file)
@@ -93,7 +93,7 @@ class CRM_Core_Payment_AuthorizeNetIPNTest extends CiviUnitTestCase {
         'billing_country_id-5' => 1228,
         'frequency_interval' => 1,
         'frequency_unit' => 'month',
-        'installments' => '',
+        'installments' => 2,
         'hidden_AdditionalDetail' => 1,
         'hidden_Premium' => 1,
         'payment_processor_id' => $this->_paymentProcessorID,
@@ -109,24 +109,30 @@ class CRM_Core_Payment_AuthorizeNetIPNTest extends CiviUnitTestCase {
     $this->_contributionID = $contribution->id;
     $this->ids['Contribution'][0] = $contribution->id;
     $this->_contributionRecurID = $contribution->contribution_recur_id;
-    $recur_params = [
-      'id' => $this->_contributionRecurID,
-      'return' => 'processor_id',
-    ];
-    $processor_id = civicrm_api3('ContributionRecur', 'getvalue', $recur_params);
-    // Process the initial one.
+
+    $contributionRecur  = $this->callAPISuccessGetSingle('ContributionRecur', ['id' => $this->_contributionRecurID]);
+    $processor_id = $contributionRecur['processor_id'];
+    $this->assertEquals('Pending', CRM_Core_PseudoConstant::getName('CRM_Contribute_BAO_Contribution', 'contribution_status_id', $contributionRecur['contribution_status_id']));
+    // Process the initial one after a second's break to ensure modified date really is later.
+    sleep(1);
     $IPN = new CRM_Core_Payment_AuthorizeNetIPN(
       $this->getRecurTransaction(['x_subscription_id' => $processor_id])
     );
     $IPN->main();
+    $updatedContributionRecur = $this->callAPISuccessGetSingle('ContributionRecur', ['id' => $this->_contributionRecurID]);
+    $this->assertEquals('In Progress', CRM_Core_PseudoConstant::getName('CRM_Contribute_BAO_ContributionRecur', 'contribution_status_id', $updatedContributionRecur['contribution_status_id']));
+    $this->assertTrue(strtotime($updatedContributionRecur['modified_date']) > strtotime($contributionRecur['modified_date']));
 
     // Now send a second one (authorize seems to treat first and second contributions
     // differently.
-    $IPN = new CRM_Core_Payment_AuthorizeNetIPN($this->getRecurSubsequentTransaction(
-      ['x_subscription_id' => $processor_id]
-    ));
+    $IPN = new CRM_Core_Payment_AuthorizeNetIPN($this->getRecurSubsequentTransaction([
+      'x_subscription_id' => $processor_id,
+      'x_subscription_paynum' => 2,
+    ]));
     $IPN->main();
-
+    $updatedContributionRecurAgain = $this->callAPISuccessGetSingle('ContributionRecur', ['id' => $this->_contributionRecurID]);
+    $this->assertEquals('Completed', CRM_Core_PseudoConstant::getName('CRM_Contribute_BAO_ContributionRecur', 'contribution_status_id', $updatedContributionRecurAgain['contribution_status_id']));
+    $this->assertEquals(date('Y-m-d'), substr($updatedContributionRecurAgain['end_date'], 0, 10));
     // There should not be any email.
     $mut->assertMailLogEmpty();
   }
index 746dc8c1a7fe544c9d1d3f3d7153e6529248c138..acc4eb5433ee77de98b54119281d5a4d0dcf16f5 100644 (file)
@@ -93,7 +93,6 @@ class CRM_Core_Payment_BaseIPNTest extends CiviUnitTestCase {
    */
   public function tearDown() {
     $this->quickCleanUpFinancialEntities();
-    CRM_Member_PseudoConstant::membershipType(NULL, TRUE);
     CRM_Member_PseudoConstant::membershipStatus(NULL, NULL, 'name', TRUE);
   }
 
@@ -104,12 +103,12 @@ class CRM_Core_Payment_BaseIPNTest extends CiviUnitTestCase {
     $this->_setUpMembershipObjects();
     $this->_setUpRecurringContribution();
     $this->IPN->loadObjects($this->input, $this->ids, $this->objects, FALSE, $this->_processorId);
-    $this->assertFalse(empty($this->objects['membership']));
+    $this->assertNotEmpty($this->objects['membership']);
     $this->assertArrayHasKey($this->_membershipTypeID, $this->objects['membership']);
     $this->assertTrue(is_a($this->objects['membership'][$this->_membershipTypeID], 'CRM_Member_BAO_Membership'));
     $this->assertTrue(is_a($this->objects['financialType'], 'CRM_Financial_BAO_FinancialType'));
-    $this->assertFalse(empty($this->objects['contributionRecur']));
-    $this->assertFalse(empty($this->objects['paymentProcessor']));
+    $this->assertNotEmpty($this->objects['contributionRecur']);
+    $this->assertNotEmpty($this->objects['paymentProcessor']);
   }
 
   /**
@@ -145,7 +144,7 @@ class CRM_Core_Payment_BaseIPNTest extends CiviUnitTestCase {
     $contribution->id = $this->_contributionId;
     $contribution->find(TRUE);
     $contribution->loadRelatedObjects($this->input, $this->ids, TRUE);
-    $this->assertFalse(empty($contribution->_relatedObjects['membership']));
+    $this->assertNotEmpty($contribution->_relatedObjects['membership']);
     $this->assertArrayHasKey($this->_membershipTypeID, $contribution->_relatedObjects['membership']);
     $this->assertTrue(is_a($contribution->_relatedObjects['membership'][$this->_membershipTypeID], 'CRM_Member_BAO_Membership'));
     $this->assertTrue(is_a($contribution->_relatedObjects['financialType'], 'CRM_Financial_BAO_FinancialType'));
@@ -156,12 +155,13 @@ class CRM_Core_Payment_BaseIPNTest extends CiviUnitTestCase {
   /**
    * Test the LoadObjects function with recurring membership data.
    */
-  public function testsendMailMembershipObjects() {
+  public function testSendMailMembershipObjects() {
     $this->_setUpMembershipObjects();
+    $contribution = new CRM_Contribute_BAO_Contribution();
+    $contribution->id = $this->_contributionId;
     $values = [];
-    $this->IPN->loadObjects($this->input, $this->ids, $this->objects, FALSE, $this->_processorId);
-    $msg = $this->IPN->sendMail($this->input, $this->ids, $this->objects, $values, FALSE, TRUE);
-    $this->assertTrue(is_array($msg), "Message returned as an array in line");
+    $msg = $contribution->composeMessageArray($this->input, $this->ids, $values);
+    $this->assertInternalType('array', $msg, 'Message returned as an array in line');
     $this->assertEquals('Mr. Anthony Anderson II', $msg['to']);
     $this->assertContains('Membership Type: General', $msg['body']);
   }
@@ -173,9 +173,10 @@ class CRM_Core_Payment_BaseIPNTest extends CiviUnitTestCase {
    */
   public function testSendMailMembershipObjectsNoLeakage() {
     $this->_setUpMembershipObjects();
+    $contribution = new CRM_Contribute_BAO_Contribution();
     $values = [];
-    $this->IPN->loadObjects($this->input, $this->ids, $this->objects, FALSE, $this->_processorId);
-    $msg = $this->IPN->sendMail($this->input, $this->ids, $this->objects, $values, FALSE, TRUE);
+    $contribution->id = $this->_contributionId;
+    $msg = $contribution->composeMessageArray($this->input, $this->ids, $values);
     $this->assertEquals('Mr. Anthony Anderson II', $msg['to']);
     $this->assertContains('Membership Type: General', $msg['body']);
 
@@ -188,7 +189,9 @@ class CRM_Core_Payment_BaseIPNTest extends CiviUnitTestCase {
     $this->input['invoiceID'] = 'abc';
     $this->IPN->loadObjects($this->input, $this->ids, $this->objects, FALSE, $this->_processorId);
     $this->assertEquals('Donald', $this->objects['contact']->first_name);
-    $msg = $this->IPN->sendMail($this->input, $this->ids, $this->objects, $values, FALSE, TRUE);
+    $contribution = new CRM_Contribute_BAO_Contribution();
+    $contribution->id = $this->_contributionId;
+    $msg = $contribution->composeMessageArray($this->input, $this->ids, $values);
     $this->assertEquals('Dr. Donald Duck II', $msg['to']);
     $this->assertContains('Membership Type: Fowl', $msg['body']);
   }
@@ -196,11 +199,12 @@ class CRM_Core_Payment_BaseIPNTest extends CiviUnitTestCase {
   /**
    * Test the LoadObjects function with recurring membership data.
    */
-  public function testsendMailMembershipWithoutLoadObjects() {
+  public function testSendMailMembershipWithoutLoadObjects() {
     $this->_setUpMembershipObjects();
-    $values = [];
-    $msg = $this->IPN->sendMail($this->input, $this->ids, $this->objects, $values, FALSE, TRUE);
-    $this->assertTrue(is_array($msg), "Message returned as an array in line" . __LINE__);
+    $contribution = new CRM_Contribute_BAO_Contribution();
+    $contribution->id = $this->_contributionId;
+    $msg = $contribution->composeMessageArray($this->input, $this->ids, $values);
+    $this->assertInternalType('array', $msg, 'Message not returned as an array');
     $this->assertEquals('Mr. Anthony Anderson II', $msg['to']);
     $this->assertContains('Membership Type: General', $msg['body']);
   }
@@ -217,7 +221,7 @@ class CRM_Core_Payment_BaseIPNTest extends CiviUnitTestCase {
     $this->assertFalse(empty($this->objects['event']));
     $this->assertTrue(is_a($this->objects['event'], 'CRM_Event_BAO_Event'));
     $this->assertTrue(is_a($this->objects['contribution'], 'CRM_Contribute_BAO_Contribution'));
-    $this->assertFalse(empty($this->objects['event']->id));
+    $this->assertNotEmpty($this->objects['event']->id);
   }
 
   /**
@@ -227,8 +231,10 @@ class CRM_Core_Payment_BaseIPNTest extends CiviUnitTestCase {
     $this->_setUpParticipantObjects();
     $this->IPN->loadObjects($this->input, $this->ids, $this->objects, FALSE, $this->_processorId);
     $values = [];
-    $this->assertFalse(empty($this->objects['event']));
-    $msg = $this->IPN->sendMail($this->input, $this->ids, $this->objects, $values, FALSE, TRUE);
+    $this->assertNotEmpty($this->objects['event']);
+    $contribution = new CRM_Contribute_BAO_Contribution();
+    $contribution->id = $this->_contributionId;
+    $msg = $contribution->composeMessageArray($this->input, $this->ids, $values);
     $this->assertContains('registration has been received and your status has been updated to Attended.', $msg['body']);
     $this->assertContains('Annual CiviCRM meet', $msg['html']);
   }
@@ -237,9 +243,9 @@ class CRM_Core_Payment_BaseIPNTest extends CiviUnitTestCase {
    */
   public function testComposeMailParticipantObjects() {
     $this->_setUpParticipantObjects();
-    $values = [];
-    $msg = $this->IPN->sendMail($this->input, $this->ids, $this->objects, $values, FALSE, TRUE);
-    $this->assertTrue(is_array($msg), "Message returned as an array in line" . __LINE__);
+    $contribution = new CRM_Contribute_BAO_Contribution();
+    $contribution->id = $this->_contributionId;
+    $msg = $contribution->composeMessageArray($this->input, $this->ids, $values);
     $this->assertEquals('Mr. Anthony Anderson II', $msg['to']);
     $this->assertContains('Thank you for your registration', $msg['body']);
   }
@@ -247,12 +253,12 @@ class CRM_Core_Payment_BaseIPNTest extends CiviUnitTestCase {
   /**
    * Test the LoadObjects function with recurring membership data.
    */
-  public function testsendMailParticipantObjectsCheckLog() {
+  public function testSendMailParticipantObjectsCheckLog() {
     $this->_setUpParticipantObjects();
-    $values = [];
     $mut = new CiviMailUtils($this, TRUE);
-    $this->IPN->loadObjects($this->input, $this->ids, $this->objects, FALSE, $this->_processorId);
-    $this->IPN->sendMail($this->input, $this->ids, $this->objects, $values, FALSE, FALSE);
+    $this->callAPISuccess('Contribution', 'sendconfirmation', [
+      'id' => $this->_contributionId,
+    ]);
     $mut->checkMailLog([
       'Thank you for your registration',
       'Annual CiviCRM meet',
@@ -276,8 +282,9 @@ class CRM_Core_Payment_BaseIPNTest extends CiviUnitTestCase {
     ];
     $this->quickCleanup($tablesToTruncate, FALSE);
     $mut = new CiviMailUtils($this, TRUE);
-    $this->IPN->loadObjects($this->input, $this->ids, $this->objects, FALSE, $this->_processorId);
-    $this->IPN->sendMail($this->input, $this->ids, $this->objects, $values, FALSE, FALSE);
+    $contribution = new CRM_Contribute_BAO_Contribution();
+    $contribution->id = $this->_contributionId;
+    $msg = $contribution->composeMessageArray($this->input, $this->ids, $values);
     $mut->assertMailLogEmpty('no mail should have been send as event set to no confirm');
     $mut->stop();
   }
@@ -330,11 +337,11 @@ class CRM_Core_Payment_BaseIPNTest extends CiviUnitTestCase {
   /**
    * Test the LoadObjects function with a pledge.
    */
-  public function testsendMailPledge() {
+  public function testSendMailPledge() {
     $this->_setUpPledgeObjects();
-    $values = [];
-    $this->IPN->loadObjects($this->input, $this->ids, $this->objects, FALSE, NULL);
-    $msg = $this->IPN->sendMail($this->input, $this->ids, $this->objects, $values, FALSE, TRUE);
+    $contribution = new CRM_Contribute_BAO_Contribution();
+    $contribution->id = $this->_contributionId;
+    $msg = $contribution->composeMessageArray($this->input, $this->ids, $values);
     $this->assertContains('Contribution Information', $msg['html']);
   }
 
index 421afbef93833b4663d8bd0bdbd060b7f5206a87..120253be360fe09ab72ea8fbb4bb31ee662bbfef 100644 (file)
@@ -15,6 +15,8 @@
  */
 class CRM_Event_BAO_EventPermissionsTest extends CiviUnitTestCase {
 
+  use CRMTraits_ACL_PermissionTrait;
+
   public function setUp() {
     parent::setUp();
     $this->_contactId = $this->createLoggedInUser();
@@ -99,9 +101,18 @@ class CRM_Event_BAO_EventPermissionsTest extends CiviUnitTestCase {
     $this->assertTrue($permissions);
   }
 
+  /**
+   * Test that the contact can view an event with an ACL permitting everyone to view it.
+   */
+  public function testViewAclEventAllowed() {
+    $this->setupScenarioCoreACLEveryonePermittedToEvent();
+    $permittedEventID = CRM_Core_Permission::event(CRM_Core_Permission::VIEW, $this->scenarioIDs['Event']['permitted_event']);
+    $this->assertEquals($this->scenarioIDs['Event']['permitted_event'], $permittedEventID);
+  }
+
   public function testEditOtherEventDenied() {
     $this->_loggedInUser = CRM_Core_Session::singleton()->get('userID');
-    self::setViewAllEventPermissions();
+    $this->setViewAllEventPermissions();
     unset(\Civi::$statics['CRM_Event_BAO_Event']['permissions']);
     $permissions = CRM_Event_BAO_Event::checkPermission($this->_otherEventId, CRM_Core_Permission::EDIT);
     $this->assertFalse($permissions);
index 0a3cba0fd9c5de0e1c6f7b92e562707446cee40c..eb8dc5700842b0a681e17e3baeeedf799c3716ce 100644 (file)
@@ -434,27 +434,14 @@ class CRM_Event_BAO_ParticipantTest extends CiviUnitTestCase {
       'start_date' => $startDate,
     ]);
     $url = CRM_Utils_System::url('civicrm/event/info', "reset=1&id={$this->_eventId}");
-    // If we return without an error, then success.  But we don't always expect success.
-    try {
-      CRM_Event_BAO_Participant::getSelfServiceEligibility($participantId, $url, $isBackOffice);
-    }
-    catch (\Exception $e) {
-      if ($successExpected === FALSE) {
-        return;
-      }
-      else {
-        $this->fail();
-      }
-    }
-    if ($successExpected === FALSE) {
-      $this->fail();
-    }
+    $details = CRM_Event_BAO_Participant::getSelfServiceEligibility($participantId, $url, $isBackOffice);
+    $this->assertEquals($details['eligible'], $successExpected);
   }
 
   public function selfServiceScenarios() {
     // Standard pass scenario
     $scenarios[] = [
-      'selfSvcEnabled' => TRUE,
+      'selfSvcEnabled' => 1,
       'selfSvcHours' => 12,
       'hoursToEvent' => 16,
       'participantStatusId' => 1,
@@ -463,7 +450,7 @@ class CRM_Event_BAO_ParticipantTest extends CiviUnitTestCase {
     ];
     // Too late to self-service
     $scenarios[] = [
-      'selfSvcEnabled' => TRUE,
+      'selfSvcEnabled' => 1,
       'selfSvcHours' => 12,
       'hoursToEvent' => 8,
       'participantStatusId' => 1,
@@ -472,13 +459,40 @@ class CRM_Event_BAO_ParticipantTest extends CiviUnitTestCase {
     ];
     // Participant status is other than "Registered".
     $scenarios[] = [
-      'selfSvcEnabled' => TRUE,
+      'selfSvcEnabled' => 1,
       'selfSvcHours' => 12,
       'hoursToEvent' => 16,
       'participantStatusId' => 2,
       'isBackOffice' => FALSE,
       'successExpected' => FALSE,
     ];
+    // Event doesn't allow self-service
+    $scenarios[] = [
+      'selfSvcEnabled' => 0,
+      'selfSvcHours' => 12,
+      'hoursToEvent' => 16,
+      'participantStatusId' => 1,
+      'isBackOffice' => FALSE,
+      'successExpected' => FALSE,
+    ];
+    // Cancellation deadline is > 24 hours, still ok to cancel
+    $scenarios[] = [
+      'selfSvcEnabled' => 1,
+      'selfSvcHours' => 36,
+      'hoursToEvent' => 46,
+      'participantStatusId' => 1,
+      'isBackOffice' => FALSE,
+      'successExpected' => TRUE,
+    ];
+    // Cancellation deadline is > 24 hours, too late to cancel
+    $scenarios[] = [
+      'selfSvcEnabled' => 1,
+      'selfSvcHours' => 36,
+      'hoursToEvent' => 25,
+      'participantStatusId' => 1,
+      'isBackOffice' => FALSE,
+      'successExpected' => FALSE,
+    ];
     return $scenarios;
   }
 
index d96c4e9ff5d31e0e97ead59114fba73f40691906..cdb0ae133c6782d223b7b93dfe0b3ceb0c767134 100644 (file)
@@ -859,7 +859,7 @@ class CRM_Event_Form_ParticipantTest extends CiviUnitTestCase {
    * @return int
    */
   protected function getEventID(): int {
-    return $this->ids['event']['event'];
+    return $this->ids['Event']['event'];
   }
 
   /**
diff --git a/tests/phpunit/CRM/Event/Form/Task/ParticipantStatusTest.php b/tests/phpunit/CRM/Event/Form/Task/ParticipantStatusTest.php
new file mode 100644 (file)
index 0000000..ac809b1
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ *  Test CRM_Event_Form_Registration functions.
+ *
+ * @package   CiviCRM
+ * @group headless
+ */
+class CRM_Event_Form_Task_ParticipantStatusTest extends CiviUnitTestCase {
+
+  /**
+   * Test the the submit function on the event participant submit function.
+   *
+   * @todo extract submit functions on other Batch update classes, use dataprovider to test on all.
+   */
+  public function testSubmit() {
+    $group = $this->customGroupCreate(['extends' => 'Participant', 'title' => 'Participant']);
+    $field = $this->customFieldCreate(['custom_group_id' => $group['id'], 'html_type' => 'CheckBox', 'option_values' => ['two' => 'A couple', 'three' => 'A few', 'four' => 'Too Many']]);
+    $participantID = $this->participantCreate();
+    $participant = $this->callAPISuccessGetSingle('Participant', ['id' => $participantID]);
+    $this->assertEquals(2, $participant['participant_status_id']);
+
+    $form = $this->getFormObject('CRM_Event_Form_Task_Batch');
+    $form->submit(['field' => [$participantID => ['participant_status_id' => 1, 'custom_' . $field['id'] => ['two' => 1, 'four' => 1]]]]);
+
+    $participant = $this->callAPISuccessGetSingle('Participant', ['id' => $participantID]);
+    $this->assertEquals(1, $participant['participant_status_id']);
+  }
+
+}
index 649bbde3ba1fa049525b75b8847b42a813df8e7e..dd0eb83661bf4507aa3ca1bf828ad0df07907d36 100644 (file)
@@ -279,7 +279,7 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       'Phone Extension' => '',
       'Phone Type' => '',
       'Email' => 'home@example.com',
-      'On Hold' => '',
+      'On Hold' => 'No',
       'Use for Bulk Mail' => '',
       'Signature Text' => '',
       'Signature Html' => '',
@@ -1089,7 +1089,7 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       'Phone Extension' => '',
       'Phone Type' => '',
       'Email' => 'home@example.com',
-      'On Hold' => '',
+      'On Hold' => 'No',
       'Use for Bulk Mail' => '',
       'Signature Text' => '',
       'Signature Html' => '',
@@ -1725,9 +1725,8 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       'case_type' => 1,
       'case_role' => 1,
       'case_deleted' => 1,
-      'case_recent_activity_date' => 1,
-      'case_recent_activity_type' => 1,
-      'case_scheduled_activity_date' => 1,
+      'case_activity_date_time' => 1,
+      'case_activity_type' => 1,
     ];
   }
 
@@ -2288,23 +2287,22 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
     return [
       82 => 'Contact ID',
       83 => 'Case ID',
-      84 => 'case_activity_subject',
+      84 => 'Subject',
       85 => 'Case Subject',
       86 => 'Case Status',
       87 => 'Case Type',
       88 => 'Role in Case',
       89 => 'Case is in the Trash',
-      90 => 'case_recent_activity_date',
-      91 => 'case_recent_activity_type',
-      92 => 'case_scheduled_activity_date',
+      90 => 'Activity Date',
+      91 => 'Activity Type',
       93 => 'Case Start Date',
       94 => 'Case End Date',
-      95 => 'case_source_contact_id',
-      96 => 'case_activity_status',
-      97 => 'case_activity_duration',
-      98 => 'case_activity_medium_id',
-      99 => 'case_activity_details',
-      100 => 'case_activity_is_auto',
+      95 => 'Activity Reporter',
+      96 => 'Activity Status',
+      97 => 'Duration',
+      98 => 'Activity Medium',
+      99 => 'Details',
+      100 => 'Activity Auto-generated?',
     ];
   }
 
@@ -2554,21 +2552,20 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
       'case_end_date' => '`case_end_date` varchar(32)',
       'case_subject' => '`case_subject` varchar(128)',
       'case_source_contact_id' => '`case_source_contact_id` varchar(255)',
-      'case_activity_status' => '`case_activity_status` text',
-      'case_activity_duration' => '`case_activity_duration` text',
-      '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',
+      'case_activity_status' => '`case_activity_status` varchar(255)',
+      'case_activity_duration' => '`case_activity_duration` varchar(16)',
+      'case_activity_medium_id' => '`case_activity_medium_id` varchar(16)',
+      'case_activity_details' => '`case_activity_details` longtext',
+      'case_activity_is_auto' => '`case_activity_is_auto` varchar(16)',
       'contact_id' => '`contact_id` varchar(16)',
       'case_id' => '`case_id` varchar(16)',
-      'case_activity_subject' => '`case_activity_subject` text',
+      'case_activity_subject' => '`case_activity_subject` varchar(255)',
       'case_status' => '`case_status` text',
       'case_type' => '`case_type` text',
       'case_role' => '`case_role` text',
       'case_deleted' => '`case_deleted` varchar(16)',
-      'case_recent_activity_date' => '`case_recent_activity_date` text',
-      'case_recent_activity_type' => '`case_recent_activity_type` text',
-      'case_scheduled_activity_date' => '`case_scheduled_activity_date` text',
+      'case_activity_date_time' => '`case_activity_date_time` varchar(32)',
+      'case_activity_type' => '`case_activity_type` varchar(255)',
     ];
   }
 
@@ -2896,7 +2893,7 @@ class CRM_Export_BAO_ExportTest extends CiviUnitTestCase {
         $this->assertContains($row[$key], $alternatives[$key]);
       }
       else {
-        $this->assertEquals($value, $row[$key]);
+        $this->assertEquals($value, $row[$key], 'mismatch on ' . $key);
       }
     }
   }
index e7c4ef15bf721b4afb6a6905de675cc441b66fe8..09bf5353f5551e80f0eaa807a29c8cd90d6219ab 100644 (file)
@@ -35,6 +35,8 @@ class CRM_Member_BAO_MembershipStatusTest extends CiviUnitTestCase {
       'Database check on updated membership status record.'
     );
     $this->assertEquals($result, 'pending', 'Verify membership status is_active.');
+
+    $this->callAPISuccess('MembershipStatus', 'Delete', ['id' => $membershipStatus->id]);
   }
 
   public function testRetrieve() {
@@ -88,6 +90,8 @@ class CRM_Member_BAO_MembershipStatusTest extends CiviUnitTestCase {
       'Database check on updated membership status record.'
     );
     $this->assertEquals($isActive, 0, 'Verify membership status is_active.');
+
+    $this->callAPISuccess('MembershipStatus', 'Delete', ['id' => $membershipStatus->id]);
   }
 
   public function testGetMembershipStatus() {
@@ -99,6 +103,8 @@ class CRM_Member_BAO_MembershipStatusTest extends CiviUnitTestCase {
     $membershipStatus = CRM_Member_BAO_MembershipStatus::add($params);
     $result = CRM_Member_BAO_MembershipStatus::getMembershipStatus($membershipStatus->id);
     $this->assertEquals($result['name'], 'pending', 'Verify membership status name.');
+
+    $this->callAPISuccess('MembershipStatus', 'Delete', ['id' => $membershipStatus->id]);
   }
 
   public function testDel() {
@@ -157,6 +163,7 @@ class CRM_Member_BAO_MembershipStatusTest extends CiviUnitTestCase {
       'is_active' => 1,
       'is_reserved' => 0,
     ]);
+    CRM_Core_DAO::executeQuery("UPDATE civicrm_membership_status SET id=4 WHERE name='Expired'");
 
   }
 
@@ -173,6 +180,244 @@ class CRM_Member_BAO_MembershipStatusTest extends CiviUnitTestCase {
 
     $result = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($toDate, $toDate, $toDate, 'today', TRUE, NULL, $params);
     $this->assertEquals($result['name'], 'Current', 'Verify membership status record.');
+
+    $this->callAPISuccess('MembershipStatus', 'Delete', ['id' => $membershipStatus->id]);
+  }
+
+  /**
+   * Test getMembershipStatusByDate more
+   *
+   * @dataProvider statusByDateProvider
+   *
+   * @param array $input
+   * @param array $expected
+   */
+  public function testGetMembershipStatusByDateMore($input, $expected) {
+    // Sanity check we have something close to the stock install.
+    $this->assertEquals(7, $this->callAPISuccess('MembershipStatus', 'getcount'));
+
+    $this->assertEquals(
+      $expected,
+      CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate(
+        $input['startDate'],
+        $input['endDate'],
+        $input['joinDate'],
+        $input['statusDate']
+      )
+    );
+  }
+
+  /**
+   * Data provider for testGetMembershipStatusByDateMore
+   * @return array
+   */
+  public function statusByDateProvider():array {
+    return [
+      [
+        [
+          'startDate' => '2020-02-01',
+          'endDate' => '2020-04-30',
+          'joinDate' => '2020-01-01',
+          'statusDate' => '2020-03-01',
+        ],
+        [
+          'id' => '1',
+          'name' => 'New',
+        ],
+      ],
+      [
+        [
+          'startDate' => '2020-02-01',
+          'endDate' => '2020-04-30',
+          'joinDate' => '2020-01-01',
+          'statusDate' => '2020-04-29',
+        ],
+        [
+          'id' => '2',
+          'name' => 'Current',
+        ],
+      ],
+      [
+        [
+          'startDate' => '2020-02-01',
+          'endDate' => '2020-04-30',
+          'joinDate' => '2020-01-01',
+          'statusDate' => '2020-05-01',
+        ],
+        [
+          'id' => '3',
+          'name' => 'Grace',
+        ],
+      ],
+      [
+        [
+          'startDate' => '2020-02-01',
+          'endDate' => '2020-04-30',
+          'joinDate' => '2020-01-01',
+          'statusDate' => '2020-06-01',
+        ],
+        [
+          'id' => '4',
+          'name' => 'Expired',
+        ],
+      ],
+      [
+        [
+          'startDate' => '2020-02-01',
+          'endDate' => '2020-04-30',
+          'joinDate' => '2019-01-01',
+          'statusDate' => '2020-03-01',
+        ],
+        [
+          'id' => '2',
+          'name' => 'Current',
+        ],
+      ],
+      [
+        [
+          'startDate' => '2020-02-01',
+          'endDate' => '2020-04-30',
+          'joinDate' => '2019-01-01',
+          'statusDate' => '2020-04-29',
+        ],
+        [
+          'id' => '2',
+          'name' => 'Current',
+        ],
+      ],
+      [
+        [
+          'startDate' => '2020-02-01',
+          'endDate' => '2020-04-30',
+          'joinDate' => '2019-01-01',
+          'statusDate' => '2020-05-01',
+        ],
+        [
+          'id' => '3',
+          'name' => 'Grace',
+        ],
+      ],
+      [
+        [
+          'startDate' => '2020-02-01',
+          'endDate' => '2020-04-30',
+          'joinDate' => '2019-01-01',
+          'statusDate' => '2020-06-01',
+        ],
+        [
+          'id' => '4',
+          'name' => 'Expired',
+        ],
+      ],
+      [
+        [
+          'startDate' => '2020-02-01',
+          'endDate' => '2021-01-31',
+          'joinDate' => '2020-01-01',
+          'statusDate' => '2020-03-01',
+        ],
+        [
+          'id' => '1',
+          'name' => 'New',
+        ],
+      ],
+      [
+        [
+          'startDate' => '2020-02-01',
+          'endDate' => '2021-01-31',
+          'joinDate' => '2020-01-01',
+          'statusDate' => '2020-04-29',
+        ],
+        [
+          'id' => '2',
+          'name' => 'Current',
+        ],
+      ],
+      [
+        [
+          'startDate' => '2020-02-01',
+          'endDate' => '2021-01-31',
+          'joinDate' => '2020-01-01',
+          'statusDate' => '2020-12-30',
+        ],
+        [
+          'id' => '2',
+          'name' => 'Current',
+        ],
+      ],
+      [
+        [
+          'startDate' => '2020-02-01',
+          'endDate' => '2021-01-31',
+          'joinDate' => '2020-01-01',
+          'statusDate' => '2021-01-01',
+        ],
+        [
+          'id' => '2',
+          'name' => 'Current',
+        ],
+      ],
+      [
+        [
+          'startDate' => '2020-02-01',
+          'endDate' => '2021-01-31',
+          'joinDate' => '2020-01-01',
+          'statusDate' => '2021-01-31',
+        ],
+        [
+          'id' => '2',
+          'name' => 'Current',
+        ],
+      ],
+      [
+        [
+          'startDate' => '2020-02-01',
+          'endDate' => '2021-01-31',
+          'joinDate' => '2020-01-01',
+          'statusDate' => '2021-02-21',
+        ],
+        [
+          'id' => '3',
+          'name' => 'Grace',
+        ],
+      ],
+      [
+        [
+          'startDate' => '2020-02-01',
+          'endDate' => '2021-01-31',
+          'joinDate' => '2020-01-01',
+          'statusDate' => '2021-03-21',
+        ],
+        [
+          'id' => '4',
+          'name' => 'Expired',
+        ],
+      ],
+      [
+        [
+          'startDate' => '2020-02-01',
+          'endDate' => '',
+          'joinDate' => '2020-01-01',
+          'statusDate' => '2020-03-01',
+        ],
+        [
+          'id' => '1',
+          'name' => 'New',
+        ],
+      ],
+      [
+        [
+          'startDate' => '2020-02-01',
+          'endDate' => '',
+          'joinDate' => '2020-01-01',
+          'statusDate' => '2020-06-01',
+        ],
+        [
+          'id' => '2',
+          'name' => 'Current',
+        ],
+      ],
+    ];
   }
 
   public function testgetMembershipStatusCurrent() {
@@ -186,6 +431,8 @@ class CRM_Member_BAO_MembershipStatusTest extends CiviUnitTestCase {
     $result = CRM_Member_BAO_MembershipStatus::getMembershipStatusCurrent();
 
     $this->assertEquals(empty($result), FALSE, 'Verify membership status records is_current_member.');
+
+    $this->callAPISuccess('MembershipStatus', 'Delete', ['id' => $membershipStatus->id]);
   }
 
 }
index fc4feafb0899959b1f39292b76a97fdba6427ebd..d03f933036dc0f44714edf39d21459145a38ee50 100644 (file)
@@ -123,4 +123,133 @@ class CRM_PCP_BAO_PCPTest extends CiviUnitTestCase {
     ], CRM_PCP_BAO_PCP::getPcpDashboardInfo($contactID));
   }
 
+  /**
+   * Test that CRM_Contribute_BAO_Contribution::_gatherMessageValues() works
+   * with PCP.
+   */
+  public function testGatherMessageValuesForPCP() {
+    // set up a pcp page
+    $block = CRM_PCP_BAO_PCPBlock::create($this->pcpBlockParams());
+    // The owner of the pcp, who gets the soft credit
+    $contact_owner = $this->individualCreate([], 0, TRUE);
+    $contributionPage = $this->callAPISuccessGetSingle('ContributionPage', []);
+    $pcp = $this->callAPISuccess('Pcp', 'create', [
+      'contact_id' => $contact_owner,
+      'title' => 'pcp',
+      'page_id' => $contributionPage['id'],
+      'pcp_block_id' => $block->id,
+      'is_active' => TRUE,
+      'status_id' => 'Approved',
+    ]);
+
+    // set up a payment processor
+    $payment_processor_type = $this->callAPISuccess('PaymentProcessorType', 'get', ['name' => 'Dummy']);
+    $payment_processor = $this->callAPISuccess('PaymentProcessor', 'create', [
+      'name' => 'Dummy PP',
+      'payment_processor_type_id' => $payment_processor_type['id'],
+      'class_name' => $payment_processor_type['values'][$payment_processor_type['id']]['class_name'],
+    ]);
+
+    // create a contribution with the pcp soft credit
+    $contact_contributor = $this->individualCreate([], 1, TRUE);
+    $address = $this->callAPISuccess('address', 'create', [
+      'address_name' => "Giver {$contact_contributor}",
+      'street_address' => '123 Main St.',
+      'location_type_id' => 'Billing',
+      'is_billing' => 1,
+      'contact_id' => $contact_contributor,
+    ]);
+    $contribution = $this->callAPISuccess('Contribution', 'create', [
+      'contact_id' => $contact_contributor,
+      'address_id' => $address['id'],
+      'total_amount' => 10,
+      'receive_date' => date('YmdHis'),
+      'financial_type_id' => 'Donation',
+      'payment_processor' => $payment_processor['id'],
+      'payment_instrument_id' => 'Credit Card',
+    ]);
+    $contribution_soft = $this->callAPISuccess('ContributionSoft', 'create', [
+      'contribution_id' => $contribution['id'],
+      'amount' => 10,
+      'contact_id' => $contact_owner,
+      'pcp_id' => $pcp['id'],
+      'pcp_display_in_roll' => 1,
+      'pcp_roll_nickname' => "Giver {$contact_contributor}",
+      'soft_credit_type_id' => 'pcp',
+    ]);
+
+    // Retrieve it using BAO so we can call gatherMessageValues
+    $contribution_bao = new CRM_Contribute_BAO_Contribution();
+    $contribution_bao->id = $contribution['id'];
+    $contribution_bao->find(TRUE);
+
+    $contribution_bao->_component = 'contribute';
+
+    // call and check result. $values has to be defined since it's pass-by-ref.
+    $values = [
+      'receipt_from_name' => 'CiviCRM Fundraising Dept.',
+      'receipt_from_email' => 'donationFake@civicrm.org',
+      'contribution_status' => 'Completed',
+    ];
+    $gathered_values = $contribution_bao->_gatherMessageValues(
+      [
+        'payment_processor_id' => $payment_processor['id'],
+        'is_email_receipt' => TRUE,
+      ],
+      $values,
+      [
+        'component' => 'contribute',
+        'contact_id' => $contact_contributor,
+        'contact' => $contact_contributor,
+        'financialType' => $contribution['values'][$contribution['id']]['financial_type_id'],
+        'contributionType' => $contribution['values'][$contribution['id']]['contribution_type_id'],
+        'contributionPage' => $contributionPage['id'],
+        'membership' => [],
+        'paymentProcessor' => $payment_processor['id'],
+        'contribution' => $contribution['id'],
+      ]
+    );
+
+    $this->assertEquals([
+      'receipt_from_name' => 'CiviCRM Fundraising Dept.',
+      'receipt_from_email' => 'donationFake@civicrm.org',
+      'contribution_status' => 'Completed',
+      'billingName' => "Giver {$contact_contributor}",
+      'address' => "Giver {$contact_contributor}\n123 Main St.\n",
+      'softContributions' => NULL,
+      'title' => 'Contribution',
+      'priceSetID' => '1',
+      'useForMember' => FALSE,
+      'lineItem' => [
+        0 => [
+          1 => [
+            'qty' => 1.0,
+            'label' => 'Contribution Amount',
+            'unit_price' => '10.00',
+            'line_total' => '10.00',
+            'price_field_id' => '1',
+            'participant_count' => NULL,
+            'price_field_value_id' => '1',
+            'field_title' => 'Contribution Amount',
+            'html_type' => 'Text',
+            'description' => NULL,
+            'entity_id' => '1',
+            'entity_table' => 'civicrm_contribution',
+            'contribution_id' => '1',
+            'financial_type_id' => '1',
+            'financial_type' => 'Donation',
+            'membership_type_id' => NULL,
+            'membership_num_terms' => NULL,
+            'tax_amount' => 0.0,
+            'price_set_id' => '1',
+            'tax_rate' => FALSE,
+            'subTotal' => 10.0,
+          ],
+        ],
+      ],
+      'customGroup' => [],
+      'is_pay_later' => '0',
+    ], $gathered_values);
+  }
+
 }
index af9378e32c8d9689a3d1442857c311a74b56fc2c..877b2f9a4918e60ed3d6b6daf5a08a180e3ff89f 100644 (file)
@@ -85,4 +85,26 @@ class CRM_SMS_ProviderTest extends CiviUnitTestCase {
     $message->toContactID = $testSourceContact;
   }
 
+  /**
+   * Some providers, like the mock one for these tests at the time of writing,
+   * or the dummy SMS provider extension, might not provide a default url,
+   * but the form shouldn't fail because of that.
+   */
+  public function testMissingUrl() {
+    $form = $this->getFormObject('CRM_SMS_Form_Provider');
+    $_REQUEST['key'] = 'CiviTestSMSProvider';
+
+    // This shouldn't give a notice
+    $defaults = $form->setDefaultValues();
+
+    $this->assertEquals([
+      'name' => 'CiviTestSMSProvider',
+      'api_url' => '',
+      'is_default' => 1,
+      'is_active' => 1,
+    ], $defaults);
+
+    unset($_REQUEST['key']);
+  }
+
 }
index 6ee808a4356161ad6d23ba03d79d33f9bd11f39b..7ea035594e0d4d89fdd0c2eacfa270b9d8bd8f0a 100644 (file)
@@ -45,4 +45,28 @@ class CRM_UF_Page_ProfileEditorTest extends CiviUnitTestCase {
 
   }
 
+  /**
+   * Test that with an extension adding in UF Fields for an enttiy that isn't supplied by Core e.g. Grant
+   * That an appropriate entitytype can be specfied in the backbone.marionette profile editor e.g. GrantModel
+   */
+  public function testGetSchemaWithHooks() {
+    CRM_Utils_Hook::singleton()->setHook('civicrm_alterUFFields', [$this, 'hook_civicrm_alterUFFIelds']);
+    $schema = CRM_UF_Page_ProfileEditor::getSchema(['IndividualModel', 'GrantModel']);
+    $this->assertEquals('Grant', $schema['GrantModel']['schema']['grant_decision_date']['civiFieldType']);
+  }
+
+  /**
+   * Tries to load up the profile schema for a model where there is no corresponding set of fields avaliable.
+   *
+   * @expectedException \CRM_Core_Exception
+   */
+  public function testGetSchemaWithHooksWithInvalidModel() {
+    CRM_Utils_Hook::singleton()->setHook('civicrm_alterUFFields', [$this, 'hook_civicrm_alterUFFIelds']);
+    $schema = CRM_UF_Page_ProfileEditor::getSchema(['IndividualModel', 'GrantModel', 'PledgeModel']);
+  }
+
+  public function hook_civicrm_alterUFFIelds(&$fields) {
+    $fields['Grant'] = CRM_Grant_BAO_Grant::exportableFields();
+  }
+
 }
index b9d6d9ae4da191978476b2b1dec3d9cab103d6ad..dc0c2882e005ba44d413785c445d924fc07f329c 100644 (file)
@@ -107,7 +107,7 @@ trait CRMTraits_ACL_PermissionTrait {
    *
    * @throws CRM_Core_Exception
    */
-  public function setupCoreACLPermittedToGroup($permissionedEntities = [], $groupAllowedAccess = 'Everyone', $operation = 'View', $entity = 'Group') {
+  public function setupCoreACLPermittedAcl($permissionedEntities = [], $groupAllowedAccess = 'Everyone', $operation = 'View', $entity = 'Group') {
     $tableMap = ['Group' => 'civicrm_saved_search', 'CustomGroup' => 'civicrm_custom_group', 'Profile' => 'civicrm_uf_match', 'Event' => 'civicrm_event'];
     $entityTable = $tableMap[$entity];
 
@@ -146,7 +146,27 @@ trait CRMTraits_ACL_PermissionTrait {
     $result = $this->callAPISuccess('GroupContact', 'create', ['group_id' => $this->scenarioIDs['Group']['permitted_group'], 'contact_id' => $this->scenarioIDs['Contact']['permitted_contact'], 'status' => 'Added']);
     $this->scenarioIDs['Contact']['non_permitted_contact'] = $this->individualCreate();
     CRM_Core_Config::singleton()->userPermissionClass->permissions = [];
-    $this->setupCoreACLPermittedToGroup([$this->scenarioIDs['Group']['permitted_group']]);
+    $this->setupCoreACLPermittedAcl([$this->scenarioIDs['Group']['permitted_group']]);
+  }
+
+  /**
+   * Set up a scenario where everyone can access the permissioned group.
+   *
+   * A scenario in this class involves multiple defined assets. In this case we create
+   * - a group to which the everyone has permission
+   * - a contact in the group
+   * - a contact not in the group
+   *
+   * These are arrayed as follows
+   *   $this->scenarioIDs['Contact'] = ['permitted_contact' => x, 'non_permitted_contact' => y]
+   *   $this->scenarioIDs['Group'] = ['permitted_group' => x]
+   */
+  public function setupScenarioCoreACLEveryonePermittedToEvent() {
+    $this->quickCleanup(['civicrm_acl_cache', 'civicrm_acl_contact_cache']);
+    $this->scenarioIDs['Event']['permitted_event'] = $this->eventCreate()['id'];
+    $this->scenarioIDs['Contact']['permitted_contact'] = $this->individualCreate();
+    CRM_Core_Config::singleton()->userPermissionClass->permissions = ['view event info'];
+    $this->setupCoreACLPermittedAcl([$this->scenarioIDs['Event']['permitted_event']], 'Everyone', 'View', 'Event');
   }
 
   /**
index a200260d53d2a59d8ea50be03e89a7cc2956df06..34bba898b12081837f4ce15e08683c3003211c87 100644 (file)
@@ -1054,12 +1054,13 @@ class CiviUnitTestCase extends PHPUnit\Framework\TestCase {
    * @throws \CRM_Core_Exception
    */
   protected function eventCreatePaid($params, $options = [['name' => 'hundy', 'amount' => 100]], $key = 'event') {
+    $params['is_monetary'] = TRUE;
     $event = $this->eventCreate($params);
-    $this->ids['event'][$key] = (int) $event['id'];
-    $this->priceSetID = $this->ids['PriceSet'][] = $this->eventPriceSetCreate(55, 0, 'Radio', $options);
-    CRM_Price_BAO_PriceSet::addTo('civicrm_event', $event['id'], $this->priceSetID);
-    $priceSet = CRM_Price_BAO_PriceSet::getSetDetail($this->priceSetID, TRUE, FALSE);
-    $priceSet = $priceSet[$this->priceSetID] ?? NULL;
+    $this->ids['Event'][$key] = (int) $event['id'];
+    $this->ids['PriceSet'][$key] = $this->eventPriceSetCreate(55, 0, 'Radio', $options);
+    CRM_Price_BAO_PriceSet::addTo('civicrm_event', $event['id'], $this->ids['PriceSet'][$key]);
+    $priceSet = CRM_Price_BAO_PriceSet::getSetDetail($this->ids['PriceSet'][$key], TRUE, FALSE);
+    $priceSet = $priceSet[$this->ids['PriceSet'][$key]] ?? NULL;
     $this->eventFeeBlock = $priceSet['fields'] ?? NULL;
     return $event;
   }
@@ -2779,13 +2780,10 @@ VALUES
   protected function swapMessageTemplateForTestTemplate($templateName = 'contribution_online_receipt', $type = 'html') {
     $testTemplate = file_get_contents(__DIR__ . '/../../templates/message_templates/' . $templateName . '_' . $type . '.tpl');
     CRM_Core_DAO::executeQuery(
-      "UPDATE civicrm_option_group og
-      LEFT JOIN civicrm_option_value ov ON ov.option_group_id = og.id
-      LEFT JOIN civicrm_msg_template m ON m.workflow_id = ov.id
-      SET m.msg_{$type} = %1
-      WHERE og.name LIKE 'msg_tpl_workflow_%'
-      AND ov.name = '{$templateName}'
-      AND m.is_default = 1", [1 => [$testTemplate, 'String']]
+      "UPDATE civicrm_msg_template
+      SET msg_{$type} = %1
+      WHERE workflow_name = '{$templateName}'
+      AND is_default = 1", [1 => [$testTemplate, 'String']]
     );
   }
 
index bea3aed15ce4e050ed0705104cc2c52789c47f79..9dc8203194272fd66ad5065f1448232dec0d9005 100644 (file)
@@ -3974,6 +3974,42 @@ class api_v3_ContactTest extends CiviUnitTestCase {
 
   }
 
+  /**
+   * Test that a blank location does not overwrite a location with data.
+   *
+   * This is a poor data edge case where a contact has an address record with no meaningful data.
+   * This record should be removed in favour of the one with data.
+   *
+   * @dataProvider  getBooleanDataProvider
+   *
+   * @param bool $isReverse
+   *
+   * @throws \CRM_Core_Exception
+   */
+  public function testMergeWithBlankLocationData($isReverse) {
+    $this->createLoggedInUser();
+    $this->ids['contact'][0] = $this->callAPISuccess('contact', 'create', $this->_params)['id'];
+    $this->ids['contact'][1] = $this->callAPISuccess('contact', 'create', $this->_params)['id'];
+    $contactIDWithBlankAddress = ($isReverse ? $this->ids['contact'][1] : $this->ids['contact'][0]);
+    $contactIDWithoutBlankAddress = ($isReverse ? $this->ids['contact'][0] : $this->ids['contact'][1]);
+    $this->callAPISuccess('Address', 'create', [
+      'contact_id' => $contactIDWithBlankAddress,
+      'location_type_id' => 1,
+    ]);
+    $this->callAPISuccess('Address', 'create', [
+      'country_id' => 'MX',
+      'contact_id' => $contactIDWithoutBlankAddress,
+      'street_address' => 'First on the left after you cross the border',
+      'postal_code' => 90210,
+      'location_type_id' => 1,
+    ]);
+
+    $contact = $this->doMerge($isReverse);
+    $this->assertEquals('Mexico', $contact['country']);
+    $this->assertEquals('90210', $contact['postal_code']);
+    $this->assertEquals('First on the left after you cross the border', $contact['street_address']);
+  }
+
   /**
    * Test merging 2 contacts with custom fields.
    *
@@ -4843,4 +4879,21 @@ class api_v3_ContactTest extends CiviUnitTestCase {
     $this->callAPISuccess('Contact', 'delete', ['id' => $contact2, 'skip_undelete' => 1]);
   }
 
+  /**
+   * Do the merge on the 2 contacts.
+   *
+   * @param bool $isReverse
+   *
+   * @return array|int
+   * @throws \CRM_Core_Exception
+   */
+  protected function doMerge($isReverse = FALSE) {
+    $this->callAPISuccess('Contact', 'merge', [
+      'to_keep_id' => $isReverse ? $this->ids['contact'][1] : $this->ids['contact'][0],
+      'to_remove_id' => $isReverse ? $this->ids['contact'][0] : $this->ids['contact'][1],
+      'auto_flip' => FALSE,
+    ]);
+    return $this->callAPISuccessGetSingle('Contact', ['id' => $isReverse ? $this->ids['contact'][1] : $this->ids['contact'][0]]);
+  }
+
 }
index b5779446337865592541cd580a48ffa8b3c883dc..8de1a75b8960397935b5d6895490fc57d35e0115 100644 (file)
@@ -9,6 +9,8 @@
  +--------------------------------------------------------------------+
  */
 
+use Civi\Api4\Contribution;
+
 /**
  *  Test APIv3 civicrm_contribute_* functions
  *
@@ -107,7 +109,7 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
    */
   public function tearDown() {
     $this->quickCleanUpFinancialEntities();
-    $this->quickCleanup(['civicrm_uf_match']);
+    $this->quickCleanup(['civicrm_uf_match'], TRUE);
     $financialAccounts = $this->callAPISuccess('FinancialAccount', 'get', []);
     foreach ($financialAccounts['values'] as $financialAccount) {
       if ($financialAccount['name'] === 'Test Tax financial account ' || $financialAccount['name'] === 'Test taxable financial Type') {
@@ -2326,6 +2328,46 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
     ], 'online');
   }
 
+  /**
+   * Test custom data is copied over from the template transaction.
+   *
+   * (Over time various discussions have deemed this to be the most recent one, allowing
+   * users to alter custom data going forwards. This is implemented for line items already.
+   *
+   * @throws \API_Exception
+   * @throws \CRM_Core_Exception
+   */
+  public function testRepeatTransactionWithCustomData() {
+    $this->createCustomGroupWithFieldOfType(['extends' => 'Contribution', 'name' => 'Repeat'], 'text');
+    $originalContribution = $this->setUpRepeatTransaction([], 'single', [$this->getCustomFieldName('text') => 'first']);
+    $this->callAPISuccess('contribution', 'repeattransaction', [
+      'contribution_recur_id' => $originalContribution['contribution_recur_id'],
+      'contribution_status_id' => 'Completed',
+      'trxn_id' => 'my_trxn',
+    ]);
+
+    $contribution = Contribution::get()
+      ->addWhere('trxn_id', '=', 'my_trxn')
+      ->addSelect('Custom_Group.Enter_text_here')
+      ->addSelect('id')
+      ->execute()->first();
+    $this->assertEquals('first', $contribution['Custom_Group.Enter_text_here']);
+
+    Contribution::update()->setValues(['Custom_Group.Enter_text_here' => 'second'])->addWhere('id', '=', $contribution['id'])->execute();
+
+    $this->callAPISuccess('contribution', 'repeattransaction', [
+      'original_contribution_id' => $originalContribution['id'],
+      'contribution_status_id' => 'Completed',
+      'trxn_id' => 'number_3',
+    ]);
+
+    $contribution = Contribution::get()
+      ->addWhere('trxn_id', '=', 'number_3')
+      ->setSelect(['id', 'Custom_Group.Enter_text_here'])
+      ->execute()->first();
+    $this->assertEquals('second', $contribution['Custom_Group.Enter_text_here']);
+  }
+
   /**
    * Test repeat contribution successfully creates line items (plural).
    *
@@ -2509,6 +2551,36 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
     $this->callAPISuccessGetCount('MembershipPayment', ['membership_id' => $membership['id']]);
   }
 
+  /**
+   * This is one of those tests that locks in existing behaviour.
+   *
+   * I feel like correct behaviour is arguable & has been discussed in the past. However, if the membership has
+   * a date which says it should be expired then the result of repeattransaction is to push that date
+   * to be one membership term from 'now' with status 'new'.
+   */
+  public function testRepeattransactionRenewMembershipOldMembership() {
+    $entities = $this->setUpAutoRenewMembership();
+    $newStatusID = CRM_Core_PseudoConstant::getKey('CRM_Member_BAO_Membership', 'status_id', 'New');
+    $membership = $this->callAPISuccess('Membership', 'create', [
+      'id' => $entities[1]['id'],
+      'join_date' => '4 months ago',
+      'start_date' => '3 months ago',
+      'end_date' => '2 months ago',
+    ]);
+    $membership = $membership['values'][$membership['id']];
+
+    // This status does not appear to be calculated at all and is set to 'new'. Feels like a bug.
+    $this->assertEquals($newStatusID, $membership['status_id']);
+
+    // So it seems renewing this expired membership results in it's new status being current and it being pushed to a future date
+    $this->callAPISuccess('Contribution', 'repeattransaction', ['original_contribution_id' => $entities[0]['id'], 'contribution_status_id' => 'Completed']);
+    $membership = $this->callAPISuccessGetSingle('Membership', ['id' => $membership['id']]);
+    // If this date calculation winds up being flakey the spirit of the test would be maintained by just checking
+    // date is greater than today.
+    $this->assertEquals(date('Y-m-d', strtotime('+ 1 month -1 day')), $membership['end_date']);
+    $this->assertEquals($newStatusID, $membership['membership_type_id']);
+  }
+
   /**
    * CRM-19945 Tests that Contribute.repeattransaction DOES NOT renew a membership when contribution status=Failed
    *
@@ -2642,7 +2714,10 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
   }
 
   /**
-   * CRM-17718 test appropriate action if financial type has changed for single line items.
+   * Test financial_type_id override behaviour with a single line item.
+   *
+   * CRM-17718 a passed in financial_type_id is allowed to override the original contribution where there
+   * is only one line item.
    */
   public function testRepeatTransactionPassedInFinancialType() {
     $originalContribution = $this->setUpRecurringContribution();
@@ -2669,7 +2744,7 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
       ],
     ];
 
-    $this->callAPISuccessGetSingle('contribution', [
+    $this->callAPISuccessGetSingle('Contribution', [
       'total_amount' => 100,
       'financial_type_id' => 2,
     ]);
@@ -2692,6 +2767,37 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
     $this->assertEquals($expectedLineItem, $lineItem2['values'][0]);
   }
 
+  /**
+   * Test financial_type_id override behaviour with a single line item.
+   *
+   * CRM-17718 a passed in financial_type_id is not allowed to override the original contribution where there
+   * is more than one line item.
+   */
+  public function testRepeatTransactionPassedInFinancialTypeTwoLineItems() {
+    $this->_params = $this->getParticipantOrderParams();
+    $originalContribution = $this->setUpRecurringContribution();
+
+    $this->callAPISuccess('Contribution', 'repeattransaction', [
+      'original_contribution_id' => $originalContribution['id'],
+      'contribution_status_id' => 'Completed',
+      'trxn_id' => 'repeat',
+      'financial_type_id' => 2,
+    ]);
+
+    // Retrieve the new contribution and note the financial type passed in has been ignored.
+    $contribution = $this->callAPISuccessGetSingle('Contribution', [
+      'trxn_id' => 'repeat',
+    ]);
+    $this->assertEquals(4, $contribution['financial_type_id']);
+
+    $lineItems = $this->callAPISuccess('line_item', 'get', [
+      'entity_id' => $contribution['id'],
+    ])['values'];
+    foreach ($lineItems as $lineItem) {
+      $this->assertNotEquals(2, $lineItem['financial_type_id']);
+    }
+  }
+
   /**
    * CRM-17718 test appropriate action if financial type has changed for single line items.
    */
@@ -2905,7 +3011,10 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
     $this->callAPISuccess('contribution', 'completetransaction', ['id' => $contribution['id'], 'trxn_date' => date('Y-m-d')]);
     $contribution = $this->callAPISuccess('contribution', 'get', ['id' => $contribution['id'], 'sequential' => 1]);
     $this->assertEquals('Completed', $contribution['values'][0]['contribution_status']);
-    $this->assertEquals(date('Y-m-d'), date('Y-m-d', strtotime($contribution['values'][0]['receive_date'])));
+    // Make sure receive_date is original date and make sure payment date is today
+    $this->assertEquals('2012-05-11', date('Y-m-d', strtotime($contribution['values'][0]['receive_date'])));
+    $payment = $this->callAPISuccess('payment', 'get', ['contribution_id' => $contribution['id'], 'sequential' => 1]);
+    $this->assertEquals(date('Y-m-d'), date('Y-m-d', strtotime($payment['values'][0]['trxn_date'])));
     $mut->checkMailLog([
       'Receipt - Contribution',
       'receipt_date:::' . date('Ymd'),
@@ -2939,7 +3048,7 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
    * Test that $is_recur is assigned to the receipt.
    */
   public function testCompleteTransactionForRecurring() {
-
+    $this->mut = new CiviMailUtils($this, TRUE);
     $this->swapMessageTemplateForTestTemplate();
     $recurring = $this->setUpRecurringContribution();
     $contributionPage = $this->createReceiptableContributionPage(['is_recur' => TRUE, 'recur_frequency_unit' => 'month', 'recur_interval' => 1]);
@@ -3184,7 +3293,11 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
     $this->assertEquals(1, $status);
     $mut->checkMailLog([
       'amount:::500.00',
-      'receive_date:::20130201000000',
+      // The `receive_date` should remain as it was created.
+      // TODO: the latest payment transaction date (and maybe other details,
+      // such as amount and payment instrument) would be a useful token to make
+      // available.
+      'receive_date:::20120511000000',
       "receipt_date:::\n",
     ]);
     $mut->stop();
@@ -3410,14 +3523,32 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
   }
 
   /**
-   * Test membership is renewed when transaction completed.
+   * Test membership is renewed for 2 terms when transaction completed based on the line item having 2 terms as qty.
+   *
+   * Also check that altering the qty for the most recent contribution results in repeattransaction picking it up.
    */
   public function testCompleteTransactionMembershipPriceSetTwoTerms() {
     $this->createPriceSetWithPage('membership');
     $this->setUpPendingContribution($this->_ids['price_field_value'][1]);
     $this->callAPISuccess('contribution', 'completetransaction', ['id' => $this->_ids['contribution']]);
-    $membership = $this->callAPISuccess('membership', 'getsingle', ['id' => $this->_ids['membership']]);
+    $membership = $this->callAPISuccessGetSingle('membership', ['id' => $this->_ids['membership']]);
     $this->assertEquals(date('Y-m-d', strtotime('yesterday + 2 years')), $membership['end_date']);
+
+    $paymentProcessorID = $this->paymentProcessorAuthorizeNetCreate();
+
+    $contributionRecurID = $this->callAPISuccess('ContributionRecur', 'create', ['contact_id' => $membership['contact_id'], 'payment_processor_id' => $paymentProcessorID, 'amount' => 20, 'frequency_interval' => 1])['id'];
+    $this->callAPISuccess('Contribution', 'create', ['id' => $this->_ids['contribution'], 'contribution_recur_id' => $contributionRecurID]);
+    $this->callAPISuccess('contribution', 'repeattransaction', ['contribution_recur_id' => $contributionRecurID, 'contribution_status_id' => 'Completed']);
+    $membership = $this->callAPISuccessGetSingle('membership', ['id' => $this->_ids['membership']]);
+    $this->assertEquals(date('Y-m-d', strtotime('yesterday + 4 years')), $membership['end_date']);
+
+    // Update the most recent contribution to have a qty of 1 in it's line item and then repeat, expecting just 1 year to be added.
+    $contribution = Contribution::get()->setOrderBy(['id' => 'DESC'])->setSelect(['id'])->execute()->first();
+    CRM_Core_DAO::executeQuery('UPDATE civicrm_line_item SET price_field_value_id = ' . $this->_ids['price_field_value'][0] . ' WHERE contribution_id = ' . $contribution['id']);
+    $this->callAPISuccess('contribution', 'repeattransaction', ['contribution_recur_id' => $contributionRecurID, 'contribution_status_id' => 'Completed']);
+    $membership = $this->callAPISuccessGetSingle('membership', ['id' => $this->_ids['membership']]);
+    $this->assertEquals(date('Y-m-d', strtotime('yesterday + 5 years')), $membership['end_date']);
+
     $this->cleanUpAfterPriceSets();
   }
 
@@ -4015,6 +4146,7 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
    *   Parameters to merge into the recur only.
    *
    * @return array|int
+   * @throws \CRM_Core_Exception
    */
   protected function setUpRecurringContribution($generalParams = [], $recurParams = []) {
     $contributionRecur = $this->callAPISuccess('contribution_recur', 'create', array_merge([
@@ -4028,12 +4160,14 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
       'frequency_unit' => 'month',
       'payment_processor_id' => $this->paymentProcessorID,
     ], $generalParams, $recurParams));
-    $originalContribution = $this->callAPISuccess('contribution', 'create', array_merge(
+    $contributionParams = array_merge(
       $this->_params,
       [
         'contribution_recur_id' => $contributionRecur['id'],
-      ], $generalParams)
-    );
+        'contribution_status_id' => 'Pending',
+      ], $generalParams);
+    $contributionParams['api.Payment.create'] = ['total_amount' => $contributionParams['total_amount']];
+    $originalContribution = $this->callAPISuccess('Order', 'create', $contributionParams);
     return $originalContribution;
   }
 
@@ -4170,6 +4304,7 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
       $params = array_merge($params, $contributionParams);
       $originalContribution = $this->callAPISuccess('contribution', 'create', $params);
     }
+    $originalContribution['contribution_recur_id'] = $contributionRecur['id'];
     $originalContribution['payment_processor_id'] = $paymentProcessorID;
     return $originalContribution;
   }
@@ -4738,4 +4873,30 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
     return $result;
   }
 
+  /**
+   * Make sure that recording a payment doesn't alter the receive_date of a
+   * pending contribution.
+   */
+  public function testPaymentDontChangeReceiveDate() {
+    $params = [
+      'contact_id' => $this->_individualId,
+      'total_amount' => 100,
+      'receive_date' => '2020-02-02',
+      'contribution_status_id' => 'Pending',
+    ];
+    $contributionID = $this->contributionCreate($params);
+    $paymentParams = [
+      'contribution_id' => $contributionID,
+      'total_amount' => 100,
+      'trxn_date' => '2020-03-04',
+    ];
+    $this->callAPISuccess('payment', 'create', $paymentParams);
+
+    //check if contribution status is set to "Completed".
+    $contribution = $this->callAPISuccess('Contribution', 'getSingle', [
+      'id' => $contributionID,
+    ]);
+    $this->assertEquals('2020-02-02 00:00:00', $contribution['receive_date']);
+  }
+
 }
index ed769640ea9b40c64d938aedb64cc133c276f00d..e1b09ea9234a3221a45db6df2f6b67e2e0249512 100644 (file)
@@ -118,6 +118,18 @@ class api_v3_MailingGroupTest extends CiviUnitTestCase {
    * Test civicrm_mailing_group_event_subscribe and civicrm_mailing_event_confirm functions - success expected.
    */
   public function testMailerProcess() {
+    $this->callAPISuccess('MailSettings', 'create', [
+      'domain_id' => 1,
+      'name' => "my mail setting",
+      'domain' => 'setting.com',
+      'localpart' => 'civicrm+',
+      'server' => "localhost",
+      'username' => 'sue',
+      'password' => 'pass',
+      'is_default' => 1,
+    ]);
+    $mut = new CiviMailUtils($this, TRUE);
+    Civi::settings()->set('include_message_id', 1);
     $params = [
       'first_name' => 'Test',
       'last_name' => 'Test',
@@ -134,6 +146,13 @@ class api_v3_MailingGroupTest extends CiviUnitTestCase {
       'time_stamp' => '20101212121212',
     ];
     $result = $this->callAPISuccess('mailing_event_subscribe', 'create', $params);
+    // Check that subscription email has been sent.
+    $msgs = $mut->getAllMessages();
+    $this->assertCount(1, $msgs, 'Subscription email failed to send');
+    $mut->checkMailLog([
+      'Message-ID: <civicrm+s',
+      'To confirm this subscription, reply to this email or click',
+    ]);
 
     $this->assertEquals($result['values'][$result['id']]['contact_id'], $contactID);
 
@@ -147,6 +166,7 @@ class api_v3_MailingGroupTest extends CiviUnitTestCase {
 
     $this->callAPISuccess('mailing_event_confirm', 'create', $params);
     $this->contactDelete($contactID);
+    Civi::settings()->set('include_message_id', 0);
   }
 
 }
index 5d0bc095107fee43b861af96b90c9debf7a43769..bd956ebf6dfa554e050149d30f09f2c19139292d 100644 (file)
@@ -50,7 +50,6 @@ class api_v3_MembershipTest extends CiviUnitTestCase {
     ]);
     $this->_membershipStatusID = $this->membershipStatusCreate('test status');
 
-    CRM_Member_PseudoConstant::membershipType(NULL, TRUE);
     CRM_Member_PseudoConstant::membershipStatus(NULL, NULL, 'name', TRUE);
     CRM_Core_PseudoConstant::activityType(TRUE, TRUE, TRUE, 'name');
 
@@ -114,7 +113,7 @@ class api_v3_MembershipTest extends CiviUnitTestCase {
       'total_amount' => 100,
       'contact_id' => $this->_params['contact_id'],
     ]);
-    $membershipPaymentCreate = $this->callAPISuccess('MembershipPayment', 'create', [
+    $this->callAPISuccess('MembershipPayment', 'create', [
       'sequential' => 1,
       'contribution_id' => $ContributionCreate['values'][0]['id'],
       'membership_id' => $membershipID,
@@ -139,20 +138,17 @@ class api_v3_MembershipTest extends CiviUnitTestCase {
   public function testActivityForCancelledContribution() {
     $contactId = $this->createLoggedInUser();
     $membershipID = $this->contactMembershipCreate($this->_params);
-    $this->assertDBRowExist('CRM_Member_DAO_Membership', $membershipID);
 
     $ContributionCreate = $this->callAPISuccess('Contribution', 'create', [
-      'financial_type_id' => "Member Dues",
+      'financial_type_id' => 'Member Dues',
       'total_amount' => 100,
       'contact_id' => $this->_params['contact_id'],
     ]);
-    $membershipPaymentCreate = $this->callAPISuccess('MembershipPayment', 'create', [
+    $this->callAPISuccess('MembershipPayment', 'create', [
       'sequential' => 1,
       'contribution_id' => $ContributionCreate['id'],
       'membership_id' => $membershipID,
     ]);
-    $instruments = $this->callAPISuccess('contribution', 'getoptions', ['field' => 'payment_instrument_id']);
-    $this->paymentInstruments = $instruments['values'];
 
     $form = new CRM_Contribute_Form_Contribution();
     $form->_id = $ContributionCreate['id'];
@@ -160,16 +156,20 @@ class api_v3_MembershipTest extends CiviUnitTestCase {
       'total_amount' => 100,
       'financial_type_id' => 1,
       'contact_id' => $contactId,
-      'payment_instrument_id' => array_search('Check', $this->paymentInstruments),
+      'payment_instrument_id' => CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'payment_instrument_id', 'Check'),
       'contribution_status_id' => 3,
     ],
     CRM_Core_Action::UPDATE);
 
-    $activity = $this->callAPISuccess('Activity', 'get', [
-      'activity_type_id' => "Change Membership Status",
+    $this->callAPISuccessGetSingle('Activity', [
+      'activity_type_id' => 'Membership Signup',
+      'source_record_id' => $membershipID,
+      'subject' => 'General - Payment - Status: test status',
+    ]);
+    $this->callAPISuccessGetSingle('Activity', [
+      'activity_type_id' => 'Change Membership Status',
       'source_record_id' => $membershipID,
     ]);
-    $this->assertNotEmpty($activity['values']);
   }
 
   /**
index c01bf4b60829a788b9f8e740af85491642485d2a..046f1f6058dff34fac7e1ecd4ff056a93bfb0092 100644 (file)
@@ -899,52 +899,146 @@ class api_v3_PaymentTest extends CiviUnitTestCase {
   }
 
   /**
-   * Test create payment api for pay later contribution with partial payment.
+   * Test create payment api for failed contribution.
    *
    * @throws \CRM_Core_Exception
    */
-  public function testCreatePaymentPayLaterPartialPayment() {
+  public function testCreatePaymentOnFailedContribution() {
     $this->createLoggedInUser();
+    //Create a direct Failed Contribution (no ft record inserted).
+    $contributionParams = [
+      'total_amount' => 50,
+      'currency' => 'USD',
+      'contact_id' => $this->_individualId,
+      'financial_type_id' => 1,
+      'contribution_status_id' => 'Failed',
+    ];
+    $contribution = $this->callAPISuccess('Contribution', 'create', $contributionParams);
+
+    //Complete the payment in a single call.
+    $params = [
+      'contribution_id' => $contribution['id'],
+      'total_amount' => 50,
+    ];
+    $payment = $this->callAPISuccess('Payment', 'create', $params);
+
+    //Verify 2 rows are added to the financial trxn as payment is moved from
+    //Failed -> Pending -> Completed, i.e, 0 -> 7(Account receivable) -> 6 (Deposit Bank).
+    $params = [
+      'entity_id' => $contribution['id'],
+      'entity_table' => 'civicrm_contribution',
+    ];
+    $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
+    $this->assertEquals($eft['count'], 2);
+
+    //Test 2
+    //Create a Pending Contribution so an FT record is inserted.
     $contributionParams = [
       'total_amount' => 100,
       'currency' => 'USD',
       'contact_id' => $this->_individualId,
       'financial_type_id' => 1,
-      'contribution_status_id' => 2,
+      'contribution_status_id' => 'Pending',
       'is_pay_later' => 1,
     ];
     $contribution = $this->callAPISuccess('Order', 'create', $contributionParams);
-    //Create partial payment
+
+    //Mark it as failed. No FT record inserted on this update
+    //so the payment is still in the account receivable account id 7.
+    $this->callAPISuccess('Contribution', 'create', [
+      'id' => $contribution['id'],
+      'contribution_status_id' => 'Failed',
+    ]);
+    $this->createPartialPaymentOnContribution($contribution['id'], 60, 100.00);
+
+    //Call payment create on the failed contribution.
     $params = [
       'contribution_id' => $contribution['id'],
-      'total_amount' => 60,
+      'total_amount' => 40,
     ];
     $payment = $this->callAPISuccess('Payment', 'create', $params);
     $expectedResult = [
       $payment['id'] => [
-        'total_amount' => 60,
+        'from_financial_account_id' => 7,
+        'to_financial_account_id' => 6,
+        'total_amount' => 40,
         'status_id' => 1,
         'is_payment' => 1,
       ],
     ];
     $this->checkPaymentResult($payment, $expectedResult);
-    // Check entity financial trxn created properly
+
+    //Check total ft rows are 4: 2 from initial pending + partial payment
+    //+ 2 for failed -> completed transition.
     $params = [
       'entity_id' => $contribution['id'],
       'entity_table' => 'civicrm_contribution',
+    ];
+    $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
+    $this->assertEquals($eft['count'], 4);
+
+    $this->validateAllPayments();
+  }
+
+  /**
+   * Create partial payment for contribution
+   *
+   * @param $contributionID
+   * @param $partialAmount
+   * @param $totalAmount
+   */
+  public function createPartialPaymentOnContribution($contributionID, $partialAmount, $totalAmount) {
+    //Create partial payment
+    $params = [
+      'contribution_id' => $contributionID,
+      'total_amount' => $partialAmount,
+    ];
+    $payment = $this->callAPISuccess('Payment', 'create', $params);
+    $expectedResult = [
+      $payment['id'] => [
+        'total_amount' => $partialAmount,
+        'status_id' => 1,
+        'is_payment' => 1,
+      ],
+    ];
+    $this->checkPaymentResult($payment, $expectedResult);
+    // Check entity financial trxn created properly
+    $params = [
+      'entity_id' => $contributionID,
+      'entity_table' => 'civicrm_contribution',
       'financial_trxn_id' => $payment['id'],
     ];
     $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
-    $this->assertEquals($eft['values'][$eft['id']]['amount'], 60);
+    $this->assertEquals($eft['values'][$eft['id']]['amount'], $partialAmount);
     $params = [
       'entity_table' => 'civicrm_financial_item',
       'financial_trxn_id' => $payment['id'],
     ];
     $eft = $this->callAPISuccess('EntityFinancialTrxn', 'get', $params);
-    $this->assertEquals($eft['values'][$eft['id']]['amount'], 60);
-    $contribution = $this->callAPISuccess('contribution', 'get', ['id' => $contribution['id']]);
+    $this->assertEquals($eft['values'][$eft['id']]['amount'], $partialAmount);
+    $contribution = $this->callAPISuccess('contribution', 'get', ['id' => $contributionID]);
     $this->assertEquals($contribution['values'][$contribution['id']]['contribution_status'], 'Partially paid');
-    $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], 100.00);
+    $this->assertEquals($contribution['values'][$contribution['id']]['total_amount'], $totalAmount);
+  }
+
+  /**
+   * Test create payment api for pay later contribution with partial payment.
+   *
+   * @throws \CRM_Core_Exception
+   */
+  public function testCreatePaymentPayLaterPartialPayment() {
+    $this->createLoggedInUser();
+    $contributionParams = [
+      'total_amount' => 100,
+      'currency' => 'USD',
+      'contact_id' => $this->_individualId,
+      'financial_type_id' => 1,
+      'contribution_status_id' => 2,
+      'is_pay_later' => 1,
+    ];
+    $contribution = $this->callAPISuccess('Order', 'create', $contributionParams);
+    $this->createPartialPaymentOnContribution($contribution['id'], 60, 100.00);
+
     //Create full payment
     $params = [
       'contribution_id' => $contribution['id'],
@@ -1124,9 +1218,7 @@ class api_v3_PaymentTest extends CiviUnitTestCase {
     $this->assertEquals($trxnID, $contribution['trxn_id'],
       "Contribution trxn_id should have been set to that of the payment.");
 
-    // change $trxnDate for $receiveDate if we agree that transactions should NOT
-    // update contributions.
-    $this->assertEquals($trxnDate, $contribution['receive_date'],
+    $this->assertEquals($originalReceiveDate, $contribution['receive_date'],
       "Contribution receive date was changed, but should not have been.");
 
     $this->validateAllPayments();
diff --git a/tests/phpunit/api/v4/Entity/SystemTest.php b/tests/phpunit/api/v4/Entity/SystemTest.php
new file mode 100644 (file)
index 0000000..11203e7
--- /dev/null
@@ -0,0 +1,80 @@
+<?php
+
+/*
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC. All rights reserved.                        |
+ |                                                                    |
+ | This work is published under the GNU AGPLv3 license with some      |
+ | permitted exceptions and without any warranty. For full license    |
+ | and copyright information, see https://civicrm.org/licensing       |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ *
+ * @package CRM
+ * @copyright CiviCRM LLC https://civicrm.org/licensing
+ */
+
+
+namespace api\v4\Entity;
+
+use Civi\Api4\Setting;
+use Civi\Api4\StatusPreference;
+use Civi\Api4\System;
+use api\v4\UnitTestCase;
+
+/**
+ * @group headless
+ */
+class SystemTest extends UnitTestCase {
+
+  public function testSystemCheck() {
+    $origEnv = \CRM_Core_Config::environment();
+    $hooks = \CRM_Utils_Hook::singleton();
+    $hooks->setHook('civicrm_check', [$this, 'hook_civicrm_check']);
+
+    // Test on non-prod site
+    Setting::set()->addValue('environment', 'Development')->setCheckPermissions(FALSE)->execute();
+
+    StatusPreference::delete()->setCheckPermissions(FALSE)->addWhere('name', '=', 'checkLastCron')->execute();
+
+    // Won't run on non-prod site without $includeDisabled
+    $check = System::check()->addWhere('name', '=', 'checkLastCron')->execute();
+    // Will have skipped our hook because name matched a core check
+    $this->assertCount(0, $check);
+
+    // This should only run the php check
+    $check = System::check()->addWhere('name', '=', 'checkPhpVersion')->setIncludeDisabled(TRUE)->execute();
+    // Hook should have been skipped because name clause was fulfilled
+    $this->assertCount(1, $check);
+
+    // Ensure cron check has not run
+    $this->assertCount(0, StatusPreference::get()->setCheckPermissions(FALSE)->addWhere('name', '=', 'checkLastCron')->execute());
+
+    // Will run on non-prod site with $includeDisabled.
+    // Giving a more-specific name will run all checks with less-specific names too
+    $check = System::check()->addWhere('name', '=', 'checkLastCronAbc')->setIncludeDisabled(TRUE)->execute()->indexBy('name');
+    // Will have run our hook too because name wasn't an exact match
+    $this->assertCount(2, $check);
+    $this->assertEquals('Ok', $check['hook_civicrm_check']['title']);
+
+    // We know the cron check has run because it would have left a record marked 'new'
+    $record = StatusPreference::get()->setCheckPermissions(FALSE)->addWhere('name', '=', 'checkLastCron')->execute()->first();
+    $this->assertEquals('new', $record['prefs']);
+
+    // Restore env
+    Setting::set()->addValue('environment', $origEnv)->setCheckPermissions(FALSE)->execute();
+    $hooks->reset();
+  }
+
+  public function hook_civicrm_check(&$messages, $statusNames, $includeDisabled) {
+    $messages[] = new \CRM_Utils_Check_Message(
+      __FUNCTION__,
+      'Hook running',
+      'Ok',
+      \Psr\Log\LogLevel::DEBUG
+    );
+  }
+
+}
index 54d4b01f6c525e08b905e6069ae903ee25b35690..dc9967e4fec5e4a6463761017d15ee14bfcbb9c1 100644 (file)
@@ -96,7 +96,7 @@ VALUES
 {ldelim}domain.address{rdelim}{/ts}',1,1),
     ('{ts escape="sql"}Subscribe Message{/ts}','Subscribe','{ts escape="sql"}Subscription Confirmation Request{/ts}','{ts escape="sql" 1=$subgroup 2=$suburl}You have a pending subscription to the %1 mailing list. To confirm this subscription, reply to this email or click <a href="%2">here</a>.{/ts}','{ts escape="sql" 1=$subgroup 2=$suburl}You have a pending subscription to the %1 mailing list. To confirm this subscription, reply to this email or click on this link: %2{/ts}',1,1),
     ('{ts escape="sql"}Welcome Message{/ts}','Welcome','{ts escape="sql"}Your Subscription has been Activated{/ts}','{ts escape="sql" 1=$welgroup}Welcome. Your subscription to the %1 mailing list has been activated.{/ts}','{ts escape="sql" 1=$welgroup}Welcome. Your subscription to the %1 mailing list has been activated.{/ts}',1,1),
-    ('{ts escape="sql"}Unsubscribe Message{/ts}','Unsubscribe','{ts escape="sql"}Un-subscribe Confirmation{/ts}','{ts escape="sql" 1=$unsubgroup 2=$actresub 3=$actresuburl}You have been un-subscribed from the following groups: %1. You can re-subscribe by mailing %2 or clicking <a href="%3">here</a>.{/ts}','{ts escape="sql" 1=$unsubgroup 2=$actresub}You have been un-subscribed from the following groups: %1. You can re-subscribe by mailing %2 or clicking %3{/ts}',1,1),
+    ('{ts escape="sql"}Unsubscribe Message{/ts}','Unsubscribe','{ts escape="sql"}Un-subscribe Confirmation{/ts}','{ts escape="sql" 1=$unsubgroup 2=$actresub 3=$actresuburl}You have been un-subscribed from the following groups: %1. You can re-subscribe by mailing %2 or clicking <a href="%3">here</a>.{/ts}','{ts escape="sql" 1=$unsubgroup 2=$actresub 3=$actresuburl}You have been un-subscribed from the following groups: %1. You can re-subscribe by mailing %2 or clicking %3{/ts}',1,1),
     ('{ts escape="sql"}Resubscribe Message{/ts}','Resubscribe','{ts escape="sql"}Re-subscribe Confirmation{/ts}','{ts escape="sql" 1=$resubgroup 2=$actunsub 3=$actunsuburl}You have been re-subscribed to the following groups: %1. You can un-subscribe by mailing %2 or clicking <a href="%3">here</a>.{/ts}','{ts escape="sql" 1=$resubgroup 2=$actunsub 3=$actunsuburl}You have been re-subscribed to the following groups: %1. You can un-subscribe by mailing %2 or clicking %3{/ts}',1,1),
     ('{ts escape="sql"}Opt-out Message{/ts}','OptOut','{ts escape="sql"}Opt-out Confirmation{/ts}','{ts escape="sql" 1=$domname}Your email address has been removed from %1 mailing lists.{/ts}','{ts escape="sql" 1=$domname}Your email address has been removed from %1 mailing lists.{/ts}',1,1),
     ('{ts escape="sql"}Auto-responder{/ts}','Reply','{ts escape="sql"}Please Send Inquiries to Our Contact Email Address{/ts}','{ts escape="sql"}This is an automated reply from an un-attended mailbox. Please send any inquiries to the contact email address listed on our web-site.{/ts}','{ts escape="sql"}This is an automated reply from an un-attended mailbox. Please send any inquiries to the contact email address listed on our web-site.{/ts}',1,1);