CRM-17586 - ensure total goal is accurate.
[civicrm-core.git] / CRM / Report / Form / Contribute / PCP.php
CommitLineData
6a488035 1<?php
6a488035
TO
2/*
3 +--------------------------------------------------------------------+
7e9e8871 4 | CiviCRM version 4.7 |
6a488035 5 +--------------------------------------------------------------------+
e7112fa7 6 | Copyright CiviCRM LLC (c) 2004-2015 |
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
e7112fa7 31 * @copyright CiviCRM LLC (c) 2004-2015
6a488035
TO
32 * $Id$
33 *
34 */
35class CRM_Report_Form_Contribute_PCP extends CRM_Report_Form {
74cf4551 36 /**
74cf4551
EM
37 */
38 /**
74cf4551 39 */
00be9182 40 public function __construct() {
6a488035 41 $this->_columns = array(
9d72cede 42 'civicrm_contact' => array(
6a488035 43 'dao' => 'CRM_Contact_DAO_Contact',
9d72cede
EM
44 'fields' => array(
45 'sort_name' => array(
46 'title' => ts('Supporter'),
6a488035
TO
47 'required' => TRUE,
48 'default' => TRUE,
49 ),
9d72cede 50 'id' => array(
6a488035
TO
51 'required' => TRUE,
52 'no_display' => TRUE,
53 ),
9d72cede 54 'contact_type' => array(
30f85891
RN
55 'title' => ts('Supporter Contact Type'),
56 ),
9d72cede 57 'contact_sub_type' => array(
b8f96eb8 58 'title' => ts('Supporter Contact Subtype'),
30f85891 59 ),
6a488035 60 ),
9d72cede
EM
61 'filters' => array(
62 'sort_name' => array(
63 'title' => ts('Supporter Name'),
6a488035
TO
64 'type' => CRM_Utils_Type::T_STRING,
65 'operator' => 'like',
66 ),
9d72cede
EM
67 'id' => array(
68 'title' => ts('Contact ID'),
6a488035
TO
69 'no_display' => TRUE,
70 ),
71 ),
72 'grouping' => 'pcp-fields',
73 ),
9d72cede 74 'civicrm_contribution_page' => array(
6a488035 75 'dao' => 'CRM_Contribute_DAO_ContributionPage',
9d72cede
EM
76 'fields' => array(
77 'page_title' => array(
78 'title' => ts('Contribution Page Title'),
6a488035
TO
79 'name' => 'title',
80 'default' => TRUE,
81 ),
82 ),
9d72cede
EM
83 'filters' => array(
84 'page_title' => array(
85 'title' => ts('Contribution Page Title'),
6a488035
TO
86 'name' => 'title',
87 'type' => CRM_Utils_Type::T_STRING,
88 ),
89 ),
90 'grouping' => 'pcp-fields',
91 ),
9d72cede 92 'civicrm_pcp' => array(
6a488035 93 'dao' => 'CRM_PCP_DAO_PCP',
9d72cede
EM
94 'fields' => array(
95 'title' => array(
96 'title' => ts('Personal Campaign Title'),
6a488035
TO
97 'default' => TRUE,
98 ),
9d72cede
EM
99 'goal_amount' => array(
100 'title' => ts('Goal Amount'),
6a488035
TO
101 'type' => CRM_Utils_Type::T_MONEY,
102 'default' => TRUE,
103 ),
104 ),
9d72cede
EM
105 'filters' => array(
106 'title' => array(
107 'title' => ts('Personal Campaign Title'),
6a488035
TO
108 'type' => CRM_Utils_Type::T_STRING,
109 ),
110 ),
111 'grouping' => 'pcp-fields',
112 ),
9d72cede 113 'civicrm_contribution_soft' => array(
6a488035 114 'dao' => 'CRM_Contribute_DAO_ContributionSoft',
9d72cede
EM
115 'fields' => array(
116 'amount_1' => array(
117 'title' => ts('Committed Amount'),
6a488035
TO
118 'name' => 'amount',
119 'type' => CRM_Utils_Type::T_MONEY,
120 'default' => TRUE,
9d72cede
EM
121 'statistics' => array(
122 'sum' => ts('Committed Amount'),
6a488035
TO
123 ),
124 ),
9d72cede
EM
125 'amount_2' => array(
126 'title' => ts('Amount Received'),
6a488035
TO
127 'name' => 'amount',
128 'type' => CRM_Utils_Type::T_MONEY,
129 'default' => TRUE,
130 // nice trick with dbAlias
131 'dbAlias' => 'SUM(IF( contribution_civireport.contribution_status_id > 1, 0, contribution_soft_civireport.amount))',
132 ),
9d72cede
EM
133 'soft_id' => array(
134 'title' => ts('Number of Donors'),
6a488035
TO
135 'name' => 'id',
136 'default' => TRUE,
9d72cede
EM
137 'statistics' => array(
138 'count' => ts('Number of Donors'),
6a488035
TO
139 ),
140 ),
141 ),
9d72cede
EM
142 'filters' => array(
143 'amount_2' => array(
144 'title' => ts('Amount Received'),
6a488035
TO
145 'type' => CRM_Utils_Type::T_MONEY,
146 'dbAlias' => 'SUM(IF( contribution_civireport.contribution_status_id > 1, 0, contribution_soft_civireport.amount))',
147 ),
148 ),
149 'grouping' => 'pcp-fields',
150 ),
9d72cede 151 'civicrm_contribution' => array(
6a488035 152 'dao' => 'CRM_Contribute_DAO_Contribution',
9d72cede
EM
153 'fields' => array(
154 'contribution_id' => array(
6a488035
TO
155 'name' => 'id',
156 'no_display' => TRUE,
157 'required' => TRUE,
158 ),
9d72cede
EM
159 'receive_date' => array(
160 'title' => ts('Most Recent Contribution'),
6a488035 161 'default' => TRUE,
9d72cede
EM
162 'statistics' => array(
163 'max' => ts('Most Recent Contribution'),
6a488035
TO
164 ),
165 ),
166 ),
167 'grouping' => 'pcp-fields',
168 ),
169 );
170
171 parent::__construct();
172 }
173
00be9182 174 public function from() {
6a488035
TO
175 $this->_from = "
176FROM civicrm_pcp {$this->_aliases['civicrm_pcp']}
177
2f4c2f5d 178LEFT JOIN civicrm_contribution_soft {$this->_aliases['civicrm_contribution_soft']}
179 ON {$this->_aliases['civicrm_pcp']}.id =
6a488035
TO
180 {$this->_aliases['civicrm_contribution_soft']}.pcp_id
181
2f4c2f5d 182LEFT JOIN civicrm_contribution {$this->_aliases['civicrm_contribution']}
183 ON {$this->_aliases['civicrm_contribution_soft']}.contribution_id =
6a488035
TO
184 {$this->_aliases['civicrm_contribution']}.id
185
2f4c2f5d 186LEFT JOIN civicrm_contact {$this->_aliases['civicrm_contact']}
187 ON {$this->_aliases['civicrm_pcp']}.contact_id =
188 {$this->_aliases['civicrm_contact']}.id
6a488035
TO
189
190LEFT JOIN civicrm_contribution_page {$this->_aliases['civicrm_contribution_page']}
2f4c2f5d 191 ON {$this->_aliases['civicrm_pcp']}.page_id =
6a488035
TO
192 {$this->_aliases['civicrm_contribution_page']}.id";
193 }
194
00be9182 195 public function groupBy() {
6a488035
TO
196 $this->_groupBy = "GROUP BY {$this->_aliases['civicrm_pcp']}.id";
197 }
198
00be9182 199 public function orderBy() {
6a488035
TO
200 $this->_orderBy = " ORDER BY {$this->_aliases['civicrm_contact']}.sort_name ";
201 }
202
00be9182 203 public function where() {
6a488035
TO
204 $whereClauses = $havingClauses = array();
205
206 foreach ($this->_columns as $tableName => $table) {
207 if (array_key_exists('filters', $table)) {
208 foreach ($table['filters'] as $fieldName => $field) {
209 $clause = NULL;
210
211 if (CRM_Utils_Array::value('type', $field) & CRM_Utils_Type::T_DATE) {
212 $relative = CRM_Utils_Array::value("{$fieldName}_relative", $this->_params);
9d72cede
EM
213 $from = CRM_Utils_Array::value("{$fieldName}_from", $this->_params);
214 $to = CRM_Utils_Array::value("{$fieldName}_to", $this->_params);
215 $clause = $this->dateClause($field['name'], $relative, $from, $to, $field['type']);
6a488035
TO
216 }
217 else {
218 $op = CRM_Utils_Array::value("{$fieldName}_op", $this->_params);
219
220 if ($op) {
221 $clause = $this->whereClause($field,
222 $op,
223 CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
224 CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
225 CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
226 );
227 }
228 }
229
230 if (!empty($clause)) {
231 if ($tableName == 'civicrm_contribution_soft' &&
232 $fieldName == 'amount_2'
233 ) {
234 $havingClauses[] = $clause;
235 }
236 else {
237 $whereClauses[] = $clause;
238 }
239 }
240 }
241 }
242 }
243 if (empty($whereClauses)) {
244 $this->_where = "WHERE ( 1 ) ";
245 }
246 else {
247 $this->_where = "WHERE " . implode(' AND ', $whereClauses);
248 }
249 if ($this->_aclWhere) {
250 $this->_where .= " AND {$this->_aclWhere} ";
251 }
252 $this->_having = "";
253 if (!empty($havingClauses)) {
254 // use this clause to construct group by clause.
255 $this->_having = "HAVING " . implode(' AND ', $havingClauses);
256 }
257 }
258
74cf4551
EM
259 /**
260 * @param $rows
261 *
262 * @return array
263 */
00be9182 264 public function statistics(&$rows) {
ecd4d80f
JM
265 $statistics = parent::statistics($rows);
266
ea9ec579 267 // Calculate totals from the civicrm_contribution_soft table.
389bcebf 268 $select
ea9ec579 269 = "SELECT SUM({$this->_aliases['civicrm_contribution_soft']}.amount) as committed_total, " .
389bcebf 270 "COUNT({$this->_aliases['civicrm_contribution_soft']}.id) as donors_total, " .
271 "SUM(IF( contribution_civireport.contribution_status_id > 1, 0, contribution_soft_civireport.amount)) AS received_total ";
ecd4d80f
JM
272 $sql = "{$select} {$this->_from} {$this->_where}";
273 $dao = CRM_Core_DAO::executeQuery($sql);
274 $dao->fetch();
ea9ec579
JM
275 $committed_total = $dao->committed_total;
276 $received_total = $dao->received_total;
277 $donors_total = $dao->donors_total;
278
279 // Calculate goal total goal from the PCP table (we only want one result per
280 // PCP page - the query above produces one result per contribution made).
281 $sql =
282 "SELECT SUM(goal_amount) as goal_total FROM civicrm_pcp WHERE ".
283 "goal_amount IS NOT NULL AND id IN (" .
284 "SELECT DISTINCT {$this->_aliases['civicrm_pcp']}.id {$this->_from} ".
285 "{$this->_where}".
286 ")";
287 $dao = CRM_Core_DAO::executeQuery($sql);
288 $dao->fetch();
289 $goal_total = $dao->goal_total;
290
ecd4d80f
JM
291 $statistics['counts']['goal_total'] = array(
292 'title' => ts('Goal Total'),
ea9ec579 293 'value' => $goal_total,
21dfd5f5 294 'type' => CRM_Utils_Type::T_MONEY,
ecd4d80f
JM
295 );
296 $statistics['counts']['committed_total'] = array(
297 'title' => ts('Total Committed'),
ea9ec579 298 'value' => $committed_total,
21dfd5f5 299 'type' => CRM_Utils_Type::T_MONEY,
ecd4d80f
JM
300 );
301 $statistics['counts']['received_total'] = array(
302 'title' => ts('Total Received'),
ea9ec579 303 'value' => $received_total,
21dfd5f5 304 'type' => CRM_Utils_Type::T_MONEY,
ecd4d80f
JM
305 );
306 $statistics['counts']['donors_total'] = array(
307 'title' => ts('Total Donors'),
ea9ec579 308 'value' => $donors_total,
21dfd5f5 309 'type' => CRM_Utils_Type::T_INT,
ecd4d80f
JM
310 );
311 return $statistics;
312 }
74cf4551
EM
313
314 /**
ced9bfed
EM
315 * Alter display of rows.
316 *
317 * Iterate through the rows retrieved via SQL and make changes for display purposes,
318 * such as rendering contacts as links.
319 *
320 * @param array $rows
321 * Rows generated by SQL, with an array for each row.
74cf4551 322 */
00be9182 323 public function alterDisplay(&$rows) {
6a488035
TO
324 $entryFound = FALSE;
325 $checkList = array();
326 foreach ($rows as $rowNum => $row) {
327 if (!empty($this->_noRepeats) && $this->_outputMode != 'csv') {
328 // not repeat contact sort names if it matches with the one
329 // in previous row
330 $repeatFound = FALSE;
331
332 foreach ($row as $colName => $colVal) {
a7488080 333 if (!empty($checkList[$colName]) &&
6a488035
TO
334 is_array($checkList[$colName]) &&
335 in_array($colVal, $checkList[$colName])
336 ) {
337 $rows[$rowNum][$colName] = "";
338 $repeatFound = TRUE;
339 }
340 if (in_array($colName, $this->_noRepeats)) {
341 $checkList[$colName][] = $colVal;
342 }
343 }
344 }
345
346 if (array_key_exists('civicrm_contact_sort_name', $row) &&
347 $rows[$rowNum]['civicrm_contact_sort_name'] &&
348 array_key_exists('civicrm_contact_id', $row)
349 ) {
350 $url = CRM_Utils_System::url("civicrm/contact/view",
351 'reset=1&cid=' . $row['civicrm_contact_id'],
352 $this->_absoluteUrl
353 );
354 $rows[$rowNum]['civicrm_contact_sort_name_link'] = $url;
355 $rows[$rowNum]['civicrm_contact_sort_name_hover'] = ts("View Contact Summary for this Contact.");
356 $entryFound = TRUE;
357 }
358
359 if (!$entryFound) {
360 break;
361 }
362 }
363 }
96025800 364
6a488035 365}