Merge pull request #10157 from eileenmcnaughton/iida3
authorEileen McNaughton <eileen@mcnaughty.com>
Thu, 20 Apr 2017 22:57:39 +0000 (10:57 +1200)
committerGitHub <noreply@github.com>
Thu, 20 Apr 2017 22:57:39 +0000 (10:57 +1200)
CRM-20264, Added Card type and Pan Truncation form fields on Payment …

25 files changed:
CRM/Admin/Form/Options.php
CRM/Admin/Form/PaymentProcessor.php
CRM/Admin/Page/APIExplorer.php
CRM/Admin/Page/Options.php
CRM/Admin/Page/PaymentProcessor.php
CRM/Case/BAO/Case.php
CRM/Contribute/BAO/Contribution.php
CRM/Contribute/Form/AbstractEditPayment.php
CRM/Contribute/PseudoConstant.php
CRM/Core/Payment/AuthorizeNetIPN.php
CRM/Core/Payment/BaseIPN.php
CRM/Financial/BAO/FinancialTypeAccount.php
CRM/Utils/Hook.php
Civi/API/Events.php
Civi/Core/CiviEventInspector.php [new file with mode: 0644]
Civi/Core/Container.php
Civi/Core/Event/SystemInstallEvent.php
api/v3/Contribution.php
tests/phpunit/CRM/Activity/BAO/ActivityTest.php
tests/phpunit/CRM/Core/Payment/AuthorizeNetIPNTest.php
tests/phpunit/CRM/Financial/BAO/FinancialTypeAccountTest.php
tests/phpunit/Civi/Core/CiviEventInspectorTest.php [new file with mode: 0644]
tests/phpunit/CiviTest/CiviUnitTestCase.php
tests/phpunit/api/v3/ContributionTest.php
tests/phpunit/api/v3/EventTest.php

index 670a21688a3c503f6ceb2d010b4e7c60b2c58519..7dc2560376b1916639b5524e0695394cc9af6258 100644 (file)
@@ -132,7 +132,7 @@ class CRM_Admin_Form_Options extends CRM_Admin_Form {
     }
     // CRM-11516
     if ($this->_gName == 'payment_instrument' && $this->_id) {
-      $defaults['financial_account_id'] = CRM_Financial_BAO_FinancialTypeAccount::getFinancialAccount($this->_id, 'civicrm_option_value', 'financial_account_id');
+      $defaults['financial_account_id'] = CRM_Contribute_PseudoConstant::getRelationalFinancialAccount($this->_id, NULL, 'civicrm_option_value');
     }
     if (empty($this->_id) || !CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', $this->_id, 'color')) {
       $defaults['color'] = '#ffffff';
index e444eea37a23fa0b34bf384ac44a6782d5ee8dde..64fd697ea88a225d50f71076085d884fbfa558c7 100644 (file)
@@ -359,7 +359,7 @@ class CRM_Admin_Form_PaymentProcessor extends CRM_Admin_Form {
         $defaults[$testName] = $testDAO->{$field['name']};
       }
     }
-    $defaults['financial_account_id'] = CRM_Financial_BAO_FinancialTypeAccount::getFinancialAccount($dao->id, 'civicrm_payment_processor', 'financial_account_id');
+    $defaults['financial_account_id'] = CRM_Contribute_PseudoConstant::getRelationalFinancialAccount($dao->id, NULL, 'civicrm_payment_processor');
 
     return $defaults;
   }
index 6097d5831a3f895ca037361ae0429e5e482501b5..c5bfa84a05a36fee6fd4d0b0e398b77c19e22007 100644 (file)
@@ -184,7 +184,12 @@ class CRM_Admin_Page_APIExplorer extends CRM_Core_Page {
    * @param string $text
    * @return string
    */
-  private static function formatDocBlock($text) {
+  public static function formatDocBlock($text) {
+    // Normalize #leading spaces.
+    $lines = explode("\n", $text);
+    $lines = preg_replace('/^ +\*/', ' *', $lines);
+    $text = implode("\n", $lines);
+
     // Get rid of comment stars
     $text = str_replace(array("\n * ", "\n *\n", "\n */\n", "/**\n"), array("\n", "\n\n", '', ''), $text);
 
index 71d826feb05950dfc698fb65c47f98a44ce7bafd..1a5fdb8671ef5c7771de63f9864aadd7cff64fc4 100644 (file)
@@ -245,7 +245,7 @@ class CRM_Admin_Page_Options extends CRM_Core_Page_Basic {
     // retrieve financial account name for the payment method page
     if ($gName = "payment_instrument") {
       foreach ($optionValue as $key => $option) {
-        $optionValue[$key]['financial_account'] = CRM_Financial_BAO_FinancialTypeAccount::getFinancialAccount($key, 'civicrm_option_value');
+        $optionValue[$key]['financial_account'] = CRM_Contribute_PseudoConstant::getRelationalFinancialAccount($key, NULL, 'civicrm_option_value', 'financial_account_id.name');
       }
     }
     $this->assign('rows', $optionValue);
index 40e5683a54470a5282f3fb0f6c0a72518101510e..63c9e1917607fe96b04aee7a428b3db6f1bbdc6e 100644 (file)
@@ -156,7 +156,7 @@ class CRM_Admin_Page_PaymentProcessor extends CRM_Core_Page_Basic {
         'PaymentProcessor',
         $dao->id
       );
-      $paymentProcessor[$dao->id]['financialAccount'] = CRM_Financial_BAO_FinancialTypeAccount::getFinancialAccount($dao->id, 'civicrm_payment_processor');
+      $paymentProcessor[$dao->id]['financialAccount'] = CRM_Contribute_PseudoConstant::getRelationalFinancialAccount($dao->id, NULL, 'civicrm_payment_processor', 'financial_account_id.name');
     }
 
     $this->assign('rows', $paymentProcessor);
index 78943a5254a191cb4ef6059d6b5191bb3a4829c9..991ccb9e330921949d0c3e3a551dc84c53994fd6 100644 (file)
@@ -1347,9 +1347,8 @@ SELECT case_status.label AS case_status, status_id, civicrm_case_type.title AS c
     }
 
     $result = array();
-    list($name, $address) = CRM_Contact_BAO_Contact_Location::getEmailDetails($userID);
-
-    $receiptFrom = "$name <$address>";
+    // CRM-20308 get receiptFrom defaults see https://issues.civicrm.org/jira/browse/CRM-20308
+    $receiptFrom = self::getReceiptFrom($activityId);
 
     $recordedActivityParams = array();
 
@@ -2999,7 +2998,7 @@ WHERE id IN (' . implode(',', $copiedActivityIds) . ')';
  AS SELECT ca.case_id, a.id, a.activity_date_time, a.status_id, a.activity_type_id
  FROM civicrm_case_activity ca
  INNER JOIN civicrm_activity a ON ca.activity_id=a.id
- WHERE a.activity_date_time = 
+ WHERE a.activity_date_time =
 (SELECT b.activity_date_time FROM civicrm_case_activity bca
  INNER JOIN civicrm_activity b ON bca.activity_id=b.id
  WHERE b.activity_date_time <= DATE_ADD( NOW(), INTERVAL 14 DAY )
@@ -3012,7 +3011,7 @@ WHERE id IN (' . implode(',', $copiedActivityIds) . ')';
  AS SELECT ca.case_id, a.id, a.activity_date_time, a.status_id, a.activity_type_id
  FROM civicrm_case_activity ca
  INNER JOIN civicrm_activity a ON ca.activity_id=a.id
- WHERE a.activity_date_time = 
+ WHERE a.activity_date_time =
 (SELECT b.activity_date_time FROM civicrm_case_activity bca
  INNER JOIN civicrm_activity b ON bca.activity_id=b.id
  WHERE b.activity_date_time >= DATE_SUB( NOW(), INTERVAL 14 DAY )
@@ -3170,4 +3169,39 @@ WHERE id IN (' . implode(',', $copiedActivityIds) . ')';
     return $clauses;
   }
 
+  /**
+   * CRM-20308: Method to get the contact id to use as from contact for email copy
+   * 1. Activity Added by Contact's email address
+   * 2. System Default From Address
+   * 3. Default Organization Contact email address
+   * 4. Logged in user
+   *
+   * @param int $activityID
+   *
+   * @return mixed $emailFromContactId
+   * @see https://issues.civicrm.org/jira/browse/CRM-20308
+   */
+  public static function getReceiptFrom($activityID) {
+    $name = $address = NULL;
+
+    if (!empty($activityID)) {
+      // There is always a 'Added by' contact for a activity,
+      //  so we can safely use ActivityContact.Getvalue API
+      $sourceContactId = civicrm_api3('ActivityContact', 'getvalue', array(
+        'activity_id' => $activityID,
+        'record_type_id' => 'Activity Source',
+        'return' => 'contact_id',
+      ));
+      list($name, $address) = CRM_Contact_BAO_Contact_Location::getEmailDetails($sourceContactId);
+    }
+
+    // If 'From' email address not found for Source Activity Contact then
+    //   fetch the email from domain or logged in user.
+    if (empty($address)) {
+      list($name, $address) = CRM_Core_BAO_Domain::getDefaultReceiptFrom();
+    }
+
+    return "$name <$address>";
+  }
+
 }
index c18b70b871fb0df722af5a7b4bf7f3e10d999d96..a6d6b67f5de887b20c9b7dbafe86f2929582f058 100644 (file)
@@ -3169,7 +3169,7 @@ INNER JOIN civicrm_activity ON civicrm_activity_contact.activity_id = civicrm_ac
         );
       }
       elseif (!empty($params['payment_processor'])) {
-        $params['to_financial_account_id'] = CRM_Financial_BAO_FinancialTypeAccount::getFinancialAccount($params['payment_processor'], 'civicrm_payment_processor', 'financial_account_id');
+        $params['to_financial_account_id'] = CRM_Contribute_PseudoConstant::getRelationalFinancialAccount($params['payment_processor'], NULL, 'civicrm_payment_processor');
         $params['payment_instrument_id'] = civicrm_api3('PaymentProcessor', 'getvalue', array(
           'id' => $params['payment_processor'],
           'return' => 'payment_instrument_id',
@@ -4444,14 +4444,10 @@ WHERE eft.financial_trxn_id IN ({$trxnId}, {$baseTrxnId['financialTrxnId']})
    * @param CRM_Core_Transaction $transaction
    * @param int $recur
    * @param CRM_Contribute_BAO_Contribution $contribution
-   * @param bool $isRecurring
-   *   Duplication of param needs review. Only used by AuthorizeNetIPN
-   * @param int $isFirstOrLastRecurringPayment
-   *   Deprecated param only used by AuthorizeNetIPN.
    *
    * @return array
    */
-  public static function completeOrder(&$input, &$ids, $objects, $transaction, $recur, $contribution, $isRecurring, $isFirstOrLastRecurringPayment) {
+  public static function completeOrder(&$input, &$ids, $objects, $transaction, $recur, $contribution) {
     $primaryContributionID = isset($contribution->id) ? $contribution->id : $objects['first_contribution']->id;
     // The previous details are used when calculating line items so keep it before any code that 'does something'
     if (!empty($contribution->id)) {
@@ -4584,43 +4580,52 @@ LIMIT 1;";
             }
             $dao->free();
 
-            $membershipParams['num_terms'] = $contribution->getNumTermsByContributionAndMembershipType(
-              $membershipParams['membership_type_id'],
-              $primaryContributionID
-            );
-            $dates = array_fill_keys(array('join_date', 'start_date', 'end_date'), NULL);
-            if ($currentMembership) {
-              /*
-               * Fixed FOR CRM-4433
-               * In BAO/Membership.php(renewMembership function), we skip the extend membership date and status
-               * when Contribution mode is notify and membership is for renewal )
-               */
-              CRM_Member_BAO_Membership::fixMembershipStatusBeforeRenew($currentMembership, $changeDate);
-
-              // @todo - we should pass membership_type_id instead of null here but not
-              // adding as not sure of testing
-              $dates = CRM_Member_BAO_MembershipType::getRenewalDatesForMembershipType($membershipParams['id'],
-                $changeDate, NULL, $membershipParams['num_terms']
-              );
-
-              $dates['join_date'] = $currentMembership['join_date'];
+            if (CRM_Core_PseudoConstant::getLabel('CRM_Contribute_BAO_Contribution', 'contribution_status_id', CRM_Utils_Array::value('contribution_status_id', $input)) === 'Pending') {
+              $membershipParams['num_terms'] = 0;
             }
+            else {
+              $membershipParams['num_terms'] = $contribution->getNumTermsByContributionAndMembershipType(
+                $membershipParams['membership_type_id'],
+                $primaryContributionID
+              );
+              // @todo remove all this stuff in favour of letting the api call further down handle in
+              // (it is a duplication of what the api does).
+              $dates = array_fill_keys(array('join_date', 'start_date', 'end_date'), NULL);
+              if ($currentMembership) {
+                /*
+                 * Fixed FOR CRM-4433
+                 * In BAO/Membership.php(renewMembership function), we skip the extend membership date and status
+                 * when Contribution mode is notify and membership is for renewal )
+                 */
+                CRM_Member_BAO_Membership::fixMembershipStatusBeforeRenew($currentMembership, $changeDate);
+
+                // @todo - we should pass membership_type_id instead of null here but not
+                // adding as not sure of testing
+                $dates = CRM_Member_BAO_MembershipType::getRenewalDatesForMembershipType($membershipParams['id'],
+                  $changeDate, NULL, $membershipParams['num_terms']
+                );
+
+                $dates['join_date'] = $currentMembership['join_date'];
+              }
 
-            //get the status for membership.
-            $calcStatus = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($dates['start_date'],
-              $dates['end_date'],
-              $dates['join_date'],
-              'today',
-              TRUE,
-              $membershipParams['membership_type_id'],
-              $membershipParams
-            );
+              //get the status for membership.
+              $calcStatus = CRM_Member_BAO_MembershipStatus::getMembershipStatusByDate($dates['start_date'],
+                $dates['end_date'],
+                $dates['join_date'],
+                'today',
+                TRUE,
+                $membershipParams['membership_type_id'],
+                $membershipParams
+              );
 
-            $membershipParams['status_id'] = CRM_Utils_Array::value('id', $calcStatus, 'New');
-            //we might be renewing membership,
-            //so make status override false.
-            $membershipParams['is_override'] = FALSE;
+              unset($dates['end_date']);
+              $membershipParams['status_id'] = CRM_Utils_Array::value('id', $calcStatus, 'New');
+              //we might be renewing membership,
+              //so make status override false.
+              $membershipParams['is_override'] = FALSE;
+            }
             //CRM-17723 - reset static $relatedContactIds array()
+            // @todo move it to Civi Statics.
             $var = TRUE;
             CRM_Member_BAO_Membership::createRelatedMemberships($var, $var, TRUE);
             civicrm_api3('Membership', 'create', $membershipParams);
@@ -4707,10 +4712,6 @@ LIMIT 1;";
     }
 
     CRM_Core_Error::debug_log_message("Success: Database updated");
-    if ($isRecurring) {
-      CRM_Contribute_BAO_ContributionRecur::sendRecurringStartOrEndNotification($ids, $recur,
-        $isFirstOrLastRecurringPayment);
-    }
     return $contributionResult;
   }
 
@@ -4871,7 +4872,7 @@ LIMIT 1;";
       $balanceTrxnParams['to_financial_account_id'] = CRM_Contribute_PseudoConstant::getRelationalFinancialAccount($contribution['financial_type_id'], 'Accounts Receivable Account is');
     }
     elseif (!empty($params['payment_processor'])) {
-      $balanceTrxnParams['to_financial_account_id'] = CRM_Financial_BAO_FinancialTypeAccount::getFinancialAccount($contribution['payment_processor'], 'civicrm_payment_processor', 'financial_account_id');
+      $balanceTrxnParams['to_financial_account_id'] = CRM_Contribute_PseudoConstant::getRelationalFinancialAccount($contribution['payment_processor'], NULL, 'civicrm_payment_processor');
     }
     elseif (!empty($params['payment_instrument_id'])) {
       $balanceTrxnParams['to_financial_account_id'] = CRM_Financial_BAO_FinancialTypeAccount::getInstrumentFinancialAccount($contribution['payment_instrument_id']);
index 62e05145317ca4df92ef4cbe0ceb258e19c79157..ceed89165e91018413f93cce4e524ca4a0ac864f 100644 (file)
@@ -394,33 +394,6 @@ WHERE  contribution_id = {$id}
     return $result;
   }
 
-  /**
-   * @param int $financialTypeId
-   *
-   * @return array
-   */
-  public function getFinancialAccounts($financialTypeId) {
-    $financialAccounts = array();
-    CRM_Core_PseudoConstant::populate($financialAccounts,
-      'CRM_Financial_DAO_EntityFinancialAccount',
-      $all = TRUE,
-      $retrieve = 'financial_account_id',
-      $filter = NULL,
-      " entity_id = {$financialTypeId} ", NULL, 'account_relationship');
-    return $financialAccounts;
-  }
-
-  /**
-   * @param int $financialTypeId
-   * @param int $relationTypeId
-   *
-   * @return mixed
-   */
-  public function getFinancialAccount($financialTypeId, $relationTypeId) {
-    $financialAccounts = $this->getFinancialAccounts($financialTypeId);
-    return CRM_Utils_Array::value($relationTypeId, $financialAccounts);
-  }
-
   public function preProcessPledge() {
     //get the payment values associated with given pledge payment id OR check for payments due.
     $this->_pledgeValues = array();
index 522e0cb3286996ac2af75610297f7bd07e506734..1cc6cd9859b1a1825844695164305d717aac32bb 100644 (file)
@@ -377,20 +377,24 @@ class CRM_Contribute_PseudoConstant extends CRM_Core_PseudoConstant {
    *
    * @param int $entityId
    * @param string $accountRelationType
-   *
+   * @param string $entityTable
+   * @param string $returnField
    * @return int
    */
-  public static function getRelationalFinancialAccount($entityId, $accountRelationType) {
-    $result = civicrm_api3('EntityFinancialAccount', 'get', array(
-      'return' => array("financial_account_id"),
-      'account_relationship.name' => $accountRelationType,
-      'entity_table' => 'civicrm_financial_type',
+  public static function getRelationalFinancialAccount($entityId, $accountRelationType, $entityTable = 'civicrm_financial_type', $returnField = 'financial_account_id') {
+    $params = array(
+      'return' => array($returnField),
+      'entity_table' => $entityTable,
       'entity_id' => $entityId,
-    ));
+    );
+    if ($accountRelationType) {
+      $params['account_relationship.name'] = $accountRelationType;
+    }
+    $result = civicrm_api3('EntityFinancialAccount', 'get', $params);
     if (!$result['count']) {
       return NULL;
     }
-    return $result['values'][$result['id']]['financial_account_id'];
+    return $result['values'][$result['id']][$returnField];
   }
 
   /**
index 5933ff9a6d65d6dd1ad912497402196450ae7f4d..2b87415b19b9d178868ff5fbdfc9ccac99aeb2f4 100644 (file)
@@ -148,7 +148,7 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
       $contribution->financial_type_id = $objects['contributionType']->id;
       $contribution->contribution_page_id = $ids['contributionPage'];
       $contribution->contribution_recur_id = $ids['contributionRecur'];
-      $contribution->receive_date = $now;
+      $contribution->receive_date = $input['receive_date'];
       $contribution->currency = $objects['contribution']->currency;
       $contribution->payment_instrument_id = $objects['contribution']->payment_instrument_id;
       $contribution->amount_level = $objects['contribution']->amount_level;
@@ -163,12 +163,13 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
 
     $this->checkMD5($paymentProcessorObject, $input);
 
+    $isFirstOrLastRecurringPayment = FALSE;
     if ($input['response_code'] == 1) {
       // Approved
       if ($first) {
         $recur->start_date = $now;
         $recur->trxn_id = $recur->processor_id;
-        $this->_isFirstOrLastRecurringPayment = CRM_Core_Payment::RECURRING_PAYMENT_START;
+        $isFirstOrLastRecurringPayment = CRM_Core_Payment::RECURRING_PAYMENT_START;
       }
       $statusName = 'In Progress';
       if (($recur->installments > 0) &&
@@ -177,7 +178,7 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
         // this is the last payment
         $statusName = 'Completed';
         $recur->end_date = $now;
-        $this->_isFirstOrLastRecurringPayment = CRM_Core_Payment::RECURRING_PAYMENT_END;
+        $isFirstOrLastRecurringPayment = CRM_Core_Payment::RECURRING_PAYMENT_END;
       }
       $recur->modified_date = $now;
       $recur->contribution_status_id = array_search($statusName, $contributionStatus);
@@ -209,6 +210,16 @@ class CRM_Core_Payment_AuthorizeNetIPN extends CRM_Core_Payment_BaseIPN {
     }
 
     $this->completeTransaction($input, $ids, $objects, $transaction, $recur);
+
+    // 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
+    // from isSentReceipt to an array of which receipts to send.
+    // Note that there is site-by-site opinions on which notifications are good to send.
+    if ($isFirstOrLastRecurringPayment) {
+      CRM_Contribute_BAO_ContributionRecur::sendRecurringStartOrEndNotification($ids, $recur,
+        $isFirstOrLastRecurringPayment);
+    }
+
   }
 
   /**
@@ -228,6 +239,8 @@ 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, 'now');
 
     if ($input['trxn_id']) {
       $input['is_test'] = 0;
index d1bbb00cba24008b7f3259371b7b836d5189e4c6..c4a1af336ce7c440d0453b396669ee91b8c5088c 100644 (file)
@@ -392,6 +392,8 @@ class CRM_Core_Payment_BaseIPN {
   }
 
   /**
+   * @deprecated
+   *
    * Jumbled up function.
    *
    * The purpose of this function is to transition a pending transaction to Completed including updating any
@@ -445,12 +447,9 @@ class CRM_Core_Payment_BaseIPN {
    * @param bool $recur
    */
   public function completeTransaction(&$input, &$ids, &$objects, &$transaction, $recur = FALSE) {
-    $isRecurring = $this->_isRecurring;
-    $isFirstOrLastRecurringPayment = $this->_isFirstOrLastRecurringPayment;
     $contribution = &$objects['contribution'];
 
-    CRM_Contribute_BAO_Contribution::completeOrder($input, $ids, $objects, $transaction, $recur, $contribution,
-      $isRecurring, $isFirstOrLastRecurringPayment);
+    CRM_Contribute_BAO_Contribution::completeOrder($input, $ids, $objects, $transaction, $recur, $contribution);
   }
 
   /**
index a023d233cd1966dc549aafa23b0e736db9dba9c5..92b8aa8d6199e39f2ca84770126e0e5c122222e9 100644 (file)
@@ -151,34 +151,6 @@ class CRM_Financial_BAO_FinancialTypeAccount extends CRM_Financial_DAO_EntityFin
     CRM_Core_Session::setStatus(ts('Unbalanced transactions may be created if you delete the account of type: %1.', array(1 => $relationValues[$financialType->account_relationship])));
   }
 
-  /**
-   * Get Financial Account Name.
-   *
-   * @param int $entityId
-   *
-   * @param string $entityTable
-   *
-   * @param string $columnName
-   *   Column to fetch.
-   *
-   * @return null|string
-   */
-  public static function getFinancialAccount($entityId, $entityTable, $columnName = 'name') {
-    $join = $columnName == 'name' ? 'LEFT JOIN civicrm_financial_account ON civicrm_entity_financial_account.financial_account_id = civicrm_financial_account.id' : NULL;
-    $query = "
-SELECT {$columnName}
-FROM civicrm_entity_financial_account
-{$join}
-WHERE entity_table = %1
-AND entity_id = %2";
-
-    $params = array(
-      1 => array($entityTable, 'String'),
-      2 => array($entityId, 'Integer'),
-    );
-    return CRM_Core_DAO::singleValueQuery($query, $params);
-  }
-
   /**
    * Financial Account for payment instrument.
    *
index e09561a0135ce633a57235191160b1d0d9688665..28462ccf971abd9de0bfddeaff4edaab1c6d65a3 100644 (file)
@@ -1841,6 +1841,18 @@ abstract class CRM_Utils_Hook {
     );
   }
 
+  /**
+   * Build a description of available hooks.
+   *
+   * @param \Civi\Core\CiviEventInspector $inspector
+   */
+  public static function eventDefs($inspector) {
+    $event = \Civi\Core\Event\GenericHookEvent::create(array(
+      'inspector' => $inspector,
+    ));
+    Civi::dispatcher()->dispatch('hook_civicrm_eventDefs', $event);
+  }
+
   /**
    * This hook is called while preparing a profile form.
    *
index 1dd734927820f70b0d3d2f17c7e62190d882d0bf..3f14a2ef5cccad247f86db57b0391fc8df6d1c7c 100644 (file)
@@ -105,4 +105,16 @@ class Events {
     );
   }
 
+  /**
+   * @param \Civi\Core\Event\GenericHookEvent $e
+   * @see \CRM_Utils_Hook::eventDefs
+   */
+  public static function hookEventDefs($e) {
+    $e->inspector->addEventClass(self::AUTHORIZE, 'Civi\API\Event\AuthorizeEvent');
+    $e->inspector->addEventClass(self::EXCEPTION, 'Civi\API\Event\ExceptionEvent');
+    $e->inspector->addEventClass(self::PREPARE, 'Civi\API\Event\PrepareEvent');
+    $e->inspector->addEventClass(self::RESOLVE, 'Civi\API\Event\ResolveEvent');
+    $e->inspector->addEventClass(self::RESPOND, 'Civi\API\Event\RespondEvent');
+  }
+
 }
diff --git a/Civi/Core/CiviEventInspector.php b/Civi/Core/CiviEventInspector.php
new file mode 100644 (file)
index 0000000..4f74cc5
--- /dev/null
@@ -0,0 +1,227 @@
+<?php
+namespace Civi\Core;
+
+/**
+ * Class CiviEventInspector
+ *
+ * The event inspector is a development tool which provides metadata about events.
+ * It can be used for code-generators and documentation-generators.
+ *
+ * @code
+ * $i = new CiviEventInspector();
+ * print_r(CRM_Utils_Array::collect('name', $i->getAll()));
+ * @endCode
+ *
+ * An event definition includes these fields:
+ *  - type: string, required. Ex: 'hook' or 'object'
+ *  - name: string, required. Ex: 'hook_civicrm_post' or 'civi.dao.postInsert'
+ *  - class: string, required. Ex: 'Civi\Core\Event\GenericHookEvent'.
+ *  - signature: string, required FOR HOOKS. Ex: '$first, &$second'.
+ *  - fields: array, required FOR HOOKS. List of hook parameters.
+ *  - stub: ReflectionMethod, optional. An example function with docblocks/inputs.
+ *
+ * Note: The inspector is only designed for use in developer workflows, such
+ * as code-generation and inspection. It should be not called by regular
+ * runtime logic.
+ */
+class CiviEventInspector {
+
+  /**
+   * Register the default hooks defined by 'CRM_Utils_Hook'.
+   *
+   * @param \Civi\Core\Event\GenericHookEvent $e
+   * @see \CRM_Utils_Hook::eventDefs()
+   */
+  public static function findBuiltInEvents(\Civi\Core\Event\GenericHookEvent $e) {
+    $skipList = array('singleton');
+    $e->inspector->addStaticStubs('CRM_Utils_Hook', 'hook_civicrm_',
+      function ($eventDef, $method) use ($skipList) {
+        return in_array($method->name, $skipList) ? NULL : $eventDef;
+      });
+  }
+
+  /**
+   * @var array
+   *   Array(string $name => array $eventDef).
+   *
+   * Ex: $eventDefs['hook_civicrm_foo']['description_html'] = 'Hello world';
+   */
+  protected $eventDefs;
+
+  /**
+   * Perform a scan to identify/describe all events.
+   *
+   * @param bool $force
+   * @return CiviEventInspector
+   */
+  public function build($force = FALSE) {
+    if ($force || $this->eventDefs === NULL) {
+      $this->eventDefs = array();
+      \CRM_Utils_Hook::eventDefs($this);
+      ksort($this->eventDefs);
+    }
+    return $this;
+  }
+
+  /**
+   * Get a list of all events.
+   *
+   * @return array
+   *   Array(string $name => array $eventDef).
+   *   Ex: $result['hook_civicrm_foo']['description_html'] = 'Hello world';
+   */
+  public function getAll() {
+    $this->build();
+    return $this->eventDefs;
+  }
+
+  /**
+   * Find any events that match a pattern.
+   *
+   * @param string $regex
+   * @return array
+   *   Array(string $name => array $eventDef).
+   *   Ex: $result['hook_civicrm_foo']['description_html'] = 'Hello world';
+   */
+  public function find($regex) {
+    $this->build();
+    return array_filter($this->eventDefs, function ($e) use ($regex) {
+      return preg_match($regex, $e['name']);
+    });
+  }
+
+  /**
+   * Get the definition of one event.
+   *
+   * @param string $name
+   *   Ex: 'hook_civicrm_alterSettingsMetaData'.
+   * @return array
+   *   Ex: $result['description_html'] = 'Hello world';
+   */
+  public function get($name) {
+    $this->build();
+    return $this->eventDefs[$name];
+  }
+
+  /**
+   * @param $eventDef
+   * @return bool
+   *   TRUE if valid.
+   */
+  public function validate($eventDef) {
+    if (!is_array($eventDef) || empty($eventDef['name']) || !isset($eventDef['type'])) {
+      return FALSE;
+    }
+
+    if (!in_array($eventDef['type'], array('hook', 'object'))) {
+      return FALSE;
+    }
+
+    if ($eventDef['type'] === 'hook') {
+      if (!isset($eventDef['signature']) || !is_array($eventDef['fields'])) {
+        return FALSE;
+      }
+    }
+
+    return TRUE;
+  }
+
+  /**
+   * Add a new event definition.
+   *
+   * @param array $eventDef
+   * @return CiviEventInspector
+   */
+  public function add($eventDef) {
+    $name = isset($eventDef['name']) ? $eventDef['name'] : NULL;
+
+    if (!isset($eventDef['type'])) {
+      $eventDef['type'] = preg_match('/^hook_/', $eventDef['name']) ? 'hook' : 'object';
+    }
+
+    if ($eventDef['type'] === 'hook' && empty($eventDef['signature'])) {
+      $eventDef['signature'] = implode(', ', array_map(
+        function ($field) {
+          $sigil = $field['ref'] ? '&$' : '$';
+          return $sigil . $field['name'];
+        },
+        $eventDef['fields']
+      ));
+    }
+
+    if (TRUE !== $this->validate($eventDef)) {
+      throw new \CRM_Core_Exception("Failed to register event ($name). Invalid definition.");
+    }
+
+    $this->eventDefs[$name] = $eventDef;
+    return $this;
+  }
+
+  /**
+   * Scan a Symfony event class for metadata, and add it.
+   *
+   * @param string $event
+   *   Ex: 'civi.api.authorize'.
+   * @param string $className
+   *   Ex: 'Civi\API\Event\AuthorizeEvent'.
+   * @return CiviEventInspector
+   */
+  public function addEventClass($event, $className) {
+    $this->add(array(
+      'name' => $event,
+      'class' => $className,
+    ));
+    return $this;
+  }
+
+  /**
+   * Scan a class for hook stubs, and add all of them.
+   *
+   * @param string $className
+   *   The name of a class which contains static stub functions.
+   *   Ex: 'CRM_Utils_Hook'.
+   * @param string $prefix
+   *   A prefix to apply to all hook names.
+   *   Ex: 'hook_civicrm_'.
+   * @param null|callable $filter
+   *   An optional function to filter/rewrite the metadata for each hook.
+   * @return CiviEventInspector
+   */
+  public function addStaticStubs($className, $prefix, $filter = NULL) {
+    $class = new \ReflectionClass($className);
+
+    foreach ($class->getMethods(\ReflectionMethod::IS_STATIC) as $method) {
+      if (!isset($method->name)) {
+        continue;
+      }
+
+      $eventDef = array(
+        'name' => $prefix . $method->name,
+        'description_html' => $method->getDocComment() ? \CRM_Admin_Page_APIExplorer::formatDocBlock($method->getDocComment()) : '',
+        'fields' => array(),
+        'class' => 'Civi\Core\Event\GenericHookEvent',
+        'stub' => $method,
+      );
+
+      foreach ($method->getParameters() as $parameter) {
+        $eventDef['fields'][$parameter->getName()] = array(
+          'name' => $parameter->getName(),
+          'ref' => (bool) $parameter->isPassedByReference(),
+          // WISHLIST: 'type' => 'mixed',
+        );
+      }
+
+      if ($filter !== NULL) {
+        $eventDef = $filter($eventDef, $method);
+        if ($eventDef === NULL) {
+          continue;
+        }
+      }
+
+      $this->add($eventDef);
+    }
+
+    return $this;
+  }
+
+}
index 8693d24272d94dd192ea4ae7f57a2febedde0d40..97e23379cfb85219ab92454b5551a01aa7359b6d 100644 (file)
@@ -250,6 +250,10 @@ class Container {
     $dispatcher->addListener('hook_civicrm_post::Case', array('\Civi\CCase\Events', 'fireCaseChange'));
     $dispatcher->addListener('hook_civicrm_caseChange', array('\Civi\CCase\Events', 'delegateToXmlListeners'));
     $dispatcher->addListener('hook_civicrm_caseChange', array('\Civi\CCase\SequenceListener', 'onCaseChange_static'));
+    $dispatcher->addListener('hook_civicrm_eventDefs', array('\Civi\Core\CiviEventInspector', 'findBuiltInEvents'));
+    // TODO We need a better code-convention for metadata about non-hook events.
+    $dispatcher->addListener('hook_civicrm_eventDefs', array('\Civi\API\Events', 'hookEventDefs'));
+    $dispatcher->addListener('hook_civicrm_eventDefs', array('\Civi\Core\Event\SystemInstallEvent', 'hookEventDefs'));
     $dispatcher->addListener('civi.dao.postInsert', array('\CRM_Core_BAO_RecurringEntity', 'triggerInsert'));
     $dispatcher->addListener('civi.dao.postUpdate', array('\CRM_Core_BAO_RecurringEntity', 'triggerUpdate'));
     $dispatcher->addListener('civi.dao.postDelete', array('\CRM_Core_BAO_RecurringEntity', 'triggerDelete'));
index 64858020f7597e7047435f677cdccf5bf9482715..e3e8d4f001a66449e8b0fc8a6a4409dcafb004ac 100644 (file)
@@ -38,4 +38,12 @@ class SystemInstallEvent extends \Symfony\Component\EventDispatcher\Event {
    */
   const EVENT_NAME = 'civi.core.install';
 
+  /**
+   * @param \Civi\Core\Event\GenericHookEvent $e
+   * @see \CRM_Utils_Hook::eventDefs
+   */
+  public static function hookEventDefs($e) {
+    $e->inspector->addEventClass(self::EVENT_NAME, __CLASS__);
+  }
+
 }
index aa58066f25127da0ddc479387ddb04f87d8a2efa..033091ce39b77d1ef6c1ec5d6bce05355776c13b 100644 (file)
@@ -712,8 +712,7 @@ function _ipn_process_transaction(&$params, $contribution, $input, $ids, $firstC
   $input['pan_truncation'] = CRM_Utils_Array::value('pan_truncation', $params);
   $transaction = new CRM_Core_Transaction();
   return CRM_Contribute_BAO_Contribution::completeOrder($input, $ids, $objects, $transaction, !empty
-  ($contribution->contribution_recur_id), $contribution,
-    FALSE, FALSE);
+  ($contribution->contribution_recur_id), $contribution);
 }
 
 /**
index dd549d7f853461c2fbd7cda46b1597f5e24b70c7..644e175b375e94f576b5dc5c6839e37c806354eb 100644 (file)
@@ -704,4 +704,68 @@ class CRM_Activity_BAO_ActivityTest extends CiviUnitTestCase {
     }
   }
 
+  /**
+   * CRM-20308: Test from email address when a 'copy of Activity' event occur
+   */
+  public function testEmailAddressOfActivityCopy() {
+    // Case 1: assert the 'From' Email Address of source Actvity Contact ID
+    // create activity with source contact ID which has email address
+    $assigneeContactId = $this->individualCreate();
+    $sourceContactParams = array(
+      'first_name' => 'liz',
+      'last_name' => 'hurleey',
+      'email' => substr(sha1(rand()), 0, 7) . '@testemail.com',
+    );
+    $sourceContactID = $this->individualCreate($sourceContactParams);
+    $sourceDisplayName = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact', $sourceContactID, 'display_name');
+
+    // create an activity using API
+    $params = array(
+      'source_contact_id' => $sourceContactID,
+      'subject' => 'Scheduling Meeting ' . substr(sha1(rand()), 0, 4),
+      'activity_type_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Meeting'),
+      'assignee_contact_id' => array($assigneeContactId),
+      'activity_date_time' => date('Ymd'),
+    );
+    $activity = $this->callAPISuccess('Activity', 'create', $params);
+
+    // Check that from address is in "Source-Display-Name <source-email>"
+    $formAddress = CRM_Case_BAO_Case::getReceiptFrom($activity['id']);
+    $expectedFromAddress = sprintf("%s <%s>", $sourceDisplayName, $sourceContactParams['email']);
+    $this->assertEquals($expectedFromAddress, $formAddress);
+    // ----------------------- End of Case 1 ---------------------------
+
+    // Case 2: System Default From Address
+    //  but first erase the email address of existing source contact ID
+    $withoutEmailParams = array(
+      'email' => '',
+    );
+    $sourceContactID = $this->individualCreate($withoutEmailParams);
+    $params = array(
+      'source_contact_id' => $sourceContactID,
+      'subject' => 'Scheduling Meeting ' . substr(sha1(rand()), 0, 4),
+      'activity_type_id' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Meeting'),
+      'activity_date_time' => date('Ymd'),
+    );
+    $activity = $this->callAPISuccess('Activity', 'create', $params);
+    // fetch domain info
+    $domainInfo = $this->callAPISuccess('Domain', 'getsingle', array('id' => CRM_Core_Config::domainID()));
+
+    $formAddress = CRM_Case_BAO_Case::getReceiptFrom($activity['id']);
+    if (!empty($domainInfo['from_email'])) {
+      $expectedFromAddress = sprintf("%s <%s>", $domainInfo['from_name'], $domainInfo['from_email']);
+    }
+    // Case 3: fetch default Organization Contact email address
+    elseif (!empty($domainInfo['domain_email'])) {
+      $expectedFromAddress = sprintf("%s <%s>", $domainInfo['name'], $domainInfo['domain_email']);
+    }
+    // TODO: due to unknown reason the following assertion fails on
+    //   test.civicrm.org test build but works fine on local
+    // $this->assertEquals($expectedFromAddress, $formAddress);
+    // ----------------------- End of Case 2 ---------------------------
+
+    // TODO: Case 4 about checking the $formAddress on basis of logged contact ID respectively needs,
+    //  to change the domain setting, which isn't straight forward in test environment
+  }
+
 }
index cbb5ce2920e0b70ba988807c39312438602b2618..169d751f26d9683d7101c2b9aab36ca90b36b37c 100644 (file)
@@ -56,8 +56,35 @@ class CRM_Core_Payment_AuthorizeNetIPNTest extends CiviUnitTestCase {
       ));
     $this->assertEquals(2, $contribution['count']);
     $this->assertEquals('second_one', $contribution['values'][1]['trxn_id']);
+    $this->assertEquals(date('Y-m-d'), date('Y-m-d', strtotime($contribution['values'][1]['receive_date'])));
   }
 
+  /**
+   * Test IPN response updates contribution_recur & contribution for first & second contribution
+   */
+  public function testIPNPaymentRecurSuccessSuppliedReceiveDate() {
+    $this->setupRecurringPaymentProcessorTransaction();
+    $IPN = new CRM_Core_Payment_AuthorizeNetIPN($this->getRecurTransaction());
+    $IPN->main();
+    $contribution = $this->callAPISuccess('contribution', 'getsingle', array('id' => $this->_contributionID));
+    $this->assertEquals(1, $contribution['contribution_status_id']);
+    $this->assertEquals('6511143069', $contribution['trxn_id']);
+    // source gets set by processor
+    $this->assertTrue(substr($contribution['contribution_source'], 0, 20) == "Online Contribution:");
+    $contributionRecur = $this->callAPISuccess('contribution_recur', 'getsingle', array('id' => $this->_contributionRecurID));
+    $this->assertEquals(5, $contributionRecur['contribution_status_id']);
+    $IPN = new CRM_Core_Payment_AuthorizeNetIPN(array_merge(array('receive_date' => '1 July 2010'), $this->getRecurSubsequentTransaction()));
+    $IPN->main();
+    $contribution = $this->callAPISuccess('contribution', 'get', array(
+      'contribution_recur_id' => $this->_contributionRecurID,
+      'sequential' => 1,
+    ));
+    $this->assertEquals(2, $contribution['count']);
+    $this->assertEquals('second_one', $contribution['values'][1]['trxn_id']);
+    $this->assertEquals('2010-07-01', date('Y-m-d', strtotime($contribution['values'][1]['receive_date'])));
+  }
+
+
   /**
    * Test IPN response updates contribution_recur & contribution for first & second contribution
    */
index 099aff6789586bb4e73841bcce498cf0db9901f8..88172853d05d21f4af7d1cd58d3df536c20261cb 100644 (file)
@@ -70,7 +70,7 @@ class CRM_Financial_BAO_FinancialTypeAccountTest extends CiviUnitTestCase {
   }
 
   /**
-   * Check method getFinancialAccount()
+   * Check method retrieve()
    */
   public function testRetrieve() {
     list($financialAccount, $financialType, $financialAccountType) = $this->createFinancialAccount(
@@ -91,29 +91,6 @@ class CRM_Financial_BAO_FinancialTypeAccountTest extends CiviUnitTestCase {
     $this->assertEquals($financialAccountType['financial_account_id'], $financialAccount->id, 'Verify Financial Account Id.');
   }
 
-  /**
-   * Check method getFinancialAccount()
-   */
-  public function testGetFinancialAccount() {
-    list($financialAccount, $financialType, $financialAccountType) = $this->createFinancialAccount(
-      'Asset'
-    );
-    $params = array(
-      'financial_account_id' => $financialAccount->id,
-      'payment_processor_type_id' => 1,
-      'domain_id' => 1,
-      'billing_mode' => 1,
-      'name' => 'paymentProcessor',
-    );
-    $processor = CRM_Financial_BAO_PaymentProcessor::create($params);
-
-    $account = CRM_Financial_BAO_FinancialTypeAccount::getFinancialAccount(
-      $processor->id,
-      'civicrm_payment_processor'
-    );
-    $this->assertEquals($account, $financialAccount->name, 'Verify Financial Account Name');
-  }
-
   /**
    * Check method getInstrumentFinancialAccount()
    */
diff --git a/tests/phpunit/Civi/Core/CiviEventInspectorTest.php b/tests/phpunit/Civi/Core/CiviEventInspectorTest.php
new file mode 100644 (file)
index 0000000..144232d
--- /dev/null
@@ -0,0 +1,52 @@
+<?php
+namespace Civi\Core;
+
+/**
+ * Class CiviEventInspectorTest
+ * @group headless
+ */
+class CiviEventInspectorTest extends \CiviUnitTestCase {
+
+  public function testGet() {
+    $inspector = new CiviEventInspector();
+    $eventDef = $inspector->get('hook_civicrm_alterSettingsMetaData');
+    $this->assertEquals('hook_civicrm_alterSettingsMetaData', $eventDef['name']);
+    $this->assertEquals(array('settingsMetaData', 'domainID', 'profile'), array_keys($eventDef['fields']));
+    $this->assertEquals('hook', $eventDef['type']);
+    $this->assertNotEmpty($eventDef['description_html']);
+    $this->assertTrue($eventDef['fields']['settingsMetaData']['ref']);
+    $this->assertFalse($eventDef['fields']['domainID']['ref']);
+    $this->assertEquals('&$settingsMetaData, $domainID, $profile', $eventDef['signature']);
+    $this->assertTrue($inspector->validate($eventDef));
+    $this->assertTrue($eventDef['stub'] instanceof \ReflectionMethod);
+    $this->assertTrue($eventDef['stub']->isStatic());
+  }
+
+  public function testGetAll() {
+    $inspector = new CiviEventInspector();
+    $all = $inspector->getAll();
+    $this->assertTrue(count($all) > 1);
+    $this->assertTrue(isset($all['hook_civicrm_alterSettingsMetaData']));
+    foreach ($all as $name => $eventDef) {
+      $this->assertEquals($name, $eventDef['name']);
+      $this->assertTrue($inspector->validate($eventDef));
+      if (isset($eventDef['stub'])) {
+        $this->assertTrue($eventDef['stub'] instanceof \ReflectionMethod);
+        $this->assertTrue($eventDef['stub']->isStatic());
+      }
+    }
+  }
+
+  public function testFind() {
+    $inspector = new CiviEventInspector();
+
+    $result_a = $inspector->find('/^hook_civicrm_post/');
+    $this->assertTrue(is_array($result_a['hook_civicrm_post']));
+    $this->assertFalse(isset($result_a['hook_civicrm_pre']));
+
+    $result_b = $inspector->find('/^hook_civicrm_pre/');
+    $this->assertTrue(is_array($result_b['hook_civicrm_pre']));
+    $this->assertFalse(isset($result_b['hook_civicrm_post']));
+  }
+
+}
index 380320f424e49d043ca3efa18a9d020b77cb4df5..20845448a5ec77e80b1c3956ee7f374ea1e6dd34 100644 (file)
@@ -3800,4 +3800,16 @@ AND    ( TABLE_NAME LIKE 'civicrm_value_%' )
   public function aclWhereHookNoResults($type, &$tables, &$whereTables, &$contactID, &$where) {
   }
 
+  /**
+   * @implements CRM_Utils_Hook::selectWhereClause
+   *
+   * @param string $entity
+   * @param array $clauses
+   */
+  public function selectWhereClauseHook($entity, &$clauses) {
+    if ($entity == 'Event') {
+      $clauses['event_type_id'][] = "IN (2, 3, 4)";
+    }
+  }
+
 }
index decce19157b36ad87e79886447c4c01f31ccd452..9e36a6210dadb8e5d869f2ccad96ae6965b21758 100644 (file)
@@ -3418,6 +3418,45 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
     $this->quickCleanUpFinancialEntities();
   }
 
+  /**
+   * CRM-20008 Tests repeattransaction creates pending membership.
+   */
+  public function testRepeatTransactionPendingMembership() {
+    list($originalContribution, $membership) = $this->setUpAutoRenewMembership();
+    $this->callAPISuccess('membership', 'create', array(
+      'id' => $membership['id'],
+      'end_date' => 'yesterday',
+      'status_id' => 'Expired',
+    ));
+    $repeatedContribution = $this->callAPISuccess('contribution', 'repeattransaction', array(
+      'contribution_recur_id' => $originalContribution['values'][1]['contribution_recur_id'],
+      'contribution_status_id' => 'Pending',
+      'trxn_id' => uniqid(),
+    ));
+    $membershipStatusId = $this->callAPISuccess('membership', 'getvalue', array(
+      'id' => $membership['id'],
+      'return' => 'status_id',
+    ));
+
+    // Let's see if the membership payments got created while we're at it.
+    $membershipPayments = $this->callAPISuccess('MembershipPayment', 'get', array(
+      'memberhip_id' => $membership['id'],
+    ));
+    $this->assertEquals(2, $membershipPayments['count']);
+
+    $this->assertEquals('Expired', CRM_Core_PseudoConstant::getLabel('CRM_Member_BAO_Membership', 'status_id', $membershipStatusId));
+    $this->callAPISuccess('Contribution', 'completetransaction', array('id' => $repeatedContribution['id']));
+    $membership = $this->callAPISuccessGetSingle('membership', array(
+      'id' => $membership['id'],
+      'return' => 'status_id, end_date',
+    ));
+    $this->assertEquals('New', CRM_Core_PseudoConstant::getLabel('CRM_Member_BAO_Membership', 'status_id', $membership['status_id']));
+    $this->assertEquals(date('Y-m-d', strtotime('yesterday + 1 month')), $membership['end_date']);
+
+    $this->quickCleanUpFinancialEntities();
+    $this->contactDelete($originalContribution['values'][1]['contact_id']);
+  }
+
   /**
    * Test sending a mail via the API.
    */
index ac5f7f2bbd6b9bd86cadb57df25af9ed7d9cb14e..eb02eeb8b75adef21131e57d555d530ca36d0121 100644 (file)
@@ -119,6 +119,32 @@ class api_v3_EventTest extends CiviUnitTestCase {
     $this->assertEquals($result['values'][$this->_eventIds[1]]['event_title'], 'Annual CiviCRM meet 2');
   }
 
+  /**
+   * Test getLocationEvents() function invokes selectWhereClause() hook
+   */
+  public function testGetEventWithPermissionHook() {
+    $address = $this->callAPISuccess('address', 'create', array(
+      'contact_id' => 'null',
+      'location_type_id' => 1,
+      'street_address' => '1234567',
+    ));
+    $params = array(
+      'address_id' => $address['id'],
+    );
+    $result = $this->callAPISuccess('loc_block', 'create', $params);
+    $params = array(
+      'id' => $this->_events[1]['id'],
+      'loc_block_id' => $result['id'],
+    );
+    $this->callAPISuccess('Event', 'create', $params);
+    $result = CRM_Event_BAO_Event::getLocationEvents();
+    $this->assertEquals(1, count($result));
+
+    $this->hookClass->setHook('civicrm_selectWhereClause', array($this, 'selectWhereClauseHook'));
+    $result = CRM_Event_BAO_Event::getLocationEvents();
+    $this->assertEquals(0, count($result));
+  }
+
   public function testGetEventByEventTitle() {
 
     $params = array(