Skip to content

Integrações Contábeis (ERP)

Visão Geral

O módulo de contabilidade conecta o PopinaFlow a quatro sistemas ERP/contábeis brasileiros. A cada lançamento gerado (vendas, pagamentos, folha, etc.) o AccountingQueueProcessor enfileira o envio assíncrono ao ERP ativo do tenant via BullMQ.

ProvedorTipoAutenticaçãoMódulo cliente
OmieERP cloud BRapp_key + app_secret no bodyOmieClient
Conta AzulERP cloud BROAuth2 Bearer + auto-refreshContaAzulClient
SAP Business OneERP on-premiseSession cookie B1SESSION (Basic Auth login)SapClient
SPED ECDArquivo fiscalN/A — geração local/S3SpedClient

Localização

CamadaArquivo
Clientes HTTPbackend/src/accounting/providers/{omie,contaazul,sap,sped}.client.ts
Retry utilbackend/src/accounting/providers/retry.util.ts
Schema de credenciaisbackend/src/accounting/schemas/accounting-integration.schema.ts
Módulo de filabackend/src/accounting-queue/
View Adminfrontend-react/src/views/admin/accounting/AccountingIntegrationsView.tsx

Schema: AccountingIntegration

Um documento por (tenant, provider) — índice único composto.

CampoTipoDescrição
providerenumomie | contaazul | sap | sped
enabledbooleanIntegração ativa. Default false até configurar.
testModebooleanQuando true, usa stub CSV em vez de chamada real. Default true.
apiKeyEncryptedEncryptedFieldCredencial primária (app_key / access_token / username SAP) — AES-256-GCM
apiSecretEncryptedEncryptedFieldCredencial secundária (app_secret / refresh_token / password SAP)
baseUrlOverridestring | nullURL customizada. Obrigatório para SAP. Para SPED: caminho S3 ou filesystem.
lastSyncAtDateTimestamp do último envio com sucesso.
lastErrorstringMensagem do último erro (limpo na próxima sincronização com sucesso).

OmieClient

Endpoint: POST https://app.omie.com.br/api/v1/financas/lancamentos/ (call: IncluirLancamento)

Idempotência: campo cCodIntLanc com formato popinaflow-{tenantSlug}-{entryId}-{pairIndex}. O Omie de-dupes por esse campo dentro da mesma conta — sem suporte a idempotency header.

Mapeamento de lançamentos compostos: entradas N:M (N débitos × M créditos) são cross-pareadas — cada par é enviado como um lancamento separado com sufixo _D1C1, _D1C2, etc.

Mapeamento de tipo:

origin do JournalEntrycTipo Omie
sale, payment_received, card_receivableLCR (crédito)
expense, supplier_payment, payrollLCP (débito)
outrosADI

Limitação conhecida: o campo nCodCC (conta bancária Omie) é enviado como 0 — o contador precisa remapear na interface do Omie.

ContaAzulClient

Endpoint: POST https://api.contaazul.com/v1/financial-entries

Idempotência: header Idempotency-Key com popinaflow-{tenantSlug}-{entryId}-{pair} (truncado para 36 chars).

Refresh automático de token: se a chamada retorna 401, o cliente troca o refresh_token por um novo access_token via POST /auth/token e retenta uma vez. Se o refresh falhar, o erro é surfaceado para o operador reautorizar.

Mapeamento: cada par de linhas gera um financial-entry com date, description, reference (número do lançamento), amount, debit_account, credit_account.

SapClient

Endpoint: POST {baseUrl}/JournalEntries (SAP B1 Service Layer)

Sessão: o cliente faz POST {baseUrl}/Login com UserName, Password, CompanyDB → extrai B1SESSION do header Set-Cookie. A cookie é reutilizada por até 30 minutos. Em 401 o cliente re-autentica uma vez automaticamente.

Campo obrigatório: baseUrlOverride deve ser configurado (ex: https://192.168.1.100:50000/b1s/v1). Sem esse campo a chamada falha imediatamente.

SSL self-signed: para servidores SAP on-premise com certificado auto-assinado, defina ACCOUNTING_SAP_REJECT_UNAUTHORIZED=false no .env do backend.

Mapeamento de campos:

JournalEntrySAP JournalEntries
competenceDateReferenceDate, DueDate, TaxDate
description (100 chars)Memo
entryNumberReference1
lines[].accountCodeJournalEntryLines[].AccountCode
lines[].debitDebit
lines[].creditCredit
lines[].memoLineMemo

SpedClient

O SPED ECD não é uma API HTTP — gera um arquivo texto no formato da Receita Federal (Blocos 0, I, Z) para transmissão manual via PVA SPED Contábil.

Destinos de upload configurados via baseUrlOverride:

PrefixoComportamento
file:///var/spedSalva no filesystem do servidor
s3://meu-bucket/spedUpload para AWS S3 (via @aws-sdk/client-s3)
null / não configuradoRetorna o conteúdo em memória (para download manual)

Blocos gerados automaticamente: 0 (abertura + I050 plano de contas + 0990), I (I200 cabeçalho + I250 linhas + I990), Z (fechamento).

Blocos fora do escopo: Block J (balanço), assinatura digital ICP-Brasil, transmissão via PGE-SPED. O arquivo gerado é para revisão do contador antes da transmissão oficial.

retry.util.ts — Política de Retentativa Compartilhada

Todos os clientes usam retryWithBackoff():

ParâmetroValor
maxAttempts3
Delays1s → 2s → 4s (base-2 exponencial)
429 Too Many RequestsRespeita header Retry-After; se ausente usa backoff normal
4xx (exceto 429)Não-retryável — lança imediatamente
5xx / erros de redeRetryável até maxAttempts

Segurança de Credenciais

apiKeyEncrypted e apiSecretEncrypted são armazenados como EncryptedField (AES-256-GCM via TenantKmsService). Nunca são retornados em texto claro pela API — a interface exibe apenas **** para confirmar que foram configurados.

Testar a Conexão

Cada cliente expõe um método ping() que realiza uma chamada leve de validação:

ClienteChamada de ping
OmieClientPOST /geral/categorias/ com nPagina=1, nRegPorPagina=1
ContaAzulClientGET /v1/company
SapClientPOST /Login + POST /Logout imediato
SpedClientN/A — validação via generateAndSave() em modo dry-run

Resposta de sucesso: { ok: true, providerVersion: "..." }. Resposta de falha: { ok: false, error: "..." }.

Relacionados

Lançado sob a licença MIT.