Problem
CDR partition tables in asteriskcdrdb (cdr_YYYY and cdr_YYYY-MM) accumulate rows belonging to periods other than the table's own period. This silently inflates counts returned by any API query whose date range spans more than one month, and inflates every CDR dashboard widget by approximately 2x.
Root cause — daily INSERT IGNORE in partition templates
root/opt/nethvoice-report/api/templates/cdr_year.sql and cdr_month.sql contain a daily INSERT IGNORE block that copies "yesterday's" rows from the source cdr table (or year table) into the partition target. The block filters by calldate >= NOW() - INTERVAL 1 DAY AND calldate < NOW() but lacks any constraint on the target table's own period.
The nightly tasks cdr job iterates every year/month from cdr_first_month to the current month, and for every iteration it executes the INSERT IGNORE block. As a result, yesterday's rows are inserted into every historical partition table, regardless of whether yesterday belongs to that partition's period.
Runtime symptom 1 — multi-month API queries
api/methods/queries.go buildCdrQuery builds a UNION ALL across the monthly partition tables that intersect the requested time range. Each subquery applies the same outer WHERE calldate BETWEEN start AND end. When a partition table contains rows belonging to other months that fall inside the requested range, those rows are returned by both their "rightful" partition and any contaminated partition, double-counting.
Example: with date range March–April, the outbound recap summary returns ~5992 calls instead of the correct ~4083 (March 2261 + April 1822).
Runtime symptom 2 — dashboard widgets
The precomputed dashboard tables dashboard_cdr_*_past_* are built by root/opt/nethvoice-report/api/views/dashboard_cdr_*.sql. These views read from year tables (cdr_YYYY) and UNION ALL the previous-year and current-year tables. When either year table contains rows of the other year (the contamination above), every dashboard widget for past_week, past_month, past_quarter, past_semester, past_year, current_* is inflated approximately 2x.
Combined effect
- Multi-month API CDR queries (pbx and personal sections) over-count by a factor proportional to the number of months covered.
- All 18 dashboard CDR widgets inflated by ~2x.
- Multi-month group-by-month charts show duplicated values on every visible month.
Fix
Problem
CDR partition tables in
asteriskcdrdb(cdr_YYYYandcdr_YYYY-MM) accumulate rows belonging to periods other than the table's own period. This silently inflates counts returned by any API query whose date range spans more than one month, and inflates every CDR dashboard widget by approximately 2x.Root cause — daily INSERT IGNORE in partition templates
root/opt/nethvoice-report/api/templates/cdr_year.sqlandcdr_month.sqlcontain a dailyINSERT IGNOREblock that copies "yesterday's" rows from the sourcecdrtable (or year table) into the partition target. The block filters bycalldate >= NOW() - INTERVAL 1 DAY AND calldate < NOW()but lacks any constraint on the target table's own period.The nightly
tasks cdrjob iterates every year/month fromcdr_first_monthto the current month, and for every iteration it executes theINSERT IGNOREblock. As a result, yesterday's rows are inserted into every historical partition table, regardless of whether yesterday belongs to that partition's period.Runtime symptom 1 — multi-month API queries
api/methods/queries.gobuildCdrQuerybuilds aUNION ALLacross the monthly partition tables that intersect the requested time range. Each subquery applies the same outerWHERE calldate BETWEEN start AND end. When a partition table contains rows belonging to other months that fall inside the requested range, those rows are returned by both their "rightful" partition and any contaminated partition, double-counting.Example: with date range March–April, the outbound recap summary returns ~5992 calls instead of the correct ~4083 (March 2261 + April 1822).
Runtime symptom 2 — dashboard widgets
The precomputed dashboard tables
dashboard_cdr_*_past_*are built byroot/opt/nethvoice-report/api/views/dashboard_cdr_*.sql. These views read from year tables (cdr_YYYY) andUNION ALLthe previous-year and current-year tables. When either year table contains rows of the other year (the contamination above), every dashboard widget forpast_week,past_month,past_quarter,past_semester,past_year,current_*is inflated approximately 2x.Combined effect
Fix
cdr_year.sqlandcdr_month.sql, and adds an idempotenttasks cleanupcommand that removes out-of-period rows from all CDR partition tables.NETHVOICE_REPORT_COMMITto the fix and wirestasks cleanupinto the nightlyreports-scheduler.servicebetweencostandviews, so retroactive sanitization runs during the existing nightly window (not during package upgrade) and is safe to re-run.