Revert "ICM-17 Added conditional checks for reports"
[civicrm-core.git] / CRM / Report / Form / Contribute / TopDonor.php
CommitLineData
6a488035 1<?php
6a488035
TO
2/*
3 +--------------------------------------------------------------------+
7e9e8871 4 | CiviCRM version 4.7 |
6a488035 5 +--------------------------------------------------------------------+
e7112fa7 6 | Copyright CiviCRM LLC (c) 2004-2015 |
6a488035
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
d25dd0ee 26 */
6a488035
TO
27
28/**
29 *
30 * @package CRM
e7112fa7 31 * @copyright CiviCRM LLC (c) 2004-2015
6a488035
TO
32 * $Id$
33 *
34 */
35class CRM_Report_Form_Contribute_TopDonor extends CRM_Report_Form {
36
37 protected $_summary = NULL;
70bea8e2 38 protected $_customGroupExtends = array(
39 'Contact',
40 'Individual',
7d793900 41 'Contribution',
70bea8e2 42 );
6a488035
TO
43
44 public $_drilldownReport = array('contribute/detail' => 'Link to Detail Report');
45
46 protected $_charts = array(
47 '' => 'Tabular',
48 'barChart' => 'Bar Chart',
49 'pieChart' => 'Pie Chart',
50 );
2f4c2f5d 51
74cf4551 52 /**
74cf4551 53 */
00be9182 54 public function __construct() {
70bea8e2 55 $this->_autoIncludeIndexedFieldsAsOrderBys = 1;
6a488035 56 $this->_columns = array(
ae5ffbb7
TO
57 'civicrm_contact' => array(
58 'dao' => 'CRM_Contact_DAO_Contact',
59 'fields' => array(
ae5ffbb7
TO
60 'display_name' => array(
61 'title' => ts('Contact Name'),
62 'required' => TRUE,
63 'no_repeat' => TRUE,
64 ),
65 'first_name' => array(
66 'title' => ts('First Name'),
67 ),
70bea8e2 68 'middle_name' => array(
69 'title' => ts('Middle Name'),
70 ),
ae5ffbb7
TO
71 'last_name' => array(
72 'title' => ts('Last Name'),
73 ),
70bea8e2 74 'id' => array(
75 'no_display' => TRUE,
76 'required' => TRUE,
77 ),
78 'gender_id' => array(
79 'title' => ts('Gender'),
80 ),
81 'birth_date' => array(
82 'title' => ts('Birth Date'),
83 ),
84 'age' => array(
85 'title' => ts('Age'),
86 'dbAlias' => 'TIMESTAMPDIFF(YEAR, contact_civireport.birth_date, CURDATE())',
87 ),
ae5ffbb7
TO
88 'contact_type' => array(
89 'title' => ts('Contact Type'),
90 ),
91 'contact_sub_type' => array(
92 'title' => ts('Contact Subtype'),
7a961f19 93 ),
6a488035 94 ),
49e1ea9f 95 'filters' => array(
96 'gender_id' => array(
97 'title' => ts('Gender'),
98 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
99 'options' => CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'gender_id'),
100 ),
ee436328 101 'contact_type' => array(
102 'title' => ts('Contact Type'),
ae5ffbb7
TO
103 ),
104 'contact_sub_type' => array(
105 'title' => ts('Contact Subtype'),
7a961f19 106 ),
6a488035 107 ),
6e68fe2a 108 'filters' => array(
109 'gender_id' => array(
110 'title' => ts('Gender'),
111 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
112 'options' => CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'gender_id'),
113 ),
114 ),
ae5ffbb7 115 ),
cbfbab2f
E
116 'civicrm_line_item' => array(
117 'dao' => 'CRM_Price_DAO_LineItem',
118 ),
ae5ffbb7
TO
119 );
120 $this->_columns += $this->getAddressColumns();
121 $this->_columns += array(
122 'civicrm_contribution' => array(
123 'dao' => 'CRM_Contribute_DAO_Contribution',
124 'fields' => array(
125 'total_amount' => array(
126 'title' => ts('Amount Statistics'),
127 'required' => TRUE,
128 'statistics' => array(
129 'sum' => ts('Aggregate Amount'),
130 'count' => ts('Donations'),
131 'avg' => ts('Average'),
f3bc9ff5 132 ),
6a488035 133 ),
ae5ffbb7
TO
134 'currency' => array(
135 'required' => TRUE,
136 'no_display' => TRUE,
6a488035
TO
137 ),
138 ),
ae5ffbb7 139 'filters' => array(
70bea8e2 140 'sort_name' => array(
141 'title' => ts('Participant Name'),
142 'operator' => 'like',
143 ),
144 'id' => array(
145 'title' => ts('Contact ID'),
146 'no_display' => TRUE,
147 ),
70bea8e2 148 'birth_date' => array(
149 'title' => ts('Birth Date'),
150 'operatorType' => CRM_Report_Form::OP_DATE,
151 ),
152 'contact_type' => array(
153 'title' => ts('Contact Type'),
154 ),
155 'contact_sub_type' => array(
156 'title' => ts('Contact Subtype'),
157 ),
ae5ffbb7
TO
158 'receive_date' => array(
159 'default' => 'this.year',
160 'operatorType' => CRM_Report_Form::OP_DATE,
161 ),
162 'currency' => array(
163 'title' => 'Currency',
164 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
165 'options' => CRM_Core_OptionGroup::values('currencies_enabled'),
166 'default' => NULL,
167 'type' => CRM_Utils_Type::T_STRING,
168 ),
169 'total_range' => array(
170 'title' => ts('Show no. of Top Donors'),
171 'type' => CRM_Utils_Type::T_INT,
172 'default_op' => 'eq',
173 ),
174 'financial_type_id' => array(
175 'name' => 'financial_type_id',
176 'title' => ts('Financial Type'),
177 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
cbfbab2f 178 'options' => CRM_Financial_BAO_FinancialType::getAvailableFinancialTypes(),
ae5ffbb7
TO
179 ),
180 'contribution_status_id' => array(
181 'title' => ts('Contribution Status'),
182 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
183 'options' => CRM_Contribute_PseudoConstant::contributionStatus(),
184 'default' => array(1),
6a488035
TO
185 ),
186 ),
ae5ffbb7
TO
187 ),
188 'civicrm_email' => array(
189 'dao' => 'CRM_Core_DAO_Email',
190 'fields' => array(
191 'email' => array(
192 'title' => ts('Email'),
193 'default' => TRUE,
194 'no_repeat' => TRUE,
195 ),
196 ),
197 'grouping' => 'email-fields',
198 ),
199 'civicrm_phone' => array(
200 'dao' => 'CRM_Core_DAO_Phone',
201 'fields' => array(
202 'phone' => array(
203 'title' => ts('Phone'),
204 'default' => TRUE,
205 'no_repeat' => TRUE,
6a488035
TO
206 ),
207 ),
ae5ffbb7
TO
208 'grouping' => 'phone-fields',
209 ),
210 );
6a488035 211
16e2e80c 212 $this->_groupFilter = TRUE;
6a488035 213 $this->_tagFilter = TRUE;
7a961f19 214 $this->_currencyColumn = 'civicrm_contribution_currency';
6a488035
TO
215 parent::__construct();
216 }
217
00be9182 218 public function preProcess() {
6a488035
TO
219 parent::preProcess();
220 }
221
00be9182 222 public function select() {
6a488035
TO
223 $select = array();
224 $this->_columnHeaders = array();
225 //Headers for Rank column
226 $this->_columnHeaders["civicrm_donor_rank"]['title'] = ts('Rank');
227 $this->_columnHeaders["civicrm_donor_rank"]['type'] = 1;
228 //$select[] ="(@rank:=@rank+1) as civicrm_donor_rank ";
229
230 foreach ($this->_columns as $tableName => $table) {
231 if (array_key_exists('fields', $table)) {
232 foreach ($table['fields'] as $fieldName => $field) {
9d72cede
EM
233 if (!empty($field['required']) ||
234 !empty($this->_params['fields'][$fieldName])
235 ) {
6a488035 236 // only include statistics columns if set
a7488080 237 if (!empty($field['statistics'])) {
6a488035
TO
238 foreach ($field['statistics'] as $stat => $label) {
239 switch (strtolower($stat)) {
240 case 'sum':
241 $select[] = "SUM({$field['dbAlias']}) as {$tableName}_{$fieldName}_{$stat}";
242 $this->_columnHeaders["{$tableName}_{$fieldName}_{$stat}"]['title'] = $label;
243 $this->_columnHeaders["{$tableName}_{$fieldName}_{$stat}"]['type'] = $field['type'];
244 $this->_statFields[] = "{$tableName}_{$fieldName}_{$stat}";
245 break;
246
247 case 'count':
248 $select[] = "COUNT({$field['dbAlias']}) as {$tableName}_{$fieldName}_{$stat}";
249 $this->_columnHeaders["{$tableName}_{$fieldName}_{$stat}"]['title'] = $label;
250 $this->_columnHeaders["{$tableName}_{$fieldName}_{$stat}"]['type'] = CRM_Utils_Type::T_INT;
251 $this->_statFields[] = "{$tableName}_{$fieldName}_{$stat}";
252 break;
253
254 case 'avg':
255 $select[] = "ROUND(AVG({$field['dbAlias']}),2) as {$tableName}_{$fieldName}_{$stat}";
256 $this->_columnHeaders["{$tableName}_{$fieldName}_{$stat}"]['type'] = $field['type'];
257 $this->_columnHeaders["{$tableName}_{$fieldName}_{$stat}"]['title'] = $label;
258 $this->_statFields[] = "{$tableName}_{$fieldName}_{$stat}";
259 break;
260 }
261 }
262 }
263 else {
264 $select[] = "{$field['dbAlias']} as {$tableName}_{$fieldName}";
21d62de7
DG
265 // $field['type'] is not always set. Use string type as default if not set.
266 $this->_columnHeaders["{$tableName}_{$fieldName}"]['type'] = isset($field['type']) ? $field['type'] : 2;
6a488035
TO
267 $this->_columnHeaders["{$tableName}_{$fieldName}"]['title'] = $field['title'];
268 }
269 }
270 }
271 }
272 }
65f9ed10 273
6a488035
TO
274 $this->_select = " SELECT * FROM ( SELECT " . implode(', ', $select) . " ";
275 }
276
74cf4551
EM
277 /**
278 * @param $fields
279 * @param $files
280 * @param $self
281 *
282 * @return array
283 */
00be9182 284 public static function formRule($fields, $files, $self) {
6a488035
TO
285 $errors = array();
286
287 $op = CRM_Utils_Array::value('total_range_op', $fields);
288 $val = CRM_Utils_Array::value('total_range_value', $fields);
289
290 if (!in_array($op, array(
9d72cede 291 'eq',
21dfd5f5 292 'lte',
9d72cede
EM
293 ))
294 ) {
6a488035
TO
295 $errors['total_range_op'] = ts("Please select 'Is equal to' OR 'Is Less than or equal to' operator");
296 }
297
298 if ($val && !CRM_Utils_Rule::positiveInteger($val)) {
299 $errors['total_range_value'] = ts("Please enter positive number");
300 }
301 return $errors;
302 }
303
00be9182 304 public function from() {
6a488035
TO
305 $this->_from = "
306 FROM civicrm_contact {$this->_aliases['civicrm_contact']} {$this->_aclFrom}
65f9ed10
E
307 INNER JOIN civicrm_contribution {$this->_aliases['civicrm_contribution']}
308 ON {$this->_aliases['civicrm_contact']}.id = {$this->_aliases['civicrm_contribution']}.contact_id AND {$this->_aliases['civicrm_contribution']}.is_test = 0
2f4c2f5d 309 LEFT JOIN civicrm_email {$this->_aliases['civicrm_email']}
310 ON {$this->_aliases['civicrm_contact']}.id = {$this->_aliases['civicrm_email']}.contact_id
6a488035 311 AND {$this->_aliases['civicrm_email']}.is_primary = 1
2f4c2f5d 312 LEFT JOIN civicrm_phone {$this->_aliases['civicrm_phone']}
6a488035 313 ON {$this->_aliases['civicrm_contact']}.id = {$this->_aliases['civicrm_phone']}.contact_id AND
50757f01 314 {$this->_aliases['civicrm_phone']}.is_primary = 1";
21d62de7 315 $this->addAddressFromClause();
6a488035
TO
316 }
317
00be9182 318 public function where() {
6a488035 319 $clauses = array();
93406a82 320 $this->_tempClause = $this->_outerCluase = $this->_groupLimit = '';
6a488035
TO
321 foreach ($this->_columns as $tableName => $table) {
322 if (array_key_exists('filters', $table)) {
323 foreach ($table['filters'] as $fieldName => $field) {
324 $clause = NULL;
325 if (CRM_Utils_Array::value('type', $field) & CRM_Utils_Type::T_DATE) {
326 $relative = CRM_Utils_Array::value("{$fieldName}_relative", $this->_params);
9d72cede
EM
327 $from = CRM_Utils_Array::value("{$fieldName}_from", $this->_params);
328 $to = CRM_Utils_Array::value("{$fieldName}_to", $this->_params);
6a488035
TO
329
330 if ($relative || $from || $to) {
331 $clause = $this->dateClause($field['name'], $relative, $from, $to, $field['type']);
332 }
333 }
334 else {
335 $op = CRM_Utils_Array::value("{$fieldName}_op", $this->_params);
336 if ($op) {
337 $clause = $this->whereClause($field,
338 $op,
339 CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
340 CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
341 CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
342 );
343 }
344 }
345
346 if (!empty($clause)) {
347 if ($fieldName == 'total_range') {
348 $value = CRM_Utils_Array::value("total_range_value", $this->_params);
349 $this->_outerCluase = " WHERE (( @rows := @rows + 1) <= {$value}) ";
93406a82 350 $this->_groupLimit = " LIMIT {$value}";
6a488035
TO
351 }
352 else {
353 $clauses[] = $clause;
354 }
355 }
356 }
357 }
358 }
359 if (empty($clauses)) {
360 $this->_where = "WHERE ( 1 ) ";
361 }
362 else {
363 $this->_where = "WHERE " . implode(' AND ', $clauses);
364 }
365
366 if ($this->_aclWhere) {
367 $this->_where .= " AND {$this->_aclWhere} ";
368 }
369 }
370
00be9182 371 public function groupBy() {
7a961f19 372 $this->_groupBy = "GROUP BY {$this->_aliases['civicrm_contact']}.id, {$this->_aliases['civicrm_contribution']}.currency";
6a488035
TO
373 }
374
00be9182 375 public function postProcess() {
6a488035
TO
376
377 $this->beginPostProcess();
378
379 // get the acl clauses built before we assemble the query
380 $this->buildACLClause($this->_aliases['civicrm_contact']);
381
382 $this->select();
383
384 $this->from();
fe32835e 385 $this->getPermissionedFTQuery($this);
6a488035
TO
386
387 $this->where();
388
389 $this->groupBy();
390
391 $this->limit();
392
6a488035
TO
393 //set the variable value rank, rows = 0
394 $setVariable = " SET @rows:=0, @rank=0 ";
395 CRM_Core_DAO::singleValueQuery($setVariable);
396
2f4c2f5d 397 $sql = " {$this->_select} {$this->_from} {$this->_where} {$this->_groupBy}
6a488035
TO
398 ORDER BY civicrm_contribution_total_amount_sum DESC
399 ) as abc {$this->_outerCluase} $this->_limit
400 ";
401
402 $dao = CRM_Core_DAO::executeQuery($sql);
403
404 while ($dao->fetch()) {
405 $row = array();
406 foreach ($this->_columnHeaders as $key => $value) {
407 if (property_exists($dao, $key)) {
408 $row[$key] = $dao->$key;
409 }
410 }
411 $rows[] = $row;
412 }
413 $this->formatDisplay($rows);
414
415 $this->doTemplateAssignment($rows);
416
417 $this->endPostProcess($rows);
418 }
419
74cf4551 420 /**
100fef9d 421 * @param int $groupID
74cf4551 422 */
00be9182 423 public function add2group($groupID) {
6a488035
TO
424 if (is_numeric($groupID)) {
425
2f4c2f5d 426 $sql = "
427{$this->_select} {$this->_from} {$this->_where} {$this->_groupBy}
6a488035 428ORDER BY civicrm_contribution_total_amount_sum DESC
93406a82 429) as abc {$this->_groupLimit}";
6a488035
TO
430 $dao = CRM_Core_DAO::executeQuery($sql);
431
432 $contact_ids = array();
433 // Add resulting contacts to group
434 while ($dao->fetch()) {
435 $contact_ids[$dao->civicrm_contact_id] = $dao->civicrm_contact_id;
436 }
437
438 CRM_Contact_BAO_GroupContact::addContactsToGroup($contact_ids, $groupID);
439 CRM_Core_Session::setStatus(ts("Listed contact(s) have been added to the selected group."), ts('Contacts Added'), 'success');
440 }
441 }
442
74cf4551
EM
443 /**
444 * @param int $rowCount
445 */
00be9182 446 public function limit($rowCount = CRM_Report_Form::ROW_COUNT_LIMIT) {
6a488035
TO
447 // lets do the pager if in html mode
448 $this->_limit = NULL;
74cf4551 449
dbb4a0f9
PN
450 // CRM-14115, over-ride row count if rowCount is specified in URL
451 if ($this->_dashBoardRowCount) {
452 $rowCount = $this->_dashBoardRowCount;
453 }
6a488035 454 if ($this->_outputMode == 'html' || $this->_outputMode == 'group') {
ab432335 455 // Replace only first occurrence of SELECT.
6a488035
TO
456 $this->_select = preg_replace('/SELECT/', 'SELECT SQL_CALC_FOUND_ROWS ', $this->_select, 1);
457 $pageId = CRM_Utils_Request::retrieve('crmPID', 'Integer', CRM_Core_DAO::$_nullObject);
458
459 if (!$pageId && !empty($_POST) && isset($_POST['crmPID_B'])) {
460 if (!isset($_POST['PagerBottomButton'])) {
461 unset($_POST['crmPID_B']);
462 }
463 else {
9d72cede 464 $pageId = max((int) @$_POST['crmPID_B'], 1);
6a488035
TO
465 }
466 }
467
468 $pageId = $pageId ? $pageId : 1;
469 $this->set(CRM_Utils_Pager::PAGE_ID, $pageId);
470 $offset = ($pageId - 1) * $rowCount;
471
bf00d1b6
DL
472 $offset = CRM_Utils_Type::escape($offset, 'Int');
473 $rowCount = CRM_Utils_Type::escape($rowCount, 'Int');
474
6a488035
TO
475 $this->_limit = " LIMIT $offset, " . $rowCount;
476 }
477 }
478
74cf4551 479 /**
ced9bfed
EM
480 * Alter display of rows.
481 *
482 * Iterate through the rows retrieved via SQL and make changes for display purposes,
483 * such as rendering contacts as links.
484 *
485 * @param array $rows
486 * Rows generated by SQL, with an array for each row.
74cf4551 487 */
00be9182 488 public function alterDisplay(&$rows) {
6a488035
TO
489 $entryFound = FALSE;
490 $rank = 1;
491 if (!empty($rows)) {
492 foreach ($rows as $rowNum => $row) {
493
494 $rows[$rowNum]['civicrm_donor_rank'] = $rank++;
495 // convert display name to links
496 if (array_key_exists('civicrm_contact_display_name', $row) &&
9d72cede
EM
497 array_key_exists('civicrm_contact_id', $row) &&
498 !empty($row['civicrm_contribution_currency'])
499 ) {
6a488035 500 $url = CRM_Report_Utils_Report::getNextUrl('contribute/detail',
9d72cede
EM
501 'reset=1&force=1&id_op=eq&id_value=' . $row['civicrm_contact_id'] .
502 "&currency_value=" . $row['civicrm_contribution_currency'],
6a488035
TO
503 $this->_absoluteUrl, $this->_id, $this->_drilldownReport
504 );
505 $rows[$rowNum]['civicrm_contact_display_name_link'] = $url;
506 $entryFound = TRUE;
507 }
21d62de7 508 $entryFound = $this->alterDisplayAddressFields($row, $rows, $rowNum, 'contribute/detail', 'List all contribution(s)') ? TRUE : $entryFound;
6a488035 509
7d793900 510 //handle gender
511 if (array_key_exists('civicrm_contact_gender_id', $row)) {
512 if ($value = $row['civicrm_contact_gender_id']) {
513 $gender = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'gender_id');
514 $rows[$rowNum]['civicrm_contact_gender_id'] = $gender[$value];
515 }
516 $entryFound = TRUE;
70bea8e2 517 }
70bea8e2 518
7d793900 519 // display birthday in the configured custom format
520 if (array_key_exists('civicrm_contact_birth_date', $row)) {
521 $birthDate = $row['civicrm_contact_birth_date'];
522 if ($birthDate) {
523 $rows[$rowNum]['civicrm_contact_birth_date'] = CRM_Utils_Date::customFormat($birthDate, '%Y%m%d');
524 }
525 $entryFound = TRUE;
70bea8e2 526 }
70bea8e2 527
6a488035
TO
528 // skip looking further in rows, if first row itself doesn't
529 // have the column we need
530 if (!$entryFound) {
531 break;
532 }
533 }
534 }
535 }
96025800 536
6a488035 537}