Função para criar grupo de perguntas SX1 no Protheus 12

Olá pessoal…

Hoje trago até vocês uma função que fiz para criar um grupo de perguntas (substituindo a PutSX1).

Nas versões mais novas do Protheus 12, a antiga função PutSX1 foi bloqueada para utilização, e se por acaso você também não quer utilizar a ParamBox, eu desenvolvi uma rotina que cria um grupo de perguntas.

Os parâmetros para utilização são:
cGrupo – Grupo de Perguntas (ex.: X_TESTE)
cOrdem – Ordem da Pergunta (ex.: 01, 02, 03, …)
cTexto – Texto da Pergunta (ex.: Produto De, Produto Até, Data De, …)
cMVPar – MV_PAR?? da Pergunta (ex.: MV_PAR01, MV_PAR02, MV_PAR03, …)
cVariavel – Variável da Pergunta (ex.: MV_CH0, MV_CH1, MV_CH2, …)
cTipoCamp – Tipo do Campo (C = Caracter, N = Numérico, D = Data)
nTamanho – Tamanho da Pergunta (Máximo de 60)
nDecimal – Tamanho de Decimais (Máximo de 9)
cTipoPar – Tipo do Parâmetro (G = Get, C = Combo, F = Escolha de Arquivos, K = Check Box)
cValid – Validação da Pergunta (ex.: Positivo(), u_SuaFuncao(), …)
cF3 – Consulta F3 da Pergunta (ex.: SB1, SA1, …)
cPicture – Máscara do Parâmetro (ex.: @!, @E 999.99, …)
cDef01 – Primeira opção do combo
cDef02 – Segunda opção do combo
cDef03 – Terceira opção do combo
cDef04 – Quarta opção do combo
cDef05 – Quinta opção do combo
cHelp – Texto de Help do parâmetro

Abaixo um print de uma pergunta criada através dessa função.

Exemplo de Pergunte criado pela zPutSX1

Exemplo de Pergunte criado pela zPutSX1

Abaixo o código fonte desenvolvido:

//Bibliotecas
#Include "Protheus.ch"

/*/{Protheus.doc} zPutSX1
Função para criar Grupo de Perguntas
@author Atilio
@since 09/06/2017
@version 1.0
@type function
	@param cGrupo,    characters, Grupo de Perguntas       (ex.: X_TESTE)
	@param cOrdem,    characters, Ordem da Pergunta        (ex.: 01, 02, 03, ...)
	@param cTexto,    characters, Texto da Pergunta        (ex.: Produto De, Produto Até, Data De, ...)
	@param cMVPar,    characters, MV_PAR?? da Pergunta     (ex.: MV_PAR01, MV_PAR02, MV_PAR03, ...)
	@param cVariavel, characters, Variável da Pergunta     (ex.: MV_CH0, MV_CH1, MV_CH2, ...)
	@param cTipoCamp, characters, Tipo do Campo            (C = Caracter, N = Numérico, D = Data)
	@param nTamanho,  numeric,    Tamanho da Pergunta      (Máximo de 60)
	@param nDecimal,  numeric,    Tamanho de Decimais      (Máximo de 9)
	@param cTipoPar,  characters, Tipo do Parâmetro        (G = Get, C = Combo, F = Escolha de Arquivos, K = Check Box)
	@param cValid,    characters, Validação da Pergunta    (ex.: Positivo(), u_SuaFuncao(), ...)
	@param cF3,       characters, Consulta F3 da Pergunta  (ex.: SB1, SA1, ...)
	@param cPicture,  characters, Máscara do Parâmetro     (ex.: @!, @E 999.99, ...)
	@param cDef01,    characters, Primeira opção do combo
	@param cDef02,    characters, Segunda opção do combo
	@param cDef03,    characters, Terceira opção do combo
	@param cDef04,    characters, Quarta opção do combo
	@param cDef05,    characters, Quinta opção do combo
	@param cHelp,     characters, Texto de Help do parâmetro
	@obs Função foi criada, pois a partir de algumas versões do Protheus 12, a função padrão PutSX1 não funciona (por medidas de segurança)
	@example Abaixo um exemplo de como criar um grupo de perguntas
	
	cPerg    := "X_TST"
	
	cValid   := ""
	cF3      := ""
	cPicture := ""
	cDef01   := ""
	cDef02   := ""
	cDef03   := ""
	cDef04   := ""
	cDef05   := ""
	
	u_zPutSX1(cPerg, "01", "Produto De?",       "MV_PAR01", "MV_CH0", "C", TamSX3('B1_COD')[01], 0, "G", cValid,       "SB1", cPicture,        cDef01,  cDef02,        cDef03,        cDef04,    cDef05, "Informe o produto inicial")
	u_zPutSX1(cPerg, "02", "Produto Até?",      "MV_PAR02", "MV_CH1", "C", TamSX3('B1_COD')[01], 0, "G", cValid,       "SB1", cPicture,        cDef01,  cDef02,        cDef03,        cDef04,    cDef05, "Informe o produto final")
	u_zPutSX1(cPerg, "03", "A partir da Data?", "MV_PAR03", "MV_CH2", "D", 08,                   0, "G", cValid,       cF3,   cPicture,        cDef01,  cDef02,        cDef03,        cDef04,    cDef05, "Informe a data inicial a ser considerada")
	u_zPutSX1(cPerg, "04", "Média maior que?",  "MV_PAR04", "MV_CH3", "N", 09,                   2, "G", "Positivo()", cF3,   "@E 999,999.99", cDef01,  cDef02,        cDef03,        cDef04,    cDef05, "Informe a média de atraso que será considerada")
	u_zPutSX1(cPerg, "05", "Tipo de Saldos?",   "MV_PAR05", "MV_CH4", "N", 01,                   0, "C", cValid,       cF3,   cPicture,        "Todos", "Maior que 0", "Menor que 0", "Zerados", cDef05, "Informe o tipo de saldo a ser considerado")
	u_zPutSX1(cPerg, "06", "Tipos de Produto?", "MV_PAR06", "MV_CH5", "C", 60,                   0, "K", cValid,       cF3,   cPicture,        "PA",    "PI",          "MP",          cDef04,    cDef05, "Informe os tipos de produto que serão considerados")
	u_zPutSX1(cPerg, "07", "Caminho de Log?",   "MV_PAR07", "MV_CH6", "C", 60,                   0, "F", cValid,       cF3,   cPicture,        cDef01,  cDef02,        cDef03,        cDef04,    cDef05, "Informe o caminho para geração do log")
/*/

