Skip to content

feat(meta-orcamento-consolidado): adicionando view de orcamento conso…#592

Open
lucasansei wants to merge 3 commits intohomolfrom
feat/meta-orcamento-consolidado
Open

feat(meta-orcamento-consolidado): adicionando view de orcamento conso…#592
lucasansei wants to merge 3 commits intohomolfrom
feat/meta-orcamento-consolidado

Conversation

@lucasansei
Copy link
Member

@lucasansei lucasansei commented Feb 26, 2026

…lidado e triggers

Summary by CodeRabbit

  • New Features
    • Consolidated budget summaries for metas with totals by category (general, project, activity, special operations) and updated timestamps.
    • Automatic recalculation and background refresh of consolidated totals when planned or realized budgets change, with initial population of consolidated data.
    • Meta API now includes an optional consolidated budget section on meta items for consumers to read current totals.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 26, 2026

📝 Walkthrough

Walkthrough

Adds a consolidated per-meta budget table and Prisma model, PostgreSQL functions/triggers to aggregate and upsert totals from planned/realized budgets, a deduplicated queue task and worker service to refresh consolidations, and exposes consolidated totals in the Meta API response. Initial population and recalculation are included.

Changes

Cohort / File(s) Summary
Database Migration
backend/prisma/migrations/20260226121720_meta_orcamento_consolidado/migration.sql
Creates meta_orcamento_consolidado table with per-meta totals (general, projeto, atividade, operacao_especial), atualizado_em timestamp, FK to meta, and index on atualizado_em.
Postgres functions & triggers
backend/prisma/manual-copy/0056-atualiza-meta-orcamento-consolidado.pgsql
Adds parsing/classification helpers (f_extrair_projeto_atividade, f_classificar_projeto_atividade), refresh function (f_refresh_meta_orcamento_consolidado), task enqueue proc/wrapper, trigger functions (tg_orcamento_planejado_refresh_consolidado, tg_orcamento_realizado_refresh_consolidado), triggers on planned/realized tables, and initial population/recalculation logic.
Prisma schema
backend/prisma/schema.prisma
Adds MetaOrcamentoConsolidado model mapped to meta_orcamento_consolidado, one-to-one relation on Meta, and new task enum value refresh_meta_orcamento_consolidado.
API entities
backend/src/meta/entities/meta.entity.ts
Adds MetaOrcamentoConsolidado DTO/class and an optional orcamento property on MetaItemDto.
Meta service
backend/src/meta/meta.service.ts
Selects and maps MetaOrcamentoConsolidado when meta id filter is present; populates orcamento on returned Meta items.
Task DTO & module
backend/src/task/refresh_meta_orcamento_consolidado/...
Adds DTO CreateRefreshMetaOrcamentoConsolidadoDto, module and provider for RefreshMetaOrcamentoConsolidadoService.
Task service wiring
backend/src/task/task.module.ts, backend/src/task/task.parseParams.ts, backend/src/task/task.service.ts
Registers new module/service, parses new task type, wires service into task dispatch/execution and marks it as a foreground task.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant API as Backend API
  participant TaskQ as Task Queue (DB table)
  participant DB as Postgres
  Client->>API: create/update/delete orcamento_planejado/realizado
  API->>DB: execute DML
  DB->>DB: trigger tg_orcamento_*_refresh_consolidado fires
  DB->>TaskQ: insert deduplicated refresh task (refresh_meta_orcamento_consolidado)
  Note right of TaskQ: Task worker (TaskService) picks tasks
  TaskQ->>API: TaskService executes RefreshMetaOrcamentoConsolidadoService
  API->>DB: call f_refresh_meta_orcamento_consolidado(meta_id) within tx
  DB->>DB: aggregate planned/realized by classification and upsert meta_orcamento_consolidado
  DB-->>API: success
  API-->>Client: subsequent reads include MetaOrcamentoConsolidado
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • robsonsobral

Poem

