Conversation
Porta o app Bling ERP (app_id 102418) do repositório app-bling-erp-v2 para
o monorepo, usando a API v3 do Bling: exportação de pedidos e produtos,
importação de estoque, pedidos e categorias, e renovação automática dos
tokens OAuth.
Funções: `blingerp-onStoreEvent` (eventos da loja), `blingerp-callback`
(callbacks de estoque/pedidos do Bling), `blingerp-authCallback` (fluxo de
autorização OAuth) e `blingerp-cronRefreshToken`.
A fila do app v1 em Firestore (`queue/{storeId}/events` + `running_events`)
foi substituída pelo PubSub de eventos do monorepo, e o `appSdk` multi-loja
pelo `@cloudcommerce/api`. Tokens ficam em `blingTokens/{storeId}` e o cache
de situações de venda em `blingStatuses/{storeId}`.
Correções sobre o comportamento do app v1:
- atualização de produto com variações falhava com 400 no Bling, porque as
variações eram enviadas sem ID (a listagem `/produtos?codigo=` devolve o
produto resumido);
- preço por variação era perdido na exportação (o Bling aplica o preço do
produto pai), agora corrigido com PUT por variação divergente;
- callback de estoque de variação sem SKU no Bling era descartado, agora usa
o ID do Bling como referência;
- configuração "Importar produto" não tinha efeito, pois o callback forçava
`canCreateNew: false`;
- status "Devolvido" era enviado como fulfillment inválido;
- limite diário da API gravava a flag invertida, liberando novas chamadas;
- grades de variação importadas viram `size`/`age_group`/`gender` como no
sentido inverso, em vez de slug do rótulo;
- sem situação correspondente no Bling, o pedido não falha mais: registra
aviso e segue exportado.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Erros em exportações disparadas por evento da loja (não pela fila manual) só apareciam no log do Cloud Functions, ficando invisíveis para o lojista no painel. Sucessos de importação continuam fora do log para não inundá-lo. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
🤖 Revisão adversarial —
|
Pedido devolvido era enviado ao Bling como "aprovado", então o estoque não retornava e a nota fiscal não era cancelada; agora vai como "cancelado", no mesmo padrão do tiny-erp. O callback público aceitava requisições sem token quando nenhum estava configurado, permitindo importação forjada de pedidos e produtos na loja; agora exige token e rejeita quando não há nenhum configurado. Inclui testes de regressão para os dois casos. O round-trip que regride "entregue" para "nf emitida" em contas Bling padrão fica marcado como todo, pois o conserto pertence ao import. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Um refresh concorrente (cron e callback ao mesmo tempo) fazia o perdedor da corrida receber invalid_grant e gravar isBloqued, desativando a integração da loja até re-autorização manual, mesmo tendo havido um refresh bem-sucedido ao lado. O Bling rotaciona o refresh_token a cada uso, então essa corrida é esperada. Agora, ao falhar, o doc é relido e o token renovado por outro processo é reusado; só bloqueia em invalid_grant genuíno sem refresh concorrente. A contagem de erros transitórios passa a usar FieldValue.increment, evitando a corrida de read-then-set. A decisão fica isolada num módulo puro, com testes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contas Bling padrão não têm situações de envio/entrega, então "enviado" e "entregue" colapsam em "Atendido", que volta como nf emitida. O pedido regredia de "entregue" para "nf emitida" a cada importação. Agora o import ignora a transição para trás dentro da esteira de fulfillment. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A exportação comparava a quantidade da loja com saldoVirtualTotal (virtual, somado de todos os depósitos), mas ajusta o saldo físico e a importação lê o saldo do depósito configurado. Em lojas com reserva ou múltiplos depósitos isso movimentava o estoque a cada exportação ou deixava de corrigir o físico. Agora compara contra o saldo físico do depósito usado, a mesma base do import. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adiciona um job que roda `pnpm install --frozen-lockfile` em PRs que mexem em qualquer package.json ou no lock. Hoje o CI instala com --no-frozen-lockfile e mascara um lock desatualizado; este check falha em vez de regenerar em silêncio. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…urado O fail-closed anterior rejeitava toda loja que nunca configurou callback_token (campo opcional, não auto-gerado). Como o corpo do callback só traz identificadores e os handlers re-buscam o dado no Bling autenticado, o risco de um callback forjado é apenas disparar importação dos próprios dados da loja (sem injeção). Não justifica derrubar lojas em produção, então volta ao comportamento anterior: exige token apenas quando a loja configurou um. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A exportação comparava o estoque sempre pelo saldo físico, mas a importação usa o saldo virtual quando a loja tem reserva de estoque (has_stock_reserve). Lojas com reserva divergiam em toda exportação, sobrescrevendo o físico do Bling com o virtual. Extrai parseStockFromDeposits para um helper único usado pelos dois lados, garantindo a mesma base (virtual/físico e soma por depósito). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…estore A releitura do doc de tokens no tratamento de erro do refresh não tinha catch: uma falha do Firestore substituiria o erro original e pularia a gravação de estado. Envolve em catch devolvendo undefined, preservando a decisão. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
🔄 Status atualizado — fixes aplicados + re-review adversarial do deltaSeguindo a revisão adversarial acima, os 6 Criticals foram tratados e, depois, rodei um segundo review adversarial focado só nos commits de fix (para pegar regressão que o próprio fix pudesse introduzir — o autor tem ponto cego sobre o próprio código). Esse re-review pegou 2 regressões nos meus fixes e corrigiu um exagero do review original — tudo já remediado. Estado verificado abaixo. Placar final dos Criticals
O que o re-review encontrou (e como foi resolvido)
Pendências (não-Critical)
VerificaçãoTodos os fixes verificados com build real ( Fixes e re-review gerados com Claude Code (Opus). O re-review do delta rodou 3 agentes adversariais sobre os commits de fix — pegou C6 e C2 antes do merge. |
Porta o app Bling ERP (
app_id102418) do repositório app-bling-erp-v2 para o monorepo, usando a API v3 do Bling.Funções
blingerp-onStoreEventapplications-dataSetblingerp-callbackblingerp-authCallbackcodedo fluxo OAuth e grava os tokensblingerp-cronRefreshTokenaccess_tokenantes de expirarMudanças de arquitetura em relação ao app v1
queue/{storeId}/events+running_events+handle-queue) deu lugar ao PubSub de eventos do monorepo (maxInstances: 1) com a fila emdatado app;appSdkmulti-loja substituído por@cloudcommerce/apicom as credenciais da própria loja;blingTokens/{storeId}e cache das situações de venda emblingStatuses/{storeId}, no projeto Firebase da loja;products/skus:{sku}no lugar do ElasticSearch.Correções sobre o comportamento do v1
Encontradas ao portar e ao validar contra a API real:
/produtos?codigo=devolve o produto resumido, semvariacoes, então oPUTia sem os IDs e o Bling rejeitava como se fossem novas variações;PUT /produtos/{idVariacao}apenas para as divergentes;canCreateNew: false;fulfillment_statusinválido;other_configera lido comoouther_config(typo), então o tipo de contato nunca era aplicado;quantity), causando lançamento redundante a cada exportação;Grades de variação importadas passam a mapear para
size/age_group/gender(antes sóCorera normalizada), mantendo o round-trip estável com a exportação.Testes
packages/apps/bling-erp/tests/— 37 testes comnode --test, offline, sem credenciais: pedido e produto nos dois sentidos, mapeamento de status (incluindoparse_statuscustomizado), endereço/CEP, parcelamento, prazo de entrega com dias úteis e feriados, variações sem SKU e normalização de grades.scripts/bling-smoke.mjsfaz uma varredura read-only na API do Bling validando credenciais e todos os endpoints usados.Validação em produção
Loja de teste (1011) + conta Bling de teste, com as funções deployadas em um projeto Firebase real:
blingerp-authCallback→ tokens no Firestore;blingerp-onStoreEvent→ pedido criado no Bling com contato, item vinculado, frete, etiqueta e parcela;delivered→ "Atendido") e round-trip de status;blingerp-cronRefreshTokenexecutando e validando o token.Notas
admin_settings) continua no repositórioapp-bling-erp-v2; este pacote traz apenas o runtime;ignore_triggersnas configurações do app para o app central parar de processá-la;pnpm-lock.yamlnão foi atualizado neste PR — o CI instala com--no-frozen-lockfile.🤖 Generated with Claude Code