3 +--------------------------------------------------------------------+
4 | Copyright CiviCRM LLC. All rights reserved. |
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 |
9 +--------------------------------------------------------------------+
15 * @copyright CiviCRM LLC https://civicrm.org/licensing
17 class CRM_Report_Form_Contribute_Recur
extends CRM_Report_Form
{
20 * This report has not been optimised for group filtering.
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.
27 * @see https://issues.civicrm.org/jira/browse/CRM-19170
29 protected $groupFilterNotOptimised = TRUE;
34 public function __construct() {
36 'civicrm_contact' => [
37 'dao' => 'CRM_Contact_DAO_Contact',
40 'title' => ts("Last name, First name"),
45 'title' => ts('Contact Name'),
56 'dao' => 'CRM_Core_DAO_Email',
59 'title' => ts('Email'),
63 'grouping' => 'contact-fields',
66 'dao' => 'CRM_Core_DAO_Phone',
69 'title' => ts('Phone'),
73 'grouping' => 'contact-fields',
75 'civicrm_contribution' => [
76 'dao' => 'CRM_Contribute_DAO_Contribution',
83 'title' => ts('Amount Contributed to Date'),
85 'sum' => ts("Total Amount Contributed"),
89 'title' => ts('Contribution Source'),
93 'civicrm_financial_trxn' => [
94 'dao' => 'CRM_Financial_DAO_FinancialTrxn',
97 'title' => ts('Credit Card Type'),
98 'dbAlias' => 'GROUP_CONCAT(financial_trxn_civireport.card_type_id SEPARATOR ",")',
103 'title' => ts('Credit Card Type'),
104 'operatorType' => CRM_Report_Form
::OP_MULTISELECT
,
105 'options' => CRM_Financial_DAO_FinancialTrxn
::buildOptions('card_type_id'),
107 'type' => CRM_Utils_Type
::T_STRING
,
111 'civicrm_contribution_recur' => [
112 'dao' => 'CRM_Contribute_DAO_ContributionRecur',
115 'no_display' => TRUE,
119 'title' => ts("Currency"),
121 'no_display' => TRUE,
123 'contribution_status_id' => [
124 'title' => ts('Contribution Status'),
126 'frequency_interval' => [
127 'title' => ts('Frequency interval'),
130 'frequency_unit' => [
131 'title' => ts('Frequency unit'),
135 'title' => ts('Installment Amount'),
139 'title' => ts('Installments'),
143 'title' => ts('Start Date'),
146 'title' => ts('Create Date'),
149 'title' => ts('Modified Date'),
152 'title' => ts('Cancel Date'),
155 'title' => ts('End Date'),
157 'next_sched_contribution_date' => [
158 'title' => ts('Next Scheduled Contribution Date'),
161 'title' => ts('Failure Count'),
163 'failure_retry_date' => [
164 'title' => ts('Failure Retry Date'),
166 'payment_processor_id' => [
167 'title' => ts('Payment Processor'),
171 'contribution_status_id' => [
172 'title' => ts('Contribution Status'),
173 'operatorType' => CRM_Report_Form
::OP_MULTISELECT
,
174 'options' => CRM_Contribute_BAO_Contribution
::buildOptions('contribution_status_id', 'search'),
176 'type' => CRM_Utils_Type
::T_INT
,
179 'title' => ts('Currency'),
180 'operatorType' => CRM_Report_Form
::OP_MULTISELECT
,
181 'options' => CRM_Core_OptionGroup
::values('currencies_enabled'),
183 'type' => CRM_Utils_Type
::T_STRING
,
185 'financial_type_id' => [
186 'title' => ts('Financial Type'),
187 'operatorType' => CRM_Report_Form
::OP_MULTISELECT
,
188 'options' => CRM_Contribute_BAO_Contribution
::buildOptions('financial_type_id', 'search'),
189 'type' => CRM_Utils_Type
::T_INT
,
191 'frequency_unit' => [
192 'title' => ts('Frequency Unit'),
193 'operatorType' => CRM_Report_Form
::OP_MULTISELECT
,
194 'options' => CRM_Core_OptionGroup
::values('recur_frequency_units'),
195 'type' => CRM_Utils_Type
::T_STRING
,
197 'frequency_interval' => [
198 'title' => ts('Frequency Interval'),
199 'type' => CRM_Utils_Type
::T_INT
,
202 'title' => ts('Installment Amount'),
203 'type' => CRM_Utils_Type
::T_MONEY
,
206 'title' => ts('Installments'),
207 'type' => CRM_Utils_Type
::T_INT
,
210 'title' => ts('Start Date'),
211 'operatorType' => CRM_Report_Form
::OP_DATE
,
212 'type' => CRM_Utils_Type
::T_DATE + CRM_Utils_Type
::T_TIME
,
214 'next_sched_contribution_date' => [
215 'title' => ts('Next Scheduled Contribution Date'),
216 'operatorType' => CRM_Report_Form
::OP_DATE
,
217 'type' => CRM_Utils_Type
::T_DATE + CRM_Utils_Type
::T_TIME
,
220 'title' => ts('End Date'),
221 'operatorType' => CRM_Report_Form
::OP_DATE
,
222 'type' => CRM_Utils_Type
::T_DATE + CRM_Utils_Type
::T_TIME
,
225 'title' => ts('Last Contribution Processed'),
226 'operatorType' => CRM_Report_Form
::OP_DATE
,
227 'type' => CRM_Utils_Type
::T_DATE + CRM_Utils_Type
::T_TIME
,
229 'calculated_end_date' => [
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
,
233 'pseudofield' => TRUE,
235 'payment_processor_id' => [
236 'title' => ts('Payment Processor'),
237 'operatorType' => CRM_Report_Form
::OP_MULTISELECT
,
238 'options' => CRM_Contribute_BAO_ContributionRecur
::buildOptions('payment_processor_id', 'get'),
240 'type' => CRM_Utils_Type
::T_INT
,
245 $this->_currencyColumn
= 'civicrm_contribution_recur_currency';
246 $this->_groupFilter
= TRUE;
247 parent
::__construct();
251 * Get template file name.
255 public function getTemplateName() {
256 return 'CRM/Report/Form.tpl';
260 * Generate FROM SQL clause.
262 public function 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";
268 LEFT JOIN civicrm_contribution {$this->_aliases['civicrm_contribution']}
269 ON {$this->_aliases['civicrm_contribution_recur']}.id = {$this->_aliases['civicrm_contribution']}.contribution_recur_id";
271 $this->joinPhoneFromContact();
272 $this->joinEmailFromContact();
274 // for credit card type
275 $this->addFinancialTrxnFromClause();
278 public function groupBy() {
279 $this->_groupBy
= CRM_Contact_BAO_Query
::getGroupByFromSelectColumns($this->_selectClauses
, "{$this->_aliases['civicrm_contribution_recur']}.id");
282 public function 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)
289 $date_suffixes = ['relative', 'from', 'to'];
290 foreach ($date_suffixes as $suffix) {
292 // Check to see if the user wants to search by calculated date.
293 if (!empty($this->_params
['calculated_end_date_' . $suffix])) {
294 // The calculated date field is in use - spring into action
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;
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'];
307 // The end date clause is simple to construct
308 $end_date_clause = $this->dateClause($end_date_db_alias, $relative, $from, $to, $end_date_type, NULL, NULL);
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.
315 $this->_where
.= 'AND (' .
316 $this->dateClause("DATE_ADD($start_date_db_alias, INTERVAL $installments_db_alias * COALESCE($frequency_interval_db_alias,1) month)",
317 $relative, $from, $to, $start_date_type, NULL, NULL);
318 $this->_where
.= " AND $frequency_unit_db_alias = 'month' ) OR \n";
320 $this->_where
.= '(' .
321 $this->dateClause("DATE_ADD($start_date_db_alias, INTERVAL $installments_db_alias * COALESCE($frequency_interval_db_alias,1) day)",
322 $relative, $from, $to, $start_date_type, NULL, NULL);
323 $this->_where
.= " AND $frequency_unit_db_alias = 'day' ) OR \n";
325 $this->_where
.= '(' .
326 $this->dateClause("DATE_ADD($start_date_db_alias, INTERVAL $installments_db_alias * COALESCE($frequency_interval_db_alias, 1) week)",
327 $relative, $from, $to, $start_date_type, NULL, NULL);
328 $this->_where
.= " AND $frequency_unit_db_alias = 'week' ) OR \n";
330 $this->_where
.= '(' .
331 $this->dateClause("DATE_ADD($start_date_db_alias, INTERVAL $installments_db_alias * COALESCE($frequency_interval_db_alias, 1) year)",
332 $relative, $from, $to, $start_date_type, NULL, NULL);
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))
339 if (!empty($this->_params
['modified_date_' . $suffix])) {
340 $this->_where
.= " AND {$this->_aliases['civicrm_contribution_recur']}.contribution_status_id = 1";
343 if (!empty($isBreak)) {
350 * Alter display of rows.
352 * Iterate through the rows retrieved via SQL and make changes for display purposes,
353 * such as rendering contacts as links.
356 * Rows generated by SQL, with an array for each row.
358 public function alterDisplay(&$rows) {
359 $contributionStatus = CRM_Contribute_PseudoConstant
::contributionStatus(NULL, 'label');
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)
366 $url = CRM_Utils_System
::url('civicrm/contact/view',
367 'reset=1&cid=' . $row['civicrm_contact_id'],
370 $rows[$rowNum]['civicrm_contact_sort_name_link'] = $url;
371 $rows[$rowNum]['civicrm_contact_sort_name_hover'] = ts('View Contact Summary for this Contact.');
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];
379 if ($value = CRM_Utils_Array
::value('civicrm_contribution_recur_amount', $row)) {
380 $rows[$rowNum]['civicrm_contribution_recur_amount'] = CRM_Utils_Money
::format($rows[$rowNum]['civicrm_contribution_recur_amount'], $rows[$rowNum]['civicrm_contribution_recur_currency']);
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');
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');