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.
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:
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.
Feito isso será aberto um browse com os registros.
E ao clicar em Visualizar, ele mostra as informações dos logs.
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:
| Tabela | Onde 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.





Muito boa essa dica, não conhecia essa funcionalidade, valeu Atilio.
Opa, nós que agradecemos pelo comentário.
Um grande abraço.
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.