(dev/core/40) Show List of Contributions On Recurring Contribution View (#11920)
authorCamilo Rodríguez <camilo@compucorp.co.uk>
Mon, 7 May 2018 02:07:20 +0000 (21:07 -0500)
committerEileen McNaughton <eileen@mcnaughty.com>
Mon, 7 May 2018 02:07:20 +0000 (14:07 +1200)
* CRM-40: Show List of Contributions On Recurring Contribution View

Altered ContributionRecur page so that the list of contributions related to a
recurring contribution are shown when viewing said recurring contribution.

Implemented by running CRM_Contribute_Form_Search ebedded within the page and
including CRM/Contribute/Form/Selector.tpl template within the page's
template. Also included ContributionTotals.tpl to show, which I though could
be cool.

* CRM-40: Don't Use CRM_Contribute_Form_Search to Show Contributions

CRM_Contribute_Form_Search class is very hard to read and maintain, which is
why it was found better to look for related contributions manually and show
them using an ajax datatable.

* CRM-40: Fix Failing Test

* CRM-40: Show Contribution List Using Ajax Call

Added new Page that shows related payments for a given relted contribution in
a data table and included the table on recurring contribution's detail view
using an ajax call.

CRM/Contribute/Form/Task.php
CRM/Contribute/Form/UpdateSubscription.php
CRM/Contribute/Page/ContributionRecur.php
CRM/Contribute/Page/ContributionRecurPayments.php [new file with mode: 0644]
CRM/Contribute/xml/Menu/Contribute.xml
templates/CRM/Contribute/Page/ContributionRecur.tpl
templates/CRM/Contribute/Page/ContributionRecurPayments.tpl [new file with mode: 0644]

index dbfb3976e28afcd2f61335b7947ce6e95c038ad3..296401626407cb367dd9f7ce5492b7dfb20b60e8 100644 (file)
@@ -116,10 +116,12 @@ class CRM_Contribute_Form_Task extends CRM_Core_Form {
     else {
       $queryParams = $form->get('queryParams');
       $isTest = FALSE;
-      foreach ($queryParams as $fields) {
-        if ($fields[0] == 'contribution_test') {
-          $isTest = TRUE;
-          break;
+      if (is_array($queryParams)) {
+        foreach ($queryParams as $fields) {
+          if ($fields[0] == 'contribution_test') {
+            $isTest = TRUE;
+            break;
+          }
         }
       }
       if (!$isTest) {
index 31907156ec9a89ab7b5611d837b91cd53e674e4a..5f09e5c0fd4c9c3568f1dc30465c6c94122c44ff 100644 (file)
@@ -87,6 +87,9 @@ class CRM_Contribute_Form_UpdateSubscription extends CRM_Core_Form {
       catch (CRM_Core_Exception $e) {
         CRM_Core_Error::statusBounce(ts('There is no valid processor for this subscription so it cannot be edited.'));
       }
+      catch (CiviCRM_API3_Exception $e) {
+        CRM_Core_Error::statusBounce(ts('There is no valid processor for this subscription so it cannot be edited.'));
+      }
       $this->_subscriptionDetails = CRM_Contribute_BAO_ContributionRecur::getSubscriptionDetails($this->contributionRecurID);
     }
 
index 84ba834139ac0c3db5d4f0523065cabe684f8a95..dea041f3b6a94d498e33a8af07fb1f0c497f0dbc 100644 (file)
@@ -39,6 +39,8 @@ class CRM_Contribute_Page_ContributionRecur extends CRM_Core_Page {
   static $_links = NULL;
   public $_permission = NULL;
   public $_contactId = NULL;
+  public $_id = NULL;
+  public $_action = NULL;
 
   /**
    * View details of a recurring contribution.
@@ -57,7 +59,9 @@ class CRM_Contribute_Page_ContributionRecur extends CRM_Core_Page {
       CRM_Core_Error::statusBounce('Recurring contribution not found (ID: ' . $this->_id);
     }
 
-    $contributionRecur['payment_processor'] = CRM_Financial_BAO_PaymentProcessor::getPaymentProcessorName($contributionRecur['payment_processor_id']);
+    $contributionRecur['payment_processor'] = CRM_Financial_BAO_PaymentProcessor::getPaymentProcessorName(
+      CRM_Utils_Array::value('payment_processor_id', $contributionRecur)
+    );
     $idFields = array('contribution_status_id', 'campaign_id', 'financial_type_id');
     foreach ($idFields as $idField) {
       if (!empty($contributionRecur[$idField])) {
diff --git a/CRM/Contribute/Page/ContributionRecurPayments.php b/CRM/Contribute/Page/ContributionRecurPayments.php
new file mode 100644 (file)
index 0000000..746e2ec
--- /dev/null
@@ -0,0 +1,221 @@
+<?php\r
+\r
+/**\r
+ * Shows list of contributions done as payments within a recurring contribution.\r
+ */\r
+class CRM_Contribute_Page_ContributionRecurPayments extends CRM_Core_Page {\r
+\r
+  /**\r
+   * Contribution ID\r
+   *\r
+   * @var int\r
+   */\r
+  private $id = NULL;\r
+\r
+  /**\r
+   * Contact ID\r
+   *\r
+   * @var int\r
+   */\r
+  private $contactId = NULL;\r
+\r
+  /**\r
+   * Builds list of contributions for a given recurring contribution.\r
+   *\r
+   * @return null\r
+   */\r
+  public function run() {\r
+    $this->id = CRM_Utils_Request::retrieve('id', 'Positive', $this, TRUE);\r
+    $this->contactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this, TRUE);\r
+\r
+    $this->loadRelatedContributions();\r
+\r
+    return parent::run();\r
+  }\r
+\r
+  /**\r
+   * Loads contributions associated to the current recurring contribution being\r
+   * viewed.\r
+   */\r
+  private function loadRelatedContributions() {\r
+    $relatedContributions = array();\r
+\r
+    $relatedContributionsResult = civicrm_api3('Contribution', 'get', array(\r
+      'sequential' => 1,\r
+      'contribution_recur_id' => $this->id,\r
+      'contact_id' => $this->contactId,\r
+      'options' => array('limit' => 0),\r
+    ));\r
+\r
+    foreach ($relatedContributionsResult['values'] as $contribution) {\r
+      $this->insertAmountExpandingPaymentsControl($contribution);\r
+      $this->fixDateFormats($contribution);\r
+      $this->insertStatusLabels($contribution);\r
+      $this->insertContributionActions($contribution);\r
+\r
+      $relatedContributions[] = $contribution;\r
+    }\r
+\r
+    if (count($relatedContributions) > 0) {\r
+      $this->assign('contributionsCount', count($relatedContributions));\r
+      $this->assign('relatedContributions', json_encode($relatedContributions));\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Inserts a string into the array with the html used to show the expanding\r
+   * payments control, which loads when user clicks on the amount.\r
+   *\r
+   * @param array $contribution\r
+   *   Reference to the array holding the contribution's data and where the\r
+   *   control will be inserted into\r
+   */\r
+  private function insertAmountExpandingPaymentsControl(&$contribution) {\r
+    $amount = CRM_Utils_Money::format($contribution['total_amount'], $contribution['currency']);\r
+\r
+    $expandPaymentsUrl = CRM_Utils_System::url('civicrm/payment',\r
+      array(\r
+        'view' => 'transaction',\r
+        'component' => 'contribution',\r
+        'action' => 'browse',\r
+        'cid' => $this->contactId,\r
+        'id' => $contribution['contribution_id'],\r
+        'selector' => 1,\r
+      ),\r
+      FALSE, NULL, TRUE\r
+    );\r
+\r
+    $contribution['amount_control'] = '\r
+      <a class="nowrap bold crm-expand-row" title="view payments" href="' . $expandPaymentsUrl . '">\r
+        &nbsp; ' . $amount . '\r
+      </a>\r
+    ';\r
+  }\r
+\r
+  /**\r
+   * Fixes date fields present in the given contribution.\r
+   *\r
+   * @param array $contribution\r
+   *   Reference to the array holding the contribution's data\r
+   */\r
+  private function fixDateFormats(&$contribution) {\r
+    $config = CRM_Core_Config::singleton();\r
+\r
+    $contribution['formatted_receive_date'] = CRM_Utils_Date::customFormat($contribution['receive_date'], $config->dateformatDatetime);\r
+    $contribution['formatted_thankyou_date'] = CRM_Utils_Date::customFormat($contribution['thankyou_date'], $config->dateformatDatetime);\r
+  }\r
+\r
+  /**\r
+   * Inserts a contribution_status_label key into the array, with the value\r
+   * showing the current status plus observations on the current status.\r
+   *\r
+   * @param array $contribution\r
+   *   Reference to the array holding the contribution's data and where the new\r
+   *   position will be inserted\r
+   */\r
+  private function insertStatusLabels(&$contribution) {\r
+    $contribution['contribution_status_label'] = $contribution['contribution_status'];\r
+\r
+    if ($contribution['is_pay_later'] && CRM_Utils_Array::value('contribution_status', $contribution) == 'Pending') {\r
+      $contribution['contribution_status_label'] .= ' (' . ts('Pay Later') . ')';\r
+    }\r
+    elseif (CRM_Utils_Array::value('contribution_status', $contribution) == 'Pending') {\r
+      $contribution['contribution_status_label'] .= ' (' . ts('Incomplete Transaction') . ')';\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Inserts into the given array a string with the 'action' key, holding the\r
+   * html to be used to show available actions for the contribution.\r
+   *\r
+   * @param $contribution\r
+   *   Reference to the array holding the contribution's data. It is also the\r
+   *   array where the new 'action' key will be inserted.\r
+   */\r
+  private function insertContributionActions(&$contribution) {\r
+    $contribution['action'] = CRM_Core_Action::formLink(\r
+      $this->buildContributionLinks($contribution),\r
+      $this->getContributionPermissionsMask(),\r
+      array(\r
+        'id' => $contribution['contribution_id'],\r
+        'cid' => $contribution['contact_id'],\r
+        'cxt' => 'contribution',\r
+      ),\r
+      ts('more'),\r
+      FALSE,\r
+      'contribution.selector.row',\r
+      'Contribution',\r
+      $contribution['contribution_id']\r
+    );\r
+  }\r
+\r
+  /**\r
+   * Builds list of links for authorized actions that can be done on given\r
+   * contribution.\r
+   *\r
+   * @param array $contribution\r
+   *\r
+   * @return array\r
+   */\r
+  private function buildContributionLinks($contribution) {\r
+    $links = CRM_Contribute_Selector_Search::links($contribution['contribution_id'],\r
+      CRM_Utils_Request::retrieve('action', 'String'),\r
+      NULL,\r
+      NULL\r
+    );\r
+\r
+    $isPayLater = FALSE;\r
+    if ($contribution['is_pay_later'] && CRM_Utils_Array::value('contribution_status', $contribution) == 'Pending') {\r
+      $isPayLater = TRUE;\r
+\r
+      $links[CRM_Core_Action::ADD] = array(\r
+        'name' => ts('Pay with Credit Card'),\r
+        'url' => 'civicrm/contact/view/contribution',\r
+        'qs' => 'reset=1&action=update&id=%%id%%&cid=%%cid%%&context=%%cxt%%&mode=live',\r
+        'title' => ts('Pay with Credit Card'),\r
+      );\r
+    }\r
+\r
+    if (in_array($contribution['contribution_status'], array('Partially paid', 'Pending refund')) || $isPayLater) {\r
+      $buttonName = ts('Record Payment');\r
+\r
+      if ($contribution['contribution_status'] == 'Pending refund') {\r
+        $buttonName = ts('Record Refund');\r
+      }\r
+      elseif (CRM_Core_Config::isEnabledBackOfficeCreditCardPayments()) {\r
+        $links[CRM_Core_Action::BASIC] = array(\r
+          'name' => ts('Submit Credit Card payment'),\r
+          'url' => 'civicrm/payment/add',\r
+          'qs' => 'reset=1&id=%%id%%&cid=%%cid%%&action=add&component=contribution&mode=live',\r
+          'title' => ts('Submit Credit Card payment'),\r
+        );\r
+      }\r
+      $links[CRM_Core_Action::ADD] = array(\r
+        'name' => $buttonName,\r
+        'url' => 'civicrm/payment',\r
+        'qs' => 'reset=1&id=%%id%%&cid=%%cid%%&action=add&component=contribution',\r
+        'title' => $buttonName,\r
+      );\r
+    }\r
+\r
+    return $links;\r
+  }\r
+\r
+  /**\r
+   * Builds a mask with allowed contribution related permissions.\r
+   *\r
+   * @return int\r
+   */\r
+  private function getContributionPermissionsMask() {\r
+    $permissions = array(CRM_Core_Permission::VIEW);\r
+    if (CRM_Core_Permission::check('edit contributions')) {\r
+      $permissions[] = CRM_Core_Permission::EDIT;\r
+    }\r
+    if (CRM_Core_Permission::check('delete in CiviContribute')) {\r
+      $permissions[] = CRM_Core_Permission::DELETE;\r
+    }\r
+\r
+    return CRM_Core_Action::mask($permissions);\r
+  }\r
+\r
+}\r
index 66b318e5f3a54809a008ed3e65d96fb869e4957d..3b3d94a7b3b4dd2814babbe0426b1e2c05aa0d8e 100644 (file)
     <page_callback>CRM_Contribute_Page_AJAX::getSoftContributionRows</page_callback>
     <access_arguments>access CiviCRM</access_arguments>
   </item>
+  <item>
+    <path>civicrm/contribute/contributionrecur-payments</path>
+    <title>Recurring Contribution's Payments</title>
+    <page_callback>CRM_Contribute_Page_ContributionRecurPayments</page_callback>
+    <access_arguments>access CiviContribute</access_arguments>
+  </item>
 </menu>
index 3d4368acb94551d3d350a48849ee2a3d10d9b867..767e62bff20c1e7b8fee57cbb0729a002e4c6e12 100644 (file)
           <div class="crm-submit-buttons"><a class="button cancel crm-form-submit" href="{crmURL p='civicrm/contact/view' q='action=browse&selectedChild=contribute'}">{ts}Done{/ts}</a></div>
         </div>
     {/if}
+
+  <script type="text/javascript">
+    var recurContribID = {$recur.id};
+    var contactID = {$contactId};
+    {literal}
+    CRM.$(function($) {
+      CRM.loadPage(
+        CRM.url(
+          'civicrm/contribute/contributionrecur-payments',
+          {
+            reset: 1,
+            id: recurContribID,
+            cid: contactID
+          },
+          'back'
+        ),
+        {
+          target : '#recurring-contribution-payments',
+          dialog : false
+        }
+      );
+    });
+    {/literal}
+  </script>
+  <div id="recurring-contribution-payments"></div>
 {/if}
 {if $recurRows}
     {strip}
diff --git a/templates/CRM/Contribute/Page/ContributionRecurPayments.tpl b/templates/CRM/Contribute/Page/ContributionRecurPayments.tpl
new file mode 100644 (file)
index 0000000..566a466
--- /dev/null
@@ -0,0 +1,42 @@
+{if $contributionsCount > 0}\r
+  <div class="crm-accordion-wrapper">\r
+    <div class="crm-accordion-header">{ts}Related Contributions{/ts}</div>\r
+    <div class="crm-accordion-body">\r
+      <table class="crm-contact-contributions">\r
+        <thead>\r
+        <tr>\r
+          <th class='crm-contact-total_amount'>{ts}Amount{/ts}</th>\r
+          <th class='crm-contact-financial_type_id'>{ts}Type{/ts}</th>\r
+          <th class='crm-contact-contribution_source'>{ts}Source{/ts}</th>\r
+          <th class='crm-contact-receive_date'>{ts}Recieved{/ts}</th>\r
+          <th class='crm-contact-thankyou_date'>{ts}Thank-you Sent{/ts}</th>\r
+          <th class='crm-contact-contribution_status'>{ts}Status{/ts}</th>\r
+          <th>&nbsp;</th>\r
+        </tr>\r
+        </thead>\r
+      </table>\r
+      <script type="text/javascript">\r
+        var tableData = {$relatedContributions};\r
+        {literal}\r
+        cj('table.crm-contact-contributions').DataTable({\r
+          data : tableData,\r
+          columns: [\r
+            { data: 'amount_control' },\r
+            { data: 'financial_type' },\r
+            { data: 'contribution_source' },\r
+            { data: 'formatted_receive_date' },\r
+            { data: 'formatted_thankyou_date' },\r
+            { data: 'contribution_status_label' },\r
+            { data: 'action' }\r
+          ]\r
+        });\r
+        {/literal}\r
+      </script>\r
+    </div>\r
+  </div>\r
+{else}\r
+  <div class="messages status no-popup">\r
+    <div class="icon inform-icon"></div>\r
+    {ts}No contributions have been recorded for this recurring contribution.{/ts}\r
+  </div>\r
+{/if}\r