clean up campaigns for reports
[civicrm-core.git] / CRM / Report / Form / Contribute / Lybunt.php
CommitLineData
6a488035 1<?php
6a488035
TO
2/*
3 +--------------------------------------------------------------------+
fee14197 4 | CiviCRM version 5 |
6a488035 5 +--------------------------------------------------------------------+
8c9251b3 6 | Copyright CiviCRM LLC (c) 2004-2018 |
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
8c9251b3 31 * @copyright CiviCRM LLC (c) 2004-2018
6a488035
TO
32 */
33class CRM_Report_Form_Contribute_Lybunt extends CRM_Report_Form {
34
6a488035
TO
35 protected $_charts = array(
36 '' => 'Tabular',
37 'barChart' => 'Bar Chart',
38 'pieChart' => 'Pie Chart',
39 );
40
c160fde8 41 /**
42 * This is the report that links will lead to.
43 *
44 * It is a bit problematic to use contribute/detail for anything other than a single contact
45 * as the filtering from this report does not carry over to that report.
46 *
47 * @var array
48 */
6a488035
TO
49 public $_drilldownReport = array('contribute/detail' => 'Link to Detail Report');
50
51 protected $lifeTime_from = NULL;
430ae6dd 52 protected $lifeTime_where = NULL;
c160fde8 53 protected $_customGroupExtends = array(
54 'Contact',
55 'Individual',
56 'Household',
57 'Organization',
58 );
59
60 /**
61 * Table containing list of contact IDs.
62 *
63 * @var string
64 */
65 protected $contactTempTable = '';
66
67 /**
87755286 68 * This report has been optimised for group filtering.
c160fde8 69 *
87755286 70 * CRM-19170
71 *
72 * @var bool
c160fde8 73 */
87755286 74 protected $groupFilterNotOptimised = FALSE;
430ae6dd 75
c160fde8 76 /**
77 * Class constructor.
74cf4551 78 */
00be9182 79 public function __construct() {
66ddb273 80 $this->optimisedForOnlyFullGroupBy = FALSE;
55f71fa7 81 $this->_rollup = 'WITH ROLLUP';
49e1ea9f 82 $this->_autoIncludeIndexedFieldsAsOrderBys = 1;
9d72cede 83 $yearsInPast = 10;
6a488035 84 $yearsInFuture = 1;
9d72cede
EM
85 $date = CRM_Core_SelectValues::date('custom', NULL, $yearsInPast, $yearsInFuture);
86 $count = $date['maxYear'];
6a488035
TO
87 while ($date['minYear'] <= $count) {
88 $optionYear[$date['minYear']] = $date['minYear'];
89 $date['minYear']++;
90 }
91
92 $this->_columns = array(
a130e045
DG
93 'civicrm_contact' => array(
94 'dao' => 'CRM_Contact_DAO_Contact',
95 'grouping' => 'contact-field',
c160fde8 96 'fields' => $this->getBasicContactFields(),
49e1ea9f 97 'order_bys' => array(
98 'sort_name' => array(
99 'title' => ts('Last Name, First Name'),
a7d034b3 100 'default' => '0',
49e1ea9f 101 'default_order' => 'ASC',
102 ),
103 'first_name' => array(
104 'name' => 'first_name',
105 'title' => ts('First Name'),
106 ),
107 'gender_id' => array(
108 'name' => 'gender_id',
109 'title' => ts('Gender'),
110 ),
111 'birth_date' => array(
112 'name' => 'birth_date',
113 'title' => ts('Birth Date'),
114 ),
a130e045
DG
115 'contact_type' => array(
116 'title' => ts('Contact Type'),
117 ),
118 'contact_sub_type' => array(
119 'title' => ts('Contact Subtype'),
6a488035
TO
120 ),
121 ),
a130e045
DG
122 'filters' => array(
123 'sort_name' => array(
124 'title' => ts('Donor Name'),
125 'operator' => 'like',
6a488035 126 ),
49e1ea9f 127 'id' => array(
128 'title' => ts('Contact ID'),
129 'no_display' => TRUE,
130 ),
131 'gender_id' => array(
132 'title' => ts('Gender'),
133 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
134 'options' => CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'gender_id'),
135 ),
136 'birth_date' => array(
137 'title' => ts('Birth Date'),
138 'operatorType' => CRM_Report_Form::OP_DATE,
139 ),
140 'contact_type' => array(
141 'title' => ts('Contact Type'),
142 ),
143 'contact_sub_type' => array(
144 'title' => ts('Contact Subtype'),
145 ),
c160fde8 146 'is_deceased' => array(),
147 'do_not_phone' => array(),
148 'do_not_email' => array(),
149 'do_not_sms' => array(),
150 'do_not_mail' => array(),
151 'is_opt_out' => array(),
6a488035 152 ),
a130e045 153 ),
3191db62
E
154 'civicrm_line_item' => array(
155 'dao' => 'CRM_Price_DAO_LineItem',
156 ),
a130e045
DG
157 'civicrm_email' => array(
158 'dao' => 'CRM_Core_DAO_Email',
159 'grouping' => 'contact-field',
160 'fields' => array(
161 'email' => array(
162 'title' => ts('Email'),
163 'default' => TRUE,
6a488035 164 ),
0a618a8d 165 'on_hold' => array(
166 'title' => ts('Email on hold'),
167 ),
6a488035 168 ),
a130e045
DG
169 ),
170 'civicrm_phone' => array(
171 'dao' => 'CRM_Core_DAO_Phone',
172 'grouping' => 'contact-field',
173 'fields' => array(
174 'phone' => array(
175 'title' => ts('Phone'),
176 'default' => TRUE,
177 ),
178 ),
179 ),
ae5ffbb7 180 );
c160fde8 181 $this->_columns += $this->addAddressFields(FALSE);
ae5ffbb7 182 $this->_columns += array(
a130e045
DG
183 'civicrm_contribution' => array(
184 'dao' => 'CRM_Contribute_DAO_Contribution',
185 'fields' => array(
186 'contact_id' => array(
187 'title' => ts('contactId'),
188 'no_display' => TRUE,
189 'required' => TRUE,
190 'no_repeat' => TRUE,
191 ),
a130e045
DG
192 'receive_date' => array(
193 'title' => ts('Year'),
194 'no_display' => TRUE,
195 'required' => TRUE,
196 'no_repeat' => TRUE,
6a488035 197 ),
c160fde8 198 'last_year_total_amount' => array(
199 'title' => ts('Last Year Total'),
200 'default' => TRUE,
201 'type' => CRM_Utils_Type::T_MONEY,
3fd9a92a 202 'required' => TRUE,
c160fde8 203 ),
204 'civicrm_life_time_total' => array(
205 'title' => ts('Lifetime Total'),
206 'default' => TRUE,
207 'type' => CRM_Utils_Type::T_MONEY,
208 'statistics' => array('sum' => ts('Lifetime total')),
209 ),
6a488035 210 ),
a130e045
DG
211 'filters' => array(
212 'yid' => array(
213 'name' => 'receive_date',
214 'title' => ts('This Year'),
215 'operatorType' => CRM_Report_Form::OP_SELECT,
216 'options' => $optionYear,
217 'default' => date('Y'),
55f71fa7 218 'type' => CRM_Utils_Type::T_INT,
a130e045
DG
219 ),
220 'financial_type_id' => array(
221 'title' => ts('Financial Type'),
525ae77a 222 'type' => CRM_Utils_Type::T_INT,
a130e045 223 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
3191db62 224 'options' => CRM_Financial_BAO_FinancialType::getAvailableFinancialTypes(),
a130e045
DG
225 ),
226 'contribution_status_id' => array(
227 'title' => ts('Contribution Status'),
228 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
229 'options' => CRM_Contribute_PseudoConstant::contributionStatus(),
230 'default' => array('1'),
231 ),
232 ),
a7d034b3 233 'order_bys' => array(
c160fde8 234 'last_year_total_amount' => array(
235 'title' => ts('Total amount last year'),
236 'default' => '1',
a7d034b3 237 'default_weight' => '0',
238 'default_order' => 'DESC',
239 ),
240 ),
a130e045
DG
241 ),
242 );
62a40853
E
243 $this->_columns += array(
244 'civicrm_financial_trxn' => array(
245 'dao' => 'CRM_Financial_DAO_FinancialTrxn',
246 'fields' => array(
5e0343e8 247 'card_type_id' => array(
d72b084a 248 'title' => ts('Credit Card Type'),
5e0343e8 249 'dbAlias' => 'GROUP_CONCAT(financial_trxn_civireport.card_type_id SEPARATOR ",")',
62a40853
E
250 ),
251 ),
252 'filters' => array(
5e0343e8 253 'card_type_id' => array(
d72b084a 254 'title' => ts('Credit Card Type'),
62a40853 255 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
5e0343e8 256 'options' => CRM_Financial_DAO_FinancialTrxn::buildOptions('card_type_id'),
62a40853
E
257 'default' => NULL,
258 'type' => CRM_Utils_Type::T_STRING,
259 ),
260 ),
261 ),
262 );
6a488035 263
d62fab33 264 // If we have a campaign, build out the relevant elements
689c6bd2 265 $this->addCampaignFields('civicrm_contribution');
d62fab33 266
16e2e80c 267 $this->_groupFilter = TRUE;
6a488035
TO
268 $this->_tagFilter = TRUE;
269 parent::__construct();
270 }
271
c160fde8 272 /**
273 * Build select clause for a single field.
274 *
275 * @param string $tableName
276 * @param string $tableKey
277 * @param string $fieldName
278 * @param string $field
279 *
280 * @return string
281 */
282 public function selectClause(&$tableName, $tableKey, &$fieldName, &$field) {
283 if ($fieldName == 'last_year_total_amount') {
284 $this->_columnHeaders["{$tableName}_{$fieldName}"] = $field;
285 $this->_columnHeaders["{$tableName}_{$fieldName}"]['title'] = $this->getLastYearColumnTitle();
286 $this->_statFields[$this->getLastYearColumnTitle()] = "{$tableName}_{$fieldName}";
287 return "SUM(IF(" . $this->whereClauseLastYear('contribution_civireport.receive_date') . ", contribution_civireport.total_amount, 0)) as {$tableName}_{$fieldName}";
288 }
289 if ($fieldName == 'civicrm_life_time_total') {
290 $this->_columnHeaders["{$tableName}_{$fieldName}"] = $field;
291 $this->_statFields[$field['title']] = "{$tableName}_{$fieldName}";
292 return "SUM({$this->_aliases[$tableName]}.total_amount) as {$tableName}_{$fieldName}";
293 }
294 if ($fieldName == 'receive_date') {
295 return self::fiscalYearOffset($field['dbAlias']) .
296 " as {$tableName}_{$fieldName} ";
297 }
298 return FALSE;
299 }
6a488035 300
c160fde8 301 /**
302 * Get the title for the last year column.
303 */
304 public function getLastYearColumnTitle() {
305 if ($this->getYearFilterType() == 'calendar') {
306 return ts('Total for ') . ($this->getCurrentYear() - 1);
307 }
308 return ts('Total for Fiscal Year ') . ($this->getCurrentYear() - 1) . '-' . ($this->getCurrentYear());
309 }
6a488035 310
c160fde8 311 /**
312 * Construct from clause.
313 *
314 * On the first run we are creating a table of contacts to include in the report.
315 *
316 * Once contactTempTable is populated we should avoid using any further filters that affect
317 * the contacts that should be visible.
318 */
319 public function from() {
320 if (!empty($this->contactTempTable)) {
321 $this->_from = "
322 FROM civicrm_contribution {$this->_aliases['civicrm_contribution']}
323 INNER JOIN $this->contactTempTable restricted_contacts
324 ON restricted_contacts.cid = {$this->_aliases['civicrm_contribution']}.contact_id
325 AND {$this->_aliases['civicrm_contribution']}.is_test = 0
326 INNER JOIN civicrm_contact {$this->_aliases['civicrm_contact']}
327 ON restricted_contacts.cid = {$this->_aliases['civicrm_contact']}.id";
18f511e2 328
329 $this->joinAddressFromContact();
330 $this->joinPhoneFromContact();
331 $this->joinEmailFromContact();
6a488035 332 }
c160fde8 333 else {
87755286 334 $this->setFromBase('civicrm_contact');
6a488035 335
c160fde8 336 $this->_from .= " INNER JOIN civicrm_contribution {$this->_aliases['civicrm_contribution']} ";
337 if (!$this->groupTempTable) {
338 // The received_date index is better than the contribution_status_id index (fairly substantially).
339 // But if we have already pre-filtered down to a group of contacts then we want that to be the
340 // primary filter and the index hint will block that.
341 $this->_from .= "USE index (received_date)";
342 }
343 $this->_from .= " ON {$this->_aliases['civicrm_contribution']}.contact_id = {$this->_aliases['civicrm_contact']}.id
344 AND {$this->_aliases['civicrm_contribution']}.is_test = 0
345 AND " . $this->whereClauseLastYear("{$this->_aliases['civicrm_contribution']}.receive_date") . "
1679e19c 346 {$this->_aclFrom} ";
c160fde8 347 $this->selectivelyAddLocationTablesJoinsToFilterQuery();
348 }
6a488035 349
62a40853
E
350 // for credit card type
351 $this->addFinancialTrxnFromClause();
c160fde8 352 }
6a488035 353
c160fde8 354 /**
355 * Generate where clause.
356 *
357 * We are overriding this primarily for 'before-after' handling of the receive_date placeholder field.
358 *
359 * We call this twice. The first time we are generating a temp table and we want to do an IS NULL on the
360 * join that draws in contributions from this year. The second time we are filtering elsewhere (contacts via
361 * the temp table & contributions via selective addition of contributions in the select function).
362 *
363 * If lifetime total is NOT selected we can add a further filter here to possibly improve performance
364 * but the benefit if unproven as yet.
365 * $clause = $this->whereClauseLastYear("{$this->_aliases['civicrm_contribution']}.receive_date");
366 *
367 * @param array $field Field specifications
368 * @param string $op Query operator (not an exact match to sql)
369 * @param mixed $value
370 * @param float $min
371 * @param float $max
372 *
373 * @return null|string
374 */
375 public function whereClause(&$field, $op, $value, $min, $max) {
376 if ($field['name'] == 'receive_date') {
377 $clause = 1;
378 if (empty($this->contactTempTable)) {
1679e19c 379 $clause = "{$this->_aliases['civicrm_contact']}.id NOT IN (
380 SELECT cont_exclude.contact_id
381 FROM civicrm_contribution cont_exclude
382 WHERE " . $this->whereClauseThisYear('cont_exclude.receive_date')
383 . ")";
c160fde8 384 }
385 }
87755286 386 // Group filtering is already done so skip.
387 elseif (!empty($field['group']) && $this->contactTempTable) {
388 return 1;
389 }
c160fde8 390 else {
391 $clause = parent::whereClause($field, $op, $value, $min, $max);
a27c90f2 392 }
c160fde8 393 return $clause;
6a488035
TO
394 }
395
c160fde8 396 /**
397 * Generate where clause for last calendar year or fiscal year.
398 *
399 * @todo must be possible to re-use relative dates stuff.
400 *
401 * @param string $fieldName
402 *
403 * @return string
404 */
405 public function whereClauseLastYear($fieldName) {
406 return "$fieldName BETWEEN '" . $this->getFirstDateOfPriorRange() . "' AND '" . $this->getLastDateOfPriorRange() . "'";
6a488035
TO
407 }
408
a7d034b3 409 /**
410 * Generate where clause for last calendar year or fiscal year.
411 *
412 * @todo must be possible to re-use relative dates stuff.
413 *
414 * @param string $fieldName
415 *
c160fde8 416 * @param int $current_year
a7d034b3 417 * @return null|string
418 */
c160fde8 419 public function whereClauseThisYear($fieldName, $current_year = NULL) {
420 return "$fieldName BETWEEN '" . $this->getFirstDateOfCurrentRange() . "' AND '" . $this->getLastDateOfCurrentRange() . "'";
421 }
422
423
424 /**
425 * Get the year value for the current year.
426 *
427 * @return string
428 */
429 public function getCurrentYear() {
430 return $this->_params['yid_value'];
431 }
432
433 /**
434 * Get the date time of the first date in the 'this year' range.
435 *
436 * @return string
437 */
438 public function getFirstDateOfCurrentRange() {
439 $current_year = $this->getCurrentYear();
440 if ($this->getYearFilterType() == 'calendar') {
441 return "{$current_year }-01-01";
a7d034b3 442 }
443 else {
444 $fiscalYear = CRM_Core_Config::singleton()->fiscalYearStart;
c160fde8 445 return "{$current_year}-{$fiscalYear['M']}-{$fiscalYear['d']}";
a7d034b3 446 }
a7d034b3 447 }
448
c160fde8 449 /**
450 * Get the year value for the current year.
451 *
452 * @return string
453 */
454 public function getYearFilterType() {
455 return CRM_Utils_Array::value('yid_op', $this->_params, 'calendar');
456 }
a7d034b3 457
c160fde8 458 /**
459 * Get the date time of the last date in the 'this year' range.
460 *
461 * @return string
462 */
463 public function getLastDateOfCurrentRange() {
464 return date('YmdHis', strtotime('+ 1 year - 1 second', strtotime($this->getFirstDateOfCurrentRange())));
465 }
a7d034b3 466
c160fde8 467 /**
468 * Get the date time of the first date in the 'last year' range.
469 *
470 * @return string
471 */
472 public function getFirstDateOfPriorRange() {
473 return date('YmdHis', strtotime('- 1 year', strtotime($this->getFirstDateOfCurrentRange())));
474 }
a7d034b3 475
c160fde8 476 /**
477 * Get the date time of the last date in the 'last year' range.
478 *
479 * @return string
480 */
481 public function getLastDateOfPriorRange() {
482 return date('YmdHis', strtotime('+ 1 year - 1 second', strtotime($this->getFirstDateOfPriorRange())));
483 }
484
485
486 public function groupBy() {
487 $this->_groupBy = "GROUP BY {$this->_aliases['civicrm_contribution']}.contact_id ";
36d2f4d5 488 $this->_select = CRM_Contact_BAO_Query::appendAnyValueToSelect($this->_selectClauses, "{$this->_aliases['civicrm_contribution']}.contact_id");
6a488035
TO
489 $this->assign('chartSupported', TRUE);
490 }
491
74cf4551
EM
492 /**
493 * @param $rows
494 *
495 * @return array
496 */
00be9182 497 public function statistics(&$rows) {
c160fde8 498
6a488035 499 $statistics = parent::statistics($rows);
c160fde8 500 // The parent class does something odd where it adds an extra row to the count for the grand total.
501 // Perhaps that works on some other report? But here it just seems odd.
502 $this->countStat($statistics, count($rows));
6a488035 503 if (!empty($rows)) {
c160fde8 504 if (!empty($this->rollupRow) && !empty($this->rollupRow['civicrm_contribution_last_year_total_amount'])) {
505 $statistics['counts']['civicrm_contribution_last_year_total_amount'] = array(
506 'value' => $this->rollupRow['civicrm_contribution_last_year_total_amount'],
507 'title' => $this->getLastYearColumnTitle(),
508 'type' => CRM_Utils_Type::T_MONEY,
509 );
510
511 }
512 if (!empty($this->rollupRow) && !empty($this->rollupRow['civicrm_contribution_civicrm_life_time_total'])) {
513 $statistics['counts']['civicrm_contribution_civicrm_life_time_total'] = array(
514 'value' => $this->rollupRow['civicrm_contribution_civicrm_life_time_total'],
515 'title' => ts('Total LifeTime'),
6a488035
TO
516 'type' => CRM_Utils_Type::T_MONEY,
517 );
518 }
c160fde8 519 else {
520 $select = "SELECT SUM({$this->_aliases['civicrm_contribution']}.total_amount) as amount,
521 SUM(IF( " . $this->whereClauseLastYear('contribution_civireport.receive_date') . ", contribution_civireport.total_amount, 0)) as last_year
522 ";
523 $sql = "{$select} {$this->_from} {$this->_where}";
524 $dao = CRM_Core_DAO::executeQuery($sql);
525 if ($dao->fetch()) {
526 $statistics['counts']['amount'] = array(
527 'value' => $dao->amount,
528 'title' => ts('Total LifeTime'),
529 'type' => CRM_Utils_Type::T_MONEY,
530 );
531 $statistics['counts']['last_year'] = array(
532 'value' => $dao->last_year,
533 'title' => $this->getLastYearColumnTitle(),
534 'type' => CRM_Utils_Type::T_MONEY,
535 );
536 }
537 }
6a488035
TO
538 }
539
540 return $statistics;
541 }
542
c160fde8 543 /**
544 * This function is called by both the api (tests) and the UI.
545 */
546 public function beginPostProcessCommon() {
a7d034b3 547 $this->buildQuery();
c160fde8 548 // @todo this acl has no test coverage and is very hard to test manually so could be fragile.
4400048b 549 $this->resetFormSqlAndWhereHavingClauses();
6a488035 550
f0197a3d 551 $this->contactTempTable = $this->createTemporaryTable('rptlybunt', "
552 SELECT SQL_CALC_FOUND_ROWS {$this->_aliases['civicrm_contact']}.id as cid {$this->_from}
553 {$this->_where}
554 GROUP BY {$this->_aliases['civicrm_contact']}.id"
555 );
e463c072 556 $this->limit();
e463c072 557 if (empty($this->_params['charts'])) {
6a488035
TO
558 $this->setPager();
559 }
560
c160fde8 561 // Reset where clauses to be regenerated in postProcess.
562 $this->_whereClauses = array();
563 }
a7d034b3 564
c160fde8 565 /**
566 * Build the report query.
567 *
568 * The issue we are hitting is that if we want to do group by & then ORDER BY we have to
569 * wrap the query in an outer query with the order by - otherwise the group by takes precedent.
570 * This is an issue when we want to group by contact but order by the maximum aggregate donation.
571 *
572 * @param bool $applyLimit
573 *
574 * @return string
575 */
576 public function buildQuery($applyLimit = TRUE) {
87755286 577 $this->buildGroupTempTable();
f0384ec0 578 $this->buildPermissionClause();
2c0e8e6b 579 // Calling where & select before FROM allows us to build temp tables to use in from.
580 $this->where();
c160fde8 581 $this->select();
582 $this->from();
583 $this->customDataFrom(empty($this->contactTempTable));
2c0e8e6b 584
c160fde8 585 $this->groupBy();
586 $this->orderBy();
c160fde8 587 $limitFilter = '';
588
589 // order_by columns not selected for display need to be included in SELECT
590 // This differs from parent in that we are getting those not in order by rather than not in
591 // sections, as we need to adapt to our contact group by.
592 $unselectedSectionColumns = array_diff_key($this->_orderByFields, $this->getSelectColumns());
593 foreach ($unselectedSectionColumns as $alias => $section) {
594 $this->_select .= ", {$section['dbAlias']} as {$alias}";
595 }
6a488035 596
c160fde8 597 if ($applyLimit && empty($this->_params['charts'])) {
598 $this->limit();
599 }
6a488035 600
bad98dd5 601 $sql = "{$this->_select} {$this->_from} {$this->_where} {$limitFilter} {$this->_groupBy} {$this->_having} {$this->_rollup}";
6a488035 602
c160fde8 603 if (!empty($this->_orderByArray)) {
604 $this->_orderBy = str_replace('contact_civireport.', 'civicrm_contact_', "ORDER BY ISNULL(civicrm_contribution_contact_id), " . implode(', ', $this->_orderByArray));
605 $this->_orderBy = str_replace('contribution_civireport.', 'civicrm_contribution_', $this->_orderBy);
606 foreach ($this->_orderByFields as $field) {
607 $this->_orderBy = str_replace($field['dbAlias'], $field['tplField'], $this->_orderBy);
6a488035 608 }
c160fde8 609 $sql = str_replace('SQL_CALC_FOUND_ROWS', '', $sql);
610 $sql = "SELECT SQL_CALC_FOUND_ROWS * FROM ( $sql ) as inner_query {$this->_orderBy} $this->_limit";
6a488035
TO
611 }
612
c160fde8 613 CRM_Utils_Hook::alterReportVar('sql', $this, $this);
614 $this->addToDeveloperTab($sql);
6a488035 615
c160fde8 616 return $sql;
6a488035
TO
617 }
618
a7d034b3 619 /**
4400048b 620 * Reset the form sql and where / having clause arrays.
621 *
622 * We do an early iteration of the report queries to generate the temp table.
623 *
624 * However, that iteration populates the sql for the developer tab,
625 * the whereClauses & the havingClauses and they are populated again in the normal
626 * report flow. This is harmless but confusing - ie. the where clause winds up repeating
627 * the same filters and the dev tab shows the query twice, so we rest them.
a7d034b3 628 */
4400048b 629 protected function resetFormSqlAndWhereHavingClauses() {
a7d034b3 630 $this->sql = '';
4400048b 631 $this->_havingClauses = array();
632 $this->_whereClauses = array();
c160fde8 633 $this->sqlArray = array();
a7d034b3 634 }
635
74cf4551
EM
636 /**
637 * @param $rows
638 */
00be9182 639 public function buildChart(&$rows) {
6a488035
TO
640
641 $graphRows = array();
9d72cede
EM
642 $count = 0;
643 $display = array();
6a488035
TO
644
645 $current_year = $this->_params['yid_value'];
646 $previous_year = $current_year - 1;
647 $interval[$previous_year] = $previous_year;
648 $interval['life_time'] = 'Life Time';
649
650 foreach ($rows as $key => $row) {
9d72cede
EM
651 $display['life_time'] = CRM_Utils_Array::value('life_time', $display) +
652 $row['civicrm_life_time_total'];
ae5ffbb7 653 $display[$previous_year] = CRM_Utils_Array::value($previous_year, $display) + $row[$previous_year];
6a488035
TO
654 }
655
9d72cede 656 $config = CRM_Core_Config::Singleton();
6a488035 657 $graphRows['value'] = $display;
9d72cede
EM
658 $chartInfo = array(
659 'legend' => ts('Lybunt Report'),
6a488035
TO
660 'xname' => ts('Year'),
661 'yname' => ts('Amount (%1)', array(1 => $config->defaultCurrency)),
662 );
663 if ($this->_params['charts']) {
664 // build chart.
665 CRM_Utils_OpenFlashChart::reportChart($graphRows, $this->_params['charts'], $interval, $chartInfo);
666 $this->assign('chartType', $this->_params['charts']);
667 }
668 }
669
74cf4551 670 /**
ced9bfed
EM
671 * Alter display of rows.
672 *
673 * Iterate through the rows retrieved via SQL and make changes for display purposes,
674 * such as rendering contacts as links.
675 *
676 * @param array $rows
677 * Rows generated by SQL, with an array for each row.
74cf4551 678 */
00be9182 679 public function alterDisplay(&$rows) {
72a9af52
NG
680 $entryFound = FALSE;
681
6a488035
TO
682 foreach ($rows as $rowNum => $row) {
683 //Convert Display name into link
684 if (array_key_exists('civicrm_contact_sort_name', $row) &&
685 array_key_exists('civicrm_contribution_contact_id', $row)
686 ) {
687 $url = CRM_Report_Utils_Report::getNextUrl('contribute/detail',
9d72cede
EM
688 'reset=1&force=1&id_op=eq&id_value=' .
689 $row['civicrm_contribution_contact_id'],
6a488035
TO
690 $this->_absoluteUrl, $this->_id, $this->_drilldownReport
691 );
692 $rows[$rowNum]['civicrm_contact_sort_name_link'] = $url;
693 $rows[$rowNum]['civicrm_contact_sort_name_hover'] = ts("View Contribution Details for this Contact.");
72a9af52 694 $entryFound = TRUE;
6a488035 695 }
d62fab33
RN
696
697 // convert campaign_id to campaign title
698 if (array_key_exists('civicrm_contribution_campaign_id', $row)) {
699 if ($value = $row['civicrm_contribution_campaign_id']) {
700 $rows[$rowNum]['civicrm_contribution_campaign_id'] = $this->activeCampaigns[$value];
701 $entryFound = TRUE;
702 }
703 }
0a618a8d 704 // Display 'Yes' if the email is on hold (leave blank for no so it stands out better).
705 if (array_key_exists('civicrm_email_on_hold', $row)) {
706 $rows[$rowNum]['civicrm_email_on_hold'] = $row['civicrm_email_on_hold'] ? ts('Yes') : '';
707 $entryFound = TRUE;
708 }
a27c90f2 709
c160fde8 710 $entryFound = $this->alterDisplayAddressFields($row, $rows, $rowNum, NULL, 'List all contribution(s)') ? TRUE : $entryFound;
711 $entryFound = $this->alterDisplayContactFields($row, $rows, $rowNum, NULL, 'List all contribution(s)') ? TRUE : $entryFound;
49e1ea9f 712 //handle gender
713 if (array_key_exists('civicrm_contact_gender_id', $row)) {
714 if ($value = $row['civicrm_contact_gender_id']) {
715 $gender = CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'gender_id');
716 $rows[$rowNum]['civicrm_contact_gender_id'] = $gender[$value];
717 }
718 $entryFound = TRUE;
719 }
720
721 // display birthday in the configured custom format
722 if (array_key_exists('civicrm_contact_birth_date', $row)) {
723 $birthDate = $row['civicrm_contact_birth_date'];
724 if ($birthDate) {
725 $rows[$rowNum]['civicrm_contact_birth_date'] = CRM_Utils_Date::customFormat($birthDate, '%Y%m%d');
726 }
727 $entryFound = TRUE;
728 }
729
5e0343e8 730 if (!empty($row['civicrm_financial_trxn_card_type_id'])) {
731 $rows[$rowNum]['civicrm_financial_trxn_card_type_id'] = $this->getLabels($row['civicrm_financial_trxn_card_type_id'], 'CRM_Financial_DAO_FinancialTrxn', 'card_type_id');
62a40853
E
732 $entryFound = TRUE;
733 }
734
72a9af52
NG
735 // skip looking further in rows, if first row itself doesn't
736 // have the column we need
737 if (!$entryFound) {
738 break;
a27c90f2 739 }
6a488035
TO
740 }
741 }
742
74cf4551 743 /**
4f1f1f2a 744 * Override "This Year" $op options
74cf4551
EM
745 * @param string $type
746 * @param null $fieldName
747 *
748 * @return array
749 */
00be9182 750 public function getOperationPair($type = "string", $fieldName = NULL) {
6a488035 751 if ($fieldName == 'yid') {
9d72cede
EM
752 return array(
753 'calendar' => ts('Is Calendar Year'),
21dfd5f5 754 'fiscal' => ts('Fiscal Year Starting'),
9d72cede 755 );
6a488035
TO
756 }
757 return parent::getOperationPair($type, $fieldName);
758 }
96025800 759
6a488035 760}