Merge pull request #9438 from jmcclelland/CRM-19298
authorEileen McNaughton <eileen@mcnaughty.com>
Mon, 28 Nov 2016 22:39:18 +0000 (11:39 +1300)
committerGitHub <noreply@github.com>
Mon, 28 Nov 2016 22:39:18 +0000 (11:39 +1300)
CRM-19298 - ensure we get two receipts, with no total line.

24 files changed:
CRM/Admin/Form/WordReplacements.php
CRM/Case/XMLProcessor/Report.php
CRM/Contribute/BAO/Contribution.php
CRM/Contribute/BAO/Contribution/Utils.php
CRM/Contribute/Form/Contribution.php
CRM/Contribute/Form/Contribution/Confirm.php
CRM/Contribute/Form/Contribution/Main.php
CRM/Core/BAO/Dashboard.php
CRM/Core/BAO/WordReplacement.php
CRM/Event/BAO/Query.php
CRM/Member/BAO/Membership.php
CRM/Price/BAO/LineItem.php
CRM/Profile/Page/MultipleRecordFieldsListing.php
CRM/Report/Utils/Get.php
CRM/Utils/System/Base.php
CRM/Utils/System/DrupalBase.php
api/v3/Membership.php
templates/CRM/Contact/Page/DedupeException.tpl
templates/CRM/Profile/Page/MultipleRecordFieldsListing.tpl
tests/phpunit/CiviTest/CiviUnitTestCase.php
tests/phpunit/api/v3/ContributionPageTest.php
tests/phpunit/api/v3/ContributionTest.php
tests/phpunit/api/v3/DashboardTest.php
tests/phpunit/api/v3/ParticipantTest.php

index 0a5fabdb0c5f127b86352e33aa98c302b6ee549c..a130f505d2d9b41baaa0e332a9e63ffe947dd5db 100644 (file)
@@ -226,7 +226,8 @@ class CRM_Admin_Form_WordReplacements extends CRM_Core_Form {
     CRM_Core_BAO_WordReplacement::setLocaleCustomStrings($config->lcMessages, $overrides);
 
     // This controller was originally written to CRUD $config->locale_custom_strings,
-    // but that's no longer the canonical store. Sync changes to canonical store.
+    // but that's no longer the canonical store. Sync changes to canonical store
+    // (civicrm_word_replacement table in the database).
     // This is inefficient - at some point, we should rewrite this UI.
     CRM_Core_BAO_WordReplacement::rebuildWordReplacementTable();
 
index 8f460c53e8bee9a4a923b0471688d813533007be..2cd0e4d40634887bf63592906c84518e90298d53 100644 (file)
@@ -688,10 +688,11 @@ SELECT label, value
 
       foreach ($sql as $tableName => $values) {
         $columnNames = implode(',', $values);
-        $tableName = CRM_Utils_Type::escape($tableName, 'MysqlColumnNameOrAlias');
+        $title = CRM_Core_DAO::escapeString($groupTitle[$tableName]);
+        $mysqlTableName = CRM_Utils_Type::escape($tableName, 'MysqlColumnNameOrAlias');
         $sql[$tableName] = "
-SELECT '" . CRM_Core_DAO::escapeString($groupTitle[$tableName]) . "' as groupTitle, $columnNames
-FROM   $tableName
+SELECT '" . $title . "' as groupTitle, $columnNames
+FROM   $mysqlTableName
 WHERE  entity_id = %1
 ";
       }
index 0e235f5f1104d6c5f47ea2baece8b9c329461e0b..c94874f3cfb20181482579533389600789487cb0 100644 (file)
@@ -1916,6 +1916,9 @@ LEFT JOIN  civicrm_contribution contribution ON ( componentPayment.contribution_
             //update related Memberships.
             CRM_Member_BAO_Membership::updateRelatedMemberships($membership->id, $formattedParams);
 
+            //CRM-19678: No Membership Renewal Activity is created when a Pay Later is set to Completed
+            CRM_Activity_BAO_Activity::addActivity($membership, 'Membership Renewal', $membership->contact_id);
+
             $updateResult['membership_end_date'] = CRM_Utils_Date::customFormat($dates['end_date'],
               '%B %E%f, %Y'
             );
index 4fb880088775c3ea24a7a2c7f9ae84831185d244..a4bc54c941e417f79ca15400597a88d354a6c27c 100644 (file)
@@ -64,7 +64,6 @@ class CRM_Contribute_BAO_Contribution_Utils {
     $isRecur
   ) {
     CRM_Core_Payment_Form::mapParams($form->_bltID, $form->_params, $paymentParams, TRUE);
-    $lineItems = $form->_lineItem;
     $isPaymentTransaction = self::isPaymentTransaction($form);
 
     $financialType = new CRM_Financial_DAO_FinancialType();
@@ -104,12 +103,15 @@ class CRM_Contribute_BAO_Contribution_Utils {
       $contributionParams = array(
         'id' => CRM_Utils_Array::value('contribution_id', $paymentParams),
         'contact_id' => $contactID,
-        'line_item' => $lineItems,
         'is_test' => $isTest,
         'campaign_id' => CRM_Utils_Array::value('campaign_id', $paymentParams, CRM_Utils_Array::value('campaign_id', $form->_values)),
         'contribution_page_id' => $form->_id,
         'source' => CRM_Utils_Array::value('source', $paymentParams, CRM_Utils_Array::value('description', $paymentParams)),
       );
+      if (isset($paymentParams['line_item'])) {
+        // @todo make sure this is consisently set at this point.
+        $contributionParams['line_item'] = $paymentParams['line_item'];
+      }
       if (!empty($form->_paymentProcessor)) {
         $contributionParams['payment_instrument_id'] = $paymentParams['payment_instrument_id'] = $form->_paymentProcessor['payment_instrument_id'];
       }
index 31667ac21e03f0870477e60ac5ad9a05bc724f2c..757073e6fec9d216644df7cc709859ab30ebf819 100644 (file)
@@ -1404,6 +1404,7 @@ class CRM_Contribute_Form_Contribution extends CRM_Contribute_Form_AbstractEditP
         'id' => $params['id'],
       ));
       $this->_id = $params['id'];
+      $this->_values = $existingContribution;
     }
     else {
       $existingContribution = array();
index f04afe21e722ff1de3bb001cb122653c9f65f4ea..e4fcfd4817b8b8c0b585c19a3ccb655b5c8b0eb6 100644 (file)
@@ -1456,6 +1456,7 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
     $errors = $paymentResults = array();
     $form->_values['isMembership'] = TRUE;
     $isRecurForFirstTransaction = CRM_Utils_Array::value('is_recur', $form->_values, CRM_Utils_Array::value('is_recur', $membershipParams));
+    $unprocessedLineItems = $form->_lineItem;
     $totalAmount = $membershipParams['amount'];
 
     if ($isPaidMembership) {
@@ -1470,6 +1471,11 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
       if (!$isProcessSeparateMembershipTransaction) {
         $membershipParams['skipLineItem'] = 1;
       }
+      else {
+        $membershipParams['total_amount'] = $totalAmount;
+        CRM_Price_BAO_LineItem::getLineItemArray($membershipParams);
+
+      }
       $paymentResult = CRM_Contribute_BAO_Contribution_Utils::processConfirm($form, $membershipParams,
         $contactID,
         $financialTypeID,
@@ -1494,7 +1500,7 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
         if (empty($form->_params['auto_renew']) && !empty($membershipParams['is_recur'])) {
           unset($membershipParams['is_recur']);
         }
-        list($membershipContribution, $secondPaymentResult) = $this->processSecondaryFinancialTransaction($contactID, $form, $membershipParams,
+        list($membershipContribution, $secondPaymentResult) = $this->processSecondaryFinancialTransaction($contactID, $form, array_merge($membershipParams, array('skipLineItem' => 1)),
           $isTest, $membershipLineItems, CRM_Utils_Array::value('minimum_fee', $membershipDetails, 0), CRM_Utils_Array::value('financial_type_id', $membershipDetails));
         $paymentResults[] = array('contribution_id' => $membershipContribution->id, 'result' => $secondPaymentResult);
       }
@@ -1516,7 +1522,26 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
     //@todo it should no longer be possible for it to get to this point & membership to not be an array
     if (is_array($membershipTypeIDs) && !empty($membershipContributionID)) {
       $typesTerms = CRM_Utils_Array::value('types_terms', $membershipParams, array());
+
+      $membershipLines = $nonMembershipLines = array();
+      foreach ($unprocessedLineItems as $priceSetID => $lines) {
+        foreach ($lines as $line) {
+          if (!empty($line['membership_type_id'])) {
+            $membershipLines[$line['membership_type_id']] = $line['price_field_value_id'];
+          }
+        }
+      }
+
+      $i = 1;
       foreach ($membershipTypeIDs as $memType) {
+        if ($i < count($membershipTypeIDs)) {
+          $membershipLineItems[$priceSetID][$membershipLines[$memType]] = $unprocessedLineItems[$priceSetID][$membershipLines[$memType]];
+          unset($unprocessedLineItems[$priceSetID][$membershipLines[$memType]]);
+        }
+        else {
+          $membershipLineItems = $unprocessedLineItems;
+        }
+        $i++;
         $numTerms = CRM_Utils_Array::value($memType, $typesTerms, 1);
         if (!empty($membershipContribution)) {
           $pendingStatus = CRM_Core_OptionGroup::getValue('contribution_status', 'Pending', 'name');
@@ -1551,7 +1576,8 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
           date('YmdHis'), CRM_Utils_Array::value('cms_contactID', $membershipParams),
           $customFieldsFormatted,
           $numTerms, $membershipID, $pending,
-          $contributionRecurID, $membershipSource, $isPayLater, $campaignId, array(), $membershipContribution
+          $contributionRecurID, $membershipSource, $isPayLater, $campaignId, array(), $membershipContribution,
+          $membershipLineItems
         );
 
         $form->set('renewal_mode', $renewalMode);
@@ -1563,6 +1589,7 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
         if (!empty($membershipContribution)) {
           // update recurring id for membership record
           CRM_Member_BAO_Membership::updateRecurMembership($membership, $membershipContribution);
+          // Next line is probably redundant. Checksprevent it happening twice.
           CRM_Member_BAO_Membership::linkMembershipPayment($membership, $membershipContribution);
         }
       }
@@ -1929,9 +1956,20 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
     else {
       $form->_params['payment_processor_id'] = 0;
     }
+
     $priceFields = $priceFields[$priceSetID]['fields'];
     CRM_Price_BAO_PriceSet::processAmount($priceFields, $paramsProcessedForForm, $lineItems, 'civicrm_contribution');
     $form->_lineItem = array($priceSetID => $lineItems);
+    $membershipPriceFieldIDs = array();
+    foreach ((array) $lineItems as $lineItem) {
+      if (!empty($lineItem['membership_type_id'])) {
+        $form->set('useForMember', 1);
+        $form->_useForMember = 1;
+        $membershipPriceFieldIDs['id'] = $priceSetID;
+        $membershipPriceFieldIDs[] = $lineItem['price_field_value_id'];
+      }
+    }
+    $form->set('memberPriceFieldIDS', $membershipPriceFieldIDs);
     $form->processFormSubmission(CRM_Utils_Array::value('contact_id', $params));
   }
 
@@ -2318,7 +2356,7 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
     $priceFieldIds = $this->get('memberPriceFieldIDS');
 
     if (!empty($priceFieldIds)) {
-      $contributionTypeID = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $priceFieldIds['id'], 'financial_type_id');
+      $financialTypeID = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $priceFieldIds['id'], 'financial_type_id');
       unset($priceFieldIds['id']);
       $membershipTypeIds = array();
       $membershipTypeTerms = array();
@@ -2337,7 +2375,7 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
         }
       }
       $membershipParams['selectMembership'] = $membershipTypeIds;
-      $membershipParams['financial_type_id'] = $contributionTypeID;
+      $membershipParams['financial_type_id'] = $financialTypeID;
       $membershipParams['types_terms'] = $membershipTypeTerms;
     }
     if (!empty($membershipParams['selectMembership'])) {
index 981fbfa105101af7e5abb717f205017481e14536..363ca318909cf0b8db43ccafc0fcac2ff845fa0c 100644 (file)
@@ -1054,7 +1054,7 @@ class CRM_Contribute_Form_Contribution_Main extends CRM_Contribute_Form_Contribu
 
     $params['currencyID'] = CRM_Core_Config::singleton()->defaultCurrency;
 
-    $is_quick_config = 0;
+    // @todo refactor this & leverage it from the unit tests.
     if (!empty($params['priceSetId'])) {
       $is_quick_config = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $this->_priceSetId, 'is_quick_config');
       if ($is_quick_config) {
@@ -1118,7 +1118,7 @@ class CRM_Contribute_Form_Contribution_Main extends CRM_Contribute_Form_Contribu
       }
     }
     //If the membership & contribution is used in contribution page & not separate payment
