Commit | Line | Data |
---|---|---|
c1413e28 DG |
1 | <?php |
2 | /* | |
3 | +--------------------------------------------------------------------+ | |
bc77d7c0 | 4 | | Copyright CiviCRM LLC. All rights reserved. | |
c1413e28 | 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 | | |
c1413e28 | 9 | +--------------------------------------------------------------------+ |
d25dd0ee | 10 | */ |
c1413e28 DG |
11 | |
12 | /** | |
13 | * | |
14 | * @package CRM | |
ca5cec67 | 15 | * @copyright CiviCRM LLC https://civicrm.org/licensing |
c1413e28 DG |
16 | */ |
17 | class CRM_Report_Form_Contribute_Recur extends CRM_Report_Form { | |
18 | ||
1728e9a0 | 19 | /** |
20 | * This report has not been optimised for group filtering. | |
21 | * | |
22 | * The functionality for group filtering has been improved but not | |
23 | * all reports have been adjusted to take care of it. This report has not | |
24 | * and will run an inefficient query until fixed. | |
25 | * | |
1728e9a0 | 26 | * @var bool |
0e480632 | 27 | * @see https://issues.civicrm.org/jira/browse/CRM-19170 |
1728e9a0 | 28 | */ |
29 | protected $groupFilterNotOptimised = TRUE; | |
30 | ||
ced9bfed EM |
31 | /** |
32 | * Class constructor. | |
33 | */ | |
00be9182 | 34 | public function __construct() { |
be2fb01f CW |
35 | $this->_columns = [ |
36 | 'civicrm_contact' => [ | |
c1413e28 | 37 | 'dao' => 'CRM_Contact_DAO_Contact', |
be2fb01f CW |
38 | 'order_bys' => [ |
39 | 'sort_name' => [ | |
c1413e28 | 40 | 'title' => ts("Last name, First name"), |
be2fb01f CW |
41 | ], |
42 | ], | |
43 | 'fields' => [ | |
44 | 'sort_name' => [ | |
c1413e28 DG |
45 | 'title' => ts('Contact Name'), |
46 | 'no_repeat' => TRUE, | |
47 | 'default' => TRUE, | |
be2fb01f CW |
48 | ], |
49 | 'id' => [ | |
c1413e28 DG |
50 | 'no_display' => TRUE, |
51 | 'required' => TRUE, | |
be2fb01f CW |
52 | ], |
53 | ], | |
54 | ], | |
55 | 'civicrm_email' => [ | |
c1413e28 | 56 | 'dao' => 'CRM_Core_DAO_Email', |
be2fb01f CW |
57 | 'fields' => [ |
58 | 'email' => [ | |
c1413e28 DG |
59 | 'title' => ts('Email'), |
60 | 'no_repeat' => TRUE, | |
be2fb01f CW |
61 | ], |
62 | ], | |
c1413e28 | 63 | 'grouping' => 'contact-fields', |
be2fb01f CW |
64 | ], |
65 | 'civicrm_phone' => [ | |
c1413e28 | 66 | 'dao' => 'CRM_Core_DAO_Phone', |
be2fb01f CW |
67 | 'fields' => [ |
68 | 'phone' => [ | |
c1413e28 DG |
69 | 'title' => ts('Phone'), |
70 | 'no_repeat' => TRUE, | |
be2fb01f CW |
71 | ], |
72 | ], | |
c1413e28 | 73 | 'grouping' => 'contact-fields', |
be2fb01f CW |
74 | ], |
75 | 'civicrm_contribution' => [ | |
c1413e28 | 76 | 'dao' => 'CRM_Contribute_DAO_Contribution', |
be2fb01f CW |
77 | 'fields' => [ |
78 | 'id' => [ | |
c1413e28 DG |
79 | 'no_display' => TRUE, |
80 | 'required' => TRUE, | |
be2fb01f CW |
81 | ], |
82 | 'total_amount' => [ | |
c1413e28 | 83 | 'title' => ts('Amount Contributed to Date'), |
be2fb01f | 84 | 'statistics' => [ |
21dfd5f5 | 85 | 'sum' => ts("Total Amount Contributed"), |
be2fb01f CW |
86 | ], |
87 | ], | |
6dce38a5 AM |
88 | 'source' => [ |
89 | 'title' => ts('Contribution Source'), | |
90 | ], | |
be2fb01f CW |
91 | ], |
92 | ], | |
93 | 'civicrm_financial_trxn' => [ | |
96b82f45 | 94 | 'dao' => 'CRM_Financial_DAO_FinancialTrxn', |
be2fb01f CW |
95 | 'fields' => [ |
96 | 'card_type_id' => [ | |
d72b084a | 97 | 'title' => ts('Credit Card Type'), |
5e0343e8 | 98 | 'dbAlias' => 'GROUP_CONCAT(financial_trxn_civireport.card_type_id SEPARATOR ",")', |
be2fb01f CW |
99 | ], |
100 | ], | |
101 | 'filters' => [ | |
102 | 'card_type_id' => [ | |
d72b084a | 103 | 'title' => ts('Credit Card Type'), |
96b82f45 | 104 | 'operatorType' => CRM_Report_Form::OP_MULTISELECT, |
5e0343e8 | 105 | 'options' => CRM_Financial_DAO_FinancialTrxn::buildOptions('card_type_id'), |
96b82f45 E |
106 | 'default' => NULL, |
107 | 'type' => CRM_Utils_Type::T_STRING, | |
be2fb01f CW |
108 | ], |
109 | ], | |
110 | ], | |
111 | 'civicrm_contribution_recur' => [ | |
c1413e28 | 112 | 'dao' => 'CRM_Contribute_DAO_ContributionRecur', |
be2fb01f CW |
113 | 'fields' => [ |
114 | 'id' => [ | |
c1413e28 DG |
115 | 'no_display' => TRUE, |
116 | 'required' => TRUE, | |
be2fb01f CW |
117 | ], |
118 | 'currency' => [ | |
c1413e28 DG |
119 | 'title' => ts("Currency"), |
120 | 'required' => TRUE, | |
121 | 'no_display' => TRUE, | |
be2fb01f CW |
122 | ], |
123 | 'contribution_status_id' => [ | |
be205937 | 124 | 'title' => ts('Contribution Status'), |
be2fb01f CW |
125 | ], |
126 | 'frequency_interval' => [ | |
c1413e28 DG |
127 | 'title' => ts('Frequency interval'), |
128 | 'default' => TRUE, | |
be2fb01f CW |
129 | ], |
130 | 'frequency_unit' => [ | |
c1413e28 DG |
131 | 'title' => ts('Frequency unit'), |
132 | 'default' => TRUE, | |
be2fb01f CW |
133 | ], |
134 | 'amount' => [ | |
979f1561 | 135 | 'title' => ts('Installment Amount'), |
2006e4c4 | 136 | 'default' => TRUE, |
be2fb01f CW |
137 | ], |
138 | 'installments' => [ | |
c1413e28 DG |
139 | 'title' => ts('Installments'), |
140 | 'default' => TRUE, | |
be2fb01f CW |
141 | ], |
142 | 'start_date' => [ | |
c1413e28 | 143 | 'title' => ts('Start Date'), |
be2fb01f CW |
144 | ], |
145 | 'create_date' => [ | |
c1413e28 | 146 | 'title' => ts('Create Date'), |
be2fb01f CW |
147 | ], |
148 | 'modified_date' => [ | |
c1413e28 | 149 | 'title' => ts('Modified Date'), |
be2fb01f CW |
150 | ], |
151 | 'cancel_date' => [ | |
c1413e28 | 152 | 'title' => ts('Cancel Date'), |
be2fb01f CW |
153 | ], |
154 | 'end_date' => [ | |
c1413e28 | 155 | 'title' => ts('End Date'), |
be2fb01f CW |
156 | ], |
157 | 'next_sched_contribution_date' => [ | |
c1413e28 | 158 | 'title' => ts('Next Scheduled Contribution Date'), |
be2fb01f CW |
159 | ], |
160 | 'failure_count' => [ | |
c1413e28 | 161 | 'title' => ts('Failure Count'), |
be2fb01f CW |
162 | ], |
163 | 'failure_retry_date' => [ | |
c1413e28 | 164 | 'title' => ts('Failure Retry Date'), |
be2fb01f CW |
165 | ], |
166 | 'payment_processor_id' => [ | |
b7327f07 | 167 | 'title' => ts('Payment Processor'), |
be2fb01f CW |
168 | ], |
169 | ], | |
170 | 'filters' => [ | |
171 | 'contribution_status_id' => [ | |
be205937 | 172 | 'title' => ts('Contribution Status'), |
c1413e28 | 173 | 'operatorType' => CRM_Report_Form::OP_MULTISELECT, |
c0aaecf9 | 174 | 'options' => CRM_Contribute_BAO_Contribution::buildOptions('contribution_status_id', 'search'), |
be2fb01f | 175 | 'default' => [5], |
c1413e28 | 176 | 'type' => CRM_Utils_Type::T_INT, |
be2fb01f CW |
177 | ], |
178 | 'currency' => [ | |
fd6a6828 | 179 | 'title' => ts('Currency'), |
c1413e28 DG |
180 | 'operatorType' => CRM_Report_Form::OP_MULTISELECT, |
181 | 'options' => CRM_Core_OptionGroup::values('currencies_enabled'), | |
182 | 'default' => NULL, | |
183 | 'type' => CRM_Utils_Type::T_STRING, | |
be2fb01f CW |
184 | ], |
185 | 'financial_type_id' => [ | |
c1413e28 DG |
186 | 'title' => ts('Financial Type'), |
187 | 'operatorType' => CRM_Report_Form::OP_MULTISELECT, | |
51d1f926 | 188 | 'options' => CRM_Contribute_BAO_Contribution::buildOptions('financial_type_id', 'search'), |
c1413e28 | 189 | 'type' => CRM_Utils_Type::T_INT, |
be2fb01f CW |
190 | ], |
191 | 'frequency_unit' => [ | |
c1413e28 DG |
192 | 'title' => ts('Frequency Unit'), |
193 | 'operatorType' => CRM_Report_Form::OP_MULTISELECT, | |
84178120 | 194 | 'options' => CRM_Core_OptionGroup::values('recur_frequency_units'), |
d3f09acb | 195 | 'type' => CRM_Utils_Type::T_STRING, |
be2fb01f CW |
196 | ], |
197 | 'frequency_interval' => [ | |
c1413e28 DG |
198 | 'title' => ts('Frequency Interval'), |
199 | 'type' => CRM_Utils_Type::T_INT, | |
be2fb01f CW |
200 | ], |
201 | 'amount' => [ | |
2006e4c4 | 202 | 'title' => ts('Installment Amount'), |
203 | 'type' => CRM_Utils_Type::T_MONEY, | |
be2fb01f CW |
204 | ], |
205 | 'installments' => [ | |
c1413e28 DG |
206 | 'title' => ts('Installments'), |
207 | 'type' => CRM_Utils_Type::T_INT, | |
be2fb01f CW |
208 | ], |
209 | 'start_date' => [ | |
c1413e28 DG |
210 | 'title' => ts('Start Date'), |
211 | 'operatorType' => CRM_Report_Form::OP_DATE, | |
8fea776b | 212 | 'type' => CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME, |
be2fb01f CW |
213 | ], |
214 | 'next_sched_contribution_date' => [ | |
c1413e28 DG |
215 | 'title' => ts('Next Scheduled Contribution Date'), |
216 | 'operatorType' => CRM_Report_Form::OP_DATE, | |
8fea776b | 217 | 'type' => CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME, |
be2fb01f CW |
218 | ], |
219 | 'end_date' => [ | |
c1413e28 DG |
220 | 'title' => ts('End Date'), |
221 | 'operatorType' => CRM_Report_Form::OP_DATE, | |
8fea776b | 222 | 'type' => CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME, |
be2fb01f CW |
223 | ], |
224 | 'modified_date' => [ | |
979f1561 | 225 | 'title' => ts('Last Contribution Processed'), |
226 | 'operatorType' => CRM_Report_Form::OP_DATE, | |
8fea776b | 227 | 'type' => CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME, |
be2fb01f CW |
228 | ], |
229 | 'calculated_end_date' => [ | |
c1413e28 DG |
230 | 'title' => ts('Calculated end date (either end date or date all installments will be made)'), |
231 | 'description' => "does this work?", | |
232 | 'operatorType' => CRM_Report_Form::OP_DATE, | |
21dfd5f5 | 233 | 'pseudofield' => TRUE, |
be2fb01f CW |
234 | ], |
235 | 'payment_processor_id' => [ | |
b7327f07 MWMC |
236 | 'title' => ts('Payment Processor'), |
237 | 'operatorType' => CRM_Report_Form::OP_MULTISELECT, | |
238 | 'options' => CRM_Contribute_BAO_ContributionRecur::buildOptions('payment_processor_id', 'get'), | |
239 | 'default' => NULL, | |
240 | 'type' => CRM_Utils_Type::T_INT, | |
be2fb01f CW |
241 | ], |
242 | ], | |
243 | ], | |
244 | ]; | |
c1413e28 | 245 | $this->_currencyColumn = 'civicrm_contribution_recur_currency'; |
979f1561 | 246 | $this->_groupFilter = TRUE; |
c1413e28 DG |
247 | parent::__construct(); |
248 | } | |
353ffa53 | 249 | |
ced9bfed EM |
250 | /** |
251 | * Get template file name. | |
252 | * | |
253 | * @return string | |
254 | */ | |
00be9182 | 255 | public function getTemplateName() { |
84178120 | 256 | return 'CRM/Report/Form.tpl'; |
c1413e28 DG |
257 | } |
258 | ||
ced9bfed EM |
259 | /** |
260 | * Generate FROM SQL clause. | |
261 | */ | |
00be9182 | 262 | public function from() { |
c1413e28 DG |
263 | $this->_from = " |
264 | FROM civicrm_contact {$this->_aliases['civicrm_contact']} | |
265 | INNER JOIN civicrm_contribution_recur {$this->_aliases['civicrm_contribution_recur']} | |
266 | ON {$this->_aliases['civicrm_contact']}.id = {$this->_aliases['civicrm_contribution_recur']}.contact_id"; | |
267 | $this->_from .= " | |
268 | LEFT JOIN civicrm_contribution {$this->_aliases['civicrm_contribution']} | |
269 | ON {$this->_aliases['civicrm_contribution_recur']}.id = {$this->_aliases['civicrm_contribution']}.contribution_recur_id"; | |
3b2bbbfb | 270 | |
271 | $this->joinPhoneFromContact(); | |
272 | $this->joinEmailFromContact(); | |
96b82f45 E |
273 | |
274 | // for credit card type | |
987c1844 | 275 | $this->addFinancialTrxnFromClause(); |
c1413e28 DG |
276 | } |
277 | ||
00be9182 | 278 | public function groupBy() { |
b708c08d | 279 | $this->_groupBy = CRM_Contact_BAO_Query::getGroupByFromSelectColumns($this->_selectClauses, "{$this->_aliases['civicrm_contribution_recur']}.id"); |
c1413e28 DG |
280 | } |
281 | ||
00be9182 | 282 | public function where() { |
c1413e28 DG |
283 | parent::where(); |
284 | // Handle calculated end date. This can come from one of two sources: | |
285 | // Either there is a specified end date for the end_date field | |
286 | // Or, we calculate the end date based on the start date + | |
287 | // installments * intervals using the mysql date_add function, along | |
288 | // with the interval unit (e.g. DATE_ADD(start_date, INTERVAL 12 * 1 MONTH) | |
be2fb01f | 289 | $date_suffixes = ['relative', 'from', 'to']; |
e34af001 | 290 | foreach ($date_suffixes as $suffix) { |
979f1561 | 291 | $isBreak = FALSE; |
c1413e28 | 292 | // Check to see if the user wants to search by calculated date. |
22e263ad | 293 | if (!empty($this->_params['calculated_end_date_' . $suffix])) { |
c1413e28 DG |
294 | // The calculated date field is in use - spring into action |
295 | // Gather values | |
9c1bc317 CW |
296 | $relative = $this->_params["calculated_end_date_relative"] ?? NULL; |
297 | $from = $this->_params["calculated_end_date_from"] ?? NULL; | |
298 | $to = $this->_params["calculated_end_date_to"] ?? NULL; | |
c1413e28 DG |
299 | $end_date_db_alias = $this->_columns['civicrm_contribution_recur']['filters']['end_date']['dbAlias']; |
300 | $end_date_type = $this->_columns['civicrm_contribution_recur']['filters']['end_date']['type']; | |
301 | $start_date_type = $this->_columns['civicrm_contribution_recur']['filters']['start_date']['type']; | |
302 | $frequency_unit_db_alias = $this->_columns['civicrm_contribution_recur']['filters']['frequency_unit']['dbAlias']; | |
303 | $frequency_interval_db_alias = $this->_columns['civicrm_contribution_recur']['filters']['frequency_interval']['dbAlias']; | |
304 | $installments_db_alias = $this->_columns['civicrm_contribution_recur']['filters']['installments']['dbAlias']; | |
305 | $start_date_db_alias = $this->_columns['civicrm_contribution_recur']['filters']['start_date']['dbAlias']; | |
306 | ||
307 | // The end date clause is simple to construct | |
353ffa53 | 308 | $end_date_clause = $this->dateClause($end_date_db_alias, $relative, $from, $to, $end_date_type, NULL, NULL); |
c1413e28 DG |
309 | |
310 | // NOTE: For the calculation based on installment, there doesn't | |
311 | // seem to be a way to include the interval unit (e.g. month, | |
312 | // date, etc) as a field name - so we have to build a complex | |
313 | // OR statement instead. | |
314 | ||
979f1561 | 315 | $this->_where .= 'AND (' . |
c1413e28 | 316 | $this->dateClause("DATE_ADD($start_date_db_alias, INTERVAL $installments_db_alias * COALESCE($frequency_interval_db_alias,1) month)", |
353ffa53 | 317 | $relative, $from, $to, $start_date_type, NULL, NULL); |
979f1561 | 318 | $this->_where .= " AND $frequency_unit_db_alias = 'month' ) OR \n"; |
c1413e28 | 319 | |
979f1561 | 320 | $this->_where .= '(' . |
c1413e28 | 321 | $this->dateClause("DATE_ADD($start_date_db_alias, INTERVAL $installments_db_alias * COALESCE($frequency_interval_db_alias,1) day)", |
353ffa53 | 322 | $relative, $from, $to, $start_date_type, NULL, NULL); |
979f1561 | 323 | $this->_where .= " AND $frequency_unit_db_alias = 'day' ) OR \n"; |
c1413e28 | 324 | |
979f1561 | 325 | $this->_where .= '(' . |
c1413e28 | 326 | $this->dateClause("DATE_ADD($start_date_db_alias, INTERVAL $installments_db_alias * COALESCE($frequency_interval_db_alias, 1) week)", |
353ffa53 | 327 | $relative, $from, $to, $start_date_type, NULL, NULL); |
cc3360ca | 328 | $this->_where .= " AND $frequency_unit_db_alias = 'week' ) OR \n"; |
c1413e28 | 329 | |
979f1561 | 330 | $this->_where .= '(' . |
c1413e28 | 331 | $this->dateClause("DATE_ADD($start_date_db_alias, INTERVAL $installments_db_alias * COALESCE($frequency_interval_db_alias, 1) year)", |
353ffa53 | 332 | $relative, $from, $to, $start_date_type, NULL, NULL); |
979f1561 | 333 | $this->_where .= " AND $frequency_unit_db_alias = 'year' ) |
334 | AND (($end_date_db_alias IS NOT NULL AND $end_date_clause) | |
335 | OR ($installments_db_alias IS NOT NULL)) | |
336 | "; | |
337 | $isBreak = TRUE; | |
338 | } | |
8fea776b | 339 | if (!empty($this->_params['modified_date_' . $suffix])) { |
340 | $this->_where .= " AND {$this->_aliases['civicrm_contribution_recur']}.contribution_status_id = 1"; | |
979f1561 | 341 | $isBreak = TRUE; |
342 | } | |
343 | if (!empty($isBreak)) { | |
c1413e28 DG |
344 | break; |
345 | } | |
346 | } | |
347 | } | |
348 | ||
ced9bfed EM |
349 | /** |
350 | * Alter display of rows. | |
351 | * | |
352 | * Iterate through the rows retrieved via SQL and make changes for display purposes, | |
353 | * such as rendering contacts as links. | |
354 | * | |
355 | * @param array $rows | |
356 | * Rows generated by SQL, with an array for each row. | |
357 | */ | |
00be9182 | 358 | public function alterDisplay(&$rows) { |
c3b82060 | 359 | $contributionStatus = CRM_Contribute_PseudoConstant::contributionStatus(NULL, 'label'); |
c1413e28 DG |
360 | foreach ($rows as $rowNum => $row) { |
361 | // convert display name to links | |
362 | if (array_key_exists('civicrm_contact_sort_name', $row) && | |
363 | CRM_Utils_Array::value('civicrm_contact_sort_name', $rows[$rowNum]) && | |
364 | array_key_exists('civicrm_contact_id', $row) | |
365 | ) { | |
366 | $url = CRM_Utils_System::url('civicrm/contact/view', | |
367 | 'reset=1&cid=' . $row['civicrm_contact_id'], | |
368 | $this->_absoluteUrl | |
369 | ); | |
370 | $rows[$rowNum]['civicrm_contact_sort_name_link'] = $url; | |
371 | $rows[$rowNum]['civicrm_contact_sort_name_hover'] = ts('View Contact Summary for this Contact.'); | |
372 | } | |
373 | ||
374 | // handle contribution status id | |
375 | if ($value = CRM_Utils_Array::value('civicrm_contribution_recur_contribution_status_id', $row)) { | |
376 | $rows[$rowNum]['civicrm_contribution_recur_contribution_status_id'] = $contributionStatus[$value]; | |
377 | } | |
84178120 | 378 | |
c1413e28 | 379 | if ($value = CRM_Utils_Array::value('civicrm_contribution_recur_amount', $row)) { |
84178120 | 380 | $rows[$rowNum]['civicrm_contribution_recur_amount'] = CRM_Utils_Money::format($rows[$rowNum]['civicrm_contribution_recur_amount'], $rows[$rowNum]['civicrm_contribution_recur_currency']); |
44fd0292 | 381 | } |
96b82f45 | 382 | |
5e0343e8 | 383 | if (!empty($row['civicrm_financial_trxn_card_type_id'])) { |
384 | $rows[$rowNum]['civicrm_financial_trxn_card_type_id'] = $this->getLabels($row['civicrm_financial_trxn_card_type_id'], 'CRM_Financial_DAO_FinancialTrxn', 'card_type_id'); | |
96b82f45 | 385 | } |
b7327f07 MWMC |
386 | |
387 | if (!empty($row['civicrm_contribution_recur_payment_processor_id'])) { | |
388 | $rows[$rowNum]['civicrm_contribution_recur_payment_processor_id'] = $this->getLabels($row['civicrm_contribution_recur_payment_processor_id'], 'CRM_Contribute_BAO_ContributionRecur', 'payment_processor_id'); | |
389 | } | |
c1413e28 DG |
390 | } |
391 | } | |
96025800 | 392 | |
ef10e0b5 | 393 | } |