Expose the receipt action for standalone or searchkit use
authoreileen <emcnaughton@wikimedia.org>
Tue, 6 Apr 2021 11:07:40 +0000 (23:07 +1200)
committereileen <emcnaughton@wikimedia.org>
Wed, 7 Apr 2021 02:24:14 +0000 (14:24 +1200)
Adds controller for id based tasks

Supports a url like https://dmaster.localhost:32353/civicrm/contribute/task?task=receipt&id=40,41

Note the pdf option doesn't work in pop-up mode - to discuss

Also note this exposes it as an action on the contribution results. That's optional. I think it has
been requested / would be useful but it's mostly included to make the page accessible for testing
and to work through the issue around filtering - the action only works on some statuses

CRM/Contribute/Controller/Task.php [new file with mode: 0644]
CRM/Contribute/Form/Task/PDF.php
CRM/Contribute/Selector/Search.php
CRM/Contribute/Task.php
CRM/Contribute/xml/Menu/Contribute.xml
CRM/Core/Controller/Task.php [new file with mode: 0644]

diff --git a/CRM/Contribute/Controller/Task.php b/CRM/Contribute/Controller/Task.php
new file mode 100644 (file)
index 0000000..49e2d60
--- /dev/null
@@ -0,0 +1,52 @@
+<?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_Export_Controller_Standalone
+ */
+class CRM_Contribute_Controller_Task extends CRM_Core_Controller_Task {
+
+  /**
+   * Get the name used to construct the class.
+   *
+   * @return string
+   */
+  public function getEntity():string {
+    return 'Contribution';
+  }
+
+  /**
+   * Get the available tasks for the entity.
+   *
+   * @return array
+   */
+  public function getAvailableTasks():array {
+    return CRM_Contribute_Task::tasks();
+  }
+
+  /**
+   * Override parent to avoid e-notice if the page is 'Search'.
+   *
+   * There are no form values for Search when the standalone processor is used
+   * - move along.
+   *
+   * @param string $pageName
+   *
+   * @return array
+   */
+  public function exportValues($pageName = NULL) {
+    if ($pageName === 'Search') {
+      return [];
+    }
+    return parent::exportValues($pageName);
+  }
+
+}
index 8a7ce4c5cd32a01ba930739bf507a2fce3a65a5c..a114dfbab9007baa112ae28a737ee727eee6e22e 100644 (file)
@@ -66,6 +66,8 @@ AND    {$this->_componentClause}";
     parent::setContactIDs();
     CRM_Utils_System::appendBreadCrumb($breadCrumb);
     CRM_Utils_System::setTitle(ts('Print Contribution Receipts'));
