Refazer SF1 quando não tem dados

Nesse artigo vamos demonstrar uma customização para recriar a SF1 quando não há dados lançados nela.

Infelizmente pessoal, pode ser que existam cenários, ou bugs, principalmente em ambientes customizados ou quando há alguma queda de energia, onde corrompem as informações de alguma tabela.

 

Ou até mesmo algum “des-posicionamento” de informações.

 

Já pegamos essa situação em mais de um cliente com a tabela SF1, onde as informações tinham na SD1, mas a SF1 não constava nada lançado para ela.

 

Como não conhecíamos o cenário da empresa,  nem as customizações envolvidas, o que fizemos foi o seguinte:

  1. Uma rotina que lê a SD1
  2. Abre uma tela de markbrowse e o usuário seleciona os registros
  3. É recriado as informações da SF1
  4. Nisso, o usuário depois de recriar, ele tem que ir na tela de documento de entrada e excluir o registro
  5. Depois lançar novamente

 

Isso pessoal, é apenas um paliativo, até vocês investigarem o que houve e corrigirem de fato o problema. No cenário que pegamos, era um ponto de entrada que em certas condições “des-posicionava” a SF1 no momento da gravação (falta de FWGetArea e FWRestArea).

 

Abaixo o código fonte criado para refazer a SF1:

//Bibliotecas
#Include "Totvs.ch"
#Include "FWMVCDef.ch"
#Include "TopConn.ch"

/*/{Protheus.doc} User Function zRefazSF1
Refaz SF1
@author Daniel Atilio
@since 10/10/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

User Function zRefazSF1()
	Local aArea := FWGetArea()
	Local aPergs   := {}
	Local xPar0 := sToD(cValToChar(Year(Date())) + "0101")
	
	//Adicionando os parametros do ParamBox
	aAdd(aPergs, {1, "Considera a partir de", xPar0,  "", ".T.", "", ".T.", 80,  .T.})
	
	//Se a pergunta for confirma, chama a tela
	If ParamBox(aPergs, "Informe os parametros", , , , , , , , , .F., .F.)
		fMontaTela()
	EndIf
	
	FWRestArea(aArea)
Return

/*/{Protheus.doc} fMontaTela
Monta a tela com a marcação de dados
@author Daniel Atilio
@since 10/10/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

