Files
sar-android/_bmad-output/implementation-artifacts/1-2-sincronizacao-da-taxa-de-acrescimo-do-erp.md
Julio Schlickmann dc61705c91 add project files
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-16 22:33:42 -03:00

13 KiB

Story 1.2: Sincronização da Taxa de Acréscimo do ERP

Status: done

Story

Como representante de vendas, quero que a taxa de acréscimo de cada forma de pagamento seja sincronizada do ERP para o app durante a comunicação, para que os cálculos de acréscimo usem sempre os valores atualizados do servidor.

Acceptance Criteria

  1. Dado que gestao.formapag no PostgreSQL possui a coluna acresc com valores preenchidos Quando a ComunicaActivity executar o sync de formas de pagamento Então o valor de acresc é gravado em formapag.tx_acrescimo no SQLite para cada forma de pagamento

  2. Dado que gestao.formapag no PostgreSQL não possui a coluna acresc (schema antigo) Quando o sync de formas de pagamento for executado Então a comunicação continua sem erro e tx_acrescimo permanece com o valor anterior (ou 0)

  3. Dado que o VO FormaPagamento é carregado após o sync Quando FormaPagamentoDB preencher o objeto Então o campo tx_acrescimo está acessível no VO, com valor 0.0 quando NULL no banco

Tasks / Subtasks

  • Task 1: Atualizar FormaPagamentoPGSQL.selectAll() para ler acresc do PostgreSQL (AC: 1, 2, 3)
    • 1.1 - Refatorar selectAll() em dois métodos privados para suportar fallback:
      • Criar private List<FormaPagamento> executaSelectAll(Date ultAtualizacao, boolean comAcresc) throws Exception
      • O método usa comAcresc para decidir se inclui coalesce(acresc, 0.0) as acresc no SELECT (coluna 10)
      • Quando comAcresc = true: adicionar , coalesce(acresc, 0.0) as acresc ao final da lista de colunas e ler rs.getDouble(10)setTxAcrescimo()
      • Quando comAcresc = false: não adicionar a coluna; chamar forPag.setTxAcrescimo(0.0) explicitamente
    • 1.2 - Alterar selectAll() público para chamar executaSelectAll(ultAtualizacao, true) envolvido em try/catch:
      public List<FormaPagamento> selectAll(Date ultAtualizacao) throws Exception {
          try {
              return executaSelectAll(ultAtualizacao, true);
          } catch (Exception e) {
              Log.w("FormaPagamentoPGSQL", "Coluna acresc ausente no servidor, usando 0.0: " + e.getMessage());
              return executaSelectAll(ultAtualizacao, false);
          }
      }
      
    • 1.3 - Verificar que FormaPagamentoDB.insert() e update() já persistem tx_acrescimo (implementados na Story 1.1 — confirmado: linhas 68, 79, 100)

Review Findings (2026-04-16)

  • [Review][Patch] Catch muito abrangente: catch (Exception e) deveria ser catch (SQLException e) para não mascarar falhas reais de rede/autenticacao como "coluna ausente" [postgres/FormaPagamentoPGSQL.java:24] — corrigido
  • [Review][Defer] Resource leak: PreparedStatement/ResultSet nao fechados em bloco finally [postgres/FormaPagamentoPGSQL.java:45-68] — deferred, pre-existing
  • [Review][Defer] SQL injection via concatenacao de strings no WHERE (pre-existente em toda a classe) [postgres/FormaPagamentoPGSQL.java] — deferred, pre-existing
  • [Review][Defer] coalesce(libera_credito) sem argumento padrao e no-op (nao protege contra NULL) [postgres/FormaPagamentoPGSQL.java:35] — deferred, pre-existing
  • [Review][Defer] setDescontoPerc le coluna decimal como getInt, truncando frações [postgres/FormaPagamentoPGSQL.java:56] — deferred, pre-existing
  • [Review][Defer] Chave mal colocada em AtualizaDados.atualizaFormaPag: inativaAll executa em toda chamada, nao so quando ultAtualizacao == null [comunicacao/AtualizaDados.java:377-379] — deferred, pre-existing

Dev Notes

Escopo desta história

Esta história cobre EXCLUSIVAMENTE a leitura de gestao.formapag.acresc no PostgreSQL e o mapeamento para FormaPagamento.txAcrescimo no VO durante o sync.

  • Um único arquivo a modificar: FormaPagamentoPGSQL.java
  • Toda a cadeia downstream (AtualizaDados.atualizaFormaPagFormaPagamentoDB.salvarinsert/update) já suporta txAcrescimo corretamente desde a Story 1.1 — não alterar
  • Cálculo de acréscimo na UI e persistência no pedido são escopo do Epic 2

Estado atual verificado de FormaPagamentoPGSQL.java

O método selectAll() atual (linha 22) retorna 9 colunas e não lê acresc:

