Como habilitar e consultar o log de alterações de Clientes, Fornecedores e Produtos via tabela AIF

No artigo de hoje, vamos demonstrar em como gravar log de alteração de campos dos cadastros de Fornecedores, Clientes, etc através da tabela padrão AIF.

Para habilitar esse recurso, vá no configurador e altere o parâmetro MV_HISTTAB.

Habilitando o parâmetro

Feito isso, ao fazer alterações nos cadastros citados abaixo, será gravado um log de alteração (através da função MSGrvHist):

  • SA1 – Clientes – MATA030 / CRMA980
  • SA2 – Fornecedores – MATA020
  • SA4 – Transportadoras – MATA050
  • SA5 – Produtos x Fornecedores – MATA060
  • SB1 – Produtos – MATA010

Abaixo um print dos logs salvos:

Visualizando os logs em uma query SQL

Para consultar em tela, eu não consegui encontrar uma rotina padrão, então desenvolvi uma rotina em MVC básica para fazer as consultas, sendo que ao abrir, será exibido uma tela de parâmetros caso deseja filtrar o browse.

Tela de Parâmetros

Feito isso será aberto um browse com os registros.

Listagem de dados no browse

E ao clicar em Visualizar, ele mostra as informações dos logs.

Visualizando o log

Abaixo o código fonte desenvolvido:

//Bibliotecas
#Include "Totvs.ch"
#Include "FWMVCDef.ch"
  
//Variveis Estaticas
Static cTitulo := "Logs da AIF"
Static cAliasMVC := "AIF"
  
/*/{Protheus.doc} User Function zVerAIF
Tela para visualizar logs da AIF
@author Atilio
@since 07/02/2023
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/
  
User Function zVerAIF()
    Local aArea   := FWGetArea()
    Local oBrowse
    Private aRotina := {}
  
    //Definicao do menu
    aRotina := MenuDef()
  
    //Instanciando o browse
    oBrowse := FWMBrowse():New()
    oBrowse:SetAlias(cAliasMVC)
    oBrowse:SetDescription(cTitulo)
    oBrowse:DisableDetails()
  
    //Adicionando as Legendas
    oBrowse:AddLegend( "AIF->AIF_TABELA == 'SA2'", "BLACK",     "Fornecedores" )
    oBrowse:AddLegend( "AIF->AIF_TABELA == 'SB1'", "BLUE",      "Produtos" )
    oBrowse:AddLegend( "AIF->AIF_TABELA == 'SA5'", "GREEN",     "Produtos x Fornecedores" )
    oBrowse:AddLegend( "AIF->AIF_TABELA == 'SA1'", "ORANGE",    "Clientes" )
    oBrowse:AddLegend( "AIF->AIF_TABELA == 'SA4'", "RED",       "Transportadoras" )
  
    //Filtrando o browse
    cFiltro := fMontaFilt()
    If ! Empty(cFiltro)
        oBrowse:SetFilterDefault(cFiltro)
    EndIf
  
    //Ativa a Browse
    oBrowse:Activate()
  
    FWRestArea(aArea)
Return Nil
  
/*/{Protheus.doc} MenuDef
Menu de opcoes na funcao zVerAIF
@author Atilio
@since 07/02/2023
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/
  
Static Function MenuDef()
    Local aRotina := {}
  
    //Adicionando opcoes do menu
    ADD OPTION aRotina TITLE "Visualizar" ACTION "VIEWDEF.zVerAIF" OPERATION 1 ACCESS 0
  
Return aRotina
  
/*/{Protheus.doc} ModelDef
Modelo de dados na funcao zVerAIF
@author Atilio
@since 07/02/2023
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/
  
Static Function ModelDef()
    Local oStruct := FWFormStruct(1, cAliasMVC)
    Local oModel
    Local bPre := Nil
    Local bPos := Nil
    Local bCommit := Nil
    Local bCancel := Nil
  
  
    //Cria o modelo de dados para cadastro
    oModel := MPFormModel():New("zVerAIFM", bPre, bPos, bCommit, bCancel)
    oModel:AddFields("AIFMASTER", /*cOwner*/, oStruct)
    oModel:SetDescription("Modelo de dados - " + cTitulo)
    oModel:GetModel("AIFMASTER"):SetDescription( "Dados de - " + cTitulo)
    oModel:SetPrimaryKey({})
Return oModel
  
/*/{Protheus.doc} ViewDef
Visualizacao de dados na funcao zVerAIF
@author Atilio
@since 07/02/2023
@version 1.0
@type function
@obs Codigo gerado automaticamente pelo Autumn Code Maker
@see http://autumncodemaker.com
/*/
  