Static Function fMontaTela()
    Local aArea         := GetArea()
    Local aCampos := {}
    Local oTempTable := Nil
    Local aColunas := {}
    Local cFontPad    := 'Tahoma'
    Local oFontGrid   := TFont():New(cFontPad,,-14)
    //Janela e componentes
    Private oDlgMark
    Private oPanGrid
    Private oMarkBrowse
    Private cAliasTmp := GetNextAlias()
    Private aRotina   := MenuDef()
    //Tamanho da janela
    Private aTamanho := MsAdvSize()
    Private nJanLarg := aTamanho[5]
    Private nJanAltu := aTamanho[6]
     
    //Adiciona as colunas que serão criadas na temporária
    aAdd(aCampos, { 'OK',         'C', 2, 0}) //Flag para marcação
    aAdd(aCampos, { 'D1_FILIAL',  'C', TamSX3('D1_FILIAL')[1], 0}) //Filial
    aAdd(aCampos, { 'D1_DOC',     'C', TamSX3('D1_DOC')[1], 0}) //Documento
    aAdd(aCampos, { 'D1_SERIE',   'C', TamSX3('D1_SERIE')[1], 0}) //Série
    aAdd(aCampos, { 'D1_FORNECE', 'C', TamSX3('D1_FORNECE')[1], 0}) //Fornecedor
    aAdd(aCampos, { 'D1_LOJA',    'C', TamSX3('D1_LOJA')[1], 0}) //Loja
    aAdd(aCampos, { 'D1_DTDIGIT', 'D', TamSX3('D1_DTDIGIT')[1], 0}) //Data Inclusão
    aAdd(aCampos, { 'D1_EMISSAO', 'D', TamSX3('D1_EMISSAO')[1], 0}) //Data Emissão
    aAdd(aCampos, { 'D1_TIPO',    'C', TamSX3('D1_TIPO')[1], 0}) //Tipo

    //Cria a tabela temporária
    oTempTable:= FWTemporaryTable():New(cAliasTmp)
    oTempTable:SetFields( aCampos )
    oTempTable:Create()  

    //Popula a tabela temporária
    Processa({|| fPopula()}, 'Processando...')

    //Adiciona as colunas que serão exibidas no FWMarkBrowse
    aColunas := fCriaCols()
     
    //Criando a janela
    DEFINE MSDIALOG oDlgMark TITLE 'Tela para Marcação de dados - Autumn Code Maker' FROM 000, 000  TO nJanAltu, nJanLarg COLORS 0, 16777215 PIXEL
        //Dados
        oPanGrid := tPanel():New(001, 001, '', oDlgMark, , , , RGB(000,000,000), RGB(254,254,254), (nJanLarg/2)-1,     (nJanAltu/2 - 1))
        oMarkBrowse := FWMarkBrowse():New()
        oMarkBrowse:SetAlias(cAliasTmp)                
        oMarkBrowse:SetDescription('NFs nao encontradas - Refazer SF1 baseado na SD1')
        oMarkBrowse:DisableFilter()
        oMarkBrowse:DisableConfig()
        oMarkBrowse:DisableSeek()
        oMarkBrowse:DisableSaveConfig()
        oMarkBrowse:SetFontBrowse(oFontGrid)
        oMarkBrowse:SetFieldMark('OK')
        oMarkBrowse:SetTemporary(.T.)
        oMarkBrowse:SetColumns(aColunas)
        //oMarkBrowse:AllMark() 
        oMarkBrowse:SetOwner(oPanGrid)
        oMarkBrowse:Activate()
    ACTIVATE MsDialog oDlgMark CENTERED
    
    //Deleta a temporária e desativa a tela de marcação
    oTempTable:Delete()
    oMarkBrowse:DeActivate()
    
    RestArea(aArea)
Return

/*/{Protheus.doc} MenuDef
Botões usados no Browse
@author Daniel Atilio
@since 10/10/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

Static Function MenuDef()
    Local aRotina := {}
     
    //Criação das opções
    ADD OPTION aRotina TITLE 'Continuar'  ACTION 'u_zCOMM21O'     OPERATION 2 ACCESS 0
Return aRotina

/*/{Protheus.doc} fPopula
Executa a query SQL e popula essa informação na tabela temporária usada no browse
@author Daniel Atilio
@since 10/10/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

