Files
sar-android/docs/architecture.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

7.8 KiB

Arquitetura — SARAndroid

Resumo Executivo

SAR Android (Sistema de Atendimento ao Representante) é um app Android legado em Java para representantes comerciais. Permite gerenciar clientes, produtos e pedidos completamente offline, sincronizando periodicamente com um servidor PostgreSQL via JDBC direto. O app opera em modo offline-first: toda interação do usuário usa SQLite local; a sincronização com o servidor é explicitamente iniciada pelo usuário.


Stack de Tecnologia

Camada Tecnologia Versão
Linguagem Java (sem Kotlin)
Plataforma Android Min SDK 19 / Target SDK 35
Build Eclipse ADT pré-Gradle
Banco local SQLite via SQLiteOpenHelper schema v40
Banco remoto PostgreSQL via JDBC direto 8.x
Driver JDBC postgresql-8.2-512.jdbc3.jar 8.2 JDBC3 (fixo)
Data/Hora Joda-Time 2.5
FTP Apache Commons Net 3.3
UI compat android.support.v4 (support library legada)

Padrão Arquitetural: Offline-First com Dual-Database

┌─────────────────────────────────────────────┐
│                 DISPOSITIVO                  │
│                                              │
│  Activities / Fragments                      │
│       ↕ (UI Thread)                          │
│  Value Objects (vo/)                         │
│       ↕                                      │
│  DAOs SQLite (*DB.java / *BD.java)           │
│       ↕                                      │
│  SQLite Local (jcsinformatica.sar v40)        │
│                                              │
└──────────────────────┬──────────────────────┘
                       │ ComunicaActivity
                       │ (sync explícita, background thread)
                       ↓
┌─────────────────────────────────────────────┐
│               SERVIDOR                       │
│                                              │
│  DAOs PostgreSQL (*PGSQL.java)               │
│       ↕                                      │
│  ConnectionManager (JDBC, timeout 20s)       │
│       ↕                                      │
│  PostgreSQL (ERP central)                    │
│                                              │
└─────────────────────────────────────────────┘

Fluxo de Entrada

SplashScreen
    └→ LoginActivity          (valida senha local, carrega Empresa no Global)
          ├→ ComunicaActivity  (se última sync > 7 dias → força sync total)
          └→ MainActivity      (menu expandable)
                ├→ Pedidos
                │     ├→ UpdatePedidoActivity   (criar/editar pedido)
                │     │     ├── FlexPedidoFragment
                │     │     ├── ItensPedidoFragment
                │     │     │     └→ UpdatePedItemActivity (editar item)
                │     │     └── TotalPedidoFragment
                │     └→ BrowsePedido            (listar pedidos)
                ├→ Produtos
                │     ├→ BrowseProduto
                │     ├→ UpdateProduto
                │     └→ FotosProduto
                ├→ Clientes
                │     ├→ BrowseCliente
                │     ├→ UpdateCliente
                │     └→ BrowseCTR              (contas a receber)
                ├→ Consulta
                │     ├→ BrowsePedidoConsulta
                │     └→ ConsultaVendasActivity
                └→ Comunicação
                      └→ ComunicaActivity        (sync manual)

Classes Centrais

Global (singleton estático)

Mantém o estado de runtime da sessão:

  • Global.empresaEmpresa ativa (inclui Representante, configs de conexão)
  • Global.pedidoPedido em edição (null fora do contexto de pedido)
  • Global.pedItemItemPedido em edição

⚠️ Global.getEmpresa() lança WarningException se empresa == null. Sempre use try/catch.

GlobalActivity (base Activity pós-login)

Global.getEmpresa() no onCreate() e configura o título da tela. Toda Activity pós-login deve estender GlobalActivity.

GlobalActivityFragment (base para Activities com Fragments)

Estende FragmentActivity da support library v4. Usada por UpdatePedidoActivity.

DatabaseHelper (SQLiteOpenHelper)

  • DB name: jcsinformatica.sar
  • Versão atual: 40
  • PRAGMA foreign_keys = ON ativado em onOpen()
  • onUpgrade() com guards if (oldVersion < N) para cada versão

ConnectionManager (JDBC)

  • getConnection(Context, Config) — cria conexão PostgreSQL com timeout 20s
  • closeAll(conn, stmt, rs) — sempre usar em finally

ComunicaActivity (orquestrador de sync)

  • Único ponto de sincronização com o servidor
  • Roda em Thread background (AtualizaDados)
  • Usa postUserFeedback() para atualizar progresso na UI
  • Mantém WakeLock durante a sync

Padrão DAO Dual

Cada entidade sincronizável tem dois DAOs:

Classe Banco Responsabilidade
*DB.java / *BD.java SQLite CRUD local + detecção de mudanças por MD5
*PGSQL.java PostgreSQL Leitura/escrita remota durante sync

Padrão de detecção de mudanças:

// No DAO SQLite (ex: ClienteDB)
SparseArray<String> arrayMd5 = selectIdMd5(db); // carrega id_erp → md5
for (Cliente c : clientesDoServidor) {
    String md5Local = arrayMd5.get(c.getIdErp());
    if (md5Local == null)       insert(c, db);   // novo
    else if (md5Local.equals(c.getMd5())) continue; // sem mudança
    else                        update(c, db);   // atualizado
}

Lógica de Negócio em Pedido.java

A classe Pedido contém lógica de negócio significativa (não apenas VO):

Método Descrição
calcTotal(context) Recalcula descontos, comissões e totais de todos os itens
calcComissao(context, item) Calcula comissão por item considerando desconto de rateio
calcIpi(context, item) Calcula IPI por item
calcIcmsSt(context, item) Calcula ICMS-ST por item (modal 5=pauta, MVA)
calcDescPauta(context) Aplica descontos de pauta por faixa de peso/volume
getValidaPedidoMinimo(context) Valida preço mínimo por produto
getTotalDesconto() Calcula e atribui vl_liquido em cada item

⚠️ calcTotal() tem efeito colateral: modifica os ItemPedido internos. Deve ser chamado antes de salvar o pedido.


Padrão de UI

  • ListView + SimpleArrayAdapter* customizado para todas as listas
  • ViewPager + Fragments para tela de pedido (UpdatePedidoActivity)
  • ExpandableListView para menu principal (MainActivity)
  • Buscas em Thread dedicada (ThreadBusca*.java)
  • Erros exibidos via Util.sendError(activity, exception) → AlertDialog

Geração de PDF

Util contém gerarPdf() que usa android.graphics.pdf.PdfDocument (API 19+) para gerar PDF do pedido e compartilhar via FileProvider.


Permissões

Permissão Uso
INTERNET JDBC PostgreSQL + FTP
ACCESS_NETWORK_STATE Verificar conectividade antes da sync
WRITE/READ_EXTERNAL_STORAGE Fotos de produtos e PDF
WAKE_LOCK Manter dispositivo ativo durante sync longa
VIBRATE Feedback ao concluir sync

Sem Testes Automatizados

O projeto não tem infraestrutura de testes. Não há test/ ou androidTest/. Validação é exclusivamente manual via dispositivo/emulador.