Documentação — Integração SK - B2B Fabritech
Fonte: skpostfabritech
Analista: Jose Antonio
Visão Geral
Integrações entre o Protheus (tabelas ZK1, ZK2, PVF, SB1, etc.) e a plataforma B2B Fabritech (via API REST), trabalhando com:
- Envio de produtos (JSON) recebidos da VTEX para Fabritech.
- Envio de estoques por filial.
- Sinalização de alterações de preço e envio via PUT.
- Atualizações em lote nas tabelas de controle (
ZK1,ZK2).
O objetivo desta documentação é descrever cada função, explicar parâmetros, retornos, dependências e pontos de atenção — e também servir como estrutura para conversão em mindmap.
Estrutura e convenções
ZK1— tabela de produtos recebidos da VTEX.ZK2— tabela de estoques por produto/filial.PVF,SB1,SA2,ACV,ACU— tabelas do Protheus usadas nas consultas.- Convenção de status:
P= Pendente (para envio).I= Integrado (sucesso).F= Falha.
- Muitas funções usam
GetNextAlias()e consultas viaMPSysOpenQuery(...).
Índice
- SKEnvPrd
- EnviaLote
- PreparaAtualizacao
- AtuZK1Batch
- UpdateBatch
- AtuZK1Individual
- SKaltPrc
- ProcessaProdutoPreco
- PUTPRECO
- ParseOriginalJson
- GenProdJson
- GetManufInfo / GetProdGroup / GetManufName / GetLocCat
- StrSanitize / Implode / IsOracle
- GetPricesJ / GetPrcData / ProcPrcRecFull
- GetStockJs / GetStockData / ProcStockRec / GetStockQt
- SKCarZk2 / InsereZk2
- SKEnvEst / GenEstqJson / EnvLotEstq / AtuZK2Batch / UpdZK2Batch / AtuZK2Ind
- RETUFFIL
- Notas de qualidade, melhorias e erros comuns
- Mindmap (formato baseado em headings)
SKEnvPrd
Assinatura: User Function SKEnvPrd(nLoteSize, lTestMode)
Descrição curta: Varre a tabela ZK1 buscando produtos recebidos da VTEX (status 'P') e não enviados para a Fabritech, formata JSONs via GenProdJson, agrupa em lotes e envia via EnviaLote. Atualiza ZK1 em lote com resultados.
Parâmetros:
nLoteSize(opcional): tamanho máximo do lote. Aceita numérico ou string numérica. Default interno usado: 100 (ajusta para 50 se menor igual 0).lTestMode(opcional):.T.para simular (não envia).
Retorno: array [total_processado, sucesso_geral, lotes_enviados, detalhes_erros]
Passo a passo:
- Salva contexto/área atual (
GetArea()). - Ajusta
nMaxLotetratandonLoteSize. - Se necessário, chama
RpcSetEnv(...)para configurar ambiente. - Obtém token com
U_GetB2BTk()— se falhar, retorna erro. - Monta query para selecionar produtos em
ZK1comZK1_ATUALI = 'P'e não integrados (!= 'V').- Quando Oracle, reconstitui campos LONG/Lob (uses
UTL_RAW.CAST_TO_VARCHAR2(DBMS_LOB.SUBSTR(...))).
- Quando Oracle, reconstitui campos LONG/Lob (uses
- Para cada registro:
- Reconstroi JSON original (concatena pedaços em Oracle).
- Faz parse seguro com
ParseOriginalJson. - Valida mínimo:
RefIdeName. - Gera novo JSON com
GenProdJson. - Acumula JSONs e códigos em
aLote/aLoteCodes. - Quando lote atinge
nMaxLote, chamaEnviaLote(a menos quelTestMode), registra sucesso/falha emaDataviaPreparaAtualizacao. - Periodicamente chama
AtuZK1Batch(aData)quandoaDataatinge 100 itens.
- Ao final envia último lote (se existir) e faz última atualização em
ZK1. - Restaura ambiente e retorna resumo.
Pontos importantes / erros comuns:
- Depende de
U_GetB2BTk(); sem token o envio não ocorre. - JSONs muito grandes no Oracle são reconstruídos por múltiplos campos
Json1..Json99. lTestModeútil para debug (não chama web service).- Mensagens de log com
ConOut(...)para acompanhamento.
EnviaLote
Assinatura: Static Function EnviaLote(aLote, cToken, aErrors)
Descrição: Junta uma lista de JSONs (aLote) em um array JSON e faz envio via U_EnvLoteB2B("PRODUTOS", cJsonFinal, cToken) com até 3 tentativas. Registra erros em aErrors.
Parâmetros:
aLote— array de strings (JSONs).cToken— token de autenticação.aErrors— array passado por referência para armazenar mensagens de erro.
Retorno: .T. se sucesso.
Passos:
- Monta string
cJsonFinal = "[" + items + "]", validando que cada item seja texto (ValType == "C"). - Se problema na formação do JSON, adiciona erro em
aErrorse retorna.F.. - Loop de tentativas (1..3):
- Se tentativa > 1, renova token com
U_GetB2BTk()eSleep. - Chama
U_EnvLoteB2B. - Em caso de erro registra
TCSQLERROR()(ou mensagem desconhecida).
- Se tentativa > 1, renova token com
- Log de sucesso ou falha após 3 tentativas.
Observações:
- Reaproveita
U_EnvLoteB2B(função externa do código base). - Retentativas com pequeno backoff.
PreparaAtualizacao
Assinatura: Static Function PreparaAtualizacao(aLote, aData, lSuccess, aCodes)
Descrição: Para cada item do lote adiciona um registro em aData com o código, status (I ou F), data, hora e mensagem (em caso de erro). Usada para atualização em lote posterior.
Parâmetros:
aLote— array de JSONs (não usado diretamente além do loop).aData— array (referência) que será preenchido.lSuccess— status booleano do envio do lote.aCodes— array com códigos dos itens do lote.
Retorno: void (modifica aData por referência).
AtuZK1Batch
Assinatura: Static Function AtuZK1Batch(aData)
Descrição: Atualiza a tabela ZK1 em lotes, separando registros com sucesso e falha. Usa UpdateBatch para atualizações em lote e, em caso de falha, usa AtuZK1Individual.
Parâmetros: aData — array de arrays com formato [codigo, status, data, hora, msg].
Detalhes operacionais:
- Separa
aDataemaCodesI(sucesso) eaCodesF(falha). - Atualiza em lotes (
nBatchSize = 500) viaUpdateBatch. - Se
UpdateBatchfalhar tenta atualizar individualmente viaAtuZK1Individual.
UpdateBatch
Assinatura: Static Function UpdateBatch(cStatus, aCodes, nStart, nEnd, cData, cHora, cMsg)
Descrição: Monta e executa uma query SQL UPDATE ... WHERE ZK1_CODIGO IN (...) para atualizar vários códigos de uma só vez. Remove marcações de encoding [UTF-8] antes de executar.
Parâmetros importantes:
cStatus:'I'ou'F'.aCodes: array de códigos.nStart,nEnd: limites do sub-lote.cData,cHora: valores paraZK1_DTINTEeZK1_HRINTE.cMsg: mensagem de erro.
Retornos: .T. se sucesso.
Observações: Verifica retorno TCSQLEXEC(cQuery) < 0 para detectar erro e loga TCSQLERROR().
AtuZK1Individual
Assinatura: Static Function AtuZK1Individual(aData, cFilterStatus)
Descrição: Atualiza ZK1 um a um. Usada como fallback quando UpdateBatch falha.
Parâmetros:
aData: array com os dados.cFilterStatus: se informado, atualiza apenas registros com este status.
Observações: Faz TCSQLEXEC por registro e loga query (parcial) em caso de erro.
Utilitários: Implode, IsOracle, StrSanitize
Implode
Assinatura: Static Function Implode(cSeparator, aArray)
Concatena elementos de aArray com separador cSeparator. Retorna string.
StrSanitize
Remove aspas duplas, quebras de linha e faz AllTrim. Usada para preparar strings para JSON.
ParseOriginalJson
Assinatura: Static Function ParseOriginalJson(cJson)
Descrição: Recebe cJson (string) e retorna JsonObject() com fromJson(cJson); em caso de erro retorna Nil. Loga aviso/erro via ConOut.
Pontos críticos:
- Se o JSON estiver vazio ou for inválido retorna
Nil. - Em Oracle o JSON pode estar fragmentado em vários campos — reconstruído antes desta chamada.
GenProdJson
Assinatura: Static Function GenProdJson(oProd)
Descrição: Gera o JSON no formato esperado pela Fabritech a partir do objeto original oProd (parseado do JSON vindo da VTEX). Junta dados de fabricante, categorias, imagens, relacionamentos, preços e estoques.
Parâmetros: oProd — objeto JSON (tipo J).
Retorno: string JSON formatada (ou "" em caso de falha).
Lógica (resumida, passo a passo):
- Valida
oProd(ValType(oProd) == "J"). - Garante que
RefIdeNameexistam (fallback para""). - Obtém
oManuf := GetManufInfo(RefId). cGroup := GetProdGroup(oManuf)ecManuf := GetManufName(oManuf).oCat := GetLocCat(RefId)— se existir inclui estrutura de categorias comoCat:ToJson(); senão usaoProd["Category"].- Monta campos principais (
_id,name,slug,description,brand,manufacturer,ean/barcode, etc). - Insere
technicalSpecificationa partir do SKU quando presente; faz consulta emSB1para quantidade por caixa (B1_XLOTVEN). - Adiciona arrays de
image,alternatives/relatedviaGetRelPrdJ. - Anexa
pricesviaGetPricesJestocksviaGetStockJs. - Retorna
cJsonse começar com{, senão"".
Pontos de atenção:
- Usa
StrSanitizepara limpar textos. - Se
Skusestiver vazio muitos campos técnicos ficam com 0 ou vazio. - Faz consulta em
SB1para montarboxQuantity. - Se alguma função auxiliar falhar (ex:
GetLocCat) é aplicado fallback.
Manuf. e Categoria (GetManufInfo, GetProdGroup, GetManufName, GetLocCat)
GetManufInfo(cProdCod)
- Query em
SB1para obtercodFab,codMarca,codGrupo. RetornaJsonObjectcom estes campos ou objeto vazio.
GetProdGroup(oManuf)
- Se
oManuf["codGrupo"]existir, consultaSBMe retornaBM_DESC.
GetManufName(oManuf)
- Se
oManuf["codFab"]existir, consultaSA2e retornaA2_NOME.
GetLocCat(cProdCod)
- Lê tabela
ACVpara categoria do produto e, comWITH(CatHierarchy), percorre níveis de categoria emACUe monta JSON com levels (3=department, 2=category, 1=subcategory). Retorna objeto JSON ou vazio.
Relacionamentos (GetRelPrdJ, GetAltProd, GetRelProd)
GetAltProd: Busca emVB1por alternativas; monta lista única.GetRelProd: Busca emVPDpor produtos relacionados; monta lista única.GetRelPrdJ: Monta os arrays"alternatives":[...]e"related":[...]em JSON pronto para inclusão na saída do produto.
Preços (GetPricesJ, GetPrcData, ProcPrcRecFull)
GetPricesJ(cProdCod)
- Usa
GetPrcDatapara coletar registros de preço (PVF), compõe array JSON de preços e retorna como"prices":[...],ou, em contexto de outra chamada (U_SKaltPrc), retorna objeto JSON.
GetPrcData(cProdCod)
- Executa uma query complexa com
ROW_NUMBER()para obter preços por UF (cadaPVFpor UF). Para cada linha chamaProcPrcRecFull.
ProcPrcRecFull(cAlias)
- Processa todos os campos de preço do registro
PVF, cria strings JSON para cada preço comid,name,promotion(false) evalue. Retorna uma estrutura contendo ouf,aItems,aStrsecAll(concatenação).
Estoque (GetStockJs, GetStockData, ProcStockRec, GetStockQt)
GetStockJs(cProdCod)
- Retorna a string
"stocks":[...]usandoGetStockData.
GetStockData(cProdCod)
- Query em
PVFporPVF_CODFIL, PVF_UFe chamaProcStockRecpor filial.
ProcStockRec(cProdCod, cAlias, aStock)
- Para cada filial listada em MV (
ES_FILB2B) busca entrada emSZPe chamaGetStockQtpara obter saldo (funçãou_specc013usada para cálculo). Monta objeto{ "id":"09,filial", "name":"filial UF", "value":qtd }e adiciona emaStock.
GetStockQt(cProdCod, cFilOrig, cUF)
- Chama
u_specc013(função externa) para obter saldo. Retorna array[cProdCod, cFilOrig, cUF, saldo]com tratamento de saldo negativo.
SKaltPrc
Assinatura: User Function SKaltPrc()
Descrição: Verifica na tabela PVF por produtos cujo PVF_DTCALC/PVF_HRCALC são posteriores ao último envio em ZK1 (ou seja, preços atualizados desde a última integração) e dispara ProcessaProdutoPreco para cada um, sinalizando os produtos que devem ser atualizados via API (PUT).
Retorno: [total_processado, total_sinalizados, detalhes_erros]
Fluxo:
- Ajusta ambiente (RPC) se necessário.
- Query eficiente com
GROUP BYpara trazer produtos comPVFmais recente queZK1. - Coleta todos os produtos em memória
aProdutos. - Obtém token
U_GetB2BTk(). - Para cada produto chama
ProcessaProdutoPreco(...). - Restaura ambiente e retorna resumo.
ProcessaProdutoPreco
Assinatura: Static Function ProcessaProdutoPreco(cProduto, cDataAlt, cHoraAlt, cToken, aErrors)
Descrição: Marca produto como pendente ('P') em ZK1, gera JSON de preços (GetPricesJ), tenta enviar via PUTPRECO (com retentativas), atualiza ZK1 com resultado.
Retorno: 1 em sucesso, 0 em falha.
Detalhes:
- Faz até 3 tentativas; renova token em cada tentativa se necessário.
- No sucesso chama
AtualizaStatusZK1(cProduto, "I", ...). - Em falha ao final chama
AtualizaStatusZK1(cProduto, "F", ...).
PUTPRECO
Assinatura: Static Function PUTPRECO(cProduto, cJson, cToken, cObsInt)
Descrição: Monta e executa requisição HTTP PUT para "/v1/collection/products/"+cProduto usando FWRest() com headers (Content-Type, Accept, Origin, Authorization). Envia JSON de preços no corpo (EncodeUTF8 para cp1252).
Retorno: .T. se status HTTP entre 200 e 299.
Efeito colateral: Atualiza registro ZK1 (status, data/hora e ZK1_OBSINT) conforme resultado.
Erros comuns: Falha de rede, token inválido, status 4xx. HTTPGetStatus(@cError) é usado para obter código.
RETUFFIL (RETFIL/RETFIL?)
Assinatura: STATIC FUNCTION RETUFFIL(cEmpOri, cFilOri)
Descrição: Lê tabela SZP para retornar informações da filial (nomeFil, codEmp, codFil, cgc, empresa, uf) e retorna o primeiro item do array oJson["filiais"][1].
Observação: A função é usada para preencher o name/UF ao gerar JSON de estoque.
SKCarZk2 / InsereZk2
SKCarZk2()
- Busca produtos integrados (
ZK1_ATUALI = 'I') que não existem emZK2e insere um registro inicial por filial (lista de filiais emES_FILB2B). - Usa
InsereZk2para a inserção.
InsereZk2(cCodigo, cFilOri)
- Obtém estoque via
u_specc013e insere emZK2com status"N"(novo) e gravando data/hora/obs. UsaRecLock("ZK2", .T.)para inserir eMsUnlock().
SKEnvEst / GenEstqJson / EnvLotEstq / AtuZK2Batch / UpdZK2Batch / AtuZK2Ind
SKEnvEst(nLoteSize, lTestMode) — Similar a SKEnvPrd, mas para estoque:
- Varre
ZK2buscando itens comZK2_STATUEindicando alteração (lógica no código original). - Monta JSON por (
GenEstqJson) e envia lotes viaEnvLotEstq. - Atualiza
ZK2em lote viaAtuZK2Batch.
GenEstqJson(cProdCod, cFilOri, nSaldo)
- Monta JSON com
_id= produto estockcomid="09," + filial,name=filial UFevalue=nSaldo.
EnvLotEstq(aLote, cToken, aErrors)
- Monta JSON array e envia (mesma lógica de retentativas do envio de produtos).
AtuZK2Batch / UpdZK2Batch / AtuZK2Ind
- Funções de atualização em lote/individual para
ZK2(similar arquitetura aZK1).
Notas de Qualidade, Melhorias e Pontos de Atenção
- Tratamento de erros e logs: O código usa
ConOutpara logs eaErrorspara coletar erros. Seria interessante centralizar logs e adicionar níveis (INFO/ERROR). - Reuso de tokens: A renovação do token em cada tentativa pode ser otimizada verificando validade do token antes de renovar.
- Performance em Oracle: A montagem do JSON a partir de vários campos (Json1..Json99) pode produzir strings muito longas — verificar limites de
DBMS_LOB.SUBSTRe memória. - Encoding: Há muitas chamadas a
StrTran(..., "[UTF-8]", "")eEncodeUTF8(...). Validar encoding em origem e padronizar (usar UTF-8 consistentemente). - Tratamento de concorrência: Em
InsereZk2foi usadoRecLockeMsUnlock(), mas é necessário confirmar se há tratamento de deadlock em cenários concorrentes. - Testes e modo de simulação:
lTestModeimplementado em funções de envio — manter cobertura de testes unitários para ambas as rotas (simulação e execução real). - Documentação inline: Blocos
/{Protheus.doc}estão presentes e foram usados como base.
Mindmap (estrutura hierárquica para importação)
- Integração Protheus SK - Fabritech
- SKEnvPrd (envio produtos)
- ParseOriginalJson
- GenProdJson
- GetManufInfo
- GetProdGroup
- GetManufName
- GetLocCat
- GetRelPrdJ
- GetPricesJ
- GetPrcData
- ProcPrcRecFull
- GetPrcData
- GetStockJs
- GetStockData
- ProcStockRec
- GetStockQt
- ProcStockRec
- GetStockData
- EnviaLote
- U_EnvLoteB2B (externa)
- PreparaAtualizacao
- AtuZK1Batch
- UpdateBatch
- AtuZK1Individual
- SKEnvEst (envio estoque)
- GenEstqJson
- EnvLotEstq
- AtuZK2Batch
- UpdZK2Batch
- AtuZK2Ind
- SKaltPrc (sinaliza alteração de preço)
- ProcessaProdutoPreco
- PUTPRECO
- ProcessaProdutoPreco
- SKCarZk2 (carga inicial ZK2)
- InsereZk2
- Utilitários
- Implode / StrSanitize / IsOracle / RETUFFIL
- SKEnvPrd (envio produtos)