// SELECT atual (linha 24-26):
sql.append("SELECT id_formapag, codigo,");
sql.append(" descr, ativa, numparc, desco, md5(descr || ativa || numparc || desco || vl_ped_minimo || libera_credito),");
sql.append(" coalesce(vl_ped_minimo,0.00) as vl_ped_minimo, coalesce(libera_credito) as libera_credito");

// Mapeamento atual (linhas 38-46): 9 colunas, sem leitura de acresc
// forPag.setTxAcrescimo() NUNCA é chamado — sempre fica 0.0 (padrão do double)

Estado atual verificado de AtualizaDados.java (linha 367-382)

private void atualizaFormaPag(Date ultAtualizacao) throws Exception {
    FormaPagamentoPGSQL forPagPG = new FormaPagamentoPGSQL(conn);
    FormaPagamentoDB forPagtoDB = new FormaPagamentoDB(comunica);
    List<FormaPagamento> forPagtosPG = forPagPG.selectAll(ultAtualizacao);  // ← apenas esta chamada
    // ...
    forPagtoDB.salvar(context, forPagtosPG);
}

Nenhuma alteração necessária em AtualizaDados.java.

Estado atual verificado de FormaPagamentoDB.java (já implementado em Story 1.1)

insert() (linha 68-79) e update() (linhas 88-105) já incluem tx_acrescimo. Confirmar sem alterar.

Implementação completa esperada de FormaPagamentoPGSQL.java

public List<FormaPagamento> selectAll(Date ultAtualizacao) throws Exception {
    try {
        return executaSelectAll(ultAtualizacao, true);
    } catch (Exception e) {
        Log.w("FormaPagamentoPGSQL", "Coluna acresc ausente no servidor, usando 0.0: " + e.getMessage());
        return executaSelectAll(ultAtualizacao, false);
    }
}

private List<FormaPagamento> executaSelectAll(Date ultAtualizacao, boolean comAcresc) throws Exception {
    List<FormaPagamento> formaPagtos = new ArrayList<FormaPagamento>();
    StringBuilder sql = new StringBuilder("SELECT id_formapag, codigo,");
    sql.append(" descr, ativa, numparc, desco, md5(descr || ativa || numparc || desco || vl_ped_minimo || libera_credito),");
    sql.append(" coalesce(vl_ped_minimo,0.00) as vl_ped_minimo, coalesce(libera_credito) as libera_credito");
    if (comAcresc) {
        sql.append(", coalesce(acresc, 0.0) as acresc");
    }
    sql.append(" FROM gestao.formapag");
    sql.append(" WHERE id_empresa=" + Global.getEmpresa().getIdMatriz());
    sql.append("   AND ativa = 1 AND integrar_sar=1");
    if (ultAtualizacao != null)
        sql.append(" AND dt_atual >='" + Util.formatDateDB(ultAtualizacao) + "'");
    Log.i("SQL FORMA DE PAGAMENTO", sql.toString());
    PreparedStatement st = conn.prepareStatement(sql.toString());
    ResultSet rs = st.executeQuery();
    while (rs.next()) {
        FormaPagamento forPag = new FormaPagamento();
        forPag.setId(0);
        forPag.setIdErp(rs.getInt(1));
        forPag.setCodigo(rs.getInt(2));
        forPag.setDescricao(rs.getString(3));
        forPag.setAtivo(rs.getInt(4) == 1);
        forPag.setParcelas(rs.getInt(5));
        forPag.setDescontoPerc(rs.getInt(6));
        forPag.setMd5(Util.corrigeString(rs.getString(7)));
        forPag.setVlPedMin(rs.getDouble(8));
        forPag.setLiberaCredito(rs.getInt(9) == 1);
        if (comAcresc) {
            forPag.setTxAcrescimo(rs.getDouble(10));
        } else {
            forPag.setTxAcrescimo(0.0);
        }
        formaPagtos.add(forPag);
    }
    rs.close();
    st.close();
    return formaPagtos;
}

Regras críticas do projeto

  • Sem testes automatizados — validação é manual via dispositivo/emulador. Não criar arquivos de teste.
  • Sem Kotlin — somente Java puro
  • Sem Gradle — projeto Eclipse ADT, não criar build.gradle
  • JDBC sempre em thread backgroundexecutaSelectAll() é chamado de dentro de AtualizaDados que já roda em thread separada; não há alteração necessária
  • Sem JARs novos — implementação usa apenas java.sql.* já disponível
  • acresc pode ser NULL no PostgreSQL — usar coalesce(acresc, 0.0) na query para tratar no lado do servidor quando a coluna existe
  • acresc pode não existir no schema — tratar via try/catch (NFR5): nunca interromper a comunicação por coluna ausente
  • Conexão JDBC (conn) já existe e é passada no construtor — não criar nova conexão
  • Strings com acentos em código Java são proibidas — os logs usam apenas ASCII

Por que try/catch em vez de coalesce

coalesce(acresc, 0.0) trata NULL mas não trata coluna ausente — se acresc não existir no schema PostgreSQL, o conn.prepareStatement() lança SQLException (column not found). O try/catch captura esse erro e reexecuta sem a coluna, garantindo NFR5 sem interromper a comunicação.

