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