Commit 20a46408 authored by Kevin Cristiano's avatar Kevin Cristiano 🌎
Browse files

Create Bookkeping Report to handle issues with Multiple Memberships being...

Create Bookkeping Report to handle issues with Multiple Memberships being recorded on the same Form.   This is leading to duplication of records on standard reports
parent 6c8752fa
<?php
// This file declares a managed database record of type "ReportTemplate".
// The record will be automatically inserted, updated, or deleted from the
// database as appropriate. For more details, see "hook_civicrm_managed" at:
// http://wiki.civicrm.org/confluence/display/CRMDOC42/Hook+Reference
return array (
0 =>
array (
'name' => 'CRM_Additionalreports_Form_Report_BookkeepingMembership',
'entity' => 'ReportTemplate',
'params' =>
array (
'version' => 3,
'label' => 'BookkeepingMembership',
'description' => 'BookkeepingMembership (cc.tadpole.additionalreports)',
'class_name' => 'CRM_Additionalreports_Form_Report_BookkeepingMembership',
'report_url' => 'cc.tadpole.additionalreports/bookkeepingmembership',
'component' => 'CiviContribute',
),
),
);
<?php
/*
+--------------------------------------------------------------------+
| CiviCRM version 4.7 |
+--------------------------------------------------------------------+
| Copyright CiviCRM LLC (c) 2004-2017 |
+--------------------------------------------------------------------+
| This file is a part of CiviCRM. |
| |
| CiviCRM is free software; you can copy, modify, and distribute it |
| under the terms of the GNU Affero General Public License |
| Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
| |
| CiviCRM is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU Affero General Public License for more details. |
| |
| You should have received a copy of the GNU Affero General Public |
| License and the CiviCRM Licensing Exception along |
| with this program; if not, contact CiviCRM LLC |
| at info[AT]civicrm[DOT]org. If you have questions about the |
| GNU Affero General Public License or the licensing of CiviCRM, |
| see the CiviCRM license FAQ at http://civicrm.org/licensing |
+--------------------------------------------------------------------+
*/
/**
*
* @package CRM
* @copyright CiviCRM LLC (c) 2004-2017
*/
class CRM_Additionalreports_Form_Report_BookkeepingMembership extends CRM_Report_Form {
protected $_addressField = FALSE;
protected $_emailField = FALSE;
protected $_summary = NULL;
protected $_customGroupExtends = array(
'Contact',
'Individual',
'Contribution',
'Membership',
);
/**
* This report has not been optimised for group filtering.
*
* The functionality for group filtering has been improved but not
* all reports have been adjusted to take care of it. This report has not
* and will run an inefficient query until fixed.
*
* CRM-19170
*
* @var bool
*/
protected $groupFilterNotOptimised = TRUE;
/**
* Class constructor.
*/
public function __construct() {
$this->_autoIncludeIndexedFieldsAsOrderBys = 1;
$this->_columns = array(
'civicrm_contact' => array(
'dao' => 'CRM_Contact_DAO_Contact',
'fields' => array(
'sort_name' => array(
'title' => ts('Contact Name'),
'required' => TRUE,
'no_repeat' => TRUE,
),
'first_name' => array(
'title' => ts('First Name'),
),
'middle_name' => array(
'title' => ts('Middle Name'),
),
'last_name' => array(
'title' => ts('Last Name'),
),
'id' => array(
'no_display' => TRUE,
'required' => TRUE,
),
'gender_id' => array(
'title' => ts('Gender'),
),
'birth_date' => array(
'title' => ts('Birth Date'),
),
'age' => array(
'title' => ts('Age'),
'dbAlias' => 'TIMESTAMPDIFF(YEAR, contact_civireport.birth_date, CURDATE())',
),
'contact_type' => array(
'title' => ts('Contact Type'),
),
'contact_sub_type' => array(
'title' => ts('Contact Subtype'),
),
),
'grouping' => 'contact-fields',
'order_bys' => array(
'sort_name' => array(
'title' => ts('Last Name, First Name'),
'default' => '1',
'default_weight' => '0',
'default_order' => 'ASC',
),
'first_name' => array(
'name' => 'first_name',
'title' => ts('First Name'),
),
'gender_id' => array(
'name' => 'gender_id',
'title' => ts('Gender'),
),
'birth_date' => array(
'name' => 'birth_date',
'title' => ts('Birth Date'),
),
'contact_type' => array(
'title' => ts('Contact Type'),
),
'contact_sub_type' => array(
'title' => ts('Contact Subtype'),
),
),
'filters' => array(
'sort_name' => array(
'title' => ts('Contact Name'),
'operator' => 'like',
),
'id' => array(
'title' => ts('Contact ID'),
'no_display' => TRUE,
),
'gender_id' => array(
'title' => ts('Gender'),
'operatorType' => CRM_Report_Form::OP_MULTISELECT,
'options' => CRM_Core_PseudoConstant::get('CRM_Contact_DAO_Contact', 'gender_id'),
),
'birth_date' => array(
'title' => ts('Birth Date'),
'operatorType' => CRM_Report_Form::OP_DATE,
),
'contact_type' => array(
'title' => ts('Contact Type'),
),
'contact_sub_type' => array(
'title' => ts('Contact Subtype'),
),
),
),
'civicrm_membership' => array(
'dao' => 'CRM_Member_DAO_Membership',
'fields' => array(
'id' => array(
'title' => ts('Membership #'),
'no_display' => TRUE,
'required' => TRUE,
),
),
),
'civicrm_financial_account' => array(
'dao' => 'CRM_Financial_DAO_FinancialAccount',
'fields' => array(
'debit_accounting_code' => array(
'title' => ts('Financial Account Code - Debit'),
'name' => 'accounting_code',
'alias' => 'financial_account_civireport_debit',
'default' => TRUE,
),
'credit_accounting_code' => array(
'title' => ts('Financial Account Code - Credit'),
'name' => 'accounting_code',
'alias' => 'financial_account_civireport_credit',
'default' => TRUE,
),
'debit_name' => array(
'title' => ts('Financial Account Name - Debit'),
'name' => 'name',
'alias' => 'financial_account_civireport_debit',
'default' => TRUE,
),
'credit_name' => array(
'title' => ts('Financial Account Name - Credit'),
'name' => 'name',
'alias' => 'financial_account_civireport_credit',
'default' => TRUE,
),
),
'filters' => array(
'debit_accounting_code' => array(
'title' => ts('Financial Account Code - Debit'),
'operatorType' => CRM_Report_Form::OP_MULTISELECT,
'options' => CRM_Contribute_PseudoConstant::financialAccount(NULL, NULL, 'accounting_code', 'accounting_code'),
'name' => 'accounting_code',
'alias' => 'financial_account_civireport_debit',
),
'credit_accounting_code' => array(
'title' => ts('Financial Account Code - Credit'),
'type' => CRM_Utils_Type::T_INT,
'operatorType' => CRM_Report_Form::OP_MULTISELECT,
'options' => CRM_Contribute_PseudoConstant::financialAccount(NULL, NULL, 'accounting_code', 'accounting_code'),
),
'debit_name' => array(
'title' => ts('Financial Account Name - Debit'),
'type' => CRM_Utils_Type::T_STRING,
'operatorType' => CRM_Report_Form::OP_MULTISELECT,
'options' => CRM_Contribute_PseudoConstant::financialAccount(),
'name' => 'id',
'alias' => 'financial_account_civireport_debit',
),
'credit_name' => array(
'title' => ts('Financial Account Name - Credit'),
'type' => CRM_Utils_Type::T_STRING,
'operatorType' => CRM_Report_Form::OP_MULTISELECT,
'options' => CRM_Contribute_PseudoConstant::financialAccount(),
),
),
),
'civicrm_line_item' => array(
'dao' => 'CRM_Price_DAO_LineItem',
'fields' => array(
'financial_type_id' => array(
'title' => ts('Financial Type'),
'default' => TRUE,
),
),
'filters' => array(
'financial_type_id' => array(
'title' => ts('Financial Type'),
'type' => CRM_Utils_Type::T_INT,
'operatorType' => CRM_Report_Form::OP_MULTISELECT,
'options' => CRM_Financial_BAO_FinancialType::getAvailableFinancialTypes(),
),
),
'order_bys' => array(
'financial_type_id' => array('title' => ts('Financial Type')),
),
),
'civicrm_batch' => array(
'dao' => 'CRM_Batch_DAO_Batch',
'fields' => array(
'title' => array(
'title' => ts('Batch Title'),
'alias' => 'batch',
'default' => FALSE,
),
'name' => array(
'title' => ts('Batch Name'),
'alias' => 'batch',
'default' => TRUE,
),
),
),
'civicrm_contribution' => array(
'dao' => 'CRM_Contribute_DAO_Contribution',
'fields' => array(
'receive_date' => array(
'default' => TRUE,
),
'invoice_id' => array(
'title' => ts('Invoice ID'),
'default' => TRUE,
),
'contribution_status_id' => array(
'title' => ts('Contribution Status'),
'default' => TRUE,
),
'id' => array(
'title' => ts('Contribution #'),
'default' => TRUE,
),
),
'filters' => array(
'receive_date' => array('operatorType' => CRM_Report_Form::OP_DATE),
'contribution_status_id' => array(
'title' => ts('Contribution Status'),
'operatorType' => CRM_Report_Form::OP_MULTISELECT,
'options' => CRM_Contribute_PseudoConstant::contributionStatus(),
'default' => array(1),
),
),
'order_bys' => array(
'contribution_id' => array('title' => ts('Contribution #')),
'contribution_status_id' => array('title' => ts('Contribution Status')),
),
'grouping' => 'contri-fields',
),
'civicrm_financial_trxn' => array(
'dao' => 'CRM_Financial_DAO_FinancialTrxn',
'fields' => array(
'check_number' => array(
'title' => ts('Cheque #'),
'default' => TRUE,
),
'payment_instrument_id' => array(
'title' => ts('Payment Method'),
'default' => TRUE,
),
'currency' => array(
'required' => TRUE,
'no_display' => TRUE,
),
'trxn_date' => array(
'title' => ts('Transaction Date'),
'default' => TRUE,
'type' => CRM_Utils_Type::T_DATE,
),
'trxn_id' => array(
'title' => ts('Trans #'),
'default' => TRUE,
),
),
'filters' => array(
'payment_instrument_id' => array(
'title' => ts('Payment Method'),
'type' => CRM_Utils_Type::T_INT,
'operatorType' => CRM_Report_Form::OP_MULTISELECT,
'options' => CRM_Contribute_PseudoConstant::paymentInstrument(),
),
'currency' => array(
'title' => ts('Currency'),
'operatorType' => CRM_Report_Form::OP_MULTISELECT,
'options' => CRM_Core_OptionGroup::values('currencies_enabled'),
'default' => NULL,
'type' => CRM_Utils_Type::T_STRING,
),
'trxn_date' => array(
'title' => ts('Transaction Date'),
'operatorType' => CRM_Report_Form::OP_DATE,
'type' => CRM_Utils_Type::T_DATE,
),
'status_id' => array(
'title' => ts('Financial Transaction Status'),
'operatorType' => CRM_Report_Form::OP_MULTISELECT,
'options' => CRM_Contribute_PseudoConstant::contributionStatus(),
'default' => array(1),
),
),
'order_bys' => array(
'payment_instrument_id' => array('title' => ts('Payment Method')),
),
),
'civicrm_entity_financial_trxn' => array(
'dao' => 'CRM_Financial_DAO_EntityFinancialTrxn',
'fields' => array(
'amount' => array(
'title' => ts('Amount'),
'default' => TRUE,
'type' => CRM_Utils_Type::T_STRING,
),
),
'filters' => array(
'amount' => array('title' => ts('Amount')),
),
),
)
+ $this->addAddressFields(FALSE);
$this->_groupFilter = TRUE;
$this->_tagFilter = TRUE;
parent::__construct();
}
public function preProcess() {
parent::preProcess();
}
public function select() {
$select = array();
$this->_columnHeaders = array();
foreach ($this->_columns as $tableName => $table) {
if (array_key_exists('fields', $table)) {
foreach ($table['fields'] as $fieldName => $field) {
if (!empty($field['required']) ||
!empty($this->_params['fields'][$fieldName])
) {
switch ($fieldName) {
case 'credit_accounting_code':
$select[] = " CASE
WHEN {$this->_aliases['civicrm_financial_trxn']}.from_financial_account_id IS NOT NULL
THEN {$this->_aliases['civicrm_financial_account']}_credit_1.accounting_code
ELSE {$this->_aliases['civicrm_financial_account']}_credit_2.accounting_code
END AS civicrm_financial_account_credit_accounting_code ";
break;
case 'amount':
$select[] = " CASE
WHEN {$this->_aliases['civicrm_entity_financial_trxn']}_item.entity_id IS NOT NULL
THEN {$this->_aliases['civicrm_entity_financial_trxn']}_item.amount
ELSE {$this->_aliases['civicrm_entity_financial_trxn']}.amount
END AS civicrm_entity_financial_trxn_amount ";
break;
case 'credit_name':
$select[] = " CASE
WHEN {$this->_aliases['civicrm_financial_trxn']}.from_financial_account_id IS NOT NULL
THEN {$this->_aliases['civicrm_financial_account']}_credit_1.name
ELSE {$this->_aliases['civicrm_financial_account']}_credit_2.name
END AS civicrm_financial_account_credit_name ";
break;
default:
$select[] = "{$field['dbAlias']} as {$tableName}_{$fieldName}";
break;
}
$this->_columnHeaders["{$tableName}_{$fieldName}"]['title'] = $field['title'];
$this->_columnHeaders["{$tableName}_{$fieldName}"]['type'] = CRM_Utils_Array::value('type', $field);
}
}
}
}
$this->_selectClauses = $select;
$this->_select = 'SELECT ' . implode(', ', $select) . ' ';
}
public function from() {
$this->_from = NULL;
$this->_from = "FROM civicrm_contact {$this->_aliases['civicrm_contact']} {$this->_aclFrom}
INNER JOIN civicrm_contribution {$this->_aliases['civicrm_contribution']}
ON {$this->_aliases['civicrm_contact']}.id = {$this->_aliases['civicrm_contribution']}.contact_id AND
{$this->_aliases['civicrm_contribution']}.is_test = 0
LEFT JOIN civicrm_membership_payment payment
ON ( {$this->_aliases['civicrm_contribution']}.id = payment.contribution_id )
LEFT JOIN civicrm_membership {$this->_aliases['civicrm_membership']}
ON payment.membership_id = {$this->_aliases['civicrm_membership']}.id
LEFT JOIN civicrm_entity_financial_trxn {$this->_aliases['civicrm_entity_financial_trxn']}
ON ({$this->_aliases['civicrm_contribution']}.id = {$this->_aliases['civicrm_entity_financial_trxn']}.entity_id AND
{$this->_aliases['civicrm_entity_financial_trxn']}.entity_table = 'civicrm_contribution')
LEFT JOIN civicrm_financial_trxn {$this->_aliases['civicrm_financial_trxn']}
ON {$this->_aliases['civicrm_financial_trxn']}.id = {$this->_aliases['civicrm_entity_financial_trxn']}.financial_trxn_id
LEFT JOIN civicrm_financial_account {$this->_aliases['civicrm_financial_account']}_debit
ON {$this->_aliases['civicrm_financial_trxn']}.to_financial_account_id = {$this->_aliases['civicrm_financial_account']}_debit.id
LEFT JOIN civicrm_financial_account {$this->_aliases['civicrm_financial_account']}_credit_1
ON {$this->_aliases['civicrm_financial_trxn']}.from_financial_account_id = {$this->_aliases['civicrm_financial_account']}_credit_1.id
LEFT JOIN civicrm_entity_financial_trxn {$this->_aliases['civicrm_entity_financial_trxn']}_item
ON ({$this->_aliases['civicrm_financial_trxn']}.id = {$this->_aliases['civicrm_entity_financial_trxn']}_item.financial_trxn_id AND
{$this->_aliases['civicrm_entity_financial_trxn']}_item.entity_table = 'civicrm_financial_item')
LEFT JOIN civicrm_financial_item fitem
ON fitem.id = {$this->_aliases['civicrm_entity_financial_trxn']}_item.entity_id
LEFT JOIN civicrm_financial_account {$this->_aliases['civicrm_financial_account']}_credit_2
ON fitem.financial_account_id = {$this->_aliases['civicrm_financial_account']}_credit_2.id
LEFT JOIN civicrm_address {$this->_aliases['civicrm_address']}
ON {$this->_aliases['civicrm_address']}.contact_id = {$this->_aliases['civicrm_contact']}.id AND {$this->_aliases['civicrm_address']}.is_primary = 1
LEFT JOIN civicrm_line_item {$this->_aliases['civicrm_line_item']}
ON fitem.entity_id = {$this->_aliases['civicrm_line_item']}.id AND fitem.entity_table = 'civicrm_line_item' ";
if ($this->isTableSelected('civicrm_batch')) {
$this->_from .= "LEFT JOIN civicrm_entity_batch ent_batch
ON {$this->_aliases['civicrm_financial_trxn']}.id = ent_batch.entity_id AND ent_batch.entity_table = 'civicrm_financial_trxn'
LEFT JOIN civicrm_batch batch
ON ent_batch.batch_id = batch.id";
}
$this->getPermissionedFTQuery($this, "civicrm_line_item_1");
}
public function orderBy() {
parent::orderBy();
// please note this will just add the order-by columns to select query, and not display in column-headers.
// This is a solution to not throw fatal errors when there is a column in order-by, not present in select/display columns.
foreach ($this->_orderByFields as $orderBy) {
if (!array_key_exists($orderBy['name'], $this->_params['fields']) &&
empty($orderBy['section'])
) {
$this->_select .= ", {$orderBy['dbAlias']} as {$orderBy['tplField']}";
}
}
}
public function where() {
foreach ($this->_columns as $tableName => $table) {
if (array_key_exists('filters', $table)) {
foreach ($table['filters'] as $fieldName => $field) {
$clause = NULL;
if ($fieldName == 'credit_accounting_code') {
$field['dbAlias'] = "CASE
WHEN financial_trxn_civireport.from_financial_account_id IS NOT NULL
THEN financial_account_civireport_credit_1.accounting_code
ELSE financial_account_civireport_credit_2.accounting_code
END";
}
elseif ($fieldName == 'credit_name') {
$field['dbAlias'] = "CASE
WHEN financial_trxn_civireport.from_financial_account_id IS NOT NULL
THEN financial_account_civireport_credit_1.id
ELSE financial_account_civireport_credit_2.id
END";
}
if (CRM_Utils_Array::value('type', $field) & CRM_Utils_Type::T_DATE) {
$relative = CRM_Utils_Array::value("{$fieldName}_relative", $this->_params);
$from = CRM_Utils_Array::value("{$fieldName}_from", $this->_params);
$to = CRM_Utils_Array::value("{$fieldName}_to", $this->_params);
$clause = $this->dateClause($field['name'], $relative, $from, $to, $field['type']);
}
else {
$op = CRM_Utils_Array::value("{$fieldName}_op", $this->_params);
if ($op) {
$clause = $this->whereClause($field,
$op,
CRM_Utils_Array::value("{$fieldName}_value", $this->_params),
CRM_Utils_Array::value("{$fieldName}_min", $this->_params),
CRM_Utils_Array::value("{$fieldName}_max", $this->_params)
);
}
}
if (!empty($clause)) {
$clauses[] = $clause;
}
}
}
}
if (empty($clauses)) {
$this->_where = 'WHERE ( 1 )';
}
else {
$this->_where = 'WHERE ' . implode(' AND ', $clauses);
}
}
public function postProcess() {
// get the acl clauses built before we assemble the query
$this->buildACLClause($this->_aliases['civicrm_contact']);
parent::postProcess();
}
public function groupBy() {
$groupBy = array(
"{$this->_aliases['civicrm_entity_financial_trxn']}.id",
/* Removed due to Membership Duplicates
"{$this->_aliases['civicrm_line_item']}.id",
*/
);
$this->_groupBy = CRM_Contact_BAO_Query::getGroupByFromSelectColumns($this->_selectClauses, $groupBy);
}
/**
* @param $rows
*
* @return array
*/
public function statistics(&$rows) {
$statistics = parent::statistics($rows);
$tempTableName = CRM_Core_DAO::createTempTableName('civicrm_contribution');
$financialSelect = "CASE WHEN {$this->_aliases['civicrm_entity_financial_trxn']}_item.entity_id IS NOT NULL
THEN {$this->_aliases['civicrm_entity_financial_trxn']}_item.amount
ELSE {$this->_aliases['civicrm_entity_financial_trxn']}.amount
END as amount";
$this->_selectClauses = array(
"{$this->_aliases['civicrm_contribution']}.id",
"{$this->_aliases['civicrm_entity_financial_trxn']}.id as trxnID",