Sincronização incremental e MD5

O MD5 computado no PostgreSQL (md5(descr || ativa || numparc || desco || vl_ped_minimo || libera_credito)) não inclui acresc. Isso é intencional: a mudança de acresc no ERP normalmente atualiza dt_atual na tabela, fazendo o registro aparecer no sync incremental (dt_atual >= ultAtualizacao). Para syncs totais (ultAtualizacao = null), todos os registros são atualizados. Não alterar o MD5.

Arquivos a modificar

Arquivo Caminho O que muda
FormaPagamentoPGSQL.java src/br/com/jcsinformatica/sarandroid/postgres/ selectAll() refatorado + executaSelectAll() privado com flag comAcresc

NÃO modificar nesta história:

  • AtualizaDados.java — sem mudança necessária
  • ComunicaActivity.java — sem mudança necessária
  • FormaPagamentoDB.java — já atualizado na Story 1.1
  • FormaPagamento.java (VO) — já atualizado na Story 1.1
  • Qualquer Activity ou layout — escopo do Epic 2

Verificação manual após implementação

  1. Com coluna acresc: executar sync com servidor que possui gestao.formapag.acresc → verificar em SQLite que formapag.tx_acrescimo recebe o valor correto
  2. Sem coluna acresc: executar sync com servidor que não possui a coluna → verificar no log "Coluna acresc ausente no servidor" e que a comunicação completa sem erro
  3. acresc = NULL: verificar que formas de pagamento com acresc = NULL recebem tx_acrescimo = 0.0 (via coalesce)

Project Structure Notes

  • Estrutura Eclipse ADT: código em src/, pacote br.com.jcsinformatica.sarandroid
  • DAOs PostgreSQL: src/br/com/jcsinformatica/sarandroid/postgres/
  • Padrão de sync: *PGSQL.java lê do servidor → VO → *DB.java persiste no SQLite

References

  • [Source: _bmad-output/project-context.md#Padrão Dual-Banco] — ciclo JDBC, ConnectionManager, sync pattern
  • [Source: _bmad-output/project-context.md#Regras Críticas] — proibições absolutas
  • [Source: _bmad-output/planning-artifacts/epics.md#Story 1.2] — ACs e requisitos FR1, FR2, NFR5, NFR6
  • [Source: _bmad-output/planning-artifacts/prd.md#Sincronização de Dados] — FR1, FR2
  • [Source: _bmad-output/planning-artifacts/prd.md#NonFunctional Requirements] — NFR5, NFR6
  • [Source: _bmad-output/implementation-artifacts/1-1-migracao-do-schema-sqlite-para-suporte-a-acrescimo.md] — Story 1.1 completa; FormaPagamentoDB.insert/update já persistem tx_acrescimo; mapeamento PostgreSQL→SQLite documentado
  • [Source: src/br/com/jcsinformatica/sarandroid/postgres/FormaPagamentoPGSQL.java] — estado atual linha 22-53: 9 colunas, sem acresc
  • [Source: src/br/com/jcsinformatica/sarandroid/comunicacao/AtualizaDados.java:367] — atualizaFormaPag() chama selectAll() e salvar()
  • [Source: src/br/com/jcsinformatica/sarandroid/database/FormaPagamentoDB.java:63-105] — insert/update já incluem tx_acrescimo (Story 1.1)

Dev Agent Record

Agent Model Used

claude-sonnet-4-6 (dev-story workflow)

Debug Log References

Completion Notes List

  • Story 1.2 implementada em 2026-04-16.
  • FormaPagamentoPGSQL.selectAll() refatorado: método público agora delega para executaSelectAll(ultAtualizacao, true) com try/catch que faz fallback para executaSelectAll(ultAtualizacao, false) em caso de coluna acresc ausente no servidor.
  • executaSelectAll(Date, boolean) privado: quando comAcresc=true adiciona , coalesce(acresc, 0.0) as acresc ao SELECT e lê rs.getDouble(10)setTxAcrescimo(); quando comAcresc=false chama setTxAcrescimo(0.0) explicitamente.
  • FormaPagamentoDB.insert() e update() confirmados: ambos ja persistem tx_acrescimo desde a Story 1.1 — nenhuma alteracao necessaria.
  • AtualizaDados.atualizaFormaPag() confirmado: sem alteracao necessaria — fluxo selectAll()salvar() e transparente a esta mudanca.
  • Sem testes automatizados (projeto nao possui infraestrutura de testes). Validacao e manual via dispositivo/emulador.
  • NFR5 satisfeito: try/catch captura Exception ao preparar/executar o SELECT com acresc; comunicacao nao e interrompida em schemas antigos.
  • NFR6 satisfeito: coalesce(acresc, 0.0) garante que NULL e tratado como 0.0 no servidor antes de chegar ao VO.

File List

  • src/br/com/jcsinformatica/sarandroid/postgres/FormaPagamentoPGSQL.java