Static Function fPopula()
    Local cQryDados := ''
    Local nTotal := 0
    Local nAtual := 0

    //Monta a consulta
    cQryDados += "SELECT "		+ CRLF
    cQryDados += " D1_FILIAL, "		+ CRLF
    cQryDados += " D1_DOC, "		+ CRLF
    cQryDados += " D1_SERIE, "		+ CRLF
    cQryDados += " D1_FORNECE, "		+ CRLF
    cQryDados += " D1_LOJA, "		+ CRLF
    cQryDados += " D1_DTDIGIT, "		+ CRLF
    cQryDados += " D1_EMISSAO, "		+ CRLF
    cQryDados += " D1_TIPO, "		+ CRLF
    cQryDados += " COUNT(SF1.F1_DOC) AS TOTAL "		+ CRLF
    cQryDados += "FROM "		+ CRLF
    cQryDados += " " + RetSQLName("SD1") + " SD1 "		+ CRLF
    cQryDados += " LEFT JOIN " + RetSQLName("SF1") + " SF1 ON ( "		+ CRLF
    cQryDados += " F1_FILIAL = D1_FILIAL "		+ CRLF
    cQryDados += " AND F1_DOC = D1_DOC "		+ CRLF
    cQryDados += " AND F1_SERIE = D1_SERIE "		+ CRLF
    cQryDados += " AND F1_FORNECE = D1_FORNECE "		+ CRLF
    cQryDados += " AND F1_LOJA = D1_LOJA "		+ CRLF
    cQryDados += " AND SF1.D_E_L_E_T_ = ' ' "		+ CRLF
    cQryDados += " ) "		+ CRLF
    cQryDados += "WHERE "		+ CRLF
    cQryDados += " D1_DTDIGIT >= '" + dToS(MV_PAR01) + "' "		+ CRLF
    cQryDados += " AND SD1.D_E_L_E_T_ = ' ' "		+ CRLF
    cQryDados += "GROUP BY "		+ CRLF
    cQryDados += " D1_FILIAL, "		+ CRLF
    cQryDados += " D1_DOC, "		+ CRLF
    cQryDados += " D1_SERIE, "		+ CRLF
    cQryDados += " D1_FORNECE, "		+ CRLF
    cQryDados += " D1_LOJA, "		+ CRLF
    cQryDados += " D1_DTDIGIT, "		+ CRLF
    cQryDados += " D1_EMISSAO, "		+ CRLF
    cQryDados += " D1_TIPO "		+ CRLF
    cQryDados += "HAVING "		+ CRLF
    cQryDados += " COUNT(SF1.F1_DOC) = 0 "		+ CRLF
    cQryDados += "ORDER BY TOTAL DESC"		+ CRLF
    TCQuery cQryDados New Alias 'QRYDADTMP'
    TCSetField('QRYDADTMP', 'D1_DTDIGIT', 'D')
    TCSetField('QRYDADTMP', 'D1_EMISSAO', 'D')

    //Definindo o tamanho da régua
    DbSelectArea('QRYDADTMP')
    Count to nTotal
    ProcRegua(nTotal)
    QRYDADTMP->(DbGoTop())

    //Enquanto houver registros, adiciona na temporária
    While ! QRYDADTMP->(EoF())
        nAtual++
        IncProc('Analisando registro ' + cValToChar(nAtual) + ' de ' + cValToChar(nTotal) + '...')

        RecLock(cAliasTmp, .T.)
            (cAliasTmp)->OK := Space(2)
            (cAliasTmp)->D1_FILIAL := QRYDADTMP->D1_FILIAL
            (cAliasTmp)->D1_DOC := QRYDADTMP->D1_DOC
            (cAliasTmp)->D1_SERIE := QRYDADTMP->D1_SERIE
            (cAliasTmp)->D1_FORNECE := QRYDADTMP->D1_FORNECE
            (cAliasTmp)->D1_LOJA := QRYDADTMP->D1_LOJA
            (cAliasTmp)->D1_DTDIGIT := QRYDADTMP->D1_DTDIGIT
            (cAliasTmp)->D1_EMISSAO := QRYDADTMP->D1_EMISSAO
            (cAliasTmp)->D1_TIPO := QRYDADTMP->D1_TIPO
        (cAliasTmp)->(MsUnlock())

        QRYDADTMP->(DbSkip())
    EndDo
    QRYDADTMP->(DbCloseArea())
    (cAliasTmp)->(DbGoTop())
Return

/*/{Protheus.doc} fCriaCols
Função que gera as colunas usadas no browse (similar ao antigo aHeader)
@author Daniel Atilio
@since 10/10/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

Static Function fCriaCols()
    Local nAtual       := 0 
    Local aColunas := {}
    Local aEstrut  := {}
    Local oColumn
    
    //Adicionando campos que serão mostrados na tela
    //[1] - Campo da Temporaria
    //[2] - Titulo
    //[3] - Tipo
    //[4] - Tamanho
    //[5] - Decimais
    //[6] - Máscara
    aAdd(aEstrut, { 'D1_FILIAL',  'Filial',        'C', TamSX3('D1_FILIAL')[1], 0, ''})
    aAdd(aEstrut, { 'D1_DOC',     'Documento',     'C', TamSX3('D1_DOC')[1], 0, ''})
    aAdd(aEstrut, { 'D1_SERIE',   'Série',         'C', TamSX3('D1_SERIE')[1], 0, ''})
    aAdd(aEstrut, { 'D1_FORNECE', 'Fornecedor',    'C', TamSX3('D1_FORNECE')[1], 0, ''})
    aAdd(aEstrut, { 'D1_LOJA',    'Loja',          'C', TamSX3('D1_LOJA')[1], 0, ''})
    aAdd(aEstrut, { 'D1_DTDIGIT', 'Data Inclusão', 'D', TamSX3('D1_DTDIGIT')[1], 0, ''})
    aAdd(aEstrut, { 'D1_EMISSAO', 'Data Emissão',  'D', TamSX3('D1_EMISSAO')[1], 0, ''})
    aAdd(aEstrut, { 'D1_TIPO',    'Tipo',          'C', TamSX3('D1_TIPO')[1], 0, ''})

    //Percorrendo todos os campos da estrutura
    For nAtual := 1 To Len(aEstrut)
        //Cria a coluna
        oColumn := FWBrwColumn():New()
        oColumn:SetData(&('{|| ' + cAliasTmp + '->' + aEstrut[nAtual][1] +'}'))
        oColumn:SetTitle(aEstrut[nAtual][2])
        oColumn:SetType(aEstrut[nAtual][3])
        oColumn:SetSize(aEstrut[nAtual][4])
        oColumn:SetDecimal(aEstrut[nAtual][5])
        oColumn:SetPicture(aEstrut[nAtual][6])

        //Adiciona a coluna
        aAdd(aColunas, oColumn)
    Next
Return aColunas

/*/{Protheus.doc} User Function zCOMM21O
Função acionada pelo botão continuar da rotina
@author Daniel Atilio
@since 10/10/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

