From 5f5e7a766e4b54a52462542046baf7f960c49e6e Mon Sep 17 00:00:00 2001 From: Omar abu hussein Date: Wed, 11 Jul 2018 15:39:00 +0100 Subject: [PATCH 001/408] dev/core#253: Cancelling or An Error during event registration payment should cancel all additional participates --- CRM/Core/Payment/BaseIPN.php | 18 +-- .../phpunit/CRM/Core/Payment/BaseIPNTest.php | 139 ++++++++---------- 2 files changed, 68 insertions(+), 89 deletions(-) diff --git a/CRM/Core/Payment/BaseIPN.php b/CRM/Core/Payment/BaseIPN.php index 96cdc87698f5..1829889ab670 100644 --- a/CRM/Core/Payment/BaseIPN.php +++ b/CRM/Core/Payment/BaseIPN.php @@ -273,12 +273,9 @@ public function failed(&$objects, &$transaction, $input = array()) { } if ($participant) { - $participantStatuses = CRM_Core_PseudoConstant::get('CRM_Event_DAO_Participant', 'status_id', array( - 'labelColumn' => 'name', - 'flip' => 1, - )); - $participant->status_id = $participantStatuses['Cancelled']; - $participant->save(); + $participantParams['id'] = $participant->id; + $participantParams['status_id'] = 'Cancelled'; + civicrm_api3('Participant', 'create', $participantParams); } } @@ -370,12 +367,9 @@ public function cancelled(&$objects, &$transaction, $input = array()) { } if ($participant) { - $participantStatuses = CRM_Core_PseudoConstant::get('CRM_Event_DAO_Participant', 'status_id', array( - 'labelColumn' => 'name', - 'flip' => 1, - )); - $participant->status_id = $participantStatuses['Cancelled']; - $participant->save(); + $participantParams['id'] = $participant->id; + $participantParams['status_id'] = 'Cancelled'; + civicrm_api3('Participant', 'create', $participantParams); } } $transaction->commit(); diff --git a/tests/phpunit/CRM/Core/Payment/BaseIPNTest.php b/tests/phpunit/CRM/Core/Payment/BaseIPNTest.php index 821c75d0cf5c..51f3f7b19103 100644 --- a/tests/phpunit/CRM/Core/Payment/BaseIPNTest.php +++ b/tests/phpunit/CRM/Core/Payment/BaseIPNTest.php @@ -411,82 +411,63 @@ public function testRequiredWithContributionPageError() { $this->assertFalse(is_array($result)); } - /* @codingStandardsIgnoreStart - * Test calls main functions in sequence per 'main' - I had hoped to test the functions more - * fully but the calls to the POST happen in more than one function - * keeping this as good example of data to bring back to life later - - public function testMainFunctionActions() { - $ids = $objects = array( ); - $input['component'] = 'Contribute'; - $postedParams = array( - 'x_response_code' => 1, - 'x_response_reason_code' => 1, - 'x_response_reason_text' => 'This transaction has been approved.', - 'x_avs_code' => 'Y', - 'x_auth_code' => 140454, - 'x_trans_id' => 4353599599, - 'x_method' => 'CC', - 'x_card_type' => 'American Express', - 'x_account_number' => 'XXXX2701', - 'x_first_name' => 'Arthur', - 'x_last_name' => 'Jacobs', - 'x_company' => null, - 'x_address' => '866 2166th St SN', - 'x_city' => 'Edwardstown', - 'x_state' => 'WA', - 'x_zip' => 98026, - 'x_country' => 'US', - 'x_phone' => null, - 'x_fax' => null, - 'x_email' => null, - 'x_invoice_num' => 'a9fb56c24576lk4c9490f6', - 'x_description' => 'my desc', - 'x_type' => 'auth_capture', - 'x_cust_id' => 5191, - 'x_ship_to_first_name' => null, - 'x_ship_to_last_name' => null, - 'x_ship_to_company' => null, - 'x_ship_to_address' => null, - 'x_ship_to_city' => null, - 'x_ship_to_state' => null, - 'x_ship_to_zip' => null, - 'x_ship_to_country' => null, - 'x_amount' => 60.00, - 'x_tax' => 0.00, - 'x_duty' => 0.00, - 'x_freight' => 0.00, - 'x_tax_exempt' => FALSE, - 'x_po_num' => null, - 'x_MD5_Hash' => '069ECAD13C8E15AC205CDF92B8B58CC7', - 'x_cvv2_resp_code' => null, - 'x_cavv_response' => null, - 'x_test_request' => false, - 'description' => 'my description' - ); - $this->IPN->getInput( $input, $ids ); - $this->IPN->getIDs( $ids, $input ); - - CRM_Core_Error::debug_var( '$ids', $ids ); - CRM_Core_Error::debug_var( '$input', $input ); - - $paymentProcessorID = CRM_Core_DAO::getFieldValue( 'CRM_Financial_DAO_PaymentProcessorType', - 'AuthNet', 'id', 'name' ); - - if ( ! $this->IPN->validateData( $input, $ids, $objects, true, $paymentProcessorID ) ) { - return false; - } - - if ( $component == 'contribute' && $ids['contributionRecur'] ) { - // check if first contribution is completed, else complete first contribution - $first = true; - if ( $objects['contribution']->contribution_status_id == 1 ) { - $first = false; - } - return $this->IPN->recur( $input, $ids, $objects, $first ); - } - } - @codingStandardsIgnoreEnd */ + public function testThatCancellingEventPaymentWillCancelAllAdditionalPendingParticipantsAndCreateCancellationActivities() { + $this->_setUpParticipantObjects('Pending from incomplete transaction'); + $this->IPN->loadObjects($this->input, $this->ids, $this->objects, FALSE, $this->_processorId); + $additionalParticipantId = $this->participantCreate(array( + 'event_id' => $this->_eventId, + 'registered_by_id' => $this->_participantId, + 'status_id' => 'Pending from incomplete transaction', + )); + + $transaction = new CRM_Core_Transaction(); + $this->IPN->cancelled($this->objects, $transaction); + + $cancelledParticipantsCount = civicrm_api3('Participant', 'get', [ + 'sequential' => 1, + 'id' => ['IN' => [$this->_participantId, $additionalParticipantId]], + 'status_id' => 'Cancelled', + ])['count']; + $this->assertEquals(2, $cancelledParticipantsCount); + + $cancelledActivatesCount = civicrm_api3('Activity', 'get', [ + 'sequential' => 1, + 'activity_type_id' => 'Event Registration', + 'subject' => ['LIKE' => '%Cancelled%'], + 'source_record_id' => ['IN' => [$this->_participantId, $additionalParticipantId]], + ]); + + $this->assertEquals(2, $cancelledActivatesCount['count']); + } + + public function testThatFailedEventPaymentWillCancelAllAdditionalPendingParticipantsAndCreateCancellationActivities() { + $this->_setUpParticipantObjects('Pending from incomplete transaction'); + $this->IPN->loadObjects($this->input, $this->ids, $this->objects, FALSE, $this->_processorId); + $additionalParticipantId = $this->participantCreate(array( + 'event_id' => $this->_eventId, + 'registered_by_id' => $this->_participantId, + 'status_id' => 'Pending from incomplete transaction', + )); + + $transaction = new CRM_Core_Transaction(); + $this->IPN->failed($this->objects, $transaction); + + $cancelledParticipantsCount = civicrm_api3('Participant', 'get', [ + 'sequential' => 1, + 'id' => ['IN' => [$this->_participantId, $additionalParticipantId]], + 'status_id' => 'Cancelled', + ])['count']; + $this->assertEquals(2, $cancelledParticipantsCount); + + $cancelledActivatesCount = civicrm_api3('Activity', 'get', [ + 'sequential' => 1, + 'activity_type_id' => 'Event Registration', + 'subject' => ['LIKE' => '%Cancelled%'], + 'source_record_id' => ['IN' => [$this->_participantId, $additionalParticipantId]], + ]); + + $this->assertEquals(2, $cancelledActivatesCount['count']); + } /** * Prepare for contribution Test - involving only contribution objects @@ -606,14 +587,18 @@ public function _setUpRecurringContribution() { /** * Set up participant requirements for test. + * + * @param string $participantStatus + * The participant to create status */ - public function _setUpParticipantObjects() { + public function _setUpParticipantObjects($participantStatus = 'Attended') { $event = $this->eventCreate(array('is_email_confirm' => 1)); $this->_eventId = $event['id']; $this->_participantId = $this->participantCreate(array( 'event_id' => $this->_eventId, 'contact_id' => $this->_contactId, + 'status_id' => $participantStatus, )); $this->callAPISuccess('participant_payment', 'create', array( From af131476bacabc2187ddeae2efdd15124c73cae9 Mon Sep 17 00:00:00 2001 From: Omar abu hussein Date: Fri, 27 Jul 2018 17:32:49 +0100 Subject: [PATCH 002/408] dev/core#288 : Use membership actuall end date on pending payment completion --- CRM/Contribute/BAO/Contribution.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CRM/Contribute/BAO/Contribution.php b/CRM/Contribute/BAO/Contribution.php index bd1d1d452ef5..ac2068dfcd70 100644 --- a/CRM/Contribute/BAO/Contribution.php +++ b/CRM/Contribute/BAO/Contribution.php @@ -2008,7 +2008,7 @@ public static function transitionComponents($params, $processContributionObject ); } - $updateResult['membership_end_date'] = CRM_Utils_Date::customFormat($dates['end_date'], + $updateResult['membership_end_date'] = CRM_Utils_Date::customFormat($membership->end_date, '%B %E%f, %Y' ); $updateResult['updatedComponents']['CiviMember'] = $membership->status_id; From 2ddf0fcdae8f287515b397b2c94603a4a9da0f5c Mon Sep 17 00:00:00 2001 From: Aniessh Sethh Date: Thu, 9 Aug 2018 09:56:31 +0530 Subject: [PATCH 003/408] Fix for CRM-314 --- CRM/Event/Form/SelfSvcTransfer.php | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/CRM/Event/Form/SelfSvcTransfer.php b/CRM/Event/Form/SelfSvcTransfer.php index 7452ccb246ab..e3ede8ea345b 100644 --- a/CRM/Event/Form/SelfSvcTransfer.php +++ b/CRM/Event/Form/SelfSvcTransfer.php @@ -337,10 +337,22 @@ public function postProcess() { } else { //cancel 'from' participant row - $query = "select contact_id from civicrm_email where email = '" . $params['email'] . "'"; - $dao = CRM_Core_DAO::executeQuery($query); - while ($dao->fetch()) { - $contact_id = $dao->contact_id; + try{ + $contact_id_result = civicrm_api3('Contact', 'get', array( + 'sequential' => 1, + 'return' => array("id"), + 'email' => $params['email'], + 'options' => array('limit' => 1), + )); + $contact_id_result = $contact_id_result['values'][0]; + $contact_id = $contact_id_result['contact_id']; + $contact_is_deleted = $contact_id_result['contact_is_deleted']; + if ($contact_is_deleted || !is_numeric($contact_id)) { + CRM_Core_Error::statusBounce(ts('Contact does not exist.')); + } + } + catch (CiviCRM_API3_Exception $e) { + CRM_Core_Error::statusBounce(ts('Contact does not exist.')); } } $from_participant = $params = array(); From d4a64d9ade0b5d2b0da6e6a0aef6efe43799ce79 Mon Sep 17 00:00:00 2001 From: Aniessh Sethh Date: Fri, 17 Aug 2018 09:57:33 +0530 Subject: [PATCH 004/408] fix for Issue - 314 --- CRM/Event/Form/SelfSvcTransfer.php | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/CRM/Event/Form/SelfSvcTransfer.php b/CRM/Event/Form/SelfSvcTransfer.php index e3ede8ea345b..fc1703720326 100644 --- a/CRM/Event/Form/SelfSvcTransfer.php +++ b/CRM/Event/Form/SelfSvcTransfer.php @@ -337,21 +337,16 @@ public function postProcess() { } else { //cancel 'from' participant row - try{ - $contact_id_result = civicrm_api3('Contact', 'get', array( - 'sequential' => 1, - 'return' => array("id"), - 'email' => $params['email'], - 'options' => array('limit' => 1), - )); - $contact_id_result = $contact_id_result['values'][0]; - $contact_id = $contact_id_result['contact_id']; - $contact_is_deleted = $contact_id_result['contact_is_deleted']; - if ($contact_is_deleted || !is_numeric($contact_id)) { - CRM_Core_Error::statusBounce(ts('Contact does not exist.')); - } - } - catch (CiviCRM_API3_Exception $e) { + $contact_id_result = civicrm_api3('Contact', 'get', array( + 'sequential' => 1, + 'return' => array("id"), + 'email' => $params['email'], + 'options' => array('limit' => 1), + )); + $contact_id_result = $contact_id_result['values'][0]; + $contact_id = $contact_id_result['contact_id']; + $contact_is_deleted = $contact_id_result['contact_is_deleted']; + if ($contact_is_deleted || !is_numeric($contact_id)) { CRM_Core_Error::statusBounce(ts('Contact does not exist.')); } } From 6bc9b1f60b82eaf6267f6c708d4cf1408de13662 Mon Sep 17 00:00:00 2001 From: Francis Whittle Date: Fri, 12 Oct 2018 16:36:14 +1100 Subject: [PATCH 005/408] CIVICRM-990: Quote fee levels for regular expression in Participant search. --- CRM/Event/BAO/Query.php | 4 +++- CRM/Event/Form/Search.php | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CRM/Event/BAO/Query.php b/CRM/Event/BAO/Query.php index 1f96e40b1924..7d90935bc61f 100644 --- a/CRM/Event/BAO/Query.php +++ b/CRM/Event/BAO/Query.php @@ -340,11 +340,13 @@ public static function whereClauseSingle(&$values, &$query) { return; case 'participant_fee_id': + $val_regexp = []; foreach ($value as $k => &$val) { $val = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceFieldValue', $val, 'label'); + $val_regexp[$k] = CRM_Core_DAO::escapeString(preg_quote(trim($val))); $val = CRM_Core_DAO::escapeString(trim($val)); } - $feeLabel = implode('|', $value); + $feeLabel = implode('|', $val_regexp); $query->_where[$grouping][] = "civicrm_participant.fee_level REGEXP '{$feeLabel}'"; $query->_qill[$grouping][] = ts("Fee level") . " IN " . implode(', ', $value); $query->_tables['civicrm_participant'] = $query->_whereTables['civicrm_participant'] = 1; diff --git a/CRM/Event/Form/Search.php b/CRM/Event/Form/Search.php index c5b73d81403b..a1421cbe3a9f 100644 --- a/CRM/Event/Form/Search.php +++ b/CRM/Event/Form/Search.php @@ -209,11 +209,13 @@ public function buildQuickForm() { // CRM-15379 if (!empty($this->_formValues['participant_fee_id'])) { $participant_fee_id = $this->_formValues['participant_fee_id']; + $val_regexp = []; foreach ($participant_fee_id as $k => &$val) { $val = CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceFieldValue', $val, 'label'); + $val_regexp[$k] = CRM_Core_DAO::escapeString(preg_quote(trim($val))); $val = CRM_Core_DAO::escapeString(trim($val)); } - $feeLabel = implode('|', $participant_fee_id); + $feeLabel = implode('|', $val_regexp); $seatClause[] = "( participant.fee_level REGEXP '{$feeLabel}' )"; } From 81eb94b557c9eaffbb8f07b4440e009ee351c23b Mon Sep 17 00:00:00 2001 From: Alice Frumin Date: Wed, 7 Nov 2018 17:36:52 -0500 Subject: [PATCH 006/408] send links on any page that extends CRM_Core_Page_basic thru hook_civicrm_links --- CRM/Core/Page/Basic.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/CRM/Core/Page/Basic.php b/CRM/Core/Page/Basic.php index 48af5ebf531b..de39350eb762 100644 --- a/CRM/Core/Page/Basic.php +++ b/CRM/Core/Page/Basic.php @@ -319,11 +319,12 @@ public function action(&$object, $action, &$values, &$links, $permission, $force } } + $object_type = get_class($object); + if (!$forceAction) { if (array_key_exists('is_reserved', $object) && $object->is_reserved) { $values['class'] = 'reserved'; // check if object is relationship type - $object_type = get_class($object); $exceptions = array( 'CRM_Contact_BAO_RelationshipType', @@ -365,7 +366,16 @@ public function action(&$object, $action, &$values, &$links, $permission, $force // make sure we only allow those actions that the user is permissioned for $newAction = $newAction & CRM_Core_Action::mask($permissions); - $values['action'] = CRM_Core_Action::formLink($links, $newAction, array('id' => $object->id)); + $values['action'] = CRM_Core_Action::formLink( + $links, + $newAction, + ['id' => $object->id], + 'more', + FALSE, + "basic.$object_type.page", + $object_type, + $object->id + ); } /** From 2e40be0a16fb3f741a28d8caea030fd7322eb81a Mon Sep 17 00:00:00 2001 From: Omar abu hussein Date: Thu, 15 Nov 2018 23:48:44 +0200 Subject: [PATCH 007/408] dev/core#288: Move membership end date notification format to transitionComponentWithReturnMessage method --- CRM/Contribute/BAO/Contribution.php | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/CRM/Contribute/BAO/Contribution.php b/CRM/Contribute/BAO/Contribution.php index ac2068dfcd70..c0c2916fabb5 100644 --- a/CRM/Contribute/BAO/Contribution.php +++ b/CRM/Contribute/BAO/Contribution.php @@ -2008,9 +2008,6 @@ public static function transitionComponents($params, $processContributionObject ); } - $updateResult['membership_end_date'] = CRM_Utils_Date::customFormat($membership->end_date, - '%B %E%f, %Y' - ); $updateResult['updatedComponents']['CiviMember'] = $membership->status_id; if ($processContributionObject) { $processContribution = TRUE; @@ -5223,7 +5220,7 @@ public static function transitionComponentWithReturnMessage($contributionId, $st $statusMsg .= "
" . ts("Membership for %1 has been Expired.", array(1 => $userDisplayName)); } else { - $endDate = CRM_Utils_Array::value('membership_end_date', $updateResult); + $endDate = self::getFormattedMembershipEndDateFromContributionId($contributionId); if ($endDate) { $statusMsg .= "
" . ts("Membership for %1 has been updated. The membership End Date is %2.", array( @@ -5266,6 +5263,25 @@ public static function transitionComponentWithReturnMessage($contributionId, $st return $statusMsg; } + private static function getFormattedMembershipEndDateFromContributionId($contributionId) { + $endDateResponse = civicrm_api3('MembershipPayment', 'get', [ + 'sequential' => 1, + 'contribution_id' => $contributionId, + 'api.Membership.get' => ['id' => '$value.id', 'return' => ['end_date']], + 'options' => ['limit' => 1, 'sort' => 'id DESC'], + ]); + + $endDate = NULL; + if (!empty($endDateResponse['values'][0]['api.Membership.get']['count'])) { + $endDate = $endDateResponse['values'][0]['api.Membership.get']['values'][0]['end_date']; + $endDate = CRM_Utils_Date::customFormat($endDate, + '%B %E%f, %Y' + ); + } + + return $endDate; + } + /** * Get the contribution as it is in the database before being updated. * From ec5480d9f0ed2fbce2ecb38723a3067da81b7bde Mon Sep 17 00:00:00 2001 From: Omar abu hussein Date: Fri, 16 Nov 2018 12:09:55 +0000 Subject: [PATCH 008/408] dev/core#288 Removing the date from the membership update notification --- CRM/Contribute/BAO/Contribution.php | 44 ++++++----------------------- 1 file changed, 9 insertions(+), 35 deletions(-) diff --git a/CRM/Contribute/BAO/Contribution.php b/CRM/Contribute/BAO/Contribution.php index c0c2916fabb5..854f73c24e1a 100644 --- a/CRM/Contribute/BAO/Contribution.php +++ b/CRM/Contribute/BAO/Contribution.php @@ -5213,23 +5213,16 @@ public static function transitionComponentWithReturnMessage($contributionId, $st $updatedStatusName = CRM_Utils_Array::value($updatedStatusId, CRM_Member_PseudoConstant::membershipStatus() ); - if ($updatedStatusName == 'Cancelled') { - $statusMsg .= "
" . ts("Membership for %1 has been Cancelled.", array(1 => $userDisplayName)); - } - elseif ($updatedStatusName == 'Expired') { - $statusMsg .= "
" . ts("Membership for %1 has been Expired.", array(1 => $userDisplayName)); - } - else { - $endDate = self::getFormattedMembershipEndDateFromContributionId($contributionId); - if ($endDate) { - $statusMsg .= "
" . ts("Membership for %1 has been updated. The membership End Date is %2.", - array( - 1 => $userDisplayName, - 2 => $endDate, - ) - ); - } + + $statusNameMsgPart = 'updated'; + switch ($updatedStatusName) { + case 'Cancelled': + case 'Expired': + $statusNameMsgPart = $updatedStatusName; + break; } + + $statusMsg .= "
" . ts("Membership for %1 has been %2.", array(1 => $userDisplayName, 2 => $statusNameMsgPart)); } if ($componentName == 'CiviEvent') { @@ -5263,25 +5256,6 @@ public static function transitionComponentWithReturnMessage($contributionId, $st return $statusMsg; } - private static function getFormattedMembershipEndDateFromContributionId($contributionId) { - $endDateResponse = civicrm_api3('MembershipPayment', 'get', [ - 'sequential' => 1, - 'contribution_id' => $contributionId, - 'api.Membership.get' => ['id' => '$value.id', 'return' => ['end_date']], - 'options' => ['limit' => 1, 'sort' => 'id DESC'], - ]); - - $endDate = NULL; - if (!empty($endDateResponse['values'][0]['api.Membership.get']['count'])) { - $endDate = $endDateResponse['values'][0]['api.Membership.get']['values'][0]['end_date']; - $endDate = CRM_Utils_Date::customFormat($endDate, - '%B %E%f, %Y' - ); - } - - return $endDate; - } - /** * Get the contribution as it is in the database before being updated. * From 0816f78c486829c5af80fbc6f17e56e6ac587fb6 Mon Sep 17 00:00:00 2001 From: Eli Lisseck Date: Mon, 26 Nov 2018 10:46:42 -0800 Subject: [PATCH 009/408] dev/core/544 add report support for filtering on multiple contact subtypes --- CRM/Report/Form.php | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/CRM/Report/Form.php b/CRM/Report/Form.php index 325eb064a440..37cf4013ba7e 100644 --- a/CRM/Report/Form.php +++ b/CRM/Report/Form.php @@ -2055,6 +2055,10 @@ public function whereClause(&$field, $op, $value, $min, $max) { break; } + //dev/core/544 Add report support for multiple contact subTypes + if ($field['name'] == 'contact_sub_type' && $clause) { + $clause = $this->whereSubtypeClause($field, $value, $op); + } if (!empty($field['group']) && $clause) { $clause = $this->whereGroupClause($field, $value, $op); } @@ -2073,6 +2077,27 @@ public function whereClause(&$field, $op, $value, $min, $max) { return $clause; } + /** + * Get SQL where clause for contact subtypes + * @param string $field + * @param mixed $value + * @param string $op SQL Operator + * + * @return string + */ + public function whereSubtypeClause($field, $value, $op) { + $clause = '( '; + $subtypeFilters = count($value); + for ($i = 0; $i < $subtypeFilters; $i++) { + $clause .= "{$field['dbAlias']} LIKE '%$value[$i]%'"; + if ($i !== ($subtypeFilters - 1)) { + $clause .= " OR "; + } + } + $clause .= ' )'; + return $clause; + } + /** * Get SQL where clause for a date field. * From a21270c09309062f6ab429566255953e229de0b6 Mon Sep 17 00:00:00 2001 From: Jon Goldberg Date: Wed, 5 Dec 2018 22:37:13 -0500 Subject: [PATCH 010/408] core#571 - check logged in OR checksum user permissions to edit recurring contributions --- CRM/Contribute/Form/CancelSubscription.php | 3 +-- CRM/Contribute/Form/UpdateBilling.php | 3 +-- CRM/Contribute/Form/UpdateSubscription.php | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/CRM/Contribute/Form/CancelSubscription.php b/CRM/Contribute/Form/CancelSubscription.php index ec4aabd93beb..4b633d808158 100644 --- a/CRM/Contribute/Form/CancelSubscription.php +++ b/CRM/Contribute/Form/CancelSubscription.php @@ -106,8 +106,7 @@ public function preProcess() { } if (!CRM_Core_Permission::check('edit contributions')) { - $userChecksum = CRM_Utils_Request::retrieve('cs', 'String', $this, FALSE); - if (!CRM_Contact_BAO_Contact_Utils::validChecksum($this->_subscriptionDetails->contact_id, $userChecksum)) { + if ($this->_subscriptionDetails->contact_id != $this->getContactID()) { CRM_Core_Error::fatal(ts('You do not have permission to cancel this recurring contribution.')); } $this->_selfService = TRUE; diff --git a/CRM/Contribute/Form/UpdateBilling.php b/CRM/Contribute/Form/UpdateBilling.php index da6604388bf0..0ef1fdfcb9c8 100644 --- a/CRM/Contribute/Form/UpdateBilling.php +++ b/CRM/Contribute/Form/UpdateBilling.php @@ -88,8 +88,7 @@ public function preProcess() { CRM_Core_Error::fatal('Required information missing.'); } if (!CRM_Core_Permission::check('edit contributions')) { - $userChecksum = CRM_Utils_Request::retrieve('cs', 'String', $this, FALSE); - if (!CRM_Contact_BAO_Contact_Utils::validChecksum($this->_subscriptionDetails->contact_id, $userChecksum)) { + if ($this->_subscriptionDetails->contact_id != $this->getContactID()) { CRM_Core_Error::fatal(ts('You do not have permission to cancel subscription.')); } $this->_selfService = TRUE; diff --git a/CRM/Contribute/Form/UpdateSubscription.php b/CRM/Contribute/Form/UpdateSubscription.php index 3ed257189bf3..4bea1cd892e0 100644 --- a/CRM/Contribute/Form/UpdateSubscription.php +++ b/CRM/Contribute/Form/UpdateSubscription.php @@ -124,8 +124,7 @@ public function preProcess() { } if (!CRM_Core_Permission::check('edit contributions')) { - $userChecksum = CRM_Utils_Request::retrieve('cs', 'String', $this, FALSE); - if (!CRM_Contact_BAO_Contact_Utils::validChecksum($this->_subscriptionDetails->contact_id, $userChecksum)) { + if ($this->_subscriptionDetails->contact_id != $this->getContactID()) { CRM_Core_Error::statusBounce(ts('You do not have permission to update subscription.')); } $this->_selfService = TRUE; From 5c19e6ace2da23c79da2cf6183bab4076f54ad50 Mon Sep 17 00:00:00 2001 From: Andrew Hunt Date: Wed, 12 Dec 2018 17:38:50 -0500 Subject: [PATCH 011/408] CiviMember: be more forgiving when `expired` status is disabled or missing --- CRM/Member/BAO/Membership.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CRM/Member/BAO/Membership.php b/CRM/Member/BAO/Membership.php index 897226518ba7..d16175821c62 100644 --- a/CRM/Member/BAO/Membership.php +++ b/CRM/Member/BAO/Membership.php @@ -2241,7 +2241,7 @@ public static function updateAllMembershipStatus() { // Tests for this function are in api_v3_JobTest. Please add tests for all updates. $updateCount = $processCount = self::updateDeceasedMembersStatuses(); - $allStatus = CRM_Member_PseudoConstant::membershipStatus(); + $allStatus = CRM_Member_BAO_Membership::buildOptions('status_id', 'get'); $allTypes = CRM_Member_PseudoConstant::membershipType(); // This query retrieves ALL memberships of active types. @@ -2262,7 +2262,7 @@ public static function updateAllMembershipStatus() { INNER JOIN civicrm_contact ON ( civicrm_membership.contact_id = civicrm_contact.id ) INNER JOIN civicrm_membership_type ON (civicrm_membership.membership_type_id = civicrm_membership_type.id AND civicrm_membership_type.is_active = 1) -WHERE civicrm_membership.is_test = 0 +WHERE civicrm_membership.is_test = 0 AND civicrm_contact.is_deceased = 0 "; $deceaseStatusId = array_search('Deceased', $allStatus); @@ -2272,7 +2272,8 @@ public static function updateAllMembershipStatus() { 'Cancelled', CRM_Member_PseudoConstant::membershipStatus(NULL, " name = 'Cancelled' ", 'name', FALSE, TRUE) ); - $expiredStatusId = array_search('Expired', $allStatus); + // Expired is not reserved so might not exist. A value of `0` won't break. + $expiredStatusId = array_search('Expired', $allStatus) ?: 0; $query = $baseQuery . " AND civicrm_membership.is_override IS NOT NULL AND civicrm_membership.status_override_end_date IS NOT NULL"; $dao1 = CRM_Core_DAO::executeQuery($query); From 1380445718fe1c52b98ba1b3cad7b293456baab8 Mon Sep 17 00:00:00 2001 From: Andrew Hunt Date: Wed, 12 Dec 2018 17:55:26 -0500 Subject: [PATCH 012/408] CiviMember: test to confirm it's okay to disable or delete `expired` status --- .../CRM/Member/BAO/MembershipStatusTest.php | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/phpunit/CRM/Member/BAO/MembershipStatusTest.php b/tests/phpunit/CRM/Member/BAO/MembershipStatusTest.php index 5e78ed95f593..5128a5ccfe3b 100644 --- a/tests/phpunit/CRM/Member/BAO/MembershipStatusTest.php +++ b/tests/phpunit/CRM/Member/BAO/MembershipStatusTest.php @@ -130,6 +130,40 @@ public function testDel() { $this->assertEquals(empty($result), TRUE, 'Verify membership status record deletion.'); } + public function testExpiredDisabled() { + $result = civicrm_api3('MembershipStatus', 'get', [ + 'label' => "Expired", + 'api.MembershipStatus.create' => ['is_active' => 0], + ]); + + // Disabling 'Expired' is OK. + $result = $this->callAPISuccess('job', 'process_membership', []); + + $result = civicrm_api3('MembershipStatus', 'get', [ + 'label' => "Expired", + 'api.MembershipStatus.delete' => [], + ]); + + // Deleting 'Expired' is OK. + $result = $this->callAPISuccess('job', 'process_membership', []); + + // Put things back like normal + $result = civicrm_api3('MembershipStatus', 'create', [ + 'name' => 'Expired', + 'label' => 'Expired', + 'start_event' => 'end_date', + 'start_event_adjust_unit' => 'month', + 'start_event_adjust_interval' => 1, + 'is_current_member' => 0, + 'is_admin' => 0, + 'weight' => 4, + 'is_default' => 0, + 'is_active' => 1, + 'is_reserved' => 0, + ]); + + } + public function testGetMembershipStatusByDate() { $params = array( 'name' => 'Current', From f257308bc15734ed32d574138e52b965c66b97db Mon Sep 17 00:00:00 2001 From: Pradeep Nayak Date: Fri, 4 Jan 2019 13:03:45 +0000 Subject: [PATCH 013/408] dev/core/issues/570, Check Dedupe fails for limited permission user --- CRM/Core/Permission.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CRM/Core/Permission.php b/CRM/Core/Permission.php index 7b73d6c9d96f..df6c0a03e446 100644 --- a/CRM/Core/Permission.php +++ b/CRM/Core/Permission.php @@ -975,6 +975,9 @@ public static function getEntityActionPermissions() { 'getquick' => array( array('access CiviCRM', 'access AJAX API'), ), + 'duplicatecheck' => array( + 'access CiviCRM', + ), ); // CRM-16963 - Permissions for country. From abe33166bcfb082571cce1805fe9312d36e542ab Mon Sep 17 00:00:00 2001 From: spalmstr Date: Mon, 28 Jan 2019 16:46:57 +0000 Subject: [PATCH 014/408] Core-688 - Contacts - New Email Fix Smarty/plugins/function.crmSetting.php --- CRM/Core/Smarty/plugins/function.crmSetting.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CRM/Core/Smarty/plugins/function.crmSetting.php b/CRM/Core/Smarty/plugins/function.crmSetting.php index 8a58e155c6eb..72411c998b3d 100644 --- a/CRM/Core/Smarty/plugins/function.crmSetting.php +++ b/CRM/Core/Smarty/plugins/function.crmSetting.php @@ -51,7 +51,8 @@ function smarty_function_crmSetting($params, &$smarty) { require_once 'api/api.php'; $result = civicrm_api('setting', 'getvalue', $params); unset($errorScope); - if ($result === FALSE) { + // Core-688 FALSE is returned by Boolean settings, thus giving false errors. + if ($result === NULL) { $smarty->trigger_error("Unknown error"); return NULL; } From 09b946d7ef93becd2895e2d29e57a7b4d667e4e5 Mon Sep 17 00:00:00 2001 From: Wouter H Date: Fri, 8 Feb 2019 22:58:12 +0100 Subject: [PATCH 015/408] Refs #706 Edit contribution : wrong decimal separator on total_amount for participant(s) --- CRM/Contribute/Form/Contribution.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/CRM/Contribute/Form/Contribution.php b/CRM/Contribute/Form/Contribution.php index e9c86d36de57..d1b1e06d12e6 100644 --- a/CRM/Contribute/Form/Contribution.php +++ b/CRM/Contribute/Form/Contribution.php @@ -366,16 +366,14 @@ public function setDefaultValues() { $this->assign('newCredit', CRM_Core_Config::isEnabledBackOfficeCreditCardPayments()); // Fix the display of the monetary value, CRM-4038. - if (isset($defaults['total_amount'])) { + if ($total_value = isset($defaults['total_amount'])) { + $defaults['total_amount'] = CRM_Utils_Money::format($defaults['total_amount'], NULL, '%a'); if (!empty($defaults['tax_amount'])) { $componentDetails = CRM_Contribute_BAO_Contribution::getComponentDetails($this->_id); if (!(CRM_Utils_Array::value('membership', $componentDetails) || CRM_Utils_Array::value('participant', $componentDetails))) { - $defaults['total_amount'] = CRM_Utils_Money::format($defaults['total_amount'] - $defaults['tax_amount'], NULL, '%a'); + $defaults['total_amount'] = CRM_Utils_Money::format($total_value - $defaults['tax_amount'], NULL, '%a'); } } - else { - $defaults['total_amount'] = CRM_Utils_Money::format($defaults['total_amount'], NULL, '%a'); - } } $amountFields = array('non_deductible_amount', 'fee_amount'); From 9ca472a10b050ec6702888338e787264d739f8b2 Mon Sep 17 00:00:00 2001 From: Pradeep Nayak Date: Thu, 14 Feb 2019 23:03:02 +0000 Subject: [PATCH 016/408] dev/core/issues/726, Fixed fatal error when searched using group type --- CRM/Contact/BAO/Query.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CRM/Contact/BAO/Query.php b/CRM/Contact/BAO/Query.php index 2db3cb961640..807734aa55fb 100644 --- a/CRM/Contact/BAO/Query.php +++ b/CRM/Contact/BAO/Query.php @@ -3018,6 +3018,10 @@ public function group($values) { $regularGroupIDs = array_merge($regularGroupIDs, $childGroupIds); } + if (empty($regularGroupIDs)) { + $regularGroupIDs = [0]; + } + // if $regularGroupIDs is populated with regular child group IDs // then change the mysql operator to desired if (count($regularGroupIDs) > 1) { From 2ba9854d19a3f0bb0c5ed633a138e64f27082a6c Mon Sep 17 00:00:00 2001 From: Pradeep Nayak Date: Tue, 19 Feb 2019 17:41:30 +0000 Subject: [PATCH 017/408] dev/core/issues/740, Show form on validation error --- templates/CRM/Note/Form/Note.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/CRM/Note/Form/Note.tpl b/templates/CRM/Note/Form/Note.tpl index 3643a368d6da..f43dbf704f60 100644 --- a/templates/CRM/Note/Form/Note.tpl +++ b/templates/CRM/Note/Form/Note.tpl @@ -25,4 +25,4 @@ *} {* This tpl is empty. Since notes is a simple form, the tpl is embedded within the parent tpl *} {* This might change in the future *} - +{include file="CRM/Contact/Page/View/Note.tpl"} From eaf39b47cbe8672a080b94ea7824188933b750c4 Mon Sep 17 00:00:00 2001 From: Mark Hanna Date: Thu, 14 Feb 2019 12:35:38 -0600 Subject: [PATCH 018/408] CiviCRM API, lookup state_province_id options based on country parameter if present, or default country, with test --- CRM/Core/BAO/Address.php | 2 +- api/v3/utils.php | 18 ++++++++++++++---- tests/phpunit/api/v3/AddressTest.php | 20 ++++++++++++++++++++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/CRM/Core/BAO/Address.php b/CRM/Core/BAO/Address.php index 4ada8f0bdffc..b2c594ad9ce5 100644 --- a/CRM/Core/BAO/Address.php +++ b/CRM/Core/BAO/Address.php @@ -1320,7 +1320,7 @@ public static function buildOptions($fieldName, $context = NULL, $props = array( $props['country_id'] = $config->defaultContactCountry; } } - if (!empty($props['country_id']) && $context !== 'validate') { + if (!empty($props['country_id'])) { $params['condition'] = 'country_id IN (' . implode(',', (array) $props['country_id']) . ')'; } break; diff --git a/api/v3/utils.php b/api/v3/utils.php index e21de9789802..52ffaedd0115 100644 --- a/api/v3/utils.php +++ b/api/v3/utils.php @@ -2069,7 +2069,11 @@ function _civicrm_api3_validate_integer(&$params, $fieldName, &$fieldInfo, $enti } } if (!empty($fieldInfo['pseudoconstant']) || !empty($fieldInfo['options'])) { - _civicrm_api3_api_match_pseudoconstant($fieldValue, $entity, $fieldName, $fieldInfo, $op); + $additional_lookup_params = array(); + if (strtolower($entity) == 'address' && $fieldName == 'state_province_id' && !empty($params['country_id'])) { + $additional_lookup_params = ['country_id' => $params['country_id']]; + } + _civicrm_api3_api_match_pseudoconstant($fieldValue, $entity, $fieldName, $fieldInfo, $op, $additional_lookup_params); } // After swapping options, ensure we have an integer(s) @@ -2213,10 +2217,11 @@ function _civicrm_api3_validate_string(&$params, &$fieldName, &$fieldInfo, $enti * @param string $fieldName : field name used in api call (not necessarily the canonical name) * @param array $fieldInfo : getfields meta-data * @param string $op + * @param array $additional_lookup_params * * @throws \API_Exception */ -function _civicrm_api3_api_match_pseudoconstant(&$fieldValue, $entity, $fieldName, $fieldInfo, $op = '=') { +function _civicrm_api3_api_match_pseudoconstant(&$fieldValue, $entity, $fieldName, $fieldInfo, $op = '=', $additional_lookup_params = array()) { if (in_array($op, array('>', '<', '>=', '<=', 'LIKE', 'NOT LIKE'))) { return; } @@ -2228,11 +2233,16 @@ function _civicrm_api3_api_match_pseudoconstant(&$fieldValue, $entity, $fieldNam // We need to get the options from the entity the field relates to. $entity = $fieldInfo['entity']; } - $options = civicrm_api($entity, 'getoptions', array( + $options_lookup_params = [ 'version' => 3, 'field' => $fieldInfo['name'], 'context' => 'validate', - )); + ]; + if (!empty($additional_lookup_params)) { + $options_lookup_params = array_merge($additional_lookup_params, $options_lookup_params); + } + $options = civicrm_api($entity, 'getoptions', $options_lookup_params); + $options = CRM_Utils_Array::value('values', $options, array()); } diff --git a/tests/phpunit/api/v3/AddressTest.php b/tests/phpunit/api/v3/AddressTest.php index a496071e778d..ad1c1c401ea3 100644 --- a/tests/phpunit/api/v3/AddressTest.php +++ b/tests/phpunit/api/v3/AddressTest.php @@ -390,4 +390,24 @@ public function testGetWithJoin() { $this->assertEquals('Individual', $result['contact_id.contact_type']); } + /** + * Test Address create with a state name that at least two countries have, e.g. Maryland, United States vs. Maryland, Liberia + * + * @see https://lab.civicrm.org/dev/core/issues/725 + */ + public function testCreateAddressStateProvinceIDCorrectForCountry() { + $params = $this->_params; + $params['sequential'] = 1; + $params['country_id'] = '1228'; // United States country id + $params['state_province_id'] = 'Maryland'; + $params['city'] = 'Baltimore'; + $params['street_address'] = '600 N Charles St.'; + $params['postal_code'] = '21201'; + unset($params['street_name']); + unset($params['street_number']); + $address1 = $this->callAPISuccess('address', 'create', $params); + // should find state_province_id of 1019, Maryland, United States ... NOT 3497, Maryland, Liberia + $this->assertEquals('1019', $address1['values'][0]['state_province_id']); + } + } From b8cb7e46ca7e5def15f41f0b0aa300f892c1a731 Mon Sep 17 00:00:00 2001 From: "Matthew Wire (MJW Consulting)" Date: Wed, 5 Dec 2018 18:10:54 +0000 Subject: [PATCH 019/408] Add 'Find Duplicates' hook to override duplicate checking when registering/contributing --- CRM/Contact/BAO/Contact.php | 23 +++++++++--- CRM/Event/Form/Registration/Register.php | 2 +- CRM/Utils/Hook.php | 23 ++++++++++++ tests/phpunit/CRM/Dedupe/DedupeFinderTest.php | 37 ++++++++++++++++++- 4 files changed, 78 insertions(+), 7 deletions(-) diff --git a/CRM/Contact/BAO/Contact.php b/CRM/Contact/BAO/Contact.php index a38e8409cb3a..8395ded73d9e 100644 --- a/CRM/Contact/BAO/Contact.php +++ b/CRM/Contact/BAO/Contact.php @@ -3594,14 +3594,25 @@ public function addSelectWhereClause() { * @param bool $checkPermissions * @param int $ruleGroupID * ID of the rule group to be used if an override is desirable. + * @param array $contextParams + * The context if relevant, eg. ['event_id' => X] * * @return array */ - public static function getDuplicateContacts($input, $contactType, $rule = 'Unsupervised', $excludedContactIDs = array(), $checkPermissions = TRUE, $ruleGroupID = NULL) { + public static function getDuplicateContacts($input, $contactType, $rule = 'Unsupervised', $excludedContactIDs = [], $checkPermissions = TRUE, $ruleGroupID = NULL, $contextParams = []) { $dedupeParams = CRM_Dedupe_Finder::formatParams($input, $contactType); $dedupeParams['check_permission'] = $checkPermissions; - $ids = CRM_Dedupe_Finder::dupesByParams($dedupeParams, $contactType, $rule, $excludedContactIDs, $ruleGroupID); - return $ids; + $dedupeParams['contact_type'] = $contactType; + $dedupeParams['rule'] = $rule; + $dedupeParams['rule_group_id'] = $ruleGroupID; + $dedupeParams['excluded_contact_ids'] = $excludedContactIDs; + $dedupeResults['ids'] = []; + $dedupeResults['handled'] = FALSE; + CRM_Utils_Hook::findDuplicates($dedupeParams, $dedupeResults, $contextParams); + if (!$dedupeResults['handled']) { + $dedupeResults['ids'] = CRM_Dedupe_Finder::dupesByParams($dedupeParams, $contactType, $rule, $excludedContactIDs, $ruleGroupID); + } + return $dedupeResults['ids']; } /** @@ -3618,11 +3629,13 @@ public static function getDuplicateContacts($input, $contactType, $rule = 'Unsup * @param bool $checkPermissions * @param int $ruleGroupID * ID of the rule group to be used if an override is desirable. + * @param array $contextParams + * The context if relevant, eg. ['event_id' => X] * * @return int|NULL */ - public static function getFirstDuplicateContact($input, $contactType, $rule = 'Unsupervised', $excludedContactIDs = array(), $checkPermissions = TRUE, $ruleGroupID = NULL) { - $ids = self::getDuplicateContacts($input, $contactType, $rule, $excludedContactIDs, $checkPermissions, $ruleGroupID); + public static function getFirstDuplicateContact($input, $contactType, $rule = 'Unsupervised', $excludedContactIDs = [], $checkPermissions = TRUE, $ruleGroupID = NULL, $contextParams = []) { + $ids = self::getDuplicateContacts($input, $contactType, $rule, $excludedContactIDs, $checkPermissions, $ruleGroupID, $contextParams); if (empty($ids)) { return NULL; } diff --git a/CRM/Event/Form/Registration/Register.php b/CRM/Event/Form/Registration/Register.php index da54819b40ce..d2ed584ad111 100644 --- a/CRM/Event/Form/Registration/Register.php +++ b/CRM/Event/Form/Registration/Register.php @@ -99,7 +99,7 @@ public static function getRegistrationContactID($fields, $form, $isAdditional) { $contactID = $form->getContactID(); } if (!$contactID && is_array($fields) && $fields) { - $contactID = CRM_Contact_BAO_Contact::getFirstDuplicateContact($fields, 'Individual', 'Unsupervised', array(), FALSE, CRM_Utils_Array::value('dedupe_rule_group_id', $form->_values['event'])); + $contactID = CRM_Contact_BAO_Contact::getFirstDuplicateContact($fields, 'Individual', 'Unsupervised', [], FALSE, CRM_Utils_Array::value('dedupe_rule_group_id', $form->_values['event']), ['event_id' => CRM_Utils_Array::value('id', $form->_values['event'])]); } return $contactID; } diff --git a/CRM/Utils/Hook.php b/CRM/Utils/Hook.php index 021ecc5d338f..e759533aa49d 100644 --- a/CRM/Utils/Hook.php +++ b/CRM/Utils/Hook.php @@ -1297,6 +1297,29 @@ public static function dupeQuery($obj, $type, &$query) { ); } + /** + * Check for duplicate contacts + * + * @param array $dedupeParams + * Array of params for finding duplicates: [ + * '{parameters returned by CRM_Dedupe_Finder::formatParams} + * 'check_permission' => TRUE/FALSE; + * 'contact_type' => $contactType; + * 'rule' = $rule; + * 'rule_group_id' => $ruleGroupID; + * 'excludedContactIDs' => $excludedContactIDs; + * @param array $dedupeResults + * Array of results ['handled' => TRUE/FALSE, 'ids' => array of IDs of duplicate contacts] + * @param array $contextParams + * The context if relevant, eg. ['event_id' => X] + * + * @return mixed + */ + public static function findDuplicates($dedupeParams, &$dedupeResults, $contextParams) { + return self::singleton() + ->invoke(array('dedupeParams', 'dedupeResults', 'contextParams'), $dedupeParams, $dedupeResults, $contextParams, self::$_nullObject, self::$_nullObject, self::$_nullObject, 'civicrm_findDuplicates'); + } + /** * This hook is called AFTER EACH email has been processed by the script bin/EmailProcessor.php * diff --git a/tests/phpunit/CRM/Dedupe/DedupeFinderTest.php b/tests/phpunit/CRM/Dedupe/DedupeFinderTest.php index 00382553ea67..f559aece3c18 100644 --- a/tests/phpunit/CRM/Dedupe/DedupeFinderTest.php +++ b/tests/phpunit/CRM/Dedupe/DedupeFinderTest.php @@ -169,6 +169,8 @@ public function testDupesByParams() { ), ); + $this->hookClass->setHook('civicrm_findDuplicates', array($this, 'hook_civicrm_findDuplicates')); + $count = 1; foreach ($params as $param) { @@ -192,7 +194,7 @@ public function testDupesByParams() { 'street_address' => 'Ambachtstraat 23', ); CRM_Core_TemporaryErrorScope::useException(); - $ids = CRM_Contact_BAO_Contact::getDuplicateContacts($fields, 'Individual', 'General'); + $ids = CRM_Contact_BAO_Contact::getDuplicateContacts($fields, 'Individual', 'General', [], TRUE, NULL, ['event_id' => 1]); // Check with default Individual-General rule $this->assertEquals(count($ids), 2, 'Check Individual-General rule for dupesByParams().'); @@ -203,6 +205,39 @@ public function testDupesByParams() { } } + /** + * Implements hook_civicrm_findDuplicates(). + * + * Locks in expected params + * + */ + public function hook_civicrm_findDuplicates($dedupeParams, &$dedupeResults, $contextParams) { + $expectedDedupeParams = [ + 'check_permission' => TRUE, + 'contact_type' => 'Individual', + 'rule' => 'General', + 'rule_group_id' => NULL, + 'excluded_contact_ids' => [], + ]; + foreach ($expectedDedupeParams as $key => $value) { + $this->assertEquals($value, $dedupeParams[$key]); + } + $expectedDedupeResults = [ + 'ids' => [], + 'handled' => FALSE, + ]; + foreach ($expectedDedupeResults as $key => $value) { + $this->assertEquals($value, $dedupeResults[$key]); + } + + $expectedContext = ['event_id' => 1]; + foreach ($expectedContext as $key => $value) { + $this->assertEquals($value, $contextParams[$key]); + } + + return $dedupeResults; + } + /** * Set up a group of dedupable contacts. */ From 8d369f66465e1802a49f71b6e0ae8c4cd137ebc5 Mon Sep 17 00:00:00 2001 From: Patrick Figel Date: Fri, 25 Jan 2019 16:35:01 +0100 Subject: [PATCH 020/408] dev/core#664 - CRM/Logging - Add indexes when updating log schema This change causes indexes set by the "alterLogTables" hook to be added regardless of whether the schema was changed. --- CRM/Logging/Schema.php | 18 +++++++++--------- tests/phpunit/api/v3/LoggingTest.php | 23 +++++++++++++++++++++++ 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/CRM/Logging/Schema.php b/CRM/Logging/Schema.php index c540c93fbf94..c75652fa784c 100644 --- a/CRM/Logging/Schema.php +++ b/CRM/Logging/Schema.php @@ -299,7 +299,7 @@ public function fixSchemaDifferences($enableLogging = FALSE) { * Update log tables structure. * * This function updates log tables to have the log_conn_id type of varchar - * and also implements any engine change to INNODB defined by the hooks. + * and also implements the engine change defined by the hook (i.e. INNODB). * * Note changing engine & adding hook-defined indexes, but not changing back * to ARCHIVE if engine has not been deliberately set (by hook) and not dropping @@ -312,15 +312,15 @@ public function updateLogTableSchema() { $tableSpec = $this->logTableSpec[$mainTable]; if (isset($tableSpec['engine']) && strtoupper($tableSpec['engine']) != $this->getEngineForLogTable($logTable)) { $alterSql[] = "ENGINE=" . $tableSpec['engine'] . " " . CRM_Utils_Array::value('engine_config', $tableSpec); - if (!empty($tableSpec['indexes'])) { - $indexes = $this->getIndexesForTable($logTable); - foreach ($tableSpec['indexes'] as $indexName => $indexSpec) { - if (!in_array($indexName, $indexes)) { - if (is_array($indexSpec)) { - $indexSpec = implode(" , ", $indexSpec); - } - $alterSql[] = "ADD INDEX {$indexName}($indexSpec)"; + } + if (!empty($tableSpec['indexes'])) { + $indexes = $this->getIndexesForTable($logTable); + foreach ($tableSpec['indexes'] as $indexName => $indexSpec) { + if (!in_array($indexName, $indexes)) { + if (is_array($indexSpec)) { + $indexSpec = implode(" , ", $indexSpec); } + $alterSql[] = "ADD INDEX {$indexName}($indexSpec)"; } } } diff --git a/tests/phpunit/api/v3/LoggingTest.php b/tests/phpunit/api/v3/LoggingTest.php index 0d373b93b37b..7ff702a307bd 100644 --- a/tests/phpunit/api/v3/LoggingTest.php +++ b/tests/phpunit/api/v3/LoggingTest.php @@ -157,6 +157,11 @@ public function testUpdateLogTableHookINNODB() { $this->assertEquals(array(), $spec['civicrm_contact']); $this->callAPISuccess('System', 'updatelogtables', array()); $this->checkINNODBLogTableCreated(); + // Check if API creates new indexes when they're added by hook + $this->hookClass->setHook('civicrm_alterLogTables', [$this, 'innodbLogTableSpecNewIndex']); + $this->callAPISuccess('System', 'updatelogtables', array()); + $this->checkINNODBLogTableCreated(); + $this->assertContains('KEY `index_log_user_id` (`log_user_id`)', $this->checkLogTableCreated()); } /** @@ -200,6 +205,24 @@ public function innodbLogTableSpec(&$logTableSpec) { ); } + /** + * Set log engine to InnoDB and add one index + * + * @param array $logTableSpec + */ + public function innodbLogTableSpecNewIndex(&$logTableSpec) { + $logTableSpec['civicrm_contact'] = array( + 'engine' => 'InnoDB', + 'engine_config' => 'ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4', + 'indexes' => array( + 'index_id' => 'id', + 'index_log_conn_id' => 'log_conn_id', + 'index_log_date' => 'log_date', + 'index_log_user_id' => 'log_user_id', // new index + ), + ); + } + /** * Check the log tables were created and look OK. */ From 98a9c88c9fa706a8cca7e446aee303f3e98c1edb Mon Sep 17 00:00:00 2001 From: Patrick Figel Date: Mon, 25 Feb 2019 15:30:28 +0100 Subject: [PATCH 021/408] CRM/Event - Fix participant note search parameter being ignored This fixes a bug in Search Builder that prevents criteria on the "Participant Note" field from being applied. --- CRM/Event/BAO/Query.php | 15 +++++--- tests/phpunit/CRM/Event/BAO/QueryTest.php | 42 +++++++++++++++++++++++ 2 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 tests/phpunit/CRM/Event/BAO/QueryTest.php diff --git a/CRM/Event/BAO/Query.php b/CRM/Event/BAO/Query.php index e43e38377cfe..f9e5e7129a83 100644 --- a/CRM/Event/BAO/Query.php +++ b/CRM/Event/BAO/Query.php @@ -187,10 +187,10 @@ public static function select(&$query) { //participant note if (!empty($query->_returnProperties['participant_note'])) { - $query->_select['participant_note'] = "civicrm_note.note as participant_note"; + $query->_select['participant_note'] = "participant_note.note as participant_note"; $query->_element['participant_note'] = 1; $query->_tables['participant_note'] = 1; - $query->_whereTables['civicrm_note'] = 1; + $query->_whereTables['participant_note'] = 1; } if (!empty($query->_returnProperties['participant_is_pay_later'])) { @@ -465,6 +465,13 @@ public static function whereClauseSingle(&$values, &$query) { list($op, $value) = CRM_Contact_BAO_Query::buildQillForFieldValue('CRM_Event_DAO_Event', $name, $value, $op, array('check_permission' => $checkPermission)); $query->_qill[$grouping][] = ts('%1 %2 %3', array(1 => $fields[$qillName]['title'], 2 => $op, 3 => $value)); return; + + case 'participant_note': + $query->_tables['civicrm_participant'] = $query->_whereTables['civicrm_participant'] = 1; + $query->_tables['participant_note'] = $query->_whereTables['participant_note'] = 1; + $query->_where[$grouping][] = CRM_Contact_BAO_Query::buildClause('participant_note.note', $op, $value, 'String'); + $query->_qill[$grouping][] = ts('%1 %2 %3', array(1 => $fields[$name]['title'], 2 => $op, 3 => $value)); + break; } } @@ -493,8 +500,8 @@ public static function from($name, $mode, $side) { break; case 'participant_note': - $from .= " $side JOIN civicrm_note ON ( civicrm_note.entity_table = 'civicrm_participant' AND - civicrm_participant.id = civicrm_note.entity_id )"; + $from .= " $side JOIN civicrm_note participant_note ON ( participant_note.entity_table = 'civicrm_participant' AND + civicrm_participant.id = participant_note.entity_id )"; break; case 'participant_status': diff --git a/tests/phpunit/CRM/Event/BAO/QueryTest.php b/tests/phpunit/CRM/Event/BAO/QueryTest.php new file mode 100644 index 000000000000..d95a7fbb0ed6 --- /dev/null +++ b/tests/phpunit/CRM/Event/BAO/QueryTest.php @@ -0,0 +1,42 @@ +eventCreate(); + $this->individualCreate([ + 'api.participant.create' => [ + 'event_id' => $event['id'], + 'note' => 'some_note', + ] + ]); + $this->individualCreate([ + 'api.participant.create' => [ + 'event_id' => $event['id'], + 'note' => 'some_other_note', + ] + ]); + $params = [ + [ + 0 => 'participant_note', + 1 => '=', + 2 => 'some_note', + 3 => 1, + 4 => 0, + ] + ]; + + $query = new CRM_Contact_BAO_Query($params, NULL, NULL, FALSE, FALSE, CRM_Contact_BAO_Query::MODE_CONTACTS); + $sql = $query->query(FALSE); + $result = CRM_Core_DAO::executeQuery(implode(' ', $sql)); + $this->assertEquals(1, $result->N); + } + +} From 0bf170de95dc539bead6b9a97dad9b03bd6be532 Mon Sep 17 00:00:00 2001 From: Wouter H Date: Wed, 27 Feb 2019 10:57:20 +0100 Subject: [PATCH 022/408] Changed $total_value declaration Fixed: this will make $total_value equal to 1 --- CRM/Contribute/Form/Contribution.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CRM/Contribute/Form/Contribution.php b/CRM/Contribute/Form/Contribution.php index d1b1e06d12e6..6edae916c5f2 100644 --- a/CRM/Contribute/Form/Contribution.php +++ b/CRM/Contribute/Form/Contribution.php @@ -366,8 +366,9 @@ public function setDefaultValues() { $this->assign('newCredit', CRM_Core_Config::isEnabledBackOfficeCreditCardPayments()); // Fix the display of the monetary value, CRM-4038. - if ($total_value = isset($defaults['total_amount'])) { - $defaults['total_amount'] = CRM_Utils_Money::format($defaults['total_amount'], NULL, '%a'); + if (isset($defaults['total_amount'])) { + $total_value = $defaults['total_amount']; + $defaults['total_amount'] = CRM_Utils_Money::format($total_value, NULL, '%a'); if (!empty($defaults['tax_amount'])) { $componentDetails = CRM_Contribute_BAO_Contribution::getComponentDetails($this->_id); if (!(CRM_Utils_Array::value('membership', $componentDetails) || CRM_Utils_Array::value('participant', $componentDetails))) { From ce023e5dafaca0df1df0b387d69e31e7e2b74c1f Mon Sep 17 00:00:00 2001 From: Jitendra Purohit Date: Fri, 1 Mar 2019 13:57:37 +0530 Subject: [PATCH 023/408] dev/core#771 - Smart group with uf_group_id does not load contacts with same search profile --- CRM/Contact/BAO/SavedSearch.php | 1 + .../CRM/Contact/BAO/SavedSearchTest.php | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/CRM/Contact/BAO/SavedSearch.php b/CRM/Contact/BAO/SavedSearch.php index 26af399caa02..67e95d095fb4 100644 --- a/CRM/Contact/BAO/SavedSearch.php +++ b/CRM/Contact/BAO/SavedSearch.php @@ -467,6 +467,7 @@ public static function saveSkippedElement(&$queryParams, $formValues) { 'operator', 'component_mode', 'display_relationship_type', + 'uf_group_id', ); foreach ($specialElements as $element) { if (!empty($formValues[$element])) { diff --git a/tests/phpunit/CRM/Contact/BAO/SavedSearchTest.php b/tests/phpunit/CRM/Contact/BAO/SavedSearchTest.php index ecf650fbd8ba..babcbe14092d 100644 --- a/tests/phpunit/CRM/Contact/BAO/SavedSearchTest.php +++ b/tests/phpunit/CRM/Contact/BAO/SavedSearchTest.php @@ -143,6 +143,37 @@ public function testDateRange() { $this->assertEquals('01/01/2009', $result['participant_register_date_low']); $this->assertEquals('01/01/2018', $result['participant_register_date_high']); } + + /** + * Test if skipped elements are correctly + * stored and retrieved as formvalues. + */ + public function testSkippedElements() { + $relTypeID = $this->relationshipTypeCreate(); + $savedSearch = new CRM_Contact_BAO_SavedSearch(); + $formValues = array( + 'operator' => 'AND', + 'title' => 'testsmart', + 'radio_ts' => 'ts_all', + 'component_mode' => CRM_Contact_BAO_Query::MODE_CONTACTS, + 'display_relationship_type' => "{$relTypeID}_a_b", + 'uf_group_id' => 1, + ); + $queryParams = array(); + CRM_Contact_BAO_SavedSearch::saveSkippedElement($queryParams, $formValues); + $savedSearch->form_values = serialize($queryParams); + $savedSearch->save(); + + $result = CRM_Contact_BAO_SavedSearch::getFormValues(CRM_Core_DAO::singleValueQuery('SELECT LAST_INSERT_ID()')); + $expectedResult = array( + 'operator' => 'AND', + 'component_mode' => CRM_Contact_BAO_Query::MODE_CONTACTS, + 'display_relationship_type' => "{$relTypeID}_a_b", + 'uf_group_id' => 1, + ); + $this->checkArrayEquals($result, $expectedResult); + } + /** * Test if relative dates are stored correctly * in civicrm_saved_search table. From 54ec483944e1891efaed51f42c1814e60e0f6c41 Mon Sep 17 00:00:00 2001 From: eileen Date: Thu, 7 Mar 2019 18:07:23 +1300 Subject: [PATCH 024/408] [REF] small cleanups on payment.create flow. In the interests of keeping some momentum I added this small cleanup which does 3 things 1) uses the preferred function to get 'from_financial_account_id', 2 moves a line of code to get participantID & 3 removes the conditionals around is_payment. This probably needs the most double checking but I believe recordPartialPaymet used to be called from places other than Payment.create so it may not have always been handling a payment - however it I can't see a case for it not be is_payment now --- CRM/Contribute/BAO/Contribution.php | 17 +++++------------ CRM/Financial/BAO/Payment.php | 7 +++---- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/CRM/Contribute/BAO/Contribution.php b/CRM/Contribute/BAO/Contribution.php index b89d304cee71..b9fd75d7324e 100644 --- a/CRM/Contribute/BAO/Contribution.php +++ b/CRM/Contribute/BAO/Contribution.php @@ -4716,8 +4716,7 @@ public function loadRelatedMembershipObjects($ids = []) { public static function recordPartialPayment($contribution, $params) { $balanceTrxnParams['to_financial_account_id'] = self::getToFinancialAccount($contribution, $params); - $fromFinancialAccountId = CRM_Contribute_PseudoConstant::getRelationalFinancialAccount($contribution['financial_type_id'], 'Accounts Receivable Account is'); - $balanceTrxnParams['from_financial_account_id'] = $fromFinancialAccountId; + $balanceTrxnParams['from_financial_account_id'] = CRM_Financial_BAO_FinancialAccount::getFinancialAccountForFinancialTypeByRelationship($contribution['financial_type_id'], 'Accounts Receivable Account is'); $balanceTrxnParams['total_amount'] = $params['total_amount']; $balanceTrxnParams['contribution_id'] = $params['contribution_id']; $balanceTrxnParams['trxn_date'] = CRM_Utils_Array::value('trxn_date', $params, CRM_Utils_Array::value('contribution_receive_date', $params, date('YmdHis'))); @@ -4728,18 +4727,12 @@ public static function recordPartialPayment($contribution, $params) { $balanceTrxnParams['status_id'] = CRM_Core_PseudoConstant::getKey('CRM_Core_BAO_FinancialTrxn', 'status_id', 'Completed'); $balanceTrxnParams['payment_instrument_id'] = CRM_Utils_Array::value('payment_instrument_id', $params, $contribution['payment_instrument_id']); $balanceTrxnParams['check_number'] = CRM_Utils_Array::value('check_number', $params); - - // @todo the logic of this section seems very wrong. This code is ONLY reached from the Payment.create - // routine so is_payment should ALWAYS be true - $contributionStatuses = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'name'); - $statusId = array_search('Completed', $contributionStatuses); - if ($fromFinancialAccountId != NULL && - ($statusId == array_search('Completed', $contributionStatuses) || $statusId == array_search('Partially paid', $contributionStatuses)) - ) { - $balanceTrxnParams['is_payment'] = 1; - } + $balanceTrxnParams['is_payment'] = 1; if (!empty($params['payment_processor'])) { + // I can't find evidence this is passed in - I was gonna just remove it but decided to deprecate as I see self::getToFinancialAccount + // also anticipates it. + CRM_Core_Error::deprecatedFunctionWarning('passing payment_processor is deprecated - use payment_processor_id'); $balanceTrxnParams['payment_processor_id'] = $params['payment_processor']; } return CRM_Core_BAO_FinancialTrxn::create($balanceTrxnParams); diff --git a/CRM/Financial/BAO/Payment.php b/CRM/Financial/BAO/Payment.php index e7d3aff4df66..84e01390b827 100644 --- a/CRM/Financial/BAO/Payment.php +++ b/CRM/Financial/BAO/Payment.php @@ -358,10 +358,6 @@ public static function recordRefundPayment($contributionId, $trxnData, $updateSt public static function recordPayment($contributionId, $trxnData, $participantId) { list($contributionDAO, $params) = self::getContributionAndParamsInFormatForRecordFinancialTransaction($contributionId); - if (!$participantId) { - $participantId = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_ParticipantPayment', $contributionId, 'participant_id', 'contribution_id'); - } - $trxnData['trxn_date'] = !empty($trxnData['trxn_date']) ? $trxnData['trxn_date'] : date('YmdHis'); $params['payment_instrument_id'] = CRM_Utils_Array::value('payment_instrument_id', $trxnData, CRM_Utils_Array::value('payment_instrument_id', $params)); @@ -428,6 +424,9 @@ public static function recordPayment($contributionId, $trxnData, $participantId) // which in 'Partial Paid' => 'Completed' is not useful, instead specific financial record updates // are coded below i.e. just updating financial_item status to 'Paid' + if (!$participantId) { + $participantId = CRM_Core_DAO::getFieldValue('CRM_Event_DAO_ParticipantPayment', $contributionId, 'participant_id', 'contribution_id'); + } if ($participantId) { // update participant status $participantStatuses = CRM_Event_PseudoConstant::participantStatus(); From 882bd8cb3d845f5545248662a1a031ac506eca35 Mon Sep 17 00:00:00 2001 From: "Matthew Wire (MJW Consulting)" Date: Mon, 4 Mar 2019 14:11:44 +0000 Subject: [PATCH 025/408] Add billingblock region to event registration confirm/thankyou to match contribution confirm/thankyou --- templates/CRM/Event/Form/Registration/Confirm.tpl | 14 ++++++++------ templates/CRM/Event/Form/Registration/ThankYou.tpl | 14 ++++++++------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/templates/CRM/Event/Form/Registration/Confirm.tpl b/templates/CRM/Event/Form/Registration/Confirm.tpl index f5d857828616..26398922f981 100644 --- a/templates/CRM/Event/Form/Registration/Confirm.tpl +++ b/templates/CRM/Event/Form/Registration/Confirm.tpl @@ -168,17 +168,19 @@ {/if} {if $contributeMode eq 'direct' and ! $is_pay_later and !$isAmountzero and !$isOnWaitlist and !$isRequireApproval} + {crmRegion name="event-confirm-billing-block"}
-
- {ts}Credit Card Information{/ts} -
-
-
{$credit_card_type}
+
+ {ts}Credit Card Information{/ts} +
+
+
{$credit_card_type}
{$credit_card_number}
-
{ts}Expires{/ts}: {$credit_card_exp_date|truncate:7:''|crmDate}
+
{if $credit_card_exp_date}{ts}Expires{/ts}: {$credit_card_exp_date|truncate:7:''|crmDate}{/if}
+ {/crmRegion} {/if} {if $contributeMode NEQ 'notify'} {* In 'notify mode, contributor is taken to processor payment forms next *} diff --git a/templates/CRM/Event/Form/Registration/ThankYou.tpl b/templates/CRM/Event/Form/Registration/ThankYou.tpl index cdf500de279f..72d6aa06b28b 100644 --- a/templates/CRM/Event/Form/Registration/ThankYou.tpl +++ b/templates/CRM/Event/Form/Registration/ThankYou.tpl @@ -189,17 +189,19 @@ {/if} {if $contributeMode eq 'direct' and $paidEvent and ! $is_pay_later and !$isAmountzero and !$isOnWaitlist and !$isRequireApproval} + {crmRegion name="event-thankyou-billing-block"}
-
- {ts}Credit Card Information{/ts} -
-
-
{$credit_card_type}
+
+ {ts}Credit Card Information{/ts} +
+
+
{$credit_card_type}
{$credit_card_number}
-
{ts}Expires{/ts}: {$credit_card_exp_date|truncate:7:''|crmDate}
+
{if $credit_card_exp_date}{ts}Expires{/ts}: {$credit_card_exp_date|truncate:7:''|crmDate}{/if}
+ {/crmRegion} {/if} {if $event.thankyou_footer_text} From a4b6430d72c4324839e26211841047c26f28afd8 Mon Sep 17 00:00:00 2001 From: "Matthew Wire (MJW Consulting)" Date: Thu, 7 Mar 2019 19:43:28 +0000 Subject: [PATCH 026/408] Minor cleanup to contribution confirm billingblock for consistency --- templates/CRM/Contribute/Form/Contribution/Confirm.tpl | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/templates/CRM/Contribute/Form/Contribution/Confirm.tpl b/templates/CRM/Contribute/Form/Contribution/Confirm.tpl index bb48dddede92..ca76503344cf 100644 --- a/templates/CRM/Contribute/Form/Contribution/Confirm.tpl +++ b/templates/CRM/Contribute/Form/Contribution/Confirm.tpl @@ -281,10 +281,9 @@ {/if} {else}
-
{$credit_card_type|escape}
-
{$credit_card_number|escape}
-
{if $credit_card_exp_date}{ts}Expires{/ts}: {$credit_card_exp_date|truncate:7:''|crmDate}{/if}
+
{$credit_card_type}
+
{$credit_card_number}
+
{if $credit_card_exp_date}{ts}Expires{/ts}: {$credit_card_exp_date|truncate:7:''|crmDate}{/if}
{/if} From eb48403e8f35f3295c7ab7481dc49c293f21be17 Mon Sep 17 00:00:00 2001 From: "wouter.hechtermans" Date: Fri, 8 Mar 2019 14:39:25 +0100 Subject: [PATCH 027/408] refs issue 788 added extra & sign. --- CRM/Contribute/Form/Contribution/Main.php | 2 +- CRM/Event/Form/Registration/Register.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CRM/Contribute/Form/Contribution/Main.php b/CRM/Contribute/Form/Contribution/Main.php index 8be60178b1cf..89de770a1a45 100644 --- a/CRM/Contribute/Form/Contribution/Main.php +++ b/CRM/Contribute/Form/Contribution/Main.php @@ -897,7 +897,7 @@ public static function formRule($fields, $files, $self) { // return if this is express mode $config = CRM_Core_Config::singleton(); if ($self->_paymentProcessor && - $self->_paymentProcessor['billing_mode'] & CRM_Core_Payment::BILLING_MODE_BUTTON + $self->_paymentProcessor['billing_mode'] && CRM_Core_Payment::BILLING_MODE_BUTTON ) { if (!empty($fields[$self->_expressButtonName . '_x']) || !empty($fields[$self->_expressButtonName . '_y']) || CRM_Utils_Array::value($self->_expressButtonName, $fields) diff --git a/CRM/Event/Form/Registration/Register.php b/CRM/Event/Form/Registration/Register.php index da54819b40ce..ef96be1ebefa 100644 --- a/CRM/Event/Form/Registration/Register.php +++ b/CRM/Event/Form/Registration/Register.php @@ -1147,7 +1147,7 @@ public function postProcess() { $this->handlePreApproval($params); } elseif ($this->_paymentProcessor && - $this->_paymentProcessor['billing_mode'] & CRM_Core_Payment::BILLING_MODE_NOTIFY + $this->_paymentProcessor['billing_mode'] && CRM_Core_Payment::BILLING_MODE_NOTIFY ) { // The concept of contributeMode is deprecated - but still needs removal from the message templates. $this->set('contributeMode', 'notify'); From 5e3148f4fa983a506f3196521427b58e22a7f150 Mon Sep 17 00:00:00 2001 From: "wouter.hechtermans" Date: Fri, 8 Mar 2019 18:17:37 +0100 Subject: [PATCH 028/408] refs issue 788 removed extra & sign, added int casting. --- CRM/Contribute/Form/Contribution/Main.php | 2 +- CRM/Event/Form/Registration/Register.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CRM/Contribute/Form/Contribution/Main.php b/CRM/Contribute/Form/Contribution/Main.php index 89de770a1a45..0115fab9a93a 100644 --- a/CRM/Contribute/Form/Contribution/Main.php +++ b/CRM/Contribute/Form/Contribution/Main.php @@ -897,7 +897,7 @@ public static function formRule($fields, $files, $self) { // return if this is express mode $config = CRM_Core_Config::singleton(); if ($self->_paymentProcessor && - $self->_paymentProcessor['billing_mode'] && CRM_Core_Payment::BILLING_MODE_BUTTON + (int) $self->_paymentProcessor['billing_mode'] & CRM_Core_Payment::BILLING_MODE_BUTTON ) { if (!empty($fields[$self->_expressButtonName . '_x']) || !empty($fields[$self->_expressButtonName . '_y']) || CRM_Utils_Array::value($self->_expressButtonName, $fields) diff --git a/CRM/Event/Form/Registration/Register.php b/CRM/Event/Form/Registration/Register.php index ef96be1ebefa..1cc5f83235c2 100644 --- a/CRM/Event/Form/Registration/Register.php +++ b/CRM/Event/Form/Registration/Register.php @@ -1147,7 +1147,7 @@ public function postProcess() { $this->handlePreApproval($params); } elseif ($this->_paymentProcessor && - $this->_paymentProcessor['billing_mode'] && CRM_Core_Payment::BILLING_MODE_NOTIFY + (int) $this->_paymentProcessor['billing_mode'] & CRM_Core_Payment::BILLING_MODE_NOTIFY ) { // The concept of contributeMode is deprecated - but still needs removal from the message templates. $this->set('contributeMode', 'notify'); From 90e5222f20d2e77baa678e540540fcb0077f036e Mon Sep 17 00:00:00 2001 From: mark burdett Date: Mon, 25 Feb 2019 04:09:05 -0800 Subject: [PATCH 029/408] Use TempTable methods; add getCreateSql() method for debugging purposes. --- CRM/Contact/Form/Search/Custom/DateAdded.php | 62 ++++---------------- CRM/Contact/Form/Task.php | 10 ++-- CRM/Utils/SQL/TempTable.php | 11 ++++ 3 files changed, 27 insertions(+), 56 deletions(-) diff --git a/CRM/Contact/Form/Search/Custom/DateAdded.php b/CRM/Contact/Form/Search/Custom/DateAdded.php index 55a599b9665e..fb6f378bf308 100644 --- a/CRM/Contact/Form/Search/Custom/DateAdded.php +++ b/CRM/Contact/Form/Search/Custom/DateAdded.php @@ -32,7 +32,6 @@ */ class CRM_Contact_Form_Search_Custom_DateAdded extends CRM_Contact_Form_Search_Custom_Base implements CRM_Contact_Form_Search_Interface { - protected $_debug = 0; protected $_aclFrom = NULL; protected $_aclWhere = NULL; @@ -179,18 +178,15 @@ public function all( */ public function from() { //define table name - $this->_datesTable = CRM_Utils_SQL_TempTable::build()->setCategory('dates')->getName(); - $this->_xgTable = CRM_Utils_SQL_TempTable::build()->setCategory('xg')->getName(); - $this->_igTable = CRM_Utils_SQL_TempTable::build()->setCategory('ig')->getName(); + $datesTable = CRM_Utils_SQL_TempTable::build()->setCategory('dates')->setMemory(); + $this->_datesTable = $datesTable->getName(); + $xgTable = CRM_Utils_SQL_TempTable::build()->setCategory('xg')->setMemory(); + $this->_xgTable = $xgTable->getName(); + $igTable = CRM_Utils_SQL_TempTable::build()->setCategory('ig')->setMemory(); + $this->_igTable = $igTable->getName(); //grab the contacts added in the date range first - $sql = "CREATE TEMPORARY TABLE {$this->_datesTable} ( id int primary key, date_added date ) ENGINE=HEAP"; - if ($this->_debug > 0) { - print "-- Date range query:
";
-      print "$sql;";
-      print "
"; - } - CRM_Core_DAO::executeQuery($sql); + $datesTable->createWithColumns('id int primary key, date_added date'); $startDate = !empty($this->_formValues['start_date']) ? $this->_formValues['start_date'] : date('Y-m-d'); $endDateFix = NULL; @@ -213,12 +209,6 @@ public function from() { date_added >= '$startDate 00:00:00' $endDateFix"; - if ($this->_debug > 0) { - print "-- Date range query:
";
-      print "$dateRange;";
-      print "
"; - } - CRM_Core_DAO::executeQuery($dateRange, CRM_Core_DAO::$_nullArray); // Only include groups in the search query of one or more Include OR Exclude groups has been selected. @@ -251,10 +241,8 @@ public function from() { $xGroups = 0; } - $sql = "DROP TEMPORARY TABLE IF EXISTS {$this->_xgTable}"; - CRM_Core_DAO::executeQuery($sql, CRM_Core_DAO::$_nullArray); - $sql = "CREATE TEMPORARY TABLE {$this->_xgTable} ( contact_id int primary key) ENGINE=HEAP"; - CRM_Core_DAO::executeQuery($sql, CRM_Core_DAO::$_nullArray); + $xgTable->drop(); + $xgTable->createWithColumns('contact_id int primary key'); //used only when exclude group is selected if ($xGroups != 0) { @@ -286,20 +274,10 @@ public function from() { } } - $sql = "DROP TEMPORARY TABLE IF EXISTS {$this->_igTable}"; - CRM_Core_DAO::executeQuery($sql, CRM_Core_DAO::$_nullArray); - $sql = "CREATE TEMPORARY TABLE {$this->_igTable} - ( id int PRIMARY KEY AUTO_INCREMENT, + $igTable->drop(); + $igTable->createWithColumns('id int PRIMARY KEY AUTO_INCREMENT, contact_id int, - group_names varchar(64)) ENGINE=HEAP"; - - if ($this->_debug > 0) { - print "-- Include groups query:
";
-        print "$sql;";
-        print "
"; - } - - CRM_Core_DAO::executeQuery($sql, CRM_Core_DAO::$_nullArray); + group_names varchar(64)'); $includeGroup = "INSERT INTO {$this->_igTable} (contact_id, group_names) SELECT d.id as contact_id, civicrm_group.name as group_name @@ -323,12 +301,6 @@ public function from() { $includeGroup .= " AND {$this->_xgTable}.contact_id IS null"; } - if ($this->_debug > 0) { - print "-- Include groups query:
";
-        print "$includeGroup;";
-        print "
"; - } - CRM_Core_DAO::executeQuery($includeGroup, CRM_Core_DAO::$_nullArray); //search for smart group contacts @@ -357,22 +329,12 @@ public function from() { $smartSql"; CRM_Core_DAO::executeQuery($smartGroupQuery, CRM_Core_DAO::$_nullArray); - if ($this->_debug > 0) { - print "-- Smart group query:
";
-            print "$smartGroupQuery;";
-            print "
"; - } $insertGroupNameQuery = "UPDATE IGNORE {$this->_igTable} SET group_names = (SELECT title FROM civicrm_group WHERE civicrm_group.id = $values) WHERE {$this->_igTable}.contact_id IS NOT NULL AND {$this->_igTable}.group_names IS NULL"; CRM_Core_DAO::executeQuery($insertGroupNameQuery, CRM_Core_DAO::$_nullArray); - if ($this->_debug > 0) { - print "-- Smart group query:
";
-            print "$insertGroupNameQuery;";
-            print "
"; - } } } } diff --git a/CRM/Contact/Form/Task.php b/CRM/Contact/Form/Task.php index 74a62c32a00f..857d1b22b00a 100644 --- a/CRM/Contact/Form/Task.php +++ b/CRM/Contact/Form/Task.php @@ -153,12 +153,10 @@ public static function preProcessCommon(&$form) { $form->assign('taskName', CRM_Utils_Array::value($form->_task, $crmContactTaskTasks)); if ($useTable) { - $form->_componentTable = CRM_Utils_SQL_TempTable::build()->setCategory('tskact')->setDurable()->setId($qfKey)->getName(); - $sql = " DROP TABLE IF EXISTS {$form->_componentTable}"; - CRM_Core_DAO::executeQuery($sql); - - $sql = "CREATE TABLE {$form->_componentTable} ( contact_id int primary key) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci"; - CRM_Core_DAO::executeQuery($sql); + $tempTable = CRM_Utils_SQL_TempTable::build()->setCategory('tskact')->setDurable()->setId($qfKey)->setUtf8(); + $form->_componentTable = $tempTable->getName(); + $tempTable->drop(); + $tempTable->createWithColumns('contact_id int primary key'); } // all contacts or action = save a search diff --git a/CRM/Utils/SQL/TempTable.php b/CRM/Utils/SQL/TempTable.php index 7f1955003c7e..444f1ff92b5c 100644 --- a/CRM/Utils/SQL/TempTable.php +++ b/CRM/Utils/SQL/TempTable.php @@ -88,6 +88,8 @@ class CRM_Utils_SQL_TempTable { protected $memory; + protected $createSql; + /** * @return CRM_Utils_SQL_TempTable */ @@ -138,6 +140,7 @@ public function createWithQuery($selectQuery) { ($selectQuery instanceof CRM_Utils_SQL_Select ? $selectQuery->toSQL() : $selectQuery) ); CRM_Core_DAO::executeQuery($sql, array(), TRUE, NULL, TRUE, FALSE); + $this->createSql = $sql; return $this; } @@ -157,6 +160,7 @@ public function createWithColumns($columns) { $this->utf8 ? self::UTF8 : '' ); CRM_Core_DAO::executeQuery($sql, array(), TRUE, NULL, TRUE, FALSE); + $this->createSql = $sql; return $this; } @@ -208,6 +212,13 @@ public function getId() { return $this->id; } + /** + * @return string|NULL + */ + public function getCreateSql() { + return $this->createSql; + } + /** * @return bool */ From 830bab406b317ecc3a687e391bf4798e85423ece Mon Sep 17 00:00:00 2001 From: "Matthew Wire (MJW Consulting)" Date: Fri, 8 Mar 2019 12:05:57 +0000 Subject: [PATCH 030/408] Extract case action links into a separate function to facilitate refactoring --- CRM/Case/BAO/Case.php | 153 +++++++++++++++++++++++------------------- 1 file changed, 83 insertions(+), 70 deletions(-) diff --git a/CRM/Case/BAO/Case.php b/CRM/Case/BAO/Case.php index fb84b9ce3546..09e2cb6fe09c 100644 --- a/CRM/Case/BAO/Case.php +++ b/CRM/Case/BAO/Case.php @@ -1062,48 +1062,22 @@ public static function getCaseActivity($caseID, &$params, $contactID, $context = $activityTypes = CRM_Case_PseudoConstant::caseActivityType(FALSE, TRUE); - $url = CRM_Utils_System::url("civicrm/case/activity", - "reset=1&cid={$contactID}&caseid={$caseID}", FALSE, NULL, FALSE - ); - - $contextUrl = ''; - if ($context == 'fulltext') { - $contextUrl = "&context={$context}"; - } - $editUrl = "{$url}&action=update{$contextUrl}"; - $deleteUrl = "{$url}&action=delete{$contextUrl}"; - $restoreUrl = "{$url}&action=renew{$contextUrl}"; - $viewTitle = ts('View activity'); - - $emailActivityTypeIDs = array( - 'Email' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Email'), - 'Inbound Email' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Inbound Email'), - ); - - $caseDeleted = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_Case', $caseID, 'is_deleted'); - $compStatusValues = array_keys( CRM_Activity_BAO_Activity::getStatusesByType(CRM_Activity_BAO_Activity::COMPLETED) + CRM_Activity_BAO_Activity::getStatusesByType(CRM_Activity_BAO_Activity::CANCELLED) ); if (!$userID) { - $session = CRM_Core_Session::singleton(); - $userID = $session->get('userID'); + $userID = CRM_Core_Session::getLoggedInContactID(); } - $caseActivities = array(); + $caseActivities = []; while ($dao->fetch()) { $caseActivityId = $dao->id; - $allowView = self::checkPermission($caseActivityId, 'view', $dao->activity_type_id, $userID); - $allowEdit = self::checkPermission($caseActivityId, 'edit', $dao->activity_type_id, $userID); - $allowDelete = self::checkPermission($caseActivityId, 'delete', $dao->activity_type_id, $userID); - - //do not have sufficient permission - //to access given case activity record. - if (!$allowView && !$allowEdit && !$allowDelete) { + //Do we have permission to access given case activity record. + if (!self::checkPermission($caseActivityId, 'view', $dao->activity_type_id, $userID)) { continue; } @@ -1176,46 +1150,8 @@ public static function getCaseActivity($caseID, &$params, $contactID, $context = // Activity Status Label for Case activities list $caseActivities[$caseActivityId]['status_id'] = CRM_Core_PseudoConstant::getLabel('CRM_Activity_BAO_Activity', 'activity_status_id', $dao->status); - // FIXME: Why are we not using CRM_Core_Action for these links? This is too much manual work and likely to get out-of-sync with core markup. - $url = ""; - $css = 'class="action-item crm-hover-button"'; - if ($allowView) { - $viewUrl = CRM_Utils_System::url('civicrm/case/activity/view', array('cid' => $contactID, 'aid' => $caseActivityId)); - $url = '' . ts('View') . ''; - } - $additionalUrl = "&id={$caseActivityId}"; - if (!$dao->deleted) { - //hide edit link of activity type email.CRM-4530. - if (!in_array($dao->type, $emailActivityTypeIDs)) { - //hide Edit link if activity type is NOT editable (special case activities).CRM-5871 - if ($allowEdit) { - $url .= '' . ts('Edit') . ' '; - } - } - if ($allowDelete) { - $url .= ' ' . ts('Delete') . ''; - } - } - elseif (!$caseDeleted) { - $url = ' ' . ts('Restore') . ''; - $caseActivities[$caseActivityId]['status_id'] = $caseActivities[$caseActivityId]['status_id'] . '
(deleted)'; - } - - //check for operations. - if (self::checkPermission($caseActivityId, 'Move To Case', $dao->activity_type_id)) { - $url .= ' ' . ts('Move To Case') . ' '; - } - if (self::checkPermission($caseActivityId, 'Copy To Case', $dao->activity_type_id)) { - $url .= ' ' . ts('Copy To Case') . ' '; - } - // if there are file attachments we will return how many and, if only one, add a link to it - if (!empty($dao->attachment_ids)) { - $attachmentIDs = array_unique(explode(',', $dao->attachment_ids)); - $caseActivities[$caseActivityId]['no_attachments'] = count($attachmentIDs); - $url .= implode(' ', CRM_Core_BAO_File::paperIconAttachment('civicrm_activity', $caseActivityId)); - } - - $caseActivities[$caseActivityId]['links'] = $url; + $caseActivities[$caseActivityId] + = self::addCaseActivityLinks($caseID, $contactID, $userID, $context, $dao, $caseActivities[$caseActivityId]); } $caseActivitiesDT = array(); @@ -1226,6 +1162,83 @@ public static function getCaseActivity($caseID, &$params, $contactID, $context = return $caseActivitiesDT; } + /** + * FIXME: This is a transitional function to facilitate a refactor of this to use CRM_Core_Action and actionLinks + * Add the set of "actionLinks" to the case activity + * + * @param int $caseID + * @param int $contactID + * @param int $userID + * @param string $context + * @param \CRM_Core_DAO $dao + * @param array $caseActivity + * + * @return array caseActivity + */ + public static function addCaseActivityLinks($caseID, $contactID, $userID, $context, $dao, $caseActivity) { + // FIXME: Why are we not using CRM_Core_Action for these links? This is too much manual work and likely to get out-of-sync with core markup. + $caseActivityId = $dao->id; + $allowView = self::checkPermission($caseActivityId, 'view', $dao->activity_type_id, $userID); + $allowEdit = self::checkPermission($caseActivityId, 'edit', $dao->activity_type_id, $userID); + $allowDelete = self::checkPermission($caseActivityId, 'delete', $dao->activity_type_id, $userID); + $emailActivityTypeIDs = [ + 'Email' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Email'), + 'Inbound Email' => CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', 'activity_type_id', 'Inbound Email'), + ]; + $url = CRM_Utils_System::url("civicrm/case/activity", + "reset=1&cid={$contactID}&caseid={$caseID}", FALSE, NULL, FALSE + ); + $contextUrl = ''; + if ($context == 'fulltext') { + $contextUrl = "&context={$context}"; + } + $editUrl = "{$url}&action=update{$contextUrl}"; + $deleteUrl = "{$url}&action=delete{$contextUrl}"; + $restoreUrl = "{$url}&action=renew{$contextUrl}"; + $viewTitle = ts('View activity'); + $caseDeleted = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_Case', $caseID, 'is_deleted'); + + $url = ""; + $css = 'class="action-item crm-hover-button"'; + if ($allowView) { + $viewUrl = CRM_Utils_System::url('civicrm/case/activity/view', array('cid' => $contactID, 'aid' => $caseActivityId)); + $url = '' . ts('View') . ''; + } + $additionalUrl = "&id={$caseActivityId}"; + if (!$dao->deleted) { + //hide edit link of activity type email.CRM-4530. + if (!in_array($dao->type, $emailActivityTypeIDs)) { + //hide Edit link if activity type is NOT editable (special case activities).CRM-5871 + if ($allowEdit) { + $url .= '' . ts('Edit') . ' '; + } + } + if ($allowDelete) { + $url .= ' ' . ts('Delete') . ''; + } + } + elseif (!$caseDeleted) { + $url = ' ' . ts('Restore') . ''; + $caseActivity['status_id'] = $caseActivity['status_id'] . '
(deleted)'; + } + + //check for operations. + if (self::checkPermission($caseActivityId, 'Move To Case', $dao->activity_type_id)) { + $url .= ' ' . ts('Move To Case') . ' '; + } + if (self::checkPermission($caseActivityId, 'Copy To Case', $dao->activity_type_id)) { + $url .= ' ' . ts('Copy To Case') . ' '; + } + // if there are file attachments we will return how many and, if only one, add a link to it + if (!empty($dao->attachment_ids)) { + $attachmentIDs = array_unique(explode(',', $dao->attachment_ids)); + $caseActivity['no_attachments'] = count($attachmentIDs); + $url .= implode(' ', CRM_Core_BAO_File::paperIconAttachment('civicrm_activity', $caseActivityId)); + } + $caseActivity['links'] = $url; + return $caseActivity; + } + /** * Helper function to generate a formatted contact link/name for display in the Case activities tab * From 16924c84b2ed7bbb50e22f062a8b28fd00dbe709 Mon Sep 17 00:00:00 2001 From: mark burdett Date: Sun, 10 Mar 2019 19:54:57 -0700 Subject: [PATCH 031/408] Upgrade zetacomponents/base and zetacomponents/mail. --- composer.json | 4 ++-- composer.lock | 32 +++++++++++++++++++++----------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/composer.json b/composer.json index 0a2bb8786f40..d08ba21edfb5 100644 --- a/composer.json +++ b/composer.json @@ -46,8 +46,8 @@ "symfony/finder": "^2.8.44 || ~3.0", "tecnickcom/tcpdf" : "6.2.*", "totten/ca-config": "~17.05", - "zetacomponents/base": "1.7.*", - "zetacomponents/mail": "dev-1.7-civi", + "zetacomponents/base": "1.9.*", + "zetacomponents/mail": "dev-1.8-civi", "marcj/topsort": "~1.1", "phpoffice/phpword": "^0.15.0", "pear/Validate_Finance_CreditCard": "dev-master", diff --git a/composer.lock b/composer.lock index 5e4c864c041d..a7092756308a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "55c8f835d55c424d93e0e9dad1efc729", + "content-hash": "0f9eab6b0bf1c120dace5cf229223605", "packages": [ { "name": "civicrm/civicrm-cxn-rpc", @@ -2144,18 +2144,22 @@ }, { "name": "zetacomponents/base", - "version": "1.7", + "version": "1.9.1", "source": { "type": "git", "url": "https://github.com/zetacomponents/Base.git", - "reference": "2612ee3ce88902632d45b93e379277e9d46b70a7" + "reference": "489e20235989ddc97fdd793af31ac803972454f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zetacomponents/Base/zipball/2612ee3ce88902632d45b93e379277e9d46b70a7", - "reference": "2612ee3ce88902632d45b93e379277e9d46b70a7", + "url": "https://api.github.com/repos/zetacomponents/Base/zipball/489e20235989ddc97fdd793af31ac803972454f1", + "reference": "489e20235989ddc97fdd793af31ac803972454f1", "shasum": "" }, + "require-dev": { + "phpunit/phpunit": "~5.7", + "zetacomponents/unit-test": "*" + }, "type": "library", "autoload": { "classmap": [ @@ -2164,7 +2168,7 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "apache2" + "Apache-2.0" ], "authors": [ { @@ -2200,15 +2204,21 @@ ], "description": "The Base package provides the basic infrastructure that all packages rely on. Therefore every component relies on this package.", "homepage": "https://github.com/zetacomponents", - "time": "2009-06-29T10:47:39+00:00" + "time": "2017-11-28T11:30:00+00:00" }, { "name": "zetacomponents/mail", - "version": "dev-1.7-civi", + "version": "dev-1.8-civi", "source": { "type": "git", "url": "https://github.com/civicrm/zetacomponents-mail.git", - "reference": "e0feff0e1860f16fa2b3c42795c0351db58120a0" + "reference": "b60e9a543f6c3d9a9ec74452d4ff5736a1c63a77" + }, + "require": { + "zetacomponents/base": "~1.8" + }, + "require-dev": { + "zetacomponents/unit-test": "*" }, "type": "library", "autoload": { @@ -2217,7 +2227,7 @@ ] }, "license": [ - "apache2" + "Apache-2.0" ], "authors": [ { @@ -2262,7 +2272,7 @@ ], "description": "The component allows you construct and/or parse Mail messages conforming to the mail standard. It has support for attachments, multipart messages and HTML mail. It also interfaces with SMTP to send mail or IMAP, POP3 or mbox to retrieve e-mail.", "homepage": "https://github.com/zetacomponents", - "time": "2017-03-14T06:51:24+00:00" + "time": "2019-02-13T11:33:09+00:00" } ], "packages-dev": [], From 9dcd46efea53f53577246237a94a9b5980d6c568 Mon Sep 17 00:00:00 2001 From: mark burdett Date: Mon, 11 Mar 2019 15:04:23 -0700 Subject: [PATCH 032/408] Non-multipart body is now an ezcMailFile object stored in tmp directory. --- CRM/Utils/Mail/EmailProcessor.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CRM/Utils/Mail/EmailProcessor.php b/CRM/Utils/Mail/EmailProcessor.php index 5f609153b414..3c9842d9e247 100644 --- a/CRM/Utils/Mail/EmailProcessor.php +++ b/CRM/Utils/Mail/EmailProcessor.php @@ -290,6 +290,9 @@ public static function _process($civiMail, $dao, $is_create_activities) { elseif ($mail->body instanceof ezcMailMultipart) { $text = self::getTextFromMultipart($mail->body); } + elseif ($mail->body instanceof ezcMailFile) { + $text = file_get_contents($mail->body->__get('fileName')); + } if ( empty($text) && From 51b1143b10d1b5198026efb52efff29265c05304 Mon Sep 17 00:00:00 2001 From: mark burdett Date: Mon, 11 Mar 2019 15:07:11 -0700 Subject: [PATCH 033/408] Fix invalid quoted-printable encoding of test fixture emails. --- .../Utils/Mail/data/bounces/test_nested_message.eml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/phpunit/CRM/Utils/Mail/data/bounces/test_nested_message.eml b/tests/phpunit/CRM/Utils/Mail/data/bounces/test_nested_message.eml index 96caf13eebd8..d52c68c5ef3d 100644 --- a/tests/phpunit/CRM/Utils/Mail/data/bounces/test_nested_message.eml +++ b/tests/phpunit/CRM/Utils/Mail/data/bounces/test_nested_message.eml @@ -42,15 +42,15 @@ Content-Transfer-Encoding: quoted-printable There was a problem delivering your message to bob@example.com. See the te= chnical details below, or try resending in a few minutes. -Learn more here: https://checkspam.secureserver.net/?sid=xxxxxxxxxxxx= -1&mid=xxxxxxxxxxxxxxxx +Learn more here: https://checkspam.secureserver.net/?sid=3Dxxxxxxxxxxxx= +1&mid=3Dxxxxxxxxxxxxxxxx (Warning: This link will take you to a third-party site) The response from the remote server was: 552 5.2.0 aaaaaaaaaaaaaaaa - bbbbbbbbbbbbbbbb This message has been = rejected due to content judged to be spam by the internet community IB212 -= If you feel this is in error, please submit a request using the following = -page. --f403043ae60413e7eb055f6de972 @@ -89,7 +89,7 @@ below, or try resending in a few minutes. LEARN MORE +t/?sid=3Dxxxxxxxxxxxxxxxxxxx&mid=3Dxxxxxxxxxxxxxxxx">LEARN MORE @@ -108,8 +108,8 @@ The response from the remote server was:
552 5.2.0 aaaaaaaaaaaaaaaa - bbbbbbbbbbbbbbbbbbb This message has been = rejected due to content judged to be spam by the internet community IB212 -= If you feel this is in error, please submit a request using the following = -page. <https://checkspam.secureserver.net/?sid=xxxxxxxx&m= -id=xxxxxxxxxxxxxxxx> +page. <https://checkspam.secureserver.net/?sid=3Dxxxxxxxx&m= +id=3Dxxxxxxxxxxxxxxxx>

From a6b674bb1aab0a6e4d4c593c985020fbef726cce Mon Sep 17 00:00:00 2001 From: eileen Date: Tue, 12 Mar 2019 13:11:15 +1300 Subject: [PATCH 034/408] Formatting cleanup --- .../phpunit/CRM/Activity/Form/SearchTest.php | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/tests/phpunit/CRM/Activity/Form/SearchTest.php b/tests/phpunit/CRM/Activity/Form/SearchTest.php index 8777aa1b3233..b3fdb796bf17 100644 --- a/tests/phpunit/CRM/Activity/Form/SearchTest.php +++ b/tests/phpunit/CRM/Activity/Form/SearchTest.php @@ -9,14 +9,17 @@ class CRM_Activity_Form_SearchTest extends CiviUnitTestCase { public function setUp() { parent::setUp(); $this->individualID = $this->individualCreate(); - $this->contributionCreate(array('contact_id' => $this->individualID, 'receive_date' => '2017-01-30')); + $this->contributionCreate([ + 'contact_id' => $this->individualID, + 'receive_date' => '2017-01-30', + ]); } public function tearDown() { - $tablesToTruncate = array( + $tablesToTruncate = [ 'civicrm_activity', 'civicrm_activity_contact', - ); + ]; $this->quickCleanup($tablesToTruncate); } @@ -32,7 +35,8 @@ public function testSearch() { $form->postProcess(); $qfKey = $form->controller->_key; $rows = $form->controller->get('rows'); - $this->assertEquals(array(array( + $this->assertEquals([ + [ 'contact_id' => '3', 'contact_type' => '
', 'sort_name' => 'Anderson, Anthony', @@ -46,8 +50,8 @@ public function testSearch() { 'activity_type_id' => '6', 'activity_type' => 'Contribution', 'activity_is_test' => '0', - 'target_contact_name' => array(), - 'assignee_contact_name' => array(), + 'target_contact_name' => [], + 'assignee_contact_name' => [], 'source_contact_id' => '3', 'source_contact_name' => 'Anderson, Anthony', 'checkbox' => 'mark_x_1', @@ -56,7 +60,8 @@ public function testSearch() { 'campaign' => NULL, 'campaign_id' => NULL, 'repeat' => '', - )), $rows); + ], + ], $rows); } } From 64412b4e9485820b8a9d0e7ab93db2a86d3f56e2 Mon Sep 17 00:00:00 2001 From: "Matthew Wire (MJW Consulting)" Date: Tue, 12 Mar 2019 00:49:10 +0000 Subject: [PATCH 035/408] Actually use the values processed by processBillingAddress() --- CRM/Member/Form/Membership.php | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/CRM/Member/Form/Membership.php b/CRM/Member/Form/Membership.php index ea63606ec41a..b246aedb8534 100644 --- a/CRM/Member/Form/Membership.php +++ b/CRM/Member/Form/Membership.php @@ -1108,17 +1108,16 @@ public function submit() { $isTest = ($this->_mode == 'test') ? 1 : 0; $this->storeContactFields($this->_params); $this->beginPostProcess(); - $formValues = $this->_params; $joinDate = $startDate = $endDate = NULL; $membershipTypes = $membership = $calcDate = array(); $membershipType = NULL; $paymentInstrumentID = $this->_paymentProcessor['object']->getPaymentInstrumentID(); - - $mailSend = FALSE; - $formValues = $this->setPriceSetParameters($formValues); $params = $softParams = $ids = array(); + $mailSend = FALSE; $this->processBillingAddress(); + $formValues = $this->_params; + $formValues = $this->setPriceSetParameters($formValues); if ($this->_id) { $ids['membership'] = $params['id'] = $this->_id; @@ -1369,11 +1368,6 @@ public function submit() { $params['register_date'] = date('YmdHis'); // add all the additional payment params we need - // @todo the country & state values should be set by the call to $this->assignBillingAddress. - $formValues["state_province-{$this->_bltID}"] = $formValues["billing_state_province-{$this->_bltID}"] - = CRM_Core_PseudoConstant::stateProvinceAbbreviation($formValues["billing_state_province_id-{$this->_bltID}"]); - $formValues["country-{$this->_bltID}"] = $formValues["billing_country-{$this->_bltID}"] = CRM_Core_PseudoConstant::countryIsoCode($formValues["billing_country_id-{$this->_bltID}"]); - $formValues['amount'] = $params['total_amount']; // @todo this is a candidate for beginPostProcessFunction. $formValues['currencyID'] = $config->defaultCurrency; @@ -1399,6 +1393,7 @@ public function submit() { } // This is a candidate for shared beginPostProcess function. + // @todo Do we need this now we have $this->formatParamsForPaymentProcessor() ? CRM_Core_Payment_Form::mapParams($this->_bltID, $formValues, $paymentParams, TRUE); // CRM-7137 -for recurring membership, // we do need contribution and recurring records. From 8fc9f99a7201acad4c66ba1c652c2218e1466aa4 Mon Sep 17 00:00:00 2001 From: eileen Date: Tue, 12 Mar 2019 13:39:51 +1300 Subject: [PATCH 036/408] Fix relative dates when searching on activity_date_time In testing I found that there is an unreleased regression relating to our date conversion on activity_date_time in activity search. This fixes and adds tests. (regression was it was being ignored). Note that the option value is capitalised which makes the capitalisation slightly odd but I think accepting that is the least bad option --- CRM/Contact/BAO/Query.php | 63 +++++++++++++++++++ .../phpunit/CRM/Activity/Form/SearchTest.php | 59 +++++++++++++++++ 2 files changed, 122 insertions(+) diff --git a/CRM/Contact/BAO/Query.php b/CRM/Contact/BAO/Query.php index abd8711a80be..1b98afbb00ef 100644 --- a/CRM/Contact/BAO/Query.php +++ b/CRM/Contact/BAO/Query.php @@ -1784,6 +1784,11 @@ public static function fixWhereValues($id, &$values, $wildcard = 0, $useEquals = * @param string $apiEntity */ public function whereClauseSingle(&$values, $apiEntity = NULL) { + if ($this->isARelativeDateField($values[0])) { + $this->buildRelativeDateQuery($values); + return; + } + // do not process custom fields or prefixed contact ids or component params if (CRM_Core_BAO_CustomField::getKeyID($values[0]) || (substr($values[0], 0, CRM_Core_Form::CB_PREFIX_LEN) == CRM_Core_Form::CB_PREFIX) || @@ -6886,4 +6891,62 @@ protected function isPseudoFieldAnFK($fieldSpec) { return TRUE; } + /** + * Is the field a relative date field. + * + * @param string $fieldName + * + * @return bool + */ + protected function isARelativeDateField($fieldName) { + if (substr($fieldName, -9, 9) !== '_relative') { + return FALSE; + } + $realField = substr($fieldName, 0, strlen($fieldName) - 9); + return isset($this->_fields[$realField]); + } + + /** + * @param $values + */ + protected function buildRelativeDateQuery(&$values) { + $value = CRM_Utils_Array::value(2, $values); + if (empty($value)) { + return; + } + $fieldName = substr($values[0], 0, strlen($values[0]) - 9); + $fieldSpec = $this->_fields[$fieldName]; + $tableName = $fieldSpec['table_name']; + $filters = CRM_Core_OptionGroup::values('relative_date_filters'); + $grouping = CRM_Utils_Array::value(3, $values); + $this->_tables[$tableName] = $this->_whereTables[$tableName] = 1; + + $dates = CRM_Utils_Date::getFromTo($value, NULL, NULL); + if (empty($dates[0])) { + // ie. no start date we only have end date + $this->_where[$grouping][] = $fieldSpec['where'] . " <= '{$dates[1]}'"; + + $this->_qill[$grouping][] = ts('%1 is ', [$fieldSpec['title']]) . $filters[$value] . ' (' . ts("to %1", [ + CRM_Utils_Date::customFormat($dates[1]), + ]) . ')'; + } + elseif (empty($dates[1])) { + // ie. no end date we only have start date + $this->_where[$grouping][] = $fieldSpec['where'] . " >= '{$dates[1]}'"; + + $this->_qill[$grouping][] = ts('%1 is ', [$fieldSpec['title']]) . $filters[$value] . ' (' . ts("from %1", [ + CRM_Utils_Date::customFormat($dates[0]), + ]) . ')'; + } + else { + // we have start and end dates. + $this->_where[$grouping][] = $fieldSpec['where'] . " BETWEEN '{$dates[0]}' AND '{$dates[1]}'"; + + $this->_qill[$grouping][] = ts('%1 is ', [$fieldSpec['title']]) . $filters[$value] . ' (' . ts("between %1 and %2", [ + CRM_Utils_Date::customFormat($dates[0]), + CRM_Utils_Date::customFormat($dates[1]), + ]) . ')'; + } + } + } diff --git a/tests/phpunit/CRM/Activity/Form/SearchTest.php b/tests/phpunit/CRM/Activity/Form/SearchTest.php index b3fdb796bf17..9061313f1f5a 100644 --- a/tests/phpunit/CRM/Activity/Form/SearchTest.php +++ b/tests/phpunit/CRM/Activity/Form/SearchTest.php @@ -64,4 +64,63 @@ public function testSearch() { ], $rows); } + /** + * Test the Qill for activity Date time. + * + * @dataProvider getSearchCriteria + * + * @param array $searchCriteria + * @param array $expectedQill + */ + public function testQill($searchCriteria, $expectedQill) { + $selector = new CRM_Activity_Selector_Search($searchCriteria); + $this->assertEquals($expectedQill, $selector->getQILL()); + } + + /** + * Get criteria for activity testing. + */ + public function getSearchCriteria() { + + // We have to define format because tests crash trying to access the config param from the dataProvider + // perhaps because there is no property on config? + $format = '%B %E%f, %Y %l:%M %P'; + $dates['ending_60.day'] = CRM_Utils_Date::getFromTo('ending_60.day', NULL, NULL); + $dates['earlier.year'] = CRM_Utils_Date::getFromTo('earlier.year', NULL, NULL); + $dates['greater.year'] = CRM_Utils_Date::getFromTo('greater.year', NULL, NULL); + return [ + [ + 'search_criteria' => [ + ['activity_date_time_relative', '=', 'ending_60.day', 0, 0], + ], + 'expected_qill' => [['Activity Date is Last 60 days including today (between ' . CRM_Utils_Date::customFormat($dates['ending_60.day'][0], $format) . ' and ' . CRM_Utils_Date::customFormat($dates['ending_60.day'][1], $format) . ')']], + ], + [ + 'search_criteria' => [ + ['activity_date_time_relative', '=', 'earlier.year', 0, 0], + ], + 'expected_qill' => [['Activity Date is To end of previous calendar year (to ' . CRM_Utils_Date::customFormat($dates['earlier.year'][1], $format) . ')']], + ], + [ + 'search_criteria' => [ + ['activity_date_time_relative', '=', 'greater.year', 0, 0], + ], + 'expected_qill' => [['Activity Date is From start of current calendar year (from ' . CRM_Utils_Date::customFormat($dates['greater.year'][0], $format) . ')']], + ], + [ + 'search_criteria' => [ + ['activity_date_time_low', '=', '2019-03-05', 0, 0], + ['activity_date_time_high', '=', '2019-03-27', 0, 0], + ], + 'expected_qill' => [['Activity Date - greater than or equal to "March 5th, 2019 12:00 AM" AND less than or equal to "March 27th, 2019 11:59 PM"']], + ], + [ + 'search_criteria' => [ + ['activity_status_id', '=', ['IN' => ['1', '2']], 0, 0] + ], + 'expected_qill' => [['Activity Status In Scheduled, Completed']], + ], + ]; + } + } From 8a4cd1f8379e13d70790aac10619a60569390777 Mon Sep 17 00:00:00 2001 From: Seamus Lee Date: Thu, 3 Jan 2019 07:45:16 +1100 Subject: [PATCH 037/408] (dev/core#491) Standardise the adding of campaign fields on the mailing summary report and add a post upgrade message about needing to re-save report given the changes made to the report template Update language on postupgrade message Move upgrade to 5.13 --- CRM/Report/Form/Mailing/Summary.php | 34 ++++++-------------- CRM/Upgrade/Incremental/php/FiveThirteen.php | 9 +++--- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/CRM/Report/Form/Mailing/Summary.php b/CRM/Report/Form/Mailing/Summary.php index e1397b688655..b862ffcc72c6 100644 --- a/CRM/Report/Form/Mailing/Summary.php +++ b/CRM/Report/Form/Mailing/Summary.php @@ -45,8 +45,6 @@ class CRM_Report_Form_Mailing_Summary extends CRM_Report_Form { 'bar_3dChart' => 'Bar Chart', ); - public $campaignEnabled = FALSE; - /** * Class constructor. */ @@ -297,23 +295,8 @@ public function __construct() { ), ), ); - $config = CRM_Core_Config::singleton(); - $this->campaignEnabled = in_array("CiviCampaign", $config->enableComponents); - if ($this->campaignEnabled) { - $this->_columns['civicrm_campaign'] = array( - 'dao' => 'CRM_Campaign_DAO_Campaign', - 'fields' => array( - 'title' => array( - 'title' => ts('Campaign Name'), - ), - ), - 'filters' => array( - 'title' => array( - 'type' => CRM_Utils_Type::T_STRING, - ), - ), - ); - } + // If we have campaigns enabled, add those elements to both the fields, filters. + $this->addCampaignFields('civicrm_mailing'); parent::__construct(); } @@ -428,12 +411,6 @@ public function from() { LEFT JOIN civicrm_mailing_group {$this->_aliases['civicrm_mailing_group']} ON {$this->_aliases['civicrm_mailing_group']}.mailing_id = {$this->_aliases['civicrm_mailing']}.id"; } - if ($this->campaignEnabled) { - $this->_from .= " - LEFT JOIN civicrm_campaign {$this->_aliases['civicrm_campaign']} - ON {$this->_aliases['civicrm_campaign']}.id = {$this->_aliases['civicrm_mailing']}.campaign_id"; - } - // need group by and order by //print_r($this->_from); @@ -679,6 +656,13 @@ public function alterDisplay(&$rows) { $entryFound = TRUE; } } + // convert campaign_id to campaign title + if (array_key_exists('civicrm_mailing_campaign_id', $row)) { + if ($value = $row['civicrm_mailing_campaign_id']) { + $rows[$rowNum]['civicrm_mailing_campaign_id'] = $this->campaigns[$value]; + $entryFound = TRUE; + } + } // skip looking further in rows, if first row itself doesn't // have the column we need if (!$entryFound) { diff --git a/CRM/Upgrade/Incremental/php/FiveThirteen.php b/CRM/Upgrade/Incremental/php/FiveThirteen.php index 1e4131226514..81dc3c42fae6 100644 --- a/CRM/Upgrade/Incremental/php/FiveThirteen.php +++ b/CRM/Upgrade/Incremental/php/FiveThirteen.php @@ -55,10 +55,11 @@ public function setPreUpgradeMessage(&$preUpgradeMessage, $rev, $currentVer = NU * an intermediate version; note that setPostUpgradeMessage is called repeatedly with different $revs. */ public function setPostUpgradeMessage(&$postUpgradeMessage, $rev) { - // Example: Generate a post-upgrade message. - // if ($rev == '5.12.34') { - // $postUpgradeMessage .= '

' . ts("By default, CiviCRM now disables the ability to import directly from SQL. To use this feature, you must explicitly grant permission 'import SQL datasource'."); - // } + $config = CRM_Core_Config::singleton(); + $campaignEnabled = in_array("CiviCampaign", $config->enableComponents); + if ($rev == '5.13.alpha1' && $campaignEnabled) { + $postUpgradeMessage .= '

' . ts("If you have created a report based on the Mailing Summary Report template and it outputs or filters on campaigns, You will need to go back to that report and re-save the report after selecting and or setting the campaign filters up again"); + } } /* From 8a8cbada51b958bbbd15f59cdd3d8311606f3963 Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Tue, 12 Mar 2019 22:15:20 -0700 Subject: [PATCH 038/408] (Fast)ArrayDecorator - Emit expected exception when using WP and strict PSR-16 Suppose someone calls `ArrayDecorator::get()` or `FastArrayDecorator::get()` with an invalid key (e.g. passing `float` or an `array` instead of a `string`). This patch improves error-reporting for that scenario. This is primarily about fixing multiple test failures in `E2E_Cache_ArrayDecoratorTest` reported on `wp-demo`. These generally look like ``` 1) E2E_Cache_ArrayDecoratorTest::testGetInvalidKeys with data set #1 (true) array_key_exists(): The first argument should be either a string or an integer /Users/totten/bknix/build/wpmaster/wp-content/plugins/civicrm/civicrm/CRM/Utils/Cache/ArrayDecorator.php:102 /Users/totten/bknix/build/wpmaster/wp-content/plugins/civicrm/civicrm/packages/Cache/IntegrationTests/LegacySimpleCacheTest.php:409 /Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar:598 ``` Before ------ The ArrayDecorator first checks its front cache (`array_key_exists`) to see if the key is defined. In the `wp-demo` environment, this produces a warning and causes the test to fail. The condition *is* erroneous, but PSR-16 specifies that the error should be reported as exception. After ----- The condition is reported as the expected exception. The test passes on `wp-demo`. Comment ------- This brings the code in `(Fast)ArrayDecorator.php` into alignment with most of the other `CRM/Utils/Cache/*.php` drivers; in most drivers, it is typical to validate the key at the start of most functions. --- CRM/Utils/Cache/ArrayDecorator.php | 3 +++ CRM/Utils/Cache/FastArrayDecorator.php | 2 ++ 2 files changed, 5 insertions(+) diff --git a/CRM/Utils/Cache/ArrayDecorator.php b/CRM/Utils/Cache/ArrayDecorator.php index b3c7e091c3e4..c9007070c3cf 100644 --- a/CRM/Utils/Cache/ArrayDecorator.php +++ b/CRM/Utils/Cache/ArrayDecorator.php @@ -94,6 +94,7 @@ public function set($key, $value, $ttl = NULL) { } public function get($key, $default = NULL) { + CRM_Utils_Cache::assertValidKey($key); if (array_key_exists($key, $this->values) && $this->expires[$key] > CRM_Utils_Time::getTimeRaw()) { return $this->reobjectify($this->values[$key]); } @@ -110,6 +111,7 @@ public function get($key, $default = NULL) { } public function delete($key) { + CRM_Utils_Cache::assertValidKey($key); unset($this->values[$key]); unset($this->expires[$key]); return $this->delegate->delete($key); @@ -126,6 +128,7 @@ public function clear() { } public function has($key) { + CRM_Utils_Cache::assertValidKey($key); if (array_key_exists($key, $this->values) && $this->expires[$key] > CRM_Utils_Time::getTimeRaw()) { return TRUE; } diff --git a/CRM/Utils/Cache/FastArrayDecorator.php b/CRM/Utils/Cache/FastArrayDecorator.php index 5926f23354ea..82ef578d7257 100644 --- a/CRM/Utils/Cache/FastArrayDecorator.php +++ b/CRM/Utils/Cache/FastArrayDecorator.php @@ -99,6 +99,7 @@ public function set($key, $value, $ttl = NULL) { } public function get($key, $default = NULL) { + CRM_Utils_Cache::assertValidKey($key); if (array_key_exists($key, $this->values)) { return $this->values[$key]; } @@ -114,6 +115,7 @@ public function get($key, $default = NULL) { } public function delete($key) { + CRM_Utils_Cache::assertValidKey($key); unset($this->values[$key]); return $this->delegate->delete($key); } From 7ab67b4303ce62b3ae580ca7ca2ec08a81dcaf3d Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Wed, 13 Mar 2019 00:16:43 -0700 Subject: [PATCH 039/408] (ops#878) phpunit.xml.dist - Prevent conflict in WordPress E2E with "stderr=true" Before ------ When running any of the end-to-end (E2E) tests on CiviCRM-WordPress, the output is polluted with these warnings: ``` [bknix-dfl:~/bknix/build/wpmaster/wp-content/plugins/civicrm/civicrm] phpunit5 tests/phpunit/E2E/Cache/FastArrayDecoratorTest.php PHPUnit 5.7.27 by Sebastian Bergmann and contributors. PHP Warning: session_start(): Cannot send session cookie - headers already sent by (output started at phar:///Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar/phpunit/Util/Printer.php:110) in /Users/totten/bknix/build/wpmaster/wp-content/plugins/civicrm/civicrm.php on line 346 PHP Stack trace: PHP 1. {main}() /Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar:0 PHP 2. PHPUnit_TextUI_Command::main() /Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar:598 PHP 3. PHPUnit_TextUI_Command->run() phar:///Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar/phpunit/TextUI/Command.php:116 PHP 4. PHPUnit_TextUI_TestRunner->doRun() phar:///Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar/phpunit/TextUI/Command.php:186 PHP 5. PHPUnit_Framework_TestSuite->run() phar:///Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar/phpunit/TextUI/TestRunner.php:517 PHP 6. call_user_func:{phar:///Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar/phpunit/Framework/TestSuite.php:679}() phar:///Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar/phpunit/Framework/TestSuite.php:679 PHP 7. E2E_Cache_CacheTestCase::setUpBeforeClass() phar:///Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar/phpunit/Framework/TestSuite.php:679 PHP 8. CRM_Utils_System::loadBootStrap() /Users/totten/bknix/build/wpmaster/wp-content/plugins/civicrm/civicrm/tests/phpunit/E2E/Cache/CacheTestCase.php:43 PHP 9. CRM_Utils_System_WordPress->loadBootStrap() /Users/totten/bknix/build/wpmaster/wp-content/plugins/civicrm/civicrm/CRM/Utils/System.php:1477 PHP 10. require_once() /Users/totten/bknix/build/wpmaster/wp-content/plugins/civicrm/civicrm/CRM/Utils/System/WordPress.php:479 PHP 11. require_once() /Users/totten/bknix/build/wpmaster/wp-load.php:37 PHP 12. require_once() /Users/totten/bknix/build/wpmaster/wp-config.php:94 PHP 13. do_action() /Users/totten/bknix/build/wpmaster/wp-settings.php:325 PHP 14. WP_Hook->do_action() /Users/totten/bknix/build/wpmaster/wp-includes/plugin.php:453 PHP 15. WP_Hook->apply_filters() /Users/totten/bknix/build/wpmaster/wp-includes/class-wp-hook.php:323 PHP 16. call_user_func_array:{/Users/totten/bknix/build/wpmaster/wp-includes/class-wp-hook.php:298}() /Users/totten/bknix/build/wpmaster/wp-includes/class-wp-hook.php:298 PHP 17. CiviCRM_For_WordPress->setup_instance() /Users/totten/bknix/build/wpmaster/wp-includes/class-wp-hook.php:298 PHP 18. session_start() /Users/totten/bknix/build/wpmaster/wp-content/plugins/civicrm/civicrm.php:346 ``` After ----- The session_start warnings are no longer generated.. Comments -------- The problem appears to be this: 1. When PHPUnit starts, it puts some messages on STDOUT. 2. When the specific tests/test-suites are setup, they bootstrap WordPress, and WordPress tries to setup a session, which requires setting some headers 3. But we've already started writing STDOUT, and we can't send any headers. The patch is based on suggestion [a StackExchange discussion](https://stackoverflow.com/questions/23270650/cannot-send-session-cookie-headers-already-sent-phpunit-laravel/38045422) -- basically, by setting the `stderr` option (which is documented lightly in the cli `phpunit5 --help`), we prevent step 1 above -- because PHPUnit now prints messages to STDERR instead of STDOUT. The only concern (`r-tech`) would be... is there anything in our ecosystem which depends on piping information from PHPUnit's STDOUT? Obviously, I can't speak for third-parties, but the general pattern in `civicrm.org` CI scripts (e.g. `civi-test-run`) is to evaluate PHPUnit output through a mix of (1) exit-codes and (2) JUnit files. In which case... it doesn't matter if PHPUnit writes messages to STDERR or STDOUT. I'd suggest paying close attention to the console output for the PR-test here; if that's good, then we're probably OK. --- phpunit.xml.dist | 1 + 1 file changed, 1 insertion(+) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 0da4639ae815..4d19c763c4c7 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -7,6 +7,7 @@ processIsolation="false" stopOnFailure="false" syntaxCheck="false" + stderr="true" beStrictAboutTestsThatDoNotTestAnything="false" bootstrap="tests/phpunit/CiviTest/bootstrap.php" > From c4b164f7a3fad3e6aa37fb76fb251f87678959df Mon Sep 17 00:00:00 2001 From: "Matthew Wire (MJW Consulting)" Date: Wed, 13 Mar 2019 10:29:57 +0000 Subject: [PATCH 040/408] Add comments about usage for doPayment() function --- CRM/Core/Payment.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CRM/Core/Payment.php b/CRM/Core/Payment.php index 7603137137a5..ad06c818e0b2 100644 --- a/CRM/Core/Payment.php +++ b/CRM/Core/Payment.php @@ -1183,6 +1183,13 @@ protected function doDirectPayment(&$params) { * Once this function is fully rolled out then it will be preferred for processors to throw exceptions than to * return Error objects * + * Usage: + * Payment processors should override this function directly instead of using doDirectPayment/doTransferCheckout which are deprecated. + * Payment processors should set and return payment_status_id (Pending if the IPN will complete it, Completed if successful). + * @fixme For the contribution workflow we have a contributionID, but for the event and membership workflow the contribution has not yet been created + * so we can't update params directly on the contribution. However if you return trxn_id, fee_amount, net_amount they will be set on the contribution + * by those workflows. Ideally all workflows would create a pending contribution BEFORE calling doPayment (eg. https://github.com/civicrm/civicrm-core/pull/13763 for events) + * * @param array $params * * @param string $component From cd355351eda2f06c8af2f1ac8e59b45ac06c8630 Mon Sep 17 00:00:00 2001 From: "Matthew Wire (MJW Consulting)" Date: Wed, 13 Mar 2019 14:00:14 +0000 Subject: [PATCH 041/408] Add a class to handle test entities consistently --- CRM/Activity/Selector/Search.php | 2 +- CRM/Contribute/BAO/ContributionSoft.php | 2 +- .../Page/ContributionRecurPayments.php | 3 + CRM/Core/TestEntity.php | 58 +++++++++++++++++++ CRM/Event/Form/ParticipantView.php | 2 +- CRM/Event/Selector/Search.php | 2 +- CRM/Member/Form/MembershipView.php | 2 +- CRM/Member/Selector/Search.php | 2 +- CRM/Pledge/Selector/Search.php | 2 +- .../WebTest/Event/AddParticipationTest.php | 2 +- 10 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 CRM/Core/TestEntity.php diff --git a/CRM/Activity/Selector/Search.php b/CRM/Activity/Selector/Search.php index 0d9e36c5d156..f6de0e43dd50 100644 --- a/CRM/Activity/Selector/Search.php +++ b/CRM/Activity/Selector/Search.php @@ -310,7 +310,7 @@ public function &getRows($action, $offset, $rowCount, $sort, $output = NULL) { $accessMailingReport = FALSE; $activityTypeId = $row['activity_type_id']; if ($row['activity_is_test']) { - $row['activity_type'] = $row['activity_type'] . " (test)"; + $row['activity_type'] = CRM_Core_TestEntity::appendTestText($row['activity_type']); } $row['mailingId'] = ''; if ( diff --git a/CRM/Contribute/BAO/ContributionSoft.php b/CRM/Contribute/BAO/ContributionSoft.php index 1f6671cb3dbb..8b7e1ec8c9d6 100644 --- a/CRM/Contribute/BAO/ContributionSoft.php +++ b/CRM/Contribute/BAO/ContributionSoft.php @@ -520,7 +520,7 @@ public static function getSoftContributionList($contact_id, $filter = NULL, $isT $result[$cs->id]['links'] = CRM_Core_Action::formLink($links, NULL, $replace); if ($isTest) { - $result[$cs->id]['contribution_status'] = $result[$cs->id]['contribution_status'] . '
(test)'; + $result[$cs->id]['contribution_status'] = CRM_Core_TestEntity::appendTestText($result[$cs->id]['contribution_status']); } } return $result; diff --git a/CRM/Contribute/Page/ContributionRecurPayments.php b/CRM/Contribute/Page/ContributionRecurPayments.php index 0410bdca3b14..0237481dbf70 100644 --- a/CRM/Contribute/Page/ContributionRecurPayments.php +++ b/CRM/Contribute/Page/ContributionRecurPayments.php @@ -53,6 +53,9 @@ private function loadRelatedContributions() { $this->insertStatusLabels($contribution); $this->insertContributionActions($contribution); + if ($contribution['is_test']) { + $contribution['financial_type'] = CRM_Core_TestEntity::appendTestText($contribution['financial_type']); + } $relatedContributions[] = $contribution; } diff --git a/CRM/Core/TestEntity.php b/CRM/Core/TestEntity.php new file mode 100644 index 000000000000..ee288dea1a68 --- /dev/null +++ b/CRM/Core/TestEntity.php @@ -0,0 +1,58 @@ +participant_id; diff --git a/CRM/Member/Form/MembershipView.php b/CRM/Member/Form/MembershipView.php index 7274bba59a52..b5ac8470107c 100644 --- a/CRM/Member/Form/MembershipView.php +++ b/CRM/Member/Form/MembershipView.php @@ -398,7 +398,7 @@ public function preProcess() { } if (!empty($values['is_test'])) { - $values['membership_type'] .= ' (test) '; + $values['membership_type'] = CRM_Core_TestEntity::appendTestText($values['membership_type']); } $subscriptionCancelled = CRM_Member_BAO_Membership::isSubscriptionCancelled($this->membershipID); diff --git a/CRM/Member/Selector/Search.php b/CRM/Member/Selector/Search.php index f46782627aa1..0d7c3639c0f8 100644 --- a/CRM/Member/Selector/Search.php +++ b/CRM/Member/Selector/Search.php @@ -377,7 +377,7 @@ public function &getRows($action, $offset, $rowCount, $sort, $output = NULL) { $row['campaign_id'] = $result->member_campaign_id; if (!empty($row['member_is_test'])) { - $row['membership_type'] = $row['membership_type'] . " (test)"; + $row['membership_type'] = CRM_Core_TestEntity::appendTestText($row['membership_type']); } $row['checkbox'] = CRM_Core_Form::CB_PREFIX . $result->membership_id; diff --git a/CRM/Pledge/Selector/Search.php b/CRM/Pledge/Selector/Search.php index c7c75ce36d7f..f7548ed4d7a8 100644 --- a/CRM/Pledge/Selector/Search.php +++ b/CRM/Pledge/Selector/Search.php @@ -326,7 +326,7 @@ public function &getRows($action, $offset, $rowCount, $sort, $output = NULL) { } // append (test) to status label if (!empty($row['pledge_is_test'])) { - $row['pledge_status'] .= ' (test)'; + $row['pledge_status'] = CRM_Core_TestEntity::appendTestText($row['pledge_status']); } $hideOption = array(); diff --git a/tests/phpunit/WebTest/Event/AddParticipationTest.php b/tests/phpunit/WebTest/Event/AddParticipationTest.php index 0c21bd928608..044dd24d320b 100644 --- a/tests/phpunit/WebTest/Event/AddParticipationTest.php +++ b/tests/phpunit/WebTest/Event/AddParticipationTest.php @@ -342,7 +342,7 @@ public function testEventAddMultipleParticipants() { $this->clickLink("_qf_Search_refresh", "participantSearch"); //verifying the registered participants - $status = "Registered (test)"; + $status = CRM_Core_TestEntity::appendTestText("Registered"); foreach ($contacts as $contact) { $this->verifyText("xpath=//div[@id='participantSearch']//table//tbody//tr/td[@class='crm-participant-sort_name']/a[text()='{$contact['sort_name']}']/../../td[9]", preg_quote($status)); From f3a5913cb6bfcd138fa2a1e3a974fbce74ccf77d Mon Sep 17 00:00:00 2001 From: Jon Goldberg Date: Wed, 13 Mar 2019 12:12:41 -0400 Subject: [PATCH 042/408] core#798 - fix rendering of public-facing prefix/suffix select2 --- css/civicrm.css | 1 - 1 file changed, 1 deletion(-) diff --git a/css/civicrm.css b/css/civicrm.css index 087f64c56c48..de957adb3bfb 100644 --- a/css/civicrm.css +++ b/css/civicrm.css @@ -3597,7 +3597,6 @@ span.crm-status-icon { } .crm-container.crm-public .select2-container .select2-choice { padding: 5px 5px 5px 8px; - height: auto; } .crm-container.crm-public .select2-container-multi .select2-choices { padding: 4px; From 9ba02e3e25fe10e8d1eb46c07b77b7fa407eda0d Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Wed, 13 Mar 2019 00:35:54 -0700 Subject: [PATCH 043/408] (ops#878) Enforce common signature for CRM_Utils_System::loadBootStrap(). Fix WP E2E error. Before ------ 1. Most `CRM_Utils_System_*` classes implement a method `loadBootStrap($params = array(),...)`. However, `WordPress` and `UnitTests` implement a different signature (`loadBootStrap($name = NULL, $pass = NULL)`), and `Soap` does not implement it all. This is problematic -- because the function is invoked in a centralized way (e.g. `CRM_Utils_System::loadBootStrap()` invokes `$config->userSystem->loadBootStrap($params, $loadUser, $throwError, $realPath)`), which implies that all UF drivers need to support this signature. 2. When running any of the end-to-end (E2E) tests on CiviCRM-WordPress, the output is polluted with these warnings: ``` bknix-dfl:~/bknix/build/wpmaster/wp-content/plugins/civicrm/civicrm] phpunit5 tests/phpunit/E2E/Cache/FastArrayDecoratorTest.php ; echo "exit=$?" PHPUnit 5.7.27 by Sebastian Bergmann and contributors. PHP Warning: strip_tags() expects parameter 1 to be string, array given in /Users/totten/bknix/build/wpmaster/wp-includes/formatting.php on line 4649 PHP Stack trace: PHP 1. {main}() /Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar:0 PHP 2. PHPUnit_TextUI_Command::main() /Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar:598 PHP 3. PHPUnit_TextUI_Command->run() phar:///Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar/phpunit/TextUI/Command.php:116 PHP 4. PHPUnit_TextUI_TestRunner->doRun() phar:///Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar/phpunit/TextUI/Command.php:186 PHP 5. PHPUnit_Framework_TestSuite->run() phar:///Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar/phpunit/TextUI/TestRunner.php:517 PHP 6. call_user_func:{phar:///Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar/phpunit/Framework/TestSuite.php:679}() phar:///Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar/phpunit/Framework/TestSuite.php:679 PHP 7. E2E_Cache_CacheTestCase::setUpBeforeClass() phar:///Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar/phpunit/Framework/TestSuite.php:679 PHP 8. CRM_Utils_System::loadBootStrap() /Users/totten/bknix/build/wpmaster/wp-content/plugins/civicrm/civicrm/tests/phpunit/E2E/Cache/CacheTestCase.php:43 PHP 9. CRM_Utils_System_WordPress->loadBootStrap() /Users/totten/bknix/build/wpmaster/wp-content/plugins/civicrm/civicrm/CRM/Utils/System.php:1477 PHP 10. wp_authenticate() /Users/totten/bknix/build/wpmaster/wp-content/plugins/civicrm/civicrm/CRM/Utils/System/WordPress.php:495 PHP 11. sanitize_user() /Users/totten/bknix/build/wpmaster/wp-includes/pluggable.php:515 PHP 12. wp_strip_all_tags() /Users/totten/bknix/build/wpmaster/wp-includes/formatting.php:1850 PHP 13. strip_tags() /Users/totten/bknix/build/wpmaster/wp-includes/formatting.php:4649 Warning: strip_tags() expects parameter 1 to be string, array given in /Users/totten/bknix/build/wpmaster/wp-includes/formatting.php on line 4649 Call Stack: 0.0026 425040 1. {main}() /Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar:0 0.0766 14246216 2. PHPUnit_TextUI_Command::main() /Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar:598 0.0766 14246952 3. PHPUnit_TextUI_Command->run() phar:///Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar/phpunit/TextUI/Command.php:116 0.4267 23405608 4. PHPUnit_TextUI_TestRunner->doRun() phar:///Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar/phpunit/TextUI/Command.php:186 0.4336 23511184 5. PHPUnit_Framework_TestSuite->run() phar:///Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar/phpunit/TextUI/TestRunner.php:517 0.4403 23516840 6. call_user_func:{phar:///Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar/phpunit/Framework/TestSuite.php:679}() phar:///Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar/phpunit/Framework/TestSuite.php:679 0.4403 23516920 7. E2E_Cache_CacheTestCase::setUpBeforeClass() phar:///Users/totten/bknix/civicrm-buildkit/extern/phpunit5/phpunit5.phar/phpunit/Framework/TestSuite.php:679 0.5065 31975824 8. CRM_Utils_System::loadBootStrap() /Users/totten/bknix/build/wpmaster/wp-content/plugins/civicrm/civicrm/tests/phpunit/E2E/Cache/CacheTestCase.php:43 0.5065 31976344 9. CRM_Utils_System_WordPress->loadBootStrap() /Users/totten/bknix/build/wpmaster/wp-content/plugins/civicrm/civicrm/CRM/Utils/System.php:1477 0.6517 57998912 10. wp_authenticate() /Users/totten/bknix/build/wpmaster/wp-content/plugins/civicrm/civicrm/CRM/Utils/System/WordPress.php:495 0.6517 57998992 11. sanitize_user() /Users/totten/bknix/build/wpmaster/wp-includes/pluggable.php:515 0.6517 57999088 12. wp_strip_all_tags() /Users/totten/bknix/build/wpmaster/wp-includes/formatting.php:1850 0.6517 57999736 13. strip_tags() /Users/totten/bknix/build/wpmaster/wp-includes/formatting.php:4649 ``` 3. The warning indicates that (on WordPress) the E2E test is not doing what it's trying to do -- specifically, `E2E_Cache_CacheTestCase::setUpBeforeClass()` (or, similarly, `CiviEndToEndTestCase::setUpBeforeClass()`) calls `CRM_Utils_System::loadBootStrap()` to authenticate as the CMS administrator, but this fails because WP's implementation of `loadBootStrap()` does not respect the same signature. After ----- 1. `CRM_Utils_System_Base` defines an abstract function `loadBootStrap($params = array(),...)`. Any non-compliant driver (which uses a different signature or which omits the function) will produce a syntax error. 2. The classes `CRM_Utils_System_{WordPress,UnitTests}` have been updated to comply with the signature. 3. The class `CRM_Utils_System_Soap` nominally complies. However, this class isn't really a UF driver, and it doesn't make sense for it to extend this base class, and the implementation is a stub. But we don't need to scope-creep the bugfix. 4. The `loadBootStrap...strip_tags()...` warnings are no longer generated when running E2E tests on WP. Comments -------- * I verified that all extant classes in `CRM/Utils/System/*.php` are loadable/compilable (i.e they now comply with the delcared signature). * The SOAP integration has test-coverage viia `E2E_Extern_SoapTest`. * In the PR test output, you'll only see E2E results from D7. *However*, this patch is part of a bigger effort (infrastructure/ops#878) which will eventually give some visibility on that. --- CRM/Utils/System/Base.php | 2 ++ CRM/Utils/System/Soap.php | 5 +++++ CRM/Utils/System/UnitTests.php | 9 +-------- CRM/Utils/System/WordPress.php | 21 +++++++++++++++------ 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/CRM/Utils/System/Base.php b/CRM/Utils/System/Base.php index c2978ecf942e..01ff9094996e 100644 --- a/CRM/Utils/System/Base.php +++ b/CRM/Utils/System/Base.php @@ -56,6 +56,8 @@ public function initialize() { } } + public abstract function loadBootStrap($params = array(), $loadUser = TRUE, $throwError = TRUE, $realPath = NULL); + /** * Append an additional breadcrumb tag to the existing breadcrumb. * diff --git a/CRM/Utils/System/Soap.php b/CRM/Utils/System/Soap.php index ddb3eb358870..df688a033c0b 100644 --- a/CRM/Utils/System/Soap.php +++ b/CRM/Utils/System/Soap.php @@ -124,4 +124,9 @@ public function getLoginURL($destination = '') { throw new Exception("Method not implemented: getLoginURL"); } + public function loadBootStrap($params = array(), $loadUser = TRUE, $throwError = TRUE, $realPath = NULL) { + // It makes zero sense for this class to extend CRM_Utils_System_Base. + throw new \RuntimeException("Not implemented"); + } + } diff --git a/CRM/Utils/System/UnitTests.php b/CRM/Utils/System/UnitTests.php index 7d4426f6ab43..ea220a416948 100644 --- a/CRM/Utils/System/UnitTests.php +++ b/CRM/Utils/System/UnitTests.php @@ -54,15 +54,8 @@ public function authenticate($name, $password, $loadCMSBootstrap = FALSE, $realP /** * Bootstrap the phony CMS. - * - * @param string $name - * Optional username for login. - * @param string $pass - * Optional password for login. - * - * @return bool */ - public function loadBootStrap($name = NULL, $pass = NULL) { + public function loadBootStrap($params = array(), $loadUser = TRUE, $throwError = TRUE, $realPath = NULL) { return TRUE; } diff --git a/CRM/Utils/System/WordPress.php b/CRM/Utils/System/WordPress.php index f450056bdbd6..08e286e0539c 100644 --- a/CRM/Utils/System/WordPress.php +++ b/CRM/Utils/System/WordPress.php @@ -338,7 +338,10 @@ public function authenticate($name, $password, $loadCMSBootstrap = FALSE, $realP $config = CRM_Core_Config::singleton(); if ($loadCMSBootstrap) { - $config->userSystem->loadBootStrap($name, $password); + $config->userSystem->loadBootStrap([ + 'name' => $name, + 'pass' => $password, + ]); } $user = wp_authenticate($name, $password); @@ -453,16 +456,22 @@ public function setUFLocale($civicrm_language) { /** * Load wordpress bootstrap. * - * @param string $name - * optional username for login. - * @param string $pass - * optional password for login. + * @param array $params + * Optional credentials + * - name: string, cms username + * - pass: string, cms password * * @return bool */ - public function loadBootStrap($name = NULL, $pass = NULL) { + public function loadBootStrap($params = array(), $loadUser = TRUE, $throwError = TRUE, $realPath = NULL) { global $wp, $wp_rewrite, $wp_the_query, $wp_query, $wpdb, $current_site, $current_blog, $current_user; + $name = CRM_Utils_Array::value('name', $params); + $pass = CRM_Utils_Array::value('pass', $params); + if (isset($params['uid'])) { + throw new \RuntimeException("Not implemented WordPress::loadBootStrap([uid=>\$num]))"); + } + if (!defined('WP_USE_THEMES')) { define('WP_USE_THEMES', FALSE); } From 8b5445c8b8c07618497c075559d7c68d2cb0fe5d Mon Sep 17 00:00:00 2001 From: eileen Date: Wed, 13 Mar 2019 15:00:35 +1300 Subject: [PATCH 044/408] Pass 'check permissions' flag through to merge function The inner function will only delete the merged contact if checkPermissions is false or the logged in user has permission to delete. Our api model expects check_permissions to be respected at the BAO level --- api/v3/Contact.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/api/v3/Contact.php b/api/v3/Contact.php index 8f82b41259e1..54ce858580f7 100644 --- a/api/v3/Contact.php +++ b/api/v3/Contact.php @@ -1195,12 +1195,14 @@ function _civicrm_api3_contact_deprecation() { * @throws API_Exception */ function civicrm_api3_contact_merge($params) { - if (($result = CRM_Dedupe_Merger::merge([ - [ - 'srcID' => $params['to_remove_id'], - 'dstID' => $params['to_keep_id'], - ], - ], [], $params['mode'])) != FALSE) { + if (($result = CRM_Dedupe_Merger::merge( + [['srcID' => $params['to_remove_id'], 'dstID' => $params['to_keep_id']]], + [], + $params['mode'], + FALSE, + CRM_Utils_Array::value('check_permissions', $params) + )) != FALSE) { + return civicrm_api3_create_success($result, $params); } throw new API_Exception('Merge failed'); From 72d57998d17a80c776ed85460cd0699b03a050a3 Mon Sep 17 00:00:00 2001 From: eileen Date: Mon, 11 Mar 2019 12:44:36 +1300 Subject: [PATCH 045/408] Further cleanup on getRelatedMemberships - just get them with the api Per work by Matt it makes sense to just retrieve as an api rather than do weird object wrangling. This is intended to not change the logic about what is fetched --- CRM/Contribute/BAO/Contribution.php | 45 ++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/CRM/Contribute/BAO/Contribution.php b/CRM/Contribute/BAO/Contribution.php index 989129001f93..f7d7abd6324e 100644 --- a/CRM/Contribute/BAO/Contribution.php +++ b/CRM/Contribute/BAO/Contribution.php @@ -949,20 +949,24 @@ protected static function getToFinancialAccount($contribution, $params) { * @return array */ protected static function getRelatedMemberships($contributionID) { - $contribution = new CRM_Contribute_BAO_Contribution(); - $contribution->id = $contributionID; - $contribution->fetch(TRUE); - $contribution->loadRelatedMembershipObjects(); - $result = CRM_Utils_Array::value('membership', $contribution->_relatedObjects, []); - $memberships = []; - foreach ($result as $membership) { - if (empty($membership)) { - continue; - } - // @todo - remove this again & just call api in the first place. - _civicrm_api3_object_to_array($membership, $memberships[$membership->id]); - } - return $memberships; + $membershipPayments = civicrm_api3('MembershipPayment', 'get', [ + 'return' => 'membership_id', + 'contribution_id' => (int) $contributionID, + ])['values']; + $membershipIDs = []; + foreach ($membershipPayments as $membershipPayment) { + $membershipIDs[] = $membershipPayment['membership_id']; + } + if (empty($membershipIDs)) { + return []; + } + // We could combine this with the MembershipPayment.get - we'd + // need to re-wrangle the params (here or in the calling function) + // as they would then me membership.contact_id, membership.is_test etc + return civicrm_api3('Membership', 'get', [ + 'id' => ['IN' => $membershipIDs], + 'return' => ['id', 'contact_id', 'membership_type_id', 'is_test'] + ])['values']; } /** @@ -2414,6 +2418,14 @@ public static function getContributionDates() { * @throws Exception */ public function loadRelatedObjects(&$input, &$ids, $loadAll = FALSE) { + // @todo deprecate this function - the steps should be + // 1) add additional functions like 'getRelatedMemberships' + // 2) switch all calls that refer to ->_relatedObjects to + // using the helper functions + // 3) make ->_relatedObjects noisy in some way (deprecation won't work for properties - hmm + // 4) make ->_relatedObjects protected + // 5) hone up the individual functions to not use rely on this having been called + // 6) deprecate like mad if ($loadAll) { $ids = array_merge($this->getComponentDetails($this->id), $ids); if (empty($ids['contact']) && isset($this->contact_id)) { @@ -2476,6 +2488,8 @@ public function loadRelatedObjects(&$input, &$ids, $loadAll = FALSE) { } } + // These are probably no longer accessed from anywhere + // @todo remove this line, after ensuring not used. $ids = $this->loadRelatedMembershipObjects($ids); if ($this->_component != 'contribute') { @@ -4518,6 +4532,7 @@ public static function completeOrder(&$input, &$ids, $objects, $transaction, $re $input['participant_id'] = $contribution->_relatedObjects['participant']->id; } elseif (!empty($contribution->_relatedObjects['membership'])) { + // @todo - use getRelatedMemberships instead $input['contribution_mode'] = 'membership'; $contribution->contribution_status_id = $contributionParams['contribution_status_id']; $contribution->trxn_id = CRM_Utils_Array::value('trxn_id', $input); @@ -4652,6 +4667,8 @@ public static function createCreditNoteId() { /** * Load related memberships. * + * @deprecated + * * Note that in theory it should be possible to retrieve these from the line_item table * with the membership_payment table being deprecated. Attempting to do this here causes tests to fail * as it seems the api is not correctly linking the line items when the contribution is created in the flow From c931044d461bfdd82ce29105a16abb8361c79e1b Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Thu, 14 Mar 2019 12:38:35 -0400 Subject: [PATCH 046/408] dev/core#790 - Exclue menubar on frontend pages --- CRM/Core/Resources.php | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/CRM/Core/Resources.php b/CRM/Core/Resources.php index 3c9ecf006e9e..0e4e7755ece0 100644 --- a/CRM/Core/Resources.php +++ b/CRM/Core/Resources.php @@ -750,9 +750,17 @@ public function coreResourceList($region) { $contactID = CRM_Core_Session::getLoggedInContactID(); // Menubar - $position = $contactID && CRM_Core_Permission::check('access CiviCRM') ? Civi::settings()->get('menubar_position') : 'none'; - if ($position !== 'none' && !@constant('CIVICRM_DISABLE_DEFAULT_MENU') && !CRM_Core_Config::isUpgradeMode()) { - $cms = strtolower(CRM_Core_Config::singleton()->userFramework); + $position = 'none'; + if ( + $contactID && !$config->userFrameworkFrontend + && CRM_Core_Permission::check('access CiviCRM') + && !@constant('CIVICRM_DISABLE_DEFAULT_MENU') + && !CRM_Core_Config::isUpgradeMode() + ) { + $position = Civi::settings()->get('menubar_position') ?: 'over-cms-menu'; + } + if ($position !== 'none') { + $cms = strtolower($config->userFramework); $cms = $cms === 'drupal' ? 'drupal7' : $cms; $items[] = 'bower_components/smartmenus/dist/jquery.smartmenus.min.js'; $items[] = 'bower_components/smartmenus/dist/addons/keyboard/jquery.smartmenus.keyboard.min.js'; @@ -762,7 +770,7 @@ public function coreResourceList($region) { $items[] = "css/menubar-$cms.css"; $items[] = [ 'menubar' => [ - 'position' => $position ?: 'over-cms-menu', + 'position' => $position, 'qfKey' => CRM_Core_Key::get('CRM_Contact_Controller_Search', TRUE), 'cacheCode' => CRM_Core_BAO_Navigation::getCacheKey($contactID), ], From 1295f5c1736508b9ff25fa1243483c4fecadf858 Mon Sep 17 00:00:00 2001 From: Seamus Lee Date: Fri, 15 Mar 2019 07:20:48 +1100 Subject: [PATCH 047/408] Update lockfile to take into account of civicrm/zetacomponents-mail#4 being merged --- composer.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.lock b/composer.lock index a7092756308a..881fda86660d 100644 --- a/composer.lock +++ b/composer.lock @@ -2212,7 +2212,7 @@ "source": { "type": "git", "url": "https://github.com/civicrm/zetacomponents-mail.git", - "reference": "b60e9a543f6c3d9a9ec74452d4ff5736a1c63a77" + "reference": "7286a167a4ec3199ab3c69a361967d853ffbcd90" }, "require": { "zetacomponents/base": "~1.8" @@ -2272,7 +2272,7 @@ ], "description": "The component allows you construct and/or parse Mail messages conforming to the mail standard. It has support for attachments, multipart messages and HTML mail. It also interfaces with SMTP to send mail or IMAP, POP3 or mbox to retrieve e-mail.", "homepage": "https://github.com/zetacomponents", - "time": "2019-02-13T11:33:09+00:00" + "time": "2019-03-14T11:29:52+00:00" } ], "packages-dev": [], From 2bdce12cef9cfcc106a1155687b7a6c057860605 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Thu, 14 Mar 2019 18:23:18 -0400 Subject: [PATCH 048/408] Make cacheCode optional in CRM.loadScript --- js/Common.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/js/Common.js b/js/Common.js index c090e9ceefe2..ce8546c5708e 100644 --- a/js/Common.js +++ b/js/Common.js @@ -238,9 +238,13 @@ if (!CRM.vars) CRM.vars = {}; }; var scriptsLoaded = {}; - CRM.loadScript = function(url) { + CRM.loadScript = function(url, appendCacheCode) { if (!scriptsLoaded[url]) { - var script = document.createElement('script'); + var script = document.createElement('script'), + src = url; + if (appendCacheCode !== false) { + src += (_.includes(url, '?') ? '&r=' : '?r=') + CRM.config.resourceCacheCode; + } scriptsLoaded[url] = $.Deferred(); script.onload = function () { // Give the script time to execute @@ -256,7 +260,7 @@ if (!CRM.vars) CRM.vars = {}; CRM.CMSjQuery = window.jQuery; window.jQuery = CRM.$; } - script.src = url + (_.includes(url, '?') ? '&r=' : '?r=') + CRM.config.resourceCacheCode; + script.src = src; document.getElementsByTagName("head")[0].appendChild(script); } return scriptsLoaded[url]; From dbc654ec81263616178d32782adbc45c088d9473 Mon Sep 17 00:00:00 2001 From: eileen Date: Mon, 11 Mar 2019 13:04:57 +1300 Subject: [PATCH 049/408] Support calling ContributionPage.validate in POST context. Because the validation data is buried deep within the form we need to load the form in order to validate - but currently the validKey check borks in post requests. Note the validity of credit card details is not checked when submitting this form, other than possibly the luhn validation. A likely use case for the validation is when the is being submitted and some handling is to be done before processing but the validity of input needs to be checked first. For example Paypal Checkout will replace the confirm button with it's own but we are able to validate before paypal launches it's modal. In this case the is post but we need validation to succeed. --- api/v3/ContributionPage.php | 20 +++++++++++++++++++ tests/phpunit/api/v3/ContributionPageTest.php | 16 +++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/api/v3/ContributionPage.php b/api/v3/ContributionPage.php index 393dfa75f367..1a1e822b6e1b 100644 --- a/api/v3/ContributionPage.php +++ b/api/v3/ContributionPage.php @@ -114,6 +114,13 @@ function civicrm_api3_contribution_page_submit($params) { * API result array */ function civicrm_api3_contribution_page_validate($params) { + // If we are calling this as a result of a POST action (e.g validating a form submission before first getting payment + // authorization from a payment processor like Paypal checkout) the lack of a qfKey will not result in a valid + // one being generated so we generate one first. + $qfKey = CRM_Utils_Array::value('qfKey', $_REQUEST); + if (!$qfKey) { + $_REQUEST['qfKey'] = CRM_Core_Key::get('CRM_Core_Controller', TRUE); + } $form = new CRM_Contribute_Form_Contribution_Main(); $form->controller = new CRM_Core_Controller(); $form->set('id', $params['id']); @@ -125,6 +132,19 @@ function civicrm_api3_contribution_page_validate($params) { return civicrm_api3_create_success($errors, $params, 'ContributionPage', 'validate'); } +/** + * Metadata for validate action. + * + * @param array $params + */ +function _civicrm_api3_contribution_page_validate_spec(&$params) { + $params['id'] = [ + 'title' => ts('Contribution Page ID'), + 'api.required' => TRUE, + 'type' => CRM_Utils_Type::T_INT, + ]; +} + /** * Set default getlist parameters. * diff --git a/tests/phpunit/api/v3/ContributionPageTest.php b/tests/phpunit/api/v3/ContributionPageTest.php index 6232aceb7dba..6b96a7f5e60f 100644 --- a/tests/phpunit/api/v3/ContributionPageTest.php +++ b/tests/phpunit/api/v3/ContributionPageTest.php @@ -1922,6 +1922,22 @@ public function testValidate() { $this->assertEmpty($errors); } + /** + * Test validating a contribution page submit in POST context. + * + * A likely use case for the validation is when the is being submitted and some handling is + * to be done before processing but the validity of input needs to be checked first. + * + * For example Paypal Checkout will replace the confirm button with it's own but we are able to validate + * before paypal launches it's modal. In this case the $_REQUEST is post but we need validation to succeed. + */ + public function testValidatePost() { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $this->setUpContributionPage(); + $errors = $this->callAPISuccess('ContributionPage', 'validate', array_merge($this->getBasicSubmitParams(), ['action' => 'submit']))['values']; + $this->assertEmpty($errors); + } + /** * Implements hook_civicrm_alterPaymentProcessorParams(). * From a1a013006f54b12cdafaeb10b82ad133edcc456e Mon Sep 17 00:00:00 2001 From: eileen Date: Mon, 11 Mar 2019 13:21:01 +1300 Subject: [PATCH 050/408] Add unit test on validate --- api/v3/ContributionPage.php | 2 ++ tests/phpunit/api/v3/ContributionPageTest.php | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/api/v3/ContributionPage.php b/api/v3/ContributionPage.php index 1a1e822b6e1b..9ffbd59edbbc 100644 --- a/api/v3/ContributionPage.php +++ b/api/v3/ContributionPage.php @@ -117,6 +117,7 @@ function civicrm_api3_contribution_page_validate($params) { // If we are calling this as a result of a POST action (e.g validating a form submission before first getting payment // authorization from a payment processor like Paypal checkout) the lack of a qfKey will not result in a valid // one being generated so we generate one first. + $originalRequest = $_REQUEST; $qfKey = CRM_Utils_Array::value('qfKey', $_REQUEST); if (!$qfKey) { $_REQUEST['qfKey'] = CRM_Core_Key::get('CRM_Core_Controller', TRUE); @@ -129,6 +130,7 @@ function civicrm_api3_contribution_page_validate($params) { if ($errors === TRUE) { $errors = []; } + $_REQUEST = $originalRequest; return civicrm_api3_create_success($errors, $params, 'ContributionPage', 'validate'); } diff --git a/tests/phpunit/api/v3/ContributionPageTest.php b/tests/phpunit/api/v3/ContributionPageTest.php index 6b96a7f5e60f..e773ba39f0ce 100644 --- a/tests/phpunit/api/v3/ContributionPageTest.php +++ b/tests/phpunit/api/v3/ContributionPageTest.php @@ -1936,6 +1936,21 @@ public function testValidatePost() { $this->setUpContributionPage(); $errors = $this->callAPISuccess('ContributionPage', 'validate', array_merge($this->getBasicSubmitParams(), ['action' => 'submit']))['values']; $this->assertEmpty($errors); + unset($_SERVER['REQUEST_METHOD']); + } + + /** + * Test that an error is generated if required fields are not submitted. + */ + public function testValidateOutputOnMissingRecurFields() { + $this->params['is_recur_interval'] = 1; + $this->setUpContributionPage(TRUE); + $submitParams = array_merge($this->getBasicSubmitParams(), ['action' => 'submit']); + $submitParams['is_recur'] = 1; + $submitParams['frequency_interval'] = ''; + $submitParams['frequency_unit'] = ''; + $errors = $this->callAPISuccess('ContributionPage', 'validate', $submitParams)['values']; + $this->assertEquals('Please enter a number for how often you want to make this recurring contribution (EXAMPLE: Every 3 months).', $errors['frequency_interval']); } /** From b2a883a81abdec4a13f4ca06687ac76c06d03d50 Mon Sep 17 00:00:00 2001 From: eileen Date: Sat, 9 Mar 2019 14:41:47 +1300 Subject: [PATCH 051/408] Catch payment processor exceptions, log, hide, do not return 500 error --- CRM/Core/Payment.php | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/CRM/Core/Payment.php b/CRM/Core/Payment.php index 7603137137a5..95800b7881f1 100644 --- a/CRM/Core/Payment.php +++ b/CRM/Core/Payment.php @@ -1288,14 +1288,23 @@ public static function paypalRedirect(&$paymentProcessor) { * Page callback for civicrm/payment/ipn */ public static function handleIPN() { - self::handlePaymentMethod( - 'PaymentNotification', - array( - 'processor_name' => @$_GET['processor_name'], - 'processor_id' => @$_GET['processor_id'], - 'mode' => @$_GET['mode'], - ) - ); + try { + self::handlePaymentMethod( + 'PaymentNotification', + [ + 'processor_name' => CRM_Utils_Request::retrieveValue('processor_name', 'String'), + 'processor_id' => CRM_Utils_Request::retrieveValue('processor_id', 'Integer'), + 'mode' => CRM_Utils_Request::retrieveValue('mode', 'Alphanumeric'), + ] + ); + } + catch (CRM_Core_Exception $e) { + Civi::log()->error('ipn_payment_callback_exception', [ + 'context' => [ + 'backtrace' => CRM_Core_Error::formatBacktrace(debug_backtrace()), + ] + ]); + } CRM_Utils_System::civiExit(); } @@ -1357,7 +1366,7 @@ public static function handlePaymentMethod($method, $params = array()) { // Check whether we found anything at all. if (!$dao->N) { - CRM_Core_Error::fatal($notFound); + throw new CRM_Core_Exception($notFound); } $method = 'handle' . $method; @@ -1401,7 +1410,7 @@ public static function handlePaymentMethod($method, $params = array()) { if (!$extension_instance_found) { $message = "No extension instances of the '%1' payment processor were found.
" . "%2 method is unsupported in legacy payment processors."; - CRM_Core_Error::fatal(ts($message, array(1 => $params['processor_name'], 2 => $method))); + throw new CRM_Core_Exception(ts($message, [1 => $params['processor_name'], 2 => $method])); } } From 1004b68954fca664cca58f448aa999558e84a941 Mon Sep 17 00:00:00 2001 From: eileen Date: Fri, 15 Mar 2019 10:08:02 +1300 Subject: [PATCH 052/408] Add unit test to date parsing on import This is primarily as a demo of how to test this class. Basically extract the parts that we want to check the formatting of into manageable functions. I made the name on the second one pretty generic so slowly all formatting can be moved into it, with testing. This would include moving the various bits of work done in _civicrm_api3_deprecated_formatted_param into this function - that code really does just belong on this class as it is not called from anywhere else. It also does the checking, but not the formatting, for these date fields - sigh I would have liked to have made the method protected but the mucking around that required in the test classes didn't seem to justify it --- CRM/Contribute/Import/Parser/Contribution.php | 177 ++++++++++-------- .../Import/Parser/ContributionTest.php | 18 ++ 2 files changed, 121 insertions(+), 74 deletions(-) diff --git a/CRM/Contribute/Import/Parser/Contribution.php b/CRM/Contribute/Import/Parser/Contribution.php index 6d572c1551e8..a528527f00b5 100644 --- a/CRM/Contribute/Import/Parser/Contribution.php +++ b/CRM/Contribute/Import/Parser/Contribution.php @@ -177,49 +177,7 @@ public function summary(&$values) { $errorMessage = NULL; //for date-Formats - $session = CRM_Core_Session::singleton(); - $dateType = $session->get('dateTypes'); - foreach ($params as $key => $val) { - if ($val) { - switch ($key) { - case 'receive_date': - if ($dateValue = CRM_Utils_Date::formatDate($params[$key], $dateType)) { - $params[$key] = $dateValue; - } - else { - CRM_Contact_Import_Parser_Contact::addToErrorMsg('Receive Date', $errorMessage); - } - break; - - case 'cancel_date': - if ($dateValue = CRM_Utils_Date::formatDate($params[$key], $dateType)) { - $params[$key] = $dateValue; - } - else { - CRM_Contact_Import_Parser_Contact::addToErrorMsg('Cancel Date', $errorMessage); - } - break; - - case 'receipt_date': - if ($dateValue = CRM_Utils_Date::formatDate($params[$key], $dateType)) { - $params[$key] = $dateValue; - } - else { - CRM_Contact_Import_Parser_Contact::addToErrorMsg('Receipt date', $errorMessage); - } - break; - - case 'thankyou_date': - if ($dateValue = CRM_Utils_Date::formatDate($params[$key], $dateType)) { - $params[$key] = $dateValue; - } - else { - CRM_Contact_Import_Parser_Contact::addToErrorMsg('Thankyou Date', $errorMessage); - } - break; - } - } - } + $errorMessage = $this->formatDateFields($params); //date-Format part ends $params['contact_type'] = 'Contribution'; @@ -257,42 +215,12 @@ public function import($onDuplicate, &$values) { $params = &$this->getActiveFieldParams(); $formatted = ['version' => 3, 'skipRecentView' => TRUE, 'skipCleanMoney' => FALSE]; - $dateType = CRM_Core_Session::singleton()->get('dateTypes'); - - $customDataType = !empty($params['contact_type']) ? $params['contact_type'] : 'Contribution'; - $customFields = CRM_Core_BAO_CustomField::getFields($customDataType); //CRM-10994 if (isset($params['total_amount']) && $params['total_amount'] == 0) { $params['total_amount'] = '0.00'; } - foreach ($params as $key => $val) { - if ($val) { - switch ($key) { - case 'receive_date': - case 'cancel_date': - case 'receipt_date': - case 'thankyou_date': - $params[$key] = CRM_Utils_Date::formatDate($params[$key], $dateType); - break; - - case 'pledge_payment': - $params[$key] = CRM_Utils_String::strtobool($val); - break; - - } - if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) { - if ($customFields[$customFieldID]['data_type'] == 'Date') { - CRM_Contact_Import_Parser_Contact::formatCustomDate($params, $formatted, $dateType, $key); - unset($params[$key]); - } - elseif ($customFields[$customFieldID]['data_type'] == 'Boolean') { - $params[$key] = CRM_Utils_String::strtoboolstr($val); - } - } - } - } - //date-Format part ends + $this->formatInput($params); static $indieFields = NULL; if ($indieFields == NULL) { @@ -602,4 +530,105 @@ public function &getImportedContributions() { public function fini() { } + /** + * Format date fields from input to mysql. + * + * @param array $params + * + * @return array + * Error messages, if any. + */ + public function formatDateFields(&$params) { + $errorMessage = NULL; + $dateType = CRM_Core_Session::singleton()->get('dateTypes'); + foreach ($params as $key => $val) { + if ($val) { + switch ($key) { + case 'receive_date': + if ($dateValue = CRM_Utils_Date::formatDate($params[$key], $dateType)) { + $params[$key] = $dateValue; + } + else { + CRM_Contact_Import_Parser_Contact::addToErrorMsg('Receive Date', $errorMessage); + } + break; + + case 'cancel_date': + if ($dateValue = CRM_Utils_Date::formatDate($params[$key], $dateType)) { + $params[$key] = $dateValue; + } + else { + CRM_Contact_Import_Parser_Contact::addToErrorMsg('Cancel Date', $errorMessage); + } + break; + + case 'receipt_date': + if ($dateValue = CRM_Utils_Date::formatDate($params[$key], $dateType)) { + $params[$key] = $dateValue; + } + else { + CRM_Contact_Import_Parser_Contact::addToErrorMsg('Receipt date', $errorMessage); + } + break; + + case 'thankyou_date': + if ($dateValue = CRM_Utils_Date::formatDate($params[$key], $dateType)) { + $params[$key] = $dateValue; + } + else { + CRM_Contact_Import_Parser_Contact::addToErrorMsg('Thankyou Date', $errorMessage); + } + break; + } + } + } + return $errorMessage; + } + + /** + * Format input params to suit api handling. + * + * Over time all the parts of _civicrm_api3_deprecated_formatted_param + * and all the parts of the import function on this class that relate to + * reformatting input should be moved here and tests should be added in + * CRM_Contribute_Import_Parser_ContributionTest. + * + * @param array $params + */ + public function formatInput(&$params) { + $dateType = CRM_Core_Session::singleton()->get('dateTypes'); + $customDataType = !empty($params['contact_type']) ? $params['contact_type'] : 'Contribution'; + $customFields = CRM_Core_BAO_CustomField::getFields($customDataType); + // @todo call formatDateFields & move custom data handling there. + // Also note error handling for dates is currently in _civicrm_api3_deprecated_formatted_param + // we should use the error handling in formatDateFields. + foreach ($params as $key => $val) { + // @todo - call formatDateFields instead. + if ($val) { + switch ($key) { + case 'receive_date': + case 'cancel_date': + case 'receipt_date': + case 'thankyou_date': + $params[$key] = CRM_Utils_Date::formatDate($params[$key], $dateType); + break; + + case 'pledge_payment': + $params[$key] = CRM_Utils_String::strtobool($val); + break; + + } + if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($key)) { + if ($customFields[$customFieldID]['data_type'] == 'Date') { + CRM_Contact_Import_Parser_Contact::formatCustomDate($params, $params, $dateType, $key); + unset($params[$key]); + } + elseif ($customFields[$customFieldID]['data_type'] == 'Boolean') { + $params[$key] = CRM_Utils_String::strtoboolstr($val); + } + } + } + } + } + } diff --git a/tests/phpunit/CRM/Contribute/Import/Parser/ContributionTest.php b/tests/phpunit/CRM/Contribute/Import/Parser/ContributionTest.php index 64810f7606d8..740178e609a9 100644 --- a/tests/phpunit/CRM/Contribute/Import/Parser/ContributionTest.php +++ b/tests/phpunit/CRM/Contribute/Import/Parser/ContributionTest.php @@ -69,6 +69,24 @@ public function testImportParserWithSoftCreditsByExternalIdentifier($thousandSep $this->callAPISuccess('ContributionSoft', 'Delete', ['id' => $contributionsOfSoftContact->id]); $this->callAPISuccess('Contribution', 'Delete', ['id' => $contributionsOfMainContact->id]); } + + /** + * Test dates are parsed + */ + public function testParsedDates() { + $mapperKeys = []; + $form = new CRM_Contribute_Import_Parser_Contribution($mapperKeys); + $params = ['receive_date' => '20/10/2019']; + CRM_Core_Session::singleton()->set('dateTypes', 32); + $form->formatDateFields($params); + $this->assertEquals('20191020', $params['receive_date']); + + $params = ['receive_date' => '20/10/2019']; + CRM_Core_Session::singleton()->set('dateTypes', 32); + $form->formatInput($params); + $this->assertEquals('20191020', $params['receive_date']); + } + /** * Run the import parser. * From 341c643b40b1da08713eebe06c8d1e82b8667583 Mon Sep 17 00:00:00 2001 From: eileen Date: Fri, 15 Mar 2019 11:49:42 +1300 Subject: [PATCH 053/408] Fix error message handling while we are at it Turns out that instead of translating we are passing the error message to a truly silly function --- CRM/Contact/Import/Parser/Contact.php | 4 ++++ CRM/Contribute/Import/Parser/Contribution.php | 12 ++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/CRM/Contact/Import/Parser/Contact.php b/CRM/Contact/Import/Parser/Contact.php index e742e11407f3..1c5fd1069c8c 100644 --- a/CRM/Contact/Import/Parser/Contact.php +++ b/CRM/Contact/Import/Parser/Contact.php @@ -1691,6 +1691,10 @@ public static function in_value($value, $valueArray) { /** * Build error-message containing error-fields * + * Once upon a time there was a dev who hadn't heard of implode. That dev wrote this function. + * + * @todo just say no! + * * @param string $errorName * A string containing error-field name. * @param string $errorMessage diff --git a/CRM/Contribute/Import/Parser/Contribution.php b/CRM/Contribute/Import/Parser/Contribution.php index a528527f00b5..8d0ac2297168 100644 --- a/CRM/Contribute/Import/Parser/Contribution.php +++ b/CRM/Contribute/Import/Parser/Contribution.php @@ -177,7 +177,7 @@ public function summary(&$values) { $errorMessage = NULL; //for date-Formats - $errorMessage = $this->formatDateFields($params); + $errorMessage = implode('; ', $this->formatDateFields($params)); //date-Format part ends $params['contact_type'] = 'Contribution'; @@ -539,7 +539,7 @@ public function fini() { * Error messages, if any. */ public function formatDateFields(&$params) { - $errorMessage = NULL; + $errorMessage = []; $dateType = CRM_Core_Session::singleton()->get('dateTypes'); foreach ($params as $key => $val) { if ($val) { @@ -549,7 +549,7 @@ public function formatDateFields(&$params) { $params[$key] = $dateValue; } else { - CRM_Contact_Import_Parser_Contact::addToErrorMsg('Receive Date', $errorMessage); + $errorMessage[] = ts('Receive Date'); } break; @@ -558,7 +558,7 @@ public function formatDateFields(&$params) { $params[$key] = $dateValue; } else { - CRM_Contact_Import_Parser_Contact::addToErrorMsg('Cancel Date', $errorMessage); + $errorMessage[] = ts('Cancel Date'); } break; @@ -567,7 +567,7 @@ public function formatDateFields(&$params) { $params[$key] = $dateValue; } else { - CRM_Contact_Import_Parser_Contact::addToErrorMsg('Receipt date', $errorMessage); + $errorMessage[] = ts('Receipt date'); } break; @@ -576,7 +576,7 @@ public function formatDateFields(&$params) { $params[$key] = $dateValue; } else { - CRM_Contact_Import_Parser_Contact::addToErrorMsg('Thankyou Date', $errorMessage); + $errorMessage[] = ts('Thankyou Date'); } break; } From 80b646c0f573ebbb80fa3f52e603c72328cbae1a Mon Sep 17 00:00:00 2001 From: Mathieu Lutfy Date: Thu, 14 Mar 2019 12:47:31 -0400 Subject: [PATCH 054/408] dev/core#801 Fix from email on PDF Letters, such as Thank You Letters. --- CRM/Contribute/Form/Task/PDFLetterCommon.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CRM/Contribute/Form/Task/PDFLetterCommon.php b/CRM/Contribute/Form/Task/PDFLetterCommon.php index f8a9724e25d8..044d7df56f9a 100644 --- a/CRM/Contribute/Form/Task/PDFLetterCommon.php +++ b/CRM/Contribute/Form/Task/PDFLetterCommon.php @@ -39,6 +39,9 @@ public static function postProcess(&$form, $formValues = NULL) { 'subject' => CRM_Utils_Array::value('subject', $formValues), 'from' => CRM_Utils_Array::value('from_email_address', $formValues), ); + + $emailParams['from'] = CRM_Utils_Mail::formatFromAddress($emailParams['from']); + // We need display_name for emailLetter() so add to returnProperties here $returnProperties['display_name'] = 1; if (stristr($formValues['email_options'], 'pdfemail')) { From ee9ff51753379d10f306afff5239e8be7cb07b0c Mon Sep 17 00:00:00 2001 From: Tim Otten Date: Wed, 13 Mar 2019 12:00:29 -0700 Subject: [PATCH 055/408] (NFC, infra/ops#878) AssetBuilderTest - Relax getUrl() assertion for WP compat The test ensures that AssetBuilder produces plausible URLs when caching is disabled. Generated URLs look different in the default `drupal-clean` and `wp-demo` configurations, e.g. * D7 (drupal-clean): `http://dmaster.bknix:8001/civicrm/asset/builder?an=square.js&ap=...` * WP (wp-demo): `http://wpmaster.bknix:8001/?page=CiviCRM&q=civicrm%2Fasset%2Fbuilder&an=square.js&ap=... The assertion in `AssetBuilderTest` was coded in a way that fails on working URLs. Before ------ The test fails on WP. After ----- The test passes on WP. --- tests/phpunit/E2E/Core/AssetBuilderTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/phpunit/E2E/Core/AssetBuilderTest.php b/tests/phpunit/E2E/Core/AssetBuilderTest.php index 0295c8e1f150..5d5766d9acd7 100644 --- a/tests/phpunit/E2E/Core/AssetBuilderTest.php +++ b/tests/phpunit/E2E/Core/AssetBuilderTest.php @@ -150,7 +150,8 @@ public function testGetUrl_uncached($asset, $params, $expectedMimeType, $expecte \Civi::service('asset_builder')->setCacheEnabled(FALSE); $url = \Civi::service('asset_builder')->getUrl($asset, $params); $this->assertEquals(0, $this->fired['hook_civicrm_buildAsset']); - $this->assertRegExp(';^https?:.*civicrm/asset/builder.*square.(txt|js);', $url); + // Ex: Traditional URLs on D7 have "/". Traditional URLs on WP have "%2F". + $this->assertRegExp(';^https?:.*civicrm(/|%2F)asset(/|%2F)builder.*square.(txt|js);', $url); // Simulate a request. Our fake hook won't fire in a real request. parse_str(parse_url($url, PHP_URL_QUERY), $get); From de09f942ff41411a8be5ada59470f33e1f51593b Mon Sep 17 00:00:00 2001 From: eileen Date: Thu, 7 Mar 2019 18:45:09 +1300 Subject: [PATCH 056/408] Display test contributions when viewing contributions related to a test recurring contribution --- CRM/Contribute/Page/ContributionRecurPayments.php | 1 + 1 file changed, 1 insertion(+) diff --git a/CRM/Contribute/Page/ContributionRecurPayments.php b/CRM/Contribute/Page/ContributionRecurPayments.php index 0237481dbf70..70f62f8ca9e3 100644 --- a/CRM/Contribute/Page/ContributionRecurPayments.php +++ b/CRM/Contribute/Page/ContributionRecurPayments.php @@ -45,6 +45,7 @@ private function loadRelatedContributions() { 'contribution_recur_id' => $this->id, 'contact_id' => $this->contactId, 'options' => array('limit' => 0), + 'contribution_test' => '', )); foreach ($relatedContributionsResult['values'] as $contribution) { From 12f2d014ac9a6ae351fa4a7b4140662807c7a0d4 Mon Sep 17 00:00:00 2001 From: eileen Date: Fri, 15 Mar 2019 12:53:42 +1300 Subject: [PATCH 057/408] Attempt to improve false negatives on Logging test It might be significant that the one I added sleep(1) to before wasn't a fail in this one... https://test.civicrm.org/job/CiviCRM-Core-PR/25137/ --- tests/phpunit/api/v3/LoggingTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/phpunit/api/v3/LoggingTest.php b/tests/phpunit/api/v3/LoggingTest.php index 3d387038cf94..eaa9fdb64159 100644 --- a/tests/phpunit/api/v3/LoggingTest.php +++ b/tests/phpunit/api/v3/LoggingTest.php @@ -295,6 +295,9 @@ public function testRevert() { public function testRevertNoDate() { $contactId = $this->individualCreate(); $this->callAPISuccess('Setting', 'create', array('logging' => TRUE)); + // Pause for one second here to ensure the timestamps between the first create action + // and the second differ. + sleep(1); CRM_Core_DAO::executeQuery("SET @uniqueID = 'Wot woot'"); $this->callAPISuccess('Contact', 'create', array( 'id' => $contactId, From 6e793248baf0ea5b37ad97a3cac42eae1ec52cdd Mon Sep 17 00:00:00 2001 From: eileen Date: Wed, 6 Mar 2019 10:42:16 +1300 Subject: [PATCH 058/408] Activity tab performance fix - switch to faster getActivities & getActivitiesCount The getActivitiesCount & getActivities functions are faster & call permission hooks but we weren't able to switch to them until we resolved some performance issues (done) and resolved acl inconsistencies (resolved in 5.12) -we can do this now. From a performance POV the difference is tab-crashes vs tab resolves quickly on contacts with > 10k activities --- CRM/Activity/BAO/Activity.php | 501 +----------------- CRM/Activity/Page/AJAX.php | 6 +- CRM/Activity/Selector/Activity.php | 4 +- CRM/Contact/BAO/Contact.php | 2 +- CRM/Utils/Date.php | 37 ++ templates/CRM/Activity/Selector/Selector.tpl | 6 +- .../phpunit/CRM/Activity/BAO/ActivityTest.php | 85 ++- 7 files changed, 85 insertions(+), 556 deletions(-) diff --git a/CRM/Activity/BAO/Activity.php b/CRM/Activity/BAO/Activity.php index 4645121311e1..6235dfde0ed5 100644 --- a/CRM/Activity/BAO/Activity.php +++ b/CRM/Activity/BAO/Activity.php @@ -858,269 +858,6 @@ public static function filterActivityTypes($params) { return array('IN' => array_keys($activityTypes)); } - /** - * Get the list Activities. - * - * @deprecated - * - * @todo - use the api for this - this is working but have temporarily backed out - * due to performance issue to be resolved - CRM-20481. - * - * @param array $input - * Array of parameters. - * Keys include - * - contact_id int contact_id whose activities we want to retrieve - * - offset int which row to start from ? - * - rowCount int how many rows to fetch - * - sort object|array object or array describing sort order for sql query. - * - admin boolean if contact is admin - * - caseId int case ID - * - context string page on which selector is build - * - activity_type_id int|string the activitiy types we want to restrict by - * - * @return array - * Relevant data object values of open activities - */ - public static function deprecatedGetActivities($input) { - // Step 1: Get the basic activity data. - $bulkActivityTypeID = CRM_Core_PseudoConstant::getKey('CRM_Activity_BAO_Activity', - 'activity_type_id', - 'Bulk Email' - ); - - $activityContacts = CRM_Activity_BAO_ActivityContact::buildOptions('record_type_id', 'validate'); - $sourceID = CRM_Utils_Array::key('Activity Source', $activityContacts); - $assigneeID = CRM_Utils_Array::key('Activity Assignees', $activityContacts); - $targetID = CRM_Utils_Array::key('Activity Targets', $activityContacts); - - $config = CRM_Core_Config::singleton(); - - $activityTempTable = CRM_Utils_SQL_TempTable::build()->setCategory('actdetail')->getName(); - - $tableFields = array( - 'activity_id' => 'int unsigned', - 'activity_date_time' => 'datetime', - 'source_record_id' => 'int unsigned', - 'status_id' => 'int unsigned', - 'subject' => 'varchar(255)', - 'source_contact_name' => 'varchar(255)', - 'activity_type_id' => 'int unsigned', - 'activity_type' => 'varchar(128)', - 'case_id' => 'int unsigned', - 'case_subject' => 'varchar(255)', - 'campaign_id' => 'int unsigned', - ); - - $sql = "CREATE TEMPORARY TABLE {$activityTempTable} ( "; - $insertValueSQL = $selectColumns = array(); - // The activityTempTable contains the sorted rows - // so in order to maintain the sort order as-is we add an auto_increment - // field; we can sort by this later to ensure the sort order stays correct. - $sql .= " fixed_sort_order INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,"; - foreach ($tableFields as $name => $desc) { - $sql .= "$name $desc,\n"; - $insertValueSQL[] = $name; - if ($name == 'source_contact_name' && CRM_Utils_SQL::supportsFullGroupBy()) { - $selectColumns[] = "ANY_VALUE(tbl.$name)"; - } - else { - $selectColumns[] = "tbl.$name"; - } - } - - // add unique key on activity_id just to be sure - // this cannot be primary key because we need that for the auto_increment - // fixed_sort_order field - $sql .= " - UNIQUE KEY ( activity_id ) - ) ENGINE=HEAP DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci - "; - - CRM_Core_DAO::executeQuery($sql); - - $insertSQL = "INSERT IGNORE INTO {$activityTempTable} (" . implode(',', $insertValueSQL) . " ) "; - - $order = $limit = $groupBy = ''; - $groupBy = " GROUP BY tbl.activity_id, tbl.activity_type, tbl.case_id, tbl.case_subject "; - - if (!empty($input['sort'])) { - if (is_a($input['sort'], 'CRM_Utils_Sort')) { - $orderBy = $input['sort']->orderBy(); - if (!empty($orderBy)) { - $order = " ORDER BY $orderBy"; - } - } - elseif (trim($input['sort'])) { - $sort = CRM_Utils_Type::escape($input['sort'], 'String'); - $order = " ORDER BY $sort "; - } - } - - if (empty($order)) { - // context = 'activity' in Activities tab. - $order = " ORDER BY tbl.activity_date_time desc "; - } - - if (!empty($input['rowCount']) && - $input['rowCount'] > 0 - ) { - $limit = " LIMIT {$input['offset']}, {$input['rowCount']} "; - } - - $input['count'] = FALSE; - list($sqlClause, $params) = self::deprecatedGetActivitySQLClause($input); - - $query = sprintf("{$insertSQL} \n SELECT DISTINCT %s from ( %s ) \n as tbl ", implode(', ', $selectColumns), $sqlClause); - - // Filter case activities - CRM-5761. - $components = self::activityComponents(); - if (!in_array('CiviCase', $components)) { - $query .= " -LEFT JOIN civicrm_case_activity ON ( civicrm_case_activity.activity_id = tbl.activity_id ) - WHERE civicrm_case_activity.id IS NULL"; - } - - $query = $query . $groupBy . $order . $limit; - - $dao = CRM_Core_DAO::executeQuery($query, $params); - - // step 2: Get target and assignee contacts for above activities - // create temp table for target contacts - $activityContactTempTable = CRM_Utils_SQL_TempTable::build()->setCategory('actcontact')->getName(); - $query = "CREATE TEMPORARY TABLE {$activityContactTempTable} ( - activity_id int unsigned, contact_id int unsigned, record_type_id varchar(16), - contact_name varchar(255), is_deleted int unsigned, counter int unsigned, INDEX index_activity_id( activity_id ) ) - ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci"; - - CRM_Core_DAO::executeQuery($query); - - // note that we ignore bulk email for targets, since we don't show it in selector - $query = " -INSERT INTO {$activityContactTempTable} ( activity_id, contact_id, record_type_id, contact_name, is_deleted ) -SELECT ac.activity_id, - ac.contact_id, - ac.record_type_id, - c.sort_name, - c.is_deleted -FROM {$activityTempTable} -INNER JOIN civicrm_activity a ON ( a.id = {$activityTempTable}.activity_id ) -INNER JOIN civicrm_activity_contact ac ON ( ac.activity_id = {$activityTempTable}.activity_id ) -INNER JOIN civicrm_contact c ON c.id = ac.contact_id -WHERE ac.record_type_id != %1 -"; - $params = array(1 => array($targetID, 'Integer')); - CRM_Core_DAO::executeQuery($query, $params); - - $activityFields = array("ac.activity_id", "ac.contact_id", "ac.record_type_id", "c.sort_name", "c.is_deleted"); - $select = CRM_Contact_BAO_Query::appendAnyValueToSelect($activityFields, "ac.activity_id"); - - // for each activity insert one target contact - // if we load all target contacts the performance will suffer a lot for mass-activities. - $query = " -INSERT INTO {$activityContactTempTable} ( activity_id, contact_id, record_type_id, contact_name, is_deleted, counter ) -{$select}, count(ac.contact_id) -FROM {$activityTempTable} -INNER JOIN civicrm_activity a ON ( a.id = {$activityTempTable}.activity_id ) -INNER JOIN civicrm_activity_contact ac ON ( ac.activity_id = {$activityTempTable}.activity_id ) -INNER JOIN civicrm_contact c ON c.id = ac.contact_id -WHERE ac.record_type_id = %1 -GROUP BY ac.activity_id -"; - - CRM_Core_DAO::executeQuery($query, $params); - - // step 3: Combine all temp tables to get final query for activity selector - // sort by the original sort order, stored in fixed_sort_order - $query = " -SELECT {$activityTempTable}.*, - {$activityContactTempTable}.contact_id, - {$activityContactTempTable}.record_type_id, - {$activityContactTempTable}.contact_name, - {$activityContactTempTable}.is_deleted, - {$activityContactTempTable}.counter, - re.parent_id as is_recurring_activity -FROM {$activityTempTable} -INNER JOIN {$activityContactTempTable} on {$activityTempTable}.activity_id = {$activityContactTempTable}.activity_id -LEFT JOIN civicrm_recurring_entity re on {$activityContactTempTable}.activity_id = re.entity_id -ORDER BY fixed_sort_order - "; - - $dao = CRM_Core_DAO::executeQuery($query); - - // CRM-3553, need to check user has access to target groups. - $mailingIDs = CRM_Mailing_BAO_Mailing::mailingACLIDs(); - $accessCiviMail = ( - (CRM_Core_Permission::check('access CiviMail')) || - (CRM_Mailing_Info::workflowEnabled() && - CRM_Core_Permission::check('create mailings')) - ); - - // Get all campaigns. - $allCampaigns = CRM_Campaign_BAO_Campaign::getCampaigns(NULL, NULL, FALSE, FALSE, FALSE, TRUE); - $values = array(); - while ($dao->fetch()) { - $activityID = $dao->activity_id; - $values[$activityID]['activity_id'] = $dao->activity_id; - $values[$activityID]['source_record_id'] = $dao->source_record_id; - $values[$activityID]['activity_type_id'] = $dao->activity_type_id; - $values[$activityID]['activity_type'] = $dao->activity_type; - $values[$activityID]['activity_date_time'] = $dao->activity_date_time; - $values[$activityID]['status_id'] = $dao->status_id; - $values[$activityID]['subject'] = $dao->subject; - $values[$activityID]['campaign_id'] = $dao->campaign_id; - $values[$activityID]['is_recurring_activity'] = $dao->is_recurring_activity; - - if ($dao->campaign_id) { - $values[$activityID]['campaign'] = $allCampaigns[$dao->campaign_id]; - } - - if (empty($values[$activityID]['assignee_contact_name'])) { - $values[$activityID]['assignee_contact_name'] = array(); - } - - if (empty($values[$activityID]['target_contact_name'])) { - $values[$activityID]['target_contact_name'] = array(); - $values[$activityID]['target_contact_counter'] = $dao->counter; - } - - // if deleted, wrap in - if ($dao->is_deleted) { - $dao->contact_name = "{$dao->contact_name}"; - } - - if ($dao->record_type_id == $sourceID && $dao->contact_id) { - $values[$activityID]['source_contact_id'] = $dao->contact_id; - $values[$activityID]['source_contact_name'] = $dao->contact_name; - } - - if (!$bulkActivityTypeID || ($bulkActivityTypeID != $dao->activity_type_id)) { - // build array of target / assignee names - if ($dao->record_type_id == $targetID && $dao->contact_id) { - $values[$activityID]['target_contact_name'][$dao->contact_id] = $dao->contact_name; - } - if ($dao->record_type_id == $assigneeID && $dao->contact_id) { - $values[$activityID]['assignee_contact_name'][$dao->contact_id] = $dao->contact_name; - } - - // case related fields - $values[$activityID]['case_id'] = $dao->case_id; - $values[$activityID]['case_subject'] = $dao->case_subject; - } - else { - $values[$activityID]['recipients'] = ts('(%1 recipients)', array(1 => $dao->counter)); - $values[$activityID]['mailingId'] = FALSE; - if ( - $accessCiviMail && - ($mailingIDs === TRUE || in_array($dao->source_record_id, $mailingIDs)) - ) { - $values[$activityID]['mailingId'] = TRUE; - } - } - } - - return $values; - } - /** * @inheritDoc */ @@ -1210,234 +947,6 @@ public static function getActivitiesCount($input) { return civicrm_api3('Activity', 'getcount', $activityParams); } - /** - * Get the activity Count. - * - * @deprecated - * - * @param array $input - * Array of parameters. - * Keys include - * - contact_id int contact_id whose activities we want to retrieve - * - admin boolean if contact is admin - * - caseId int case ID - * - context string page on which selector is build - * - activity_type_id int|string the activity types we want to restrict by - * - * @return int - * count of activities - */ - public static function deprecatedGetActivitiesCount($input) { - $input['count'] = TRUE; - list($sqlClause, $params) = self::deprecatedGetActivitySQLClause($input); - - //filter case activities - CRM-5761 - $components = self::activityComponents(); - if (!in_array('CiviCase', $components)) { - $query = " - SELECT COUNT(DISTINCT(tbl.activity_id)) as count - FROM ( {$sqlClause} ) as tbl -LEFT JOIN civicrm_case_activity ON ( civicrm_case_activity.activity_id = tbl.activity_id ) - WHERE civicrm_case_activity.id IS NULL"; - } - else { - $query = "SELECT COUNT(DISTINCT(activity_id)) as count from ( {$sqlClause} ) as tbl"; - } - - return CRM_Core_DAO::singleValueQuery($query, $params); - } - - /** - * Get the activity sql clause to pick activities. - * - * @deprecated - * - * @param array $input - * Array of parameters. - * Keys include - * - contact_id int contact_id whose activities we want to retrieve - * - admin boolean if contact is admin - * - caseId int case ID - * - context string page on which selector is build - * - count boolean are we interested in the count clause only? - * - activity_type_id int|string the activity types we want to restrict by - * - * @return int - * count of activities - */ - public static function deprecatedGetActivitySQLClause($input) { - $params = array(); - $sourceWhere = $targetWhere = $assigneeWhere = $caseWhere = 1; - - $config = CRM_Core_Config::singleton(); - if (!CRM_Utils_Array::value('admin', $input, FALSE)) { - $sourceWhere = ' ac.contact_id = %1 '; - $caseWhere = ' civicrm_case_contact.contact_id = %1 '; - - $params = array(1 => array($input['contact_id'], 'Integer')); - } - - $commonClauses = array( - "civicrm_option_group.name = 'activity_type'", - "civicrm_activity.is_deleted = 0", - "civicrm_activity.is_current_revision = 1", - "civicrm_activity.is_test= 0", - ); - - if (isset($input['activity_date_relative']) || - (!empty($input['activity_date_low']) || !empty($input['activity_date_high'])) - ) { - list($from, $to) = CRM_Utils_Date::getFromTo( - CRM_Utils_Array::value('activity_date_relative', $input, 0), - CRM_Utils_Array::value('activity_date_low', $input), - CRM_Utils_Array::value('activity_date_high', $input) - ); - $commonClauses[] = sprintf('civicrm_activity.activity_date_time BETWEEN "%s" AND "%s" ', $from, $to); - } - - if (!empty($input['activity_status_id'])) { - $commonClauses[] = sprintf("civicrm_activity.status_id IN (%s)", $input['activity_status_id']); - } - - // Filter on component IDs. - $components = self::activityComponents(); - if (!empty($components)) { - $componentsIn = implode(',', array_keys($components)); - $commonClauses[] = "( civicrm_option_value.component_id IS NULL OR civicrm_option_value.component_id IN ( $componentsIn ) )"; - } - else { - $commonClauses[] = "civicrm_option_value.component_id IS NULL"; - } - - // activity type ID clause - if (!empty($input['activity_type_id'])) { - if (is_array($input['activity_type_id'])) { - foreach ($input['activity_type_id'] as $idx => $value) { - $input['activity_type_id'][$idx] = CRM_Utils_Type::escape($value, 'Positive'); - } - $commonClauses[] = "civicrm_activity.activity_type_id IN ( " . implode(",", $input['activity_type_id']) . " ) "; - } - else { - $activityTypeID = CRM_Utils_Type::escape($input['activity_type_id'], 'Positive'); - $commonClauses[] = "civicrm_activity.activity_type_id = $activityTypeID"; - } - } - - // exclude by activity type clause - if (!empty($input['activity_type_exclude_id'])) { - if (is_array($input['activity_type_exclude_id'])) { - foreach ($input['activity_type_exclude_id'] as $idx => $value) { - $input['activity_type_exclude_id'][$idx] = CRM_Utils_Type::escape($value, 'Positive'); - } - $commonClauses[] = "civicrm_activity.activity_type_id NOT IN ( " . implode(",", $input['activity_type_exclude_id']) . " ) "; - } - else { - $activityTypeID = CRM_Utils_Type::escape($input['activity_type_exclude_id'], 'Positive'); - $commonClauses[] = "civicrm_activity.activity_type_id != $activityTypeID"; - } - } - - $commonClause = implode(' AND ', $commonClauses); - - $includeCaseActivities = FALSE; - if (in_array('CiviCase', $components)) { - $includeCaseActivities = TRUE; - } - - // build main activity table select clause - $sourceSelect = ''; - - $activityContacts = CRM_Activity_BAO_ActivityContact::buildOptions('record_type_id', 'validate'); - $sourceID = CRM_Utils_Array::key('Activity Source', $activityContacts); - $sourceJoin = " -INNER JOIN civicrm_activity_contact ac ON ac.activity_id = civicrm_activity.id -INNER JOIN civicrm_contact contact ON ac.contact_id = contact.id -"; - - if (!$input['count']) { - $sourceSelect = ', - civicrm_activity.activity_date_time, - civicrm_activity.source_record_id, - civicrm_activity.status_id, - civicrm_activity.subject, - contact.sort_name as source_contact_name, - civicrm_option_value.value as activity_type_id, - civicrm_option_value.label as activity_type, - null as case_id, null as case_subject, - civicrm_activity.campaign_id as campaign_id - '; - - $sourceJoin .= " -LEFT JOIN civicrm_activity_contact src ON (src.activity_id = ac.activity_id AND src.record_type_id = {$sourceID} AND src.contact_id = contact.id) -"; - } - - $sourceClause = " - SELECT civicrm_activity.id as activity_id - {$sourceSelect} - from civicrm_activity - left join civicrm_option_value on - civicrm_activity.activity_type_id = civicrm_option_value.value - left join civicrm_option_group on - civicrm_option_group.id = civicrm_option_value.option_group_id - {$sourceJoin} - where - {$sourceWhere} - AND $commonClause - "; - - // Build case clause - // or else exclude Inbound Emails that have been filed on a case. - $caseClause = ''; - - if ($includeCaseActivities) { - $caseSelect = ''; - if (!$input['count']) { - $caseSelect = ', - civicrm_activity.activity_date_time, - civicrm_activity.source_record_id, - civicrm_activity.status_id, - civicrm_activity.subject, - contact.sort_name as source_contact_name, - civicrm_option_value.value as activity_type_id, - civicrm_option_value.label as activity_type, - null as case_id, null as case_subject, - civicrm_activity.campaign_id as campaign_id'; - } - - $caseClause = " - union all - - SELECT civicrm_activity.id as activity_id - {$caseSelect} - from civicrm_activity - inner join civicrm_case_activity on - civicrm_case_activity.activity_id = civicrm_activity.id - inner join civicrm_case on - civicrm_case_activity.case_id = civicrm_case.id - inner join civicrm_case_contact on - civicrm_case_contact.case_id = civicrm_case.id and {$caseWhere} - left join civicrm_option_value on - civicrm_activity.activity_type_id = civicrm_option_value.value - left join civicrm_option_group on - civicrm_option_group.id = civicrm_option_value.option_group_id - {$sourceJoin} - where - {$caseWhere} - AND $commonClause - and ( ( civicrm_case_activity.case_id IS NULL ) OR - ( civicrm_option_value.name <> 'Inbound Email' AND - civicrm_option_value.name <> 'Email' AND civicrm_case_activity.case_id - IS NOT NULL ) - ) - "; - } - - $returnClause = " {$sourceClause} {$caseClause} "; - - return array($returnClause, $params); - } - /** * Send the message to all the contacts. * @@ -2852,6 +2361,7 @@ protected static function getActivityParamsForDashboardFunctions($params) { 'is_current_revision' => 1, 'is_test' => 0, 'contact_id' => CRM_Utils_Array::value('contact_id', $params), + 'activity_date_time' => CRM_Utils_Array::value('activity_date_time', $params), 'check_permissions' => 1, 'options' => [ 'offset' => CRM_Utils_Array::value('offset', $params, 0), @@ -2919,12 +2429,13 @@ public static function getContactActivitySelector(&$params) { $activityIcons[$type['value']] = $type['icon']; } } + CRM_Utils_Date::convertFormDateToApiFormat($params, 'activity_date_time', FALSE); // Get contact activities. - $activities = CRM_Activity_BAO_Activity::deprecatedGetActivities($params); + $activities = CRM_Activity_BAO_Activity::getActivities($params); // Add total. - $params['total'] = CRM_Activity_BAO_Activity::deprecatedGetActivitiesCount($params); + $params['total'] = CRM_Activity_BAO_Activity::getActivitiesCount($params); // Format params and add links. $contactActivities = array(); @@ -2943,7 +2454,7 @@ public static function getContactActivitySelector(&$params) { $mask = CRM_Core_Action::mask($permissions); foreach ($activities as $activityId => $values) { - $activity = array(); + $activity = ['source_contact_name' => '', 'target_contact_name' => '']; $activity['DT_RowId'] = $activityId; // Add class to this row if overdue. $activity['DT_RowClass'] = "crm-entity status-id-{$values['status_id']}"; @@ -2961,7 +2472,6 @@ public static function getContactActivitySelector(&$params) { $activity['activity_type'] = (!empty($activityIcons[$values['activity_type_id']]) ? ' ' : '') . $values['activity_type']; $activity['subject'] = $values['subject']; - $activity['source_contact_name'] = ''; if ($params['contact_id'] == $values['source_contact_id']) { $activity['source_contact_name'] = $values['source_contact_name']; } @@ -2980,7 +2490,6 @@ public static function getContactActivitySelector(&$params) { $activity['source_contact_name'] = 'n/a'; } - $activity['target_contact_name'] = ''; if (isset($values['mailingId']) && !empty($values['mailingId'])) { $activity['target_contact'] = CRM_Utils_System::href($values['recipients'], 'civicrm/mailing/report/event', diff --git a/CRM/Activity/Page/AJAX.php b/CRM/Activity/Page/AJAX.php index e8be4c76e388..e44818dec64f 100644 --- a/CRM/Activity/Page/AJAX.php +++ b/CRM/Activity/Page/AJAX.php @@ -401,9 +401,9 @@ public static function getContactActivity() { 'activity_type_id' => 'Integer', 'activity_type_exclude_id' => 'Integer', 'activity_status_id' => 'String', - 'activity_date_relative' => 'String', - 'activity_date_low' => 'String', - 'activity_date_high' => 'String', + 'activity_date_time_relative' => 'String', + 'activity_date_time_low' => 'String', + 'activity_date_time_high' => 'String', ); $params = CRM_Core_Page_AJAX::defaultSortAndPagerParams(); diff --git a/CRM/Activity/Selector/Activity.php b/CRM/Activity/Selector/Activity.php index 544724ffde99..405fd50d02ef 100644 --- a/CRM/Activity/Selector/Activity.php +++ b/CRM/Activity/Selector/Activity.php @@ -358,7 +358,7 @@ public function getTotalCount($action, $case = NULL) { 'rowCount' => 0, 'sort' => NULL, ); - return CRM_Activity_BAO_Activity::deprecatedGetActivitiesCount($params); + return CRM_Activity_BAO_Activity::getActivitiesCount($params); } /** @@ -392,7 +392,7 @@ public function &getRows($action, $offset, $rowCount, $sort, $output = NULL, $ca 'sort' => $sort, ); $config = CRM_Core_Config::singleton(); - $rows = CRM_Activity_BAO_Activity::deprecatedGetActivities($params); + $rows = CRM_Activity_BAO_Activity::getActivities($params); if (empty($rows)) { return $rows; diff --git a/CRM/Contact/BAO/Contact.php b/CRM/Contact/BAO/Contact.php index 561f60777f1d..cea1e9da86aa 100644 --- a/CRM/Contact/BAO/Contact.php +++ b/CRM/Contact/BAO/Contact.php @@ -2734,7 +2734,7 @@ public static function getCountComponent($component, $contactId, $tableName = NU 'caseId' => NULL, 'context' => 'activity', ); - return CRM_Activity_BAO_Activity::deprecatedGetActivitiesCount($input); + return CRM_Activity_BAO_Activity::getActivitiesCount($input); case 'mailing': $params = array('contact_id' => $contactId); diff --git a/CRM/Utils/Date.php b/CRM/Utils/Date.php index 4223ab35eff8..e1fa77bcf4a0 100644 --- a/CRM/Utils/Date.php +++ b/CRM/Utils/Date.php @@ -2170,4 +2170,41 @@ public static function getCalendarDayOfMonth() { return $month; } + + /** + * Convert a relative date format to an api field. + * + * @param array $params + * @param string $dateField + * @param bool $isDatePicker + * Non datepicker fields are deprecated. Exterminate Exterminate. + * (but for now handle them). + */ + public static function convertFormDateToApiFormat(&$params, $dateField, $isDatePicker = TRUE) { + if (!empty($params[$dateField . '_relative'])) { + $dates = CRM_Utils_Date::getFromTo($params[$dateField . '_relative'], NULL, NULL); + unset($params[$dateField . '_relative']); + } + if (!empty($params[$dateField . '_low'])) { + $dates[0] = $isDatePicker ? $params[$dateField . '_low'] : date('Y-m-d H:i:s', strtotime($params[$dateField . '_low'])); + unset($params[$dateField . '_low']); + } + if (!empty($params[$dateField . '_high'])) { + $dates[1] = $isDatePicker ? $params[$dateField . '_high'] : date('Y-m-d 23:59:59', strtotime($params[$dateField . '_high'])); + unset($params[$dateField . '_high']); + } + if (empty($dates)) { + return; + } + if (empty($dates[0])) { + $params[$dateField] = ['<=' => $dates[1]]; + } + elseif (empty($dates[1])) { + $params[$dateField] = ['>=' => $dates[0]]; + } + else { + $params[$dateField] = ['BETWEEN' => $dates]; + } + } + } diff --git a/templates/CRM/Activity/Selector/Selector.tpl b/templates/CRM/Activity/Selector/Selector.tpl index d3986fc8163d..03dd2fc38a81 100644 --- a/templates/CRM/Activity/Selector/Selector.tpl +++ b/templates/CRM/Activity/Selector/Selector.tpl @@ -71,9 +71,9 @@ var status_id = $('.crm-activity-selector-' + context + ' select#status_id').val() || []; d.activity_type_id = $('.crm-activity-selector-' + context + ' select#activity_type_filter_id').val(), d.activity_type_exclude_id = $('.crm-activity-selector-' + context + ' select#activity_type_exclude_filter_id').val(), - d.activity_date_relative = $('select#activity_date_relative').val(), - d.activity_date_low = $('#activity_date_low').val(), - d.activity_date_high = $('#activity_date_high').val(), + d.activity_date_time_relative = $('select#activity_date_relative').val(), + d.activity_date_time_low = $('#activity_date_low').val(), + d.activity_date_time_high = $('#activity_date_high').val(), d.activity_status_id = status_id.join(',') } } diff --git a/tests/phpunit/CRM/Activity/BAO/ActivityTest.php b/tests/phpunit/CRM/Activity/BAO/ActivityTest.php index 988148cf622b..1921d5ef1565 100644 --- a/tests/phpunit/CRM/Activity/BAO/ActivityTest.php +++ b/tests/phpunit/CRM/Activity/BAO/ActivityTest.php @@ -322,8 +322,6 @@ public function testDeleteActivityAssignment() { */ public function testGetActivitiesCountForAdminDashboard() { $this->setUpForActivityDashboardTests(); - $activityCount = CRM_Activity_BAO_Activity::deprecatedGetActivitiesCount($this->_params); - $this->assertEquals(8, $activityCount); $activityCount = CRM_Activity_BAO_Activity::getActivitiesCount($this->_params); $this->assertEquals(8, $activityCount); } @@ -351,12 +349,8 @@ public function testGetActivitiesCountforNonAdminDashboard() { 'sort' => NULL, ); - $activityCount = CRM_Activity_BAO_Activity::deprecatedGetActivitiesCount($params); - //since we are loading activities from dataset, we know total number of activities for this contact // 5 activities ( 2 scheduled, 3 Completed ), note that dashboard shows only scheduled activities - $count = 2; - $this->assertEquals($count, $activityCount); $this->assertEquals(2, CRM_Activity_BAO_Activity::getActivitiesCount($params)); } @@ -381,12 +375,9 @@ public function testGetActivitiesCountforContactSummary() { 'rowCount' => 0, 'sort' => NULL, ); - $activityCount = CRM_Activity_BAO_Activity::deprecatedGetActivitiesCount($params); //since we are loading activities from dataset, we know total number of activities for this contact // 5 activities, Contact Summary should show all activities - $count = 5; - $this->assertEquals($count, $activityCount); $this->assertEquals(5, CRM_Activity_BAO_Activity::getActivitiesCount($params)); } @@ -455,11 +446,9 @@ public function testGetActivitiesCountforContactSummaryWithNoActivities() { 'rowCount' => 0, 'sort' => NULL, ); - $activityCount = CRM_Activity_BAO_Activity::deprecatedGetActivitiesCount($params); //since we are loading activities from dataset, we know total number of activities for this contact // this contact does not have any activity - $this->assertEquals(0, $activityCount); $this->assertEquals(0, CRM_Activity_BAO_Activity::getActivitiesCount($params)); } @@ -468,14 +457,13 @@ public function testGetActivitiesCountforContactSummaryWithNoActivities() { */ public function testGetActivitiesForAdminDashboard() { $this->setUpForActivityDashboardTests(); - $activitiesDeprecatedFn = CRM_Activity_BAO_Activity::deprecatedGetActivities($this->_params); $activitiesNew = CRM_Activity_BAO_Activity::getActivities($this->_params); // $this->assertEquals($activities, $activitiesDeprecatedFn); //since we are loading activities from dataset, we know total number of activities // with no contact ID and there should be 8 schedule activities shown on dashboard $count = 8; - foreach (array($activitiesNew, $activitiesDeprecatedFn) as $activities) { + foreach (array($activitiesNew) as $activities) { $this->assertEquals($count, count($activities)); foreach ($activities as $key => $value) { @@ -492,10 +480,9 @@ public function testGetActivitiesForAdminDashboard() { public function testGetActivitiesForAdminDashboardNoViewContacts() { CRM_Core_Config::singleton()->userPermissionClass->permissions = array('access CiviCRM'); $this->setUpForActivityDashboardTests(); - $activitiesDeprecated = CRM_Activity_BAO_Activity::deprecatedGetActivities($this->_params); - foreach (array($activitiesDeprecated, CRM_Activity_BAO_Activity::getActivities($this->_params)) as $activities) { + foreach (array(CRM_Activity_BAO_Activity::getActivities($this->_params)) as $activities) { // Skipped until we get back to the upgraded version properly. - //$this->assertEquals(0, count($activities)); + $this->assertEquals(0, count($activities)); } } @@ -507,11 +494,7 @@ public function testGetActivitiesForAdminDashboardAclLimitedViewContacts() { $this->allowedContacts = array(1, 3, 4, 5); $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereMultipleContacts')); $this->setUpForActivityDashboardTests(); - $activitiesDeprecated = CRM_Activity_BAO_Activity::deprecatedGetActivities($this->_params); - foreach (array($activitiesDeprecated, CRM_Activity_BAO_Activity::getActivities($this->_params)) as $activities) { - //$this->assertEquals(1, count($activities)); - } - + $this->assertEquals(7, count(CRM_Activity_BAO_Activity::getActivities($this->_params))); } /** @@ -537,9 +520,8 @@ public function testGetActivitiesforNonAdminDashboard() { 'rowCount' => 0, 'sort' => NULL, ); - $activitiesDep = CRM_Activity_BAO_Activity::deprecatedGetActivities($params); - foreach (array($activitiesDep, CRM_Activity_BAO_Activity::getActivities($params)) as $activities) { + foreach (array(CRM_Activity_BAO_Activity::getActivities($params)) as $activities) { //since we are loading activities from dataset, we know total number of activities for this contact // 5 activities ( 2 scheduled, 3 Completed ), note that dashboard shows only scheduled activities $count = 2; @@ -581,8 +563,7 @@ public function testTargetCountforContactSummary() { 'contact_id' => $contactId, 'context' => 'activity', ); - $activitiesDep = CRM_Activity_BAO_Activity::deprecatedGetActivities($params); - foreach (array($activitiesDep, CRM_Activity_BAO_Activity::getActivities($params)) as $activities) { + foreach (array(CRM_Activity_BAO_Activity::getActivities($params)) as $activities) { //verify target count $this->assertEquals($targetCount, $activities[1]['target_contact_counter']); $this->assertEquals([$targetContactIDs[0] => 'Anderson, Anthony'], $activities[1]['target_contact_name']); @@ -612,12 +593,11 @@ public function testGetActivitiesforContactSummary() { 'rowCount' => 0, 'sort' => NULL, ); - $activitiesDep = CRM_Activity_BAO_Activity::deprecatedGetActivities($params); //since we are loading activities from dataset, we know total number of activities for this contact // 5 activities, Contact Summary should show all activities $count = 5; - foreach (array($activitiesDep, CRM_Activity_BAO_Activity::getActivities($params)) as $activities) { + foreach (array(CRM_Activity_BAO_Activity::getActivities($params)) as $activities) { $this->assertEquals($count, count($activities)); @@ -724,11 +704,10 @@ public function testGetActivitiesforContactSummaryWithActivities() { ); foreach ($testCases as $caseName => $testCase) { - $activitiesDep = CRM_Activity_BAO_Activity::deprecatedGetActivities($testCase['params']); - $activityCount = CRM_Activity_BAO_Activity::deprecatedGetActivitiesCount($testCase['params']); + $activityCount = CRM_Activity_BAO_Activity::getActivitiesCount($testCase['params']); $activitiesNew = CRM_Activity_BAO_Activity::getActivities($testCase['params']); - foreach (array($activitiesDep, $activitiesNew) as $activities) { + foreach (array($activitiesNew) as $activities) { //$this->assertEquals($activityCount, CRM_Activity_BAO_Activity::getActivitiesCount($testCase['params'])); if ($caseName == 'with-no-activity') { $this->assertEquals(0, count($activities)); @@ -782,6 +761,7 @@ public function testGetActivitiesforContactSummaryWithActivities() { * CRM-20793 : Test getActivities by using activity date and status filter */ public function testByActivityDateAndStatus() { + CRM_Core_Config::singleton()->userPermissionClass->permissions = ['view all contacts', 'access CiviCRM']; $op = new PHPUnit_Extensions_Database_Operation_Insert(); $op->execute($this->_dbconn, $this->createFlatXMLDataSet( @@ -829,7 +809,7 @@ public function testByActivityDateAndStatus() { 'admin' => TRUE, 'caseId' => NULL, 'context' => 'activity', - 'activity_date_relative' => 'this.day', + 'activity_date_time_relative' => 'this.day', 'activity_type_id' => NULL, 'offset' => 0, 'rowCount' => 0, @@ -842,8 +822,8 @@ public function testByActivityDateAndStatus() { 'admin' => TRUE, 'caseId' => NULL, 'context' => 'activity', - 'activity_date_low' => date('Y/m/d', strtotime('yesterday')), - 'activity_date_high' => date('Y/m/d'), + 'activity_date_time_low' => date('Y/m/d', strtotime('yesterday')), + 'activity_date_time_high' => date('Y/m/d'), 'activity_type_id' => NULL, 'offset' => 0, 'rowCount' => 0, @@ -856,7 +836,7 @@ public function testByActivityDateAndStatus() { 'admin' => TRUE, 'caseId' => NULL, 'context' => 'activity', - 'activity_date_relative' => 'previous.week', + 'activity_date_time_relative' => 'previous.week', 'activity_type_id' => NULL, 'offset' => 0, 'rowCount' => 0, @@ -869,7 +849,7 @@ public function testByActivityDateAndStatus() { 'admin' => TRUE, 'caseId' => NULL, 'context' => 'activity', - 'activity_date_relative' => 'this.quarter', + 'activity_date_time_relative' => 'this.quarter', 'activity_type_id' => NULL, 'offset' => 0, 'rowCount' => 0, @@ -892,34 +872,37 @@ public function testByActivityDateAndStatus() { ); foreach ($testCases as $caseName => $testCase) { - $activitiesDep = CRM_Activity_BAO_Activity::deprecatedGetActivities($testCase['params']); - $activityCount = CRM_Activity_BAO_Activity::deprecatedGetActivitiesCount($testCase['params']); - asort($activitiesDep); - $activityIDs = array_keys($activitiesDep); + CRM_Utils_Date::convertFormDateToApiFormat($testCase['params'], 'activity_date_time', FALSE); + $activities = CRM_Activity_BAO_Activity::getActivities($testCase['params']); + $activityCount = CRM_Activity_BAO_Activity::getActivitiesCount($testCase['params']); + asort($activities); + $activityIDs = array_keys($activities); if ($caseName == 'todays-activity' || $caseName == 'todays-activity-filtered-by-range') { - $this->assertEquals(count($todayActivities), $activityCount); - $this->assertEquals(count($todayActivities), count($activitiesDep)); - $this->checkArrayEquals($todayActivities, $activityIDs); + // Only one of the 4 activities today relates to contact id 1. + $this->assertEquals(1, $activityCount); + $this->assertEquals(1, count($activities)); + $this->assertEquals([7], array_keys($activities)); } elseif ($caseName == 'last-week-activity') { - $this->assertEquals(count($lastWeekActivities), $activityCount); - $this->assertEquals(count($lastWeekActivities), count($activitiesDep)); - $this->checkArrayEquals($lastWeekActivities, $activityIDs); + // Only one of the 3 activities today relates to contact id 1. + $this->assertEquals(1, $activityCount); + $this->assertEquals(1, count($activities)); + $this->assertEquals([1], $activityIDs); } elseif ($caseName == 'lhis-quarter-activity') { $this->assertEquals(count($lastTwoMonthsActivities), $activityCount); - $this->assertEquals(count($lastTwoMonthsActivities), count($activitiesDep)); + $this->assertEquals(count($lastTwoMonthsActivities), count($activities)); $this->checkArrayEquals($lastTwoMonthsActivities, $activityIDs); } elseif ($caseName == 'last-or-next-year-activity') { $this->assertEquals(count($lastOrNextYearActivities), $activityCount); - $this->assertEquals(count($lastOrNextYearActivities), count($activitiesDep)); + $this->assertEquals(count($lastOrNextYearActivities), count($activities)); $this->checkArrayEquals($lastOrNextYearActivities, $activityIDs); } elseif ($caseName == 'activity-of-all-statuses') { - $this->assertEquals(16, $activityCount); - $this->assertEquals(16, count($activitiesDep)); + $this->assertEquals(3, $activityCount); + $this->assertEquals(3, count($activities)); } } } @@ -940,8 +923,8 @@ public function testActivityRelativeDateFilter($params, $expected) { foreach ($dates as $date) { $this->activityCreate(['activity_date_time' => $date]); } - $activitiesDep = CRM_Activity_BAO_Activity::deprecatedGetActivities($params); - $activityCount = CRM_Activity_BAO_Activity::deprecatedGetActivitiesCount($params); + $activitiesDep = CRM_Activity_BAO_Activity::getActivities($params); + $activityCount = CRM_Activity_BAO_Activity::getActivitiesCount($params); $this->assertEquals(count($activitiesDep), $activityCount); foreach ($activitiesDep as $activity) { $this->assertTrue(strtotime($activity['activity_date_time']) >= $expected['earliest'], $activity['activity_date_time'] . ' should be no earlier than ' . date('Y-m-d H:i:s', $expected['earliest'])); From 7f6e5735befa1c9db67e98c96d057cc53ea4b17c Mon Sep 17 00:00:00 2001 From: eileen Date: Fri, 15 Mar 2019 15:29:12 +1300 Subject: [PATCH 059/408] --amend Change-Id: Icea6f894d7a9e4656beae3cdb4cb5e44842b59b2 --- CRM/Activity/Form/ActivityFilter.php | 2 +- templates/CRM/Activity/Selector/Selector.tpl | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CRM/Activity/Form/ActivityFilter.php b/CRM/Activity/Form/ActivityFilter.php index 46ff5fcfbf12..ba3c66f34081 100644 --- a/CRM/Activity/Form/ActivityFilter.php +++ b/CRM/Activity/Form/ActivityFilter.php @@ -43,7 +43,7 @@ public function buildQuickForm() { $this->add('select', 'activity_type_filter_id', ts('Include'), array('' => ts('- all activity type(s) -')) + $activityOptions); $this->add('select', 'activity_type_exclude_filter_id', ts('Exclude'), array('' => ts('- select activity type -')) + $activityOptions); CRM_Core_Form_Date::buildDateRange( - $this, 'activity_date', 1, + $this, 'activity_date_time', 1, '_low', '_high', ts('From:'), FALSE, array(), 'searchDate', FALSE, array('class' => 'crm-select2 medium') diff --git a/templates/CRM/Activity/Selector/Selector.tpl b/templates/CRM/Activity/Selector/Selector.tpl index 03dd2fc38a81..fc44167a6885 100644 --- a/templates/CRM/Activity/Selector/Selector.tpl +++ b/templates/CRM/Activity/Selector/Selector.tpl @@ -37,7 +37,7 @@ {$form.activity_type_exclude_filter_id.label}
{$form.activity_type_exclude_filter_id.html|crmAddClass:medium} - {include file="CRM/Core/DateRange.tpl" fieldName="activity_date" from='_low' to='_high' label=''} + {include file="CRM/Core/DateRange.tpl" fieldName="activity_date_time" from='_low' to='_high' label=''}
{$form.status_id.html|crmAddClass:medium} @@ -53,7 +53,7 @@ {ts}Added By{/ts} {ts}With{/ts} {ts}Assigned{/ts} - {ts}Date{/ts} + {ts}Date{/ts} {ts}Status{/ts}   @@ -71,9 +71,9 @@ var status_id = $('.crm-activity-selector-' + context + ' select#status_id').val() || []; d.activity_type_id = $('.crm-activity-selector-' + context + ' select#activity_type_filter_id').val(), d.activity_type_exclude_id = $('.crm-activity-selector-' + context + ' select#activity_type_exclude_filter_id').val(), - d.activity_date_time_relative = $('select#activity_date_relative').val(), - d.activity_date_time_low = $('#activity_date_low').val(), - d.activity_date_time_high = $('#activity_date_high').val(), + d.activity_date_time_relative = $('select#activity_date_time_relative').val(), + d.activity_date_time_low = $('#activity_date_time_low').val(), + d.activity_date_time_high = $('#activity_date_time_high').val(), d.activity_status_id = status_id.join(',') } } From a7aa881ce2578ab5239970f1a872d87727d5fd27 Mon Sep 17 00:00:00 2001 From: "Matthew Wire (MJW Consulting)" Date: Fri, 15 Mar 2019 11:02:55 +0000 Subject: [PATCH 060/408] Whitespace on MembershipBlock.tpl --- .../Form/Contribution/MembershipBlock.tpl | 392 +++++++++--------- 1 file changed, 196 insertions(+), 196 deletions(-) diff --git a/templates/CRM/Contribute/Form/Contribution/MembershipBlock.tpl b/templates/CRM/Contribute/Form/Contribution/MembershipBlock.tpl index 126e7c33f5a8..9fe630106126 100644 --- a/templates/CRM/Contribute/Form/Contribution/MembershipBlock.tpl +++ b/templates/CRM/Contribute/Form/Contribution/MembershipBlock.tpl @@ -24,279 +24,279 @@ +--------------------------------------------------------------------+ *} {if !empty($useForMember) AND !$is_quick_config} -
-{if $context EQ "makeContribution"} -
+
+ {if $context EQ "makeContribution"} +
- {if $renewal_mode} + {if $renewal_mode} {if $membershipBlock.renewal_title} - {$membershipBlock.renewal_title} + {$membershipBlock.renewal_title} {/if} {if $membershipBlock.renewal_text} -
- {$membershipBlock.renewal_text} -
+
+ {$membershipBlock.renewal_text} +
{/if} - {else} - {if $membershipBlock.new_title} + {else} + {if $membershipBlock.new_title} {$membershipBlock.new_title} - {/if} - {if $membershipBlock.new_text} + {/if} + {if $membershipBlock.new_text}
- {$membershipBlock.new_text} + {$membershipBlock.new_text}
+ {/if} {/if} - {/if} - {if !empty($membershipTypes)} + {if !empty($membershipTypes)} {foreach from=$membershipTypes item=row} - {if array_key_exists( 'current_membership', $row )} -
- {* Lifetime memberships have no end-date so current_membership array key exists but is NULL *} - {if $row.current_membership} - {if $row.current_membership|date_format:"%Y%m%d" LT $smarty.now|date_format:"%Y%m%d"} - {ts 1=$row.current_membership|crmDate 2=$row.name}Your %2 membership expired on %1.{/ts}
- {else} - {ts 1=$row.current_membership|crmDate 2=$row.name}Your %2 membership expires on %1.{/ts}
- {/if} + {if array_key_exists( 'current_membership', $row )} +
+ {* Lifetime memberships have no end-date so current_membership array key exists but is NULL *} + {if $row.current_membership} + {if $row.current_membership|date_format:"%Y%m%d" LT $smarty.now|date_format:"%Y%m%d"} + {ts 1=$row.current_membership|crmDate 2=$row.name}Your %2 membership expired on %1.{/ts}
{else} - {ts 1=$row.name}Your %1 membership does not expire (you do not need to renew that membership).{/ts}
+ {ts 1=$row.current_membership|crmDate 2=$row.name}Your %2 membership expires on %1.{/ts}
{/if} -
- {/if} + {else} + {ts 1=$row.name}Your %1 membership does not expire (you do not need to renew that membership).{/ts}
+ {/if} +
+ {/if} {/foreach} - {/if} + {/if} - {include file="CRM/Price/Form/PriceSet.tpl" extends="Membership"} + {include file="CRM/Price/Form/PriceSet.tpl" extends="Membership"}
-
-{elseif $lineItem and $priceSetID AND !$is_quick_config} - {assign var="totalAmount" value=$amount} -
- {ts}Membership Fee{/ts} -
-
- {include file="CRM/Price/Page/LineItem.tpl" context="Membership"} +
+ {elseif $lineItem and $priceSetID AND !$is_quick_config} + {assign var="totalAmount" value=$amount} +
+ {ts}Membership Fee{/ts} +
+
+ {include file="CRM/Price/Page/LineItem.tpl" context="Membership"} +
+ {/if}
-{/if} -
{literal} - + } + }); + {/literal} {elseif $membershipBlock AND !$is_quick_config} -
- {if $context EQ "makeContribution"} -
+
+ {if $context EQ "makeContribution"} +
{if $renewal_mode } {if $membershipBlock.renewal_title} - {$membershipBlock.renewal_title} + {$membershipBlock.renewal_title} {/if} {if $membershipBlock.renewal_text} -
-

{$membershipBlock.renewal_text}

-
+
+

{$membershipBlock.renewal_text}

+
{/if} {else} {if $membershipBlock.new_title} - {$membershipBlock.new_title} + {$membershipBlock.new_title} {/if} {if $membershipBlock.new_text} -
-

{$membershipBlock.new_text}

-
+
+

{$membershipBlock.new_text}

+
{/if} {/if} - {/if} - {if $context neq "makeContribution" } + {/if} + {if $context neq "makeContribution" }
- {if $renewal_mode } - {if $membershipBlock.renewal_title} - {$membershipBlock.renewal_title} - {else} - {ts}Select a Membership Renewal Level{/ts} - {/if} + {if $renewal_mode } + {if $membershipBlock.renewal_title} + {$membershipBlock.renewal_title} + {else} + {ts}Select a Membership Renewal Level{/ts} + {/if} + {else} + {if $membershipBlock.new_title} + {$membershipBlock.new_title} {else} - {if $membershipBlock.new_title} - {$membershipBlock.new_title} - {else} - {ts}Select a Membership Level{/ts} - {/if} + {ts}Select a Membership Level{/ts} {/if} + {/if}
- {/if} + {/if} - {if $context EQ "makeContribution"} -
+ {if $context EQ "makeContribution"} +
{/if} -
+
{/if}{* membership block end here *} {if $membershipBlock AND $is_quick_config} -{if $context neq "makeContribution" } -
- {if $renewal_mode } - {if $membershipBlock.renewal_title} - {$membershipBlock.renewal_title} - {else} - {ts}Select a Membership Renewal Level{/ts} - {/if} - {else} - {if $membershipBlock.new_title} - {$membershipBlock.new_title} - {else} - {ts}Select a Membership Level{/ts} - {/if} + {if $context neq "makeContribution" } +
+ {if $renewal_mode } + {if $membershipBlock.renewal_title} + {$membershipBlock.renewal_title} + {else} + {ts}Select a Membership Renewal Level{/ts} + {/if} + {else} + {if $membershipBlock.new_title} + {$membershipBlock.new_title} + {else} + {ts}Select a Membership Level{/ts} {/if} + {/if}
-{/if} - {strip} - - {foreach from=$membershipTypes item=row} + {/if} + {strip} +
+ {foreach from=$membershipTypes item=row} - {if $showRadio } - {assign var="pid" value=$row.id} - - {else} - - {/if} - + {else} + + {/if} + + {$row.description}   + - + {else} +   + {/if} + - {/foreach} + {/foreach} {if isset($form.auto_renew) } - + + + {/if} + {if $showRadio} + {if $showRadioNoThanks } {* Provide no-thanks option when Membership signup is not required - per membership block configuration. *} + + + {/if} - {if $showRadio} - {if $showRadioNoThanks } {* Provide no-thanks option when Membership signup is not required - per membership block configuration. *} - - - - - {/if} - {/if} -
{$form.selectMembership.$pid.html}  + {if $showRadio } + {assign var="pid" value=$row.id} + {$form.selectMembership.$pid.html}  {$row.name}   {if ($membershipBlock.display_min_fee AND $context EQ "makeContribution") AND $row.minimum_fee GT 0 } - {if $is_separate_payment OR ! $form.amount.label} - – {$row.minimum_fee|crmMoney} - {else} - {ts 1=$row.minimum_fee|crmMoney}(contribute at least %1 to be eligible for this membership){/ts} - {/if} + {if $is_separate_payment OR ! $form.amount.label} + – {$row.minimum_fee|crmMoney} + {else} + {ts 1=$row.minimum_fee|crmMoney}(contribute at least %1 to be eligible for this membership){/ts} + {/if} {/if}
- {$row.description}   -
- {* Check if there is an existing membership of this type (current_membership NOT empty) and if the end-date is prior to today. *} - {if array_key_exists( 'current_membership', $row ) AND $context EQ "makeContribution" } - {if $row.current_membership} - {if $row.current_membership|date_format:"%Y%m%d" LT $smarty.now|date_format:"%Y%m%d"} -
{ts 1=$row.current_membership|crmDate 2=$row.name}Your %2 membership expired on %1.{/ts} - {else} -
{ts 1=$row.current_membership|crmDate 2=$row.name}Your %2 membership expires on %1.{/ts} - {/if} - {else} - {ts 1=$row.name}Your %1 membership does not expire (you do not need to renew that membership).{/ts}
- {/if} +
+ {* Check if there is an existing membership of this type (current_membership NOT empty) and if the end-date is prior to today. *} + {if array_key_exists( 'current_membership', $row ) AND $context EQ "makeContribution" } + {if $row.current_membership} + {if $row.current_membership|date_format:"%Y%m%d" LT $smarty.now|date_format:"%Y%m%d"} +
{ts 1=$row.current_membership|crmDate 2=$row.name}Your %2 membership expired on %1.{/ts} + {else} +
{ts 1=$row.current_membership|crmDate 2=$row.name}Your %2 membership expires on %1.{/ts} + {/if} {else} -   + {ts 1=$row.name}Your %1 membership does not expire (you do not need to renew that membership).{/ts}
{/if} -
{$form.auto_renew.html} - {$form.auto_renew.label} + {$form.auto_renew.label}
{$form.selectMembership.no_thanks.html}{ts}No thank you{/ts}
{$form.selectMembership.no_thanks.html}{ts}No thank you{/ts}
- {/strip} + {/if} + + {/strip} {/if} {* Include JS for auto renew membership if priceset is Quick Config*} {if $membershipBlock} {literal} - + }); + }); + {/literal}{/if}{literal} + {/literal} {/if} From c7b43c699aca6eccca4f6469acf6b5b68051e06a Mon Sep 17 00:00:00 2001 From: eileen Date: Sat, 16 Mar 2019 09:35:03 +1300 Subject: [PATCH 061/408] Add more data when test fails --- tests/phpunit/api/v3/LoggingTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/phpunit/api/v3/LoggingTest.php b/tests/phpunit/api/v3/LoggingTest.php index eaa9fdb64159..4b2a9faf449e 100644 --- a/tests/phpunit/api/v3/LoggingTest.php +++ b/tests/phpunit/api/v3/LoggingTest.php @@ -443,7 +443,7 @@ public function assertLoggingIncludes($diffs, $expect) { return TRUE; } } - throw new CRM_Core_Exception("No match found for key : $expectKey with value : $expectValue"); + throw new CRM_Core_Exception("No match found for key : $expectKey with value : $expectValue" . print_r($diffs, 1)); } /** From d7a2d3159754bcf0dbba538d60c3b135ff144d8a Mon Sep 17 00:00:00 2001 From: eileen Date: Sat, 16 Mar 2019 09:36:34 +1300 Subject: [PATCH 062/408] Attempt to fix test with 1 second delay (note in 'real life' the events are not generally so close together --- tests/phpunit/api/v3/LoggingTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/phpunit/api/v3/LoggingTest.php b/tests/phpunit/api/v3/LoggingTest.php index 4b2a9faf449e..f79a2745811e 100644 --- a/tests/phpunit/api/v3/LoggingTest.php +++ b/tests/phpunit/api/v3/LoggingTest.php @@ -412,6 +412,9 @@ public function testGetNoDate() { $contactId = $this->individualCreate(); $this->callAPISuccess('Setting', 'create', array('logging' => TRUE)); CRM_Core_DAO::executeQuery("SET @uniqueID = 'wooty wop wop'"); + // Perhaps if initialize & create are exactly the same time it can't cope. + // 1 second delay + sleep(1); $this->callAPISuccess('Contact', 'create', array( 'id' => $contactId, 'first_name' => 'Dopey', From 2f0db03468f8b0813e8e551e6674fda938b7b76a Mon Sep 17 00:00:00 2001 From: Seamus Lee Date: Sat, 16 Mar 2019 08:09:55 +1100 Subject: [PATCH 063/408] Deploy PEAR Log package and upgrade to latest version in the process --- composer.json | 3 ++- composer.lock | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index d08ba21edfb5..4bf16d0bd346 100644 --- a/composer.json +++ b/composer.json @@ -59,7 +59,8 @@ "civicrm/civicrm-setup": "~0.2.0", "guzzlehttp/guzzle": "^6.3", "psr/simple-cache": "~1.0.1", - "cweagans/composer-patches": "~1.0" + "cweagans/composer-patches": "~1.0", + "pear/log": "1.13.1" }, "repositories": [ { diff --git a/composer.lock b/composer.lock index 881fda86660d..c9e1fdca310b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "0f9eab6b0bf1c120dace5cf229223605", + "content-hash": "17588dc1a1e09a5f449c38e1169c4209", "packages": [ { "name": "civicrm/civicrm-cxn-rpc", @@ -591,6 +591,59 @@ "description": "More info available on: http://pear.php.net/package/Console_Getopt", "time": "2015-07-20T20:28:12+00:00" }, + { + "name": "pear/log", + "version": "1.13.1", + "source": { + "type": "git", + "url": "https://github.com/pear/Log.git", + "reference": "c4be9ded2353c7c231d4c35cc3da75b209453803" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pear/Log/zipball/c4be9ded2353c7c231d4c35cc3da75b209453803", + "reference": "c4be9ded2353c7c231d4c35cc3da75b209453803", + "shasum": "" + }, + "require": { + "pear/pear_exception": "1.0.0", + "php": ">5.2" + }, + "require-dev": { + "phpunit/phpunit": "*" + }, + "suggest": { + "pear/db": "Install optionally via your project's composer.json" + }, + "type": "library", + "autoload": { + "psr-0": { + "Log": "./" + } + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jon Parise", + "email": "jon@php.net", + "homepage": "http://www.indelible.org", + "role": "Developer" + } + ], + "description": "PEAR Logging Framework", + "homepage": "http://pear.github.io/Log/", + "keywords": [ + "log", + "logging" + ], + "time": "2016-04-16T00:49:33+00:00" + }, { "name": "pear/mail", "version": "v1.4.1", From 18fe20ebde71c79cc571c74bb3bd9a7db5c8eace Mon Sep 17 00:00:00 2001 From: eileen Date: Sat, 16 Mar 2019 10:11:45 +1300 Subject: [PATCH 064/408] [NFC] remove unnecessary variable --- CRM/Event/Form/Registration/Confirm.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CRM/Event/Form/Registration/Confirm.php b/CRM/Event/Form/Registration/Confirm.php index 8557a30dec30..d7475ca9c9e4 100644 --- a/CRM/Event/Form/Registration/Confirm.php +++ b/CRM/Event/Form/Registration/Confirm.php @@ -527,8 +527,7 @@ public function postProcess() { // transactions etc // for things like tell a friend if (!$this->getContactID() && !empty($value['is_primary'])) { - $session = CRM_Core_Session::singleton(); - $session->set('transaction.userID', $contactID); + CRM_Core_Session::singleton()->set('transaction.userID', $contactID); } $value['description'] = ts('Online Event Registration') . ': ' . $this->_values['event']['title']; From 3c884887c1104f3359e9450923326df0e6e4c689 Mon Sep 17 00:00:00 2001 From: eileen Date: Sat, 16 Mar 2019 10:31:50 +1300 Subject: [PATCH 065/408] Minor code cleanup - remove unnecessary ids declaration is not used is only used to set ['id'] so this can be simplified --- CRM/Event/Form/Registration/Confirm.php | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/CRM/Event/Form/Registration/Confirm.php b/CRM/Event/Form/Registration/Confirm.php index 8557a30dec30..5034b1fb069c 100644 --- a/CRM/Event/Form/Registration/Confirm.php +++ b/CRM/Event/Form/Registration/Confirm.php @@ -1017,21 +1017,14 @@ public static function processContribution( $contribParams['is_test'] = 1; } - $contribID = NULL; if (!empty($contribParams['invoice_id'])) { - $contribID = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', + $contribParams['id'] = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $contribParams['invoice_id'], 'id', 'invoice_id' ); } - $ids = array(); - if ($contribID) { - $ids['contribution'] = $contribID; - $contribParams['id'] = $contribID; - } - if (CRM_Contribute_BAO_Contribution::checkContributeSettings('deferred_revenue_enabled')) { $eventStartDate = CRM_Utils_Array::value( 'start_date', From ec5e7bcfbe278e4c79ad353ac83016f3d8d049d5 Mon Sep 17 00:00:00 2001 From: eileen Date: Sat, 16 Mar 2019 11:19:45 +1300 Subject: [PATCH 066/408] Minor code cleanup Invoicing code has been poorly integrated into CiviCRM with much copy & paste, no following of settings spec and an awful lot of outright hacking. This is a small step towards moving invoice logic to a centralised place - specifically in this case the unpacking of the non-standard settings that have been used. Perhaps once using these functions we can standardise them! Ideally I'd like to see all the invoicing assigns in a function on this class, better yet once which mimics the pre or buildForm hook & even better one day to grow up & be a real hook --- CRM/Contribute/Form/Contribution/ThankYou.php | 6 ++---- CRM/Event/Form/Registration/ThankYou.php | 6 ++---- CRM/Invoicing/Utils.php | 11 +++++++++++ 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/CRM/Contribute/Form/Contribution/ThankYou.php b/CRM/Contribute/Form/Contribution/ThankYou.php index 05efdae22666..f393a4c0a9a2 100644 --- a/CRM/Contribute/Form/Contribution/ThankYou.php +++ b/CRM/Contribute/Form/Contribution/ThankYou.php @@ -107,13 +107,11 @@ public function buildQuickForm() { } $params = $this->_params; - $invoiceSettings = Civi::settings()->get('contribution_invoice_settings'); - $invoicing = CRM_Utils_Array::value('invoicing', $invoiceSettings); + $invoicing = CRM_Invoicing_Utils::isInvoicingEnabled(); // Make a copy of line items array to use for display only $tplLineItems = $this->_lineItem; if ($invoicing) { $getTaxDetails = FALSE; - $taxTerm = CRM_Utils_Array::value('tax_term', $invoiceSettings); foreach ($this->_lineItem as $key => $value) { foreach ($value as $k => $v) { if (isset($v['tax_rate'])) { @@ -126,7 +124,7 @@ public function buildQuickForm() { } } $this->assign('getTaxDetails', $getTaxDetails); - $this->assign('taxTerm', $taxTerm); + $this->assign('taxTerm', CRM_Invoicing_Utils::getTaxTerm()); $this->assign('totalTaxAmount', $params['tax_amount']); } diff --git a/CRM/Event/Form/Registration/ThankYou.php b/CRM/Event/Form/Registration/ThankYou.php index 95d67d719873..600f4891b65d 100644 --- a/CRM/Event/Form/Registration/ThankYou.php +++ b/CRM/Event/Form/Registration/ThankYou.php @@ -96,9 +96,7 @@ public function buildQuickForm() { } $this->assignToTemplate(); - $invoiceSettings = Civi::settings()->get('contribution_invoice_settings'); - $taxTerm = CRM_Utils_Array::value('tax_term', $invoiceSettings); - $invoicing = CRM_Utils_Array::value('invoicing', $invoiceSettings); + $invoicing = CRM_Invoicing_Utils::isInvoicingEnabled(); $getTaxDetails = FALSE; $taxAmount = 0; @@ -129,7 +127,7 @@ public function buildQuickForm() { if ($invoicing) { $this->assign('getTaxDetails', $getTaxDetails); $this->assign('totalTaxAmount', $taxAmount); - $this->assign('taxTerm', $taxTerm); + $this->assign('taxTerm', CRM_Invoicing_Utils::getTaxTerm()); } $this->assign('totalAmount', $this->_totalAmount); diff --git a/CRM/Invoicing/Utils.php b/CRM/Invoicing/Utils.php index 907f089ad62b..bad42ae8bce4 100644 --- a/CRM/Invoicing/Utils.php +++ b/CRM/Invoicing/Utils.php @@ -94,4 +94,15 @@ public static function getDefaultPaymentPage() { return CRM_Utils_Array::value('default_invoice_page', $invoiceSettings); } + /** + * Function to get the tax term. + * + * The value is nested in the contribution_invoice_settings setting - which + * is unsupported. Here we have a wrapper function to make later cleanup easier. + */ + public static function getTaxTerm() { + $invoiceSettings = Civi::settings()->get('contribution_invoice_settings'); + return CRM_Utils_Array::value('tax_term', $invoiceSettings); + } + } From 4a0626d0c617c33f84ad3948c49e86aa3f3568e6 Mon Sep 17 00:00:00 2001 From: Seamus Lee Date: Sat, 16 Mar 2019 12:29:48 +1100 Subject: [PATCH 067/408] Remove amavisd now that it is removed from the packages repository --- distmaker/dists/common.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/distmaker/dists/common.sh b/distmaker/dists/common.sh index 1ad546ef5b21..2b12fa2a02fa 100644 --- a/distmaker/dists/common.sh +++ b/distmaker/dists/common.sh @@ -96,7 +96,7 @@ function dm_install_packages() { local to="$2" local excludes_rsync="" - for exclude in .git .svn _ORIGINAL_ SeleniumRC PHPUnit PhpDocumentor SymfonyComponents amavisd-new git-footnote PHP/CodeCoverage ; do + for exclude in .git .svn _ORIGINAL_ SeleniumRC PHPUnit PhpDocumentor SymfonyComponents git-footnote PHP/CodeCoverage ; do excludes_rsync="--exclude=${exclude} ${excludes_rsync}" done From 97dc7b6463f4503b10d449d8d72df52a44861dc0 Mon Sep 17 00:00:00 2001 From: eileen Date: Sat, 16 Mar 2019 20:19:30 +1300 Subject: [PATCH 068/408] Add FrontEndPaymentFormTrait to start to share functionality between Event and Contribution forms. I've done one small function extraction in the process --- CRM/Contribute/Form/Contribution/Confirm.php | 13 +--- .../Form/FrontEndPaymentFormTrait.php | 69 +++++++++++++++++++ 2 files changed, 71 insertions(+), 11 deletions(-) create mode 100644 CRM/Financial/Form/FrontEndPaymentFormTrait.php diff --git a/CRM/Contribute/Form/Contribution/Confirm.php b/CRM/Contribute/Form/Contribution/Confirm.php index cf3644476784..0afaf65fb15f 100644 --- a/CRM/Contribute/Form/Contribution/Confirm.php +++ b/CRM/Contribute/Form/Contribution/Confirm.php @@ -35,6 +35,7 @@ * form to process actions on the group aspect of Custom Data */ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_ContributionBase { + use CRM_Financial_Form_FrontEndPaymentFormTrait; /** * The id of the contact associated with this contribution. @@ -514,17 +515,7 @@ public function buildQuickForm() { if ($invoicing) { $getTaxDetails = FALSE; $taxTerm = CRM_Utils_Array::value('tax_term', $invoiceSettings); - foreach ($this->_lineItem as $key => $value) { - foreach ($value as $k => $v) { - if (isset($v['tax_rate'])) { - if ($v['tax_rate'] != '') { - $getTaxDetails = TRUE; - // Cast to float to display without trailing zero decimals - $tplLineItems[$key][$k]['tax_rate'] = (float) $v['tax_rate']; - } - } - } - } + list($getTaxDetails, $tplLineItems) = $this->alterLineItemsForTemplate($tplLineItems); $this->assign('getTaxDetails', $getTaxDetails); $this->assign('taxTerm', $taxTerm); $this->assign('totalTaxAmount', $params['tax_amount']); diff --git a/CRM/Financial/Form/FrontEndPaymentFormTrait.php b/CRM/Financial/Form/FrontEndPaymentFormTrait.php new file mode 100644 index 000000000000..c74dea5ad474 --- /dev/null +++ b/CRM/Financial/Form/FrontEndPaymentFormTrait.php @@ -0,0 +1,69 @@ + $value) { + foreach ($value as $k => $v) { + if (isset($v['tax_rate'])) { + if ($v['tax_rate'] != '') { + $getTaxDetails = TRUE; + // Cast to float to display without trailing zero decimals + $tplLineItems[$key][$k]['tax_rate'] = (float) $v['tax_rate']; + } + } + } + } + // @todo fix this to only return $tplLineItems. Calling function can check for tax rate and + // do all invoicing related assigns + // another discrete function (it's just one more iteration through a an array with only a handful of + // lines so the separation of concerns is more important than 'efficiency' + return [$getTaxDetails, $tplLineItems]; + } + +} From d0858949c728e4f39ae43cdb14438284e1942e71 Mon Sep 17 00:00:00 2001 From: Seamus Lee Date: Sat, 16 Mar 2019 12:56:22 +1100 Subject: [PATCH 069/408] Remove require_once statements --- CRM/Core/Config.php | 1 - CRM/Core/Error.php | 2 -- 2 files changed, 3 deletions(-) diff --git a/CRM/Core/Config.php b/CRM/Core/Config.php index 2e5c7307daab..320ec6d85fa8 100644 --- a/CRM/Core/Config.php +++ b/CRM/Core/Config.php @@ -35,7 +35,6 @@ * @copyright CiviCRM LLC (c) 2004-2019 */ -require_once 'Log.php'; require_once 'Mail.php'; require_once 'api/api.php'; diff --git a/CRM/Core/Error.php b/CRM/Core/Error.php index 163a1b44d3be..fc2ebe9856ad 100644 --- a/CRM/Core/Error.php +++ b/CRM/Core/Error.php @@ -37,8 +37,6 @@ require_once 'PEAR/Exception.php'; require_once 'CRM/Core/Exception.php'; -require_once 'Log.php'; - /** * Class CRM_Exception */ From 4f897b756c233359d21cf0be029dcda8a7cac19a Mon Sep 17 00:00:00 2001 From: Seamus Lee Date: Sun, 17 Mar 2019 08:36:22 +1100 Subject: [PATCH 070/408] Ensure that all original Log Files are removed especially on Joomla --- CRM/Utils/Check/Component/Source.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CRM/Utils/Check/Component/Source.php b/CRM/Utils/Check/Component/Source.php index 2ec2e4230956..2dc5d153e269 100644 --- a/CRM/Utils/Check/Component/Source.php +++ b/CRM/Utils/Check/Component/Source.php @@ -51,6 +51,24 @@ public function getRemovedFiles() { $files[] = '[civicrm.vendor]/pear/net_smtp/phpdoc.sh'; $files[] = '[civicrm.vendor]/phpoffice/phpword/samples'; $files[] = '[civicrm.root]/templates/CRM/common/version.tpl'; + $files[] = '[civicrm.packages]/Log.php'; + $files[] = '[civicrm.packages]/_ORIGINAL_/Log.php'; + $files[] = '[civicrm.packages]/Log/composite.php'; + $files[] = '[civicrm.packages]/Log/console.php'; + $files[] = '[civicrm.packages]/Log/daemon.php'; + $files[] = '[civicrm.packages]/Log/display.php'; + $files[] = '[civicrm.packages]/Log/error_log.php'; + $files[] = '[civicrm.packages]/Log/file.php'; + $files[] = '[civicrm.packages]/Log/firebug.php'; + $files[] = '[civicrm.packages]/Log/mail.php'; + $files[] = '[civicrm.packages]/Log/mcal.php'; + $files[] = '[civicrm.packages]/Log/mdb2.php'; + $files[] = '[civicrm.packages]/Log/null.php'; + $files[] = '[civicrm.packages]/Log/observer.php'; + $files[] = '[civicrm.packages]/Log/sql.php'; + $files[] = '[civicrm.packages]/Log/sqlite.php'; + $files[] = '[civicrm.packages]/Log/syslog.php'; + $files[] = '[civicrm.packages]/Log/win.php'; return $files; } From 7652022e24d13df9e097de13c9832dfc40d4079e Mon Sep 17 00:00:00 2001 From: Seamus Lee Date: Sun, 17 Mar 2019 09:35:39 +1100 Subject: [PATCH 071/408] Add in tests of purifying HTML output Fix up test to work with earlier html purfier --- CRM/Utils/String.php | 1 + tests/phpunit/CRM/Utils/StringTest.php | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/CRM/Utils/String.php b/CRM/Utils/String.php index 8099f23180b2..66f8931f2939 100644 --- a/CRM/Utils/String.php +++ b/CRM/Utils/String.php @@ -642,6 +642,7 @@ public static function purifyHTML($string) { if (!$_filter) { $config = HTMLPurifier_Config::createDefault(); $config->set('Core.Encoding', 'UTF-8'); + $config->set('Attr.AllowedFrameTargets', ['_blank', '_self', '_parent', '_top']); // Disable the cache entirely $config->set('Cache.DefinitionImpl', NULL); diff --git a/tests/phpunit/CRM/Utils/StringTest.php b/tests/phpunit/CRM/Utils/StringTest.php index 0f273e2281ae..0b94f57981b0 100644 --- a/tests/phpunit/CRM/Utils/StringTest.php +++ b/tests/phpunit/CRM/Utils/StringTest.php @@ -353,4 +353,21 @@ public function parseURLProvider() { ); } + public function purifyHTMLProvider() { + $tests = []; + $tests[] = ['HOVER', 'HOVER']; + $tests[] = ['hello', 'hello']; + return $tests; + } + + /** + * Test ouput of purifyHTML + * @param string $testString + * @param string $expectedString + * @dataProvider purifyHTMLProvider + */ + public function testPurifyHTML($testString, $expectedString) { + $this->assertEquals($expectedString, CRM_Utils_String::purifyHTML($testString)); + } + } From 9257f129992bc72f446be68679a49cdda1b788ff Mon Sep 17 00:00:00 2001 From: eileen Date: Sat, 16 Mar 2019 10:19:59 +1300 Subject: [PATCH 072/408] Create contribution before taking payment, per contribution page workflow --- CRM/Event/Form/Registration/Confirm.php | 52 +++++++++++++++++++------ 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/CRM/Event/Form/Registration/Confirm.php b/CRM/Event/Form/Registration/Confirm.php index 7da2d0455140..71a3fd2bb8ca 100644 --- a/CRM/Event/Form/Registration/Confirm.php +++ b/CRM/Event/Form/Registration/Confirm.php @@ -559,7 +559,6 @@ public function postProcess() { $preApprovalParams = $this->_paymentProcessor['object']->getPreApprovalDetails($this->get('pre_approval_parameters')); $value = array_merge($value, $preApprovalParams); } - $result = NULL; if (!empty($value['is_pay_later']) || $value['amount'] == 0 || @@ -582,16 +581,6 @@ public function postProcess() { if (empty($value['email'])) { $value['email'] = CRM_Utils_Array::valueByRegexKey('/^email-/', $value); } - - if (is_object($payment)) { - // Not quite sure why we don't just user $value since it contains the data - // from result - // @todo ditch $result & retest. - list($result, $value) = $this->processPayment($payment, $value); - } - else { - CRM_Core_Error::fatal($paymentObjError); - } } $value['receive_date'] = $now; @@ -618,8 +607,44 @@ public function postProcess() { $isAdditionalAmount = TRUE; } + CRM_Contribute_Form_AbstractEditPayment::formatCreditCardDetails($params[0]); //passing contribution id is already registered. - $contribution = self::processContribution($this, $value, $result, $contactID, $pending, $isAdditionalAmount, $this->_paymentProcessor); + $contribution = self::processContribution($this, $value, NULL, $contactID, TRUE, $isAdditionalAmount, $this->_paymentProcessor); + + try { + // @todo this should really be if $amount > 0, for pay later we should just load the + // manual pseudo processor (0) so there *should* always be a defined processor + if (!empty($payment)) { + $result = $payment->doPayment($value, 'event'); + if ($result['payment_status_id'] == CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed')) { + try { + civicrm_api3('contribution', 'completetransaction', [ + 'id' => $contribution->id, + 'trxn_id' => $result['trxn_id'], + 'payment_processor_id' => $this->_paymentProcessor['id'], + 'is_transactional' => FALSE, + 'fee_amount' => CRM_Utils_Array::value('fee_amount', $result), + 'is_email_receipt' => FALSE, + 'card_type_id' => CRM_Utils_Array::value('card_type_id', $params[0]), + 'pan_truncation' => CRM_Utils_Array::value('pan_truncation', $params[0]), + ]); + // This has now been set to 1 in the DB - declare it here also + $contribution->contribution_status_id = 1; + } + catch (CiviCRM_API3_Exception $e) { + if ($e->getErrorCode() != 'contribution_completed') { + throw new CRM_Core_Exception('Failed to update contribution in database'); + } + } + } + } + } + catch (\Civi\Payment\Exception\PaymentProcessorException $e) { + Civi::log()->error('Payment processor exception: ' . $e->getMessage()); + CRM_Core_Session::singleton()->setStatus($e->getMessage()); + CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/event/register', "id={$this->_eventId}")); + } + $value['contributionID'] = $contribution->id; $value['contributionTypeID'] = $contribution->financial_type_id; $value['receive_date'] = $contribution->receive_date; @@ -973,6 +998,9 @@ public static function processContribution( } // CRM-20264: fetch CC type ID and number (last 4 digit) and assign it back to $params + // @todo remove this once backoffice form is doing it - front end is doing it twice. + // (in general they are sharing much more code than they should - anything that truly should be shared + // should not be on this class). CRM_Contribute_Form_AbstractEditPayment::formatCreditCardDetails($params); $contribParams = array( From a24722475ff8fbfb7c8ad34a9397f07663dde0b2 Mon Sep 17 00:00:00 2001 From: mark burdett Date: Mon, 18 Mar 2019 10:54:07 +1300 Subject: [PATCH 073/408] Use TempTable methods - bookkeeping report --- CRM/Report/Form/Contribute/Bookkeeping.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/CRM/Report/Form/Contribute/Bookkeeping.php b/CRM/Report/Form/Contribute/Bookkeeping.php index ee117af7a4b7..053b8b3718aa 100644 --- a/CRM/Report/Form/Contribute/Bookkeeping.php +++ b/CRM/Report/Form/Contribute/Bookkeeping.php @@ -602,7 +602,6 @@ public function groupBy() { */ public function statistics(&$rows) { $statistics = parent::statistics($rows); - $tempTableName = CRM_Core_DAO::createTempTableName('civicrm_contribution'); $financialSelect = "CASE WHEN {$this->_aliases['civicrm_entity_financial_trxn']}_item.entity_id IS NOT NULL THEN {$this->_aliases['civicrm_entity_financial_trxn']}_item.amount ELSE {$this->_aliases['civicrm_entity_financial_trxn']}.amount @@ -618,9 +617,8 @@ public function statistics(&$rows) { $this->groupBy(); - $tempQuery = "CREATE TEMPORARY TABLE {$tempTableName} {$this->_databaseAttributes} AS - {$select} {$this->_from} {$this->_where} {$this->_groupBy} "; - CRM_Core_DAO::executeQuery($tempQuery); + $tempTableName = $this->createTemporaryTable('tempTable', " + {$select} {$this->_from} {$this->_where} {$this->_groupBy} "); $sql = "SELECT COUNT(trxnID) as count, SUM(amount) as amount, currency FROM {$tempTableName} From fe42be711d810d53b04a5f13699e44cb0aaea8cd Mon Sep 17 00:00:00 2001 From: mark burdett Date: Thu, 14 Mar 2019 16:42:46 -0700 Subject: [PATCH 074/408] Use TempTable methods. --- CRM/Report/Form/Contribute/Detail.php | 23 ++++++++----------- .../phpunit/CRM/Report/Form/ActivityTest.php | 3 --- .../CRM/Report/Form/Contribute/DetailTest.php | 7 ------ .../phpunit/CRM/Report/Form/TestCaseTest.php | 7 ------ 4 files changed, 10 insertions(+), 30 deletions(-) diff --git a/CRM/Report/Form/Contribute/Detail.php b/CRM/Report/Form/Contribute/Detail.php index eccb17c26b43..9796c52599b8 100644 --- a/CRM/Report/Form/Contribute/Detail.php +++ b/CRM/Report/Form/Contribute/Detail.php @@ -491,7 +491,7 @@ public function statistics(&$rows) { public function buildQuery($applyLimit = FALSE) { if ($this->isTempTableBuilt) { $this->limit(); - return "SELECT SQL_CALC_FOUND_ROWS * FROM civireport_contribution_detail_temp3 $this->_orderBy $this->_limit"; + return "SELECT SQL_CALC_FOUND_ROWS * FROM {$this->temporaryTables['civireport_contribution_detail_temp3']['name']} $this->_orderBy $this->_limit"; } return parent::buildQuery($applyLimit); } @@ -544,9 +544,7 @@ public function beginPostProcessCommon() { // we inner join with temp1 to restrict soft contributions to those in temp1 table. // no group by here as we want to display as many soft credit rows as actually exist. $sql = "{$select} {$this->_from} {$this->_where} $this->_groupBy"; - $tempQuery = "CREATE TEMPORARY TABLE civireport_contribution_detail_temp2 {$this->_databaseAttributes} AS {$sql}"; - $this->executeReportQuery($tempQuery); - $this->temporaryTables['civireport_contribution_detail_temp2'] = ['name' => 'civireport_contribution_detail_temp2', 'temporary' => TRUE]; + $this->createTemporaryTable('civireport_contribution_detail_temp2', $sql); if (CRM_Utils_Array::value('contribution_or_soft_value', $this->_params) == 'soft_credits_only' @@ -568,24 +566,23 @@ public function beginPostProcessCommon() { // 3. Decide where to populate temp3 table from if ($this->isContributionBaseMode ) { - $this->executeReportQuery( - "CREATE TEMPORARY TABLE civireport_contribution_detail_temp3 {$this->_databaseAttributes} AS (SELECT * FROM {$this->temporaryTables['civireport_contribution_detail_temp1']['name']})" + $this->createTemporaryTable('civireport_contribution_detail_temp3', + "(SELECT * FROM {$this->temporaryTables['civireport_contribution_detail_temp1']['name']})" ); } elseif (CRM_Utils_Array::value('contribution_or_soft_value', $this->_params) == 'soft_credits_only' ) { - $this->executeReportQuery( - "CREATE TEMPORARY TABLE civireport_contribution_detail_temp3 {$this->_databaseAttributes} AS (SELECT * FROM civireport_contribution_detail_temp2)" + $this->createTemporaryTable('civireport_contribution_detail_temp3', + "(SELECT * FROM {$this->temporaryTables['civireport_contribution_detail_temp2']['name']})" ); } else { - $this->executeReportQuery("CREATE TEMPORARY TABLE civireport_contribution_detail_temp3 {$this->_databaseAttributes} + $this->createTemporaryTable('civireport_contribution_detail_temp3', " (SELECT * FROM {$this->temporaryTables['civireport_contribution_detail_temp1']['name']}) UNION ALL -(SELECT * FROM civireport_contribution_detail_temp2)"); +(SELECT * FROM {$this->temporaryTables['civireport_contribution_detail_temp2']['name']})"); } - $this->temporaryTables['civireport_contribution_detail_temp3'] = ['name' => 'civireport_contribution_detail_temp3', 'temporary' => TRUE]; $this->isTempTableBuilt = TRUE; } @@ -730,7 +727,7 @@ public function alterDisplay(&$rows) { ) { $query = " SELECT civicrm_contact_id, civicrm_contact_sort_name, civicrm_contribution_total_amount_sum, civicrm_contribution_currency -FROM civireport_contribution_detail_temp2 +FROM {$this->temporaryTables['civireport_contribution_detail_temp2']['name']} WHERE civicrm_contribution_contribution_id={$row['civicrm_contribution_contribution_id']}"; $dao = CRM_Core_DAO::executeQuery($query); $string = ''; @@ -834,7 +831,7 @@ public function sectionTotals() { } $query = $this->_select . - "$addtotals, count(*) as ct from civireport_contribution_detail_temp3 group by " . + "$addtotals, count(*) as ct from {$this->temporaryTables['civireport_contribution_detail_temp3']['name']} group by " . implode(", ", $sectionAliases); // initialize array of total counts $sumcontribs = $totals = array(); diff --git a/tests/phpunit/CRM/Report/Form/ActivityTest.php b/tests/phpunit/CRM/Report/Form/ActivityTest.php index 582dd6a4ce91..d7001ea91aeb 100644 --- a/tests/phpunit/CRM/Report/Form/ActivityTest.php +++ b/tests/phpunit/CRM/Report/Form/ActivityTest.php @@ -46,9 +46,6 @@ public function setUp() { public function tearDown() { parent::tearDown(); - CRM_Core_DAO::executeQuery('DROP TEMPORARY TABLE IF EXISTS civireport_contribution_detail_temp1'); - CRM_Core_DAO::executeQuery('DROP TEMPORARY TABLE IF EXISTS civireport_contribution_detail_temp2'); - CRM_Core_DAO::executeQuery('DROP TEMPORARY TABLE IF EXISTS civireport_contribution_detail_temp3'); CRM_Core_DAO::executeQuery('DROP TEMPORARY TABLE IF EXISTS civireport_activity_temp_target'); } diff --git a/tests/phpunit/CRM/Report/Form/Contribute/DetailTest.php b/tests/phpunit/CRM/Report/Form/Contribute/DetailTest.php index af89473113a8..835f37462d10 100644 --- a/tests/phpunit/CRM/Report/Form/Contribute/DetailTest.php +++ b/tests/phpunit/CRM/Report/Form/Contribute/DetailTest.php @@ -70,13 +70,6 @@ public function setUp() { $this->quickCleanup($this->_tablesToTruncate); } - public function tearDown() { - parent::tearDown(); - CRM_Core_DAO::executeQuery('DROP TEMPORARY TABLE IF EXISTS civireport_contribution_detail_temp1'); - CRM_Core_DAO::executeQuery('DROP TEMPORARY TABLE IF EXISTS civireport_contribution_detail_temp2'); - CRM_Core_DAO::executeQuery('DROP TEMPORARY TABLE IF EXISTS civireport_contribution_detail_temp3'); - } - /** * @dataProvider dataProvider * @param $reportClass diff --git a/tests/phpunit/CRM/Report/Form/TestCaseTest.php b/tests/phpunit/CRM/Report/Form/TestCaseTest.php index 7d144fb7c6db..0f1471084b17 100644 --- a/tests/phpunit/CRM/Report/Form/TestCaseTest.php +++ b/tests/phpunit/CRM/Report/Form/TestCaseTest.php @@ -134,13 +134,6 @@ public function setUp() { $this->quickCleanup($this->_tablesToTruncate); } - public function tearDown() { - parent::tearDown(); - CRM_Core_DAO::executeQuery('DROP TEMPORARY TABLE IF EXISTS civireport_contribution_detail_temp1'); - CRM_Core_DAO::executeQuery('DROP TEMPORARY TABLE IF EXISTS civireport_contribution_detail_temp2'); - CRM_Core_DAO::executeQuery('DROP TEMPORARY TABLE IF EXISTS civireport_contribution_detail_temp3'); - } - /** * @dataProvider dataProvider * @param $reportClass From 60345ce23a1f21dd22fc3fae375a921e1af8fed9 Mon Sep 17 00:00:00 2001 From: Martin Date: Sun, 17 Mar 2019 19:47:49 -0400 Subject: [PATCH 075/408] dev/core#789 - Bug fix for event reg error when skipping participants (#13800) --- CRM/Event/Form/Registration/Confirm.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CRM/Event/Form/Registration/Confirm.php b/CRM/Event/Form/Registration/Confirm.php index 7da2d0455140..3284eb437f52 100644 --- a/CRM/Event/Form/Registration/Confirm.php +++ b/CRM/Event/Form/Registration/Confirm.php @@ -215,7 +215,6 @@ public function buildQuickForm() { $taxAmount = 0; foreach ($this->_params as $k => $v) { - $this->cleanMoneyFields($v); if ($v == 'skip') { continue; } @@ -223,6 +222,7 @@ public function buildQuickForm() { //display tax amount on confirmation page $taxAmount += $v['tax_amount']; if (is_array($v)) { + $this->cleanMoneyFields($v); foreach (array( 'first_name', 'last_name', From 9e3bf561d5b210cc6f8e3974afb24313ec9aa817 Mon Sep 17 00:00:00 2001 From: eileen Date: Mon, 18 Mar 2019 10:41:41 +1300 Subject: [PATCH 076/408] [NFC] code formatting only IDE reformatting to fix array formats --- CRM/Core/Payment.php | 284 +++++++++++++++++++++++-------------------- 1 file changed, 155 insertions(+), 129 deletions(-) diff --git a/CRM/Core/Payment.php b/CRM/Core/Payment.php index e88c11c660fc..f21aeec500e7 100644 --- a/CRM/Core/Payment.php +++ b/CRM/Core/Payment.php @@ -413,7 +413,8 @@ protected function supportsRecurContributionsForPledges() { * - pre_approval_parameters (this will be stored on the calling form & available later) * - redirect_url (if set the browser will be redirected to this. */ - public function doPreApproval(&$params) {} + public function doPreApproval(&$params) { + } /** * Get any details that may be available to the payment processor due to an approval process having happened. @@ -426,7 +427,7 @@ public function doPreApproval(&$params) {} * @return array */ public function getPreApprovalDetails($storedDetails) { - return array(); + return []; } /** @@ -509,7 +510,10 @@ public function getText($context, $params) { switch ($context) { case 'contributionPageRecurringHelp': // require exactly two parameters - if (array_keys($params) == array('is_recur_installments', 'is_email_receipt')) { + if (array_keys($params) == [ + 'is_recur_installments', + 'is_email_receipt', + ]) { $gotText = ts('Your recurring contribution will be processed automatically.'); if ($params['is_recur_installments']) { $gotText .= ' ' . ts('You can specify the number of installments, or you can leave the number of installments blank if you want to make an open-ended commitment. In either case, you can choose to cancel at any time.'); @@ -571,7 +575,7 @@ public function getPaymentTypeLabel() { */ public function getPaymentFormFields() { if ($this->_paymentProcessor['billing_mode'] == 4) { - return array(); + return []; } return $this->_paymentProcessor['payment_type'] == 1 ? $this->getCreditCardFormFields() : $this->getDirectDebitFormFields(); } @@ -603,7 +607,7 @@ public function getPaymentFormFields() { */ public function getEditableRecurringScheduleFields() { if ($this->supports('changeSubscriptionAmount')) { - return array('amount'); + return ['amount']; } } @@ -627,7 +631,7 @@ public function getRecurringScheduleUpdateHelpText() { * @return array; */ protected function getMandatoryFields() { - $mandatoryFields = array(); + $mandatoryFields = []; foreach ($this->getAllFields() as $field_name => $field_spec) { if (!empty($field_spec['is_required'])) { $mandatoryFields[$field_name] = $field_spec; @@ -646,18 +650,19 @@ protected function getAllFields() { $billingFields = array_intersect_key($this->getBillingAddressFieldsMetadata(), array_flip($this->getBillingAddressFields())); return array_merge($paymentFields, $billingFields); } + /** * Get array of fields that should be displayed on the payment form for credit cards. * * @return array */ protected function getCreditCardFormFields() { - return array( + return [ 'credit_card_type', 'credit_card_number', 'cvv2', 'credit_card_exp_date', - ); + ]; } /** @@ -666,12 +671,12 @@ protected function getCreditCardFormFields() { * @return array */ protected function getDirectDebitFormFields() { - return array( + return [ 'account_holder', 'bank_account_number', 'bank_identification_number', 'bank_name', - ); + ]; } /** @@ -684,160 +689,164 @@ protected function getDirectDebitFormFields() { */ public function getPaymentFormFieldsMetadata() { //@todo convert credit card type into an option value - $creditCardType = array('' => ts('- select -')) + CRM_Contribute_PseudoConstant::creditCard(); + $creditCardType = ['' => ts('- select -')] + CRM_Contribute_PseudoConstant::creditCard(); $isCVVRequired = Civi::settings()->get('cvv_backoffice_required'); if (!$this->isBackOffice()) { $isCVVRequired = TRUE; } - return array( - 'credit_card_number' => array( + return [ + 'credit_card_number' => [ 'htmlType' => 'text', 'name' => 'credit_card_number', 'title' => ts('Card Number'), - 'attributes' => array( + 'attributes' => [ 'size' => 20, 'maxlength' => 20, 'autocomplete' => 'off', 'class' => 'creditcard', - ), + ], 'is_required' => TRUE, // 'description' => '16 digit card number', // If you enable a description field it will be shown below the field on the form - ), - 'cvv2' => array( + ], + 'cvv2' => [ 'htmlType' => 'text', 'name' => 'cvv2', 'title' => ts('Security Code'), - 'attributes' => array( + 'attributes' => [ 'size' => 5, 'maxlength' => 10, 'autocomplete' => 'off', - ), + ], 'is_required' => $isCVVRequired, - 'rules' => array( - array( + 'rules' => [ + [ 'rule_message' => ts('Please enter a valid value for your card security code. This is usually the last 3-4 digits on the card\'s signature panel.'), 'rule_name' => 'integer', 'rule_parameters' => NULL, - ), - ), - ), - 'credit_card_exp_date' => array( + ], + ], + ], + 'credit_card_exp_date' => [ 'htmlType' => 'date', 'name' => 'credit_card_exp_date', 'title' => ts('Expiration Date'), 'attributes' => CRM_Core_SelectValues::date('creditCard'), 'is_required' => TRUE, - 'rules' => array( - array( + 'rules' => [ + [ 'rule_message' => ts('Card expiration date cannot be a past date.'), 'rule_name' => 'currentDate', 'rule_parameters' => TRUE, - ), - ), + ], + ], 'extra' => ['class' => 'crm-form-select'], - ), - 'credit_card_type' => array( + ], + 'credit_card_type' => [ 'htmlType' => 'select', 'name' => 'credit_card_type', 'title' => ts('Card Type'), 'attributes' => $creditCardType, 'is_required' => FALSE, - ), - 'account_holder' => array( + ], + 'account_holder' => [ 'htmlType' => 'text', 'name' => 'account_holder', 'title' => ts('Account Holder'), - 'attributes' => array( + 'attributes' => [ 'size' => 20, 'maxlength' => 34, 'autocomplete' => 'on', - ), + ], 'is_required' => TRUE, - ), + ], //e.g. IBAN can have maxlength of 34 digits - 'bank_account_number' => array( + 'bank_account_number' => [ 'htmlType' => 'text', 'name' => 'bank_account_number', 'title' => ts('Bank Account Number'), - 'attributes' => array( + 'attributes' => [ 'size' => 20, 'maxlength' => 34, 'autocomplete' => 'off', - ), - 'rules' => array( - array( + ], + 'rules' => [ + [ 'rule_message' => ts('Please enter a valid Bank Identification Number (value must not contain punctuation characters).'), 'rule_name' => 'nopunctuation', 'rule_parameters' => NULL, - ), - ), + ], + ], 'is_required' => TRUE, - ), + ], //e.g. SWIFT-BIC can have maxlength of 11 digits - 'bank_identification_number' => array( + 'bank_identification_number' => [ 'htmlType' => 'text', 'name' => 'bank_identification_number', 'title' => ts('Bank Identification Number'), - 'attributes' => array( + 'attributes' => [ 'size' => 20, 'maxlength' => 11, 'autocomplete' => 'off', - ), + ], 'is_required' => TRUE, - 'rules' => array( - array( + 'rules' => [ + [ 'rule_message' => ts('Please enter a valid Bank Identification Number (value must not contain punctuation characters).'), 'rule_name' => 'nopunctuation', 'rule_parameters' => NULL, - ), - ), - ), - 'bank_name' => array( + ], + ], + ], + 'bank_name' => [ 'htmlType' => 'text', 'name' => 'bank_name', 'title' => ts('Bank Name'), - 'attributes' => array( + 'attributes' => [ 'size' => 20, 'maxlength' => 64, 'autocomplete' => 'off', - ), + ], 'is_required' => TRUE, - ), - 'check_number' => array( + ], + 'check_number' => [ 'htmlType' => 'text', 'name' => 'check_number', 'title' => ts('Check Number'), 'is_required' => FALSE, 'attributes' => NULL, - ), - 'pan_truncation' => array( + ], + 'pan_truncation' => [ 'htmlType' => 'text', 'name' => 'pan_truncation', 'title' => ts('Last 4 digits of the card'), 'is_required' => FALSE, - 'attributes' => array( + 'attributes' => [ 'size' => 4, 'maxlength' => 4, 'minlength' => 4, 'autocomplete' => 'off', - ), - 'rules' => array( - array( + ], + 'rules' => [ + [ 'rule_message' => ts('Please enter valid last 4 digit card number.'), 'rule_name' => 'numeric', 'rule_parameters' => NULL, - ), - ), - ), - 'payment_token' => array( + ], + ], + ], + 'payment_token' => [ 'htmlType' => 'hidden', 'name' => 'payment_token', 'title' => ts('Authorization token'), 'is_required' => FALSE, - 'attributes' => ['size' => 10, 'autocomplete' => 'off', 'id' => 'payment_token'], - ), - ); + 'attributes' => [ + 'size' => 10, + 'autocomplete' => 'off', + 'id' => 'payment_token', + ], + ], + ]; } /** @@ -858,9 +867,9 @@ public function getBillingAddressFields($billingLocationID = NULL) { $billingLocationID = CRM_Core_BAO_LocationType::getBilling(); } if ($this->_paymentProcessor['billing_mode'] != 1 && $this->_paymentProcessor['billing_mode'] != 3) { - return array(); + return []; } - return array( + return [ 'first_name' => 'billing_first_name', 'middle_name' => 'billing_middle_name', 'last_name' => 'billing_last_name', @@ -869,7 +878,7 @@ public function getBillingAddressFields($billingLocationID = NULL) { 'country' => "billing_country_id-{$billingLocationID}", 'state_province' => "billing_state_province_id-{$billingLocationID}", 'postal_code' => "billing_postal_code-{$billingLocationID}", - ); + ]; } /** @@ -887,103 +896,103 @@ public function getBillingAddressFieldsMetadata($billingLocationID = NULL) { // So taking this as a param is possibly something to be removed in favour of the standard default. $billingLocationID = CRM_Core_BAO_LocationType::getBilling(); } - $metadata = array(); - $metadata['billing_first_name'] = array( + $metadata = []; + $metadata['billing_first_name'] = [ 'htmlType' => 'text', 'name' => 'billing_first_name', 'title' => ts('Billing First Name'), 'cc_field' => TRUE, - 'attributes' => array( + 'attributes' => [ 'size' => 30, 'maxlength' => 60, 'autocomplete' => 'off', - ), + ], 'is_required' => TRUE, - ); + ]; - $metadata['billing_middle_name'] = array( + $metadata['billing_middle_name'] = [ 'htmlType' => 'text', 'name' => 'billing_middle_name', 'title' => ts('Billing Middle Name'), 'cc_field' => TRUE, - 'attributes' => array( + 'attributes' => [ 'size' => 30, 'maxlength' => 60, 'autocomplete' => 'off', - ), + ], 'is_required' => FALSE, - ); + ]; - $metadata['billing_last_name'] = array( + $metadata['billing_last_name'] = [ 'htmlType' => 'text', 'name' => 'billing_last_name', 'title' => ts('Billing Last Name'), 'cc_field' => TRUE, - 'attributes' => array( + 'attributes' => [ 'size' => 30, 'maxlength' => 60, 'autocomplete' => 'off', - ), + ], 'is_required' => TRUE, - ); + ]; - $metadata["billing_street_address-{$billingLocationID}"] = array( + $metadata["billing_street_address-{$billingLocationID}"] = [ 'htmlType' => 'text', 'name' => "billing_street_address-{$billingLocationID}", 'title' => ts('Street Address'), 'cc_field' => TRUE, - 'attributes' => array( + 'attributes' => [ 'size' => 30, 'maxlength' => 60, 'autocomplete' => 'off', - ), + ], 'is_required' => TRUE, - ); + ]; - $metadata["billing_city-{$billingLocationID}"] = array( + $metadata["billing_city-{$billingLocationID}"] = [ 'htmlType' => 'text', 'name' => "billing_city-{$billingLocationID}", 'title' => ts('City'), 'cc_field' => TRUE, - 'attributes' => array( + 'attributes' => [ 'size' => 30, 'maxlength' => 60, 'autocomplete' => 'off', - ), + ], 'is_required' => TRUE, - ); + ]; - $metadata["billing_state_province_id-{$billingLocationID}"] = array( + $metadata["billing_state_province_id-{$billingLocationID}"] = [ 'htmlType' => 'chainSelect', 'title' => ts('State/Province'), 'name' => "billing_state_province_id-{$billingLocationID}", 'cc_field' => TRUE, 'is_required' => TRUE, - ); + ]; - $metadata["billing_postal_code-{$billingLocationID}"] = array( + $metadata["billing_postal_code-{$billingLocationID}"] = [ 'htmlType' => 'text', 'name' => "billing_postal_code-{$billingLocationID}", 'title' => ts('Postal Code'), 'cc_field' => TRUE, - 'attributes' => array( + 'attributes' => [ 'size' => 30, 'maxlength' => 60, 'autocomplete' => 'off', - ), + ], 'is_required' => TRUE, - ); + ]; - $metadata["billing_country_id-{$billingLocationID}"] = array( + $metadata["billing_country_id-{$billingLocationID}"] = [ 'htmlType' => 'select', 'name' => "billing_country_id-{$billingLocationID}", 'title' => ts('Country'), 'cc_field' => TRUE, - 'attributes' => array( - '' => ts('- select -'), - ) + CRM_Core_PseudoConstant::country(), + 'attributes' => [ + '' => ts('- select -'), + ] + CRM_Core_PseudoConstant::country(), 'is_required' => TRUE, - ); + ]; return $metadata; } @@ -1047,20 +1056,20 @@ public function getCancelUrl($qfKey, $participantID) { } if ($this->_component == 'event') { - return CRM_Utils_System::url($this->getBaseReturnUrl(), array( + return CRM_Utils_System::url($this->getBaseReturnUrl(), [ 'reset' => 1, 'cc' => 'fail', 'participantId' => $participantID, - ), + ], TRUE, NULL, FALSE ); } - return CRM_Utils_System::url($this->getBaseReturnUrl(), array( + return CRM_Utils_System::url($this->getBaseReturnUrl(), [ '_qf_Main_display' => 1, 'qfKey' => $qfKey, 'cancel' => 1, - ), + ], TRUE, NULL, FALSE ); } @@ -1077,10 +1086,10 @@ protected function getReturnSuccessUrl($qfKey) { return $this->successUrl; } - return CRM_Utils_System::url($this->getBaseReturnUrl(), array( + return CRM_Utils_System::url($this->getBaseReturnUrl(), [ '_qf_ThankYou_display' => 1, 'qfKey' => $qfKey, - ), + ], TRUE, NULL, FALSE ); } @@ -1123,10 +1132,10 @@ protected function getReturnFailUrl($key, $participantID = NULL, $eventID = NULL * @return string url */ protected function getGoBackUrl($qfKey) { - return CRM_Utils_System::url($this->getBaseReturnUrl(), array( + return CRM_Utils_System::url($this->getBaseReturnUrl(), [ '_qf_Confirm_display' => 'true', 'qfKey' => $qfKey, - ), + ], TRUE, NULL, FALSE ); } @@ -1143,7 +1152,7 @@ protected function getGoBackUrl($qfKey) { protected function getNotifyUrl() { $url = CRM_Utils_System::url( 'civicrm/payment/ipn/' . $this->_paymentProcessor['id'], - array(), + [], TRUE, NULL, FALSE, @@ -1250,7 +1259,7 @@ public function doPayment(&$params, $component = 'contribute') { * - fee_amount Amount of fee paid */ public function doQuery($params) { - return array(); + return []; } /** @@ -1309,7 +1318,7 @@ public static function handleIPN() { Civi::log()->error('ipn_payment_callback_exception', [ 'context' => [ 'backtrace' => CRM_Core_Error::formatBacktrace(debug_backtrace()), - ] + ], ]); } CRM_Utils_System::civiExit(); @@ -1332,7 +1341,7 @@ public static function handleIPN() { * @throws \CRM_Core_Exception * @throws \Exception */ - public static function handlePaymentMethod($method, $params = array()) { + public static function handlePaymentMethod($method, $params = []) { if (!isset($params['processor_id']) && !isset($params['processor_name'])) { $q = explode('/', CRM_Utils_Array::value(CRM_Core_Config::singleton()->userFrameworkURLVar, $_GET, '')); $lastParam = array_pop($q); @@ -1355,18 +1364,18 @@ public static function handlePaymentMethod($method, $params = array()) { if (isset($params['processor_id'])) { $sql .= " WHERE pp.id = %2"; - $args[2] = array($params['processor_id'], 'Integer'); - $notFound = ts("No active instances of payment processor %1 were found.", array(1 => $params['processor_id'])); + $args[2] = [$params['processor_id'], 'Integer']; + $notFound = ts("No active instances of payment processor %1 were found.", [1 => $params['processor_id']]); } else { // This is called when processor_name is passed - passing processor_id instead is recommended. $sql .= " WHERE ppt.name = %2 AND pp.is_test = %1"; - $args[1] = array( + $args[1] = [ (CRM_Utils_Array::value('mode', $params) == 'test') ? 1 : 0, 'Integer', - ); - $args[2] = array($params['processor_name'], 'String'); - $notFound = ts("No active instances of payment processor '%1' were found.", array(1 => $params['processor_name'])); + ]; + $args[2] = [$params['processor_name'], 'String']; + $notFound = ts("No active instances of payment processor '%1' were found.", [1 => $params['processor_name']]); } $dao = CRM_Core_DAO::executeQuery($sql, $args); @@ -1399,7 +1408,7 @@ public static function handlePaymentMethod($method, $params = array()) { // Does PP implement this method, and can we call it? if (!method_exists($processorInstance, $method) || - !is_callable(array($processorInstance, $method)) + !is_callable([$processorInstance, $method]) ) { // on the off chance there is a double implementation of this processor we should keep looking for another // note that passing processor_id is more reliable & we should work to deprecate processor_name @@ -1417,7 +1426,10 @@ public static function handlePaymentMethod($method, $params = array()) { if (!$extension_instance_found) { $message = "No extension instances of the '%1' payment processor were found.
" . "%2 method is unsupported in legacy payment processors."; - throw new CRM_Core_Exception(ts($message, [1 => $params['processor_name'], 2 => $method])); + throw new CRM_Core_Exception(ts($message, [ + 1 => $params['processor_name'], + 2 => $method, + ])); } } @@ -1528,7 +1540,12 @@ public function subscriptionURL($entityID = NULL, $entity = NULL, $action = 'can FROM civicrm_contribution_recur rec INNER JOIN civicrm_contribution con ON ( con.contribution_recur_id = rec.id ) WHERE rec.id = %1"; - $contactID = CRM_Core_DAO::singleValueQuery($sql, array(1 => array($entityID, 'Integer'))); + $contactID = CRM_Core_DAO::singleValueQuery($sql, [ + 1 => [ + $entityID, + 'Integer', + ], + ]); $entityArg = 'crid'; break; } @@ -1567,10 +1584,19 @@ public function subscriptionURL($entityID = NULL, $entity = NULL, $action = 'can * @return string */ protected function getPaymentDescription($params, $length = 24) { - $parts = array('contactID', 'contributionID', 'description', 'billing_first_name', 'billing_last_name'); - $validParts = array(); + $parts = [ + 'contactID', + 'contributionID', + 'description', + 'billing_first_name', + 'billing_last_name', + ]; + $validParts = []; if (isset($params['description'])) { - $uninformativeStrings = array(ts('Online Event Registration: '), ts('Online Contribution: ')); + $uninformativeStrings = [ + ts('Online Event Registration: '), + ts('Online Contribution: '), + ]; $params['description'] = str_replace($uninformativeStrings, '', $params['description']); } foreach ($parts as $part) { From ff3833b084c7a72ffe65725756090b03281cb0a4 Mon Sep 17 00:00:00 2001 From: eileen Date: Mon, 18 Mar 2019 13:03:42 +1300 Subject: [PATCH 077/408] [NFC] Code reformatting IDE reformat to fix array() vs [] --- tests/phpunit/api/v3/ACLPermissionTest.php | 479 ++++++++++++++------- 1 file changed, 319 insertions(+), 160 deletions(-) diff --git a/tests/phpunit/api/v3/ACLPermissionTest.php b/tests/phpunit/api/v3/ACLPermissionTest.php index 689c0cf6c7fb..4d37a88d9cae 100644 --- a/tests/phpunit/api/v3/ACLPermissionTest.php +++ b/tests/phpunit/api/v3/ACLPermissionTest.php @@ -43,8 +43,8 @@ class api_v3_ACLPermissionTest extends CiviUnitTestCase { public function setUp() { parent::setUp(); $baoObj = new CRM_Core_DAO(); - $baoObj->createTestObject('CRM_Pledge_BAO_Pledge', array(), 1, 0); - $baoObj->createTestObject('CRM_Core_BAO_Phone', array(), 1, 0); + $baoObj->createTestObject('CRM_Pledge_BAO_Pledge', [], 1, 0); + $baoObj->createTestObject('CRM_Core_BAO_Phone', [], 1, 0); $this->prepareForACLs(); } @@ -54,7 +54,7 @@ public function setUp() { */ public function tearDown() { $this->cleanUpAfterACLs(); - $tablesToTruncate = array( + $tablesToTruncate = [ 'civicrm_contact', 'civicrm_group_contact', 'civicrm_group', @@ -70,7 +70,7 @@ public function tearDown() { 'civicrm_note', 'civicrm_entity_tag', 'civicrm_tag', - ); + ]; $this->quickCleanup($tablesToTruncate); } @@ -78,11 +78,14 @@ public function tearDown() { * Function tests that an empty where hook returns no results. */ public function testContactGetNoResultsHook() { - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookNoResults')); - $result = $this->callAPISuccess('contact', 'get', array( + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereHookNoResults', + ]); + $result = $this->callAPISuccess('contact', 'get', [ 'check_permissions' => 1, 'return' => 'display_name', - )); + ]); $this->assertEquals(0, $result['count']); } @@ -93,12 +96,18 @@ public function testContactGetNoResultsHook() { */ public function testContactGetOneResultHookWithViewMyContact() { $this->createLoggedInUser(); - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookNoResults')); - CRM_Core_Config::singleton()->userPermissionClass->permissions = array('access CiviCRM', 'view my contact'); - $result = $this->callAPISuccess('contact', 'get', array( + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereHookNoResults', + ]); + CRM_Core_Config::singleton()->userPermissionClass->permissions = [ + 'access CiviCRM', + 'view my contact', + ]; + $result = $this->callAPISuccess('contact', 'get', [ 'check_permissions' => 1, 'return' => 'display_name', - )); + ]); $this->assertEquals(1, $result['count']); } @@ -107,12 +116,18 @@ public function testContactGetOneResultHookWithViewMyContact() { */ public function testContactEditHookWithEditMyContact() { $cid = $this->createLoggedInUser(); - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookNoResults')); - CRM_Core_Config::singleton()->userPermissionClass->permissions = array('access CiviCRM', 'edit my contact'); - $this->callAPISuccess('contact', 'create', array( + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereHookNoResults', + ]); + CRM_Core_Config::singleton()->userPermissionClass->permissions = [ + 'access CiviCRM', + 'edit my contact', + ]; + $this->callAPISuccess('contact', 'create', [ 'check_permissions' => 1, 'id' => $cid, - )); + ]); } /** @@ -120,16 +135,30 @@ public function testContactEditHookWithEditMyContact() { */ public function testAddressWithoutContactIDAccess() { $ownID = $this->createLoggedInUser(); - CRM_Core_Config::singleton()->userPermissionClass->permissions = array('access CiviCRM', 'view all contacts'); - $this->callAPISuccess('Address', 'create', array( + CRM_Core_Config::singleton()->userPermissionClass->permissions = [ + 'access CiviCRM', + 'view all contacts', + ]; + $this->callAPISuccess('Address', 'create', [ 'city' => 'Mouseville', 'location_type_id' => 'Main', 'api.LocBlock.create' => 1, 'contact_id' => $ownID, - )); - $this->callAPISuccessGetSingle('Address', array('city' => 'Mouseville', 'check_permissions' => 1)); - CRM_Core_DAO::executeQuery('UPDATE civicrm_address SET contact_id = NULL WHERE contact_id = %1', array(1 => array($ownID, 'Integer'))); - $this->callAPISuccessGetSingle('Address', array('city' => 'Mouseville', 'check_permissions' => 1)); + ]); + $this->callAPISuccessGetSingle('Address', [ + 'city' => 'Mouseville', + 'check_permissions' => 1, + ]); + CRM_Core_DAO::executeQuery('UPDATE civicrm_address SET contact_id = NULL WHERE contact_id = %1', [ + 1 => [ + $ownID, + 'Integer', + ], + ]); + $this->callAPISuccessGetSingle('Address', [ + 'city' => 'Mouseville', + 'check_permissions' => 1, + ]); } /** @@ -137,57 +166,77 @@ public function testAddressWithoutContactIDAccess() { */ public function testRelatedEntityPermissions() { $this->createLoggedInUser(); - $disallowedContact = $this->individualCreate(array(), 0); - $this->allowedContactId = $this->individualCreate(array(), 1); - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereOnlyOne')); - CRM_Core_Config::singleton()->userPermissionClass->permissions = array('access CiviCRM'); - $testEntities = array( - 'Email' => array('email' => 'null@nothing', 'location_type_id' => 1), - 'Phone' => array('phone' => '123456', 'location_type_id' => 1), - 'IM' => array('name' => 'hello', 'location_type_id' => 1), - 'Website' => array('url' => 'http://test'), - 'Address' => array('street_address' => '123 Sesame St.', 'location_type_id' => 1), - ); + $disallowedContact = $this->individualCreate([], 0); + $this->allowedContactId = $this->individualCreate([], 1); + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereOnlyOne', + ]); + CRM_Core_Config::singleton()->userPermissionClass->permissions = ['access CiviCRM']; + $testEntities = [ + 'Email' => ['email' => 'null@nothing', 'location_type_id' => 1], + 'Phone' => ['phone' => '123456', 'location_type_id' => 1], + 'IM' => ['name' => 'hello', 'location_type_id' => 1], + 'Website' => ['url' => 'http://test'], + 'Address' => [ + 'street_address' => '123 Sesame St.', + 'location_type_id' => 1, + ], + ]; foreach ($testEntities as $entity => $params) { - $params += array( + $params += [ 'contact_id' => $disallowedContact, 'check_permissions' => 1, - ); + ]; // We should be prevented from getting or creating entities for a contact we don't have permission for $this->callAPIFailure($entity, 'create', $params); - $this->callAPISuccess($entity, 'create', array('check_permissions' => 0) + $params); - $results = $this->callAPISuccess($entity, 'get', array('contact_id' => $disallowedContact, 'check_permissions' => 1)); + $this->callAPISuccess($entity, 'create', ['check_permissions' => 0] + $params); + $results = $this->callAPISuccess($entity, 'get', [ + 'contact_id' => $disallowedContact, + 'check_permissions' => 1, + ]); $this->assertEquals(0, $results['count']); // We should be allowed to create and get for contacts we do have permission on $params['contact_id'] = $this->allowedContactId; $this->callAPISuccess($entity, 'create', $params); - $results = $this->callAPISuccess($entity, 'get', array('contact_id' => $this->allowedContactId, 'check_permissions' => 1)); + $results = $this->callAPISuccess($entity, 'get', [ + 'contact_id' => $this->allowedContactId, + 'check_permissions' => 1, + ]); $this->assertGreaterThan(0, $results['count']); } - $newTag = civicrm_api3('Tag', 'create', array( + $newTag = civicrm_api3('Tag', 'create', [ 'name' => 'Foo123', - )); - $relatedEntities = array( - 'Note' => array('note' => 'abc'), - 'EntityTag' => array('tag_id' => $newTag['id']), - ); + ]); + $relatedEntities = [ + 'Note' => ['note' => 'abc'], + 'EntityTag' => ['tag_id' => $newTag['id']], + ]; foreach ($relatedEntities as $entity => $params) { - $params += array( + $params += [ 'entity_id' => $disallowedContact, 'entity_table' => 'civicrm_contact', 'check_permissions' => 1, - ); + ]; // We should be prevented from getting or creating entities for a contact we don't have permission for $this->callAPIFailure($entity, 'create', $params); - $this->callAPISuccess($entity, 'create', array('check_permissions' => 0) + $params); - $results = $this->callAPISuccess($entity, 'get', array('entity_id' => $disallowedContact, 'entity_table' => 'civicrm_contact', 'check_permissions' => 1)); + $this->callAPISuccess($entity, 'create', ['check_permissions' => 0] + $params); + $results = $this->callAPISuccess($entity, 'get', [ + 'entity_id' => $disallowedContact, + 'entity_table' => 'civicrm_contact', + 'check_permissions' => 1, + ]); $this->assertEquals(0, $results['count']); // We should be allowed to create and get for entities we do have permission on $params['entity_id'] = $this->allowedContactId; $this->callAPISuccess($entity, 'create', $params); - $results = $this->callAPISuccess($entity, 'get', array('entity_id' => $this->allowedContactId, 'entity_table' => 'civicrm_contact', 'check_permissions' => 1)); + $results = $this->callAPISuccess($entity, 'get', [ + 'entity_id' => $this->allowedContactId, + 'entity_table' => 'civicrm_contact', + 'check_permissions' => 1, + ]); $this->assertGreaterThan(0, $results['count']); } } @@ -196,11 +245,14 @@ public function testRelatedEntityPermissions() { * Function tests all results are returned. */ public function testContactGetAllResultsHook() { - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults')); - $result = $this->callAPISuccess('contact', 'get', array( + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereHookAllResults', + ]); + $result = $this->callAPISuccess('contact', 'get', [ 'check_permissions' => 1, 'return' => 'display_name', - )); + ]); $this->assertEquals(2, $result['count']); } @@ -209,12 +261,15 @@ public function testContactGetAllResultsHook() { * Function tests that deleted contacts are not returned. */ public function testContactGetPermissionHookNoDeleted() { - $this->callAPISuccess('contact', 'create', array('id' => 2, 'is_deleted' => 1)); - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults')); - $result = $this->callAPISuccess('contact', 'get', array( + $this->callAPISuccess('contact', 'create', ['id' => 2, 'is_deleted' => 1]); + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereHookAllResults', + ]); + $result = $this->callAPISuccess('contact', 'get', [ 'check_permissions' => 1, 'return' => 'display_name', - )); + ]); $this->assertEquals(1, $result['count']); } @@ -222,12 +277,15 @@ public function testContactGetPermissionHookNoDeleted() { * Test permissions limited by hook. */ public function testContactGetHookLimitingHook() { - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereOnlySecond')); + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereOnlySecond', + ]); - $result = $this->callAPISuccess('contact', 'get', array( + $result = $this->callAPISuccess('contact', 'get', [ 'check_permissions' => 1, 'return' => 'display_name', - )); + ]); $this->assertEquals(1, $result['count']); } @@ -235,10 +293,10 @@ public function testContactGetHookLimitingHook() { * Confirm that without check permissions we still get 2 contacts returned. */ public function testContactGetHookLimitingHookDontCheck() { - $result = $this->callAPISuccess('contact', 'get', array( + $result = $this->callAPISuccess('contact', 'get', [ 'check_permissions' => 0, 'return' => 'display_name', - )); + ]); $this->assertEquals(2, $result['count']); } @@ -246,12 +304,15 @@ public function testContactGetHookLimitingHookDontCheck() { * Check that id works as a filter. */ public function testContactGetIDFilter() { - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults')); - $result = $this->callAPISuccess('contact', 'get', array( + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereHookAllResults', + ]); + $result = $this->callAPISuccess('contact', 'get', [ 'sequential' => 1, 'id' => 2, 'check_permissions' => 1, - )); + ]); $this->assertEquals(1, $result['count']); $this->assertEquals(2, $result['id']); @@ -261,14 +322,17 @@ public function testContactGetIDFilter() { * Check that address IS returned. */ public function testContactGetAddressReturned() { - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereOnlySecond')); - $fullresult = $this->callAPISuccess('contact', 'get', array( + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereOnlySecond', + ]); + $fullresult = $this->callAPISuccess('contact', 'get', [ 'sequential' => 1, - )); + ]); //return doesn't work for all keys - can't fix that here so let's skip ... //prefix & suffix are inconsistent due to CRM-7929 // unsure about others but return doesn't work on them - $elementsReturnDoesntSupport = array( + $elementsReturnDoesntSupport = [ 'prefix', 'suffix', 'gender', @@ -278,13 +342,13 @@ public function testContactGetAddressReturned() { 'phone', 'worldregion_id', 'world_region', - ); + ]; $expectedReturnElements = array_diff(array_keys($fullresult['values'][0]), $elementsReturnDoesntSupport); - $result = $this->callAPISuccess('contact', 'get', array( + $result = $this->callAPISuccess('contact', 'get', [ 'check_permissions' => 1, 'return' => $expectedReturnElements, 'sequential' => 1, - )); + ]); $this->assertEquals(1, $result['count']); foreach ($expectedReturnElements as $element) { $this->assertArrayHasKey($element, $result['values'][0]); @@ -295,15 +359,18 @@ public function testContactGetAddressReturned() { * Check that pledge IS not returned. */ public function testContactGetPledgeIDNotReturned() { - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults')); - $this->callAPISuccess('contact', 'get', array( + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereHookAllResults', + ]); + $this->callAPISuccess('contact', 'get', [ 'sequential' => 1, - )); - $result = $this->callAPISuccess('contact', 'get', array( + ]); + $result = $this->callAPISuccess('contact', 'get', [ 'check_permissions' => 1, 'return' => 'pledge_id', 'sequential' => 1, - )); + ]); $this->assertArrayNotHasKey('pledge_id', $result['values'][0]); } @@ -311,15 +378,18 @@ public function testContactGetPledgeIDNotReturned() { * Check that pledge IS not an allowable filter. */ public function testContactGetPledgeIDNotFiltered() { - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults')); - $this->callAPISuccess('contact', 'get', array( + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereHookAllResults', + ]); + $this->callAPISuccess('contact', 'get', [ 'sequential' => 1, - )); - $result = $this->callAPISuccess('contact', 'get', array( + ]); + $result = $this->callAPISuccess('contact', 'get', [ 'check_permissions' => 1, 'pledge_id' => 1, 'sequential' => 1, - )); + ]); $this->assertEquals(2, $result['count']); } @@ -327,31 +397,34 @@ public function testContactGetPledgeIDNotFiltered() { * Check that chaining doesn't bypass permissions */ public function testContactGetPledgeNotChainable() { - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereOnlySecond')); - $this->callAPISuccess('contact', 'get', array( + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereOnlySecond', + ]); + $this->callAPISuccess('contact', 'get', [ 'sequential' => 1, - )); - $this->callAPIFailure('contact', 'get', array( - 'check_permissions' => 1, - 'api.pledge.get' => 1, - 'sequential' => 1, - ), + ]); + $this->callAPIFailure('contact', 'get', [ + 'check_permissions' => 1, + 'api.pledge.get' => 1, + 'sequential' => 1, + ], 'Error in call to Pledge_get : API permission check failed for Pledge/get call; insufficient permission: require access CiviCRM and access CiviPledge' ); } public function setupCoreACL() { $this->createLoggedInUser(); - $this->_permissionedDisabledGroup = $this->groupCreate(array( + $this->_permissionedDisabledGroup = $this->groupCreate([ 'title' => 'pick-me-disabled', 'is_active' => 0, 'name' => 'pick-me-disabled', - )); - $this->_permissionedGroup = $this->groupCreate(array( + ]); + $this->_permissionedGroup = $this->groupCreate([ 'title' => 'pick-me-active', 'is_active' => 1, 'name' => 'pick-me-active', - )); + ]); $this->setupACL(); } @@ -361,13 +434,16 @@ public function setupCoreACL() { * @param $entity */ public function testEntitiesGetHookLimitingHookNoCheck($entity) { - CRM_Core_Config::singleton()->userPermissionClass->permissions = array(); + CRM_Core_Config::singleton()->userPermissionClass->permissions = []; $this->setUpEntities($entity); - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookNoResults')); - $result = $this->callAPISuccess($entity, 'get', array( + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereHookNoResults', + ]); + $result = $this->callAPISuccess($entity, 'get', [ 'check_permissions' => 0, 'return' => 'contact_id', - )); + ]); $this->assertEquals(2, $result['count']); } @@ -380,11 +456,14 @@ public function testEntitiesGetCoreACLLimitingHookNoCheck($entity) { $this->setupCoreACL(); //CRM_Core_Config::singleton()->userPermissionClass->permissions = array(); $this->setUpEntities($entity); - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookNoResults')); - $result = $this->callAPISuccess($entity, 'get', array( + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereHookNoResults', + ]); + $result = $this->callAPISuccess($entity, 'get', [ 'check_permissions' => 0, 'return' => 'contact_id', - )); + ]); $this->assertEquals(2, $result['count']); } @@ -397,10 +476,10 @@ public function testEntitiesGetCoreACLLimitingHookNoCheck($entity) { public function testEntitiesGetCoreACLLimitingCheck($entity) { $this->setupCoreACL(); $this->setUpEntities($entity); - $result = $this->callAPISuccess($entity, 'get', array( + $result = $this->callAPISuccess($entity, 'get', [ 'check_permissions' => 1, 'return' => 'contact_id', - )); + ]); $this->assertEquals(0, $result['count']); } @@ -412,12 +491,15 @@ public function testEntitiesGetCoreACLLimitingCheck($entity) { */ public function testEntityGetNoResultsHook($entity) { $this->markTestIncomplete('hook acls only work with contacts so far'); - CRM_Core_Config::singleton()->userPermissionClass->permissions = array(); + CRM_Core_Config::singleton()->userPermissionClass->permissions = []; $this->setUpEntities($entity); - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookNoResults')); - $result = $this->callAPISuccess($entity, 'get', array( + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereHookNoResults', + ]); + $result = $this->callAPISuccess($entity, 'get', [ 'check_permission' => 1, - )); + ]); $this->assertEquals(0, $result['count']); } @@ -425,7 +507,10 @@ public function testEntityGetNoResultsHook($entity) { * @return array */ public static function entities() { - return array(array('contribution'), array('participant'));// @todo array('pledge' => 'pledge') + return [ + ['contribution'], + ['participant'], + ];// @todo array('pledge' => 'pledge') } /** @@ -434,22 +519,22 @@ public static function entities() { */ public function setUpEntities($entity) { $baoObj = new CRM_Core_DAO(); - $baoObj->createTestObject(_civicrm_api3_get_BAO($entity), array(), 2, 0); - CRM_Core_Config::singleton()->userPermissionClass->permissions = array( + $baoObj->createTestObject(_civicrm_api3_get_BAO($entity), [], 2, 0); + CRM_Core_Config::singleton()->userPermissionClass->permissions = [ 'access CiviCRM', 'access CiviContribute', 'access CiviEvent', 'view event participants', - ); + ]; } /** * Basic check that an unpermissioned call keeps working and permissioned call fails. */ public function testGetActivityNoPermissions() { - $this->setPermissions(array()); - $this->callAPISuccess('Activity', 'get', array()); - $this->callAPIFailure('Activity', 'get', array('check_permissions' => 1)); + $this->setPermissions([]); + $this->callAPISuccess('Activity', 'get', []); + $this->callAPIFailure('Activity', 'get', ['check_permissions' => 1]); } /** @@ -457,16 +542,19 @@ public function testGetActivityNoPermissions() { */ public function testGetActivityViewAllActivitiesDoesntCutItAnymore() { $activity = $this->activityCreate(); - $this->setPermissions(array('view all activities', 'access CiviCRM')); - $this->callAPISuccessGetCount('Activity', ['check_permissions' => 1, 'id' => $activity['id']], 0); + $this->setPermissions(['view all activities', 'access CiviCRM']); + $this->callAPISuccessGetCount('Activity', [ + 'check_permissions' => 1, + 'id' => $activity['id'], + ], 0); } /** * View all activities is required unless id is passed in. */ public function testGetActivityViewAllContactsEnoughWithoutID() { - $this->setPermissions(array('view all contacts', 'access CiviCRM')); - $this->callAPISuccess('Activity', 'get', array('check_permissions' => 1)); + $this->setPermissions(['view all contacts', 'access CiviCRM']); + $this->callAPISuccess('Activity', 'get', ['check_permissions' => 1]); } /** @@ -474,8 +562,11 @@ public function testGetActivityViewAllContactsEnoughWithoutID() { */ public function testGetActivityViewAllContactsEnoughWIthID() { $activity = $this->activityCreate(); - $this->setPermissions(array('view all contacts', 'access CiviCRM')); - $this->callAPISuccess('Activity', 'getsingle', array('check_permissions' => 1, 'id' => $activity['id'])); + $this->setPermissions(['view all contacts', 'access CiviCRM']); + $this->callAPISuccess('Activity', 'getsingle', [ + 'check_permissions' => 1, + 'id' => $activity['id'], + ]); } /** @@ -483,8 +574,11 @@ public function testGetActivityViewAllContactsEnoughWIthID() { */ public function testGetActivityAccessCiviCRMNotEnough() { $activity = $this->activityCreate(); - $this->setPermissions(array('access CiviCRM')); - $this->callAPIFailure('Activity', 'getsingle', array('check_permissions' => 1, 'id' => $activity['id'])); + $this->setPermissions(['access CiviCRM']); + $this->callAPIFailure('Activity', 'getsingle', [ + 'check_permissions' => 1, + 'id' => $activity['id'], + ]); } /** @@ -499,10 +593,19 @@ public function testGetActivityAccessCiviCRMNotEnough() { public function testGetActivityCheckPermissionsByComponent() { $activity = $this->activityCreate(['activity_type_id' => 'Contribution']); $activity2 = $this->activityCreate(['activity_type_id' => 'Pledge Reminder']); - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults')); + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereHookAllResults', + ]); $this->setPermissions(['access CiviCRM', 'access CiviContribute']); - $this->callAPISuccessGetSingle('Activity', ['check_permissions' => 1, 'id' => ['IN' => [$activity['id'], $activity2['id']]]]); - $this->callAPISuccessGetCount('Activity', ['check_permissions' => 1, 'id' => ['IN' => [$activity['id'], $activity2['id']]]], 1); + $this->callAPISuccessGetSingle('Activity', [ + 'check_permissions' => 1, + 'id' => ['IN' => [$activity['id'], $activity2['id']]], + ]); + $this->callAPISuccessGetCount('Activity', [ + 'check_permissions' => 1, + 'id' => ['IN' => [$activity['id'], $activity2['id']]], + ], 1); } @@ -513,10 +616,23 @@ public function testGetActivityCheckPermissionsByCaseComponent() { CRM_Core_BAO_ConfigSetting::enableComponent('CiviCase'); $activity = $this->activityCreate(['activity_type_id' => 'Open Case']); $activity2 = $this->activityCreate(['activity_type_id' => 'Pledge Reminder']); - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults')); - $this->setPermissions(['access CiviCRM', 'access CiviContribute', 'access all cases and activities']); - $this->callAPISuccessGetSingle('Activity', ['check_permissions' => 1, 'id' => ['IN' => [$activity['id'], $activity2['id']]]]); - $this->callAPISuccessGetCount('Activity', ['check_permissions' => 1, 'id' => ['IN' => [$activity['id'], $activity2['id']]]], 1); + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereHookAllResults', + ]); + $this->setPermissions([ + 'access CiviCRM', + 'access CiviContribute', + 'access all cases and activities', + ]); + $this->callAPISuccessGetSingle('Activity', [ + 'check_permissions' => 1, + 'id' => ['IN' => [$activity['id'], $activity2['id']]], + ]); + $this->callAPISuccessGetCount('Activity', [ + 'check_permissions' => 1, + 'id' => ['IN' => [$activity['id'], $activity2['id']]], + ], 1); } /** @@ -526,12 +642,21 @@ public function testGetActivityCheckPermissionsByCaseComponent() { * Otherwise it sticks with the blunt original permissions. */ public function testGetActivityByACL() { - $this->setPermissions(array('access CiviCRM')); + $this->setPermissions(['access CiviCRM']); $activity = $this->activityCreate(); - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults')); - $this->callAPISuccessGetSingle('Activity', ['check_permissions' => 1, 'id' => $activity['id']]); - $this->callAPISuccessGetCount('Activity', ['check_permissions' => 1, 'id' => $activity['id']]); + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereHookAllResults', + ]); + $this->callAPISuccessGetSingle('Activity', [ + 'check_permissions' => 1, + 'id' => $activity['id'], + ]); + $this->callAPISuccessGetCount('Activity', [ + 'check_permissions' => 1, + 'id' => $activity['id'], + ]); } /** @@ -544,14 +669,25 @@ public function testGetActivityByAclCannotViewAllContacts() { foreach ($contacts as $role => $contact_id) { $this->allowedContactId = $contact_id; - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereOnlyOne')); + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereOnlyOne', + ]); $this->cleanupCachedPermissions(); $result = $this->callAPISuccessGetSingle('Activity', [ 'check_permissions' => 1, 'id' => $activity['id'], - 'return' => ['source_contact_id', 'target_contact_id', 'assignee_contact_id'], + 'return' => [ + 'source_contact_id', + 'target_contact_id', + 'assignee_contact_id', + ], ]); - foreach (['source_contact', 'target_contact', 'assignee_contact'] as $roleName) { + foreach ([ + 'source_contact', + 'target_contact', + 'assignee_contact', + ] as $roleName) { $roleKey = $roleName . '_id'; if ($role !== $roleKey) { $this->assertTrue(empty($result[$roleKey]), "Only contact in $role is permissioned to be returned, not $roleKey"); @@ -570,10 +706,13 @@ public function testGetActivityByAclCannotViewAllContacts() { public function testGetActivityByAclCannotViewAnyContacts() { $activity = $this->activityCreate(); $contacts = $this->getActivityContacts($activity); - $this->setPermissions(array('access CiviCRM')); + $this->setPermissions(['access CiviCRM']); foreach ($contacts as $contact_id) { - $this->callAPIFailure('Activity', 'getsingle', array('check_permissions' => 1, 'id' => $activity['id'])); + $this->callAPIFailure('Activity', 'getsingle', [ + 'check_permissions' => 1, + 'id' => $activity['id'], + ]); } } @@ -585,13 +724,19 @@ public function testGetActivityByAclCannotViewAnyContacts() { * @throws \CRM_Core_Exception */ public function testGetActivityACLSourceContactDeleted() { - $this->setPermissions(array('access CiviCRM', 'delete contacts')); + $this->setPermissions(['access CiviCRM', 'delete contacts']); $activity = $this->activityCreate(); $contacts = $this->getActivityContacts($activity); - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults')); + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereHookAllResults', + ]); $this->contactDelete($contacts['source_contact_id']); - $this->callAPISuccess('Activity', 'getsingle', array('check_permissions' => 1, 'id' => $activity['id'])); + $this->callAPISuccess('Activity', 'getsingle', [ + 'check_permissions' => 1, + 'id' => $activity['id'], + ]); } /** @@ -602,13 +747,16 @@ public function testActivitiesGetMultipleIdsCheckPermissions() { $this->createLoggedInUser(); $activity = $this->activityCreate(); $activity2 = $this->activityCreate(); - $this->setPermissions(array('access CiviCRM')); - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults')); + $this->setPermissions(['access CiviCRM']); + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereHookAllResults', + ]); // Get activities associated with contact $this->_contactID. - $params = array( - 'id' => array('IN' => array($activity['id'], $activity2['id'])), + $params = [ + 'id' => ['IN' => [$activity['id'], $activity2['id']]], 'check_permissions' => TRUE, - ); + ]; $result = $this->callAPISuccess('activity', 'get', $params); $this->assertEquals(2, $result['count']); } @@ -622,21 +770,29 @@ public function testActivitiesGetMultipleIdsCheckPermissionsLimitedACL() { $this->createLoggedInUser(); $activity = $this->activityCreate(); $contacts = $this->getActivityContacts($activity); - $this->setPermissions(array('access CiviCRM')); + $this->setPermissions(['access CiviCRM']); foreach ($contacts as $contact_id) { $this->allowedContacts[] = $contact_id; } - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereMultipleContacts')); + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereMultipleContacts', + ]); $contact2 = $this->individualCreate(); - $activity2 = $this->activityCreate(array('source_contact_id' => $contact2)); + $activity2 = $this->activityCreate(['source_contact_id' => $contact2]); // Get activities associated with contact $this->_contactID. - $params = array( - 'id' => array('IN' => array($activity['id'])), + $params = [ + 'id' => ['IN' => [$activity['id']]], 'check_permissions' => TRUE, - ); + ]; $result = $this->callAPISuccess('activity', 'get', $params); $this->assertEquals(1, $result['count']); - $this->callAPIFailure('activity', 'get', array_merge($params, array('id' => array('IN', array($activity2['id']))))); + $this->callAPIFailure('activity', 'get', array_merge($params, [ + 'id' => [ + 'IN', + [$activity2['id']], + ], + ])); } /** @@ -647,13 +803,16 @@ public function testActivitiesGetMultipleIdsCheckPermissionsNotIN() { $this->createLoggedInUser(); $activity = $this->activityCreate(); $activity2 = $this->activityCreate(); - $this->setPermissions(array('access CiviCRM')); - $this->hookClass->setHook('civicrm_aclWhereClause', array($this, 'aclWhereHookAllResults')); + $this->setPermissions(['access CiviCRM']); + $this->hookClass->setHook('civicrm_aclWhereClause', [ + $this, + 'aclWhereHookAllResults', + ]); // Get activities associated with contact $this->_contactID. - $params = array( - 'id' => array('NOT IN' => array($activity['id'], $activity2['id'])), + $params = [ + 'id' => ['NOT IN' => [$activity['id'], $activity2['id']]], 'check_permissions' => TRUE, - ); + ]; $result = $this->callAPISuccess('activity', 'get', $params); $this->assertEquals(0, $result['count']); } @@ -667,14 +826,14 @@ public function testActivitiesGetMultipleIdsCheckPermissionsNotIN() { * @throws \CRM_Core_Exception */ protected function getActivityContacts($activity) { - $contacts = array(); + $contacts = []; - $activityContacts = $this->callAPISuccess('ActivityContact', 'get', array( + $activityContacts = $this->callAPISuccess('ActivityContact', 'get', [ 'activity_id' => $activity['id'], - ) + ] ); - $activityRecordTypes = $this->callAPISuccess('ActivityContact', 'getoptions', array('field' => 'record_type_id')); + $activityRecordTypes = $this->callAPISuccess('ActivityContact', 'getoptions', ['field' => 'record_type_id']); foreach ($activityContacts['values'] as $activityContact) { $type = $activityRecordTypes['values'][$activityContact['record_type_id']]; switch ($type) { From 7a17438cc31e7a5ccb188699debd10a928da67f8 Mon Sep 17 00:00:00 2001 From: eileen Date: Mon, 18 Mar 2019 14:21:06 +1300 Subject: [PATCH 078/408] Update Cancel Billing & update billing to use status bounce rather than fatal Per https://lab.civicrm.org/dev/core/issues/560 we have resolved to get rid of fatal & move to throwing Exceptions. However, I'm leaning towards making statusBounces the rules for when we just deem a form inaccessible. In this case we have 3 paralel forms - cancel, update & a similar update but slightly different just cos. One does a status bounce - 2 spit out fatals when access not available. Just looking at Cancel these are the places that still have fatal - The recurring contribution looks to have been cancelled already - Required information missing I'm not sure the value of a fatal as opposed to the gentler statusBounces in either of those cases. Throwing an exception looks very much like a fatal except 1) it doesn't hurt tests or cli tools as much 2) IF display backtrace is enabled THEN the back trace displays. so, it's generally better BUT I kinda feel like the only time when it's actually better than a status bounce is when a bug has occurred (eg. an unexpectedly failed api call) - anything we anticipate seems like a bounce to me.... --- CRM/Contribute/Form/CancelSubscription.php | 2 +- CRM/Contribute/Form/UpdateBilling.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CRM/Contribute/Form/CancelSubscription.php b/CRM/Contribute/Form/CancelSubscription.php index 8c76d9502dde..c904f7fa9462 100644 --- a/CRM/Contribute/Form/CancelSubscription.php +++ b/CRM/Contribute/Form/CancelSubscription.php @@ -107,7 +107,7 @@ public function preProcess() { if (!CRM_Core_Permission::check('edit contributions')) { if ($this->_subscriptionDetails->contact_id != $this->getContactID()) { - CRM_Core_Error::fatal(ts('You do not have permission to cancel this recurring contribution.')); + CRM_Core_Error::statusBounce(ts('You do not have permission to cancel this recurring contribution.')); } $this->_selfService = TRUE; } diff --git a/CRM/Contribute/Form/UpdateBilling.php b/CRM/Contribute/Form/UpdateBilling.php index e9c19c4332fb..0e7cc9b267e4 100644 --- a/CRM/Contribute/Form/UpdateBilling.php +++ b/CRM/Contribute/Form/UpdateBilling.php @@ -89,7 +89,7 @@ public function preProcess() { } if (!CRM_Core_Permission::check('edit contributions')) { if ($this->_subscriptionDetails->contact_id != $this->getContactID()) { - CRM_Core_Error::fatal(ts('You do not have permission to cancel subscription.')); + CRM_Core_Error::statusBounce(ts('You do not have permission to cancel subscription.')); } $this->_selfService = TRUE; } From b974584b962ddd1bcb1cfbbd7f6af0c10e9e907d Mon Sep 17 00:00:00 2001 From: "Matthew Wire (MJW Consulting)" Date: Mon, 18 Mar 2019 17:44:21 +1300 Subject: [PATCH 079/408] Code cleanup on membership block loop --- CRM/Contribute/Form/ContributionBase.php | 31 ++++++++++++++---------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/CRM/Contribute/Form/ContributionBase.php b/CRM/Contribute/Form/ContributionBase.php index f6e71a167d9a..f8b6f1a1467b 100644 --- a/CRM/Contribute/Form/ContributionBase.php +++ b/CRM/Contribute/Form/ContributionBase.php @@ -1195,6 +1195,18 @@ protected function buildMembershipBlock( $membershipTypeValues = CRM_Member_BAO_Membership::buildMembershipTypeValues($this, $membershipTypeIds); $this->_membershipTypeValues = $membershipTypeValues; $endDate = NULL; + + // Check if we support auto-renew on this contribution page + // FIXME: If any of the payment processors do NOT support recurring you cannot setup an + // auto-renew payment even if that processor is not selected. + $allowAutoRenewOpt = TRUE; + if (is_array($this->_paymentProcessors)) { + foreach ($this->_paymentProcessors as $id => $val) { + if ($id && !$val['is_recur']) { + $allowAutoRenewOpt = FALSE; + } + } + } foreach ($membershipTypeIds as $value) { $memType = $membershipTypeValues[$value]; if ($selectedMembershipTypeID != NULL) { @@ -1217,23 +1229,16 @@ protected function buildMembershipBlock( } } elseif ($memType['is_active']) { - $javascriptMethod = NULL; - $allowAutoRenewOpt = (int) $memType['auto_renew']; - if (is_array($this->_paymentProcessors)) { - foreach ($this->_paymentProcessors as $id => $val) { - if ($id && !$val['is_recur']) { - $allowAutoRenewOpt = 0; - continue; - } - } - } - - $javascriptMethod = array('onclick' => "return showHideAutoRenew( this.value );"); - $autoRenewMembershipTypeOptions["autoRenewMembershipType_{$value}"] = (int) $allowAutoRenewOpt * CRM_Utils_Array::value($value, CRM_Utils_Array::value('auto_renew', $this->_membershipBlock));; if ($allowAutoRenewOpt) { + $javascriptMethod = array('onclick' => "return showHideAutoRenew( this.value );"); + $autoRenewMembershipTypeOptions["autoRenewMembershipType_{$value}"] = (int) $memType['auto_renew'] * CRM_Utils_Array::value($value, CRM_Utils_Array::value('auto_renew', $this->_membershipBlock)); $allowAutoRenewMembership = TRUE; } + else { + $javascriptMethod = NULL; + $autoRenewMembershipTypeOptions["autoRenewMembershipType_{$value}"] = 0; + } //add membership type. $radio[$memType['id']] = $this->createElement('radio', NULL, NULL, NULL, From 28cfbff70d436446c348fefdf37b64ef8c47d0c7 Mon Sep 17 00:00:00 2001 From: Pradeep Nayak Date: Mon, 18 Mar 2019 12:17:47 +0000 Subject: [PATCH 080/408] dev/core/issues/806, Fixed DB error already exist when recording recurring payment having tax --- CRM/Contribute/BAO/ContributionRecur.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CRM/Contribute/BAO/ContributionRecur.php b/CRM/Contribute/BAO/ContributionRecur.php index 126cf8f67d95..af0dc48824a3 100644 --- a/CRM/Contribute/BAO/ContributionRecur.php +++ b/CRM/Contribute/BAO/ContributionRecur.php @@ -901,7 +901,7 @@ public static function updateOnNewPayment($recurringContributionID, $paymentStat */ protected static function isComplete($recurringContributionID, $installments) { $paidInstallments = CRM_Core_DAO::singleValueQuery( - 'SELECT count(*) FROM civicrm_contribution + 'SELECT count(*) FROM civicrm_contribution WHERE contribution_recur_id = %1 AND contribution_status_id = ' . CRM_Core_PseudoConstant::getKey('CRM_Contribute_BAO_Contribution', 'contribution_status_id', 'Completed'), array(1 => array($recurringContributionID, 'Integer')) @@ -949,13 +949,13 @@ public static function calculateRecurLineItems($recurId, $total_amount, $financi $priceField = new CRM_Price_DAO_PriceField(); $priceField->id = $lineItem['price_field_id']; $priceField->find(TRUE); - $lineSets[$priceField->price_set_id][] = $lineItem; + $lineSets[$priceField->price_set_id][$lineItem['price_field_id']] = $lineItem; } } // CRM-19309 if more than one then just pass them through: elseif (count($lineItems) > 1) { foreach ($lineItems as $index => $lineItem) { - $lineSets[$index][] = $lineItem; + $lineSets[$index][$lineItem['price_field_id']] = $lineItem; } } From 453c80e75b2700571c2a8a54d239c0039131e068 Mon Sep 17 00:00:00 2001 From: Pradeep Nayak Date: Tue, 5 Feb 2019 20:49:28 +0000 Subject: [PATCH 081/408] Display contact sub type always --- templates/CRM/Contact/Form/Edit/Household.tpl | 28 ++++++------- .../CRM/Contact/Form/Edit/Organization.tpl | 42 ++++++++++--------- 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/templates/CRM/Contact/Form/Edit/Household.tpl b/templates/CRM/Contact/Form/Edit/Household.tpl index 9cb855705d06..8f679031bc47 100644 --- a/templates/CRM/Contact/Form/Edit/Household.tpl +++ b/templates/CRM/Contact/Form/Edit/Household.tpl @@ -25,18 +25,18 @@ *} {* tpl for building Household related fields *} - - - - - - - + + + + +
{$form.household_name.label}
- {$form.household_name.html} -
{$form.nick_name.label}
- {$form.nick_name.html}
{if $action == 1 and $contactSubType} {else} - {$form.contact_sub_type.label}
- {$form.contact_sub_type.html} - {/if} -
+ {$form.household_name.label}
+ {$form.household_name.html} +
+ {$form.nick_name.label}
+ {$form.nick_name.html} +
+ {$form.contact_sub_type.label}
+ {$form.contact_sub_type.html} +
diff --git a/templates/CRM/Contact/Form/Edit/Organization.tpl b/templates/CRM/Contact/Form/Edit/Organization.tpl index 94a1503abe84..d1254f8084bd 100644 --- a/templates/CRM/Contact/Form/Edit/Organization.tpl +++ b/templates/CRM/Contact/Form/Edit/Organization.tpl @@ -25,24 +25,26 @@ *} {* tpl for building Organization related fields *} - - - - - - - - - - - + + + + + + +
{$form.organization_name.label}
- {$form.organization_name.html} -
{$form.legal_name.label}
- {$form.legal_name.html}
{$form.nick_name.label}
- {$form.nick_name.html}
{$form.sic_code.label}
- {$form.sic_code.html}
{if $action == 1 and $contactSubType} {else} - {$form.contact_sub_type.label}
- {$form.contact_sub_type.html} - {/if} -
{ + $form.organization_name.label}
+ {$form.organization_name.html} +
+ {$form.legal_name.label}
+ {$form.legal_name.html} +
+ {$form.nick_name.label}
+ {$form.nick_name.html} +
+ {$form.sic_code.label}
+ {$form.sic_code.html} +
+ {$form.contact_sub_type.label}
+ {$form.contact_sub_type.html} +
From 4e60e3752d8fee1c64ddf81c17bf057975c54753 Mon Sep 17 00:00:00 2001 From: Andrew Hunt Date: Mon, 18 Mar 2019 12:03:38 -0400 Subject: [PATCH 082/408] CiviMember: excluding Expired memberships by name, not label --- CRM/Member/BAO/Membership.php | 12 ++++++------ .../phpunit/CRM/Member/BAO/MembershipStatusTest.php | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CRM/Member/BAO/Membership.php b/CRM/Member/BAO/Membership.php index d16175821c62..bce4b15e5419 100644 --- a/CRM/Member/BAO/Membership.php +++ b/CRM/Member/BAO/Membership.php @@ -2241,7 +2241,11 @@ public static function updateAllMembershipStatus() { // Tests for this function are in api_v3_JobTest. Please add tests for all updates. $updateCount = $processCount = self::updateDeceasedMembersStatuses(); - $allStatus = CRM_Member_BAO_Membership::buildOptions('status_id', 'get'); + + // We want all of the statuses as id => name, even the disabled ones (cf. + // CRM-15475), to identify which are Pending, Deceased, Cancelled, and + // Expired. + $allStatus = CRM_Member_BAO_Membership::buildOptions('status_id', 'validate'); $allTypes = CRM_Member_PseudoConstant::membershipType(); // This query retrieves ALL memberships of active types. @@ -2267,11 +2271,7 @@ public static function updateAllMembershipStatus() { $deceaseStatusId = array_search('Deceased', $allStatus); $pendingStatusId = array_search('Pending', $allStatus); - // CRM-15475 - $cancelledStatusId = array_search( - 'Cancelled', - CRM_Member_PseudoConstant::membershipStatus(NULL, " name = 'Cancelled' ", 'name', FALSE, TRUE) - ); + $cancelledStatusId = array_search('Cancelled', $allStatus); // Expired is not reserved so might not exist. A value of `0` won't break. $expiredStatusId = array_search('Expired', $allStatus) ?: 0; diff --git a/tests/phpunit/CRM/Member/BAO/MembershipStatusTest.php b/tests/phpunit/CRM/Member/BAO/MembershipStatusTest.php index 5128a5ccfe3b..fa118e137355 100644 --- a/tests/phpunit/CRM/Member/BAO/MembershipStatusTest.php +++ b/tests/phpunit/CRM/Member/BAO/MembershipStatusTest.php @@ -132,7 +132,7 @@ public function testDel() { public function testExpiredDisabled() { $result = civicrm_api3('MembershipStatus', 'get', [ - 'label' => "Expired", + 'name' => "Expired", 'api.MembershipStatus.create' => ['is_active' => 0], ]); @@ -140,7 +140,7 @@ public function testExpiredDisabled() { $result = $this->callAPISuccess('job', 'process_membership', []); $result = civicrm_api3('MembershipStatus', 'get', [ - 'label' => "Expired", + 'name' => "Expired", 'api.MembershipStatus.delete' => [], ]); From 06f210644508d79b1d9c9e2fa4c2abf35027468b Mon Sep 17 00:00:00 2001 From: Tunbola Ogunwande Date: Thu, 7 Feb 2019 15:34:16 +0100 Subject: [PATCH 083/408] dev/core#641: Implementing Case Activity Assignment Restriction functionality --- CRM/Case/BAO/CaseType.php | 21 ++++++ CRM/Case/Form/Activity.php | 105 +++++++++++++++++++++++++-- ang/crmCaseType.js | 7 ++ ang/crmCaseType/caseTypeDetails.html | 17 +++++ 4 files changed, 143 insertions(+), 7 deletions(-) diff --git a/CRM/Case/BAO/CaseType.php b/CRM/Case/BAO/CaseType.php index ec5210d13d59..aa65688f8766 100644 --- a/CRM/Case/BAO/CaseType.php +++ b/CRM/Case/BAO/CaseType.php @@ -190,7 +190,20 @@ public static function convertDefinitionToXML($name, $definition) { $xmlFile .= "\n"; } + if (array_key_exists('restrictActivityAsgmtToCmsUser', $definition)) { + $xmlFile .= "" . $definition['restrictActivityAsgmtToCmsUser'] . "\n"; + } + + if (!empty($definition['activityAsgmtGrps'])) { + $xmlFile .= "\n"; + foreach ($definition['activityAsgmtGrps'] as $value) { + $xmlFile .= "$value\n"; + } + $xmlFile .= "\n"; + } + $xmlFile .= ''; + return $xmlFile; } @@ -226,6 +239,14 @@ public static function convertXmlToDefinition($xml) { $definition['forkable'] = (int) $xml->forkable; } + if (isset($xml->RestrictActivityAsgmtToCmsUser)) { + $definition['restrictActivityAsgmtToCmsUser'] = (int) $xml->RestrictActivityAsgmtToCmsUser; + } + + if (isset($xml->ActivityAsgmtGrps)) { + $definition['activityAsgmtGrps'] = (array) $xml->ActivityAsgmtGrps->Group; + } + // set activity types if (isset($xml->ActivityTypes)) { $definition['activityTypes'] = array(); diff --git a/CRM/Case/Form/Activity.php b/CRM/Case/Form/Activity.php index 7a7b3b92b6c7..9e2dda642d88 100644 --- a/CRM/Case/Form/Activity.php +++ b/CRM/Case/Form/Activity.php @@ -37,16 +37,16 @@ class CRM_Case_Form_Activity extends CRM_Activity_Form_Activity { /** - * The default variable defined. + * Cases this activity belongs to. * - * @var int + * @var []int */ public $_caseId; /** * The default case type variable defined. * - * @var int + * @var []int */ public $_caseType; @@ -57,12 +57,20 @@ class CRM_Case_Form_Activity extends CRM_Activity_Form_Activity { */ public $_relatedContacts; + /** + * The case type definition column info + * for the caseId; + * + * @var array + */ + public $_caseTypeDefinition; + /** * Build the form object. */ public function preProcess() { - $caseIds = CRM_Utils_Request::retrieve('caseid', 'String', $this); - $this->_caseId = explode(',', $caseIds); + $caseIds = CRM_Utils_Request::retrieve('caseid', 'CommaSeparatedIntegers', $this); + $this->_caseId = $caseIds ? explode(',', $caseIds) : []; $this->_context = CRM_Utils_Request::retrieve('context', 'Alphanumeric', $this); if (!$this->_context) { $this->_context = 'caseActivity'; @@ -76,7 +84,7 @@ public function preProcess() { $this->assign('scheduleStatusId', $scheduleStatusId); if (!$this->_caseId && $this->_activityId) { - $this->_caseId = CRM_Core_DAO::getFieldValue('CRM_Case_DAO_CaseActivity', $this->_activityId, + $this->_caseId = (array) CRM_Core_DAO::getFieldValue('CRM_Case_DAO_CaseActivity', $this->_activityId, 'case_id', 'activity_id' ); } @@ -124,6 +132,8 @@ public function preProcess() { } $this->assign('caseType', $this->_caseType); + $this->_caseTypeDefinition = $this->getCaseTypeDefinition(); + $xmlProcessorProcess = new CRM_Case_XMLProcessor_Process(); $isMultiClient = $xmlProcessorProcess->getAllowMultipleCaseClients(); $this->assign('multiClient', $isMultiClient); @@ -248,10 +258,31 @@ public function buildQuickForm() { $this->_fields['source_contact_id']['label'] = ts('Reported By'); unset($this->_fields['status_id']['attributes']['required']); + if ($this->restrictAssignmentByUserAccount()) { + $assigneeParameters['uf_user'] = 1; + } + + $activityAssignmentGroups = $this->getActivityAssignmentGroups(); + if (!empty($activityAssignmentGroups)) { + $assigneeParameters['group'] = ['IN' => $activityAssignmentGroups]; + } + + if (!empty($assigneeParameters)) { + $this->_fields['assignee_contact_id']['attributes']['api']['params'] + = array_merge($this->_fields['assignee_contact_id']['attributes']['api']['params'], $assigneeParameters); + + $this->_fields['followup_assignee_contact_id']['attributes']['api']['params'] + = array_merge($this->_fields['followup_assignee_contact_id']['attributes']['api']['params'], $assigneeParameters); + + //Disallow creating a contact from the assignee field UI. + $this->_fields['assignee_contact_id']['attributes']['create'] = FALSE; + $this->_fields['followup_assignee_contact_id']['attributes']['create'] = FALSE; + } + if ($this->_caseType) { $xmlProcessor = new CRM_Case_XMLProcessor_Process(); $aTypes = array(); - foreach ($this->_caseType as $key => $val) { + foreach (array_unique($this->_caseType) as $val) { $activityTypes = $xmlProcessor->get($val, 'ActivityTypes', TRUE); $aTypes = $aTypes + $activityTypes; } @@ -651,4 +682,64 @@ public function postProcess($params = NULL) { } } + /** + * Returns the groups that contacts must belong to in order to be assigned + * an activity for this case. It returns an empty array if no groups are found for + * the case type linked to the caseId. + * + * @return array + */ + private function getActivityAssignmentGroups() { + if (!$this->_caseTypeDefinition) { + return []; + } + + $assignmentGroups = []; + foreach ($this->_caseTypeDefinition as $caseId => $definition) { + if (!empty($definition['activityAsgmtGrps'])) { + $assignmentGroups = array_merge($assignmentGroups, $definition['activityAsgmtGrps']); + } + } + + return $assignmentGroups; + } + + /** + * Returns whether contacts must have a user account in order to be + * assigned an activity for this case. + * + * @return bool + */ + private function restrictAssignmentByUserAccount() { + if (!$this->_caseTypeDefinition) { + return FALSE; + } + + foreach ($this->_caseTypeDefinition as $caseId => $definition) { + if (!empty($definition['restrictActivityAsgmtToCmsUser'])) { + return TRUE; + } + } + + return FALSE; + } + + /** + * Returns the case type definition column value for the case type linked to the caseId. + * + * @return array + */ + private function getCaseTypeDefinition() { + if (!$this->_caseId) { + return []; + } + + $definitions = civicrm_api3('CaseType', 'get', [ + 'return' => ['name', 'definition'], + 'name' => ['IN' => array_unique($this->_caseType)], + ]); + + return array_column($definitions['values'], 'definition', 'name'); + } + } diff --git a/ang/crmCaseType.js b/ang/crmCaseType.js index 994c9fb1f06a..ab8e2d4c1283 100644 --- a/ang/crmCaseType.js +++ b/ang/crmCaseType.js @@ -312,6 +312,8 @@ $scope.caseType.definition.caseRoles = $scope.caseType.definition.caseRoles || []; $scope.caseType.definition.statuses = $scope.caseType.definition.statuses || []; $scope.caseType.definition.timelineActivityTypes = $scope.caseType.definition.timelineActivityTypes || []; + $scope.caseType.definition.restrictActivityAsgmtToCmsUser = $scope.caseType.definition.restrictActivityAsgmtToCmsUser || 0; + $scope.caseType.definition.activityAsgmtGrps = $scope.caseType.definition.activityAsgmtGrps || []; _.each($scope.caseType.definition.activitySets, function (set) { _.each(set.activityTypes, function (type, name) { @@ -525,6 +527,11 @@ }); // Ignore if ALL or NONE selected $scope.caseType.definition.statuses = selectedStatuses.length == _.size($scope.selectedStatuses) ? [] : selectedStatuses; + + if ($scope.caseType.definition.activityAsgmtGrps) { + $scope.caseType.definition.activityAsgmtGrps = $scope.caseType.definition.activityAsgmtGrps.toString().split(","); + } + var result = crmApi('CaseType', 'create', $scope.caseType, true); result.then(function(data) { if (data.is_error === 0 || data.is_error == '0') { diff --git a/ang/crmCaseType/caseTypeDetails.html b/ang/crmCaseType/caseTypeDetails.html index 9b121d0f4dd7..99f91f3807d9 100644 --- a/ang/crmCaseType/caseTypeDetails.html +++ b/ang/crmCaseType/caseTypeDetails.html @@ -41,5 +41,22 @@
+
+ +
+
+ +
From db04bdc9d5761df04dd4110e8394a1db4baefca2 Mon Sep 17 00:00:00 2001 From: Andrew Hunt Date: Mon, 18 Mar 2019 13:46:49 -0400 Subject: [PATCH 084/408] 5.12.0 release notes: raw from script --- release-notes/5.12.0.md | 387 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 387 insertions(+) create mode 100644 release-notes/5.12.0.md diff --git a/release-notes/5.12.0.md b/release-notes/5.12.0.md new file mode 100644 index 000000000000..608bed73e8f5 --- /dev/null +++ b/release-notes/5.12.0.md @@ -0,0 +1,387 @@ +# CiviCRM 5.12.0 + +Released April 3, 2019; + +- **[Features](#features)** +- **[Bugs resolved](#bugs)** +- **[Miscellany](#misc)** +- **[Credits](#credits)** + +## Features + +### Core CiviCRM + +- **CRM-21643 Missing Summary ([12337](https://github.com/civicrm/civicrm-core/pull/12337))** + +## Bugs resolved + +### Core CiviCRM + +- **dev/core#801 Fix from email on PDF Letters, such as Thank You Letters. ([13825](https://github.com/civicrm/civicrm-core/pull/13825))** + +- **dev/core#790 - Exclue menubar on frontend pages ([13820](https://github.com/civicrm/civicrm-core/pull/13820))** + +- **dev/core#659 Catch payment processor exceptions, log, hide, do not return 500 error ([13796](https://github.com/civicrm/civicrm-core/pull/13796))** + +- **Fix unrelased regression where activity date relative filters are ingnored in the rc ([13801](https://github.com/civicrm/civicrm-core/pull/13801))** + +- **(ops#878) (Fast)ArrayDecorator - Emit expected exception when using WP and strict PSR-16 ([13808](https://github.com/civicrm/civicrm-core/pull/13808))** + +- **Merge forward 5.11 => master ([13777](https://github.com/civicrm/civicrm-core/pull/13777))** + +- **Remove mcrypt system status check ([13770](https://github.com/civicrm/civicrm-core/pull/13770))** + +- **Fix api bug whereby 0 & '0' are not accepted as range parameters for BETWEEN ([13766](https://github.com/civicrm/civicrm-core/pull/13766))** + +- **Render Note field tokens correctly - they are already HTML. ([13283](https://github.com/civicrm/civicrm-core/pull/13283))** + +- **dev/core#644 fix from address before calling hook ([13776](https://github.com/civicrm/civicrm-core/pull/13776))** + +- **[REF] separate financial handling & component transitioning in Payment.create ([13756](https://github.com/civicrm/civicrm-core/pull/13756))** + +- **Fix typo in comments ([13771](https://github.com/civicrm/civicrm-core/pull/13771))** + +- **Removes redundant IF ([13769](https://github.com/civicrm/civicrm-core/pull/13769))** + +- **[REF] towards cleanup of update membership code ([13759](https://github.com/civicrm/civicrm-core/pull/13759))** + +- **Extract getSearchSQLParts function ([13735](https://github.com/civicrm/civicrm-core/pull/13735))** + +- **Convert activity_date_time field to datepicker and add support for url input ([13746](https://github.com/civicrm/civicrm-core/pull/13746))** + +- **Speed up contribution results by removing join on civicrm_financial_type table when rendering search results. ([13720](https://github.com/civicrm/civicrm-core/pull/13720))** + +- **Try and add data set example where email_on_hold / on_hold is NULL in… ([13765](https://github.com/civicrm/civicrm-core/pull/13765))** + +- **Upgrade Karma version to latest version ([13751](https://github.com/civicrm/civicrm-core/pull/13751))** + +- **Rationalise Activity api ACLs for consistency, to respect the hook & improve performance ([13664](https://github.com/civicrm/civicrm-core/pull/13664))** + +- **report clean up - remove redundant code ([13761](https://github.com/civicrm/civicrm-core/pull/13761))** + +- **dev/core#767 Add 'Cancelled / Refunded Date' and 'Cancellation / Refund Reason' ([13726](https://github.com/civicrm/civicrm-core/pull/13726))** + +- **5.11 ([13760](https://github.com/civicrm/civicrm-core/pull/13760))** + +- **reporting#8 - add thank-you dates to Contribution Summary/Detail reports ([13653](https://github.com/civicrm/civicrm-core/pull/13653))** + +- **[REF] extract getToFinancialAccount from CRM_Contribute_PseudoConstantt::contributionStatus ([13757](https://github.com/civicrm/civicrm-core/pull/13757))** + +- **[ref] Extract activity payment creation ([13695](https://github.com/civicrm/civicrm-core/pull/13695))** + +- **Fix Custom post outer div class on event registration form ([13753](https://github.com/civicrm/civicrm-core/pull/13753))** + +- **dev/core#770 - View Case Activity page displays disabled custom fields ([13741](https://github.com/civicrm/civicrm-core/pull/13741))** + +- **Clean up Payment.create function ([13690](https://github.com/civicrm/civicrm-core/pull/13690))** + +- **fix broken logic in CRM_Utils_System_DrupalBase::formatResourceUrl() ([13400](https://github.com/civicrm/civicrm-core/pull/13400))** + +- **5.11 ([13750](https://github.com/civicrm/civicrm-core/pull/13750))** + +- **merge 5.11 to master ([13747](https://github.com/civicrm/civicrm-core/pull/13747))** + +- **Allow viewing of cancelled recurring contributions ([13745](https://github.com/civicrm/civicrm-core/pull/13745))** + +- **Upgrader: Don't abort if state_province already exists ([13744](https://github.com/civicrm/civicrm-core/pull/13744))** + +- **dev/core#708, Fix Qill for Added by and Modified By ([13566](https://github.com/civicrm/civicrm-core/pull/13566))** + +- **Fix the invocation of post hook for ParticipantPayment ensuring that … ([13739](https://github.com/civicrm/civicrm-core/pull/13739))** + +- **Decommision getPartialPaymentTrxn function ([13718](https://github.com/civicrm/civicrm-core/pull/13718))** + +- **5.11 ([13740](https://github.com/civicrm/civicrm-core/pull/13740))** + +- **Status of test contribution is not fetched on ThankYou page. ([13724](https://github.com/civicrm/civicrm-core/pull/13724))** + +- **CiviCRM Membership Detail report, add column to display if membership is Primary or Inherited ([13736](https://github.com/civicrm/civicrm-core/pull/13736))** + +- **dev/core#769 - Fix for ZipArchive->open() PHP bug ([13728](https://github.com/civicrm/civicrm-core/pull/13728))** + +- **dev/core#748 Move UPPER() from sql to php domain ([13732](https://github.com/civicrm/civicrm-core/pull/13732))** + +- **5.11 ([13730](https://github.com/civicrm/civicrm-core/pull/13730))** + +- **[REF] Extract lines to add the pseudoconstant to the select ([13717](https://github.com/civicrm/civicrm-core/pull/13717))** + +- **Mark de.systopia.recentitems obsolete ([13729](https://github.com/civicrm/civicrm-core/pull/13729))** + +- **5.11 to master ([13722](https://github.com/civicrm/civicrm-core/pull/13722))** + +- **dev/core#561 Upgrade age_asof_date to datepicker in search ([13704](https://github.com/civicrm/civicrm-core/pull/13704))** + +- **Upgrade PHPWord ([13686](https://github.com/civicrm/civicrm-core/pull/13686))** + +- **[minor cleanup] reduce params passed to searchQuery ([13715](https://github.com/civicrm/civicrm-core/pull/13715))** + +- **Migrate date field to datepicker on ChangeCaseType form ([13701](https://github.com/civicrm/civicrm-core/pull/13701))** + +- **[REF] Extract recordPayment portion ([13692](https://github.com/civicrm/civicrm-core/pull/13692))** + +- **Merge 5.11 to master ([13710](https://github.com/civicrm/civicrm-core/pull/13710))** + +- **Move assign of currency for entityForm outside of foreach so order of fields don't matter ([13696](https://github.com/civicrm/civicrm-core/pull/13696))** + +- **[TEST FIX] Increase uniqueness in testSingleNowDates ([13705](https://github.com/civicrm/civicrm-core/pull/13705))** + +- **dev/core#735 Do not include product in search results if site has none ([13638](https://github.com/civicrm/civicrm-core/pull/13638))** + +- **Code cleanup - remove extraneous permissions clause ([13645](https://github.com/civicrm/civicrm-core/pull/13645))** + +- **Fix & test searchQuery order by to be less dependent on what is selected for search ([13680](https://github.com/civicrm/civicrm-core/pull/13680))** + +- **Add pseudoconstant for payment_processor_id to contributionrecur ([13702](https://github.com/civicrm/civicrm-core/pull/13702))** + +- **dev/core#739 Fix case detail report breaking when sorted by case type. ([13666](https://github.com/civicrm/civicrm-core/pull/13666))** + +- **Phase out CIVICRM_TEMP_FORCE_UTF8 ([13658](https://github.com/civicrm/civicrm-core/pull/13658))** + +- **[REF] minor refactor around retrieving processor id for recur ([13643](https://github.com/civicrm/civicrm-core/pull/13643))** + +- **Extract record refund function ([13694](https://github.com/civicrm/civicrm-core/pull/13694))** + +- **Migrate KAM smartmenus to core ([13582](https://github.com/civicrm/civicrm-core/pull/13582))** + +- **Revert "[REF] Extract record refund function" ([13693](https://github.com/civicrm/civicrm-core/pull/13693))** + +- **[REF] Extract record refund function ([13691](https://github.com/civicrm/civicrm-core/pull/13691))** + +- **Move pear/mail from packages to composer.json ([13289](https://github.com/civicrm/civicrm-core/pull/13289))** + +- **Do not attempt to store out-of-range street number ([13340](https://github.com/civicrm/civicrm-core/pull/13340))** + +- **[REF] Extract getSearchSQL from getSearchQuery. ([13668](https://github.com/civicrm/civicrm-core/pull/13668))** + +- **Use CRM_Utils_SQL_TempTable to drop and create table. ([13688](https://github.com/civicrm/civicrm-core/pull/13688))** + +- **Record change log entry when contact is moved to or restored from trash ([13276](https://github.com/civicrm/civicrm-core/pull/13276))** + +- **geocode job: Do not return more messages than can fit in the log data column ([13346](https://github.com/civicrm/civicrm-core/pull/13346))** + +- **Towards supporting EntityForm for 'View Action' ([13578](https://github.com/civicrm/civicrm-core/pull/13578))** + +- **dev/core#631 - Enable 'add new' by default on merge screen ([13588](https://github.com/civicrm/civicrm-core/pull/13588))** + +- **reporting#9: parity between getContactFields and getBasicContactFields ([13657](https://github.com/civicrm/civicrm-core/pull/13657))** + +- **dev/core#742 Fix XML parasing by swapping & for , ([13654](https://github.com/civicrm/civicrm-core/pull/13654))** + +- **only set custom field to null if it is really null, not string 'null' ([13042](https://github.com/civicrm/civicrm-core/pull/13042))** + +- **CiviMail: Fix reply forwarding for mailers with From: and Return-path: limitations ([12641](https://github.com/civicrm/civicrm-core/pull/12641))** + +- **CRM/Logging - Fix various bugs in schema parsing ([13441](https://github.com/civicrm/civicrm-core/pull/13441))** + +- **Force utf8mb4 query to throw exception as the check expects ([13682](https://github.com/civicrm/civicrm-core/pull/13682))** + +- **Minor code cleanup ([13687](https://github.com/civicrm/civicrm-core/pull/13687))** + +- **[NFC, test class] formatting, remove unused variables ([13634](https://github.com/civicrm/civicrm-core/pull/13634))** + +- **Refactor CRM_Utils_SQL_TempTable::build()->createWithQuery($sql) interface to support MEMORY tabls ([13644](https://github.com/civicrm/civicrm-core/pull/13644))** + +- **dev/core#746 Add in unit tests to ensure that where clause is as is w… ([13685](https://github.com/civicrm/civicrm-core/pull/13685))** + +- **5.11 ([13684](https://github.com/civicrm/civicrm-core/pull/13684))** + +- **Payment notification formatting, move greeting into table ([13669](https://github.com/civicrm/civicrm-core/pull/13669))** + +- **CRM/Logging - Fix log table exceptions ([13675](https://github.com/civicrm/civicrm-core/pull/13675))** + +- **test for reporting#10 ([13678](https://github.com/civicrm/civicrm-core/pull/13678))** + +- **reporting-11 - fix Soft Credit report with full group by ([13671](https://github.com/civicrm/civicrm-core/pull/13671))** + +- **5.11 to master ([13676](https://github.com/civicrm/civicrm-core/pull/13676))** + +- **REF Convert deprecated functions to buildOptions for case ([13364](https://github.com/civicrm/civicrm-core/pull/13364))** + +- **Switch additional payment form to use Payment.sendconfirmation api ([13649](https://github.com/civicrm/civicrm-core/pull/13649))** + +- **5.11 to master ([13661](https://github.com/civicrm/civicrm-core/pull/13661))** + +- **/dev/core#716 - Add decimals in Contribution Amount on Repeat Contrib… ([13659](https://github.com/civicrm/civicrm-core/pull/13659))** + +- **[REF] minor code cleanup - do not build order var just to hurt brains ([13650](https://github.com/civicrm/civicrm-core/pull/13650))** + +- **[REF] minor cleanup of groupBy definition. ([13656](https://github.com/civicrm/civicrm-core/pull/13656))** + +- **Update Payment Notification to use greeting, remove text to 'Please print this confirmation for your records. ([13655](https://github.com/civicrm/civicrm-core/pull/13655))** + +- **Payment.sendconfirmation api - add further tpl variables. ([13610](https://github.com/civicrm/civicrm-core/pull/13610))** + +- **Authorizenet test - reduce chance of intermittent fails ([13642](https://github.com/civicrm/civicrm-core/pull/13642))** + +- **[unused code cleanup] Remove unused 'signupType' url support ([13620](https://github.com/civicrm/civicrm-core/pull/13620))** + +- **Payment.sendconfirmation api - add further tpl variables. ([13609](https://github.com/civicrm/civicrm-core/pull/13609))** + +- **(dev/core#696) Changes to copied event phone and email reflects in or… ([13534](https://github.com/civicrm/civicrm-core/pull/13534))** + +- **5.11 ([13639](https://github.com/civicrm/civicrm-core/pull/13639))** + +- **Remove another instance of 'lower' ([13636](https://github.com/civicrm/civicrm-core/pull/13636))** + +- **dev/core#720 Remove median & mode stats from contribution summary in order to improve performance ([13630](https://github.com/civicrm/civicrm-core/pull/13630))** + +- **[Test changes] Mailing job test use ([13629](https://github.com/civicrm/civicrm-core/pull/13629))** + +- **Fix html2pdf default PDF format when multiple pdf_format are available. ([13543](https://github.com/civicrm/civicrm-core/pull/13543))** + +- ** EntityRef - standardize on PascalCase for entity name and fix minor bug ([13631](https://github.com/civicrm/civicrm-core/pull/13631))** + +- **[REF] Remove useless class CRM_Report_Form_Event ([13632](https://github.com/civicrm/civicrm-core/pull/13632))** + +- **Contribution/ContributionRecur metadata updates for EntityForm ([13579](https://github.com/civicrm/civicrm-core/pull/13579))** + +- **dev/core#720 [REF] refactor out components of contributionSummary function ([13607](https://github.com/civicrm/civicrm-core/pull/13607))** + +- **Standardize format for entityRef create links ([13628](https://github.com/civicrm/civicrm-core/pull/13628))** + +- **[Code cleanup] Remove unused $stationery_path parameter ([13624](https://github.com/civicrm/civicrm-core/pull/13624))** + +- **[REF] extract cancelled stats to own function ([13626](https://github.com/civicrm/civicrm-core/pull/13626))** + +- **[REF] Move entityRef filters into their respective BAOs ([13625](https://github.com/civicrm/civicrm-core/pull/13625))** + +- **[REF] extract basic soft credit stats to separate function ([13622](https://github.com/civicrm/civicrm-core/pull/13622))** + +- **[code cleanup] Default wrong declared ([13621](https://github.com/civicrm/civicrm-core/pull/13621))** + +- **[REF] Remove unused function parameter ([13619](https://github.com/civicrm/civicrm-core/pull/13619))** + +- **Remove long block of commented out code from 4 years ago ([13623](https://github.com/civicrm/civicrm-core/pull/13623))** + +- **Always load recaptcha JS over HTTPS ([13601](https://github.com/civicrm/civicrm-core/pull/13601))** + +- **If a profile is used to create a contact with a subtype the contact will not have any existing subtypes ([13499](https://github.com/civicrm/civicrm-core/pull/13499))** + +- **[Test support] Add extra output info when getsingle fails as this seems to be common in intermittant fails ([13618](https://github.com/civicrm/civicrm-core/pull/13618))** + +- **[REF] extract add median to stats ([13616](https://github.com/civicrm/civicrm-core/pull/13616))** + +- **Remove tests that no longer work due to dead service ([13617](https://github.com/civicrm/civicrm-core/pull/13617))** + +- **Fix (sometimes serious) performance problem on submitting profiles for specified contacts ([13606](https://github.com/civicrm/civicrm-core/pull/13606))** + +- **[REF] extract calculation of mode stat ([13614](https://github.com/civicrm/civicrm-core/pull/13614))** + +- **5.11 to master ([13615](https://github.com/civicrm/civicrm-core/pull/13615))** + +- **fixes core#580 - view all groups when appropriately permissioned ([13373](https://github.com/civicrm/civicrm-core/pull/13373))** + +- **Move l10n.js to coreResourcesList ([13612](https://github.com/civicrm/civicrm-core/pull/13612))** + +- **Add install and runtime status warnings if MySQL utf8mb4 is not supported ([13425](https://github.com/civicrm/civicrm-core/pull/13425))** + +- **[REF] extract calculation of basic stats ([13608](https://github.com/civicrm/civicrm-core/pull/13608))** + +- **[REF] Move addSelectWhere-like function to be located on BAO_Contribution ([13587](https://github.com/civicrm/civicrm-core/pull/13587))** + +- **[REF] Fix silly function to do less handling of non-existent scenarios ([13563](https://github.com/civicrm/civicrm-core/pull/13563))** + +- **Add in Exception API to support the refactor of Dedupe Exception Page ([13611](https://github.com/civicrm/civicrm-core/pull/13611))** + +- **fixes dev/core#683 Incorrectly encoded state and country names ([13591](https://github.com/civicrm/civicrm-core/pull/13591))** + +- **dev/core#720 add unit test, remove legacy code style. ([13605](https://github.com/civicrm/civicrm-core/pull/13605))** + +- **[REF] extract chunk of code to a separate function ([13600](https://github.com/civicrm/civicrm-core/pull/13600))** + +- **dev/core#657 - Add filter for country on Repeat Contributions Report ([13432](https://github.com/civicrm/civicrm-core/pull/13432))** + +- **5.11 to master ([13602](https://github.com/civicrm/civicrm-core/pull/13602))** + +- **(dev/core#705) Disabling Alphabetical Pager is not respected for cont… ([13592](https://github.com/civicrm/civicrm-core/pull/13592))** + +- **Add new Payment.sendconfirmation api ([13561](https://github.com/civicrm/civicrm-core/pull/13561))** + +- **Find Contributions columns/headers not aligned when "Contributions OR Soft Credits?" filter set to "Soft Credits Only" ([13517](https://github.com/civicrm/civicrm-core/pull/13517))** + +- **dev/report#7 fix trxn_date on bookkeeping report ([13571](https://github.com/civicrm/civicrm-core/pull/13571))** + +- **dev/core#684 - Case Manager not updating correctly ([13528](https://github.com/civicrm/civicrm-core/pull/13528))** + +- **dev/core#469 Fix Error on action 'Email - schedule/send via CiviMail' with multiple event names filter ([13539](https://github.com/civicrm/civicrm-core/pull/13539))** + +- **[REF} User api rather than selector for rendering contributions on user dashboard ([13584](https://github.com/civicrm/civicrm-core/pull/13584))** + +- **dev/core#397 Dedupe for Individual Birth Date Results in Error ([13538](https://github.com/civicrm/civicrm-core/pull/13538))** + +- **Improves styling on Joomla! upgrade screen ([13557](https://github.com/civicrm/civicrm-core/pull/13557))** + +- **dev/core/issues/714, Inline edit should be disabled if user doesn't have edit group permission ([13573](https://github.com/civicrm/civicrm-core/pull/13573))** + +- **dev/core#691 Make default country optional on setting form ([13523](https://github.com/civicrm/civicrm-core/pull/13523))** + +- **[REF] switch from (undeclared) class property to local variable. ([13583](https://github.com/civicrm/civicrm-core/pull/13583))** + +- **[REF] Minor readability cleanup ([13562](https://github.com/civicrm/civicrm-core/pull/13562))** + +- **Remove activitystatus js. Add submitOnce handler for activity create ([13342](https://github.com/civicrm/civicrm-core/pull/13342))** + +- **Bump minimum upgradable ver to 4.2.9 ([13580](https://github.com/civicrm/civicrm-core/pull/13580))** + +- **5.11 to master ([13585](https://github.com/civicrm/civicrm-core/pull/13585))** + +- **Fix typo and space ([13577](https://github.com/civicrm/civicrm-core/pull/13577))** + +- **5.11 to master ([13576](https://github.com/civicrm/civicrm-core/pull/13576))** + +- **Remove hurty free calls from campaign and case ([13564](https://github.com/civicrm/civicrm-core/pull/13564))** + +- **Fix contact ID help on advanced search ([13569](https://github.com/civicrm/civicrm-core/pull/13569))** + +- **Add unit test on getContributionBalance fn (#13187) ([13558](https://github.com/civicrm/civicrm-core/pull/13558))** + +- **dev/core#562 Remove free calls from Activity and Member sections of CRM ([13560](https://github.com/civicrm/civicrm-core/pull/13560))** + +- **Used buildoptions function to get all groups ([13327](https://github.com/civicrm/civicrm-core/pull/13327))** + +- **Show Add to group on create new report after refresh of result ([13404](https://github.com/civicrm/civicrm-core/pull/13404))** + +- **(REF) Rename variables and adjust variable definitions for Event Register form ([13287](https://github.com/civicrm/civicrm-core/pull/13287))** + +- **Optimize CRM_Core_BAO_FinancialTrxn::getTotalPayment ([13187](https://github.com/civicrm/civicrm-core/pull/13187))** + +- **CRM.loadScript improvements ([13555](https://github.com/civicrm/civicrm-core/pull/13555))** + +- **dev/core/issues/700, Show Qill when searched using contact id ([13549](https://github.com/civicrm/civicrm-core/pull/13549))** + +- **Make submitOnce() button js into a button parameter ([13333](https://github.com/civicrm/civicrm-core/pull/13333))** + +- **dev/core#690 - Civi\API - Fix entity permission check for trusted calls ([13529](https://github.com/civicrm/civicrm-core/pull/13529))** + +- **6.x-5.10 ([566](https://github.com/civicrm/civicrm-drupal/pull/566))** + +- **Port fix for dev/core#381 to custom file field handler file ([564](https://github.com/civicrm/civicrm-drupal/pull/564))** + +- **7.x 5.11 ([565](https://github.com/civicrm/civicrm-drupal/pull/565))** + +- **7.x 5.11 to master (no changes in here - just admin) ([562](https://github.com/civicrm/civicrm-drupal/pull/562))** + +- **Make address Supplemental line 3 available to views ([551](https://github.com/civicrm/civicrm-drupal/pull/551))** + +- **CMS path fix in wp-cli ([147](https://github.com/civicrm/civicrm-wordpress/pull/147))** + +- **(NFC) formatting changes ([148](https://github.com/civicrm/civicrm-wordpress/pull/148))** + +- **Merge forward: 1.x-5.11 => 1.x-master ([66](https://github.com/civicrm/civicrm-backdrop/pull/66))** + +- **Remove old menu plugin ([240](https://github.com/civicrm/civicrm-packages/pull/240))** + +- **"Only variable references should be returned by reference" notice in Mail_smtp ([220](https://github.com/civicrm/civicrm-packages/pull/220))** + +## Miscellany + +## Credits + +This release was developed by the following code authors: + +AGH Strategies - Alice Frumin, Andrew Hunt; Agileware - Alok Patel; alexymik; Australian Greens - Seamus Lee; avall-llovera; CiviCRM - Coleman Watts, Tim Otten; CiviDesk - Yashodha Chaku; Coop SymbioTIC - Mathieu Lutfy; Electronic Frontier Foundation - Mark Burdett; Francesc Bassas i Bullich; Fuzion - Jitendra Purohit; GreenPeace Central and Eastern Europe - Patrick Figel; JMA Consulting - Edsel Lopez, Monish Deb; Ken West; Lighthouse Design and Consulting - Brian Shaughnessy; Megaphone Technology Consulting - Jon Goldberg; MJW Consulting - Matthew Wire; Nicol Wistreich; Pradeep Nayak; Skvare - Mark Hanna; Squiffle Consulting - Aidan Saunders; Wikimedia Foundation - Eileen McNaughton + +Most authors also reviewed code for this release; in addition, the following +reviewers contributed their comments: + +AGH Strategies - Alice Frumin, Andrew Hunt; Agileware - Alok Patel, Justin Freeman; Australian Greens - Seamus Lee; awasson; Circle Interactive - Dave Jenkins; civibot[bot]; civicrm-builder; CiviCRM - Coleman Watts, Tim Otten; CiviDesk - Sunil Pawar, Yashodha Chaku; Coop SymbioTIC - Mathieu Lutfy; Dave D; Electronic Frontier Foundation - Mark Burdett; Francesc Bassas i Bullich; Fuzion - Jitendra Purohit, Peter Davis; GreenPeace Central and Eastern Europe - Patrick Figel; JMA Consulting - Joe Murray, Monish Deb; Lighthouse Design and Consulting - Brian Shaughnessy; Megaphone Technology Consulting - Jon Goldberg; MJCO - Mikey O'Toole; MJW Consulting - Matthew Wire; mwestergaard; Nicol Wistreich; Pradeep Nayak; Progressive Technology Project - Jamie McClelland; reecebenson; Richard van Oosterhout; Skvare - Mark Hanna; Squiffle Consulting - Aidan Saunders; Tadpole Collective - Kevin Cristiano; Third Sector Design - Michael McAndrew; Wikimedia Foundation - Eileen McNaughton \ No newline at end of file From 766b558fe6dbcaec89e2cc6ddfb78ba02f06d8e0 Mon Sep 17 00:00:00 2001 From: Andrew Hunt Date: Mon, 18 Mar 2019 13:57:16 -0400 Subject: [PATCH 085/408] 5.12.0 release notes: added boilerplate --- release-notes.md | 13 ++++++++++++- release-notes/5.12.0.md | 12 ++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/release-notes.md b/release-notes.md index 16a4767f91d6..9d85e58ec898 100644 --- a/release-notes.md +++ b/release-notes.md @@ -14,7 +14,18 @@ Other resources for identifying changes are: * https://github.com/civicrm/civicrm-joomla * https://github.com/civicrm/civicrm-wordpress -# CiviCRM 5.11.0 +## CiviCRM 5.12.0 + +Released April 3, 2019 + +- **[Synopsis](release-notes/5.12.0.md#synopsis)** +- **[Features](release-notes/5.12.0.md#features)** +- **[Bugs resolved](release-notes/5.12.0.md#bugs)** +- **[Miscellany](release-notes/5.12.0.md#misc)** +- **[Credits](release-notes/5.12.0.md#credits)** +- **[Feedback](release-notes/5.12.0.md#feedback)** + +## CiviCRM 5.11.0 Released March 6, 2019 diff --git a/release-notes/5.12.0.md b/release-notes/5.12.0.md index 608bed73e8f5..aa87553f8a92 100644 --- a/release-notes/5.12.0.md +++ b/release-notes/5.12.0.md @@ -1,11 +1,13 @@ # CiviCRM 5.12.0 -Released April 3, 2019; +Released April 3, 2019 +- **[Synopsis](#synopsis)** - **[Features](#features)** - **[Bugs resolved](#bugs)** - **[Miscellany](#misc)** - **[Credits](#credits)** +- **[Feedback](#feedback)** ## Features @@ -384,4 +386,10 @@ AGH Strategies - Alice Frumin, Andrew Hunt; Agileware - Alok Patel; alexymik; Au Most authors also reviewed code for this release; in addition, the following reviewers contributed their comments: -AGH Strategies - Alice Frumin, Andrew Hunt; Agileware - Alok Patel, Justin Freeman; Australian Greens - Seamus Lee; awasson; Circle Interactive - Dave Jenkins; civibot[bot]; civicrm-builder; CiviCRM - Coleman Watts, Tim Otten; CiviDesk - Sunil Pawar, Yashodha Chaku; Coop SymbioTIC - Mathieu Lutfy; Dave D; Electronic Frontier Foundation - Mark Burdett; Francesc Bassas i Bullich; Fuzion - Jitendra Purohit, Peter Davis; GreenPeace Central and Eastern Europe - Patrick Figel; JMA Consulting - Joe Murray, Monish Deb; Lighthouse Design and Consulting - Brian Shaughnessy; Megaphone Technology Consulting - Jon Goldberg; MJCO - Mikey O'Toole; MJW Consulting - Matthew Wire; mwestergaard; Nicol Wistreich; Pradeep Nayak; Progressive Technology Project - Jamie McClelland; reecebenson; Richard van Oosterhout; Skvare - Mark Hanna; Squiffle Consulting - Aidan Saunders; Tadpole Collective - Kevin Cristiano; Third Sector Design - Michael McAndrew; Wikimedia Foundation - Eileen McNaughton \ No newline at end of file +AGH Strategies - Alice Frumin, Andrew Hunt; Agileware - Alok Patel, Justin Freeman; Australian Greens - Seamus Lee; awasson; Circle Interactive - Dave Jenkins; civibot[bot]; civicrm-builder; CiviCRM - Coleman Watts, Tim Otten; CiviDesk - Sunil Pawar, Yashodha Chaku; Coop SymbioTIC - Mathieu Lutfy; Dave D; Electronic Frontier Foundation - Mark Burdett; Francesc Bassas i Bullich; Fuzion - Jitendra Purohit, Peter Davis; GreenPeace Central and Eastern Europe - Patrick Figel; JMA Consulting - Joe Murray, Monish Deb; Lighthouse Design and Consulting - Brian Shaughnessy; Megaphone Technology Consulting - Jon Goldberg; MJCO - Mikey O'Toole; MJW Consulting - Matthew Wire; mwestergaard; Nicol Wistreich; Pradeep Nayak; Progressive Technology Project - Jamie McClelland; reecebenson; Richard van Oosterhout; Skvare - Mark Hanna; Squiffle Consulting - Aidan Saunders; Tadpole Collective - Kevin Cristiano; Third Sector Design - Michael McAndrew; Wikimedia Foundation - Eileen McNaughton + +## Feedback + +These release notes are edited by Alice Frumin and Andrew Hunt. If you'd like +to provide feedback on them, please log in to https://chat.civicrm.org/civicrm +and contact `@agh1`. From f0191689d7d95089e6d9e9079de25d5919f3c749 Mon Sep 17 00:00:00 2001 From: Andrew Hunt Date: Mon, 18 Mar 2019 17:21:06 -0400 Subject: [PATCH 086/408] CiviMember: test renaming `expired` doesn't trip up status update --- tests/phpunit/CRM/Member/BAO/MembershipStatusTest.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/phpunit/CRM/Member/BAO/MembershipStatusTest.php b/tests/phpunit/CRM/Member/BAO/MembershipStatusTest.php index fa118e137355..79c2ecac9303 100644 --- a/tests/phpunit/CRM/Member/BAO/MembershipStatusTest.php +++ b/tests/phpunit/CRM/Member/BAO/MembershipStatusTest.php @@ -131,6 +131,14 @@ public function testDel() { } public function testExpiredDisabled() { + $result = civicrm_api3('MembershipStatus', 'get', [ + 'name' => "Expired", + 'api.MembershipStatus.create' => ['label' => 'Expiiiired'], + ]); + + // Calling it 'Expiiiired' is OK. + $result = $this->callAPISuccess('job', 'process_membership', []); + $result = civicrm_api3('MembershipStatus', 'get', [ 'name' => "Expired", 'api.MembershipStatus.create' => ['is_active' => 0], From d8bd20072f92df4e9bd7c8709c941364cba6fbd2 Mon Sep 17 00:00:00 2001 From: Pradeep Nayak Date: Mon, 18 Mar 2019 21:32:02 +0000 Subject: [PATCH 087/408] added unit test --- tests/phpunit/api/v3/ContributionTest.php | 27 +++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/phpunit/api/v3/ContributionTest.php b/tests/phpunit/api/v3/ContributionTest.php index b6df822f75e8..9b99b42f9fd6 100644 --- a/tests/phpunit/api/v3/ContributionTest.php +++ b/tests/phpunit/api/v3/ContributionTest.php @@ -4299,4 +4299,31 @@ public function testContributionGetUnique() { $this->assertEquals(array('invoice_id'), $result['values']['UI_contrib_invoice_id']); } + /** + * Test Repeat Transaction Contribution with Tax amount. + * https://lab.civicrm.org/dev/core/issues/806 + */ + public function testRepeatContributionWithTaxAmount() { + $this->enableTaxAndInvoicing(); + $financialType = $this->callAPISuccess('financial_type', 'create', [ + 'name' => 'Test taxable financial Type', + 'is_reserved' => 0, + 'is_active' => 1, + ]); + $this->relationForFinancialTypeWithFinancialAccount($financialType['id']); + $contribution = $this->setUpRepeatTransaction( + [], + 'single', + [ + 'financial_type_id' => $financialType['id'], + ] + ); + $this->callAPISuccess('contribution', 'repeattransaction', array( + 'original_contribution_id' => $contribution['id'], + 'contribution_status_id' => 'Completed', + 'trxn_id' => uniqid(), + )); + $this->callAPISuccessGetCount('Contribution', [], 2); + } + } From 88a90442958cb6f15c3bac7465f7ab58a9ee7e00 Mon Sep 17 00:00:00 2001 From: eileen Date: Tue, 19 Mar 2019 16:55:52 +1300 Subject: [PATCH 088/408] Reset REQUEST, GET & POST in main tearDown I've been noticing tests failing on lines which indicate they were getting variables from these - e.g CRM_Member_Form_MembershipTest::testSubmitUpdateMembershipFromPartiallyPaid CiviCRM_API3_Exception: Expected one Contact but found 0 /home/jenkins/bknix-dfl/build/core-13854-7x4fu/sites/all/modules/civicrm/api/api.php:45 /home/jenkins/bknix-dfl/build/core-13854-7x4fu/sites/all/modules/civicrm/CRM/Contribute/Form/AbstractEditPayment.php:757 /home/jenkins/bknix-dfl/build/core-13854-7x4fu/sites/all/modules/civicrm/CRM/Contribute/Form/AbstractEditPayment.php:256 /home/jenkins/bknix-dfl/build/core-13854-7x4fu/sites/all/modules/civicrm/CRM/Member/Form.php:153 /home/jenkins/bknix-dfl/build/core-13854-7x4fu/sites/all/modules/civicrm/CRM/Member/Form/Membership.php:224 /home/jenkins/bknix-dfl/build/core-13854-7x4fu/sites/all/modules/civicrm/tests/phpunit/CRM/Member/Form/MembershipTest.php:832 /home/jenkins/bknix-dfl/build/core-13854-7x4fu/sites/all/modules/civicrm/tests/phpunit/CRM/Member/Form/MembershipTest.php:895 /home/jenkins/bknix-dfl/build/core-13854-7x4fu/sites/all/modules/civicrm/tests/phpunit/CiviTest/CiviUnitTestCase.php:196 /home/jenkins/bknix-dfl/civicrm-buildkit/extern/phpunit5/phpunit5.phar:598 --- tests/phpunit/CiviTest/CiviUnitTestCase.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/phpunit/CiviTest/CiviUnitTestCase.php b/tests/phpunit/CiviTest/CiviUnitTestCase.php index a0f04fe81af5..c12a2dd92e34 100644 --- a/tests/phpunit/CiviTest/CiviUnitTestCase.php +++ b/tests/phpunit/CiviTest/CiviUnitTestCase.php @@ -336,6 +336,7 @@ protected function setUp() { //flush component settings CRM_Core_Component::getEnabledComponents(TRUE); + $_REQUEST = $_GET = $_POST = []; error_reporting(E_ALL); $this->_sethtmlGlobals(); From 97288cdc6a08d6249cfc344b2a0302bb95422c59 Mon Sep 17 00:00:00 2001 From: eileen Date: Tue, 19 Mar 2019 23:11:36 +1300 Subject: [PATCH 089/408] Minor code cleanups around invoicing assignment --- CRM/Contribute/Form/Contribution/Confirm.php | 24 +++++++++---------- .../Form/FrontEndPaymentFormTrait.php | 10 ++++---- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/CRM/Contribute/Form/Contribution/Confirm.php b/CRM/Contribute/Form/Contribution/Confirm.php index 0afaf65fb15f..6d791a5db9cd 100644 --- a/CRM/Contribute/Form/Contribution/Confirm.php +++ b/CRM/Contribute/Form/Contribution/Confirm.php @@ -508,18 +508,22 @@ public function buildQuickForm() { $amount_block_is_active = $this->get('amount_block_is_active'); $this->assign('amount_block_is_active', $amount_block_is_active); - $invoiceSettings = Civi::settings()->get('contribution_invoice_settings'); - $invoicing = CRM_Utils_Array::value('invoicing', $invoiceSettings); // Make a copy of line items array to use for display only $tplLineItems = $this->_lineItem; - if ($invoicing) { - $getTaxDetails = FALSE; - $taxTerm = CRM_Utils_Array::value('tax_term', $invoiceSettings); + if (CRM_Invoicing_Utils::isInvoicingEnabled()) { list($getTaxDetails, $tplLineItems) = $this->alterLineItemsForTemplate($tplLineItems); $this->assign('getTaxDetails', $getTaxDetails); - $this->assign('taxTerm', $taxTerm); + $this->assign('taxTerm', CRM_Invoicing_Utils::getTaxTerm()); $this->assign('totalTaxAmount', $params['tax_amount']); } + if ($this->_priceSetId && !CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $this->_priceSetId, 'is_quick_config')) { + $this->assign('lineItem', $tplLineItems); + } + else { + $this->assign('is_quick_config', 1); + $this->_params['is_quick_config'] = 1; + } + if (!empty($params['selectProduct']) && $params['selectProduct'] != 'no_thanks') { $option = CRM_Utils_Array::value('options_' . $params['selectProduct'], $params); $productID = $params['selectProduct']; @@ -574,13 +578,7 @@ public function buildQuickForm() { $this->_separateMembershipPayment = $this->get('separateMembershipPayment'); $this->assign('is_separate_payment', $this->_separateMembershipPayment); - if ($this->_priceSetId && !CRM_Core_DAO::getFieldValue('CRM_Price_DAO_PriceSet', $this->_priceSetId, 'is_quick_config')) { - $this->assign('lineItem', $tplLineItems); - } - else { - $this->assign('is_quick_config', 1); - $this->_params['is_quick_config'] = 1; - } + $this->assign('priceSetID', $this->_priceSetId); // The concept of contributeMode is deprecated. diff --git a/CRM/Financial/Form/FrontEndPaymentFormTrait.php b/CRM/Financial/Form/FrontEndPaymentFormTrait.php index c74dea5ad474..c65d8898ed44 100644 --- a/CRM/Financial/Form/FrontEndPaymentFormTrait.php +++ b/CRM/Financial/Form/FrontEndPaymentFormTrait.php @@ -50,12 +50,10 @@ protected function alterLineItemsForTemplate($tplLineItems) { $getTaxDetails = FALSE; foreach ($tplLineItems as $key => $value) { foreach ($value as $k => $v) { - if (isset($v['tax_rate'])) { - if ($v['tax_rate'] != '') { - $getTaxDetails = TRUE; - // Cast to float to display without trailing zero decimals - $tplLineItems[$key][$k]['tax_rate'] = (float) $v['tax_rate']; - } + if (isset($v['tax_rate']) && $v['tax_rate'] != '') { + $getTaxDetails = TRUE; + // Cast to float to display without trailing zero decimals + $tplLineItems[$key][$k]['tax_rate'] = (float) $v['tax_rate']; } } } From 1532c327918591093c9d0c0620a9795085e09514 Mon Sep 17 00:00:00 2001 From: Mathieu Lutfy Date: Tue, 19 Mar 2019 08:45:35 -0400 Subject: [PATCH 090/408] dev/core#795 Fix PHP warning when updating a multiselect country field. --- CRM/Core/BAO/CustomValueTable.php | 1 - 1 file changed, 1 deletion(-) diff --git a/CRM/Core/BAO/CustomValueTable.php b/CRM/Core/BAO/CustomValueTable.php index 84417ab6f664..bd4807cc1cfd 100644 --- a/CRM/Core/BAO/CustomValueTable.php +++ b/CRM/Core/BAO/CustomValueTable.php @@ -124,7 +124,6 @@ public static function create(&$customParams) { case 'Country': $type = 'Integer'; - $mulValues = explode(',', $value); if (is_array($value)) { $value = CRM_Core_DAO::VALUE_SEPARATOR . implode(CRM_Core_DAO::VALUE_SEPARATOR, $value) . CRM_Core_DAO::VALUE_SEPARATOR; $type = 'String'; From d9f57ab1a8a551b3b51621a82a86704b26fbd571 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Tue, 19 Mar 2019 12:50:23 -0400 Subject: [PATCH 091/408] Add fieldset and help for activity assignee setting --- ang/crmCaseType.js | 3 ++- ang/crmCaseType/caseTypeDetails.html | 38 ++++++++++++++++------------ templates/CRM/Case/CaseType.hlp | 11 ++++++++ 3 files changed, 35 insertions(+), 17 deletions(-) create mode 100644 templates/CRM/Case/CaseType.hlp diff --git a/ang/crmCaseType.js b/ang/crmCaseType.js index ab8e2d4c1283..986b1ccaed86 100644 --- a/ang/crmCaseType.js +++ b/ang/crmCaseType.js @@ -237,7 +237,7 @@ }; }); - crmCaseType.controller('CaseTypeCtrl', function($scope, crmApi, apiCalls) { + crmCaseType.controller('CaseTypeCtrl', function($scope, crmApi, apiCalls, crmUiHelp) { var REL_TYPE_CNAME, defaultAssigneeDefaultValue, ts; (function init () { @@ -245,6 +245,7 @@ REL_TYPE_CNAME = CRM.crmCaseType.REL_TYPE_CNAME; ts = $scope.ts = CRM.ts(null); + $scope.hs = crmUiHelp({file: 'CRM/Case/CaseType'}); $scope.locks = { caseTypeName: true, activitySetName: true }; $scope.workflows = { timeline: 'Timeline', sequence: 'Sequence' }; defaultAssigneeDefaultValue = _.find(apiCalls.defaultAssigneeTypes.values, { is_default: '1' }) || {}; diff --git a/ang/crmCaseType/caseTypeDetails.html b/ang/crmCaseType/caseTypeDetails.html index 99f91f3807d9..0f74ff9a9b72 100644 --- a/ang/crmCaseType/caseTypeDetails.html +++ b/ang/crmCaseType/caseTypeDetails.html @@ -41,22 +41,28 @@
-
- -
-
- +
+ {{ ts('Activity assignment settings') }} +
+
+ +
+
+ +
+
+
diff --git a/templates/CRM/Case/CaseType.hlp b/templates/CRM/Case/CaseType.hlp new file mode 100644 index 000000000000..561836e75e16 --- /dev/null +++ b/templates/CRM/Case/CaseType.hlp @@ -0,0 +1,11 @@ +{htxt id="activityAsgmtGrps"} +

+ {ts}Selecting one or more groups here will limit the choices when assigning an activity.{/ts} +

+{/htxt} + +{htxt id="restrictActivityAsgmtToCmsUser"} +

+ {ts}This will limit the choices when selecting an activity assignee to contacts with a user account on this website.{/ts} +

+{/htxt} From 72924e188d54140df8d026db49e7da76c98d0085 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Tue, 19 Mar 2019 13:18:52 -0400 Subject: [PATCH 092/408] dev/core#811 - Autocomplete only enabled options --- CRM/Core/BAO/CustomField.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CRM/Core/BAO/CustomField.php b/CRM/Core/BAO/CustomField.php index 82038c39e4c6..24b0bd5864ce 100644 --- a/CRM/Core/BAO/CustomField.php +++ b/CRM/Core/BAO/CustomField.php @@ -1097,7 +1097,7 @@ public static function addQuickFormElement( 'placeholder' => $placeholder, 'multiple' => $search, 'api' => array( - 'params' => array('option_group_id' => $field->option_group_id), + 'params' => array('option_group_id' => $field->option_group_id, 'is_active' => 1), ), ); $element = $qf->addEntityRef($elementName, $label, $attributes, $useRequired && !$search); From 958b4ccf1d9afb0a37e0359a92fd669fea242ff9 Mon Sep 17 00:00:00 2001 From: Alice Frumin Date: Tue, 19 Mar 2019 14:51:34 -0400 Subject: [PATCH 093/408] Fixing formatting of contributors section --- release-notes/5.11.0.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-notes/5.11.0.md b/release-notes/5.11.0.md index d8332da1092b..64fe5fb47dbe 100644 --- a/release-notes/5.11.0.md +++ b/release-notes/5.11.0.md @@ -714,8 +714,8 @@ J. Gómez; Fuzion - Jitendra Purohit; Greenpeace Central and Eastern Europe - Patrick Figel; iXiam - Luciano Spiegel; JMA Consulting - Monish Deb; Joinery - Allen Shaw; Ken West; Liquid Web, Inc. - Jason Gillman Jr.; Megaphone Technology Consulting - Jon Goldberg; MillerTech - Chamil Wijesooriya; MJW Consulting - -Matthew Wire; Oxfam Germany - Thomas Schüttler; PeaceWorks Technology Solutions -- Martin Hansen; Pradeep Nayak; Progressive Technology Project - Jamie +Matthew Wire; Oxfam Germany - Thomas Schüttler; PeaceWorks Technology Solutions - +Martin Hansen; Pradeep Nayak; Progressive Technology Project - Jamie McClelland; Squiffle Consulting - Aidan Saunders; Wikimedia Foundation - Eileen McNaughton From 7f59431188688d4697bff55738fe17996abe442f Mon Sep 17 00:00:00 2001 From: eileen Date: Sat, 2 Mar 2019 19:41:32 +1300 Subject: [PATCH 094/408] Fix bug whereby sorting by state province gives an error in search builder --- CRM/Contact/BAO/Query.php | 44 +++++++++++---------- CRM/Contact/Selector.php | 3 +- tests/phpunit/CRM/Contact/BAO/QueryTest.php | 26 ++++++++++++ tests/phpunit/CRM/Contact/SelectorTest.php | 3 +- 4 files changed, 53 insertions(+), 23 deletions(-) diff --git a/CRM/Contact/BAO/Query.php b/CRM/Contact/BAO/Query.php index 050beffcff62..fc7d9a75e93b 100644 --- a/CRM/Contact/BAO/Query.php +++ b/CRM/Contact/BAO/Query.php @@ -2680,6 +2680,18 @@ protected static function getEntitySpecificJoins($name, $mode, $side, $primaryLo //CRM-14263 further handling of address joins further down... return " $side JOIN civicrm_address ON ( contact_a.id = civicrm_address.contact_id {$limitToPrimaryClause} )"; + case 'civicrm_state_province': + // This is encountered when doing an export after having applied a 'sort' - it pretty much implies primary + // but that will have been implied-in by the calling function. + // test cover in testContactIDQuery + return " $side JOIN civicrm_state_province ON ( civicrm_address.state_province_id = civicrm_state_province.id )"; + + case 'civicrm_country': + // This is encountered when doing an export after having applied a 'sort' - it pretty much implies primary + // but that will have been implied-in by the calling function. + // test cover in testContactIDQuery + return " $side JOIN civicrm_country ON ( civicrm_address.country_id = civicrm_country.id )"; + case 'civicrm_phone': return " $side JOIN civicrm_phone ON (contact_a.id = civicrm_phone.contact_id {$limitToPrimaryClause}) "; @@ -2699,8 +2711,9 @@ protected static function getEntitySpecificJoins($name, $mode, $side, $primaryLo return " $side JOIN civicrm_openid ON ( civicrm_openid.contact_id = contact_a.id {$limitToPrimaryClause} )"; case 'civicrm_worldregion': - $from = " $side JOIN civicrm_country ON civicrm_address.country_id = civicrm_country.id "; - return "$from $side JOIN civicrm_worldregion ON civicrm_country.region_id = civicrm_worldregion.id "; + // We can be sure from the calling function that country will already be joined in. + // we really don't need world_region - we could use a pseudoconstant for it. + return "$side JOIN civicrm_worldregion ON civicrm_country.region_id = civicrm_worldregion.id "; case 'civicrm_location_type': return " $side JOIN civicrm_location_type ON civicrm_address.location_type_id = civicrm_location_type.id "; @@ -6320,26 +6333,18 @@ protected function prepareOrderBy($sort, $sortByChar, $sortOrder, $additionalFro $orderByClauseParts = explode(' ', trim($orderByClause)); $field = $orderByClauseParts[0]; $direction = isset($orderByClauseParts[1]) ? $orderByClauseParts[1] : 'asc'; + $fieldSpec = $this->getMetadataForRealField($field); - switch ($field) { - case 'city': - case 'postal_code': - $this->_tables["civicrm_address"] = $this->_whereTables["civicrm_address"] = 1; - $order = str_replace($field, "civicrm_address.{$field}", $order); - break; + if ($this->_returnProperties === []) { + if (!empty($fieldSpec['table_name']) && !isset($this->_tables[$fieldSpec['table_name']])) { + $this->_tables[$fieldSpec['table_name']] = 1; + $order = $fieldSpec['where'] . ' ' . $direction; + } - case 'country': - case 'state_province': - $this->_tables["civicrm_{$field}"] = $this->_whereTables["civicrm_{$field}"] = 1; - if (is_array($this->_returnProperties) && empty($this->_returnProperties)) { - $additionalFromClause .= " LEFT JOIN civicrm_{$field} ON civicrm_{$field}.id = civicrm_address.{$field}_id"; - } - $order = str_replace($field, "civicrm_{$field}.name", $order); - break; + } + switch ($field) { - case 'email': - $this->_tables["civicrm_email"] = $this->_whereTables["civicrm_email"] = 1; - $order = str_replace($field, "civicrm_email.{$field}", $order); + case 'placeholder-will-remove-next-pr-but-jenkins-will-not-accept-without-and-removing-switch-will-make-hard-to-read': break; default: @@ -6363,7 +6368,6 @@ protected function prepareOrderBy($sort, $sortByChar, $sortOrder, $additionalFro // is not declared for them. // @todo so far only integer fields are being handled. If we add string fields we need to look at // escaping. - $fieldSpec = $this->getMetadataForRealField($field); $pseudoConstantMetadata = CRM_Utils_Array::value('pseudoconstant', $fieldSpec, FALSE); if (!empty($pseudoConstantMetadata) ) { diff --git a/CRM/Contact/Selector.php b/CRM/Contact/Selector.php index 7f3952a1692c..fc5bcc33170e 100644 --- a/CRM/Contact/Selector.php +++ b/CRM/Contact/Selector.php @@ -500,8 +500,7 @@ public function &getColumnHeaders($action = NULL, $output = NULL) { CRM_Core_PseudoConstant::getKey('CRM_Core_DAO_Address', 'location_type_id', $loc) ) ); - // use field name instead of table alias - $prop = $fld; + } elseif (isset($this->_query->_fields[$prop]) && isset($this->_query->_fields[$prop]['title'])) { $title = $this->_query->_fields[$prop]['title']; diff --git a/tests/phpunit/CRM/Contact/BAO/QueryTest.php b/tests/phpunit/CRM/Contact/BAO/QueryTest.php index 1f94137f69f0..a387a60777bd 100644 --- a/tests/phpunit/CRM/Contact/BAO/QueryTest.php +++ b/tests/phpunit/CRM/Contact/BAO/QueryTest.php @@ -696,6 +696,32 @@ public function testContactIDClause() { $this->fail('Test failed for some reason which is not good'); } + /** + * Test the sorting on the contact ID query works. + * + * Checking for lack of fatal. + * + * @param string $sortOrder + * Param reflecting how sort is passed in. + * - 1_d is column 1 descending. + * + * @dataProvider getSortOptions + */ + public function testContactIDQuery($sortOrder) { + $selector = new CRM_Contact_Selector(NULL, ['radio_ts' => 'ts_all'], NULL, ['sort_name' => 1]); + $selector->contactIDQuery([], $sortOrder); + } + + public function getSortOptions() { + return [ + ['1_d'], + ['2_d'], + ['3_d'], + ['4_d'], + ['5_d'], + ['6_d'], + ]; + } /** * Test the summary query does not add an acl clause when acls not enabled.. diff --git a/tests/phpunit/CRM/Contact/SelectorTest.php b/tests/phpunit/CRM/Contact/SelectorTest.php index 2e3bc97fc8dc..1eb5337323e3 100644 --- a/tests/phpunit/CRM/Contact/SelectorTest.php +++ b/tests/phpunit/CRM/Contact/SelectorTest.php @@ -550,10 +550,11 @@ public function getDefaultSelectString() { */ public function getDefaultFromString() { return ' FROM civicrm_contact contact_a LEFT JOIN civicrm_address ON ( contact_a.id = civicrm_address.contact_id AND civicrm_address.is_primary = 1 )' + . ' LEFT JOIN civicrm_country ON ( civicrm_address.country_id = civicrm_country.id ) ' . ' LEFT JOIN civicrm_email ON (contact_a.id = civicrm_email.contact_id AND civicrm_email.is_primary = 1)' . ' LEFT JOIN civicrm_phone ON (contact_a.id = civicrm_phone.contact_id AND civicrm_phone.is_primary = 1)' . ' LEFT JOIN civicrm_im ON (contact_a.id = civicrm_im.contact_id AND civicrm_im.is_primary = 1) ' - . 'LEFT JOIN civicrm_country ON civicrm_address.country_id = civicrm_country.id LEFT JOIN civicrm_worldregion ON civicrm_country.region_id = civicrm_worldregion.id '; + . 'LEFT JOIN civicrm_worldregion ON civicrm_country.region_id = civicrm_worldregion.id '; } /** From 7b7813264ed846b9c98f883edae14ecf2c3ef7fa Mon Sep 17 00:00:00 2001 From: eileen Date: Wed, 20 Mar 2019 13:40:44 +1300 Subject: [PATCH 095/408] As discussed, delete webtests They were extremely hard to maintain when we were maintaining them, now they have been unmaitained so long that they would take more work to get functional than starting from scratch. They make grepping harder --- .../CiviTest/CiviSeleniumSettings.auto.php | 65 - .../CiviTest/CiviSeleniumSettings.php.txt | 72 - .../phpunit/CiviTest/CiviSeleniumTestCase.php | 2661 ----------------- .../WebTest/ACL/AssignUsersToRolesTest.php | 427 --- .../Activity/AddRecurringActivityTest.php | 155 - .../Activity/ContactContextAddTest.php | 233 -- tests/phpunit/WebTest/Activity/IcalTest.php | 121 - .../WebTest/Activity/StandaloneAddTest.php | 267 -- tests/phpunit/WebTest/Admin/CustomAddTest.php | 197 -- .../WebTest/Admin/CustomAddTestSameField.php | 174 -- .../Admin/Form/ScheduleReminderTest.php | 92 - .../Admin/Form/Setting/DebuggingTest.php | 55 - .../Admin/Form/Setting/LocalizationTest.php | 62 - .../WebTest/Admin/MoveCustomDataTest.php | 495 --- .../WebTest/Admin/RelationshipTypeAddTest.php | 126 - tests/phpunit/WebTest/AllTests.php | 58 - .../phpunit/WebTest/Campaign/ActivityTest.php | 210 -- .../Campaign/CampaignDescriptionTest.php | 97 - .../phpunit/WebTest/Campaign/MailingTest.php | 288 -- .../WebTest/Campaign/MembershipTest.php | 172 -- .../Campaign/OfflineContributionTest.php | 272 -- .../Campaign/OfflineEventRegistrationTest.php | 235 -- .../Campaign/OnlineContributionTest.php | 307 -- .../Campaign/OnlineEventRegistrationTest.php | 366 --- .../Campaign/PetitionUsageScenarioTest.php | 275 -- tests/phpunit/WebTest/Campaign/PledgeTest.php | 186 -- .../Campaign/SurveyUsageScenarioTest.php | 617 ---- .../WebTest/Case/ActivityToCaseTest.php | 425 --- tests/phpunit/WebTest/Case/AddCaseTest.php | 304 -- .../phpunit/WebTest/Case/AddCaseTypeTest.php | 147 - .../WebTest/Case/CaseCustomFieldsTest.php | 438 --- .../WebTest/Case/CaseDashboardTest.php | 133 - .../WebTest/Contact/AddCmsUserTest.php | 127 - .../AddContactsToEventAdvancedSearchTest.php | 71 - tests/phpunit/WebTest/Contact/AddTest.php | 567 ---- .../WebTest/Contact/AddViaProfileTest.php | 45 - .../WebTest/Contact/AddressParsingTest.php | 162 - .../WebTest/Contact/AdvanceSearchPaneTest.php | 368 --- .../AdvanceSearchPrivacyOptionsTest.php | 232 -- .../WebTest/Contact/AdvancedSearchTest.php | 516 ---- .../AdvancedSearchedRelatedContactTest.php | 341 --- .../Contact/ContactReferenceFieldTest.php | 176 -- .../WebTest/Contact/ContactTagTest.php | 152 - .../Contact/CreateCmsUserFromContactTest.php | 248 -- .../WebTest/Contact/CustomDataAddTest.php | 344 --- .../DeceasedContactsAdvancedSearchTest.php | 122 - .../WebTest/Contact/DupeContactTest.php | 152 - .../WebTest/Contact/EditContactTest.php | 170 -- .../phpunit/WebTest/Contact/GroupAddTest.php | 320 -- .../WebTest/Contact/InlineFieldsEditTest.php | 351 --- .../WebTest/Contact/MergeContactsTest.php | 1016 ------- .../Contact/MultipleContactSubTypes.php | 255 -- .../phpunit/WebTest/Contact/PrevNextTest.php | 130 - .../Contact/PrivacyOptionSearchTest.php | 156 - .../WebTest/Contact/ProfileChecksumTest.php | 193 -- .../WebTest/Contact/RelationshipAddTest.php | 422 --- .../WebTest/Contact/SearchBuilderTest.php | 551 ---- tests/phpunit/WebTest/Contact/SearchTest.php | 263 -- .../Contact/SearchbyDateFilterTest.php | 348 --- .../phpunit/WebTest/Contact/SignatureTest.php | 143 - tests/phpunit/WebTest/Contact/TagAddTest.php | 114 - .../WebTest/Contact/TagSetSearchTest.php | 160 - .../Contact/TaskActionAddToGroupTest.php | 146 - .../Contact/TaskActionSendMassMailing.php | 136 - .../WebTest/Contact/TaskActionSendSMS.php | 121 - .../WebTest/Contact/UpdateProfileTest.php | 81 - .../WebTest/Contribute/AddBatchesTest.php | 343 --- .../WebTest/Contribute/AddPricesetTest.php | 611 ---- .../Contribute/ConfirmOptionalTest.php | 114 - .../Contribute/ContactContextAddTest.php | 194 -- .../Contribute/ContributionPageAddTest.php | 445 --- .../Contribute/OfflineContributionTest.php | 571 ---- .../OfflineRecurContributionTest.php | 111 - .../Contribute/OnBehalfOfOrganization.php | 1478 --------- .../Contribute/OnlineContributionTest.php | 731 ----- .../OnlineMultiplePaymentProcessorTest.php | 208 -- .../OnlineRecurContributionTest.php | 156 - .../phpunit/WebTest/Contribute/PCPAddTest.php | 210 -- .../WebTest/Contribute/StandaloneAddTest.php | 320 -- .../UpdateBatchPendingContributionTest.php | 236 -- .../Contribute/UpdateContributionTest.php | 508 ---- .../UpdatePendingContributionTest.php | 316 -- .../Contribute/VerifySSLContributionTest.php | 135 - tests/phpunit/WebTest/Event/AddEventTest.php | 1252 -------- .../WebTest/Event/AddParticipationTest.php | 460 --- .../phpunit/WebTest/Event/AddPricesetTest.php | 779 ----- .../WebTest/Event/AddRecurringEventTest.php | 106 - .../WebTest/Event/AdditionalPaymentTest.php | 217 -- .../WebTest/Event/ChangeParticipantStatus.php | 167 -- .../WebTest/Event/EventListingTest.php | 166 - .../WebTest/Event/EventWaitListTest.php | 242 -- .../MultipleEventRegistrationbyCartTest.php | 514 ---- .../WebTest/Event/MultiprofileEventTest.php | 842 ------ tests/phpunit/WebTest/Event/PCPAddTest.php | 557 ---- .../WebTest/Event/ParticipantCountTest.php | 475 --- .../WebTest/Event/ParticipantSearchTest.php | 255 -- .../WebTest/Event/PricesetMaxCountTest.php | 1192 -------- .../phpunit/WebTest/Event/TellAFriendTest.php | 279 -- tests/phpunit/WebTest/Export/ContactTest.php | 572 ---- .../Export/ExportCiviSeleniumTestCase.php | 165 - .../Financial/FinancialAccountTest.php | 144 - .../Financial/FinancialAccountTypeTest.php | 102 - .../Financial/FinancialBatchExport.php | 140 - .../WebTest/Generic/CheckActivityTest.php | 86 - .../WebTest/Generic/CheckDashboardTest.php | 171 -- .../phpunit/WebTest/Generic/CheckFindTest.php | 47 - .../Generic/GeneralClickAroundTest.php | 359 --- .../WebTest/Grant/ContactContextAddTest.php | 140 - .../WebTest/Grant/CustomFieldsetTest.php | 125 - .../WebTest/Grant/StandaloneAddTest.php | 109 - tests/phpunit/WebTest/Import/ActivityTest.php | 102 - .../WebTest/Import/AddressImportTest.php | 312 -- .../WebTest/Import/AddressParsingTest.php | 289 -- .../WebTest/Import/ContactCustomDataTest.php | 194 -- .../WebTest/Import/ContactSubtypeTest.php | 433 --- tests/phpunit/WebTest/Import/ContactTest.php | 425 --- .../WebTest/Import/ContributionTest.php | 198 -- .../phpunit/WebTest/Import/CustomDataTest.php | 356 --- .../phpunit/WebTest/Import/DateFormatTest.php | 471 --- .../WebTest/Import/DuplicateMatchingTest.php | 494 --- tests/phpunit/WebTest/Import/GroupTest.php | 142 - .../Import/ImportCiviSeleniumTestCase.php | 599 ---- .../WebTest/Import/MatchExternalIdTest.php | 366 --- tests/phpunit/WebTest/Import/MemberTest.php | 214 -- .../Import/MultipleRelationshipTest.php | 229 -- .../WebTest/Import/ParticipantTest.php | 340 --- .../WebTest/Import/SavedMappingTest.php | 142 - tests/phpunit/WebTest/Import/TagTest.php | 140 - .../phpunit/WebTest/Mailing/ABMailingTest.php | 537 ---- .../Mailing/AddMessageTemplateTest.php | 177 -- .../Mailing/AddNewMailingComponentTest.php | 149 - tests/phpunit/WebTest/Mailing/MailingTest.php | 573 ---- tests/phpunit/WebTest/Mailing/SpoolTest.php | 98 - .../ValidateBodyMailingComponentTest.php | 71 - .../Member/BatchUpdateViaProfileTest.php | 278 -- .../WebTest/Member/ContactContextAddTest.php | 238 -- .../Member/DefaultMembershipPricesetTest.php | 299 -- .../WebTest/Member/EditMembershipTest.php | 157 - .../Member/FixedMembershipTypeTest.php | 658 ---- .../Member/InheritedMembershipTest.php | 523 ---- .../Member/OfflineAutoRenewMembershipTest.php | 149 - .../OfflineMembershipAddPricesetTest.php | 452 --- .../Member/OfflineMembershipRenewTest.php | 429 --- .../OnlineAutoRenewMembershipGCTest.php | 87 - .../Member/OnlineAutoRenewMembershipTest.php | 214 -- .../OnlineMembershipAddPricesetTest.php | 526 ---- .../Member/OnlineMembershipCreateTest.php | 629 ---- .../Member/OnlineMembershipRenewTest.php | 959 ------ .../Member/SeperateMembershipPaymentTest.php | 166 - .../WebTest/Member/StandaloneAddTest.php | 258 -- .../Member/UpdateMembershipScriptTest.php | 132 - .../WebTest/Pledge/AddCancelPaymentTest.php | 125 - .../WebTest/Pledge/ContactContextAddTest.php | 121 - .../ContactContextPledgePaymentAddTest.php | 455 --- .../Pledge/StandaloneAddDeleteTest.php | 144 - .../WebTest/Pledge/StandaloneAddTest.php | 45 - .../WebTest/Profile/BatchUpdateTest.php | 748 ----- tests/phpunit/WebTest/Profile/DedupeTest.php | 91 - .../Profile/MultiRecordProfileAddTest.php | 407 --- .../WebTest/Profile/ProfileAddTest.php | 333 --- .../WebTest/Profile/ProfileCountryState.php | 155 - .../Profile/ProfileGroupSubscriptionTest.php | 146 - tests/phpunit/WebTest/Profile/SearchTest.php | 251 -- tests/phpunit/WebTest/README | 4 - .../phpunit/WebTest/Release/InstallScript.php | 67 - .../WebTest/Release/ReleaseTestCase.php | 64 - .../phpunit/WebTest/Release/UpgradeScript.php | 51 - tests/phpunit/WebTest/Report/AddTest.php | 202 -- .../WebTest/Report/DonarReportTest.php | 154 - .../WebTest/Report/LoggingReportTest.php | 381 --- .../Report/RolePermissionReportTest.php | 260 -- tests/phpunit/WebTest/Utils/RedirectTest.php | 125 - .../import/ImportActivityTestWHdrs.csv | 1 - .../import/ImportContactTestWHdrs.csv | 1 - .../resources/import/ImportContribs1.csv | 1 - .../resources/import/ImportContribs2.csv | 1 - .../resources/import/ImportContribsExtID.csv | 1 - .../import/ImportContribs_custom.csv | 1 - .../resources/import/ImportHouse_Update.csv | 1 - .../import/ImportHouseholds_WHdrs.csv | 1 - .../resources/import/ImportIndiv_Update.csv | 1 - .../resources/import/ImportOrgs_Update.csv | 1 - .../resources/import/ImportOrgs_WHdrs.csv | 1 - .../resources/import/Import_Participants.csv | 1 - 184 files changed, 52327 deletions(-) delete mode 100644 tests/phpunit/CiviTest/CiviSeleniumSettings.auto.php delete mode 100644 tests/phpunit/CiviTest/CiviSeleniumSettings.php.txt delete mode 100644 tests/phpunit/CiviTest/CiviSeleniumTestCase.php delete mode 100644 tests/phpunit/WebTest/ACL/AssignUsersToRolesTest.php delete mode 100644 tests/phpunit/WebTest/Activity/AddRecurringActivityTest.php delete mode 100644 tests/phpunit/WebTest/Activity/ContactContextAddTest.php delete mode 100644 tests/phpunit/WebTest/Activity/IcalTest.php delete mode 100644 tests/phpunit/WebTest/Activity/StandaloneAddTest.php delete mode 100644 tests/phpunit/WebTest/Admin/CustomAddTest.php delete mode 100644 tests/phpunit/WebTest/Admin/CustomAddTestSameField.php delete mode 100644 tests/phpunit/WebTest/Admin/Form/ScheduleReminderTest.php delete mode 100644 tests/phpunit/WebTest/Admin/Form/Setting/DebuggingTest.php delete mode 100644 tests/phpunit/WebTest/Admin/Form/Setting/LocalizationTest.php delete mode 100644 tests/phpunit/WebTest/Admin/MoveCustomDataTest.php delete mode 100644 tests/phpunit/WebTest/Admin/RelationshipTypeAddTest.php delete mode 100644 tests/phpunit/WebTest/AllTests.php delete mode 100644 tests/phpunit/WebTest/Campaign/ActivityTest.php delete mode 100644 tests/phpunit/WebTest/Campaign/CampaignDescriptionTest.php delete mode 100644 tests/phpunit/WebTest/Campaign/MailingTest.php delete mode 100644 tests/phpunit/WebTest/Campaign/MembershipTest.php delete mode 100644 tests/phpunit/WebTest/Campaign/OfflineContributionTest.php delete mode 100644 tests/phpunit/WebTest/Campaign/OfflineEventRegistrationTest.php delete mode 100644 tests/phpunit/WebTest/Campaign/OnlineContributionTest.php delete mode 100644 tests/phpunit/WebTest/Campaign/OnlineEventRegistrationTest.php delete mode 100644 tests/phpunit/WebTest/Campaign/PetitionUsageScenarioTest.php delete mode 100644 tests/phpunit/WebTest/Campaign/PledgeTest.php delete mode 100644 tests/phpunit/WebTest/Campaign/SurveyUsageScenarioTest.php delete mode 100644 tests/phpunit/WebTest/Case/ActivityToCaseTest.php delete mode 100644 tests/phpunit/WebTest/Case/AddCaseTest.php delete mode 100644 tests/phpunit/WebTest/Case/AddCaseTypeTest.php delete mode 100644 tests/phpunit/WebTest/Case/CaseCustomFieldsTest.php delete mode 100644 tests/phpunit/WebTest/Case/CaseDashboardTest.php delete mode 100644 tests/phpunit/WebTest/Contact/AddCmsUserTest.php delete mode 100644 tests/phpunit/WebTest/Contact/AddContactsToEventAdvancedSearchTest.php delete mode 100644 tests/phpunit/WebTest/Contact/AddTest.php delete mode 100644 tests/phpunit/WebTest/Contact/AddViaProfileTest.php delete mode 100644 tests/phpunit/WebTest/Contact/AddressParsingTest.php delete mode 100644 tests/phpunit/WebTest/Contact/AdvanceSearchPaneTest.php delete mode 100644 tests/phpunit/WebTest/Contact/AdvanceSearchPrivacyOptionsTest.php delete mode 100644 tests/phpunit/WebTest/Contact/AdvancedSearchTest.php delete mode 100644 tests/phpunit/WebTest/Contact/AdvancedSearchedRelatedContactTest.php delete mode 100644 tests/phpunit/WebTest/Contact/ContactReferenceFieldTest.php delete mode 100644 tests/phpunit/WebTest/Contact/ContactTagTest.php delete mode 100644 tests/phpunit/WebTest/Contact/CreateCmsUserFromContactTest.php delete mode 100644 tests/phpunit/WebTest/Contact/CustomDataAddTest.php delete mode 100644 tests/phpunit/WebTest/Contact/DeceasedContactsAdvancedSearchTest.php delete mode 100644 tests/phpunit/WebTest/Contact/DupeContactTest.php delete mode 100644 tests/phpunit/WebTest/Contact/EditContactTest.php delete mode 100644 tests/phpunit/WebTest/Contact/GroupAddTest.php delete mode 100644 tests/phpunit/WebTest/Contact/InlineFieldsEditTest.php delete mode 100644 tests/phpunit/WebTest/Contact/MergeContactsTest.php delete mode 100644 tests/phpunit/WebTest/Contact/MultipleContactSubTypes.php delete mode 100644 tests/phpunit/WebTest/Contact/PrevNextTest.php delete mode 100644 tests/phpunit/WebTest/Contact/PrivacyOptionSearchTest.php delete mode 100644 tests/phpunit/WebTest/Contact/ProfileChecksumTest.php delete mode 100644 tests/phpunit/WebTest/Contact/RelationshipAddTest.php delete mode 100644 tests/phpunit/WebTest/Contact/SearchBuilderTest.php delete mode 100644 tests/phpunit/WebTest/Contact/SearchTest.php delete mode 100644 tests/phpunit/WebTest/Contact/SearchbyDateFilterTest.php delete mode 100644 tests/phpunit/WebTest/Contact/SignatureTest.php delete mode 100644 tests/phpunit/WebTest/Contact/TagAddTest.php delete mode 100644 tests/phpunit/WebTest/Contact/TagSetSearchTest.php delete mode 100644 tests/phpunit/WebTest/Contact/TaskActionAddToGroupTest.php delete mode 100644 tests/phpunit/WebTest/Contact/TaskActionSendMassMailing.php delete mode 100644 tests/phpunit/WebTest/Contact/TaskActionSendSMS.php delete mode 100644 tests/phpunit/WebTest/Contact/UpdateProfileTest.php delete mode 100644 tests/phpunit/WebTest/Contribute/AddBatchesTest.php delete mode 100644 tests/phpunit/WebTest/Contribute/AddPricesetTest.php delete mode 100644 tests/phpunit/WebTest/Contribute/ConfirmOptionalTest.php delete mode 100644 tests/phpunit/WebTest/Contribute/ContactContextAddTest.php delete mode 100644 tests/phpunit/WebTest/Contribute/ContributionPageAddTest.php delete mode 100644 tests/phpunit/WebTest/Contribute/OfflineContributionTest.php delete mode 100644 tests/phpunit/WebTest/Contribute/OfflineRecurContributionTest.php delete mode 100644 tests/phpunit/WebTest/Contribute/OnBehalfOfOrganization.php delete mode 100644 tests/phpunit/WebTest/Contribute/OnlineContributionTest.php delete mode 100644 tests/phpunit/WebTest/Contribute/OnlineMultiplePaymentProcessorTest.php delete mode 100644 tests/phpunit/WebTest/Contribute/OnlineRecurContributionTest.php delete mode 100644 tests/phpunit/WebTest/Contribute/PCPAddTest.php delete mode 100644 tests/phpunit/WebTest/Contribute/StandaloneAddTest.php delete mode 100644 tests/phpunit/WebTest/Contribute/UpdateBatchPendingContributionTest.php delete mode 100644 tests/phpunit/WebTest/Contribute/UpdateContributionTest.php delete mode 100644 tests/phpunit/WebTest/Contribute/UpdatePendingContributionTest.php delete mode 100644 tests/phpunit/WebTest/Contribute/VerifySSLContributionTest.php delete mode 100644 tests/phpunit/WebTest/Event/AddEventTest.php delete mode 100644 tests/phpunit/WebTest/Event/AddParticipationTest.php delete mode 100644 tests/phpunit/WebTest/Event/AddPricesetTest.php delete mode 100644 tests/phpunit/WebTest/Event/AddRecurringEventTest.php delete mode 100644 tests/phpunit/WebTest/Event/AdditionalPaymentTest.php delete mode 100644 tests/phpunit/WebTest/Event/ChangeParticipantStatus.php delete mode 100644 tests/phpunit/WebTest/Event/EventListingTest.php delete mode 100644 tests/phpunit/WebTest/Event/EventWaitListTest.php delete mode 100644 tests/phpunit/WebTest/Event/MultipleEventRegistrationbyCartTest.php delete mode 100644 tests/phpunit/WebTest/Event/MultiprofileEventTest.php delete mode 100644 tests/phpunit/WebTest/Event/PCPAddTest.php delete mode 100644 tests/phpunit/WebTest/Event/ParticipantCountTest.php delete mode 100644 tests/phpunit/WebTest/Event/ParticipantSearchTest.php delete mode 100644 tests/phpunit/WebTest/Event/PricesetMaxCountTest.php delete mode 100644 tests/phpunit/WebTest/Event/TellAFriendTest.php delete mode 100644 tests/phpunit/WebTest/Export/ContactTest.php delete mode 100644 tests/phpunit/WebTest/Export/ExportCiviSeleniumTestCase.php delete mode 100644 tests/phpunit/WebTest/Financial/FinancialAccountTest.php delete mode 100644 tests/phpunit/WebTest/Financial/FinancialAccountTypeTest.php delete mode 100644 tests/phpunit/WebTest/Financial/FinancialBatchExport.php delete mode 100644 tests/phpunit/WebTest/Generic/CheckActivityTest.php delete mode 100644 tests/phpunit/WebTest/Generic/CheckDashboardTest.php delete mode 100644 tests/phpunit/WebTest/Generic/CheckFindTest.php delete mode 100644 tests/phpunit/WebTest/Generic/GeneralClickAroundTest.php delete mode 100644 tests/phpunit/WebTest/Grant/ContactContextAddTest.php delete mode 100644 tests/phpunit/WebTest/Grant/CustomFieldsetTest.php delete mode 100644 tests/phpunit/WebTest/Grant/StandaloneAddTest.php delete mode 100644 tests/phpunit/WebTest/Import/ActivityTest.php delete mode 100644 tests/phpunit/WebTest/Import/AddressImportTest.php delete mode 100644 tests/phpunit/WebTest/Import/AddressParsingTest.php delete mode 100644 tests/phpunit/WebTest/Import/ContactCustomDataTest.php delete mode 100644 tests/phpunit/WebTest/Import/ContactSubtypeTest.php delete mode 100644 tests/phpunit/WebTest/Import/ContactTest.php delete mode 100644 tests/phpunit/WebTest/Import/ContributionTest.php delete mode 100644 tests/phpunit/WebTest/Import/CustomDataTest.php delete mode 100644 tests/phpunit/WebTest/Import/DateFormatTest.php delete mode 100644 tests/phpunit/WebTest/Import/DuplicateMatchingTest.php delete mode 100644 tests/phpunit/WebTest/Import/GroupTest.php delete mode 100644 tests/phpunit/WebTest/Import/ImportCiviSeleniumTestCase.php delete mode 100644 tests/phpunit/WebTest/Import/MatchExternalIdTest.php delete mode 100644 tests/phpunit/WebTest/Import/MemberTest.php delete mode 100644 tests/phpunit/WebTest/Import/MultipleRelationshipTest.php delete mode 100644 tests/phpunit/WebTest/Import/ParticipantTest.php delete mode 100644 tests/phpunit/WebTest/Import/SavedMappingTest.php delete mode 100644 tests/phpunit/WebTest/Import/TagTest.php delete mode 100644 tests/phpunit/WebTest/Mailing/ABMailingTest.php delete mode 100644 tests/phpunit/WebTest/Mailing/AddMessageTemplateTest.php delete mode 100644 tests/phpunit/WebTest/Mailing/AddNewMailingComponentTest.php delete mode 100644 tests/phpunit/WebTest/Mailing/MailingTest.php delete mode 100644 tests/phpunit/WebTest/Mailing/SpoolTest.php delete mode 100644 tests/phpunit/WebTest/Mailing/ValidateBodyMailingComponentTest.php delete mode 100644 tests/phpunit/WebTest/Member/BatchUpdateViaProfileTest.php delete mode 100644 tests/phpunit/WebTest/Member/ContactContextAddTest.php delete mode 100644 tests/phpunit/WebTest/Member/DefaultMembershipPricesetTest.php delete mode 100644 tests/phpunit/WebTest/Member/EditMembershipTest.php delete mode 100644 tests/phpunit/WebTest/Member/FixedMembershipTypeTest.php delete mode 100644 tests/phpunit/WebTest/Member/InheritedMembershipTest.php delete mode 100644 tests/phpunit/WebTest/Member/OfflineAutoRenewMembershipTest.php delete mode 100644 tests/phpunit/WebTest/Member/OfflineMembershipAddPricesetTest.php delete mode 100644 tests/phpunit/WebTest/Member/OfflineMembershipRenewTest.php delete mode 100644 tests/phpunit/WebTest/Member/OnlineAutoRenewMembershipGCTest.php delete mode 100644 tests/phpunit/WebTest/Member/OnlineAutoRenewMembershipTest.php delete mode 100644 tests/phpunit/WebTest/Member/OnlineMembershipAddPricesetTest.php delete mode 100644 tests/phpunit/WebTest/Member/OnlineMembershipCreateTest.php delete mode 100644 tests/phpunit/WebTest/Member/OnlineMembershipRenewTest.php delete mode 100644 tests/phpunit/WebTest/Member/SeperateMembershipPaymentTest.php delete mode 100644 tests/phpunit/WebTest/Member/StandaloneAddTest.php delete mode 100644 tests/phpunit/WebTest/Member/UpdateMembershipScriptTest.php delete mode 100644 tests/phpunit/WebTest/Pledge/AddCancelPaymentTest.php delete mode 100644 tests/phpunit/WebTest/Pledge/ContactContextAddTest.php delete mode 100644 tests/phpunit/WebTest/Pledge/ContactContextPledgePaymentAddTest.php delete mode 100644 tests/phpunit/WebTest/Pledge/StandaloneAddDeleteTest.php delete mode 100644 tests/phpunit/WebTest/Pledge/StandaloneAddTest.php delete mode 100644 tests/phpunit/WebTest/Profile/BatchUpdateTest.php delete mode 100644 tests/phpunit/WebTest/Profile/DedupeTest.php delete mode 100644 tests/phpunit/WebTest/Profile/MultiRecordProfileAddTest.php delete mode 100644 tests/phpunit/WebTest/Profile/ProfileAddTest.php delete mode 100644 tests/phpunit/WebTest/Profile/ProfileCountryState.php delete mode 100644 tests/phpunit/WebTest/Profile/ProfileGroupSubscriptionTest.php delete mode 100644 tests/phpunit/WebTest/Profile/SearchTest.php delete mode 100644 tests/phpunit/WebTest/README delete mode 100644 tests/phpunit/WebTest/Release/InstallScript.php delete mode 100644 tests/phpunit/WebTest/Release/ReleaseTestCase.php delete mode 100644 tests/phpunit/WebTest/Release/UpgradeScript.php delete mode 100644 tests/phpunit/WebTest/Report/AddTest.php delete mode 100644 tests/phpunit/WebTest/Report/DonarReportTest.php delete mode 100644 tests/phpunit/WebTest/Report/LoggingReportTest.php delete mode 100644 tests/phpunit/WebTest/Report/RolePermissionReportTest.php delete mode 100644 tests/phpunit/WebTest/Utils/RedirectTest.php delete mode 100644 tests/phpunit/WebTest/resources/import/ImportActivityTestWHdrs.csv delete mode 100644 tests/phpunit/WebTest/resources/import/ImportContactTestWHdrs.csv delete mode 100644 tests/phpunit/WebTest/resources/import/ImportContribs1.csv delete mode 100644 tests/phpunit/WebTest/resources/import/ImportContribs2.csv delete mode 100644 tests/phpunit/WebTest/resources/import/ImportContribsExtID.csv delete mode 100644 tests/phpunit/WebTest/resources/import/ImportContribs_custom.csv delete mode 100644 tests/phpunit/WebTest/resources/import/ImportHouse_Update.csv delete mode 100644 tests/phpunit/WebTest/resources/import/ImportHouseholds_WHdrs.csv delete mode 100644 tests/phpunit/WebTest/resources/import/ImportIndiv_Update.csv delete mode 100644 tests/phpunit/WebTest/resources/import/ImportOrgs_Update.csv delete mode 100644 tests/phpunit/WebTest/resources/import/ImportOrgs_WHdrs.csv delete mode 100644 tests/phpunit/WebTest/resources/import/Import_Participants.csv diff --git a/tests/phpunit/CiviTest/CiviSeleniumSettings.auto.php b/tests/phpunit/CiviTest/CiviSeleniumSettings.auto.php deleted file mode 100644 index cec0a0fa382f..000000000000 --- a/tests/phpunit/CiviTest/CiviSeleniumSettings.auto.php +++ /dev/null @@ -1,65 +0,0 @@ -sandboxURL = substr($GLOBALS['_CV']['CMS_URL'], 0, strlen($GLOBALS['_CV']['CMS_URL']) - strlen($path)); - $this->sandboxPATH = $path; - $this->fullSandboxPath = $GLOBALS['_CV']['CMS_URL']; - $this->adminUsername = $GLOBALS['_CV']['ADMIN_USER']; - $this->adminPassword = $GLOBALS['_CV']['ADMIN_PASS']; - $this->username = $GLOBALS['_CV']['DEMO_USER']; - $this->password = $GLOBALS['_CV']['DEMO_PASS']; - $this->siteKey = CIVICRM_SITE_KEY; - $this->adminApiKey = md5('apikeyadmin' . $GLOBALS['_CV']['CMS_DB_DSN'] . CIVICRM_SITE_KEY); - $this->cookies = array(); - } - - // /** - // * @return array - // */ - // function createConstCookie() { - // global $civibuild; - // $now = time(); - // $civiConsts = array( - // 'CIVICRM_DSN' => CIVICRM_DSN, - // 'CIVICRM_UF_DSN' => CIVICRM_UF_DSN, - // 'ts' => $now, - // 'sig' => md5(implode(';;', array(CIVICRM_DSN, CIVICRM_UF_DSN, $civibuild['SITE_TOKEN'], $now))), - // ); - // - // return array( - // 'name' => 'civiConsts', - // 'value' => urlencode(json_encode($civiConsts)), - // ); - // } - -} diff --git a/tests/phpunit/CiviTest/CiviSeleniumSettings.php.txt b/tests/phpunit/CiviTest/CiviSeleniumSettings.php.txt deleted file mode 100644 index 37b868d4875c..000000000000 --- a/tests/phpunit/CiviTest/CiviSeleniumSettings.php.txt +++ /dev/null @@ -1,72 +0,0 @@ -fullSandboxPath = $this->sandboxURL . $this->sandboxPATH; - // $this->cookies[] = array( - // 'name' => 'mycookie', - // 'value' => 'myvalue', - // 'path' => '/', - // 'max_age' => 24*60*60, - // );; - } - -} -?> diff --git a/tests/phpunit/CiviTest/CiviSeleniumTestCase.php b/tests/phpunit/CiviTest/CiviSeleniumTestCase.php deleted file mode 100644 index 82f342a12b77..000000000000 --- a/tests/phpunit/CiviTest/CiviSeleniumTestCase.php +++ /dev/null @@ -1,2661 +0,0 @@ -loggedInAs = NULL; - - $this->settings = new CiviSeleniumSettings(); - if (property_exists($this->settings, 'serverStartupTimeOut') && $this->settings->serverStartupTimeOut) { - global $CiviSeleniumTestCase_polled; - if (!$CiviSeleniumTestCase_polled) { - $CiviSeleniumTestCase_polled = TRUE; - CRM_Utils_Network::waitForServiceStartup( - $this->drivers[0]->getHost(), - $this->drivers[0]->getPort(), - $this->settings->serverStartupTimeOut - ); - } - } - - // autoload - require_once 'CRM/Core/ClassLoader.php'; - CRM_Core_ClassLoader::singleton()->register(); - - // also initialize a connection to the db - // FIXME: not necessary for most tests, consider moving into functions that need this - $config = CRM_Core_Config::singleton(); - } - - protected function setUp() { - $this->setBrowser($this->settings->browser); - // Make sure that below strings have path separator at the end - $this->setBrowserUrl($this->settings->sandboxURL); - $this->sboxPath = $this->settings->sandboxPATH; - if (property_exists($this->settings, 'rcHost') && $this->settings->rcHost) { - $this->setHost($this->settings->rcHost); - } - if (property_exists($this->settings, 'rcPort') && $this->settings->rcPort) { - $this->setPort($this->settings->rcPort); - } - $this->settingCache = array(); - } - - /** - * @return string - */ - protected function prepareTestSession() { - $result = parent::prepareTestSession(); - - // Set any cookies required by local installation - // Note: considered doing this in setUp(), but the Selenium session wasn't yet initialized. - if (property_exists($this->settings, 'cookies')) { - // We don't really care about this page, but it seems we need - // to open a page before setting a cookie. - $this->open($this->sboxPath); - $this->waitForPageToLoad($this->getTimeoutMsec()); - $this->setCookies($this->settings->cookies); - } - return $result; - } - - /** - * @param array $cookies - * Each item is an Array with keys: - * - name: string - * - value: string; note that RFC's don't define particular encoding scheme, so - * you must pick one yourself and pre-encode; does not allow values with - * commas, semicolons, or whitespace - * - path: string; default: '/' - * - max_age: int; default: 1 week (7*24*60*60) - */ - protected function setCookies($cookies) { - foreach ($cookies as $cookie) { - if (!isset($cookie['path'])) { - $cookie['path'] = '/'; - } - if (!isset($cookie['max_age'])) { - $cookie['max_age'] = 7 * 24 * 60 * 60; - } - $this->deleteCookie($cookie['name'], $cookie['path']); - $optionExprs = array(); - foreach ($cookie as $key => $value) { - if ($key != 'name' && $key != 'value') { - $optionExprs[] = "$key=$value"; - } - } - $this->createCookie("{$cookie['name']}={$cookie['value']}", implode(', ', $optionExprs)); - } - } - - protected function tearDown() { - } - - /** - * Authenticate as drupal user. - * @param $user : (str) the key 'user' or 'admin', or a literal username - * @param $pass : (str) if $user is a literal username and not 'user' or 'admin', supply the password - */ - public function webtestLogin($user = 'user', $pass = NULL) { - // If already logged in as correct user, do nothing - if ($this->loggedInAs === $user) { - return; - } - // If we are logged in as a different user, log out first - if ($this->loggedInAs) { - $this->webtestLogout(); - } - $this->open("{$this->sboxPath}user"); - // Lookup username & password if not supplied - $username = $user; - if ($pass === NULL) { - $pass = $user == 'admin' ? $this->settings->adminPassword : $this->settings->password; - $username = $user == 'admin' ? $this->settings->adminUsername : $this->settings->username; - } - // Make sure login form is available - $this->waitForElementPresent('edit-submit'); - $this->type('edit-name', $username); - $this->type('edit-pass', $pass); - $this->click('edit-submit'); - $this->waitForPageToLoad($this->getTimeoutMsec()); - $this->loggedInAs = $user; - } - - public function webtestLogout() { - if ($this->loggedInAs) { - $this->open($this->sboxPath . "user/logout"); - $this->waitForPageToLoad($this->getTimeoutMsec()); - } - $this->loggedInAs = NULL; - } - - /** - * Open an internal path beginning with 'civicrm/' - * - * @param string $url - * omit the 'civicrm/' it will be added for you. - * @param string|array $args - * optional url arguments. - * @param $waitFor - * Page element to wait for - using this is recommended to ensure the document is fully loaded. - * - * Although it doesn't seem to do much now, using this function is recommended for - * opening all civi pages, and using the $args param is also strongly encouraged - * This will make it much easier to run webtests in other CMSs in the future - */ - public function openCiviPage($url, $args = NULL, $waitFor = 'civicrm-footer') { - // Construct full url with args - // This could be extended in future to work with other CMS style urls - if ($args) { - if (is_array($args)) { - $sep = '?'; - foreach ($args as $key => $val) { - $url .= $sep . $key . '=' . $val; - $sep = '&'; - } - } - else { - $url .= "?$args"; - } - } - $this->open("{$this->sboxPath}civicrm/$url"); - $this->waitForPageToLoad($this->getTimeoutMsec()); - $this->checkForErrorsOnPage(); - if ($waitFor) { - $this->waitForElementPresent($waitFor); - } - } - - /** - * Click on a link or button. - * Wait for the page to load - * Wait for an element to be present - * @param $element - * @param string $waitFor - * @param bool $waitForPageLoad - */ - public function clickLink($element, $waitFor = 'civicrm-footer', $waitForPageLoad = TRUE) { - $this->click($element); - // conditional wait for page load e.g for ajax form save - if ($waitForPageLoad) { - $this->waitForPageToLoad($this->getTimeoutMsec()); - $this->checkForErrorsOnPage(); - } - if ($waitFor) { - $this->waitForElementPresent($waitFor); - } - } - - /** - * Click a link or button and wait for an ajax dialog to load. - * @param string $element - * @param string $waitFor - */ - public function clickPopupLink($element, $waitFor = NULL) { - $this->clickAjaxLink($element, 'css=.ui-dialog'); - if ($waitFor) { - $this->waitForElementPresent($waitFor); - } - } - - /** - * Click a link or button and wait for ajax content to load or refresh. - * @param string $element - * @param string $waitFor - */ - public function clickAjaxLink($element, $waitFor = NULL) { - $this->click($element); - if ($waitFor) { - $this->waitForElementPresent($waitFor); - } - $this->waitForAjaxContent(); - } - - /** - * Force a link to open full-page, even if it would normally open in a popup - * @note: works with links only, not buttons - * @param string $element - * @param string $waitFor - */ - public function clickLinkSuppressPopup($element, $waitFor = 'civicrm-footer') { - $link = $this->getAttribute($element . '@href'); - $this->open($link); - $this->waitForPageToLoad($this->getTimeoutMsec()); - if ($waitFor) { - $this->waitForElementPresent($waitFor); - } - } - - /** - * Wait for all ajax snippets to finish loading. - */ - public function waitForAjaxContent() { - $this->waitForElementNotPresent('css=.blockOverlay'); - // Some ajax calls happen in pairs (e.g. submit a popup form then refresh the underlying content) - // So we'll wait a sec and recheck to see if any more stuff is loading - sleep(1); - if ($this->isElementPresent('css=.blockOverlay')) { - $this->waitForAjaxContent(); - } - } - - /** - * Call the API on the local server. - * (kind of defeats the point of a webtest - see CRM-11889) - * @param $entity - * @param $action - * @param $params - * @return array|int - */ - public function webtest_civicrm_api($entity, $action, $params) { - if (!isset($params['version'])) { - $params['version'] = 3; - } - - $result = civicrm_api($entity, $action, $params); - $this->assertAPISuccess($result); - return $result; - } - - /** - * Call the API on the remote server using the AJAX endpoint. - * - * @see CRM-11889 - * @param $entity - * @param $action - * @param array $params - * @return mixed - */ - public function rest_civicrm_api($entity, $action, $params = array()) { - $params += array( - 'version' => 3, - ); - static $reqId = 0; - $reqId++; - - $jsCmd = ' - setTimeout(function(){ - CRM.api3("@entity", "@action", @params).then(function(a){ - cj("