4 +--------------------------------------------------------------------+
5 | CiviCRM version 4.6 |
6 +--------------------------------------------------------------------+
7 | Copyright CiviCRM LLC (c) 2004-2014 |
8 +--------------------------------------------------------------------+
9 | This file is a part of CiviCRM. |
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. |
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. |
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 +--------------------------------------------------------------------+
32 * @copyright CiviCRM LLC (c) 2004-2014
36 class CRM_Report_Form_Contribute_Repeat
extends CRM_Report_Form
{
37 protected $_amountClauseWithAND = NULL;
39 public $_drilldownReport = array('contribute/detail' => 'Link to Detail Report');
47 public function __construct() {
48 $this->_columns
= array(
49 'civicrm_contact' => array(
50 'dao' => 'CRM_Contact_DAO_Contact',
51 'grouping' => 'contact-fields',
54 'title' => ts('Contact Name'),
58 'display_name' => array(
59 'title' => ts('Display Name'),
62 'addressee_display' => array(
63 'title' => ts('Addressee Name'),
70 'contact_type' => array(
71 'title' => ts('Contact Type'),
74 'contact_sub_type' => array(
75 'title' => ts('Contact Subtype'),
80 'percentage_change' => array(
81 'title' => ts('Percentage Change'),
82 'type' => CRM_Utils_Type
::T_INT
,
83 'operatorType' => CRM_Report_Form
::OP_INT
,
84 'name' => 'percentage_change',
85 'dbAlias' => '( ( contribution_civireport2.total_amount_sum - contribution_civireport1.total_amount_sum ) * 100 / contribution_civireport1.total_amount_sum )',
90 'title' => ts('Contact'),
95 'civicrm_email' => array(
96 'dao' => 'CRM_Core_DAO_Email',
99 'title' => ts('Email'),
103 'grouping' => 'contact-fields',
105 'civicrm_phone' => array(
106 'dao' => 'CRM_Core_DAO_Phone',
109 'title' => ts('Phone'),
113 'grouping' => 'contact-fields',
115 'civicrm_address' => array(
116 'dao' => 'CRM_Core_DAO_Address',
117 'grouping' => 'contact-fields',
119 'street_address' => array('title' => ts('Street Address')),
120 'supplemental_address_1' => array('title' => ts('Supplemental Address 1')),
121 'city' => array('title' => ts('City')),
122 'country_id' => array('title' => ts('Country')),
123 'state_province_id' => array('title' => ts('State/Province')),
124 'postal_code' => array('title' => ts('Postal Code')),
126 'group_bys' => array(
127 'country_id' => array('title' => ts('Country')),
128 'state_province_id' => array(
129 'title' => ts('State/Province'),
133 'civicrm_financial_type' => array(
134 'dao' => 'CRM_Financial_DAO_FinancialType',
135 'fields' => array('financial_type' => array('title' => ts('Financial Type'))),
136 'grouping' => 'contri-fields',
137 'group_bys' => array(
138 'financial_type' => array(
140 'title' => ts('Financial Type'),
144 'civicrm_contribution' => array(
145 'dao' => 'CRM_Contribute_DAO_Contribution',
147 'contribution_source' => NULL,
148 'total_amount1' => array(
149 'name' => 'total_amount',
150 'alias' => 'contribution1',
151 'title' => ts('Range One Stat'),
152 'type' => CRM_Utils_Type
::T_MONEY
,
156 contribution_civireport1.total_amount_count as contribution1_total_amount_count,
157 contribution_civireport1.total_amount_sum as contribution1_total_amount_sum',
159 'total_amount2' => array(
160 'name' => 'total_amount',
161 'alias' => 'contribution2',
162 'title' => ts('Range Two Stat'),
163 'type' => CRM_Utils_Type
::T_MONEY
,
167 contribution_civireport2.total_amount_count as contribution2_total_amount_count,
168 contribution_civireport2.total_amount_sum as contribution2_total_amount_sum',
171 'grouping' => 'contri-fields',
173 'receive_date1' => array(
174 'title' => ts('Initial Date Range'),
175 'default' => 'previous.year',
176 'type' => CRM_Utils_Type
::T_DATE
,
177 'operatorType' => CRM_Report_Form
::OP_DATE
,
178 'name' => 'receive_date',
180 'receive_date2' => array(
181 'title' => ts('Second Date Range'),
182 'default' => 'this.year',
183 'type' => CRM_Utils_Type
::T_DATE
,
184 'operatorType' => CRM_Report_Form
::OP_DATE
,
185 'name' => 'receive_date',
187 'total_amount1' => array(
188 'title' => ts('Range One Amount'),
189 'type' => CRM_Utils_Type
::T_INT
,
190 'operatorType' => CRM_Report_Form
::OP_INT
,
191 'name' => 'total_amount',
193 'total_amount2' => array(
194 'title' => ts('Range Two Amount'),
195 'type' => CRM_Utils_Type
::T_INT
,
196 'operatorType' => CRM_Report_Form
::OP_INT
,
197 'name' => 'total_amount',
199 'financial_type_id' => array(
200 'title' => ts('Financial Type'),
201 'operatorType' => CRM_Report_Form
::OP_MULTISELECT
,
202 'options' => CRM_Contribute_PseudoConstant
::financialType(),
204 'contribution_status_id' => array(
205 'title' => ts('Contribution Status'),
206 'operatorType' => CRM_Report_Form
::OP_MULTISELECT
,
207 'options' => CRM_Contribute_PseudoConstant
::contributionStatus(),
208 'default' => array('1'),
211 'group_bys' => array('contribution_source' => NULL),
215 $this->_groupFilter
= TRUE;
216 $this->_tagFilter
= TRUE;
218 parent
::__construct();
221 public function preProcess() {
222 parent
::preProcess();
226 * @param bool $freeze
230 public function setDefaultValues($freeze = TRUE) {
231 return parent
::setDefaultValues($freeze);
234 public function select() {
237 // since contact fields not related to financial type
238 if (array_key_exists('financial_type', $this->_params
['group_bys']) ||
239 array_key_exists('contribution_source', $this->_params
['group_bys'])
241 unset($this->_columns
['civicrm_contact']['fields']['id']);
244 foreach ($this->_columns
as $tableName => $table) {
245 if (array_key_exists('fields', $table)) {
246 foreach ($table['fields'] as $fieldName => $field) {
247 if (!empty($field['required']) ||
248 !empty($this->_params
['fields'][$fieldName])
250 if (isset($field['clause'])) {
251 $select[] = $field['clause'];
253 // FIXME: dirty hack for setting columnHeaders
254 $this->_columnHeaders
["{$field['alias']}_{$field['name']}_sum"]['type'] = CRM_Utils_Array
::value('type', $field);
255 $this->_columnHeaders
["{$field['alias']}_{$field['name']}_sum"]['title'] = $field['title'];
256 $this->_columnHeaders
["{$field['alias']}_{$field['name']}_count"]['type'] = CRM_Utils_Array
::value('type', $field);
257 $this->_columnHeaders
["{$field['alias']}_{$field['name']}_count"]['title'] = $field['title'];
261 // only include statistics columns if set
262 $select[] = "{$field['dbAlias']} as {$field['alias']}_{$field['name']}";
263 $this->_columnHeaders
["{$field['alias']}_{$field['name']}"]['type'] = CRM_Utils_Array
::value('type', $field);
264 $this->_columnHeaders
["{$field['alias']}_{$field['name']}"]['title'] = CRM_Utils_Array
::value('title', $field);
265 if (!empty($field['no_display'])) {
266 $this->_columnHeaders
["{$field['alias']}_{$field['name']}"]['no_display'] = TRUE;
273 $this->_select
= "SELECT " . implode(', ', $select) . " ";
277 * @param bool $tableCol
279 public function groupBy($tableCol = FALSE) {
280 $this->_groupBy
= "";
281 if (!empty($this->_params
['group_bys']) &&
282 is_array($this->_params
['group_bys'])
284 foreach ($this->_columns
as $tableName => $table) {
285 if (array_key_exists('group_bys', $table)) {
286 foreach ($table['group_bys'] as $fieldName => $field) {
287 if (!empty($this->_params
['group_bys'][$fieldName])) {
289 return array($tableName, $field['alias'], $field['name']);
292 $this->_groupBy
[] = "{$field['dbAlias']}";
299 $this->_groupBy
= "GROUP BY " . implode(', ', $this->_groupBy
);
303 public function from() {
304 list($fromTable, $fromAlias, $fromCol) = $this->groupBy(TRUE);
305 $from = "$fromTable $fromAlias";
307 if ($fromTable == 'civicrm_contact') {
308 $contriCol = "contact_id";
310 LEFT JOIN civicrm_address {$this->_aliases['civicrm_address']} ON {$this->_aliases['civicrm_contact']}.id = {$this->_aliases['civicrm_address']}.contact_id
311 LEFT JOIN civicrm_email {$this->_aliases['civicrm_email']}
312 ON {$this->_aliases['civicrm_contact']}.id = {$this->_aliases['civicrm_email']}.contact_id AND {$this->_aliases['civicrm_email']}.is_primary = 1
313 LEFT JOIN civicrm_phone {$this->_aliases['civicrm_phone']}
314 ON {$this->_aliases['civicrm_contact']}.id = {$this->_aliases['civicrm_phone']}.contact_id AND {$this->_aliases['civicrm_phone']}.is_primary = 1";
317 elseif ($fromTable == 'civicrm_financial_type') {
318 $contriCol = "financial_type_id";
320 elseif ($fromTable == 'civicrm_contribution') {
321 $contriCol = $fromCol;
323 elseif ($fromTable == 'civicrm_address') {
325 INNER JOIN civicrm_contact {$this->_aliases['civicrm_contact']} ON {$this->_aliases['civicrm_address']}.contact_id = {$this->_aliases['civicrm_contact']}.id";
326 $fromAlias = $this->_aliases
['civicrm_contact'];
328 $contriCol = "contact_id";
333 LEFT JOIN civicrm_temp_civireport_repeat1 {$this->_aliases['civicrm_contribution']}1
334 ON $fromAlias.$fromCol = {$this->_aliases['civicrm_contribution']}1.$contriCol
335 LEFT JOIN civicrm_temp_civireport_repeat2 {$this->_aliases['civicrm_contribution']}2
336 ON $fromAlias.$fromCol = {$this->_aliases['civicrm_contribution']}2.$contriCol";
340 * @param string $replaceAliasWith
342 * @return mixed|string
344 public function whereContribution($replaceAliasWith = 'contribution1') {
345 $clauses = array("is_test" => "{$this->_aliases['civicrm_contribution']}.is_test = 0");
347 foreach ($this->_columns
['civicrm_contribution']['filters'] as $fieldName => $field) {
349 if (CRM_Utils_Array
::value('type', $field) & CRM_Utils_Type
::T_DATE
) {
350 $relative = CRM_Utils_Array
::value("{$fieldName}_relative", $this->_params
);
351 $from = CRM_Utils_Array
::value("{$fieldName}_from", $this->_params
);
352 $to = CRM_Utils_Array
::value("{$fieldName}_to", $this->_params
);
354 $clause = $this->dateClause($field['dbAlias'], $relative, $from, $to, $field['type']);
357 $op = CRM_Utils_Array
::value("{$fieldName}_op", $this->_params
);
359 $clause = $this->whereClause($field,
361 CRM_Utils_Array
::value("{$fieldName}_value", $this->_params
),
362 CRM_Utils_Array
::value("{$fieldName}_min", $this->_params
),
363 CRM_Utils_Array
::value("{$fieldName}_max", $this->_params
)
367 if (!empty($clause)) {
368 $clauses[$fieldName] = $clause;
372 if (!$this->_amountClauseWithAND
) {
373 $amountClauseWithAND = array();
374 if (!empty($clauses['total_amount1'])) {
375 $amountClauseWithAND[] = str_replace("{$this->_aliases['civicrm_contribution']}.total_amount",
376 "{$this->_aliases['civicrm_contribution']}1.total_amount_sum", $clauses['total_amount1']);
378 if (!empty($clauses['total_amount2'])) {
379 $amountClauseWithAND[] = str_replace("{$this->_aliases['civicrm_contribution']}.total_amount",
380 "{$this->_aliases['civicrm_contribution']}2.total_amount_sum", $clauses['total_amount2']);
382 $this->_amountClauseWithAND
= !empty($amountClauseWithAND) ?
implode(' AND ', $amountClauseWithAND) : NULL;
385 if ($replaceAliasWith == 'contribution1') {
386 unset($clauses['receive_date2'], $clauses['total_amount2']);
389 unset($clauses['receive_date1'], $clauses['total_amount1']);
392 $whereClause = !empty($clauses) ?
"WHERE " . implode(' AND ', $clauses) : '';
394 if ($replaceAliasWith) {
395 $whereClause = str_replace($this->_aliases
['civicrm_contribution'], $replaceAliasWith, $whereClause);
401 public function where() {
402 if (!$this->_amountClauseWithAND
) {
403 $this->_amountClauseWithAND
=
404 "!({$this->_aliases['civicrm_contribution']}1.total_amount_count IS NULL AND {$this->_aliases['civicrm_contribution']}2.total_amount_count IS NULL)";
406 $clauses = array("atleast_one_amount" => $this->_amountClauseWithAND
);
408 foreach ($this->_columns
as $tableName => $table) {
409 if (array_key_exists('filters', $table) &&
410 $tableName != 'civicrm_contribution'
412 foreach ($table['filters'] as $fieldName => $field) {
414 $op = CRM_Utils_Array
::value("{$fieldName}_op", $this->_params
);
416 $clause = $this->whereClause($field,
418 CRM_Utils_Array
::value("{$fieldName}_value", $this->_params
),
419 CRM_Utils_Array
::value("{$fieldName}_min", $this->_params
),
420 CRM_Utils_Array
::value("{$fieldName}_max", $this->_params
)
423 if (!empty($clause)) {
424 $clauses[$fieldName] = $clause;
430 $this->_where
= !empty($clauses) ?
"WHERE " . implode(' AND ', $clauses) : '';
440 public static function formRule($fields, $files, $self) {
442 $errors = $checkDate = $errorCount = array();
457 'supplemental_address_1',
460 'country_id' => array('country_id'),
461 'state_province_id' => array('country_id', 'state_province_id'),
462 'contribution_source' => array('contribution_source'),
463 'financial_type' => array('financial_type'),
467 'id' => ts('Contact'),
468 'exposed_id' => ts('Contact'),
469 'country_id' => ts('Country'),
470 'state_province_id' => ts('State/Province'),
471 'contribution_source' => ts('Contribution Source'),
472 'financial_type' => ts('Financial Type'),
473 'sort_name' => ts('Contact Name'),
474 'email' => ts('Email'),
475 'phone' => ts('Phone'),
478 if (empty($fields['group_bys'])) {
479 $errors['fields'] = ts('Please select at least one Group by field.');
481 elseif ((array_key_exists('contribution_source', $fields['group_bys']) ||
482 array_key_exists('contribution_type', $fields['group_bys'])
484 (count($fields['group_bys']) > 1)
486 $errors['fields'] = ts('You can not use other Group by with Financial type or Contribution source.');
489 foreach ($fields['fields'] as $fld_id => $value) {
490 if (!($fld_id == 'total_amount1') && !($fld_id == 'total_amount2')) {
492 $invlidGroups = array();
493 foreach ($fields['group_bys'] as $grp_id => $val) {
494 $validFields = $rules[$grp_id];
495 if (in_array($fld_id, $validFields)) {
499 $invlidGroups[] = $idMapping[$grp_id];
503 $erorrGrps = implode(',', $invlidGroups);
504 $tempErrors[] = ts("Do not select field %1 with Group by %2.", array(
505 1 => $idMapping[$fld_id],
511 if (!empty($tempErrors)) {
512 $errors['fields'] = implode("<br>", $tempErrors);
516 if (!empty($fields['gid_value']) && !empty($fields['group_bys'])) {
517 if (!array_key_exists('id', $fields['group_bys'])) {
518 $errors['gid_value'] = ts("Filter with Group only allow with group by Contact");
522 if ($fields['receive_date1_relative'] == '0') {
523 $checkDate['receive_date1']['receive_date1_from'] = $fields['receive_date1_from'];
524 $checkDate['receive_date1']['receive_date1_to'] = $fields['receive_date1_to'];
527 if ($fields['receive_date2_relative'] == '0') {
528 $checkDate['receive_date2']['receive_date2_from'] = $fields['receive_date2_from'];
529 $checkDate['receive_date2']['receive_date2_to'] = $fields['receive_date2_to'];
532 foreach ($checkDate as $date_range => $range_data) {
533 foreach ($range_data as $key => $value) {
534 if (CRM_Utils_Date
::isDate($value)) {
535 $errorCount[$date_range][$key]['valid'] = 'true';
536 $errorCount[$date_range][$key]['is_empty'] = 'false';
539 $errorCount[$date_range][$key]['valid'] = 'false';
540 $errorCount[$date_range][$key]['is_empty'] = 'true';
541 if (is_array($value)) {
542 foreach ($value as $v) {
544 $errorCount[$date_range][$key]['is_empty'] = 'false';
548 elseif (!isset($value)) {
549 $errorCount[$date_range][$key]['is_empty'] = 'false';
555 $errorText = ts("Select valid date range");
556 foreach ($errorCount as $date_range => $error_data) {
558 if (($error_data[$date_range . '_from']['valid'] == 'false') &&
559 ($error_data[$date_range . '_to']['valid'] == 'false')
562 if (($error_data[$date_range . '_from']['is_empty'] == 'true') &&
563 ($error_data[$date_range . '_to']['is_empty'] == 'true')
565 $errors[$date_range . '_relative'] = $errorText;
568 if ($error_data[$date_range . '_from']['is_empty'] == 'false') {
569 $errors[$date_range . '_from'] = $errorText;
572 if ($error_data[$date_range . '_to']['is_empty'] == 'false') {
573 $errors[$date_range . '_to'] = $errorText;
576 elseif (($error_data[$date_range . '_from']['valid'] == 'true') &&
577 ($error_data[$date_range . '_to']['valid'] == 'false')
579 if ($error_data[$date_range . '_to']['is_empty'] == 'false') {
580 $errors[$date_range . '_to'] = $errorText;
583 elseif (($error_data[$date_range . '_from']['valid'] == 'false') &&
584 ($error_data[$date_range . '_to']['valid'] == 'true')
586 if ($error_data[$date_range . '_from']['is_empty'] == 'false') {
587 $errors[$date_range . '_from'] = $errorText;
600 public function statistics(&$rows) {
601 $statistics = parent
::statistics($rows);
603 //fetch contributions for both date ranges from pre-existing temp tables
605 CREATE TEMPORARY TABLE civicrm_temp_civireport_repeat3
606 SELECT contact_id FROM civicrm_temp_civireport_repeat1 UNION SELECT contact_id FROM civicrm_temp_civireport_repeat2;";
607 $dao = CRM_Core_DAO
::executeQuery($sql);
610 SELECT civicrm_temp_civireport_repeat3.contact_id,
611 civicrm_temp_civireport_repeat1.total_amount_sum as contribution1_total_amount_sum,
612 civicrm_temp_civireport_repeat2.total_amount_sum as contribution2_total_amount_sum
613 FROM civicrm_temp_civireport_repeat3
614 LEFT JOIN civicrm_temp_civireport_repeat1
615 ON civicrm_temp_civireport_repeat3.contact_id = civicrm_temp_civireport_repeat1.contact_id
616 LEFT JOIN civicrm_temp_civireport_repeat2
617 ON civicrm_temp_civireport_repeat3.contact_id = civicrm_temp_civireport_repeat2.contact_id";
618 $dao = CRM_Core_DAO
::executeQuery($sql);
620 //store contributions in array 'contact_sums' for comparison
621 $contact_sums = array();
622 while ($dao->fetch()) {
623 $contact_sums[$dao->contact_id
] =
625 'contribution1_total_amount_sum' => $dao->contribution1_total_amount_sum
,
626 'contribution2_total_amount_sum' => $dao->contribution2_total_amount_sum
630 $total_distinct_contacts = count($contact_sums);
631 $number_maintained = 0;
632 $number_upgraded = 0;
633 $number_downgraded = 0;
637 foreach ($contact_sums as $uid => $row) {
638 if ($row['contribution1_total_amount_sum'] &&
639 $row['contribution2_total_amount_sum']
641 $change = ($row['contribution1_total_amount_sum'] -
642 $row['contribution2_total_amount_sum']);
644 $number_maintained +
= 1;
646 elseif ($change > 0) {
647 $number_upgraded +
= 1;
649 elseif ($change < 0) {
650 $number_downgraded +
= 1;
653 elseif ($row['contribution1_total_amount_sum']) {
656 elseif ($row['contribution2_total_amount_sum']) {
661 //calculate percentages from numbers
662 $percent_maintained = ($number_maintained / $total_distinct_contacts) * 100;
663 $percent_upgraded = ($number_upgraded / $total_distinct_contacts) * 100;
664 $percent_downgraded = ($number_downgraded / $total_distinct_contacts) * 100;
665 $percent_new = ($number_new / $total_distinct_contacts) * 100;
666 $percent_lapsed = ($number_lapsed / $total_distinct_contacts) * 100;
668 //display percentages for new, lapsed, upgraded, downgraded, and maintained contributors
669 $statistics['counts']['count_new'] = array(
670 'value' => $percent_new,
671 'title' => '% New Donors',
673 $statistics['counts']['count_lapsed'] = array(
674 'value' => $percent_lapsed,
675 'title' => '% Lapsed Donors',
677 $statistics['counts']['count_upgraded'] = array(
678 'value' => $percent_upgraded,
679 'title' => '% Upgraded Donors',
681 $statistics['counts']['count_downgraded'] = array(
682 'value' => $percent_downgraded,
683 'title' => '% Downgraded Donors',
685 $statistics['counts']['count_maintained'] = array(
686 'value' => $percent_maintained,
687 'title' => '% Maintained Donors',
691 SELECT COUNT({$this->_aliases['civicrm_contribution']}1.total_amount_count ) as count,
692 SUM({$this->_aliases['civicrm_contribution']}1.total_amount_sum ) as amount,
693 ROUND(AVG({$this->_aliases['civicrm_contribution']}1.total_amount_sum), 2) as avg,
694 COUNT({$this->_aliases['civicrm_contribution']}2.total_amount_count ) as count2,
695 SUM({$this->_aliases['civicrm_contribution']}2.total_amount_sum ) as amount2,
696 ROUND(AVG({$this->_aliases['civicrm_contribution']}2.total_amount_sum), 2) as avg2,
698 $sql = "{$select} {$this->_from} {$this->_where}
701 $dao = CRM_Core_DAO
::executeQuery($sql);
703 $amount = $average = $amount2 = $average2 = array();
704 $count = $count2 = 0;
705 while ($dao->fetch()) {
708 CRM_Utils_Money
::format($dao->amount
, $dao->currency
) . "(" .
710 $average[] = CRM_Utils_Money
::format($dao->avg
, $dao->currency
);
713 $count +
= $dao->count
;
716 CRM_Utils_Money
::format($dao->amount2
, $dao->currency
) . "(" .
718 $average2[] = CRM_Utils_Money
::format($dao->avg2
, $dao->currency
);
720 $count2 +
= $dao->count2
;
723 $statistics['counts']['range_one_title'] = array('title' => 'Initial Date Range:');
724 $statistics['counts']['amount'] = array(
725 'value' => implode(', ', $amount),
726 'title' => 'Total Amount',
727 'type' => CRM_Utils_Type
::T_STRING
,
729 $statistics['counts']['count'] = array(
731 'title' => 'Total Donations',
733 $statistics['counts']['avg'] = array(
734 'value' => implode(', ', $average),
735 'title' => 'Average',
736 'type' => CRM_Utils_Type
::T_STRING
,
738 $statistics['counts']['range_two_title'] = array(
739 'title' => 'Second Date Range:',
741 $statistics['counts']['amount2'] = array(
742 'value' => implode(', ', $amount2),
743 'title' => 'Total Amount',
744 'type' => CRM_Utils_Type
::T_STRING
,
746 $statistics['counts']['count2'] = array(
748 'title' => 'Total Donations',
750 $statistics['counts']['avg2'] = array(
751 'value' => implode(', ', $average2),
752 'title' => 'Average',
753 'type' => CRM_Utils_Type
::T_STRING
,
759 public function postProcess() {
760 $this->beginPostProcess();
761 $create = $subSelect1 = $subSelect2 = NULL;
762 list($fromTable, $fromAlias, $fromCol) = $this->groupBy(TRUE);
763 if ($fromTable == 'civicrm_contact') {
764 $contriCol = "contact_id";
766 elseif ($fromTable == 'civicrm_contribution_type') {
767 $contriCol = "contribution_type_id";
769 elseif ($fromTable == 'civicrm_contribution') {
770 $contriCol = $fromCol;
772 elseif ($fromTable == 'civicrm_address') {
773 $contriCol = "contact_id";
775 elseif ($fromTable == 'civicrm_financial_type') {
776 $contriCol = 'financial_type_id';
777 $subSelect1 = 'contribution1.contact_id,';
778 $subSelect2 = 'contribution2.contact_id,';
779 $create = 'contact_id int unsigned,';
782 $subWhere = $this->whereContribution();
783 $subContributionQuery1 = "
784 SELECT {$subSelect1} contribution1.{$contriCol},
785 sum( contribution1.total_amount ) AS total_amount_sum,
786 count( * ) AS total_amount_count
787 FROM civicrm_contribution contribution1
789 GROUP BY contribution1.{$contriCol}";
791 $subWhere = $this->whereContribution('contribution2');
792 $subContributionQuery2 = "
793 SELECT {$subSelect2} contribution2.{$contriCol},
794 sum( contribution2.total_amount ) AS total_amount_sum,
795 count( * ) AS total_amount_count,
797 FROM civicrm_contribution contribution2
799 GROUP BY contribution2.{$contriCol}";
802 CREATE TEMPORARY TABLE civicrm_temp_civireport_repeat1 (
804 {$contriCol} int unsigned,
805 total_amount_sum int,
806 total_amount_count int
807 ) ENGINE=HEAP DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci";
808 CRM_Core_DAO
::executeQuery($sql);
809 $sql = "INSERT INTO civicrm_temp_civireport_repeat1 {$subContributionQuery1}";
810 CRM_Core_DAO
::executeQuery($sql);
813 CREATE TEMPORARY TABLE civicrm_temp_civireport_repeat2 (
815 {$contriCol} int unsigned,
816 total_amount_sum int,
817 total_amount_count int,
819 ) ENGINE=HEAP DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci";
820 CRM_Core_DAO
::executeQuery($sql);
821 $sql = "INSERT INTO civicrm_temp_civireport_repeat2 {$subContributionQuery2}";
822 CRM_Core_DAO
::executeQuery($sql);
831 $sql = "{$this->_select} {$this->_from} {$this->_where} {$this->_groupBy} {$this->_limit}";
832 $dao = CRM_Core_DAO
::executeQuery($sql);
834 while ($dao->fetch()) {
835 foreach ($this->_columnHeaders
as $key => $value) {
836 $rows[$count][$key] = $dao->$key;
841 // FIXME: calculate % using query
842 foreach ($rows as $uid => $row) {
843 if ($row['contribution1_total_amount_sum'] &&
844 $row['contribution2_total_amount_sum']
846 $rows[$uid]['change'] = number_format((($row['contribution2_total_amount_sum'] -
847 $row['contribution1_total_amount_sum']
849 ($row['contribution1_total_amount_sum']), 2
852 elseif ($row['contribution1_total_amount_sum']) {
853 $rows[$uid]['change'] = ts('Skipped Donation');
855 elseif ($row['contribution2_total_amount_sum']) {
856 $rows[$uid]['change'] = ts('New Donor');
858 if ($row['contribution1_total_amount_count']) {
859 $rows[$uid]['contribution1_total_amount_sum'] =
860 $row['contribution1_total_amount_sum'] .
861 " ({$row['contribution1_total_amount_count']})";
863 if ($row['contribution2_total_amount_count']) {
864 $rows[$uid]['contribution2_total_amount_sum'] =
865 $row['contribution2_total_amount_sum'] .
866 " ({$row['contribution2_total_amount_count']})";
869 $this->_columnHeaders
['change'] = array(
870 'title' => '% Change',
871 'type' => CRM_Utils_Type
::T_INT
,
875 list($from1, $to1) = $this->getFromTo(CRM_Utils_Array
::value("receive_date1_relative", $this->_params
),
876 CRM_Utils_Array
::value("receive_date1_from", $this->_params
),
877 CRM_Utils_Array
::value("receive_date1_to", $this->_params
)
879 $from1 = CRM_Utils_Date
::customFormat($from1, NULL, array('d'));
880 $to1 = CRM_Utils_Date
::customFormat($to1, NULL, array('d'));
882 list($from2, $to2) = $this->getFromTo(CRM_Utils_Array
::value("receive_date2_relative", $this->_params
),
883 CRM_Utils_Array
::value("receive_date2_from", $this->_params
),
884 CRM_Utils_Array
::value("receive_date2_to", $this->_params
)
886 $from2 = CRM_Utils_Date
::customFormat($from2, NULL, array('d'));
887 $to2 = CRM_Utils_Date
::customFormat($to2, NULL, array('d'));
889 $this->_columnHeaders
['contribution1_total_amount_sum']['title'] = "$from1 -<br/> $to1";
890 $this->_columnHeaders
['contribution2_total_amount_sum']['title'] = "$from2 -<br/> $to2";
891 unset($this->_columnHeaders
['contribution1_total_amount_count'],
892 $this->_columnHeaders
['contribution2_total_amount_count']
895 $this->formatDisplay($rows);
897 // assign variables to templates
898 $this->doTemplateAssignment($rows);
900 $this->endPostProcess($rows);
906 public function alterDisplay(&$rows) {
907 // custom code to alter rows
908 list($from1, $to1) = $this->getFromTo(CRM_Utils_Array
::value("receive_date1_relative", $this->_params
),
909 CRM_Utils_Array
::value("receive_date1_from", $this->_params
),
910 CRM_Utils_Array
::value("receive_date1_to", $this->_params
)
912 list($from2, $to2) = $this->getFromTo(CRM_Utils_Array
::value("receive_date2_relative", $this->_params
),
913 CRM_Utils_Array
::value("receive_date2_from", $this->_params
),
914 CRM_Utils_Array
::value("receive_date2_to", $this->_params
)
919 $dateUrl .= "receive_date1_from={$from1}&";
922 $dateUrl .= "receive_date1_to={$to1}&";
925 $dateUrl .= "receive_date2_from={$from2}&";
928 $dateUrl .= "receive_date2_to={$to2}&";
931 foreach ($rows as $rowNum => $row) {
933 if (array_key_exists('address_civireport_country_id', $row)) {
934 if ($value = $row['address_civireport_country_id']) {
935 $rows[$rowNum]['address_civireport_country_id'] = CRM_Core_PseudoConstant
::country($value, FALSE);
937 $url = CRM_Report_Utils_Report
::getNextUrl('contribute/detail',
939 "country_id_op=in&country_id_value={$value}&" .
941 $this->_absoluteUrl
, $this->_id
, $this->_drilldownReport
944 $rows[$rowNum]['address_civireport_country_id_link'] = $url;
945 $rows[$rowNum]['address_civireport_country_id_hover'] = ts("View contributions for this Country.");
949 // handle state province
950 if (array_key_exists('address_civireport_state_province_id', $row)) {
951 if ($value = $row['address_civireport_state_province_id']) {
952 $rows[$rowNum]['address_civireport_state_province_id'] = CRM_Core_PseudoConstant
::stateProvince($value, FALSE);
954 $url = CRM_Report_Utils_Report
::getNextUrl('contribute/detail',
956 "state_province_id_op=in&state_province_id_value={$value}&" .
958 $this->_absoluteUrl
, $this->_id
, $this->_drilldownReport
961 $rows[$rowNum]['address_civireport_state_province_id_link'] = $url;
962 $rows[$rowNum]['address_civireport_state_province_id_hover'] = ts("View repeatDetails for this state.");
966 // convert display name to links
967 if (array_key_exists('contact_civireport_sort_name', $row) &&
968 array_key_exists('contact_civireport_id', $row)
970 $url = CRM_Report_Utils_Report
::getNextUrl('contribute/detail',
971 'reset=1&force=1&id_op=eq&id_value=' . $row['contact_civireport_id'],
972 $this->_absoluteUrl
, $this->_id
, $this->_drilldownReport
975 $rows[$rowNum]['contact_civireport_sort_name_link'] = $url;
976 $rows[$rowNum]['contact_civireport_sort_name_hover'] = ts("View Contribution details for this contact");