User Function zPutSX1(cGrupo, cOrdem, cTexto, cMVPar, cVariavel, cTipoCamp, nTamanho, nDecimal, cTipoPar, cValid, cF3, cPicture, cDef01, cDef02, cDef03, cDef04, cDef05, cHelp)
	Local aArea       := GetArea()
	Local cChaveHelp  := ""
	Local nPreSel     := 0
	Default cGrupo    := Space(10)
	Default cOrdem    := Space(02)
	Default cTexto    := Space(30)
	Default cMVPar    := Space(15)
	Default cVariavel := Space(6)
	Default cTipoCamp := Space(1)
	Default nTamanho  := 0
	Default nDecimal  := 0
	Default cTipoPar  := "G"
	Default cValid    := Space(60)
	Default cF3       := Space(6)
	Default cPicture  := Space(40)
	Default cDef01    := Space(15)
	Default cDef02    := Space(15)
	Default cDef03    := Space(15)
	Default cDef04    := Space(15)
	Default cDef05    := Space(15)
	Default cHelp     := ""
	
	//Se tiver Grupo, Ordem, Texto, Parâmetro, Variável, Tipo e Tamanho, continua para a criação do parâmetro
	If !Empty(cGrupo) .And. !Empty(cOrdem) .And. !Empty(cTexto) .And. !Empty(cMVPar) .And. !Empty(cVariavel) .And. !Empty(cTipoCamp) .And. nTamanho != 0
		
		//Definição de variáveis
		cGrupo     := PadR(cGrupo, Len(SX1->X1_GRUPO), " ")           //Adiciona espaços a direita para utilização no DbSeek
		cChaveHelp := "P." + AllTrim(cGrupo) + AllTrim(cOrdem) + "."  //Define o nome da pergunta
		cMVPar     := Upper(cMVPar)                                   //Deixa o MV_PAR tudo em maiúsculo
		nPreSel    := Iif(cTipoPar == "C", 1, 0)                      //Se for Combo, o pré-selecionado será o Primeiro
		cDef01     := Iif(cTipoPar == "F", "56", cDef01)              //Se for File, muda a definição para ser tanto Servidor quanto Local
		nTamanho   := Iif(nTamanho > 60, 60, nTamanho)                //Se o tamanho for maior que 60, volta para 60 - Limitação do Protheus
		nDecimal   := Iif(nDecimal > 9,  9,  nDecimal)                //Se o decimal for maior que 9, volta para 9
		nDecimal   := Iif(cTipoPar == "N", nDecimal, 0)               //Se não for parâmetro do tipo numérico, será 0 o Decimal
		cTipoCamp  := Upper(cTipoCamp)                                //Deixa o tipo do Campo em maiúsculo
		cTipoCamp  := Iif(! cTipoCamp $ 'C;D;N;', 'C', cTipoCamp)     //Se o tipo do Campo não estiver entre Caracter / Data / Numérico, será Caracter
		cTipoPar   := Upper(cTipoPar)                                 //Deixa o tipo do Parâmetro em maiúsculo
		cTipoPar   := Iif(Empty(cTipoPar), 'G', cTipoPar)             //Se o tipo do Parâmetro estiver em branco, será um Get
		nTamanho   := Iif(cTipoPar == "C", 1, nTamanho)               //Se for Combo, o tamanho será 1
	
		DbSelectArea('SX1')
		SX1->(DbSetOrder(1)) // Grupo + Ordem
	
		//Se não conseguir posicionar, a pergunta será criada
		If ! SX1->(DbSeek(cGrupo + cOrdem))
			RecLock('SX1', .T.)
				X1_GRUPO   := cGrupo
				X1_ORDEM   := cOrdem
				X1_PERGUNT := cTexto
				X1_PERSPA  := cTexto
				X1_PERENG  := cTexto
				X1_VAR01   := cMVPar
				X1_VARIAVL := cVariavel
				X1_TIPO    := cTipoCamp
				X1_TAMANHO := nTamanho
				X1_DECIMAL := nDecimal
				X1_GSC     := cTipoPar
				X1_VALID   := cValid
				X1_F3      := cF3
				X1_PICTURE := cPicture
				X1_DEF01   := cDef01
				X1_DEFSPA1 := cDef01
				X1_DEFENG1 := cDef01
				X1_DEF02   := cDef02
				X1_DEFSPA2 := cDef02
				X1_DEFENG2 := cDef02
				X1_DEF03   := cDef03
				X1_DEFSPA3 := cDef03
				X1_DEFENG3 := cDef03
				X1_DEF04   := cDef04
				X1_DEFSPA4 := cDef04
				X1_DEFENG4 := cDef04
				X1_DEF05   := cDef05
				X1_DEFSPA5 := cDef05
				X1_DEFENG5 := cDef05
				X1_PRESEL  := nPreSel
				
				//Se tiver Help da Pergunta
				If !Empty(cHelp)
					X1_HELP    := ""
					
					fPutHelp(cChaveHelp, cHelp)
				EndIf
			SX1->(MsUnlock())
		EndIf
	EndIf
	
	RestArea(aArea)
