· 6 years ago · Jun 18, 2019, 08:40 PM
1diff --git a/CRM/Activity/BAO/Query.php b/CRM/Activity/BAO/Query.php
2index 8f7cd076b8..2eb50d4e5c 100644
3--- a/CRM/Activity/BAO/Query.php
4+++ b/CRM/Activity/BAO/Query.php
5@@ -212,7 +212,7 @@ class CRM_Activity_BAO_Query {
6
7 $qillName = $name;
8 if (in_array($name, ['activity_engagement_level', 'activity_id'])) {
9- $name = $qillName = str_replace('activity_', '', $name);
10+ $name = str_replace('activity_', '', $name);
11 }
12 if (in_array($name, [
13 'activity_status_id',
14diff --git a/CRM/Admin/Form/Preferences.php b/CRM/Admin/Form/Preferences.php
15index 55578d404a..43115d26d9 100644
16--- a/CRM/Admin/Form/Preferences.php
17+++ b/CRM/Admin/Form/Preferences.php
18@@ -282,7 +282,7 @@ class CRM_Admin_Form_Preferences extends CRM_Core_Form {
19 ) . CRM_Core_DAO::VALUE_SEPARATOR;
20 }
21 else {
22- $this->_config->$settingName = NULL;
23+ $this->_config->$settingName = CRM_Core_DAO::VALUE_SEPARATOR . '' . CRM_Core_DAO::VALUE_SEPARATOR;
24 }
25 break;
26
27diff --git a/CRM/Case/BAO/Case.php b/CRM/Case/BAO/Case.php
28index 222860016a..4e343a4be1 100644
29--- a/CRM/Case/BAO/Case.php
30+++ b/CRM/Case/BAO/Case.php
31@@ -947,7 +947,7 @@ SELECT case_status.label AS case_status, status_id, civicrm_case_type.title AS c
32 }
33
34 $groupBy = "
35- GROUP BY ca.id, tcc.id, scc.id, acc.id, ov.value";
36+ GROUP BY ca.id, ov.value";
37
38 $sortBy = CRM_Utils_Array::value('sortBy', $params);
39 if (!$sortBy) {
40@@ -1641,7 +1641,7 @@ SELECT case_status.label AS case_status, status_id, civicrm_case_type.title AS c
41 $searchParams = array('name' => $groupInfo['name']);
42 $results = array();
43 CRM_Contact_BAO_Group::retrieve($searchParams, $results);
44- if ($results) {
45+ if ($results && CRM_Contact_BAO_Contact_Permission::allow($results['id'])) {
46 $groupInfo['id'] = $results['id'];
47 $groupInfo['title'] = $results['title'];
48 $params = array(array('group', '=', $groupInfo['id'], 0, 0));
49@@ -2305,43 +2305,36 @@ SELECT id
50 //copy case relationship.
51 if ($duplicateContacts) {
52 //migrate relationship records.
53- $otherRelationship = new CRM_Contact_DAO_Relationship();
54- $otherRelationship->case_id = $otherCaseId;
55- $otherRelationship->find();
56+ $otherRelationshipValues = civicrm_api3('Relationship', 'get', [
57+ 'sequential' => 1,
58+ 'case_id' => $otherCaseId,
59+ ]);
60+ $otherRelationshipValues = CRM_Utils_Array::value('values', $otherRelationshipValues, array());
61 $otherRelationshipIds = array();
62- while ($otherRelationship->fetch()) {
63- $otherRelVals = array();
64+ foreach ($otherRelationshipValues as $val) {
65 $updateOtherRel = FALSE;
66- CRM_Core_DAO::storeValues($otherRelationship, $otherRelVals);
67+ $otherRelVals = $val;
68+ $otherRelVals['id'] = NULL;
69+ $otherRelVals['case_id'] = $mainCaseId;
70
71- $mainRelationship = new CRM_Contact_DAO_Relationship();
72- $mainRelationship->copyValues($otherRelVals);
73- $mainRelationship->id = NULL;
74- $mainRelationship->case_id = $mainCaseId;
75- if ($mainRelationship->contact_id_a == $otherContactId) {
76+ if ($otherRelVals['contact_id_a'] == $otherContactId) {
77 $updateOtherRel = TRUE;
78- $mainRelationship->contact_id_a = $mainContactId;
79+ $otherRelVals['contact_id_a'] = $mainContactId;
80 }
81
82 //case creator change only when we merge user contact.
83- if ($mainRelationship->contact_id_b == $otherContactId) {
84+ if ($otherRelVals['contact_id_b'] == $otherContactId) {
85 //do not change creator for change client.
86 if (!$changeClient) {
87 $updateOtherRel = TRUE;
88- $mainRelationship->contact_id_b = ($currentUserId) ? $currentUserId : $mainContactId;
89+ $otherRelVals['contact_id_b'] = ($currentUserId) ? $currentUserId : $mainContactId;
90 }
91 }
92- $mainRelationship->end_date = CRM_Utils_Date::isoToMysql($otherRelationship->end_date);
93- $mainRelationship->start_date = CRM_Utils_Date::isoToMysql($otherRelationship->start_date);
94-
95- //avoid duplicate object.
96- if (!$mainRelationship->find(TRUE)) {
97- $mainRelationship->save();
98- }
99+ civicrm_api3('Relationship', 'create', $otherRelVals);
100
101 //get the other relationship ids to update end date.
102 if ($updateOtherRel) {
103- $otherRelationshipIds[$otherRelationship->id] = $otherRelationship->id;
104+ $otherRelationshipIds[$val['id']] = $val['id'];
105 }
106 }
107
108diff --git a/CRM/Case/Form/Activity.php b/CRM/Case/Form/Activity.php
109index 4b9cdbe1dd..a8673149bc 100644
110--- a/CRM/Case/Form/Activity.php
111+++ b/CRM/Case/Form/Activity.php
112@@ -620,7 +620,8 @@ class CRM_Case_Form_Activity extends CRM_Activity_Form_Activity {
113 //CRM-5695
114 //check for notification settings for assignee contacts
115 $selectedContacts = ['contact_check'];
116- if (Civi::settings()->get('activity_assignee_notification')) {
117+ if (Civi::settings()->get('activity_assignee_notification')
118+ && !in_array($activity->activity_type_id, Civi::settings()->get('do_not_notify_assignees_for'))) {
119 $selectedContacts[] = 'assignee_contact_id';
120 }
121
122diff --git a/CRM/Case/XMLProcessor/Process.php b/CRM/Case/XMLProcessor/Process.php
123index b83e11cce6..d0e1b26fb6 100644
124--- a/CRM/Case/XMLProcessor/Process.php
125+++ b/CRM/Case/XMLProcessor/Process.php
126@@ -630,6 +630,31 @@ AND a.is_deleted = 0
127 }
128
129 /**
130+ * Update role name after relationship is edited.
131+ *
132+ * @param string $prevName
133+ * @param string $updatedName
134+ */
135+ public function updateCaseRoleNames($prevName, $updatedName) {
136+ $repo = new CRM_Case_XMLRepository();
137+ foreach ($repo->getAllCaseTypes() as $caseId => $caseTypeName) {
138+ $caseTypeXML = $repo->retrieve($caseTypeName);
139+ if (in_array($prevName, $this->getDeclaredRelationshipTypes($caseTypeXML))) {
140+ foreach ($caseTypeXML->CaseRoles->RelationshipType as $relType) {
141+ if ($relType->name == $prevName) {
142+ $relType->name = $updatedName;
143+ }
144+ }
145+ $updateParams = [
146+ 'id' => $caseId,
147+ 'definition' => CRM_Case_BAO_CaseType::convertXmlToDefinition($caseTypeXML),
148+ ];
149+ CRM_Case_BAO_CaseType::create($updateParams);
150+ }
151+ }
152+ }
153+
154+ /**
155 * Returns the default assignee for the activity by searching for the target's
156 * contact relationship type defined in the activity's details.
157 *
158diff --git a/CRM/Contact/BAO/Contact.php b/CRM/Contact/BAO/Contact.php
159index 7280f6d5c7..d565a9a33c 100644
160--- a/CRM/Contact/BAO/Contact.php
161+++ b/CRM/Contact/BAO/Contact.php
162@@ -1765,7 +1765,7 @@ WHERE civicrm_contact.id = " . CRM_Utils_Type::escape($id, 'Integer');
163 * A hierarchical property tree if appropriate
164 */
165 public static function &makeHierReturnProperties($fields, $contactId = NULL) {
166- $locationTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id');
167+ $locationTypes = CRM_Core_BAO_Address::buildOptions('location_type_id', 'validate');
168
169 $returnProperties = array();
170
171diff --git a/CRM/Contact/BAO/Query.php b/CRM/Contact/BAO/Query.php
172index e5f9b4c604..0ad85c9cbc 100644
173--- a/CRM/Contact/BAO/Query.php
174+++ b/CRM/Contact/BAO/Query.php
175@@ -3668,9 +3668,11 @@ WHERE $smartGroupClause
176 list($name, $op, $value, $grouping, $wildcard) = $values;
177
178 $name = trim($value);
179- $cond = " contact_a.sort_name LIKE '" . CRM_Core_DAO::escapeWildCardString($name) . "%'";
180- $this->_where[$grouping][] = $cond;
181- $this->_qill[$grouping][] = ts('Showing only Contacts starting with: \'%1\'', [1 => $name]);
182+ if ($name != 'all') {
183+ $cond = " contact_a.sort_name LIKE '" . strtolower(CRM_Core_DAO::escapeWildCardString($name)) . "%'";
184+ $this->_where[$grouping][] = $cond;
185+ $this->_qill[$grouping][] = ts('Showing only Contacts starting with: \'%1\'', array(1 => $name));
186+ }
187 }
188
189 /**
190@@ -6589,7 +6591,7 @@ AND displayRelType.is_active = 1
191 FROM (
192 SELECT civicrm_contribution.total_amount, civicrm_contribution.currency
193 $from
194- $where AND civicrm_contribution.cancel_date IS NOT NULL
195+ $where AND civicrm_contribution.cancel_date IS NOT NULL
196 GROUP BY civicrm_contribution.id
197 ) as conts
198 GROUP BY currency";
199diff --git a/CRM/Contact/BAO/Relationship.php b/CRM/Contact/BAO/Relationship.php
200index e271d16cb1..37ea9c27df 100644
201--- a/CRM/Contact/BAO/Relationship.php
202+++ b/CRM/Contact/BAO/Relationship.php
203@@ -1459,12 +1459,12 @@ LEFT JOIN civicrm_country ON (civicrm_address.country_id = civicrm_country.id)
204 * @return array
205 * array reference of all relationship types with context to current contact type .
206 */
207- public static function getRelationType($targetContactType) {
208+ public static function getRelationType($targetContactType, $includeAllContactType = FALSE) {
209 $relationshipType = array();
210 $allRelationshipType = CRM_Core_PseudoConstant::relationshipType();
211
212 foreach ($allRelationshipType as $key => $type) {
213- if ($type['contact_type_b'] == $targetContactType || empty($type['contact_type_b'])) {
214+ if ($type['contact_type_b'] == $targetContactType || (!empty($includeAllContactType) && empty($type['contact_type_b']))) {
215 $relationshipType[$key . '_a_b'] = $type['label_a_b'];
216 }
217 }
218diff --git a/CRM/Contact/BAO/RelationshipType.php b/CRM/Contact/BAO/RelationshipType.php
219index bc11bf2f02..718826f388 100644
220--- a/CRM/Contact/BAO/RelationshipType.php
221+++ b/CRM/Contact/BAO/RelationshipType.php
222@@ -99,6 +99,9 @@ class CRM_Contact_BAO_RelationshipType extends CRM_Contact_DAO_RelationshipType
223 $params['name_b_a'] = $params['label_b_a'];
224 }
225 }
226+ else {
227+ $previousLabelBA = CRM_Core_DAO::getFieldValue('CRM_Contact_BAO_RelationshipType', $params['id'], 'label_b_a');
228+ }
229
230 // action is taken depending upon the mode
231 $relationshipType = new CRM_Contact_DAO_RelationshipType();
232@@ -109,6 +112,12 @@ class CRM_Contact_BAO_RelationshipType extends CRM_Contact_DAO_RelationshipType
233 $relationshipType->copyValues($params);
234 $relationshipType->save();
235
236+ //Update case roles definition if label is changed.
237+ if (!empty($previousLabelBA) && !empty($params['label_b_a']) && $previousLabelBA != $params['label_b_a']) {
238+ $xmlProcessor = new CRM_Case_XMLProcessor_Process();
239+ $xmlProcessor->updateCaseRoleNames($previousLabelBA, $params['label_b_a']);
240+ }
241+
242 CRM_Utils_Hook::post($hook, 'RelationshipType', $relationshipType->id, $relationshipType);
243
244 CRM_Core_PseudoConstant::relationshipType('label', TRUE);
245diff --git a/CRM/Contact/Form/Task/AddToParentClass.php b/CRM/Contact/Form/Task/AddToParentClass.php
246index 3a1231f5b3..18fbe69828 100644
247--- a/CRM/Contact/Form/Task/AddToParentClass.php
248+++ b/CRM/Contact/Form/Task/AddToParentClass.php
249@@ -55,7 +55,7 @@ class CRM_Contact_Form_Task_AddToParentClass extends CRM_Contact_Form_Task {
250 [
251 '' => ts('- select -'),
252 ] +
253- CRM_Contact_BAO_Relationship::getRelationType($contactType), TRUE
254+ CRM_Contact_BAO_Relationship::getRelationType($contactType, TRUE), TRUE
255 );
256
257 $searchRows = $this->get('searchRows');
258diff --git a/CRM/Contact/Import/Parser/Contact.php b/CRM/Contact/Import/Parser/Contact.php
259index 542a65ba55..6152537731 100644
260--- a/CRM/Contact/Import/Parser/Contact.php
261+++ b/CRM/Contact/Import/Parser/Contact.php
262@@ -1383,7 +1383,7 @@ class CRM_Contact_Import_Parser_Contact extends CRM_Contact_Import_Parser {
263 if (strlen($gender) > strlen($value)) {
264 continue;
265 }
266- if ($gender == $value) {
267+ if ($gender == $key || $gender == $value) {
268 return $value;
269 }
270 if (substr_compare($value, $gender, 0, strlen($gender), TRUE) === 0) {
271diff --git a/CRM/Contribute/BAO/Contribution.php b/CRM/Contribute/BAO/Contribution.php
272index 02cee6dd71..8db86573b5 100644
273--- a/CRM/Contribute/BAO/Contribution.php
274+++ b/CRM/Contribute/BAO/Contribution.php
275@@ -1982,6 +1982,8 @@ LEFT JOIN civicrm_contribution contribution ON ( componentPayment.contribution_
276 );
277
278 $formattedParams = array(
279+ 'contact_id' => $membership->contact_id,
280+ 'membership_type_id' => $membership->membership_type_id,
281 'status_id' => CRM_Utils_Array::value('id', $calcStatus,
282 array_search('Current', $membershipStatuses)
283 ),
284@@ -1994,6 +1996,7 @@ LEFT JOIN civicrm_contribution contribution ON ( componentPayment.contribution_
285
286 $membership->copyValues($formattedParams);
287 $membership->save();
288+ unset($formattedParams['contact_id']);
289
290 //updating the membership log
291 $membershipLog = array();
292diff --git a/CRM/Contribute/BAO/ContributionPage.php b/CRM/Contribute/BAO/ContributionPage.php
293index 492afdb67c..4df6bc9b21 100644
294--- a/CRM/Contribute/BAO/ContributionPage.php
295+++ b/CRM/Contribute/BAO/ContributionPage.php
296@@ -438,7 +438,7 @@ class CRM_Contribute_BAO_ContributionPage extends CRM_Contribute_DAO_Contributio
297 'contactId' => $contactID,
298 'tplParams' => $tplParams,
299 'isTest' => $isTest,
300- 'PDFFilename' => 'receipt.pdf',
301+ 'PDFFilename' => !empty($values['is_pay_later']) ? 'invoice.pdf' : 'receipt.pdf',
302 ];
303
304 if ($returnMessageText) {
305diff --git a/CRM/Contribute/BAO/ContributionRecur.php b/CRM/Contribute/BAO/ContributionRecur.php
306index a416a9573f..8a02836748 100644
307--- a/CRM/Contribute/BAO/ContributionRecur.php
308+++ b/CRM/Contribute/BAO/ContributionRecur.php
309@@ -600,7 +600,7 @@ INNER JOIN civicrm_contribution con ON ( con.id = mp.contribution_id )
310 $soft_contribution->contribution_id = CRM_Core_DAO::getFieldValue('CRM_Contribute_DAO_Contribution', $recurId, 'id', 'contribution_recur_id');
311
312 // Check if first recurring contribution has any associated soft credit.
313- if ($soft_contribution->find(TRUE)) {
314+ if ($soft_contribution->find(TRUE) && $soft_contribution->contribution_id != $targetContributionId) {
315 $soft_contribution->contribution_id = $targetContributionId;
316 unset($soft_contribution->id);
317 $soft_contribution->save();
318diff --git a/CRM/Contribute/Form/AdditionalPayment.php b/CRM/Contribute/Form/AdditionalPayment.php
319index 1c37915b58..d5e5d0d0d9 100644
320--- a/CRM/Contribute/Form/AdditionalPayment.php
321+++ b/CRM/Contribute/Form/AdditionalPayment.php
322@@ -259,6 +259,19 @@ class CRM_Contribute_Form_AdditionalPayment extends CRM_Contribute_Form_Abstract
323 );
324 $this->addRule('net_amount', ts('Please enter a valid monetary value for Net Amount.'), 'money');
325 }
326+ $ft = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($this->_contributionId);
327+ if (!empty($ft['financialTrxnId'])) {
328+ $defaults = [];
329+ $ftParams = ['id' => $ft['financialTrxnId']];
330+ $financialTrxn = CRM_Core_BAO_FinancialTrxn::retrieve($ftParams, $defaults);
331+ if (!empty($financialTrxn->payment_processor_id)) {
332+ $processor = Civi\Payment\System::singleton()->getById($financialTrxn->payment_processor_id);
333+ if ($processor->supports('Refund')) {
334+ $this->addElement('checkbox', 'processor_refund', ts('Record refund from the payment processor?'));
335+ $this->assign('processorRefund', TRUE);
336+ }
337+ }
338+ }
339
340 $buttonName = $this->_refund ? 'Record Refund' : 'Record Payment';
341 $this->addButtons([
342diff --git a/CRM/Contribute/Form/Contribution/Confirm.php b/CRM/Contribute/Form/Contribution/Confirm.php
343index 9add6a4ec1..252ee63006 100644
344--- a/CRM/Contribute/Form/Contribution/Confirm.php
345+++ b/CRM/Contribute/Form/Contribution/Confirm.php
346@@ -2260,11 +2260,11 @@ class CRM_Contribute_Form_Contribution_Confirm extends CRM_Contribute_Form_Contr
347
348 $this->_useForMember = $this->get('useForMember');
349
350+ $priceFieldIds = $this->get('memberPriceFieldIDS');
351 // store the fact that this is a membership and membership type is selected
352 if ((!empty($membershipParams['selectMembership']) &&
353 $membershipParams['selectMembership'] != 'no_thanks'
354- ) ||
355- $this->_useForMember
356+ ) || ($this->_useForMember && !empty($priceFieldIds))
357 ) {
358 if (!$this->_useForMember) {
359 $this->assign('membership_assign', TRUE);
360diff --git a/CRM/Contribute/Form/Contribution/Main.php b/CRM/Contribute/Form/Contribution/Main.php
361index 601c8e08fd..de939cb05c 100644
362--- a/CRM/Contribute/Form/Contribution/Main.php
363+++ b/CRM/Contribute/Form/Contribution/Main.php
364@@ -797,7 +797,10 @@ class CRM_Contribute_Form_Contribution_Main extends CRM_Contribute_Form_Contribu
365 elseif (!$value['is_enter_qty'] && !empty($fields['price_' . $priceId])) {
366 // The check for {!$value['is_enter_qty']} is done since, quantity fields allow entering
367 // quantity. And the quantity can't be conisdered as civicrm_price_field_value.id, CRM-9577
368- $priceFieldIDS[] = $fields['price_' . $priceId];
369+ $optionId = $fields['price_' . $priceId];
370+ if (!empty($value['options']) && !empty($value['options'][$optionId]) && !empty($value['options'][$optionId]['membership_type_id'])) {
371+ $priceFieldIDS[] = $fields['price_' . $priceId];
372+ }
373 }
374
375 if (!empty($value['options'])) {
376diff --git a/CRM/Contribute/Form/ContributionBase.php b/CRM/Contribute/Form/ContributionBase.php
377index 971479e633..0ed205c16c 100644
378--- a/CRM/Contribute/Form/ContributionBase.php
379+++ b/CRM/Contribute/Form/ContributionBase.php
380@@ -581,9 +581,16 @@ class CRM_Contribute_Form_ContributionBase extends CRM_Core_Form {
381 }
382 $this->assignPaymentFields();
383
384- $this->assign('email',
385- $this->controller->exportValue('Main', "email-{$this->_bltID}")
386- );
387+ if ($this->_emailExists && empty($this->_params["email-{$this->_bltID}"])) {
388+ foreach ($this->_params as $key => $val) {
389+ if (substr($key, 0, 6) == 'email-') {
390+ $this->assign('email', $this->_params[$key]);
391+ }
392+ }
393+ }
394+ else {
395+ $this->assign('email', $this->_params["email-{$this->_bltID}"]);
396+ }
397
398 // also assign the receipt_text
399 if (isset($this->_values['receipt_text'])) {
400diff --git a/CRM/Contribute/Form/Task/PDF.php b/CRM/Contribute/Form/Task/PDF.php
401index c27b4fd176..30b4534f6e 100644
402--- a/CRM/Contribute/Form/Task/PDF.php
403+++ b/CRM/Contribute/Form/Task/PDF.php
404@@ -197,6 +197,13 @@ AND {$this->_componentClause}";
405 1 => [$contribution->trxn_id, 'String'],
406 ]);
407
408+ if (!empty($ids['membership'])) {
409+ $membershipPayments = (array) CRM_Member_BAO_Membership::getMembershipContributionId($ids['membership'][0], TRUE);
410+ if (in_array($contribID, $membershipPayments) && $contribID != current($membershipPayments)) {
411+ $template->assign('renewal_mode', TRUE);
412+ }
413+ }
414+
415 // CRM_Contribute_BAO_Contribution::composeMessageArray expects mysql formatted date
416 $objects['contribution']->receive_date = CRM_Utils_Date::isoToMysql($objects['contribution']->receive_date);
417
418diff --git a/CRM/Contribute/Form/UpdateSubscription.php b/CRM/Contribute/Form/UpdateSubscription.php
419index 162748d9cf..2cbb5af15d 100644
420--- a/CRM/Contribute/Form/UpdateSubscription.php
421+++ b/CRM/Contribute/Form/UpdateSubscription.php
422@@ -137,6 +137,8 @@ class CRM_Contribute_Form_UpdateSubscription extends CRM_Contribute_Form_Contrib
423 }
424
425 $this->assign('editableScheduleFields', array_diff($this->editableScheduleFields, $alreadyHardCodedFields));
426+ $this->assign('frequency_unit', $this->_subscriptionDetails->frequency_unit);
427+ $this->assign('frequency_interval', $this->_subscriptionDetails->frequency_interval);
428
429 if ($this->_subscriptionDetails->contact_id) {
430 list($this->_donorDisplayName, $this->_donorEmail) = CRM_Contact_BAO_Contact::getContactDetails($this->_subscriptionDetails->contact_id);
431diff --git a/CRM/Core/BAO/CustomField.php b/CRM/Core/BAO/CustomField.php
432index 6dd3d5b208..56aea513bf 100644
433--- a/CRM/Core/BAO/CustomField.php
434+++ b/CRM/Core/BAO/CustomField.php
435@@ -226,42 +226,42 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField {
436 //CRM-16659: if option_value then create an option group for this custom field.
437 if ($params['option_type'] == 1 && (empty($params['option_group_id']) || !empty($params['option_value']))) {
438 // first create an option group for this custom group
439- $optionGroup = new CRM_Core_DAO_OptionGroup();
440- $optionGroup->name = "{$columnName}_" . date('YmdHis');
441- $optionGroup->title = $params['label'];
442- $optionGroup->is_active = 1;
443- // Don't set reserved as it's not a built-in option group and may be useful for other custom fields.
444- $optionGroup->is_reserved = 0;
445- $optionGroup->data_type = $dataType;
446- $optionGroup->save();
447+ $ogParams = [
448+ 'name' => "{$columnName}_" . date('YmdHis'),
449+ 'title' => $params['label'],
450+ 'is_active' => 1,
451+ 'is_reserved' => 0,
452+ 'data_type' => $dataType,
453+ ];
454+ $optionGroup = CRM_Core_BAO_OptionGroup::add($ogParams);
455 $params['option_group_id'] = $optionGroup->id;
456 if (!empty($params['option_value']) && is_array($params['option_value'])) {
457 foreach ($params['option_value'] as $k => $v) {
458 if (strlen(trim($v))) {
459- $optionValue = new CRM_Core_DAO_OptionValue();
460- $optionValue->option_group_id = $optionGroup->id;
461- $optionValue->label = $params['option_label'][$k];
462- $optionValue->name = CRM_Utils_String::titleToVar($params['option_label'][$k]);
463+ $ovParams = [
464+ 'option_group_id' => $optionGroup->id,
465+ 'label' => $params['option_label'][$k],
466+ 'name' => CRM_Utils_String::titleToVar($params['option_label'][$k]),
467+ 'weight' => $params['option_weight'][$k],
468+ 'is_active' => CRM_Utils_Array::value($k, $params['option_status'], FALSE),
469+ ];
470 switch ($dataType) {
471 case 'Money':
472- $optionValue->value = CRM_Utils_Rule::cleanMoney($v);
473+ $ovParams['value'] = CRM_Utils_Rule::cleanMoney($v);
474 break;
475
476 case 'Int':
477- $optionValue->value = intval($v);
478+ $ovParams['value'] = intval($v);
479 break;
480
481 case 'Float':
482- $optionValue->value = floatval($v);
483+ $ovParams['value'] = floatval($v);
484 break;
485
486 default:
487- $optionValue->value = trim($v);
488+ $ovParams['value'] = trim($v);
489 }
490-
491- $optionValue->weight = $params['option_weight'][$k];
492- $optionValue->is_active = CRM_Utils_Array::value($k, $params['option_status'], FALSE);
493- $optionValue->save();
494+ $optionValue = CRM_Core_BAO_OptionValue::add($ovParams);
495 }
496 }
497 }
498@@ -886,10 +886,17 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField {
499 if (!isset($label)) {
500 $label = $field->label;
501 }
502+ $isPublicCg = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_CustomGroup', $field->custom_group_id, 'is_public');
503+ if (!$isPublicCg && in_array(get_class($qf), ['CRM_Contribute_Form_Contribution_Main', 'CRM_Event_Form_Registration_Register'])) {
504+ $widget = 'hidden';
505+ }
506
507 // at some point in time we might want to split the below into small functions
508-
509 switch ($widget) {
510+ case 'hidden':
511+ $qf->addElement('hidden', $elementName);
512+ break;
513+
514 case 'Text':
515 case 'Link':
516 if ($field->is_search_range && $search && in_array($field->data_type, $rangeDataTypes)) {
517@@ -1157,6 +1164,9 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField {
518 * The field object.
519 */
520 public static function deleteField($field) {
521+ $params = [];
522+ CRM_Utils_Hook::pre('delete', 'CustomField', $field->id, $params);
523+
524 CRM_Utils_System::flushCache();
525
526 // first delete the custom option group and values associated with this field
527@@ -1293,7 +1303,11 @@ class CRM_Core_BAO_CustomField extends CRM_Core_DAO_CustomField {
528 $fileId = $value;
529 }
530 else {
531- $fileId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_File', $value, 'id', 'uri');
532+ $fileId = CRM_Core_DAO::singleValueQuery(
533+ "SELECT cf.id
534+ from civicrm_file cf
535+ LEFT JOIN civicrm_entity_file cef ON cf.id = cef.file_id
536+ WHERE cef.entity_id = {$entityId} AND cf.uri = '{$value}'");
537 }
538 $url = self::getFileURL($entityId, $field['id'], $fileId);
539 if ($url) {
540@@ -1614,6 +1628,12 @@ SELECT id
541 }
542 }
543
544+ if ($customFields[$customFieldId]['html_type'] == 'Radio' && $customFields[$customFieldId]['data_type'] == 'String') {
545+ if (empty($value) && $value !== 0) {
546+ $value = 'null';
547+ }
548+ }
549+
550 if ($customFields[$customFieldId]['html_type'] == 'Multi-Select') {
551 if ($value) {
552 $value = CRM_Utils_Array::implodePadded($value);
553diff --git a/CRM/Core/BAO/CustomGroup.php b/CRM/Core/BAO/CustomGroup.php
554index d20a3188d9..036b939af9 100644
555--- a/CRM/Core/BAO/CustomGroup.php
556+++ b/CRM/Core/BAO/CustomGroup.php
557@@ -1328,6 +1328,8 @@ ORDER BY civicrm_custom_group.weight,
558 * False if field exists for this group, true if group gets deleted.
559 */
560 public static function deleteGroup($group, $force = FALSE) {
561+ $params = [];
562+ CRM_Utils_Hook::pre('delete', 'CustomGroup', $group->id, $params);
563
564 //check whether this contain any custom fields
565 $customField = new CRM_Core_DAO_CustomField();
566diff --git a/CRM/Core/BAO/File.php b/CRM/Core/BAO/File.php
567index c2c06bd279..5e40c8802b 100644
568--- a/CRM/Core/BAO/File.php
569+++ b/CRM/Core/BAO/File.php
570@@ -493,7 +493,7 @@ AND CEF.entity_id = %2";
571 'placeholder' => ts('Description'),
572 ]);
573
574- if (!empty($tags)) {
575+ if (!empty($tags) && CRM_Core_Permission::check('manage tags')) {
576 $form->add('select', "tag_$i", ts('Tags'), $tags, FALSE,
577 [
578 'id' => "tags_$i",
579diff --git a/CRM/Core/BAO/OptionGroup.php b/CRM/Core/BAO/OptionGroup.php
580index ca491c19fc..7c26c2d5fd 100644
581--- a/CRM/Core/BAO/OptionGroup.php
582+++ b/CRM/Core/BAO/OptionGroup.php
583@@ -92,9 +92,13 @@ class CRM_Core_BAO_OptionGroup extends CRM_Core_DAO_OptionGroup {
584 CRM_Core_Error::deprecatedFunctionWarning('no $ids array');
585 $params['id'] = $ids['optionGroup'];
586 }
587+ $op = empty($params['id']) ? 'create' : 'edit';
588+ CRM_Utils_Hook::pre($op, 'OptionGroup', CRM_Utils_Array::value('id', $params), $params);
589+
590 $optionGroup = new CRM_Core_DAO_OptionGroup();
591 $optionGroup->copyValues($params);;
592 $optionGroup->save();
593+ CRM_Utils_Hook::post($op, 'OptionGroup', $optionGroup->id, $optionGroup);
594 return $optionGroup;
595 }
596
597@@ -112,7 +116,10 @@ class CRM_Core_BAO_OptionGroup extends CRM_Core_DAO_OptionGroup {
598
599 $optionGroup = new CRM_Core_DAO_OptionGroup();
600 $optionGroup->id = $optionGroupId;
601+ CRM_Utils_Hook::pre('delete', 'OptionGroup', $optionGroupId);
602+
603 $optionGroup->delete();
604+ CRM_Utils_Hook::post('delete', 'OptionGroup', $optionGroupId);
605 }
606
607 /**
608diff --git a/CRM/Core/BAO/OptionValue.php b/CRM/Core/BAO/OptionValue.php
609index a681756418..a68847c206 100644
610--- a/CRM/Core/BAO/OptionValue.php
611+++ b/CRM/Core/BAO/OptionValue.php
612@@ -171,6 +171,8 @@ class CRM_Core_BAO_OptionValue extends CRM_Core_DAO_OptionValue {
613 */
614 public static function add(&$params, $ids = []) {
615 $id = CRM_Utils_Array::value('id', $params, CRM_Utils_Array::value('optionValue', $ids));
616+ $op = empty($id) ? 'create' : 'edit';
617+ CRM_Utils_Hook::pre($op, 'OptionValue', $id, $params);
618 // CRM-10921: do not reset attributes to default if this is an update
619 //@todo consider if defaults are being set in the right place. 'dumb' defaults like
620 // these would be usefully set @ the api layer so they are visible to api users
621@@ -242,6 +244,7 @@ class CRM_Core_BAO_OptionValue extends CRM_Core_DAO_OptionValue {
622
623 $optionValue->id = $id;
624 $optionValue->save();
625+ CRM_Utils_Hook::post($op, 'OptionValue', $optionValue->id, $optionValue);
626 CRM_Core_PseudoConstant::flush();
627
628 // Create relationship for payment instrument options
629diff --git a/CRM/Core/Payment/PayPalImpl.php b/CRM/Core/Payment/PayPalImpl.php
630index 5b4a109802..37a8ecb377 100644
631--- a/CRM/Core/Payment/PayPalImpl.php
632+++ b/CRM/Core/Payment/PayPalImpl.php
633@@ -463,6 +463,15 @@ class CRM_Core_Payment_PayPalImpl extends CRM_Core_Payment {
634 }
635
636 /**
637+ * Does this payment processor support refund?
638+ *
639+ * @return bool
640+ */
641+ public function supportsRefund() {
642+ return TRUE;
643+ }
644+
645+ /**
646 * Initialise.
647 *
648 * @param $args
649@@ -478,6 +487,41 @@ class CRM_Core_Payment_PayPalImpl extends CRM_Core_Payment {
650 }
651
652 /**
653+ * Submit a refund payment
654+ *
655+ * @throws \Civi\Payment\Exception\PaymentProcessorException
656+ *
657+ * @param array $params
658+ * Assoc array of input parameters for this transaction.
659+ */
660+ public function doRefund(&$params) {
661+ if (empty($params['trxn_id'])) {
662+ throw new \Civi\Payment\Exception\PaymentProcessorException('transaction id not set');
663+ }
664+ $trxnDetails = $this->doQuery($params);
665+
666+ $args = [];
667+ $this->initialize($args, 'RefundTransaction');
668+ $args['amt'] = $params['total_amount'];
669+ $args['REFUNDTYPE'] = ($params['total_amount'] == $trxnDetails['net_amount']) ? 'full' : 'partial';
670+ $args['CURRENCYCODE'] = $params['currency'];
671+ $args['TRANSACTIONID'] = $params['trxn_id'];
672+
673+ $result = $this->invokeAPI($args);
674+ if (is_a($result, 'CRM_Core_Error')) {
675+ return FALSE;
676+ }
677+ $params['trxn_id'] = CRM_Utils_Array::value('refundtransactionid', $result);
678+ $params['fee_amount'] = CRM_Utils_Array::value('feerefundamt', $result);
679+ $params['net_amount'] = CRM_Utils_Array::value('netrefundamt', $result);
680+ /* Success */
681+ if ($result['ack'] == 'Success') {
682+ return TRUE;
683+ }
684+ return FALSE;
685+ }
686+
687+ /**
688 * Process payment - this function wraps around both doTransferCheckout and doDirectPayment.
689 *
690 * The function ensures an exception is thrown & moves some of this logic out of the form layer and makes the forms
691diff --git a/CRM/Dedupe/Finder.php b/CRM/Dedupe/Finder.php
692index 7b6c936e72..9c3a804b6a 100644
693--- a/CRM/Dedupe/Finder.php
694+++ b/CRM/Dedupe/Finder.php
695@@ -281,6 +281,8 @@ class CRM_Dedupe_Finder {
696 if (preg_match('/(.*)-(Primary-[\d+])$|(.*)-(\d+|Primary)$/', $key, $matches)) {
697 $return = array_values(array_filter($matches));
698 $flat[$return[1]] = $value;
699+ // make sure the first occurrence is kept, not the last
700+ $flat[$return[1]] = !isset($flat[$return[1]]) ? $value : $flat[$return[1]];
701 unset($flat[$key]);
702 }
703 }
704diff --git a/CRM/Event/Form/Registration/Register.php b/CRM/Event/Form/Registration/Register.php
705index fd5a218f3e..7d419414ab 100644
706--- a/CRM/Event/Form/Registration/Register.php
707+++ b/CRM/Event/Form/Registration/Register.php
708@@ -294,8 +294,8 @@ class CRM_Event_Form_Registration_Register extends CRM_Event_Form_Registration {
709 CRM_Core_Payment_ProcessorForm::buildQuickForm($this);
710
711 $contactID = $this->getContactID();
712+ $this->assign('contact_id', $contactID);
713 if ($contactID) {
714- $this->assign('contact_id', $contactID);
715 $this->assign('display_name', CRM_Contact_BAO_Contact::displayName($contactID));
716 }
717
718diff --git a/CRM/Event/Form/Search.php b/CRM/Event/Form/Search.php
719index 71e58e1f3f..e639a457a1 100644
720--- a/CRM/Event/Form/Search.php
721+++ b/CRM/Event/Form/Search.php
722@@ -180,7 +180,8 @@ class CRM_Event_Form_Search extends CRM_Core_Form_Search {
723 foreach ((array) $this->_formValues['participant_role_id'] as $participantRole) {
724 $escapedRoles[] = CRM_Utils_Type::escape($participantRole, 'String');
725 }
726- $seatClause[] = "( participant.role_id IN ( '" . implode("' , '", $escapedRoles) . "' ) )";
727+ $escapedRolesRegex = implode('|', $escapedRoles);
728+ $seatClause[] = "( participant.role_id REGEXP '{$escapedRolesRegex}' )";
729 }
730
731 // CRM-15379
732diff --git a/CRM/Event/Form/SelfSvcTransfer.php b/CRM/Event/Form/SelfSvcTransfer.php
733index c3af950956..8c1cea4dff 100644
734--- a/CRM/Event/Form/SelfSvcTransfer.php
735+++ b/CRM/Event/Form/SelfSvcTransfer.php
736@@ -351,8 +351,31 @@ class CRM_Event_Form_SelfSvcTransfer extends CRM_Core_Form {
737 CRM_Core_Error::statusBounce(ts('Contact does not exist.'));
738 }
739 }
740- $from_participant = $params = [];
741- $query = "select role_id, source, fee_level, is_test, is_pay_later, fee_amount, discount_id, fee_currency,campaign_id, discount_amount from civicrm_participant where id = " . $this->_from_participant_id;
742+ self::transferParticipantRegistration($this->_from_participant_id, $contact_id);
743+
744+ $contact_details = CRM_Contact_BAO_Contact::getContactDetails($contact_id);
745+ $display_name = current($contact_details);
746+ $this->assign('to_participant', $display_name);
747+ $this->sendCancellation();
748+ list($displayName, $email) = CRM_Contact_BAO_Contact_Location::getEmailDetails($contact_id);
749+ $statusMsg = ts('Event registration information for %1 has been updated.', [1 => $displayName]);
750+ $statusMsg .= ' ' . ts('A confirmation email has been sent to %1.', [1 => $email]);
751+ CRM_Core_Session::setStatus($statusMsg, ts('Registration Transferred'), 'success');
752+ if ($this->isBackoffice) {
753+ return;
754+ }
755+ $url = CRM_Utils_System::url('civicrm/event/info', "reset=1&id={$this->_event_id}");
756+ CRM_Utils_System::redirect($url);
757+ }
758+
759+ /**
760+ * Move Participant registration to new contact.
761+ *
762+ * @param int $fromParticipantID
763+ * @param int $toContactID
764+ */
765+ public static function transferParticipantRegistration($fromParticipantID, $toContactID) {
766+ $query = "select role_id, source, fee_level, is_test, is_pay_later, fee_amount, discount_id, fee_currency,campaign_id, discount_amount from civicrm_participant where id = " . $fromParticipantID;
767 $dao = CRM_Core_DAO::executeQuery($query);
768 $value_to = [];
769 while ($dao->fetch()) {
770@@ -363,46 +386,36 @@ class CRM_Event_Form_SelfSvcTransfer extends CRM_Core_Form {
771 $value_to['is_pay_later'] = $dao->is_pay_later;
772 $value_to['fee_amount'] = $dao->fee_amount;
773 }
774- $value_to['contact_id'] = $contact_id;
775- $value_to['event_id'] = $this->_event_id;
776+ $value_to['contact_id'] = $toContactID;
777+ $value_to['event_id'] = CRM_Core_DAO::getFieldValue('CRM_Event_BAO_Participant', $fromParticipantID, 'event_id');
778 $value_to['status_id'] = 1;
779 $value_to['register_date'] = date("Y-m-d");
780 //first create the new participant row -don't set registered_by yet or email won't be sent
781 $participant = CRM_Event_BAO_Participant::create($value_to);
782 //send a confirmation email to the new participant
783- $this->participantTransfer($participant);
784+ self::sendConfirmationEmail($participant);
785 //now update registered_by_id
786 $query = "UPDATE civicrm_participant cp SET cp.registered_by_id = %1 WHERE cp.id = ({$participant->id})";
787- $params = [1 => [$this->_from_participant_id, 'Integer']];
788+ $params = [1 => [$fromParticipantID, 'Integer']];
789 $dao = CRM_Core_DAO::executeQuery($query, $params);
790 //copy line items to new participant
791- $line_items = CRM_Price_BAO_LineItem::getLineItems($this->_from_participant_id);
792- foreach ($line_items as $item) {
793+ $line_items = CRM_Price_BAO_LineItem::getLineItems($fromParticipantID);
794+ foreach ($line_items as $id => $item) {
795+ //Remove contribution id from older participant line item.
796+ CRM_Core_DAO::singleValueQuery("UPDATE civicrm_line_item SET contribution_id = NULL WHERE id = %1", [1 => [$id, 'Integer']]);
797 $item['entity_id'] = $participant->id;
798 $item['id'] = NULL;
799 $item['entity_table'] = "civicrm_participant";
800- $new_item = CRM_Price_BAO_LineItem::create($item);
801+ CRM_Price_BAO_LineItem::create($item);
802 }
803+
804 //now cancel the from participant record, leaving the original line-item(s)
805 $value_from = [];
806- $value_from['id'] = $this->_from_participant_id;
807+ $value_from['id'] = $fromParticipantID;
808 $tansferId = array_search('Transferred', CRM_Event_PseudoConstant::participantStatus(NULL, "class = 'Negative'"));
809 $value_from['status_id'] = $tansferId;
810- $value_from['transferred_to_contact_id'] = $contact_id;
811- $contact_details = CRM_Contact_BAO_Contact::getContactDetails($contact_id);
812- $display_name = current($contact_details);
813- $this->assign('to_participant', $display_name);
814+ $value_from['transferred_to_contact_id'] = $toContactID;
815 CRM_Event_BAO_Participant::create($value_from);
816- $this->sendCancellation();
817- list($displayName, $email) = CRM_Contact_BAO_Contact_Location::getEmailDetails($contact_id);
818- $statusMsg = ts('Event registration information for %1 has been updated.', [1 => $displayName]);
819- $statusMsg .= ' ' . ts('A confirmation email has been sent to %1.', [1 => $email]);
820- CRM_Core_Session::setStatus($statusMsg, ts('Registration Transferred'), 'success');
821- if ($this->isBackoffice) {
822- return;
823- }
824- $url = CRM_Utils_System::url('civicrm/event/info', "reset=1&id={$this->_event_id}");
825- CRM_Utils_System::redirect($url);
826 }
827
828 /**
829@@ -410,7 +423,7 @@ class CRM_Event_Form_SelfSvcTransfer extends CRM_Core_Form {
830 *
831 * return @ void
832 */
833- public function participantTransfer($participant) {
834+ public static function sendConfirmationEmail($participant) {
835 $contactDetails = [];
836 $contactIds[] = $participant->contact_id;
837 list($currentContactDetails) = CRM_Utils_Token::getTokenDetails($contactIds, NULL,
838diff --git a/CRM/Event/Form/SelfSvcUpdate.php b/CRM/Event/Form/SelfSvcUpdate.php
839index de7e8090fc..f8aafbddb5 100644
840--- a/CRM/Event/Form/SelfSvcUpdate.php
841+++ b/CRM/Event/Form/SelfSvcUpdate.php
842@@ -283,7 +283,6 @@ class CRM_Event_Form_SelfSvcUpdate extends CRM_Core_Form {
843 * return @void
844 */
845 public function transferParticipant($params) {
846- $isBackOfficeArg = $this->isBackoffice ? '&is_backoffice=1' : '';
847 CRM_Utils_System::redirect(CRM_Utils_System::url(
848 'civicrm/event/selfsvctransfer',
849 [
850@@ -291,6 +290,7 @@ class CRM_Event_Form_SelfSvcUpdate extends CRM_Core_Form {
851 'action' => 'add',
852 'pid' => $this->_participant_id,
853 'cs' => $this->_userChecksum,
854+ 'is_backoffice' => $this->isBackoffice,
855 ]
856 ));
857 }
858diff --git a/CRM/Event/Page/EventInfo.php b/CRM/Event/Page/EventInfo.php
859index 6cdcab5bdd..b6f7d52dc3 100644
860--- a/CRM/Event/Page/EventInfo.php
861+++ b/CRM/Event/Page/EventInfo.php
862@@ -360,7 +360,7 @@ class CRM_Event_Page_EventInfo extends CRM_Core_Page {
863 }
864 $this->assign('location', $values['location']);
865
866- if (CRM_Core_Permission::check('access CiviEvent')) {
867+ if (CRM_Core_Permission::check(array('access CiviCRM', 'access CiviEvent'))) {
868 $enableCart = Civi::settings()->get('enable_cart');
869 $this->assign('manageEventLinks', CRM_Event_Page_ManageEvent::tabs($enableCart));
870 }
871diff --git a/CRM/Financial/BAO/Payment.php b/CRM/Financial/BAO/Payment.php
872index e743d2d796..17102c1118 100644
873--- a/CRM/Financial/BAO/Payment.php
874+++ b/CRM/Financial/BAO/Payment.php
875@@ -307,7 +307,26 @@ class CRM_Financial_BAO_Payment {
876 */
877 public static function recordRefundPayment($contributionId, $trxnData, $updateStatus) {
878 list($contributionDAO, $params) = self::getContributionAndParamsInFormatForRecordFinancialTransaction($contributionId);
879-
880+ $ft = CRM_Core_BAO_FinancialTrxn::getFinancialTrxnId($contributionId);
881+ if (!empty($ft['financialTrxnId'])) {
882+ $defaults = [];
883+ $ftParams = ['id' => $ft['financialTrxnId']];
884+ $financialTrxn = CRM_Core_BAO_FinancialTrxn::retrieve($ftParams, $defaults);
885+ //Refund the payment from the payment processor side.
886+ if (!empty($financialTrxn->payment_processor_id) && !empty($trxnData['processor_refund'])) {
887+ $processor = Civi\Payment\System::singleton()->getById($financialTrxn->payment_processor_id);
888+ if (!empty($params['trxn_id']) && $processor->supports('Refund')) {
889+ $trxnData['trxn_id'] = $params['trxn_id'];
890+ $refundResult = $processor->doRefund($trxnData);
891+ if (!$refundResult) {
892+ return FALSE;
893+ }
894+ $trxnData['payment_processor_id'] = $financialTrxn->payment_processor_id;
895+ $params['card_type_id'] = $trxnData['card_type_id'] = $financialTrxn->card_type_id;
896+ $params['pan_truncation'] = $trxnData['pan_truncation'] = $financialTrxn->pan_truncation;
897+ }
898+ }
899+ }
900 $params['payment_instrument_id'] = CRM_Utils_Array::value('payment_instrument_id', $trxnData, CRM_Utils_Array::value('payment_instrument_id', $params));
901
902 $paidStatus = CRM_Core_PseudoConstant::getKey('CRM_Financial_DAO_FinancialItem', 'status_id', 'Paid');
903@@ -335,7 +354,10 @@ class CRM_Financial_BAO_Payment {
904 if ($lineItemValue['qty'] == 0) {
905 continue;
906 }
907- $paid = $lineItemValue['line_total'] * ($financialTrxn->total_amount / $contributionDAO->total_amount);
908+ $paid = $financialTrxn->total_amount;
909+ if (!empty(floatval($contributionDAO->total_amount))) {
910+ $paid = $lineItemValue['line_total'] * ($financialTrxn->total_amount / $contributionDAO->total_amount);
911+ }
912 $addFinancialEntry = [
913 'transaction_date' => $financialTrxn->trxn_date,
914 'contact_id' => $contributionDAO->contact_id,
915diff --git a/CRM/Financial/Form/PaymentEdit.php b/CRM/Financial/Form/PaymentEdit.php
916index 105b98641c..2a1ea42e92 100644
917--- a/CRM/Financial/Form/PaymentEdit.php
918+++ b/CRM/Financial/Form/PaymentEdit.php
919@@ -253,17 +253,28 @@ class CRM_Financial_Form_PaymentEdit extends CRM_Core_Form {
920 $contributionDAO->id = $contributionID;
921 $contributionDAO->find(TRUE);
922
923- foreach (['trxn_id', 'check_number'] as $fieldName) {
924- if (!empty($params[$fieldName])) {
925- if (!empty($contributionDAO->$fieldName)) {
926- $values = explode(',', $contributionDAO->$fieldName);
927- // if submitted check_number or trxn_id value is
928- // already present then ignore else add to $values array
929- if (!in_array($params[$fieldName], $values)) {
930- $values[] = $params[$fieldName];
931- }
932- $contributionDAO->$fieldName = implode(',', $values);
933+ if (!empty($params['trxn_id'])) {
934+ $financialTrxnDAO = CRM_Core_DAO::executeQuery("SELECT trxn_id
935+ FROM civicrm_financial_trxn cft
936+ LEFT JOIN civicrm_entity_financial_trxn ceft
937+ ON ceft.financial_trxn_id = cft.id AND ceft.entity_table = 'civicrm_contribution'
938+ WHERE entity_id = {$contributionID}");
939+ $trxnIds = array();
940+ while ($financialTrxnDAO->fetch()) {
941+ $trxnIds[] = $financialTrxnDAO->trxn_id;
942+ }
943+ $contributionDAO->trxn_id = implode(',', $trxnIds);
944+ }
945+
946+ if (!empty($params['check_number'])) {
947+ if (!empty($contributionDAO->check_number)) {
948+ $values = explode(',', $contributionDAO->check_number);
949+ // if submitted check_number or trxn_id value is
950+ // already present then ignore else add to $values array
951+ if (!in_array($params['check_number'], $values)) {
952+ $values[] = $params['check_number'];
953 }
954+ $contributionDAO->check_number = implode(',', $values);
955 }
956 }
957
958diff --git a/CRM/Member/BAO/Membership.php b/CRM/Member/BAO/Membership.php
959index 49e5181b8b..fa7ebadd2d 100644
960--- a/CRM/Member/BAO/Membership.php
961+++ b/CRM/Member/BAO/Membership.php
962@@ -2272,7 +2272,7 @@ WHERE civicrm_membership.is_test = 0
963 self::processOverriddenUntilDateMembership($dao1);
964 }
965
966- $query = $baseQuery . " AND (civicrm_membership.is_override = 0 OR civicrm_membership.is_override IS NULL)
967+ $query = $baseQuery . " AND (civicrm_membership.is_override = 0 OR civicrm_membership.is_override IS NULL)
968 AND civicrm_membership.status_id NOT IN (%1, %2, %3, %4)
969 AND civicrm_membership.owner_membership_id IS NULL ";
970 $params = array(
971diff --git a/CRM/Member/Form/Membership.php b/CRM/Member/Form/Membership.php
972index ec39152a44..f94b17d645 100644
973--- a/CRM/Member/Form/Membership.php
974+++ b/CRM/Member/Form/Membership.php
975@@ -213,9 +213,7 @@ class CRM_Member_Form_Membership extends CRM_Member_Form {
976 // This string makes up part of the class names, differentiating them (not sure why) from the membership fields.
977 $this->assign('formClass', 'membership');
978 parent::preProcess();
979- if ($this->isUpdateToExistingRecurringMembership()) {
980- $this->entityFields['end_date']['is_freeze'] = TRUE;
981- }
982+
983 // get price set id.
984 $this->_priceSetId = CRM_Utils_Array::value('priceSetId', $_GET);
985 $this->set('priceSetId', $this->_priceSetId);
986diff --git a/CRM/PCP/Form/PCPAccount.php b/CRM/PCP/Form/PCPAccount.php
987index ccac09cf54..8313cfb7c6 100644
988--- a/CRM/PCP/Form/PCPAccount.php
989+++ b/CRM/PCP/Form/PCPAccount.php
990@@ -266,7 +266,9 @@ class CRM_PCP_Form_PCPAccount extends CRM_Core_Form {
991 }
992 }
993
994- $this->_contactID = CRM_Contact_BAO_Contact::getFirstDuplicateContact($params, 'Individual', 'Unsupervised', [], FALSE);
995+ if (!$this->_id || !$this->_contactID) {
996+ $this->_contactID = CRM_Contact_BAO_Contact::getFirstDuplicateContact($params, 'Individual', 'Unsupervised', array(), FALSE);
997+ }
998
999 $contactID = CRM_Contact_BAO_Contact::createProfileContact($params, $this->_fields, $this->_contactID);
1000 $this->set('contactID', $contactID);
1001diff --git a/CRM/Pledge/BAO/PledgeBlock.php b/CRM/Pledge/BAO/PledgeBlock.php
1002index 732a61a450..f0bd39b013 100644
1003--- a/CRM/Pledge/BAO/PledgeBlock.php
1004+++ b/CRM/Pledge/BAO/PledgeBlock.php
1005@@ -219,7 +219,7 @@ class CRM_Pledge_BAO_PledgeBlock extends CRM_Pledge_DAO_PledgeBlock {
1006 'scheduled_amount' => CRM_Utils_Rule::cleanMoney($value['scheduled_amount']),
1007 'scheduled_amount_currency' => $value['currency'],
1008 'scheduled_date' => CRM_Utils_Date::customFormat($value['scheduled_date'],
1009- '%B %d'
1010+ '%B %d %Y'
1011 ),
1012 );
1013 }
1014@@ -232,7 +232,7 @@ class CRM_Pledge_BAO_PledgeBlock extends CRM_Pledge_DAO_PledgeBlock {
1015 'scheduled_amount' => CRM_Utils_Rule::cleanMoney($value['scheduled_amount']),
1016 'scheduled_amount_currency' => $value['currency'],
1017 'scheduled_date' => CRM_Utils_Date::customFormat($value['scheduled_date'],
1018- '%B %d'
1019+ '%B %d %Y'
1020 ),
1021 );
1022 $isNextPayment = TRUE;
1023diff --git a/CRM/SMS/Provider.php b/CRM/SMS/Provider.php
1024index da800cb497..9b1e1d85e3 100644
1025--- a/CRM/SMS/Provider.php
1026+++ b/CRM/SMS/Provider.php
1027@@ -226,10 +226,8 @@ INNER JOIN civicrm_mailing_job mj ON mj.mailing_id = m.id AND mj.id = %1";
1028 // unknown mobile sender -- create new contact
1029 // use fake @mobile.sms email address for new contact since civi
1030 // requires email or name for all contacts
1031- $locationTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id');
1032- $phoneTypes = CRM_Core_PseudoConstant::get('CRM_Core_DAO_Phone', 'phone_type_id');
1033- $phoneloc = array_search('Home', $locationTypes);
1034- $phonetype = array_search('Mobile', $phoneTypes);
1035+ $phoneloc = CRM_Core_PseudoConstant::getKey('CRM_Core_BAO_Address', 'location_type_id', 'Home');
1036+ $phonetype = CRM_Core_PseudoConstant::getKey('CRM_Core_BAO_Phone', 'phone_type_id', 'Mobile');
1037 $stripFrom = $this->stripPhone($message->from);
1038 $contactparams = array(
1039 'contact_type' => 'Individual',
1040diff --git a/ang/crmMailing/Recipients.js b/ang/crmMailing/Recipients.js
1041index 4203d4a3c8..bdf142b648 100644
1042--- a/ang/crmMailing/Recipients.js
1043+++ b/ang/crmMailing/Recipients.js
1044@@ -36,7 +36,7 @@
1045 // @param string id an encoded string like "4 civicrm_mailing include"
1046 // @return Object keys: entity_id, entity_type, mode
1047 function convertValueToObj(id) {
1048- var a = id.split(" ");
1049+ var a = id.toString().split(" ");
1050 return {entity_id: parseInt(a[0]), entity_type: a[1], mode: a[2]};
1051 }
1052
1053diff --git a/api/v3/Contact.php b/api/v3/Contact.php
1054index c493cad4c8..2e0d9e83f9 100644
1055--- a/api/v3/Contact.php
1056+++ b/api/v3/Contact.php
1057@@ -1280,11 +1280,15 @@ function _civicrm_api3_contact_getmergedto($params) {
1058 ],
1059 ])['values'];
1060 if (!empty($deleteActivity)) {
1061- $contactID = civicrm_api3('ActivityContact', 'getvalue', [
1062- 'activity_id' => $deleteActivity[0]['activity_id.parent_id'],
1063- 'record_type_id' => 'Activity Targets',
1064- 'return' => 'contact_id',
1065- ]);
1066+ try {
1067+ $contactID = civicrm_api3('ActivityContact', 'getvalue', [
1068+ 'activity_id' => $deleteActivity[0]['activity_id.parent_id'],
1069+ 'record_type_id' => 'Activity Targets',
1070+ 'return' => 'contact_id',
1071+ ]);
1072+ }
1073+ catch (CiviCRM_API3_Exception $e) {
1074+ }
1075 }
1076 return $contactID;
1077 }
1078diff --git a/templates/CRM/Contribute/Form/AdditionalPayment.tpl b/templates/CRM/Contribute/Form/AdditionalPayment.tpl
1079index 23443f10fd..a070d4d78b 100644
1080--- a/templates/CRM/Contribute/Form/AdditionalPayment.tpl
1081+++ b/templates/CRM/Contribute/Form/AdditionalPayment.tpl
1082@@ -112,6 +112,12 @@
1083 <span class="description">{ts}Processing fee for this transaction (if applicable).{/ts}</span></td></tr>
1084 <tr class="crm-payment-form-block-net_amount"><td class="label">{$form.net_amount.label}</td><td>{$form.net_amount.html|crmMoney:$currency:'':1}<br />
1085 <span class="description">{ts}Net value of the payment (Total Amount minus Fee).{/ts}</span></td></tr>
1086+ {if $processorRefund}
1087+ <tr class="crm-payment-form-block-processor_refund">
1088+ <td class="label">{$form.processor_refund.label}</td>
1089+ <td>{$form.processor_refund.html}</td>
1090+ </tr>
1091+ {/if}
1092 </table>
1093 </div>
1094 {/if}
1095diff --git a/templates/CRM/Contribute/Form/UpdateSubscription.tpl b/templates/CRM/Contribute/Form/UpdateSubscription.tpl
1096index 3e45a885a5..6c8ba57120 100644
1097--- a/templates/CRM/Contribute/Form/UpdateSubscription.tpl
1098+++ b/templates/CRM/Contribute/Form/UpdateSubscription.tpl
1099@@ -52,7 +52,8 @@
1100 {/if}
1101 </table>
1102
1103- {include file="CRM/common/customDataBlock.tpl"}
1104-
1105+ {if call_user_func(array('CRM_Core_Permission','check'), 'access CiviCRM')}
1106+ {include file="CRM/common/customDataBlock.tpl"}
1107+ {/if}
1108 <div class="crm-submit-buttons">{include file="CRM/common/formButtons.tpl" location="bottom"}</div>
1109 </div>
1110diff --git a/templates/CRM/Event/Form/Registration/Register.tpl b/templates/CRM/Event/Form/Registration/Register.tpl
1111index 756d377dff..7429f8e5a0 100644
1112--- a/templates/CRM/Event/Form/Registration/Register.tpl
1113+++ b/templates/CRM/Event/Form/Registration/Register.tpl
1114@@ -68,7 +68,10 @@
1115 <div class="crm-public-form-item crm-section additional_participants-section" id="noOfparticipants">
1116 <div class="label">{$form.additional_participants.label} <span class="crm-marker" title="{ts}This field is required.{/ts}">*</span></div>
1117 <div class="content">
1118- {$form.additional_participants.html}{if $contact_id || $contact_id == NULL}{ts}(including yourself){/ts}{/if}
1119+ {$form.additional_participants.html}
1120+ {if ($contact_id || $contact_id == NULL) && $contact_id != '0'}
1121+ {ts}(including yourself){/ts}
1122+ {/if}
1123 <br/>
1124 <span
1125 class="description">{ts}Fill in your registration information on this page. If you are registering additional people, you will be able to enter their registration information after you complete this page and click "Continue".{/ts}</span>