🐰
I hop through dots and ledger light,
Triggers tingle in the night,
I sum each meta, neat and sweet,
Queue a job and skip a beat,
Crunchy totals—task complete! 🥕

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title partially captures the main change (adding consolidated budget view and triggers) but is truncated mid-word, appearing incomplete and creating ambiguity about the full scope of work. Complete the truncated title to clearly describe the full change, e.g., 'feat(meta-orcamento-consolidado): adicionando view de orcamento consolidado, triggers e processamento assincrono' or similar comprehensive phrasing.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/meta-orcamento-consolidado

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
backend/src/meta/meta.service.ts (1)

630-649: Gate MetaOrcamentoConsolidado select on both ID filter and non-permission-check flows.

When skipObjects is true (e.g., in assertMetaWriteOrThrow), this relation is still selected if filters.id is set, adding unnecessary DB work. The orcamento mapping happens outside the if (!skipObjects) guard and is always returned (null or mapped), but fetching the relation remains wasteful during permission-only checks.

♻️ Suggested change
                 MetaOrcamentoConsolidado:
-                    filters?.id !== undefined
+                    filters?.id !== undefined && !skipObjects
                         ? {
                               select: {
                                   total_previsao: true,
                                   total_empenhado: true,
                                   total_liquidado: true,
                                   total_previsao_projeto: true,
                                   total_empenhado_projeto: true,
                                   total_liquidado_projeto: true,
                                   total_previsao_atividade: true,
                                   total_empenhado_atividade: true,
                                   total_liquidado_atividade: true,
                                   total_previsao_operacao_especial: true,
                                   total_empenhado_operacao_especial: true,
                                   total_liquidado_operacao_especial: true,
                                   atualizado_em: true,
                               },
                           }
                         : undefined,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/meta/meta.service.ts` around lines 630 - 649, The
MetaOrcamentoConsolidado relation is being selected whenever filters.id is set
even when skipObjects is true (e.g., inside assertMetaWriteOrThrow), causing
unnecessary DB work; update the selection logic where MetaOrcamentoConsolidado
is added so it only includes the select block when skipObjects is false AND
filters?.id !== undefined (i.e., gate the existing select behind a check of
skipObjects), keeping the existing fields and leaving the orcamento mapping
unchanged so permission-only flows avoid fetching the relation.
backend/prisma/manual-copy/0056-atualiza-meta-orcamento-consolidado.pgsql (1)

262-323: Consider extracting shared meta resolution logic.

The trigger functions tg_orcamento_planejado_refresh_consolidado and tg_orcamento_realizado_refresh_consolidado share nearly identical logic. Consider extracting the meta resolution into a helper function to reduce duplication and ease maintenance:

CREATE OR REPLACE FUNCTION f_resolve_meta_id(
    p_meta_id INT, 
    p_iniciativa_id INT, 
    p_atividade_id INT
) RETURNS INT AS $$
DECLARE
    v_meta_id INT;
BEGIN
    IF p_meta_id IS NOT NULL THEN
        RETURN p_meta_id;
    ELSIF p_iniciativa_id IS NOT NULL THEN
        SELECT meta_id INTO v_meta_id FROM iniciativa WHERE id = p_iniciativa_id;
        RETURN v_meta_id;
    ELSIF p_atividade_id IS NOT NULL THEN
        SELECT i.meta_id INTO v_meta_id 
        FROM atividade a 
        JOIN iniciativa i ON i.id = a.iniciativa_id 
        WHERE a.id = p_atividade_id;
        RETURN v_meta_id;
    END IF;
    RETURN NULL;
END;
$$ LANGUAGE plpgsql STABLE;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/prisma/manual-copy/0056-atualiza-meta-orcamento-consolidado.pgsql`
around lines 262 - 323, Both tg_orcamento_planejado_refresh_consolidado and
tg_orcamento_realizado_refresh_consolidado duplicate the same meta resolution
logic; extract that logic into a new helper function (suggested name
f_resolve_meta_id(p_meta_id INT, p_iniciativa_id INT, p_atividade_id INT)
RETURNS INT STABLE) and replace the repeated blocks that compute v_meta_id and
v_old_meta_id with calls to f_resolve_meta_id(NEW.meta_id, NEW.iniciativa_id,
NEW.atividade_id) and f_resolve_meta_id(OLD.meta_id, OLD.iniciativa_id,
OLD.atividade_id) respectively, leaving the calls to
f_refresh_meta_orcamento_consolidado(v_meta_id) and the UPDATE-old-vs-new
comparison logic intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/prisma/manual-copy/0056-atualiza-meta-orcamento-consolidado.pgsql`:
- Around line 246-249: The NULL comparison can short-circuit the IF when
v_meta_id is NULL; change the condition so a difference with NULL is
detected—e.g., in the IF that currently reads "IF v_old_meta_id IS NOT NULL AND
v_old_meta_id != v_meta_id THEN" replace the inequality check with a NULL-safe
comparison (use IS DISTINCT FROM) so it becomes "v_old_meta_id IS NOT NULL AND
v_old_meta_id IS DISTINCT FROM v_meta_id", ensuring
f_refresh_meta_orcamento_consolidado(v_old_meta_id) is called when the old meta
differs or the new meta is NULL.
- Around line 315-318: The current IF condition uses "v_old_meta_id IS NOT NULL
AND v_old_meta_id != v_meta_id" which fails when v_meta_id is NULL; update the
condition in the trigger to use SQL NULL-safe comparison so the refresh runs
when values differ or one is NULL — e.g., change the check around
f_refresh_meta_orcamento_consolidado to "IF v_old_meta_id IS NOT NULL AND
v_old_meta_id IS DISTINCT FROM v_meta_id THEN PERFORM
f_refresh_meta_orcamento_consolidado(v_old_meta_id); END IF;" so v_meta_id NULL
is handled correctly.

---

Nitpick comments:
In `@backend/prisma/manual-copy/0056-atualiza-meta-orcamento-consolidado.pgsql`:
- Around line 262-323: Both tg_orcamento_planejado_refresh_consolidado and
tg_orcamento_realizado_refresh_consolidado duplicate the same meta resolution
logic; extract that logic into a new helper function (suggested name
f_resolve_meta_id(p_meta_id INT, p_iniciativa_id INT, p_atividade_id INT)
RETURNS INT STABLE) and replace the repeated blocks that compute v_meta_id and
v_old_meta_id with calls to f_resolve_meta_id(NEW.meta_id, NEW.iniciativa_id,
NEW.atividade_id) and f_resolve_meta_id(OLD.meta_id, OLD.iniciativa_id,
OLD.atividade_id) respectively, leaving the calls to
f_refresh_meta_orcamento_consolidado(v_meta_id) and the UPDATE-old-vs-new
comparison logic intact.

In `@backend/src/meta/meta.service.ts`:
- Around line 630-649: The MetaOrcamentoConsolidado relation is being selected
whenever filters.id is set even when skipObjects is true (e.g., inside
assertMetaWriteOrThrow), causing unnecessary DB work; update the selection logic
where MetaOrcamentoConsolidado is added so it only includes the select block
when skipObjects is false AND filters?.id !== undefined (i.e., gate the existing
select behind a check of skipObjects), keeping the existing fields and leaving
the orcamento mapping unchanged so permission-only flows avoid fetching the
relation.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 32d6f8e and 9b0ad44.

📒 Files selected for processing (5)
  • backend/prisma/manual-copy/0056-atualiza-meta-orcamento-consolidado.pgsql
  • backend/prisma/migrations/20260226121720_meta_orcamento_consolidado/migration.sql
  • backend/prisma/schema.prisma
  • backend/src/meta/entities/meta.entity.ts
  • backend/src/meta/meta.service.ts

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
backend/prisma/manual-copy/0056-atualiza-meta-orcamento-consolidado.pgsql (2)

263-323: Consider extracting shared meta resolution logic.

The trigger functions tg_orcamento_planejado_refresh_consolidado and tg_orcamento_realizado_refresh_consolidado share identical meta_id resolution logic. Consider extracting this into a helper function to reduce duplication:

CREATE OR REPLACE FUNCTION f_resolve_meta_id_from_budget(
    p_meta_id INT, p_iniciativa_id INT, p_atividade_id INT
) RETURNS INT AS $$
...

This is a nice-to-have improvement and can be deferred.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/prisma/manual-copy/0056-atualiza-meta-orcamento-consolidado.pgsql`
around lines 263 - 323, Extract the repeated meta_id resolution into a new
function named f_resolve_meta_id_from_budget(p_meta_id INT, p_iniciativa_id INT,
p_atividade_id INT) RETURNS INT that returns the resolved meta_id (use the same
logic: return p_meta_id if not null, otherwise lookup iniciativa.meta_id by
p_iniciativa_id, otherwise join atividade->iniciativa to get meta_id by
p_atividade_id). Replace the inline resolution blocks in
tg_orcamento_realizado_refresh_consolidado (both NEW and OLD resolution and
v_meta_id/v_old_meta_id assignments) and the equivalent blocks in
tg_orcamento_planejado_refresh_consolidado to call
f_resolve_meta_id_from_budget(NEW.meta_id, NEW.iniciativa_id, NEW.atividade_id)
and f_resolve_meta_id_from_budget(OLD.meta_id, OLD.iniciativa_id,
OLD.atividade_id) respectively, keeping the same conditional calls to
f_refresh_meta_orcamento_consolidado and the UPDATE comparison logic.

