autocensup/core/tasks.py
Rogério Lima 36d3386d2d feat: protect manual edits from API overwrite, fix pending situacao, sort CRUD lists
- Add Pessoa/Vinculo.atualizado_manualmente flag, set automatically on web CRUD
  save; all Gennera/txt import paths now skip records flagged this way instead
  of overwriting them
- Vinculo import: finalize step corrects leftover "situacao nao informada"
  vinculos to "Desvinculado", pulling carga horaria from censup_carga_horaria
- Generic CRUD list view: click a column header to sort (asc/desc), persists
  through pagination; FK columns sort by their related display field
- Rename GENNERA_API_BASE_URL setting to GENNERA_LOCAL_BASE_URL

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-06 15:39:36 -03:00

106 lines
3.2 KiB
Python

from __future__ import annotations
from functools import partial
from typing import Any
from celery import shared_task
from django.conf import settings
from .importers import (
fetch_gennera_vinculos_censup,
import_carga_horaria_from_gennera,
import_pessoas_ingressantes_from_gennera,
import_vinculos_from_gennera,
)
@shared_task(bind=True)
def import_pessoas_ingressantes_task(
self, primeiro_ano: int, page_size: int = 100
) -> dict[str, Any]:
def report_progress(page: int, total_pages: int, processed: int, total_count: int) -> None:
self.update_state(
state="PROGRESS",
meta={
"processed": processed,
"total": total_count,
"message": f"Pagina {page}/{total_pages}",
},
)
result = import_pessoas_ingressantes_from_gennera(
primeiro_ano=primeiro_ano,
base_url=settings.GENNERA_LOCAL_BASE_URL,
token=settings.GENNERA_LOCAL_AUTH_TOKEN,
page_size=page_size,
progress_callback=report_progress,
)
return {
"created": result.created,
"skipped": result.skipped,
"ignorados_sem_cpf": result.ignorados_sem_cpf,
"errors": len(result.errors),
"total": result.total,
}
@shared_task(bind=True)
def import_vinculos_censup_task(
self, ano: int, page_size: int = 100, threads: int = 4
) -> dict[str, Any]:
def report_progress(index: int, total: int, cpf: str, vinculos: list) -> None:
self.update_state(
state="PROGRESS",
meta={
"processed": index,
"total": total,
"message": f"CPF {cpf}",
},
)
result = import_vinculos_from_gennera(
ano=ano,
base_url=settings.GENNERA_LOCAL_BASE_URL,
token=settings.GENNERA_LOCAL_AUTH_TOKEN,
fetcher=partial(fetch_gennera_vinculos_censup, page_size=page_size),
progress_callback=report_progress,
max_workers=threads,
)
return {
"pessoas_processed": result.pessoas_processed,
"pessoas_without_vinculo": result.pessoas_without_vinculo,
"created": result.created,
"updated": result.updated,
"situacao_nao_informada_corrigidos": result.situacao_nao_informada_corrigidos,
"errors": len(result.errors),
}
@shared_task(bind=True)
def import_carga_horaria_censup_task(
self, page_size: int = 100, threads: int = 4
) -> dict[str, Any]:
def report_progress(index: int, total: int, matricula: str, vinculos: list) -> None:
self.update_state(
state="PROGRESS",
meta={
"processed": index,
"total": total,
"message": f"Matricula {matricula}",
},
)
result = import_carga_horaria_from_gennera(
base_url=settings.GENNERA_LOCAL_BASE_URL,
token=settings.GENNERA_LOCAL_AUTH_TOKEN,
page_size=page_size,
max_workers=threads,
progress_callback=report_progress,
)
return {
"matriculas_processadas": result.matriculas_processadas,
"vinculos_atualizados": result.vinculos_atualizados,
"sem_dados": result.sem_dados,
"errors": len(result.errors),
}