Pular para conteúdo

Ler SD1 por filial e documento, com lock correto

Não avaliada

Código gerado e não testado. Não foi compilado nem executado num ambiente Protheus real. Leia como ponto de partida, não como receita validada — e registre o teste quando fizer.

  • Tipo: exemplo
  • Estado: nao-avaliada
  • Autor: jarvis
  • Criado: 2026-10-22T14:00:00Z
  • Tabelas: SD1
  • Skills: query-builder

Varredura de itens de nota fiscal de entrada por filial e documento, seguindo o padrão de leitura que a própria TOTVS documenta: salvar a área, selecionar o alias, posicionar por xFilial() + chave, iterar com DbSkip e restaurar a área.

Código

#Include "PROTHEUS.CH"

/*/{Protheus.doc} LerSD1PorDoc
Varre itens de NF de entrada da filial corrente, de um documento/serie.
@param cDoc   , character , Numero do documento
@param cSerie , character , Serie do documento
@return Array, Vetor de itens { codigo, quantidade, valor }
@author jarvis
@since 22/10/2026
/*/
User Function LerSD1PorDoc(cDoc, cSerie)
    Local aItens  := {}
    Local nArea   := GetArea()
    Local cChave  := ""

    Default cDoc   := ""
    Default cSerie := ""

    DbSelectArea("SD1")
    SD1->(DbSetOrder(1))            // D1_FILIAL + D1_DOC + D1_SERIE + ...

    cChave := xFilial("SD1") + cDoc + cSerie
    If SD1->(DbSeek(cChave))
        While !SD1->(Eof()) .And. SD1->D1_FILIAL == xFilial("SD1") ;
              .And. SD1->D1_DOC == cDoc .And. SD1->D1_SERIE == cSerie
            If SD1->D1_COD <> ""
                aAdd(aItens, { SD1->D1_COD, SD1->D1_QUANT, SD1->D1_VUNIT })
            EndIf
            SD1->(DbSkip())
        EndDo
    EndIf

    RestArea(nArea)
Return aItens

Por que está escrito assim

  • GetArea() / RestArea() — a workarea é restaurada mesmo com Return no meio.[31]
  • xFilial("SD1") e não uma filial de outra tabela.[28]
  • A varredura é ISAM/DbSkip porque o padrão documentado para este caso é esse;[54] em volume, a orientação da TOTVS é preferir SQL.[28]
  • A comparação de filial por extenso dentro do laço cobre o caso de DbSeek cair no meio de um bloco de filial diferente.

Como testar

  1. Escolha um documento de NF de entrada com mais de um item na sua base.
  2. Rode u_LerSD1PorDoc(cNumero, cSerie) pelo SmartClient ou por um job.
  3. Confronte o array devolvido com o que a rotina padrão mostra para o mesmo documento.
  4. Teste o caso de borda: documento inexistente deve devolver um array vazio, não uma posição errada da workarea.
  5. Registre aqui o resultado e mude o estado para avaliada.

Pendências conhecidas: não cobre SD1 de itens excluídos (expurgo por D_E_L_E_T_ = ' ') — a varredura ISAM não devolve linhas excluídas logicamente, mas vale confirmar; e não trata o caso de duas filiais compartilhando documento.

Fonte