Reported: when the generate-report page is filtered by BOTH project and
team, every amount in the "Worker Breakdown" and "Payments by Date"
tables blew up by ~100x. Example: Billy Baloyi R 5,400 (correct)
became R 604,800 (wrong, 112x) after selecting Wilkot + Civils One.
Root cause:
_build_report_context chained `records.filter(work_logs__project_id=X)
.distinct().filter(work_logs__team_id=Y).distinct()`. In Django's ORM
each chained M2M filter creates a SEPARATE JOIN alias on
core_payrollrecord_work_logs, so the SQL produces the cartesian product
of (matching-logs-for-project) x (matching-logs-for-team) rows per
PayrollRecord. A downstream `.values().annotate(Sum('amount_paid'))`
then summed across those duplicated rows - inflating every total by
N * M where N and M are the log counts per record.
Why total_paid_out looked correct: `.aggregate(Sum(...))` wraps the
query in a subquery when distinct() is in play, so it dedupes before
summing. `.values().annotate(Sum(...))` uses GROUP BY on the raw
joined rows and doesn't get that help.
Fix:
Replace chained M2M filters with id__in subquery filters:
records.filter(id__in=PayrollRecord.objects.filter(
work_logs__project_id=X).values('id'))
This keeps the outer queryset JOIN-free, so values().annotate(Sum())
aggregates over distinct records. Same pattern applied to the
adjustments team-filter (worker__teams M2M) for the adjustment
summary.
Tests: 5 new regression tests in ReportContextFilterInflationTests
covering project-only, team-only, both-filters, total_paid_out
invariant, and the adjustment summary path. All 24 tests pass
(19 existing + 5 new).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Flatlogic Python Template Workspace
This workspace houses the Django application scaffold used for Python-based templates.
Requirements
- Python 3.11+
- MariaDB (or MySQL-compatible server) with the credentials prepared by
setup_mariadb_project.sh - System packages:
pkg-config,libmariadb-dev(already installed on golden images)
Getting Started
python3 -m pip install --break-system-packages -r requirements.txt
python3 manage.py migrate
python3 manage.py runserver 0.0.0.0:8000
Environment variables are loaded from ../.env (the executor root). See .env.example if you need to populate values manually.
Project Structure
config/– Django project settings, URLs, WSGI entrypoint.core/– Default app with a basic health-check route.manage.py– Django management entrypoint.
Next Steps
- Create additional apps and views according to the generated project requirements.
- Configure serving via Apache + mod_wsgi or gunicorn (instructions to be added).
- Run
python3 manage.py collectstaticbefore serving through Apache.
Description
Languages
JavaScript
42.5%
SCSS
41.7%
CSS
11.9%
Python
3.2%
HTML
0.6%