Uploaded image for project: 'CiviCRM'
  1. CiviCRM
  2. CRM-16997

Statistics fields incorrect on Repeating Contribution Report

    Details

    • Type: Bug
    • Status: Done/Fixed
    • Priority: Trivial
    • Resolution: Fixed/Completed
    • Affects Version/s: 4.6
    • Fix Version/s: 4.7
    • Component/s: None
    • Labels:
    • Documentation Required?:
      None
    • Funding Source:
      Contributed Code

      Description

      The statistics fields on Repeating Contribution reports shows incorrect numbers.
      _________________________________________________________________________

      Here is the workflow as per the current code
      (https://github.com/civicrm/civicrm-core/blob/master/CRM/Report/Form/Contribute/Repeat.php#L805)
      1. Creates temp table having contribution of initial date range

      CREATE TEMPORARY TABLE civicrm_temp_civireport_repeat1 (

      contact_id int unsigned,
      total_amount_sum int,
      total_amount_count int
      ) ENGINE=HEAP DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;

      INSERT INTO civicrm_temp_civireport_repeat1
      SELECT contribution1.contact_id,
      sum( contribution1.total_amount ) AS total_amount_sum,
      count( * ) AS total_amount_count
      FROM civicrm_contribution contribution1 INNER JOIN civicrm_contribution_temp temp ON contribution1.id = temp.id
      WHERE contribution1.is_test = 0 AND ( contribution1.receive_date >= 20140101 ) AND ( contribution1.receive_date <= 20141231 ) AND ( contribution1.contribution_status_id IN (1) )
      GROUP BY contribution1.contact_id

      2. Creates temp table having contribution of second date range

      CREATE TEMPORARY TABLE civicrm_temp_civireport_repeat2 (

      contact_id int unsigned,
      total_amount_sum int,
      total_amount_count int,
      currency varchar(3)
      ) ENGINE=HEAP DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;

      INSERT INTO civicrm_temp_civireport_repeat2
      SELECT contribution2.contact_id,
      sum( contribution2.total_amount ) AS total_amount_sum,
      count( * ) AS total_amount_count,
      currency
      FROM civicrm_contribution contribution2 INNER JOIN civicrm_contribution_temp temp ON contribution2.id = temp.id
      WHERE contribution2.is_test = 0 AND ( contribution2.receive_date >= 20150101 ) AND ( contribution2.receive_date <= 20151231 ) AND ( contribution2.contribution_status_id IN (1) )
      GROUP BY contribution2.contact_id

      3. Merge's 2 tables from #1 and #2 joining with contact tables and add's Where clause

      SELECT SQL_CALC_FOUND_ROWS contact_civireport.sort_name as contact_civireport_sort_name, contact_civireport.id as contact_civireport_id, contribution_civireport1.total_amount_count as contribution1_total_amount_count, contribution_civireport1.total_amount_sum as contribution1_total_amount_sum, contribution_civireport2.total_amount_count as contribution2_total_amount_count, contribution_civireport2.total_amount_sum as contribution2_total_amount_sum
      FROM civicrm_contact contact_civireport
      LEFT JOIN civicrm_address address_civireport ON contact_civireport.id = address_civireport.contact_id
      LEFT JOIN civicrm_email email_civireport
      ON contact_civireport.id = email_civireport.contact_id AND email_civireport.is_primary = 1
      LEFT JOIN civicrm_phone phone_civireport
      ON contact_civireport.id = phone_civireport.contact_id AND phone_civireport.is_primary = 1
      LEFT JOIN civicrm_temp_civireport_repeat1 contribution_civireport1
      ON contact_civireport.id = contribution_civireport1.contact_id
      LEFT JOIN civicrm_temp_civireport_repeat2 contribution_civireport2
      ON contact_civireport.id = contribution_civireport2.contact_id WHERE !(contribution_civireport1.total_amount_count IS NULL AND contribution_civireport2.total_amount_count IS NULL) AND contact_civireport.id IN (
      SELECT DISTINCT cgroup_civireport.contact_id
      FROM civicrm_group_contact cgroup_civireport
      WHERE cgroup_civireport.group_id IN (5) AND cgroup_civireport.status = 'Added'
      ) GROUP BY contact_civireport.id LIMIT 0, 50

      The sql at #1 and #2 for inserting records in temp table has all the records. The 3rd sql removes unwanted rows by adding filters in Where clause.

      =========================================================================

      For statistics(https://github.com/civicrm/civicrm-core/blob/master/CRM/Report/Form/Contribute/Repeat.php#L623)

      1. Uses temp table's create at step #1 and #2. Unions it and store its in 3rd temp table
      CREATE TEMPORARY TABLE civicrm_temp_civireport_repeat3
      SELECT contact_id FROM civicrm_temp_civireport_repeat1 UNION SELECT contact_id FROM civicrm_temp_civireport_repeat2;

      2. Below sql is used to calculate 'New Donor', 'lapsed donor's', 'upgraded donors', downgraded donors', 'maintained donors'. (https://github.com/civicrm/civicrm-core/blob/master/CRM/Report/Form/Contribute/Repeat.php#L660)
      SELECT civicrm_temp_civireport_repeat3.contact_id,
      civicrm_temp_civireport_repeat1.total_amount_sum as contribution1_total_amount_sum,
      civicrm_temp_civireport_repeat2.total_amount_sum as contribution2_total_amount_sum
      FROM civicrm_temp_civireport_repeat3
      LEFT JOIN civicrm_temp_civireport_repeat1
      ON civicrm_temp_civireport_repeat3.contact_id = civicrm_temp_civireport_repeat1.contact_id
      LEFT JOIN civicrm_temp_civireport_repeat2
      ON civicrm_temp_civireport_repeat3.contact_id = civicrm_temp_civireport_repeat2.contact_id

      3. Below sql is used to get count of 'Initial Date Range', 'Total Amount', 'Total Donations', 'Average', 'Second Date Range', 'Total Amount', 'Total Donations', 'Average'.
      SELECT COUNT(contribution_civireport1.total_amount_count ) as count,
      SUM(contribution_civireport1.total_amount_sum ) as amount,
      ROUND(AVG(contribution_civireport1.total_amount_sum), 2) as avg,
      COUNT(contribution_civireport2.total_amount_count ) as count2,
      SUM(contribution_civireport2.total_amount_sum ) as amount2,
      ROUND(AVG(contribution_civireport2.total_amount_sum), 2) as avg2,
      currency
      FROM civicrm_contact contact_civireport
      LEFT JOIN civicrm_address address_civireport ON contact_civireport.id = address_civireport.contact_id
      LEFT JOIN civicrm_email email_civireport
      ON contact_civireport.id = email_civireport.contact_id AND email_civireport.is_primary = 1
      LEFT JOIN civicrm_phone phone_civireport
      ON contact_civireport.id = phone_civireport.contact_id AND phone_civireport.is_primary = 1
      LEFT JOIN civicrm_temp_civireport_repeat1 contribution_civireport1
      ON contact_civireport.id = contribution_civireport1.contact_id
      LEFT JOIN civicrm_temp_civireport_repeat2 contribution_civireport2
      ON contact_civireport.id = contribution_civireport2.contact_id WHERE !(contribution_civireport1.total_amount_count IS NULL AND contribution_civireport2.total_amount_count IS NULL) AND contact_civireport.id IN (
      SELECT DISTINCT cgroup_civireport.contact_id
      FROM civicrm_group_contact cgroup_civireport
      WHERE cgroup_civireport.group_id IN (5) AND cgroup_civireport.status = 'Added'
      )
      GROUP BY currency

      When joining 2 tables it unions all the contribution without adding Where clause, which ends up calculating statistics for all contribution

        Attachments

          Activity

            People

            • Assignee:
              rohan1990 Rohan Ramesh Katkar
              Reporter:
              pradeep.nayak Pradeep Nayak
            • Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: