LLMs e o Futuro da Programação: O Fim dos Devs?
Modelos de linguagem de grande escala estão automatizando tarefas de código, mas a criatividade humana ainda é insubstituível...
Mergulhe em descobertas fascinantes da tecnologia e das ciências. Pesquisas, curiosidades e tendências que moldam o mundo digital e científico.
Os conteúdos mais relevantes e instigantes da semana
Modelos de linguagem e geração de imagens levantam questões profundas sobre autoria, originalidade e o papel do ser humano no processo criativo...
Ler artigo →Processador quântico resolve em segundos um problema que levaria milênios a computadores clássicos...
Ler artigo →Neurocientistas descobrem surpreendentes paralelos entre sinapses biológicas e redes de deep learning...
Ler artigo →Encontre conteúdos organizados por área do conhecimento
Machine learning, redes neurais e automação inteligente
42 artigosAstronomia, astrofísica e missões espaciais
28 artigosGenômica, CRISPR e inovações na medicina
35 artigosProteção digital, criptografia e privacidade
19 artigosMecânica quântica, partículas e o universo
23 artigosRobôs autônomos, exoesqueletos e automação
17 artigosInovações, tendências e o que vem por aí no universo tecnológico
Modelos de linguagem de grande escala estão automatizando tarefas de código, mas a criatividade humana ainda é insubstituível...
Com o avanço dos computadores quânticos, os algoritmos de criptografia atuais estão com os dias contados...
Enquanto o 5G ainda se expande, laboratórios ao redor do mundo já desenvolvem o padrão que o sucederá...
Dispositivos cada vez mais potentes permitem rodar modelos de IA diretamente no hardware local, sem internet...
Fatos surpreendentes que vão mudar a forma como você vê o mundo
Se esticado, o DNA de uma única célula mediria cerca de 2 metros. Multiplicado por todas as células do corpo, daria para ir até Plutão e voltar várias vezes.
Se somarmos a massa de todos os elétrons em movimento transmitindo dados pela internet simultaneamente, o resultado é aproximadamente 50 gramas.
A Radiação de Hawking prevê que buracos negros lentamente "evaporam" ao longo de tempo astronomicamente longo, perdendo massa e energia.
Em testes duplo-cegos, ouvintes não conseguem diferenciar composições de IA de músicas criadas por humanos em mais de 60% dos casos.
Um neurônio dispara a cerca de 200 Hz, enquanto transistores modernos operam a GHz — mas a eficiência energética do cérebro ainda é imbatível.
Um grão de areia contém cerca de 10²³ átomos, enquanto o universo observável tem estimados 10²² estrelas.
Pesquisas e descobertas que expandem os limites do conhecimento humano
A nova geração de ferramentas de edição genética permite corrigir mutações pontuais com precisão sem precedentes...
Imagens do telescópio espacial contradizem previsões cosmológicas e provocam revisão de teorias sobre a formação do universo...
Cientistas avançam no mapeamento de todas as conexões neurais de organismos, em busca de compreender consciência e memória...
Experimentos subterrâneos detectam sinais que podem finalmente revelar a natureza do componente mais abundante do universo...
SQL, ADVPL, Power BI, n8n e Protheus — dicas e exemplos reais para o seu dia a dia
Selecionar todas as colunas desperdiça banda e memória. Sempre especifique apenas as colunas necessárias.
-- Ruim
SELECT * FROM clientes
-- Bom
SELECT id, nome, email
FROM clientes
WHERE ativo = 1
Common Table Expressions (WITH) tornam queries longas muito mais legíveis e fáceis de manter.
WITH VendasMensais AS (
SELECT vendedor_id,
SUM(valor) AS total,
MONTH(data_venda) AS mes
FROM vendas
GROUP BY vendedor_id, MONTH(data_venda)
)
SELECT v.nome, vm.total, vm.mes
FROM VendasMensais vm
JOIN vendedores v ON v.id = vm.vendedor_id
ORDER BY vm.total DESC
Funções de janela permitem calcular rankings e numerações sem agrupamentos, mantendo todas as linhas.
SELECT nome, departamento, salario,
RANK() OVER (
PARTITION BY departamento
ORDER BY salario DESC
) AS rank_depto,
ROW_NUMBER() OVER (
ORDER BY salario DESC
) AS rank_geral
FROM funcionarios
Crie índices nas colunas mais usadas em WHERE, JOIN e ORDER BY. Um índice bem posicionado pode reduzir tempo de query em 100x.
-- Criar índice simples
CREATE INDEX idx_cliente_email
ON clientes (email);
-- Índice composto (ordem importa!)
CREATE INDEX idx_pedido_data_status
ON pedidos (data_pedido, status);
Use CASE WHEN para criar colunas calculadas e categorizar dados diretamente na query, sem precisar de código na aplicação.
SELECT nome, salario,
CASE
WHEN salario < 2000 THEN 'Júnior'
WHEN salario < 5000 THEN 'Pleno'
WHEN salario < 10000 THEN 'Sênior'
ELSE 'Especialista'
END AS nivel
FROM funcionarios
Use ROW_NUMBER() para identificar e remover duplicatas de forma segura, sem apagar dados por acidente.
-- Identificar e remover duplicatas
WITH Duplicatas AS (
SELECT *,
ROW_NUMBER() OVER (
PARTITION BY email
ORDER BY id
) AS rn
FROM clientes
)
DELETE FROM Duplicatas WHERE rn > 1
INNER JOIN retorna só registros com correspondência. LEFT JOIN retorna todos da esquerda mesmo sem correspondência. Use o tipo certo para evitar perder ou duplicar registros.
-- INNER: apenas pedidos com cliente
SELECT p.id, c.nome
FROM pedidos p
INNER JOIN clientes c ON c.id = p.cliente_id
-- LEFT: todos clientes, mesmo sem pedido
SELECT c.nome, COUNT(p.id) AS total
FROM clientes c
LEFT JOIN pedidos p ON p.cliente_id = c.id
GROUP BY c.nome
PIVOT (SQL Server) ou CASE WHEN + GROUP BY transformam dados verticais em horizontais — útil para relatórios mensais, comparativos e dashboards.
SELECT vendedor,
SUM(CASE WHEN mes = 1 THEN valor ELSE 0 END) AS Jan,
SUM(CASE WHEN mes = 2 THEN valor ELSE 0 END) AS Fev,
SUM(CASE WHEN mes = 3 THEN valor ELSE 0 END) AS Mar
FROM vendas
GROUP BY vendedor
Procedures encapsulam lógica no banco, melhoram performance por reutilizar plano de execução e centralizam regras de negócio que envolvem múltiplas tabelas.
CREATE PROCEDURE sp_VendasPorPeriodo
@dInicio DATE,
@dFim DATE,
@cFilial VARCHAR(4) = '0101'
AS BEGIN
SELECT v.id, c.nome, v.valor
FROM vendas v
INNER JOIN clientes c ON c.id = v.cliente_id
WHERE v.data_venda BETWEEN @dInicio AND @dFim
ORDER BY v.data_venda DESC
END
Use o plano de execução para identificar Table Scans caros, índices faltantes e operações desnecessárias antes de colocar uma query em produção.
-- Ver plano de execução estimado
SET SHOWPLAN_TEXT ON; GO
SELECT * FROM pedidos WHERE status = 'P'
GO; SET SHOWPLAN_TEXT OFF
-- Estatísticas de I/O e tempo
SET STATISTICS IO ON
SET STATISTICS TIME ON
-- Forçar uso de índice (hint)
SELECT * FROM pedidos WITH (INDEX(idx_status))
WHERE status = 'P'
Todo programa ADVPL começa com uma declaração de função. Variáveis locais são declaradas com Local, e a função retorna valor com Return.
User Function MinhaFuncao()
Local cNome := Space(40)
Local nValor := 0
Local lAtivo := .T.
cNome := AllTrim(SA1->A1_NOME)
nValor := SA1->A1_SALARIO
If lAtivo
MsgInfo('Cliente: ' + cNome)
EndIf
Return NIL
Use TCQuery para executar SQL direto no banco via Protheus. Sempre feche o alias ao terminar para liberar recursos.
Local cQuery := ''
Local cAlias := 'QRY' + DToS(Date())
cQuery := 'SELECT A1_COD, A1_NOME, A1_CGC '
cQuery += 'FROM ' + RetSQLName('SA1') + ' SA1 '
cQuery += 'WHERE SA1.D_E_L_E_T_ = ' '
cQuery += 'AND SA1.A1_FILIAL = ''' + xFilial('SA1') + ''''
TCQuery cQuery New Alias cAlias
While !(cAlias)->(Eof())
MsgInfo((cAlias)->A1_NOME)
(cAlias)->(DbSkip())
EndDo
(cAlias)->(DbCloseArea())
Nunca altere campos diretamente sem travar o registro. Use RecLock para garantir integridade em ambientes multi-usuário.
DbSelectArea('SA1')
DbSetOrder(1)
If DbSeek(xFilial('SA1') + cCodCliente)
If RecLock('SA1', .F.)
SA1->A1_EMAIL := '[email protected]'
SA1->A1_DDD := '11'
MsUnlock()
Else
MsgAlert('Registro em uso!')
EndIf
EndIf
Arrays são amplamente usados no ADVPL para listas, parâmetros de tela e estruturas de dados. Conheça as funções essenciais.
Local aItens := {}
aAdd(aItens, {'001', 'Produto A', 100.00})
aAdd(aItens, {'002', 'Produto B', 250.50})
Local nI
For nI := 1 To Len(aItens)
MsgInfo(aItens[nI][2])
Next nI
Local nPos := AScan(aItens, {|x| x[1] == '002'})
If nPos > 0
MsgInfo('Encontrado: ' + aItens[nPos][2])
EndIf
Para gravar múltiplos registros com segurança, use transações. Se qualquer etapa falhar, o RollBackTran desfaz tudo.
Local lOk := .T.
BeginTran()
If !GrvCabecalho()
lOk := .F.
EndIf
If lOk .And. !GrvItens()
lOk := .F.
EndIf
If lOk
CommitTran()
MsgInfo('Gravação concluída!')
Else
RollBackTran()
MsgAlert('Erro. Operação cancelada.')
EndIf
O SetPrint é a forma padrão de configurar impressão no Protheus. Combine com o TReport para relatórios modernos.
Local aRet := {}
Local wnrel := 'MEUREL'
aRet := SetPrint(wnrel, wnrel,, 'Relatório de Clientes', .T.)
If Empty(aRet)
Return
EndIf
SetDefault(aRet, wnrel)
If aRet[1] == 'V'
Set Printer To
Else
Set Printer To (aRet[2])
EndIf
Set Device To Printer
// ... corpo do relatório ...
Set Device To Screen
Manipulação de strings é rotina no ADVPL. Conheça as funções mais usadas para limpar, formatar e comparar textos nos campos do Protheus.
Local cTexto := ' Joao Silva '
AllTrim(cTexto) // 'Joao Silva'
Upper(cTexto) // ' JOAO SILVA '
SubStr(cTexto, 3, 4) // 'Joao'
StrTran(cTexto,' ','-') // '--Joao-Silva--'
At('Silva', cTexto) // 8 (posicao)
PadR(AllTrim(cTexto),20) // padded a direita
Use a classe TMailMsg para enviar e-mails com HTML, anexos e múltiplos destinatários diretamente do ADVPL via SMTP configurado no Protheus.
Local oMail := TMailMsg():New()
oMail:SetFrom('[email protected]','ERP')
oMail:AddTo('[email protected]')
oMail:SetSubject('Relatorio de Vendas')
oMail:SetBody('Total: R$ 15.000,00',.F.)
oMail:AddAttachment('
elatendas.pdf')
oMail:Send('smtp.empresa.com',587,'user','senha',.T.)
oMail:End()
Os parâmetros do Protheus (SX6) armazenam configurações por empresa e filial. Use SuperGetMV para leitura com valor default e PutMV para gravação.
// Ler com default
Local cEmail := SuperGetMV('MV_EMAILENV',.F.,'[email protected]')
Local nLim := SuperGetMV('MV_LIMDESC',.F.,10)
// Gravar
PutMV('MV_EMAILENV', '[email protected]')
// Checar existencia
If ExistMV('MV_LIMDESC')
MsgInfo(cValToChar(nLim) + '%')
EndIf
Use FWRest para consumir APIs REST externas direto do Protheus, com suporte a GET, POST, headers customizados e autenticação Bearer.
Local oRest := FWRest():New('https://api.empresa.com')
oRest:setPath('/v1/pedidos')
oRest:setChaveHeader('Authorization','Bearer '+cToken)
oRest:setChaveHeader('Content-Type','application/json')
If oRest:Post(cBody)
Local oRet := JsonObject():New()
oRet:fromJson(oRest:GetResult())
MsgInfo(oRet['mensagem'])
Else
MsgAlert('Erro: '+cValToChar(oRest:GetStatus()))
EndIf
oRest:End()
| Tabela | Módulo | Descrição | Chave Principal |
|---|---|---|---|
| SA1 | Cadastro | Cadastro de Clientes | A1_FILIAL + A1_COD + A1_LOJA |
| SA2 | Cadastro | Cadastro de Fornecedores | A2_FILIAL + A2_COD + A2_LOJA |
| SA3 | Cadastro | Cadastro de Vendedores | A3_FILIAL + A3_COD |
| SA4 | Cadastro | Cadastro de Transportadoras | A4_FILIAL + A4_COD |
| SA5 | Cadastro | Produto x Cliente (tabela de preços por cliente) | A5_FILIAL + A5_CODPRO + A5_CLIENTE + A5_LOJA |
| SA6 | Cadastro | Bancos | A6_FILIAL + A6_COD |
| SA7 | Cadastro | Relação de Cobrança (formas de pagamento) | A7_FILIAL + A7_COD |
| SAB | Cadastro | Contas Bancárias | AB_FILIAL + AB_BANCO + AB_AGENCIA + AB_CONTA |
| SB1 | Estoque | Cadastro de Produtos | B1_FILIAL + B1_COD |
| SB2 | Estoque | Saldo em Estoque por Armazém | B2_FILIAL + B2_COD + B2_LOCAL |
| SB3 | Estoque | Rastreabilidade (lotes/sublotes) | B3_FILIAL + B3_COD + B3_LOCAL + B3_LOTECTL |
| SB4 | Estoque | Grupo de Produto | B4_FILIAL + B4_GRUPO |
| SB5 | Estoque | Complemento do Produto | B5_FILIAL + B5_COD |
| SB6 | Estoque | Curva ABC de Produtos | B6_FILIAL + B6_COD |
| SB7 | Estoque | Saldo de Lotes em Estoque | B7_FILIAL + B7_COD + B7_LOCAL + B7_LOTE |
| SB8 | Estoque | Saldo por Número de Série | B8_FILIAL + B8_COD + B8_LOCAL + B8_NUMSERI |
| SB9 | Estoque | Endereçamento de Estoque (WMS) | B9_FILIAL + B9_COD + B9_LOCAL + B9_LOTECTL |
| SD3 | Estoque | Movimentos Internos de Estoque | D3_FILIAL + D3_COD + D3_DOC |
| SC1 | Compras | Solicitações de Compra | C1_FILIAL + C1_NUM + C1_ITEM + C1_PRODUTO |
| SC2 | Compras | Ordens de Compra | C2_FILIAL + C2_NUM + C2_ITEM + C2_PRODUTO |
| SC7 | Compras | Pedidos de Compra | C7_FILIAL + C7_NUM + C7_ITEM |
| SD1 | Compras | Itens das Notas Fiscais de Entrada | D1_FILIAL + D1_DOC + D1_SERIE + D1_FORNECE + D1_LOJA |
| SF1 | Compras | Cabeçalho das Notas Fiscais de Entrada | F1_FILIAL + F1_DOC + F1_SERIE + F1_FORNECE + F1_LOJA |
| SQB | Compras | Cotações de Compra | QB_FILIAL + QB_NUM + QB_FORNECE |
| SC5 | Vendas | Cabeçalho dos Pedidos de Venda | C5_FILIAL + C5_NUM |
| SC6 | Vendas | Itens dos Pedidos de Venda | C6_FILIAL + C6_NUM + C6_ITEM |
| SD2 | Vendas | Itens das Notas Fiscais de Saída | D2_FILIAL + D2_DOC + D2_SERIE + D2_CLIENTE + D2_LOJA |
| SF2 | Vendas | Cabeçalho das Notas Fiscais de Saída | F2_FILIAL + F2_DOC + F2_SERIE + F2_CLIENTE + F2_LOJA |
| SCJ | Vendas | Tabela de Preços de Venda | CJ_FILIAL + CJ_TABELA + CJ_PRODUTO |
| SDA | Vendas | Devoluções de Venda | DA_FILIAL + DA_DOC + DA_SERIE |
| SE1 | Financeiro | Contas a Receber (títulos) | E1_FILIAL + E1_PREFIXO + E1_NUM + E1_PARCELA + E1_TIPO + E1_CLIENTE + E1_LOJA |
| SE2 | Financeiro | Contas a Pagar (títulos) | E2_FILIAL + E2_PREFIXO + E2_NUM + E2_PARCELA + E2_TIPO + E2_FORNECE + E2_LOJA |
| SE5 | Financeiro | Movimentação Bancária (extrato) | E5_FILIAL + E5_BANCO + E5_AGENCIA + E5_CONTA + E5_PREFIXO + E5_NUM |
| SEA | Financeiro | Adiantamentos de Clientes | EA_FILIAL + EA_CLIENTE + EA_LOJA |
| SEB | Financeiro | Adiantamentos de Fornecedores | EB_FILIAL + EB_FORNECE + EB_LOJA |
| SEF | Financeiro | Saldos Bancários | EF_FILIAL + EF_BANCO + EF_AGENCIA + EF_CONTA |
| SEG | Financeiro | Naturezas Financeiras | EG_FILIAL + EG_CODIGO |
| CT1 | Contábil | Plano de Contas Contábil | CT1_FILIAL + CT1_CONTA |
| CT2 | Contábil | Lançamentos Contábeis (partidas) | CT2_FILIAL + CT2_LOTE + CT2_SEQUEN |
| CT5 | Contábil | Centro de Custo | CT5_FILIAL + CT5_CLVL |
| CTD | Contábil | Saldos Contábeis | CTD_FILIAL + CTD_CONTA + CTD_CLVL + CTD_MES + CTD_ANO |
| CTG | Contábil | Grupos de Lançamento Contábil | CTG_FILIAL + CTG_GRPCTA |
| SF3 | Fiscal | Livro Fiscal (SPED / registros fiscais) | F3_FILIAL + F3_DOC + F3_SERIE + F3_FORNECE |
| SFB | Fiscal | Tributações por UF (ICMS) | FB_FILIAL + FB_EST + FB_TIPO + FB_TRIB |
| SFC | Fiscal | Tabela de IPI | FC_FILIAL + FC_CODIGO |
| SFD | Fiscal | Classificações Fiscais (NCM / TIPI) | FD_FILIAL + FD_CODIGO |
| SFP | Fiscal | Apuração de ICMS/IPI | FP_FILIAL + FP_ESTAB + FP_MESREF |
| SFF | Fiscal | Operações Fiscais (CFOP) | FF_FILIAL + FF_CODIGO |
| SC4 | Produção | Ordens de Produção (cabeçalho) | C4_FILIAL + C4_NUM |
| SG1 | Produção | Estrutura do Produto (BOM) | G1_FILIAL + G1_COD + G1_COMP + G1_TRT + G1_REVINI |
| SG2 | Produção | Centro de Trabalho (Recursos) | G2_FILIAL + G2_COD |
| SH1 | Produção | Roteiros de Fabricação (cabeçalho) | H1_FILIAL + H1_COD + H1_ROTEIRO |
| SH2 | Produção | Roteiros de Fabricação (operações) | H2_FILIAL + H2_ROTEIRO + H2_OPERAC |
| SH6 | Produção | Apontamento de Produção | H6_FILIAL + H6_OP + H6_ITEM |
| SRA | RH | Cadastro de Funcionários | RA_FILIAL + RA_MAT |
| SRB | RH | Histórico de Cargos e Salários | RB_FILIAL + RB_MAT + RB_DATAALT |
| SRC | RH | Verba / Evento da Folha de Pagamento | RC_FILIAL + RC_MAT + RC_CODVER |
| SRD | RH | Dependentes do Funcionário | RD_FILIAL + RD_MAT + RD_CODEP |
| SRH | RH | Histórico de Frequência | RH_FILIAL + RH_MAT + RH_DATA |
| SRJ | RH | Cargos / Funções | RJ_FILIAL + RJ_CARGO |
| SRV | RH | Verbas / Eventos da Folha (tabela mestre) | RV_FILIAL + RV_COD |
| SX5 | Cadastro | Tabelas Genéricas do Sistema (domínios) | X5_FILIAL + X5_TABELA + X5_CHAVE |
| SX3 | Cadastro | Dicionário de Dados dos Campos (SXS) | X3_ARQUIVO + X3_CAMPO |
| SM0 | Cadastro | Cadastro de Empresas / Filiais | M0_FILIAL + M0_CODFIL |
| SM4 | Cadastro | Moedas do Sistema | M4_MOEDA |
| SNF | Cadastro | Séries de Notas Fiscais | NF_FILIAL + NF_SERIE + NF_TIPO |
⚠ Todas as tabelas possuem os campos padrão: D_E_L_E_T_ (exclusão lógica), R_E_C_N_O_ (número do registro) e R_E_C_D_E_L_. Sempre filtre por D_E_L_E_T_ = ' ' em queries SQL.
Tabela mais consultada do Protheus. Campos-chave para joins: A1_FILIAL + A1_COD + A1_LOJA formam a chave única do cliente.
SELECT
A1_COD, A1_LOJA, A1_NOME,
A1_CGC AS CNPJ,
A1_EMAIL, A1_TEL,
A1_END, A1_MUN, A1_EST
FROM SA1010
WHERE D_E_L_E_T_ = ' '
AND A1_FILIAL = '0101'
ORDER BY A1_NOME
SC5 é o cabeçalho do pedido de venda e SC6 os itens. O JOIN usa C5_NUM = C6_NUM + filial. Relacione com SA1 (cliente) e SB1 (produto).
SELECT
C5.C5_NUM, C5.C5_EMISSAO,
SA1.A1_NOME AS Cliente,
SB1.B1_DESC AS Produto,
C6.C6_QTDVEN * C6.C6_PRCVEN AS Total
FROM SC5010 C5
INNER JOIN SC6010 C6
ON C6.C6_NUM = C5.C5_NUM
INNER JOIN SA1010 SA1
ON SA1.A1_COD = C5.C5_CLIENTE
INNER JOIN SB1010 SB1
ON SB1.B1_COD = C6.C6_PRODUTO
WHERE C5.D_E_L_E_T_ = ' '
AND C5.C5_FILIAL = '0101'
SE1 é contas a receber, SE2 contas a pagar. E1_SALDO > 0 indica título em aberto. Use DATEDIFF para calcular dias de atraso.
SELECT
E1_NUM, SA1.A1_NOME AS Cliente,
E1_VENCREA, E1_VALOR, E1_SALDO,
DATEDIFF(DAY,
CONVERT(DATE,E1_VENCREA,112),
GETDATE()) AS DiasAtraso
FROM SE1010 E1
LEFT JOIN SA1010 SA1
ON SA1.A1_COD = E1_CLIENTE
WHERE E1.D_E_L_E_T_ = ' '
AND E1_SALDO > 0
SF3 registra todos os documentos fiscais. Essencial para apuração de impostos, auditoria e conciliação contábil. F3_TIPO distingue entrada (E) de saída (S).
SELECT
F3_DOC, F3_SERIE, F3_EMISSAO,
CASE F3_TIPO
WHEN 'E' THEN 'Entrada'
WHEN 'S' THEN 'Saída'
END AS Tipo,
F3_VALBRUT, F3_VALIPI,
F3_VALICM, F3_VALPIS, F3_VALCOF
FROM SF3010
WHERE D_E_L_E_T_ = ' '
AND F3_EMISSAO BETWEEN
'20250101' AND '20251231'
Tabela de fornecedores. Chave composta por A2_FILIAL + A2_COD + A2_LOJA. Campos fiscais como A2_CGC (CNPJ), A2_INSCEST (IE) e A2_PAIS são críticos para NF de entrada e apuração fiscal.
SELECT
A2_COD, A2_LOJA, A2_NOME,
A2_CGC AS CNPJ,
A2_INSCEST AS IE,
A2_END, A2_MUN, A2_EST,
A2_EMAIL, A2_TEL,
A2_TIPO -- F=Físico J=Jurídico
FROM SA2010
WHERE D_E_L_E_T_ = ' '
AND A2_FILIAL = '0101'
ORDER BY A2_NOME
SB1 é o cadastro de produtos (descrição, unidade, NCM, grupo). SB2 guarda o saldo físico e financeiro por filial e armazém. Para saldo atual sempre use SB2, nunca SB1.
SELECT
SB1.B1_COD, SB1.B1_DESC, SB1.B1_UM,
SB1.B1_POSIPI AS NCM,
SB2.B2_LOCAL AS Armazem,
SB2.B2_QATU AS SaldoFisico,
SB2.B2_CM1 AS CustoMedio,
SB2.B2_QATU * SB2.B2_CM1 AS Valor
FROM SB1010 SB1
INNER JOIN SB2010 SB2
ON SB2.B2_COD = SB1.B1_COD
WHERE SB1.D_E_L_E_T_ = ' '
AND SB2.B2_QATU > 0
SC1 armazena os pedidos de compra (solicitações). Campo C1_NUM identifica o pedido, C1_PRODUTO o item e C1_FORNECE o fornecedor. C1_DATPRF é a data de entrega prevista.
SELECT
C1.C1_NUM, C1.C1_PRODUTO,
SB1.B1_DESC AS Produto,
C1.C1_QUANT - C1.C1_QUJE AS Saldo,
C1.C1_DATPRF AS DataPrevista,
SA2.A2_NOME AS Fornecedor
FROM SC1010 C1
LEFT JOIN SB1010 SB1 ON SB1.B1_COD = C1.C1_PRODUTO
LEFT JOIN SA2010 SA2 ON SA2.A2_COD = C1.C1_FORNECE
WHERE C1.D_E_L_E_T_ = ' '
AND C1.C1_QUANT > C1.C1_QUJE
SF2 é o cabeçalho da Nota Fiscal de saída emitida pelo Protheus. SD2 contém os itens. O JOIN é por F2_DOC + F2_SERIE + F2_CLIENTE. Campos fiscais como D2_TES, D2_CF e D2_BASICO são essenciais para apuração.
SELECT
F2.F2_DOC, F2.F2_SERIE, F2.F2_EMISSAO,
SA1.A1_NOME AS Cliente,
D2.D2_CF AS CFOP,
D2.D2_QUANT, D2.D2_TOTAL,
D2.D2_BASICO AS BaseICMS,
D2.D2_VALICM, D2.D2_VALIPI
FROM SF2010 F2
INNER JOIN SD2010 D2
ON D2.D2_DOC = F2.F2_DOC
AND D2.D2_SERIE = F2.F2_SERIE
WHERE F2.D_E_L_E_T_ = ' '
AND F2.F2_FILIAL = '0101'
SD1 contém os itens das notas fiscais de entrada (compras). O cabeçalho fica na SF1. D1_DOC + D1_SERIE + D1_FORNECE formam o vínculo com o documento. D1_PEDIDO liga ao pedido de compra (SC7).
SELECT
SF1.F1_DOC, SF1.F1_EMISSAO,
SA2.A2_NOME AS Fornecedor,
D1.D1_COD, D1.D1_CF AS CFOP,
D1.D1_QUANT, D1.D1_TOTAL,
D1.D1_BASEIA AS BaseICMS,
D1.D1_PEDIDO AS PedidoCompra
FROM SF1010 SF1
INNER JOIN SD1010 D1
ON D1.D1_DOC = SF1.F1_DOC
AND D1.D1_SERIE = SF1.F1_SERIE
WHERE SF1.D_E_L_E_T_ = ' '
SRA é o cadastro de funcionários no módulo RH/Folha. SRB contém os departamentos. Campos como RA_MAT (matrícula), RA_NOME, RA_SALARIO e RA_CODFUNC são os mais utilizados em relatórios gerenciais de RH.
SELECT
SRA.RA_MAT AS Matricula,
SRA.RA_NOME AS Funcionario,
SRB.RB_DESC AS Departamento,
SRC.RC_DESC AS Cargo,
SRA.RA_SALARIO AS Salario,
SRA.RA_ADMISSA AS Admissao
FROM SRA010 SRA
LEFT JOIN SRB010 SRB ON SRB.RB_DEPTO = SRA.RA_DEPTO
LEFT JOIN SRC010 SRC ON SRC.RC_CARGO = SRA.RA_CARGO
WHERE SRA.RA_SITFOLH = '1'
SX5 centraliza todas as tabelas de domínio do Protheus: UFs, países, grupos de produto, tipos de entrada/saída, naturezas de operação etc. X5_TABELA identifica qual tabela e X5_CHAVE + X5_DESCRI são chave/valor.
-- Tabelas de domínio do Protheus
SELECT X5_CHAVE, X5_DESCRI
FROM SX5010
WHERE D_E_L_E_T_ = ' '
AND X5_TABELA = '12' -- UFs
-- No ADVPL:
-- Posicione('SX5', 1,
-- xFilial('SX5')+'12'+cUF,
-- 'X5_DESCRI')
SM0 contém o cadastro de todas as empresas e filiais do ambiente Protheus. Essencial para relatórios multi-empresa, validação de filial ativa e integração entre módulos em ambiente multi-filial.
-- Empresas e filiais do ambiente
SELECT
M0_CODIGO AS Empresa,
M0_CODFIL AS Filial,
M0_NOME AS NomeEmpresa,
M0_CGC AS CNPJ,
M0_ESTADO AS UF
FROM SM0010
WHERE D_E_L_E_T_ = ' '
ORDER BY M0_CODIGO, M0_CODFIL
Colunas calculadas ficam salvas no modelo e aumentam o tamanho do arquivo. Medidas são calculadas em tempo de execução e são muito mais eficientes para agregações.
-- ❌ Evite: coluna calculada
Lucro = Vendas[Receita] - Vendas[Custo]
-- ✅ Prefira: medida
Lucro Total =
SUM(Vendas[Receita]) - SUM(Vendas[Custo])
CALCULATE permite modificar o contexto de filtro de uma medida. É a função mais poderosa do DAX — dominar ela é essencial para qualquer análise avançada.
-- Vendas apenas da região Sul
Vendas Sul =
CALCULATE(
SUM(Vendas[Valor]),
Regioes[Regiao] = "Sul"
)
-- Vendas do ano anterior
Vendas Ano Anterior =
CALCULATE(
SUM(Vendas[Valor]),
SAMEPERIODLASTYEAR(Calendario[Data])
)
Para usar funções de inteligência de tempo (YTD, MTD, ano anterior) você precisa de uma tabela calendário marcada como "tabela de data" com uma linha para cada dia.
Calendario =
ADDCOLUMNS(
CALENDAR(DATE(2020,1,1), DATE(2030,12,31)),
"Ano", YEAR([Date]),
"Mes", MONTH([Date]),
"NomeMes", FORMAT([Date], "MMMM"),
"Trimestre", "T" & ROUNDUP(MONTH([Date])/3,0),
"DiaSemana", WEEKDAY([Date], 2)
)
Use as funções de inteligência temporal nativas do DAX para acumular valores no ano, trimestre ou mês. Exigem tabela calendário corretamente configurada.
Vendas YTD =
TOTALYTD(SUM(Vendas[Valor]), Calendario[Data])
Vendas MTD =
TOTALMTD(SUM(Vendas[Valor]), Calendario[Data])
Crescimento % =
DIVIDE(
[Vendas YTD] - [Vendas Ano Anterior],
[Vendas Ano Anterior],
0
)
RANKX cria rankings que se atualizam automaticamente conforme os filtros do relatório, sem precisar ordenar tabelas manualmente.
Ranking Vendedores =
RANKX(
ALL(Vendedores[Nome]),
[Vendas Total],
,
DESC,
DENSE
)
-- Filtrar top 5 em visuals:
Top 5 =
IF([Ranking Vendedores] <= 5, [Vendas Total])
Para datasets grandes, defina tabelas de agregação pré-calculadas. O Power BI usa automaticamente a agregação quando possível, caindo para o detalhe só quando necessário.
// Tabela de agregação por mês
let
Fonte = Vendas,
Agrupado = Table.Group(
Fonte,
{"AnoMes", "Regiao"},
{
{"TotalVendas", each List.Sum([Valor]), type number},
{"QtdPedidos", each Table.RowCount(_), type number}
}
)
in
Agrupado
RELATED busca um valor da tabela relacionada (lado 1). RELATEDTABLE retorna a tabela filtrada (lado N). Essenciais em modelos estrela.
-- Busca campo da tabela pai
Segmento = RELATED(Clientes[Segmento])
-- Conta linhas relacionadas
Total Pedidos =
COUNTROWS(RELATEDTABLE(Pedidos))
-- Com filtro:
Concluidos =
CALCULATE(
COUNTROWS(RELATEDTABLE(Pedidos)),
Pedidos[Status] = "Concluido"
)
SWITCH substitui múltiplos IFs e é muito mais legível. Use SWITCH(TRUE()) para condições por faixa — equivalente ao CASE WHEN do SQL.
Classificacao =
SWITCH(TRUE(),
[Vendas Total] >= 100000, "Diamante",
[Vendas Total] >= 50000, "Ouro",
[Vendas Total] >= 20000, "Prata",
[Vendas Total] >= 5000, "Bronze",
"Iniciante"
)
Status Desc =
SWITCH(Pedidos[Status],
"A", "Aberto",
"F", "Faturado",
"C", "Cancelado",
"Desconhecido"
)
Tabelas What-If criam sliders para simular cenários (ex: % desconto, meta de crescimento) sem alterar os dados reais do modelo.
-- Medida do What-If:
Desconto Valor =
'Desconto'[Desconto] / 100
-- Usar o parametro:
Receita Simulada =
SUM(Vendas[Valor]) * (1 - [Desconto Valor])
Lucro Simulado =
[Receita Simulada] - SUM(Vendas[Custo])
Limpeza de dados deve ser feita no Power Query, não em DAX. Renomeie colunas, ajuste tipos e filtre registros antes de carregar no modelo.
let
Fonte = Sql.Database("srv","banco"),
Tabela = Fonte{[Item="Vendas"]}[Data],
Filtrado = Table.SelectRows(Tabela,
each [Status] = "A"),
Renomeado = Table.RenameColumns(Filtrado,{
{"C5_NUM", "NrPedido"},
{"C5_EMISSAO", "DataEmissao"}
}),
Tipado = Table.TransformColumnTypes(
Renomeado,{{"DataEmissao",type date}}
)
in Tipado
Todo workflow n8n tem um nó de gatilho (Trigger) que inicia a execução, seguido de nós de ação conectados. Dados fluem como JSON de nó em nó através de "items".
// Cada nó recebe e passa arrays de items
[
{
"json": {
"id": 1,
"nome": "João Silva",
"email": "[email protected]"
}
}
]
Use expressões entre {{ }} para acessar dados do nó anterior. $json acessa o item atual, $('NomeDoNó').item.json acessa dados de um nó específico.
// Item atual
{{ $json.nome }}
{{ $json.email }}
// Nó específico pelo nome
{{ $('HTTP Request').item.json.status }}
// Operações na expressão
{{ $json.preco * $json.quantidade }}
{{ new Date($json.data).toLocaleDateString('pt-BR') }}
O nó Code permite escrever JavaScript puro para transformar dados de forma avançada. Ideal quando os nós nativos não cobrem o caso de uso.
// Processar e transformar items
const resultado = items.map(item => {
const d = item.json;
return {
json: {
nome: d.nome.trim(),
email: d.email.toLowerCase(),
valor: `R$ ${d.valor.toFixed(2)}`,
data: new Date(d.data)
.toLocaleDateString('pt-BR'),
ativo: d.status === 'A'
}
};
});
return resultado;
Use o nó Webhook como trigger para que sistemas externos (ERPs, e-commerce, formulários) disparem seu workflow via HTTP POST. Ideal para integrações em tempo real.
// Payload recebido no Webhook
{
"evento": "pedido_criado",
"pedido": {
"id": "PED-001",
"cliente": "João Silva",
"valor": 1500.00
}
}
// Acessar no próximo nó:
{{ $json.body.pedido.cliente }}
{{ $json.body.pedido.valor }}
Ao processar listas grandes (ex: enviar e-mail para 1000 contatos), use o nó "Split in Batches" para processar em grupos e evitar timeout ou limite de APIs.
// Fluxo para grandes volumes:
//
// [Buscar dados] → lista completa
// ↓
// [Split in Batches] → tamanho: 50
// ↓
// [Processar cada item]
// ↓
// [Wait] → 1s entre batches
// Verificar último batch (nó Code):
if ($input.context.noItemsLeft) {
// todos processados!
}
Configure um "Error Workflow" nas configurações do n8n para capturar falhas de qualquer workflow automaticamente. Ideal para enviar alertas no Slack, Teams ou e-mail quando algo quebrar.
// Dados no Error Workflow:
// $json.workflow.name → nome do workflow
// $json.error.message → mensagem do erro
// $json.execution.url → link no n8n
// Montar alerta para Slack:
const msg = [
`❌ *Erro:* ${$json.workflow.name}`,
`📋 ${$json.error.message}`,
`🔗 ${$json.execution.url}`
].join('
');
return [{ json: { text: msg } }];
O nó IF divide o fluxo em dois caminhos: "true" e "false". Use expressões para comparar valores e rotear os dados para o nó correto.
// Condições no nó IF:
// Campo existe e não está vazio
{{ $json.email !== '' && $json.email !== undefined }}
// Comparar número
{{ $json.valor > 1000 }}
// Array tem itens
{{ $json.itens.length > 0 }}
// Múltiplas condições
{{ $json.tipo === 'PJ' && $json.cnpj !== '' }}
O nó HTTP Request é o canivete suíço do n8n. Com ele você consome qualquer API REST, envia dados, autentica com Bearer Token ou API Key e trata a resposta.
// URL com variável de ambiente:
https://api.empresa.com/v1/pedidos
// Header de autenticação:
Authorization: Bearer {{ $env.API_TOKEN }}
// Body dinâmico:
{
"cliente": "{{ $json.codCliente }}",
"itens": {{ JSON.stringify($json.itens) }},
"total": {{ $json.valorTotal }}
}
Use o Schedule Trigger para executar workflows automaticamente em horários fixos. Suporta expressões cron para agendamentos avançados como "segunda às 8h" ou "todo dia 1 do mês".
// Todo dia às 8h
0 8 * * *
// Seg–Sex às 7h30
30 7 * * 1-5
// Dia 1 de cada mês às 6h
0 6 1 * *
// A cada 30min em horário comercial
*/30 8-18 * * 1-5
// Toda segunda às 9h
0 9 * * 1
O nó Merge une dados de dois ramos do workflow. No modo "Combine by Field" faz um JOIN entre os dois fluxos por uma chave comum — como juntar dados de duas APIs diferentes pelo ID do registro.
// Após Merge (Combine by Field: id)
const merged = items.map(item => {
const d = item.json;
return {
json: {
id: d.id,
// Do CRM:
nomeCliente: d.nome,
// Do ERP:
saldoERP: d.saldo,
// Calculado:
utilizacao:
((d.saldo / d.limite) * 100)
.toFixed(1) + '%'
}
};
});
return merged;
A Reforma (EC 132/2023 + PLP 68/2024) extingue PIS, COFINS, ICMS, ISS e IPI, substituindo por CBS (federal), IBS (estados/municípios) e IS (seletivo). Transição entre 2026 e 2032.
Extintos:
PIS+COFINS → CBS (federal)
ICMS+ISS → IBS (est.+mun.)
IPI → IS (seletivo)
Cronograma:
2026 → testes 0,1%
2027 → CBS plena
2029-2032 → IBS gradual
2033 → regime pleno
CBS é federal (substitui PIS+COFINS, alíquota ~8,8%). IBS é subnacional (substitui ICMS+ISS, alíquota ~17,7%). Ambos têm não-cumulatividade plena e mesmo mecanismo de crédito.
CBS IBS
Esfera Federal Est.+Mun.
Substitui PIS+COFINS ICMS+ISS
Alíquota ~8,8% ~17,7%
Crédito Pleno Pleno
Início 2027 2029
Durante a transição a NF-e continuará com campos atuais. A SEFAZ publicará versão 4.x com campos CBS/IBS/IS. No Protheus, aguardar pacotes TOTVS Legislação com novos campos em SF2/SD2.
NF-e 4.x (previsto):
<CBS> alíquota + valor
<IBS> alíquota + valor
<IS> alíquota + valor
Protheus — aguardar TOTVS:
MV_CBSALIQ, MV_IBSALIQ
SF2/SD2 → novos campos
Pacote TOTVS Legislação
No split payment o imposto é recolhido automaticamente no ato do pagamento pelo banco/adquirente. O vendedor recebe o valor líquido. Acaba o "float tributário". Impacto direto no fluxo de caixa.
Hoje:
Venda R$ 1.000 → recebe R$ 1.000
Imposto: recolhe mês seguinte
Split Payment (2027+):
Venda R$ 1.000
Banco → R$ 270 ao fisco
Empresa recebe → R$ 730
Fim do "float tributário"
Crédito pleno e imediato sobre todas as aquisições usadas na atividade — insumos, serviços, energia, ativo imobilizado, aluguel. Fim das restrições atuais do PIS/COFINS não-cumulativo.
Geram crédito:
Mercadorias para revenda
Insumos, energia, fretes
Servicos contratados
Aluguel (atividade)
Ativo imobilizado
Sem crédito:
Simples Nacional / MEI
Uso pessoal
O IS incide sobre bens e serviços prejudiciais à saúde ou ao meio ambiente. Não gera crédito CBS/IBS para o comprador. Incide antes do CBS/IBS (integra a base de cálculo deles).
Sujeitos ao IS:
Tabaco, álcool, refrigerantes
Veículos (exceto elétricos)
Agrotóxicos, armas
Minérios
Regras:
IS não gera crédito
Base CBS/IBS inclui IS
Famílias do CadÚnico recebem devolução de parte do CBS/IBS pago em compras do dia a dia. O CPF na NF-e é obrigatório para que o fisco rastreie as compras e calcule o benefício automaticamente.
Quem recebe:
CadÚnico + CPF na NF-e
Devolução:
CBS: 20% IBS: 20%
Cesta básica: 100%
Para o ERP:
CPF na NF-e é obrigatório
Simples Nacional recolhe CBS/IBS dentro do DAS (alíquota reduzida) mas quem compra recebe apenas crédito presumido. Entidades imunes e MEI não recolhem e não geram crédito para o comprador.
Simples Nacional:
CBS/IBS no DAS
Comprador: crédito presumido
Imunes + MEI:
Não recolhem → sem crédito
Lucro Presumido:
Regime geral → crédito normal
Ainda estamos no período pré-transição (2026 é o ano-teste). Mas há ações concretas que podem ser feitas já para minimizar o impacto quando os pacotes TOTVS chegarem.
Fazer AGORA:
1. Atualizar pacotes TOTVS
2. Revisar NCM (SB1.B1_POSIPI)
3. CPF/CNPJ em todas as NF-e
4. Revisar CFOP por operação
5. Documentar pontos de entrada
Aguardar TOTVS 2026+:
NF-e 4.x, MV_CBS*, MV_IBS*
Split Payment, SIGAFIS novo
O Protheus tem arquitetura 3 camadas: SmartClient/Web, Application Server (AppServer) e banco de dados. O DBAccess faz a ponte entre AppServer e banco (SQL Server, Oracle ou Progress).
[SmartClient / WebApp]
TCP/IP
[TOTVS AppServer]
DBAccess
[DBAccess Server]
ODBC / driver
[SQL Server / Oracle]
Portas: AppServer 1234
DBAccess 7890
REST 8080
Conhecer a estrutura de pastas é essencial para instalar RPOs, incluir fontes customizados, configurar o appserver.ini e separar ambientes de produção e desenvolvimento.
Protheus Apo tttm120.rpo (RPO padrão)
custom.rpo (customizações)
Bin\AppServer Bin\SmartClient Protheus_Data Systemload\ (fontes .prw)
appserver.ini
dbaccess.ini
O appserver.ini controla porta, RPO, empresa, licenças e ambientes. Erros aqui impedem o servidor de subir. Mantenha sempre backup antes de qualquer alteração.
[TCP]
Port=1234
[ENVIRONMENT]
sourcepath=...\Systemload
RootPath=...\Protheus_Data
RpoDb=Top
RpoVersion=120
[TOP]
Server=localhost
Port=7890
Database=MSSQL
; RpoCustom=...\custom.rpo
O TDS (TOTVS Developer Studio) para VS Code é a IDE oficial e gratuita para ADVPL/TLPP. Substitui o TDS Eclipse. Permite compilar, depurar e navegar nos fontes diretamente do editor.
1. VS Code + extensão TOTVS
2. Add Server:
Host: IP do AppServer
Porta: 1234
Ambiente: SEU_AMBIENTE
3. Compilar:
Ctrl+F9 → arquivo
Ctrl+Shift+F9 → pasta
4. Debug: F5 → Launch ADVPL
RPO (Repository Object) é o arquivo binário com todos os fontes compilados. Separe customizações em RPO próprio (custom.rpo). Nunca compile direto no RPO padrão da TOTVS.
// RPO separado:
// RpoCustom=...\custom.rpo
// Prefixo: Z + módulo + seq
// ZFIN001.PRW, ZVEN002.TLPP
/*/{Protheus.doc}
Funcao : ZFIN001
Descricao : Relatorio X
Autor : Dev
Data : 01/01/2026
/{*/
// Versionar com Git
Nunca desenvolva em produção. Configure DEV, HML e PRD como environments distintos no mesmo appserver.ini, cada um apontando para um banco diferente.
; Um AppServer → 3 ambientes
[DESENV]
RootPath=...\Protheus_Data_DEV
[HOMOLOG]
RootPath=...\Protheus_Data_HML
[PRODUCAO]
RootPath=...\Protheus_Data_PRD
; SmartClient → escolher no login
O TDS permite depurar em tempo real com breakpoints condicionais. Para ambientes sem debug disponível, use log em arquivo com MemoWrite() ou ConOut() para saída no console do AppServer.
// Breakpoint condicional TDS:
// Right-click → Conditional
// Ex: nValor > 1000
// Log em arquivo:
MemoWrite(GetTempPath()+'debug.log',
DToS(Date())+' '+cValToChar(nValor),
.T.)
// Console AppServer:
ConOut('nValor: '+cValToChar(nValor))
Configure o HTTP no appserver.ini e use anotações @Get/@Post no TLPP para expor endpoints REST nativos. Suporte a JWT e TOTVS RAC para autenticação.
; appserver.ini:
[HTTPSERVER]
Enable=1
Ports=8080
; TLPP:
#include 'tlpp-rest.th'
@Get('/api/pedidos')
Function getPedidos() As Object
Local oBody := JsonObject():New()
oBody['status'] := 'ok'
oRest:getResponse():setStatus(200)
Return oRest:getResponse()
Versione fontes ADVPL com Git. Configure .gitignore para excluir binários. Use TDS-CLI para compilação automática em pipelines CI/CD, eliminando dependência de abrir o VS Code manualmente.
# .gitignore ADVPL:
*.rpo *.err *.ind
*.dbf *.log
# Versionar:
# *.prw *.tlpp *.ch *.th
# TDS-CLI (pipeline CI/CD):
tdscli compile --server=localhost --port=1234 --env=DESENV --program=ZFIN001.PRW --rpoCustom=custom.rpo
Investigações ativas sobre tecnologia, dados e automação — acompanhe o progresso em tempo real
Investigação sobre o desempenho de modelos de linguagem (GPT-4o, Claude, Gemini) na extração de cláusulas e identificação de riscos em contratos brasileiros, comparando acurácia e custo por token.
Mapeamento e automação do fluxo de contas a pagar e receber integrando o n8n ao Protheus via REST API, com notificações automáticas e geração de relatórios no Power BI.
Desenvolvimento de um modelo preditivo de abandono de clientes integrado diretamente no Power BI, combinando medidas DAX complexas com modelos de machine learning via Python visual.
Estudo comparativo de estratégias de otimização de queries nas tabelas SF2, SD1, SC5 e SE1 em instâncias com mais de 10 anos de dados, avaliando índices, planos de execução e uso de CTEs.
Fine-tuning de BERTimbau para classificação de tickets de suporte em português, atingindo 94% de acurácia em produção com latência média de 120ms por requisição.
Construção de pipeline ETL usando Python e Airflow para consolidar dados de múltiplas filiais Protheus em um data warehouse centralizado para análise no Power BI.
Tem uma ideia que merece ser investigada? Compartilhe aqui — as melhores sugestões viram pesquisas reais publicadas no site.