User Function zCOMM21O()
    Processa({|| fProcessa()}, 'Processando...')
Return

/*/{Protheus.doc} fProcessa
Função que percorre os registros da tela
@author Daniel Atilio
@since 10/10/2022
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/

Static Function fProcessa()
    Local aArea     := FWGetArea()
    Local cMarca    := oMarkBrowse:Mark()
    Local nAtual    := 0
    Local nTotal    := 0
    Local nTotMarc := 0
    
    //Define o tamanho da régua
    DbSelectArea(cAliasTmp)
    (cAliasTmp)->(DbGoTop())
    Count To nTotal
    ProcRegua(nTotal)
    
    //Percorrendo os registros
    (cAliasTmp)->(DbGoTop())
    While ! (cAliasTmp)->(EoF())
        nAtual++
        IncProc('Analisando registro ' + cValToChar(nAtual) + ' de ' + cValToChar(nTotal) + '...')
    
        //Caso esteja marcado
        If oMarkBrowse:IsMark(cMarca)
            nTotMarc++

            RecLock("SF1", .T.)
                SF1->F1_FILIAL  := (cAliasTmp)->D1_FILIAL 
                SF1->F1_DOC     := (cAliasTmp)->D1_DOC
                SF1->F1_SERIE   := (cAliasTmp)->D1_SERIE 
                SF1->F1_FORNECE := (cAliasTmp)->D1_FORNECE 
                SF1->F1_LOJA    := (cAliasTmp)->D1_LOJA 
                SF1->F1_DTDIGIT := (cAliasTmp)->D1_DTDIGIT 
                SF1->F1_EMISSAO := (cAliasTmp)->D1_EMISSAO 
                SF1->F1_TIPO    := (cAliasTmp)->D1_TIPO 
                SF1->F1_DUPL    := (cAliasTmp)->D1_DOC
                SF1->F1_ESPECIE := "SPED"
                SF1->F1_STATUS  := "A"
                SF1->F1_ORIGEM  := "zRefazSF1"
            SF1->(MsUnlock())
        EndIf
         
        (cAliasTmp)->(DbSkip())
    EndDo
    
    //Mostra a mensagem de término e caso queria fechar a dialog, basta usar o método End()
    FWAlertSuccess('Dos [' + cValToChar(nTotal) + '] registros, foram processados [' + cValToChar(nTotMarc) + '] registros', 'Atenção')
    oDlgMark:End()

    FWRestArea(aArea)
Return

Bom pessoal, por hoje é só.

 

Abraços e até a próxima.

Dan (Daniel Atilio)
Cristão de ramificação protestante. Especialista em Engenharia de Software pela FIB, graduado em Banco de Dados pela FATEC Bauru e técnico em informática pelo CTI da Unesp. Entusiasta de soluções Open Source e blogueiro nas horas vagas. Autor e mantenedor do portal Terminal de Informação.

Deixe uma resposta

Terminal de Informação