Merge pull request #22957 from colemanw/afformClearCache
[civicrm-core.git] / CRM / Report / Form / Member / Summary.php
CommitLineData
6a488035 1<?php
6a488035
TO
2/*
3 +--------------------------------------------------------------------+
bc77d7c0 4 | Copyright CiviCRM LLC. All rights reserved. |
6a488035 5 | |
bc77d7c0
TO
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 |
6a488035 9 +--------------------------------------------------------------------+
d25dd0ee 10 */
6a488035
TO
11
12/**
13 *
14 * @package CRM
ca5cec67 15 * @copyright CiviCRM LLC https://civicrm.org/licensing
6a488035
TO
16 */
17class CRM_Report_Form_Member_Summary extends CRM_Report_Form {
18
19 protected $_summary = NULL;
20 protected $_interval = NULL;
f787b3c4 21
6a488035
TO
22 protected $_add2groupSupported = FALSE;
23
be2fb01f 24 protected $_customGroupExtends = ['Membership'];
f813f78e 25 protected $_customGroupGroupBy = FALSE;
be2fb01f 26 public $_drilldownReport = ['member/detail' => 'Link to Detail Report'];
6a488035 27
74cf4551 28 /**
1728e9a0 29 * This report has not been optimised for group filtering.
30 *
31 * The functionality for group filtering has been improved but not
32 * all reports have been adjusted to take care of it. This report has not
33 * and will run an inefficient query until fixed.
34 *
1728e9a0 35 * @var bool
0e480632 36 * @see https://issues.civicrm.org/jira/browse/CRM-19170
74cf4551 37 */
1728e9a0 38 protected $groupFilterNotOptimised = TRUE;
39
74cf4551 40 /**
73b448bf 41 * Class constructor.
74cf4551 42 */
00be9182 43 public function __construct() {
be2fb01f
CW
44 $this->_columns = [
45 'civicrm_membership' => [
67bded5c 46 'dao' => 'CRM_Member_DAO_Membership',
6a488035 47 'grouping' => 'member-fields',
be2fb01f
CW
48 'fields' => [
49 'membership_type_id' => [
ccc29f8e 50 'title' => ts('Membership Type'),
6a488035 51 'required' => TRUE,
be2fb01f
CW
52 ],
53 ],
54 'filters' => [
bca8f840 55 'membership_join_date' => [
9d72cede 56 'title' => ts('Member Since'),
6a488035
TO
57 'type' => CRM_Utils_Type::T_DATE,
58 'operatorType' => CRM_Report_Form::OP_DATE,
be2fb01f
CW
59 ],
60 'membership_start_date' => [
6a488035
TO
61 'name' => 'start_date',
62 'title' => ts('Membership Start Date'),
63 'type' => CRM_Utils_Type::T_DATE,
64 'operatorType' => CRM_Report_Form::OP_DATE,
be2fb01f
CW
65 ],
66 'membership_end_date' => [
6a488035
TO
67 'name' => 'end_date',
68 'title' => ts('Membership End Date'),
69 'type' => CRM_Utils_Type::T_DATE,
70 'operatorType' => CRM_Report_Form::OP_DATE,
be2fb01f
CW
71 ],
72 'owner_membership_id' => [
455a0d0e 73 'title' => ts('Primary Membership'),
8043337a 74 'type' => CRM_Utils_Type::T_INT,
5a9a44d9 75 'operatorType' => CRM_Report_Form::OP_INT,
be2fb01f
CW
76 ],
77 'membership_type_id' => [
9d72cede 78 'title' => ts('Membership Type'),
8ee006e7 79 'type' => CRM_Utils_Type::T_INT,
6a488035
TO
80 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
81 'options' => CRM_Member_PseudoConstant::membershipType(),
be2fb01f
CW
82 ],
83 'status_id' => [
9d72cede 84 'title' => ts('Membership Status'),
8ee006e7 85 'type' => CRM_Utils_Type::T_INT,
6a488035
TO
86 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
87 'options' => CRM_Member_PseudoConstant::membershipStatus(NULL, NULL, 'label'),
be2fb01f
CW
88 ],
89 ],
90 'group_bys' => [
91 'join_date' => [
9d72cede 92 'title' => ts('Member Since'),
6a488035
TO
93 'default' => TRUE,
94 'frequency' => TRUE,
95 'chart' => TRUE,
96 'type' => 12,
be2fb01f
CW
97 ],
98 'membership_type_id' => [
ccc29f8e 99 'title' => ts('Membership Type'),
6a488035
TO
100 'default' => TRUE,
101 'chart' => TRUE,
be2fb01f
CW
102 ],
103 ],
104 ],
105 'civicrm_contact' => [
6a488035 106 'dao' => 'CRM_Contact_DAO_Contact',
be2fb01f
CW
107 'fields' => [
108 'contact_id' => [
6a488035 109 'no_display' => TRUE,
be2fb01f
CW
110 ],
111 'contact_type' => [
30f85891 112 'title' => ts('Contact Type'),
be2fb01f
CW
113 ],
114 'contact_sub_type' => [
b8f96eb8 115 'title' => ts('Contact Subtype'),
be2fb01f
CW
116 ],
117 ],
118 ],
119 'civicrm_contribution' => [
6a488035 120 'dao' => 'CRM_Contribute_DAO_Contribution',
be2fb01f
CW
121 'fields' => [
122 'currency' => [
9d72cede 123 'required' => TRUE,
35d8497b 124 'no_display' => TRUE,
be2fb01f
CW
125 ],
126 'total_amount' => [
9d72cede 127 'title' => ts('Amount Statistics'),
1c786c96 128 'default' => TRUE,
be2fb01f 129 'statistics' => [
9d72cede 130 'sum' => ts('Total Payments Made'),
6a488035
TO
131 'count' => ts('Contribution Count'),
132 'avg' => ts('Average'),
be2fb01f
CW
133 ],
134 ],
135 ],
136 'filters' => [
137 'currency' => [
ccc29f8e 138 'title' => ts('Currency'),
35d8497b 139 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
140 'options' => CRM_Core_OptionGroup::values('currencies_enabled'),
d1b0931b 141 'default' => NULL,
35d8497b 142 'type' => CRM_Utils_Type::T_STRING,
be2fb01f
CW
143 ],
144 'contribution_status_id' => [
9d72cede 145 'title' => ts('Contribution Status'),
6a488035 146 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
c0aaecf9 147 'options' => CRM_Contribute_BAO_Contribution::buildOptions('contribution_status_id', 'search'),
be2fb01f
CW
148 ],
149 ],
6a488035 150 'grouping' => 'member-fields',
be2fb01f
CW
151 ],
152 ];
6a488035 153 $this->_tagFilter = TRUE;
f813f78e 154
a5f92eba 155 // If we have campaigns enabled, add those elements to both the fields, filters and group by
156 $this->addCampaignFields('civicrm_membership', TRUE);
f813f78e 157
f787b3c4
BT
158 // Add charts support
159 $this->_charts = [
160 '' => ts('Tabular'),
161 'barChart' => ts('Bar Chart'),
162 'pieChart' => ts('Pie Chart'),
163 ];
164
6a488035 165 $this->_groupFilter = TRUE;
35d8497b 166 $this->_currencyColumn = 'civicrm_contribution_currency';
6a488035
TO
167 parent::__construct();
168 }
169
00be9182 170 public function select() {
be2fb01f 171 $select = [];
6a488035 172 $groupBys = FALSE;
be2fb01f 173 $this->_columnHeaders = [];
6a488035
TO
174 $select[] = " COUNT( DISTINCT {$this->_aliases['civicrm_membership']}.id ) as civicrm_membership_member_count";
175 $select['joinDate'] = " {$this->_aliases['civicrm_membership']}.join_date as civicrm_membership_member_join_date";
be2fb01f 176 $this->_columnHeaders["civicrm_membership_member_join_date"] = [
9d72cede 177 'title' => ts('Member Since'),
6a488035 178 'type' => CRM_Utils_Type::T_DATE,
be2fb01f 179 ];
6a488035
TO
180 foreach ($this->_columns as $tableName => $table) {
181 if (array_key_exists('group_bys', $table)) {
182 foreach ($table['group_bys'] as $fieldName => $field) {
a7488080 183 if (!empty($this->_params['group_bys'][$fieldName])) {
6a488035
TO
184
185 switch (CRM_Utils_Array::value($fieldName, $this->_params['group_bys_freq'])) {
186 case 'YEARWEEK':
187 $select[] = "DATE_SUB({$field['dbAlias']}, INTERVAL WEEKDAY({$field['dbAlias']}) DAY) AS {$tableName}_{$fieldName}_start";
188
9d72cede
EM
189 $select[] = "YEARWEEK({$field['dbAlias']}) AS {$tableName}_{$fieldName}_subtotal";
190 $select[] = "WEEKOFYEAR({$field['dbAlias']}) AS {$tableName}_{$fieldName}_interval";
6a488035
TO
191 $field['title'] = 'Week';
192 break;
193
194 case 'YEAR':
9d72cede
EM
195 $select[] = "MAKEDATE(YEAR({$field['dbAlias']}), 1) AS {$tableName}_{$fieldName}_start";
196 $select[] = "YEAR({$field['dbAlias']}) AS {$tableName}_{$fieldName}_subtotal";
197 $select[] = "YEAR({$field['dbAlias']}) AS {$tableName}_{$fieldName}_interval";
6a488035
TO
198 $field['title'] = 'Year';
199 break;
200
201 case 'MONTH':
9d72cede
EM
202 $select[] = "DATE_SUB({$field['dbAlias']}, INTERVAL (DAYOFMONTH({$field['dbAlias']})-1) DAY) as {$tableName}_{$fieldName}_start";
203 $select[] = "MONTH({$field['dbAlias']}) AS {$tableName}_{$fieldName}_subtotal";
204 $select[] = "MONTHNAME({$field['dbAlias']}) AS {$tableName}_{$fieldName}_interval";
6a488035
TO
205 $field['title'] = 'Month';
206 break;
207
208 case 'QUARTER':
9d72cede
EM
209 $select[] = "STR_TO_DATE(CONCAT( 3 * QUARTER( {$field['dbAlias']} ) -2 , '/', '1', '/', YEAR( {$field['dbAlias']} ) ), '%m/%d/%Y') AS {$tableName}_{$fieldName}_start";
210 $select[] = "QUARTER({$field['dbAlias']}) AS {$tableName}_{$fieldName}_subtotal";
211 $select[] = "QUARTER({$field['dbAlias']}) AS {$tableName}_{$fieldName}_interval";
6a488035
TO
212 $field['title'] = 'Quarter';
213 break;
214 }
a7488080 215 if (!empty($this->_params['group_bys_freq'][$fieldName])) {
6a488035 216 $this->_interval = $field['title'];
389bcebf 217 $this->_columnHeaders["{$tableName}_{$fieldName}_start"]['title'] = $field['title'] . ' Beginning';
6a488035
TO
218 $this->_columnHeaders["{$tableName}_{$fieldName}_start"]['type'] = $field['type'];
219 $this->_columnHeaders["{$tableName}_{$fieldName}_start"]['group_by'] = $this->_params['group_bys_freq'][$fieldName];
220
b44e3f84 221 // just to make sure these values are transferred to rows.
6a488035
TO
222 // since we need that for calculation purpose,
223 // e.g making subtotals look nicer or graphs
be2fb01f
CW
224 $this->_columnHeaders["{$tableName}_{$fieldName}_interval"] = ['no_display' => TRUE];
225 $this->_columnHeaders["{$tableName}_{$fieldName}_subtotal"] = ['no_display' => TRUE];
6a488035
TO
226 }
227 $groupBys = TRUE;
228 }
229 }
230 }
231 // end of select
232
233 if (array_key_exists('fields', $table)) {
234 foreach ($table['fields'] as $fieldName => $field) {
9d72cede
EM
235 if (!empty($field['required']) ||
236 !empty($this->_params['fields'][$fieldName])
237 ) {
6a488035
TO
238
239 // only include statistics columns if set
a7488080 240 if (!empty($field['statistics'])) {
6a488035
TO
241 $this->_statFields[] = 'civicrm_membership_member_count';
242 foreach ($field['statistics'] as $stat => $label) {
243 switch (strtolower($stat)) {
244 case 'sum':
245 $select[] = "IFNULL(SUM({$field['dbAlias']}), 0) as {$tableName}_{$fieldName}_{$stat}";
246 $this->_columnHeaders["{$tableName}_{$fieldName}_{$stat}"]['title'] = $label;
247 $this->_columnHeaders["{$tableName}_{$fieldName}_{$stat}"]['type'] = $field['type'];
248 $this->_statFields[] = "{$tableName}_{$fieldName}_{$stat}";
249 break;
250
251 case 'count':
252 $select[] = "COUNT({$field['dbAlias']}) as {$tableName}_{$fieldName}_{$stat}";
253 $this->_columnHeaders["{$tableName}_{$fieldName}_{$stat}"]['type'] = CRM_Utils_Type::T_INT;
254 $this->_columnHeaders["{$tableName}_{$fieldName}_{$stat}"]['title'] = $label;
255 $this->_statFields[] = "{$tableName}_{$fieldName}_{$stat}";
256 break;
257
258 case 'avg':
259 $select[] = "IFNULL(ROUND(AVG({$field['dbAlias']}),2), 0) as {$tableName}_{$fieldName}_{$stat}";
260 $this->_columnHeaders["{$tableName}_{$fieldName}_{$stat}"]['type'] = $field['type'];
261 $this->_columnHeaders["{$tableName}_{$fieldName}_{$stat}"]['title'] = $label;
262 $this->_statFields[] = "{$tableName}_{$fieldName}_{$stat}";
263 break;
264 }
265 }
266 }
267 elseif ($fieldName == 'membership_type_id') {
9d72cede
EM
268 if (empty($this->_params['group_bys']['membership_type_id']) &&
269 !empty($this->_params['group_bys']['join_date'])
270 ) {
6a488035
TO
271 $select[] = "GROUP_CONCAT(DISTINCT {$field['dbAlias']} ORDER BY {$field['dbAlias']} ) as {$tableName}_{$fieldName}";
272 }
273 else {
274 $select[] = "{$field['dbAlias']} as {$tableName}_{$fieldName}";
275 }
276 $this->_columnHeaders["{$tableName}_{$fieldName}"]['title'] = $field['title'];
9c1bc317 277 $this->_columnHeaders["{$tableName}_{$fieldName}"]['operatorType'] = $field['operatorType'] ?? NULL;
6a488035
TO
278 }
279 else {
280 $select[] = "{$field['dbAlias']} as {$tableName}_{$fieldName}";
281 $this->_columnHeaders["{$tableName}_{$fieldName}"]['title'] = $field['title'];
9c1bc317 282 $this->_columnHeaders["{$tableName}_{$fieldName}"]['operatorType'] = $field['operatorType'] ?? NULL;
6a488035
TO
283 }
284 }
285 }
286 }
be2fb01f 287 $this->_columnHeaders["civicrm_membership_member_count"] = [
9d72cede 288 'title' => ts('Member Count'),
6a488035 289 'type' => CRM_Utils_Type::T_INT,
be2fb01f 290 ];
6a488035
TO
291 }
292 //If grouping is availabled then remove join date from field
293 if ($groupBys) {
294 unset($select['joinDate']);
295 unset($this->_columnHeaders["civicrm_membership_member_join_date"]);
296 }
d1641c51 297 $this->_selectClauses = $select;
6a488035
TO
298 $this->_select = "SELECT " . implode(', ', $select) . " ";
299 }
300
00be9182 301 public function from() {
6a488035
TO
302 $this->_from = "
303 FROM civicrm_membership {$this->_aliases['civicrm_membership']}
f813f78e 304
305 LEFT JOIN civicrm_contact {$this->_aliases['civicrm_contact']} ON ( {$this->_aliases['civicrm_membership']}.contact_id = {$this->_aliases['civicrm_contact']}.id )
306
307 LEFT JOIN civicrm_membership_status
6a488035
TO
308 ON ({$this->_aliases['civicrm_membership']}.status_id = civicrm_membership_status.id )
309 LEFT JOIN civicrm_membership_payment payment
310 ON ( {$this->_aliases['civicrm_membership']}.id = payment.membership_id )
f813f78e 311 LEFT JOIN civicrm_contribution {$this->_aliases['civicrm_contribution']}
6a488035
TO
312 ON payment.contribution_id = {$this->_aliases['civicrm_contribution']}.id";
313 }
9d72cede 314
00be9182 315 public function where() {
74cf4551 316 $this->_whereClauses[] = "{$this->_aliases['civicrm_membership']}.is_test = 0 AND
d51206ff 317 {$this->_aliases['civicrm_contact']}.is_deleted = 0";
aa83a942 318 parent::where();
6a488035
TO
319 }
320
00be9182 321 public function groupBy() {
47c0ee09 322 $this->_groupBy = "";
6a488035
TO
323 if (is_array($this->_params['group_bys']) &&
324 !empty($this->_params['group_bys'])
325 ) {
70e504f2 326 foreach ($this->_columns as $table) {
6a488035
TO
327 if (array_key_exists('group_bys', $table)) {
328 foreach ($table['group_bys'] as $fieldName => $field) {
a7488080
CW
329 if (!empty($this->_params['group_bys'][$fieldName])) {
330 if (!empty($field['chart'])) {
6a488035
TO
331 $this->assign('chartSupported', TRUE);
332 }
9d72cede
EM
333 if (!empty($table['group_bys'][$fieldName]['frequency']) &&
334 !empty($this->_params['group_bys_freq'][$fieldName])
335 ) {
6a488035 336
20047181 337 $append = "YEAR({$field['dbAlias']})";
6a488035 338 if (in_array(strtolower($this->_params['group_bys_freq'][$fieldName]),
be2fb01f 339 ['year']
9d72cede 340 )) {
6a488035
TO
341 $append = '';
342 }
70e504f2 343 $this->_groupByArray[] = $append;
344 $this->_groupByArray[] = "{$this->_params['group_bys_freq'][$fieldName]}({$field['dbAlias']})";
6a488035
TO
345 $append = TRUE;
346 }
347 else {
70e504f2 348 $this->_groupByArray[] = $field['dbAlias'];
6a488035
TO
349 }
350 }
351 }
352 }
353 }
354
355 $this->_rollup = ' WITH ROLLUP';
70e504f2 356 $this->_select = CRM_Contact_BAO_Query::appendAnyValueToSelect($this->_selectClauses, array_filter($this->_groupByArray));
357 $this->_groupBy = 'GROUP BY ' . implode(', ', array_filter($this->_groupByArray)) .
9d72cede 358 " {$this->_rollup} ";
6a488035
TO
359 }
360 else {
b708c08d 361 $this->_groupBy = CRM_Contact_BAO_Query::getGroupByFromSelectColumns($this->_selectClauses, "{$this->_aliases['civicrm_membership']}.join_date");
6a488035
TO
362 }
363 }
364
74cf4551 365 /**
71d8f758 366 * @param array $rows
74cf4551
EM
367 *
368 * @return array
369 */
00be9182 370 public function statistics(&$rows) {
6a488035 371 $statistics = parent::statistics($rows);
6a488035
TO
372 $select = "
373 SELECT COUNT({$this->_aliases['civicrm_contribution']}.total_amount ) as count,
374 IFNULL(SUM({$this->_aliases['civicrm_contribution']}.total_amount ), 0) as amount,
375 IFNULL(ROUND(AVG({$this->_aliases['civicrm_contribution']}.total_amount), 2),0) as avg,
35d8497b 376 COUNT( DISTINCT {$this->_aliases['civicrm_membership']}.id ) as memberCount,
377 {$this->_aliases['civicrm_contribution']}.currency as currency
6a488035
TO
378 ";
379
35d8497b 380 $sql = "{$select} {$this->_from} {$this->_where}
f813f78e 381GROUP BY {$this->_aliases['civicrm_contribution']}.currency
35d8497b 382";
6a488035 383
35d8497b 384 $dao = CRM_Core_DAO::executeQuery($sql);
f813f78e 385
be2fb01f 386 $totalAmount = $average = [];
35d8497b 387 $count = $memberCount = 0;
388 while ($dao->fetch()) {
389bcebf 389 $totalAmount[] = CRM_Utils_Money::format($dao->amount, $dao->currency) . "(" . $dao->count . ")";
9d72cede 390 $average[] = CRM_Utils_Money::format($dao->avg, $dao->currency);
35d8497b 391 $count += $dao->count;
392 $memberCount += $dao->memberCount;
393 }
be2fb01f 394 $statistics['counts']['amount'] = [
35d8497b 395 'title' => ts('Total Amount'),
396 'value' => implode(', ', $totalAmount),
397 'type' => CRM_Utils_Type::T_STRING,
be2fb01f
CW
398 ];
399 $statistics['counts']['count'] = [
be205937 400 'title' => ts('Total Contributions'),
35d8497b 401 'value' => $count,
be2fb01f
CW
402 ];
403 $statistics['counts']['memberCount'] = [
35d8497b 404 'title' => ts('Total Members'),
405 'value' => $memberCount,
be2fb01f
CW
406 ];
407 $statistics['counts']['avg'] = [
35d8497b 408 'title' => ts('Average'),
409 'value' => implode(', ', $average),
410 'type' => CRM_Utils_Type::T_STRING,
be2fb01f 411 ];
6a488035 412
9d72cede 413 if (!(int) $statistics['counts']['amount']['value']) {
35d8497b 414 //if total amount is zero then hide Chart Options
415 $this->assign('chartSupported', FALSE);
6a488035
TO
416 }
417
418 return $statistics;
419 }
420
00be9182 421 public function postProcess() {
6a488035
TO
422 parent::postProcess();
423 }
424
302ccf93 425 public function getOperationPair($type = "string", $fieldName = NULL) {
302ccf93 426 //re-name IS NULL/IS NOT NULL for clarity
427 if ($fieldName == 'owner_membership_id') {
455a0d0e 428 $result = [];
302ccf93 429 $result['nll'] = ts('Primary members only');
430 $result['nnll'] = ts('Non-primary members only');
455a0d0e
SL
431 $options = parent::getOperationPair($type, $fieldName);
432 foreach ($options as $key => $label) {
433 if (!array_key_exists($key, $result)) {
434 $result[$key] = $label;
435 }
436 }
437 }
438 else {
439 $result = parent::getOperationPair($type, $fieldName);
302ccf93 440 }
302ccf93 441 return $result;
442 }
443
74cf4551
EM
444 /**
445 * @param $rows
446 */
00be9182 447 public function buildChart(&$rows) {
be2fb01f 448 $graphRows = [];
6a488035
TO
449 $count = 0;
450 $membershipTypeValues = CRM_Member_PseudoConstant::membershipType();
9c1bc317
CW
451 $isMembershipType = $this->_params['group_bys']['membership_type_id'] ?? NULL;
452 $isJoiningDate = $this->_params['group_bys']['join_date'] ?? NULL;
a7488080 453 if (!empty($this->_params['charts'])) {
6a488035
TO
454 foreach ($rows as $key => $row) {
455 if (!($row['civicrm_membership_join_date_subtotal'] &&
9d72cede
EM
456 $row['civicrm_membership_membership_type_id']
457 )
458 ) {
6a488035
TO
459 continue;
460 }
461 if ($isMembershipType) {
9c1bc317
CW
462 $join_date = $row['civicrm_membership_join_date_start'] ?? NULL;
463 $displayInterval = $row['civicrm_membership_join_date_interval'] ?? NULL;
6a488035
TO
464 if ($join_date) {
465 list($year, $month) = explode('-', $join_date);
466 }
a7488080 467 if (!empty($row['civicrm_membership_join_date_subtotal'])) {
6a488035
TO
468
469 switch ($this->_interval) {
470 case 'Month':
471 $displayRange = $displayInterval . ' ' . $year;
472 break;
473
474 case 'Quarter':
475 $displayRange = 'Quarter ' . $displayInterval . ' of ' . $year;
476 break;
477
478 case 'Week':
479 $displayRange = 'Week ' . $displayInterval . ' of ' . $year;
480 break;
481
482 case 'Year':
483 $displayRange = $year;
484 break;
485 }
9d72cede
EM
486 $membershipType = $displayRange . "-" .
487 $membershipTypeValues[$row['civicrm_membership_membership_type_id']];
6a488035
TO
488 }
489 else {
490
491 $membershipType = $membershipTypeValues[$row['civicrm_membership_membership_type_id']];
492 }
493
494 $interval[$membershipType] = $membershipType;
495 $display[$membershipType] = $row['civicrm_contribution_total_amount_sum'];
496 }
497 else {
9c1bc317
CW
498 $graphRows['receive_date'][] = $row['civicrm_membership_join_date_start'] ?? NULL;
499 $graphRows[$this->_interval][] = $row['civicrm_membership_join_date_interval'] ?? NULL;
6a488035
TO
500 $graphRows['value'][] = $row['civicrm_contribution_total_amount_sum'];
501 $count++;
502 }
503 }
504
505 // build chart.
506 if ($isMembershipType) {
507 $graphRows['value'] = $display;
be2fb01f 508 $chartInfo = [
b35e00df 509 'legend' => ts('Membership Summary'),
e60e0c01 510 'xname' => ts('Member Since / Member Type'),
511 'yname' => ts('Fees'),
be2fb01f 512 ];
dc61ee93 513 CRM_Utils_Chart::reportChart($graphRows, $this->_params['charts'], $interval, $chartInfo);
6a488035
TO
514 }
515 else {
dc61ee93 516 CRM_Utils_Chart::chart($graphRows, $this->_params['charts'], $this->_interval);
6a488035
TO
517 }
518 }
519 $this->assign('chartType', $this->_params['charts']);
520 }
521
74cf4551 522 /**
ced9bfed
EM
523 * Alter display of rows.
524 *
525 * Iterate through the rows retrieved via SQL and make changes for display purposes,
526 * such as rendering contacts as links.
527 *
528 * @param array $rows
529 * Rows generated by SQL, with an array for each row.
74cf4551 530 */
00be9182 531 public function alterDisplay(&$rows) {
6a488035
TO
532 $entryFound = FALSE;
533 foreach ($rows as $rowNum => $row) {
534 // make count columns point to detail report
9d72cede
EM
535 if (!empty($this->_params['group_bys']['join_date']) &&
536 !empty($row['civicrm_membership_join_date_start']) &&
6a488035
TO
537 $row['civicrm_membership_join_date_start'] &&
538 $row['civicrm_membership_join_date_subtotal']
539 ) {
540
541 $dateStart = CRM_Utils_Date::customFormat($row['civicrm_membership_join_date_start'], '%Y%m%d');
9d72cede 542 $endDate = new DateTime($dateStart);
be2fb01f 543 $dateEnd = [];
6a488035
TO
544
545 list($dateEnd['Y'], $dateEnd['M'], $dateEnd['d']) = explode(':', $endDate->format('Y:m:d'));
546
547 switch (strtolower($this->_params['group_bys_freq']['join_date'])) {
548 case 'month':
549 $dateEnd = date("Ymd", mktime(0, 0, 0, $dateEnd['M'] + 1,
9d72cede
EM
550 $dateEnd['d'] - 1, $dateEnd['Y']
551 ));
6a488035
TO
552 break;
553
554 case 'year':
555 $dateEnd = date("Ymd", mktime(0, 0, 0, $dateEnd['M'],
9d72cede
EM
556 $dateEnd['d'] - 1, $dateEnd['Y'] + 1
557 ));
6a488035
TO
558 break;
559
560 case 'yearweek':
561 $dateEnd = date("Ymd", mktime(0, 0, 0, $dateEnd['M'],
9d72cede
EM
562 $dateEnd['d'] + 6, $dateEnd['Y']
563 ));
6a488035
TO
564 break;
565
566 case 'quarter':
567 $dateEnd = date("Ymd", mktime(0, 0, 0, $dateEnd['M'] + 3,
9d72cede
EM
568 $dateEnd['d'] - 1, $dateEnd['Y']
569 ));
6a488035
TO
570 break;
571 }
572 $typeUrl = '';
a7488080 573 if (!empty($this->_params['group_bys']['membership_type_id']) &&
6a488035
TO
574 $typeID = $row['civicrm_membership_membership_type_id']
575 ) {
576 $typeUrl = "&tid_op=in&tid_value={$typeID}";
577 }
578 $statusUrl = '';
579 if (!empty($this->_params['status_id_value'])) {
9d72cede
EM
580 $statusUrl = "&sid_op=in&sid_value=" .
581 implode(",", $this->_params['status_id_value']);
6a488035
TO
582 }
583 $url = CRM_Report_Utils_Report::getNextUrl('member/detail',
b2c9a0e3 584 "reset=1&force=1&membership_join_date_from={$dateStart}&membership_join_date_to={$dateEnd}{$typeUrl}{$statusUrl}",
6a488035
TO
585 $this->_absoluteUrl, $this->_id, $this->_drilldownReport
586 );
587 $row['civicrm_membership_join_date_start'] = CRM_Utils_Date::format($row['civicrm_membership_join_date_start']);
588 $rows[$rowNum]['civicrm_membership_join_date_start_link'] = $url;
589 $rows[$rowNum]['civicrm_membership_join_date_start_hover'] = ts("Lists Summary of Memberships for this date unit.");
590
591 $entryFound = TRUE;
592 }
593
594 // handle Membership Types
595 if (array_key_exists('civicrm_membership_membership_type_id', $row)) {
596 if ($value = $row['civicrm_membership_membership_type_id']) {
597 $value = explode(',', $value);
598 foreach ($value as $key => $id) {
599 $value[$key] = CRM_Member_PseudoConstant::membershipType($id, FALSE);
600 }
601 $rows[$rowNum]['civicrm_membership_membership_type_id'] = implode(' , ', $value);
602 }
603 $entryFound = TRUE;
604 }
605
606 // make subtotals look nicer
607 if (array_key_exists('civicrm_membership_join_date_subtotal', $row) &&
608 !$row['civicrm_membership_join_date_subtotal']
609 ) {
610 $this->fixSubTotalDisplay($rows[$rowNum], $this->_statFields);
611 $entryFound = TRUE;
612 }
613 elseif (array_key_exists('civicrm_membership_join_date_subtotal', $row) &&
614 $row['civicrm_membership_join_date_subtotal'] &&
615 !$row['civicrm_membership_membership_type_id']
616 ) {
617 $this->fixSubTotalDisplay($rows[$rowNum], $this->_statFields, FALSE);
8c2959c8 618 $rows[$rowNum]['civicrm_membership_membership_type_id'] = '<b>' . ts('Subtotal') . '</b>';
6a488035
TO
619 $entryFound = TRUE;
620 }
f813f78e 621
a7dbbc5d
CD
622 // If using campaigns, convert campaign_id to campaign title
623 if (array_key_exists('civicrm_membership_campaign_id', $row)) {
624 if ($value = $row['civicrm_membership_campaign_id']) {
a5f92eba 625 $rows[$rowNum]['civicrm_membership_campaign_id'] = $this->campaigns[$value];
a7dbbc5d
CD
626 }
627 $entryFound = TRUE;
628 }
6a488035
TO
629
630 // skip looking further in rows, if first row itself doesn't
631 // have the column we need
632 if (!$entryFound) {
633 break;
634 }
635 }
636 }
96025800 637
6a488035 638}