Olá pessoal…
Hoje vou mostrar um exemplo que fiz, de função para cadastro de dados em uma tabela genérica – SX5.
O intuito da rotina, é liberar o cadastro de informações nas tabelas genéricas para um usuário comum, que se fosse uma pequena AxCadastro de manipulação dos dados.
Para utilizar a rotina, basta passar por parâmetro qual é a tabela genérica e o título da rotina.
Ao executar, é mostrado uma grid com os registros da tabela genérica.
Ao clicar em Incluir, Alterar, etc é mostrado a tela, porém sem o campo de Tabela, apenas a Chave e os dados, e a Chave liberada apenas na Inclusão.
Fonte Novo (2024)
Foi atualizado o fonte, dando uma modernizada nos comandos.
Abaixo segue o código:
//Bibliotecas #Include "Totvs.ch" #Include "FWMVCDef.ch" //Variveis Estaticas Static cTitulo := "Tabelas Genéricas" Static cAliasMVC := "SX5" /*/{Protheus.doc} User Function zCadSX5 Cadastro de Tabela Genérica @author Atilio @since 15/02/2024 @version 1.0 @type function @example u_zCadSX5("01", "Séries de NF") /*/ User Function zCadSX5(cTabela, cTitTela) Local aArea := FWGetArea() Local oBrowse Local aInfoCab := {} Local aColunas := {} Private aRotina := {} Private cTabGen := "" Default cTabela := "" Default cTitTela := "" //Somente se tiver tabela If ! Empty(cTabela) //Atualiza a tabela em uso e o título cTabGen := cTabela cTitulo := cTitTela //Se o título tiver vazio, busca do cadastro do cabeçalho da tabela If Empty(cTitulo) aInfoCab := FWGetSX5("00", cTabGen) cTitulo := Alltrim(Capital(aInfoCab[1][4])) EndIf //Definicao do menu aRotina := MenuDef() //Adiciona as colunas que vão ser apresentadas no browse aAdd(aColunas, { 'Código', 'X5_CHAVE', 'C', TamSX3('X5_CHAVE')[1], 0, ''}) aAdd(aColunas, { 'Descrição', 'X5_DESCRI', 'C', TamSX3('X5_DESCRI')[1], 0, ''}) //Instanciando o browse oBrowse := FWMBrowse():New() oBrowse:SetAlias(cAliasMVC) oBrowse:SetOnlyFields({"X5_FILIAL"}) oBrowse:SetFields(aColunas) oBrowse:SetDescription(cTitulo) oBrowse:DisableDetails() //Filtrando conforme a tabela que veio oBrowse:SetFilterDefault("SX5->X5_TABELA == '" + cTabGen + "'") //Ativa a Browse oBrowse:Activate() EndIf FWRestArea(aArea) Return Nil /*/{Protheus.doc} MenuDef Menu de opcoes na funcao zCadSX5 @author Atilio @since 15/02/2024 @version 1.0 @type function /*/ Static Function MenuDef() Local aRotina := {} //Adicionando opcoes do menu ADD OPTION aRotina TITLE "Visualizar" ACTION "VIEWDEF.zCadSX5" OPERATION 1 ACCESS 0 ADD OPTION aRotina TITLE "Incluir" ACTION "VIEWDEF.zCadSX5" OPERATION 3 ACCESS 0 ADD OPTION aRotina TITLE "Alterar" ACTION "VIEWDEF.zCadSX5" OPERATION 4 ACCESS 0 //ADD OPTION aRotina TITLE "Excluir" ACTION "VIEWDEF.zCadSX5" OPERATION 5 ACCESS 0 ADD OPTION aRotina TITLE "Copiar" ACTION "VIEWDEF.zCadSX5" OPERATION 9 ACCESS 0 Return aRotina /*/{Protheus.doc} ModelDef Modelo de dados na funcao zCadSX5 @author Atilio @since 15/02/2024 @version 1.0 @type function /*/ Static Function ModelDef() Local oStruct := FWFormStruct(1, cAliasMVC) Local oModel Local bPre := Nil Local bPos := {|| u_zSX5Vld()} Local bCancel := Nil //Editando características do dicionário oStruct:SetProperty('X5_TABELA', MODEL_FIELD_WHEN, FwBuildFeature(STRUCT_FEATURE_WHEN, '.F.')) //Modo de Edição oStruct:SetProperty('X5_TABELA', MODEL_FIELD_INIT, FwBuildFeature(STRUCT_FEATURE_INIPAD, 'cTabGen')) //Ini Padrão oStruct:SetProperty('X5_CHAVE', MODEL_FIELD_WHEN, FwBuildFeature(STRUCT_FEATURE_WHEN, 'Iif(INCLUI, .T., .F.)')) //Modo de Edição oStruct:SetProperty('X5_CHAVE', MODEL_FIELD_VALID, FwBuildFeature(STRUCT_FEATURE_VALID, 'u_zSX5Vld()')) //Validação de Campo oStruct:SetProperty('X5_CHAVE', MODEL_FIELD_OBRIGAT, .T. ) //Campo Obrigatório oStruct:SetProperty('X5_DESCRI', MODEL_FIELD_OBRIGAT, .T. ) //Campo Obrigatório //Cria o modelo de dados para cadastro oModel := MPFormModel():New("zCadSX5M", bPre, bPos, /*bCommit*/, bCancel) oModel:AddFields("SX5MASTER", /*cOwner*/, oStruct) oModel:SetPrimaryKey({'X5_FILIAL', 'X5_TABELA', 'X5_CHAVE'}) oModel:SetDescription("Modelo de dados - " + cTitulo) oModel:GetModel("SX5MASTER"):SetDescription( "Dados de - " + cTitulo) oModel:SetPrimaryKey({}) Return oModel /*/{Protheus.doc} ViewDef Visualizacao de dados na funcao zCadSX5 @author Atilio @since 15/02/2024 @version 1.0 @type function /*/ Static Function ViewDef() Local cCamposPrin := "X5_CHAVE|X5_DESCRI|" Local oModel := FWLoadModel("zCadSX5") Local oStructPrin := FWFormStruct(2, cAliasMVC, {|cCampo| AllTrim(cCampo) $ cCamposPrin}) Local oStructOutr := FWFormStruct(2, cAliasMVC, {|cCampo| ! AllTrim(cCampo) $ cCamposPrin}) Local oView //Retira as abas padrões oStructPrin:SetNoFolder() oStructOutr:SetNoFolder() //Altera o título dos campos principais oStructPrin:SetProperty('X5_CHAVE', MVC_VIEW_TITULO, 'Código') oStructPrin:SetProperty('X5_DESCRI', MVC_VIEW_TITULO, 'Descrição') //Altera o título dos outros campos oStructOutr:SetProperty('X5_TABELA', MVC_VIEW_TITULO, 'Código Interno Tabela') oStructOutr:SetProperty('X5_DESCSPA', MVC_VIEW_TITULO, 'Descrição Espanhol') oStructOutr:SetProperty('X5_DESCENG', MVC_VIEW_TITULO, 'Descrição Inglês') //Cria a visualizacao do cadastro oView := FWFormView():New() oView:SetModel(oModel) oView:AddField("VIEW_PRIN", oStructPrin, "SX5MASTER") oView:AddField("VIEW_OUTR", oStructOutr, "SX5MASTER") //Cria o controle de Abas oView:CreateFolder('ABAS') oView:AddSheet('ABAS', 'ABA_PRIN', 'Cadastro') oView:AddSheet('ABAS', 'ABA_OUTR', 'Outros Campos') //Cria os Box que serão vinculados as abas oView:CreateHorizontalBox('BOX_PRIN' ,100, /*owner*/, /*lUsePixel*/, 'ABAS', 'ABA_PRIN') oView:CreateHorizontalBox('BOX_OUTR' ,100, /*owner*/, /*lUsePixel*/, 'ABAS', 'ABA_OUTR') //Amarra as Abas aos Views de Struct criados oView:SetOwnerView('VIEW_PRIN', 'BOX_PRIN') oView:SetOwnerView('VIEW_OUTR', 'BOX_OUTR') Return oView /*/{Protheus.doc} zSX5Vld Função que valida a digitação do campo Chave, para verificar se já existe @type function @author Atilio @since 15/02/2024 @version 1.0 /*/ User Function zSX5Vld() Local aArea := GetArea() Local lRet := .T. Local cX5Chave := FWFldGet("X5_CHAVE") Local oModel := FWModelActive() Local nOper := oModel:GetOperation() //Se for operação de inclusão (ou a cópia) If nOper == 3 DbSelectArea('SX5') SX5->(DbSetOrder(1)) // X5_FILIAL+X5_TABELA+X5_CHAVE SX5->(DbGoTop()) //Se conseguir posicionar, já existe If SX5->(DbSeek(FWxFilial('SX5') + cTabGen + cX5Chave)) ExibeHelp("Help", "Código já existe!", "Informe um código diferente.") lRet := .F. EndIf EndIf RestArea(aArea) Return lRet
Fonte Original (2016)
Abaixo o exemplo do código fonte desenvolvido lá em 2016, que na época funcionava bem no Protheus 11.
//Bibliotecas #Include 'Protheus.ch' #Include 'FWMVCDef.ch' //Variáveis Estáticas Static cTitulo := "" /*/{Protheus.doc} zCadSX5 Cadastro de tabelas SX5 @author Atilio @since 05/08/2016 @version 1.0 @param cTabela, character, Código da tabela genérica @param cTitRot, character, Título da Rotina @example u_zCadSX5("01", "Séries de NF") /*/ User Function zCadSX5(cTabela, cTitRot) Local aArea := GetArea() Local oBrowse Local cFunBkp := FunName() Default cTitRot := "" Private cTabX := cTabela //Senão tiver chave, finaliza If Empty(cTabela) Return EndIf DbSelectArea('SX5') SX5->(DbSetOrder(1)) // X5_FILIAL+X5_TABELA+X5_CHAVE SX5->(DbGoTop()) //Se vier título por parâmetro If !Empty(cTitRot) cTitulo := cTitRot EndIf //Se ainda tiver em branco, pega o da própria tabela If Empty(cTitulo) //Se conseguir posicionar If SX5->(DbSeek(FWxFilial("SX5") + "00" + cTabela)) cTitulo := SX5->X5_DESCRI Else MsgAlert("Tabela não encontrada!", "Atenção") Return EndIf EndIf //Instânciando FWMBrowse - Somente com dicionário de dados SetFunName("zCadSX5") oBrowse := FWMBrowse():New() //Setando a tabela de cadastro de Autor/Interprete oBrowse:SetAlias("SX5") //Setando a descrição da rotina oBrowse:SetDescription(cTitulo) //Filtrando oBrowse:SetFilterDefault("SX5->X5_TABELA = '"+cTabela+"'") //Ativa a Browse oBrowse:Activate() SetFunName(cFunBkp) RestArea(aArea) Return /*---------------------------------------------------------------------* | Func: MenuDef | | Autor: Daniel Atilio | | Data: 05/08/2016 | | Desc: Criação do menu MVC | *---------------------------------------------------------------------*/ Static Function MenuDef() Local aRot := {} //Adicionando opções ADD OPTION aRot TITLE 'Visualizar' ACTION 'VIEWDEF.zCadSX5' OPERATION MODEL_OPERATION_VIEW ACCESS 0 //OPERATION 1 ADD OPTION aRot TITLE 'Incluir' ACTION 'VIEWDEF.zCadSX5' OPERATION MODEL_OPERATION_INSERT ACCESS 0 //OPERATION 3 ADD OPTION aRot TITLE 'Alterar' ACTION 'VIEWDEF.zCadSX5' OPERATION MODEL_OPERATION_UPDATE ACCESS 0 //OPERATION 4 ADD OPTION aRot TITLE 'Excluir' ACTION 'VIEWDEF.zCadSX5' OPERATION MODEL_OPERATION_DELETE ACCESS 0 //OPERATION 5 Return aRot /*---------------------------------------------------------------------* | Func: ModelDef | | Autor: Daniel Atilio | | Data: 05/08/2016 | | Desc: Criação do modelo de dados MVC | *---------------------------------------------------------------------*/ Static Function ModelDef() //Criação do objeto do modelo de dados Local oModel := Nil //Criação da estrutura de dados utilizada na interface Local oStSX5 := FWFormStruct(1, "SX5") //Editando características do dicionário oStSX5:SetProperty('X5_TABELA', MODEL_FIELD_WHEN, FwBuildFeature(STRUCT_FEATURE_WHEN, '.F.')) //Modo de Edição oStSX5:SetProperty('X5_TABELA', MODEL_FIELD_INIT, FwBuildFeature(STRUCT_FEATURE_INIPAD, 'cTabX')) //Ini Padrão oStSX5:SetProperty('X5_CHAVE', MODEL_FIELD_WHEN, FwBuildFeature(STRUCT_FEATURE_WHEN, 'Iif(INCLUI, .T., .F.)')) //Modo de Edição oStSX5:SetProperty('X5_CHAVE', MODEL_FIELD_VALID, FwBuildFeature(STRUCT_FEATURE_VALID, 'u_zSX5Chv()')) //Validação de Campo oStSX5:SetProperty('X5_CHAVE', MODEL_FIELD_OBRIGAT, .T. ) //Campo Obrigatório oStSX5:SetProperty('X5_DESCRI', MODEL_FIELD_OBRIGAT, .T. ) //Campo Obrigatório //Instanciando o modelo, não é recomendado colocar nome da user function (por causa do u_), respeitando 10 caracteres oModel := MPFormModel():New("zCadSX5M",/*bPre*/,/*bPos*/,/*bCommit*/,/*bCancel*/) //Atribuindo formulários para o modelo oModel:AddFields("FORMSX5",/*cOwner*/,oStSX5) //Setando a chave primária da rotina oModel:SetPrimaryKey({'X5_FILIAL', 'X5_TABELA', 'X5_CHAVE'}) //Adicionando descrição ao modelo oModel:SetDescription("Modelo de Dados do Cadastro "+cTitulo) //Setando a descrição do formulário oModel:GetModel("FORMSX5"):SetDescription("Formulário do Cadastro "+cTitulo) Return oModel /*---------------------------------------------------------------------* | Func: ViewDef | | Autor: Daniel Atilio | | Data: 05/08/2016 | | Desc: Criação da visão MVC | *---------------------------------------------------------------------*/ Static Function ViewDef() //Criação do objeto do modelo de dados da Interface do Cadastro de Autor/Interprete Local oModel := FWLoadModel("zCadSX5") //Criação da estrutura de dados utilizada na interface do cadastro de Autor Local oStSX5 := FWFormStruct(2, "SX5") //pode se usar um terceiro parâmetro para filtrar os campos exibidos { |cCampo| cCampo $ 'SX5_NOME|SX5_DTAFAL|'} //Criando oView como nulo Local oView := Nil //Criando a view que será o retorno da função e setando o modelo da rotina oView := FWFormView():New() oView:SetModel(oModel) //Atribuindo formulários para interface oView:AddField("VIEW_SX5", oStSX5, "FORMSX5") //Criando um container com nome tela com 100% oView:CreateHorizontalBox("TELA",100) //Colocando título do formulário oView:EnableTitleView('VIEW_SX5', 'Dados - '+cTitulo ) //Força o fechamento da janela na confirmação oView:SetCloseOnOk({||.T.}) //O formulário da interface será colocado dentro do container oView:SetOwnerView("VIEW_SX5","TELA") //Retira o campo de tabela da visualização oStSX5:RemoveField("X5_TABELA") Return oView /*/{Protheus.doc} zSX5Chv Função que valida a digitação do campo Chave, para verificar se já existe @type function @author Atilio @since 05/08/2016 @version 1.0 /*/ User Function zSX5Chv() Local aArea := GetArea() Local lRet := .T. Local cX5Chave := M->X5_CHAVE DbSelectArea('SX5') SX5->(DbSetOrder(1)) // X5_FILIAL+X5_TABELA+X5_CHAVE SX5->(DbGoTop()) //Se conseguir posicionar, já existe If SX5->(DbSeek(FWxFilial('SX5') + cTabX + cX5Chave)) MsgAlert("Já existe chave com esse código (<b>"+cX5Chave+"</b>)!", "Atenção") lRet := .F. EndIf RestArea(aArea) Return lRet
Bom pessoal, por hoje é só.
Abraços e até a próxima.
Onde devo chamar as funções estáticas?
Bom dia Maycon, tudo bem?
Não entendi a dúvida. Você quer acionar as funções estáticas isoladamente?
Pois como é um fonte em MVC, você não precisa fazer isso, basta criar uma função, por exemplo:
Ai no menu do sistema, você coloca essa função zTst.
Ao tentar excluir aparece esse erro “CPA_CODNAT”: invalid identifier
e a query
SELECT 1 REG FROM SX5300 DOM WHERE X5_FILIAL = ‘ ‘ AND X5_TABELA = ‘Z4’ AND X5_CHAVE = ‘329 ‘ AND EXISTS (SELECT 1 FROM CPA300 CDOM WHERE CPA_FILIAL = ‘ ‘ AND ‘LX’ = ‘Z4’ AND CPA_CODNAT = ‘329 ‘ AND CDOM.D_E_L_E_T_ = ‘ ‘ ) on FWESX9EXEC(FWEVALSX9.PRW) 27/06/2024 17:13:41 line : 513
o que pode ser?
Bom dia Vinicius, tudo joia?
Então, até deixei o Excluir comentado do fonte por causa disso.
Por padrão, o MVC vai validar se tem algum Relation na SX9 para poder prosseguir com a exclusão.
Como é a SX5, ai ele pode dar problemas na montagem da query que faz essa validação.
Então para exclusão de informações, o indicado é usar o SIGACFG.
Tenha uma ótima e abençoada terça feira.
Um grande abraço.