256-260: Row-level triggers may cause performance issues during bulk operations.

These FOR EACH ROW triggers will call f_refresh_meta_orcamento_consolidado for every affected row. During bulk inserts/updates (e.g., batch imports), this results in redundant recalculations for the same meta_id.

Consider whether bulk operations on these tables are common. If so, you might want to:

  1. Add a mechanism to temporarily disable triggers during bulk operations
  2. Or implement a deferred/batched approach using a queue table
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/prisma/manual-copy/0056-atualiza-meta-orcamento-consolidado.pgsql`
around lines 256 - 260, The FOR EACH ROW trigger
tg_orcamento_planejado_refresh_consolidado on table orcamento_planejado calls
f_refresh_meta_orcamento_consolidado for every row and will cause redundant work
in bulk operations; to fix, either convert to a FOR EACH STATEMENT trigger (so
the function runs once per statement) or implement a two-step batched approach:
change the trigger to collect distinct meta_id values into a queue table (e.g.,
refresh_meta_queue) from tg_orcamento_planejado_refresh_consolidado and create a
separate worker/function that processes distinct meta_id entries and calls
f_refresh_meta_orcamento_consolidado, or document adding ALTER TABLE ... DISABLE
TRIGGER for controlled bulk loads — update trigger definition and related logic
accordingly to avoid per-row recalculation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/prisma/manual-copy/0056-atualiza-meta-orcamento-consolidado.pgsql`:
- Around line 12-14: Update the misleading inline comment near the code that
concatenates array elements into codigo: the comment currently says "índices 5 e
6" but the code uses partes[6] and partes[7], so change the comment to "índices
6 e 7" (or otherwise reword to state they refer to the 6th and 7th elements) to
accurately reflect the PostgreSQL 1-based array indices used by the partes ->
codigo concatenation.