Return

/*---------------------------------------------------*
 | Função: fPutHelp                                  |
 | Desc:   Função que insere o Help do Parametro     |
 *---------------------------------------------------*/

Static Function fPutHelp(cKey, cHelp, lUpdate)
	Local cFilePor  := "SIGAHLP.HLP"
	Local cFileEng  := "SIGAHLE.HLE"
	Local cFileSpa  := "SIGAHLS.HLS"
	Local nRet      := 0
	Default cKey    := ""
	Default cHelp   := ""
	Default lUpdate := .F.
	
	//Se a Chave ou o Help estiverem em branco
	If Empty(cKey) .Or. Empty(cHelp)
		Return
	EndIf
	
	//**************************** Português
	nRet := SPF_SEEK(cFilePor, cKey, 1)
	
	//Se não encontrar, será inclusão
	If nRet < 0
		SPF_INSERT(cFilePor, cKey, , , cHelp)
	
	//Senão, será atualização
	Else
		If lUpdate
			SPF_UPDATE(cFilePor, nRet, cKey, , , cHelp)
		EndIf
	EndIf
	
	
	
	//**************************** Inglês
	nRet := SPF_SEEK(cFileEng, cKey, 1)
	
	//Se não encontrar, será inclusão
	If nRet < 0
		SPF_INSERT(cFileEng, cKey, , , cHelp)
	
	//Senão, será atualização
	Else
		If lUpdate
			SPF_UPDATE(cFileEng, nRet, cKey, , , cHelp)
		EndIf
	EndIf
	
	
	
	//**************************** Espanhol
	nRet := SPF_SEEK(cFileSpa, cKey, 1)
	
	//Se não encontrar, será inclusão
	If nRet < 0
		SPF_INSERT(cFileSpa, cKey, , , cHelp)
	
	//Senão, será atualização
	Else
		If lUpdate
			SPF_UPDATE(cFileSpa, nRet, cKey, , , cHelp)
		EndIf
	EndIf
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.

