Merge pull request #21665 from civicrm/5.42
[civicrm-core.git] / CRM / Member / Form / MembershipView.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
5 | |
6 | This work is published under the GNU AGPLv3 license with some |
7 | permitted exceptions and without any warranty. For full license |
8 | and copyright information, see https://civicrm.org/licensing |
9 +--------------------------------------------------------------------+
10 */
11
12 /**
13 *
14 * @package CRM
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
16 */
17
18 /**
19 * This class generates form components for Payment-Instrument
20 */
21 class CRM_Member_Form_MembershipView extends CRM_Core_Form {
22
23 /**
24 * The action links that we need to display for the browse screen.
25 *
26 * @var array
27 */
28 public static $_links = NULL;
29
30 /**
31 * The id of the membership being viewed.
32 *
33 * @var int
34 */
35 private $membershipID;
36
37 /**
38 * Contact's ID.
39 *
40 * @var int
41 */
42 private $contactID;
43
44 /**
45 * Add context information at the end of a link.
46 *
47 * @return string
48 * extra query parameters
49 */
50 public function addContext() {
51 $extra = '';
52 foreach (['context', 'selectedChild'] as $arg) {
53 if ($value = CRM_Utils_Request::retrieve($arg, 'String', $this)) {
54 $extra .= "&{$arg}={$value}";
55 }
56 }
57 return $extra;
58 }
59
60 /**
61 * Get action Links.
62 *
63 * @return array
64 * (reference) of action links
65 */
66 public function &links() {
67 if (!(self::$_links)) {
68 self::$_links = [
69 CRM_Core_Action::DELETE => [
70 'name' => ts('Delete'),
71 'url' => 'civicrm/contact/view/membership',
72 'qs' => 'action=view&id=%%id%%&cid=%%cid%%&relAction=delete&mid=%%mid%%&reset=1' . $this->addContext(),
73 'title' => ts('Cancel Related Membership'),
74 ],
75 CRM_Core_Action::ADD => [
76 'name' => ts('Create'),
77 'url' => 'civicrm/contact/view/membership',
78 'qs' => 'action=view&id=%%id%%&cid=%%cid%%&relAction=create&rid=%%rid%%&reset=1' . $this->addContext(),
79 'title' => ts('Create Related Membership'),
80 ],
81 ];
82 }
83 return self::$_links;
84 }
85
86 /**
87 * Perform create or delete action on related memberships.
88 *
89 * @param string $action
90 * Create or delete.
91 * @param array $owner
92 * Primary membership info (membership_id, contact_id, membership_type ...).
93 *
94 * @throws \CRM_Core_Exception
95 * @throws \CiviCRM_API3_Exception
96 */
97 public function relAction($action, $owner) {
98 switch ($action) {
99 case 'delete':
100 $id = CRM_Utils_Request::retrieve('mid', 'Positive', $this);
101 $relatedContactId = CRM_Utils_Request::retrieve('cid', 'Positive', $this);
102 $relatedDisplayName = CRM_Contact_BAO_Contact::displayName($relatedContactId);
103 CRM_Member_BAO_Membership::del($id);
104 CRM_Core_Session::setStatus(ts('Related membership for %1 has been deleted.', [1 => $relatedDisplayName]),
105 ts('Membership Deleted'), 'success');
106 break;
107
108 case 'create':
109 $params = [
110 'contact_id' => CRM_Utils_Request::retrieve('rid', 'Positive', $this),
111 'membership_type_id' => $owner['membership_type_id'],
112 'owner_membership_id' => $owner['id'],
113 'join_date' => CRM_Utils_Date::processDate($owner['join_date'], NULL, TRUE, 'Ymd'),
114 'start_date' => CRM_Utils_Date::processDate($owner['start_date'], NULL, TRUE, 'Ymd'),
115 'end_date' => CRM_Utils_Date::processDate($owner['end_date'], NULL, TRUE, 'Ymd'),
116 'source' => ts('Manual Assignment of Related Membership'),
117 'is_test' => $owner['is_test'],
118 'campaign_id' => $owner['campaign_id'] ?? NULL,
119 'status_id' => $owner['status_id'],
120 'skipStatusCal' => TRUE,
121 'createActivity' => TRUE,
122 ];
123 CRM_Member_BAO_Membership::create($params);
124 $relatedDisplayName = CRM_Contact_BAO_Contact::displayName($params['contact_id']);
125 CRM_Core_Session::setStatus(ts('Related membership for %1 has been created.', [1 => $relatedDisplayName]),
126 ts('Membership Added'), 'success');
127 break;
128
129 default:
130 throw new CRM_Core_Exception(ts('Invalid action specified in URL'));
131 }
132
133 // Redirect back to membership view page for the owner, without the relAction parameters
134 CRM_Utils_System::redirect(
135 CRM_Utils_System::url(
136 'civicrm/contact/view/membership',
137 "action=view&reset=1&id={$owner['membership_id']}&cid={$owner['contact_id']}" . $this->addContext()
138 )
139 );
140 }
141
142 /**
143 * Set variables up before form is built.
144 *
145 * @return void
146 */
147 public function preProcess() {
148 $values = [];
149 $this->membershipID = CRM_Utils_Request::retrieve('id', 'Positive', $this);
150 $this->contactID = CRM_Utils_Request::retrieve('cid', 'Positive', $this);
151
152 // Make sure context is assigned to template for condition where we come here view civicrm/membership/view
153 $context = CRM_Utils_Request::retrieve('context', 'Alphanumeric', $this);
154 $this->assign('context', $context);
155
156 if ($this->membershipID) {
157 $params = ['id' => $this->membershipID];
158 CRM_Member_BAO_Membership::retrieve($params, $values);
159 if (CRM_Financial_BAO_FinancialType::isACLFinancialTypeStatus()) {
160 $finTypeId = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_MembershipType', $values['membership_type_id'], 'financial_type_id');
161 $finType = CRM_Contribute_PseudoConstant::financialType($finTypeId);
162 if (!CRM_Core_Permission::check('view contributions of type ' . $finType)) {
163 CRM_Core_Error::statusBounce(ts('You do not have permission to access this page.'));
164 }
165 }
166 else {
167 $this->assign('noACL', TRUE);
168 }
169 $membershipType = CRM_Member_BAO_MembershipType::getMembershipTypeDetails($values['membership_type_id']);
170
171 // Do the action on related Membership if needed
172 $relAction = CRM_Utils_Request::retrieve('relAction', 'String', $this);
173 if ($relAction) {
174 $this->relAction($relAction, $values);
175 }
176
177 // build associated contributions
178 $this->assign('accessContribution', FALSE);
179 if (CRM_Core_Permission::access('CiviContribute')) {
180 $this->assign('accessContribution', TRUE);
181 CRM_Member_Page_Tab::associatedContribution($values['contact_id'], $this->membershipID);
182 }
183
184 //Provide information about membership source when it is the result of a relationship (CRM-1901)
185 $values['owner_membership_id'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership',
186 $this->membershipID,
187 'owner_membership_id'
188 );
189
190 if (isset($values['owner_membership_id'])) {
191 $values['owner_contact_id'] = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership',
192 $values['owner_membership_id'],
193 'contact_id',
194 'id'
195 );
196
197 $values['owner_display_name'] = CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_Contact',
198 $values['owner_contact_id'],
199 'display_name',
200 'id'
201 );
202
203 $direction = strrev($membershipType['relationship_direction']);
204 // To display relationship type in view membership page
205 $relTypeIds = str_replace(CRM_Core_DAO::VALUE_SEPARATOR, ",", $membershipType['relationship_type_id']);
206 $sql = "
207 SELECT relationship_type_id,
208 CASE
209 WHEN contact_id_a = {$values['owner_contact_id']} AND contact_id_b = {$values['contact_id']} THEN 'b_a'
210 WHEN contact_id_b = {$values['owner_contact_id']} AND contact_id_a = {$values['contact_id']} THEN 'a_b'
211 END AS 'relType'
212 FROM civicrm_relationship
213 WHERE relationship_type_id IN ($relTypeIds)";
214 $dao = CRM_Core_DAO::executeQuery($sql);
215 $values['relationship'] = NULL;
216 while ($dao->fetch()) {
217 $typeId = $dao->relationship_type_id;
218 $direction = $dao->relType;
219 if ($direction && $typeId) {
220 if ($values['relationship']) {
221 $values['relationship'] .= ',';
222 }
223 $values['relationship'] .= CRM_Core_DAO::getFieldValue('CRM_Contact_DAO_RelationshipType',
224 $typeId,
225 "name_$direction",
226 'id'
227 );
228 }
229 }
230 }
231
232 $this->assign('has_related', FALSE);
233 // if membership can be granted, and we are the owner of the membership
234 if (!empty($membershipType['relationship_type_id']) && empty($values['owner_membership_id'])) {
235 // display related contacts/membership block
236 $this->assign('has_related', TRUE);
237 $this->assign('max_related', CRM_Utils_Array::value('max_related', $values, ts('Unlimited')));
238 // split the relations in 2 arrays based on direction
239 $relTypeId = explode(CRM_Core_DAO::VALUE_SEPARATOR, $membershipType['relationship_type_id']);
240 $relDirection = explode(CRM_Core_DAO::VALUE_SEPARATOR, $membershipType['relationship_direction']);
241 foreach ($relTypeId as $rid) {
242 $relTypeDir[substr($relDirection[0], 0, 1)][] = $rid;
243 }
244 // build query in 2 parts with a UNION if necessary
245 // _x and _y are replaced with _a and _b first, then vice-versa
246 // comment is a qualifier for the relationship - now just job_title
247 $select = "
248 SELECT r.id, c.id as cid, c.display_name as name, c.job_title as comment,
249 rt.name_x_y as relation, r.start_date, r.end_date,
250 m.id as mid, ms.is_current_member, ms.label as status
251 FROM civicrm_relationship r
252 LEFT JOIN civicrm_relationship_type rt ON rt.id = r.relationship_type_id
253 LEFT JOIN civicrm_contact c ON c.id = r.contact_id_x
254 LEFT JOIN civicrm_membership m ON (m.owner_membership_id = {$values['id']}
255 AND m.contact_id = r.contact_id_x AND m.is_test = 0)
256 LEFT JOIN civicrm_membership_status ms ON ms.id = m.status_id
257 WHERE r.contact_id_y = {$values['contact_id']} AND r.is_active = 1 AND c.is_deleted = 0";
258 $query = '';
259 foreach (['a', 'b'] as $dir) {
260 if (isset($relTypeDir[$dir])) {
261 $query .= ($query ? ' UNION ' : '')
262 . str_replace('_y', '_' . $dir, str_replace('_x', '_' . ($dir == 'a' ? 'b' : 'a'), $select))
263 . ' AND r.relationship_type_id IN (' . implode(',', $relTypeDir[$dir]) . ')';
264 }
265 }
266 $query .= " ORDER BY is_current_member DESC";
267 $dao = CRM_Core_DAO::executeQuery($query);
268 $related = [];
269 $relatedRemaining = CRM_Utils_Array::value('max_related', $values, PHP_INT_MAX);
270 $rowElememts = [
271 'id',
272 'cid',
273 'name',
274 'comment',
275 'relation',
276 'mid',
277 'start_date',
278 'end_date',
279 'is_current_member',
280 'status',
281 ];
282
283 while ($dao->fetch()) {
284 $row = [];
285 foreach ($rowElememts as $field) {
286 $row[$field] = $dao->$field;
287 }
288 if ($row['mid'] && ($row['is_current_member'] == 1)) {
289 $relatedRemaining--;
290 $row['action'] = CRM_Core_Action::formLink(self::links(), CRM_Core_Action::DELETE,
291 [
292 'id' => CRM_Utils_Request::retrieve('id', 'Positive', $this),
293 'cid' => $row['cid'],
294 'mid' => $row['mid'],
295 ],
296 ts('more'),
297 FALSE,
298 'membership.relationship.action',
299 'Relationship',
300 CRM_Utils_Request::retrieve('id', 'Positive', $this)
301 );
302 }
303 else {
304 if ($relatedRemaining > 0) {
305 $row['action'] = CRM_Core_Action::formLink(self::links(), CRM_Core_Action::ADD,
306 [
307 'id' => CRM_Utils_Request::retrieve('id', 'Positive', $this),
308 'cid' => $row['cid'],
309 'rid' => $row['cid'],
310 ],
311 ts('more'),
312 FALSE,
313 'membership.relationship.action',
314 'Relationship',
315 CRM_Utils_Request::retrieve('id', 'Positive', $this)
316 );
317 }
318 }
319 $related[] = $row;
320 }
321 $this->assign('related', $related);
322 if ($relatedRemaining <= 0) {
323 $this->assign('related_text', ts('None available'));
324 }
325 else {
326 if ($relatedRemaining < 100000) {
327 $this->assign('related_text', ts('%1 available', [1 => $relatedRemaining]));
328 }
329 else {
330 $this->assign('related_text', ts('Unlimited', [1 => $relatedRemaining]));
331 }
332 }
333 }
334
335 $displayName = CRM_Contact_BAO_Contact::displayName($values['contact_id']);
336 $this->assign('displayName', $displayName);
337
338 // Check if this is default domain contact CRM-10482
339 if (CRM_Contact_BAO_Contact::checkDomainContact($values['contact_id'])) {
340 $displayName .= ' (' . ts('default organization') . ')';
341 }
342
343 // omitting contactImage from title for now since the summary overlay css doesn't work outside crm-container
344 $this->setTitle(ts('View Membership for') . ' ' . $displayName);
345
346 // add viewed membership to recent items list
347 $recentTitle = $displayName . ' - ' . ts('Membership Type:') . ' ' . $values['membership_type'];
348 $url = CRM_Utils_System::url('civicrm/contact/view/membership',
349 "action=view&reset=1&id={$values['id']}&cid={$values['contact_id']}&context=home"
350 );
351
352 $recentOther = [];
353 if (CRM_Core_Permission::checkActionPermission('CiviMember', CRM_Core_Action::UPDATE)) {
354 $recentOther['editUrl'] = CRM_Utils_System::url('civicrm/contact/view/membership',
355 "action=update&reset=1&id={$values['id']}&cid={$values['contact_id']}&context=home"
356 );
357 }
358 if (CRM_Core_Permission::checkActionPermission('CiviMember', CRM_Core_Action::DELETE)) {
359 $recentOther['deleteUrl'] = CRM_Utils_System::url('civicrm/contact/view/membership',
360 "action=delete&reset=1&id={$values['id']}&cid={$values['contact_id']}&context=home"
361 );
362 }
363 CRM_Utils_Recent::add($recentTitle,
364 $url,
365 $values['id'],
366 'Membership',
367 $values['contact_id'],
368 NULL,
369 $recentOther
370 );
371
372 CRM_Member_Page_Tab::setContext($this, $values['contact_id']);
373
374 $memType = CRM_Core_DAO::getFieldValue("CRM_Member_DAO_Membership", $this->membershipID, "membership_type_id");
375
376 $groupTree = CRM_Core_BAO_CustomGroup::getTree('Membership', NULL, $this->membershipID, 0, $memType, NULL,
377 TRUE, NULL, FALSE, CRM_Core_Permission::VIEW);
378 CRM_Core_BAO_CustomGroup::buildCustomDataView($this, $groupTree, FALSE, NULL, NULL, NULL, $this->membershipID);
379
380 $isRecur = CRM_Core_DAO::getFieldValue('CRM_Member_DAO_Membership', $this->membershipID, 'contribution_recur_id');
381
382 $autoRenew = (bool) $isRecur;
383 }
384
385 if (!empty($values['is_test'])) {
386 $values['membership_type'] = CRM_Core_TestEntity::appendTestText($values['membership_type']);
387 }
388
389 $subscriptionCancelled = CRM_Member_BAO_Membership::isSubscriptionCancelled($this->membershipID);
390 $values['auto_renew'] = ($autoRenew && !$subscriptionCancelled) ? 'Yes' : 'No';
391
392 //do check for campaigns
393 if ($campaignId = CRM_Utils_Array::value('campaign_id', $values)) {
394 $campaigns = CRM_Campaign_BAO_Campaign::getCampaigns($campaignId);
395 $values['campaign'] = $campaigns[$campaignId];
396 }
397
398 $this->assign($values);
399 }
400
401 /**
402 * Build the form object.
403 *
404 * @return void
405 */
406 public function buildQuickForm() {
407 $this->addButtons([
408 [
409 'type' => 'cancel',
410 'name' => ts('Done'),
411 'spacing' => '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;',
412 'isDefault' => TRUE,
413 ],
414 ]);
415 }
416
417 }