---

Nitpick comments:
In `@backend/prisma/manual-copy/0056-atualiza-meta-orcamento-consolidado.pgsql`:
- Around line 263-323: Extract the repeated meta_id resolution into a new
function named f_resolve_meta_id_from_budget(p_meta_id INT, p_iniciativa_id INT,
p_atividade_id INT) RETURNS INT that returns the resolved meta_id (use the same
logic: return p_meta_id if not null, otherwise lookup iniciativa.meta_id by
p_iniciativa_id, otherwise join atividade->iniciativa to get meta_id by
p_atividade_id). Replace the inline resolution blocks in
tg_orcamento_realizado_refresh_consolidado (both NEW and OLD resolution and
v_meta_id/v_old_meta_id assignments) and the equivalent blocks in
tg_orcamento_planejado_refresh_consolidado to call
f_resolve_meta_id_from_budget(NEW.meta_id, NEW.iniciativa_id, NEW.atividade_id)
and f_resolve_meta_id_from_budget(OLD.meta_id, OLD.iniciativa_id,
OLD.atividade_id) respectively, keeping the same conditional calls to
f_refresh_meta_orcamento_consolidado and the UPDATE comparison logic.
- Around line 256-260: The FOR EACH ROW trigger
tg_orcamento_planejado_refresh_consolidado on table orcamento_planejado calls
f_refresh_meta_orcamento_consolidado for every row and will cause redundant work
in bulk operations; to fix, either convert to a FOR EACH STATEMENT trigger (so
the function runs once per statement) or implement a two-step batched approach:
change the trigger to collect distinct meta_id values into a queue table (e.g.,
refresh_meta_queue) from tg_orcamento_planejado_refresh_consolidado and create a
separate worker/function that processes distinct meta_id entries and calls
f_refresh_meta_orcamento_consolidado, or document adding ALTER TABLE ... DISABLE
TRIGGER for controlled bulk loads — update trigger definition and related logic
accordingly to avoid per-row recalculation.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9b0ad44 and 7cd0442.