-    $fieldId = $memPresent = $membershipLabel = $fieldOption = $is_quick_config = NULL;
+    $memPresent = $membershipLabel = $fieldOption = $is_quick_config = NULL;
     $proceFieldAmount = 0;
     if (property_exists($this, '_separateMembershipPayment') && $this->_separateMembershipPayment == 0) {
       $is_quick_config = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $this->_priceSetId, 'is_quick_config');
index 91e560c6c7f5b5bfa72f18c75f1be8d72d92a76c..7fbfa07c70f45d0b9ddb1aabcef232042a41a628 100644 (file)
@@ -431,31 +431,34 @@ class CRM_Core_BAO_Dashboard extends CRM_Core_DAO_Dashboard {
     $contactIDs = array();
     if ($admin) {
       $query = "SELECT distinct( contact_id )
-                        FROM civicrm_dashboard_contact
-                        WHERE contact_id NOT IN (
-                            SELECT distinct( contact_id )
-                            FROM civicrm_dashboard_contact WHERE dashboard_id = {$dashlet->id}
-                            )";
-
+                        FROM civicrm_dashboard_contact";
       $dao = CRM_Core_DAO::executeQuery($query);
       while ($dao->fetch()) {
-        $contactIDs[] = $dao->contact_id;
+        $contactIDs[$dao->contact_id] = NULL;
       }
     }
     else {
       //Get the id of Logged in User
-      $session = CRM_Core_Session::singleton();
-      $contactID = $session->get('userID');
+      $contactID = CRM_Core_Session::getLoggedInContactID();
       if (!empty($contactID)) {
-        $contactIDs[] = $session->get('userID');
+        $contactIDs[$contactID] = NULL;
       }
     }
 
+    // Remove contact ids that already have this dashlet to avoid DB
+    // constraint violation.
+    $query = "SELECT distinct( contact_id )
+              FROM civicrm_dashboard_contact WHERE dashboard_id = {$dashlet->id}";
+    $dao = CRM_Core_DAO::executeQuery($query);
+    while ($dao->fetch()) {
+      if (array_key_exists($dao->contact_id, $contactIDs)) {
+        unset($contactIDs[$dao->contact_id]);
+      }
+    }
     if (!empty($contactIDs)) {
-      foreach ($contactIDs as $contactID) {
+      foreach ($contactIDs as $contactID => $value) {
         $valuesArray[] = " ( {$dashlet->id}, {$contactID} )";
       }
-
       $valuesString = implode(',', $valuesArray);
       $query = "
                   INSERT INTO civicrm_dashboard_contact ( dashboard_id, contact_id )
index 6f880fca6a1b5ceda71964dd672e24e9193d62c2..cef03ad579ef2c5b4af8938028339efd3b2b65e5 100644 (file)
@@ -205,8 +205,9 @@ WHERE  domain_id = %1
   /**
    * Get word replacements for the api.
    *
-   * Get all the word-replacements stored in config-arrays
-   * and convert them to params for the WordReplacement.create API.
+   * Get all the word-replacements stored in config-arrays for the
+   * configured language, and convert them to params for the
+   * WordReplacement.create API.
    *
    * Note: This function is duplicated in CRM_Core_BAO_WordReplacement and
    * CRM_Upgrade_Incremental_php_FourFour to ensure that the incremental upgrade
@@ -222,6 +223,12 @@ WHERE  domain_id = %1
    * @see CRM_Core_BAO_WordReplacement::convertConfigArraysToAPIParams
    */
   public static function getConfigArraysAsAPIParams($rebuildEach) {
+    $settingsResult = civicrm_api3('Setting', 'get', array(
+      'return' => 'lcMessages',
+    ));
+    $returnValues = CRM_Utils_Array::first($settingsResult['values']);
+    $lang = $returnValues['lcMessages'];
+
     $wordReplacementCreateParams = array();
     // get all domains
     $result = civicrm_api3('domain', 'get', array(
@@ -236,19 +243,20 @@ WHERE  domain_id = %1
         $localeCustomArray = unserialize($value["locale_custom_strings"]);
         if (!empty($localeCustomArray)) {
           $wordMatchArray = array();
-          // Traverse Language array
-          foreach ($localeCustomArray as $localCustomData) {
-            // Traverse status array "enabled" "disabled"
-            foreach ($localCustomData as $status => $matchTypes) {
-              $params["is_active"] = ($status == "enabled") ? TRUE : FALSE;
-              // Traverse Match Type array "wildcardMatch" "exactMatch"
-              foreach ($matchTypes as $matchType => $words) {
-                $params["match_type"] = $matchType;
-                foreach ($words as $word => $replace) {
-                  $params["find_word"] = $word;
-                  $params["replace_word"] = $replace;
-                  $wordReplacementCreateParams[] = $params;
-                }
+          // Only return the replacement strings of the current language,
+          // otherwise some replacements will be duplicated, which will
+          // lead to undesired results, like CRM-19683.
+          $localCustomData = $localeCustomArray[$lang];
+          // Traverse status array "enabled" "disabled"
+          foreach ($localCustomData as $status => $matchTypes) {
+            $params["is_active"] = ($status == "enabled") ? TRUE : FALSE;
+            // Traverse Match Type array "wildcardMatch" "exactMatch"
+            foreach ($matchTypes as $matchType => $words) {
+              $params["match_type"] = $matchType;
+              foreach ($words as $word => $replace) {
+                $params["find_word"] = $word;
+                $params["replace_word"] = $replace;
+                $wordReplacementCreateParams[] = $params;
               }
             }
           }
index 4d3c728b66f777ce6cbe5a2b6d36a90fba8979ae..ba13d92bf0c27a30e25bee685f619b7402bb3b9e 100644 (file)
@@ -410,6 +410,8 @@ class CRM_Event_BAO_Query extends CRM_Core_BAO_Query {
         $qillName = $name;
         $name = 'role_id';
 
+        $dataType = !empty($fields[$qillName]['type']) ? CRM_Utils_Type::typeToString($fields[$qillName]['type']) : 'String';
+        $tableName = empty($tableName) ? 'civicrm_participant' : $tableName;
         if (is_array($value) && in_array(key($value), CRM_Core_DAO::acceptedSQLOperators(), TRUE)) {
           $op = key($value);
           $value = $value[$op];
index 0b871f6782a44c5fe393397d4860ade7501f1cd1..c54ee9acaaa201cb03272b1e9edbc4b9c8daf67c 100644 (file)
@@ -227,7 +227,7 @@ class CRM_Member_BAO_Membership extends CRM_Member_DAO_Membership {
    * @param array $params
    *   (reference ) an assoc array of name/value pairs.
    * @param array $ids
-   *   The array that holds all the db ids.
+   *   Deprecated parameter The array that holds all the db ids.
    * @param bool $skipRedirect
    * @param string $activityType
    *
@@ -321,6 +321,7 @@ class CRM_Member_BAO_Membership extends CRM_Member_DAO_Membership {
       );
     }
 
+    // This code ensures a line item is created but it is recomended you pass in 'skipLineItem' or 'line_item'
     if (empty($params['line_item']) && !empty($params['membership_type_id']) && empty($params['skipLineItem'])) {
       CRM_Price_BAO_LineItem::getLineItemArray($params, NULL, 'membership', $params['membership_type_id']);
     }
@@ -341,7 +342,26 @@ class CRM_Member_BAO_Membership extends CRM_Member_DAO_Membership {
       CRM_Price_BAO_LineItem::deleteLineItems($ids['membership'], 'civicrm_membership');
     }
 
+    // This could happen if there is no contribution or we are in one of many
+    // weird and wonderful flows. This is scary code. Keep adding tests.
     if (!empty($params['line_item']) && empty($ids['contribution'])) {
+
+      foreach ($params['line_item'] as $priceSetId => $lineItems) {
+        foreach ($lineItems as $lineIndex => $lineItem) {
+          $lineMembershipType = CRM_Utils_Array::value('membership_type_id', $lineItem);
+          if (CRM_Utils_Array::value('contribution', $params)) {
+            $params['line_item'][$priceSetId][$lineIndex]['contribution_id'] = $params['contribution']->id;
+          }
+          if ($lineMembershipType && $lineMembershipType == CRM_Utils_Array::value('membership_type_id', $params)) {
+            $params['line_item'][$priceSetId][$lineIndex]['entity_id'] = $membership->id;
+            $params['line_item'][$priceSetId][$lineIndex]['entity_table'] = 'civicrm_membership';
+          }
+          elseif (!$lineMembershipType && CRM_Utils_Array::value('contribution', $params)) {
+            $params['line_item'][$priceSetId][$lineIndex]['entity_id'] = $params['contribution']->id;
+            $params['line_item'][$priceSetId][$lineIndex]['entity_table'] = 'civicrm_contribution';
+          }
+        }
+      }
       CRM_Price_BAO_LineItem::processPriceSet(
         $membership->id,
         $params['line_item'],
@@ -1814,11 +1834,13 @@ INNER JOIN  civicrm_contact contact ON ( contact.id = membership.contact_id AND
    * @param $isPayLater
    * @param int $campaignId
    * @param array $formDates
+   * @param null|CRM_Contribute_BAO_Contribution $contribution
+   * @param array $lineItems
    *
-   * @throws CRM_Core_Exception
    * @return array
+   * @throws \CRM_Core_Exception
    */
-  public static function processMembership($contactID, $membershipTypeID, $is_test, $changeToday, $modifiedID, $customFieldsFormatted, $numRenewTerms, $membershipID, $pending, $contributionRecurID, $membershipSource, $isPayLater, $campaignId, $formDates = array(), $contribution = NULL) {
+  public static function processMembership($contactID, $membershipTypeID, $is_test, $changeToday, $modifiedID, $customFieldsFormatted, $numRenewTerms, $membershipID, $pending, $contributionRecurID, $membershipSource, $isPayLater, $campaignId, $formDates = array(), $contribution = NULL, $lineItems = array()) {
     $renewalMode = $updateStatusId = FALSE;
     $allStatus = CRM_Member_PseudoConstant::membershipStatus();
     $format = '%Y%m%d';
@@ -1850,6 +1872,7 @@ INNER JOIN  civicrm_contact contact ON ( contact.id = membership.contact_id AND
           'status_id' => $currentMembership['status_id'],
           'start_date' => $currentMembership['start_date'],
           'end_date' => $currentMembership['end_date'],
+          'line_item' => $lineItems,
           'join_date' => $currentMembership['join_date'],
           'membership_type_id' => $membershipTypeID,
           'max_related' => !empty($membershipTypeDetails['max_related']) ? $membershipTypeDetails['max_related'] : NULL,
@@ -2028,6 +2051,9 @@ INNER JOIN  civicrm_contact contact ON ( contact.id = membership.contact_id AND
 
     $memParams['contribution'] = $contribution;
     $memParams['custom'] = $customFieldsFormatted;
+    // Load all line items & process all in membership. Don't do in contribution.
+    // Relevant tests in api_v3_ContributionPageTest.
+    $memParams['line_item'] = $lineItems;
     $membership = self::create($memParams, $ids, FALSE, $activityType);
 
     // not sure why this statement is here, seems quite odd :( - Lobo: 12/26/2010
index 9b9b458306c91e7c721090ed5f0839cc9e2a8484..0d0d6ad520f04174d8b93c5705fe4a0b5a8f83f3 100644 (file)
@@ -51,7 +51,10 @@ class CRM_Price_BAO_LineItem extends CRM_Price_DAO_LineItem {
    * @param array $params
    *   (reference) an assoc array of name/value pairs.
    *
-   * @return CRM_Price_DAO_LineItem
+   * @return \CRM_Price_DAO_LineItem
+   *
+   * @throws \CiviCRM_API3_Exception
+   * @throws \Exception
    */
   public static function create(&$params) {
     $id = CRM_Utils_Array::value('id', $params);
@@ -69,6 +72,11 @@ class CRM_Price_BAO_LineItem extends CRM_Price_DAO_LineItem {
     if ($id) {
       unset($params['entity_id'], $params['entity_table']);
     }
+    else {
+      if (!isset($params['unit_price'])) {
+        $params['unit_price'] = 0;
+      }
+    }
     if (CRM_Financial_BAO_FinancialType::isACLFinancialTypeStatus() && CRM_Utils_Array::value('check_permissions', $params)) {
       if (empty($params['financial_type_id'])) {
         throw new Exception('Mandatory key(s) missing from params array: financial_type_id');
index 7ad6318131862d0b67dacbe8200102bde5a06837..3b22b56cf5aa42d80feaa5d3bf869e8c29004569 100644 (file)
@@ -167,7 +167,7 @@ class CRM_Profile_Page_MultipleRecordFieldsListing extends CRM_Core_Page_Basic {
    */
   public function browse() {
     $dateFields = NULL;
-    $cgcount = 0;
+    $newCgCount = $cgcount = 0;
     $attributes = $result = $headerAttr = array();
     $dateFieldsVals = NULL;
     if ($this->_pageViewType == 'profileDataView' && $this->_profileId) {
@@ -259,7 +259,7 @@ class CRM_Profile_Page_MultipleRecordFieldsListing extends CRM_Core_Page_Basic {
       $linkAction = array_sum(array_keys($this->links()));
     }
 
-    if (!empty($fieldIDs) && $this->_contactId && empty($this->_headersOnly)) {
+    if (!empty($fieldIDs) && $this->_contactId) {
       $DTparams = !empty($this->_DTparams) ? $this->_DTparams : NULL;
       // commonly used for both views i.e profile listing view (profileDataView) and custom data listing view (customDataView)
       $result = CRM_Core_BAO_CustomValueTable::getEntityValues($this->_contactId, NULL, $fieldIDs, TRUE, $DTparams);
@@ -288,7 +288,8 @@ class CRM_Profile_Page_MultipleRecordFieldsListing extends CRM_Core_Page_Basic {
       // $cgcount is defined before 'if' condition as entity may have no record
       // and $cgcount is used to build new record url
       $cgcount = 1;
-      if ($result && !empty($result)) {
+      $newCgCount = (!$reached) ? $resultCount + 1 : NULL;
+      if (!empty($result) && empty($this->_headersOnly)) {
         $links = self::links();
         if ($this->_pageViewType == 'profileDataView') {
           $pageCheckSum = $this->get('pageCheckSum');
@@ -302,7 +303,6 @@ class CRM_Profile_Page_MultipleRecordFieldsListing extends CRM_Core_Page_Basic {
         if ($reached) {
           unset($links[CRM_Core_Action::COPY]);
         }
-        $newCgCount = (!$reached) ? $resultCount + 1 : NULL;
         if (!empty($DTparams)) {
           $this->_total = $resultCount;
           $cgcount = $DTparams['offset'] + 1;
@@ -452,6 +452,7 @@ class CRM_Profile_Page_MultipleRecordFieldsListing extends CRM_Core_Page_Basic {
     $this->assign('dateFields', $dateFields);
     $this->assign('dateFieldsVals', $dateFieldsVals);
     $this->assign('cgcount', $cgcount);
+    $this->assign('newCgCount', $newCgCount);
     $this->assign('contactId', $this->_contactId);
     $this->assign('contactType', $this->_contactType);
     $this->assign('customGroupTitle', $this->_customGroupTitle);
index 8669159425a3b3c5277e1610f7a99c0157a0c42d..21005661f3fe1926cc8ea5e6e0108fed28c0571a 100644 (file)
@@ -66,9 +66,12 @@ class CRM_Report_Utils_Get {
     $from = self::getTypedValue("{$fieldName}_from", $type);
     $to = self::getTypedValue("{$fieldName}_to", $type);
 
-    $relative = CRM_Utils_Array::value("{$fieldName}_relative", $_GET);
+    $relative = self::getTypedValue("{$fieldName}_relative", CRM_Utils_Type::T_STRING);
+    if ($relative !== NULL) {
+      $defaults["{$fieldName}_relative"] = $relative;
+    }
     if ($relative) {
-      list($from, $to) = CRM_Report_Form::getFromTo($relative, NULL, NULL);
+      list($from, $to) = CRM_Utils_Date::getFromTo($relative, NULL, NULL);
       $from = substr($from, 0, 8);
       $to = substr($to, 0, 8);
     }
index b053e547fda4665e8da8320dc24fc3cf96c1f1c7..b3f8dcb4435bd0d70dadc74ea61f3787d5e7960f 100644 (file)
@@ -582,7 +582,7 @@ abstract class CRM_Utils_System_Base {
         $filesURL = $baseURL . "sites/$siteName/files/civicrm/";
       }
       else {
-        $filesURL = $config->userSystem->checkMultisite($civicrm_root, $baseURL);
+        $filesURL = $baseURL . "sites/default/files/civicrm/";
       }
     }
     elseif ($config->userFramework == 'UnitTests') {
index 943ea51905247840453eab19211210a66a22bf69..3129073181edf76306eb345afad7d17624305e22 100644 (file)
@@ -568,92 +568,4 @@ abstract class CRM_Utils_System_DrupalBase extends CRM_Utils_System_Base {
     return $siteName;
   }
 
-  /**
-   * @var $basepath String cached basepath to prevent having to parse it repeatedly.
-   */
-  protected $basepath;
-
-  /**
-   * @var $filesUrl String holds resolved path.
-   */
-  protected $filesUrl;
-
-  /**
-   *  checkBasePath - Returns root directory with respect to $civicrm_root
-   *
-   * @param $root String
-   * @param $seek String
-   */
-  public function checkBasePath($root, $seek = "/sites/") {
-    if (!isset($this->basepath)) {
-      $this->basepath = substr($root, 0, stripos($root, $seek) + 1);
-    }
-
-    return $this->basepath;
-  }
-
-  /**
-   * check if files exist in path.  Just a simple helper function for viewing
-   * existence of sites.
-   *
-   * @param $basepath string
-   * @param $basepath string
-   */
-  private function checkFilesExists($basepath, $folder) {
-    return file_exists("{$basepath}sites/$folder/files/civicrm/");
-  }
-
-  /**
-   * Returns the concatenated url for existing path.
-   *
-   * @param $baseUrl string
-   * @param $folder string
-   */
-  private function getUrl($baseUrl, $folder) {
-    return "{$baseUrl}sites/$folder/files/civicrm/";
-  }
-
-  /**
-   * Returns the location of /sites/SITENAME/files/civicrm depending
-   * on system configuration.
-   *
-   * @fixed CRM-19303
-   * @param $root string
-   * @param $baseUrl string
-   * @param $default string
-   */
-  public function checkMultisite($root, $baseUrl, $default = "default") {
-    if (isset($this->filesUrl)) {
-      return $this->filesUrl;
-    }
-
-    $basepath = $this->checkBasePath($root);
-    $correct = NULL;
-    if ($this->checkFilesExists($root, $default)) {
-      $correct = $default;
-    }
-    else {
-      //Check for any other directories if default doesn't exist.
-      $folders = scandir($basepath . 'sites/');
-      foreach ($folders as $folder) {
-        //Ignore hidden directories/files...
-        if (strpos($folder, '.') === 0 || $folder == 'all') {
-          continue;
-        }
-        //Check if it is a directory
-        if (!is_dir($basepath . 'sites/' . $folder)) {
-          continue;
-        }
-
-        //Check if files path exists...
-        if ($this->checkFilesExists($basepath, $folder) && $folder == $_SERVER['HTTP_HOST']) {
-          $correct = $folder;
-          break;
-        }
-      }
-    }
-    $this->filesUrl = self::getUrl($baseUrl, $correct);
-    return $this->filesUrl;
-  }
-
 }
index cf056f9050b9f444767eb4afb105c083d8c87f1b..560dc81000f6a60f47ecaabc828f8e957a12b32f 100644 (file)
@@ -136,6 +136,7 @@ function civicrm_api3_membership_create($params) {
     $ids['userId'] = $params['contact_id'];
   }
   //for edit membership id should be present
+  // probably not required now.
   if (!empty($params['id'])) {
     $ids['membership'] = $params['id'];
     $action = CRM_Core_Action::UPDATE;
index 8ef52954603841dbb10c462cbd1cd094e8d3e86e..6214675a6f2d2847c230ea60612e0f445fa62b85 100644 (file)
@@ -51,8 +51,8 @@
   <tbody>
     {foreach from=$dedupeExceptions item=exception key=id}
       <tr id="dupeRow_{$id}" class="{cycle values="odd-row,even-row"}">
-        <td>{$exception.main.name}</td>
-        <td>{$exception.other.name}</td>
+        <td><a href ={crmURL p='civicrm/contact/view' q="reset=1&cid=`$exception.main.id`"}>{$exception.main.name}</a></td>
+        <td><a href ={crmURL p='civicrm/contact/view' q="reset=1&cid=`$exception.other.id`"}>{$exception.other.name}</a></td>
         <td><a id='duplicateContacts' href="#" title={ts}Remove Exception{/ts} onClick="processDupes( {$exception.main.id}, {$exception.other.id}, 'nondupe-dupe', 'dedupe-exception' );return false;">&raquo; {ts}Remove Exception{/ts}</a></td>
       </tr>
     {/foreach}
index a9f04333a3f9c7f21f3d6fe69c750679004ed5d0..9992233745e51af878589e3aaea653a2c9f0c68f 100644 (file)
   {if !$reachedMax}
     <div class="action-link">
       {if $pageViewType eq 'customDataView'}
-        <br/><a accesskey="N" title="{ts 1=$customGroupTitle}Add %1 Record{/ts}" href="{crmURL p='civicrm/contact/view/cd/edit' q="reset=1&type=$ctype&groupID=$customGroupId&entityID=$contactId&cgcount=$cgcount&multiRecordDisplay=single&mode=add"}"
+        <br/><a accesskey="N" title="{ts 1=$customGroupTitle}Add %1 Record{/ts}" href="{crmURL p='civicrm/contact/view/cd/edit' q="reset=1&type=$ctype&groupID=$customGroupId&entityID=$contactId&cgcount=$newCgCount&multiRecordDisplay=single&mode=add"}"
          class="button action-item"><span><i class="crm-i fa-plus-circle"></i> {ts 1=$customGroupTitle}Add %1 Record{/ts}</span></a>
       {else}
         <a accesskey="N" href="{crmURL p='civicrm/profile/edit' q="reset=1&id=`$contactId`&multiRecord=add&gid=`$gid`&context=multiProfileDialog&onPopupClose=`$onPopupClose`"}"
index 1fd3c05d1d777cf867af78a63c59b75faee6f994..643c4153d0ba0fd96fe3d76de01c24e45f626155 100644 (file)
@@ -1362,7 +1362,7 @@ class CiviUnitTestCase extends PHPUnit_Extensions_Database_TestCase {
    * @return int
    *   Id Payment Processor
    */
-  public function processorCreate() {
+  public function processorCreate($params = array()) {
     $processorParams = array(
       'domain_id' => 1,
       'name' => 'Dummy',
@@ -1377,6 +1377,7 @@ class CiviUnitTestCase extends PHPUnit_Extensions_Database_TestCase {
       'sequential' => 1,
       'payment_instrument_id' => 'Debit Card',
     );
+    $processorParams = array_merge($processorParams, $params);
     $processor = $this->callAPISuccess('PaymentProcessor', 'create', $processorParams);
     return $processor['id'];
   }
@@ -3647,4 +3648,78 @@ AND    ( TABLE_NAME LIKE 'civicrm_value_%' )
     return Civi::settings()->set('contribution_invoice_settings', $contributeSetting);
   }
 
+  /**
+   * Create price set with contribution test for test setup.
+   *
+   * This could be merged with 4.5 function setup in api_v3_ContributionPageTest::setUpContributionPage
+   * on parent class at some point (fn is not in 4.4).
+   *
+   * @param $entity
+   * @param array $params
+   */
+  public function createPriceSetWithPage($entity = NULL, $params = array()) {
+    $membershipTypeID = $this->membershipTypeCreate(array('name' => 'Special'));
+    $contributionPageResult = $this->callAPISuccess('contribution_page', 'create', array(
+      'title' => "Test Contribution Page",
+      'financial_type_id' => 1,
+      'currency' => 'NZD',
+      'goal_amount' => 50,
+      'is_pay_later' => 1,
+      'is_monetary' => TRUE,
+      'is_email_receipt' => FALSE,
+    ));
+    $priceSet = $this->callAPISuccess('price_set', 'create', array(
+      'is_quick_config' => 0,
+      'extends' => 'CiviMember',
+      'financial_type_id' => 1,
+      'title' => 'my Page',
+    ));
+    $priceSetID = $priceSet['id'];
+
+    CRM_Price_BAO_PriceSet::addTo('civicrm_contribution_page', $contributionPageResult['id'], $priceSetID);
+    $priceField = $this->callAPISuccess('price_field', 'create', array(
+      'price_set_id' => $priceSetID,
+      'label' => 'Goat Breed',
+      'html_type' => 'Radio',
+    ));
+    $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
+        'price_set_id' => $priceSetID,
+        'price_field_id' => $priceField['id'],
+        'label' => 'Long Haired Goat',
+        'amount' => 20,
+        'financial_type_id' => 'Donation',
+        'membership_type_id' => $membershipTypeID,
+        'membership_num_terms' => 1,
+      )
+    );
+    $this->_ids['price_field_value'] = array($priceFieldValue['id']);
+    $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
+        'price_set_id' => $priceSetID,
+        'price_field_id' => $priceField['id'],
+        'label' => 'Shoe-eating Goat',
+        'amount' => 10,
+        'financial_type_id' => 'Donation',
+        'membership_type_id' => $membershipTypeID,
+        'membership_num_terms' => 2,
+      )
+    );
+    $this->_ids['price_field_value'][] = $priceFieldValue['id'];
+
+    $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
+        'price_set_id' => $priceSetID,
+        'price_field_id' => $priceField['id'],
+        'label' => 'Shoe-eating Goat',
+        'amount' => 10,
+        'financial_type_id' => 'Donation',
+      )
+    );
+    $this->_ids['price_field_value']['cont'] = $priceFieldValue['id'];
+
+    $this->_ids['price_set'] = $priceSetID;
+    $this->_ids['contribution_page'] = $contributionPageResult['id'];
+    $this->_ids['price_field'] = array($priceField['id']);
+
+    $this->_ids['membership_type'] = $membershipTypeID;
+  }
+
 }
index fe257feb0db424ed5f3ebeef9f9e39b481c6ced2..023d3260fdedcdf41bb692947cbc91adace75ecd 100644 (file)
@@ -401,7 +401,8 @@ class api_v3_ContributionPageTest extends CiviUnitTestCase {
     $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__, __FILE__, 'submit contribution page', NULL);
     $contributions = $this->callAPISuccess('contribution', 'get', array('contribution_page_id' => $this->_ids['contribution_page']));
     $this->assertCount(2, $contributions['values']);
-    $this->callAPISuccessGetCount('LineItem', array(), 2);
+    $lines = $this->callAPISuccess('LineItem', 'get', array('sequential' => 1));
+    $this->assertEquals(10, $lines['values'][0]['line_total']);
     $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
     $this->assertTrue(in_array($membershipPayment['contribution_id'], array_keys($contributions['values'])));
     $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
@@ -663,6 +664,224 @@ class api_v3_ContributionPageTest extends CiviUnitTestCase {
     $this->assertEquals(5, $recurringContribution['contribution_status_id']);
   }
 
+  /**
+   * Test submit recurring membership with immediate confirmation (IATS style).
+   *
+   * - we process 2 membership transactions against with a recurring contribution against a contribution page with an immediate
+   * processor (IATS style - denoted by returning trxn_id)
+   * - the first creates a new membership, completed contribution, in progress recurring. Check these
+   * - create another - end date should be extended
+   */
+  public function testSubmitMembershipComplexNonPriceSetPaymentPaymentProcessorRecurInstantPayment() {
+    $this->params['is_recur'] = 1;
+    $this->params['recur_frequency_unit'] = 'month';
+    // Add a membership so membership & contribution are not both 1.
+    $preExistingMembershipID = $this->contactMembershipCreate(array('contact_id' => $this->contactIds[0]));
+    $this->setUpMembershipContributionPage();
+    $dummyPP = Civi\Payment\System::singleton()->getByProcessor($this->_paymentProcessor);
+    $dummyPP->setDoDirectPaymentResult(array('payment_status_id' => 1, 'trxn_id' => 'create_first_success'));
+    $processor = $dummyPP->getPaymentProcessor();
+
+    $submitParams = array(
+      'price_' . $this->_ids['price_field'][0] => reset($this->_ids['price_field_value']),
+      'price_' . $this->_ids['price_field']['cont'] => 88,
+      'id' => (int) $this->_ids['contribution_page'],
+      'amount' => 10,
+      'billing_first_name' => 'Billy',
+      'billing_middle_name' => 'Goat',
+      'billing_last_name' => 'Gruff',
+      'email' => 'billy@goat.gruff',
+      'selectMembership' => $this->_ids['membership_type'],
+      'payment_processor_id' => 1,
+      'credit_card_number' => '4111111111111111',
+      'credit_card_type' => 'Visa',
+      'credit_card_exp_date' => array('M' => 9, 'Y' => 2040),
+      'cvv2' => 123,
+      'is_recur' => 1,
+      'frequency_interval' => 1,
+      'frequency_unit' => 'month',
+    );
+
+    $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__, __FILE__, 'submit contribution page', NULL);
+    $contribution = $this->callAPISuccess('contribution', 'getsingle', array(
+      'contribution_page_id' => $this->_ids['contribution_page'],
+      'contribution_status_id' => 1,
+    ));
+    $this->assertEquals($processor['payment_instrument_id'], $contribution['payment_instrument_id']);
+
+    $this->assertEquals('create_first_success', $contribution['trxn_id']);
+    $membershipPayment = $this->callAPISuccess('membership_payment', 'getsingle', array());
+    $this->assertEquals($membershipPayment['contribution_id'], $contribution['id']);
+    $membership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
+    $this->assertEquals($membership['contact_id'], $contribution['contact_id']);
+    $this->assertEquals(1, $membership['status_id']);
+    $this->callAPISuccess('contribution_recur', 'getsingle', array('id' => $contribution['contribution_recur_id']));
+
+    $lines = $this->callAPISuccess('line_item', 'get', array('sequential' => 1, 'contribution_id' => $contribution['id']));
+    $this->assertEquals(2, $lines['count']);
+    $this->assertEquals('civicrm_membership', $lines['values'][0]['entity_table']);
+    $this->assertEquals($preExistingMembershipID + 1, $lines['values'][0]['entity_id']);
+    $this->assertEquals('civicrm_contribution', $lines['values'][1]['entity_table']);
+    $this->assertEquals($contribution['id'], $lines['values'][1]['entity_id']);
+    $this->callAPISuccessGetSingle('MembershipPayment', array('contribution_id' => $contribution['id'], 'membership_id' => $preExistingMembershipID + 1));
+
+    //renew it with processor setting completed - should extend membership
+    $submitParams['contact_id'] = $contribution['contact_id'];
+    $dummyPP->setDoDirectPaymentResult(array('payment_status_id' => 1, 'trxn_id' => 'create_second_success'));
+    $this->callAPISuccess('contribution_page', 'submit', $submitParams);
+    $renewContribution = $this->callAPISuccess('contribution', 'getsingle', array(
+      'id' => array('NOT IN' => array($contribution['id'])),
+      'contribution_page_id' => $this->_ids['contribution_page'],
+      'contribution_status_id' => 1,
+    ));
+    $lines = $this->callAPISuccess('line_item', 'get', array('sequential' => 1, 'contribution_id' => $renewContribution['id']));
+    $this->assertEquals(2, $lines['count']);
+    $this->assertEquals('civicrm_membership', $lines['values'][0]['entity_table']);
+    $this->assertEquals($preExistingMembershipID + 1, $lines['values'][0]['entity_id']);
+    $this->assertEquals('civicrm_contribution', $lines['values'][1]['entity_table']);
+    $this->assertEquals($renewContribution['id'], $lines['values'][1]['entity_id']);
+
+    $renewedMembership = $this->callAPISuccessGetSingle('membership', array('id' => $membershipPayment['membership_id']));
+    $this->assertEquals(date('Y-m-d', strtotime('+ 1 year', strtotime($membership['end_date']))), $renewedMembership['end_date']);
+    $recurringContribution = $this->callAPISuccess('contribution_recur', 'getsingle', array('id' => $contribution['contribution_recur_id']));
+    $this->assertEquals($processor['payment_instrument_id'], $recurringContribution['payment_instrument_id']);
+    $this->assertEquals(5, $recurringContribution['contribution_status_id']);
+  }
+
+  /**
+   * Test submit recurring membership with immediate confirmation (IATS style).
+   *
+   * - we process 2 membership transactions against with a recurring contribution against a contribution page with an immediate
+   * processor (IATS style - denoted by returning trxn_id)
+   * - the first creates a new membership, completed contribution, in progress recurring. Check these
+   * - create another - end date should be extended
+   */
+  public function testSubmitMembershipComplexPriceSetPaymentPaymentProcessorRecurInstantPayment() {
+    $this->params['is_recur'] = 1;
+    $this->params['recur_frequency_unit'] = 'month';
+    // Add a membership so membership & contribution are not both 1.
+    $preExistingMembershipID = $this->contactMembershipCreate(array('contact_id' => $this->contactIds[0]));
+    $this->createPriceSetWithPage();
+    $this->addSecondOrganizationMembershipToPriceSet();
+    $this->setupPaymentProcessor();
+
+    $dummyPP = Civi\Payment\System::singleton()->getByProcessor($this->_paymentProcessor);
+    $dummyPP->setDoDirectPaymentResult(array('payment_status_id' => 1, 'trxn_id' => 'create_first_success'));
+    $processor = $dummyPP->getPaymentProcessor();
+
+    $submitParams = array(
+      'price_' . $this->_ids['price_field'][0] => $this->_ids['price_field_value']['cont'],
+      'price_' . $this->_ids['price_field']['org1'] => $this->_ids['price_field_value']['org1'],
+      'price_' . $this->_ids['price_field']['org2'] => $this->_ids['price_field_value']['org2'],
+      'id' => (int) $this->_ids['contribution_page'],
+      'amount' => 10,
+      'billing_first_name' => 'Billy',
+      'billing_middle_name' => 'Goat',
+      'billing_last_name' => 'Gruff',
+      'email' => 'billy@goat.gruff',
+      'selectMembership' => NULL,
+      'payment_processor_id' => 1,
+      'credit_card_number' => '4111111111111111',
+      'credit_card_type' => 'Visa',
+      'credit_card_exp_date' => array('M' => 9, 'Y' => 2040),
+      'cvv2' => 123,
+      'frequency_interval' => 1,
+      'frequency_unit' => 'month',
+    );
+
+    $this->callAPIAndDocument('contribution_page', 'submit', $submitParams, __FUNCTION__, __FILE__, 'submit contribution page', NULL);
+    $contribution = $this->callAPISuccess('contribution', 'getsingle', array(
+      'contribution_page_id' => $this->_ids['contribution_page'],
+      'contribution_status_id' => 1,
+    ));
+    $this->assertEquals($processor['payment_instrument_id'], $contribution['payment_instrument_id']);
+
+    $this->assertEquals('create_first_success', $contribution['trxn_id']);
+    $membershipPayments = $this->callAPISuccess('membership_payment', 'get', array(
+      'sequential' => 1,
+      'contribution_id' => $contribution['id'],
+    ));
+    $this->assertEquals(2, $membershipPayments['count']);
+    $lines = $this->callAPISuccess('line_item', 'get', array('sequential' => 1, 'contribution_id' => $contribution['id']));
+    $this->assertEquals(3, $lines['count']);
+    $this->assertEquals('civicrm_membership', $lines['values'][0]['entity_table']);
+    $this->assertEquals($preExistingMembershipID + 1, $lines['values'][0]['entity_id']);
+    $this->assertEquals('civicrm_contribution', $lines['values'][1]['entity_table']);
+    $this->assertEquals($contribution['id'], $lines['values'][1]['entity_id']);
+    $this->assertEquals('civicrm_membership', $lines['values'][2]['entity_table']);
+    $this->assertEquals($preExistingMembershipID + 2, $lines['values'][2]['entity_id']);
+
+    $this->callAPISuccessGetSingle('MembershipPayment', array('contribution_id' => $contribution['id'], 'membership_id' => $preExistingMembershipID + 1));
+    $membership = $this->callAPISuccessGetSingle('membership', array('id' => $preExistingMembershipID + 1));
+
+    //renew it with processor setting completed - should extend membership
+    $submitParams['contact_id'] = $contribution['contact_id'];
+    $dummyPP->setDoDirectPaymentResult(array('payment_status_id' => 1, 'trxn_id' => 'create_second_success'));
+    $this->callAPISuccess('contribution_page', 'submit', $submitParams);
+    $renewContribution = $this->callAPISuccess('contribution', 'getsingle', array(
+      'id' => array('NOT IN' => array($contribution['id'])),
+      'contribution_page_id' => $this->_ids['contribution_page'],
+      'contribution_status_id' => 1,
+    ));
+    $lines = $this->callAPISuccess('line_item', 'get', array('sequential' => 1, 'contribution_id' => $renewContribution['id']));
+    $this->assertEquals(3, $lines['count']);
+    $this->assertEquals('civicrm_membership', $lines['values'][0]['entity_table']);
+    $this->assertEquals($preExistingMembershipID + 1, $lines['values'][0]['entity_id']);
+    $this->assertEquals('civicrm_contribution', $lines['values'][1]['entity_table']);
+    $this->assertEquals($renewContribution['id'], $lines['values'][1]['entity_id']);
+
+    $renewedMembership = $this->callAPISuccessGetSingle('membership', array('id' => $preExistingMembershipID + 1));
+    $this->assertEquals(date('Y-m-d', strtotime('+ 1 year', strtotime($membership['end_date']))), $renewedMembership['end_date']);
+  }
+
+  /**
+   * Extend the price set with a second organisation's membership.
+   */
+  public function addSecondOrganizationMembershipToPriceSet() {
+    $organization2ID = $this->organizationCreate();
+    $membershipTypes = $this->callAPISuccess('MembershipType', 'get', array());
+    $this->_ids['membership_type'] = array_keys($membershipTypes['values']);
+    $this->_ids['membership_type']['org2'] = $this->membershipTypeCreate(array('contact_id' => $organization2ID, 'name' => 'Org 2'));
+    $priceField = $this->callAPISuccess('PriceField', 'create', array(
+      'price_set_id' => $this->_ids['price_set'],
+      'html_type' => 'Radio',
+      'name' => 'Org1 Price',
+      'label' => 'Org1Price',
+    ));
+    $this->_ids['price_field']['org1'] = $priceField['id'];
+
+    $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
+      'name' => 'org1 amount',
+      'label' => 'org 1 Amount',
+      'amount' => 2,
+      'financial_type_id' => 'Member Dues',
+      'format.only_id' => TRUE,
+      'membership_type_id' => reset($this->_ids['membership_type']),
+      'price_field_id' => $priceField['id'],
+    ));
+    $this->_ids['price_field_value']['org1'] = $priceFieldValue;
+
+    $priceField = $this->callAPISuccess('PriceField', 'create', array(
+      'price_set_id' => $this->_ids['price_set'],
+      'html_type' => 'Radio',
+      'name' => 'Org2 Price',
+      'label' => 'Org2Price',
+    ));
+    $this->_ids['price_field']['org2'] = $priceField['id'];
+
+    $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
+      'name' => 'org2 amount',
+      'label' => 'org 2 Amount',
+      'amount' => 200,
+      'financial_type_id' => 'Member Dues',
+      'format.only_id' => TRUE,
+      'membership_type_id' => $this->_ids['membership_type']['org2'],
+      'price_field_id' => $priceField['id'],
+    ));
+    $this->_ids['price_field_value']['org2'] = $priceFieldValue;
+
+  }
+
   /**
    * Test submit recurring membership with immediate confirmation (IATS style).
    *
@@ -867,7 +1086,7 @@ class api_v3_ContributionPageTest extends CiviUnitTestCase {
       $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
         'name' => 'membership_amount',
         'label' => 'Membership Amount',
-        'amount' => 1,
+        'amount' => 2,
         'financial_type_id' => 'Donation',
         'format.only_id' => TRUE,
         'membership_type_id' => $membershipTypeID,
@@ -875,6 +1094,45 @@ class api_v3_ContributionPageTest extends CiviUnitTestCase {
       ));
       $this->_ids['price_field_value'][] = $priceFieldValue;
     }
+    if (!empty($this->_ids['membership_type']['org2'])) {
+      $priceField = $this->callAPISuccess('price_field', 'create', array(
+        'price_set_id' => reset($this->_ids['price_set']),
+        'name' => 'membership_org2',
+        'label' => 'Membership Org2',
+        'html_type' => 'Checkbox',
+        'sequential' => 1,
+      ));
+      $this->_ids['price_field']['org2'] = $priceField['id'];
+
+      $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
+        'name' => 'membership_org2',
+        'label' => 'Membership org 2',
+        'amount' => 55,
+        'financial_type_id' => 'Member Dues',
+        'format.only_id' => TRUE,
+        'membership_type_id' => $this->_ids['membership_type']['org2'],
+        'price_field_id' => $priceField['id'],
+      ));
+      $this->_ids['price_field_value']['org2'] = $priceFieldValue;
+    }
+    $priceField = $this->callAPISuccess('price_field', 'create', array(
+      'price_set_id' => reset($this->_ids['price_set']),
+      'name' => 'Contribution',
+      'label' => 'Contribution',
+      'html_type' => 'Text',
+      'sequential' => 1,
+      'is_enter_qty' => 1,
+    ));
+    $this->_ids['price_field']['cont'] = $priceField['id'];
+    $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
+      'name' => 'contribution',
+      'label' => 'Give me money',
+      'amount' => 88,
+      'financial_type_id' => 'Donation',
+      'format.only_id' => TRUE,
+      'price_field_id' => $priceField['id'],
+    ));
+    $this->_ids['price_field_value'][] = $priceFieldValue;
   }
 
   /**
index 440e8506b8eeb20b32c89485f3af963fdcfe5a34..e3e6c0936aa3eaec21381ccc9d7053748af6dadb 100644 (file)
@@ -1713,7 +1713,6 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
     $this->revertTemplateToReservedTemplate();
   }
 
-
   /**
    * Test to check whether contact billing address is used when no contribution address
    */
@@ -2497,6 +2496,65 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
     $this->cleanUpAfterPriceSets();
   }
 
+  /**
+   * Test if renewal activity is create after changing Pending contribution to Completed via offline
+   */
+  public function testPendingToCompleteContribution() {
+    $contributionPage = $this->createPriceSetWithPage('membership');
+    $stateOfGrace = $this->callAPISuccess('MembershipStatus', 'getvalue', array(
+      'name' => 'Grace',
+      'return' => 'id')
+    );
+    $this->setUpPendingContribution($this->_ids['price_field_value'][0]);
+    $this->callAPISuccess('membership', 'getsingle', array('id' => $this->_ids['membership']));
+
+    // change pending contribution to completed
+    $form = new CRM_Contribute_Form_Contribution();
+    $error = FALSE;
+    $form->_params = array(
+      'id' => $this->_ids['contribution'],
+      'total_amount' => 20,
+      'net_amount' => 20,
+      'fee_amount' => 0,
+      'financial_type_id' => 1,
+      'receive_date' => '04/21/2015',
+      'receive_date_time' => '11:27PM',
+      'contact_id' => $this->_individualId,
+      'contribution_status_id' => 1,
+      'billing_middle_name' => '',
+      'billing_last_name' => 'Adams',
+      'billing_street_address-5' => '790L Lincoln St S',
+      'billing_city-5' => 'Maryknoll',
+      'billing_state_province_id-5' => 1031,
+      'billing_postal_code-5' => 10545,
+      'billing_country_id-5' => 1228,
+      'frequency_interval' => 1,
+      'frequency_unit' => 'month',
+      'installments' => '',
+      'hidden_AdditionalDetail' => 1,
+      'hidden_Premium' => 1,
+      'from_email_address' => '"civi45" <civi45@civicrm.com>',
+      'receipt_date' => '',
+      'receipt_date_time' => '',
+      'payment_processor_id' => $this->paymentProcessorID,
+      'currency' => 'USD',
+      'contribution_page_id' => $this->_ids['contribution_page'],
+      'contribution_mode' => 'membership',
+      'source' => 'Membership Signup and Renewal',
+    );
+    try {
+      $form->testSubmit($form->_params, CRM_Core_Action::UPDATE);
+    }
+    catch (Civi\Payment\Exception\PaymentProcessorException $e) {
+      $error = TRUE;
+    }
+    $activity = $this->callAPISuccess('Activity', 'get', array(
+      'activity_type_id' => 'Membership Renewal',
+      'source_record_id' => $this->_ids['contribution'],
+    ));
+    $this->assertEquals(1, $activity['count']);
+  }
+
   /**
    * Test membership is renewed when transaction completed.
    */
@@ -2514,70 +2572,6 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
     $this->contactDelete($this->_ids['contact']);
   }
 
-
-  /**
-   * Create price set with contribution test for test setup.
-   *
-   * This could be merged with 4.5 function setup in api_v3_ContributionPageTest::setUpContributionPage
-   * on parent class at some point (fn is not in 4.4).
-   *
-   * @param $entity
-   * @param array $params
-   */
-  public function createPriceSetWithPage($entity, $params = array()) {
-    $membershipTypeID = $this->membershipTypeCreate();
-    $contributionPageResult = $this->callAPISuccess('contribution_page', 'create', array(
-      'title' => "Test Contribution Page",
-      'financial_type_id' => 1,
-      'currency' => 'NZD',
-      'goal_amount' => 50,
-      'is_pay_later' => 1,
-      'is_monetary' => TRUE,
-      'is_email_receipt' => FALSE,
-    ));
-    $priceSet = $this->callAPISuccess('price_set', 'create', array(
-      'is_quick_config' => 0,
-      'extends' => 'CiviMember',
-      'financial_type_id' => 1,
-      'title' => 'my Page',
-    ));
-    $priceSetID = $priceSet['id'];
-
-    CRM_Price_BAO_PriceSet::addTo('civicrm_contribution_page', $contributionPageResult['id'], $priceSetID);
-    $priceField = $this->callAPISuccess('price_field', 'create', array(
-      'price_set_id' => $priceSetID,
-      'label' => 'Goat Breed',
-      'html_type' => 'Radio',
-    ));
-    $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
-        'price_set_id' => $priceSetID,
-        'price_field_id' => $priceField['id'],
-        'label' => 'Long Haired Goat',
-        'amount' => 20,
-        'financial_type_id' => 'Donation',
-        'membership_type_id' => $membershipTypeID,
-        'membership_num_terms' => 1,
-      )
-    );
-    $this->_ids['price_field_value'] = array($priceFieldValue['id']);
-    $priceFieldValue = $this->callAPISuccess('price_field_value', 'create', array(
-        'price_set_id' => $priceSetID,
-        'price_field_id' => $priceField['id'],
-        'label' => 'Shoe-eating Goat',
-        'amount' => 10,
-        'financial_type_id' => 'Donation',
-        'membership_type_id' => $membershipTypeID,
-        'membership_num_terms' => 2,
-      )
-    );
-    $this->_ids['price_field_value'][] = $priceFieldValue['id'];
-    $this->_ids['price_set'] = $priceSetID;
-    $this->_ids['contribution_page'] = $contributionPageResult['id'];
-    $this->_ids['price_field'] = array($priceField['id']);
-
-    $this->_ids['membership_type'] = $membershipTypeID;
-  }
-
   /**
    * Set up a pending transaction with a specific price field id.
    *
@@ -2596,7 +2590,7 @@ class api_v3_ContributionTest extends CiviUnitTestCase {
       'domain_id' => 1,
       'contact_id' => $contactID,
       'receive_date' => date('Ymd'),
-      'total_amount' => 100.00,
+      'total_amount' => 20.00,
       'financial_type_id' => 1,
       'payment_instrument_id' => 'Credit Card',
       'non_deductible_amount' => 10.00,
index bbc33cbb424ee7151918c71827288b954061c2c9..e9f5169fa24edd09a68a9e9cef3003c9990a1b69 100644 (file)
@@ -61,6 +61,28 @@ class api_v3_DashboardTest extends CiviUnitTestCase {
     $this->assertEquals($dashboard['values'][$dashboard['id']]['is_active'], 1);
   }
 
+  /**
+   * CRM-19534.
+   *
+   * Ensure that Dashboard create works fine for non admins
+   */
+  public function testDashboardCreateByNonAdmins() {
+    $loggedInContactID = $this->createLoggedInUser();
+    CRM_Core_Config::singleton()->userPermissionClass->permissions = array();
+    $params = array(
+      'label' => 'New Dashlet element',
+      'name' => 'New Dashlet element',
+      'url' => 'civicrm/report/list&reset=1&compid=99',
+      'fullscreen_url' => 'civicrm/report/list&compid=99&reset=1&context=dashletFullscreen',
+    );
+    $dashboard = $this->callAPISuccess('dashboard', 'create', $params);
+    $this->assertTrue(is_numeric($dashboard['id']), "In line " . __LINE__);
+    $this->assertTrue($dashboard['id'] > 0, "In line " . __LINE__);
+
+    $this->callAPISuccess('dashboard', 'create', $params);
+    $this->assertEquals($dashboard['values'][$dashboard['id']]['is_active'], 1);
+  }
+
   /**
    * CRM-19217.
    *
index b46b253151e715bad34e7731348c9413d6a4bf8a..c5b0d837a6542f16e5ec793591f96278c4bfc789 100644 (file)
@@ -98,6 +98,44 @@ class api_v3_ParticipantTest extends CiviUnitTestCase {
     $this->quickCleanup($tablesToTruncate, TRUE);
   }
 
+  /**
+   * Test get participants with role_id.
+   */
+  public function testGetParticipantWithRole() {
+    $roleId = array(1, 2, 3);
+    foreach ($roleId as $role) {
+      $this->participantCreate(array(
+        'contact_id' => $this->individualCreate(),
+        'role_id' => $role,
+        'event_id' => $this->_eventID,
+      ));
+    }
+
+    $params = array(
+      'role_id' => 2,
+    );
+    $result = $this->callAPISuccess('participant', 'get', $params);
+    //Assert all the returned participants has a role_id of 2
+    foreach ($result['values'] as $pid => $values) {
+      $this->assertEquals($values['participant_role_id'], 2);
+    }
+
+    $this->participantCreate(array(
+      'id' => $this->_participantID,
+      'role_id' => NULL,
+      'event_id' => $this->_eventID,
+    ));
+
+    $params['role_id'] = array(
+      'IS NULL' => 1,
+    );
+    $result = $this->callAPISuccess('participant', 'get', $params);
+    foreach ($result['values'] as $pid => $values) {
+      $this->assertEquals($values['participant_role_id'], NULL);
+    }
+
+  }
+
   /**
    * Check with complete array + custom field
    * Note that the test is written on purpose without any