+    // Ajax submit would interfere with pdf file download
+    $this->preventAjaxSubmit();
   }
 
   /**
index 010d05116d85dc93b61c334a6425139989c74b87..4e745c54bddd015956f5a1de16f59eb5b87d1768 100644 (file)
@@ -353,6 +353,7 @@ class CRM_Contribute_Selector_Search extends CRM_Core_Selector_Base implements C
           $qfKey,
           $componentContext
       );
+
       $checkLineItem = FALSE;
       $row = [];
       // Now check for lineItems
@@ -445,6 +446,7 @@ class CRM_Contribute_Selector_Search extends CRM_Core_Selector_Base implements C
           'title' => $buttonName,
         ];
       }
+      $links = $links + CRM_Contribute_Task::getContextualLinks($row);
 
       $row['action'] = CRM_Core_Action::formLink(
         $links,
index eb9c057d7038df4668e19ffce7252ea0ff1ea094..01dad553a9e9a8f572fe9f193416b6b6f686d1c8 100644 (file)
@@ -89,6 +89,12 @@ class CRM_Contribute_Task extends CRM_Core_Task {
           'title' => ts('Receipts - print or email'),
           'class' => 'CRM_Contribute_Form_Task_PDF',
           'result' => FALSE,
+          'title_single_mode' => ts('Send Receipt'),
+          'name' => ts('Send Receipt'),
+          'is_support_standalone' => TRUE,
+          'key' => 'receipt',
+          'filters' => ['contribution_status_id' => [CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed')]],
+          'is_single_mode' => TRUE,
         ],
         self::PDF_THANKYOU => [
           'title' => ts('Thank-you letters - print or email'),
@@ -123,6 +129,35 @@ class CRM_Contribute_Task extends CRM_Core_Task {
     return self::$_tasks;
   }
 
+  /**
+   * Get links appropriate to the context of the row.
+   *
+   * @param $row
+   *
+   * @return array
+   */
+  public static function getContextualLinks($row) {
+    $tasks = self::tasks();
+    foreach ($tasks as $key => $task) {
+      if (empty($task['is_single_mode'])) {
+        unset($tasks[$key]);
+        continue;
+      }
+      if (!empty($task['filters'])) {
+        foreach ($task['filters'] as $filter => $values) {
+          if (!in_array($row[$filter], $values, FALSE)) {
+            unset($tasks[$key]);
+            continue 2;
+          }
+        }
+      }
+      $tasks[$key]['url'] = 'civicrm/contribute/task';
+      $tasks[$key]['qs'] = ['reset' => 1, 'id' => $row['contribution_id'], 'task' => $task['key']];
+      $tasks[$key]['title'] = $task['title_single_mode'] ?? $task['title'];
+    }
+    return $tasks;
+  }
+
   /**
    * Show tasks selectively based on the permission level
    * of the user
index 7aacf023b3d99fd9d20625ed90f674cc97f4839e..9409e579bfb2511706dbcced3da0dc6e4eb0fddc 100644 (file)
     <weight>0</weight>
     <is_public>true</is_public>
   </item>
+  <item>
+    <path>civicrm/contribute/task</path>
+    <title>Contribution Task</title>
+    <page_callback>CRM_Contribute_Controller_Task</page_callback>
+    <access_arguments>access CiviContribute</access_arguments>
+  </item>
 </menu>
diff --git a/CRM/Core/Controller/Task.php b/CRM/Core/Controller/Task.php
new file mode 100644 (file)
index 0000000..5af9740
--- /dev/null
@@ -0,0 +1,84 @@
+<?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_Export_Controller_Standalone
+ */
+abstract class CRM_Core_Controller_Task extends CRM_Core_Controller {
+
+  /**
+   * Class constructor.
+   *
+   * @param string $title
+   * @param bool|int $action
+   * @param bool $modal
+   *
+   * @throws \CRM_Core_Exception
+   * @throws \CiviCRM_API3_Exception
+   */
+  public function __construct($title = NULL, $action = CRM_Core_Action::NONE, $modal = TRUE) {
+
+    parent::__construct($title, $modal);
+    $id = explode(',', CRM_Utils_Request::retrieve('id', 'CommaSeparatedIntegers', $this, TRUE));
+
+    // Check permissions
+    $perm = civicrm_api3($this->getEntity(), 'get', [
+      'return' => 'id',
+      'options' => ['limit' => 0],
+      'check_permissions' => 1,
+      'id' => ['IN' => $id],
+    ])['values'];
+    if (empty($perm)) {
+      throw new CRM_Core_Exception(ts('No records available'));
+    }
+    $this->set('id', implode(',', array_keys($perm)));
+    $pages = array_fill_keys($this->getTaskClass(), NULL);
+
+    $this->_stateMachine = new CRM_Core_StateMachine($this);
+    $this->_stateMachine->addSequentialPages($pages);
+    // create and instantiate the pages
+    $this->addPages($this->_stateMachine, $action);
+    // add all the actions
+    $this->addActions();
+  }
+
+  /**
+   * Get the name used to construct the class.
+   *
+   * @return string
+   */
+  abstract public function getEntity():string;
+
+  /**
+   * Get the available tasks for the entity.
+   *
+   * @return array
+   */
+  abstract public function getAvailableTasks():array;
+
+  /**
+   * Get the class for the action.
+   *
+   * @return array Array of the classes for the form controlle.
+   *
+   * @throws \CRM_Core_Exception
+   */
+  protected function getTaskClass(): array {
+    $task = CRM_Utils_Request::retrieve('task', 'Alphanumeric', $this, TRUE);
+    foreach ($this->getAvailableTasks() as $taskAction) {
+      if (($taskAction['key'] ?? '') === $task) {
+        return (array) $taskAction['class'];
+      }
+    }
+    throw new CRM_Core_Exception(ts('Invalid task'));
+  }
+
+}