diff --git a/CRM/Report/Form.php b/CRM/Report/Form.php index f4ba42cae783..c07f760b503d 100644 --- a/CRM/Report/Form.php +++ b/CRM/Report/Form.php @@ -2114,32 +2114,34 @@ public function whereClause(&$field, $op, $value, $min, $max) { */ public function whereSubtypeClause($field, $value, $op) { // Get the correct SQL operator. + $orNull = FALSE; switch ($op) { case 'notin': $op = 'nhas'; - $clauseSeparator = 'AND'; + $clauseSeparator = ' AND '; + $orNull = TRUE; break; case 'in': $op = 'has'; - $clauseSeparator = 'OR'; + $clauseSeparator = ' OR '; break; } $sqlOp = $this->getSQLOperator($op); - $clause = '( '; - $subtypeFilters = count($value); if ($sqlOp == 'IS NULL' || $sqlOp == 'IS NOT NULL') { - $clause .= "{$field['dbAlias']} $sqlOp"; + $clause = "{$field['dbAlias']} $sqlOp"; } else { - for ($i = 0; $i < $subtypeFilters; $i++) { - $clause .= "{$field['dbAlias']} $sqlOp '%$value[$i]%'"; - if ($i !== ($subtypeFilters - 1)) { - $clause .= " $clauseSeparator "; - } + $subclauses = []; + foreach ($value as $item) { + $subclauses[] = "( {$field['dbAlias']} $sqlOp '%" . CRM_Core_DAO::VALUE_SEPARATOR . $item . CRM_Core_DAO::VALUE_SEPARATOR . "%' )"; } + $clause = implode($clauseSeparator, $subclauses); + } + $clause = "( $clause )"; + if ($orNull) { + $clause = "( ( {$field['dbAlias']} IS NULL ) OR $clause )"; } - $clause .= ' )'; return $clause; } diff --git a/tests/phpunit/api/v3/ReportTemplateTest.php b/tests/phpunit/api/v3/ReportTemplateTest.php index dbc0b6318675..872d6cc58869 100644 --- a/tests/phpunit/api/v3/ReportTemplateTest.php +++ b/tests/phpunit/api/v3/ReportTemplateTest.php @@ -1145,6 +1145,44 @@ public function testContactSubtypeNull() { $this->assertEquals(1, $rows['count']); } + /** + * Test contact subtype filter on summary report. + * + * @throws \CRM_Core_Exception + */ + public function testContactSubtypeIn() { + $this->individualCreate(['contact_sub_type' => ['Student', 'Parent']]); + $this->individualCreate(); + + $rows = $this->callAPISuccess('report_template', 'getrows', [ + 'report_id' => 'contact/summary', + 'contact_sub_type_op' => 'in', + 'contact_sub_type_value' => ['Student'], + 'contact_type_op' => 'in', + 'contact_type_value' => 'Individual', + ]); + $this->assertEquals(1, $rows['count']); + } + + /** + * Test contact subtype filter on summary report. + * + * @throws \CRM_Core_Exception + */ + public function testContactSubtypeNotIn() { + $this->individualCreate(['contact_sub_type' => ['Student', 'Parent']]); + $this->individualCreate(); + + $rows = $this->callAPISuccess('report_template', 'getrows', [ + 'report_id' => 'contact/summary', + 'contact_sub_type_op' => 'notin', + 'contact_sub_type_value' => ['Student'], + 'contact_type_op' => 'in', + 'contact_type_value' => 'Individual', + ]); + $this->assertEquals(1, $rows['count']); + } + /** * Test PCP report to ensure total donors and total committed is accurate. */