Merge pull request #8767 from francescbassas/patch-4
[civicrm-core.git] / CRM / Report / Form / Contribute / Detail.php
CommitLineData
6a488035 1<?php
6a488035
TO
2/*
3 +--------------------------------------------------------------------+
7e9e8871 4 | CiviCRM version 4.7 |
6a488035 5 +--------------------------------------------------------------------+
fa938177 6 | Copyright CiviCRM LLC (c) 2004-2016 |
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
fa938177 31 * @copyright CiviCRM LLC (c) 2004-2016
6a488035
TO
32 * $Id$
33 *
34 */
35class CRM_Report_Form_Contribute_Detail extends CRM_Report_Form {
36 protected $_addressField = FALSE;
37
38 protected $_emailField = FALSE;
6a488035
TO
39
40 protected $_summary = NULL;
41
e9b25936
E
42 protected $_softFrom = NULL;
43
70bea8e2 44 protected $_customGroupExtends = array(
45 'Contact',
46 'Individual',
7d793900 47 'Contribution',
70bea8e2 48 );
6a488035 49
74cf4551 50 /**
74cf4551 51 */
00be9182 52 public function __construct() {
70bea8e2 53 $this->_autoIncludeIndexedFieldsAsOrderBys = 1;
f813f78e 54 // Check if CiviCampaign is a) enabled and b) has active campaigns
6a488035
TO
55 $config = CRM_Core_Config::singleton();
56 $campaignEnabled = in_array("CiviCampaign", $config->enableComponents);
57 if ($campaignEnabled) {
58 $getCampaigns = CRM_Campaign_BAO_Campaign::getPermissionedCampaigns(NULL, NULL, TRUE, FALSE, TRUE);
59 $this->activeCampaigns = $getCampaigns['campaigns'];
60 asort($this->activeCampaigns);
61 }
62 $this->_columns = array(
a1a2a83d
TO
63 'civicrm_contact' => array(
64 'dao' => 'CRM_Contact_DAO_Contact',
a703d90c 65 'fields' => $this->getBasicContactFields(),
a1a2a83d
TO
66 'filters' => array(
67 'sort_name' => array(
68 'title' => ts('Donor Name'),
69 'operator' => 'like',
70 ),
71 'id' => array(
72 'title' => ts('Contact ID'),
73 'no_display' => TRUE,
74 'type' => CRM_Utils_Type::T_INT,
6a488035 75 ),
70bea8e2 76 'gender_id' => array(
77 'title' => ts('Gender'),
78 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
79 'options' => CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'gender_id'),
80 ),
81 'birth_date' => array(
82 'title' => ts('Birth Date'),
83 'operatorType' => CRM_Report_Form::OP_DATE,
84 ),
85 'contact_type' => array(
86 'title' => ts('Contact Type'),
87 ),
88 'contact_sub_type' => array(
89 'title' => ts('Contact Subtype'),
90 ),
6a488035 91 ),
70bea8e2 92 'grouping' => 'contact-fields',
a1a2a83d
TO
93 'order_bys' => array(
94 'sort_name' => array(
95 'title' => ts('Last Name, First Name'),
96 'default' => '1',
97 'default_weight' => '0',
98 'default_order' => 'ASC',
a0e67d3c 99 ),
70bea8e2 100 'first_name' => array(
101 'name' => 'first_name',
102 'title' => ts('First Name'),
103 ),
104 'gender_id' => array(
105 'name' => 'gender_id',
106 'title' => ts('Gender'),
107 ),
108 'birth_date' => array(
109 'name' => 'birth_date',
110 'title' => ts('Birth Date'),
111 ),
112 'contact_type' => array(
113 'title' => ts('Contact Type'),
114 ),
115 'contact_sub_type' => array(
116 'title' => ts('Contact Subtype'),
117 ),
6a488035 118 ),
70bea8e2 119
a1a2a83d
TO
120 ),
121 'civicrm_email' => array(
122 'dao' => 'CRM_Core_DAO_Email',
123 'fields' => array(
124 'email' => array(
125 'title' => ts('Donor Email'),
126 'default' => TRUE,
1ebef749 127 ),
a1a2a83d
TO
128 ),
129 'grouping' => 'contact-fields',
130 ),
4a39d437
E
131 'civicrm_line_item' => array(
132 'dao' => 'CRM_Price_DAO_LineItem',
133 ),
a1a2a83d
TO
134 'civicrm_phone' => array(
135 'dao' => 'CRM_Core_DAO_Phone',
136 'fields' => array(
137 'phone' => array(
138 'title' => ts('Donor Phone'),
139 'default' => TRUE,
140 'no_repeat' => TRUE,
141 ),
142 ),
143 'grouping' => 'contact-fields',
144 ),
145 'civicrm_contribution' => array(
146 'dao' => 'CRM_Contribute_DAO_Contribution',
147 'fields' => array(
148 'contribution_id' => array(
149 'name' => 'id',
150 'no_display' => TRUE,
151 'required' => TRUE,
152 ),
153 'list_contri_id' => array(
154 'name' => 'id',
155 'title' => ts('Contribution ID'),
156 ),
157 'financial_type_id' => array(
158 'title' => ts('Financial Type'),
159 'default' => TRUE,
160 ),
161 'contribution_status_id' => array(
162 'title' => ts('Contribution Status'),
163 ),
164 'contribution_page_id' => array(
165 'title' => ts('Contribution Page'),
166 ),
167 'source' => array(
168 'title' => ts('Source'),
169 ),
170 'payment_instrument_id' => array(
171 'title' => ts('Payment Type'),
172 ),
173 'check_number' => array(
174 'title' => ts('Check Number'),
175 ),
176 'currency' => array(
177 'required' => TRUE,
178 'no_display' => TRUE,
179 ),
180 'trxn_id' => NULL,
181 'receive_date' => array('default' => TRUE),
182 'receipt_date' => NULL,
183 'total_amount' => array(
184 'title' => ts('Amount'),
185 'required' => TRUE,
186 'statistics' => array('sum' => ts('Amount')),
6a488035 187 ),
a1a2a83d
TO
188 'fee_amount' => NULL,
189 'net_amount' => NULL,
190 'contribution_or_soft' => array(
191 'title' => ts('Contribution OR Soft Credit?'),
192 'dbAlias' => "'Contribution'",
193 ),
194 'soft_credits' => array(
195 'title' => ts('Soft Credits'),
196 'dbAlias' => "NULL",
197 ),
198 'soft_credit_for' => array(
199 'title' => ts('Soft Credit For'),
200 'dbAlias' => "NULL",
6a488035 201 ),
6a488035 202 ),
a1a2a83d
TO
203 'filters' => array(
204 'contribution_or_soft' => array(
205 'title' => ts('Contribution OR Soft Credit?'),
206 'clause' => "(1)",
207 'operatorType' => CRM_Report_Form::OP_SELECT,
208 'type' => CRM_Utils_Type::T_STRING,
209 'options' => array(
210 'both' => ts('Both'),
211 'contributions_only' => ts('Contributions Only'),
212 'soft_credits_only' => ts('Soft Credits Only'),
9d72cede 213 ),
51fa20cb 214 ),
a1a2a83d
TO
215 'receive_date' => array('operatorType' => CRM_Report_Form::OP_DATE),
216 'currency' => array(
217 'title' => 'Currency',
218 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
219 'options' => CRM_Core_OptionGroup::values('currencies_enabled'),
220 'default' => NULL,
221 'type' => CRM_Utils_Type::T_STRING,
222 ),
223 'financial_type_id' => array(
224 'title' => ts('Financial Type'),
225 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
4f166b15 226 'options' => CRM_Financial_BAO_FinancialType::getAvailableFinancialTypes(),
a1a2a83d
TO
227 'type' => CRM_Utils_Type::T_INT,
228 ),
229 'contribution_page_id' => array(
230 'title' => ts('Contribution Page'),
231 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
232 'options' => CRM_Contribute_PseudoConstant::contributionPage(),
233 'type' => CRM_Utils_Type::T_INT,
234 ),
235 'payment_instrument_id' => array(
236 'title' => ts('Payment Type'),
237 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
238 'options' => CRM_Contribute_PseudoConstant::paymentInstrument(),
239 'type' => CRM_Utils_Type::T_INT,
240 ),
241 'contribution_status_id' => array(
242 'title' => ts('Contribution Status'),
243 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
244 'options' => CRM_Contribute_PseudoConstant::contributionStatus(),
245 'default' => array(1),
246 'type' => CRM_Utils_Type::T_INT,
247 ),
248 'total_amount' => array('title' => ts('Contribution Amount')),
51fa20cb 249 ),
a1a2a83d
TO
250 'order_bys' => array(
251 'financial_type_id' => array('title' => ts('Financial Type')),
252 'contribution_status_id' => array('title' => ts('Contribution Status')),
536f0e02 253 'payment_instrument_id' => array('title' => ts('Payment Method')),
7bc6b5bb 254 'receive_date' => array('title' => ts('Date Received')),
a1a2a83d
TO
255 ),
256 'grouping' => 'contri-fields',
257 ),
258 'civicrm_contribution_soft' => array(
259 'dao' => 'CRM_Contribute_DAO_ContributionSoft',
260 'fields' => array(
261 'soft_credit_type_id' => array('title' => ts('Soft Credit Type')),
262 ),
263 'filters' => array(
264 'soft_credit_type_id' => array(
265 'title' => 'Soft Credit Type',
266 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
267 'options' => CRM_Core_OptionGroup::values('soft_credit_type'),
268 'default' => NULL,
269 'type' => CRM_Utils_Type::T_STRING,
6a488035
TO
270 ),
271 ),
a1a2a83d 272 ),
433465bc
PN
273 'civicrm_batch' => array(
274 'dao' => 'CRM_Batch_DAO_EntityBatch',
275 'grouping' => 'contri-fields',
276 'fields' => array(
277 'batch_id' => array(
49d516c6 278 'name' => 'batch_id',
433465bc
PN
279 'title' => ts('Batch Name'),
280 ),
281 ),
282 'filters' => array(
283 'bid' => array(
284 'title' => ts('Batch Name'),
285 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
286 'options' => CRM_Batch_BAO_Batch::getBatches(),
287 'type' => CRM_Utils_Type::T_INT,
288 'dbAlias' => 'batch_civireport.batch_id',
289 ),
290 ),
291 ),
a1a2a83d
TO
292 'civicrm_contribution_ordinality' => array(
293 'dao' => 'CRM_Contribute_DAO_Contribution',
294 'alias' => 'cordinality',
295 'filters' => array(
296 'ordinality' => array(
297 'title' => ts('Contribution Ordinality'),
298 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
299 'options' => array(
300 0 => 'First by Contributor',
301 1 => 'Second or Later by Contributor',
302 ),
303 'type' => CRM_Utils_Type::T_INT,
6a488035 304 ),
a1a2a83d
TO
305 ),
306 ),
307 'civicrm_note' => array(
308 'dao' => 'CRM_Core_DAO_Note',
309 'fields' => array(
310 'contribution_note' => array(
311 'name' => 'note',
312 'title' => ts('Contribution Note'),
313 ),
314 ),
315 'filters' => array(
316 'note' => array(
317 'name' => 'note',
318 'title' => ts('Contribution Note'),
319 'operator' => 'like',
320 'type' => CRM_Utils_Type::T_STRING,
6a488035
TO
321 ),
322 ),
a1a2a83d
TO
323 ),
324 ) + $this->addAddressFields(FALSE);
a703d90c 325 // The tests test for this variation of the sort_name field. Don't argue with the tests :-).
25cf1ac5 326 $this->_columns['civicrm_contact']['fields']['sort_name']['title'] = ts('Donor Name');
16e2e80c 327 $this->_groupFilter = TRUE;
6a488035 328 $this->_tagFilter = TRUE;
1c4d8c3e 329
9d72cede 330 // If we have active campaigns add those elements to both the fields and filters
6a488035
TO
331 if ($campaignEnabled && !empty($this->activeCampaigns)) {
332 $this->_columns['civicrm_contribution']['fields']['campaign_id'] = array(
333 'title' => ts('Campaign'),
334 'default' => 'false',
335 );
9d72cede
EM
336 $this->_columns['civicrm_contribution']['filters']['campaign_id'] = array(
337 'title' => ts('Campaign'),
6a488035
TO
338 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
339 'options' => $this->activeCampaigns,
942b1d01 340 'type' => CRM_Utils_Type::T_INT,
6a488035
TO
341 );
342 $this->_columns['civicrm_contribution']['order_bys']['campaign_id'] = array('title' => ts('Campaign'));
343 }
7a961f19 344
345 $this->_currencyColumn = 'civicrm_contribution_currency';
6a488035
TO
346 parent::__construct();
347 }
348
00be9182 349 public function preProcess() {
6a488035
TO
350 parent::preProcess();
351 }
352
00be9182 353 public function select() {
6a488035 354 $this->_columnHeaders = array();
6a488035 355
f2947aea 356 parent::select();
8e3ad5e0
WA
357 //total_amount was affected by sum as it is considered as one of the stat field
358 //so it is been replaced with correct alias, CRM-13833
359 $this->_select = str_replace("sum({$this->_aliases['civicrm_contribution']}.total_amount)", "{$this->_aliases['civicrm_contribution']}.total_amount", $this->_select);
d1641c51 360 $this->_selectClauses = str_replace("sum({$this->_aliases['civicrm_contribution']}.total_amount)", "{$this->_aliases['civicrm_contribution']}.total_amount", $this->_selectClauses);
f2947aea
DS
361 }
362
00be9182 363 public function orderBy() {
f2947aea
DS
364 parent::orderBy();
365
366 // please note this will just add the order-by columns to select query, and not display in column-headers.
367 // This is a solution to not throw fatal errors when there is a column in order-by, not present in select/display columns.
368 foreach ($this->_orderByFields as $orderBy) {
9d72cede 369 if (!array_key_exists($orderBy['name'], $this->_params['fields']) &&
263b89e5 370 empty($orderBy['section']) && (strpos($this->_select, $orderBy['dbAlias']) === FALSE)
9d72cede 371 ) {
f2947aea
DS
372 $this->_select .= ", {$orderBy['dbAlias']} as {$orderBy['tplField']}";
373 }
374 }
6a488035
TO
375 }
376
74cf4551
EM
377 /**
378 * @param bool $softcredit
379 */
00be9182 380 public function from($softcredit = FALSE) {
6a488035
TO
381 $this->_from = "
382 FROM civicrm_contact {$this->_aliases['civicrm_contact']} {$this->_aclFrom}
1c4d8c3e 383 INNER JOIN civicrm_contribution {$this->_aliases['civicrm_contribution']}
6c7de867 384 ON {$this->_aliases['civicrm_contact']}.id = {$this->_aliases['civicrm_contribution']}.contact_id AND {$this->_aliases['civicrm_contribution']}.is_test = 0";
40c655aa 385
9d72cede
EM
386 if (CRM_Utils_Array::value('contribution_or_soft_value', $this->_params) ==
387 'both'
388 ) {
51fa20cb 389 $this->_from .= "\n LEFT JOIN civicrm_contribution_soft contribution_soft_civireport
390 ON contribution_soft_civireport.contribution_id = {$this->_aliases['civicrm_contribution']}.id";
391 }
9d72cede
EM
392 elseif (CRM_Utils_Array::value('contribution_or_soft_value', $this->_params) ==
393 'soft_credits_only'
394 ) {
51fa20cb 395 $this->_from .= "\n INNER JOIN civicrm_contribution_soft contribution_soft_civireport
396 ON contribution_soft_civireport.contribution_id = {$this->_aliases['civicrm_contribution']}.id";
c548e07b 397 }
6a488035 398
70c41bce
DS
399 if ($softcredit) {
400 $this->_from = "
c548e07b 401 FROM civireport_contribution_detail_temp1 temp1_civireport
70c41bce 402 INNER JOIN civicrm_contribution {$this->_aliases['civicrm_contribution']}
c548e07b
DS
403 ON temp1_civireport.civicrm_contribution_contribution_id = {$this->_aliases['civicrm_contribution']}.id
404 INNER JOIN civicrm_contribution_soft contribution_soft_civireport
405 ON contribution_soft_civireport.contribution_id = {$this->_aliases['civicrm_contribution']}.id
33650a20
J
406 INNER JOIN civicrm_contact {$this->_aliases['civicrm_contact']}
407 ON {$this->_aliases['civicrm_contact']}.id = contribution_soft_civireport.contact_id
6c7de867 408 {$this->_aclFrom}";
70c41bce
DS
409 }
410
6a488035
TO
411 if (!empty($this->_params['ordinality_value'])) {
412 $this->_from .= "
1c4d8c3e 413 INNER JOIN (SELECT c.id, IF(COUNT(oc.id) = 0, 0, 1) AS ordinality FROM civicrm_contribution c LEFT JOIN civicrm_contribution oc ON c.contact_id = oc.contact_id AND oc.receive_date < c.receive_date GROUP BY c.id) {$this->_aliases['civicrm_contribution_ordinality']}
6a488035
TO
414 ON {$this->_aliases['civicrm_contribution_ordinality']}.id = {$this->_aliases['civicrm_contribution']}.id";
415 }
416
850e4640 417 $this->addPhoneFromClause();
6a488035 418
9d72cede
EM
419 if ($this->_addressField OR
420 (!empty($this->_params['state_province_id_value']) OR
421 !empty($this->_params['country_id_value']))
422 ) {
6a488035 423 $this->_from .= "
1c4d8c3e
DL
424 LEFT JOIN civicrm_address {$this->_aliases['civicrm_address']}
425 ON {$this->_aliases['civicrm_contact']}.id = {$this->_aliases['civicrm_address']}.contact_id AND
6a488035
TO
426 {$this->_aliases['civicrm_address']}.is_primary = 1\n";
427 }
428
429 if ($this->_emailField) {
1c4d8c3e
DL
430 $this->_from .= "
431 LEFT JOIN civicrm_email {$this->_aliases['civicrm_email']}
432 ON {$this->_aliases['civicrm_contact']}.id = {$this->_aliases['civicrm_email']}.contact_id AND
6a488035
TO
433 {$this->_aliases['civicrm_email']}.is_primary = 1\n";
434 }
6a488035 435 // include contribution note
9d72cede
EM
436 if (!empty($this->_params['fields']['contribution_note']) ||
437 !empty($this->_params['note_value'])
438 ) {
439 $this->_from .= "
6a488035
TO
440 LEFT JOIN civicrm_note {$this->_aliases['civicrm_note']}
441 ON ( {$this->_aliases['civicrm_note']}.entity_table = 'civicrm_contribution' AND
442 {$this->_aliases['civicrm_contribution']}.id = {$this->_aliases['civicrm_note']}.entity_id )";
443 }
444 //for contribution batches
433465bc
PN
445 if (!empty($this->_params['fields']['batch_id']) ||
446 !empty($this->_params['bid_value'])
9d72cede 447 ) {
6a488035 448 $this->_from .= "
433465bc
PN
449 LEFT JOIN civicrm_entity_financial_trxn eft
450 ON eft.entity_id = {$this->_aliases['civicrm_contribution']}.id AND
451 eft.entity_table = 'civicrm_contribution'
452 LEFT JOIN civicrm_entity_batch {$this->_aliases['civicrm_batch']}
453 ON ({$this->_aliases['civicrm_batch']}.entity_id = eft.financial_trxn_id
454 AND {$this->_aliases['civicrm_batch']}.entity_table = 'civicrm_financial_trxn')";
6a488035
TO
455 }
456 }
457
00be9182 458 public function groupBy() {
d1641c51 459 $groupBy = array("{$this->_aliases['civicrm_contact']}.id", "{$this->_aliases['civicrm_contribution']}.id");
b708c08d 460 $this->_groupBy = CRM_Contact_BAO_Query::getGroupByFromSelectColumns($this->_selectClauses, $groupBy);
6a488035
TO
461 }
462
74cf4551
EM
463 /**
464 * @param $rows
465 *
466 * @return array
467 */
00be9182 468 public function statistics(&$rows) {
6a488035
TO
469 $statistics = parent::statistics($rows);
470
7010bab9 471 $totalAmount = $average = $fees = $net = array();
7a961f19 472 $count = 0;
6a488035
TO
473 $select = "
474 SELECT COUNT({$this->_aliases['civicrm_contribution']}.total_amount ) as count,
475 SUM( {$this->_aliases['civicrm_contribution']}.total_amount ) as amount,
7a961f19 476 ROUND(AVG({$this->_aliases['civicrm_contribution']}.total_amount), 2) as avg,
7010bab9 477 {$this->_aliases['civicrm_contribution']}.currency as currency,
e468f7a2 478 SUM( {$this->_aliases['civicrm_contribution']}.fee_amount ) as fees,
7010bab9 479 SUM( {$this->_aliases['civicrm_contribution']}.net_amount ) as net
6a488035
TO
480 ";
481
7a961f19 482 $group = "\nGROUP BY {$this->_aliases['civicrm_contribution']}.currency";
483 $sql = "{$select} {$this->_from} {$this->_where} {$group}";
6a488035
TO
484 $dao = CRM_Core_DAO::executeQuery($sql);
485
7a961f19 486 while ($dao->fetch()) {
7010bab9
DG
487 $totalAmount[] = CRM_Utils_Money::format($dao->amount, $dao->currency) . " (" . $dao->count . ")";
488 $fees[] = CRM_Utils_Money::format($dao->fees, $dao->currency);
489 $net[] = CRM_Utils_Money::format($dao->net, $dao->currency);
9d72cede 490 $average[] = CRM_Utils_Money::format($dao->avg, $dao->currency);
1c4d8c3e 491 $count += $dao->count;
6a488035 492 }
7a961f19 493 $statistics['counts']['amount'] = array(
be205937 494 'title' => ts('Total Amount (Contributions)'),
7a961f19 495 'value' => implode(', ', $totalAmount),
496 'type' => CRM_Utils_Type::T_STRING,
497 );
498 $statistics['counts']['count'] = array(
be205937 499 'title' => ts('Total Contributions'),
7a961f19 500 'value' => $count,
501 );
7010bab9
DG
502 $statistics['counts']['fees'] = array(
503 'title' => ts('Fees'),
504 'value' => implode(', ', $fees),
505 'type' => CRM_Utils_Type::T_STRING,
506 );
507 $statistics['counts']['net'] = array(
508 'title' => ts('Net'),
509 'value' => implode(', ', $net),
510 'type' => CRM_Utils_Type::T_STRING,
511 );
7a961f19 512 $statistics['counts']['avg'] = array(
513 'title' => ts('Average'),
514 'value' => implode(', ', $average),
515 'type' => CRM_Utils_Type::T_STRING,
516 );
6a488035 517
70c41bce 518 // Stats for soft credits
9d72cede
EM
519 if ($this->_softFrom &&
520 CRM_Utils_Array::value('contribution_or_soft_value', $this->_params) !=
521 'contributions_only'
522 ) {
c548e07b 523 $totalAmount = $average = array();
9d72cede 524 $count = 0;
c548e07b 525 $select = "
70c41bce
DS
526SELECT COUNT(contribution_soft_civireport.amount ) as count,
527 SUM(contribution_soft_civireport.amount ) as amount,
528 ROUND(AVG(contribution_soft_civireport.amount), 2) as avg,
529 {$this->_aliases['civicrm_contribution']}.currency as currency";
c548e07b 530 $sql = "
f813f78e 531{$select}
532{$this->_softFrom}
c548e07b
DS
533GROUP BY {$this->_aliases['civicrm_contribution']}.currency";
534 $dao = CRM_Core_DAO::executeQuery($sql);
535 while ($dao->fetch()) {
6c552737 536 $totalAmount[] = CRM_Utils_Money::format($dao->amount, $dao->currency) . " (" .
9d72cede
EM
537 $dao->count . ")";
538 $average[] = CRM_Utils_Money::format($dao->avg, $dao->currency);
c548e07b
DS
539 $count += $dao->count;
540 }
541 $statistics['counts']['softamount'] = array(
542 'title' => ts('Total Amount (Soft Credits)'),
543 'value' => implode(', ', $totalAmount),
544 'type' => CRM_Utils_Type::T_STRING,
545 );
546 $statistics['counts']['softcount'] = array(
547 'title' => ts('Total Soft Credits'),
548 'value' => $count,
549 );
550 $statistics['counts']['softavg'] = array(
551 'title' => ts('Average (Soft Credits)'),
552 'value' => implode(', ', $average),
553 'type' => CRM_Utils_Type::T_STRING,
554 );
70c41bce 555 }
70c41bce 556
6a488035
TO
557 return $statistics;
558 }
559
00be9182 560 public function postProcess() {
6a488035
TO
561 // get the acl clauses built before we assemble the query
562 $this->buildACLClause($this->_aliases['civicrm_contact']);
70c41bce
DS
563
564 $this->beginPostProcess();
e468f7a2 565 // CRM-18312 - display soft_credits and soft_credits_for column
566 // when 'Contribution or Soft Credit?' column is not selected
567 if (empty($this->_params['fields']['contribution_or_soft'])) {
568 $this->_params['fields']['contribution_or_soft'] = 1;
569 $this->noDisplayContributionOrSoftColumn = TRUE;
570 }
f813f78e 571
9d72cede
EM
572 if (CRM_Utils_Array::value('contribution_or_soft_value', $this->_params) ==
573 'contributions_only' &&
574 !empty($this->_params['fields']['soft_credit_type_id'])
575 ) {
51fa20cb 576 unset($this->_params['fields']['soft_credit_type_id']);
577 if (!empty($this->_params['soft_credit_type_id_value'])) {
578 $this->_params['soft_credit_type_id_value'] = array();
579 }
580 }
581
70c41bce
DS
582 // 1. use main contribution query to build temp table 1
583 $sql = $this->buildQuery();
6c552737 584 $tempQuery = 'CREATE TEMPORARY TABLE civireport_contribution_detail_temp1 AS ' . $sql;
70c41bce
DS
585 CRM_Core_DAO::executeQuery($tempQuery);
586 $this->setPager();
587
c548e07b 588 // 2. customize main contribution query for soft credit, and build temp table 2 with soft credit contributions only
70c41bce 589 $this->from(TRUE);
be78fc2d
DL
590 // also include custom group from if included
591 // since this might be included in select
592 $this->customDataFrom();
593
70c41bce
DS
594 $select = str_ireplace('contribution_civireport.total_amount', 'contribution_soft_civireport.amount', $this->_select);
595 $select = str_ireplace("'Contribution' as", "'Soft Credit' as", $select);
3636b520 596 if (!empty($this->_groupBy)) {
597 $this->_groupBy .= ', contribution_soft_civireport.amount';
598 }
70c41bce 599 // we inner join with temp1 to restrict soft contributions to those in temp1 table
51fa20cb 600 $sql = "{$select} {$this->_from} {$this->_where} {$this->_groupBy}";
6c552737 601 $tempQuery = 'CREATE TEMPORARY TABLE civireport_contribution_detail_temp2 AS ' . $sql;
70c41bce 602 CRM_Core_DAO::executeQuery($tempQuery);
9d72cede
EM
603 if (CRM_Utils_Array::value('contribution_or_soft_value', $this->_params) ==
604 'soft_credits_only'
605 ) {
c548e07b
DS
606 // revise pager : prev, next based on soft-credits only
607 $this->setPager();
f813f78e 608 }
70c41bce
DS
609
610 // copy _from for later use of stats calculation for soft credits, and reset $this->_from to main query
611 $this->_softFrom = $this->_from;
c93f6d83
DL
612
613 // simple reset of ->_from
614 $this->from();
be78fc2d
DL
615
616 // also include custom group from if included
617 // since this might be included in select
c93f6d83 618 $this->customDataFrom();
70c41bce 619
c548e07b 620 // 3. Decide where to populate temp3 table from
9d72cede
EM
621 if (CRM_Utils_Array::value('contribution_or_soft_value', $this->_params) ==
622 'contributions_only'
623 ) {
1ebef749 624 $tempQuery = "(SELECT * FROM civireport_contribution_detail_temp1)";
9d72cede 625 }
4c9b6178 626 elseif (CRM_Utils_Array::value('contribution_or_soft_value', $this->_params) ==
9d72cede
EM
627 'soft_credits_only'
628 ) {
1ebef749 629 $tempQuery = "(SELECT * FROM civireport_contribution_detail_temp2)";
9d72cede
EM
630 }
631 else {
c548e07b 632 $tempQuery = "
1ebef749 633(SELECT * FROM civireport_contribution_detail_temp1)
c548e07b 634UNION ALL
1ebef749 635(SELECT * FROM civireport_contribution_detail_temp2)";
c548e07b
DS
636 }
637
638 // 4. build temp table 3
1ebef749
DS
639 $sql = "CREATE TEMPORARY TABLE civireport_contribution_detail_temp3 AS {$tempQuery}";
640 CRM_Core_DAO::executeQuery($sql);
641
642 // 5. Re-construct order-by to make sense for final query on temp3 table
643 $orderBy = '';
644 if (!empty($this->_orderByArray)) {
645 $aliases = array_flip($this->_aliases);
646 $orderClause = array();
647 foreach ($this->_orderByArray as $clause) {
648 list($alias, $rest) = explode('.', $clause);
263b89e5 649 // CRM-17280 -- In case, we are ordering by custom fields
650 // modify $rest to match the alias used for them in temp3 table
651 $grp = new CRM_Core_DAO_CustomGroup();
652 $grp->table_name = $aliases[$alias];
653 if ($grp->find()) {
654 list($fld, $order) = explode(' ', $rest);
ba5db1c7 655 foreach ($this->_columns[$aliases[$alias]]['fields'] as $fldName => $value) {
263b89e5 656 if ($value['name'] == $fld) {
657 $fld = $fldName;
658 }
659 }
44fc78ec 660 $rest = "{$fld} {$order}";
263b89e5 661 }
1ebef749
DS
662 $orderClause[] = $aliases[$alias] . "_" . $rest;
663 }
84178120 664 $orderBy = (!empty($orderClause)) ? "ORDER BY " . implode(', ', $orderClause) : '';
70c41bce
DS
665 }
666
1ebef749 667 // 6. show result set from temp table 3
70c41bce 668 $rows = array();
9d72cede 669 $sql = "SELECT * FROM civireport_contribution_detail_temp3 {$orderBy}";
70c41bce
DS
670 $this->buildRows($sql, $rows);
671
672 // format result set.
673 $this->formatDisplay($rows, FALSE);
674
675 // assign variables to templates
676 $this->doTemplateAssignment($rows);
70c41bce
DS
677 // do print / pdf / instance stuff if needed
678 $this->endPostProcess($rows);
6a488035
TO
679 }
680
74cf4551 681 /**
ced9bfed
EM
682 * Alter display of rows.
683 *
684 * Iterate through the rows retrieved via SQL and make changes for display purposes,
685 * such as rendering contacts as links.
686 *
687 * @param array $rows
688 * Rows generated by SQL, with an array for each row.
74cf4551 689 */
00be9182 690 public function alterDisplay(&$rows) {
9d72cede
EM
691 $checkList = array();
692 $entryFound = FALSE;
693 $display_flag = $prev_cid = $cid = 0;
694 $contributionTypes = CRM_Contribute_PseudoConstant::financialType();
6a488035
TO
695 $contributionStatus = CRM_Contribute_PseudoConstant::contributionStatus();
696 $paymentInstruments = CRM_Contribute_PseudoConstant::paymentInstrument();
9d72cede 697 $contributionPages = CRM_Contribute_PseudoConstant::contributionPage();
433465bc 698 $batches = CRM_Batch_BAO_Batch::getBatches();
6a488035
TO
699 foreach ($rows as $rowNum => $row) {
700 if (!empty($this->_noRepeats) && $this->_outputMode != 'csv') {
701 // don't repeat contact details if its same as the previous row
702 if (array_key_exists('civicrm_contact_id', $row)) {
703 if ($cid = $row['civicrm_contact_id']) {
704 if ($rowNum == 0) {
705 $prev_cid = $cid;
706 }
707 else {
708 if ($prev_cid == $cid) {
709 $display_flag = 1;
710 $prev_cid = $cid;
711 }
712 else {
713 $display_flag = 0;
714 $prev_cid = $cid;
715 }
716 }
717
718 if ($display_flag) {
719 foreach ($row as $colName => $colVal) {
720 // Hide repeats in no-repeat columns, but not if the field's a section header
9d72cede
EM
721 if (in_array($colName, $this->_noRepeats) &&
722 !array_key_exists($colName, $this->_sections)
723 ) {
6a488035
TO
724 unset($rows[$rowNum][$colName]);
725 }
726 }
727 }
728 $entryFound = TRUE;
729 }
730 }
731 }
732
9d72cede
EM
733 if (CRM_Utils_Array::value('civicrm_contribution_contribution_or_soft', $rows[$rowNum]) ==
734 'Contribution'
735 ) {
8e3ad5e0
WA
736 unset($rows[$rowNum]['civicrm_contribution_soft_soft_credit_type_id']);
737 }
6a488035 738
a703d90c 739 $entryFound = $this->alterDisplayContactFields($row, $rows, $rowNum, 'contribution/detail', ts('View Contribution Details')) ? TRUE : $entryFound;
6a488035 740 // convert donor sort name to link
9d72cede
EM
741 if (array_key_exists('civicrm_contact_sort_name', $row) &&
742 !empty($rows[$rowNum]['civicrm_contact_sort_name']) &&
6a488035
TO
743 array_key_exists('civicrm_contact_id', $row)
744 ) {
745 $url = CRM_Utils_System::url("civicrm/contact/view",
746 'reset=1&cid=' . $row['civicrm_contact_id'],
747 $this->_absoluteUrl
748 );
749 $rows[$rowNum]['civicrm_contact_sort_name_link'] = $url;
750 $rows[$rowNum]['civicrm_contact_sort_name_hover'] = ts("View Contact Summary for this Contact.");
751 }
752
6a488035
TO
753 if ($value = CRM_Utils_Array::value('civicrm_contribution_financial_type_id', $row)) {
754 $rows[$rowNum]['civicrm_contribution_financial_type_id'] = $contributionTypes[$value];
755 $entryFound = TRUE;
756 }
757 if ($value = CRM_Utils_Array::value('civicrm_contribution_contribution_status_id', $row)) {
758 $rows[$rowNum]['civicrm_contribution_contribution_status_id'] = $contributionStatus[$value];
759 $entryFound = TRUE;
760 }
0d0e945a
DG
761 if ($value = CRM_Utils_Array::value('civicrm_contribution_contribution_page_id', $row)) {
762 $rows[$rowNum]['civicrm_contribution_contribution_page_id'] = $contributionPages[$value];
763 $entryFound = TRUE;
764 }
6a488035
TO
765 if ($value = CRM_Utils_Array::value('civicrm_contribution_payment_instrument_id', $row)) {
766 $rows[$rowNum]['civicrm_contribution_payment_instrument_id'] = $paymentInstruments[$value];
767 $entryFound = TRUE;
768 }
433465bc
PN
769 if (!empty($row['civicrm_batch_batch_id'])) {
770 $rows[$rowNum]['civicrm_batch_batch_id'] = CRM_Utils_Array::value($row['civicrm_batch_batch_id'], $batches);
6a488035
TO
771 $entryFound = TRUE;
772 }
773
774 // Contribution amount links to viewing contribution
775 if (($value = CRM_Utils_Array::value('civicrm_contribution_total_amount_sum', $row)) &&
776 CRM_Core_Permission::check('access CiviContribute')
777 ) {
778 $url = CRM_Utils_System::url("civicrm/contact/view/contribution",
9d72cede
EM
779 "reset=1&id=" . $row['civicrm_contribution_contribution_id'] .
780 "&cid=" . $row['civicrm_contact_id'] .
781 "&action=view&context=contribution&selectedChild=contribute",
6a488035
TO
782 $this->_absoluteUrl
783 );
784 $rows[$rowNum]['civicrm_contribution_total_amount_sum_link'] = $url;
785 $rows[$rowNum]['civicrm_contribution_total_amount_sum_hover'] = ts("View Details of this Contribution.");
786 $entryFound = TRUE;
787 }
788
789 // convert campaign_id to campaign title
790 if (array_key_exists('civicrm_contribution_campaign_id', $row)) {
791 if ($value = $row['civicrm_contribution_campaign_id']) {
792 $rows[$rowNum]['civicrm_contribution_campaign_id'] = $this->activeCampaigns[$value];
793 $entryFound = TRUE;
794 }
795 }
796
70c41bce
DS
797 // soft credits
798 if (array_key_exists('civicrm_contribution_soft_credits', $row) &&
9d72cede
EM
799 'Contribution' ==
800 CRM_Utils_Array::value('civicrm_contribution_contribution_or_soft', $rows[$rowNum]) &&
70c41bce
DS
801 array_key_exists('civicrm_contribution_contribution_id', $row)
802 ) {
803 $query = "
f813f78e 804SELECT civicrm_contact_id, civicrm_contact_sort_name, civicrm_contribution_total_amount_sum, civicrm_contribution_currency
70c41bce
DS
805FROM civireport_contribution_detail_temp2
806WHERE civicrm_contribution_contribution_id={$row['civicrm_contribution_contribution_id']}";
9d72cede 807 $dao = CRM_Core_DAO::executeQuery($query);
70c41bce 808 $string = '';
1ebef749 809 $separator = ($this->_outputMode !== 'csv') ? "<br/>" : ' ';
70c41bce 810 while ($dao->fetch()) {
9d72cede
EM
811 $url = CRM_Utils_System::url("civicrm/contact/view", 'reset=1&cid=' .
812 $dao->civicrm_contact_id);
813 $string = $string . ($string ? $separator : '') .
814 "<a href='{$url}'>{$dao->civicrm_contact_sort_name}</a> " .
c548e07b 815 CRM_Utils_Money::format($dao->civicrm_contribution_total_amount_sum, $dao->civicrm_contribution_currency);
70c41bce
DS
816 }
817 $rows[$rowNum]['civicrm_contribution_soft_credits'] = $string;
818 }
819
820 if (array_key_exists('civicrm_contribution_soft_credit_for', $row) &&
9d72cede
EM
821 'Soft Credit' ==
822 CRM_Utils_Array::value('civicrm_contribution_contribution_or_soft', $rows[$rowNum]) &&
70c41bce
DS
823 array_key_exists('civicrm_contribution_contribution_id', $row)
824 ) {
825 $query = "
f813f78e 826SELECT civicrm_contact_id, civicrm_contact_sort_name
70c41bce
DS
827FROM civireport_contribution_detail_temp1
828WHERE civicrm_contribution_contribution_id={$row['civicrm_contribution_contribution_id']}";
9d72cede 829 $dao = CRM_Core_DAO::executeQuery($query);
70c41bce
DS
830 $string = '';
831 while ($dao->fetch()) {
9d72cede
EM
832 $url = CRM_Utils_System::url("civicrm/contact/view", 'reset=1&cid=' .
833 $dao->civicrm_contact_id);
834 $string = $string .
835 "\n<a href='{$url}'>{$dao->civicrm_contact_sort_name}</a>";
70c41bce
DS
836 }
837 $rows[$rowNum]['civicrm_contribution_soft_credit_for'] = $string;
838 }
839
e468f7a2 840 // CRM-18312 - hide 'contribution_or_soft' column if unchecked.
841 if (!empty($this->noDisplayContributionOrSoftColumn)) {
842 unset($rows[$rowNum]['civicrm_contribution_contribution_or_soft']);
843 unset($this->_columnHeaders['civicrm_contribution_contribution_or_soft']);
844 }
845
51fa20cb 846 //convert soft_credit_type_id into label
847 if (array_key_exists('civicrm_contribution_soft_soft_credit_type_id', $rows[$rowNum])) {
7a4192f7 848 $rows[$rowNum]['civicrm_contribution_soft_soft_credit_type_id'] = CRM_Core_PseudoConstant::getLabel(
849 'CRM_Contribute_BAO_ContributionSoft',
850 'soft_credit_type_id',
851 $row['civicrm_contribution_soft_soft_credit_type_id']
852 );
51fa20cb 853 }
854
6a488035
TO
855 $entryFound = $this->alterDisplayAddressFields($row, $rows, $rowNum, 'contribute/detail', 'List all contribution(s) for this ') ? TRUE : $entryFound;
856
857 // skip looking further in rows, if first row itself doesn't
858 // have the column we need
859 if (!$entryFound) {
860 break;
861 }
862 $lastKey = $rowNum;
863 }
864 }
1c4d8c3e 865
00be9182 866 public function sectionTotals() {
6a488035
TO
867
868 // Reports using order_bys with sections must populate $this->_selectAliases in select() method.
869 if (empty($this->_selectAliases)) {
870 return;
871 }
872
873 if (!empty($this->_sections)) {
874 // build the query with no LIMIT clause
9d72cede 875 $select = str_ireplace('SELECT SQL_CALC_FOUND_ROWS ', 'SELECT ', $this->_select);
6a488035
TO
876 $sql = "{$select} {$this->_from} {$this->_where} {$this->_groupBy} {$this->_having} {$this->_orderBy}";
877
878 // pull section aliases out of $this->_sections
879 $sectionAliases = array_keys($this->_sections);
880
881 $ifnulls = array();
882 foreach (array_merge($sectionAliases, $this->_selectAliases) as $alias) {
883 $ifnulls[] = "ifnull($alias, '') as $alias";
884 }
b708c08d 885 $this->_select = "SELECT " . implode(", ", $ifnulls);
886 $this->appendSelect($ifnulls, $sectionAliases);
6a488035
TO
887
888 /* Group (un-limited) report by all aliases and get counts. This might
e70a7fc0
TO
889 * be done more efficiently when the contents of $sql are known, ie. by
890 * overriding this method in the report class.
891 */
6a488035
TO
892
893 $addtotals = '';
894
9d72cede
EM
895 if (array_search("civicrm_contribution_total_amount_sum", $this->_selectAliases) !==
896 FALSE
897 ) {
6a488035
TO
898 $addtotals = ", sum(civicrm_contribution_total_amount_sum) as sumcontribs";
899 $showsumcontribs = TRUE;
900 }
901
b708c08d 902 $query = $this->_select .
9d72cede
EM
903 "$addtotals, count(*) as ct from civireport_contribution_detail_temp3 group by " .
904 implode(", ", $sectionAliases);
6a488035
TO
905 // initialize array of total counts
906 $sumcontribs = $totals = array();
907 $dao = CRM_Core_DAO::executeQuery($query);
908 while ($dao->fetch()) {
909
910 // let $this->_alterDisplay translate any integer ids to human-readable values.
911 $rows[0] = $dao->toArray();
912 $this->alterDisplay($rows);
913 $row = $rows[0];
914
915 // add totals for all permutations of section values
916 $values = array();
917 $i = 1;
918 $aliasCount = count($sectionAliases);
919 foreach ($sectionAliases as $alias) {
920 $values[] = $row[$alias];
921 $key = implode(CRM_Core_DAO::VALUE_SEPARATOR, $values);
922 if ($i == $aliasCount) {
923 // the last alias is the lowest-level section header; use count as-is
924 $totals[$key] = $dao->ct;
9d72cede
EM
925 if ($showsumcontribs) {
926 $sumcontribs[$key] = $dao->sumcontribs;
927 }
1c4d8c3e 928 }
6a488035
TO
929 else {
930 // other aliases are higher level; roll count into their total
84178120 931 $totals[$key] = (array_key_exists($key, $totals)) ? $totals[$key] + $dao->ct : $dao->ct;
1c4d8c3e 932 if ($showsumcontribs) {
84178120 933 $sumcontribs[$key] = array_key_exists($key, $sumcontribs) ? $sumcontribs[$key] + $dao->sumcontribs : $dao->sumcontribs;
6a488035
TO
934 }
935 }
936 }
937 }
938 if ($showsumcontribs) {
939 $totalandsum = array();
0161a899
ML
940 // ts exception to avoid having ts("%1 %2: %3")
941 $title = '%1 contributions / soft-credits: %2';
942
9d72cede
EM
943 if (CRM_Utils_Array::value('contribution_or_soft_value', $this->_params) ==
944 'contributions_only'
945 ) {
0161a899 946 $title = '%1 contributions: %2';
9d72cede 947 }
4c9b6178 948 elseif (CRM_Utils_Array::value('contribution_or_soft_value', $this->_params) ==
9d72cede
EM
949 'soft_credits_only'
950 ) {
0161a899 951 $title = '%1 soft-credits: %2';
bec9ef32 952 }
6a488035 953 foreach ($totals as $key => $total) {
0161a899 954 $totalandsum[$key] = ts($title, array(
1c4d8c3e 955 1 => $total,
21dfd5f5 956 2 => CRM_Utils_Money::format($sumcontribs[$key]),
10a5be27 957 ));
6a488035
TO
958 }
959 $this->assign('sectionTotals', $totalandsum);
960 }
961 else {
962 $this->assign('sectionTotals', $totals);
963 }
964 }
965 }
96025800 966
6a488035 967}