25 Responses

  1. Alexandre Marson disse:

    Prezado Dan_Atilio, seu post foi muito útil! Obrigado pela iniciativa.

  2. Mirnda disse:

    Boa noite não estou conseguindo,

  3. Miranda disse:

    está dando o erro abaixo

    c:\totvs12\protheus\MYPROJ~1\usuarios\zputsx1(5) Error C2051 LOCAL declaration follows executable statement

    Processo interrompido por erro FATAL de compilação.

    • Dan_Atilio disse:

      Boa noite Miranda, tudo bem?
      Estranho que a linha 5, é apenas uma linha que tem Default, você colocou a include Protheus.ch ?
      Qualquer coisa, mande o fonte por e-Mail, ou comente aqui nos comentários como está a sua função.
      Um grande abraço.

  4. Miranda disse:

    Bom dia Atílio,
    Obrigado
    Deu certo…

  5. Felipe Raposo Gonçalves de Melo disse:

    Talvez não seja uma boa ideia usar essa função.

  6. Felipe Raposo Gonçalves de Melo disse:

    Se a Totvs retirou essa função, tem um motivo. E ao meu ver, o motivo é bom. Dados de dicionário (SX1, SX2, SX3, etc) devem ser atualizados com uma UPD, com os usuários fora, e não a quente. Exceção feita ao SX5 (que já fica no banco, e não mais na system) e ao SX6, que são parâmetros. O resto, não acho boa ideia ficar mudando a quente.

  7. Alex Neto disse:

    Quando coloco pra executar a função nada acontece

    • Dan_Atilio disse:

      Bom dia Alex.
      Essa função foi criada a dois anos atrás, e de lá para cá, a TOTVS vem bloqueando funções que manipulam o banco, então se o seu Protheus estiver atualizado, pode ser esse o caso.
      Do contrário, debugue o fonte até chegar na parte do RecLock para ver o que está acontecendo.
      Abraços.

  8. Juan Regis disse:

    Uso essa função a um bom tempo, o problema e que agora com dicionario migrando pro banco, não posso mais usar ela, você tem já algo criado para esse caso??

  9. Carlos Henrique de Oliveira disse:

    Dan, na verdade a função ainda permite manipular o SX1, o que mudou é que o help passou a gravar na tabela XB4 conforme você já havia postado. Fiz uma modificação na sua função para poder gravar a informação no X1_HELP e também na XB4 e não tive problemas referente a isso.

    • Ah entendi Carlos.
      Obrigado pelo feedback jovem.
      Eu particularmente, deixei de usar a SX1 para perguntas e em meus clientes uso apenas o ParamBox, é mais rápido para montar a pergunta, e também tem a vantagem de passar pelo Code Analysis.
      Grande abraço jovem.

  10. Israel disse:

    Boa tarde, agora que o dicionário esta sendo migrado para o banco, voce tem a função atualizada com os novos métodos de acesso a SX1?

    • Bom dia Israel, tudo bem?
      Se eu não me engano a TOTVS desenvolveu uma classe, acho que o nome é FWSX1Util, ou algo assim.
      Mas, desde que eles já estavam bloqueando o lock da SX1, eu comecei a migrar os fontes que eu fazia nos clientes por ParamBox, ai não preciso ficar manipulando dicionário, deixo tudo em um array.
      Grande abraço.

  11. Hernan disse:

    Muchas gracias Dan. Esta funcion me sirvio mucho para entender algunos conceptos que no estan bien documentados.
    Quisiera preguntar, para el caso donde X1_GSC es F usas X1_DEF01 “56” para indicar que se pueden seleccionar archivos tanto del servidor como de forma local. Hay forma de indicar que solo se pueden seleccionar archivos locales?

    Desde ya muchas gracias
    Saludos

  12. Gabriel disse:

    Bom dia Dan tudo certo amigão?
    Estou com uma situação aqui, gostaria de saber se você pode me ajudar nas perguntas deste relatório.

    Nas perguntas preciso colocar todas estas opções “1=AA”,”2=A”,”3=B”,”4=C”,”5=D”,”6=E”,”7=Ambos para o usuário selecionar os níveis do Cliente, mas pelo que observei na tabela sx1 ele consegue utilizar somente 5 opções – X1_DEF01 – X1_DEF02 – X1_DEF03 – X1_DEF04 – X1_DEF05

    aAdd(vPerg,{“Nível do Cliente?” ,”C”, 1, 0, “C”,{“1=AA”,”2=A”,”3=B”,”4=C”,”5=D”,”6=E”,”7=Ambos”},””}) //MV_PAR03

    Tem como me auxiliar nesta situação? Te agradeço

  13. Prezados, essa funcionalidade a partir do release 12.1.33 é válida?

    • Bom dia Robson, tudo joia?

      Então, esse artigo é um pouco antigo, de 6 anos atrás. Pode ser que funcione algumas coisas, e outras tenham que ser adaptadas.

      Porém, atualmente a TOTVS não recomenda mais a manipulação direta de dicionário de dados (inclusive é um dos pontos do Code Analysis deles.

      O indicado então, para as perguntas é:
      1. Ou criar via Configurador antes de criar sua customização
      2. Ou se você for utilizar em vários clientes, usar ParamBox com um Array

      Abraços.

Deixe uma resposta para Alex NetoCancelar resposta

Terminal de Informação