Commit | Line | Data |
---|---|---|
6a488035 | 1 | <?php |
6a488035 TO |
2 | /* |
3 | +--------------------------------------------------------------------+ | |
bc77d7c0 | 4 | | Copyright CiviCRM LLC. All rights reserved. | |
6a488035 | 5 | | | |
bc77d7c0 TO |
6 | | This work is published under the GNU AGPLv3 license with some | |
7 | | permitted exceptions and without any warranty. For full license | | |
8 | | and copyright information, see https://civicrm.org/licensing | | |
6a488035 | 9 | +--------------------------------------------------------------------+ |
d25dd0ee | 10 | */ |
6a488035 TO |
11 | |
12 | /** | |
13 | * | |
14 | * @package CRM | |
ca5cec67 | 15 | * @copyright CiviCRM LLC https://civicrm.org/licensing |
6a488035 TO |
16 | */ |
17 | class CRM_Report_Form_Contribute_Summary extends CRM_Report_Form { | |
6a488035 | 18 | |
28ff527d | 19 | protected $_customGroupExtends = ['Contribution', 'Contact', 'Individual']; |
f813f78e | 20 | protected $_customGroupGroupBy = TRUE; |
6a488035 | 21 | |
28ff527d | 22 | public $_drilldownReport = ['contribute/detail' => 'Link to Detail Report']; |
6a488035 | 23 | |
35dd1d26 | 24 | /** |
25 | * To what frequency group-by a date column | |
26 | * | |
27 | * @var array | |
28 | */ | |
28ff527d | 29 | protected $_groupByDateFreq = [ |
35dd1d26 | 30 | 'MONTH' => 'Month', |
31 | 'YEARWEEK' => 'Week', | |
c5e4cf0e | 32 | 'DATE' => 'Day', |
35dd1d26 | 33 | 'QUARTER' => 'Quarter', |
34 | 'YEAR' => 'Year', | |
35 | 'FISCALYEAR' => 'Fiscal Year', | |
28ff527d | 36 | ]; |
35dd1d26 | 37 | |
43c1fa19 | 38 | /** |
39 | * This report has been optimised for group filtering. | |
40 | * | |
43c1fa19 | 41 | * @var bool |
0e480632 | 42 | * @see https://issues.civicrm.org/jira/browse/CRM-19170 |
43c1fa19 | 43 | */ |
44 | protected $groupFilterNotOptimised = FALSE; | |
45 | ||
50f2c453 | 46 | /** |
bd2913d3 | 47 | * Use the generic (but flawed) handling to implement full group by. |
48 | * | |
49 | * Note that because we are calling the parent group by function we set this to FALSE. | |
50 | * The parent group by function adds things to the group by in order to make the mysql pass | |
51 | * but can create incorrect results in the process. | |
50f2c453 | 52 | * |
53 | * @var bool | |
54 | */ | |
bd2913d3 | 55 | public $optimisedForOnlyFullGroupBy = FALSE; |
50f2c453 | 56 | |
74cf4551 | 57 | /** |
ae6f7290 | 58 | * Class constructor. |
74cf4551 | 59 | */ |
00be9182 | 60 | public function __construct() { |
28ff527d LS |
61 | $this->_columns = [ |
62 | 'civicrm_contact' => [ | |
a1a2a83d | 63 | 'dao' => 'CRM_Contact_DAO_Contact', |
3da9fd47 | 64 | 'fields' => array_merge( |
65 | $this->getBasicContactFields(), | |
28ff527d LS |
66 | [ |
67 | 'sort_name' => [ | |
3da9fd47 | 68 | 'title' => ts('Contact Name'), |
69 | 'no_repeat' => TRUE, | |
28ff527d LS |
70 | ], |
71 | ] | |
3da9fd47 | 72 | ), |
28ff527d | 73 | 'filters' => $this->getBasicContactFilters(['deceased' => NULL]), |
a1a2a83d | 74 | 'grouping' => 'contact-fields', |
28ff527d LS |
75 | 'group_bys' => [ |
76 | 'id' => ['title' => ts('Contact ID')], | |
77 | 'sort_name' => [ | |
a1a2a83d | 78 | 'title' => ts('Contact Name'), |
28ff527d LS |
79 | ], |
80 | ], | |
81 | ], | |
82 | 'civicrm_email' => [ | |
a1a2a83d | 83 | 'dao' => 'CRM_Core_DAO_Email', |
28ff527d LS |
84 | 'fields' => [ |
85 | 'email' => [ | |
a1a2a83d TO |
86 | 'title' => ts('Email'), |
87 | 'no_repeat' => TRUE, | |
28ff527d LS |
88 | ], |
89 | ], | |
a1a2a83d | 90 | 'grouping' => 'contact-fields', |
28ff527d LS |
91 | ], |
92 | 'civicrm_line_item' => [ | |
1f76c4cd | 93 | 'dao' => 'CRM_Price_DAO_LineItem', |
28ff527d LS |
94 | ], |
95 | 'civicrm_phone' => [ | |
a1a2a83d | 96 | 'dao' => 'CRM_Core_DAO_Phone', |
28ff527d LS |
97 | 'fields' => [ |
98 | 'phone' => [ | |
a1a2a83d TO |
99 | 'title' => ts('Phone'), |
100 | 'no_repeat' => TRUE, | |
28ff527d LS |
101 | ], |
102 | ], | |
a1a2a83d | 103 | 'grouping' => 'contact-fields', |
28ff527d LS |
104 | ], |
105 | 'civicrm_financial_type' => [ | |
a1a2a83d | 106 | 'dao' => 'CRM_Financial_DAO_FinancialType', |
28ff527d | 107 | 'fields' => ['financial_type' => NULL], |
a1a2a83d | 108 | 'grouping' => 'contri-fields', |
28ff527d LS |
109 | 'group_bys' => [ |
110 | 'financial_type' => ['title' => ts('Financial Type')], | |
111 | ], | |
112 | ], | |
113 | 'civicrm_contribution' => [ | |
a1a2a83d | 114 | 'dao' => 'CRM_Contribute_DAO_Contribution', |
9d72cede | 115 | //'bao' => 'CRM_Contribute_BAO_Contribution', |
28ff527d LS |
116 | 'fields' => [ |
117 | 'contribution_status_id' => [ | |
8a347ca5 | 118 | 'title' => ts('Contribution Status'), |
28ff527d LS |
119 | ], |
120 | 'contribution_source' => ['title' => ts('Source')], | |
121 | 'currency' => [ | |
a1a2a83d TO |
122 | 'required' => TRUE, |
123 | 'no_display' => TRUE, | |
28ff527d LS |
124 | ], |
125 | 'contribution_page_id' => [ | |
1c46a84c | 126 | 'title' => ts('Contribution Page'), |
28ff527d LS |
127 | ], |
128 | 'total_amount' => [ | |
a1a2a83d TO |
129 | 'title' => ts('Contribution Amount Stats'), |
130 | 'default' => TRUE, | |
28ff527d | 131 | 'statistics' => [ |
a1a2a83d | 132 | 'count' => ts('Contributions'), |
8a347ca5 | 133 | 'sum' => ts('Contribution Aggregate'), |
a1a2a83d | 134 | 'avg' => ts('Contribution Avg'), |
28ff527d LS |
135 | ], |
136 | ], | |
137 | 'non_deductible_amount' => [ | |
5afce5ad | 138 | 'title' => ts('Non-deductible Amount'), |
28ff527d | 139 | ], |
cbef4d61 LS |
140 | 'contribution_recur_id' => [ |
141 | 'title' => ts('Contribution Recurring'), | |
142 | 'dbAlias' => '!ISNULL(contribution_civireport.contribution_recur_id)', | |
143 | 'type' => CRM_Utils_Type::T_BOOLEAN, | |
144 | ], | |
28ff527d | 145 | ], |
a1a2a83d | 146 | 'grouping' => 'contri-fields', |
28ff527d LS |
147 | 'filters' => [ |
148 | 'receive_date' => ['operatorType' => CRM_Report_Form::OP_DATE], | |
f85b4a88 | 149 | 'receipt_date' => ['operatorType' => CRM_Report_Form::OP_DATE], |
28ff527d LS |
150 | 'thankyou_date' => ['operatorType' => CRM_Report_Form::OP_DATE], |
151 | 'contribution_status_id' => [ | |
a1a2a83d TO |
152 | 'title' => ts('Contribution Status'), |
153 | 'operatorType' => CRM_Report_Form::OP_MULTISELECT, | |
c0aaecf9 | 154 | 'options' => CRM_Contribute_BAO_Contribution::buildOptions('contribution_status_id', 'search'), |
28ff527d | 155 | 'default' => [1], |
a1a2a83d | 156 | 'type' => CRM_Utils_Type::T_INT, |
28ff527d LS |
157 | ], |
158 | 'contribution_page_id' => [ | |
1c46a84c | 159 | 'title' => ts('Contribution Page'), |
160 | 'operatorType' => CRM_Report_Form::OP_MULTISELECT, | |
161 | 'options' => CRM_Contribute_PseudoConstant::contributionPage(), | |
162 | 'type' => CRM_Utils_Type::T_INT, | |
28ff527d LS |
163 | ], |
164 | 'currency' => [ | |
fd6a6828 | 165 | 'title' => ts('Currency'), |
a1a2a83d TO |
166 | 'operatorType' => CRM_Report_Form::OP_MULTISELECT, |
167 | 'options' => CRM_Core_OptionGroup::values('currencies_enabled'), | |
168 | 'default' => NULL, | |
169 | 'type' => CRM_Utils_Type::T_STRING, | |
28ff527d LS |
170 | ], |
171 | 'financial_type_id' => [ | |
a1a2a83d TO |
172 | 'title' => ts('Financial Type'), |
173 | 'operatorType' => CRM_Report_Form::OP_MULTISELECT, | |
51d1f926 | 174 | 'options' => CRM_Contribute_BAO_Contribution::buildOptions('financial_type_id', 'search'), |
a1a2a83d | 175 | 'type' => CRM_Utils_Type::T_INT, |
28ff527d LS |
176 | ], |
177 | 'contribution_page_id' => [ | |
a1a2a83d TO |
178 | 'title' => ts('Contribution Page'), |
179 | 'operatorType' => CRM_Report_Form::OP_MULTISELECT, | |
180 | 'options' => CRM_Contribute_PseudoConstant::contributionPage(), | |
181 | 'type' => CRM_Utils_Type::T_INT, | |
28ff527d | 182 | ], |
cbef4d61 LS |
183 | 'contribution_recur_id' => [ |
184 | 'title' => ts('Contribution Recurring'), | |
185 | 'operatorType' => CRM_Report_Form::OP_SELECT, | |
186 | 'type' => CRM_Utils_Type::T_BOOLEAN, | |
187 | 'options' => [ | |
188 | '' => ts('Any'), | |
189 | TRUE => ts('Yes'), | |
190 | FALSE => ts('No'), | |
191 | ], | |
192 | 'dbAlias' => '!ISNULL(contribution_civireport.contribution_recur_id)', | |
193 | ], | |
28ff527d | 194 | 'total_amount' => [ |
a1a2a83d | 195 | 'title' => ts('Contribution Amount'), |
28ff527d LS |
196 | ], |
197 | 'non_deductible_amount' => [ | |
5afce5ad | 198 | 'title' => ts('Non-deductible Amount'), |
28ff527d LS |
199 | ], |
200 | 'total_sum' => [ | |
a1a2a83d TO |
201 | 'title' => ts('Contribution Aggregate'), |
202 | 'type' => CRM_Report_Form::OP_INT, | |
203 | 'dbAlias' => 'civicrm_contribution_total_amount_sum', | |
204 | 'having' => TRUE, | |
28ff527d LS |
205 | ], |
206 | 'total_count' => [ | |
a1a2a83d TO |
207 | 'title' => ts('Contribution Count'), |
208 | 'type' => CRM_Report_Form::OP_INT, | |
209 | 'dbAlias' => 'civicrm_contribution_total_amount_count', | |
210 | 'having' => TRUE, | |
28ff527d LS |
211 | ], |
212 | 'total_avg' => [ | |
a1a2a83d TO |
213 | 'title' => ts('Contribution Avg'), |
214 | 'type' => CRM_Report_Form::OP_INT, | |
215 | 'dbAlias' => 'civicrm_contribution_total_amount_avg', | |
216 | 'having' => TRUE, | |
28ff527d LS |
217 | ], |
218 | ], | |
219 | 'group_bys' => [ | |
220 | 'receive_date' => [ | |
a1a2a83d TO |
221 | 'frequency' => TRUE, |
222 | 'default' => TRUE, | |
223 | 'chart' => TRUE, | |
28ff527d | 224 | ], |
a1a2a83d | 225 | 'contribution_source' => NULL, |
28ff527d | 226 | 'contribution_status_id' => [ |
8a347ca5 RO |
227 | 'title' => ts('Contribution Status'), |
228 | 'operatorType' => CRM_Report_Form::OP_MULTISELECT, | |
c0aaecf9 | 229 | 'options' => CRM_Contribute_BAO_Contribution::buildOptions('contribution_status_id', 'search'), |
28ff527d | 230 | 'default' => [1], |
8a347ca5 | 231 | 'type' => CRM_Utils_Type::T_INT, |
28ff527d LS |
232 | ], |
233 | 'contribution_page_id' => [ | |
1c46a84c | 234 | 'title' => ts('Contribution Page'), |
235 | 'operatorType' => CRM_Report_Form::OP_MULTISELECT, | |
236 | 'options' => CRM_Contribute_PseudoConstant::contributionPage(), | |
237 | 'type' => CRM_Utils_Type::T_INT, | |
28ff527d | 238 | ], |
cbef4d61 LS |
239 | 'contribution_recur_id' => [ |
240 | 'title' => ts('Contribution Recurring'), | |
241 | 'type' => CRM_Utils_Type::T_BOOLEAN, | |
242 | 'dbAlias' => '!ISNULL(contribution_civireport.contribution_recur_id)', | |
243 | ], | |
28ff527d LS |
244 | ], |
245 | ], | |
246 | 'civicrm_financial_trxn' => [ | |
fa5fb88c | 247 | 'dao' => 'CRM_Financial_DAO_FinancialTrxn', |
28ff527d LS |
248 | 'fields' => [ |
249 | 'card_type_id' => [ | |
d72b084a | 250 | 'title' => ts('Credit Card Type'), |
5e0343e8 | 251 | 'dbAlias' => 'GROUP_CONCAT(financial_trxn_civireport.card_type_id SEPARATOR ",")', |
28ff527d LS |
252 | ], |
253 | ], | |
254 | 'filters' => [ | |
255 | 'card_type_id' => [ | |
fa5fb88c E |
256 | 'title' => ts('Credit Card Type'), |
257 | 'operatorType' => CRM_Report_Form::OP_MULTISELECT, | |
d72b084a | 258 | 'options' => CRM_Financial_DAO_FinancialTrxn::buildOptions('card_type_id'), |
fa5fb88c E |
259 | 'default' => NULL, |
260 | 'type' => CRM_Utils_Type::T_STRING, | |
28ff527d LS |
261 | ], |
262 | ], | |
263 | ], | |
264 | 'civicrm_batch' => [ | |
433465bc PN |
265 | 'dao' => 'CRM_Batch_DAO_EntityBatch', |
266 | 'grouping' => 'contri-fields', | |
28ff527d LS |
267 | 'fields' => [ |
268 | 'batch_id' => [ | |
8d2ca6b8 E |
269 | 'name' => 'batch_id', |
270 | 'title' => ts('Batch Title'), | |
c76af7c4 E |
271 | 'dbAlias' => 'GROUP_CONCAT(DISTINCT batch_civireport.batch_id |
272 | ORDER BY batch_civireport.batch_id SEPARATOR ",")', | |
28ff527d LS |
273 | ], |
274 | ], | |
275 | 'filters' => [ | |
276 | 'batch_id' => [ | |
433465bc PN |
277 | 'title' => ts('Batch Title'), |
278 | 'operatorType' => CRM_Report_Form::OP_MULTISELECT, | |
279 | 'options' => CRM_Batch_BAO_Batch::getBatches(), | |
280 | 'type' => CRM_Utils_Type::T_INT, | |
28ff527d LS |
281 | ], |
282 | ], | |
283 | 'group_bys' => [ | |
284 | 'batch_id' => ['title' => ts('Batch Title')], | |
285 | ], | |
286 | ], | |
287 | 'civicrm_contribution_soft' => [ | |
a1a2a83d | 288 | 'dao' => 'CRM_Contribute_DAO_ContributionSoft', |
28ff527d LS |
289 | 'fields' => [ |
290 | 'soft_amount' => [ | |
a1a2a83d TO |
291 | 'title' => ts('Soft Credit Amount Stats'), |
292 | 'name' => 'amount', | |
28ff527d | 293 | 'statistics' => [ |
a1a2a83d | 294 | 'count' => ts('Soft Credits'), |
8a347ca5 | 295 | 'sum' => ts('Soft Credit Aggregate'), |
a1a2a83d | 296 | 'avg' => ts('Soft Credit Avg'), |
28ff527d LS |
297 | ], |
298 | ], | |
299 | ], | |
a1a2a83d | 300 | 'grouping' => 'contri-fields', |
28ff527d LS |
301 | 'filters' => [ |
302 | 'amount' => [ | |
a1a2a83d | 303 | 'title' => ts('Soft Credit Amount'), |
28ff527d LS |
304 | ], |
305 | 'soft_credit_type_id' => [ | |
fd6a6828 | 306 | 'title' => ts('Soft Credit Type'), |
a1a2a83d TO |
307 | 'operatorType' => CRM_Report_Form::OP_MULTISELECT, |
308 | 'options' => CRM_Core_OptionGroup::values('soft_credit_type'), | |
309 | 'default' => NULL, | |
310 | 'type' => CRM_Utils_Type::T_STRING, | |
28ff527d LS |
311 | ], |
312 | 'soft_sum' => [ | |
a1a2a83d TO |
313 | 'title' => ts('Soft Credit Aggregate'), |
314 | 'type' => CRM_Report_Form::OP_INT, | |
315 | 'dbAlias' => 'civicrm_contribution_soft_soft_amount_sum', | |
316 | 'having' => TRUE, | |
28ff527d LS |
317 | ], |
318 | 'soft_count' => [ | |
a1a2a83d TO |
319 | 'title' => ts('Soft Credits Count'), |
320 | 'type' => CRM_Report_Form::OP_INT, | |
321 | 'dbAlias' => 'civicrm_contribution_soft_soft_amount_count', | |
322 | 'having' => TRUE, | |
28ff527d LS |
323 | ], |
324 | 'soft_avg' => [ | |
a1a2a83d TO |
325 | 'title' => ts('Soft Credit Avg'), |
326 | 'type' => CRM_Report_Form::OP_INT, | |
327 | 'dbAlias' => 'civicrm_contribution_soft_soft_amount_avg', | |
328 | 'having' => TRUE, | |
28ff527d LS |
329 | ], |
330 | ], | |
331 | ], | |
332 | ] + $this->addAddressFields(); | |
6a488035 | 333 | |
bb3ab6f8 | 334 | $this->addCampaignFields('civicrm_contribution', TRUE); |
35d8497b | 335 | |
f787b3c4 BT |
336 | // Add charts support |
337 | $this->_charts = [ | |
338 | '' => ts('Tabular'), | |
339 | 'barChart' => ts('Bar Chart'), | |
340 | 'pieChart' => ts('Pie Chart'), | |
341 | ]; | |
342 | ||
16e2e80c CW |
343 | $this->_tagFilter = TRUE; |
344 | $this->_groupFilter = TRUE; | |
35d8497b | 345 | $this->_currencyColumn = 'civicrm_contribution_currency'; |
6a488035 TO |
346 | parent::__construct(); |
347 | } | |
348 | ||
74cf4551 | 349 | /** |
ae6f7290 | 350 | * Set select clause. |
74cf4551 | 351 | */ |
00be9182 | 352 | public function select() { |
28ff527d LS |
353 | $select = []; |
354 | $this->_columnHeaders = []; | |
6a488035 TO |
355 | foreach ($this->_columns as $tableName => $table) { |
356 | if (array_key_exists('group_bys', $table)) { | |
357 | foreach ($table['group_bys'] as $fieldName => $field) { | |
a7488080 | 358 | if (!empty($this->_params['group_bys'][$fieldName])) { |
6a488035 TO |
359 | switch (CRM_Utils_Array::value($fieldName, $this->_params['group_bys_freq'])) { |
360 | case 'YEARWEEK': | |
9d72cede EM |
361 | $select[] = "DATE_SUB({$field['dbAlias']}, INTERVAL WEEKDAY({$field['dbAlias']}) DAY) AS {$tableName}_{$fieldName}_start"; |
362 | $select[] = "YEARWEEK({$field['dbAlias']}) AS {$tableName}_{$fieldName}_subtotal"; | |
363 | $select[] = "WEEKOFYEAR({$field['dbAlias']}) AS {$tableName}_{$fieldName}_interval"; | |
c5e4cf0e | 364 | $field['title'] = ts('Week Beginning'); |
6a488035 TO |
365 | break; |
366 | ||
367 | case 'YEAR': | |
9d72cede EM |
368 | $select[] = "MAKEDATE(YEAR({$field['dbAlias']}), 1) AS {$tableName}_{$fieldName}_start"; |
369 | $select[] = "YEAR({$field['dbAlias']}) AS {$tableName}_{$fieldName}_subtotal"; | |
370 | $select[] = "YEAR({$field['dbAlias']}) AS {$tableName}_{$fieldName}_interval"; | |
c5e4cf0e | 371 | $field['title'] = ts('Year Beginning'); |
6a488035 TO |
372 | break; |
373 | ||
35dd1d26 | 374 | case 'FISCALYEAR': |
375 | $config = CRM_Core_Config::singleton(); | |
376 | $fy = $config->fiscalYearStart; | |
377 | $fiscal = self::fiscalYearOffset($field['dbAlias']); | |
378 | ||
a240692a | 379 | $select[] = "DATE_ADD(MAKEDATE({$fiscal}, 1), INTERVAL ({$fy['M']})-1 MONTH) AS {$tableName}_{$fieldName}_start"; |
35dd1d26 | 380 | $select[] = "{$fiscal} AS {$tableName}_{$fieldName}_subtotal"; |
381 | $select[] = "{$fiscal} AS {$tableName}_{$fieldName}_interval"; | |
c5e4cf0e | 382 | $field['title'] = ts('Fiscal Year Beginning'); |
35dd1d26 | 383 | break; |
384 | ||
6a488035 | 385 | case 'MONTH': |
9d72cede EM |
386 | $select[] = "DATE_SUB({$field['dbAlias']}, INTERVAL (DAYOFMONTH({$field['dbAlias']})-1) DAY) as {$tableName}_{$fieldName}_start"; |
387 | $select[] = "MONTH({$field['dbAlias']}) AS {$tableName}_{$fieldName}_subtotal"; | |
388 | $select[] = "MONTHNAME({$field['dbAlias']}) AS {$tableName}_{$fieldName}_interval"; | |
c5e4cf0e | 389 | $field['title'] = ts('Month Beginning'); |
390 | break; | |
391 | ||
392 | case 'DATE': | |
393 | $select[] = "DATE({$field['dbAlias']}) as {$tableName}_{$fieldName}_start"; | |
394 | $field['title'] = ts('Date'); | |
6a488035 TO |
395 | break; |
396 | ||
397 | case 'QUARTER': | |
9d72cede EM |
398 | $select[] = "STR_TO_DATE(CONCAT( 3 * QUARTER( {$field['dbAlias']} ) -2 , '/', '1', '/', YEAR( {$field['dbAlias']} ) ), '%m/%d/%Y') AS {$tableName}_{$fieldName}_start"; |
399 | $select[] = "QUARTER({$field['dbAlias']}) AS {$tableName}_{$fieldName}_subtotal"; | |
400 | $select[] = "QUARTER({$field['dbAlias']}) AS {$tableName}_{$fieldName}_interval"; | |
6a488035 TO |
401 | $field['title'] = 'Quarter'; |
402 | break; | |
403 | } | |
a7488080 | 404 | if (!empty($this->_params['group_bys_freq'][$fieldName])) { |
891a34b4 | 405 | $this->_interval = $this->_params['group_bys_freq'][$fieldName]; |
c5e4cf0e | 406 | $this->_columnHeaders["{$tableName}_{$fieldName}_start"]['title'] = $field['title']; |
6a488035 TO |
407 | $this->_columnHeaders["{$tableName}_{$fieldName}_start"]['type'] = $field['type']; |
408 | $this->_columnHeaders["{$tableName}_{$fieldName}_start"]['group_by'] = $this->_params['group_bys_freq'][$fieldName]; | |
409 | ||
b44e3f84 | 410 | // just to make sure these values are transferred to rows. |
6a488035 TO |
411 | // since we need that for calculation purpose, |
412 | // e.g making subtotals look nicer or graphs | |
28ff527d LS |
413 | $this->_columnHeaders["{$tableName}_{$fieldName}_interval"] = ['no_display' => TRUE]; |
414 | $this->_columnHeaders["{$tableName}_{$fieldName}_subtotal"] = ['no_display' => TRUE]; | |
6a488035 TO |
415 | } |
416 | } | |
417 | } | |
418 | } | |
419 | ||
420 | if (array_key_exists('fields', $table)) { | |
421 | foreach ($table['fields'] as $fieldName => $field) { | |
9d72cede EM |
422 | if (!empty($field['required']) || |
423 | !empty($this->_params['fields'][$fieldName]) | |
424 | ) { | |
6a488035 | 425 | // only include statistics columns if set |
a7488080 | 426 | if (!empty($field['statistics'])) { |
6a488035 | 427 | foreach ($field['statistics'] as $stat => $label) { |
030eb4f9 | 428 | $this->_columnHeaders["{$tableName}_{$fieldName}_{$stat}"]['title'] = $label; |
429 | $this->_columnHeaders["{$tableName}_{$fieldName}_{$stat}"]['type'] = $field['type']; | |
430 | $this->_statFields[] = "{$tableName}_{$fieldName}_{$stat}"; | |
6a488035 TO |
431 | switch (strtolower($stat)) { |
432 | case 'sum': | |
433 | $select[] = "SUM({$field['dbAlias']}) as {$tableName}_{$fieldName}_{$stat}"; | |
6a488035 TO |
434 | break; |
435 | ||
436 | case 'count': | |
437 | $select[] = "COUNT({$field['dbAlias']}) as {$tableName}_{$fieldName}_{$stat}"; | |
438 | $this->_columnHeaders["{$tableName}_{$fieldName}_{$stat}"]['type'] = CRM_Utils_Type::T_INT; | |
6a488035 TO |
439 | break; |
440 | ||
441 | case 'avg': | |
442 | $select[] = "ROUND(AVG({$field['dbAlias']}),2) as {$tableName}_{$fieldName}_{$stat}"; | |
6a488035 TO |
443 | break; |
444 | } | |
445 | } | |
446 | } | |
447 | else { | |
448 | $select[] = "{$field['dbAlias']} as {$tableName}_{$fieldName}"; | |
9c1bc317 CW |
449 | $this->_columnHeaders["{$tableName}_{$fieldName}"]['type'] = $field['type'] ?? NULL; |
450 | $this->_columnHeaders["{$tableName}_{$fieldName}"]['title'] = $field['title'] ?? NULL; | |
6a488035 TO |
451 | } |
452 | } | |
453 | } | |
454 | } | |
455 | } | |
456 | ||
d1641c51 | 457 | $this->_selectClauses = $select; |
6a488035 TO |
458 | $this->_select = "SELECT " . implode(', ', $select) . " "; |
459 | } | |
460 | ||
74cf4551 | 461 | /** |
ae6f7290 | 462 | * Set form rules. |
463 | * | |
464 | * @param array $fields | |
465 | * @param array $files | |
466 | * @param CRM_Report_Form_Contribute_Summary $self | |
74cf4551 EM |
467 | * |
468 | * @return array | |
469 | */ | |
00be9182 | 470 | public static function formRule($fields, $files, $self) { |
ae6f7290 | 471 | // Check for searching combination of display columns and |
472 | // grouping criteria | |
28ff527d | 473 | $ignoreFields = ['total_amount', 'sort_name']; |
6a488035 TO |
474 | $errors = $self->customDataFormRule($fields, $ignoreFields); |
475 | ||
a7488080 | 476 | if (empty($fields['fields']['total_amount'])) { |
28ff527d | 477 | foreach ([ |
c86d4e7c SL |
478 | 'total_count_value', |
479 | 'total_sum_value', | |
480 | 'total_avg_value', | |
28ff527d | 481 | ] as $val) { |
a7488080 | 482 | if (!empty($fields[$val])) { |
6a488035 TO |
483 | $errors[$val] = ts("Please select the Amount Statistics"); |
484 | } | |
485 | } | |
486 | } | |
487 | ||
488 | return $errors; | |
489 | } | |
490 | ||
ae6f7290 | 491 | /** |
492 | * Set from clause. | |
493 | * | |
494 | * @param string $entity | |
73b448bf | 495 | * |
496 | * @todo fix function signature to match parent. Remove hacky passing of $entity | |
497 | * to acheive unclear results. | |
ae6f7290 | 498 | */ |
030eb4f9 | 499 | public function from($entity = NULL) { |
500 | $softCreditJoinType = "LEFT"; | |
9d72cede EM |
501 | if (!empty($this->_params['fields']['soft_amount']) && |
502 | empty($this->_params['fields']['total_amount']) | |
503 | ) { | |
9b0380d9 | 504 | // if its only soft credit stats, use inner join |
030eb4f9 | 505 | $softCreditJoinType = "INNER"; |
506 | } | |
507 | ||
508 | $softCreditJoin = "{$softCreditJoinType} JOIN civicrm_contribution_soft {$this->_aliases['civicrm_contribution_soft']} | |
509 | ON {$this->_aliases['civicrm_contribution_soft']}.contribution_id = {$this->_aliases['civicrm_contribution']}.id"; | |
510 | if ($entity == 'contribution' || empty($this->_params['fields']['soft_amount'])) { | |
511 | $softCreditJoin .= " AND {$this->_aliases['civicrm_contribution_soft']}.id = (SELECT MIN(id) FROM civicrm_contribution_soft cs WHERE cs.contribution_id = {$this->_aliases['civicrm_contribution']}.id) "; | |
9b0380d9 DS |
512 | } |
513 | ||
43c1fa19 | 514 | $this->setFromBase('civicrm_contact'); |
515 | ||
516 | $this->_from .= " | |
f813f78e | 517 | INNER JOIN civicrm_contribution {$this->_aliases['civicrm_contribution']} |
6a488035 | 518 | ON {$this->_aliases['civicrm_contact']}.id = {$this->_aliases['civicrm_contribution']}.contact_id AND |
9f108b4d JJ |
519 | {$this->_aliases['civicrm_contribution']}.is_test = 0 AND |
520 | {$this->_aliases['civicrm_contribution']}.is_template = 0 | |
030eb4f9 | 521 | {$softCreditJoin} |
f813f78e | 522 | LEFT JOIN civicrm_financial_type {$this->_aliases['civicrm_financial_type']} |
6a488035 | 523 | ON {$this->_aliases['civicrm_contribution']}.financial_type_id ={$this->_aliases['civicrm_financial_type']}.id |
18f511e2 | 524 | "; |
f813f78e | 525 | |
18f511e2 | 526 | $this->joinAddressFromContact(); |
527 | $this->joinPhoneFromContact(); | |
528 | $this->joinEmailFromContact(); | |
6a488035 | 529 | |
8d2ca6b8 E |
530 | //for contribution batches |
531 | if ($this->isTableSelected('civicrm_batch')) { | |
433465bc | 532 | $this->_from .= " |
8d2ca6b8 E |
533 | LEFT JOIN civicrm_entity_financial_trxn eft |
534 | ON eft.entity_id = {$this->_aliases['civicrm_contribution']}.id AND | |
535 | eft.entity_table = 'civicrm_contribution' | |
536 | LEFT JOIN civicrm_entity_batch {$this->_aliases['civicrm_batch']} | |
537 | ON ({$this->_aliases['civicrm_batch']}.entity_id = eft.financial_trxn_id | |
538 | AND {$this->_aliases['civicrm_batch']}.entity_table = 'civicrm_financial_trxn')"; | |
433465bc | 539 | } |
fa5fb88c | 540 | |
08730aaf | 541 | $this->addFinancialTrxnFromClause(); |
6a488035 TO |
542 | } |
543 | ||
ae6f7290 | 544 | /** |
545 | * Set group by clause. | |
546 | */ | |
00be9182 | 547 | public function groupBy() { |
bd2913d3 | 548 | parent::groupBy(); |
549 | ||
550 | $isGroupByFrequency = !empty($this->_params['group_bys_freq']); | |
551 | ||
34c3a72b | 552 | if (!empty($this->_params['group_bys']) && |
553 | is_array($this->_params['group_bys']) | |
6a488035 | 554 | ) { |
6a488035 TO |
555 | |
556 | if (!empty($this->_statFields) && | |
bd2913d3 | 557 | (($isGroupByFrequency && count($this->_groupByArray) <= 1) || (!$isGroupByFrequency)) && |
9d72cede | 558 | !$this->_having |
6a488035 TO |
559 | ) { |
560 | $this->_rollup = " WITH ROLLUP"; | |
561 | } | |
28ff527d | 562 | $groupBy = []; |
bd2913d3 | 563 | foreach ($this->_groupByArray as $key => $val) { |
dc852c7b | 564 | if (strpos($val, ';;') !== FALSE) { |
bad98dd5 | 565 | $groupBy = array_merge($groupBy, explode(';;', $val)); |
566 | } | |
567 | else { | |
bd2913d3 | 568 | $groupBy[] = $this->_groupByArray[$key]; |
bad98dd5 | 569 | } |
570 | } | |
571 | $this->_groupBy = "GROUP BY " . implode(', ', $groupBy); | |
6a488035 TO |
572 | } |
573 | else { | |
574 | $this->_groupBy = "GROUP BY {$this->_aliases['civicrm_contact']}.id"; | |
575 | } | |
d1641c51 | 576 | $this->_groupBy .= $this->_rollup; |
6a488035 TO |
577 | } |
578 | ||
ae6f7290 | 579 | /** |
580 | * Store having clauses as an array. | |
581 | */ | |
00be9182 | 582 | public function storeWhereHavingClauseArray() { |
51fa20cb | 583 | parent::storeWhereHavingClauseArray(); |
9d72cede EM |
584 | if (empty($this->_params['fields']['soft_amount']) && |
585 | !empty($this->_havingClauses) | |
586 | ) { | |
51fa20cb | 587 | foreach ($this->_havingClauses as $key => $havingClause) { |
9d72cede | 588 | if (stristr($havingClause, 'soft_soft')) { |
51fa20cb | 589 | unset($this->_havingClauses[$key]); |
590 | } | |
591 | } | |
0d668154 | 592 | } |
51fa20cb | 593 | } |
594 | ||
74cf4551 | 595 | /** |
ae6f7290 | 596 | * Set statistics. |
597 | * | |
598 | * @param array $rows | |
74cf4551 EM |
599 | * |
600 | * @return array | |
bd2913d3 | 601 | * |
602 | * @throws \CRM_Core_Exception | |
74cf4551 | 603 | */ |
00be9182 | 604 | public function statistics(&$rows) { |
6a488035 TO |
605 | $statistics = parent::statistics($rows); |
606 | ||
9c1bc317 | 607 | $softCredit = $this->_params['fields']['soft_amount'] ?? NULL; |
ae6f7290 | 608 | $onlySoftCredit = $softCredit && !CRM_Utils_Array::value('total_amount', $this->_params['fields']); |
bd2913d3 | 609 | if (!isset($this->_groupByArray['civicrm_contribution_currency'])) { |
610 | $this->_groupByArray['civicrm_contribution_currency'] = 'currency'; | |
28ff527d | 611 | } |
bd2913d3 | 612 | $group = ' GROUP BY ' . implode(', ', $this->_groupByArray); |
35d8497b | 613 | |
030eb4f9 | 614 | $this->from('contribution'); |
f14e7686 SL |
615 | if ($softCredit) { |
616 | $this->from(); | |
617 | } | |
c90bacf9 | 618 | $this->customDataFrom(); |
6dd5c484 | 619 | |
f14e7686 SL |
620 | // Ensure that Extensions that modify the from statement in the sql also modify it in the statistics. |
621 | CRM_Utils_Hook::alterReportVar('sql', $this, $this); | |
622 | ||
c5b8382f | 623 | $contriQuery = " |
1eb6b0e4 C |
624 | COUNT({$this->_aliases['civicrm_contribution']}.total_amount ) as civicrm_contribution_total_amount_count, |
625 | SUM({$this->_aliases['civicrm_contribution']}.total_amount ) as civicrm_contribution_total_amount_sum, | |
626 | ROUND(AVG({$this->_aliases['civicrm_contribution']}.total_amount), 2) as civicrm_contribution_total_amount_avg, | |
627 | {$this->_aliases['civicrm_contribution']}.currency as currency | |
628 | {$this->_from} {$this->_where} | |
629 | "; | |
9b0380d9 DS |
630 | |
631 | if ($softCredit) { | |
1eb6b0e4 C |
632 | $selectOnlySoftCredit = " |
633 | COUNT({$this->_aliases['civicrm_contribution_soft']}.amount ) as civicrm_contribution_soft_soft_amount_count, | |
634 | SUM({$this->_aliases['civicrm_contribution_soft']}.amount ) as civicrm_contribution_soft_soft_amount_sum, | |
635 | ROUND(AVG({$this->_aliases['civicrm_contribution_soft']}.amount), 2) as civicrm_contribution_soft_soft_amount_avg, | |
636 | "; | |
637 | ||
638 | $selectWithSoftCredit = " | |
639 | COUNT({$this->_aliases['civicrm_contribution_soft']}.amount ) as civicrm_contribution_soft_soft_amount_count, | |
640 | SUM({$this->_aliases['civicrm_contribution_soft']}.amount ) as civicrm_contribution_soft_soft_amount_sum, | |
641 | ROUND(AVG({$this->_aliases['civicrm_contribution_soft']}.amount), 2) as civicrm_contribution_soft_soft_amount_avg, | |
642 | COUNT({$this->_aliases['civicrm_contribution']}.total_amount ) as civicrm_contribution_total_amount_count, | |
643 | SUM({$this->_aliases['civicrm_contribution']}.total_amount ) as civicrm_contribution_total_amount_sum, | |
644 | ROUND(AVG({$this->_aliases['civicrm_contribution']}.total_amount), 2) as civicrm_contribution_total_amount_avg, | |
645 | "; | |
646 | ||
647 | if ($softCredit && $onlySoftCredit) { | |
648 | $contriQuery = "{$selectOnlySoftCredit} {$contriQuery}"; | |
649 | $softSQL = "SELECT {$selectOnlySoftCredit} {$this->_aliases['civicrm_contribution']}.currency as currency | |
650 | {$this->_from} {$this->_where} {$group} {$this->_having}"; | |
651 | } | |
652 | elseif ($softCredit && !$onlySoftCredit) { | |
653 | $contriQuery = "{$selectOnlySoftCredit} {$contriQuery}"; | |
654 | $softSQL = "SELECT {$selectWithSoftCredit} {$this->_aliases['civicrm_contribution']}.currency as currency | |
655 | {$this->_from} {$this->_where} {$group} {$this->_having}"; | |
656 | } | |
9b0380d9 | 657 | } |
c93f6d83 | 658 | |
35dd1d26 | 659 | $contriSQL = "SELECT {$contriQuery} {$group} {$this->_having}"; |
030eb4f9 | 660 | $contriDAO = CRM_Core_DAO::executeQuery($contriSQL); |
01a9464a | 661 | $this->addToDeveloperTab($contriSQL); |
28ff527d LS |
662 | $currencies = $currAmount = $currAverage = $currCount = []; |
663 | $totalAmount = $average = $mode = $median = []; | |
664 | $softTotalAmount = $softAverage = $averageCount = $averageSoftCount = []; | |
665 | $softCount = $count = 0; | |
030eb4f9 | 666 | while ($contriDAO->fetch()) { |
28ff527d LS |
667 | if (!isset($currAmount[$contriDAO->currency])) { |
668 | $currAmount[$contriDAO->currency] = 0; | |
669 | } | |
670 | if (!isset($currCount[$contriDAO->currency])) { | |
671 | $currCount[$contriDAO->currency] = 0; | |
672 | } | |
673 | if (!isset($currAverage[$contriDAO->currency])) { | |
674 | $currAverage[$contriDAO->currency] = 0; | |
675 | } | |
676 | if (!isset($averageCount[$contriDAO->currency])) { | |
677 | $averageCount[$contriDAO->currency] = 0; | |
678 | } | |
679 | $currAmount[$contriDAO->currency] += $contriDAO->civicrm_contribution_total_amount_sum; | |
680 | $currCount[$contriDAO->currency] += $contriDAO->civicrm_contribution_total_amount_count; | |
681 | $currAverage[$contriDAO->currency] += $contriDAO->civicrm_contribution_total_amount_avg; | |
682 | $averageCount[$contriDAO->currency]++; | |
030eb4f9 | 683 | $count += $contriDAO->civicrm_contribution_total_amount_count; |
28ff527d LS |
684 | |
685 | if (!in_array($contriDAO->currency, $currencies)) { | |
686 | $currencies[] = $contriDAO->currency; | |
687 | } | |
688 | } | |
689 | ||
690 | foreach ($currencies as $currency) { | |
691 | $totalAmount[] = CRM_Utils_Money::format($currAmount[$currency], $currency) . | |
692 | " (" . $currCount[$currency] . ")"; | |
693 | $average[] = CRM_Utils_Money::format(($currAverage[$currency] / $averageCount[$currency]), $currency); | |
030eb4f9 | 694 | } |
c93f6d83 | 695 | |
35dd1d26 | 696 | $groupBy = "\n{$group}, {$this->_aliases['civicrm_contribution']}.total_amount"; |
697 | $orderBy = "\nORDER BY civicrm_contribution_total_amount_count DESC"; | |
d1641c51 | 698 | $modeSQL = "SELECT MAX(civicrm_contribution_total_amount_count) as civicrm_contribution_total_amount_count, |
699 | SUBSTRING_INDEX(GROUP_CONCAT(amount ORDER BY mode.civicrm_contribution_total_amount_count DESC SEPARATOR ';'), ';', 1) as amount, | |
700 | currency | |
701 | FROM (SELECT {$this->_aliases['civicrm_contribution']}.total_amount as amount, | |
35dd1d26 | 702 | {$contriQuery} {$groupBy} {$orderBy}) as mode GROUP BY currency"; |
703 | ||
8446bae6 | 704 | $mode = $this->calculateMode($modeSQL); |
705 | $median = $this->calculateMedian(); | |
35dd1d26 | 706 | |
28ff527d | 707 | $currencies = $currSoftAmount = $currSoftAverage = $currSoftCount = []; |
030eb4f9 | 708 | if ($softCredit) { |
709 | $softDAO = CRM_Core_DAO::executeQuery($softSQL); | |
01a9464a | 710 | $this->addToDeveloperTab($softSQL); |
030eb4f9 | 711 | while ($softDAO->fetch()) { |
28ff527d LS |
712 | if (!isset($currSoftAmount[$softDAO->currency])) { |
713 | $currSoftAmount[$softDAO->currency] = 0; | |
714 | } | |
715 | if (!isset($currSoftCount[$softDAO->currency])) { | |
716 | $currSoftCount[$softDAO->currency] = 0; | |
717 | } | |
718 | if (!isset($currSoftAverage[$softDAO->currency])) { | |
719 | $currSoftAverage[$softDAO->currency] = 0; | |
720 | } | |
721 | if (!isset($averageSoftCount[$softDAO->currency])) { | |
722 | $averageSoftCount[$softDAO->currency] = 0; | |
723 | } | |
724 | $currSoftAmount[$softDAO->currency] += $softDAO->civicrm_contribution_soft_soft_amount_sum; | |
725 | $currSoftCount[$softDAO->currency] += $softDAO->civicrm_contribution_soft_soft_amount_count; | |
726 | $currSoftAverage[$softDAO->currency] += $softDAO->civicrm_contribution_soft_soft_amount_avg; | |
727 | $averageSoftCount[$softDAO->currency]++; | |
030eb4f9 | 728 | $softCount += $softDAO->civicrm_contribution_soft_soft_amount_count; |
28ff527d LS |
729 | |
730 | if (!in_array($softDAO->currency, $currencies)) { | |
731 | $currencies[] = $softDAO->currency; | |
732 | } | |
733 | } | |
734 | ||
735 | foreach ($currencies as $currency) { | |
736 | $softTotalAmount[] = CRM_Utils_Money::format($currSoftAmount[$currency], $currency) . | |
737 | " (" . $currSoftCount[$currency] . ")"; | |
738 | $softAverage[] = CRM_Utils_Money::format(($currSoftAverage[$currency] / $averageSoftCount[$currency]), $currency); | |
9b0380d9 DS |
739 | } |
740 | } | |
c93f6d83 | 741 | |
9b0380d9 | 742 | if (!$onlySoftCredit) { |
28ff527d | 743 | $statistics['counts']['amount'] = [ |
35d8497b | 744 | 'title' => ts('Total Amount'), |
745 | 'value' => implode(', ', $totalAmount), | |
746 | 'type' => CRM_Utils_Type::T_STRING, | |
28ff527d LS |
747 | ]; |
748 | $statistics['counts']['count'] = [ | |
be205937 | 749 | 'title' => ts('Total Contributions'), |
35d8497b | 750 | 'value' => $count, |
28ff527d LS |
751 | ]; |
752 | $statistics['counts']['avg'] = [ | |
35d8497b | 753 | 'title' => ts('Average'), |
754 | 'value' => implode(', ', $average), | |
755 | 'type' => CRM_Utils_Type::T_STRING, | |
28ff527d LS |
756 | ]; |
757 | $statistics['counts']['mode'] = [ | |
35dd1d26 | 758 | 'title' => ts('Mode'), |
759 | 'value' => implode(', ', $mode), | |
760 | 'type' => CRM_Utils_Type::T_STRING, | |
28ff527d LS |
761 | ]; |
762 | $statistics['counts']['median'] = [ | |
35dd1d26 | 763 | 'title' => ts('Median'), |
764 | 'value' => implode(', ', $median), | |
765 | 'type' => CRM_Utils_Type::T_STRING, | |
28ff527d | 766 | ]; |
9b0380d9 DS |
767 | } |
768 | if ($softCredit) { | |
28ff527d | 769 | $statistics['counts']['soft_amount'] = [ |
9b0380d9 DS |
770 | 'title' => ts('Total Soft Credit Amount'), |
771 | 'value' => implode(', ', $softTotalAmount), | |
772 | 'type' => CRM_Utils_Type::T_STRING, | |
28ff527d LS |
773 | ]; |
774 | $statistics['counts']['soft_count'] = [ | |
9b0380d9 DS |
775 | 'title' => ts('Total Soft Credits'), |
776 | 'value' => $softCount, | |
28ff527d LS |
777 | ]; |
778 | $statistics['counts']['soft_avg'] = [ | |
9b0380d9 DS |
779 | 'title' => ts('Average Soft Credit'), |
780 | 'value' => implode(', ', $softAverage), | |
781 | 'type' => CRM_Utils_Type::T_STRING, | |
28ff527d | 782 | ]; |
6a488035 TO |
783 | } |
784 | return $statistics; | |
785 | } | |
786 | ||
74cf4551 | 787 | /** |
ae6f7290 | 788 | * Build chart. |
789 | * | |
1577b3be | 790 | * @param array $original_rows |
74cf4551 | 791 | */ |
1577b3be | 792 | public function buildChart(&$original_rows) { |
28ff527d | 793 | $graphRows = []; |
6a488035 | 794 | |
a7488080 CW |
795 | if (!empty($this->_params['charts'])) { |
796 | if (!empty($this->_params['group_bys']['receive_date'])) { | |
0c98098b | 797 | |
f7dbf5d9 CW |
798 | $contrib = !empty($this->_params['fields']['total_amount']); |
799 | $softContrib = !empty($this->_params['fields']['soft_amount']); | |
0c98098b | 800 | |
1577b3be AW |
801 | // Make a copy so that we don't affect what gets passed later to hooks etc. |
802 | $rows = $original_rows; | |
803 | if ($this->_rollup) { | |
804 | // Remove the total row otherwise it overwrites the real last month's data since it has the | |
805 | // same date. | |
806 | array_pop($rows); | |
807 | } | |
808 | ||
0c98098b DS |
809 | foreach ($rows as $key => $row) { |
810 | if ($row['civicrm_contribution_receive_date_subtotal']) { | |
811 | $graphRows['receive_date'][] = $row['civicrm_contribution_receive_date_start']; | |
812 | $graphRows[$this->_interval][] = $row['civicrm_contribution_receive_date_interval']; | |
813 | if ($softContrib && $contrib) { | |
814 | // both contri & soft contri stats are present | |
815 | $graphRows['multiValue'][0][] = $row['civicrm_contribution_total_amount_sum']; | |
816 | $graphRows['multiValue'][1][] = $row['civicrm_contribution_soft_soft_amount_sum']; | |
9d72cede | 817 | } |
4c9b6178 | 818 | elseif ($softContrib) { |
0c98098b DS |
819 | // only soft contributions |
820 | $graphRows['multiValue'][0][] = $row['civicrm_contribution_soft_soft_amount_sum']; | |
9d72cede EM |
821 | } |
822 | else { | |
0c98098b DS |
823 | // only contributions |
824 | $graphRows['multiValue'][0][] = $row['civicrm_contribution_total_amount_sum']; | |
825 | } | |
826 | } | |
6a488035 | 827 | } |
6a488035 | 828 | |
0c98098b DS |
829 | if ($softContrib && $contrib) { |
830 | $graphRows['barKeys'][0] = ts('Contributions'); | |
831 | $graphRows['barKeys'][1] = ts('Soft Credits'); | |
832 | $graphRows['legend'] = ts('Contributions and Soft Credits'); | |
9d72cede | 833 | } |
4c9b6178 | 834 | elseif ($softContrib) { |
0c98098b DS |
835 | $graphRows['legend'] = ts('Soft Credits'); |
836 | } | |
6a488035 TO |
837 | |
838 | // build the chart. | |
9d72cede | 839 | $config = CRM_Core_Config::Singleton(); |
6a488035 | 840 | $graphRows['xname'] = $this->_interval; |
28ff527d | 841 | $graphRows['yname'] = ts('Amount (%1)', [1 => $config->defaultCurrency]); |
dc61ee93 | 842 | CRM_Utils_Chart::chart($graphRows, $this->_params['charts'], $this->_interval); |
6a488035 TO |
843 | $this->assign('chartType', $this->_params['charts']); |
844 | } | |
845 | } | |
846 | } | |
847 | ||
74cf4551 | 848 | /** |
ced9bfed EM |
849 | * Alter display of rows. |
850 | * | |
851 | * Iterate through the rows retrieved via SQL and make changes for display purposes, | |
852 | * such as rendering contacts as links. | |
853 | * | |
854 | * @param array $rows | |
855 | * Rows generated by SQL, with an array for each row. | |
74cf4551 | 856 | */ |
00be9182 | 857 | public function alterDisplay(&$rows) { |
6a488035 | 858 | $entryFound = FALSE; |
c3b82060 | 859 | $contributionStatus = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'label'); |
1c46a84c | 860 | $contributionPages = CRM_Contribute_PseudoConstant::contributionPage(); |
50f2c453 | 861 | //CRM-16338 if both soft-credit and contribution are enabled then process the contribution's |
862 | //total amount's average, count and sum separately and add it to the respective result list | |
f7dbf5d9 | 863 | $softCredit = (!empty($this->_params['fields']['soft_amount']) && !empty($this->_params['fields']['total_amount'])); |
50f2c453 | 864 | if ($softCredit) { |
865 | $this->from('contribution'); | |
866 | $this->customDataFrom(); | |
867 | $contriSQL = "{$this->_select} {$this->_from} {$this->_where} {$this->_groupBy} {$this->_having} {$this->_orderBy} {$this->_limit}"; | |
868 | CRM_Core_DAO::disableFullGroupByMode(); | |
869 | $contriDAO = CRM_Core_DAO::executeQuery($contriSQL); | |
870 | CRM_Core_DAO::reenableFullGroupByMode(); | |
871 | $this->addToDeveloperTab($contriSQL); | |
28ff527d | 872 | $contriFields = [ |
50f2c453 | 873 | 'civicrm_contribution_total_amount_sum', |
874 | 'civicrm_contribution_total_amount_avg', | |
875 | 'civicrm_contribution_total_amount_count', | |
28ff527d | 876 | ]; |
50f2c453 | 877 | $count = 0; |
878 | while ($contriDAO->fetch()) { | |
879 | foreach ($contriFields as $column) { | |
880 | $rows[$count][$column] = $contriDAO->$column; | |
881 | } | |
882 | $count++; | |
883 | } | |
884 | } | |
6a488035 TO |
885 | foreach ($rows as $rowNum => $row) { |
886 | // make count columns point to detail report | |
9d72cede EM |
887 | if (!empty($this->_params['group_bys']['receive_date']) && |
888 | !empty($row['civicrm_contribution_receive_date_start']) && | |
889 | CRM_Utils_Array::value('civicrm_contribution_receive_date_start', $row) && | |
890 | !empty($row['civicrm_contribution_receive_date_subtotal']) | |
891 | ) { | |
6a488035 TO |
892 | |
893 | $dateStart = CRM_Utils_Date::customFormat($row['civicrm_contribution_receive_date_start'], '%Y%m%d'); | |
9d72cede | 894 | $endDate = new DateTime($dateStart); |
28ff527d | 895 | $dateEnd = []; |
6a488035 TO |
896 | |
897 | list($dateEnd['Y'], $dateEnd['M'], $dateEnd['d']) = explode(':', $endDate->format('Y:m:d')); | |
898 | ||
899 | switch (strtolower($this->_params['group_bys_freq']['receive_date'])) { | |
900 | case 'month': | |
901 | $dateEnd = date("Ymd", mktime(0, 0, 0, $dateEnd['M'] + 1, | |
9d72cede EM |
902 | $dateEnd['d'] - 1, $dateEnd['Y'] |
903 | )); | |
6a488035 TO |
904 | break; |
905 | ||
906 | case 'year': | |
907 | $dateEnd = date("Ymd", mktime(0, 0, 0, $dateEnd['M'], | |
9d72cede EM |
908 | $dateEnd['d'] - 1, $dateEnd['Y'] + 1 |
909 | )); | |
6a488035 TO |
910 | break; |
911 | ||
35dd1d26 | 912 | case 'fiscalyear': |
913 | $dateEnd = date("Ymd", mktime(0, 0, 0, $dateEnd['M'], | |
914 | $dateEnd['d'] - 1, $dateEnd['Y'] + 1 | |
915 | )); | |
916 | break; | |
917 | ||
6a488035 TO |
918 | case 'yearweek': |
919 | $dateEnd = date("Ymd", mktime(0, 0, 0, $dateEnd['M'], | |
9d72cede EM |
920 | $dateEnd['d'] + 6, $dateEnd['Y'] |
921 | )); | |
6a488035 TO |
922 | break; |
923 | ||
924 | case 'quarter': | |
925 | $dateEnd = date("Ymd", mktime(0, 0, 0, $dateEnd['M'] + 3, | |
9d72cede EM |
926 | $dateEnd['d'] - 1, $dateEnd['Y'] |
927 | )); | |
6a488035 TO |
928 | break; |
929 | } | |
930 | $url = CRM_Report_Utils_Report::getNextUrl('contribute/detail', | |
9d72cede EM |
931 | "reset=1&force=1&receive_date_from={$dateStart}&receive_date_to={$dateEnd}", |
932 | $this->_absoluteUrl, | |
933 | $this->_id, | |
934 | $this->_drilldownReport | |
935 | ); | |
6a488035 TO |
936 | $rows[$rowNum]['civicrm_contribution_receive_date_start_link'] = $url; |
937 | $rows[$rowNum]['civicrm_contribution_receive_date_start_hover'] = ts('List all contribution(s) for this date unit.'); | |
938 | $entryFound = TRUE; | |
939 | } | |
940 | ||
941 | // make subtotals look nicer | |
942 | if (array_key_exists('civicrm_contribution_receive_date_subtotal', $row) && | |
943 | !$row['civicrm_contribution_receive_date_subtotal'] | |
944 | ) { | |
945 | $this->fixSubTotalDisplay($rows[$rowNum], $this->_statFields); | |
946 | $entryFound = TRUE; | |
947 | } | |
948 | ||
949 | // convert display name to links | |
950 | if (array_key_exists('civicrm_contact_sort_name', $row) && | |
951 | array_key_exists('civicrm_contact_id', $row) | |
952 | ) { | |
953 | $url = CRM_Report_Utils_Report::getNextUrl('contribute/detail', | |
954 | 'reset=1&force=1&id_op=eq&id_value=' . $row['civicrm_contact_id'], | |
955 | $this->_absoluteUrl, $this->_id, $this->_drilldownReport | |
956 | ); | |
957 | $rows[$rowNum]['civicrm_contact_sort_name_link'] = $url; | |
958 | $rows[$rowNum]['civicrm_contact_sort_name_hover'] = ts("Lists detailed contribution(s) for this record."); | |
959 | $entryFound = TRUE; | |
960 | } | |
961 | ||
8a347ca5 RO |
962 | // convert contribution status id to status name |
963 | if ($value = CRM_Utils_Array::value('civicrm_contribution_contribution_status_id', $row)) { | |
964 | $rows[$rowNum]['civicrm_contribution_contribution_status_id'] = $contributionStatus[$value]; | |
965 | $entryFound = TRUE; | |
966 | } | |
967 | ||
5e0343e8 | 968 | if (!empty($row['civicrm_financial_trxn_card_type_id'])) { |
969 | $rows[$rowNum]['civicrm_financial_trxn_card_type_id'] = $this->getLabels($row['civicrm_financial_trxn_card_type_id'], 'CRM_Financial_DAO_FinancialTrxn', 'card_type_id'); | |
fa5fb88c E |
970 | $entryFound = TRUE; |
971 | } | |
1c46a84c | 972 | |
973 | if ($value = CRM_Utils_Array::value('civicrm_contribution_contribution_page_id', $row)) { | |
974 | $rows[$rowNum]['civicrm_contribution_contribution_page_id'] = $contributionPages[$value]; | |
975 | $entryFound = TRUE; | |
976 | } | |
fa5fb88c | 977 | |
a7dbbc5d | 978 | // If using campaigns, convert campaign_id to campaign title |
6a488035 TO |
979 | if (array_key_exists('civicrm_contribution_campaign_id', $row)) { |
980 | if ($value = $row['civicrm_contribution_campaign_id']) { | |
bb3ab6f8 | 981 | $rows[$rowNum]['civicrm_contribution_campaign_id'] = $this->campaigns[$value]; |
6a488035 TO |
982 | } |
983 | $entryFound = TRUE; | |
984 | } | |
2ebf49a4 | 985 | |
8d2ca6b8 | 986 | // convert batch id to batch title |
c76af7c4 E |
987 | if (!empty($row['civicrm_batch_batch_id']) && !in_array('Subtotal', $rows[$rowNum])) { |
988 | $rows[$rowNum]['civicrm_batch_batch_id'] = $this->getLabels($row['civicrm_batch_batch_id'], 'CRM_Batch_BAO_EntityBatch', 'batch_id'); | |
8d2ca6b8 E |
989 | $entryFound = TRUE; |
990 | } | |
991 | ||
6a488035 | 992 | $entryFound = $this->alterDisplayAddressFields($row, $rows, $rowNum, 'contribute/detail', 'List all contribution(s) for this ') ? TRUE : $entryFound; |
7a4192f7 | 993 | $entryFound = $this->alterDisplayContactFields($row, $rows, $rowNum, 'contribute/detail', 'List all contribution(s) for this ') ? TRUE : $entryFound; |
6a488035 | 994 | |
6a488035 TO |
995 | // skip looking further in rows, if first row itself doesn't |
996 | // have the column we need | |
997 | if (!$entryFound) { | |
998 | break; | |
999 | } | |
1000 | } | |
1001 | } | |
96025800 | 1002 | |
8446bae6 | 1003 | /** |
1004 | * Calculate mode. | |
1005 | * | |
1006 | * Note this is a slow query. Alternative is extended reports. | |
1007 | * | |
1008 | * @param string $sql | |
1009 | * @return array|null | |
1010 | */ | |
1011 | protected function calculateMode($sql) { | |
1012 | $mode = []; | |
1013 | $modeDAO = CRM_Core_DAO::executeQuery($sql); | |
1014 | while ($modeDAO->fetch()) { | |
1015 | if ($modeDAO->civicrm_contribution_total_amount_count > 1) { | |
1016 | $mode[] = CRM_Utils_Money::format($modeDAO->amount, $modeDAO->currency); | |
1017 | } | |
1018 | else { | |
c995124e | 1019 | $mode[] = ts('N/A'); |
8446bae6 | 1020 | } |
1021 | } | |
1022 | return $mode; | |
1023 | } | |
1024 | ||
1025 | /** | |
1026 | * Calculate mode. | |
1027 | * | |
1028 | * Note this is a slow query. Alternative is extended reports. | |
1029 | * | |
1030 | * @return array|null | |
1031 | */ | |
1032 | protected function calculateMedian() { | |
1033 | $sql = "{$this->_from} {$this->_where}"; | |
1034 | $currencies = CRM_Core_OptionGroup::values('currencies_enabled'); | |
1035 | $median = []; | |
1036 | foreach ($currencies as $currency => $val) { | |
1037 | $midValue = 0; | |
1038 | $where = "AND {$this->_aliases['civicrm_contribution']}.currency = '{$currency}'"; | |
1039 | $rowCount = CRM_Core_DAO::singleValueQuery("SELECT count(*) as count {$sql} {$where}"); | |
1040 | ||
1041 | $even = FALSE; | |
1042 | $offset = 1; | |
1043 | $medianRow = floor($rowCount / 2); | |
1044 | if ($rowCount % 2 == 0 && !empty($medianRow)) { | |
1045 | $even = TRUE; | |
1046 | $offset++; | |
1047 | $medianRow--; | |
1048 | } | |
1049 | ||
1050 | $medianValue = "SELECT {$this->_aliases['civicrm_contribution']}.total_amount as median | |
1051 | {$sql} {$where} | |
1052 | ORDER BY median LIMIT {$medianRow},{$offset}"; | |
1053 | $medianValDAO = CRM_Core_DAO::executeQuery($medianValue); | |
1054 | while ($medianValDAO->fetch()) { | |
1055 | if ($even) { | |
1056 | $midValue = $midValue + $medianValDAO->median; | |
1057 | } | |
1058 | else { | |
1059 | $median[] = CRM_Utils_Money::format($medianValDAO->median, $currency); | |
1060 | } | |
1061 | } | |
1062 | if ($even) { | |
1063 | $midValue = $midValue / 2; | |
1064 | $median[] = CRM_Utils_Money::format($midValue, $currency); | |
1065 | } | |
1066 | } | |
1067 | return $median; | |
1068 | } | |
1069 | ||
6a488035 | 1070 | } |