Static Function ViewDef()
    Local oModel := FWLoadModel("zVerAIF")
    Local oStruct := FWFormStruct(2, cAliasMVC)
    Local oView
  
    //Cria a visualizacao do cadastro
    oView := FWFormView():New()
    oView:SetModel(oModel)
    oView:AddField("VIEW_AIF", oStruct, "AIFMASTER")
    oView:CreateHorizontalBox("TELA" , 100 )
    oView:SetOwnerView("VIEW_AIF", "TELA")
  
Return oView
  
/*/{Protheus.doc} fMontaFilt
Função que abre a tela de parâmetros para montagem de filtro no browse
@author Atilio
@since 07/02/2023
@version 1.0
/*/
  
Static Function fMontaFilt()
    Local aArea     := FWGetArea()
    Local cFiltro   := ""
    Local aPergs    := {}
    Local cTabela   := Space(TamSX3('AIF_TABELA')[01])
    Local cCampo    := Space(TamSX3('AIF_CAMPO')[01])
    Local dDataDe   := FirstDate(MonthSub(Date(), 1))
    Local dDataAte  := Date()
  
    //Adiciona os parâmetros que serão exibidos    
    aAdd(aPergs, {1, "Tabela",   cTabela,  "", ".T.", "HSPSX2", ".T.", 40, .F.})
    aAdd(aPergs, {1, "Campo",    cCampo,   "", ".T.", "JURSX3", ".T.", 70, .F.})
    aAdd(aPergs, {1, "Data De",  dDataDe,  "", ".T.", "",       ".T.", 80, .T.})
    aAdd(aPergs, {1, "Data Até", dDataAte, "", ".T.", "",       ".T.", 80, .T.})
      
    //Se a pergunta for confirmada
    If ParamBox(aPergs, "Informe os parâmetros", , , , , , , , , .F., .F.)
        //Filtro da Tabela
        If ! Empty(MV_PAR01)
            cFiltro += "AIF->AIF_TABELA == '" + MV_PAR01 + "'"
        EndIf
  
        //Filtro do campo
        If ! Empty(MV_PAR02)
            If ! Empty(cFiltro)
                cFiltro += " .And. "
            EndIf
            cFiltro += "AIF->AIF_CAMPO == '" + MV_PAR02 + "'"
        EndIf
  
        //Filtro da Data De
        If ! Empty(MV_PAR03)
            If ! Empty(cFiltro)
                cFiltro += " .And. "
            EndIf
            cFiltro += "AIF->AIF_DATA >= sToD('" + dToS(MV_PAR03) + "')"
        EndIf
  
        //Filtro da Data Até
        If ! Empty(MV_PAR04)
            If ! Empty(cFiltro)
                cFiltro += " .And. "
            EndIf
            cFiltro += "AIF->AIF_DATA <= sToD('" + dToS(MV_PAR04) + "')"
        EndIf
    EndIf
  
    FWRestArea(aArea)
Return cFiltro

Update – Agosto de 2023:

Pessoal, o grande Robson Gonçalves ( LinkedIn ), mandou um complemento também para o artigo. Existe um parâmetro chamado MV_HISTFIS, que quando ativado, ele grava logs de algumas tabelas, segue abaixo:

TabelaOnde ficará o log
SF4 (Tipos de Entrada e Saída)SS0
SF7 (Grupo de Tributação)SS1
SA1 (Clientes)SS2
SA2 (Fornecedores)SS3
SB1 (Produtos)SS4
SB5 (Complemento de Produtos)SS5
SBZ (Indicadores de Produtos)SS6
SED (Naturezas)SS7
SFB (Impostos Variáveis)SS8
CFC (UF x UF)SS9

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.

4 Responses

  1. Alexandre Behling disse:

    Muito boa essa dica, não conhecia essa funcionalidade, valeu Atilio.

  2. MAURO MARTINS DE FIGUEIREDO JUNIOR disse:

    não tem como saber o usuário que fez a alteração?

    • Bom dia Mauro, tudo bem?

      Por padrão a AIF não grava o usuário. Ai você pode abrir uma solicitação de melhoria de produto para que a TOTVS crie um campo novo que grave a informação do RetCodUsr() ou verificar se existe algum ponto de entrada após a gravação da AIF para você gravar essa informação.

      Um grande abraço.

Deixe uma resposta para Alexandre BehlingCancelar resposta

Terminal de Informação