Merge pull request #48 from dpradeep/merge-forward
[civicrm-core.git] / CRM / Report / Form / Contribute / Repeat.php
CommitLineData
6a488035 1<?php
6a488035
TO
2
3/*
4 +--------------------------------------------------------------------+
06b69b18 5 | CiviCRM version 4.5 |
6a488035 6 +--------------------------------------------------------------------+
06b69b18 7 | Copyright CiviCRM LLC (c) 2004-2014 |
6a488035
TO
8 +--------------------------------------------------------------------+
9 | This file is a part of CiviCRM. |
10 | |
11 | CiviCRM is free software; you can copy, modify, and distribute it |
12 | under the terms of the GNU Affero General Public License |
13 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | |
15 | CiviCRM is distributed in the hope that it will be useful, but |
16 | WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
18 | See the GNU Affero General Public License for more details. |
19 | |
20 | You should have received a copy of the GNU Affero General Public |
21 | License and the CiviCRM Licensing Exception along |
22 | with this program; if not, contact CiviCRM LLC |
23 | at info[AT]civicrm[DOT]org. If you have questions about the |
24 | GNU Affero General Public License or the licensing of CiviCRM, |
25 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
26 +--------------------------------------------------------------------+
27*/
28
29/**
30 *
31 * @package CRM
06b69b18 32 * @copyright CiviCRM LLC (c) 2004-2014
6a488035
TO
33 * $Id$
34 *
35 */
36class CRM_Report_Form_Contribute_Repeat extends CRM_Report_Form {
37 protected $_amountClauseWithAND = NULL;
38
39 public $_drilldownReport = array('contribute/detail' => 'Link to Detail Report');
40
74cf4551
EM
41 /**
42 *
43 */
44 /**
45 *
46 */
6a488035
TO
47 function __construct() {
48 $this->_columns = array(
49 'civicrm_contact' =>
50 array(
51 'dao' => 'CRM_Contact_DAO_Contact',
52 'grouping' => 'contact-fields',
53 'fields' =>
54 array(
55 'sort_name' =>
56 array(
57 'title' => ts('Contact Name'),
58 'no_repeat' => TRUE,
59 'default' => TRUE,
60 ),
61 'display_name' =>
62 array(
63 'title' => ts('Display Name'),
64 'no_repeat' => TRUE,
65 ),
66 'addressee_display' =>
67 array(
68 'title' => ts('Addressee Name'),
69 'no_repeat' => TRUE,
70 ),
71 'id' =>
72 array(
73 'no_display' => TRUE,
74 'required' => TRUE,
75 ),
30f85891
RN
76 'contact_type' =>
77 array(
78 'title' => ts('Contact Type'),
79 'no_repeat' => TRUE,
80 ),
81 'contact_sub_type' =>
82 array(
83 'title' => ts('Contact SubType'),
84 'no_repeat' => TRUE,
85 ),
6a488035
TO
86 ),
87 'filters' =>
88 array(
89 'percentage_change' =>
90 array(
91 'title' => ts('Percentage Change'),
92 'type' => CRM_Utils_Type::T_INT,
93 'operatorType' => CRM_Report_Form::OP_INT,
94 'name' => 'percentage_change',
95 'dbAlias' => '( ( contribution_civireport2.total_amount_sum - contribution_civireport1.total_amount_sum ) * 100 / contribution_civireport1.total_amount_sum )',
96 ),
97 ),
98 'group_bys' =>
99 array(
100 'id' =>
101 array(
102 'title' => ts('Contact'),
103 'default' => TRUE,
104 ),
105 ),
106 ),
107 'civicrm_email' =>
108 array(
109 'dao' => 'CRM_Core_DAO_Email',
110 'fields' =>
111 array(
112 'email' =>
113 array(
114 'title' => ts('Email'),
115 'no_repeat' => TRUE,
116 ),
117 ),
118 'grouping' => 'contact-fields',
119 ),
120 'civicrm_phone' =>
121 array(
122 'dao' => 'CRM_Core_DAO_Phone',
123 'fields' =>
124 array(
125 'phone' =>
126 array(
127 'title' => ts('Phone'),
128 'no_repeat' => TRUE,
129 ),
130 ),
131 'grouping' => 'contact-fields',
132 ),
133 'civicrm_address' =>
134 array(
135 'dao' => 'CRM_Core_DAO_Address',
136 'grouping' => 'contact-fields',
137 'fields' =>
138 array(
139 'street_address' => array('title' => ts('Street Address')),
c29131ec 140 'supplemental_address_1' => array('title' => ts('Supplemental Address 1')),
6a488035
TO
141 'city' => array('title' => ts('City')),
142 'country_id' => array('title' => ts('Country')),
143 'state_province_id' => array('title' => ts('State/Province')),
144 'postal_code' => array('title' => ts('Postal Code')),
145 ),
146 'group_bys' =>
147 array(
148 'country_id' => array('title' => ts('Country')),
149 'state_province_id' => array('title' => ts('State/Province'),
150 ),
151 ),
152 ),
153 'civicrm_financial_type' =>
154 array(
b914f4e8
PN
155 'dao' => 'CRM_Financial_DAO_FinancialType',
156 'fields' => array('financial_type' => array('title' => ts('Financial Type'))),
6a488035
TO
157 'grouping' => 'contri-fields',
158 'group_bys' =>
b914f4e8 159 array('financial_type' =>
6a488035
TO
160 array(
161 'name' => 'id',
162 'title' => ts('Financial Type'),
163 ),
164 ),
165 ),
166 'civicrm_contribution' =>
167 array(
168 'dao' => 'CRM_Contribute_DAO_Contribution',
169 'fields' =>
170 array(
171 'contribution_source' => NULL,
172 'total_amount1' =>
173 array(
174 'name' => 'total_amount',
175 'alias' => 'contribution1',
176 'title' => ts('Range One Stat'),
177 'type' => CRM_Utils_Type::T_MONEY,
178 'default' => TRUE,
179 'required' => TRUE,
180 'clause' => '
2f4c2f5d 181contribution_civireport1.total_amount_count as contribution1_total_amount_count,
6a488035
TO
182contribution_civireport1.total_amount_sum as contribution1_total_amount_sum',
183 ),
184 'total_amount2' =>
185 array(
186 'name' => 'total_amount',
187 'alias' => 'contribution2',
188 'title' => ts('Range Two Stat'),
189 'type' => CRM_Utils_Type::T_MONEY,
190 'default' => TRUE,
191 'required' => TRUE,
192 'clause' => '
2f4c2f5d 193contribution_civireport2.total_amount_count as contribution2_total_amount_count,
6a488035
TO
194contribution_civireport2.total_amount_sum as contribution2_total_amount_sum',
195 ),
196 ),
197 'grouping' => 'contri-fields',
198 'filters' =>
199 array(
200 'receive_date1' =>
201 array(
202 'title' => ts('Initial Date Range'),
203 'default' => 'previous.year',
204 'type' => CRM_Utils_Type::T_DATE,
205 'operatorType' => CRM_Report_Form::OP_DATE,
206 'name' => 'receive_date',
207 ),
208 'receive_date2' =>
209 array(
210 'title' => ts('Second Date Range'),
211 'default' => 'this.year',
212 'type' => CRM_Utils_Type::T_DATE,
213 'operatorType' => CRM_Report_Form::OP_DATE,
214 'name' => 'receive_date',
215 ),
216 'total_amount1' =>
217 array(
218 'title' => ts('Range One Amount'),
219 'type' => CRM_Utils_Type::T_INT,
220 'operatorType' => CRM_Report_Form::OP_INT,
221 'name' => 'total_amount',
222 ),
223 'total_amount2' =>
224 array(
225 'title' => ts('Range Two Amount'),
226 'type' => CRM_Utils_Type::T_INT,
227 'operatorType' => CRM_Report_Form::OP_INT,
228 'name' => 'total_amount',
229 ),
b914f4e8 230 'financial_type_id' =>
6a488035 231 array(
b914f4e8 232 'title' => ts('Financial Type'),
6a488035 233 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
b914f4e8 234 'options' => CRM_Contribute_PseudoConstant::financialType(),
6a488035
TO
235 ),
236 'contribution_status_id' =>
237 array(
b914f4e8 238 'title' => ts('Contribution Status'),
6a488035
TO
239 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
240 'options' => CRM_Contribute_PseudoConstant::contributionStatus(),
241 'default' => array('1'),
242 ),
243 ),
244 'group_bys' => array('contribution_source' => NULL),
245 ),
246 'civicrm_group' =>
247 array(
248 'dao' => 'CRM_Contact_DAO_GroupContact',
249 'alias' => 'cgroup',
250 'filters' =>
251 array(
252 'gid' =>
253 array(
254 'name' => 'group_id',
255 'title' => ts('Group'),
256 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
257 'group' => TRUE,
258 'options' => CRM_Core_PseudoConstant::group(),
259 ),
260 ),
261 ),
262 );
263
264 $this->_tagFilter = TRUE;
265
266 parent::__construct();
267 }
268
269 function preProcess() {
270 parent::preProcess();
271 }
272
74cf4551
EM
273 /**
274 * @param bool $freeze
275 *
276 * @return array
277 */
6a488035
TO
278 function setDefaultValues($freeze = TRUE) {
279 return parent::setDefaultValues($freeze);
280 }
281
282 function select() {
283 $select = array();
284 $append = NULL;
285 // since contact fields not related to financial type
b914f4e8 286 if (array_key_exists('financial_type', $this->_params['group_bys']) ||
6a488035
TO
287 array_key_exists('contribution_source', $this->_params['group_bys'])
288 ) {
289 unset($this->_columns['civicrm_contact']['fields']['id']);
290 }
291
292 foreach ($this->_columns as $tableName => $table) {
293 if (array_key_exists('fields', $table)) {
294 foreach ($table['fields'] as $fieldName => $field) {
8cc574cf 295 if (!empty($field['required']) || !empty($this->_params['fields'][$fieldName])) {
6a488035
TO
296 if (isset($field['clause'])) {
297 $select[] = $field['clause'];
298
299 // FIXME: dirty hack for setting columnHeaders
300 $this->_columnHeaders["{$field['alias']}_{$field['name']}_sum"]['type'] = CRM_Utils_Array::value('type', $field);
301 $this->_columnHeaders["{$field['alias']}_{$field['name']}_sum"]['title'] = $field['title'];
302 $this->_columnHeaders["{$field['alias']}_{$field['name']}_count"]['type'] = CRM_Utils_Array::value('type', $field);
303 $this->_columnHeaders["{$field['alias']}_{$field['name']}_count"]['title'] = $field['title'];
304 continue;
305 }
306
307 // only include statistics columns if set
308 $select[] = "{$field['dbAlias']} as {$field['alias']}_{$field['name']}";
309 $this->_columnHeaders["{$field['alias']}_{$field['name']}"]['type'] = CRM_Utils_Array::value('type', $field);
310 $this->_columnHeaders["{$field['alias']}_{$field['name']}"]['title'] = CRM_Utils_Array::value('title', $field);
a7488080 311 if (!empty($field['no_display'])) {
6a488035
TO
312 $this->_columnHeaders["{$field['alias']}_{$field['name']}"]['no_display'] = TRUE;
313 }
314 }
315 }
316 }
317 }
318
319 $this->_select = "SELECT " . implode(', ', $select) . " ";
320 }
321
74cf4551
EM
322 /**
323 * @param bool $tableCol
324 */
6a488035
TO
325 function groupBy($tableCol = FALSE) {
326 $this->_groupBy = "";
327 if (!empty($this->_params['group_bys']) && is_array($this->_params['group_bys'])) {
328 foreach ($this->_columns as $tableName => $table) {
329 if (array_key_exists('group_bys', $table)) {
330 foreach ($table['group_bys'] as $fieldName => $field) {
a7488080 331 if (!empty($this->_params['group_bys'][$fieldName])) {
6a488035
TO
332 if ($tableCol) {
333 return array($tableName, $field['alias'], $field['name']);
334 }
335 else {
336 $this->_groupBy[] = "{$field['dbAlias']}";
337 }
338 }
339 }
340 }
341 }
342
343 $this->_groupBy = "GROUP BY " . implode(', ', $this->_groupBy);
344 }
345 }
346
347 function from() {
348 list($fromTable, $fromAlias, $fromCol) = $this->groupBy(TRUE);
349 $from = "$fromTable $fromAlias";
350
351 if ($fromTable == 'civicrm_contact') {
352 $contriCol = "contact_id";
353 $from .= "
354LEFT JOIN civicrm_address {$this->_aliases['civicrm_address']} ON {$this->_aliases['civicrm_contact']}.id = {$this->_aliases['civicrm_address']}.contact_id
355LEFT JOIN civicrm_email {$this->_aliases['civicrm_email']}
356 ON {$this->_aliases['civicrm_contact']}.id = {$this->_aliases['civicrm_email']}.contact_id AND {$this->_aliases['civicrm_email']}.is_primary = 1
357LEFT JOIN civicrm_phone {$this->_aliases['civicrm_phone']}
358 ON {$this->_aliases['civicrm_contact']}.id = {$this->_aliases['civicrm_phone']}.contact_id AND {$this->_aliases['civicrm_phone']}.is_primary = 1";
359
360 }
b914f4e8
PN
361 else if ($fromTable == 'civicrm_financial_type') {
362 $contriCol = "financial_type_id";
6a488035
TO
363 }
364 elseif ($fromTable == 'civicrm_contribution') {
365 $contriCol = $fromCol;
366 }
367 elseif ($fromTable == 'civicrm_address') {
368 $from .= "
369INNER JOIN civicrm_contact {$this->_aliases['civicrm_contact']} ON {$this->_aliases['civicrm_address']}.contact_id = {$this->_aliases['civicrm_contact']}.id";
370 $fromAlias = $this->_aliases['civicrm_contact'];
371 $fromCol = "id";
372 $contriCol = "contact_id";
373 }
374
375 $this->_from = "
376FROM $from
377LEFT JOIN civicrm_temp_civireport_repeat1 {$this->_aliases['civicrm_contribution']}1
378 ON $fromAlias.$fromCol = {$this->_aliases['civicrm_contribution']}1.$contriCol
379LEFT JOIN civicrm_temp_civireport_repeat2 {$this->_aliases['civicrm_contribution']}2
380 ON $fromAlias.$fromCol = {$this->_aliases['civicrm_contribution']}2.$contriCol";
381 }
382
74cf4551
EM
383 /**
384 * @param string $replaceAliasWith
385 *
386 * @return mixed|string
387 */
6a488035
TO
388 function whereContribution($replaceAliasWith = 'contribution1') {
389 $clauses = array("is_test" => "{$this->_aliases['civicrm_contribution']}.is_test = 0");
390
391 foreach ($this->_columns['civicrm_contribution']['filters'] as $fieldName => $field) {
392 $clause = NULL;
393 if (CRM_Utils_Array::value('type', $field) & CRM_Utils_Type::T_DATE) {
394 $relative = CRM_Utils_Array::value("{$fieldName}_relative", $this->_params);
395 $from = CRM_Utils_Array::value("{$fieldName}_from", $this->_params);
396 $to = CRM_Utils_Array::value("{$fieldName}_to", $this->_params);
397
398 $clause = $this->dateClause($field['dbAlias'], $relative, $from, $to, $field['type']);
399 }
400 else {
401 $op = CRM_Utils_Array::value("{$fieldName}_op", $this->_params);
402 if ($op) {
403 $clause = $this->whereClause($field,
404 $op,
405 CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
406 CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
407 CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
408 );
409 }
410 }
411 if (!empty($clause)) {
412 $clauses[$fieldName] = $clause;
413 }
414 }
415
416 if (!$this->_amountClauseWithAND) {
417 $amountClauseWithAND = array();
a7488080 418 if (!empty($clauses['total_amount1'])) {
6a488035
TO
419 $amountClauseWithAND[] = str_replace("{$this->_aliases['civicrm_contribution']}.total_amount",
420 "{$this->_aliases['civicrm_contribution']}1.total_amount_sum", $clauses['total_amount1']);
421 }
a7488080 422 if (!empty($clauses['total_amount2'])) {
6a488035
TO
423 $amountClauseWithAND[] = str_replace("{$this->_aliases['civicrm_contribution']}.total_amount",
424 "{$this->_aliases['civicrm_contribution']}2.total_amount_sum", $clauses['total_amount2']);
425 }
426 $this->_amountClauseWithAND = !empty($amountClauseWithAND) ? implode(' AND ', $amountClauseWithAND) : NULL;
427 }
428
429 if ($replaceAliasWith == 'contribution1') {
430 unset($clauses['receive_date2'], $clauses['total_amount2']);
431 }
432 else {
433 unset($clauses['receive_date1'], $clauses['total_amount1']);
434 }
435
436 $whereClause = !empty($clauses) ? "WHERE " . implode(' AND ', $clauses) : '';
437
438 if ($replaceAliasWith) {
439 $whereClause = str_replace($this->_aliases['civicrm_contribution'], $replaceAliasWith, $whereClause);
440 }
441
442 return $whereClause;
443 }
444
445 function where() {
446 if (!$this->_amountClauseWithAND) {
447 $this->_amountClauseWithAND =
448 "!({$this->_aliases['civicrm_contribution']}1.total_amount_count IS NULL AND {$this->_aliases['civicrm_contribution']}2.total_amount_count IS NULL)";
449 }
450 $clauses = array("atleast_one_amount" => $this->_amountClauseWithAND);
451
452 foreach ($this->_columns as $tableName => $table) {
453 if (array_key_exists('filters', $table) && $tableName != 'civicrm_contribution') {
454 foreach ($table['filters'] as $fieldName => $field) {
455 $clause = NULL;
456 $op = CRM_Utils_Array::value("{$fieldName}_op", $this->_params);
457 if ($op) {
458 $clause = $this->whereClause($field,
459 $op,
460 CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
461 CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
462 CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
463 );
464 }
465 if (!empty($clause)) {
466 $clauses[$fieldName] = $clause;
467 }
468 }
469 }
470 }
471
472 $this->_where = !empty($clauses) ? "WHERE " . implode(' AND ', $clauses) : '';
473 }
474
74cf4551
EM
475 /**
476 * @param $fields
477 * @param $files
478 * @param $self
479 *
480 * @return array
481 */
6a488035
TO
482 function formRule($fields, $files, $self) {
483
484 $errors = $checkDate = $errorCount = array();
485
486 $rules = array(
487 'id' => array(
488 'sort_name',
489 'display_name',
490 'addressee_display',
30f85891
RN
491 'contact_type',
492 'contact_sub_type',
6a488035
TO
493 'email',
494 'phone',
495 'state_province_id',
496 'country_id',
497 'city',
498 'street_address',
499 'supplemental_address_1',
500 'postal_code',
501 ),
502 'country_id' => array('country_id'),
503 'state_province_id' => array('country_id', 'state_province_id'),
504 'contribution_source' => array('contribution_source'),
b914f4e8 505 'financial_type' => array('financial_type'),
6a488035
TO
506 );
507
508 $idMapping = array(
509 'id' => ts('Contact'),
510 'country_id' => ts('Country'),
511 'state_province_id' => ts('State/Province'),
512 'contribution_source' => ts('Contribution Source'),
b914f4e8 513 'financial_type' => ts('Financial Type'),
6a488035
TO
514 'sort_name' => ts('Contact Name'),
515 'email' => ts('Email'),
516 'phone' => ts('Phone'),
517 );
518
519 if (empty($fields['group_bys'])) {
520 $errors['fields'] = ts('Please select at least one Group by field.');
521 }
522 elseif ((array_key_exists('contribution_source', $fields['group_bys']) ||
523 array_key_exists('contribution_type', $fields['group_bys'])
524 ) &&
525 (count($fields['group_bys']) > 1)
526 ) {
527 $errors['fields'] = ts('You can not use other Group by with Financial type or Contribution source.');
528 }
529 else {
530 foreach ($fields['fields'] as $fld_id => $value) {
531 if (!($fld_id == 'total_amount1') && !($fld_id == 'total_amount2')) {
532 $found = FALSE;
533 $invlidGroups = array();
534 foreach ($fields['group_bys'] as $grp_id => $val) {
535 $validFields = $rules[$grp_id];
536 if (in_array($fld_id, $validFields)) {
537 $found = TRUE;
538 }
539 else {
540 $invlidGroups[] = $idMapping[$grp_id];
541 }
542 }
543 if (!$found) {
544 $erorrGrps = implode(',', $invlidGroups);
545 $tempErrors[] = ts("Do not select field %1 with Group by %2.", array(1 => $idMapping[$fld_id], 2 => $erorrGrps));
546 }
547 }
548 }
549 if (!empty($tempErrors)) {
550 $errors['fields'] = implode("<br>", $tempErrors);
551 }
552 }
553
8cc574cf 554 if (!empty($fields['gid_value']) && !empty($fields['group_bys'])) {
6a488035
TO
555 if (!array_key_exists('id', $fields['group_bys'])) {
556 $errors['gid_value'] = ts("Filter with Group only allow with group by Contact");
557 }
558 }
559
560 if ($fields['receive_date1_relative'] == '0') {
561 $checkDate['receive_date1']['receive_date1_from'] = $fields['receive_date1_from'];
562 $checkDate['receive_date1']['receive_date1_to'] = $fields['receive_date1_to'];
563 }
564
565 if ($fields['receive_date2_relative'] == '0') {
566 $checkDate['receive_date2']['receive_date2_from'] = $fields['receive_date2_from'];
567 $checkDate['receive_date2']['receive_date2_to'] = $fields['receive_date2_to'];
568 }
569
570 foreach ($checkDate as $date_range => $range_data) {
571 foreach ($range_data as $key => $value) {
572 if (CRM_Utils_Date::isDate($value)) {
573 $errorCount[$date_range][$key]['valid'] = 'true';
574 $errorCount[$date_range][$key]['is_empty'] = 'false';
575 }
576 else {
577 $errorCount[$date_range][$key]['valid'] = 'false';
578 $errorCount[$date_range][$key]['is_empty'] = 'true';
579 if (is_array($value)) {
580 foreach ($value as $v) {
581 if ($v) {
582 $errorCount[$date_range][$key]['is_empty'] = 'false';
583 }
584 }
585 }
586 elseif (!isset($value)) {
587 $errorCount[$date_range][$key]['is_empty'] = 'false';
588 }
589 }
590 }
591 }
592
593 $errorText = ts("Select valid date range");
594 foreach ($errorCount as $date_range => $error_data) {
595
596 if (($error_data[$date_range . '_from']['valid'] == 'false') &&
597 ($error_data[$date_range . '_to']['valid'] == 'false')
598 ) {
599
600 if (($error_data[$date_range . '_from']['is_empty'] == 'true') &&
601 ($error_data[$date_range . '_to']['is_empty'] == 'true')
602 ) {
603 $errors[$date_range . '_relative'] = $errorText;
604 }
605
606 if ($error_data[$date_range . '_from']['is_empty'] == 'false') {
607 $errors[$date_range . '_from'] = $errorText;
608 }
609
610 if ($error_data[$date_range . '_to']['is_empty'] == 'false') {
611 $errors[$date_range . '_to'] = $errorText;
612 }
613 }
614 elseif (($error_data[$date_range . '_from']['valid'] == 'true') &&
615 ($error_data[$date_range . '_to']['valid'] == 'false')
616 ) {
617 if ($error_data[$date_range . '_to']['is_empty'] == 'false') {
618 $errors[$date_range . '_to'] = $errorText;
619 }
620 }
621 elseif (($error_data[$date_range . '_from']['valid'] == 'false') &&
622 ($error_data[$date_range . '_to']['valid'] == 'true')
623 ) {
624 if ($error_data[$date_range . '_from']['is_empty'] == 'false') {
625 $errors[$date_range . '_from'] = $errorText;
626 }
627 }
628 }
629
630 return $errors;
631 }
632
74cf4551
EM
633 /**
634 * @param $rows
635 *
636 * @return array
637 */
6a488035
TO
638 function statistics(&$rows) {
639 $statistics = parent::statistics($rows);
640
641 //fetch contributions for both date ranges from pre-existing temp tables
642 $sql = "
643CREATE TEMPORARY TABLE civicrm_temp_civireport_repeat3
644SELECT contact_id FROM civicrm_temp_civireport_repeat1 UNION SELECT contact_id FROM civicrm_temp_civireport_repeat2;";
645 $dao = CRM_Core_DAO::executeQuery($sql);
646
647 $sql = "
2f4c2f5d 648SELECT civicrm_temp_civireport_repeat3.contact_id,
649 civicrm_temp_civireport_repeat1.total_amount_sum as contribution1_total_amount_sum,
650 civicrm_temp_civireport_repeat2.total_amount_sum as contribution2_total_amount_sum
6a488035
TO
651FROM civicrm_temp_civireport_repeat3
652LEFT JOIN civicrm_temp_civireport_repeat1
2f4c2f5d 653 ON civicrm_temp_civireport_repeat3.contact_id = civicrm_temp_civireport_repeat1.contact_id
6a488035 654LEFT JOIN civicrm_temp_civireport_repeat2
2f4c2f5d 655 ON civicrm_temp_civireport_repeat3.contact_id = civicrm_temp_civireport_repeat2.contact_id";
6a488035
TO
656 $dao = CRM_Core_DAO::executeQuery($sql);
657
658 //store contributions in array 'contact_sums' for comparison
659 $contact_sums = array();
660 while ($dao->fetch()) {
661 $contact_sums[$dao->contact_id] =
662 array(
663 'contribution1_total_amount_sum' => $dao->contribution1_total_amount_sum,
664 'contribution2_total_amount_sum' => $dao->contribution2_total_amount_sum
665 );
666 }
667
668 $total_distinct_contacts = count($contact_sums);
669 $number_maintained = 0;
670 $number_upgraded = 0;
671 $number_downgraded = 0;
672 $number_new = 0;
673 $number_lapsed = 0;
674
675 foreach ($contact_sums as $uid => $row) {
676 if ($row['contribution1_total_amount_sum'] && $row['contribution2_total_amount_sum']) {
677 $change = ($row['contribution1_total_amount_sum'] - $row['contribution2_total_amount_sum']);
678 if($change == 0)
679 $number_maintained += 1;
680 elseif($change > 0)
681 $number_upgraded += 1;
682 elseif($change < 0)
683 $number_downgraded += 1;
684 }
685 elseif ($row['contribution1_total_amount_sum']) {
686 $number_new +=1;
687 }
688 elseif ($row['contribution2_total_amount_sum']) {
689 $number_lapsed +=1;
690 }
691 }
692
693 //calculate percentages from numbers
694 $percent_maintained = ($number_maintained / $total_distinct_contacts) * 100;
695 $percent_upgraded = ($number_upgraded / $total_distinct_contacts) * 100;
696 $percent_downgraded = ($number_downgraded / $total_distinct_contacts) * 100;
697 $percent_new = ($number_new / $total_distinct_contacts) * 100;
698 $percent_lapsed = ($number_lapsed / $total_distinct_contacts) * 100;
699
700 //display percentages for new, lapsed, upgraded, downgraded, and maintained contributors
701 $statistics['counts']['count_new'] = array(
702 'value' => $percent_new,
703 'title' => '% New Donors',
704 );
705 $statistics['counts']['count_lapsed'] = array(
706 'value' => $percent_lapsed,
707 'title' => '% Lapsed Donors',
708 );
709 $statistics['counts']['count_upgraded'] = array(
710 'value' => $percent_upgraded,
711 'title' => '% Upgraded Donors',
712 );
713 $statistics['counts']['count_downgraded'] = array(
714 'value' => $percent_downgraded,
715 'title' => '% Downgraded Donors',
716 );
717 $statistics['counts']['count_maintained'] = array(
718 'value' => $percent_maintained,
719 'title' => '% Maintained Donors',
720 );
721
722 $select = "
723SELECT COUNT({$this->_aliases['civicrm_contribution']}1.total_amount_count ) as count,
724 SUM({$this->_aliases['civicrm_contribution']}1.total_amount_sum ) as amount,
725 ROUND(AVG({$this->_aliases['civicrm_contribution']}1.total_amount_sum), 2) as avg,
2f4c2f5d 726 COUNT({$this->_aliases['civicrm_contribution']}2.total_amount_count ) as count2,
6a488035 727 SUM({$this->_aliases['civicrm_contribution']}2.total_amount_sum ) as amount2,
625749cb 728 ROUND(AVG({$this->_aliases['civicrm_contribution']}2.total_amount_sum), 2) as avg2,
729 currency";
730 $sql = "{$select} {$this->_from} {$this->_where}
2f4c2f5d 731GROUP BY currency
625749cb 732";
6a488035
TO
733 $dao = CRM_Core_DAO::executeQuery($sql);
734
f0b6af80 735 $amount = $average = $amount2 = $average2 = array();
625749cb 736 $count = $count2 = 0;
737 while ($dao->fetch()) {
738 if ($dao->amount) {
739 $amount[] = CRM_Utils_Money::format($dao->amount, $dao->currency)."(".$dao->count.")";
740 $average[] = CRM_Utils_Money::format($dao->avg, $dao->currency);
741 }
742
743 $count += $dao->count;
744 if ($dao->amount2) {
745 $amount2[] = CRM_Utils_Money::format($dao->amount2, $dao->currency)."(".$dao->count.")";
746 $average2[] = CRM_Utils_Money::format($dao->avg2, $dao->currency);
747 }
748 $count2 += $dao->count2;
6a488035
TO
749 }
750
625749cb 751 $statistics['counts']['range_one_title'] = array('title' => 'Initial Date Range:');
752 $statistics['counts']['amount'] = array(
753 'value' => implode(', ', $amount),
754 'title' => 'Total Amount',
755 'type' => CRM_Utils_Type::T_STRING,
756 );
757 $statistics['counts']['count'] = array(
758 'value' => $count,
759 'title' => 'Total Donations',
760 );
761 $statistics['counts']['avg'] = array(
762 'value' => implode(', ', $average),
763 'title' => 'Average',
764 'type' => CRM_Utils_Type::T_STRING,
765 );
766 $statistics['counts']['range_two_title'] = array(
767 'title' => 'Second Date Range:',
768 );
769 $statistics['counts']['amount2'] = array(
770 'value' => implode(', ', $amount2),
771 'title' => 'Total Amount',
772 'type' => CRM_Utils_Type::T_STRING,
773 );
774 $statistics['counts']['count2'] = array(
775 'value' => $count2,
776 'title' => 'Total Donations',
777 );
778 $statistics['counts']['avg2'] = array(
779 'value' => implode(', ', $average2),
780 'title' => 'Average',
781 'type' => CRM_Utils_Type::T_STRING,
782 );
783
6a488035
TO
784 return $statistics;
785 }
786
787 function postProcess() {
788 $this->beginPostProcess();
789 $create = $subSelect1 = $subSelect2 = NULL;
790 list($fromTable, $fromAlias, $fromCol) = $this->groupBy(TRUE);
791 if ($fromTable == 'civicrm_contact') {
792 $contriCol = "contact_id";
793 }
794 elseif ($fromTable == 'civicrm_contribution_type') {
795 $contriCol = "contribution_type_id";
796 }
797 elseif ($fromTable == 'civicrm_contribution') {
798 $contriCol = $fromCol;
799 }
800 elseif ($fromTable == 'civicrm_address') {
801 $contriCol = "contact_id";
802 }
803 elseif ($fromTable == 'civicrm_financial_type') {
804 $contriCol = 'financial_type_id';
805 $subSelect1 = 'contribution1.contact_id,';
806 $subSelect2 = 'contribution2.contact_id,';
807 $create = 'contact_id int unsigned,';
808 }
809
810 $subWhere = $this->whereContribution();
811 $subContributionQuery1 = "
812SELECT {$subSelect1} contribution1.{$contriCol},
813 sum( contribution1.total_amount ) AS total_amount_sum,
814 count( * ) AS total_amount_count
815FROM civicrm_contribution contribution1
816{$subWhere}
817GROUP BY contribution1.{$contriCol}";
818
819 $subWhere = $this->whereContribution('contribution2');
820 $subContributionQuery2 = "
821SELECT {$subSelect2} contribution2.{$contriCol},
822 sum( contribution2.total_amount ) AS total_amount_sum,
625749cb 823 count( * ) AS total_amount_count,
824 currency
6a488035
TO
825FROM civicrm_contribution contribution2
826{$subWhere}
827GROUP BY contribution2.{$contriCol}";
828
829 $sql = "
830CREATE TEMPORARY TABLE civicrm_temp_civireport_repeat1 (
2f4c2f5d 831{$create}
6a488035
TO
832{$contriCol} int unsigned,
833total_amount_sum int,
2f4c2f5d 834total_amount_count int
6a488035
TO
835) ENGINE=HEAP DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci";
836 CRM_Core_DAO::executeQuery($sql);
837 $sql = "INSERT INTO civicrm_temp_civireport_repeat1 {$subContributionQuery1}";
838 CRM_Core_DAO::executeQuery($sql);
839
840 $sql = "
2f4c2f5d 841CREATE TEMPORARY TABLE civicrm_temp_civireport_repeat2 (
6a488035
TO
842{$create}
843{$contriCol} int unsigned,
844total_amount_sum int,
625749cb 845total_amount_count int,
846currency varchar(3)
6a488035
TO
847) ENGINE=HEAP DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci";
848 CRM_Core_DAO::executeQuery($sql);
849 $sql = "INSERT INTO civicrm_temp_civireport_repeat2 {$subContributionQuery2}";
850 CRM_Core_DAO::executeQuery($sql);
851
852 $this->select();
853 $this->from();
854 $this->where();
855 $this->groupBy();
856 $this->limit();
857
858 $count = 0;
859 $sql = "{$this->_select} {$this->_from} {$this->_where} {$this->_groupBy} {$this->_limit}";
860 $dao = CRM_Core_DAO::executeQuery($sql);
861 $rows = array();
862 while ($dao->fetch()) {
863 foreach ($this->_columnHeaders as $key => $value) {
864 $rows[$count][$key] = $dao->$key;
865 }
866 $count++;
867 }
868
869 // FIXME: calculate % using query
870 foreach ($rows as $uid => $row) {
871 if ($row['contribution1_total_amount_sum'] && $row['contribution2_total_amount_sum']) {
872 $rows[$uid]['change'] = number_format((($row['contribution2_total_amount_sum'] -
873 $row['contribution1_total_amount_sum']
874 ) * 100) /
875 ($row['contribution1_total_amount_sum']), 2
876 );
877 }
878 elseif ($row['contribution1_total_amount_sum']) {
879 $rows[$uid]['change'] = ts('Skipped Donation');
880 }
881 elseif ($row['contribution2_total_amount_sum']) {
882 $rows[$uid]['change'] = ts('New Donor');
883 }
884 if ($row['contribution1_total_amount_count']) {
885 $rows[$uid]['contribution1_total_amount_sum'] = $row['contribution1_total_amount_sum'] . " ({$row['contribution1_total_amount_count']})";
886 }
887 if ($row['contribution2_total_amount_count']) {
888 $rows[$uid]['contribution2_total_amount_sum'] = $row['contribution2_total_amount_sum'] . " ({$row['contribution2_total_amount_count']})";
889 }
890 }
891 $this->_columnHeaders['change'] = array(
892 'title' => '% Change',
893 'type' => CRM_Utils_Type::T_INT,
894 );
895
896 // hack to fix title
897 list($from1, $to1) = $this->getFromTo(CRM_Utils_Array::value("receive_date1_relative", $this->_params),
898 CRM_Utils_Array::value("receive_date1_from", $this->_params),
899 CRM_Utils_Array::value("receive_date1_to", $this->_params)
900 );
901 $from1 = CRM_Utils_Date::customFormat($from1, NULL, array('d'));
902 $to1 = CRM_Utils_Date::customFormat($to1, NULL, array('d'));
903
904 list($from2, $to2) = $this->getFromTo(CRM_Utils_Array::value("receive_date2_relative", $this->_params),
905 CRM_Utils_Array::value("receive_date2_from", $this->_params),
906 CRM_Utils_Array::value("receive_date2_to", $this->_params)
907 );
908 $from2 = CRM_Utils_Date::customFormat($from2, NULL, array('d'));
909 $to2 = CRM_Utils_Date::customFormat($to2, NULL, array('d'));
910
911 $this->_columnHeaders['contribution1_total_amount_sum']['title'] = "$from1 -<br/> $to1";
912 $this->_columnHeaders['contribution2_total_amount_sum']['title'] = "$from2 -<br/> $to2";
913 unset($this->_columnHeaders['contribution1_total_amount_count'],
914 $this->_columnHeaders['contribution2_total_amount_count']
915 );
916
917 $this->formatDisplay($rows);
918
919 // assign variables to templates
920 $this->doTemplateAssignment($rows);
921
922 $this->endPostProcess($rows);
923 }
924
74cf4551
EM
925 /**
926 * @param $rows
927 */
6a488035
TO
928 function alterDisplay(&$rows) {
929 // custom code to alter rows
930 list($from1, $to1) = $this->getFromTo(CRM_Utils_Array::value("receive_date1_relative", $this->_params),
931 CRM_Utils_Array::value("receive_date1_from", $this->_params),
932 CRM_Utils_Array::value("receive_date1_to", $this->_params)
933 );
934 list($from2, $to2) = $this->getFromTo(CRM_Utils_Array::value("receive_date2_relative", $this->_params),
935 CRM_Utils_Array::value("receive_date2_from", $this->_params),
936 CRM_Utils_Array::value("receive_date2_to", $this->_params)
937 );
938
939 $dateUrl = "";
940 if ($from1) {
941 $dateUrl .= "receive_date1_from={$from1}&";
942 }
943 if ($to1) {
944 $dateUrl .= "receive_date1_to={$to1}&";
945 }
946 if ($from2) {
947 $dateUrl .= "receive_date2_from={$from2}&";
948 }
949 if ($to2) {
950 $dateUrl .= "receive_date2_to={$to2}&";
951 }
952
953 foreach ($rows as $rowNum => $row) {
954 // handle country
955 if (array_key_exists('address_civireport_country_id', $row)) {
956 if ($value = $row['address_civireport_country_id']) {
957 $rows[$rowNum]['address_civireport_country_id'] = CRM_Core_PseudoConstant::country($value, FALSE);
958
959 $url = CRM_Report_Utils_Report::getNextUrl('contribute/detail',
960 "reset=1&force=1&" .
961 "country_id_op=in&country_id_value={$value}&" .
962 "$dateUrl",
963 $this->_absoluteUrl, $this->_id, $this->_drilldownReport
964 );
965
966 $rows[$rowNum]['address_civireport_country_id_link'] = $url;
967 $rows[$rowNum]['address_civireport_country_id_hover'] = ts("View contributions for this Country.");
968 }
969 }
970
971 // handle state province
972 if (array_key_exists('address_civireport_state_province_id', $row)) {
973 if ($value = $row['address_civireport_state_province_id']) {
974 $rows[$rowNum]['address_civireport_state_province_id'] = CRM_Core_PseudoConstant::stateProvince($value, FALSE);
975
976 $url = CRM_Report_Utils_Report::getNextUrl('contribute/detail',
977 "reset=1&force=1&" .
978 "state_province_id_op=in&state_province_id_value={$value}&" .
979 "$dateUrl",
980 $this->_absoluteUrl, $this->_id, $this->_drilldownReport
981 );
982
983 $rows[$rowNum]['address_civireport_state_province_id_link'] = $url;
984 $rows[$rowNum]['address_civireport_state_province_id_hover'] = ts("View repeatDetails for this state.");
985 }
986 }
987
988 // convert display name to links
989 if (array_key_exists('contact_civireport_sort_name', $row) &&
990 array_key_exists('contact_civireport_id', $row)
991 ) {
992 $url = CRM_Report_Utils_Report::getNextUrl('contribute/detail',
993 'reset=1&force=1&id_op=eq&id_value=' . $row['contact_civireport_id'],
994 $this->_absoluteUrl, $this->_id, $this->_drilldownReport
995 );
2f4c2f5d 996
6a488035
TO
997 $rows[$rowNum]['contact_civireport_sort_name_link'] = $url;
998 $rows[$rowNum]['contact_civireport_sort_name_hover'] = ts("View Contribution details for this contact");
999 }
1000 }
1001 // foreach ends
1002 }
1003}
1004