Merge pull request #17782 from civicrm/5.28
[civicrm-core.git] / CRM / Report / Form / Contribute / HouseholdSummary.php
CommitLineData
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 */
17class CRM_Report_Form_Contribute_HouseholdSummary extends CRM_Report_Form {
18
be2fb01f 19 public $_drilldownReport = ['contribute/detail' => 'Link to Detail Report'];
6a488035 20
eb3b4c04 21 protected $_summary = NULL;
2f4c2f5d 22
74cf4551 23 /**
d7e34fc6 24 * Class constructor.
74cf4551 25 */
00be9182 26 public function __construct() {
6a488035
TO
27 self::validRelationships();
28
be2fb01f
CW
29 $this->_columns = [
30 'civicrm_contact_household' => [
6a488035 31 'dao' => 'CRM_Contact_DAO_Contact',
be2fb01f
CW
32 'fields' => [
33 'household_name' => [
9d72cede
EM
34 'title' => ts('Household Name'),
35 'required' => TRUE,
be2fb01f
CW
36 ],
37 'id' => [
6a488035
TO
38 'no_display' => TRUE,
39 'required' => TRUE,
be2fb01f
CW
40 ],
41 'contact_type' => [
30f85891 42 'title' => ts('Contact Type'),
be2fb01f
CW
43 ],
44 'contact_sub_type' => [
b8f96eb8 45 'title' => ts('Contact Subtype'),
be2fb01f
CW
46 ],
47 ],
48 'filters' => [
49 'household_name' => [
d7e34fc6 50 'title' => ts('Household Name'),
be2fb01f
CW
51 ],
52 'is_deleted' => [
d7e34fc6 53 'default' => 0,
54 'type' => CRM_Utils_Type::T_BOOLEAN,
be2fb01f
CW
55 ],
56 ],
6a488035 57 'grouping' => 'household-fields',
be2fb01f
CW
58 ],
59 'civicrm_line_item' => [
08dd3452 60 'dao' => 'CRM_Price_DAO_LineItem',
be2fb01f
CW
61 ],
62 'civicrm_relationship' => [
6a488035 63 'dao' => 'CRM_Contact_DAO_Relationship',
be2fb01f
CW
64 'fields' => [
65 'relationship_type_id' => [
a92f4449 66 'title' => ts('Relationship Type'),
be2fb01f
CW
67 ],
68 ],
69 'filters' => [
70 'relationship_type_id' => [
6a488035
TO
71 'title' => ts('Relationship Type'),
72 'type' => CRM_Utils_Type::T_INT,
73 'operatorType' => CRM_Report_Form::OP_SELECT,
74 'options' => $this->relationTypes,
75f23035 75 'default' => key($this->relationTypes),
be2fb01f
CW
76 ],
77 ],
6a488035 78 'grouping' => 'household-fields',
be2fb01f
CW
79 ],
80 'civicrm_contact' => [
6a488035 81 'dao' => 'CRM_Contact_DAO_Contact',
be2fb01f
CW
82 'fields' => [
83 'sort_name' => [
a92f4449 84 'title' => ts('Contact Name'),
6a488035 85 'required' => TRUE,
be2fb01f
CW
86 ],
87 'id' => [
6a488035
TO
88 'no_display' => TRUE,
89 'required' => TRUE,
be2fb01f
CW
90 ],
91 ],
6a488035 92 'grouping' => 'contact-fields',
be2fb01f
CW
93 ],
94 'civicrm_contribution' => [
6a488035 95 'dao' => 'CRM_Contribute_DAO_Contribution',
be2fb01f
CW
96 'fields' => [
97 'total_amount' => [
a92f4449 98 'title' => ts('Amount'),
6a488035 99 'required' => TRUE,
be2fb01f
CW
100 ],
101 'id' => [
6a488035
TO
102 'no_display' => TRUE,
103 'required' => TRUE,
be2fb01f
CW
104 ],
105 'contribution_status_id' => [
fd6a6828 106 'title' => ts('Contribution Status'),
6a488035 107 'default' => TRUE,
be2fb01f
CW
108 ],
109 'check_number' => [
a92f4449 110 'title' => ts('Check Number'),
be2fb01f
CW
111 ],
112 'currency' => [
eb3b4c04 113 'required' => TRUE,
114 'no_display' => TRUE,
be2fb01f
CW
115 ],
116 'financial_type_id' => [
2feca82f 117 'title' => ts('Financial Type'),
be2fb01f 118 ],
6a488035 119 'trxn_id' => NULL,
be2fb01f 120 'receive_date' => ['default' => TRUE],
6a488035 121 'receipt_date' => NULL,
be2fb01f
CW
122 ],
123 'filters' => [
124 'receive_date' => ['operatorType' => CRM_Report_Form::OP_DATE],
f85b4a88 125 'receipt_date' => ['operatorType' => CRM_Report_Form::OP_DATE],
be2fb01f
CW
126 'total_amount' => ['title' => ts('Amount Between')],
127 'currency' => [
fd6a6828 128 'title' => ts('Currency'),
eb3b4c04 129 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
130 'options' => CRM_Core_OptionGroup::values('currencies_enabled'),
d1b0931b 131 'default' => NULL,
eb3b4c04 132 'type' => CRM_Utils_Type::T_STRING,
be2fb01f
CW
133 ],
134 'contribution_status_id' => [
a92f4449 135 'title' => ts('Contribution Status'),
6a488035 136 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
c0aaecf9 137 'options' => CRM_Contribute_BAO_Contribution::buildOptions('contribution_status_id', 'search'),
be2fb01f
CW
138 'default' => [1],
139 ],
140 'financial_type_id' => [
2feca82f
AS
141 'title' => ts('Financial Type'),
142 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
143 'options' => CRM_Contribute_PseudoConstant::financialType(),
be2fb01f
CW
144 ],
145 ],
6a488035 146 'grouping' => 'contri-fields',
be2fb01f
CW
147 ],
148 'civicrm_financial_trxn' => [
4d5f6da9 149 'dao' => 'CRM_Financial_DAO_FinancialTrxn',
be2fb01f
CW
150 'fields' => [
151 'card_type_id' => [
d72b084a 152 'title' => ts('Credit Card Type'),
5e0343e8 153 'dbAlias' => 'GROUP_CONCAT(financial_trxn_civireport.card_type_id SEPARATOR ",")',
be2fb01f
CW
154 ],
155 ],
156 'filters' => [
157 'card_type_id' => [
d72b084a 158 'title' => ts('Credit Card Type'),
4d5f6da9 159 'operatorType' => CRM_Report_Form::OP_MULTISELECT,
5e0343e8 160 'options' => CRM_Financial_DAO_FinancialTrxn::buildOptions('card_type_id'),
4d5f6da9
E
161 'default' => NULL,
162 'type' => CRM_Utils_Type::T_STRING,
be2fb01f
CW
163 ],
164 ],
165 ],
166 'civicrm_address' => [
6a488035 167 'dao' => 'CRM_Core_DAO_Address',
be2fb01f 168 'fields' => [
6a488035
TO
169 'street_address' => NULL,
170 'city' => NULL,
171 'postal_code' => NULL,
be2fb01f 172 'state_province_id' => [
a92f4449 173 'title' => ts('State/Province'),
be2fb01f
CW
174 ],
175 'country_id' => [
a92f4449 176 'title' => ts('Country'),
be2fb01f
CW
177 ],
178 ],
6a488035 179 'grouping' => 'contact-fields',
be2fb01f
CW
180 ],
181 'civicrm_email' => [
6a488035 182 'dao' => 'CRM_Core_DAO_Email',
be2fb01f 183 'fields' => [
21dfd5f5 184 'email' => NULL,
be2fb01f 185 ],
6a488035 186 'grouping' => 'contact-fields',
be2fb01f
CW
187 ],
188 ];
6a488035 189
51538a51 190 // If we have a campaign, build out the relevant elements
191 $this->addCampaignFields('civicrm_contribution');
192
eb3b4c04 193 $this->_currencyColumn = 'civicrm_contribution_currency';
6a488035
TO
194 parent::__construct();
195 }
196
00be9182 197 public function select() {
3b2bbbfb 198 // @todo remove this & use parent select.
be2fb01f 199 $this->_columnHeaders = $select = [];
6a488035
TO
200 foreach ($this->_columns as $tableName => $table) {
201 if (array_key_exists('fields', $table)) {
202 foreach ($table['fields'] as $fieldName => $field) {
9d72cede
EM
203 if (!empty($field['required']) ||
204 !empty($this->_params['fields'][$fieldName])
205 ) {
6a488035 206
a7488080 207 if (!empty($field['statistics'])) {
6a488035
TO
208 foreach ($field['statistics'] as $stat => $label) {
209 $select[] = "{$field['dbAlias']} as {$tableName}_{$fieldName}_{$stat}";
210 $this->_columnHeaders["{$tableName}_{$fieldName}_{$stat}"]['title'] = $label;
211 $this->_columnHeaders["{$tableName}_{$fieldName}_{$stat}"]['type'] = $field['type'];
212 $this->_statFields[] = "{$tableName}_{$fieldName}_{$stat}";
213 }
214 }
215 else {
22a17535 216 $select[] = "{$field['dbAlias']} as {$tableName}_{$fieldName}";
6a488035 217
9c1bc317
CW
218 $this->_columnHeaders["{$tableName}_{$fieldName}"]['title'] = $field['title'] ?? NULL;
219 $this->_columnHeaders["{$tableName}_{$fieldName}"]['type'] = $field['type'] ?? NULL;
6a488035
TO
220 }
221 }
222 }
223 }
224 }
d1641c51 225 $this->_selectClauses = $select;
6a488035
TO
226 $this->_select = "SELECT " . implode(', ', $select) . " ";
227 }
228
00be9182 229 public function from() {
6a488035 230 $this->_from = "
39eb89f4
DL
231 FROM civicrm_relationship {$this->_aliases['civicrm_relationship']}
232 LEFT JOIN civicrm_contact {$this->_aliases['civicrm_contact_household']} ON
6a488035 233 ({$this->_aliases['civicrm_contact_household']}.id = {$this->_aliases['civicrm_relationship']}.$this->householdContact AND {$this->_aliases['civicrm_contact_household']}.contact_type='Household')
39eb89f4
DL
234 LEFT JOIN civicrm_contact {$this->_aliases['civicrm_contact']} ON
235 ({$this->_aliases['civicrm_contact']}.id = {$this->_aliases['civicrm_relationship']}.$this->otherContact )
6a488035
TO
236 {$this->_aclFrom}
237 INNER JOIN civicrm_contribution {$this->_aliases['civicrm_contribution']} ON
e280410d 238 ({$this->_aliases['civicrm_contribution']}.contact_id = {$this->_aliases['civicrm_relationship']}.$this->otherContact ) AND {$this->_aliases['civicrm_contribution']}.is_test = 0 ";
6a488035 239
3b2bbbfb 240 $this->joinAddressFromContact();
241 $this->joinEmailFromContact();
4d5f6da9
E
242
243 // for credit card type
244 $this->addFinancialTrxnFromClause();
6a488035 245 }
40c655aa 246
00be9182 247 public function where() {
be2fb01f 248 $clauses = [];
6a488035
TO
249 foreach ($this->_columns as $tableName => $table) {
250 if (array_key_exists('filters', $table)) {
251 foreach ($table['filters'] as $fieldName => $field) {
252 $clause = NULL;
253 if (CRM_Utils_Array::value('type', $field) & CRM_Utils_Type::T_DATE) {
9c1bc317
CW
254 $relative = $this->_params["{$fieldName}_relative"] ?? NULL;
255 $from = $this->_params["{$fieldName}_from"] ?? NULL;
256 $to = $this->_params["{$fieldName}_to"] ?? NULL;
6a488035
TO
257 $clause = $this->dateClause($field['name'], $relative, $from, $to, $field['type']);
258 }
259 else {
9c1bc317 260 $op = $this->_params["{$fieldName}_op"] ?? NULL;
6a488035
TO
261 if ($op) {
262 if ($fieldName == 'relationship_type_id') {
389bcebf 263 $clause = "{$this->_aliases['civicrm_relationship']}.relationship_type_id=" . $this->relationshipId;
6a488035
TO
264 }
265 else {
266 $clause = $this->whereClause($field,
267 $op,
268 CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
269 CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
270 CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
271 );
272 }
273 }
274 }
275
276 if (!empty($clause)) {
277 $clauses[] = $clause;
278 }
279 }
280 }
281 }
282
283 if (empty($clauses)) {
284 $this->_where = "WHERE ( 1 )";
285 }
286 else {
287 $this->_where = "WHERE " . implode(' AND ', $clauses);
288 }
289
290 if ($this->_aclWhere) {
291 $this->_where .= " AND {$this->_aclWhere} ";
292 }
293 }
294
00be9182 295 public function groupBy() {
be2fb01f 296 $groupBy = [
d1641c51 297 "{$this->_aliases['civicrm_relationship']}.$this->householdContact",
298 "{$this->_aliases['civicrm_relationship']}.$this->otherContact",
299 "{$this->_aliases['civicrm_contribution']}.id",
300 "{$this->_aliases['civicrm_relationship']}.relationship_type_id",
be2fb01f 301 ];
b708c08d 302 $this->_groupBy = CRM_Contact_BAO_Query::getGroupByFromSelectColumns($this->_selectClauses, $groupBy);
6a488035
TO
303 }
304
00be9182 305 public function orderBy() {
6a488035
TO
306 $this->_orderBy = " ORDER BY {$this->_aliases['civicrm_contact_household']}.household_name, {$this->_aliases['civicrm_relationship']}.$this->householdContact, {$this->_aliases['civicrm_contact']}.sort_name, {$this->_aliases['civicrm_relationship']}.$this->otherContact";
307 }
308
74cf4551
EM
309 /**
310 * @param $rows
311 *
312 * @return array
313 */
00be9182 314 public function statistics(&$rows) {
6a488035
TO
315 $statistics = parent::statistics($rows);
316
317 //hack filter display for relationship type
318 $type = substr($this->_params['relationship_type_id_value'], -3);
319 foreach ($statistics['filters'] as $id => $value) {
39eb89f4
DL
320 if (
321 $value['title'] == 'Relationship Type' &&
322 isset($this->relationTypes[$this->relationshipId . '_' . $type])
323 ) {
a92f4449
EM
324 $statistics['filters'][$id]['value'] = 'Is equal to ' .
325 $this->relationTypes[$this->relationshipId . '_' . $type];
6a488035
TO
326 }
327 }
328 return $statistics;
329 }
330
00be9182 331 public function postProcess() {
6a488035
TO
332
333 $this->beginPostProcess();
be2fb01f 334 $this->buildACLClause([
353ffa53
TO
335 $this->_aliases['civicrm_contact'],
336 $this->_aliases['civicrm_contact_household'],
be2fb01f 337 ]);
75f23035 338 $sql = $this->buildQuery(TRUE);
be2fb01f 339 $rows = [];
75f23035
EM
340
341 $this->buildRows($sql, $rows);
342 $this->formatDisplay($rows);
343 $this->doTemplateAssignment($rows);
344 $this->endPostProcess($rows);
345 }
346
347 /**
fe482240 348 * Set variables to be accessed by API and form layer in processing.
75f23035 349 */
00be9182 350 public function beginPostProcessCommon() {
6a488035
TO
351 $getRelationship = $this->_params['relationship_type_id_value'];
352 $type = substr($getRelationship, -3);
353 $this->relationshipId = intval((substr($getRelationship, 0, strpos($getRelationship, '_'))));
354 if ($type == 'b_a') {
355 $this->householdContact = 'contact_id_b';
356 $this->otherContact = 'contact_id_a';
357 }
358 else {
359 $this->householdContact = 'contact_id_a';
360 $this->otherContact = 'contact_id_b';
361 }
6a488035
TO
362 }
363
00be9182 364 public function validRelationships() {
be2fb01f 365 $this->relationTypes = $relationTypes = [];
6a488035 366
be2fb01f 367 $params = ['contact_type_b' => 'Household', 'version' => 3];
39eb89f4 368 $typesA = civicrm_api('relationship_type', 'get', $params);
a7488080 369 if (empty($typesA['is_error'])) {
6a488035
TO
370 foreach ($typesA['values'] as $rel) {
371 $relationTypes[$rel['id']][$rel['id'] . '_b_a'] = $rel['label_b_a'];
372 }
373 }
be2fb01f 374 $params = ['contact_type_a' => 'Household', 'version' => 3];
39eb89f4 375 $typesB = civicrm_api('relationship_type', 'get', $params);
a7488080 376 if (empty($typesB['is_error'])) {
6a488035
TO
377 foreach ($typesB['values'] as $rel) {
378 $relationTypes[$rel['id']][$rel['id'] . '_a_b'] = $rel['label_a_b'];
379 //$this->relationTypes[$rel['id'].'_a_b'] = $rel['label_a_b'];
380 }
381 }
382
383 ksort($relationTypes);
384 foreach ($relationTypes as $relationship) {
385 foreach ($relationship as $index => $label) {
386 $this->relationTypes[$index] = $label;
387 }
388 }
389 }
390
74cf4551 391 /**
ced9bfed
EM
392 * Alter display of rows.
393 *
394 * Iterate through the rows retrieved via SQL and make changes for display purposes,
395 * such as rendering contacts as links.
396 *
397 * @param array $rows
398 * Rows generated by SQL, with an array for each row.
74cf4551 399 */
00be9182 400 public function alterDisplay(&$rows) {
6a488035
TO
401 $type = substr($this->_params['relationship_type_id_value'], -3);
402
403 $entryFound = FALSE;
404 $flagHousehold = $flagContact = 0;
6a488035
TO
405 foreach ($rows as $rowNum => $row) {
406
407 //replace retionship id by relationship name
408 if (array_key_exists('civicrm_relationship_relationship_type_id', $row)) {
409 if ($value = $row['civicrm_relationship_relationship_type_id']) {
84178120 410 $rows[$rowNum]['civicrm_relationship_relationship_type_id'] = $this->relationTypes[$value . '_' . $type];
6a488035
TO
411 $entryFound = TRUE;
412 }
413 }
414
415 //remove duplicate Organization names
9d72cede
EM
416 if (array_key_exists('civicrm_contact_household_household_name', $row) &&
417 $this->_outputMode != 'csv'
418 ) {
6a488035
TO
419 if ($value = $row['civicrm_contact_household_household_name']) {
420 if ($rowNum == 0) {
421 $priviousHousehold = $value;
422 }
423 else {
424 if ($priviousHousehold == $value) {
425 $flagHousehold = 1;
426 $priviousHousehold = $value;
427 }
428 else {
429 $flagHousehold = 0;
430 $priviousHousehold = $value;
431 }
432 }
433
434 if ($flagHousehold == 1) {
435 $rows[$rowNum]['civicrm_contact_household_household_name'] = "";
436 }
437 else {
438 $url = CRM_Utils_System::url('civicrm/contact/view',
439 'reset=1&cid=' . $rows[$rowNum]['civicrm_contact_household_id'],
440 $this->_absoluteUrl
441 );
442
389bcebf 443 $rows[$rowNum]['civicrm_contact_household_household_name'] = "<a href='$url' title='" . ts('View contact summary for this househould') . "'>" . $value . '</a>';
6a488035
TO
444 }
445 $entryFound = TRUE;
446 }
447 }
448
449 //remove duplicate Contact names and relationship type
9d72cede
EM
450 if (array_key_exists('civicrm_contact_id', $row) &&
451 $this->_outputMode != 'csv'
452 ) {
6a488035
TO
453 if ($value = $row['civicrm_contact_id']) {
454 if ($rowNum == 0) {
455 $priviousContact = $value;
456 }
457 else {
458 if ($priviousContact == $value) {
459 $flagContact = 1;
460 $priviousContact = $value;
461 }
462 else {
463 $flagContact = 0;
464 $priviousContact = $value;
465 }
466 }
467
468 if ($flagContact == 1 && $flagHousehold == 1) {
469 $rows[$rowNum]['civicrm_contact_sort_name'] = "";
470 $rows[$rowNum]['civicrm_relationship_relationship_type_id'] = "";
471 }
472
473 $entryFound = TRUE;
474 }
475 }
476
477 if (array_key_exists('civicrm_contribution_contribution_status_id', $row)) {
478 if ($value = $row['civicrm_contribution_contribution_status_id']) {
28ee38ed 479 $rows[$rowNum]['civicrm_contribution_contribution_status_id'] = CRM_Contribute_PseudoConstant::contributionStatus($value, 'label');
6a488035
TO
480 }
481 }
482
2feca82f
AS
483 if (array_key_exists('civicrm_contribution_financial_type_id', $row)) {
484 if ($value = $row['civicrm_contribution_financial_type_id']) {
485 $rows[$rowNum]['civicrm_contribution_financial_type_id'] = CRM_Contribute_PseudoConstant::financialType($value);
486 }
487 }
488
6a488035
TO
489 // convert display name to links
490 if (array_key_exists('civicrm_contact_sort_name', $row) &&
491 $rows[$rowNum]['civicrm_contact_sort_name'] &&
492 array_key_exists('civicrm_contact_id', $row)
493 ) {
494 $url = CRM_Report_Utils_Report::getNextUrl('contribute/detail',
495 'reset=1&force=1&id_op=eq&id_value=' . $row['civicrm_contact_id'],
496 $this->_absoluteUrl, $this->_id, $this->_drilldownReport
497 );
498 $rows[$rowNum]['civicrm_contact_sort_name_link'] = $url;
499 $rows[$rowNum]['civicrm_contact_sort_name_hover'] = ts('View contribution details for this individual');
500
501 $entryFound = TRUE;
502 }
503
a7488080 504 if (!empty($row['civicrm_contribution_total_amount'])) {
eb3b4c04 505 $row['civicrm_contribution_total_amount'] = CRM_Utils_Money::format($row['civicrm_contribution_total_amount'], $row['civicrm_contribution_currency']);
506 }
507
5e0343e8 508 if (!empty($row['civicrm_financial_trxn_card_type_id'])) {
509 $rows[$rowNum]['civicrm_financial_trxn_card_type_id'] = $this->getLabels($row['civicrm_financial_trxn_card_type_id'], 'CRM_Financial_DAO_FinancialTrxn', 'card_type_id');
4d5f6da9
E
510 $entryFound = TRUE;
511 }
512
6a488035
TO
513 // Contribution amount links to view contribution
514 if (($value = CRM_Utils_Array::value('civicrm_contribution_total_amount', $row)) &&
515 CRM_Core_Permission::check('access CiviContribute')
516 ) {
517 $url = CRM_Utils_System::url("civicrm/contact/view/contribution",
9d72cede
EM
518 "reset=1&id=" . $row['civicrm_contribution_id'] . "&cid=" .
519 $row['civicrm_contact_id'] .
a92f4449 520 "&action=view&context=contribution&selectedChild=contribute",
6a488035
TO
521 $this->_absoluteUrl
522 );
523 $rows[$rowNum]['civicrm_contribution_total_amount_link'] = $url;
524 $rows[$rowNum]['civicrm_contribution_total_amount_hover'] = ts("View this contribution.");
525 $entryFound = TRUE;
526 }
527
528 // convert campaign_id to campaign title
529 if (array_key_exists('civicrm_contribution_campaign_id', $row)) {
530 if ($value = $row['civicrm_contribution_campaign_id']) {
51538a51 531 $rows[$rowNum]['civicrm_contribution_campaign_id'] = $this->campaigns[$value];
6a488035
TO
532 $entryFound = TRUE;
533 }
534 }
535
5e587dd3 536 $entryFound = $this->alterDisplayAddressFields($row, $rows, $rowNum, NULL, NULL) ? TRUE : $entryFound;
537
6a488035
TO
538 // skip looking further in rows, if first row itself doesn't
539 if (!$entryFound) {
540 break;
541 }
542 $lastKey = $rowNum;
543 }
544 }
96025800 545
6a488035 546}