📒 Files selected for processing (1)
  • backend/prisma/manual-copy/0056-atualiza-meta-orcamento-consolidado.pgsql

…om fila e deduplicação para recálculo

Inclui procedure e função PL/pgSQL para enfileirar tarefas de recálculo da meta orcamento consolidado com deduplicação por txid, atualiza triggers para usar essa fila, adiciona suporte no schema Prisma, cria módulo, serviço e DTO no backend para executar a tarefa de forma resiliente com retries, e integra o novo serviço ao sistema de tasks existente. Isso melhora a escalabilidade e evita execuções redundantes do recálculo, garantindo maior eficiência e consistência.
@renatocron
Copy link
Contributor

Como tem a importação do orçamento, achei importante mover pra um refresh async

@sonarqubecloud
Copy link

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/prisma/manual-copy/0056-atualiza-meta-orcamento-consolidado.pgsql`:
- Around line 198-205: The NOT EXISTS dedup check in the task_queue insertion
uses an unnecessary criado_em = now() predicate; remove the criado_em = now()
conjunct so the check relies solely on "type" =
'refresh_meta_orcamento_consolidado', status = 'pending',
(params->>'meta_id')::INTEGER = p_meta_id and (params->>'current_txid')::bigint
= current_txid; update the same pattern wherever it appears (e.g. the similar
checks in 0031-trigger.meta.consolidado.pgsql and
0039-trigger.transferencia.consolidado.pgsql) to avoid coupling deduplication to
the timestamp.

In
`@backend/src/task/refresh_meta_orcamento_consolidado/refresh-meta-orcamento-consolidado.service.ts`:
- Around line 19-25: The UPDATE that marks duplicate tasks as completed must
also set the completion timestamp to keep audit consistency; in the method in
refresh-meta-orcamento-consolidado.service.ts where the raw query runs (using
task.id and inputParams.meta_id) update the SQL to include terminou_em = now()
(or the DB-equivalent timestamp function) alongside status='completed' and
output so duplicated rows get a termination time; ensure the same parameter
interpolation ( ${task.id}, ${inputParams.meta_id} ) is preserved.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7cd0442 and 0db06f3.

📒 Files selected for processing (8)
  • backend/prisma/manual-copy/0056-atualiza-meta-orcamento-consolidado.pgsql
  • backend/prisma/schema.prisma
  • backend/src/task/refresh_meta_orcamento_consolidado/dto/create-refresh-meta-orcamento-consolidado.dto.ts
  • backend/src/task/refresh_meta_orcamento_consolidado/refresh-meta-orcamento-consolidado.module.ts
  • backend/src/task/refresh_meta_orcamento_consolidado/refresh-meta-orcamento-consolidado.service.ts
  • backend/src/task/task.module.ts
  • backend/src/task/task.parseParams.ts
  • backend/src/task/task.service.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants